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