summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/js/models/utils/cc_throttle_function.js
diff options
context:
space:
mode:
Diffstat (limited to 'addons/mail/static/src/js/models/utils/cc_throttle_function.js')
-rw-r--r--addons/mail/static/src/js/models/utils/cc_throttle_function.js181
1 files changed, 181 insertions, 0 deletions
diff --git a/addons/mail/static/src/js/models/utils/cc_throttle_function.js b/addons/mail/static/src/js/models/utils/cc_throttle_function.js
new file mode 100644
index 00000000000..b4b87087e6d
--- /dev/null
+++ b/addons/mail/static/src/js/models/utils/cc_throttle_function.js
@@ -0,0 +1,181 @@
+odoo.define('mail.model.CCThrottleFunctionObject', function (require) {
+"use strict";
+
+var Class = require('web.Class');
+
+/**
+ * This object models the behaviour of the clearable and cancellable (CC)
+ * throttle version of a provided function.
+ */
+var CCThrottleFunctionObject = Class.extend({
+
+ /**
+ * @param {Object} params
+ * @param {integer} params.duration duration of the 'cooldown' phase, i.e.
+ * the minimum duration between the most recent function call that has
+ * been made and the following function call.
+ * @param {function} params.func provided function for making the CC
+ * throttled version.
+ */
+ init: function (params) {
+ this._arguments = undefined;
+ this._cooldownTimeout = undefined;
+ this._duration = params.duration;
+ this._func = params.func;
+ this._shouldCallFunctionAfterCD = false;
+ },
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * Cancel any buffered function call, but keep the cooldown phase running.
+ */
+ cancel: function () {
+ this._arguments = undefined;
+ this._shouldCallFunctionAfterCD = false;
+ },
+ /**
+ * Clear the internal throttle timer, so that the following function call
+ * is immediate. For instance, if there is a cooldown stage, it is aborted.
+ */
+ clear: function () {
+ if (this._cooldownTimeout) {
+ clearTimeout(this._cooldownTimeout);
+ this._onCooldownTimeout();
+ }
+ },
+ /**
+ * Called when there is a call to the function. This function is throttled,
+ * so the time it is called depends on whether the "cooldown stage" occurs
+ * or not:
+ *
+ * - no cooldown stage: function is called immediately, and it starts
+ * the cooldown stage when successful.
+ * - in cooldown stage: function is called when the cooldown stage has
+ * ended from timeout.
+ *
+ * Note that after the cooldown stage, only the last attempted function
+ * call will be considered.
+ */
+ do: function () {
+ this._arguments = Array.prototype.slice.call(arguments);
+ if (this._cooldownTimeout === undefined) {
+ this._callFunction();
+ } else {
+ this._shouldCallFunctionAfterCD = true;
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Immediately calls the function with arguments of last buffered function
+ * call. It initiates the cooldown stage after this function call.
+ *
+ * @private
+ */
+ _callFunction: function () {
+ this._func.apply(null, this._arguments);
+ this._cooldown();
+ },
+ /**
+ * Called when the function has been successfully called. The following
+ * calls to the function with this object should suffer a "cooldown stage",
+ * which prevents the function from being called until this stage has ended.
+ *
+ * @private
+ */
+ _cooldown: function () {
+ this.cancel();
+ this._cooldownTimeout = setTimeout(
+ this._onCooldownTimeout.bind(this),
+ this._duration
+ );
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Called when the cooldown stage ended from timeout. Calls the function if
+ * a function call was buffered.
+ *
+ * @private
+ */
+ _onCooldownTimeout: function () {
+ if (this._shouldCallFunctionAfterCD) {
+ this._callFunction();
+ } else {
+ this._cooldownTimeout = undefined;
+ }
+ },
+});
+
+return CCThrottleFunctionObject;
+
+});
+
+
+odoo.define('mail.model.CCThrottleFunction', function (require) {
+"use strict";
+
+var CCThrottleFunctionObject = require('mail.model.CCThrottleFunctionObject');
+
+/**
+ * A function that creates a cancellable and clearable (CC) throttle version
+ * of a provided function.
+ *
+ * This throttle mechanism allows calling a function at most once during a
+ * certain period:
+ *
+ * - When a function call is made, it enters a 'cooldown' phase, in which any
+ * attempt to call the function is buffered until the cooldown phase ends.
+ * - At most 1 function call can be buffered during the cooldown phase, and the
+ * latest one in this phase will be considered at its end.
+ * - When a cooldown phase ends, any buffered function call will be performed
+ * and another cooldown phase will follow up.
+ *
+ * This throttle version has the following interesting properties:
+ *
+ * - cancellable: it allows removing a buffered function call during the
+ * cooldown phase, but it keeps the cooldown phase running.
+ * - clearable: it allows to clear the internal clock of the throttled function,
+ * so that any cooldown phase is immediately ending.
+ *
+ * @param {Object} params
+ * @param {integer} params.duration a duration for the throttled behaviour,
+ * in milli-seconds.
+ * @param {function} params.func the function to throttle
+ * @returns {function} the cancellable and clearable throttle version of the
+ * provided function in argument.
+ */
+var CCThrottleFunction = function (params) {
+ var duration = params.duration;
+ var func = params.func;
+
+ var throttleFunctionObject = new CCThrottleFunctionObject({
+ duration: duration,
+ func: func,
+ });
+
+ var callable = function () {
+ return throttleFunctionObject.do.apply(throttleFunctionObject, arguments);
+ };
+ callable.cancel = function () {
+ throttleFunctionObject.cancel();
+ };
+ callable.clear = function () {
+ throttleFunctionObject.clear();
+ };
+
+ return callable;
+};
+
+return CCThrottleFunction;
+
+});