/* * utils - package-info.java - Copyright © 2010 David Roden * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * Light-weight template system. * * <h3>Writing Templates</h3> * * <p> * Inserting values and control structures such as loops into a template uses * a syntax that is well-known by other preprocessors, such es PHP or JSPs. * For example: * </p> * * <pre> * <html> * <head> * <title> * <% title > * </title> * </head> * </html> * </pre> * * <p> * This will insert the value of the template variable named “title” into the * template. * </p> * * <h3>Setting Template Variables</h3> * * <p> * Variables in a template are set using the * {@link net.pterodactylus.util.template.Template#set(String, Object)} method. * </p> * * <pre> * Template template = new Template(new FileReader("template.html")); * template.set("variable", "value"); * template.set("items", Arrays.asList("foo", "bar", "baz")); * template.render(outputWriter); * </pre> * * <h3>Looping Over Collections</h3> * * <p> * You can set the value of a template variable to an instance of * {@link java.util.Collection}. This allows you to iterate over the items in said collection: * </p> * * <pre> * <ul> * <%foreach pointCollection pointItem> * <li> * Item: <% pointItem> * </li> * <%/foreach> * </ul> * </pre> * * This will output the value of each item in the collection. * * <h3>Loop Properties</h3> * * <p> * Each iteration of a loop has numerous properties, such as being the first * iteration, or the last, or neither of them. These properties can be * accessed in a template. * </p> * * <pre> * <%foreach pointCollection pointItem> * <%first> * The collection contains the following items: * <ul> * <%/first> * <li> * Item: <% pointItem> * </li> * <%last> * </ul> * <%/last> * <%/foreach> * </pre> * * <p> * The loop properties that can be accessed in this way are: {@code first}, * {@code last}, {@code notfirst}, {@code notlast}, {@code odd}, {@code even}. * </p> * * <h3>Item Properties</h3> * * <p> * Template variable names can specify a hierarchy: “item.index” specifies the * member “index” of the value of template variable “item”. The default * template implementation can only handle getting members of template * variables that contain instances of {@link java.util.Map}; it is possible * to define member accessors for your own types (see below). * </p> * * <pre> * <ul> * <%foreach itemCollection item> * <li> * Item: <a href="item?id=<% item.id>"><% item.name></a> * </li> * <%/foreach> * </ul> * </pre> * * <p> * When {@code itemCollection} is properly set up this will print each item’s * name with a link to an item page that receives the ID of the item as * parameter. If {@code item} does not refer to a {@link java.util.Map} instance, * a custom accessor (see below) is necessary. * </p> * * <h3>Handling Custom Types</h3> * * <p> * The template system can be extended using * {@link net.pterodactylus.util.template.Accessor}s. An accessor is used to * allow template variable syntax like “object.foo”. Depending on the type of * {@code object} the appropriate accessor is used to find the value of the * member “foo” (which can e.g. be retrieved by calling a complicated operation * on {@code object}). * </p> * * <p> * With a custom type {@code Item} that exposes both an ID and a name (using * {@code getID()} and {@code getName()} methods), the following * {@link net.pterodactylus.util.template.Accessor} will allow the above * example to work. * </p> * * <pre> * public class ItemAccessor implements Accessor { * private final Item item; * public ItemAccessor(Item item) { this.item = item; } * public int getID() { return item.getID(); } * public String getName() { return item.getName(); } * } * </pre> * * <h3>Conditional Execution</h3> * * <p> * With a loop and its constructs (e.g. <%first> or <%even>) you * can already shape your formatted text in quite some ways. If for some * reason this is not enough you do have another possibility. * </p> * * <pre> * <p> * The color is: * <%if color.black> * black * <%elseif color.red> * red * <%elseif ! color.green> * not green * <%else> * green * <%/if> * </p> * </pre> * * <p> * At the moment the {@code <%if>} directive requires a single argument * which has to evaluate to a {@link java.lang.Boolean} object. The object may * be prepended by an exclamation point (“!”, either with or without * whitespace following it) to signify that the condition should be reversed. * Using a custom accessor this can easily be accomplished. Any further * parsing (and expression evaluation) would make the template parser and * renderer almost infinitely more complex (and very not-light-weight-anymore). * </p> * * <h3>Filtering Output</h3> * * <p> * One large issue when handling text in web pages is escaping the HTML code * so that the content of a web page does not have the capability of inserting * custom code into a web site, or destroying its design by unbalanced tags. * The template supports filtering output but does not have any output filters * added to it by default. * </p> * * <pre> * Template template = new Template(templateReader); * template.addFilter("html", new HtmlFilter()); * </pre> * * <p> * This will a filter for HTML to the list of available filters. If you want * to escape some text in your template, apply it using the pipe character * (“|”, with or without whitespace around it). * </p> * * <pre> * <div>Your name is <% name|html>, right?</div> * </pre> * * <p> * You can also use several filters for a single variable output. Those are * executed in the order they are specified. * </p> * * <pre> * <div>Your name is <% name|html|replace needle=Frank replacement=Steve>, right?</div> * </pre> * * <h3>Storing Values in the Template</h3> * * <p> * Sometimes it can be necessary to store a value in the template for later * use. In conjunction with a replacement filter this can be used to include * template variables in strings that are output by other filters, e.g. an * i18n filter. * </p> * * <pre> * <% user | html | store key='htmlUser'> * <% HelloText | i18n | html | insert needle='${user}' key='htmlUser'> * </pre> * * <p> * The “insert” filter can also read variables directly from the template. * </p> * * <h3>Internationalization / Localization (i18n, l10n)</h3> * * <p> * When creating web pages for larger projects you often have to deal with * multiple languages. One possibility to achieve multilingual support in a * template system would be to simply ignore language support in the template * system and create a new template for each language. However, this solution * is not desirable for any of the participating parties: the programmer has * to load a different template depending on the language; the designer has to * copy a desgin change into every translated template again; the translator * needs to copy and process a complete template, potentially missing * translatable items in a sea of design markup. * </p> * * <p> * One possible solution is the possibility to hardcode values in the template * and run them through arbitrary filters. * </p> * * <pre> * <div><%= Item.Name | i18n | html></div> * <div><% item.name | html></div> * <div><%= Item.ID | i18n | html></div> * <div><% item.id | html></div> * </pre> * * <p> * In this example the strings “Item.Name” and “Item.ID” are run through a * custom {@link net.pterodactylus.util.template.Filter} that replaces a * language-independent key into a translated string. To prevent nasty * surprises the translated string is also run through a HTML filter before * the final value is printed on the web page. * </p> * * <h3>Whitespace</h3> * * <p> * Sometimes, e.g. when using {@code <%=} or filters, whitespace in a filter * directive needs to be preserved. This can be accomplished by using single * quotes, double quotes, or a backslash. * </p> * * <h4>Single Quotes</h4> * * <p> * Single quotes preserve all characters until another single quote character * is encountered. * </p> * * <h4>Double Quotes</h4> * * <p> * Double quotes preserve all characters until either another double quote or * a backslash is encountered. * </p> * * <h4>Backslash</h4> * * <p> * The backslash preserves the next character but is discarded itself. * </p> * * <h4>Examples</h4> * * <pre> * <%= foo | replace needle=foo replacement="bar baz"> * </pre> * * <p> * This will replace the text “foo” with the text “bar baz”. * </p> * * <pre> * <%= "foo bar" | replace needle=foo replacement="bar baz"> * </pre> * * <p> * This will replace the text “foo bar” with the text “bar baz bar”. * </p> * * <pre> * <%= "foo bar" | replace needle='foo bar' replacement="bar baz"> * </pre> * * <p> * This will replace the text “foo bar” with the text “bar baz”. * </p> * * <pre> * <%= "foo bar" | replace needle=foo\ bar replacement="bar baz"> * </pre> * * <p> * This will also replace the text “foo bar” with the text “bar baz”. * </p> * * <pre> * <%= "foo bar" | replace needle="foo\ bar" replacement="bar baz"> * </pre> * * <p> * This will also replace the text “foo bar” with the text “bar baz”. * </p> * * <pre> * <%= "foo bar" | replace needle='foo\ bar' replacement="bar baz"> * </pre> * * <p> * This will not replace the text “foo bar” with anything because the text * “foo\ bar” is not found. * </p> * */ package net.pterodactylus.util.template;