diff --git a/src/fx.js b/src/fx.js index 9bfe99962..b35dbcd8d 100644 --- a/src/fx.js +++ b/src/fx.js @@ -146,14 +146,28 @@ jQuery.fn.extend({ }); }, - stop: function(){ + stop: function(clearQueue, gotoEnd){ var timers = jQuery.timers; - return this.each(function(){ - for ( var i = 0; i < timers.length; i++ ) - if ( timers[i].elem == this ) - timers.splice(i--, 1); - }).dequeue(); + if (clearQueue) + this.queue([]); + + this.each(function(){ + // go in reverse order so anything added to the queue during the loop is ignored + for ( var i = timers.length - 1; i >= 0; i-- ) + if ( timers[i].elem == this ) { + if (gotoEnd) + // force the next step to be the last + timers[i](true); + timers.splice(i, 1); + } + }); + + // start the next in the queue if the last step wasn't forced + if (!gotoEnd) + this.dequeue(); + + return this; } }); @@ -269,8 +283,8 @@ jQuery.fx.prototype = { this.update(); var self = this; - function t(){ - return self.step(); + function t(gotoEnd){ + return self.step(gotoEnd); } t.elem = this.elem; @@ -322,10 +336,10 @@ jQuery.fx.prototype = { }, // Each step of an animation - step: function(){ + step: function(gotoEnd){ var t = (new Date()).getTime(); - if ( t > this.options.duration + this.startTime ) { + if ( gotoEnd || t > this.options.duration + this.startTime ) { this.now = this.end; this.pos = this.state = 1; this.update(); diff --git a/test/data/testsuite.css b/test/data/testsuite.css index b9d487bc4..b15f5ef7f 100644 --- a/test/data/testsuite.css +++ b/test/data/testsuite.css @@ -11,6 +11,8 @@ p.result { margin-left: 1em; } h2.pass { background-color: green; } h2.fail { background-color: red; } +ol#tests > li > strong { cursor:pointer; } + div#fx-tests h4 { background: red; } diff --git a/test/unit/fx.js b/test/unit/fx.js index c20e39ceb..1204e261c 100644 --- a/test/unit/fx.js +++ b/test/unit/fx.js @@ -54,21 +54,101 @@ test("queue() defaults to 'fx' type", function () { test("stop()", function() { expect(3); stop(); - reset(); - var foo = $("#foo")[0]; - var h = foo.style.height; + var $foo = $("#nothiddendiv"); + var w = 0; + $foo.hide().width(200).width(); - $("#foo").slideUp(1000); + $foo.animate({ width:'show' }, 1000); setTimeout(function(){ - var nh = foo.style.height; - ok( nh != h, "An animation occurred " + nh + " " + h ); - $("#foo").stop(); + var nw = $foo.width(); + ok( nw != w, "An animation occurred " + nw + "px " + w + "px"); + $foo.stop(); - nh = foo.style.height; - ok( nh != h, "Stop didn't reset the animation " + nh + " " + h ); + nw = $foo.width(); + ok( nw != w, "Stop didn't reset the animation " + nw + "px " + w + "px"); setTimeout(function(){ - equals( nh, foo.style.height, "The animation didn't continue" ); + equals( nw, $foo.width(), "The animation didn't continue" ); + start(); + }, 100); + }, 100); +}); + +test("stop() - several in queue", function() { + expect(4); + stop(); + + var $foo = $("#nothiddendiv"); + var w = 0; + $foo.hide().width(200).width(); + + $foo.animate({ width:'show' }, 1000); + $foo.animate({ width:'hide' }, 1000); + $foo.animate({ width:'show' }, 1000); + setTimeout(function(){ + equals( $foo.queue().length, 3, "All 3 still in the queue" ); + var nw = $foo.width(); + ok( nw != w, "An animation occurred " + nw + "px " + w + "px"); + $foo.stop(); + + nw = $foo.width(); + ok( nw != w, "Stop didn't reset the animation " + nw + "px " + w + "px"); + equals( $foo.queue().length, 2, "The next animation continued" ); + $foo.stop(true); + start(); + }, 100); +}); + +test("stop(clearQueue)", function() { + expect(4); + stop(); + + var $foo = $("#nothiddendiv"); + var w = 0; + $foo.hide().width(200).width(); + + $foo.animate({ width:'show' }, 1000); + $foo.animate({ width:'hide' }, 1000); + $foo.animate({ width:'show' }, 1000); + setTimeout(function(){ + var nw = $foo.width(); + ok( nw != w, "An animation occurred " + nw + "px " + w + "px"); + $foo.stop(true); + + nw = $foo.width(); + ok( nw != w, "Stop didn't reset the animation " + nw + "px " + w + "px"); + + equals( $foo.queue().length, 0, "The animation queue was cleared" ); + setTimeout(function(){ + equals( nw, $foo.width(), "The animation didn't continue" ); + start(); + }, 100); + }, 100); +}); + +test("stop(clearQueue, gotoEnd)", function() { + expect(3); + stop(); + + var $foo = $("#nothiddendiv"); + var w = 0; + $foo.hide().width(200).width(); + + $foo.animate({ width:'show' }, 1000); + $foo.animate({ width:'hide' }, 1000); + $foo.animate({ width:'show' }, 1000); + $foo.animate({ width:'hide' }, 1000); + setTimeout(function(){ + var nw = $foo.width(); + ok( nw != w, "An animation occurred " + nw + "px " + w + "px"); + $foo.stop(false, true); + + nw = $foo.width(); + equals( nw, 200, "Stop() reset the animation" ); + + setTimeout(function(){ + equals( $foo.queue().length, 3, "The next animation continued" ); + $foo.stop(true); start(); }, 100); }, 100); @@ -77,11 +157,11 @@ test("stop()", function() { test("toggle()", function() { expect(3); var x = $("#foo"); - ok( x.is(":visible") ); + ok( x.is(":visible"), "is visible" ); x.toggle(); - ok( x.is(":hidden") ); + ok( x.is(":hidden"), "is hidden" ); x.toggle(); - ok( x.is(":visible") ); + ok( x.is(":visible"), "is visible again" ); }); var visible = {