summaryrefslogtreecommitdiff
path: root/addons/web/static/lib/qweb/qweb2.js
diff options
context:
space:
mode:
authorFabien Meghazi <fme@odoo.com>2016-09-07 16:01:16 +0200
committerFabien Meghazi <fme@odoo.com>2016-09-09 18:03:08 +0200
commit75f60f69416625713819c810d2da33db4dc0b06c (patch)
tree11c1196aff2828d6619fbd36ff37a5848376ef86 /addons/web/static/lib/qweb/qweb2.js
parenta00ea2755d93cef160a13d4652729e3c655fdbb8 (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, ...
Diffstat (limited to 'addons/web/static/lib/qweb/qweb2.js')
-rw-r--r--addons/web/static/lib/qweb/qweb2.js75
1 files changed, 71 insertions, 4 deletions
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