| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 | /** * A queue * @param {Object} options *            Available options: *            - delay: number    When provided, the queue will be flushed *                               automatically after an inactivity of this delay *                               in milliseconds. *                               Default value is null. *            - max: number      When the queue exceeds the given maximum number *                               of entries, the queue is flushed automatically. *                               Default value of max is Infinity. * @constructor Queue */function Queue(options) {  // options  this.delay = null;  this.max = Infinity;  // properties  this._queue = [];  this._timeout = null;  this._extended = null;  this.setOptions(options);}/** * Update the configuration of the queue * @param {Object} options *            Available options: *            - delay: number    When provided, the queue will be flushed *                               automatically after an inactivity of this delay *                               in milliseconds. *                               Default value is null. *            - max: number      When the queue exceeds the given maximum number *                               of entries, the queue is flushed automatically. *                               Default value of max is Infinity. */Queue.prototype.setOptions = function (options) {  if (options && typeof options.delay !== 'undefined') {    this.delay = options.delay;  }  if (options && typeof options.max !== 'undefined') {    this.max = options.max;  }  this._flushIfNeeded();};/** * Extend an object with queuing functionality. * The object will be extended with a function flush, and the methods provided * in options.replace will be replaced with queued ones. * @param {Object} object * @param {Object} options *            Available options: *            - replace: Array.<string> *                               A list with method names of the methods *                               on the object to be replaced with queued ones. *            - delay: number    When provided, the queue will be flushed *                               automatically after an inactivity of this delay *                               in milliseconds. *                               Default value is null. *            - max: number      When the queue exceeds the given maximum number *                               of entries, the queue is flushed automatically. *                               Default value of max is Infinity. * @return {Queue} Returns the created queue */Queue.extend = function (object, options) {  var queue = new Queue(options);  if (object.flush !== undefined) {    throw new Error('Target object already has a property flush');  }  object.flush = function () {    queue.flush();  };  var methods = [{    name: 'flush',    original: undefined  }];  if (options && options.replace) {    for (var i = 0; i < options.replace.length; i++) {      var name = options.replace[i];      methods.push({        name: name,        original: object[name]      });      queue.replace(object, name);    }  }  queue._extended = {    object: object,    methods: methods  };  return queue;};/** * Destroy the queue. The queue will first flush all queued actions, and in * case it has extended an object, will restore the original object. */Queue.prototype.destroy = function () {  this.flush();  if (this._extended) {    var object = this._extended.object;    var methods = this._extended.methods;    for (var i = 0; i < methods.length; i++) {      var method = methods[i];      if (method.original) {        object[method.name] = method.original;      }      else {        delete object[method.name];      }    }    this._extended = null;  }};/** * Replace a method on an object with a queued version * @param {Object} object   Object having the method * @param {string} method   The method name */Queue.prototype.replace = function(object, method) {  var me = this;  var original = object[method];  if (!original) {    throw new Error('Method ' + method + ' undefined');  }  object[method] = function () {    // create an Array with the arguments    var args = [];    for (var i = 0; i < arguments.length; i++) {      args[i] = arguments[i];    }    // add this call to the queue    me.queue({      args: args,      fn: original,      context: this    });  };};/** * Queue a call * @param {function | {fn: function, args: Array} | {fn: function, args: Array, context: Object}} entry */Queue.prototype.queue = function(entry) {  if (typeof entry === 'function') {    this._queue.push({fn: entry});  }  else {    this._queue.push(entry);  }  this._flushIfNeeded();};/** * Check whether the queue needs to be flushed * @private */Queue.prototype._flushIfNeeded = function () {  // flush when the maximum is exceeded.  if (this._queue.length > this.max) {    this.flush();  }  // flush after a period of inactivity when a delay is configured  clearTimeout(this._timeout);  if (this.queue.length > 0 && typeof this.delay === 'number') {    var me = this;    this._timeout = setTimeout(function () {      me.flush();    }, this.delay);  }};/** * Flush all queued calls */Queue.prototype.flush = function () {  while (this._queue.length > 0) {    var entry = this._queue.shift();    entry.fn.apply(entry.context || entry.fn, entry.args || []);  }};module.exports = Queue;
 |