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; });