Release: push dist to same remote as project
[jquery.git] / src / css.js
blobd8e60b8576a2689501c1217b8109acac376b305e
1 define([
2         "./core",
3         "./var/pnum",
4         "./core/access",
5         "./css/var/rmargin",
6         "./css/var/rnumnonpx",
7         "./css/var/cssExpand",
8         "./css/var/isHidden",
9         "./css/var/getStyles",
10         "./css/curCSS",
11         "./css/defaultDisplay",
12         "./css/addGetHookIf",
13         "./css/support",
14         "./data/var/dataPriv",
16         "./core/init",
17         "./css/swap",
18         "./core/ready",
19         "./selector" // contains
20 ], function( jQuery, pnum, access, rmargin, rnumnonpx, cssExpand, isHidden,
21         getStyles, curCSS, defaultDisplay, addGetHookIf, support, dataPriv ) {
23 var
24         // Swappable if display is none or starts with table
25         // except "table", "table-cell", or "table-caption"
26         // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
27         rdisplayswap = /^(none|table(?!-c[ea]).+)/,
28         rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
29         rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
31         cssShow = { position: "absolute", visibility: "hidden", display: "block" },
32         cssNormalTransform = {
33                 letterSpacing: "0",
34                 fontWeight: "400"
35         },
37         cssPrefixes = [ "Webkit", "Moz", "ms" ];
39 // Return a css property mapped to a potentially vendor prefixed property
40 function vendorPropName( style, name ) {
42         // Shortcut for names that are not vendor prefixed
43         if ( name in style ) {
44                 return name;
45         }
47         // Check for vendor prefixed names
48         var capName = name[0].toUpperCase() + name.slice(1),
49                 origName = name,
50                 i = cssPrefixes.length;
52         while ( i-- ) {
53                 name = cssPrefixes[ i ] + capName;
54                 if ( name in style ) {
55                         return name;
56                 }
57         }
59         return origName;
62 function setPositiveNumber( elem, value, subtract ) {
63         var matches = rnumsplit.exec( value );
64         return matches ?
65                 // Guard against undefined "subtract", e.g., when used as in cssHooks
66                 Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
67                 value;
70 function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
71         var i = extra === ( isBorderBox ? "border" : "content" ) ?
72                 // If we already have the right measurement, avoid augmentation
73                 4 :
74                 // Otherwise initialize for horizontal or vertical properties
75                 name === "width" ? 1 : 0,
77                 val = 0;
79         for ( ; i < 4; i += 2 ) {
80                 // Both box models exclude margin, so add it if we want it
81                 if ( extra === "margin" ) {
82                         val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
83                 }
85                 if ( isBorderBox ) {
86                         // border-box includes padding, so remove it if we want content
87                         if ( extra === "content" ) {
88                                 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
89                         }
91                         // At this point, extra isn't border nor margin, so remove border
92                         if ( extra !== "margin" ) {
93                                 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
94                         }
95                 } else {
96                         // At this point, extra isn't content, so add padding
97                         val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
99                         // At this point, extra isn't content nor padding, so add border
100                         if ( extra !== "padding" ) {
101                                 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
102                         }
103                 }
104         }
106         return val;
109 function getWidthOrHeight( elem, name, extra ) {
111         // Start with offset property, which is equivalent to the border-box value
112         var valueIsBorderBox = true,
113                 val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
114                 styles = getStyles( elem ),
115                 isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
117         // Some non-html elements return undefined for offsetWidth, so check for null/undefined
118         // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
119         // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
120         if ( val <= 0 || val == null ) {
121                 // Fall back to computed then uncomputed css if necessary
122                 val = curCSS( elem, name, styles );
123                 if ( val < 0 || val == null ) {
124                         val = elem.style[ name ];
125                 }
127                 // Computed unit is not pixels. Stop here and return.
128                 if ( rnumnonpx.test(val) ) {
129                         return val;
130                 }
132                 // Check for style in case a browser which returns unreliable values
133                 // for getComputedStyle silently falls back to the reliable elem.style
134                 valueIsBorderBox = isBorderBox &&
135                         ( support.boxSizingReliable() || val === elem.style[ name ] );
137                 // Normalize "", auto, and prepare for extra
138                 val = parseFloat( val ) || 0;
139         }
141         // Use the active box-sizing model to add/subtract irrelevant styles
142         return ( val +
143                 augmentWidthOrHeight(
144                         elem,
145                         name,
146                         extra || ( isBorderBox ? "border" : "content" ),
147                         valueIsBorderBox,
148                         styles
149                 )
150         ) + "px";
153 function showHide( elements, show ) {
154         var display, elem, hidden,
155                 values = [],
156                 index = 0,
157                 length = elements.length;
159         for ( ; index < length; index++ ) {
160                 elem = elements[ index ];
161                 if ( !elem.style ) {
162                         continue;
163                 }
165                 values[ index ] = dataPriv.get( elem, "olddisplay" );
166                 display = elem.style.display;
167                 if ( show ) {
168                         // Reset the inline display of this element to learn if it is
169                         // being hidden by cascaded rules or not
170                         if ( !values[ index ] && display === "none" ) {
171                                 elem.style.display = "";
172                         }
174                         // Set elements which have been overridden with display: none
175                         // in a stylesheet to whatever the default browser style is
176                         // for such an element
177                         if ( elem.style.display === "" && isHidden( elem ) ) {
178                                 values[ index ] = dataPriv.access(
179                                         elem,
180                                         "olddisplay",
181                                         defaultDisplay(elem.nodeName)
182                                 );
183                         }
184                 } else {
185                         hidden = isHidden( elem );
187                         if ( display !== "none" || !hidden ) {
188                                 dataPriv.set(
189                                         elem,
190                                         "olddisplay",
191                                         hidden ? display : jQuery.css( elem, "display" )
192                                 );
193                         }
194                 }
195         }
197         // Set the display of most of the elements in a second loop
198         // to avoid the constant reflow
199         for ( index = 0; index < length; index++ ) {
200                 elem = elements[ index ];
201                 if ( !elem.style ) {
202                         continue;
203                 }
204                 if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
205                         elem.style.display = show ? values[ index ] || "" : "none";
206                 }
207         }
209         return elements;
212 jQuery.extend({
214         // Add in style property hooks for overriding the default
215         // behavior of getting and setting a style property
216         cssHooks: {
217                 opacity: {
218                         get: function( elem, computed ) {
219                                 if ( computed ) {
221                                         // We should always get a number back from opacity
222                                         var ret = curCSS( elem, "opacity" );
223                                         return ret === "" ? "1" : ret;
224                                 }
225                         }
226                 }
227         },
229         // Don't automatically add "px" to these possibly-unitless properties
230         cssNumber: {
231                 "columnCount": true,
232                 "fillOpacity": true,
233                 "flexGrow": true,
234                 "flexShrink": true,
235                 "fontWeight": true,
236                 "lineHeight": true,
237                 "opacity": true,
238                 "order": true,
239                 "orphans": true,
240                 "widows": true,
241                 "zIndex": true,
242                 "zoom": true
243         },
245         // Add in properties whose names you wish to fix before
246         // setting or getting the value
247         cssProps: {
248                 "float": "cssFloat"
249         },
251         // Get and set the style property on a DOM Node
252         style: function( elem, name, value, extra ) {
254                 // Don't set styles on text and comment nodes
255                 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
256                         return;
257                 }
259                 // Make sure that we're working with the right name
260                 var ret, type, hooks,
261                         origName = jQuery.camelCase( name ),
262                         style = elem.style;
264                 name = jQuery.cssProps[ origName ] ||
265                         ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
267                 // Gets hook for the prefixed version, then unprefixed version
268                 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
270                 // Check if we're setting a value
271                 if ( value !== undefined ) {
272                         type = typeof value;
274                         // Convert "+=" or "-=" to relative numbers (#7345)
275                         if ( type === "string" && (ret = rrelNum.exec( value )) ) {
276                                 value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
277                                 // Fixes bug #9237
278                                 type = "number";
279                         }
281                         // Make sure that null and NaN values aren't set (#7116)
282                         if ( value == null || value !== value ) {
283                                 return;
284                         }
286                         // If a number was passed in, add 'px' (except for certain CSS properties)
287                         if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
288                                 value += "px";
289                         }
291                         // Support: IE9-11+
292                         // background-* props affect original clone's values
293                         if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
294                                 style[ name ] = "inherit";
295                         }
297                         // If a hook was provided, use that value, otherwise just set the specified value
298                         if ( !hooks || !("set" in hooks) ||
299                                 (value = hooks.set( elem, value, extra )) !== undefined ) {
301                                 style[ name ] = value;
302                         }
304                 } else {
305                         // If a hook was provided get the non-computed value from there
306                         if ( hooks && "get" in hooks &&
307                                 (ret = hooks.get( elem, false, extra )) !== undefined ) {
309                                 return ret;
310                         }
312                         // Otherwise just get the value from the style object
313                         return style[ name ];
314                 }
315         },
317         css: function( elem, name, extra, styles ) {
318                 var val, num, hooks,
319                         origName = jQuery.camelCase( name );
321                 // Make sure that we're working with the right name
322                 name = jQuery.cssProps[ origName ] ||
323                         ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
325                 // Try prefixed name followed by the unprefixed name
326                 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
328                 // If a hook was provided get the computed value from there
329                 if ( hooks && "get" in hooks ) {
330                         val = hooks.get( elem, true, extra );
331                 }
333                 // Otherwise, if a way to get the computed value exists, use that
334                 if ( val === undefined ) {
335                         val = curCSS( elem, name, styles );
336                 }
338                 // Convert "normal" to computed value
339                 if ( val === "normal" && name in cssNormalTransform ) {
340                         val = cssNormalTransform[ name ];
341                 }
343                 // Make numeric if forced or a qualifier was provided and val looks numeric
344                 if ( extra === "" || extra ) {
345                         num = parseFloat( val );
346                         return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
347                 }
348                 return val;
349         }
352 jQuery.each([ "height", "width" ], function( i, name ) {
353         jQuery.cssHooks[ name ] = {
354                 get: function( elem, computed, extra ) {
355                         if ( computed ) {
357                                 // Certain elements can have dimension info if we invisibly show them
358                                 // but it must have a current display style that would benefit
359                                 return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
360                                         elem.offsetWidth === 0 ?
361                                                 jQuery.swap( elem, cssShow, function() {
362                                                         return getWidthOrHeight( elem, name, extra );
363                                                 }) :
364                                                 getWidthOrHeight( elem, name, extra );
365                         }
366                 },
368                 set: function( elem, value, extra ) {
369                         var styles = extra && getStyles( elem );
370                         return setPositiveNumber( elem, value, extra ?
371                                 augmentWidthOrHeight(
372                                         elem,
373                                         name,
374                                         extra,
375                                         jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
376                                         styles
377                                 ) : 0
378                         );
379                 }
380         };
383 // Support: Android 2.3
384 jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
385         function( elem, computed ) {
386                 if ( computed ) {
387                         return jQuery.swap( elem, { "display": "inline-block" },
388                                 curCSS, [ elem, "marginRight" ] );
389                 }
390         }
393 // These hooks are used by animate to expand properties
394 jQuery.each({
395         margin: "",
396         padding: "",
397         border: "Width"
398 }, function( prefix, suffix ) {
399         jQuery.cssHooks[ prefix + suffix ] = {
400                 expand: function( value ) {
401                         var i = 0,
402                                 expanded = {},
404                                 // Assumes a single number if not a string
405                                 parts = typeof value === "string" ? value.split(" ") : [ value ];
407                         for ( ; i < 4; i++ ) {
408                                 expanded[ prefix + cssExpand[ i ] + suffix ] =
409                                         parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
410                         }
412                         return expanded;
413                 }
414         };
416         if ( !rmargin.test( prefix ) ) {
417                 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
418         }
421 jQuery.fn.extend({
422         css: function( name, value ) {
423                 return access( this, function( elem, name, value ) {
424                         var styles, len,
425                                 map = {},
426                                 i = 0;
428                         if ( jQuery.isArray( name ) ) {
429                                 styles = getStyles( elem );
430                                 len = name.length;
432                                 for ( ; i < len; i++ ) {
433                                         map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
434                                 }
436                                 return map;
437                         }
439                         return value !== undefined ?
440                                 jQuery.style( elem, name, value ) :
441                                 jQuery.css( elem, name );
442                 }, name, value, arguments.length > 1 );
443         },
444         show: function() {
445                 return showHide( this, true );
446         },
447         hide: function() {
448                 return showHide( this );
449         },
450         toggle: function( state ) {
451                 if ( typeof state === "boolean" ) {
452                         return state ? this.show() : this.hide();
453                 }
455                 return this.each(function() {
456                         if ( isHidden( this ) ) {
457                                 jQuery( this ).show();
458                         } else {
459                                 jQuery( this ).hide();
460                         }
461                 });
462         }
465 return jQuery;