Skip to content
Permalink
Browse files

Adds _mark and _unmark as a mean to keep track of ongoing non-queued …

…animations in fn.promise.
  • Loading branch information...
jaubourg committed Apr 11, 2011
1 parent f182b7b commit 3411d47a6a952e283864d2401438a6764d925b74
Showing with 183 additions and 37 deletions.
  1. +14 −3 src/effects.js
  2. +63 −29 src/queue.js
  3. +106 −5 test/unit/queue.js
@@ -118,13 +118,17 @@ jQuery.fn.extend({
var optall = jQuery.speed(speed, easing, callback);

if ( jQuery.isEmptyObject( prop ) ) {
return this.each( optall.complete );
return this.each( optall.complete, [ false ] );
}

return this[ optall.queue === false ? "each" : "queue" ](function() {
// XXX 'this' does not always have a nodeName when running the
// test suite

if ( optall.queue === false ) {
jQuery._mark( this );
}

var opt = jQuery.extend({}, optall), p,
isElement = this.nodeType === 1,
hidden = isElement && jQuery(this).is(":hidden"),
@@ -234,6 +238,10 @@ jQuery.fn.extend({
}

this.each(function() {
// clear marker counters if we know they won't be
if ( !gotoEnd ) {
jQuery._unmark( true, this );
}
// 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 ) {
@@ -295,10 +303,13 @@ jQuery.extend({

// Queueing
opt.old = opt.complete;
opt.complete = function() {
opt.complete = function( noUnmark ) {
if ( opt.queue !== false ) {
jQuery(this).dequeue();
jQuery.dequeue( this );
} else if ( noUnmark !== false ) {
jQuery._unmark( this );
}

if ( jQuery.isFunction( opt.old ) ) {
opt.old.call( this );
}
@@ -1,32 +1,74 @@
(function( jQuery ) {

function handleQueueMarkDefer( elem, type, src ) {
var deferDataKey = type + "defer",
queueDataKey = type + "queue",
markDataKey = type + "mark",
defer = jQuery.data( elem, deferDataKey, undefined, true );
if ( defer &&
( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
( src === "mark " || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {
// Give room for hard-coded callbacks to fire first
// and eventually mark/queue something else on the element
setTimeout( function() {
if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
!jQuery.data( elem, markDataKey, undefined, true ) ) {
jQuery.removeData( elem, deferDataKey, true );
defer.resolve();
}
}, 0 );
}
}

jQuery.extend({
queue: function( elem, type, data ) {
if ( !elem ) {
return;
}

type = (type || "fx") + "queue";
var q = jQuery._data( elem, type );
_mark: function( elem, type ) {
if ( elem ) {
type = (type || "fx") + "mark";
jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
}
},

// Speed up dequeue by getting out quickly if this is just a lookup
if ( !data ) {
return q || [];
_unmark: function( force, elem, type ) {
if ( force !== true ) {
type = elem;
elem = force;
force = false;
}

if ( !q || jQuery.isArray(data) ) {
q = jQuery._data( elem, type, jQuery.makeArray(data) );
if ( elem ) {
type = type || "fx";

var key = type + "mark",
count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );

} else {
q.push( data );
if ( count ) {
jQuery.data( elem, key, count, true );
} else {
jQuery.removeData( elem, key, true );
handleQueueMarkDefer( elem, type, "mark" );
}
}
},

return q;
queue: function( elem, type, data ) {
if ( elem ) {
type = (type || "fx") + "queue";
var q = jQuery.data( elem, type, undefined, true ) || [];

// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !q.length || jQuery.isArray(data) ) {
q = jQuery.data( elem, type, jQuery.makeArray(data), true );
} else {
q.push( data );
}
}
return q;
}
},

dequeue: function( elem, type ) {
type = type || "fx";

var queue = jQuery.queue( elem, type ),
fn = queue.shift(),
defer;
@@ -50,17 +92,7 @@ jQuery.extend({

if ( !queue.length ) {
jQuery.removeData( elem, type + "queue", true );
// Look if we have observers and resolve if needed
if (( defer = jQuery.data( elem, type + "defer", undefined, true ) )) {
// Give room for hard-coded callbacks to fire first
// and eventually add another animation on the element
setTimeout( function() {
if ( !jQuery.data( elem, type + "queue", undefined, true ) ) {
jQuery.removeData( elem, type + "defer", true );
defer.resolve();
}
}, 0 );
}
handleQueueMarkDefer( elem, type, "queue" );
}
}
});
@@ -120,15 +152,17 @@ jQuery.fn.extend({
i = elements.length,
count = 1,
deferDataKey = type + "defer",
queueDataKey = type + "queue";
queueDataKey = type + "queue",
markDataKey = type + "mark";
function resolve() {
if ( !( --count ) ) {
defer.resolveWith( elements, [ elements ] );
}
}
while( i-- ) {
if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
jQuery.data( elements[ i ], queueDataKey, undefined, true ) &&
( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
count++;
tmp.done( resolve );
@@ -1,10 +1,17 @@
module("queue", { teardown: moduleTeardown });

test("queue() with other types",function() {
expect(9);
expect(11);
var counter = 0;

var $div = jQuery({});
stop();

var $div = jQuery({}),
defer;

$div.promise('foo').done(function() {
equals( counter, 0, "Deferred for collection with no queue is automatically resolved" );
});

$div
.queue('foo',function(){
@@ -22,6 +29,11 @@ test("queue() with other types",function() {
equals( ++counter, 4, "Dequeuing" );
});

defer = $div.promise('foo').done(function() {
equals( counter, 4, "Testing previous call to dequeue in deferred" );
start();
});

equals( $div.queue('foo').length, 4, "Testing queue length" );

$div.dequeue('foo');
@@ -74,7 +86,7 @@ test("queue(name) passes in the next item in the queue as a parameter", function
});

test("queue() passes in the next item in the queue as a parameter to fx queues", function() {
expect(2);
expect(3);
stop();

var div = jQuery({});
@@ -87,11 +99,15 @@ test("queue() passes in the next item in the queue as a parameter to fx queues",
}).queue(function(next) {
equals(++counter, 2, "Next was called");
next();
start();
}).queue("bar", function() {
equals(++counter, 3, "Other queues are not triggered by next()")
});

jQuery.when( div.promise("fx"), div ).done(function() {
equals(counter, 2, "Deferreds resolved");
start();
});

});

test("delay()", function() {
@@ -110,7 +126,9 @@ test("delay()", function() {
});

test("clearQueue(name) clears the queue", function() {
expect(1);
expect(2);

stop()

var div = jQuery({});
var counter = 0;
@@ -123,6 +141,11 @@ test("clearQueue(name) clears the queue", function() {
counter++;
});

div.promise("foo").done(function() {
ok( true, "dequeue resolves the deferred" );
start();
});

div.dequeue("foo");

equals(counter, 1, "the queue was cleared");
@@ -146,3 +169,81 @@ test("clearQueue() clears the fx queue", function() {

div.removeData();
});

test("_mark() and _unmark()", function() {
expect(1);

var div = {},
$div = jQuery( div );

stop();

jQuery._mark( div, "foo" );
jQuery._mark( div, "foo" );
jQuery._unmark( div, "foo" );
jQuery._unmark( div, "foo" );

$div.promise( "foo" ).done(function() {
ok( true, "No more marks" );
start();
});
});

test("_mark() and _unmark() default to 'fx'", function() {
expect(1);

var div = {},
$div = jQuery( div );

stop();

jQuery._mark( div );
jQuery._mark( div );
jQuery._unmark( div, "fx" );
jQuery._unmark( div );

$div.promise().done(function() {
ok( true, "No more marks" );
start();
});
});

test("promise()", function() {
expect(1);

stop();

var objects = [];

jQuery.each( [{}, {}], function( i, div ) {
var $div = jQuery( div );
$div.queue(function( next ) {
setTimeout( function() {
if ( i ) {
next();
setTimeout( function() {
jQuery._unmark( div );
}, 20 );
} else {
jQuery._unmark( div );
setTimeout( function() {
next();
}, 20 );
}
}, 50 );
}).queue(function( next ) {
next();
});
jQuery._mark( div );
objects.push( $div );
});

jQuery.when.apply( jQuery, objects ).done(function() {
ok( true, "Deferred resolved" );
start();
});

jQuery.each( objects, function() {
this.dequeue();
});
});

0 comments on commit 3411d47

Please sign in to comment.
You can’t perform that action at this time.