|
|
- /**
- * 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;
|