Permalink
Browse files

Landing pull request 514. 1.7 - queue refactoring to handle delay sto…

…p - Fixes #6150.

More Details:
 - #514
 - http://bugs.jquery.com/ticket/6150
  • Loading branch information...
1 parent a74cbb2 commit a3b59d7f92c9e15af1888fc4e87639a290763a50 @gnarf gnarf committed with timmywil Sep 28, 2011
Showing with 150 additions and 30 deletions.
  1. +47 −19 src/effects.js
  2. +12 −10 src/queue.js
  3. +53 −1 test/unit/effects.js
  4. +38 −0 test/unit/queue.js
View
@@ -200,6 +200,7 @@ jQuery.fn.extend({
val = prop[ p ];
if ( rfxtypes.test( val ) ) {
+
// Tracks whether to show or hide based on private
// data attached to the element
method = jQuery._data( this, "toggle" + p ) || (val === "toggle" ? hidden ? "show" : "hide" : 0);
@@ -244,42 +245,62 @@ jQuery.fn.extend({
return optall.queue === false ?
this.each( doAnimation ) :
- this.queue( optall.queue || "fx", doAnimation );
+ this.queue( optall.queue, doAnimation );
},
- stop: function( clearQueue, gotoEnd ) {
- if ( clearQueue ) {
- this.queue([]);
+ stop: function( clearQueue, gotoEnd, type ) {
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
}
- this.each(function() {
- var timers = jQuery.timers,
- i = timers.length;
+ return this.each(function() {
+ var i,
+ hadTimers = false,
+ timers = jQuery.timers,
+ data = jQuery._data( this );
// clear marker counters if we know they won't be
if ( !gotoEnd ) {
jQuery._unmark( true, this );
}
- while ( i-- ) {
- if ( timers[ i ].elem === this ) {
+
+ function stopQueue( elem, data, i ) {
+ var runner = data[ i ];
+ jQuery.removeData( elem, i, true );
+ runner.stop( gotoEnd );
+ }
+
+ if ( type == null ) {
+ for ( i in data ) {
+ if ( data[ i ].stop && i.indexOf(".run") === i.length - 4 ) {
+ stopQueue( this, data, i );
+ }
+ }
+ } else if ( data[ i = type + ".run" ] && data[ i ].stop ){
+ stopQueue( this, data, i );
+ }
+
+ for ( i = timers.length; i--; ) {
+ if ( timers[ i ].elem === this && (type == null || timers[ i ].queue === type) ) {
if ( gotoEnd ) {
+
// force the next step to be the last
timers[ i ]( true );
} else {
timers[ i ].saveState();
}
-
+ hadTimers = true;
timers.splice( i, 1 );
}
}
- });
-
- // start the next in the queue if the last step wasn't forced
- if ( !gotoEnd ) {
- this.dequeue();
- }
- return this;
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( !( gotoEnd && hadTimers ) ) {
+ jQuery.dequeue( this, type );
+ }
+ });
}
});
@@ -331,15 +352,21 @@ jQuery.extend({
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+ // if undefined, set to fx
+ if ( opt.queue == null ) {
+ opt.queue = "fx";
+ }
+
// Queueing
opt.old = opt.complete;
+
opt.complete = function( noUnmark ) {
if ( jQuery.isFunction( opt.old ) ) {
opt.old.call( this );
}
- if ( opt.queue !== false ) {
- jQuery.dequeue( this, opt.queue || "fx" );
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
} else if ( noUnmark !== false ) {
jQuery._unmark( this );
}
@@ -408,6 +435,7 @@ jQuery.fx.prototype = {
return self.step( gotoEnd );
}
+ t.queue = this.options.queue;
t.elem = this.elem;
t.saveState = function() {
if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
View
@@ -70,7 +70,8 @@ jQuery.extend({
type = type || "fx";
var queue = jQuery.queue( elem, type ),
- fn = queue.shift();
+ fn = queue.shift(),
+ runner = {};
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
@@ -81,16 +82,17 @@ jQuery.extend({
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if ( type === "fx" ) {
- queue.unshift("inprogress");
+ queue.unshift( "inprogress" );
}
- fn.call(elem, function() {
+ jQuery._data( elem, type + ".run", runner );
+ fn.call( elem, function() {
jQuery.dequeue( elem, type );
- });
+ }, runner );
}
if ( !queue.length ) {
- jQuery.removeData( elem, type + "queue", true );
+ jQuery.removeData( elem, type + "queue " + type + ".run", true );
handleQueueMarkDefer( elem, type, "queue" );
}
}
@@ -125,11 +127,11 @@ jQuery.fn.extend({
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
- return this.queue( type, function() {
- var elem = this;
- setTimeout(function() {
- jQuery.dequeue( elem, type );
- }, time );
+ return this.queue( type, function( next, runner ) {
+ var timeout = setTimeout( next, time );
+ runner.stop = function() {
+ clearTimeout( timeout );
+ };
});
},
clearQueue: function( type ) {
View
@@ -357,9 +357,26 @@ test("animate option (queue === false)", function () {
});
*/
+asyncTest( "animate option { queue: false }", function() {
+ expect( 2 );
+ var foo = jQuery( "#foo" );
+
+ foo.animate({
+ fontSize: "2em"
+ }, {
+ queue: false,
+ duration: 10,
+ complete: function() {
+ ok( true, "Animation Completed" );
+ start();
+ }
+ });
+
+ equals( foo.queue().length, 0, "Queue is empty" );
+});
+
asyncTest( "animate option { queue: 'name' }", function() {
expect( 5 );
-
var foo = jQuery( "#foo" ),
origWidth = foo.width(),
order = [];
@@ -608,6 +625,41 @@ test("stop(clearQueue, gotoEnd)", function() {
}, 100);
});
+asyncTest( "stop( ..., ..., queue ) - Stop single queues", function() {
+ expect( 3 );
+ var foo = jQuery( "#foo" ),
+ saved;
+
+ foo.width( 200 ).height( 200 );
+ foo.animate({
+ width: 400
+ },{
+ duration: 1000,
+ complete: function() {
+ equals( foo.width(), 400, "Animation completed for standard queue" );
+ equals( foo.height(), saved, "Height was not changed after the second stop")
+ start();
+ }
+ });
+
+ foo.animate({
+ height: 400
+ },{
+ duration: 1000,
+ queue: "height"
+ }).dequeue( "height" ).stop( false, true, "height" );
+
+ equals( foo.height(), 400, "Height was stopped with gotoEnd" );
+
+ foo.animate({
+ height: 200
+ },{
+ duration: 1000,
+ queue: "height"
+ }).dequeue( "height" ).stop( false, false, "height" );
+ saved = foo.height();
+})
+
test("toggle()", function() {
expect(6);
var x = jQuery("#foo");
View
@@ -130,6 +130,44 @@ test("delay()", function() {
equals( run, 0, "The delay delayed the next function from running." );
});
+test("delay() can be stopped", function() {
+ expect( 3 );
+ stop();
+
+ var foo = jQuery({}), run = 0;
+
+ foo
+ .queue( "alternate", function( next ) {
+ run++;
+ ok( true, "This first function was dequeued" );
+ next();
+ })
+ .delay( 100, "alternate" )
+ .queue( "alternate", function() {
+ run++;
+ ok( true, "The function was dequeued immediately, the delay was stopped" );
+ })
+ .dequeue( "alternate" )
+
+ // stop( false ) will NOT clear the queue, so it should automatically dequeue the next
+ .stop( false, false, "alternate" )
+
+ // this test
+ .delay( 100 )
+ .queue(function() {
+ run++;
+ ok( false, "This queue should never run" );
+ })
+
+ // stop( clearQueue ) should clear the queue
+ .stop( true, false );
+
+ equal( run, 2, "Queue ran the proper functions" );
+
+ setTimeout( start, 200 );
+});
+
+
test("clearQueue(name) clears the queue", function() {
expect(2);

0 comments on commit a3b59d7

Please sign in to comment.