From 4b0a951af690b8c10aafebcd0ed9ed94a0ba1463 Mon Sep 17 00:00:00 2001 From: Jorge Pinna Puissant Date: Tue, 8 Aug 2023 08:36:07 +0000 Subject: [PATCH] [REM] remove qweb library Part of task~3443861 Part-of: odoo/odoo#130467 --- addons/point_of_sale/__manifest__.py | 1 - addons/test_website/__manifest__.py | 1 - addons/web/__manifest__.py | 4 - .../web/static/lib/qweb/qweb-benchmark.html | 57 -- addons/web/static/lib/qweb/qweb-benchmark.xml | 58 -- .../static/lib/qweb/qweb-test-attributes.xml | 83 -- addons/web/static/lib/qweb/qweb-test-call.xml | 84 -- .../lib/qweb/qweb-test-conditionals.xml | 68 -- .../web/static/lib/qweb/qweb-test-extend.xml | 62 -- .../web/static/lib/qweb/qweb-test-foreach.xml | 46 - .../web/static/lib/qweb/qweb-test-global.xml | 54 -- .../web/static/lib/qweb/qweb-test-output.xml | 47 - addons/web/static/lib/qweb/qweb-test-set.xml | 62 -- .../static/lib/qweb/qweb-test-utf8tags.xml | 8 - .../web/static/lib/qweb/qweb-test-widgets.xml | 26 - addons/web/static/lib/qweb/qweb-test.js.html | 73 -- addons/web/static/lib/qweb/qweb.js | 435 --------- addons/web/static/lib/qweb/qweb2.js | 874 ------------------ addons/web/static/src/env.js | 1 - addons/web/static/src/legacy/js/core/qweb.js | 61 -- .../web/static/src/legacy/js/core/session.js | 2 - addons/web/static/src/legacy/js/core/utils.js | 6 +- .../web/static/src/legacy/js/services/core.js | 5 - addons/web/static/tests/legacy/qweb_tests.js | 191 ---- addons/web/tooling/_eslintrc.json | 1 - .../static/src/js/wysiwyg/wysiwyg_iframe.js | 5 - addons/website_slides/__manifest__.py | 2 - odoo/addons/test_lint/tests/eslintrc | 1 - 28 files changed, 1 insertion(+), 2317 deletions(-) delete mode 100644 addons/web/static/lib/qweb/qweb-benchmark.html delete mode 100644 addons/web/static/lib/qweb/qweb-benchmark.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test-attributes.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test-call.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test-conditionals.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test-extend.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test-foreach.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test-global.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test-output.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test-set.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test-utf8tags.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test-widgets.xml delete mode 100644 addons/web/static/lib/qweb/qweb-test.js.html delete mode 100644 addons/web/static/lib/qweb/qweb.js delete mode 100644 addons/web/static/lib/qweb/qweb2.js delete mode 100644 addons/web/static/src/legacy/js/core/qweb.js delete mode 100644 addons/web/static/tests/legacy/qweb_tests.js 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 @@ - - -
-
- x -

title

-

text

-
-
- x - -

title

-

text

-
-
- - d.iter = 'one,two,three,four,five'.split(',') - - - - + - - - 1 - true -
-
- - height: 200px; border: 1px solid red; -
- - * : - - Ok this is good ! - Hi there! - [] - - - () - -
-
-
- x -

title

-

text

-
-
- - -
- x - -

Here's your value : () !!

