Modified: websites/production/tapestry/content/layout-component.html ============================================================================== --- websites/production/tapestry/content/layout-component.html (original) +++ websites/production/tapestry/content/layout-component.html Sat Feb 17 12:21:22 2018 @@ -145,7 +145,7 @@ </div> -<p>You'll see frequent reference to a <strong>Layout Component</strong> in Tapestry documentation, but you won't find such a component in the <a href="layout-component.html">component reference</a>. The Layout component is a component <em>that you create</em> to provide common elements across all of your pages.</p><p>In traditional servlet development, you may be familiar with the use of a JSP include to include a banner across the top of your page and a copyright message across the bottom. In Tapestry, you <em>could</em> implement those recurring page elements as components (a banner component, a copyright component, etc.) and then add those components to every page.</p><p>But there's an even better way. Just create a layout component that provides the overall structure and recurring content for your pages:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Layout.tml (a template for a Layout compo nent)</b></div><div class="codeContent panelContent pdl"> +<p>You'll see frequent reference to a <strong>Layout Component</strong> in Tapestry documentation, but you won't find such a component in the <a href="component-reference.html">component reference</a>. The Layout component is a component <em>that you create</em> to provide common elements across all of your pages.</p><p>In traditional servlet development, you may be familiar with the use of a JSP include to include a banner across the top of your page and a copyright message across the bottom. In Tapestry, you <em>could</em> implement those recurring page elements as components (a banner component, a copyright component, etc.) and then add those components to every page.</p><p>But there's an even better way. Just create a layout component that provides the overall structure and recurring content for your pages:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Layout.tml (a template for a Layout co mponent)</b></div><div class="codeContent panelContent pdl"> <pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"><html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"> <head> <title>My Nifty Web Application</title> @@ -173,13 +173,13 @@ </p> </html> </pre> -</div></div><p>Note the "t:type="layout" part. That says, in effect, "wrap the layout component around my <em>content</em>".</p><p>The magic is in the <t:body/> element of the layout template; this will be replaced by each page's <em>content</em>, whatever that is.</p><div class="confluence-information-macro confluence-information-macro-information"><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Remember that if your layout component includes a link to a resource such as an image or a stylesheet, you must use an <em>absolute</em> URL. The same component will be used for pages in many different folders, or with many different activation contexts, so relative URLs won't work. The best approach is to use the <a href="layout-component.html">context binding prefix</a>.</p></div></div><p>To keep our Welcome.tml page template relatively preview-able, we are using an <html> eleme nt and the t:type attribute to specify that it is a component. At render time, the page's <html> tag will be removed, and replaced with the content from the Layout.tml template (which conveniently starts with an <html> element). The <t:body> element in Layout.tml will be replaced with the page-specific content here: the <h1> and <p> tags.</p><p>Any page in the application that follows this pattern, using the Layout component, will have the same look and feel.</p><p>Layout is a regular component like other, with an ordinary component template. Like all component templates, it will be stored on the classpath (typically under src/main/resources).</p><p>Components must always have a Java class. But in this trivial example, the Layout component doesn't need any logic:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Layout.java</b></div><div class="codeContent panelContent pdl"> +</div></div><p>Note the "t:type="layout" part. That says, in effect, "wrap the layout component around my <em>content</em>".</p><p>The magic is in the <t:body/> element of the layout template; this will be replaced by each page's <em>content</em>, whatever that is.</p><div class="confluence-information-macro confluence-information-macro-information"><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Remember that if your layout component includes a link to a resource such as an image or a stylesheet, you must use an <em>absolute</em> URL. The same component will be used for pages in many different folders, or with many different activation contexts, so relative URLs won't work. The best approach is to use the <a href="assets.html">context binding prefix</a>.</p></div></div><p>To keep our Welcome.tml page template relatively preview-able, we are using an <html> element and the t:type attribute to specify that it is a component. At render time, the page's <html> tag will be removed, and replaced with the content from the Layout.tml template (which conveniently starts with an <html> element). The <t:body> element in Layout.tml will be replaced with the page-specific content here: the <h1> and <p> tags.</p><p>Any page in the application that follows this pattern, using the Layout component, will have the same look and feel.</p><p>Layout is a regular component like other, with an ordinary component template. Like all component templates, it will be stored on the classpath (typically under src/main/resources).</p><p>Components must always have a Java class. But in this trivial example, the Layout component doesn't need any logic:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Layout.java</b></div><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@Import(stylesheet="context:css/site.css") public class Layout { } </pre> -</div></div><p>We use the @<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Import.html">Import</a> annotation (in 5.2 or later), as opposed to directly adding the <link> element to the template, for significant performance benefits <a href="layout-component.html">described elsewhere</a>. (For 5.0 and 5.1, use the deprecated @<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/IncludeStylesheet.html">IncludeStyleSheet</a> annotation instead.)</p><p>You may find that your application has more than one look and feel: perhaps user registration pages have one look, while administrative pages have another. This can be accomplished by having multiple layout components (using any names you choose) and using those different layout types for different pages.</p><h2 id="LayoutComponent-NestedLayouts">Nested Layouts</h2><p>Layouts are really just ordinary components, so the y can be nested to any level needed. You can have, for example, a "CommonLayout" component that provides the peripheral elements for all your pages, and then a more specialized "AdminLayout" component that provides the layout only for the administrative pages, and make the AdminLayout component wrap itself in the CommonLayout component. So then the administrative pages would start with <code><html t:type="adminLayout" ...></code> and the other pages (and the AdminLayout component itself) would start with <code><html t:type="commonLayout" ...></code>.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>AdminLayout.tml</b></div><div class="codeContent panelContent pdl"> +</div></div><p>We use the @<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Import.html">Import</a> annotation (in 5.2 or later), as opposed to directly adding the <link> element to the template, for significant performance benefits <a href="assets.html">described elsewhere</a>. (For 5.0 and 5.1, use the deprecated @IncludeStyleSheet annotation instead.)</p><p>You may find that your application has more than one look and feel: perhaps user registration pages have one look, while administrative pages have another. This can be accomplished by having multiple layout components (using any names you choose) and using those different layout types for different pages.</p><h2 id="LayoutComponent-NestedLayouts">Nested Layouts</h2><p>Layouts are really just ordinary components, so they can be nested to any level needed. You can have, for example, a "CommonLayout" component that provides the peripheral elements for all your page s, and then a more specialized "AdminLayout" component that provides the layout only for the administrative pages, and make the AdminLayout component wrap itself in the CommonLayout component. So then the administrative pages would start with <code><html t:type="adminLayout" ...></code> and the other pages (and the AdminLayout component itself) would start with <code><html t:type="commonLayout" ...></code>.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>AdminLayout.tml</b></div><div class="codeContent panelContent pdl"> <pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"><html t:type="commonLayout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"> <h1>Administrative Functions</h1> @@ -215,7 +215,7 @@ public class Layout </body> </html> </pre> -</div></div><p>The <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Alerts.html">Alerts</a> component above is new in Tapestry 5.3; it allows the application to present alert messages to the client in a consistent way. If you want alerts to always appear in the banner of your web site, it may make sense to put it in the layout component's template, as above.</p><p>The corresponding component class is still very simple, adding support for the "title" and "style" parameters:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Layout.java</b></div><div class="codeContent panelContent pdl"> +</div></div><p>The <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Alerts.html">Alerts</a> component above (Tapestry 5.3 and later) allows the application to present alert messages to the client in a consistent way. If you want alerts to always appear in the banner of your web site, it may make sense to put it in the layout component's template, as above.</p><p>The corresponding component class is still very simple, adding support for the "title" and "style" parameters:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Layout.java</b></div><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@Import(stylesheet="context:css/site.css") public class Layout { @@ -235,7 +235,7 @@ public class Layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd" xmlns:p="tapestry:parameter"> <p:style> - TD.profile { background: url('${backgroundImage}') } + TD.profile { background: url('${userPhoto}') } </p:style> <div> @@ -244,7 +244,7 @@ public class Layout </html> </pre> -</div></div><p>The <p:style> element (and its contents) are passed to the layout component as a <code>style</code> parameter (a block parameter, in this case, so you must have the <code>xmlns:p="tapestry:parameter"</code> namespace declared, as above).</p><p>The rendered HTML would look like the following (whitespace aside, and assuming UserList.java has a backgroundImage property whose value is the string "<a class="external-link" href="http://www.example.com/fuzzy.gif" rel="nofollow">http://www.example.com/fuzzy.gif</a>"):</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>The rendered HTML</b></div><div class="codeContent panelContent pdl"> +</div></div><p>The <p:style> element (and its contents) are passed to the layout component as a <code>style</code> parameter (a block parameter, in this case, so you must have the <code>xmlns:p="tapestry:parameter"</code> namespace declared, as above).</p><p>The rendered HTML would look like the following (whitespace aside, and assuming UserList.java has a backgroundImage property whose value is the string "<span class="nolink">http://www.example.com/fuzzy.gif</span>"):</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>The rendered HTML</b></div><div class="codeContent panelContent pdl"> <pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"><!DOCTYPE html> <html> <head>
Modified: websites/production/tapestry/content/localization.html ============================================================================== --- websites/production/tapestry/content/localization.html (original) +++ websites/production/tapestry/content/localization.html Sat Feb 17 12:21:22 2018 @@ -130,7 +130,7 @@ <p>Localization support is well integrated into Tapestry. Tapestry allows you to easily separate the text you present to your users from the rest of your application ... pull it out of your Java code and even out of your component templates. You can then translate your messages into other languages and let Tapestry put everything together.</p><h2 id="Localization-ComponentMessageCatalogs">Component Message Catalogs</h2><p>Each component class may have a component message catalog. A component message catalog is a set of files with the extension ".properties". These property files are the same format used by java.util.ResourceBundle, just lines of <code>key=value</code>. These files are stored on the classpath, in the same package folder as the page or component's compiled Java class.</p><p>So for a class named <code>org.example.myapp.pages.MyPage</code>, you would have a main properties file as <code>org/example/myapp/pages/MyPage.properties</code>.</p><p>If you have a translations o f these values, you provide additional properties file, adding an <a class="external-link" href="http://www.loc.gov/standards/iso639-2/englangn.html" rel="nofollow">ISO language code</a> before the extension. Thus, if you have a French translation, you could create a file <code>MyPage_fr.properties</code>.</p><p>Any values in the more language specific file will <em>override</em> values from the main properties file. If you had an even more specific localization for just French as spoken in France, you could create <code>MyPage_fr_FR.properties</code> (that's a language code plus a country code, and you can even go further and add variants ... but its unlikely that you'll ever need to go beyond just language codes in practice).</p><p>The messages in the catalog are accessed by keys. Tapestry ignores the case of the keys when accessing messages in the catalog.</p><h3 id="Localization-ComponentMessageCatalogInheritance">Component Message Catalog Inheritance</h3><p>If a component clas s is a subclass of another component class, then it inherits that base class' message catalog. Its own message catalog extends and overrides the values inherited from the base class.</p><p>In this way, you could have a base component class that contained common messages, and extend or override those messages in subclasses (just as you would extend or override the methods of the base component class). This, of course, works for as many levels of inheritance as you care to support.</p><h2 id="Localization-Application-wideMessageCatalog">Application-wide Message Catalog</h2><p>If the file <code>WEB-INF/</code><em>AppName</em><code>.properties</code> exists in the context, it will be used as an application-wide message catalog. The <em>AppName</em> is derived from the name of the filter inside the web.xml file; this is most often just "app", thus <code>WEB-INF/app.properties</code>. The search for the file is case sensitive. The properties files may be localized.</p><p>Individual pages and components can override the values defined in the message catalog.</p><div class="navmenu" style="float:right; width:45%; background:white; margin:3px; padding:3px"> <div class="confluence-information-macro confluence-information-macro-note"><p class="title">Avoid BOMs</p><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"> -<p>Make sure that your properties files don't contain <a class="external-link" href="http://en.wikipedia.org/wiki/Byte_order_mark" rel="nofollow">byte order marks (BOM)</a>, because Java – and thus Tapestry – doesn't support BOM in properties files (see <a class="external-link" href="http://bugs.sun.com/view_bug.do?bug_id=4508058" rel="nofollow">http://bugs.sun.com/view_bug.do?bug_id=4508058</a>). Some editors write them out when saving a file in UTF-8, so watch out.</p></div></div></div><h2 id="Localization-PropertiesFileCharset">Properties File Charset</h2><p>Tapestry uses the <code>UTF-8</code> character set (charset) when reading the properties files in a message catalog. This means that you don't have to use the Java <code>native2ascii</code> tool.</p><h2 id="Localization-LocalizedComponentTemplates">Localized Component Templates</h2><p>The same lookup mechanism applies to component templates. Tapestry will search for a localized version of each component template and use the closest match. Thus you could have <code>MyPage_fr.html</code> for French users, and <code>MyPage.html</code> for all other users.</p><h2 id="Localization-AccessingLocalizedMessages">Accessing Localized Messages</h2><p>The above discusses what files to create and where to store them, but doesn't address how to make use of that information.</p><p>Messages can be accessed in one of two ways:</p><ul><li>Using the "message:" <a href="localization.html">binding expression</a> in a component template</li><li>By injecting the component's Messages object<br clear="none"> In the first case, you may use the message: binding prefix with component parameters, or with template expansions:</li></ul><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<p>Make sure that your properties files don't contain <a class="external-link" href="http://en.wikipedia.org/wiki/Byte_order_mark" rel="nofollow">byte order marks (BOM)</a>, because Java – and thus Tapestry – doesn't support BOM in properties files (see <a class="external-link" href="http://bugs.sun.com/view_bug.do?bug_id=4508058" rel="nofollow">http://bugs.sun.com/view_bug.do?bug_id=4508058</a>). Some editors write them out when saving a file in UTF-8, so watch out.</p></div></div></div><h2 id="Localization-PropertiesFileCharset">Properties File Charset</h2><p>Tapestry uses the <code>UTF-8</code> character set (charset) when reading the properties files in a message catalog. This means that you don't have to use the Java <code>native2ascii</code> tool.</p><h2 id="Localization-LocalizedComponentTemplates">Localized Component Templates</h2><p>The same lookup mechanism applies to component templates. Tapestry will search for a localized version of each component template and use the closest match. Thus you could have <code>MyPage_fr.html</code> for French users, and <code>MyPage.html</code> for all other users.</p><h2 id="Localization-AccessingLocalizedMessages">Accessing Localized Messages</h2><p>The above discusses what files to create and where to store them, but doesn't address how to make use of that information.</p><p>Messages can be accessed in one of two ways:</p><ul><li>Using the "message:" <a href="component-parameters.html">binding expression</a> in a component template</li><li>By injecting the component's Messages object<br clear="none"> In the first case, you may use the message: binding prefix with component parameters, or with template expansions:</li></ul><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"><t:layout title="message:page-title"> ${message:greeting}, ${user.name}! @@ -138,7 +138,7 @@ . . . </t:layout> </pre> -</div></div><p>Here, the <code>page-title</code> message is extracted from the catalog and passed to the Border component's title parameter.</p><p>In addition, the <code>greeting</code> message is extracted and written into the response as part of the template.</p><p>As usual, "prop:" is the default binding prefix, thus <code><a class="external-link" href="http://user.name" rel="nofollow">user.name</a></code> is a property path, not a message key.</p><p>You would extend this with a set of properties files:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +</div></div><p>Here, the <code>page-title</code> message is extracted from the catalog and passed to the Border component's title parameter.</p><p>In addition, the <code>greeting</code> message is extracted and written into the response as part of the template.</p><p>As usual, "prop:" is the default binding prefix, thus <code>user.name</code> is a property path, not a message key.</p><p>You would extend this with a set of properties files:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">page-title=Your Account greeting=Welcome back </pre> @@ -163,7 +163,7 @@ greeting=Bienvenue en arriere <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">no-items=Your shopping cart is empty. item-summary=You have %d items in your cart. </pre> -</div></div><p>As easy as conditionals are to use inside a Tapestry template, sometimes it's even easier to do it in Java code.</p><h2 id="Localization-MissingKeys">Missing Keys</h2><p>If you reference a key that is not in the message catalog, Tapestry does not throw an exception (because that would make initially developing an application very frustrating). When a key can not be located, a "placeholder" message is generated, such as "[[missing key: key-not-found]]".</p><h2 id="Localization-Reloading">Reloading</h2><p>If you change a property file in a message catalog, you'll see the change immediately, just as with component classes and component templates (provided you're not running in <a href="localization.html">production mode</a>).</p><h2 id="Localization-AssetLocalization">Asset Localization</h2><p>When <a href="localization.html">injecting assets</a>, the injected asset will be localized as well. A search for the closest match for the active locale is made, and the final A sset will reflect that.</p><h2 id="Localization-LocaleSelection">Locale Selection</h2><p>The locale for each request is determined from the HTTP request headers. The request locale reflects the environment of the web browser and possibly even the keyboard selection of the user on the client. It can be highly specific, for example, identifying British English (as en_GB) vs. American English (en).</p><p>Tapestry "narrows" the raw request locale, as specified in the request, to a known quantity. It uses the <a href="localization.html">configuration symbol</a> <code>tapestry.supported-locales</code> to choose the effective locale for each request. This value is a comma-separated list of locale names. Tapestry searches the list for the best match for the request locale; for example, a request locale of "fr_FR" would match "fr" but not "de". If no match is found, then the first locale name in the list is used as the effective locale (that is, the first locale is used as the default for n on-matching requests). Thus a site that primarily caters to French speakers would want to list "fr" as the first locale in the list.</p><h2 id="Localization-ChangingtheLocale">Changing the Locale</h2><p>The <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/PersistentLocale.html">PersistentLocale service</a> can be used to programmatically override the locale. Note: You should be careful to only set the persistent locale to a supported locale.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Toggle between English and German</b></div><div class="codeContent panelContent pdl"> +</div></div><p>As easy as conditionals are to use inside a Tapestry template, sometimes it's even easier to do it in Java code.</p><h2 id="Localization-MissingKeys">Missing Keys</h2><p>If you reference a key that is not in the message catalog, Tapestry does not throw an exception (because that would make initially developing an application very frustrating). When a key can not be located, a "placeholder" message is generated, such as "[[missing key: key-not-found]]".</p><h2 id="Localization-Reloading">Reloading</h2><p>If you change a property file in a message catalog, you'll see the change immediately, just as with component classes and component templates (provided you're not running in <a href="configuration.html">production mode</a>).</p><h2 id="Localization-AssetLocalization">Asset Localization</h2><p>When <a href="assets.html">injecting assets</a>, the injected asset will be localized as well. A search for the closest match for the active locale is made, and the final Asset will reflect that.</p><h2 id="Localization-LocaleSelection">Locale Selection</h2><p>The locale for each request is determined from the HTTP request headers. The request locale reflects the environment of the web browser and possibly even the keyboard selection of the user on the client. It can be highly specific, for example, identifying British English (as en_GB) vs. American English (en).</p><p>Tapestry "narrows" the raw request locale, as specified in the request, to a known quantity. It uses the <a href="configuration.html">configuration symbol</a> <code>tapestry.supported-locales</code> to choose the effective locale for each request. This value is a comma-separated list of locale names. Tapestry searches the list for the best match for the request locale; for example, a request locale of "fr_FR" would match "fr" but not "de". If no match is found, then the first locale name in the list is used as the effective locale (that is, the first locale is used as the default for non-m atching requests). Thus a site that primarily caters to French speakers would want to list "fr" as the first locale in the list.</p><h2 id="Localization-ChangingtheLocale">Changing the Locale</h2><p>The <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/PersistentLocale.html">PersistentLocale service</a> can be used to programmatically override the locale. Note: You should be careful to only set the persistent locale to a supported locale.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Toggle between English and German</b></div><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@Inject private PersistentLocale persistentLocale; Modified: websites/production/tapestry/content/page-navigation.html ============================================================================== --- websites/production/tapestry/content/page-navigation.html (original) +++ websites/production/tapestry/content/page-navigation.html Sat Feb 17 12:21:22 2018 @@ -155,7 +155,7 @@ </div> -<p>In essence, a Tapestry application is a number of related pages, working together. To some degree, each page is like an application unto itself.</p><p>Any individual request will be targeted at a single page. Requests come in two forms: </p><ul><li><em>component event</em> requests target a specific component on a specific page, triggering an event within that component</li><li><em>render</em> requests target a specific page, and stream the HTML markup for that page back to the client</li></ul><p>This dichotomy between component event requests and render requests alleviates a number of problems in traditional web applications related to the browser back button, or to the user hitting the refresh button in their browser.</p><p><br clear="none"><span style="color: rgb(83,145,38);">Logical Page Name Shortening</span></p><p>In certain cases, Tapestry will shorten the the logical name of a page. For example, the page class org.example.pages.address.CreateAddress will be given a l ogical name of "address/Create" (the redundant "Address" is removed as a suffix). However, this only affects how the page is referenced in URLs; the template file will still be CreateAddress.tml, whether on the classpath, or as address/CreateAddress.tml (in the web context).</p><p><span>Tapestry actually creates multiple names for the name page: "address/Create" and "address/CreateAddress" are both synonymous. You can user either in Java code that refers to a page by name, or as the page parameter of a PageLink.</span></p><h2 id="PageNavigation-ComponentEventRequests&Responses">Component Event Requests & Responses</h2><p>Main Article: <a href="page-navigation.html">Page Navigation</a></p><p>Component event requests may take the form of hyperlinks (<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/EventLink.html">EventLink</a> or <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apa che/tapestry5/corelib/components/ActionLink.html">ActionLink</a>) or form submissions (<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Form.html">Form</a>).</p><p>The value returned from an <a href="page-navigation.html">event handler method</a> controls the response sent to the client web browser.</p><p>The URL for a component event request identifies the name of the page, the nested id of the component, and the name of the event to trigger on the component (specified by the "event" parameter of EventLink, or "action" for an ActionLink). Further, a component event request may contain additional context information, which will be provided to the event handler method.</p><p>These URLs expose a bit of the internal structure of the application. Over time, as an application grows and is maintained, the ids of components may change. This means that component event request URLs should not be bookmarked. Fortunately, users will rarely have the chance to do so (see below).</p><h3 id="PageNavigation-1.Nullresponse">1. Null response</h3><p>If the event handler method returns no value, or returns null, then the current page (the page containing the component) will render the response.</p><p>A page render URL for the current page is created and sent to the client as a client side redirect. The client browser will automatically submit a new request to generate the page.</p><p>The user will see the newly generated content in their browser. In addition, the URL in the browser's address bar will be a render request URL. Render request URLs are shorter and contain less application structure (for instance, they don't include component ids or event types). Render requests URLs are what your users will bookmark. The component event request URLs are transitory, meaningful only while the application is actively engaged, and not meant to be used in later sessions.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<p>In essence, a Tapestry application is a number of related pages, working together. To some degree, each page is like an application unto itself.</p><p>Any individual request will be targeted at a single page. Requests come in two forms: </p><ul><li><em>component event</em> requests target a specific component on a specific page, triggering an event within that component</li><li><em>render</em> requests target a specific page, and stream the HTML markup for that page back to the client</li></ul><p>This dichotomy between component event requests and render requests alleviates a number of problems in traditional web applications related to the browser back button, or to the user hitting the refresh button in their browser.</p><p><br clear="none"><span style="color: rgb(83,145,38);">Logical Page Name Shortening</span></p><p>In certain cases, Tapestry will shorten the the logical name of a page. For example, the page class org.example.pages.address.CreateAddress will be given a l ogical name of "address/Create" (the redundant "Address" is removed as a suffix). However, this only affects how the page is referenced in URLs; the template file will still be CreateAddress.tml, whether on the classpath, or as address/CreateAddress.tml (in the web context).</p><p><span>Tapestry actually creates multiple names for the name page: "address/Create" and "address/CreateAddress" are both synonymous. You can user either in Java code that refers to a page by name, or as the page parameter of a PageLink.</span></p><h2 id="PageNavigation-ComponentEventRequests&Responses">Component Event Requests & Responses</h2><p>Main Article: <a href="page-navigation.html">Page Navigation</a></p><p>Component event requests may take the form of hyperlinks (<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/EventLink.html">EventLink</a> or <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apa che/tapestry5/corelib/components/ActionLink.html">ActionLink</a>) or form submissions (<a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Form.html">Form</a>).</p><p>The value returned from an <a href="component-events.html">event handler method</a> controls the response sent to the client web browser.</p><p>The URL for a component event request identifies the name of the page, the nested id of the component, and the name of the event to trigger on the component (specified by the "event" parameter of EventLink, or "action" for an ActionLink). Further, a component event request may contain additional context information, which will be provided to the event handler method.</p><p>These URLs expose a bit of the internal structure of the application. Over time, as an application grows and is maintained, the ids of components may change. This means that component event request URLs should not be bookmarked. Fortunately, user s will rarely have the chance to do so (see below).</p><h3 id="PageNavigation-1.Nullresponse">1. Null response</h3><p>If the event handler method returns no value, or returns null, then the current page (the page containing the component) will render the response.</p><p>A page render URL for the current page is created and sent to the client as a client side redirect. The client browser will automatically submit a new request to generate the page.</p><p>The user will see the newly generated content in their browser. In addition, the URL in the browser's address bar will be a render request URL. Render request URLs are shorter and contain less application structure (for instance, they don't include component ids or event types). Render requests URLs are what your users will bookmark. The component event request URLs are transitory, meaningful only while the application is actively engaged, and not meant to be used in later sessions.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public Object onAction(){ return null; }</pre> @@ -167,14 +167,14 @@ <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public Object onAction(){ return Index.class }</pre> -</div></div><h3 id="PageNavigation-4.Pageresponse">4. Page response</h3><p>You may also return an instance of a page, rather than the name or class of a page.</p><p>A page may be injected via the <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/InjectPage.html">InjectPage</a> annotation.</p><p>Often, you will configure the page in some way before returning the page (examples below).</p><p>You can also return a component within the page, but this will generate a runtime warning (unless you are doing a partial-page update via <a href="page-navigation.html">Ajax</a>).</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +</div></div><h3 id="PageNavigation-4.Pageresponse">4. Page response</h3><p>You may also return an instance of a page, rather than the name or class of a page.</p><p>A page may be injected via the <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/InjectPage.html">InjectPage</a> annotation.</p><p>Often, you will configure the page in some way before returning the page (examples below).</p><p>You can also return a component within the page, but this will generate a runtime warning (unless you are doing a partial-page update via <a href="ajax-and-zones.html">Ajax</a>).</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@InjectPage private Index index; public Object onAction(){ return index; }</pre> -</div></div><h3 id="PageNavigation-5.HttpError">5. HttpError</h3><p>An event handler method may return a <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpError.html">HttpError</a> instance to send an error response to the client.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +</div></div><h3 id="PageNavigation-5.HttpError">5. HttpError</h3><p>An event handler method may return an instance of <a class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpError.html">HttpError</a> to send an error response to the client.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public Object onAction(){ return new HttpError(302, "The Error message); }</pre> @@ -195,7 +195,7 @@ public Object onAction(){ } }; }</pre> -</div></div><p> </p><h3 id="PageNavigation-8.URLresponse">8. URL response</h3><p>A <a class="external-link" href="http://java.net" rel="nofollow">java.net</a>.URL response is handled as a client redirect to an external URL. (In Tapestry 5.3.x and earlier this only works for non-Ajax requests.)</p><h3 id="PageNavigation-9.Objectresponse">9. Object response</h3><p>Any other type of object returned from an event handler method is an error.</p><h2 id="PageNavigation-PageRenderRequests">Page Render Requests</h2><p>Render requests are simpler in structure and behavior than component event requests. In the simplest case, the URL is simply the logical name of the page.</p><p>Pages may have an <em>activation context</em>. The activation context represents persistent information about the state of the page. In practical terms, the activation context is usually the id of some database-persistent object.</p><p>When a page has an activation context, the values of the context are appended t o the URL path. For example, in <code><a class="external-link" href="http://www.example.com/myapp/foo/bar" rel="nofollow">http://www.example.com/myapp/foo/bar</a></code> the "myapp" part is the servlet context (usually the name of your app), and the "foo/bar" part is the activation context, with "foo" being the first activation parameter and "bar" being the second.</p><p>It is common for most pages to not have any activation context.</p><p>The activation context may be explicitly set when the render request link is created (the PageLink component has a context parameter for this purpose).</p><p>When no explicit activation context is provided, the page itself is queried for its activation context. This querying takes the form of an event trigger. The event name is "passivate" (as we'll see shortly, there's a corresponding "activate"). The return value of the method is used as the context. For example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeCon tent panelContent pdl"> +</div></div><p> </p><h3 id="PageNavigation-8.URLresponse">8. URL response</h3><p>A java.net.URL response is handled as a client redirect to an external URL. (In Tapestry 5.3.x and earlier this only works for non-Ajax requests.)</p><h3 id="PageNavigation-9.Objectresponse">9. Object response</h3><p>Any other type of object returned from an event handler method is an error.</p><h2 id="PageNavigation-PageRenderRequests">Page Render Requests</h2><p>Render requests are simpler in structure and behavior than component event requests. In the simplest case, the URL is simply the logical name of the page.</p><p>Pages may have an <em>activation context</em>. The activation context represents persistent information about the state of the page. In practical terms, the activation context is usually the id of some database-persistent object.</p><p>When a page has an activation context, the values of the context are appended to the URL path. For example, in <code><span class="nolink">http ://www.example.com/myapp/foo/bar</span></code> the "myapp" part is the servlet context (usually the name of your app), and the "foo/bar" part is the activation context, with "foo" being the first activation parameter and "bar" being the second.</p><p>It is common for most pages to not have any activation context.</p><p>The activation context may be explicitly set when the render request link is created (the PageLink component has a context parameter for this purpose).</p><p>When no explicit activation context is provided, the page itself is queried for its activation context. This querying takes the form of an event trigger. The event name is "passivate" (as we'll see shortly, there's a corresponding "activate"). The return value of the method is used as the context. For example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">public class ProductDetail { private Product product; @@ -203,10 +203,10 @@ public Object onAction(){ long onPassivate() { return product.getId(); } } </pre> -</div></div><p>The activation context may consist of a series of values, in which case the return value of the method should be an array or a List.</p><div class="confluence-information-macro confluence-information-macro-information"><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Note: If you are using the <a href="page-navigation.html">tapestry-hibernate</a> integration library and your passivate context is a Hibernate entity, then you can just use the entity itself, not its id. Tapestry will automatically extract the entity's id into the URL, and convert it back for the "activate" event handler method.</p></div></div><h2 id="PageNavigation-Pageactivation">Page activation</h2><p>When a page render request arrives, the page is <em>activated</em> before it is rendered.</p><div class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em"> +</div></div><p>The activation context may consist of a series of values, in which case the return value of the method should be an array or a List.</p><div class="confluence-information-macro confluence-information-macro-information"><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Note: If you are using the <a href="hibernate-user-guide.html">tapestry-hibernate</a> integration library and your passivate context is a Hibernate entity, then you can just use the entity itself, not its id. Tapestry will automatically extract the entity's id into the URL, and convert it back for the "activate" event handler method.</p></div></div><h2 id="PageNavigation-Pageactivation">Page activation</h2><p>When a page render request arrives, the page is <em>activated</em> before it is rendered.</p><div class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em"> <p> <strong>JumpStart Demos:</strong><br clear="none"> <a class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/navigation/onactivateandonpassivate/3" rel="nofollow">onActivate and onPassivate</a><br clear="none"> - <a class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/handlingabadcontext/1" rel="nofollow">Handling A Bad Context</a></p></div>Activation serves two purposes:<ul><li>It allows the page to restore its internal state from data encoded into the URL (the activation context discussed above).</li><li>It provides coarse approach to validating access to the page.</li></ul><p>The later case – validation – is generally concerned with user identity and access; if you have pages that may only be accessed by certain users, you may use the page's activate event handler for verifying that access.</p><p>Page activation uses Tapestry's <em>Component Event</em> mechanism. See <a href="page-navigation.html">Page Navigation</a> for details.</p><p>A page's activate event handler mirrors its passivate handler:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> + <a class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/handlingabadcontext/1" rel="nofollow">Handling A Bad Context</a></p></div>Activation serves two purposes:<ul><li>It allows the page to restore its internal state from data encoded into the URL (the activation context discussed above).</li><li>It provides coarse approach to validating access to the page.</li></ul><p>The later case – validation – is generally concerned with user identity and access; if you have pages that may only be accessed by certain users, you may use the page's activate event handler for verifying that access.</p><p>Page activation uses Tapestry's <em>Component Event</em> mechanism. See <a href="component-events.html">Component Events</a> for details.</p><p>A page's activate event handler mirrors its passivate handler:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> private Product product; . . . void onActivate(long productId) @@ -215,7 +215,7 @@ public Object onAction(){ } . . . </pre> -</div></div><p>Here's the relevant part: when the page renders, it is likely to include more component event request URLs (links and forms). The component event requests for those links and forms will <em>also</em> start by activating the page, before performing other work. This forms an unbroken chain of requests that include the same activation context.</p><p>To some degree, this same effect could be accomplished using a <a href="page-navigation.html">persistent page value</a>, but that requires an active servlet session, and the result is not bookmarkable.</p><p>Your activate event handler, like any event handler, may also return a value, which is treated identically to a return value of a component event method. This technique is commonly used as a simple access validation mechanism.</p><p>You sometimes need to handle multiple page activation scenarios in one page class. You could create multiple activate event handler methods with different arguments (see the "Multiple Method Matches" section at <a href="page-navigation.html">Page Navigation</a> for details), but if you do so, you should generally return <code>true</code> from each to avoid having more than one activation event handler method from being called for each page request. However, a better approach is to create one method with an EventContext argument. Tapestry will populate the EventContext argument with all of the activation parameters, and the EventContext's <code>get</code> method will retrieve and coerce each parameter to the desired type. For example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +</div></div><p>Here's the relevant part: when the page renders, it is likely to include more component event request URLs (links and forms). The component event requests for those links and forms will <em>also</em> start by activating the page, before performing other work. This forms an unbroken chain of requests that include the same activation context.</p><p>To some degree, this same effect could be accomplished using a <a href="persistent-page-data.html">persistent page value</a>, but that requires an active servlet session, and the result is not bookmarkable.</p><p>Your activate event handler, like any event handler, may also return a value, which is treated identically to a return value of a component event method. This technique is commonly used as a simple access validation mechanism.</p><p>You sometimes need to handle multiple page activation scenarios in one page class. You could create multiple activate event handler methods with different arguments (see the "Multiple Me thod Matches" section at <a href="component-events.html">Component Events</a> for details), but if you do so, you should generally return <code>true</code> from each to avoid having more than one activation event handler method from being called for each page request. However, a better approach is to create one method with an EventContext argument. Tapestry will populate the EventContext argument with all of the activation parameters, and the EventContext's <code>get</code> method will retrieve and coerce each parameter to the desired type. For example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> . . . void onActivate(EventContext eventContext) { @@ -312,7 +312,7 @@ public Object onAction(){ long onPassivate() { return productId; } </pre> -</div></div><p>The setProductId() method is no longer needed.</p><h3 id="PageNavigation-Limitations">Limitations</h3><p>As your application's workflow expands, you may find that there is not a reasonable way to avoid storing some data persistently between requests, outside of the page activation context. For example, if from the ProductDetails page, the user is allowed to navigate to related pages and then back to ProductDetails, it starts to become necessary to keep passing that product id around from page to page to page.</p><p>At some point, persistent values make more sense. Tapestry has several persistence strategies available, including one that stores data in URL query parameters. See <a href="page-navigation.html">Page Navigation</a> for details.</p></div> +</div></div><p>The setProductId() method is no longer needed.</p><h3 id="PageNavigation-Limitations">Limitations</h3><p>As your application's workflow expands, you may find that there is not a reasonable way to avoid storing some data persistently between requests, outside of the page activation context. For example, if from the ProductDetails page, the user is allowed to navigate to related pages and then back to ProductDetails, it starts to become necessary to keep passing that product id around from page to page to page.</p><p>At some point, persistent values make more sense. Tapestry has several persistence strategies available, including one that stores data in URL query parameters. See <a href="persistent-page-data.html">Persistent Page Data</a> for details.</p></div> </div> <div class="clearer"></div> Modified: websites/production/tapestry/content/parameter-type-coercion.html ============================================================================== --- websites/production/tapestry/content/parameter-type-coercion.html (original) +++ websites/production/tapestry/content/parameter-type-coercion.html Sat Feb 17 12:21:22 2018 @@ -67,20 +67,78 @@ </div> <div id="content"> - <div id="ConfluenceContent"><p><strong style="text-align: justify;">Type Coercion</strong><span style="color: rgb(0,0,0);"> is the conversion of one type of object to a new object of a different type with similar content. Tapestry frequently must coerce objects from one type to another. A common example is the coercion of a string into an integer or a double.</span></p><p>See <a href="type-coercion.html">Type Coercer Service</a> for the list of build-in coercions.</p><h2 id="ParameterTypeCoercion-ParameterTypeCoercions">Parameter Type Coercions</h2><parameter ac:name="style">float:right</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="class">aui-label</parameter><rich-text-body><parameter ac:name="showLabels">false</parameter><parameter ac:name="showSpace">false</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="cql">label in ("coercion","parameters") and space = currentSpace()</parame ter></rich-text-body><p>Tapestry automatically handles type coercions for <a href="component-parameters.html">component parameters</a>.</p><p>Type coercions occur when a value passed into a parameter (as bound in a template or in an annotation) does not match the type of the parameter.</p><p>For example, consider the Count component:</p><parameter ac:name="language">java</parameter><plain-text-body>public class Count -{ - @Parameter - private int start = 1; - - @Parameter(required = true) - private int end; - - @Parameter - private int value; - - . . . -</plain-text-body><p>Here, the type of all three parameters is <code>int</code>.</p><p>However, it is likely that the component will be used as so:</p><parameter ac:name="language">java</parameter><plain-text-body> Merry Christmas: <t:count end="3"> Ho! </t:count> -</plain-text-body><p>A bare whole number is interpreted by the prop binding prefix as a <code>long</code>. So this is the <em>long</em> value 3.</p><p>Tapestry will automatically coerce the bound value, a <code>long</code>, to the parameter's type, <code>int</code>. This may be a lossy coercion (if the <code>long</code> represents a number larger than can be stored in an <code>int</code>).</p><h2 id="ParameterTypeCoercion-TypeCoercerService">TypeCoercer Service</h2><p>Main Article: <a href="type-coercion.html">Type Coercion</a></p><p>The TypeCoercer service is responsible for this type coercion. This service is part of the <a href="ioc.html">tapestry-ioc</a> module. The service is quite extensible, allowing for new types and coercions to be added easily. The TapestryModule contributes a few additional coercions into the TypeCoercer service.</p></div> + <div id="ConfluenceContent"><p><strong style="text-align: justify;">Type Coercion</strong><span style="color: rgb(0,0,0);"> is the conversion of one type of object to a new object of a different type with similar content. Tapestry frequently must coerce objects from one type to another. A common example is the coercion of a string into an integer or a double.</span></p><p>See <a href="type-coercion.html">Type Coercer Service</a> for the list of build-in coercions.</p><h2 id="ParameterTypeCoercion-ParameterTypeCoercions">Parameter Type Coercions</h2><div class="aui-label" style="float:right" title="Related Articles"> + + + + + + + + +<h3>Related Articles</h3> + +<ul class="content-by-label"><li> + <div> + <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> + + <div class="details"> + <a href="type-coercion.html">Type Coercion</a> + + + </div> + </li><li> + <div> + <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> + + <div class="details"> + <a href="parameter-type-coercion.html">Parameter Type Coercion</a> + + + </div> + </li><li> + <div> + <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> + + <div class="details"> + <a href="enum-parameter-recipe.html">Enum Parameter Recipe</a> + + + </div> + </li><li> + <div> + <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> + + <div class="details"> + <a href="supporting-informal-parameters.html">Supporting Informal Parameters</a> + + + </div> + </li><li> + <div> + <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> + + <div class="details"> + <a href="default-parameter.html">Default Parameter</a> + + + </div> + </li><li> + <div> + <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> </div> + + <div class="details"> + <a href="component-parameters.html">Component Parameters</a> + + + </div> + </li></ul> +</div> + + +<p>Tapestry automatically handles type coercions for <a href="component-parameters.html">component parameters</a>.</p><p>Type coercions occur when a value passed into a parameter (as bound in a template or in an annotation) does not match the type of the parameter.</p><p>For example, consider the Count component:</p><p>java</p> +<p>Here, the type of all three parameters is <code>int</code>.</p><p>However, it is likely that the component will be used as so:</p><p>java</p> + Ho! ]]><p>A bare whole number is interpreted by the prop binding prefix as a <code>long</code>. So this is the <em>long</em> value 3.</p><p>Tapestry will automatically coerce the bound value, a <code>long</code>, to the parameter's type, <code>int</code>. This may be a lossy coercion (if the <code>long</code> represents a number larger than can be stored in an <code>int</code>).</p><h2 id="ParameterTypeCoercion-TypeCoercerService">TypeCoercer Service</h2><p>Main Article: <a href="type-coercion.html">Type Coercion</a></p><p>The TypeCoercer service is responsible for this type coercion. This service is part of the <a href="ioc.html">tapestry-ioc</a> module. The service is quite extensible, allowing for new types and coercions to be added easily. The TapestryModule contributes a few additional coercions into the TypeCoercer service.</p></div> </div> <div class="clearer"></div>
