PageRenderTime 36ms CodeModel.GetById 22ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/ext-4.0.7/jsbuilder/src/Template.js

https://bitbucket.org/srogerf/javascript
JavaScript | 275 lines | 129 code | 20 blank | 126 comment | 22 complexity | 258325eecf3db9ff7b63623c8be403b7 MD5 | raw file
  1/**
  2 * @class Ext.Template
  3 * <p>Represents an HTML fragment template. Templates may be {@link #compile precompiled}
  4 * for greater performance.</p>
  5 * <p>For example usage {@link #Template see the constructor}.</p>
  6 *
  7 * @constructor
  8 * An instance of this class may be created by passing to the constructor either
  9 * a single argument, or multiple arguments:
 10 * <div class="mdetail-params"><ul>
 11 * <li><b>single argument</b> : String/Array
 12 * <div class="sub-desc">
 13 * The single argument may be either a String or an Array:<ul>
 14 * <li><tt>String</tt> : </li><pre><code>
 15var t = new Ext.Template("&lt;div>Hello {0}.&lt;/div>");
 16t.{@link #append}('some-element', ['foo']);
 17   </code></pre>
 18 * <li><tt>Array</tt> : </li>
 19 * An Array will be combined with <code>join('')</code>.
 20<pre><code>
 21var t = new Ext.Template([
 22    '&lt;div name="{id}"&gt;',
 23        '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
 24    '&lt;/div&gt;',
 25]);
 26t.{@link #compile}();
 27t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
 28   </code></pre>
 29 * </ul></div></li>
 30 * <li><b>multiple arguments</b> : String, Object, Array, ...
 31 * <div class="sub-desc">
 32 * Multiple arguments will be combined with <code>join('')</code>.
 33 * <pre><code>
 34var t = new Ext.Template(
 35    '&lt;div name="{id}"&gt;',
 36        '&lt;span class="{cls}"&gt;{name} {value}&lt;/span&gt;',
 37    '&lt;/div&gt;',
 38    // a configuration object:
 39    {
 40        compiled: true,      // {@link #compile} immediately
 41    }
 42);
 43   </code></pre>
 44 * <p><b>Notes</b>:</p>
 45 * <div class="mdetail-params"><ul>
 46 * <li>Formatting and <code>disableFormats</code> are not applicable for Sencha Touch.</li>
 47 * </ul></div>
 48 * </div></li>
 49 * </ul></div>
 50 * @param {Mixed} config
 51 */
 52Ext.Template = function(html) {
 53    var me = this,
 54        a = arguments,
 55        buf = [];
 56
 57    if (Ext.isArray(html)) {
 58        html = html.join("");
 59    }
 60    else if (a.length > 1) {
 61        Ext.each(a, function(v) {
 62            if (Ext.isObject(v)) {
 63                Ext.apply(me, v);
 64            } else {
 65                buf.push(v);
 66            }
 67        });
 68        html = buf.join('');
 69    }
 70
 71    // @private
 72    me.html = html;
 73    
 74    if (me.compiled) {
 75        me.compile();
 76    }
 77};
 78
 79Ext.Template.prototype = {
 80    isTemplate: true,
 81    
 82    re: /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
 83    argsRe: /^\s*['"](.*)["']\s*$/,
 84    compileARe: /\\/g,
 85    compileBRe: /(\r\n|\n)/g,
 86    compileCRe: /'/g,
 87    
 88    /**
 89     * @cfg {Boolean} disableFormats true to disable format functions in the template. If the template doesn't contain format functions, setting 
 90     * disableFormats to true will reduce apply time (defaults to false)
 91     */
 92    disableFormats: false,
 93    
 94    /**
 95     * Returns an HTML fragment of this template with the specified values applied.
 96     * @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'})
 97     * @return {String} The HTML fragment
 98     * @hide repeat doc
 99     */
100    applyTemplate: function(values) {
101        var me = this,
102            useF = me.disableFormats !== true,
103            fm = Ext.util.Format,
104            tpl = me,
105            re,
106            i,
107            len;
108
109        if (me.compiled) {
110            return me.compiled(values);
111        }
112        function fn(m, name, format, args) {
113            if (format && useF) {
114                if (format.substr(0, 5) == "this.") {
115                    return tpl.call(format.substr(5), values[name], values);
116                }
117                else {
118                    if (args) {
119                        // quoted values are required for strings in compiled templates,
120                        // but for non compiled we need to strip them
121                        // quoted reversed for jsmin
122                        re = me.argsRe;
123                        args = args.split(',');
124                        for (i = 0, len = args.length; i < len; i++) {
125                            args[i] = args[i].replace(re, "$1");
126                        }
127                        args = [values[name]].concat(args);
128                    }
129                    else {
130                        args = [values[name]];
131                    }
132                    return fm[format].apply(fm, args);
133                }
134            }
135            else {
136                return values[name] !== undefined ? values[name] : "";
137            }
138        }
139        return me.html.replace(me.re, fn);
140    },
141
142    /**
143     * Sets the HTML used as the template and optionally compiles it.
144     * @param {String} html
145     * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
146     * @return {Ext.Template} this
147     */
148    set: function(html, compile) {
149        var me = this;
150        me.html = html;
151        me.compiled = null;
152        return compile ? me.compile() : me;
153    },
154
155    /**
156     * Compiles the template into an internal function, eliminating the RegEx overhead.
157     * @return {Ext.Template} this
158     * @hide repeat doc
159     */
160    compile: function() {
161        var me = this,
162            fm = Ext.util.Format,
163            useF = me.disableFormats !== true,
164            body;
165
166        function fn(m, name, format, args) {
167            if (format && useF) {
168                args = args ? ',' + args: "";
169                if (format.substr(0, 5) != "this.") {
170                    format = "fm." + format + '(';
171                }
172                else {
173                    format = 'this.call("' + format.substr(5) + '", ';
174                    args = ", values";
175                }
176            }
177            else {
178                args = '';
179                format = "(values['" + name + "'] == undefined ? '' : ";
180            }
181            return "'," + format + "values['" + name + "']" + args + ") ,'";
182        }
183
184
185        body = ["this.compiled = function(values){ return ['"];
186        body.push(me.html.replace(me.compileARe, '\\\\').replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn));
187        body.push("'].join('');};");
188        body = body.join('');
189        eval(body);
190        return me;
191    },
192
193    /**
194     * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
195     * @param {Mixed} el The context element
196     * @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'})
197     * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
198     * @return {HTMLElement/Ext.Element} The new node or Element
199     */
200    insertFirst: function(el, values, returnElement) {
201        return this.doInsert('afterBegin', el, values, returnElement);
202    },
203
204    /**
205     * Applies the supplied values to the template and inserts the new node(s) before el.
206     * @param {Mixed} el The context element
207     * @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'})
208     * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
209     * @return {HTMLElement/Ext.Element} The new node or Element
210     */
211    insertBefore: function(el, values, returnElement) {
212        return this.doInsert('beforeBegin', el, values, returnElement);
213    },
214
215    /**
216     * Applies the supplied values to the template and inserts the new node(s) after el.
217     * @param {Mixed} el The context element
218     * @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'})
219     * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
220     * @return {HTMLElement/Ext.Element} The new node or Element
221     */
222    insertAfter: function(el, values, returnElement) {
223        return this.doInsert('afterEnd', el, values, returnElement);
224    },
225
226    /**
227     * Applies the supplied <code>values</code> to the template and appends
228     * the new node(s) to the specified <code>el</code>.
229     * <p>For example usage {@link #Template see the constructor}.</p>
230     * @param {Mixed} el The context element
231     * @param {Object/Array} values
232     * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
233     * or an object (i.e. <code>{foo: 'bar'}</code>).
234     * @param {Boolean} returnElement (optional) true to return an Ext.Element (defaults to undefined)
235     * @return {HTMLElement/Ext.Element} The new node or Element
236     */
237    append: function(el, values, returnElement) {
238        return this.doInsert('beforeEnd', el, values, returnElement);
239    },
240
241    doInsert: function(where, el, values, returnEl) {
242        el = Ext.getDom(el);
243        var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
244        return returnEl ? Ext.get(newNode, true) : newNode;
245    },
246
247    /**
248     * Applies the supplied values to the template and overwrites the content of el with the new node(s).
249     * @param {Mixed} el The context element
250     * @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'})
251     * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
252     * @return {HTMLElement/Ext.Element} The new node or Element
253     */
254    overwrite: function(el, values, returnElement) {
255        el = Ext.getDom(el);
256        el.innerHTML = this.applyTemplate(values);
257        return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
258    },
259
260    // private function used to call members
261    call: function(fnName, value, allValues) {
262        return this[fnName](value, allValues);
263    }
264};
265/**
266 * Alias for {@link #applyTemplate}
267 * Returns an HTML fragment of this template with the specified <code>values</code> applied.
268 * @param {Object/Array} values
269 * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
270 * or an object (i.e. <code>{foo: 'bar'}</code>).
271 * @return {String} The HTML fragment
272 * @member Ext.Template
273 * @method apply
274 */
275Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;