visjs-network
Version:
A dynamic, browser-based network visualization library.
200 lines (178 loc) • 5.53 kB
JavaScript
/**
* 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