diff --git a/addons/bus/static/src/im_status_service.js b/addons/bus/static/src/im_status_service.js index c044c0788fd..24041f5103b 100644 --- a/addons/bus/static/src/im_status_service.js +++ b/addons/bus/static/src/im_status_service.js @@ -2,7 +2,7 @@ import { browser } from "@web/core/browser/browser"; import { registry } from "@web/core/registry"; -import { throttleForAnimation } from "@web/core/utils/timing"; +import { timings } from "@bus/misc"; export const UPDATE_BUS_PRESENCE_DELAY = 60000; /** @@ -18,7 +18,7 @@ export const imStatusService = { start(env, { bus_service, multi_tab, presence }) { const imStatusModelToIds = {}; let updateBusPresenceTimeout; - const throttledUpdateBusPresence = throttleForAnimation(function updateBusPresence() { + const throttledUpdateBusPresence = timings.throttle(function updateBusPresence() { clearTimeout(updateBusPresenceTimeout); if (!multi_tab.isOnMainTab()) { return; diff --git a/addons/bus/static/src/misc.js b/addons/bus/static/src/misc.js new file mode 100644 index 00000000000..6b4461eadb0 --- /dev/null +++ b/addons/bus/static/src/misc.js @@ -0,0 +1,65 @@ +/** @odoo-module */ + +import { browser } from "@web/core/browser/browser"; + +/** + * Returns a function, that, when invoked, will only be triggered at most once + * during a given window of time. Normally, the throttled function will run + * as much as it can, without ever going more than once per `wait` duration; + * but if you'd like to disable the execution on the leading edge, pass + * `{leading: false}`. To disable execution on the trailing edge, ditto. + * + * credit to `underscore.js` + */ +function throttle(func, wait, options) { + let timeout, context, args, result; + let previous = 0; + if (!options) { + options = {}; + } + + const later = function () { + previous = options.leading === false ? 0 : Date.now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) { + context = args = null; + } + }; + + const throttled = function () { + const _now = Date.now(); + if (!previous && options.leading === false) { + previous = _now; + } + const remaining = wait - (_now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + browser.clearTimeout(timeout); + timeout = null; + } + previous = _now; + result = func.apply(context, args); + if (!timeout) { + context = args = null; + } + } else if (!timeout && options.trailing !== false) { + timeout = browser.setTimeout(later, remaining); + } + return result; + }; + + throttled.cancel = function () { + browser.clearTimeout(timeout); + previous = 0; + timeout = context = args = null; + }; + + return throttled; +} + +export const timings = { + throttle, +}; diff --git a/addons/mail/static/tests/helpers/test_utils.js b/addons/mail/static/tests/helpers/test_utils.js index e3e0dc9ad99..c417018e0c4 100644 --- a/addons/mail/static/tests/helpers/test_utils.js +++ b/addons/mail/static/tests/helpers/test_utils.js @@ -1,6 +1,7 @@ /* @odoo-module */ import { getPyEnv } from "@bus/../tests/helpers/mock_python_environment"; +import { timings } from "@bus/misc"; import { loadEmoji } from "@web/core/emoji_picker/emoji_picker"; import { loadLamejs } from "@mail/discuss/voice_message/common/voice_message_service"; @@ -139,6 +140,10 @@ async function addSwitchTabDropdownItem(rootTarget, tabTarget) { */ export async function start(param0 = {}) { const { discuss = {}, hasTimeControl } = param0; + patchWithCleanup(timings, { + // make throttle instantaneous during tests + throttle: (func) => func, + }); const advanceTime = hasTimeControl ? getAdvanceTime() : undefined; let target = param0["target"] || getFixture(); if (param0.asTab) {