From 3751379f1e9a4c215fb6eb898b4ccc67659b9ace Mon Sep 17 00:00:00 2001 From: stephanchrst Date: Tue, 10 May 2022 21:51:50 +0700 Subject: initial commit 2 --- addons/mail/static/src/utils/utils.js | 193 ++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 addons/mail/static/src/utils/utils.js (limited to 'addons/mail/static/src/utils/utils.js') diff --git a/addons/mail/static/src/utils/utils.js b/addons/mail/static/src/utils/utils.js new file mode 100644 index 00000000..2cfaa531 --- /dev/null +++ b/addons/mail/static/src/utils/utils.js @@ -0,0 +1,193 @@ +odoo.define('mail/static/src/utils/utils.js', function (require) { +'use strict'; + +const { delay } = require('web.concurrency'); +const { + patch: webUtilsPatch, + unaccent, + unpatch: webUtilsUnpatch, +} = require('web.utils'); + +//------------------------------------------------------------------------------ +// Public +//------------------------------------------------------------------------------ + +const classPatchMap = new WeakMap(); +const eventHandledWeakMap = new WeakMap(); + +/** + * Returns the given string after cleaning it. The goal of the clean is to give + * more convenient results when comparing it to potential search results, on + * which the clean should also be called before comparing them. + * + * @param {string} searchTerm + * @returns {string} + */ +function cleanSearchTerm(searchTerm) { + return unaccent(searchTerm.toLowerCase()); +} + +/** + * Executes the provided functions in order, but with a potential delay between + * them if they take too much time. This is done in order to avoid blocking the + * main thread for too long. + * + * @param {function[]} functions + * @param {integer} [maxTimeFrame=100] time (in ms) until a delay is introduced + */ +async function executeGracefully(functions, maxTimeFrame = 100) { + let startDate = new Date(); + for (const func of functions) { + if (new Date() - startDate > maxTimeFrame) { + await new Promise(resolve => setTimeout(resolve)); + startDate = new Date(); + } + await func(); + } +} + +/** + * Returns whether the given event has been handled with the given markName. + * + * @param {Event} ev + * @param {string} markName + * @returns {boolean} + */ +function isEventHandled(ev, markName) { + if (!eventHandledWeakMap.get(ev)) { + return false; + } + return eventHandledWeakMap.get(ev).includes(markName); +} + +/** + * Marks the given event as handled by the given markName. Useful to allow + * handlers in the propagation chain to make a decision based on what has + * already been done. + * + * @param {Event} ev + * @param {string} markName + */ +function markEventHandled(ev, markName) { + if (!eventHandledWeakMap.get(ev)) { + eventHandledWeakMap.set(ev, []); + } + eventHandledWeakMap.get(ev).push(markName); +} + +/** + * Wait a task tick, so that anything in micro-task queue that can be processed + * is processed. + */ +async function nextTick() { + await delay(0); +} + +/** + * Inspired by web.utils:patch utility function + * + * @param {Class} Class + * @param {string} patchName + * @param {Object} patch + * @returns {function} unpatch function + */ +function patchClassMethods(Class, patchName, patch) { + let metadata = classPatchMap.get(Class); + if (!metadata) { + metadata = { + origMethods: {}, + patches: {}, + current: [] + }; + classPatchMap.set(Class, metadata); + } + if (metadata.patches[patchName]) { + throw new Error(`Patch [${patchName}] already exists`); + } + metadata.patches[patchName] = patch; + applyPatch(Class, patch); + metadata.current.push(patchName); + + function applyPatch(Class, patch) { + Object.keys(patch).forEach(function (methodName) { + const method = patch[methodName]; + if (typeof method === "function") { + const original = Class[methodName]; + if (!(methodName in metadata.origMethods)) { + metadata.origMethods[methodName] = original; + } + Class[methodName] = function (...args) { + const previousSuper = this._super; + this._super = original; + const res = method.call(this, ...args); + this._super = previousSuper; + return res; + }; + } + }); + } + + return () => unpatchClassMethods.bind(Class, patchName); +} + +/** + * @param {Class} Class + * @param {string} patchName + * @param {Object} patch + * @returns {function} unpatch function + */ +function patchInstanceMethods(Class, patchName, patch) { + return webUtilsPatch(Class, patchName, patch); +} + +/** + * Inspired by web.utils:unpatch utility function + * + * @param {Class} Class + * @param {string} patchName + */ +function unpatchClassMethods(Class, patchName) { + let metadata = classPatchMap.get(Class); + if (!metadata) { + return; + } + classPatchMap.delete(Class); + + // reset to original + for (let k in metadata.origMethods) { + Class[k] = metadata.origMethods[k]; + } + + // apply other patches + for (let name of metadata.current) { + if (name !== patchName) { + patchClassMethods(Class, name, metadata.patches[name]); + } + } +} + +/** + * @param {Class} Class + * @param {string} patchName + */ +function unpatchInstanceMethods(Class, patchName) { + return webUtilsUnpatch(Class, patchName); +} + +//------------------------------------------------------------------------------ +// Export +//------------------------------------------------------------------------------ + +return { + cleanSearchTerm, + executeGracefully, + isEventHandled, + markEventHandled, + nextTick, + patchClassMethods, + patchInstanceMethods, + unpatchClassMethods, + unpatchInstanceMethods, +}; + +}); -- cgit v1.2.3