Roo/Template.js
[roojs1] / Roo / Template.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12 /**
13 * @class Roo.Template
14 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
15 * For a list of available format functions, see {@link Roo.util.Format}.<br />
16 * Usage:
17 <pre><code>
18 var t = new Roo.Template(
19     '&lt;div name="{id}"&gt;',
20         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
21     '&lt;/div&gt;'
22 );
23 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
24 </code></pre>
25 * For more information see this blog post with examples: <a href="http://www.jackslocum.com/yui/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">DomHelper - Create Elements using DOM, HTML fragments and Templates</a>. 
26 * @constructor
27 * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
28 */
29 Roo.Template = function(html){
30     if(html instanceof Array){
31         html = html.join("");
32     }else if(arguments.length > 1){
33         html = Array.prototype.join.call(arguments, "");
34     }
35     /**@private*/
36     this.html = html;
37     
38 };
39 Roo.Template.prototype = {
40     /**
41      * Returns an HTML fragment of this template with the specified values applied.
42      * @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'})
43      * @return {String} The HTML fragment
44      */
45     applyTemplate : function(values){
46         try {
47             
48             if(this.compiled){
49                 return this.compiled(values);
50             }
51             var useF = this.disableFormats !== true;
52             var fm = Roo.util.Format, tpl = this;
53             var fn = function(m, name, format, args){
54                 if(format && useF){
55                     if(format.substr(0, 5) == "this."){
56                         return tpl.call(format.substr(5), values[name], values);
57                     }else{
58                         if(args){
59                             // quoted values are required for strings in compiled templates, 
60                             // but for non compiled we need to strip them
61                             // quoted reversed for jsmin
62                             var re = /^\s*['"](.*)["']\s*$/;
63                             args = args.split(',');
64                             for(var i = 0, len = args.length; i < len; i++){
65                                 args[i] = args[i].replace(re, "$1");
66                             }
67                             args = [values[name]].concat(args);
68                         }else{
69                             args = [values[name]];
70                         }
71                         return fm[format].apply(fm, args);
72                     }
73                 }else{
74                     return values[name] !== undefined ? values[name] : "";
75                 }
76             };
77             return this.html.replace(this.re, fn);
78         } catch (e) {
79             Roo.log(e);
80         }
81         return '';
82     },
83     
84     /**
85      * Sets the HTML used as the template and optionally compiles it.
86      * @param {String} html
87      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
88      * @return {Roo.Template} this
89      */
90     set : function(html, compile){
91         this.html = html;
92         this.compiled = null;
93         if(compile){
94             this.compile();
95         }
96         return this;
97     },
98     
99     /**
100      * True to disable format functions (defaults to false)
101      * @type Boolean
102      */
103     disableFormats : false,
104     
105     /**
106     * The regular expression used to match template variables 
107     * @type RegExp
108     * @property 
109     */
110     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
111     
112     /**
113      * Compiles the template into an internal function, eliminating the RegEx overhead.
114      * @return {Roo.Template} this
115      */
116     compile : function(){
117         var fm = Roo.util.Format;
118         var useF = this.disableFormats !== true;
119         var sep = Roo.isGecko ? "+" : ",";
120         var fn = function(m, name, format, args){
121             if(format && useF){
122                 args = args ? ',' + args : "";
123                 if(format.substr(0, 5) != "this."){
124                     format = "fm." + format + '(';
125                 }else{
126                     format = 'this.call("'+ format.substr(5) + '", ';
127                     args = ", values";
128                 }
129             }else{
130                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
131             }
132             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
133         };
134         var body;
135         // branched to use + in gecko and [].join() in others
136         if(Roo.isGecko){
137             body = "this.compiled = function(values){ return '" +
138                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
139                     "';};";
140         }else{
141             body = ["this.compiled = function(values){ return ['"];
142             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
143             body.push("'].join('');};");
144             body = body.join('');
145         }
146         /**
147          * eval:var:values
148          * eval:var:fm
149          */
150         eval(body);
151         return this;
152     },
153     
154     // private function used to call members
155     call : function(fnName, value, allValues){
156         return this[fnName](value, allValues);
157     },
158     
159     /**
160      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
161      * @param {String/HTMLElement/Roo.Element} el The context element
162      * @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'})
163      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
164      * @return {HTMLElement/Roo.Element} The new node or Element
165      */
166     insertFirst: function(el, values, returnElement){
167         return this.doInsert('afterBegin', el, values, returnElement);
168     },
169
170     /**
171      * Applies the supplied values to the template and inserts the new node(s) before el.
172      * @param {String/HTMLElement/Roo.Element} el The context element
173      * @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'})
174      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
175      * @return {HTMLElement/Roo.Element} The new node or Element
176      */
177     insertBefore: function(el, values, returnElement){
178         return this.doInsert('beforeBegin', el, values, returnElement);
179     },
180
181     /**
182      * Applies the supplied values to the template and inserts the new node(s) after el.
183      * @param {String/HTMLElement/Roo.Element} el The context element
184      * @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'})
185      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
186      * @return {HTMLElement/Roo.Element} The new node or Element
187      */
188     insertAfter : function(el, values, returnElement){
189         return this.doInsert('afterEnd', el, values, returnElement);
190     },
191     
192     /**
193      * Applies the supplied values to the template and appends the new node(s) to el.
194      * @param {String/HTMLElement/Roo.Element} el The context element
195      * @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'})
196      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
197      * @return {HTMLElement/Roo.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 = Roo.getDom(el);
205         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
206         return returnEl ? Roo.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 {String/HTMLElement/Roo.Element} el The context element
212      * @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'})
213      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
214      * @return {HTMLElement/Roo.Element} The new node or Element
215      */
216     overwrite : function(el, values, returnElement){
217         el = Roo.getDom(el);
218         el.innerHTML = this.applyTemplate(values);
219         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
220     }
221 };
222 /**
223  * Alias for {@link #applyTemplate}
224  * @method
225  */
226 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
227
228 // backwards compat
229 Roo.DomHelper.Template = Roo.Template;
230
231 /**
232  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
233  * @param {String/HTMLElement} el A DOM element or its id
234  * @returns {Roo.Template} The created template
235  * @static
236  */
237 Roo.Template.from = function(el){
238     el = Roo.getDom(el);
239     return new Roo.Template(el.value || el.innerHTML);
240 };