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