[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, ...
This commit is contained in:
Fabien Meghazi
2016-09-09 18:03:08 +02:00
parent a00ea2755d
commit 75f60f6941
3 changed files with 94 additions and 6 deletions
@@ -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>
+71 -4
View File
@@ -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
+10
View File
@@ -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