mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
166 lines
5.4 KiB
JavaScript
166 lines
5.4 KiB
JavaScript
define([
|
|
], function(){
|
|
//ASSUMES: jquery
|
|
//=============================================================================
|
|
/** @class AjaxQueue
|
|
* Class that allows queueing functions that return jQuery promises (such
|
|
* as ajax calls). Each function waits for the previous to complete before
|
|
* being called
|
|
*
|
|
* @constructor accepts a list of functions and automatically begins
|
|
* processing them
|
|
*/
|
|
function AjaxQueue( initialFunctions ){
|
|
//TODO: possibly rename to DeferredQueue
|
|
var self = this;
|
|
/** the main deferred for the entire queue - note: also sends notifications of progress */
|
|
self.deferred = jQuery.Deferred();
|
|
/** the queue array of functions */
|
|
self.queue = [];
|
|
/** cache the response from each deferred call - error or success */
|
|
self.responses = [];
|
|
/** total number of fn's to process */
|
|
self.numToProcess = 0;
|
|
/** is the queue processing/waiting for any calls to return? */
|
|
self.running = false;
|
|
|
|
self.init( initialFunctions || [] );
|
|
self.start();
|
|
|
|
return self;
|
|
}
|
|
|
|
/** add all fns in initialFunctions (if any) to the queue */
|
|
AjaxQueue.prototype.init = function init( initialFunctions ){
|
|
var self = this;
|
|
initialFunctions.forEach( function( fn ){
|
|
self.add( fn );
|
|
});
|
|
};
|
|
|
|
/** add a fn to the queue */
|
|
AjaxQueue.prototype.add = function add( fn ){
|
|
//console.debug( 'AjaxQueue.prototype.add:', fn );
|
|
var self = this,
|
|
index = this.queue.length;
|
|
this.numToProcess += 1;
|
|
|
|
this.queue.push( function(){
|
|
var xhr = fn();
|
|
// if successful, notify using the deferred to allow tracking progress
|
|
xhr.done( function( response ){
|
|
self.deferred.notify({ curr: index, total: self.numToProcess, response: response });
|
|
});
|
|
// (regardless of previous error or success) if not last ajax call, shift and call the next
|
|
// if last fn, resolve deferred
|
|
xhr.always( function( response ){
|
|
self.responses.push( response );
|
|
if( self.queue.length ){
|
|
self.queue.shift()();
|
|
} else {
|
|
self.stop();
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
/** start processing the queue */
|
|
AjaxQueue.prototype.start = function start(){
|
|
if( this.queue.length ){
|
|
this.running = true;
|
|
this.queue.shift()();
|
|
}
|
|
};
|
|
|
|
/** stop the queue
|
|
* @param {boolean} causeFail cause an error/fail on the main deferred
|
|
* @param {String} msg message to send when rejecting the main deferred
|
|
*/
|
|
AjaxQueue.prototype.stop = function stop( causeFail, msg ){
|
|
//TODO: doesn't abort current call
|
|
this.running = false;
|
|
this.queue = [];
|
|
if( causeFail ){
|
|
//TODO: spliced args instead
|
|
this.deferred.reject( msg );
|
|
} else {
|
|
this.deferred.resolve( this.responses );
|
|
}
|
|
return this;
|
|
};
|
|
|
|
// only a handful of the deferred interface for now - possible YAGNI
|
|
/** implement done from the jq deferred interface */
|
|
AjaxQueue.prototype.done = function done( fn ){
|
|
return this.deferred.done( fn );
|
|
};
|
|
/** implement fail from the jq deferred interface */
|
|
AjaxQueue.prototype.fail = function fail( fn ){
|
|
return this.deferred.fail( fn );
|
|
};
|
|
/** implement always from the jq deferred interface */
|
|
AjaxQueue.prototype.always = function always( fn ){
|
|
return this.deferred.always( fn );
|
|
};
|
|
/** implement progress from the jq deferred interface */
|
|
AjaxQueue.prototype.progress = function progress( fn ){
|
|
return this.deferred.progress( fn );
|
|
};
|
|
|
|
/** shortcut constructor / fire and forget
|
|
* @returns {Deferred} the queue's main deferred
|
|
*/
|
|
AjaxQueue.create = function create( initialFunctions ){
|
|
return new AjaxQeueue( initialFunctions ).deferred;
|
|
};
|
|
|
|
|
|
//=============================================================================
|
|
/** @class NamedAjaxQueue
|
|
* @augments AjaxQueue
|
|
* Allows associating a name with a deferring fn and prevents adding deferring
|
|
* fns if the name has already been used. Useful to prevent build up of duplicate
|
|
* async calls.
|
|
* Both the array initialFunctions sent to constructor and any added later with
|
|
* add() should be objects (NOT functions) of the form:
|
|
* { name: some unique id,
|
|
* fn: the deferring fn or ajax call }
|
|
*/
|
|
function NamedAjaxQueue( initialFunctions ){
|
|
var self = this;
|
|
self.names = {};
|
|
AjaxQueue.call( this, initialFunctions );
|
|
return self;
|
|
}
|
|
NamedAjaxQueue.prototype = new AjaxQueue();
|
|
NamedAjaxQueue.prototype.constructor = NamedAjaxQueue;
|
|
|
|
/** add the obj.fn to the queue if obj.name hasn't been used before */
|
|
NamedAjaxQueue.prototype.add = function add( obj ){
|
|
//console.debug( 'NamedAjaxQueue.prototype.add:', obj );
|
|
if( !( obj.hasOwnProperty( 'name' ) && obj.hasOwnProperty( 'fn' ) ) ){
|
|
throw new Error( 'NamedAjaxQueue.add requires an object with both "name" and "fn": ' + JSON.stringify( obj ) );
|
|
}
|
|
if( this.names.hasOwnProperty( obj.name ) ){
|
|
//console.warn( 'name has been used:', obj.name );
|
|
return;
|
|
}
|
|
this.names[ obj.name ] = true;
|
|
AjaxQueue.prototype.add.call( this, obj.fn );
|
|
};
|
|
|
|
/** shortcut constructor / fire and forget
|
|
* @returns {Deferred} the queue's main deferred
|
|
*/
|
|
NamedAjaxQueue.create = function create( initialFunctions ){
|
|
return new NamedAjaxQueue( initialFunctions ).deferred;
|
|
};
|
|
|
|
|
|
//=============================================================================
|
|
return {
|
|
AjaxQueue : AjaxQueue,
|
|
NamedAjaxQueue : NamedAjaxQueue
|
|
};
|
|
});
|