Adds _mark and _unmark as a mean to keep track of ongoing non-queued animations in fn.promise.
This commit is contained in:
parent
f182b7b921
commit
3411d47a6a
17
src/effects.js
vendored
17
src/effects.js
vendored
|
@ -118,13 +118,17 @@ jQuery.fn.extend({
|
||||||
var optall = jQuery.speed(speed, easing, callback);
|
var optall = jQuery.speed(speed, easing, callback);
|
||||||
|
|
||||||
if ( jQuery.isEmptyObject( prop ) ) {
|
if ( jQuery.isEmptyObject( prop ) ) {
|
||||||
return this.each( optall.complete );
|
return this.each( optall.complete, [ false ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
return this[ optall.queue === false ? "each" : "queue" ](function() {
|
return this[ optall.queue === false ? "each" : "queue" ](function() {
|
||||||
// XXX 'this' does not always have a nodeName when running the
|
// XXX 'this' does not always have a nodeName when running the
|
||||||
// test suite
|
// test suite
|
||||||
|
|
||||||
|
if ( optall.queue === false ) {
|
||||||
|
jQuery._mark( this );
|
||||||
|
}
|
||||||
|
|
||||||
var opt = jQuery.extend({}, optall), p,
|
var opt = jQuery.extend({}, optall), p,
|
||||||
isElement = this.nodeType === 1,
|
isElement = this.nodeType === 1,
|
||||||
hidden = isElement && jQuery(this).is(":hidden"),
|
hidden = isElement && jQuery(this).is(":hidden"),
|
||||||
|
@ -234,6 +238,10 @@ jQuery.fn.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
this.each(function() {
|
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
|
// go in reverse order so anything added to the queue during the loop is ignored
|
||||||
for ( var i = timers.length - 1; i >= 0; i-- ) {
|
for ( var i = timers.length - 1; i >= 0; i-- ) {
|
||||||
if ( timers[i].elem === this ) {
|
if ( timers[i].elem === this ) {
|
||||||
|
@ -295,10 +303,13 @@ jQuery.extend({
|
||||||
|
|
||||||
// Queueing
|
// Queueing
|
||||||
opt.old = opt.complete;
|
opt.old = opt.complete;
|
||||||
opt.complete = function() {
|
opt.complete = function( noUnmark ) {
|
||||||
if ( opt.queue !== false ) {
|
if ( opt.queue !== false ) {
|
||||||
jQuery(this).dequeue();
|
jQuery.dequeue( this );
|
||||||
|
} else if ( noUnmark !== false ) {
|
||||||
|
jQuery._unmark( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( jQuery.isFunction( opt.old ) ) {
|
if ( jQuery.isFunction( opt.old ) ) {
|
||||||
opt.old.call( this );
|
opt.old.call( this );
|
||||||
}
|
}
|
||||||
|
|
88
src/queue.js
88
src/queue.js
|
@ -1,32 +1,74 @@
|
||||||
(function( jQuery ) {
|
(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({
|
jQuery.extend({
|
||||||
queue: function( elem, type, data ) {
|
|
||||||
if ( !elem ) {
|
_mark: function( elem, type ) {
|
||||||
return;
|
if ( elem ) {
|
||||||
|
type = (type || "fx") + "mark";
|
||||||
|
jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_unmark: function( force, elem, type ) {
|
||||||
|
if ( force !== true ) {
|
||||||
|
type = elem;
|
||||||
|
elem = force;
|
||||||
|
force = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( elem ) {
|
||||||
|
type = type || "fx";
|
||||||
|
|
||||||
|
var key = type + "mark",
|
||||||
|
count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
|
||||||
|
|
||||||
|
if ( count ) {
|
||||||
|
jQuery.data( elem, key, count, true );
|
||||||
|
} else {
|
||||||
|
jQuery.removeData( elem, key, true );
|
||||||
|
handleQueueMarkDefer( elem, type, "mark" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
queue: function( elem, type, data ) {
|
||||||
|
if ( elem ) {
|
||||||
type = (type || "fx") + "queue";
|
type = (type || "fx") + "queue";
|
||||||
var q = jQuery._data( elem, type );
|
var q = jQuery.data( elem, type, undefined, true ) || [];
|
||||||
|
|
||||||
// Speed up dequeue by getting out quickly if this is just a lookup
|
// Speed up dequeue by getting out quickly if this is just a lookup
|
||||||
if ( !data ) {
|
if ( data ) {
|
||||||
return q || [];
|
if ( !q.length || jQuery.isArray(data) ) {
|
||||||
}
|
q = jQuery.data( elem, type, jQuery.makeArray(data), true );
|
||||||
|
|
||||||
if ( !q || jQuery.isArray(data) ) {
|
|
||||||
q = jQuery._data( elem, type, jQuery.makeArray(data) );
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
q.push( data );
|
q.push( data );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return q;
|
return q;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
dequeue: function( elem, type ) {
|
dequeue: function( elem, type ) {
|
||||||
type = type || "fx";
|
|
||||||
|
|
||||||
var queue = jQuery.queue( elem, type ),
|
var queue = jQuery.queue( elem, type ),
|
||||||
fn = queue.shift(),
|
fn = queue.shift(),
|
||||||
defer;
|
defer;
|
||||||
|
@ -50,17 +92,7 @@ jQuery.extend({
|
||||||
|
|
||||||
if ( !queue.length ) {
|
if ( !queue.length ) {
|
||||||
jQuery.removeData( elem, type + "queue", true );
|
jQuery.removeData( elem, type + "queue", true );
|
||||||
// Look if we have observers and resolve if needed
|
handleQueueMarkDefer( elem, type, "queue" );
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -120,7 +152,8 @@ jQuery.fn.extend({
|
||||||
i = elements.length,
|
i = elements.length,
|
||||||
count = 1,
|
count = 1,
|
||||||
deferDataKey = type + "defer",
|
deferDataKey = type + "defer",
|
||||||
queueDataKey = type + "queue";
|
queueDataKey = type + "queue",
|
||||||
|
markDataKey = type + "mark";
|
||||||
function resolve() {
|
function resolve() {
|
||||||
if ( !( --count ) ) {
|
if ( !( --count ) ) {
|
||||||
defer.resolveWith( elements, [ elements ] );
|
defer.resolveWith( elements, [ elements ] );
|
||||||
|
@ -128,7 +161,8 @@ jQuery.fn.extend({
|
||||||
}
|
}
|
||||||
while( i-- ) {
|
while( i-- ) {
|
||||||
if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
|
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 ) )) {
|
jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
|
||||||
count++;
|
count++;
|
||||||
tmp.done( resolve );
|
tmp.done( resolve );
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
module("queue", { teardown: moduleTeardown });
|
module("queue", { teardown: moduleTeardown });
|
||||||
|
|
||||||
test("queue() with other types",function() {
|
test("queue() with other types",function() {
|
||||||
expect(9);
|
expect(11);
|
||||||
var counter = 0;
|
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
|
$div
|
||||||
.queue('foo',function(){
|
.queue('foo',function(){
|
||||||
|
@ -22,6 +29,11 @@ test("queue() with other types",function() {
|
||||||
equals( ++counter, 4, "Dequeuing" );
|
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" );
|
equals( $div.queue('foo').length, 4, "Testing queue length" );
|
||||||
|
|
||||||
$div.dequeue('foo');
|
$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() {
|
test("queue() passes in the next item in the queue as a parameter to fx queues", function() {
|
||||||
expect(2);
|
expect(3);
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
var div = jQuery({});
|
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) {
|
}).queue(function(next) {
|
||||||
equals(++counter, 2, "Next was called");
|
equals(++counter, 2, "Next was called");
|
||||||
next();
|
next();
|
||||||
start();
|
|
||||||
}).queue("bar", function() {
|
}).queue("bar", function() {
|
||||||
equals(++counter, 3, "Other queues are not triggered by next()")
|
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() {
|
test("delay()", function() {
|
||||||
|
@ -110,7 +126,9 @@ test("delay()", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("clearQueue(name) clears the queue", function() {
|
test("clearQueue(name) clears the queue", function() {
|
||||||
expect(1);
|
expect(2);
|
||||||
|
|
||||||
|
stop()
|
||||||
|
|
||||||
var div = jQuery({});
|
var div = jQuery({});
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
|
@ -123,6 +141,11 @@ test("clearQueue(name) clears the queue", function() {
|
||||||
counter++;
|
counter++;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
div.promise("foo").done(function() {
|
||||||
|
ok( true, "dequeue resolves the deferred" );
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
div.dequeue("foo");
|
div.dequeue("foo");
|
||||||
|
|
||||||
equals(counter, 1, "the queue was cleared");
|
equals(counter, 1, "the queue was cleared");
|
||||||
|
@ -146,3 +169,81 @@ test("clearQueue() clears the fx queue", function() {
|
||||||
|
|
||||||
div.removeData();
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue