aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjaubourg <j@ubourg.net>2011-04-11 13:40:14 +0200
committerjaubourg <j@ubourg.net>2011-04-11 13:40:14 +0200
commit3411d47a6a952e283864d2401438a6764d925b74 (patch)
tree7d8857e732e565703d55a7e3941b60c0ee7c9255
parentf182b7b92117f8e353a1f712569d3d2642100862 (diff)
downloadjquery-3411d47a6a952e283864d2401438a6764d925b74.tar.gz
jquery-3411d47a6a952e283864d2401438a6764d925b74.zip
Adds _mark and _unmark as a mean to keep track of ongoing non-queued animations in fn.promise.
-rw-r--r--src/effects.js17
-rw-r--r--src/queue.js92
-rw-r--r--test/unit/queue.js111
3 files changed, 183 insertions, 37 deletions
diff --git a/src/effects.js b/src/effects.js
index ad2ed3c97..d6eff7b32 100644
--- a/src/effects.js
+++ b/src/effects.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 );
}
diff --git a/src/queue.js b/src/queue.js
index 701d06ade..ab06ae924 100644
--- a/src/queue.js
+++ b/src/queue.js
@@ -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,7 +152,8 @@ 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 ] );
@@ -128,7 +161,8 @@ jQuery.fn.extend({
}
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 );
diff --git a/test/unit/queue.js b/test/unit/queue.js
index 31e587db2..05461cd26 100644
--- a/test/unit/queue.js
+++ b/test/unit/queue.js
@@ -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();
+ });
+});