UNPKG

14.2 kBJavaScriptView Raw
1define( [
2 "./core",
3 "./core/access",
4 "./core/camelCase",
5 "./core/nodeName",
6 "./var/rcssNum",
7 "./css/var/rnumnonpx",
8 "./css/var/rcustomProp",
9 "./css/var/cssExpand",
10 "./css/var/getStyles",
11 "./css/var/swap",
12 "./css/curCSS",
13 "./css/adjustCSS",
14 "./css/addGetHookIf",
15 "./css/support",
16 "./css/finalPropName",
17
18 "./core/init",
19 "./core/ready",
20 "./selector" // contains
21], function( jQuery, access, camelCase, nodeName, rcssNum, rnumnonpx,
22 rcustomProp, cssExpand, getStyles, swap, curCSS, adjustCSS, addGetHookIf,
23 support, finalPropName ) {
24
25"use strict";
26
27var
28
29 // Swappable if display is none or starts with table
30 // except "table", "table-cell", or "table-caption"
31 // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
32 rdisplayswap = /^(none|table(?!-c[ea]).+)/,
33 cssShow = { position: "absolute", visibility: "hidden", display: "block" },
34 cssNormalTransform = {
35 letterSpacing: "0",
36 fontWeight: "400"
37 };
38
39function setPositiveNumber( _elem, value, subtract ) {
40
41 // Any relative (+/-) values have already been
42 // normalized at this point
43 var matches = rcssNum.exec( value );
44 return matches ?
45
46 // Guard against undefined "subtract", e.g., when used as in cssHooks
47 Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
48 value;
49}
50
51function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
52 var i = dimension === "width" ? 1 : 0,
53 extra = 0,
54 delta = 0;
55
56 // Adjustment may not be necessary
57 if ( box === ( isBorderBox ? "border" : "content" ) ) {
58 return 0;
59 }
60
61 for ( ; i < 4; i += 2 ) {
62
63 // Both box models exclude margin
64 if ( box === "margin" ) {
65 delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
66 }
67
68 // If we get here with a content-box, we're seeking "padding" or "border" or "margin"
69 if ( !isBorderBox ) {
70
71 // Add padding
72 delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
73
74 // For "border" or "margin", add border
75 if ( box !== "padding" ) {
76 delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
77
78 // But still keep track of it otherwise
79 } else {
80 extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
81 }
82
83 // If we get here with a border-box (content + padding + border), we're seeking "content" or
84 // "padding" or "margin"
85 } else {
86
87 // For "content", subtract padding
88 if ( box === "content" ) {
89 delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
90 }
91
92 // For "content" or "padding", subtract border
93 if ( box !== "margin" ) {
94 delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
95 }
96 }
97 }
98
99 // Account for positive content-box scroll gutter when requested by providing computedVal
100 if ( !isBorderBox && computedVal >= 0 ) {
101
102 // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
103 // Assuming integer scroll gutter, subtract the rest and round down
104 delta += Math.max( 0, Math.ceil(
105 elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
106 computedVal -
107 delta -
108 extra -
109 0.5
110
111 // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
112 // Use an explicit zero to avoid NaN (gh-3964)
113 ) ) || 0;
114 }
115
116 return delta;
117}
118
119function getWidthOrHeight( elem, dimension, extra ) {
120
121 // Start with computed style
122 var styles = getStyles( elem ),
123
124 // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).
125 // Fake content-box until we know it's needed to know the true value.
126 boxSizingNeeded = !support.boxSizingReliable() || extra,
127 isBorderBox = boxSizingNeeded &&
128 jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
129 valueIsBorderBox = isBorderBox,
130
131 val = curCSS( elem, dimension, styles ),
132 offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );
133
134 // Support: Firefox <=54
135 // Return a confounding non-pixel value or feign ignorance, as appropriate.
136 if ( rnumnonpx.test( val ) ) {
137 if ( !extra ) {
138 return val;
139 }
140 val = "auto";
141 }
142
143
144 // Support: IE 9 - 11 only
145 // Use offsetWidth/offsetHeight for when box sizing is unreliable.
146 // In those cases, the computed value can be trusted to be border-box.
147 if ( ( !support.boxSizingReliable() && isBorderBox ||
148
149 // Support: IE 10 - 11+, Edge 15 - 18+
150 // IE/Edge misreport `getComputedStyle` of table rows with width/height
151 // set in CSS while `offset*` properties report correct values.
152 // Interestingly, in some cases IE 9 doesn't suffer from this issue.
153 !support.reliableTrDimensions() && nodeName( elem, "tr" ) ||
154
155 // Fall back to offsetWidth/offsetHeight when value is "auto"
156 // This happens for inline elements with no explicit setting (gh-3571)
157 val === "auto" ||
158
159 // Support: Android <=4.1 - 4.3 only
160 // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
161 !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&
162
163 // Make sure the element is visible & connected
164 elem.getClientRects().length ) {
165
166 isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
167
168 // Where available, offsetWidth/offsetHeight approximate border box dimensions.
169 // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the
170 // retrieved value as a content box dimension.
171 valueIsBorderBox = offsetProp in elem;
172 if ( valueIsBorderBox ) {
173 val = elem[ offsetProp ];
174 }
175 }
176
177 // Normalize "" and auto
178 val = parseFloat( val ) || 0;
179
180 // Adjust for the element's box model
181 return ( val +
182 boxModelAdjustment(
183 elem,
184 dimension,
185 extra || ( isBorderBox ? "border" : "content" ),
186 valueIsBorderBox,
187 styles,
188
189 // Provide the current computed size to request scroll gutter calculation (gh-3589)
190 val
191 )
192 ) + "px";
193}
194
195jQuery.extend( {
196
197 // Add in style property hooks for overriding the default
198 // behavior of getting and setting a style property
199 cssHooks: {
200 opacity: {
201 get: function( elem, computed ) {
202 if ( computed ) {
203
204 // We should always get a number back from opacity
205 var ret = curCSS( elem, "opacity" );
206 return ret === "" ? "1" : ret;
207 }
208 }
209 }
210 },
211
212 // Don't automatically add "px" to these possibly-unitless properties
213 cssNumber: {
214 "animationIterationCount": true,
215 "columnCount": true,
216 "fillOpacity": true,
217 "flexGrow": true,
218 "flexShrink": true,
219 "fontWeight": true,
220 "gridArea": true,
221 "gridColumn": true,
222 "gridColumnEnd": true,
223 "gridColumnStart": true,
224 "gridRow": true,
225 "gridRowEnd": true,
226 "gridRowStart": true,
227 "lineHeight": true,
228 "opacity": true,
229 "order": true,
230 "orphans": true,
231 "widows": true,
232 "zIndex": true,
233 "zoom": true
234 },
235
236 // Add in properties whose names you wish to fix before
237 // setting or getting the value
238 cssProps: {},
239
240 // Get and set the style property on a DOM Node
241 style: function( elem, name, value, extra ) {
242
243 // Don't set styles on text and comment nodes
244 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
245 return;
246 }
247
248 // Make sure that we're working with the right name
249 var ret, type, hooks,
250 origName = camelCase( name ),
251 isCustomProp = rcustomProp.test( name ),
252 style = elem.style;
253
254 // Make sure that we're working with the right name. We don't
255 // want to query the value if it is a CSS custom property
256 // since they are user-defined.
257 if ( !isCustomProp ) {
258 name = finalPropName( origName );
259 }
260
261 // Gets hook for the prefixed version, then unprefixed version
262 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
263
264 // Check if we're setting a value
265 if ( value !== undefined ) {
266 type = typeof value;
267
268 // Convert "+=" or "-=" to relative numbers (trac-7345)
269 if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
270 value = adjustCSS( elem, name, ret );
271
272 // Fixes bug trac-9237
273 type = "number";
274 }
275
276 // Make sure that null and NaN values aren't set (trac-7116)
277 if ( value == null || value !== value ) {
278 return;
279 }
280
281 // If a number was passed in, add the unit (except for certain CSS properties)
282 // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append
283 // "px" to a few hardcoded values.
284 if ( type === "number" && !isCustomProp ) {
285 value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
286 }
287
288 // background-* props affect original clone's values
289 if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
290 style[ name ] = "inherit";
291 }
292
293 // If a hook was provided, use that value, otherwise just set the specified value
294 if ( !hooks || !( "set" in hooks ) ||
295 ( value = hooks.set( elem, value, extra ) ) !== undefined ) {
296
297 if ( isCustomProp ) {
298 style.setProperty( name, value );
299 } else {
300 style[ name ] = value;
301 }
302 }
303
304 } else {
305
306 // If a hook was provided get the non-computed value from there
307 if ( hooks && "get" in hooks &&
308 ( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
309
310 return ret;
311 }
312
313 // Otherwise just get the value from the style object
314 return style[ name ];
315 }
316 },
317
318 css: function( elem, name, extra, styles ) {
319 var val, num, hooks,
320 origName = camelCase( name ),
321 isCustomProp = rcustomProp.test( name );
322
323 // Make sure that we're working with the right name. We don't
324 // want to modify the value if it is a CSS custom property
325 // since they are user-defined.
326 if ( !isCustomProp ) {
327 name = finalPropName( origName );
328 }
329
330 // Try prefixed name followed by the unprefixed name
331 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
332
333 // If a hook was provided get the computed value from there
334 if ( hooks && "get" in hooks ) {
335 val = hooks.get( elem, true, extra );
336 }
337
338 // Otherwise, if a way to get the computed value exists, use that
339 if ( val === undefined ) {
340 val = curCSS( elem, name, styles );
341 }
342
343 // Convert "normal" to computed value
344 if ( val === "normal" && name in cssNormalTransform ) {
345 val = cssNormalTransform[ name ];
346 }
347
348 // Make numeric if forced or a qualifier was provided and val looks numeric
349 if ( extra === "" || extra ) {
350 num = parseFloat( val );
351 return extra === true || isFinite( num ) ? num || 0 : val;
352 }
353
354 return val;
355 }
356} );
357
358jQuery.each( [ "height", "width" ], function( _i, dimension ) {
359 jQuery.cssHooks[ dimension ] = {
360 get: function( elem, computed, extra ) {
361 if ( computed ) {
362
363 // Certain elements can have dimension info if we invisibly show them
364 // but it must have a current display style that would benefit
365 return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
366
367 // Support: Safari 8+
368 // Table columns in Safari have non-zero offsetWidth & zero
369 // getBoundingClientRect().width unless display is changed.
370 // Support: IE <=11 only
371 // Running getBoundingClientRect on a disconnected node
372 // in IE throws an error.
373 ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
374 swap( elem, cssShow, function() {
375 return getWidthOrHeight( elem, dimension, extra );
376 } ) :
377 getWidthOrHeight( elem, dimension, extra );
378 }
379 },
380
381 set: function( elem, value, extra ) {
382 var matches,
383 styles = getStyles( elem ),
384
385 // Only read styles.position if the test has a chance to fail
386 // to avoid forcing a reflow.
387 scrollboxSizeBuggy = !support.scrollboxSize() &&
388 styles.position === "absolute",
389
390 // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)
391 boxSizingNeeded = scrollboxSizeBuggy || extra,
392 isBorderBox = boxSizingNeeded &&
393 jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
394 subtract = extra ?
395 boxModelAdjustment(
396 elem,
397 dimension,
398 extra,
399 isBorderBox,
400 styles
401 ) :
402 0;
403
404 // Account for unreliable border-box dimensions by comparing offset* to computed and
405 // faking a content-box to get border and padding (gh-3699)
406 if ( isBorderBox && scrollboxSizeBuggy ) {
407 subtract -= Math.ceil(
408 elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
409 parseFloat( styles[ dimension ] ) -
410 boxModelAdjustment( elem, dimension, "border", false, styles ) -
411 0.5
412 );
413 }
414
415 // Convert to pixels if value adjustment is needed
416 if ( subtract && ( matches = rcssNum.exec( value ) ) &&
417 ( matches[ 3 ] || "px" ) !== "px" ) {
418
419 elem.style[ dimension ] = value;
420 value = jQuery.css( elem, dimension );
421 }
422
423 return setPositiveNumber( elem, value, subtract );
424 }
425 };
426} );
427
428jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
429 function( elem, computed ) {
430 if ( computed ) {
431 return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
432 elem.getBoundingClientRect().left -
433 swap( elem, { marginLeft: 0 }, function() {
434 return elem.getBoundingClientRect().left;
435 } )
436 ) + "px";
437 }
438 }
439);
440
441// These hooks are used by animate to expand properties
442jQuery.each( {
443 margin: "",
444 padding: "",
445 border: "Width"
446}, function( prefix, suffix ) {
447 jQuery.cssHooks[ prefix + suffix ] = {
448 expand: function( value ) {
449 var i = 0,
450 expanded = {},
451
452 // Assumes a single number if not a string
453 parts = typeof value === "string" ? value.split( " " ) : [ value ];
454
455 for ( ; i < 4; i++ ) {
456 expanded[ prefix + cssExpand[ i ] + suffix ] =
457 parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
458 }
459
460 return expanded;
461 }
462 };
463
464 if ( prefix !== "margin" ) {
465 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
466 }
467} );
468
469jQuery.fn.extend( {
470 css: function( name, value ) {
471 return access( this, function( elem, name, value ) {
472 var styles, len,
473 map = {},
474 i = 0;
475
476 if ( Array.isArray( name ) ) {
477 styles = getStyles( elem );
478 len = name.length;
479
480 for ( ; i < len; i++ ) {
481 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
482 }
483
484 return map;
485 }
486
487 return value !== undefined ?
488 jQuery.style( elem, name, value ) :
489 jQuery.css( elem, name );
490 }, name, value, arguments.length > 1 );
491 }
492} );
493
494return jQuery;
495} );