-
-
- - diff --git a/addons/web/static/lib/qweb/qweb-test-attributes.xml b/addons/web/static/lib/qweb/qweb-test-attributes.xml deleted file mode 100644 index e9f92a34ae7..00000000000 --- a/addons/web/static/lib/qweb/qweb-test-attributes.xml +++ /dev/null @@ -1,83 +0,0 @@ - - -
- -
]]> - - - Test - - ]]> - - -
- -
]]> - - -
- - {"value": "ok"} -
]]> - - -
- -
]]> - - -
- - {"value": ["foo", "bar"]} -
]]> - - -
- - {"value": {"a": 1, "b": 2, "c": 3}} -
]]> - - -
- -
]]> - - -
- - {"value": "a"} -
]]> - - -
- - {"value": 5} -
]]> - - -
- - { - "value1": 0, - "value2": 1, - "value3": 2 - } -
- ]]> - - -
- - ", - "baz": "\"\"", - "qux": {"qux": "<>"} - }]]> -
- ]]> -
diff --git a/addons/web/static/lib/qweb/qweb-test-call.xml b/addons/web/static/lib/qweb/qweb-test-call.xml deleted file mode 100644 index 888026291d5..00000000000 --- a/addons/web/static/lib/qweb/qweb-test-call.xml +++ /dev/null @@ -1,84 +0,0 @@ - - ok - - - - - - - ok - - - WHEEE - - ok - - - - - - - ok - - - ok - - ok - - - - - - - ok - - -
- - - - - -
]]> - - - -
-
-
- - {"value": "ok"} - - -
ok
- ]]>
- - - - - - - 1 - - - - - - - - - - ok - - - - - - ok -
diff --git a/addons/web/static/lib/qweb/qweb-test-conditionals.xml b/addons/web/static/lib/qweb/qweb-test-conditionals.xml deleted file mode 100644 index f4b95b697da..00000000000 --- a/addons/web/static/lib/qweb/qweb-test-conditionals.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - ok - - {"condition": true} - ok - - - fail - - {"condition": false} - - - - fail - - - - - black pearl - yellow submarine - red is dead - beer - - {"color": "red"} - red is dead - - -
beginok - ok-elseend
-
- {"condition": true} - beginokend
]]> - - -
beginfail - fail-elseend
-
- {"condition": false} - beginfail-elseend
]]> - - - if - elif1 - - elif2 - else - - {"condition": "elif1"} - - - - if - elif1 - - elif2 - else - - {"condition": "elif2"} - - - -
if
sometext
-
- {"condition": "if"} - if
sometext
]]>
- -
diff --git a/addons/web/static/lib/qweb/qweb-test-extend.xml b/addons/web/static/lib/qweb/qweb-test-extend.xml deleted file mode 100644 index f8a24c4ef8e..00000000000 --- a/addons/web/static/lib/qweb/qweb-test-extend.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - -
  • one
