4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-XTemplate'>/**
19 </span> * @class Ext.XTemplate
20 * @extends Ext.Template
21 * <p>A template class that supports advanced functionality like:<div class="mdetail-params"><ul>
22 * <li>Autofilling arrays using templates and sub-templates</li>
23 * <li>Conditional processing with basic comparison operators</li>
24 * <li>Basic math function support</li>
25 * <li>Execute arbitrary inline code with special built-in template variables</li>
26 * <li>Custom member functions</li>
27 * <li>Many special tags and built-in operators that aren't defined as part of
28 * the API, but are supported in the templates that can be created</li>
29 * </ul></div></p>
30 * <p>XTemplate provides the templating mechanism built into:<div class="mdetail-params"><ul>
31 * <li>{@link Ext.view.View}</li>
32 * </ul></div></p>
34 * The {@link Ext.Template} describes
35 * the acceptable parameters to pass to the constructor. The following
36 * examples demonstrate all of the supported features.</p>
38 * <div class="mdetail-params"><ul>
40 * <li><b><u>Sample Data</u></b>
41 * <div class="sub-desc">
42 * <p>This is the data object used for reference in each code example:</p>
43 * <pre><code>
46 title: 'Lead Developer',
47 company: 'Sencha Inc.',
48 email: 'tommy@sencha.com',
49 address: '5 Cups Drive',
53 drinks: ['Coffee', 'Soda', 'Water'],
65 </code></pre>
70 * <li><b><u>Auto filling of arrays</u></b>
71 * <div class="sub-desc">
72 * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>for</tt></b> operator are used
73 * to process the provided data object:
75 * <li>If the value specified in <tt>for</tt> is an array, it will auto-fill,
76 * repeating the template block inside the <tt>tpl</tt> tag for each item in the
78 * <li>If <tt>for="."</tt> is specified, the data object provided is examined.</li>
79 * <li>While processing an array, the special variable <tt>{#}</tt>
80 * will provide the current array index + 1 (starts at 1, not 0).</li>
83 * <pre><code>
84 &lt;tpl <b>for</b>=".">...&lt;/tpl> // loop through array at root node
85 &lt;tpl <b>for</b>="foo">...&lt;/tpl> // loop through array at foo node
86 &lt;tpl <b>for</b>="foo.bar">...&lt;/tpl> // loop through array at foo.bar node
87 </code></pre>
88 * Using the sample data above:
89 * <pre><code>
90 var tpl = new Ext.XTemplate(
91 '&lt;p>Kids: ',
92 '&lt;tpl <b>for</b>=".">', // process the data.kids node
93 '&lt;p>{#}. {name}&lt;/p>', // use current array index to autonumber
94 '&lt;/tpl>&lt;/p>'
96 tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object
97 </code></pre>
98 * <p>An example illustrating how the <b><tt>for</tt></b> property can be leveraged
99 * to access specified members of the provided data object to populate the template:</p>
100 * <pre><code>
101 var tpl = new Ext.XTemplate(
102 '&lt;p>Name: {name}&lt;/p>',
103 '&lt;p>Title: {title}&lt;/p>',
104 '&lt;p>Company: {company}&lt;/p>',
105 '&lt;p>Kids: ',
106 '&lt;tpl <b>for="kids"</b>>', // interrogate the kids property within the data
107 '&lt;p>{name}&lt;/p>',
108 '&lt;/tpl>&lt;/p>'
110 tpl.overwrite(panel.body, data); // pass the root node of the data object
111 </code></pre>
112 * <p>Flat arrays that contain values (and not objects) can be auto-rendered
113 * using the special <b><tt>{.}</tt></b> variable inside a loop. This variable
114 * will represent the value of the array at the current index:</p>
115 * <pre><code>
116 var tpl = new Ext.XTemplate(
117 '&lt;p>{name}\&#39;s favorite beverages:&lt;/p>',
118 '&lt;tpl for="drinks">',
119 '&lt;div> - {.}&lt;/div>',
122 tpl.overwrite(panel.body, data);
123 </code></pre>
124 * <p>When processing a sub-template, for example while looping through a child array,
125 * you can access the parent object's members via the <b><tt>parent</tt></b> object:</p>
126 * <pre><code>
127 var tpl = new Ext.XTemplate(
128 '&lt;p>Name: {name}&lt;/p>',
129 '&lt;p>Kids: ',
130 '&lt;tpl for="kids">',
131 '&lt;tpl if="age &amp;gt; 1">',
132 '&lt;p>{name}&lt;/p>',
133 '&lt;p>Dad: {<b>parent</b>.name}&lt;/p>',
135 '&lt;/tpl>&lt;/p>'
137 tpl.overwrite(panel.body, data);
138 </code></pre>
143 * <li><b><u>Conditional processing with basic comparison operators</u></b>
144 * <div class="sub-desc">
145 * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>if</tt></b> operator are used
146 * to provide conditional checks for deciding whether or not to render specific
147 * parts of the template. Notes:<div class="sub-desc"><ul>
148 * <li>Double quotes must be encoded if used within the conditional</li>
149 * <li>There is no <tt>else</tt> operator &mdash; if needed, two opposite
150 * <tt>if</tt> statements should be used.</li>
151 * </ul></div>
152 * <pre><code>
153 &lt;tpl if="age &gt; 1 &amp;&amp; age &lt; 10">Child&lt;/tpl>
154 &lt;tpl if="age >= 10 && age < 18">Teenager&lt;/tpl>
155 &lt;tpl <b>if</b>="this.isGirl(name)">...&lt;/tpl>
156 &lt;tpl <b>if</b>="id==\'download\'">...&lt;/tpl>
157 &lt;tpl <b>if</b>="needsIcon">&lt;img src="{icon}" class="{iconCls}"/>&lt;/tpl>
159 &lt;tpl if="name == "Tommy"">Hello&lt;/tpl>
160 // encode &#34; if it is part of the condition, e.g.
161 &lt;tpl if="name == &#38;quot;Tommy&#38;quot;">Hello&lt;/tpl>
162 * </code></pre>
163 * Using the sample data above:
164 * <pre><code>
165 var tpl = new Ext.XTemplate(
166 '&lt;p>Name: {name}&lt;/p>',
167 '&lt;p>Kids: ',
168 '&lt;tpl for="kids">',
169 '&lt;tpl if="age &amp;gt; 1">',
170 '&lt;p>{name}&lt;/p>',
172 '&lt;/tpl>&lt;/p>'
174 tpl.overwrite(panel.body, data);
175 </code></pre>
180 * <li><b><u>Basic math support</u></b>
181 * <div class="sub-desc">
182 * <p>The following basic math operators may be applied directly on numeric
183 * data values:</p><pre>
187 * <pre><code>
188 var tpl = new Ext.XTemplate(
189 '&lt;p>Name: {name}&lt;/p>',
190 '&lt;p>Kids: ',
191 '&lt;tpl for="kids">',
192 '&lt;tpl if="age &amp;gt; 1">', // <-- Note that the &gt; is encoded
193 '&lt;p>{#}: {name}&lt;/p>', // <-- Auto-number each item
194 '&lt;p>In 5 Years: {age+5}&lt;/p>', // <-- Basic math
195 '&lt;p>Dad: {parent.name}&lt;/p>',
197 '&lt;/tpl>&lt;/p>'
199 tpl.overwrite(panel.body, data);
200 </code></pre>
205 * <li><b><u>Execute arbitrary inline code with special built-in template variables</u></b>
206 * <div class="sub-desc">
207 * <p>Anything between <code>{[ ... ]}</code> is considered code to be executed
208 * in the scope of the template. There are some special variables available in that code:
210 * <li><b><tt>values</tt></b>: The values in the current scope. If you are using
211 * scope changing sub-templates, you can change what <tt>values</tt> is.</li>
212 * <li><b><tt>parent</tt></b>: The scope (values) of the ancestor template.</li>
213 * <li><b><tt>xindex</tt></b>: If you are in a looping template, the index of the
214 * loop you are in (1-based).</li>
215 * <li><b><tt>xcount</tt></b>: If you are in a looping template, the total length
216 * of the array you are looping.</li>
218 * This example demonstrates basic row striping using an inline code block and the
219 * <tt>xindex</tt> variable:</p>
220 * <pre><code>
221 var tpl = new Ext.XTemplate(
222 '&lt;p>Name: {name}&lt;/p>',
223 '&lt;p>Company: {[values.company.toUpperCase() + ", " + values.title]}&lt;/p>',
224 '&lt;p>Kids: ',
225 '&lt;tpl for="kids">',
226 '&lt;div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
229 '&lt;/tpl>&lt;/p>'
231 tpl.overwrite(panel.body, data);
232 </code></pre>
236 * <li><b><u>Template member functions</u></b>
237 * <div class="sub-desc">
238 * <p>One or more member functions can be specified in a configuration
239 * object passed into the XTemplate constructor for more complex processing:</p>
240 * <pre><code>
241 var tpl = new Ext.XTemplate(
242 '&lt;p>Name: {name}&lt;/p>',
243 '&lt;p>Kids: ',
244 '&lt;tpl for="kids">',
245 '&lt;tpl if="this.isGirl(name)">',
246 '&lt;p>Girl: {name} - {age}&lt;/p>',
248 // use opposite if statement to simulate 'else' processing:
249 '&lt;tpl if="this.isGirl(name) == false">',
250 '&lt;p>Boy: {name} - {age}&lt;/p>',
252 '&lt;tpl if="this.isBaby(age)">',
253 '&lt;p>{name} is a baby!&lt;/p>',
255 '&lt;/tpl>&lt;/p>',
257 // XTemplate configuration:
260 isGirl: function(name){
261 return name == 'Sara Grace';
263 isBaby: function(age){
268 tpl.overwrite(panel.body, data);
269 </code></pre>
273 * </ul></div>
275 * @param {Mixed} config
278 Ext.define('Ext.XTemplate', {
280 /* Begin Definitions */
282 extend: 'Ext.Template',
285 <span id='Ext-XTemplate-method-from'> /**
286 </span> * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
287 * @param {String/HTMLElement} el A DOM element or its id
288 * @return {Ext.Template} The created template
291 from: function(el, config) {
293 return new this(el.value || el.innerHTML, config || {});
297 /* End Definitions */
299 argsRe: /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
300 nameRe: /^<tpl\b[^>]*?for="(.*?)"/,
301 ifRe: /^<tpl\b[^>]*?if="(.*?)"/,
302 execRe: /^<tpl\b[^>]*?exec="(.*?)"/,
303 constructor: function() {
304 this.callParent(arguments);
319 WITHVALUES = 'with(values){ ',
320 m, matchName, matchIf, matchExec, exp, fn, exec, name, i;
322 html = ['<tpl>', html, '</tpl>'].join('');
324 while ((m = html.match(argsRe))) {
328 matchName = m[0].match(nameRe);
329 matchIf = m[0].match(ifRe);
330 matchExec = m[0].match(execRe);
332 exp = matchIf ? matchIf[1] : null;
334 fn = Ext.functionFactory(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + 'try{' + RETURN + Ext.String.htmlDecode(exp) + ';}catch(e){return;}}');
337 exp = matchExec ? matchExec[1] : null;
339 exec = Ext.functionFactory(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + Ext.String.htmlDecode(exp) + ';}');
342 name = matchName ? matchName[1] : null;
346 } else if (name === '..') {
349 name = Ext.functionFactory(VALUES, PARENT, 'try{' + WITHVALUES + RETURN + name + ';}}catch(e){return;}');
360 html = html.replace(m[0], '{xtpl' + id + '}');
364 for (i = tpls.length - 1; i >= 0; --i) {
365 me.compileTpl(tpls[i]);
367 me.master = tpls[tpls.length - 1];
372 applySubTemplate: function(id, values, parent, xindex, xcount) {
373 var me = this, t = me.tpls[id];
374 return t.compiled.call(me, values, parent, xindex, xcount);
376 <span id='Ext-XTemplate-cfg-codeRe'> /**
377 </span> * @cfg {RegExp} codeRe The regular expression used to match code variables (default: matches <tt>{[expression]}</tt>).
379 codeRe: /\{\[((?:\\\]|.|\n)*?)\]\}/g,
381 re: /\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\/]\s?[\d\.\+\-\*\/\(\)]+)?\}/g,
384 compileTpl: function(tpl) {
385 var fm = Ext.util.Format,
387 useFormat = me.disableFormats !== true,
388 body, bodyReturn, evaluatedFn;
390 function fn(m, name, format, args, math) {
392 // name is what is inside the {}
393 // Name begins with xtpl, use a Sub Template
394 if (name.substr(0, 4) == 'xtpl') {
395 return "',this.applySubTemplate(" + name.substr(4) + ", values, parent, xindex, xcount),'";
397 // name = "." - Just use the values object.
399 // filter to not include arrays/objects/nulls
400 v = 'Ext.Array.indexOf(["string", "number", "boolean"], typeof values) > -1 || Ext.isDate(values) ? values : ""';
403 // name = "#" - Use the xindex
404 else if (name == '#') {
407 else if (name.substr(0, 7) == "parent.") {
410 // name has a . in it - Use object literal notation, starting from values
411 else if (name.indexOf('.') != -1) {
412 v = "values." + name;
415 // name is a property of values
417 v = "values['" + name + "']";
420 v = '(' + v + math + ')';
422 if (format && useFormat) {
423 args = args ? ',' + args : "";
424 if (format.substr(0, 5) != "this.") {
425 format = "fm." + format + '(';
428 format = 'this.' + format.substr(5) + '(';
433 format = "(" + v + " === undefined ? '' : ";
435 return "'," + format + v + args + "),'";
438 function codeFn(m, code) {
439 // Single quotes get escaped when the template is compiled, however we want to undo this when running code.
440 return "',(" + code.replace(me.compileARe, "'") + "),'";
443 bodyReturn = tpl.body.replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn).replace(me.codeRe, codeFn);
444 body = "evaluatedFn = function(values, parent, xindex, xcount){return ['" + bodyReturn + "'].join('');};";
447 tpl.compiled = function(values, parent, xindex, xcount) {
453 if (tpl.test && !tpl.test.call(me, values, parent, xindex, xcount)) {
457 vs = tpl.target ? tpl.target.call(me, values, parent) : values;
462 parent = tpl.target ? values : parent;
463 if (tpl.target && Ext.isArray(vs)) {
467 for (i = 0; i < length; i++) {
468 buffer[buffer.length] = evaluatedFn.call(me, vs[i], parent, i + 1, length);
469 tpl.exec.call(me, vs[i], parent, i + 1, length);
472 for (i = 0; i < length; i++) {
473 buffer[buffer.length] = evaluatedFn.call(me, vs[i], parent, i + 1, length);
476 return buffer.join('');
480 tpl.exec.call(me, vs, parent, xindex, xcount);
482 return evaluatedFn.call(me, vs, parent, xindex, xcount);
488 <span id='Ext-XTemplate-method-applyTemplate'> /**
489 </span> * Returns an HTML fragment of this template with the specified values applied.
490 * @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'})
491 * @return {String} The HTML fragment
493 applyTemplate: function(values) {
494 return this.master.compiled.call(this, values, {}, 1, 1);
497 <span id='Ext-XTemplate-method-compile'> /**
498 </span> * Compile the template to a function for optimized performance. Recommended if the template will be used frequently.
499 * @return {Function} The compiled function
501 compile: function() {
505 <span id='Ext-XTemplate-method-apply'> /**
506 </span> * Alias for {@link #applyTemplate}
507 * Returns an HTML fragment of this template with the specified values applied.
508 * @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'})
509 * @return {String} The HTML fragment
510 * @member Ext.XTemplate
513 this.createAlias('apply', 'applyTemplate');