source: Dev/trunk/src/client/dojo/dom-style.js @ 527

Last change on this file since 527 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

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