-
- -
  • 3
  • -
    - -
  • 2
  • -
    - -
  • 1
  • -
    -
    -
    - - this.attr('class', 'main'); - - - - - - main-ul - - -
    -
    - - [[end]] - -
    • 1
    • 2
    • 3
    [[end]]
    -]]>
    - - -
  • [[cloned template]]
  • -
    -
    • 1
    • 2
    • 3
    • [[cloned template]]
    [[end]]
    -]]>
    - - - -
    Hi
    -
    - - World - - - Hello - - Hi -]]> - HiWorld -]]> - HelloWorld -]]> -
    diff --git a/addons/web/static/lib/qweb/qweb-test-foreach.xml b/addons/web/static/lib/qweb/qweb-test-foreach.xml deleted file mode 100644 index 9a1e8ecb7ba..00000000000 --- a/addons/web/static/lib/qweb/qweb-test-foreach.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - -[: ] - - -[0: 3 3] -[1: 2 2] -[2: 1 1] - - - - -- first last () - - -- first (even) -- (odd) -- (even) -- (odd) -- last (even) - - - - - -[: ] - - -[0: 0 0] -[1: 1 1] -[2: 2 2] - - - - - -[: - ] - - {"value": {"a": 1, "b": 2, "c": 3}} - -[0: a 1 - even] -[1: b 2 - odd] -[2: c 3 - even] - - diff --git a/addons/web/static/lib/qweb/qweb-test-global.xml b/addons/web/static/lib/qweb/qweb-test-global.xml deleted file mode 100644 index 8bdefc6ab44..00000000000 --- a/addons/web/static/lib/qweb/qweb-test-global.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - foo default -
    toto default
    - - - - - - - - - - - - - - - i - - - - 4 - - aaa - foo default - - bbb - - - 5 - - aaa - foo default - - bbb - - - 6 - - aaa - foo default - - bbb - - -
    toto default
    - -
    i
    - ]]> -
    diff --git a/addons/web/static/lib/qweb/qweb-test-output.xml b/addons/web/static/lib/qweb/qweb-test-output.xml deleted file mode 100644 index 91f7a2e638a..00000000000 --- a/addons/web/static/lib/qweb/qweb-test-output.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - ok - - - - - {"var": "ok"} - ok - - - - - "}]]> - - - - - ok]]> - - - - - - - ok - - - - - 1 - - - - - {"var": "ok"} - ok - - - - - "}]]> - ]]> - diff --git a/addons/web/static/lib/qweb/qweb-test-set.xml b/addons/web/static/lib/qweb/qweb-test-set.xml deleted file mode 100644 index 5d4c0301f9c..00000000000 --- a/addons/web/static/lib/qweb/qweb-test-set.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - ok - - - - ok - - - - ok - - - - - - - - {"value": "ok"} - - - ok - - - - - - - - - - {"value": "ok"} - - - ok - - - -
    - - - - {"value": "ok"} - - ok]]> - - - - - - - - - 2 - - - 1 -
    diff --git a/addons/web/static/lib/qweb/qweb-test-utf8tags.xml b/addons/web/static/lib/qweb/qweb-test-utf8tags.xml deleted file mode 100644 index dd51635bab2..00000000000 --- a/addons/web/static/lib/qweb/qweb-test-utf8tags.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - ]]> - diff --git a/addons/web/static/lib/qweb/qweb-test-widgets.xml b/addons/web/static/lib/qweb/qweb-test-widgets.xml deleted file mode 100644 index 503880bcc34..00000000000 --- a/addons/web/static/lib/qweb/qweb-test-widgets.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - {"value": "1988-09-16"} - 1988-09-16 - - - {"value": "1988-09-16 14:00:00"} - 1988-09-16 14:00:00 - - - {"value": "1988-09-16 14:00:00"} - 09/16/1988 16:00:00 - - - {"value": "1988-09-16 14:00:00"} - 09/16/1988 - - - {"value": "1988-09-16 01:00:00"} - 09/16/1988 - - - {"value": "1988-09-16 23:00:00"} - 09/17/1988 - - diff --git a/addons/web/static/lib/qweb/qweb-test.js.html b/addons/web/static/lib/qweb/qweb-test.js.html deleted file mode 100644 index 0ee5f27c3bd..00000000000 --- a/addons/web/static/lib/qweb/qweb-test.js.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - -
    -
    - - diff --git a/addons/web/static/lib/qweb/qweb.js b/addons/web/static/lib/qweb/qweb.js deleted file mode 100644 index cd65248589e..00000000000 --- a/addons/web/static/lib/qweb/qweb.js +++ /dev/null @@ -1,435 +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. -*/ - -//--------------------------------------------------------- -// QWeb javascript -//--------------------------------------------------------- - -/* - TODO - - String parsing - if (window.DOMParser) { - parser=new DOMParser(); - xmlDoc=parser.parseFromString(text,"text/xml"); - } else { - xmlDoc=new ActiveXObject("Msxml2.DOMDocument.4.0"); - xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); - Which versions to try, it's confusing... - xmlDoc.async="false"; - xmlDoc.async=false; - xmlDoc.preserveWhiteSpace=true; - xmlDoc.load("f.xml"); - xmlDoc.loadXML(text); ? - } - - Support space in IE by reparsing the responseText - xmlhttp.responseXML.loadXML(xmlhttp.responseText); ? - - Preprocess: (nice optimization) - preprocess by flattening all non t- element to a TEXT_NODE. - count the number of "\n" in text nodes to give an aproximate LINE NUMBER on elements for error reporting - if from IE HTMLDOM use if(a[i].specified) to avoid 88 empty attributes per element during the preprocess, - - implement t-trim 'left' 'right' 'both', is it needed ? inner=render_trim(l_inner.join(), t_att) - - Ruby/python: to backport from javascript to python/ruby render_node to use regexp, factorize foreach %var, t-att test for tuple(attname,value) - - DONE - we reintroduced t-att-id, no more t-esc-id because of the new convention t-att="["id","val"]" -*/ - -var QWeb = { - templates:{}, - prefix:"t", - reg:new RegExp(), - tag:{}, - att:{}, - ValueException: function (value, message) { - this.value = value; - this.message = message; - }, - eval_object:function(e, v) { - // TODO: Currently this will also replace and, or, ... in strings. Try - // 'hi boys and girls' != '' and 1 == 1 -- will be replaced to : 'hi boys && girls' != '' && 1 == 1 - // try to find a solution without tokenizing - e = '(' + e + ')'; - e = e.replace(/\band\b/g, " && "); - e = e.replace(/\bor\b/g, " || "); - e = e.replace(/\bgt\b/g, " > "); - e = e.replace(/\bgte\b/g, " >= "); - e = e.replace(/\blt\b/g, " < "); - e = e.replace(/\blte\b/g, " <= "); - if (v[e] != undefined) { - return v[e]; - } else { - with (v) return eval(e); - } - }, - eval_str:function(e, v) { - var r = this.eval_object(e, v); - r = (typeof(r) == "undefined" || r == null) ? "" : r.toString(); - return e == "0" ? v["0"] : r; - }, - eval_format:function(e, v) { - var m, src = e.split(/#/), r = src[0]; - for (var i = 1; i < src.length; i++) { - if (m = src[i].match(/^{(.*)}(.*)/)) { - r += this.eval_str(m[1], v) + m[2]; - } else { - r += "#" + src[i]; - } - } - return r; - }, - eval_bool:function(e, v) { - return !!this.eval_object(e, v); - }, - trim : function(v, mode) { - if (!v || !mode) return v; - switch (mode) { - case 'both': - return v.replace(/^\s*|\s*$/g, ""); - case "left": - return v.replace(/^\s*/, ""); - case "right": - return v.replace(/\s*$/, ""); - } - throw new QWeb.ValueException( - mode, "unknown trimming mode, trim mode must follow the pattern '[inner] (left|right|both)'"); - }, - escape_text:function(s) { - return s.replace(/&/g, "&").replace(//g, ">"); - }, - escape_att:function(s) { - return s.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); - }, - render_node : function(e, v, inner_trim) { - if (e.nodeType == 3) { - return inner_trim ? this.trim(e.data, inner_trim) : e.data; - } - if (e.nodeType == 1) { - var g_att = {}; - var t_att = {}; - var t_render = null; - var a = e.attributes; - for (var i = 0; i < a.length; i++) { - var an = a[i].name,av = a[i].value; - var m; - if (m = an.match(this.reg)) { - var n = m[1]; - if (n == "eval") { - n = m[2].substring(1); - av = this.eval_str(av, v); - } - var f; - if (f = this.att[n]) { - this[f](e, t_att, g_att, v, m[2], av); - } else if (f = this.tag[n]) { - t_render = f; - } - t_att[n] = av; - } else { - g_att[an] = av; - } - } - if (inner_trim && !t_att["trim"]) { - t_att["trim"] = "inner " + inner_trim; - } - if (t_render) { - return this[t_render](e, t_att, g_att, v); - } - return this.render_element(e, t_att, g_att, v); - } - return ""; - }, - render_element:function(e, t_att, g_att, v) { - var inner = "", ec = e.childNodes, trim = t_att["trim"], inner_trim; - if (trim) { - if (/\binner\b/.test(trim)) { - inner_trim = true; - if (trim == 'inner') { - trim = "both"; - } - } - var tm = /\b(both|left|right)\b/.exec(trim); - if (tm) trim = tm[1]; - } - for (var i = 0; i < ec.length; i++) { - inner += inner_trim ? this.trim(this.render_node(ec[i], v, inner_trim ? trim : null), trim) : this.render_node(ec[i], v, inner_trim ? trim : null); - } - if (trim && !inner_trim) { - inner = this.trim(inner, trim); - } - if (e.tagName == this.prefix) { - return inner; - } - var att = ""; - for (var an in g_att) { - att += " " + an + '="' + this.escape_att(g_att[an]) + '"'; - } - // Some IE versions have problems with closed tags - var opentag = !!t_att['opentag'] && this.eval_bool(t_att["opentag"], v); - return inner.length || opentag ? "<" + e.tagName + att + ">" + inner + "" : "<" + e.tagName + att + "/>"; - }, - render_att_att:function(e, t_att, g_att, v, ext, av) { - if (ext) { - var attv = this.eval_object(av, v); - if (attv != null) { - g_att[ext.substring(1)] = attv.toString(); - } - } else { - var o = this.eval_object(av, v); - if (o != null) { - // TODO: http://bonsaiden.github.com/JavaScript-Garden/#types.typeof - if (o.constructor == Array && o.length > 1 && o[1] != null) { - g_att[o[0]] = new String(o[1]); - } else if (o.constructor == Object) { - for (var i in o) { - if(o[i]!=null) { - g_att[i] = new String(o[i]); - } - } - } - } - } - }, - render_att_attf:function(e, t_att, g_att, v, ext, av) { - g_att[ext.substring(1)] = this.eval_format(av, v); - }, - render_tag_raw:function(e, t_att, g_att, v) { - return this.eval_str(t_att["raw"], v); - }, - render_tag_rawf:function(e, t_att, g_att, v) { - return this.eval_format(t_att["rawf"], v); - }, - /* - * Idea: if the name of the tag != t render the tag around the value - */ - render_tag_esc:function(e, t_att, g_att, v) { - return this.escape_text(this.eval_str(t_att["esc"], v)); - }, - render_tag_escf:function(e, t_att, g_att, v) { - return this.escape_text(this.eval_format(t_att["escf"], v)); - }, - render_tag_if:function(e, t_att, g_att, v) { - return this.eval_bool(t_att["if"], v) ? this.render_element(e, t_att, g_att, v) : ""; - }, - render_tag_set:function(e, t_att, g_att, v) { - var ev = t_att["value"]; - if (ev && ev.constructor != Function) { - v[t_att["set"]] = this.eval_object(ev, v); - } else { - v[t_att["set"]] = this.render_element(e, t_att, g_att, v); - } - return ""; - }, - render_tag_call:function(e, t_att, g_att, v) { - var d = v; - if (!t_att["import"]) { - d = {}; - for (var i in v) { - d[i] = v[i]; - } - } - d["0"] = this.render_element(e, t_att, g_att, d); - return this.render(t_att["call"], d); - }, - render_tag_js:function(e, t_att, g_att, v) { - var dict_name = t_att["js"] || "dict"; - v[dict_name] = v; - var r = this.eval_str(this.render_element(e, t_att, g_att, v), v); - delete(v[dict_name]); - return r || ''; - }, - /** - * Renders a foreach loop (@t-foreach). - * - * Adds the following elements to its context, where ${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(""); - } - } - }, - 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` - * as in it literally returns the parsed DOM Document. - * - * @param qweb the qweb instance to load the template into - * @param {String|Document} template qweb template (Document, template file, or template URL) - */ -function add_template(qweb, template) { - return new Promise(function (resolve, reject) { - qweb.add_template(template, (error, doc) => error ? reject(error) : resolve(doc)); - }); -} - -/** - * Loads the template file, and executes all the test template in a - * qunit module $title - * - * @param assert QUnit assertion module - * @param {String|Document} templateFile template container to load - * @param {Object} [context] additional rendering context - */ -async function loadTest(assert, templateFile, context) { - const qweb = new window.QWeb2.Engine(); - const doc = await add_template(qweb, qwebPath + templateFile); - - assert.expect(doc.querySelectorAll('result').length); - - const templates = qweb.templates; - for (const template in templates) { - if (!templates.hasOwnProperty(template)) { - continue; - } - // ignore templates whose name starts with _, they're - // helpers/internal - if (/^_/.test(template)) { - continue; - } - - const results = doc.querySelector(`result#${template}`).textContent.replace(/\r/g, ''); - const params = doc.querySelector(`params#${template}`) || {textContent: 'null'}; - const args = {...JSON.parse(params.textContent), ...context}; - - try { - assert.equal(trim(qweb.render(template, args)), trim(results), template); - } catch (error) { - assert.notOk(error.stack || error, `Rendering error for ${template} (in ${templateFile} with context ${JSON.stringify(args)}).`); - } - } -} - -const table = [ - {name: 'Output', file: 'qweb-test-output.xml'}, - {name: 'Context-setting', file: 'qweb-test-set.xml'}, - {name: 'Conditionals', file: 'qweb-test-conditionals.xml'}, - {name: 'Attributes manipulation', file: 'qweb-test-attributes.xml'}, - {name: 'Templates calling (to the faraway pages)', file: 'qweb-test-call.xml', context: {True: true}}, - {name: 'Foreach', file: 'qweb-test-foreach.xml'}, - { - name: 'Global', file: 'qweb-test-global.xml', - // test uses python syntax - context: {bool: (v) => !!v ? 'True' : 'False'}, - fixture: { - before() { - this.WORD_REPLACEMENT = window.QWeb2.WORD_REPLACEMENT; - window.QWeb2.WORD_REPLACEMENT = Object.assign( - {not: '!', None: 'undefined'}, - this.WORD_REPLACEMENT - ) - }, - after() { - window.QWeb2.WORD_REPLACEMENT = this.WORD_REPLACEMENT; - } - } - }, - {name: 'Template Inheritance', file: 'qweb-test-extend.xml'}, -]; -QUnit.module('QWeb', { - beforeEach() { - this.oldConsole = window.console; - window.console = hushConsole; - }, - afterEach() {window.console = this.oldConsole;} -}, () => { - for(const {name, file, context, fixture} of table) { - QUnit.test(name, async assert => { - // fake expect to avoid qunit being a pain in the ass, loadTest will - // update it - assert.expect(1); - if (fixture && 'before' in fixture) { await fixture.before(); } - try { - await loadTest(assert, file, context); - } finally { - if (fixture && 'after' in fixture) { await fixture.after(); } - } - }); - } - QUnit.test('escape', assert => { - // not strictly about qweb... - assert.expect(8); - assert.equal(escape('a'), 'a'); - assert.equal(escape(''), '<a>'); - assert.equal(escape({[escapeMethod]() { return 'a'; }}), 'a'); - assert.equal(escape({[escapeMethod]() { return ''; }}), ''); - assert.equal(escape(Markup('a')), 'a'); - assert.equal(escape(Markup('')), ''); - assert.equal(escape(Markup`a`), 'a'); - assert.equal(escape(Markup``), ''); - }); - QUnit.module('t-out', {}, () => { - QUnit.test("basics", async assert => { - assert.expect(5); - const qweb = new QWeb2.Engine; - await add_template(qweb, ` -

    -
    `); - - assert.equal( - qweb.render('t-out', {value: 'test'}), - '

    <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, ` - - - - - -
    - - - - - - - - - - - `); - - assert.equal(trim(qweb.render('litval')), '<a/>'); - assert.equal(trim(qweb.render('body')), ''); - assert.equal(trim(qweb.render('value', {val: ''})), '<a/>'); - assert.equal(trim(qweb.render('bodyout', {val: ''})), '<a/>'); - }); - }) -}); diff --git a/addons/web/tooling/_eslintrc.json b/addons/web/tooling/_eslintrc.json index 69c1b8c27f5..d6eade576fb 100644 --- a/addons/web/tooling/_eslintrc.json +++ b/addons/web/tooling/_eslintrc.json @@ -44,7 +44,6 @@ "_": "readonly", "Chart": "readonly", "fuzzy": "readonly", - "QWeb2": "readonly", "Popover": "readonly", "StackTrace": "readonly", "QUnit": "readonly", diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js index f817631790f..4f2ebb9c944 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js @@ -226,11 +226,6 @@ function getWysiwygIframeContent(params) { widget.appendTo(document.body); return widget; }); - - odoo.define('web.core.top', ['@web/legacy/js/services/core'], function (require) { - var core = require('@web/legacy/js/services/core')[Symbol.for("default")]; - core.qweb.templates = window.top.odoo.__DEBUG__.services['@web/legacy/js/services/core'].qweb.templates; - }); diff --git a/addons/website_slides/__manifest__.py b/addons/website_slides/__manifest__.py index 68f40322122..928d52959cd 100644 --- a/addons/website_slides/__manifest__.py +++ b/addons/website_slides/__manifest__.py @@ -191,7 +191,6 @@ Featuring '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', @@ -213,7 +212,6 @@ Featuring '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/odoo/addons/test_lint/tests/eslintrc b/odoo/addons/test_lint/tests/eslintrc index dc4dcc836e1..de126a4ee6c 100644 --- a/odoo/addons/test_lint/tests/eslintrc +++ b/odoo/addons/test_lint/tests/eslintrc @@ -29,7 +29,6 @@ "jQuery": "readonly", "Chart": "readonly", "fuzzy": "readonly", - "QWeb2": "readonly", "Popover": "readonly", "StackTrace": "readonly", "QUnit": "readonly",