]> source.dussan.org Git - jquery.git/commitdiff
Landing pull request 514. 1.7 - queue refactoring to handle delay stop - Fixes #6150.
authorCorey Frang <gnarf@gnarf.net>
Wed, 28 Sep 2011 15:55:29 +0000 (11:55 -0400)
committertimmywil <timmywillisn@gmail.com>
Wed, 28 Sep 2011 15:55:29 +0000 (11:55 -0400)
More Details:
 - https://github.com/jquery/jquery/pull/514
 - http://bugs.jquery.com/ticket/6150

src/effects.js
src/queue.js
test/unit/effects.js
test/unit/queue.js

index 3edb96fae203985b5bfbf219cb77eb321c727c7a..ee535e3cd8e85e5165f4b2db31fa32ed9ababcb4 100644 (file)
@@ -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 ) {
index 0c678064eb1bf54cd71a48e2a44f62de73a2584f..b2ee8de08318be4345bf3e2b493a18470329ad0c 100644 (file)
@@ -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 ) {
index d13bd587c29374922c95258e2d8b0a1ade63c25a..da1dd0a623bc54a27c158dde784765841809a7a7 100644 (file)
@@ -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");
index b5c058caa56f7d82240589c8b6c3de2e2e63d386..95bbfc97e1f91803cd9860897f0330c9c0739ead 100644 (file)
@@ -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);