/* * Ext GWT 2.2.4 - Ext for GWT * Copyright(c) 2007-2010, Ext JS, LLC. * licensing@extjs.com * * http://extjs.com/license */ package com.extjs.gxt.ui.client.core; import com.extjs.gxt.ui.client.GXT; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.user.client.Element; /** * A template class that supports advanced functionality like: * * <ul> * <li>Formatting</li> * <li>Autofilling arrays using templates and sub-templates</li> * <li>Conditional processing with basic comparison operators</li> * <li>Basic math function support</li> * <li>Execute arbitrary inline code with special built-in template variables</li> * </ul> * * <p> * Usage * </p> * <ul> * <li><b>Sample Data</b> * <p> * <br> * This is the data used for reference in each code example: * </p> * * <pre><code> class Kid extends BaseModelData { public Kid(String name, int age) { set("name", name); set("age", age); } } class Person extends BaseModelData { public Person(String name, String company, String product, String location) { set("name", name); set("company", company); set("product", product); set("location", location); } public void setKids(List<Kid> kids) { set("kids", kids); } public List<Kid> getKids() { return get("kids"); } } final Person person = new Person("Darrell Meyer", "Sencha Inc", "Ext GWT", "Washington, DC"); List<Kid> kids = new ArrayList<Kid>(); kids.add(new Kid("Alec", 4)); kids.add(new Kid("Lia", 2)); kids.add(new Kid("Andrew", 1)); person.setKids(kids); * </code></pre> * </div></li> * * <li><b>Formatting</b> * * <p> * <br> * Values can be formatted using the following syntax: * * <br> * <ul> * <li>{value:formatName} - no format param</li> * <li>{value:formatName(format)} - with format param</li></li> * </ul> * <br> * Available formats: * <ul> * <li>date(format) - format syntax uses GWT DateTimeFomat (example: * {mydate:date("m/d/yyyy")})</li> * <li>number(format) - format syntax uses GWT NumberFormat (example: * {mynumber:number("0000.0000")})</li> * <li>currency - no parameters</li> * <li>scientific - no parameters</li> * <li>decimal - mo parameters</li> * * </ul> * * </p> </li> * * <li><b>Auto filling of arrays</b> * <p> * <br> * The <b><tt>tpl</tt></b> tag and the <b><tt>for</tt></b> operator are used to * process the provided data object: * <ul> * <li>If the value specified in <tt>for</tt> is an array, it will auto-fill, * repeating the template block inside the <tt>tpl</tt> tag for each item in the * array.</li> * <li>If <tt>for="."</tt> is specified, the data object provided is examined.</li> * <li>While processing an array, the special variable <tt>{#}</tt> will provide * the current array index + 1 (starts at 1, not 0).</li> * </ul> * </p> * * <pre><code> <tpl <b>for</b>=".">...</tpl> // loop through array at root node <tpl <b>for</b>="foo">...</tpl> // loop through array at foo node <tpl <b>for</b>="foo.bar">...</tpl> // loop through array at foo.bar node * </code></pre> * Using the sample data above: * * <pre><code> // generating strings in native methods easier than in Java, can be created in Java as well public native String getTemplate() /*-{ return ['<p>Kids: ', '<tpl <b>for</b>=".">', // process the data.kids node '<p>{#}. {name}</p>', // use current array index to autonumber '</tpl></p>' ].join(""); ); XTemplate tpl = XTemplate.create(getTemplate()); tpl.overwrite(someElement, Util.getJsObject(person.getKids())); // pass the kids property of the data object * </code></pre> * <p> * An example illustrating how the <b><tt>for</tt></b> property can be leveraged * to access specified members of the provided data object to populate the * template: * </p> * * <pre><code> public native String getTemplate() /*-{ return ['<p>Name: {name}</p>', '<p>Title: {title}</p>', '<p>Company: {company}</p>', '<p>Kids: ', '<tpl <b>for="kids"</b>>', // interrogate the kids property within the data '<p>{name}</p>', '</tpl></p>' ].join(""); ); template.overwrite(someElement, Util.getJsObject(person)); * </code></pre> * <p> * * When processing a sub-template, for example while looping through a child * array, you can access the parent object's members via the <b><tt>parent</tt> * </b> object: * </p> * * <pre><code> public native String getTemplate() /*-{ return ['<p>Name: {name}</p>', '<p>Kids: ', '<tpl for="kids">', '<tpl if="age > 1">', '<p>{name}</p>', '<p>Dad: {<b>parent</b>.name}</p>', '</tpl>', '</tpl></p>' ].joint(""); ); template.overwrite(someElement, Util.getJsObject(person)); * </code></pre> * </div></li> * * * <li><b>Conditional processing with basic comparison operators</b> * <p> * <br> * The <b><tt>tpl</tt></b> tag and the <b><tt>if</tt></b> operator are used to * provide conditional checks for deciding whether or not to render specific * parts of the template. Notes:<div class="sub-desc"> * <ul> * <li>Double quotes must be encoded if used within the conditional</li> * <li>There is no <tt>else</tt> operator — if needed, two opposite * <tt>if</tt> statements should be used.</li> * </ul> * </div> * * <pre><code> <tpl if="age > 1 && age < 10">Child</tpl> <tpl if="age >= 10 && age < 18">Teenager</tpl> <tpl <b>if</b>="id==\'download\'">...</tpl> <tpl <b>if</b>="needsIcon"><img src="{icon}" class="{iconCls}"/></tpl> // no good: <tpl if="name == "Jack"">Hello</tpl> // encode " if it is part of the condition, e.g. <tpl if="name == &quot;Jack&quot;">Hello</tpl> * </code></pre> * Using the sample data above: * * <pre><code> public native String getTemplate() /*-{ return ['<p>Name: {name}</p>', '<p>Kids: ', '<tpl for="kids">', '<tpl if="age > 1">', '<p>{name}</p>', '</tpl>', '</tpl></p>' ].join(""); ); template.overwrite(someElement, Util.getJsObject(person)); * </code></pre> * </div></li> * * <li><b>Basic math support</b> * <p> * <br> * The following basic math operators may be applied directly on numeric data * values: * </p> * * <pre> * + - * / * </pre> * For example: * * <pre><code> public native String getTemplate() /*-{ return ['<p>Name: {name}</p>', '<p>Kids: ', '<tpl for="kids">', '<tpl if="age &gt; 1">', // <-- Note that the > is encoded '<p>{#}: {name}</p>', // <-- Auto-number each item '<p>In 5 Years: {age+5}</p>', // <-- Basic math '<p>Dad: {parent.name}</p>', '</tpl>', '</tpl></p>' ].join(""); ); template.overwrite(someElement, Util.getJsObject(person)); </code></pre> * </li> * * <li><b>Execute arbitrary inline code with special built-in template * variables</b> * <p> * <br> * Anything between <code>{[ ... ]}</code> is considered code to be executed in * the scope of the template. There are some special variables available in that * code: * <ul> * <li><b><tt>values</tt></b>: The values in the current scope. If you are using * scope changing sub-templates, you can change what <tt>values</tt> is.</li> * <li><b><tt>parent</tt></b>: The scope (values) of the ancestor template.</li> * <li><b><tt>xindex</tt></b>: If you are in a looping template, the index of * the loop you are in (1-based).</li> * <li><b><tt>xcount</tt></b>: If you are in a looping template, the total * length of the array you are looping.</li> * <li><b><tt>fm</tt></b>: An alias for <tt>Ext.util.Format</tt>.</li> * </ul> * This example demonstrates basic row striping using an inline code block and * the <tt>xindex</tt> variable: * </p> * * <pre><code> public native String getTemplate() /*-{ return ['<p>Name: {name}</p>', '<p>Company: {[values.company.toUpperCase() + ", " + values.title]}</p>', '<p>Kids: ', '<tpl for="kids">', '<div class="{[xindex % 2 === 0 ? "even" : "odd"]}">', '{name}', '</div>', '</tpl></p>' ].join(""); ); template.overwrite(someElement, Util.getJsObject(person)); * </code></pre> * </div></li> * * <li><b>Template member functions</b> <div class="sub-desc"> * <p><br> * One or more member functions can be specified in a configuration object * passed into the XTemplate constructor for more complex processing: * </p> * * <pre><code> var tpl = new Ext.XTemplate( '<p>Name: {name}</p>', '<p>Kids: ', '<tpl for="kids">', '<tpl if="this.isGirl(name)">', '<p>Girl: {name} - {age}</p>', '</tpl>', // use opposite if statement to simulate 'else' processing: '<tpl if="this.isGirl(name) == false">', '<p>Boy: {name} - {age}</p>', '</tpl>', '<tpl if="this.isBaby(age)">', '<p>{name} is a baby!</p>', '</tpl>', '</tpl></p>', { // XTemplate configuration: compiled: true, disableFormats: true, // member functions: isGirl: function(name){ return name == 'Sara Grace'; }, isBaby: function(age){ return age < 1; } } ); tpl.overwrite(panel.body, data); * </code></pre> * </div></li> </ul> * * */ public final class XTemplate extends JavaScriptObject { static { GXT.init(); Ext.loadExt(); Ext.loadDomHelper(); Ext.loadFormat(); Ext.loadTemplate(); Ext.loadXTemplate(); } /** * Specifies the maximum number of nested models to search when preparing the * templates data (defaults to 4). * * @param maxDepth the maximum number of nested children */ public final native void setMaxDepth(int maxDepth) /*-{ this.maxDepth = maxDepth; }-*/; /** * Returns the maximum number of nested children to process when preparing the * template's data. * * @return the max depth */ public final native int getMaxDepth() /*-{ if (!this.maxDepth) { this.maxDepth = 4; } return this.maxDepth; }-*/; /** * Returns a new template instance using the given html. * * @param html the template * @return a new template instance */ public static native XTemplate create(String html) /*-{ return new $wnd.GXT.Ext.XTemplate(html); }-*/; protected XTemplate() { } public final native Element append(Element elem, JavaScriptObject values) /*-{ return this.append(elem, values); }-*/; /** * Returns an HTML fragment of this template with the specified values * applied. * * @param values the substitution values * @return the html fragment */ public final native String applyTemplate(JavaScriptObject values) /*-{ return this.applyTemplate(values); }-*/; /** * Compiles the template into an internal function, eliminating the regex * overhead. */ public final native void compile() /*-{ this.compile(); }-*/; /** * Applies the supplied values to the template and inserts the new node(s) * after elem. * * @param elem the context element * @param values the substitution values */ public final native void insertAfter(Element elem, JavaScriptObject values) /*-{ this.insertAfter(elem, values); }-*/; /** * Applies the supplied values to the template and inserts the new node(s) * before elem. * * @param elem the context element * @param values the substitution values */ public final native void insertBefore(Element elem, JavaScriptObject values) /*-{ this.insertBefore(elem, values); }-*/; /** * Applies the supplied values to the template and overwrites the content of * elem with the new node(s). * * @param elem the context element * @param values the substitution values */ public final native void overwrite(Element elem, JavaScriptObject values) /*-{ this.overwrite(elem, values); }-*/; }