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 @@
+
+
beginok
- ok-elseend
+ ok-elseend
{"condition": true}
beginokend]]>
beginfail
- fail-elseend
+ fail-elseend
{"condition": false}
beginfail-elseend]]>
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 ````::
will give the same results as the previous example.
+Extra conditional branching directives ``t-elif`` and ``t-else`` are also
+available::
+
+
+
Happy bithday!
+
Welcome master!
+
Welcome!
+
+
+
.. _reference/qweb/loops:
loops