a6e2bb6143613a6d187a58c7f803d7beacff5afe
[jquery.git] / src / css.js
1 (function( jQuery ) {
2
3 var ralpha = /alpha\([^)]*\)/i,
4         ropacity = /opacity=([^)]*)/,
5         rdashAlpha = /-([a-z])/ig,
6         rupper = /([A-Z])/g,
7         rnumpx = /^-?\d+(?:px)?$/i,
8         rnum = /^-?\d/,
9
10         cssShow = { position: "absolute", visibility: "hidden", display: "block" },
11         cssWidth = [ "Left", "Right" ],
12         cssHeight = [ "Top", "Bottom" ],
13         curCSS,
14
15         fcamelCase = function( all, letter ) {
16                 return letter.toUpperCase();
17         };
18
19 jQuery.fn.css = function( name, value ) {
20         // Setting 'undefined' is a no-op
21         if ( arguments.length === 2 && value === undefined ) {
22                 return this;
23         }
24
25         return jQuery.access( this, name, value, true, function( elem, name, value ) {
26                 return value !== undefined ?
27                         jQuery.style( elem, name, value ) :
28                         jQuery.css( elem, name );
29         });
30 };
31
32 jQuery.extend({
33         // Add in style property hooks for overriding the default
34         // behavior of getting and setting a style property
35         cssHooks: {
36                 opacity: {
37                         get: function( elem, computed ) {
38                                 if ( computed ) {
39                                         // We should always get a number back from opacity
40                                         var ret = curCSS( elem, "opacity", "opacity" );
41                                         return ret === "" ? "1" : ret;
42
43                                 } else {
44                                         return elem.style.opacity;
45                                 }
46                         }
47                 }
48         },
49
50         // Exclude the following css properties to add px
51         cssNumber: {
52                 "zIndex": true,
53                 "fontWeight": true,
54                 "opacity": true,
55                 "zoom": true,
56                 "lineHeight": true
57         },
58
59         // Add in properties whose names you wish to fix before
60         // setting or getting the value
61         cssProps: {
62                 // normalize float css property
63                 "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
64         },
65
66         // Get and set the style property on a DOM Node
67         style: function( elem, name, value, extra ) {
68                 // Don't set styles on text and comment nodes
69                 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
70                         return;
71                 }
72
73                 // Make sure that we're working with the right name
74                 var ret, origName = jQuery.camelCase( name ),
75                         style = elem.style, hooks = jQuery.cssHooks[ origName ];
76
77                 name = jQuery.cssProps[ origName ] || origName;
78
79                 // Check if we're setting a value
80                 if ( value !== undefined ) {
81                         // Make sure that NaN and null values aren't set. See: #7116
82                         if ( typeof value === "number" && isNaN( value ) || value == null ) {
83                                 return;
84                         }
85
86                         // If a number was passed in, add 'px' to the (except for certain CSS properties)
87                         if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) {
88                                 value += "px";
89                         }
90
91                         // If a hook was provided, use that value, otherwise just set the specified value
92                         if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
93                                 // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
94                                 // Fixes bug #5509
95                                 try {
96                                         style[ name ] = value;
97                                 } catch(e) {}
98                         }
99
100                 } else {
101                         // If a hook was provided get the non-computed value from there
102                         if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
103                                 return ret;
104                         }
105
106                         // Otherwise just get the value from the style object
107                         return style[ name ];
108                 }
109         },
110
111         css: function( elem, name, extra ) {
112                 // Make sure that we're working with the right name
113                 var ret, origName = jQuery.camelCase( name ),
114                         hooks = jQuery.cssHooks[ origName ];
115
116                 name = jQuery.cssProps[ origName ] || origName;
117
118                 // If a hook was provided get the computed value from there
119                 if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
120                         return ret;
121
122                 // Otherwise, if a way to get the computed value exists, use that
123                 } else if ( curCSS ) {
124                         return curCSS( elem, name, origName );
125                 }
126         },
127
128         // A method for quickly swapping in/out CSS properties to get correct calculations
129         swap: function( elem, options, callback ) {
130                 var old = {};
131
132                 // Remember the old values, and insert the new ones
133                 for ( var name in options ) {
134                         old[ name ] = elem.style[ name ];
135                         elem.style[ name ] = options[ name ];
136                 }
137
138                 callback.call( elem );
139
140                 // Revert the old values
141                 for ( name in options ) {
142                         elem.style[ name ] = old[ name ];
143                 }
144         },
145
146         camelCase: function( string ) {
147                 return string.replace( rdashAlpha, fcamelCase );
148         }
149 });
150
151 // DEPRECATED, Use jQuery.css() instead
152 jQuery.curCSS = jQuery.css;
153
154 jQuery.each(["height", "width"], function( i, name ) {
155         jQuery.cssHooks[ name ] = {
156                 get: function( elem, computed, extra ) {
157                         var val;
158
159                         if ( computed ) {
160                                 if ( elem.offsetWidth !== 0 ) {
161                                         val = getWH( elem, name, extra );
162
163                                 } else {
164                                         jQuery.swap( elem, cssShow, function() {
165                                                 val = getWH( elem, name, extra );
166                                         });
167                                 }
168
169                                 if ( val <= 0 ) {
170                                         val = curCSS( elem, name, name );
171
172                                         if ( val != null ) {
173                                                 // Should return "auto" instead of 0, use 0 for
174                                                 // temporary backwards-compat
175                                                 return val === "" || val === "auto" ? "0px" : val;
176                                         }
177                                 }
178
179                                 if ( val < 0 || val == null ) {
180                                         val = elem.style[ name ];
181
182                                         // Should return "auto" instead of 0, use 0 for
183                                         // temporary backwards-compat
184                                         return val === "" || val === "auto" ? "0px" : val;
185                                 }
186
187                                 return typeof val === "string" ? val : val + "px";
188                         }
189                 },
190
191                 set: function( elem, value ) {
192                         if ( rnumpx.test( value ) ) {
193                                 // ignore negative width and height values #1599
194                                 value = parseFloat(value);
195
196                                 if ( value >= 0 ) {
197                                         return value + "px";
198                                 }
199
200                         } else {
201                                 return value;
202                         }
203                 }
204         };
205 });
206
207 if ( !jQuery.support.opacity ) {
208         jQuery.cssHooks.opacity = {
209                 get: function( elem, computed ) {
210                         // IE uses filters for opacity
211                         return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "") ?
212                                 (parseFloat(RegExp.$1) / 100) + "" :
213                                 computed ? "1" : "";
214                 },
215
216                 set: function( elem, value ) {
217                         var style = elem.style;
218
219                         // IE has trouble with opacity if it does not have layout
220                         // Force it by setting the zoom level
221                         style.zoom = 1;
222
223                         // Set the alpha filter to set the opacity
224                         var opacity = jQuery.isNaN(value) ?
225                                 "" :
226                                 "alpha(opacity=" + value * 100 + ")",
227                                 filter = style.filter || "";
228
229                         style.filter = ralpha.test(filter) ?
230                                 filter.replace(ralpha, opacity) :
231                                 style.filter + ' ' + opacity;
232                 }
233         };
234 }
235
236 if ( document.defaultView && document.defaultView.getComputedStyle ) {
237         curCSS = function( elem, newName, name ) {
238                 var ret, defaultView, computedStyle;
239
240                 name = name.replace( rupper, "-$1" ).toLowerCase();
241
242                 if ( !(defaultView = elem.ownerDocument.defaultView) ) {
243                         return undefined;
244                 }
245
246                 if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
247                         ret = computedStyle.getPropertyValue( name );
248                         if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
249                                 ret = jQuery.style( elem, name );
250                         }
251                 }
252
253                 return ret;
254         };
255 } else if ( document.documentElement.currentStyle ) {
256         curCSS = function( elem, name ) {
257                 var left, rsLeft,
258                         ret = elem.currentStyle && elem.currentStyle[ name ],
259                         style = elem.style;
260
261                 // From the awesome hack by Dean Edwards
262                 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
263
264                 // If we're not dealing with a regular pixel number
265                 // but a number that has a weird ending, we need to convert it to pixels
266                 if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
267                         // Remember the original values
268                         left = style.left;
269                         rsLeft = elem.runtimeStyle.left;
270
271                         // Put in the new values to get a computed value out
272                         elem.runtimeStyle.left = elem.currentStyle.left;
273                         style.left = name === "fontSize" ? "1em" : (ret || 0);
274                         ret = style.pixelLeft + "px";
275
276                         // Revert the changed values
277                         style.left = left;
278                         elem.runtimeStyle.left = rsLeft;
279                 }
280
281                 return ret === "" ? "auto" : ret;
282         };
283 }
284
285 function getWH( elem, name, extra ) {
286         var which = name === "width" ? cssWidth : cssHeight,
287                 val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
288
289         if ( extra === "border" ) {
290                 return val;
291         }
292
293         jQuery.each( which, function() {
294                 if ( !extra ) {
295                         val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0;
296                 }
297
298                 if ( extra === "margin" ) {
299                         val += parseFloat(jQuery.css( elem, "margin" + this )) || 0;
300
301                 } else {
302                         val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0;
303                 }
304         });
305
306         return val;
307 }
308
309 if ( jQuery.expr && jQuery.expr.filters ) {
310         jQuery.expr.filters.hidden = function( elem ) {
311                 var width = elem.offsetWidth,
312                         height = elem.offsetHeight;
313
314                 return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
315         };
316
317         jQuery.expr.filters.visible = function( elem ) {
318                 return !jQuery.expr.filters.hidden( elem );
319         };
320 }
321
322 })( jQuery );