]>
Commit | Line | Data |
---|---|---|
1354d172 AD |
1 | define("dojo/dom-style", ["./_base/sniff", "./dom"], function(has, dom){ |
2 | // module: | |
3 | // dojo/dom-style | |
4 | // summary: | |
5 | // This module defines the core dojo DOM style API. | |
6 | ||
7 | // ============================= | |
8 | // Style Functions | |
9 | // ============================= | |
10 | ||
11 | // getComputedStyle drives most of the style code. | |
12 | // Wherever possible, reuse the returned object. | |
13 | // | |
14 | // API functions below that need to access computed styles accept an | |
15 | // optional computedStyle parameter. | |
16 | // If this parameter is omitted, the functions will call getComputedStyle themselves. | |
17 | // This way, calling code can access computedStyle once, and then pass the reference to | |
18 | // multiple API functions. | |
19 | ||
20 | /*===== | |
21 | dojo.getComputedStyle = function(node){ | |
22 | // summary: | |
23 | // Returns a "computed style" object. | |
24 | // | |
25 | // description: | |
26 | // Gets a "computed style" object which can be used to gather | |
27 | // information about the current state of the rendered node. | |
28 | // | |
29 | // Note that this may behave differently on different browsers. | |
30 | // Values may have different formats and value encodings across | |
31 | // browsers. | |
32 | // | |
33 | // Note also that this method is expensive. Wherever possible, | |
34 | // reuse the returned object. | |
35 | // | |
36 | // Use the dojo.style() method for more consistent (pixelized) | |
37 | // return values. | |
38 | // | |
39 | // node: DOMNode | |
40 | // A reference to a DOM node. Does NOT support taking an | |
41 | // ID string for speed reasons. | |
42 | // example: | |
43 | // | dojo.getComputedStyle(dojo.byId('foo')).borderWidth; | |
44 | // | |
45 | // example: | |
46 | // Reusing the returned object, avoiding multiple lookups: | |
47 | // | var cs = dojo.getComputedStyle(dojo.byId("someNode")); | |
48 | // | var w = cs.width, h = cs.height; | |
49 | return; // CSS2Properties | |
50 | } | |
51 | =====*/ | |
52 | ||
53 | /*===== | |
54 | dojo.toPixelValue = function(node, value){ | |
55 | // summary: | |
56 | // converts style value to pixels on IE or return a numeric value. | |
57 | // node: DOMNode | |
58 | // value: String | |
59 | // returns: Number | |
60 | }; | |
61 | =====*/ | |
62 | ||
63 | /*===== | |
64 | dojo._toPixelValue = function(node, value){ | |
65 | // summary: | |
66 | // Existing alias for `dojo._toPixelValue`. Deprecated, will be removed in 2.0. | |
67 | }; | |
68 | =====*/ | |
69 | ||
70 | /*===== | |
71 | dojo.getStyle = function(node, name){ | |
72 | // summary: | |
73 | // Accesses styles on a node. | |
74 | // description: | |
75 | // Getting the style value uses the computed style for the node, so the value | |
76 | // will be a calculated value, not just the immediate node.style value. | |
77 | // Also when getting values, use specific style names, | |
78 | // like "borderBottomWidth" instead of "border" since compound values like | |
79 | // "border" are not necessarily reflected as expected. | |
80 | // If you want to get node dimensions, use `dojo.marginBox()`, | |
81 | // `dojo.contentBox()` or `dojo.position()`. | |
82 | // node: DOMNode|String | |
83 | // id or reference to node to get style for | |
84 | // name: String? | |
85 | // the style property to get | |
86 | // example: | |
87 | // Passing only an ID or node returns the computed style object of | |
88 | // the node: | |
89 | // | dojo.getStyle("thinger"); | |
90 | // example: | |
91 | // Passing a node and a style property returns the current | |
92 | // normalized, computed value for that property: | |
93 | // | dojo.getStyle("thinger", "opacity"); // 1 by default | |
94 | }; | |
95 | =====*/ | |
96 | ||
97 | /*===== | |
98 | dojo.setStyle = function(node, name, value){ | |
99 | // summary: | |
100 | // Sets styles on a node. | |
101 | // node: DOMNode|String | |
102 | // id or reference to node to set style for | |
103 | // name: String|Object | |
104 | // the style property to set in DOM-accessor format | |
105 | // ("borderWidth", not "border-width") or an object with key/value | |
106 | // pairs suitable for setting each property. | |
107 | // value: String? | |
108 | // If passed, sets value on the node for style, handling | |
109 | // cross-browser concerns. When setting a pixel value, | |
110 | // be sure to include "px" in the value. For instance, top: "200px". | |
111 | // Otherwise, in some cases, some browsers will not apply the style. | |
112 | // | |
113 | // example: | |
114 | // Passing a node, a style property, and a value changes the | |
115 | // current display of the node and returns the new computed value | |
116 | // | dojo.setStyle("thinger", "opacity", 0.5); // == 0.5 | |
117 | // | |
118 | // example: | |
119 | // Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node: | |
120 | // | dojo.setStyle("thinger", { | |
121 | // | "opacity": 0.5, | |
122 | // | "border": "3px solid black", | |
123 | // | "height": "300px" | |
124 | // | }); | |
125 | // | |
126 | // example: | |
127 | // When the CSS style property is hyphenated, the JavaScript property is camelCased. | |
128 | // font-size becomes fontSize, and so on. | |
129 | // | dojo.setStyle("thinger",{ | |
130 | // | fontSize:"14pt", | |
131 | // | letterSpacing:"1.2em" | |
132 | // | }); | |
133 | // | |
134 | // example: | |
135 | // dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling | |
136 | // dojo.style() on every element of the list. See: `dojo.query()` and `dojo.NodeList()` | |
137 | // | dojo.query(".someClassName").style("visibility","hidden"); | |
138 | // | // or | |
139 | // | dojo.query("#baz > div").style({ | |
140 | // | opacity:0.75, | |
141 | // | fontSize:"13pt" | |
142 | // | }); | |
143 | }; | |
144 | =====*/ | |
145 | ||
146 | // Although we normally eschew argument validation at this | |
147 | // level, here we test argument 'node' for (duck)type, | |
148 | // by testing nodeType, ecause 'document' is the 'parentNode' of 'body' | |
149 | // it is frequently sent to this function even | |
150 | // though it is not Element. | |
151 | var getComputedStyle, style = {}; | |
152 | if(has("webkit")){ | |
153 | getComputedStyle = function(/*DomNode*/node){ | |
154 | var s; | |
155 | if(node.nodeType == 1){ | |
156 | var dv = node.ownerDocument.defaultView; | |
157 | s = dv.getComputedStyle(node, null); | |
158 | if(!s && node.style){ | |
159 | node.style.display = ""; | |
160 | s = dv.getComputedStyle(node, null); | |
161 | } | |
162 | } | |
163 | return s || {}; | |
164 | }; | |
165 | }else if(has("ie") && (has("ie") < 9 || has("quirks"))){ | |
166 | getComputedStyle = function(node){ | |
167 | // IE (as of 7) doesn't expose Element like sane browsers | |
168 | return node.nodeType == 1 /* ELEMENT_NODE*/ ? node.currentStyle : {}; | |
169 | }; | |
170 | }else{ | |
171 | getComputedStyle = function(node){ | |
172 | return node.nodeType == 1 ? | |
173 | node.ownerDocument.defaultView.getComputedStyle(node, null) : {}; | |
174 | }; | |
175 | } | |
176 | style.getComputedStyle = getComputedStyle; | |
177 | ||
178 | var toPixel; | |
179 | if(!has("ie")){ | |
180 | toPixel = function(element, value){ | |
181 | // style values can be floats, client code may want | |
182 | // to round for integer pixels. | |
183 | return parseFloat(value) || 0; | |
184 | }; | |
185 | }else{ | |
186 | toPixel = function(element, avalue){ | |
187 | if(!avalue){ return 0; } | |
188 | // on IE7, medium is usually 4 pixels | |
189 | if(avalue == "medium"){ return 4; } | |
190 | // style values can be floats, client code may | |
191 | // want to round this value for integer pixels. | |
192 | if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); } | |
193 | var s = element.style, rs = element.runtimeStyle, cs = element.currentStyle, | |
194 | sLeft = s.left, rsLeft = rs.left; | |
195 | rs.left = cs.left; | |
196 | try{ | |
197 | // 'avalue' may be incompatible with style.left, which can cause IE to throw | |
198 | // this has been observed for border widths using "thin", "medium", "thick" constants | |
199 | // those particular constants could be trapped by a lookup | |
200 | // but perhaps there are more | |
201 | s.left = avalue; | |
202 | avalue = s.pixelLeft; | |
203 | }catch(e){ | |
204 | avalue = 0; | |
205 | } | |
206 | s.left = sLeft; | |
207 | rs.left = rsLeft; | |
208 | return avalue; | |
209 | } | |
210 | } | |
211 | style.toPixelValue = toPixel; | |
212 | ||
213 | // FIXME: there opacity quirks on FF that we haven't ported over. Hrm. | |
214 | ||
215 | var astr = "DXImageTransform.Microsoft.Alpha"; | |
216 | var af = function(n, f){ | |
217 | try{ | |
218 | return n.filters.item(astr); | |
219 | }catch(e){ | |
220 | return f ? {} : null; | |
221 | } | |
222 | }; | |
223 | ||
224 | var _getOpacity = | |
225 | has("ie") < 9 || (has("ie") && has("quirks")) ? function(node){ | |
226 | try{ | |
227 | return af(node).Opacity / 100; // Number | |
228 | }catch(e){ | |
229 | return 1; // Number | |
230 | } | |
231 | } : | |
232 | function(node){ | |
233 | return getComputedStyle(node).opacity; | |
234 | }; | |
235 | ||
236 | var _setOpacity = | |
237 | has("ie") < 9 || (has("ie") && has("quirks")) ? function(/*DomNode*/node, /*Number*/opacity){ | |
238 | var ov = opacity * 100, opaque = opacity == 1; | |
239 | node.style.zoom = opaque ? "" : 1; | |
240 | ||
241 | if(!af(node)){ | |
242 | if(opaque){ | |
243 | return opacity; | |
244 | } | |
245 | node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; | |
246 | }else{ | |
247 | af(node, 1).Opacity = ov; | |
248 | } | |
249 | ||
250 | // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661), | |
251 | //but still update the opacity value so we can get a correct reading if it is read later. | |
252 | af(node, 1).Enabled = !opaque; | |
253 | ||
254 | if(node.tagName.toLowerCase() == "tr"){ | |
255 | for(var td = node.firstChild; td; td = td.nextSibling){ | |
256 | if(td.tagName.toLowerCase() == "td"){ | |
257 | _setOpacity(td, opacity); | |
258 | } | |
259 | } | |
260 | } | |
261 | return opacity; | |
262 | } : | |
263 | function(node, opacity){ | |
264 | return node.style.opacity = opacity; | |
265 | }; | |
266 | ||
267 | var _pixelNamesCache = { | |
268 | left: true, top: true | |
269 | }; | |
270 | var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border | |
271 | function _toStyleValue(node, type, value){ | |
272 | //TODO: should we really be doing string case conversion here? Should we cache it? Need to profile! | |
273 | type = type.toLowerCase(); | |
274 | if(has("ie")){ | |
275 | if(value == "auto"){ | |
276 | if(type == "height"){ return node.offsetHeight; } | |
277 | if(type == "width"){ return node.offsetWidth; } | |
278 | } | |
279 | if(type == "fontweight"){ | |
280 | switch(value){ | |
281 | case 700: return "bold"; | |
282 | case 400: | |
283 | default: return "normal"; | |
284 | } | |
285 | } | |
286 | } | |
287 | if(!(type in _pixelNamesCache)){ | |
288 | _pixelNamesCache[type] = _pixelRegExp.test(type); | |
289 | } | |
290 | return _pixelNamesCache[type] ? toPixel(node, value) : value; | |
291 | } | |
292 | ||
293 | var _floatStyle = has("ie") ? "styleFloat" : "cssFloat", | |
294 | _floatAliases = {"cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle}; | |
295 | ||
296 | // public API | |
297 | ||
298 | style.get = function getStyle(/*DOMNode|String*/ node, /*String?*/ name){ | |
299 | var n = dom.byId(node), l = arguments.length, op = (name == "opacity"); | |
300 | if(l == 2 && op){ | |
301 | return _getOpacity(n); | |
302 | } | |
303 | name = _floatAliases[name] || name; | |
304 | var s = style.getComputedStyle(n); | |
305 | return (l == 1) ? s : _toStyleValue(n, name, s[name] || n.style[name]); /* CSS2Properties||String||Number */ | |
306 | }; | |
307 | ||
308 | style.set = function setStyle(/*DOMNode|String*/ node, /*String|Object*/ name, /*String?*/ value){ | |
309 | var n = dom.byId(node), l = arguments.length, op = (name == "opacity"); | |
310 | name = _floatAliases[name] || name; | |
311 | if(l == 3){ | |
312 | return op ? _setOpacity(n, value) : n.style[name] = value; // Number | |
313 | } | |
314 | for(var x in name){ | |
315 | style.set(node, x, name[x]); | |
316 | } | |
317 | return style.getComputedStyle(n); | |
318 | }; | |
319 | ||
320 | return style; | |
321 | }); |