aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/css.js17
-rw-r--r--src/css/adjustCSS.js61
-rw-r--r--src/effects.js56
-rw-r--r--src/var/rcssNum.js7
-rw-r--r--test/unit/css.js52
5 files changed, 135 insertions, 58 deletions
diff --git a/src/css.js b/src/css.js
index d8e60b857..497b0ec53 100644
--- a/src/css.js
+++ b/src/css.js
@@ -3,11 +3,13 @@ define([
"./var/pnum",
"./core/access",
"./css/var/rmargin",
+ "./var/rcssNum",
"./css/var/rnumnonpx",
"./css/var/cssExpand",
"./css/var/isHidden",
"./css/var/getStyles",
"./css/curCSS",
+ "./css/adjustCSS",
"./css/defaultDisplay",
"./css/addGetHookIf",
"./css/support",
@@ -17,8 +19,8 @@ define([
"./css/swap",
"./core/ready",
"./selector" // contains
-], function( jQuery, pnum, access, rmargin, rnumnonpx, cssExpand, isHidden,
- getStyles, curCSS, defaultDisplay, addGetHookIf, support, dataPriv ) {
+], function( jQuery, pnum, access, rmargin, rcssNum, rnumnonpx, cssExpand, isHidden,
+ getStyles, curCSS, adjustCSS, defaultDisplay, addGetHookIf, support, dataPriv ) {
var
// Swappable if display is none or starts with table
@@ -26,7 +28,6 @@ var
// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
- rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssNormalTransform = {
@@ -272,8 +273,8 @@ jQuery.extend({
type = typeof value;
// Convert "+=" or "-=" to relative numbers (#7345)
- if ( type === "string" && (ret = rrelNum.exec( value )) ) {
- value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ if ( type === "string" && (ret = rcssNum.exec( value )) && ret[ 1 ] ) {
+ value = adjustCSS( elem, name, ret );
// Fixes bug #9237
type = "number";
}
@@ -283,9 +284,9 @@ jQuery.extend({
return;
}
- // If a number was passed in, add 'px' (except for certain CSS properties)
- if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
- value += "px";
+ // If a number was passed in, add the unit (except for certain CSS properties)
+ if ( type === "number" ) {
+ value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
}
// Support: IE9-11+
diff --git a/src/css/adjustCSS.js b/src/css/adjustCSS.js
new file mode 100644
index 000000000..05fddd15b
--- /dev/null
+++ b/src/css/adjustCSS.js
@@ -0,0 +1,61 @@
+define([
+ "../core",
+ "../var/rcssNum"
+], function( jQuery, rcssNum ) {
+
+function adjustCSS( elem, prop, valueParts, tween ) {
+ var adjusted,
+ scale = 1,
+ maxIterations = 20,
+ currentValue = tween ?
+ function() { return tween.cur(); } :
+ function() { return jQuery.css( elem, prop, "" ); },
+ initial = currentValue(),
+ unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+ // Starting value computation is required for potential unit mismatches
+ initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
+ rcssNum.exec( jQuery.css( elem, prop ) );
+
+ if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
+ // Trust units reported by jQuery.css
+ unit = unit || initialInUnit[ 3 ];
+
+ // Make sure we update the tween properties later on
+ valueParts = valueParts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ initialInUnit = +initial || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*.
+ // Use string for doubling so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ initialInUnit = initialInUnit / scale;
+ jQuery.style( elem, prop, initialInUnit + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // Break the loop if scale is unchanged or perfect, or if we've just had enough.
+ } while (
+ scale !== (scale = currentValue() / initial) && scale !== 1 && --maxIterations
+ );
+ }
+
+ if ( valueParts ) {
+ initialInUnit = +initialInUnit || +initial || 0;
+ // Apply relative offset (+=/-=) if specified
+ adjusted = valueParts[ 1 ] ?
+ initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
+ +valueParts[ 2 ];
+ if ( tween ) {
+ tween.unit = unit;
+ tween.start = initialInUnit;
+ tween.end = adjusted;
+ }
+ }
+ return adjusted;
+}
+
+return adjustCSS;
+});
diff --git a/src/effects.js b/src/effects.js
index 3aa408b51..e19b04b06 100644
--- a/src/effects.js
+++ b/src/effects.js
@@ -1,9 +1,10 @@
define([
"./core",
"./var/document",
- "./var/pnum",
+ "./var/rcssNum",
"./css/var/cssExpand",
"./css/var/isHidden",
+ "./css/adjustCSS",
"./css/defaultDisplay",
"./data/var/dataPriv",
@@ -13,63 +14,18 @@ define([
"./css",
"./deferred",
"./traversing"
-], function( jQuery, document, pnum, cssExpand, isHidden, defaultDisplay, dataPriv ) {
+], function( jQuery, document, rcssNum, cssExpand,
+ isHidden, adjustCSS, defaultDisplay, dataPriv ) {
var
fxNow, timerId,
rfxtypes = /^(?:toggle|show|hide)$/,
- rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
rrun = /queueHooks$/,
animationPrefilters = [ defaultPrefilter ],
tweeners = {
"*": [ function( prop, value ) {
- var tween = this.createTween( prop, value ),
- target = tween.cur(),
- parts = rfxnum.exec( value ),
- unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
-
- // Starting value computation is required for potential unit mismatches
- start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
- rfxnum.exec( jQuery.css( tween.elem, prop ) ),
- scale = 1,
- maxIterations = 20;
-
- if ( start && start[ 3 ] !== unit ) {
- // Trust units reported by jQuery.css
- unit = unit || start[ 3 ];
-
- // Make sure we update the tween properties later on
- parts = parts || [];
-
- // Iteratively approximate from a nonzero starting point
- start = +target || 1;
-
- do {
- // If previous iteration zeroed out, double until we get *something*.
- // Use string for doubling so we don't accidentally see scale as unchanged below
- scale = scale || ".5";
-
- // Adjust and apply
- start = start / scale;
- jQuery.style( tween.elem, prop, start + unit );
-
- // Update scale, tolerating zero or NaN from tween.cur(),
- // break the loop if scale is unchanged or perfect, or if we've just had enough
- } while (
- scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations
- );
- }
-
- // Update tween properties
- if ( parts ) {
- start = tween.start = +start || +target || 0;
- tween.unit = unit;
- // If a +=/-= token was provided, we're doing a relative animation
- tween.end = parts[ 1 ] ?
- start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
- +parts[ 2 ];
- }
-
+ var tween = this.createTween( prop, value );
+ adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
return tween;
} ]
};
diff --git a/src/var/rcssNum.js b/src/var/rcssNum.js
new file mode 100644
index 000000000..2fc3938a5
--- /dev/null
+++ b/src/var/rcssNum.js
@@ -0,0 +1,7 @@
+define([
+ "../var/pnum"
+], function( pnum ) {
+
+return new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
+
+});
diff --git a/test/unit/css.js b/test/unit/css.js
index c03579103..d6b14eea2 100644
--- a/test/unit/css.js
+++ b/test/unit/css.js
@@ -203,6 +203,58 @@ test( "css() explicit and relative values", 29, function() {
equal( $elem.css("opacity"), "1", "'+=0.5' on opacity (params)" );
});
+test( "css() non-px relative values (gh-1711)", 17, function() {
+ var cssCurrent,
+ units = {},
+ $child = jQuery( "#nothiddendivchild" ),
+ add = function( prop, val, unit ) {
+ var str = ( val < 0 ? "-=" : "+=" ) + Math.abs( val ) + unit;
+ $child.css( prop, str );
+ equal(
+ Math.round( parseFloat( $child.css( prop ) ) ),
+ Math.round( cssCurrent += val * units[ prop ][ unit ] ),
+ prop + ": '" + str + "'"
+ );
+ },
+ getUnits = function( prop ) {
+ units[ prop ] = {
+ "px": 1,
+ "em": parseFloat( $child.css( prop, "100em" ).css( prop ) ) / 100,
+ "pt": parseFloat( $child.css( prop, "100pt" ).css( prop ) ) / 100,
+ "pc": parseFloat( $child.css( prop, "100pc" ).css( prop ) ) / 100,
+ "cm": parseFloat( $child.css( prop, "100cm" ).css( prop ) ) / 100,
+ "mm": parseFloat( $child.css( prop, "100mm" ).css( prop ) ) / 100,
+ "%" : parseFloat( $child.css( prop, "100%" ).css( prop ) ) / 100
+ };
+ };
+
+ jQuery( "#nothiddendiv" ).css({ height: 1, padding: 0, width: 400 });
+ $child.css({ height: 1, padding: 0 });
+
+ getUnits( "width" );
+ cssCurrent = parseFloat( $child.css( "width", "50%" ).css( "width" ) );
+ add( "width", 25, "%" );
+ add( "width", -50, "%" );
+ add( "width", 10, "em" );
+ add( "width", 10, "pt" );
+ add( "width", -2.3, "pt" );
+ add( "width", 5, "pc" );
+ add( "width", -5, "em" );
+ add( "width", +2, "cm" );
+ add( "width", -15, "mm" );
+ add( "width", 21, "px" );
+
+ getUnits( "lineHeight" );
+ cssCurrent = parseFloat( $child.css( "lineHeight", "1em" ).css( "lineHeight" ) );
+ add( "lineHeight", 2, "em" );
+ add( "lineHeight", -10, "px" );
+ add( "lineHeight", 20, "pt" );
+ add( "lineHeight", 30, "pc" );
+ add( "lineHeight", 1, "cm" );
+ add( "lineHeight", -20, "mm" );
+ add( "lineHeight", 50, "%" );
+});
+
test("css(String, Object)", function() {
expect( 19 );
var j, div, display, ret, success;