Upgrade to ExtJS 3.1.0 - Released 12/16/2009
[extjs.git] / src / core / core / Template.js
1 /*!
2  * Ext JS Library 3.1.0
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.Template
9  * <p>Represents an HTML fragment template. Templates may be {@link #compile precompiled}
10  * for greater performance.</p>
11  * <p>For example usage {@link #Template see the constructor}.</p>
12  * 
13  * @constructor
14  * An instance of this class may be created by passing to the constructor either
15  * a single argument, or multiple arguments:
16  * <div class="mdetail-params"><ul>
17  * <li><b>single argument</b> : String/Array
18  * <div class="sub-desc">
19  * The single argument may be either a String or an Array:<ul>
20  * <li><tt>String</tt> : </li><pre><code>
21 var t = new Ext.Template("&lt;div>Hello {0}.&lt;/div>");
22 t.{@link #append}('some-element', ['foo']);
23  * </code></pre>
24  * <li><tt>Array</tt> : </li>
25  * An Array will be combined with <code>join('')</code>.
26 <pre><code>
27 var t = new Ext.Template([
28     '&lt;div name="{id}"&gt;',
29         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
30     '&lt;/div&gt;',
31 ]);
32 t.{@link #compile}();
33 t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
34 </code></pre>
35  * </ul></div></li>
36  * <li><b>multiple arguments</b> : String, Object, Array, ...
37  * <div class="sub-desc">
38  * Multiple arguments will be combined with <code>join('')</code>.
39  * <pre><code>
40 var t = new Ext.Template(
41     '&lt;div name="{id}"&gt;',
42         '&lt;span class="{cls}"&gt;{name} {value}&lt;/span&gt;',
43     '&lt;/div&gt;',
44     // a configuration object:
45     {
46         compiled: true,      // {@link #compile} immediately
47         disableFormats: true // See Notes below.
48     } 
49 );
50  * </code></pre>
51  * <p><b>Notes</b>:</p>
52  * <div class="mdetail-params"><ul>
53  * <li>Formatting and <code>disableFormats</code> are not applicable for Ext Core.</li>
54  * <li>For a list of available format functions, see {@link Ext.util.Format}.</li>
55  * <li><code>disableFormats</code> reduces <code>{@link #apply}</code> time
56  * when no formatting is required.</li>
57  * </ul></div>
58  * </div></li>
59  * </ul></div>
60  * @param {Mixed} config
61  */
62 Ext.Template = function(html){
63     var me = this,
64         a = arguments,
65         buf = [];
66
67     if (Ext.isArray(html)) {
68         html = html.join("");
69     } else if (a.length > 1) {
70             Ext.each(a, function(v) {
71             if (Ext.isObject(v)) {
72                 Ext.apply(me, v);
73             } else {
74                 buf.push(v);
75             }
76         });
77         html = buf.join('');
78     }
79
80     /**@private*/
81     me.html = html;
82     /**
83      * @cfg {Boolean} compiled Specify <tt>true</tt> to compile the template
84      * immediately (see <code>{@link #compile}</code>).
85      * Defaults to <tt>false</tt>.
86      */
87     if (me.compiled) {
88         me.compile();
89     }
90 };
91 Ext.Template.prototype = {
92     /**
93      * @cfg {RegExp} re The regular expression used to match template variables.
94      * Defaults to:<pre><code>
95      * re : /\{([\w-]+)\}/g                                     // for Ext Core
96      * re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g      // for Ext JS
97      * </code></pre>
98      */
99     re : /\{([\w-]+)\}/g,
100     /**
101      * See <code>{@link #re}</code>.
102      * @type RegExp
103      * @property re
104      */
105
106     /**
107      * Returns an HTML fragment of this template with the specified <code>values</code> applied.
108      * @param {Object/Array} values
109      * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
110      * or an object (i.e. <code>{foo: 'bar'}</code>).
111      * @return {String} The HTML fragment
112      */
113     applyTemplate : function(values){
114                 var me = this;
115
116         return me.compiled ?
117                         me.compiled(values) :
118                                 me.html.replace(me.re, function(m, name){
119                                 return values[name] !== undefined ? values[name] : "";
120                         });
121         },
122
123     /**
124      * Sets the HTML used as the template and optionally compiles it.
125      * @param {String} html
126      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
127      * @return {Ext.Template} this
128      */
129     set : function(html, compile){
130             var me = this;
131         me.html = html;
132         me.compiled = null;
133         return compile ? me.compile() : me;
134     },
135
136     /**
137      * Compiles the template into an internal function, eliminating the RegEx overhead.
138      * @return {Ext.Template} this
139      */
140     compile : function(){
141         var me = this,
142                 sep = Ext.isGecko ? "+" : ",";
143
144         function fn(m, name){                        
145                 name = "values['" + name + "']";
146                 return "'"+ sep + '(' + name + " == undefined ? '' : " + name + ')' + sep + "'";
147         }
148                 
149         eval("this.compiled = function(values){ return " + (Ext.isGecko ? "'" : "['") +
150              me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
151              (Ext.isGecko ?  "';};" : "'].join('');};"));
152         return me;
153     },
154
155     /**
156      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
157      * @param {Mixed} el The context element
158      * @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'})
159      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
160      * @return {HTMLElement/Ext.Element} The new node or Element
161      */
162     insertFirst: function(el, values, returnElement){
163         return this.doInsert('afterBegin', el, values, returnElement);
164     },
165
166     /**
167      * Applies the supplied values to the template and inserts the new node(s) before el.
168      * @param {Mixed} el The context element
169      * @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'})
170      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
171      * @return {HTMLElement/Ext.Element} The new node or Element
172      */
173     insertBefore: function(el, values, returnElement){
174         return this.doInsert('beforeBegin', el, values, returnElement);
175     },
176
177     /**
178      * Applies the supplied values to the template and inserts the new node(s) after el.
179      * @param {Mixed} el The context element
180      * @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'})
181      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
182      * @return {HTMLElement/Ext.Element} The new node or Element
183      */
184     insertAfter : function(el, values, returnElement){
185         return this.doInsert('afterEnd', el, values, returnElement);
186     },
187
188     /**
189      * Applies the supplied <code>values</code> to the template and appends
190      * the new node(s) to the specified <code>el</code>.
191      * <p>For example usage {@link #Template see the constructor}.</p>
192      * @param {Mixed} el The context element
193      * @param {Object/Array} values
194      * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
195      * or an object (i.e. <code>{foo: 'bar'}</code>).
196      * @param {Boolean} returnElement (optional) true to return an Ext.Element (defaults to undefined)
197      * @return {HTMLElement/Ext.Element} The new node or Element
198      */
199     append : function(el, values, returnElement){
200         return this.doInsert('beforeEnd', el, values, returnElement);
201     },
202
203     doInsert : function(where, el, values, returnEl){
204         el = Ext.getDom(el);
205         var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
206         return returnEl ? Ext.get(newNode, true) : newNode;
207     },
208
209     /**
210      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
211      * @param {Mixed} el The context element
212      * @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'})
213      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
214      * @return {HTMLElement/Ext.Element} The new node or Element
215      */
216     overwrite : function(el, values, returnElement){
217         el = Ext.getDom(el);
218         el.innerHTML = this.applyTemplate(values);
219         return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
220     }
221 };
222 /**
223  * Alias for {@link #applyTemplate}
224  * Returns an HTML fragment of this template with the specified <code>values</code> applied.
225  * @param {Object/Array} values
226  * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
227  * or an object (i.e. <code>{foo: 'bar'}</code>).
228  * @return {String} The HTML fragment
229  * @member Ext.Template
230  * @method apply
231  */
232 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;
233
234 /**
235  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
236  * @param {String/HTMLElement} el A DOM element or its id
237  * @param {Object} config A configuration object
238  * @return {Ext.Template} The created template
239  * @static
240  */
241 Ext.Template.from = function(el, config){
242     el = Ext.getDom(el);
243     return new Ext.Template(el.value || el.innerHTML, config || '');
244 };