</code></pre>
* The tpl tag:
<pre><code>
- <div roo-for="a_variable or condition.."></tpl>
- <tpl roo-if="a_variable or condition"></tpl>
- <tpl roo-exec="some javascript"></tpl>
- <tpl roo-name="named_template"></tpl>
+ <div roo-for="a_variable or condition.."></div>
+ <div roo-if="a_variable or condition"></div>
+ <div roo-exec="some javascript"></div>
+ <div roo-name="named_template"></div>
</code></pre>
*
Roo.DomTemplate = function()
{
Roo.DomTemplate.superclass.constructor.apply(this, arguments);
- if (this.html) {
+ if (this.html) {
this.compile();
- }
+ }
};
Roo.extend(Roo.DomTemplate, Roo.Template, {
-
+ /**
+ * id counter for sub templates.
+ */
id : 0,
+ /**
+ * flag to indicate if dom parser is inside a pre,
+ * it will strip whitespace if not.
+ */
+ inPre : false,
/**
* The various sub templates
*/
tpls : false,
+
+
+
/**
*
* basic tag replacing syntax
* x.t:(test,tesT)
*
*/
- re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
-
+ re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
+ //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
iterChild : function (node, method) {
+
+ var oldPre = this.inPre;
+ if (node.tagName == 'PRE') {
+ this.inPre = true;
+ }
for( var i = 0; i < node.childNodes.length; i++) {
method.call(this, node.childNodes[i]);
}
+ this.inPre = oldPre;
},
+
+
/**
* compile the template
*
var s = this.html;
// covert the html into DOM...
+ var doc = false;
+ var div =false;
+ try {
+ doc = document.implementation.createHTMLDocument("");
+ doc.documentElement.innerHTML = this.html ;
+ div = doc.documentElement;
+ } catch (e) {
+ // old IE... - nasty -- it causes all sorts of issues.. with
+ // images getting pulled from server..
+ div = document.createElement('div');
+ div.innerHTML = this.html;
+ }
+ //doc.documentElement.innerHTML = htmlBody
+
- var div = document.createElement('div');
- div.innerHTML = this.html;
this.tpls = [];
-
- this.iterChild(div, this.compileNode)
+ var _t = this;
+ this.iterChild(div, function(n) {_t.compileNode(n, true); });
var tpls = this.tpls;
+ // create a top level template from the snippet..
+
+ //Roo.log(div.innerHTML);
+
+ var tpl = {
+ uid : 'master',
+ id : this.id++,
+ attr : false,
+ value : false,
+ body : div.innerHTML,
+
+ forCall : false,
+ execCall : false,
+ dom : div,
+ isTop : true
+
+ };
+ tpls.unshift(tpl);
+
+
+ // compile them...
this.tpls = [];
- for(var i = tpls.length-1; i >= 0; --i){
- this.compileTpl(tpls[i]);
- this.tpls[tpls[i].id] = tpls[i];
- }
+ Roo.each(tpls, function(tp){
+ this.compileTpl(tp);
+ this.tpls[tp.id] = tp;
+ }, this);
+
this.master = tpls[0];
return this;
},
- compileNode : function(node) {
+ compileNode : function(node, istop) {
// test for
//Roo.log(node);
+
// skip anything not a tag..
if (node.nodeType != 1) {
+ if (node.nodeType == 3 && !this.inPre) {
+ // reduce white space..
+ node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
+
+ }
return;
}
forCall : false,
execCall : false,
-
+ dom : false,
+ isTop : istop
};
+
+
switch(true) {
case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
- case (node.hasAttribute('roo-if')): tpl.attr = 'name'; break;
+ case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
// no default..
}
+
+
if (!tpl.attr) {
// just itterate children..
- this.iterChild(node,this.compileNode)
+ this.iterChild(node,this.compileNode);
return;
}
tpl.uid = this.id++;
- var value = node.getAttribute('roo-' + tpl.attr);
+ tpl.value = node.getAttribute('roo-' + tpl.attr);
node.removeAttribute('roo-'+ tpl.attr);
if (tpl.attr != 'name') {
var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
node.parentNode.replaceChild(placeholder, node);
} else {
- node.parentNode.removeChild(node);
+
+ var placeholder = document.createElement('span');
+ placeholder.className = 'roo-tpl-' + tpl.value;
+ node.parentNode.replaceChild(placeholder, node);
}
// parent now sees '{domtplXXXX}
- this.iterChild(node,this.compileNode)
+ this.iterChild(node,this.compileNode);
// we should now have node body...
var div = document.createElement('div');
div.appendChild(node);
+ tpl.dom = node;
+ // this has the unfortunate side effect of converting tagged attributes
+ // eg. href="{...}" into %7C...%7D
+ // this has been fixed by searching for those combo's although it's a bit hacky..
+
+
tpl.body = div.innerHTML;
tpl.id = tpl.uid;
switch(tpl.attr) {
case 'for' :
- switch (attr.value) {
+ switch (tpl.value) {
case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
break;
case 'name':
- tpl.id = value; // replace non characters???
+ tpl.id = tpl.value; // replace non characters???
break;
}
},
- oldwrapper : function ()
- {
- s = ['<tpl>', s, '</tpl>'].join('');
- var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
- nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
- ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
- execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
- namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
- m,
- id = 0,
- tpls = [];
- while(true == !!(m = s.match(re))){
- var forMatch = m[0].match(nameRe),
- ifMatch = m[0].match(ifRe),
- execMatch = m[0].match(execRe),
- namedMatch = m[0].match(namedRe),
-
- exp = null,
- fn = null,
- exec = null,
- name = forMatch && forMatch[1] ? forMatch[1] : '';
-
- if (ifMatch) {
- // if - puts fn into test..
- exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
- if(exp){
- fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
- }
- }
-
- if (execMatch) {
- // exec - calls a function... returns empty if true is returned.
- exp = execMatch && execMatch[1] ? execMatch[1] : null;
- if(exp){
- exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
- }
- }
-
-
- if (name) {
- // for =
- switch(name){
- case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
- case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
- default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
- }
- }
- var uid = namedMatch ? namedMatch[1] : id;
-
-
- tpls.push({
- id: namedMatch ? namedMatch[1] : id,
- target: name,
- exec: exec,
- test: fn,
- body: m[1] || ''
- });
- if (namedMatch) {
- s = s.replace(m[0], '');
- } else {
- s = s.replace(m[0], '{xtpl'+ id + '}');
- }
- ++id;
- }
-
- },
+
/**
- * same as applyTemplate, except it's done to one of the subTemplates
- * when using named templates, you can do:
- *
- * var str = pl.applySubTemplate('your-name', values);
+ * Compile a segment of the template into a 'sub-template'
*
*
- * @param {Number} id of the template
- * @param {Object} values to apply to template
- * @param {Object} parent (normaly the instance of this object)
+ *
+ *
*/
- applySubTemplate : function(id, values, parent)
- {
-
-
- var t = this.tpls[id];
-
-
- try {
- if(t.test && !t.test.call(this, values, parent)){
- return '';
- }
- } catch(e) {
- Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
- Roo.log(e.toString());
- Roo.log(t.test);
- return ''
- }
- try {
-
- if(t.exec && t.exec.call(this, values, parent)){
- return '';
- }
- } catch(e) {
- Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
- Roo.log(e.toString());
- Roo.log(t.exec);
- return ''
- }
- try {
- var vs = t.target ? t.target.call(this, values, parent) : values;
- parent = t.target ? values : parent;
- if(t.target && vs instanceof Array){
- var buf = [];
- for(var i = 0, len = vs.length; i < len; i++){
- buf[buf.length] = t.compiled.call(this, vs[i], parent);
- }
- return buf.join('');
- }
- return t.compiled.call(this, vs, parent);
- } catch (e) {
- Roo.log("Xtemplate.applySubTemplate : Exception thrown");
- Roo.log(e.toString());
- Roo.log(t.compiled);
- return '';
- }
- },
-
compileTpl : function(tpl)
{
var fm = Roo.util.Format;
var useF = this.disableFormats !== true;
- var sep = Roo.isGecko ? "+" : ",";
+
+ var sep = Roo.isGecko ? "+\n" : ",\n";
+
var undef = function(str) {
- Roo.log("Property not found :" + str);
+ Roo.debug && Roo.log("Property not found :" + str);
return '';
};
+
+ //Roo.log(tpl.body);
+
+
- var fn = function(m, name, format, args)
+ var fn = function(m, lbrace, name, format, args)
{
+ //Roo.log("ARGS");
//Roo.log(arguments);
args = args ? args.replace(/\\'/g,"'") : args;
//["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
if (typeof(format) == 'undefined') {
- format= 'htmlEncode';
+ format = 'htmlEncode';
}
if (format == 'raw' ) {
format = false;
}
- if(name.substr(0, 4) == 'xtpl'){
- return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
+ if(name.substr(0, 6) == 'domtpl'){
+ return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
}
// build an array of options to determine if value is undefined..
return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
}
- if (args.length) {
+ if (args && args.length) {
// called with xxyx.yuu:(test,test)
// change to ()
return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
return this;
},
+
+ /**
+ * same as applyTemplate, except it's done to one of the subTemplates
+ * when using named templates, you can do:
+ *
+ * var str = pl.applySubTemplate('your-name', values);
+ *
+ *
+ * @param {Number} id of the template
+ * @param {Object} values to apply to template
+ * @param {Object} parent (normaly the instance of this object)
+ */
+ applySubTemplate : function(id, values, parent)
+ {
+
+
+ var t = this.tpls[id];
+
+
+ try {
+ if(t.ifCall && !t.ifCall.call(this, values, parent)){
+ Roo.debug && Roo.log('if call on ' + t.value + ' return false');
+ return '';
+ }
+ } catch(e) {
+ Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
+ Roo.log(values);
+
+ return '';
+ }
+ try {
+
+ if(t.execCall && t.execCall.call(this, values, parent)){
+ return '';
+ }
+ } catch(e) {
+ Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
+ Roo.log(values);
+ return '';
+ }
+
+ try {
+ var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
+ parent = t.target ? values : parent;
+ if(t.forCall && vs instanceof Array){
+ var buf = [];
+ for(var i = 0, len = vs.length; i < len; i++){
+ try {
+ buf[buf.length] = t.compiled.call(this, vs[i], parent);
+ } catch (e) {
+ Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
+ Roo.log(e.body);
+ //Roo.log(t.compiled);
+ Roo.log(vs[i]);
+ }
+ }
+ return buf.join('');
+ }
+ } catch (e) {
+ Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
+ Roo.log(values);
+ return '';
+ }
+ try {
+ return t.compiled.call(this, vs, parent);
+ } catch (e) {
+ Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
+ Roo.log(e.body);
+ //Roo.log(t.compiled);
+ Roo.log(values);
+ return '';
+ }
+ },
+
+
applyTemplate : function(values){
return this.master.compiled.call(this, values, {});
});
-Roo.XTemplate.from = function(el){
+Roo.DomTemplate.from = function(el){
el = Roo.getDom(el);
- return new Roo.XTemplate(el.value || el.innerHTML);
+ return new Roo.Domtemplate(el.value || el.innerHTML);
};
\ No newline at end of file