diff --git a/addons/point_of_sale/__manifest__.py b/addons/point_of_sale/__manifest__.py index c1dbc44abb4..3f1a5dad9e9 100644 --- a/addons/point_of_sale/__manifest__.py +++ b/addons/point_of_sale/__manifest__.py @@ -167,7 +167,6 @@ 'web/static/lib/jquery/jquery.js', 'web/static/lib/jquery/jquery.browser.js', 'web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js', - 'web/static/lib/qweb/qweb2.js', 'web/static/src/legacy/js/**/*', ('remove', 'web/static/src/legacy/js/libs/**/*'), ('remove', 'web/static/src/legacy/js/public/**/*'), diff --git a/addons/test_website/__manifest__.py b/addons/test_website/__manifest__.py index 02140ea3b67..963f60da096 100644 --- a/addons/test_website/__manifest__.py +++ b/addons/test_website/__manifest__.py @@ -25,7 +25,6 @@ models which only purpose is to run tests.""", 'installable': True, 'assets': { 'test_website.test_bundle': [ - '/web/static/lib/qweb/qweb2.js', 'http://test.external.link/javascript1.js', '/web/static/lib/jquery.ui/jquery-ui.css', 'http://test.external.link/style1.css', diff --git a/addons/web/__manifest__.py b/addons/web/__manifest__.py index 38643f7bf7b..fa8f24fa8ce 100644 --- a/addons/web/__manifest__.py +++ b/addons/web/__manifest__.py @@ -110,7 +110,6 @@ This module provides the core of the Odoo Web Client. 'web/static/lib/select2/select2.js', 'web/static/lib/clipboard/clipboard.js', 'web/static/lib/jSignature/jSignatureCustom.js', - 'web/static/lib/qweb/qweb2.js', 'web/static/src/legacy/js/libs/autocomplete.js', 'web/static/src/legacy/js/libs/bootstrap.js', 'web/static/src/legacy/js/libs/content-disposition.js', @@ -132,7 +131,6 @@ This module provides the core of the Odoo Web Client. 'web/static/src/legacy/js/core/dom.js', 'web/static/src/legacy/js/core/local_storage.js', 'web/static/src/legacy/js/core/mixins.js', - 'web/static/src/legacy/js/core/qweb.js', 'web/static/src/legacy/js/core/ram_storage.js', 'web/static/src/legacy/js/core/registry.js', 'web/static/src/legacy/js/core/rpc.js', @@ -307,7 +305,6 @@ This module provides the core of the Odoo Web Client. 'web/static/lib/select2/select2.js', 'web/static/lib/clipboard/clipboard.js', 'web/static/lib/jSignature/jSignatureCustom.js', - 'web/static/lib/qweb/qweb2.js', 'web/static/src/legacy/js/libs/autocomplete.js', 'web/static/src/legacy/js/libs/bootstrap.js', 'web/static/src/legacy/js/libs/content-disposition.js', @@ -329,7 +326,6 @@ This module provides the core of the Odoo Web Client. 'web/static/src/legacy/js/core/dom.js', 'web/static/src/legacy/js/core/local_storage.js', 'web/static/src/legacy/js/core/mixins.js', - 'web/static/src/legacy/js/core/qweb.js', 'web/static/src/legacy/js/core/ram_storage.js', 'web/static/src/legacy/js/core/registry.js', 'web/static/src/legacy/js/core/rpc.js', diff --git a/addons/web/static/lib/qweb/qweb-benchmark.html b/addons/web/static/lib/qweb/qweb-benchmark.html deleted file mode 100644 index 4f7fb56ac1f..00000000000 --- a/addons/web/static/lib/qweb/qweb-benchmark.html +++ /dev/null @@ -1,57 +0,0 @@ - - -
- - - - - - - -Please, check your console for results - - - - diff --git a/addons/web/static/lib/qweb/qweb-benchmark.xml b/addons/web/static/lib/qweb/qweb-benchmark.xml deleted file mode 100644 index ee977608dfc..00000000000 --- a/addons/web/static/lib/qweb/qweb-benchmark.xml +++ /dev/null @@ -1,58 +0,0 @@ - -
- ${name}
- * is specified via @t-as:
- * * ${name} The current element itself
- * * ${name}_value Same as ${name}
- * * ${name}_index The 0-based index of the current element
- * * ${name}_first Whether the current element is the first one
- * * ${name}_parity odd|even (as strings)
- * * ${name}_all The iterated collection itself
- *
- * If the collection being iterated is an array, also adds:
- * * ${name}_last Whether the current element is the last one
- * * All members of the current object
- *
- * If the collection being iterated is an object, the value is actually the object's key
- *
- * @param e ?
- * @param t_att attributes of the element being t-foreach'd
- * @param g_att ?
- * @param old_context the context in which the foreach is evaluated
- */
- render_tag_foreach:function(e, t_att, g_att, old_context) {
- var expr = t_att["foreach"];
- var enu = this.eval_object(expr, old_context);
- var ru = [];
- if (enu) {
- var val = t_att['as'] || expr.replace(/[^a-zA-Z0-9]/g, '_');
- var context = {};
- for (var i in old_context) {
- context[i] = old_context[i];
- }
- context[val + "_all"] = enu;
- var val_value = val + "_value",
- val_index = val + "_index",
- val_first = val + "_first",
- val_last = val + "_last",
- val_parity = val + "_parity";
- var size = enu.length;
- if (size) {
- context[val + "_size"] = size;
- for (var j = 0; j < size; j++) {
- var cur = enu[j];
- context[val_value] = cur;
- context[val_index] = j;
- context[val_first] = j == 0;
- context[val_last] = j + 1 == size;
- context[val_parity] = (j % 2 == 1 ? 'odd' : 'even');
- if (cur.constructor == Object) {
- for (var k in cur) {
- context[k] = cur[k];
- }
- }
- context[val] = cur;
- var r = this.render_element(e, t_att, g_att, context);
- ru.push(r);
- }
- } else {
- var index = 0;
- for (cur in enu) {
- context[val_value] = cur;
- context[val_index] = index;
- context[val_first] = index == 0;
- context[val_parity] = (index % 2 == 1 ? 'odd' : 'even');
- context[val] = cur;
- ru.push(this.render_element(e, t_att, g_att, context));
- index += 1;
- }
- }
- return ru.join("");
- } else {
- return "qweb: foreach " + expr + " not found.";
- }
- },
- hash:function() {
- var l = [], m;
- for (var i in this) {
- if (m = i.match(/render_tag_(.*)/)) {
- this.tag[m[1]] = i;
- l.push(m[1]);
- } else if (m = i.match(/render_att_(.*)/)) {
- this.att[m[1]] = i;
- l.push(m[1]);
- }
- }
- l.sort(function(a, b) {
- return a.length > b.length ? -1 : 1;
- });
- var s = "^" + this.prefix + "-(eval|" + l.join("|") + "|.*)(.*)$";
- this.reg = new RegExp(s);
- },
- /**
- * returns the correct XMLHttpRequest instance for the browser, or null if
- * it was not able to build any XHR instance.
- *
- * @returns XMLHttpRequest|MSXML2.XMLHTTP.3.0|null
- */
- get_xhr:function () {
- if (window.XMLHttpRequest) {
- return new window.XMLHttpRequest();
- }
- try {
- return new ActiveXObject('MSXML2.XMLHTTP.3.0');
- } catch(e) {
- return null;
- }
- },
- load_xml:function(s) {
- var xml;
- if (s[0] == "<") {
- /*
- manque ca pour sarrisa
- if(window.DOMParser){
- mozilla
- if(!window.DOMParser){
- var doc = Sarissa.getDomDocument();
- doc.loadXML(sXml);
- return doc;
- };
- };
- */
- } else {
- var req = this.get_xhr();
- if (req) {
- req.open("GET", s, false);
- req.send(null);
- //if ie r.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
- xml = req.responseXML;
- /*
- TODO
- if intsernetexploror
- getdomimplmentation() for try catch
- responseXML.getImplet
- d=domimple()
- d.preserverWhitespace=1
- d.loadXML()
-
- xml.preserverWhitespace=1
- xml.loadXML(r.reponseText)
- */
- return xml;
- }
- }
- },
- add_template:function(e) {
- // TODO: keep sources so we can implement reload()
- this.hash();
- if (e.constructor == String) {
- e = this.load_xml(e);
- }
-
- var ec = e.documentElement ? e.documentElement.childNodes : ( e.childNodes ? e.childNodes : [] );
-
- for (var i = 0; i < ec.length; i++) {
- var n = ec[i];
- if (n.nodeType == 1) {
- var name = n.getAttribute(this.prefix + "-name");
- this.templates[name] = n;
- }
- }
- },
- render:function(name, v) {
- var e;
- if (e = this.templates[name]) {
- return this.render_node(e, v);
- }
- return "template " + name + " not found";
- }
-};
-
diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js
deleted file mode 100644
index 5140d938b8f..00000000000
--- a/addons/web/static/lib/qweb/qweb2.js
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
-Copyright (c) 2013, Fabien Meghazi
-
-Released under the MIT license
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
-Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-// TODO: trim support
-// TODO: line number -> https://bugzilla.mozilla.org/show_bug.cgi?id=618650
-// TODO: templates orverwritten could be called by t-call="__super__" ?
-// TODO: t-set + t-value + children node == scoped variable ?
-var QWeb2 = {
- expressions_cache: { },
- RESERVED_WORDS: 'true,false,NaN,null,undefined,debugger,console,window,in,instanceof,new,function,return,this,typeof,eval,void,Math,RegExp,Array,Object,Date'.split(','),
- ACTIONS_PRECEDENCE: 'foreach,if,elif,else,call,set,tag,out,esc,raw,js,debug,log'.split(','),
- WORD_REPLACEMENT: {
- 'and': '&&',
- 'or': '||',
- 'gt': '>',
- 'gte': '>=',
- 'lt': '<',
- 'lte': '<='
- },
- VOID_ELEMENTS: 'area,base,br,col,embed,hr,img,input,keygen,link,menuitem,meta,param,source,track,wbr'.split(','),
- tools: {
- exception: function(message, context) {
- context = context || {};
- var prefix = 'QWeb2';
- if (context.template) {
- prefix += " - template['" + context.template + "']";
- }
- throw new Error(prefix + ": " + message);
- },
- warning : function(message) {
- if (typeof(window) !== 'undefined' && window.console) {
- window.console.warn(message);
- }
- },
- trim: function(s, mode) {
- switch (mode) {
- case "left":
- return s.replace(/^\s*/, "");
- case "right":
- return s.replace(/\s*$/, "");
- default:
- return s.replace(/^\s*|\s*$/g, "");
- }
- },
- js_escape: function(s, noquotes) {
- return (noquotes ? '' : "'") + s.replace(/\r?\n/g, "\\n").replace(/'/g, "\\'") + (noquotes ? '' : "'");
- },
- html_escape: function(s) {
- if (s == null) {
- return '';
- }
- return _escape(s);
- },
- markup(s) {
- return new _Markup(s);
- },
- gen_attribute: function(o) {
- if (o !== null && o !== undefined) {
- if (o.constructor === Array) {
- if (o[1] !== null && o[1] !== undefined) {
- return this.format_attribute(o[0], o[1]);
- }
- } else if (typeof o === 'object') {
- var r = '';
- for (var k in o) {
- if (o.hasOwnProperty(k)) {
- r += this.gen_attribute([k, o[k]]);
- }
- }
- return r;
- }
- }
- return '';
- },
- format_attribute: function(name, value) {
- // we want to ensure `value` is *not* a `Markup`, because markup-safe
- // strings are not necessarily attributes-safe.
- const attrvalue = value == null ? '' : this.html_escape(String(value));
- return ` ${name}="${attrvalue}"`;
- },
- extend: function(dst, src, exclude) {
- for (var p in src) {
- if (src.hasOwnProperty(p) && !(exclude && this.arrayIndexOf(exclude, p) !== -1)) {
- dst[p] = src[p];
- }
- }
- return dst;
- },
- arrayIndexOf : function(array, item) {
- for (var i = 0, ilen = array.length; i < ilen; i++) {
- if (array[i] === item) {
- return i;
- }
- }
- return -1;
- },
- get_element_sibling: function(node, dom_attr) {
- // This helper keeps support for IE8 which does not
- // implement DOMNode.(previous|next)ElementSibling
- var sibling = node[dom_attr];
- while (sibling && sibling.nodeType !== 1) {
- sibling = sibling[dom_attr];
- }
- return sibling;
- },
- xml_node_to_string : function(node, childs_only) {
- if (childs_only) {
- var childs = node.childNodes, r = [];
- for (var i = 0, ilen = childs.length; i < ilen; i++) {
- r.push(this.xml_node_to_string(childs[i]));
- }
- return r.join('');
- } else {
- // avoid XMLSerializer with text node for IE
- if (node.nodeType == 3) {
- return node.data;
- }
- if (typeof XMLSerializer !== 'undefined') {
- return (new XMLSerializer()).serializeToString(node);
- } else {
- switch(node.nodeType) {
- case 1: return node.outerHTML;
- case 4: return '';
- case 8: return '';
- }
- throw new Error('Unknown node type ' + node.nodeType);
- }
- }
- },
- call: function(context, template, old_dict, _import, callback) {
- var new_dict = this.extend({}, old_dict);
- new_dict['__caller__'] = old_dict['__template__'];
- if (callback) {
- new_dict[0] = this.markup(callback(context, new_dict));
- }
- return this.markup(context.engine._render(template, new_dict));
- },
- foreach: function(context, enu, as, old_dict, callback) {
- if (enu != null) {
- var index, jlen, cur;
- var new_dict = this.extend({}, old_dict);
- new_dict[as + "_all"] = enu;
- var as_value = as + "_value",
- as_index = as + "_index",
- as_first = as + "_first",
- as_last = as + "_last",
- as_parity = as + "_parity";
- if (enu instanceof Array) {
- var size = enu.length;
- new_dict[as + "_size"] = size;
- for (index = 0, jlen = enu.length; index < jlen; index++) {
- cur = enu[index];
- new_dict[as_value] = cur;
- new_dict[as_index] = index;
- new_dict[as_first] = index === 0;
- new_dict[as_last] = index + 1 === size;
- new_dict[as_parity] = (index % 2 == 1 ? 'odd' : 'even');
- if (cur && cur.constructor === Object) {
- this.extend(new_dict, cur);
- }
- new_dict[as] = cur;
- callback(context, new_dict);
- }
- } else if (enu.constructor == Number) {
- var _enu = [];
- for (var i = 0; i < enu; i++) {
- _enu.push(i);
- }
- this.foreach(context, _enu, as, old_dict, callback);
- } else {
- index = 0;
- for (var k in enu) {
- if (enu.hasOwnProperty(k)) {
- cur = enu[k];
- new_dict[as_value] = cur;
- new_dict[as_index] = index;
- new_dict[as_first] = index === 0;
- new_dict[as_parity] = (index % 2 == 1 ? 'odd' : 'even');
- new_dict[as] = k;
- callback(context, new_dict);
- index += 1;
- }
- }
- }
-
- Object.keys(old_dict).forEach((z) => {
- old_dict[z] = new_dict[z];
- });
- } else {
- this.exception("No enumerator given to foreach", context);
- }
- }
- }
-};
-
-QWeb2.Engine = (function() {
- function Engine() {
- // TODO: handle prefix at template level : t-prefix="x", don't forget to lowercase it
- this.prefix = 't';
- this.debug = false;
- this.templates_resources = []; // TODO: implement this.reload()
- this.templates = {};
- this.compiled_templates = {};
- this.extend_templates = {};
- this.default_dict = {};
- this.tools = QWeb2.tools;
- this.jQuery = window.jQuery;
- this.reserved_words = QWeb2.RESERVED_WORDS.slice(0);
- this.actions_precedence = QWeb2.ACTIONS_PRECEDENCE.slice(0);
- this.void_elements = QWeb2.VOID_ELEMENTS.slice(0);
- this.word_replacement = QWeb2.tools.extend({}, QWeb2.WORD_REPLACEMENT);
- this.preprocess_node = null;
- for (var i = 0; i < arguments.length; i++) {
- this.add_template(arguments[i]);
- }
- }
-
- QWeb2.tools.extend(Engine.prototype, {
- /**
- * Add a template to the engine
- *
- * @param {String|Document} template Template as string or url or DOM Document
- * @param {Function} [callback] Called when the template is loaded, force async request
- */
- add_template : function(template, callback) {
- var self = this;
- this.templates_resources.push(template);
- if (template.constructor === String) {
- return this.load_xml(template, function (err, xDoc) {
- if (err) {
- if (callback) {
- return callback(err);
- } else {
- throw err;
- }
- }
- self.add_template(xDoc, callback);
- });
- }
- template = this.preprocess(template);
- var ec = (template.documentElement && template.documentElement.childNodes) || template.childNodes || [];
- for (var i = 0; i < ec.length; i++) {
- var node = ec[i];
- if (node.nodeType === 1) {
- var name = node.getAttribute(this.prefix + '-name');
- var extend = node.getAttribute(this.prefix + '-extend');
- if (name && extend) {
- // Clone template and extend it
- if (!this.templates[extend]) {
- return this.tools.exception("Can't clone undefined template '" + extend + "' to create '" + name + "'");
- }
- this.templates[name] = this.templates[extend].cloneNode(true);
- this.extend_templates[name] = (this.extend_templates[extend] || []).slice();
- extend = name;
- name = undefined;
- }
- if (name) {
- this.templates[name] = node;
- this.compiled_templates[name] = null;
- } else if (extend) {
- delete(this.compiled_templates[extend]);
- if (this.extend_templates[extend]) {
- this.extend_templates[extend].push(node);
- } else {
- this.extend_templates[extend] = [node];
- }
- }
- }
- }
- if (callback) {
- callback(null, template);
- }
- return true;
- },
- preprocess: function(doc) {
- /**
- * Preprocess a template's document at load time.
- * This method is mostly used for template sanitization but could
- * also be overloaded for extended features such as translations, ...
- * Throws an exception if a template is invalid.
- *
- * @param {Document} doc Document containg the loaded templates
- * @return {Document} Returns the pre-processed/sanitized template
- */
- var self = this;
- var childs = (doc.documentElement && doc.documentElement.childNodes) || doc.childNodes || [];
-
- // Check for load errors
- for (var i = 0; i < childs.length; i++) {
- var node = childs[i];
- if (node.nodeType === 1 && node.nodeName == 'parsererror') {
- return this.tools.exception(node.innerText);
- }
- }
-
- // Sanitize t-elif and t-else directives
- var tbranch = doc.querySelectorAll('[t-elif], [t-else]');
- for (var i = 0, ilen = tbranch.length; i < ilen; i++) {
- var node = tbranch[i];
- var prev_elem = self.tools.get_element_sibling(node, 'previousSibling');
- var pattr = function(name) { return prev_elem.getAttribute(name); }
- var nattr = function(name) { return +!!node.getAttribute(name); }
- if (prev_elem && (pattr('t-if') || pattr('t-elif'))) {
- if (pattr('t-foreach')) {
- return self.tools.exception("Error: t-if cannot stay at the same level as t-foreach when using t-elif or t-else");
- }
- if (['t-if', 't-elif', 't-else'].map(nattr).reduce(function(a, b) { return a + b; }) > 1) {
- return self.tools.exception("Error: only one conditional branching directive is allowed per node");
- }
- // All text nodes between branch nodes are removed
- var text_node;
- while ((text_node = node.previousSibling) !== prev_elem) {
- if (text_node.nodeType !== 8 && self.tools.trim(text_node.nodeValue)) {
- return self.tools.exception("Error: text is not allowed between branching directives");
- }
- // IE <= 11.0 doesn't support ChildNode.remove
- text_node.parentNode.removeChild(text_node);
- }
- } else {
- return self.tools.exception("Error: t-elif and t-else directives must be preceded by a t-if or t-elif directive");
- }
- }
-
- return doc;
- },
- load_xml : function(s, callback) {
- var self = this;
- var async = !!callback;
- s = this.tools.trim(s);
- if (s.charAt(0) === '<') {
- var tpl = this.load_xml_string(s);
- if (callback) {
- callback(null, tpl);
- }
- return tpl;
- } else {
- var req = this.get_xhr();
- if (this.debug) {
- s += '?debug=' + (new Date()).getTime(); // TODO fme: do it properly in case there's already url parameters
- }
- req.open('GET', s, async);
- if (async) {
- req.addEventListener("load", function() {
- // 0, not being a valid HTTP status code, is used by browsers
- // to indicate success for a non-http xhr response
- // (for example, using the file:// protocol)
- // https://developer.mozilla.org/fr/docs/Web/API/XMLHttpRequest
- // https://bugzilla.mozilla.org/show_bug.cgi?id=331610
- if (req.status == 200 || req.status == 0) {
- callback(null, self._parse_from_request(req));
- } else {
- callback(new Error("Can't load template " + s + ", http status " + req.status));
- }
- });
- }
- req.send(null);
- if (!async) {
- return this._parse_from_request(req);
- }
- }
- },
- _parse_from_request: function(req) {
- var xDoc = req.responseXML;
- if (xDoc) {
- if (!xDoc.documentElement) {
- throw new Error("QWeb2: This xml document has no root document : " + xDoc.responseText);
- }
- if (xDoc.documentElement.nodeName == "parsererror") {
- throw new Error("QWeb2: Could not parse document :" + xDoc.documentElement.childNodes[0].nodeValue);
- }
- return xDoc;
- } else {
- return this.load_xml_string(req.responseText);
- }
- },
- load_xml_string : function(s) {
- if (window.DOMParser) {
- var dp = new DOMParser();
- var r = dp.parseFromString(s, "text/xml");
- if (r.body && r.body.firstChild && r.body.firstChild.nodeName == 'parsererror') {
- throw new Error("QWeb2: Could not parse document :" + r.body.innerText);
- }
- return r;
- }
- var xDoc;
- try {
- xDoc = new ActiveXObject("MSXML2.DOMDocument");
- } catch (e) {
- throw new Error("Could not find a DOM Parser: " + e.message);
- }
- xDoc.async = false;
- xDoc.preserveWhiteSpace = true;
- xDoc.loadXML(s);
- return xDoc;
- },
- has_template : function(template) {
- return !!this.templates[template];
- },
- get_xhr : function() {
- if (window.XMLHttpRequest) {
- return new window.XMLHttpRequest();
- }
- try {
- return new ActiveXObject('MSXML2.XMLHTTP.3.0');
- } catch (e) {
- throw new Error("Could not get XHR");
- }
- },
- compile : function(node) {
- var e = new QWeb2.Element(this, node);
- var template = node.getAttribute(this.prefix + '-name');
- return " /* 'this' refers to Qweb2.Engine instance */\n" +
- " var context = { engine : this, template : " + (this.tools.js_escape(template)) + " };\n" +
- " dict = dict || {};\n" +
- " dict['__template__'] = '" + template + "';\n" +
- " var r = [];\n" +
- " /* START TEMPLATE */" +
- (this.debug ? "" : " try {\n") +
- (e.compile()) + "\n" +
- " /* END OF TEMPLATE */" +
- (this.debug ? "" : " } catch(error) {\n" +
- " if (console && console.exception) console.exception(error);\n" +
- " context.engine.tools.exception('Runtime Error: ' + error, context);\n") +
- (this.debug ? "" : " }\n") +
- " return r.join('');";
- },
- render : function(template, dict) {
- dict = dict || {};
- QWeb2.tools.extend(dict, this.default_dict);
- /*if (this.debug && window['console'] !== undefined) {
- console.time("QWeb render template " + template);
- }*/
- var r = this._render(template, dict);
- /*if (this.debug && window['console'] !== undefined) {
- console.timeEnd("QWeb render template " + template);
- }*/
- return r;
- },
- _render : function(template, dict) {
- if (this.compiled_templates[template]) {
- return this.compiled_templates[template].apply(this, [dict || {}]);
- } else if (this.templates[template]) {
- var ext;
- if (ext = this.extend_templates[template]) {
- var extend_node;
- while (extend_node = ext.shift()) {
- this.extend(template, extend_node);
- }
- }
- var code = this.compile(this.templates[template]), tcompiled;
- try {
- tcompiled = new Function(['dict'], code);
- } catch (error) {
- if (this.debug && window.console) {
- console.log(code);
- }
- this.tools.exception("Error evaluating template: " + error, { template: template });
- }
- if (!tcompiled) {
- this.tools.exception("Error evaluating template: (IE?)" + error, { template: template });
- }
- this.compiled_templates[template] = tcompiled;
- return this.render(template, dict);
- } else {
- return this.tools.exception("Template '" + template + "' not found");
- }
- },
- extend : function(template, extend_node) {
- var jQuery = this.jQuery;
- if (!jQuery) {
- return this.tools.exception("Can't extend template " + template + " without jQuery");
- }
- var template_dest = this.templates[template];
- for (var i = 0, ilen = extend_node.childNodes.length; i < ilen; i++) {
- var child = extend_node.childNodes[i];
- if (child.nodeType === 1) {
- var jquery = child.getAttribute(this.prefix + '-jquery'),
- operation = child.getAttribute(this.prefix + '-operation'),
- target,
- error_msg = "Error while extending template '" + template;
- if (jquery) {
- target = jQuery(jquery, template_dest);
- if (!target.length && window.console) {
- console.error("Can't find '" + jquery + "' when extending template " + template);
- }
- } else {
- this.tools.exception(error_msg + "No expression given");
- }
- error_msg += "' (expression='" + jquery + "') : ";
- if (operation) {
- var allowed_operations = "append,prepend,before,after,replace,inner,attributes".split(',');
- if (this.tools.arrayIndexOf(allowed_operations, operation) == -1) {
- this.tools.exception(error_msg + "Invalid operation : '" + operation + "'");
- }
- operation = {'replace' : 'replaceWith', 'inner' : 'html'}[operation] || operation;
- if (operation === 'attributes') {
- jQuery('attribute', child).each(function () {
- var attrib = jQuery(this);
- target.attr(attrib.attr('name'), attrib.text() || attrib.attr('value'));
- });
- } else {
- target[operation](child.cloneNode(true).childNodes);
- }
- } else {
- try {
- var f = new Function(['$', 'document'], this.tools.xml_node_to_string(child, true));
- } catch(error) {
- return this.tools.exception("Parse " + error_msg + error);
- }
- try {
- f.apply(target, [jQuery, template_dest.ownerDocument]);
- } catch(error) {
- return this.tools.exception("Runtime " + error_msg + error);
- }
- }
- }
- }
- }
- });
- return Engine;
-})();
-
-QWeb2.Element = (function() {
- function Element(engine, node) {
- this.engine = engine;
- this.node = node;
- this.tag = node.tagName;
- this.actions = {tag: this.tag};
- this.actions_done = [];
- this.attributes = {};
- this.children = [];
- this._top = [];
- this._bottom = [];
- this._indent = 1;
- this.process_children = true;
- this.is_void_element = ~QWeb2.tools.arrayIndexOf(this.engine.void_elements, this.tag);
- var childs = this.node.childNodes;
- if (childs) {
- for (var i = 0, ilen = childs.length; i < ilen; i++) {
- this.children.push(new QWeb2.Element(this.engine, childs[i]));
- }
- }
- var attrs = this.node.attributes;
- if (attrs) {
- for (var j = 0, jlen = attrs.length; j < jlen; j++) {
- var attr = attrs[j];
- var name = attr.name;
- var m = name.match(new RegExp("^" + this.engine.prefix + "-(.+)"));
- if (m) {
- name = m[1];
- if (name === 'name') {
- continue;
- }
- if (name.match(/^attf?(-.*)?/)) {
- this.attributes[m[0]] = attr.value;
- } else {
- this.actions[name] = attr.value;
- }
- } else {
- this.attributes[name] = attr.value;
- }
- }
- }
- if (this.engine.preprocess_node) {
- this.engine.preprocess_node.call(this);
- }
- }
-
- QWeb2.tools.extend(Element.prototype, {
- compile : function() {
- var r = [],
- instring = false,
- lines = this._compile().split('\n');
- for (var i = 0, ilen = lines.length; i < ilen; i++) {
- var m, line = lines[i];
- if (m = line.match(/^(\s*)\/\/@string=(.*)/)) {
- if (instring) {
- if (this.engine.debug) {
- // Split string lines in indented r.push arguments
- r.push((m[2].indexOf("\\n") != -1 ? "',\n\t" + m[1] + "'" : '') + m[2]);
- } else {
- r.push(m[2]);
- }
- } else {
- r.push(m[1] + "r.push('" + m[2]);
- instring = true;
- }
- } else {
- if (instring) {
- r.push("');\n");
- }
- instring = false;
- r.push(line + '\n');
- }
- }
- return r.join('');
- },
- _compile : function() {
- switch (this.node.nodeType) {
- case 3:
- case 4:
- this.top_string(this.node.data);
- break;
- case 1:
- this.compile_element();
- }
- var r = this._top.join('');
- if (this.process_children) {
- for (var i = 0, ilen = this.children.length; i < ilen; i++) {
- var child = this.children[i];
- child._indent = this._indent;
- r += child._compile();
- }
- }
- r += this._bottom.join('');
- return r;
- },
- format_expression : function(e) {
- /* Naive format expression builder. Replace reserved words and variables to dict[variable]
- * Does not handle spaces before dot yet, and causes problems for anonymous functions. Use t-js="" for that */
- if (QWeb2.expressions_cache[e]) {
- return QWeb2.expressions_cache[e];
- }
- var chars = e.split(''),
- instring = '',
- invar = '',
- invar_pos = 0,
- r = '';
- chars.push(' ');
- for (var i = 0, ilen = chars.length; i < ilen; i++) {
- var c = chars[i];
- if (instring.length) {
- if (c === instring && chars[i - 1] !== "\\") {
- instring = '';
- }
- } else if (c === '"' || c === "'") {
- instring = c;
- } else if (c.match(/[a-zA-Z_\$]/) && !invar.length) {
- invar = c;
- invar_pos = i;
- continue;
- } else if (c.match(/\W/) && invar.length) {
- // TODO: Should check for possible spaces before dot
- if (chars[invar_pos - 1] !== '.' && QWeb2.tools.arrayIndexOf(this.engine.reserved_words, invar) < 0) {
- invar = this.engine.word_replacement[invar] || ("dict['" + invar + "']");
- }
- r += invar;
- invar = '';
- } else if (invar.length) {
- invar += c;
- continue;
- }
- r += c;
- }
- r = r.slice(0, -1);
- QWeb2.expressions_cache[e] = r;
- return r;
- },
- format_str: function (e) {
- if (e == '0') {
- return 'dict[0]';
- }
- return this.format_expression(e);
- },
- string_interpolation : function(s) {
- var _this = this;
- if (!s) {
- return "''";
- }
- function append_literal(s) {
- s && r.push(_this.engine.tools.js_escape(s));
- }
-
- var re = /#{(.+?)}|{{(.+?)}}/g, start = 0, r = [], m;
- while (m = re.exec(s)) {
- // extract literal string between previous and current match
- append_literal(s.slice(start, re.lastIndex - m[0].length));
- // extract matched expression
- r.push('(' + this.format_str(m[2] || m[1]) + ')');
- // update position of new matching
- start = re.lastIndex;
- }
- // remaining text after last expression
- append_literal(s.slice(start));
-
- return r.join(' + ');
- },
- indent : function() {
- return this._indent++;
- },
- dedent : function() {
- if (this._indent !== 0) {
- return this._indent--;
- }
- },
- get_indent : function() {
- return new Array(this._indent + 1).join("\t");
- },
- top : function(s) {
- return this._top.push(this.get_indent() + s + '\n');
- },
- top_string : function(s) {
- return this._top.push(this.get_indent() + "//@string=" + this.engine.tools.js_escape(s, true) + '\n');
- },
- bottom : function(s) {
- return this._bottom.unshift(this.get_indent() + s + '\n');
- },
- bottom_string : function(s) {
- return this._bottom.unshift(this.get_indent() + "//@string=" + this.engine.tools.js_escape(s, true) + '\n');
- },
- compile_element : function() {
- for (var i = 0, ilen = this.engine.actions_precedence.length; i < ilen; i++) {
- var a = this.engine.actions_precedence[i];
- if (a in this.actions) {
- var value = this.actions[a];
- var key = 'compile_action_' + a;
- if (this[key]) {
- this[key](value);
- } else if (this.engine[key]) {
- this.engine[key].call(this, value);
- } else {
- this.engine.tools.exception("No handler method for action '" + a + "'");
- }
- }
- }
- },
- compile_action_tag : function() {
- if (this.tag.toLowerCase() !== this.engine.prefix) {
- this.top_string("<" + this.tag);
- for (var a in this.attributes) {
- var v = this.attributes[a];
- var d = a.split('-');
- if (d[0] === this.engine.prefix && d.length > 1) {
- if (d.length === 2) {
- this.top("r.push(context.engine.tools.gen_attribute(" + (this.format_expression(v)) + "));");
- } else {
- this.top("r.push(context.engine.tools.gen_attribute(['" + d.slice(2).join('-') + "', (" +
- (d[1] === 'att' ? this.format_expression(v) : this.string_interpolation(v)) + ")]));");
- }
- } else {
- this.top_string(this.engine.tools.gen_attribute([a, v]));
- }
- }
-
- if (this.actions.opentag === 'true' || (!this.children.length && this.is_void_element)) {
- // We do not enforce empty content on void elements
- // because QWeb rendering is not necessarily html.
- this.top_string("/>");
- } else {
- this.top_string(">");
- this.bottom_string("" + this.tag + ">");
- }
- }
- },
- compile_action_if : function(value) {
- this.top("if (" + (this.format_expression(value)) + ") {");
- this.bottom("}");
- this.indent();
- },
- compile_action_elif : function(value) {
- this.top("else if (" + (this.format_expression(value)) + ") {");
- this.bottom("}");
- this.indent();
- },
- compile_action_else : function(value) {
- this.top("else {");
- this.bottom("}");
- this.indent();
- },
- compile_action_foreach : function(value) {
- var as = this.actions['as'] || value.replace(/[^a-zA-Z0-9]/g, '_');
- //TODO: exception if t-as not valid
- this.top("context.engine.tools.foreach(context, " + (this.format_expression(value)) + ", " + (this.engine.tools.js_escape(as)) + ", dict, function(context, dict) {");
- this.bottom("});");
- this.indent();
- },
- compile_action_call : function(value) {
- if (this.children.length === 0) {
- return this.top("r.push(context.engine.tools.call(context, " + (this.string_interpolation(value)) + ", dict));");
- } else {
- this.top("r.push(context.engine.tools.call(context, " + (this.string_interpolation(value)) + ", dict, null, function(context, dict) {");
- this.bottom("}));");
- this.indent();
- this.top("var r = [];");
- return this.bottom("return context.engine.tools.markup(r.join(''));");
- }
- },
- compile_action_set : function(value) {
- var variable = this.format_expression(value);
- if (this.actions['value']) {
- if (this.children.length) {
- this.engine.tools.warning("@set with @value plus node chidren found. Children are ignored.");
- }
- this.top(variable + " = (" + (this.format_expression(this.actions['value'])) + ");");
- this.process_children = false;
- } else {
- if (this.children.length === 0) {
- this.top(variable + " = '';");
- } else if (this.children.length === 1 && this.children[0].node.nodeType === 3) {
- this.top(variable + " = " + (this.engine.tools.js_escape(this.children[0].node.data)) + ";");
- this.process_children = false;
- } else {
- this.top(variable + " = (function(dict) {");
- this.bottom("})(dict);");
- this.indent();
- this.top("var r = [];");
- this.bottom("return context.engine.tools.markup(r.join(''));");
- }
- }
- },
- compile_action_esc : function(value) {
- return this.compile_action_out(value);
- },
- compile_action_out(value) {
- this.top("var t = " + this.format_str(value) + ";");
- this.top("if (t != null) r.push(context.engine.tools.html_escape(t));");
- this.top("else {");
- this.bottom("}");
- this.indent();
- },
- compile_action_raw : function(value) {
- let e = this.node;
- while (e.parentElement && !e.getAttribute('t-name')) {
- e = e.parentElement;
- }
- console.warn(
- "Found deprecated directive '@t-raw=\"%s\"' in "
- + "template '%s'. Replace by @t-out, and explicitely wrap content in "
- + "utils.Markup if necessary.", value, e.getAttribute('t-name'));
- this.top("var t = " + this.format_str(value) + ";");
- this.top("if (t != null) r.push(t);");
- this.top("else {");
- this.bottom("}");
- this.indent();
- },
- compile_action_js : function(value) {
- this.top("(function(" + value + ") {");
- this.bottom("})(dict);");
- this.indent();
- var lines = this.engine.tools.xml_node_to_string(this.node, true).split(/\r?\n/);
- for (var i = 0, ilen = lines.length; i < ilen; i++) {
- this.top(lines[i]);
- }
- this.process_children = false;
- },
- compile_action_debug : function(value) {
- this.top("debugger;");
- },
- compile_action_log : function(value) {
- this.top("console.log(" + this.format_expression(value) + ");");
- }
- });
- return Element;
-})();
diff --git a/addons/web/static/src/env.js b/addons/web/static/src/env.js
index f2f2e98d83d..76091cf5f02 100644
--- a/addons/web/static/src/env.js
+++ b/addons/web/static/src/env.js
@@ -12,7 +12,6 @@ import { EventBus } from "@odoo/owl";
* @typedef {Object} OdooEnv
* @property {import("services").Services} services
* @property {EventBus} bus
- * @property {QWeb} qweb
* @property {string} debug
* @property {(str: string) => string} _t
* @property {boolean} [isSmall]
diff --git a/addons/web/static/src/legacy/js/core/qweb.js b/addons/web/static/src/legacy/js/core/qweb.js
deleted file mode 100644
index a840c0cdf20..00000000000
--- a/addons/web/static/src/legacy/js/core/qweb.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/** @odoo-module **/
-
-import { uniqueId } from "@web/core/utils/functions";
-import { range } from "@web/core/utils/numbers";
-import { _t } from "@web/core/l10n/translation";
-
-/**
- * @param {boolean} debug
- * @param {Object} default_dict
- * @param {boolean} [enableTranslation=true] if true (this is the default),
- * the rendering will translate all strings that are not marked with
- * t-translation=off. This is useful for the kanban view, which uses a
- * template which is already translated by the server
- */
-function QWeb(debug, default_dict, enableTranslation) {
- if (enableTranslation === undefined) {
- enableTranslation = true;
- }
- var qweb = new QWeb2.Engine();
- qweb.default_dict = Object.assign({}, default_dict || {}, {
- // '_' : _,
- 'uniqueId': uniqueId,
- 'range' : range,
- 'JSON': JSON,
- '_t' : _t,
- '__debug__': debug,
- 'moment': function(date) { return new moment(date); },
- 'csrf_token': odoo.csrf_token,
- });
- qweb.debug = debug;
- qweb.preprocess_node = enableTranslation ? preprocess_node : function () {};
- return qweb;
-}
-
-function preprocess_node() {
- // Note that 'this' is the Qweb Node
- switch (this.node.nodeType) {
- case Node.TEXT_NODE:
- case Node.CDATA_SECTION_NODE:
- // Text and CDATAs
- var translation = this.node.parentNode.attributes['t-translation'];
- if (translation && translation.value === 'off') {
- return;
- }
- var match = /^(\s*)([\s\S]+?)(\s*)$/.exec(this.node.data);
- if (match) {
- this.node.data = match[1] + _t(match[2]) + match[3];
- }
- break;
- case Node.ELEMENT_NODE:
- // Element
- var attr, attrs = ['label', 'title', 'alt', 'placeholder', 'aria-label'];
- while ((attr = attrs.pop())) {
- if (this.attributes[attr]) {
- this.attributes[attr] = _t(this.attributes[attr]);
- }
- }
- }
-}
-
-export default QWeb;
diff --git a/addons/web/static/src/legacy/js/core/session.js b/addons/web/static/src/legacy/js/core/session.js
index 742e9754aba..abc196d942f 100644
--- a/addons/web/static/src/legacy/js/core/session.js
+++ b/addons/web/static/src/legacy/js/core/session.js
@@ -9,7 +9,6 @@ import { loadJS } from "@web/core/assets";
var _t = core._t;
-var qweb = core.qweb;
// To do: refactor session. Session accomplishes several concerns (rpc,
// configuration, currencies (wtf?), user permissions...). They should be
@@ -63,7 +62,6 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
*/
session_bind: function (origin) {
this.setup(origin);
- qweb.default_dict._s = this.origin;
this.uid = null;
this.username = null;
this.user_context= {};
diff --git a/addons/web/static/src/legacy/js/core/utils.js b/addons/web/static/src/legacy/js/core/utils.js
index b08c8d2e9f8..7bb83c84518 100644
--- a/addons/web/static/src/legacy/js/core/utils.js
+++ b/addons/web/static/src/legacy/js/core/utils.js
@@ -9,7 +9,7 @@
import translation from "@web/legacy/js/core/translation";
import { Component } from "@odoo/owl";
-import { escape, escapeHTML, escapeMethod, sprintf as str_sprtinf } from "@web/core/utils/strings";
+import { escape, escapeMethod, sprintf as str_sprtinf } from "@web/core/utils/strings";
var _t = translation._t;
var id = -1;
@@ -287,10 +287,6 @@ _Markup.prototype[escapeMethod] = function () {
return this;
}
-// exposed for qweb2.js
-window._Markup = _Markup;
-window._escape = escapeHTML;
-
/**
* Returns a markup object, which acts like a String but is considered safe by
* `escape`, and will therefore be injected as-is (without additional
diff --git a/addons/web/static/src/legacy/js/services/core.js b/addons/web/static/src/legacy/js/services/core.js
index cb629c65630..81d76e76b71 100644
--- a/addons/web/static/src/legacy/js/services/core.js
+++ b/addons/web/static/src/legacy/js/services/core.js
@@ -1,9 +1,7 @@
/** @odoo-module **/
import Bus from "@web/legacy/js/core/bus";
-import config from "@web/legacy/js/services/config";
import Class from "@web/legacy/js/core/class";
-import QWeb from "@web/legacy/js/core/qweb";
import Registry from "@web/legacy/js/core/registry";
import translation from "@web/legacy/js/core/translation";
@@ -27,13 +25,10 @@ export var bus = new Bus();
export const _t = translation._t;
export const _lt = translation._lt;
-export const qweb = new QWeb(config.isDebug());
export const serviceRegistry = new Registry();
export const csrf_token = odoo.csrf_token;
export default {
- qweb: qweb,
-
// core classes and functions
Class: Class,
bus: bus,
diff --git a/addons/web/static/tests/legacy/qweb_tests.js b/addons/web/static/tests/legacy/qweb_tests.js
deleted file mode 100644
index c2742884729..00000000000
--- a/addons/web/static/tests/legacy/qweb_tests.js
+++ /dev/null
@@ -1,191 +0,0 @@
-/** @odoo-module **/
-
-import { Markup } from "@web/legacy/js/core/utils";
-
-var qwebPath = '/web/static/lib/qweb/';
-import {hushConsole} from "@web/../tests/helpers/utils";
-import { escape, escapeMethod } from "@web/core/utils/strings";
-
-function trim(s) {
- return s.replace(/(^\s+|\s+$)/g, '');
-}
-
-/**
- * Promise-based wrapper for QWeb2.Engine#add_template
- *
- * The base version is callbacks-based which is a bit shit, and it also has
- * variable asynchronicity: it'll be async if passed a URL but not if passed
- * either a Document or an XML string.
- *
- * Either way this converts the `(error, doc)` callback to a `Promise<i>test</i>
', - "regular t-out should just escape the contents" - ); - assert.equal( - qweb.render('t-out', {value: Markup('test')}), - 'test
', - "Markup contents should not be escaped" - ); - assert.equal( - qweb.render('t-out', {value: Markup`test ${1}`}), - 'test 1
', - "markup template string should not be escaped" - ); - const teststr = 'test'; - assert.equal( - qweb.render('t-out', {value: Markup`${teststr}`}), - '<i>test</i>
', - "the markup template should not be escaped but what it uses should be" - ); - const testMarkup = Markup(teststr); - assert.equal( - qweb.render('t-out', {value: Markup`${testMarkup}`}), - 'test
', - "markupception" - ); - }); - QUnit.test("Set", async assert => { - assert.expect(4); - const qweb = new QWeb2.Engine; - await add_template(qweb, `