@qooxdoo/framework
Version:
The JS Framework for Coders
157 lines (130 loc) • 4.42 kB
JavaScript
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
License:
MIT: https://opensource.org/licenses/MIT
See the LICENSE file in the project's top-level directory for details.
Authors:
* Sebastian Werner (wpbasti)
* Fabian Jakobs (fjakobs)
************************************************************************ */
/**
* This class manages the timer used for deferred calls. All
* {@link qx.util.DeferredCall} instances use the single timer from this class.
*
* NOTE: Instances of this class must be disposed of after use
*
*/
qx.Class.define("qx.util.DeferredCallManager", {
extend: qx.core.Object,
type: "singleton",
implement: [qx.core.IDisposable],
/*
*****************************************************************************
CONSTRUCTOR
*****************************************************************************
*/
construct() {
this.__calls = {};
this.__timeoutWrapper = qx.lang.Function.bind(this.__timeout, this);
this.__hasCalls = false;
},
/*
*****************************************************************************
MEMBERS
*****************************************************************************
*/
members: {
__timeoutId: null,
__currentQueue: null,
__calls: null,
__hasCalls: null,
__timeoutWrapper: null,
/**
* Schedule a deferred call
*
* @param deferredCall {qx.util.DeferredCall} The call to schedule
*/
schedule(deferredCall) {
if (this.__timeoutId == null) {
this.__timeoutId = window.setTimeout(this.__timeoutWrapper, 0);
}
var callKey = deferredCall.toHashCode();
// the flush is currently running and the call is already
// scheduled
if (this.__currentQueue && this.__currentQueue[callKey]) {
return;
}
this.__calls[callKey] = deferredCall;
this.__hasCalls = true;
},
/**
* Refresh the timeout if the current one is not active anymore.
* This is a very special case which can happen in unit tests using
* fakeTimers, which overrides the window.setTimeout function (amongst others)
* after restoring the sinon sandbox the timeout must be refreshed otherwise
* DeferredCalls would never fire.
*/
refreshTimeout() {
if (this.__timeoutId !== null) {
this.__timeoutId = window.setTimeout(this.__timeoutWrapper, 0);
}
},
/**
* Cancel a scheduled deferred call
*
* @param deferredCall {qx.util.DeferredCall} The call to schedule
*/
cancel(deferredCall) {
var callKey = deferredCall.toHashCode();
// the flush is currently running and the call is already
// scheduled -> remove it from the current queue
if (this.__currentQueue && this.__currentQueue[callKey]) {
this.__currentQueue[callKey] = null;
return;
}
delete this.__calls[callKey];
// stop timer if no other calls are waiting
if (qx.lang.Object.isEmpty(this.__calls) && this.__timeoutId != null) {
window.clearTimeout(this.__timeoutId);
this.__timeoutId = null;
}
},
/**
* Helper function for the timer.
*
* @signature function()
*/
__timeout: qx.event.GlobalError.observeMethod(function () {
this.__timeoutId = null;
// the queue may change while doing the flush so we work on a copy of
// the queue and loop while the queue has any entries.
while (this.__hasCalls) {
this.__currentQueue = qx.lang.Object.clone(this.__calls);
this.__calls = {};
this.__hasCalls = false;
for (var key in this.__currentQueue) {
var call = this.__currentQueue[key];
if (call) {
this.__currentQueue[key] = null;
call.call();
}
}
}
this.__currentQueue = null;
})
},
/*
*****************************************************************************
DESTRUCTOR
*****************************************************************************
*/
destruct() {
if (this.__timeoutId != null) {
window.clearTimeout(this.__timeoutId);
}
this.__timeoutWrapper = this.__calls = null;
}
});