/** * @class Ext.XTemplate * @extends Ext.Template *

A template class that supports advanced functionality like:

*

XTemplate provides the templating mechanism built into:

* *

For example usage {@link #XTemplate see the constructor}.

* * @constructor * The {@link Ext.Template#Template Ext.Template constructor} describes * the acceptable parameters to pass to the constructor. The following * examples demonstrate all of the supported features.

* *
* * @param {Mixed} config */ Ext.XTemplate = function() { Ext.XTemplate.superclass.constructor.apply(this, arguments); var me = this, s = me.html, re = /]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/, nameRe = /^]*?for="(.*?)"/, ifRe = /^]*?if="(.*?)"/, execRe = /^]*?exec="(.*?)"/, id = 0, tpls = [], VALUES = 'values', PARENT = 'parent', XINDEX = 'xindex', XCOUNT = 'xcount', RETURN = 'return ', WITHVALUES = 'with(values){ ', m, m2, m3, m4, exp, fn, exec, name, i; s = ['', s, ''].join(''); while ((m = s.match(re))) { m2 = m[0].match(nameRe); m3 = m[0].match(ifRe); m4 = m[0].match(execRe); exp = null; fn = null; exec = null; name = m2 && m2[1] ? m2[1] : ''; if (m3) { exp = m3 && m3[1] ? m3[1] : null; if (exp) { fn = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + 'try{' + RETURN + (Ext.util.Format.htmlDecode(exp)) + ';}catch(e){return;}}'); } } if (m4) { exp = m4 && m4[1] ? m4[1] : null; if (exp) { exec = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + (Ext.util.Format.htmlDecode(exp)) + '; }'); } } if (name) { switch (name) { case '.': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + VALUES + '; }'); break; case '..': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + PARENT + '; }'); break; default: name = new Function(VALUES, PARENT, WITHVALUES + RETURN + name + '; }'); } } tpls.push({ id: id, target: name, exec: exec, test: fn, body: m[1] || '' }); s = s.replace(m[0], '{xtpl' + id + '}'); ++id; } for (i = tpls.length - 1; i >= 0; --i) { me.compileTpl(tpls[i]); } me.master = tpls[tpls.length - 1]; me.tpls = tpls; }; Ext.extend(Ext.XTemplate, Ext.Template, { re: /\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\/]\s?[\d\.\+\-\*\/\(\)]+)?\}/g, /** * @cfg {RegExp} codeRe The regular expression used to match code variables (default: matches {[expression]}). */ codeRe: /\{\[((?:\\\]|.|\n)*?)\]\}/g, // @private applySubTemplate: function(id, values, parent, xindex, xcount) { var me = this, len, t = me.tpls[id], vs, buf = [], i; if ((t.test && !t.test.call(me, values, parent, xindex, xcount)) || (t.exec && t.exec.call(me, values, parent, xindex, xcount))) { return ''; } vs = t.target ? t.target.call(me, values, parent) : values; len = vs.length; parent = t.target ? values: parent; if (t.target && Ext.isArray(vs)) { for (i = 0, len = vs.length; i < len; i++) { buf[buf.length] = t.compiled.call(me, vs[i], parent, i + 1, len); } return buf.join(''); } return t.compiled.call(me, vs, parent, xindex, xcount); }, // @private compileTpl: function(tpl) { var fm = Ext.util.Format, useF = this.disableFormats !== true, body; function fn(m, name, format, args, math) { var v; // name is what is inside the {} // Name begins with xtpl, use a Sub Template if (name.substr(0, 4) == 'xtpl') { return "',this.applySubTemplate(" + name.substr(4) + ", values, parent, xindex, xcount),'"; } // name = "." - Just use the values object. if (name == '.') { v = 'typeof values == "string" ? values : ""'; } // name = "#" - Use the xindex else if (name == '#') { v = 'xindex'; } // name has a . in it - Use object literal notation, starting from values else if (name.indexOf('.') != -1) { v = "values."+name; } // name is a property of values else { v = "values['" + name + "']"; } if (math) { v = '(' + v + math + ')'; } if (format && useF) { args = args ? ',' + args: ""; if (format.substr(0, 5) != "this.") { format = "fm." + format + '('; } else { format = 'this.call("' + format.substr(5) + '", '; args = ", values"; } } else { args = ''; format = "(" + v + " === undefined ? '' : "; } return "'," + format + v + args + "),'"; } function codeFn(m, code) { // Single quotes get escaped when the template is compiled, however we want to undo this when running code. return "',(" + code.replace(/\\'/g, "'") + "),'"; } body = ["tpl.compiled = function(values, parent, xindex, xcount){return ['"]; body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn)); body.push("'].join('');};"); body = body.join(''); eval(body); return this; }, /** * Returns an HTML fragment of this template with the specified values applied. * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'}) * @return {String} The HTML fragment */ applyTemplate: function(values) { return this.master.compiled.call(this, values, {}, 1, 1); }, /** * Compile the template to a function for optimized performance. Recommended if the template will be used frequently. * @return {Function} The compiled function */ compile: function() { return this; } }); /** * Alias for {@link #applyTemplate} * Returns an HTML fragment of this template with the specified values applied. * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'}) * @return {String} The HTML fragment * @member Ext.XTemplate * @method apply */ Ext.XTemplate.prototype.apply = Ext.XTemplate.prototype.applyTemplate; if (Ext.util == undefined) { Ext.util = { Format: {} }; }