|
1 YUI.add('dom-style', function (Y, NAME) { |
|
2 |
|
3 (function(Y) { |
|
4 /** |
|
5 * Add style management functionality to DOM. |
|
6 * @module dom |
|
7 * @submodule dom-style |
|
8 * @for DOM |
|
9 */ |
|
10 |
|
11 var DOCUMENT_ELEMENT = 'documentElement', |
|
12 DEFAULT_VIEW = 'defaultView', |
|
13 OWNER_DOCUMENT = 'ownerDocument', |
|
14 STYLE = 'style', |
|
15 FLOAT = 'float', |
|
16 CSS_FLOAT = 'cssFloat', |
|
17 STYLE_FLOAT = 'styleFloat', |
|
18 TRANSPARENT = 'transparent', |
|
19 GET_COMPUTED_STYLE = 'getComputedStyle', |
|
20 GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect', |
|
21 |
|
22 WINDOW = Y.config.win, |
|
23 DOCUMENT = Y.config.doc, |
|
24 UNDEFINED = undefined, |
|
25 |
|
26 Y_DOM = Y.DOM, |
|
27 |
|
28 TRANSFORM = 'transform', |
|
29 TRANSFORMORIGIN = 'transformOrigin', |
|
30 VENDOR_TRANSFORM = [ |
|
31 'WebkitTransform', |
|
32 'MozTransform', |
|
33 'OTransform', |
|
34 'msTransform' |
|
35 ], |
|
36 |
|
37 re_color = /color$/i, |
|
38 re_unit = /width|height|top|left|right|bottom|margin|padding/i; |
|
39 |
|
40 Y.Array.each(VENDOR_TRANSFORM, function(val) { |
|
41 if (val in DOCUMENT[DOCUMENT_ELEMENT].style) { |
|
42 TRANSFORM = val; |
|
43 TRANSFORMORIGIN = val + "Origin"; |
|
44 } |
|
45 }); |
|
46 |
|
47 Y.mix(Y_DOM, { |
|
48 DEFAULT_UNIT: 'px', |
|
49 |
|
50 CUSTOM_STYLES: { |
|
51 }, |
|
52 |
|
53 |
|
54 /** |
|
55 * Sets a style property for a given element. |
|
56 * @method setStyle |
|
57 * @param {HTMLElement} An HTMLElement to apply the style to. |
|
58 * @param {String} att The style property to set. |
|
59 * @param {String|Number} val The value. |
|
60 */ |
|
61 setStyle: function(node, att, val, style) { |
|
62 style = style || node.style; |
|
63 var CUSTOM_STYLES = Y_DOM.CUSTOM_STYLES; |
|
64 |
|
65 if (style) { |
|
66 if (val === null || val === '') { // normalize unsetting |
|
67 val = ''; |
|
68 } else if (!isNaN(new Number(val)) && re_unit.test(att)) { // number values may need a unit |
|
69 val += Y_DOM.DEFAULT_UNIT; |
|
70 } |
|
71 |
|
72 if (att in CUSTOM_STYLES) { |
|
73 if (CUSTOM_STYLES[att].set) { |
|
74 CUSTOM_STYLES[att].set(node, val, style); |
|
75 return; // NOTE: return |
|
76 } else if (typeof CUSTOM_STYLES[att] === 'string') { |
|
77 att = CUSTOM_STYLES[att]; |
|
78 } |
|
79 } else if (att === '') { // unset inline styles |
|
80 att = 'cssText'; |
|
81 val = ''; |
|
82 } |
|
83 style[att] = val; |
|
84 } |
|
85 }, |
|
86 |
|
87 /** |
|
88 * Returns the current style value for the given property. |
|
89 * @method getStyle |
|
90 * @param {HTMLElement} An HTMLElement to get the style from. |
|
91 * @param {String} att The style property to get. |
|
92 */ |
|
93 getStyle: function(node, att, style) { |
|
94 style = style || node.style; |
|
95 var CUSTOM_STYLES = Y_DOM.CUSTOM_STYLES, |
|
96 val = ''; |
|
97 |
|
98 if (style) { |
|
99 if (att in CUSTOM_STYLES) { |
|
100 if (CUSTOM_STYLES[att].get) { |
|
101 return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return |
|
102 } else if (typeof CUSTOM_STYLES[att] === 'string') { |
|
103 att = CUSTOM_STYLES[att]; |
|
104 } |
|
105 } |
|
106 val = style[att]; |
|
107 if (val === '') { // TODO: is empty string sufficient? |
|
108 val = Y_DOM[GET_COMPUTED_STYLE](node, att); |
|
109 } |
|
110 } |
|
111 |
|
112 return val; |
|
113 }, |
|
114 |
|
115 /** |
|
116 * Sets multiple style properties. |
|
117 * @method setStyles |
|
118 * @param {HTMLElement} node An HTMLElement to apply the styles to. |
|
119 * @param {Object} hash An object literal of property:value pairs. |
|
120 */ |
|
121 setStyles: function(node, hash) { |
|
122 var style = node.style; |
|
123 Y.each(hash, function(v, n) { |
|
124 Y_DOM.setStyle(node, n, v, style); |
|
125 }, Y_DOM); |
|
126 }, |
|
127 |
|
128 /** |
|
129 * Returns the computed style for the given node. |
|
130 * @method getComputedStyle |
|
131 * @param {HTMLElement} An HTMLElement to get the style from. |
|
132 * @param {String} att The style property to get. |
|
133 * @return {String} The computed value of the style property. |
|
134 */ |
|
135 getComputedStyle: function(node, att) { |
|
136 var val = '', |
|
137 doc = node[OWNER_DOCUMENT], |
|
138 computed; |
|
139 |
|
140 if (node[STYLE] && doc[DEFAULT_VIEW] && doc[DEFAULT_VIEW][GET_COMPUTED_STYLE]) { |
|
141 computed = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null); |
|
142 if (computed) { // FF may be null in some cases (ticket #2530548) |
|
143 val = computed[att]; |
|
144 } |
|
145 } |
|
146 return val; |
|
147 } |
|
148 }); |
|
149 |
|
150 // normalize reserved word float alternatives ("cssFloat" or "styleFloat") |
|
151 if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== UNDEFINED) { |
|
152 Y_DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT; |
|
153 } else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== UNDEFINED) { |
|
154 Y_DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT; |
|
155 } |
|
156 |
|
157 // fix opera computedStyle default color unit (convert to rgb) |
|
158 if (Y.UA.opera) { |
|
159 Y_DOM[GET_COMPUTED_STYLE] = function(node, att) { |
|
160 var view = node[OWNER_DOCUMENT][DEFAULT_VIEW], |
|
161 val = view[GET_COMPUTED_STYLE](node, '')[att]; |
|
162 |
|
163 if (re_color.test(att)) { |
|
164 val = Y.Color.toRGB(val); |
|
165 } |
|
166 |
|
167 return val; |
|
168 }; |
|
169 |
|
170 } |
|
171 |
|
172 // safari converts transparent to rgba(), others use "transparent" |
|
173 if (Y.UA.webkit) { |
|
174 Y_DOM[GET_COMPUTED_STYLE] = function(node, att) { |
|
175 var view = node[OWNER_DOCUMENT][DEFAULT_VIEW], |
|
176 val = view[GET_COMPUTED_STYLE](node, '')[att]; |
|
177 |
|
178 if (val === 'rgba(0, 0, 0, 0)') { |
|
179 val = TRANSPARENT; |
|
180 } |
|
181 |
|
182 return val; |
|
183 }; |
|
184 |
|
185 } |
|
186 |
|
187 Y.DOM._getAttrOffset = function(node, attr) { |
|
188 var val = Y.DOM[GET_COMPUTED_STYLE](node, attr), |
|
189 offsetParent = node.offsetParent, |
|
190 position, |
|
191 parentOffset, |
|
192 offset; |
|
193 |
|
194 if (val === 'auto') { |
|
195 position = Y.DOM.getStyle(node, 'position'); |
|
196 if (position === 'static' || position === 'relative') { |
|
197 val = 0; |
|
198 } else if (offsetParent && offsetParent[GET_BOUNDING_CLIENT_RECT]) { |
|
199 parentOffset = offsetParent[GET_BOUNDING_CLIENT_RECT]()[attr]; |
|
200 offset = node[GET_BOUNDING_CLIENT_RECT]()[attr]; |
|
201 if (attr === 'left' || attr === 'top') { |
|
202 val = offset - parentOffset; |
|
203 } else { |
|
204 val = parentOffset - node[GET_BOUNDING_CLIENT_RECT]()[attr]; |
|
205 } |
|
206 } |
|
207 } |
|
208 |
|
209 return val; |
|
210 }; |
|
211 |
|
212 Y.DOM._getOffset = function(node) { |
|
213 var pos, |
|
214 xy = null; |
|
215 |
|
216 if (node) { |
|
217 pos = Y_DOM.getStyle(node, 'position'); |
|
218 xy = [ |
|
219 parseInt(Y_DOM[GET_COMPUTED_STYLE](node, 'left'), 10), |
|
220 parseInt(Y_DOM[GET_COMPUTED_STYLE](node, 'top'), 10) |
|
221 ]; |
|
222 |
|
223 if ( isNaN(xy[0]) ) { // in case of 'auto' |
|
224 xy[0] = parseInt(Y_DOM.getStyle(node, 'left'), 10); // try inline |
|
225 if ( isNaN(xy[0]) ) { // default to offset value |
|
226 xy[0] = (pos === 'relative') ? 0 : node.offsetLeft || 0; |
|
227 } |
|
228 } |
|
229 |
|
230 if ( isNaN(xy[1]) ) { // in case of 'auto' |
|
231 xy[1] = parseInt(Y_DOM.getStyle(node, 'top'), 10); // try inline |
|
232 if ( isNaN(xy[1]) ) { // default to offset value |
|
233 xy[1] = (pos === 'relative') ? 0 : node.offsetTop || 0; |
|
234 } |
|
235 } |
|
236 } |
|
237 |
|
238 return xy; |
|
239 |
|
240 }; |
|
241 |
|
242 Y_DOM.CUSTOM_STYLES.transform = { |
|
243 set: function(node, val, style) { |
|
244 style[TRANSFORM] = val; |
|
245 }, |
|
246 |
|
247 get: function(node, style) { |
|
248 return Y_DOM[GET_COMPUTED_STYLE](node, TRANSFORM); |
|
249 } |
|
250 }; |
|
251 |
|
252 Y_DOM.CUSTOM_STYLES.transformOrigin = { |
|
253 set: function(node, val, style) { |
|
254 style[TRANSFORMORIGIN] = val; |
|
255 }, |
|
256 |
|
257 get: function(node, style) { |
|
258 return Y_DOM[GET_COMPUTED_STYLE](node, TRANSFORMORIGIN); |
|
259 } |
|
260 }; |
|
261 |
|
262 |
|
263 })(Y); |
|
264 |
|
265 |
|
266 }, '@VERSION@', {"requires": ["dom-base", "color-base"]}); |