try and get ctrl-enter to add a clear all
[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     html :  '&lt;div name="{id}"&gt;' + 
20         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
21         '&lt;/div&gt;',
22     myformat: function (value, allValues) {
23         return 'XX' + value;
24     }
25 });
26 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
27 </code></pre>
28 * For more information see this blog post with examples:
29 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
30      - Create Elements using DOM, HTML fragments and Templates</a>. 
31 * @constructor
32 * @param {Object} cfg - Configuration object.
33 */
34 Roo.Template = function(cfg){
35     // BC!
36     if(cfg instanceof Array){
37         cfg = cfg.join("");
38     }else if(arguments.length > 1){
39         cfg = Array.prototype.join.call(arguments, "");
40     }
41     
42     
43     if (typeof(cfg) == 'object') {
44         Roo.apply(this,cfg)
45     } else {
46         // bc
47         this.html = cfg;
48     }
49     if (this.url) {
50         this.load();
51     }
52     
53 };
54 Roo.Template.prototype = {
55     
56     /**
57      * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
58      */
59     onLoad : false,
60     
61     
62     /**
63      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
64      *                    it should be fixed so that template is observable...
65      */
66     url : false,
67     /**
68      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
69      */
70     html : '',
71     
72     
73     compiled : false,
74     loaded : false,
75     /**
76      * Returns an HTML fragment of this template with the specified values applied.
77      * @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'})
78      * @return {String} The HTML fragment
79      */
80     
81    
82     
83     applyTemplate : function(values){
84         //Roo.log(["applyTemplate", values]);
85         try {
86            
87             if(this.compiled){
88                 return this.compiled(values);
89             }
90             var useF = this.disableFormats !== true;
91             var fm = Roo.util.Format, tpl = this;
92             var fn = function(m, name, format, args){
93                 if(format && useF){
94                     if(format.substr(0, 5) == "this."){
95                         return tpl.call(format.substr(5), values[name], values);
96                     }else{
97                         if(args){
98                             // quoted values are required for strings in compiled templates, 
99                             // but for non compiled we need to strip them
100                             // quoted reversed for jsmin
101                             var re = /^\s*['"](.*)["']\s*$/;
102                             args = args.split(',');
103                             for(var i = 0, len = args.length; i < len; i++){
104                                 args[i] = args[i].replace(re, "$1");
105                             }
106                             args = [values[name]].concat(args);
107                         }else{
108                             args = [values[name]];
109                         }
110                         return fm[format].apply(fm, args);
111                     }
112                 }else{
113                     return values[name] !== undefined ? values[name] : "";
114                 }
115             };
116             return this.html.replace(this.re, fn);
117         } catch (e) {
118             Roo.log(e);
119             throw e;
120         }
121          
122     },
123     
124     loading : false,
125       
126     load : function ()
127     {
128          
129         if (this.loading) {
130             return;
131         }
132         var _t = this;
133         
134         this.loading = true;
135         this.compiled = false;
136         
137         var cx = new Roo.data.Connection();
138         cx.request({
139             url : this.url,
140             method : 'GET',
141             success : function (response) {
142                 _t.loading = false;
143                 _t.url = false;
144                 
145                 _t.set(response.responseText,true);
146                 _t.loaded = true;
147                 if (_t.onLoad) {
148                     _t.onLoad();
149                 }
150              },
151             failure : function(response) {
152                 Roo.log("Template failed to load from " + _t.url);
153                 _t.loading = false;
154             }
155         });
156     },
157
158     /**
159      * Sets the HTML used as the template and optionally compiles it.
160      * @param {String} html
161      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
162      * @return {Roo.Template} this
163      */
164     set : function(html, compile){
165         this.html = html;
166         this.compiled = false;
167         if(compile){
168             this.compile();
169         }
170         return this;
171     },
172     
173     /**
174      * True to disable format functions (defaults to false)
175      * @type Boolean
176      */
177     disableFormats : false,
178     
179     /**
180     * The regular expression used to match template variables 
181     * @type RegExp
182     * @property 
183     */
184     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
185     
186     /**
187      * Compiles the template into an internal function, eliminating the RegEx overhead.
188      * @return {Roo.Template} this
189      */
190     compile : function(){
191         var fm = Roo.util.Format;
192         var useF = this.disableFormats !== true;
193         var sep = Roo.isGecko ? "+" : ",";
194         var fn = function(m, name, format, args){
195             if(format && useF){
196                 args = args ? ',' + args : "";
197                 if(format.substr(0, 5) != "this."){
198                     format = "fm." + format + '(';
199                 }else{
200                     format = 'this.call("'+ format.substr(5) + '", ';
201                     args = ", values";
202                 }
203             }else{
204                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
205             }
206             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
207         };
208         var body;
209         // branched to use + in gecko and [].join() in others
210         if(Roo.isGecko){
211             body = "this.compiled = function(values){ return '" +
212                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
213                     "';};";
214         }else{
215             body = ["this.compiled = function(values){ return ['"];
216             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
217             body.push("'].join('');};");
218             body = body.join('');
219         }
220         /**
221          * eval:var:values
222          * eval:var:fm
223          */
224         eval(body);
225         return this;
226     },
227     
228     // private function used to call members
229     call : function(fnName, value, allValues){
230         return this[fnName](value, allValues);
231     },
232     
233     /**
234      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
235      * @param {String/HTMLElement/Roo.Element} el The context element
236      * @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'})
237      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
238      * @return {HTMLElement/Roo.Element} The new node or Element
239      */
240     insertFirst: function(el, values, returnElement){
241         return this.doInsert('afterBegin', el, values, returnElement);
242     },
243
244     /**
245      * Applies the supplied values to the template and inserts the new node(s) before el.
246      * @param {String/HTMLElement/Roo.Element} el The context element
247      * @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'})
248      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
249      * @return {HTMLElement/Roo.Element} The new node or Element
250      */
251     insertBefore: function(el, values, returnElement){
252         return this.doInsert('beforeBegin', el, values, returnElement);
253     },
254
255     /**
256      * Applies the supplied values to the template and inserts the new node(s) after el.
257      * @param {String/HTMLElement/Roo.Element} el The context element
258      * @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'})
259      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
260      * @return {HTMLElement/Roo.Element} The new node or Element
261      */
262     insertAfter : function(el, values, returnElement){
263         return this.doInsert('afterEnd', el, values, returnElement);
264     },
265     
266     /**
267      * Applies the supplied values to the template and appends the new node(s) to el.
268      * @param {String/HTMLElement/Roo.Element} el The context element
269      * @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'})
270      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
271      * @return {HTMLElement/Roo.Element} The new node or Element
272      */
273     append : function(el, values, returnElement){
274         return this.doInsert('beforeEnd', el, values, returnElement);
275     },
276
277     doInsert : function(where, el, values, returnEl){
278         el = Roo.getDom(el);
279         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
280         return returnEl ? Roo.get(newNode, true) : newNode;
281     },
282
283     /**
284      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
285      * @param {String/HTMLElement/Roo.Element} el The context element
286      * @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'})
287      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
288      * @return {HTMLElement/Roo.Element} The new node or Element
289      */
290     overwrite : function(el, values, returnElement){
291         el = Roo.getDom(el);
292         el.innerHTML = this.applyTemplate(values);
293         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
294     }
295 };
296 /**
297  * Alias for {@link #applyTemplate}
298  * @method
299  */
300 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
301
302 // backwards compat
303 Roo.DomHelper.Template = Roo.Template;
304
305 /**
306  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
307  * @param {String/HTMLElement} el A DOM element or its id
308  * @returns {Roo.Template} The created template
309  * @static
310  */
311 Roo.Template.from = function(el){
312     el = Roo.getDom(el);
313     return new Roo.Template(el.value || el.innerHTML);
314 };