Commit a3b59d7f authored by Corey Frang's avatar Corey Frang Committed by timmywil

Landing pull request 514. 1.7 - queue refactoring to handle delay stop - Fixes #6150.

More Details:
 - https://github.com/jquery/jquery/pull/514
 - http://bugs.jquery.com/ticket/6150
parent a74cbb2b
...@@ -200,6 +200,7 @@ jQuery.fn.extend({ ...@@ -200,6 +200,7 @@ jQuery.fn.extend({
val = prop[ p ]; val = prop[ p ];
if ( rfxtypes.test( val ) ) { if ( rfxtypes.test( val ) ) {
// Tracks whether to show or hide based on private // Tracks whether to show or hide based on private
// data attached to the element // data attached to the element
method = jQuery._data( this, "toggle" + p ) || (val === "toggle" ? hidden ? "show" : "hide" : 0); method = jQuery._data( this, "toggle" + p ) || (val === "toggle" ? hidden ? "show" : "hide" : 0);
...@@ -244,42 +245,62 @@ jQuery.fn.extend({ ...@@ -244,42 +245,62 @@ jQuery.fn.extend({
return optall.queue === false ? return optall.queue === false ?
this.each( doAnimation ) : this.each( doAnimation ) :
this.queue( optall.queue || "fx", doAnimation ); this.queue( optall.queue, doAnimation );
}, },
stop: function( clearQueue, gotoEnd ) { stop: function( clearQueue, gotoEnd, type ) {
if ( clearQueue ) { if ( clearQueue && type !== false ) {
this.queue([]); this.queue( type || "fx", [] );
} }
this.each(function() { return this.each(function() {
var timers = jQuery.timers, var i,
i = timers.length; hadTimers = false,
timers = jQuery.timers,
data = jQuery._data( this );
// clear marker counters if we know they won't be // clear marker counters if we know they won't be
if ( !gotoEnd ) { if ( !gotoEnd ) {
jQuery._unmark( true, this ); 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 ) { if ( gotoEnd ) {
// force the next step to be the last // force the next step to be the last
timers[ i ]( true ); timers[ i ]( true );
} else { } else {
timers[ i ].saveState(); timers[ i ].saveState();
} }
hadTimers = true;
timers.splice( i, 1 ); 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({ ...@@ -331,15 +352,21 @@ jQuery.extend({
opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : 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; 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 // Queueing
opt.old = opt.complete; opt.old = opt.complete;
opt.complete = function( noUnmark ) { opt.complete = function( noUnmark ) {
if ( jQuery.isFunction( opt.old ) ) { if ( jQuery.isFunction( opt.old ) ) {
opt.old.call( this ); opt.old.call( this );
} }
if ( opt.queue !== false ) { if ( opt.queue ) {
jQuery.dequeue( this, opt.queue || "fx" ); jQuery.dequeue( this, opt.queue );
} else if ( noUnmark !== false ) { } else if ( noUnmark !== false ) {
jQuery._unmark( this ); jQuery._unmark( this );
} }
...@@ -408,6 +435,7 @@ jQuery.fx.prototype = { ...@@ -408,6 +435,7 @@ jQuery.fx.prototype = {
return self.step( gotoEnd ); return self.step( gotoEnd );
} }
t.queue = this.options.queue;
t.elem = this.elem; t.elem = this.elem;
t.saveState = function() { t.saveState = function() {
if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) { if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
......
...@@ -70,7 +70,8 @@ jQuery.extend({ ...@@ -70,7 +70,8 @@ jQuery.extend({
type = type || "fx"; type = type || "fx";
var queue = jQuery.queue( elem, type ), 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 the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) { if ( fn === "inprogress" ) {
...@@ -81,16 +82,17 @@ jQuery.extend({ ...@@ -81,16 +82,17 @@ jQuery.extend({
// Add a progress sentinel to prevent the fx queue from being // Add a progress sentinel to prevent the fx queue from being
// automatically dequeued // automatically dequeued
if ( type === "fx" ) { 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 ); jQuery.dequeue( elem, type );
}); }, runner );
} }
if ( !queue.length ) { if ( !queue.length ) {
jQuery.removeData( elem, type + "queue", true ); jQuery.removeData( elem, type + "queue " + type + ".run", true );
handleQueueMarkDefer( elem, type, "queue" ); handleQueueMarkDefer( elem, type, "queue" );
} }
} }
...@@ -125,11 +127,11 @@ jQuery.fn.extend({ ...@@ -125,11 +127,11 @@ jQuery.fn.extend({
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx"; type = type || "fx";
return this.queue( type, function() { return this.queue( type, function( next, runner ) {
var elem = this; var timeout = setTimeout( next, time );
setTimeout(function() { runner.stop = function() {
jQuery.dequeue( elem, type ); clearTimeout( timeout );
}, time ); };
}); });
}, },
clearQueue: function( type ) { clearQueue: function( type ) {
......
...@@ -357,9 +357,26 @@ test("animate option (queue === false)", function () { ...@@ -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() { asyncTest( "animate option { queue: 'name' }", function() {
expect( 5 ); expect( 5 );
var foo = jQuery( "#foo" ), var foo = jQuery( "#foo" ),
origWidth = foo.width(), origWidth = foo.width(),
order = []; order = [];
...@@ -608,6 +625,41 @@ test("stop(clearQueue, gotoEnd)", function() { ...@@ -608,6 +625,41 @@ test("stop(clearQueue, gotoEnd)", function() {
}, 100); }, 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() { test("toggle()", function() {
expect(6); expect(6);
var x = jQuery("#foo"); var x = jQuery("#foo");
......
...@@ -130,6 +130,44 @@ test("delay()", function() { ...@@ -130,6 +130,44 @@ test("delay()", function() {
equals( run, 0, "The delay delayed the next function from running." ); 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() { test("clearQueue(name) clears the queue", function() {
expect(2); expect(2);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment