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