1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
|
/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 3.0.0pr1
*/
YUI.add('queue', function(Y) {
/**
* Mechanism to execute a series of callbacks in a non-blocking queue. Each
* callback is executed via setTimout unless configured with a negative
* timeout, in which case it is run in blocking mode in the same execution
* thread as the previous callback. Callbacks can be function references or
* object literals with the following keys:
* <ul>
* <li><code>fn</code> - {Function} REQUIRED the callback function.</li>
* <li><code>timeout</code> - {number} millisecond delay to wait after previous callback completion before executing this callback. Negative values cause immediate blocking execution. Default 0.</li>
* <li><code>until</code> - {Function} boolean function executed before each iteration. Return true to indicate callback completion.</li>
* <li><code>iterations</code> - {Number} number of times to execute the callback before proceeding to the next callback in the queue. Incompatible with <code>until</code>.</li>
* </ul>
*
* @module queue
* @class Queue
* @constructor
* @param callback* {Function|Object} Any number of callbacks to initialize the queue
*/
Y.Queue = function () {
// Factory or Constructor
var me = this instanceof Y.Queue ? this : new Y.Queue();
/**
* The callback queue
* @property q
* @type {Array}
* @protected
*/
me.q = [];
return me.add.apply(me,arguments);
};
Y.Queue.prototype = {
/**
* Timeout id used to pause or stop execution and indicate the execution
* state of the Queue. 0 indicates paused or stopped, negatives indicate
* blocking execution, and positives indicate non-blocking execution.
* @property id
* @type {number}
* @protected
*/
id : 0,
/**
* Execute the queue callbacks (also resumes paused Queue).
* @method run
* @return {Queue} the Queue instance
*/
run : function () {
// Grab the first callback in the queue
var c = this.q[0],
fn;
// If there is no callback in the queue or the Queue is currently
// in an execution mode, return
if (!c) {
/**
* Event fired after the last queued callback is executed. Not
* fired if the Queue is stopped via q.stop().
* @event end
*/
this.fire('end');
return this;
} else if (this.id) {
return this;
}
fn = c.fn || c;
if (typeof fn === 'function') {
var ms = c.timeout || 0,
me = this;
// Execute immediately if the callback timeout is negative.
if (ms < 0) {
this.id = ms;
if (c.until) { // test .until condition
for (;!c.until();) {
this._exec(fn,c);
}
} else if (c.iterations) { // test .iterations
for (;c.iterations-- > 0;) {
this._exec(fn,c);
}
} else { // single shot callback
this._exec(fn,c);
}
this._shift();
this.id = 0;
return this.run();
} else {
if (c.until) { // test .until condition
if (c.until()) {
// Move to the next callback
this._shift();
return this.run();
}
} else if (!c.iterations || !--c.iterations) { // .iterations
this._shift();
}
// Set to execute after the configured timeout
this.id = setTimeout(function () {
me._exec(fn,c);
// Loop unless the Queue was paused from inside the callback
if (me.id) {
// Indicate ready to run state
me.id = 0;
// Start the fun all over again
me.run();
}
},ms);
}
}
return this;
},
/**
* Executes the callback function
* @method _exec
* @param fn {Function} the function to execute
* @param c {Object|Function} the callback as defined during add(c)
* @protected
*/
_exec : function (fn,c) {
/**
* Fired before a callback is executed
* @event beforeCallback
* @param o {Object} Object literal with the following keys:
* <dl>
* <dt>fn</dt><dd>The function about to be executed</dd>
* <dt>callback</dt><dd>The callback as provided to <code>add(..)</code></dd>
* </dl>
*/
this.fire('beforeCallback',{fn:fn,callback:c});
fn.call(this);
/**
* Fired before a callback is executed
* @event afterCallback
* @param o {Object} Object literal with the following keys:
* <dl>
* <dt>fn</dt><dd>The function just executed</dd>
* <dt>callback</dt><dd>The callback as provided to <code>add(..)</code></dd>
* </dl>
*/
this.fire('afterCallback',{fn:fn,callback:c});
},
/**
* Shifts the first callback off the Queue
* @method _shift
* @private
*/
_shift : function () {
/**
* Fired after a callback is shifted from the Queue
* @event shiftCallback
* @param callback {Function|Object} The callback passed to <code>add(..)</code>
*/
this.fire('shiftCallback',this.q.shift());
},
/**
* Add any number of callbacks to the end of the queue
* @method add
* @param callback* {Function|Object} Any number of callbacks
* @return {Queue} the Queue instance
*/
add : function () {
var callbacks = Y.Array(arguments,0,true);
this.q.splice.apply(this.q,[this.q.length,0].concat(callbacks));
/**
* Fired from within <code>add(..)</code> after callbacks are queued
* @event addCallback
* @param callbacks {Array} Array of callbacks passed to <code>add(..)</code>
*/
this.fire('addCallback',callbacks);
return this;
},
/**
* Pause the execution of the Queue after the execution of the current
* callback completes. If called from code outside of a queued callback,
* clears the timeout for the pending callback. Paused Queue can be
* restarted with q.run()
* @method pause
* @return {Queue} the Queue instance
*/
pause: function () {
clearTimeout(this.id);
this.id = 0;
/**
* Fired after Queue is paused
* @event pause
*/
this.fire('pause');
return this;
},
/**
* Stop and clear the Queue's queue after the current execution of the
* current callback completes.
* @method stop
* @return {Queue} the Queue instance
*/
stop : function () {
this.pause();
this.q = [];
/**
* Fired after Queue is stopped
* @event stop
*/
this.fire('stop');
return this;
}
};
Y.augment(Y.Queue,Y.Event.Target);
}, '3.0.0pr1' );
|