/* YUI 3.17.2 (build 9c3c78e) Copyright 2014 Yahoo! Inc. All rights reserved. Licensed under the BSD License. http://yuilibrary.com/license/ */ YUI.add('async-queue', function (Y, NAME) { /** *
AsyncQueue allows you create a chain of function callbacks executed * via setTimeout (or synchronously) that are guaranteed to run in order. * Items in the queue can be promoted or removed. Start or resume the * execution chain with run(). pause() to temporarily delay execution, or * stop() to halt and clear the queue.
* * @module async-queue */ /** *A specialized queue class that supports scheduling callbacks to execute * sequentially, iteratively, even asynchronously.
* *Callbacks can be function refs or objects with the following keys. Only
* the fn
key is required.
fn
-- The callback functioncontext
-- The execution context for the callbackFn.args
-- Arguments to pass to callbackFn.timeout
-- Millisecond delay before executing callbackFn.
* (Applies to each iterative execution of callback)iterations
-- Number of times to repeat the callback.
* until
-- Repeat the callback until this function returns
* true. This setting trumps iterations.autoContinue
-- Set to false to prevent the AsyncQueue from
* executing the next callback in the Queue after
* the callback completes.id
-- Name that can be used to get, promote, get the
* indexOf, or delete this callback.Static default values used to populate callback configuration properties. * Preconfigured defaults include:
* *autoContinue
: true
iterations
: 1timeout
: 10 (10ms between callbacks)until
: (function to run until iterations <= 0)added
property in the
* after phase.
*
* @method _defAddFn
* @param e {Event} the event object
* @protected
*/
_defAddFn : function(e) {
var _q = this._q,
added = [];
Y.Array.each(e.callbacks, function (c) {
if (isObject(c)) {
_q.push(c);
added.push(c);
}
});
e.added = added;
},
/**
* 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 {AsyncQueue} the AsyncQueue instance
* @chainable
*/
pause: function () {
if (this._running && isObject(this._running)) {
this._running.cancel();
}
this._running = false;
return this;
},
/**
* Stop and clear the queue after the current execution of the
* current callback completes.
*
* @method stop
* @return {AsyncQueue} the AsyncQueue instance
* @chainable
*/
stop : function () {
this._q = [];
if (this._running && isObject(this._running)) {
this._running.cancel();
this._running = false;
}
// otherwise don't systematically set this._running to false, because if
// stop has been called from inside a queued callback, the _execute method
// currenty running needs to call run() one more time for the 'complete'
// event to be fired.
// if stop is called from outside a callback, we need to explicitely call
// run() once again to fire the 'complete' event.
if (!this._executing) {
this.run();
}
return this;
},
/**
* Returns the current index of a callback. Pass in either the id or
* callback function from getCallback.
*
* @method indexOf
* @param callback {String|Function} the callback or its specified id
* @return {Number} index of the callback or -1 if not found
*/
indexOf : function (callback) {
var i = 0, len = this._q.length, c;
for (; i < len; ++i) {
c = this._q[i];
if (c === callback || c.id === callback) {
return i;
}
}
return -1;
},
/**
* Retrieve a callback by its id. Useful to modify the configuration
* while the queue is running.
*
* @method getCallback
* @param id {String} the id assigned to the callback
* @return {Object} the callback object
*/
getCallback : function (id) {
var i = this.indexOf(id);
return (i > -1) ? this._q[i] : null;
},
/**
* Promotes the named callback to the top of the queue. If a callback is
* currently executing or looping (via until or iterations), the promotion
* is scheduled to occur after the current callback has completed.
*
* @method promote
* @param callback {String|Object} the callback object or a callback's id
* @return {AsyncQueue} the AsyncQueue instance
* @chainable
*/
promote : function (callback) {
var payload = { callback : callback },e;
if (this.isRunning()) {
e = this.after(SHIFT, function () {
this.fire(PROMOTE, payload);
e.detach();
}, this);
} else {
this.fire(PROMOTE, payload);
}
return this;
},
/**
* Default functionality for the "promote" event. Promotes the * named callback to the head of the queue.
* *The event object will contain a property "callback", which * holds the id of a callback or the callback object itself.
* * @method _defPromoteFn * @param e {Event} the custom event * @protected */ _defPromoteFn : function (e) { var i = this.indexOf(e.callback), promoted = (i > -1) ? this._q.splice(i,1)[0] : null; e.promoted = promoted; if (promoted) { this._q.unshift(promoted); } }, /** * Removes the callback from the queue. If the queue is active, the * removal is scheduled to occur after the current callback has completed. * * @method remove * @param callback {String|Object} the callback object or a callback's id * @return {AsyncQueue} the AsyncQueue instance * @chainable */ remove : function (callback) { var payload = { callback : callback },e; // Can't return the removed callback because of the deferral until // current callback is complete if (this.isRunning()) { e = this.after(SHIFT, function () { this.fire(REMOVE, payload); e.detach(); },this); } else { this.fire(REMOVE, payload); } return this; }, /** *Default functionality for the "remove" event. Removes the * callback from the queue.
* *The event object will contain a property "callback", which * holds the id of a callback or the callback object itself.
* * @method _defRemoveFn * @param e {Event} the custom event * @protected */ _defRemoveFn : function (e) { var i = this.indexOf(e.callback); e.removed = (i > -1) ? this._q.splice(i,1)[0] : null; }, /** * Returns the number of callbacks in the queue. * * @method size * @return {Number} */ size : function () { // next() flushes callbacks that have met their until() criteria and // therefore shouldn't count since they wouldn't execute anyway. if (!this.isRunning()) { this.next(); } return this._q.length; } }); }, '3.17.2', {"requires": ["event-custom"]});