diff options
| author | Fabien Meghazi <fme@odoo.com> | 2016-09-07 16:01:16 +0200 |
|---|---|---|
| committer | Fabien Meghazi <fme@odoo.com> | 2016-09-09 18:03:08 +0200 |
| commit | 75f60f69416625713819c810d2da33db4dc0b06c (patch) | |
| tree | 11c1196aff2828d6619fbd36ff37a5848376ef86 | |
| parent | a00ea2755d93cef160a13d4652729e3c655fdbb8 (diff) | |
[ADD] web: Add extra condition branching (t-elif, t-else)
A new preprocess method is added to the template engine in order to do
preprocessing/sanitization of the templates before compilation.
This method can be overloaded in order to add new features such as
translation, ...
| -rw-r--r-- | addons/web/static/lib/qweb/qweb-test-conditionals.xml | 15 | ||||
| -rw-r--r-- | addons/web/static/lib/qweb/qweb2.js | 75 | ||||
| -rw-r--r-- | doc/reference/qweb.rst | 10 |
3 files changed, 94 insertions, 6 deletions
diff --git a/addons/web/static/lib/qweb/qweb-test-conditionals.xml b/addons/web/static/lib/qweb/qweb-test-conditionals.xml index b1d54bcdcf0..782feb24249 100644 --- a/addons/web/static/lib/qweb/qweb-test-conditionals.xml +++ b/addons/web/static/lib/qweb/qweb-test-conditionals.xml @@ -16,16 +16,27 @@ </t> <result id="boolean-value-condition-missing"/> + <!-- TODO: activate this test when qweb.py implements t-elif + <t t-name="boolean-value-condition-elif"> + <t t-if="color == 'black'">black pearl</t> + <t t-elif="color == 'yellow'">yellow submarine</t> + <t t-elif="color == 'red'">red is dead</t> + <t t-else="">beer</t> + </t> + <params id="boolean-value-condition-elif">{"color": "red"}</params> + <result id="boolean-value-condition-elif">red is dead</result> + --> + <t t-name="boolean-value-condition-else"> <div><span>begin</span><t t-if="condition">ok</t> - <t t-else="t-else">ok-else</t><span>end</span></div> + <t t-else="">ok-else</t><span>end</span></div> </t> <params id="boolean-value-condition-else">{"condition": true}</params> <result id="boolean-value-condition-else"><![CDATA[<div><span>begin</span>ok<span>end</span></div>]]></result> <t t-name="boolean-value-condition-false-else"> <div><span>begin</span><t t-if="condition">fail</t> - <t t-else="t-else">fail-else</t><span>end</span></div> + <t t-else="">fail-else</t><span>end</span></div> </t> <params id="boolean-value-condition-false-else">{"condition": false}</params> <result id="boolean-value-condition-false-else"><![CDATA[<div><span>begin</span>fail-else<span>end</span></div>]]></result> diff --git a/addons/web/static/lib/qweb/qweb2.js b/addons/web/static/lib/qweb/qweb2.js index 1cfc7bb69ef..d5449dae6d9 100644 --- a/addons/web/static/lib/qweb/qweb2.js +++ b/addons/web/static/lib/qweb/qweb2.js @@ -28,7 +28,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 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,call,set,esc,raw,js,debug,log'.split(','), + ACTIONS_PRECEDENCE: 'foreach,if,elif,else,call,set,esc,raw,js,debug,log'.split(','), WORD_REPLACEMENT: { 'and': '&&', 'or': '||', @@ -112,6 +112,15 @@ var QWeb2 = { } 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 = []; @@ -242,13 +251,11 @@ QWeb2.Engine = (function() { 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) { - if (node.nodeName == 'parsererror') { - return this.tools.exception(node.innerText); - } var name = node.getAttribute(this.prefix + '-name'); var extend = node.getAttribute(this.prefix + '-extend'); if (name && extend) { @@ -278,6 +285,56 @@ QWeb2.Engine = (function() { } 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 (self.tools.trim(text_node.nodeValue)) { + return self.tools.exception("Error: text is not allowed between branching directives"); + } + text_node.remove(); + } + } 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; @@ -704,6 +761,16 @@ QWeb2.Element = (function() { 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 diff --git a/doc/reference/qweb.rst b/doc/reference/qweb.rst index 1fa29212998..e73de74b94d 100644 --- a/doc/reference/qweb.rst +++ b/doc/reference/qweb.rst @@ -95,6 +95,16 @@ not have to be ``<t>``:: will give the same results as the previous example. +Extra conditional branching directives ``t-elif`` and ``t-else`` are also +available:: + + <div> + <p t-if="user.birthday == today()">Happy bithday!</p> + <p t-elif="user.login == 'root'">Welcome master!</p> + <p t-else="">Welcome!</p> + </div> + + .. _reference/qweb/loops: loops |
