All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sencha.gxt.core.client.XTemplates Maven / Gradle / Ivy

There is a newer version: 3.1.1
Show newest version
/**
 * Sencha GXT 3.0.1 - Sencha for GWT
 * Copyright(c) 2007-2012, Sencha, Inc.
 * [email protected]
 *
 * http://www.sencha.com/products/gxt/license/
 */
package com.sencha.gxt.core.client;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.sencha.gxt.core.client.XTemplates.FormatterFactories;
import com.sencha.gxt.core.client.XTemplates.FormatterFactory;
import com.sencha.gxt.core.client.XTemplates.FormatterFactoryMethod;
import com.sencha.gxt.core.client.XTemplates.TemplateCondition;

/**
 * A tag interface for declaring methods that accept objects and convert them into HTML based
 * on an associated template. Methods return {@link SafeHtml} instances which can be used in many
 * GWT and GXT widgets to render content. XTemplates support a variety of features to make it easy
 * to generate content, including:
 * 
 * 
    *
  • Reading properties and nested properties
  • *
  • Formatting data into strings
  • *
  • Collection and Array iterating, applying sub templates to each item
  • *
  • Conditional support, including the ability to call other Java methods that return boolean
  • *
  • Basic math and expression support
  • *
* *
* * Declaring a Template * *

* Templates are declared by creating a new interface that extends {@code XTemplate}, or by * extending another interface that extends {@code XTemplate}. Instances can then be created by * invoking {@code GWT.create} on the template class, and then methods can be invoked. *

*

* Template method content is created in one of two ways: either by declaring the template content * in the {@code @XTemplate} annotation, or by creating a new html file and pointing the * {@code @XTemplate} annotation at that file. *

*

public interface SampleXTemplates extends XTemplates {
  {@literal @}XTemplate("<div>Hello, {name}!</div>")
  SafeHtml hello(String name);

  {@literal @}XTemplate(source="hello.html")
  SafeHtml helloExternal(String name);
}

private SampleXTemplates tpl = GWT.create(SampleXTemplates.class);
*

* In this example, {@code tpl.hello("test")} would return a {@code SafeHtml} instance representing * the html *

<div>Hello, test!<div>
* while {@code tpl.hello("test")} would have its content depend on the template defined in the file * {@code hello.html} in the same package. * *
    *
  • * Reading properties *

    * This is the data used for reference in each code sample: *

    *
    
    public class Kid {
      public Kid(String name, int age) ...
    
      public String getName() ...
      public int getAge() ...
    }
    public class Person {
      public Person(String name, String company, String product, String location) ...
    
      public String getName() ...
      public String getCompany() ...
      public String getProduct() ...
      public String getLocation() ...
      public List<Kid> getKids() ...
    
      public void setKids(List<Kid> kids) ...
    }
    
    final Person person = new Person("Darrell Meyer", "Sencha Inc", "GXT", "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);
    
    *

    * Properties are read by naming the object or property to read in {@code { ... }} brackets in the * template body. In the main template (not in a {@code <tpl for="...">} tag) these will be * scoped based on the arguments to the template. If there is only one argument, the argument may * be named, or properties may be referred to directly. If there are multiple arguments, they must * be named. *

    *
    
    interface ReadingPropertiesTemplates extends XTemplates {
      {@literal @}XTemplate("Hello, {name}, from {person.location}") // either works
      SafeHtml oneArgument(Person person);
      
      {@literal @}XTemplate("Hello, {one.name}, {two.name}, and {three.name}!")
      SafeHtml twoArguments(Kid one, Kid two, Kid three);
    }
    ReadingPropertiesTemplates tpl = GWT.create(ReadingPropertiesTemplates.class);
    SafeHtml parentContent = tpl.oneArgument(person);
    SafeHtml childrenContent = tpl.twoArguments(person.get(0), person.get(1), person.get(2));
    
    *

    * Nested properties are read by separating each getter or method call with a '{@code .}'. * Properties are most often read from getter methods, but can also be read from zero-arg methods * by using their full name. As a result of this, the size of the list retrieved from * {@code Person.getKids()} can be expressed as {@code kids.size}: *

    *
    
    interface PersonWithKidsTemplate extends XTemplates {
      {@literal @}XTemplate("{name} has {kids.size} children")
      SafeHtml renderChildCount(Person p);
    }
    PersonWithKidsTemplate tpl = GWT.create(PersonWithKidsTemplate.class);
    SafeHtml content = tpl.renderChildCount(person);
    
    *
  • *
  • * Formatting data into strings *

    *
    * Values can be formatted using the following syntax: * *
    *

      *
    • {@code {value:formatName}} - no format param
    • *
    • {@code {value:formatName(format)}} - with format param
    • *
    *
    * Built-in formats: *
      *
    • {@code date(format)} - format syntax uses GWT DateTimeFomat (example: * {@code {mydate:date("m/d/yyyy")})}
    • *
    • {@code number(format)} - format syntax uses GWT NumberFormat (example: * {@code {mynumber:number("0000.0000")})}
    • *
    • {@code currency} - no parameters
    • *
    • {@code scientific} - no parameters
    • *
    • {@code decimal} - no parameters
    • * *
    *
    * Additional formatters can be created and registered when creating an XTemplate. They can be * declared on any class - when an XTemplates type is declared, it, and all parents will be checked * for formatters to use. Formatters can be redeclared when a type is extended - the type closest to * the final type will override other formatters. * *

    *
  • *
  • * Collections and Arrays *

    *

    *
    * The tpl tag and the for operator are used to * process the provided data object: *

      *
    • If the value specified in for is an array, it will auto-fill, * repeating the template block inside the tpl tag for each item in the * array.
    • *
    • If for="." is specified, the data object provided is examined.
    • *
    • While processing an array, the special variable {#} will provide * the current array index + 1 (starts at 1, not 0).
    • *
    *

    * *
    
    <tpl for=".">...</tpl>       // loop through array at root node
    <tpl for="foo">...</tpl>     // loop through array at foo node
    <tpl for="foo.bar">...</tpl> // loop through array at foo.bar node
     * 
    * Using the sample data above: * *
    
    interface KidListTemplate extends XTemplates {
      {@literal @}XTemplate("<p>Kids: " +
                 "<tpl for='.'>" +       // process the data.kids node
                 "<p>{#}. {name}</p>" +  // use current array index to autonumber
                 "</tpl></p>")
      SafeHtml listKids(List<Kid> kids);
    }
    KidListTemplate tpl = GWT.create(KidListTemplate.class);
    SafeHtml content = tpl.listKids(person.getKids()); // pass the kids property of the data object
     * 
    *

    * An example illustrating how the for property can be leveraged * to access specified members of the provided data object to populate the * template: *

    * *
    
    interface NestedListTemplate extends XTemplates {
      {@literal @}XTemplate("<p>Name: {name}</p>" +
                 "<p>Title: {title}</p>" +
                 "<p>Company: {company}</p>" +
                 "<p>Kids: " +
                 "<tpl for='kids'>" +     // interrogate the kids property within the data
                   "<p>{name}</p>" +
                 "</tpl></p>")
       SafeHtml renderPerson(Person person);
    }
    SafeHtml content = tpl.renderPerson(person);
     * 
    *

    * * When processing a sub-template, for example while looping through a child * array, you can access the parent object's members via the parent * object: *

    * *
    
    interface ParentChildTemplate extends XTemplates {
      {@literal @}XTemplate("<p>Name: {name}</p>" +
                 "<p>Kids: " +
                 "<tpl for=\"kids\">" +
                   "<tpl if=\"age > 1\">" +
                     "<p>{name}</p>" +
                     "<p>Dad: {parent.name}</p>" +
                   "</tpl>" +
                 "</tpl></p>")
      SafeHtml renderParentAndChildren(Person person);
    }
    SafeHtml content = tpl.renderParentAndChildren(person);
     * 
    *

    *
  • *
  • * Conditional support *

    *
    * The tpl tag and the if operator are used to * provide conditional checks for deciding whether or not to render specific * parts of the template. Notes:

    *
      *
    • If quotes are to be used in the conditionals, they must either be different quotes than were * used to define the if, or must be escaped.
    • *
    • Greater-than (>) symbols must be escaped within conditionals as &gt;
    • *
    • There is no else operator — if needed, two opposite * if statements should be used.
    • *
    * *
    
    <tpl if="age > 1 && age < 10">Child</tpl>
    <tpl if="age >= 10 && age < 18">Teenager</tpl>
    <tpl if="id==\'download\'">...</tpl>
    <tpl if="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>
     * 
    * Using the sample data above: * *
    
    interface OlderChildListTemplate extends XTemplates {
      {@literal @}XTemplate("<p>Name: {name}</p>" +
                 "<p>Kids: " +
                 "<tpl for=\"kids\">" +   // either double quotes (escaped)
                   "<tpl if='age > 1'>" + // or single are allowed
                     "<p>{name}</p>" + // (no need to escape either in an external file)
                   "</tpl>" +
                 "</tpl></p>")
      SafeHtml renderFamilyOf(Person person);
    );
    SafeHtml content = tpl.renderFamilyOf(person);
     * 
    *
    *
  • *
  • * Basic math and expressions *

    *
    * The following basic math operators may be applied directly on numeric data * values: *

    * *
     * + - * /
     * 
    * * To be returned as part of the template, expressions must be contained within {@code {[ ... ]}} * brackets. * *
    * For example: * *
    
    interface FutureAgesTemplate extends XTemplates {
      {@literal @}XTemplate("<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>")
      SafeHtml renderFutureChildAges(Person person);
    );
    SafeHtml content = tpl.renderFutureChildAges(person);
    
    *
  • * */ @FormatterFactories({ @FormatterFactory(factory = DateTimeFormat.class, methods = @FormatterFactoryMethod(name = "date", defaultArgs = "\"M/d/y\"")), @FormatterFactory(factory = NumberFormat.class, methods = { @FormatterFactoryMethod(name = "scientific", method = "getScientificFormat"), @FormatterFactoryMethod(name = "decimal", method = "getDecimalFormat"), @FormatterFactoryMethod(name = "currency", method = "getCurrencyFormat"), @FormatterFactoryMethod(name = "number", method = "getFormat", defaultArgs = "\"#\""), @FormatterFactoryMethod(name = "percentage", method = "getPercentFormat") })}) @TemplateCondition(methodName = "equals", type = Object.class) public interface XTemplates { /** * Indicates the string that should be used when generating the template. * Either an html string can be specified (like * {@link com.google.gwt.safehtml.client.SafeHtmlTemplates}, or a source file * may be specified. * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface XTemplate { /** * The template itself, defined inline */ String value() default ""; /** * The filename of the html file containing the template. The path is * relative to the current package. */ String source() default ""; } /** * A simple interface to facilitate creation of custom formatters. Instances should be created * by a static factory method, as defined by {@link FormatterFactories}. * * @param the type of data the formatter is intended to handle */ public interface Formatter { /** * Formats the given data so it can be drawn in the template as a plain string. * * @param data the parameter passed in from the template. Will never be null unless {@link FormatterFactory#acceptsNull()} is true * @return a string to render in the template */ String format(T data); } /** * Collection of {@link FormatterFactory} instances. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FormatterFactories { FormatterFactory[] value(); } /** * Declares that a class may act as a factory to provide formatter instances. * Either the name attribute must be populated with the name that this factory * will use in an XTemplate and the method getFormat will be called, or the * methods must indicate a name and a methodName to be invoked on the factory. * */ @Target({}) @Retention(RetentionPolicy.RUNTIME) public @interface FormatterFactory { Class factory(); /** * The name of the formatter being registered. If blank, then {@link #methods()} is assumed to * contain factory methods instead. * * @return name of the formatter being registered. */ String name() default ""; /** * Allows methods to be defined on a formatter factory with a name other that {@code getFormat}, * and allowed more than one factory method to be defined. * * @return one or more factory methods */ FormatterFactoryMethod[] methods() default {}; /** * True if the formatter can handle null values. If false, a null value will be rendered directly * as an empty string. * * @return false if null values should be rendered as an empty string and not formatted */ boolean acceptsNull() default false; } /** * Allows methods to be called on a factory other than 'getFormat'. More than * one instance of this may be provided to a {@link FormatterFactory} * annotation to register multiple method within the same factory. * */ @Target({}) @Retention(RetentionPolicy.RUNTIME) public @interface FormatterFactoryMethod { /** * The name of the formatter being registered. This name will be what is referenced * from the XTemplate source. * * @return the name of the formatter as it will be used in xtemplate source */ String name(); /** * The name of the method to invoke to produce a formatter. Defaults to {@code getFormat} * @return the name of the static method to invoke to produce a formatter */ String method() default "getFormat"; /** * Default arguments to pass into the format method if none are specified in the XTemplate * source. * * @return the default arguments to pass into the formatter factory method */ String defaultArgs() default ""; } /** * Defines a single method on an object that should be accessible from within XTemplate * conditional statements. * * By default, {@link Object#equals(Object)} is defined as :equals in an XTemplate, so this is * legal: *
    
    interface TemplateUsingEquals extends XTemplates {
      {@literal @}XTemplate("<tpl if='o1:equals(o2)'>true</tpl>")
      SafeHtml tpl(Object o1, Object o2);
    }
    
    * */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TemplateCondition { /** * The name of the method to define. Defaults to the {@link #methodName()}. * * @return the name of the method as it will be used in XTemplate source, or "" if the same * as {@link #methodName()} */ String name() default ""; /** * @return the type the condition method is defined on. */ Class type(); /** * The name of the method to invoke from a compiled template. This method must exist on * {@link #type()} or a superclass. * @return the method to invoke on {@link #type()} */ String methodName(); } /** * Holds a collection of {@link TemplateCondition} instances, allowing more than one to be * declared at a time. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TemplateConditions { TemplateCondition[] value(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy