diff --git a/src/effects.js b/src/effects.js index f1bbed763..0716248f1 100644 --- a/src/effects.js +++ b/src/effects.js @@ -1,6 +1,6 @@ var fxNow, timerId, rfxtypes = /^(?:toggle|show|hide)$/, - rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i, + rfxnum = /^(?:([\-+])=)?([\d+.\-]+)([a-z%]*)$/i, rrun = /queueHooks$/, animationPrefilters = [ defaultPrefilter ], tweeners = { @@ -8,9 +8,9 @@ var fxNow, timerId, var end, unit, prevScale, tween = this.createTween( prop, value ), parts = rfxnum.exec( value ), - start = tween.cur(), - scale = 1, - target = start; + target = tween.cur(), + start = +target || 0, + scale = 1; if ( parts ) { end = +parts[2]; @@ -21,7 +21,7 @@ var fxNow, timerId, // Iteratively approximate from a nonzero starting point // Prefer the current property, because this process will be trivial if it uses the same units // Fallback to end or a simple constant - start = parseFloat( jQuery.css( tween.elem, prop ) ) || end || 1; + start = jQuery.css( tween.elem, prop, true ) || end || 1; do { // If previous iteration zeroed out, double until we get *something* @@ -35,14 +35,14 @@ var fxNow, timerId, // Update scale, tolerating zeroes from tween.cur() scale = tween.cur() / target; - // Stop looping if scale is unchanged or we've hit the mark + // Stop looping if we've hit the mark or scale is unchanged } while ( scale !== 1 && scale !== prevScale ); } tween.unit = unit; tween.start = start; // If a +=/-= token was provided, we're doing a relative animation - tween.end = parts[1] ? start + end * ( parts[1] === "-=" ? -1 : 1 ) : end; + tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; } return tween; }] diff --git a/test/data/testsuite.css b/test/data/testsuite.css index d3e4b4e40..0046c2fe2 100644 --- a/test/data/testsuite.css +++ b/test/data/testsuite.css @@ -125,4 +125,7 @@ body, div { background: url(http://static.jquery.com/files/rocker/images/logo_jq #t6652 div { filter: alpha(opacity=50); } /* #10501 */ -section { background:#f0f; display:block; } \ No newline at end of file +section { background:#f0f; display:block; } + +/* #11971 */ +#foo { background: url(data/1x1.jpg) right bottom no-repeat; } diff --git a/test/unit/effects.js b/test/unit/effects.js index 57fa8c966..402a7a587 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -1677,13 +1677,40 @@ asyncTest( "animate does not change start value for non-px animation (#7109)", 1 }); }); -asyncTest("Animation callbacks (#11797)", 12, function() { +asyncTest( "non-px animation handles non-numeric start (#11971)", 2, function() { + var foo = jQuery("#foo"), + initial = foo.css("backgroundPositionX"); + + foo.animate({ backgroundPositionX: "42%" }, { + duration: 1, + progress: function( anim, percent ) { + if ( percent ) { + return; + } + + if ( parseFloat( initial ) ) { + equal( jQuery.style( this, "backgroundPositionX" ), initial, "Numeric start preserved" ); + } else { + equal( jQuery.style( this, "backgroundPositionX" ), "0%", "Non-numeric start zeroed" ); + } + }, + done: function() { + equal( jQuery.style( this, "backgroundPositionX" ), "42%", "End reached" ); + start(); + } + }); +}); + +asyncTest("Animation callbacks (#11797)", 15, function() { var targets = jQuery("#foo").children(), done = false, expectedProgress = 0; targets.eq( 0 ).animate( {}, { duration: 1, + start: function() { + ok( true, "empty: start" ); + }, progress: function( anim, percent ) { equal( percent, 0, "empty: progress 0" ); }, @@ -1699,13 +1726,16 @@ asyncTest("Animation callbacks (#11797)", 12, function() { } }); - ok( done, "animation done" ); + ok( done, "empty: done immediately" ); done = false; targets.eq( 1 ).animate({ opacity: 0 }, { duration: 1, + start: function() { + ok( true, "stopped: start" ); + }, progress: function( anim, percent ) { equal( percent, 0, "stopped: progress 0" ); }, @@ -1721,12 +1751,15 @@ asyncTest("Animation callbacks (#11797)", 12, function() { } }).stop(); - ok( done, "animation stopped" ); + ok( done, "stopped: stopped immediately" ); targets.eq( 2 ).animate({ opacity: 0 }, { duration: 1, + start: function() { + ok( true, "async: start" ); + }, progress: function( anim, percent ) { equal( percent, expectedProgress, "async: progress " + expectedProgress ); // once at 0, once at 1