diff options
Diffstat (limited to 'addons/web/static/src')
| -rw-r--r-- | addons/web/static/src/js/component_extension.js | 21 | ||||
| -rw-r--r-- | addons/web/static/src/js/core/session.js | 8 | ||||
| -rw-r--r-- | addons/web/static/src/js/core/utils.js | 75 | ||||
| -rw-r--r-- | addons/web/static/src/js/env.js | 86 | ||||
| -rw-r--r-- | addons/web/static/src/js/main.js | 27 | ||||
| -rw-r--r-- | addons/web/static/src/js/public/public_env.js | 24 |
6 files changed, 240 insertions, 1 deletions
diff --git a/addons/web/static/src/js/component_extension.js b/addons/web/static/src/js/component_extension.js new file mode 100644 index 00000000000..39568bd0594 --- /dev/null +++ b/addons/web/static/src/js/component_extension.js @@ -0,0 +1,21 @@ +/** + * Add a new method to owl Components to ensure that no performed RPC is + * resolved/rejected when the component is destroyed. + */ +(function () { + owl.Component.prototype.rpc = function () { + return new Promise((resolve, reject) => { + return this.env.services.rpc(...arguments) + .then(result => { + if (!this.__owl__.isDestroyed) { + resolve(result); + } + }) + .catch(reason => { + if (!this.__owl__.isDestroyed) { + reject(reason); + } + }); + }); + }; +})(); diff --git a/addons/web/static/src/js/core/session.js b/addons/web/static/src/js/core/session.js index 4c8a63dbdb5..a8159469145 100644 --- a/addons/web/static/src/js/core/session.js +++ b/addons/web/static/src/js/core/session.js @@ -4,7 +4,6 @@ odoo.define('web.Session', function (require) { var ajax = require('web.ajax'); var concurrency = require('web.concurrency'); var core = require('web.core'); -var local_storage = require('web.local_storage'); var mixins = require('web.mixins'); var utils = require('web.utils'); @@ -239,7 +238,14 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, { var route = '/web/webclient/qweb/' + (cacheId ? cacheId : Date.now()) + '?mods=' + mods; return $.get(route).then(function (doc) { if (!doc) { return; } + const owlTemplates = []; + for (let child of doc.querySelectorAll("templates > [owl]")) { + child.removeAttribute('owl'); + owlTemplates.push(child.outerHTML); + child.remove(); + } qweb.add_template(doc); + self.owlTemplates = `<templates> ${owlTemplates.join('\n')} </templates>`; }); }); return lock; diff --git a/addons/web/static/src/js/core/utils.js b/addons/web/static/src/js/core/utils.js index 29c2ff04c40..4fe1740d6eb 100644 --- a/addons/web/static/src/js/core/utils.js +++ b/addons/web/static/src/js/core/utils.js @@ -203,7 +203,10 @@ var diacriticsMap = { '\u0225': 'z','\u0240': 'z','\u2C6C': 'z','\uA763': 'z', }; +const patchMap = new WeakMap(); + var utils = { + /** * Throws an error if the given condition is not true * @@ -511,6 +514,51 @@ var utils = { return new Array(size - str.length + 1).join('0') + str; }, /** + * Patch a class and return a function that remove the patch + * when called. + * + * @param {Class} C Class to patch + * @param {string} patchName + * @param {Object} patch + * @returns {Function} + */ + patch: function(C, patchName, patch) { + let metadata = patchMap.get(C.prototype); + if (!metadata) { + metadata = { + origMethods: {}, + patches: {}, + current: [] + }; + patchMap.set(C.prototype, metadata); + } + const proto = C.prototype; + if (metadata.patches[patchName]) { + throw new Error(`Patch [${patchName}] already exists`); + } + metadata.patches[patchName] = patch; + applyPatch(proto, patch); + metadata.current.push(patchName); + + function applyPatch(proto, patch) { + Object.keys(patch).forEach(function (methodName) { + const method = patch[methodName]; + if (typeof method === "function") { + const original = proto[methodName]; + if (!(methodName in metadata.origMethods)) { + metadata.origMethods[methodName] = original; + } + proto[methodName] = function (...args) { + this._super = original; + return method.call(this, ...args); + }; + } + }); + } + + return this.unpatch.bind(null, C, patchName); + }, + /** * performs a half up rounding with a fixed amount of decimals, correcting for float loss of precision * See the corresponding float_round() in server/tools/float_utils.py for more info * @param {Number} value the value to be rounded @@ -662,6 +710,33 @@ var utils = { return casesensetive ? str : str.toLowerCase(); }, /** + * We define here an unpatch function. This is mostly useful if we want to + * remove a patch. For example, for testing purposes + * + * @param {Class} C + * @param {string} patchName + */ + unpatch: function(C, patchName) { + const proto = C.prototype; + let metadata = patchMap.get(proto); + if (!metdata) { + return; + } + patchMap.delete(proto); + + // reset to original + for (let k in metadata.origMethods) { + proto[k] = metadata.origMethods[k]; + } + + // apply other patches + for (let name of metadata.current) { + if (name !== patchName) { + this.patch(C, name, metadata.patches[name]); + } + } + }, + /** * @param {any} node * @param {any} strip_whitespace * @returns diff --git a/addons/web/static/src/js/env.js b/addons/web/static/src/js/env.js new file mode 100644 index 00000000000..c223fcc91ee --- /dev/null +++ b/addons/web/static/src/js/env.js @@ -0,0 +1,86 @@ +odoo.define("web.env", function (require) { + "use strict"; + + const { _lt, _t, bus } = require("web.core"); + const { blockUI, unblockUI } = require("web.framework"); + const { device, isDebug } = require("web.config"); + const { jsonRpc } = require('web.ajax'); + const rpc = require("web.rpc"); + const session = require("web.session"); + const utils = require("web.utils"); + + + const qweb = new owl.QWeb({ translateFn: _t }); + + function ajaxJsonRPC() { + return jsonRpc(...arguments); + } + + function getCookie() { + return utils.get_cookie(...arguments); + } + + function httpRequest(route, params = {}, readMethod = 'json') { + const formData = new FormData(); + for (const key in params) { + if (key === 'method') { + continue; + } + const value = params[key]; + if (Array.isArray(value) && value.length) { + for (const val of value) { + formData.append(key, val); + } + } else { + formData.append(key, value); + } + } + + return fetch(route, { + method: params.method || 'POST', + body: formData, + }).then(response => response[readMethod]()); + } + + function navigate(url, params) { + window.location = $.param.querystring(url, params); + } + + function performRPC(params, options) { + const query = rpc.buildQuery(params); + return session.rpc(query.route, query.params, options); + } + + function reloadPage() { + window.location.reload(); + } + + function setCookie() { + utils.set_cookie(...arguments); + } + + // There should be as much dependencies as possible in the env object. + // This will allow an easier testing of components. + // See https://github.com/odoo/owl/blob/master/doc/reference/environment.md#content-of-an-environment + // for more information on environments. + return { + _lt, + _t, + bus, + device, + isDebug, + qweb, + services: { + ajaxJsonRPC, + blockUI, + getCookie, + httpRequest, + navigate, + reloadPage, + rpc: performRPC, + setCookie, + unblockUI, + }, + session, + }; +}); diff --git a/addons/web/static/src/js/main.js b/addons/web/static/src/js/main.js new file mode 100644 index 00000000000..35f00254ba8 --- /dev/null +++ b/addons/web/static/src/js/main.js @@ -0,0 +1,27 @@ +odoo.define('web.web_client', function (require) { + + const env = require('web.env'); + const session = require("web.session"); + const WebClient = require('web.WebClient'); + + owl.config.mode = env.isDebug() ? "dev" : "prod"; + owl.Component.env = env; + + const webClient = new WebClient(); + + /** + * Add the owl templates to the environment and start the web client. + */ + async function startWebClient() { + await session.is_bound; + env.qweb.addTemplates(session.owlTemplates); + + await owl.utils.whenReady(); + webClient.setElement($(document.body)); + webClient.start(); + } + + startWebClient(); + + return webClient; +}); diff --git a/addons/web/static/src/js/public/public_env.js b/addons/web/static/src/js/public/public_env.js new file mode 100644 index 00000000000..373c7b512b8 --- /dev/null +++ b/addons/web/static/src/js/public/public_env.js @@ -0,0 +1,24 @@ +odoo.define("web.public_env", function (require) { + "use strict"; + + const { _t } = require("web.core"); + const rpc = require("web.rpc"); + + const qweb = new owl.QWeb({ translateFn: _t }); + + function performRPC(params, options) { + const query = rpc.buildQuery(params); + return session.rpc(query.route, query.params, options); + } + + // There should be as much dependencies as possible in the env object. + // This will allow an easier testing of components. + // See https://github.com/odoo/owl/blob/master/doc/reference/environment.md#content-of-an-environment + // for more information on environments. + return { + qweb, + services: { + rpc: performRPC, + }, + }; +}); |
