Skip to content

Commit 3411d47

Browse files
committed
Adds _mark and _unmark as a mean to keep track of ongoing non-queued animations in fn.promise.
1 parent f182b7b commit 3411d47

3 files changed

Lines changed: 183 additions & 37 deletions

File tree

src/effects.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,17 @@ jQuery.fn.extend({
118118
var optall = jQuery.speed(speed, easing, callback);
119119

120120
if ( jQuery.isEmptyObject( prop ) ) {
121-
return this.each( optall.complete );
121+
return this.each( optall.complete, [ false ] );
122122
}
123123

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

128+
if ( optall.queue === false ) {
129+
jQuery._mark( this );
130+
}
131+
128132
var opt = jQuery.extend({}, optall), p,
129133
isElement = this.nodeType === 1,
130134
hidden = isElement && jQuery(this).is(":hidden"),
@@ -234,6 +238,10 @@ jQuery.fn.extend({
234238
}
235239

236240
this.each(function() {
241+
// clear marker counters if we know they won't be
242+
if ( !gotoEnd ) {
243+
jQuery._unmark( true, this );
244+
}
237245
// go in reverse order so anything added to the queue during the loop is ignored
238246
for ( var i = timers.length - 1; i >= 0; i-- ) {
239247
if ( timers[i].elem === this ) {
@@ -295,10 +303,13 @@ jQuery.extend({
295303

296304
// Queueing
297305
opt.old = opt.complete;
298-
opt.complete = function() {
306+
opt.complete = function( noUnmark ) {
299307
if ( opt.queue !== false ) {
300-
jQuery(this).dequeue();
308+
jQuery.dequeue( this );
309+
} else if ( noUnmark !== false ) {
310+
jQuery._unmark( this );
301311
}
312+
302313
if ( jQuery.isFunction( opt.old ) ) {
303314
opt.old.call( this );
304315
}

src/queue.js

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,74 @@
11
(function( jQuery ) {
22

3+
function handleQueueMarkDefer( elem, type, src ) {
4+
var deferDataKey = type + "defer",
5+
queueDataKey = type + "queue",
6+
markDataKey = type + "mark",
7+
defer = jQuery.data( elem, deferDataKey, undefined, true );
8+
if ( defer &&
9+
( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
10+
( src === "mark " || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {
11+
// Give room for hard-coded callbacks to fire first
12+
// and eventually mark/queue something else on the element
13+
setTimeout( function() {
14+
if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
15+
!jQuery.data( elem, markDataKey, undefined, true ) ) {
16+
jQuery.removeData( elem, deferDataKey, true );
17+
defer.resolve();
18+
}
19+
}, 0 );
20+
}
21+
}
22+
323
jQuery.extend({
4-
queue: function( elem, type, data ) {
5-
if ( !elem ) {
6-
return;
7-
}
824

9-
type = (type || "fx") + "queue";
10-
var q = jQuery._data( elem, type );
25+
_mark: function( elem, type ) {
26+
if ( elem ) {
27+
type = (type || "fx") + "mark";
28+
jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
29+
}
30+
},
1131

12-
// Speed up dequeue by getting out quickly if this is just a lookup
13-
if ( !data ) {
14-
return q || [];
32+
_unmark: function( force, elem, type ) {
33+
if ( force !== true ) {
34+
type = elem;
35+
elem = force;
36+
force = false;
1537
}
1638

17-
if ( !q || jQuery.isArray(data) ) {
18-
q = jQuery._data( elem, type, jQuery.makeArray(data) );
39+
if ( elem ) {
40+
type = type || "fx";
41+
42+
var key = type + "mark",
43+
count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
1944

20-
} else {
21-
q.push( data );
45+
if ( count ) {
46+
jQuery.data( elem, key, count, true );
47+
} else {
48+
jQuery.removeData( elem, key, true );
49+
handleQueueMarkDefer( elem, type, "mark" );
50+
}
2251
}
52+
},
2353

24-
return q;
54+
queue: function( elem, type, data ) {
55+
if ( elem ) {
56+
type = (type || "fx") + "queue";
57+
var q = jQuery.data( elem, type, undefined, true ) || [];
58+
59+
// Speed up dequeue by getting out quickly if this is just a lookup
60+
if ( data ) {
61+
if ( !q.length || jQuery.isArray(data) ) {
62+
q = jQuery.data( elem, type, jQuery.makeArray(data), true );
63+
} else {
64+
q.push( data );
65+
}
66+
}
67+
return q;
68+
}
2569
},
2670

2771
dequeue: function( elem, type ) {
28-
type = type || "fx";
29-
3072
var queue = jQuery.queue( elem, type ),
3173
fn = queue.shift(),
3274
defer;
@@ -50,17 +92,7 @@ jQuery.extend({
5092

5193
if ( !queue.length ) {
5294
jQuery.removeData( elem, type + "queue", true );
53-
// Look if we have observers and resolve if needed
54-
if (( defer = jQuery.data( elem, type + "defer", undefined, true ) )) {
55-
// Give room for hard-coded callbacks to fire first
56-
// and eventually add another animation on the element
57-
setTimeout( function() {
58-
if ( !jQuery.data( elem, type + "queue", undefined, true ) ) {
59-
jQuery.removeData( elem, type + "defer", true );
60-
defer.resolve();
61-
}
62-
}, 0 );
63-
}
95+
handleQueueMarkDefer( elem, type, "queue" );
6496
}
6597
}
6698
});
@@ -120,15 +152,17 @@ jQuery.fn.extend({
120152
i = elements.length,
121153
count = 1,
122154
deferDataKey = type + "defer",
123-
queueDataKey = type + "queue";
155+
queueDataKey = type + "queue",
156+
markDataKey = type + "mark";
124157
function resolve() {
125158
if ( !( --count ) ) {
126159
defer.resolveWith( elements, [ elements ] );
127160
}
128161
}
129162
while( i-- ) {
130163
if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
131-
jQuery.data( elements[ i ], queueDataKey, undefined, true ) &&
164+
( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
165+
jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
132166
jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
133167
count++;
134168
tmp.done( resolve );

test/unit/queue.js

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
module("queue", { teardown: moduleTeardown });
22

33
test("queue() with other types",function() {
4-
expect(9);
4+
expect(11);
55
var counter = 0;
66

7-
var $div = jQuery({});
7+
stop();
8+
9+
var $div = jQuery({}),
10+
defer;
11+
12+
$div.promise('foo').done(function() {
13+
equals( counter, 0, "Deferred for collection with no queue is automatically resolved" );
14+
});
815

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

32+
defer = $div.promise('foo').done(function() {
33+
equals( counter, 4, "Testing previous call to dequeue in deferred" );
34+
start();
35+
});
36+
2537
equals( $div.queue('foo').length, 4, "Testing queue length" );
2638

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

7688
test("queue() passes in the next item in the queue as a parameter to fx queues", function() {
77-
expect(2);
89+
expect(3);
7890
stop();
7991

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

106+
jQuery.when( div.promise("fx"), div ).done(function() {
107+
equals(counter, 2, "Deferreds resolved");
108+
start();
109+
});
110+
95111
});
96112

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

112128
test("clearQueue(name) clears the queue", function() {
113-
expect(1);
129+
expect(2);
130+
131+
stop()
114132

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

144+
div.promise("foo").done(function() {
145+
ok( true, "dequeue resolves the deferred" );
146+
start();
147+
});
148+
126149
div.dequeue("foo");
127150

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

147170
div.removeData();
148171
});
172+
173+
test("_mark() and _unmark()", function() {
174+
expect(1);
175+
176+
var div = {},
177+
$div = jQuery( div );
178+
179+
stop();
180+
181+
jQuery._mark( div, "foo" );
182+
jQuery._mark( div, "foo" );
183+
jQuery._unmark( div, "foo" );
184+
jQuery._unmark( div, "foo" );
185+
186+
$div.promise( "foo" ).done(function() {
187+
ok( true, "No more marks" );
188+
start();
189+
});
190+
});
191+
192+
test("_mark() and _unmark() default to 'fx'", function() {
193+
expect(1);
194+
195+
var div = {},
196+
$div = jQuery( div );
197+
198+
stop();
199+
200+
jQuery._mark( div );
201+
jQuery._mark( div );
202+
jQuery._unmark( div, "fx" );
203+
jQuery._unmark( div );
204+
205+
$div.promise().done(function() {
206+
ok( true, "No more marks" );
207+
start();
208+
});
209+
});
210+
211+
test("promise()", function() {
212+
expect(1);
213+
214+
stop();
215+
216+
var objects = [];
217+
218+
jQuery.each( [{}, {}], function( i, div ) {
219+
var $div = jQuery( div );
220+
$div.queue(function( next ) {
221+
setTimeout( function() {
222+
if ( i ) {
223+
next();
224+
setTimeout( function() {
225+
jQuery._unmark( div );
226+
}, 20 );
227+
} else {
228+
jQuery._unmark( div );
229+
setTimeout( function() {
230+
next();
231+
}, 20 );
232+
}
233+
}, 50 );
234+
}).queue(function( next ) {
235+
next();
236+
});
237+
jQuery._mark( div );
238+
objects.push( $div );
239+
});
240+
241+
jQuery.when.apply( jQuery, objects ).done(function() {
242+
ok( true, "Deferred resolved" );
243+
start();
244+
});
245+
246+
jQuery.each( objects, function() {
247+
this.dequeue();
248+
});
249+
});

0 commit comments

Comments
 (0)