diff options
| author | Fabien Meghazi <fme@openerp.com> | 2011-05-09 12:04:45 +0200 |
|---|---|---|
| committer | Fabien Meghazi <fme@openerp.com> | 2011-05-09 12:04:45 +0200 |
| commit | f799fff396d8bbf3516e7d2949ae2cd4e74eb266 (patch) | |
| tree | ed161cb642308a609d9f126fe856a183ddbd6041 /addons/base/static/lib | |
| parent | 13b326dff8e82762bd7120ca807594d7770cbccf (diff) | |
[ADD] Added template inheritance to QWeb2 (t-extend)
bzr revid: fme@openerp.com-20110509100445-h527yh2q4j061nxq
Diffstat (limited to 'addons/base/static/lib')
| -rw-r--r-- | addons/base/static/lib/qweb/qweb-test-extend.xml | 27 | ||||
| -rw-r--r-- | addons/base/static/lib/qweb/qweb-test.js.html | 17 | ||||
| -rw-r--r-- | addons/base/static/lib/qweb/qweb2.js | 107 |
3 files changed, 149 insertions, 2 deletions
diff --git a/addons/base/static/lib/qweb/qweb-test-extend.xml b/addons/base/static/lib/qweb/qweb-test-extend.xml new file mode 100644 index 00000000000..23e10d52599 --- /dev/null +++ b/addons/base/static/lib/qweb/qweb-test-extend.xml @@ -0,0 +1,27 @@ +<templates> +<t t-name="jquery-extend"> + <ul><li>one</li></ul> +</t> +<t t-extend="jquery-extend"> + <t t-jquery="ul" t-operation="append"><li>3</li></t> +</t> +<t t-extend="jquery-extend"> + <t t-jquery="ul li:first-child" t-operation="replace"><li>2</li></t> +</t> +<t t-extend="jquery-extend"> + <t t-jquery="ul" t-operation="prepend"><li>1</li></t> + <t t-jquery="ul" t-operation="before"><hr/></t> + <t t-jquery="ul" t-operation="after"><hr/></t> +</t> +<t t-extend="jquery-extend"> + <t t-jquery="ul"> + this.attr('class', 'main'); + </t> +</t> +<t t-extend="jquery-extend"> + <t t-jquery="hr:eq(1)" t-operation="replace"><footer></footer></t> +</t> +<t t-extend="jquery-extend"> + <t t-jquery="footer" t-operation="inner"><b>END</b></t> +</t> +</templates> diff --git a/addons/base/static/lib/qweb/qweb-test.js.html b/addons/base/static/lib/qweb/qweb-test.js.html index b39527f0c13..e341fa753fd 100644 --- a/addons/base/static/lib/qweb/qweb-test.js.html +++ b/addons/base/static/lib/qweb/qweb-test.js.html @@ -5,6 +5,7 @@ <link rel="stylesheet" href="http://code.jquery.com/qunit/git/qunit.css" type="text/css" media="screen"/> <script type="text/javascript" src="http://code.jquery.com/qunit/git/qunit.js"></script> + <script type="text/javascript" src="/base/static/lib/jquery/jquery-1.5.2.js"></script> <script type="text/javascript" src="qweb2.js"></script> <script> @@ -235,6 +236,22 @@ equals(QWeb.render('loopvars-aliasing', {seq:seq}), 'even odd even odd even ', "inner loop variables should be rebound as well"); }); + + module("Template inheritance tests", { + setup: function () { + QWeb.add_template('qweb-test-extend.xml'); + }, + teardown: function () { + QWeb.templates = []; + QWeb.tag = {}; + QWeb.att = {}; + } + }); + + test("jQuery extend", function () { + equals(render('jquery-extend', {}), '<hr/><ul class="main"><li>1</li><li>2</li><li>3</li></ul><footer><b>END</b></footer>', + "Extend template with jQuery"); + }); }); </script> diff --git a/addons/base/static/lib/qweb/qweb2.js b/addons/base/static/lib/qweb/qweb2.js index edf8f8b2b21..3c473423a44 100644 --- a/addons/base/static/lib/qweb/qweb2.js +++ b/addons/base/static/lib/qweb/qweb2.js @@ -77,6 +77,41 @@ var QWeb2 = { } return -1; }, + 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 { + if (node.xml !== undefined) { + return node.xml; + } else { + return (new XMLSerializer()).serializeToString(node); + } + } + }, + xpath_selectNodes : function(node, expr) { + if (node.selectNodes !== undefined) { + return node.selectNodes(expr); + } else { + var xpath = new XPathEvaluator(); + try { + var result = xpath.evaluate(expr, node, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); + } catch(error) { + this.exception("Error with XPath expression '" + expr + "' : " + error); + } + var r = []; + if (result != null) { + var element; + while (element = result.iterateNext()) { + r.push(element); + } + } + return r + } + }, call: function(context, template, old_dict, _import, callback) { var new_dict = this.extend({}, old_dict); new_dict['__caller__'] = old_dict['__template__']; @@ -157,8 +192,10 @@ QWeb2.Engine = (function() { this.templates_resources = []; // TODO: implement this.reload() this.templates = {}; this.compiled_templates = {}; + this.extend_templates = {}; this.dict = {}; this.tools = QWeb2.tools; + this.jQuery = window.jQuery; for (var i = 0; i < arguments.length; i++) { this.add_template(arguments[i]); } @@ -178,8 +215,16 @@ QWeb2.Engine = (function() { return this.tools.exception(node.innerText); } var name = node.getAttribute(this.prefix + '-name'); + var extend = node.getAttribute(this.prefix + '-extend'); if (name) { this.templates[name] = node; + } 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]; + } } } } @@ -256,15 +301,26 @@ QWeb2.Engine = (function() { "});"; }, render : function(template, dict) { - //console.time("QWeb render template " + template); + if (this.debug && window['console'] !== undefined) { + console.time("QWeb render template " + template); + } var r = this._render(template, dict); - //console.timeEnd("QWeb render template " + template); + 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(code); TODO: Check if could use this in order to avoid eval @@ -278,6 +334,53 @@ QWeb2.Engine = (function() { } else { return this.tools.exception("Template '" + template + "' not found"); } + }, + extend : function(template, extend_node) { + if (!this.jQuery) { + return this.tools.exception("Can't extend template " + template + " without jQuery"); + } + for (var i = 0, ilen = extend_node.childNodes.length; i < ilen; i++) { + var child = extend_node.childNodes[i]; + if (child.nodeType === 1) { + var xpath = child.getAttribute(this.prefix + '-xpath'), + jquery = child.getAttribute(this.prefix + '-jquery'), + operation = child.getAttribute(this.prefix + '-operation'), + target, + error_msg = "Error while extending template '" + template; + if (jquery) { + target = this.jQuery(jquery, this.templates[template]); + } else if (xpath) { + // NOTE: due to the XPath implementation, extending a template will only work once + // when using XPath because XPathResult won't match objects with other constructor than 'Element' + // As jQuery will create HTMLElements, xpath will ignore them then causing problems when a + // template has already been extended. XPath selectors will probably be removed in QWeb. + target = this.jQuery(this.tools.xpath_selectNodes(this.templates[template], xpath)); + } else { + this.tools.exception(error_msg + "No expression given"); + } + error_msg += "' (expression='" + (jquery || xpath) + "') : "; + var inner = this.tools.xml_node_to_string(child, true); + if (operation) { + var allowed_operations = "append,prepend,before,after,replace,inner".split(','); + if (this.tools.arrayIndexOf(allowed_operations, operation) == -1) { + this.tools.exception(error_msg + "Invalid operation : '" + operation + "'"); + } + operation = {'replace' : 'replaceWith', 'inner' : 'html'}[operation] || operation; + target[operation]($(inner)); + } else { + try { + var f = new Function(['$'], inner); + } catch(error) { + return this.tools.exception("Parse " + error_msg + error); + } + try { + f.apply(target, [this.jQuery]); + } catch(error) { + return this.tools.exception("Runtime " + error_msg + error); + } + } + } + } } }); return Engine; |
