You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by bo...@apache.org on 2017/09/16 01:54:20 UTC

svn commit: r1018226 [6/41] - in /websites/production/tapestry/content: ./ cache/ styles/

Modified: websites/production/tapestry/content/component-events.html
==============================================================================
--- websites/production/tapestry/content/component-events.html (original)
+++ websites/production/tapestry/content/component-events.html Sat Sep 16 01:54:19 2017
@@ -27,6 +27,16 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -67,36 +77,118 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p><strong>Component events</strong> are Tapestry's way of conveying a user's interactions with the web page, such as clicking links and submitting forms, to designated methods in your page and component classes. When a component event is triggered, Tapestry calls the event handler method you've provided, if any, in the containing component's class.</p><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 = "request-processing" and space = currentSpace()</parameter></rich-text-body><p>Let's look at a simple example. Here's a portion of the template for a page (let's call it "Review") that lists documents and lets a user click to edit any one of th
 em.</p><parameter ac:name="language">xml</parameter><parameter ac:name="title">Review.tml (partial)</parameter><plain-text-body>&lt;p&gt; Select document to edit: &lt;/p&gt;
+                <div id="ConfluenceContent"><p><strong>Component events</strong> are Tapestry's way of conveying a user's interactions with the web page, such as clicking links and submitting forms, to designated methods in your page and component classes. When a component event is triggered, Tapestry calls the event handler method you've provided, if any, in the containing component's class.</p><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="page-navigation.html">Page Navigation</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="page-life-cycle.html">Page Life Cycle</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-rendering.html">Component Rendering</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-events.html">Component Events</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-events-faq.html">Component Events FAQ</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="request-processing.html">Request Processing</a>
+                
+                        
+                    </div>
+    </li></ul>
+</div>
+
+
+<p>Let's look at a simple example. Here's a portion of the template for a page (let's call it "Review") that lists documents and lets a user click to edit any one of them.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Review.tml (partial)</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;p&gt; Select document to edit: &lt;/p&gt;
 &lt;t:loop source="documents" value="document"&gt;
     &lt;div&gt;
         &lt;t:actionlink" t:id="edit" context="document.id"&gt; ${document.name} &lt;/t:actionlink&gt;       
     &lt;/div&gt;
 &lt;/t:loop&gt;
-</plain-text-body><p>Notice that Review.tml contains an ActionLink component in a loop. For each rendering within the loop, the ActionLink component creates a component event request URL, with the event type set to "action". In this case, each URL might look like:</p><p><code><span class="external-link">&#160;&#160;&#160; http://localhost:8080/review.edit/3</span></code></p><p>This URL identifies the <strong>page</strong> that contains the component ("review"), the&#160;<strong>Component id</strong> of the component within the page ("edit"), and the <strong>context</strong> value ("3", the "id" property of the document). <em>Additional context values, if any, are appended to the path.</em> (The URL may also contain the <strong>event name</strong>, unless, as here, it is "action".)</p><p>There's no direct mapping from URL to a piece of code. Instead, when the user clicks on the link, the ActionLink component triggers events. And then Tapestry ensures that the correct bits of code (yo
 ur event handler method, see below) get invoked for those events.</p><p>This demonstrates a critical difference between Tapestry and a more traditional, action oriented framework. The URL doesn't say what happens when the link is clicked, it identifies <em>which component is responsible</em> when the link is clicked.</p><p>Often, a navigation request (originating with the user) will spawn a number of flow-of-control requests. For example, a form component may trigger an action event, which will then trigger notification events to announce when the form submission is about to be processed, and whether it was successful or not, and those event could be further handled by the page component.</p><h1 id="ComponentEvents-EventHandlerMethods">Event Handler Methods</h1><p>When a component event occurs, Tapestry invokes any event handler methods that you have identified for that event. You can identify your event handler methods via a naming convention (see Method Naming Convention below), o
 r via the @<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/OnEvent.html">OnEvent</a> annotation.</p><parameter ac:name="language">java</parameter><plain-text-body>@OnEvent(component="edit")
+</pre>
+</div></div><p>Notice that Review.tml contains an ActionLink component in a loop. For each rendering within the loop, the ActionLink component creates a component event request URL, with the event type set to "action". In this case, each URL might look like:</p><p><code><span class="external-link">&#160;&#160;&#160; http://localhost:8080/review.edit/3</span></code></p><p>This URL identifies the <strong>page</strong> that contains the component ("review"), the&#160;<strong>Component id</strong> of the component within the page ("edit"), and the <strong>context</strong> value ("3", the "id" property of the document). <em>Additional context values, if any, are appended to the path.</em> (The URL may also contain the <strong>event name</strong>, unless, as here, it is "action".)</p><p>There's no direct mapping from URL to a piece of code. Instead, when the user clicks on the link, the ActionLink component triggers events. And then Tapestry ensures that the correct bits of code (your eve
 nt handler method, see below) get invoked for those events.</p><p>This demonstrates a critical difference between Tapestry and a more traditional, action oriented framework. The URL doesn't say what happens when the link is clicked, it identifies <em>which component is responsible</em> when the link is clicked.</p><p>Often, a navigation request (originating with the user) will spawn a number of flow-of-control requests. For example, a form component may trigger an action event, which will then trigger notification events to announce when the form submission is about to be processed, and whether it was successful or not, and those event could be further handled by the page component.</p><h1 id="ComponentEvents-EventHandlerMethods">Event Handler Methods</h1><p>When a component event occurs, Tapestry invokes any event handler methods that you have identified for that event. You can identify your event handler methods via a naming convention (see Method Naming Convention below), or via 
 the @<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/OnEvent.html">OnEvent</a> annotation.</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;">@OnEvent(component="edit")
 void editDocument(int docId)
 {
     this.selectedId = docId;
     // do something with the document here
 }
-</plain-text-body><p>Tapestry does two things here:</p><ul><li>Because of the annotation, it identifies method editDocument() as the method to invoke whenever the component whose ID is "edit" triggers an event.</li><li>Because there is a method parameter, when the link is clicked the context value of the request is converted from a string to an integer and passed in as the method's value parameter.<br clear="none"><br clear="none"></li></ul>
+</pre>
+</div></div><p>Tapestry does two things here:</p><ul><li>Because of the annotation, it identifies method editDocument() as the method to invoke whenever the component whose ID is "edit" triggers an event.</li><li>Because there is a method parameter, when the link is clicked the context value of the request is converted from a string to an integer and passed in as the method's value parameter.<br clear="none"><br clear="none"></li></ul>
 
 <div class="confluence-information-macro confluence-information-macro-information"><p class="title">Added in 5.3</p><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body">
 </div></div>
 <div class="error"><span class="error">Unknown macro: {div}</span> 
 <p>Starting in release 5.3, Tapestry will throw an exception if the component identified for the event handler method doesn't exist in the containing component's template. This helps prevent typos.</p>
-</div><p>In the above example, the editDocument() method will be invoked when any event occurs in in the "edit" component (and has at least one context value).</p><p>For some components, more than one type of event can occur, in which case you will want to be more specific:</p><parameter ac:name="language">java</parameter><plain-text-body>@OnEvent(value="action", component="edit")
+</div><p>In the above example, the editDocument() method will be invoked when any event occurs in in the "edit" component (and has at least one context value).</p><p>For some components, more than one type of event can occur, in which case you will want to be more specific:</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;">@OnEvent(value="action", component="edit")
 void editDocument(int docId)
 {
     this.selectedId = docId;
     // do something with the document here
 }
-</plain-text-body><p>For the OnEvent annotation, the <em><code>value</code></em> attribute identifies the name of the event to match. We specified "action" because the ActionLink component triggers the "action" event, as noted in the Component Events section of its <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/ActionLink.html">javadocs</a>.</p><p>Alternatively, we can use the EventLink component, in which case the name of the event is determined by us &#8211; either through the "event" parameter or the element's ID:</p><parameter ac:name="language">xml</parameter><parameter ac:name="title">An EventLink that emits the "delete" event</parameter><plain-text-body>&lt;t:eventlink event="delete" context="document.id"&gt; ${document.name} &lt;/t:eventlink&gt;</plain-text-body><p>which is equivalent to:</p><parameter ac:name="language">xml</parameter><parameter ac:name="title">An EventLink that emits the "delete" event</pa
 rameter><plain-text-body>&lt;a t:type="eventlink" t:id="delete" context="document.id"&gt; ${document.name} &lt;/a&gt;</plain-text-body><p>Note that if you omit the <code>component</code> part of the OnEvent annotation, then you'll receive notifications from <em>all</em> contained components, possibly including nested components (due to event bubbling).</p><rich-text-body><p>You should usually specify exactly which component(s) you wish to receive events from. Using @OnEvent on a method and not specifying a specific component ID means that the method will be invoked for events from <em>any</em> component.</p></rich-text-body><p>To support testing, it's a common practice to give event handler methods <em>package-private</em> visibility, as in the examples on this page, although technically they may have any visibility (even private).</p><p>A single event handler method may receive notifications from many different components.</p><p>As elsewhere, the comparison of event type and compon
 ent ID is case-insensitive.</p><h2 id="ComponentEvents-MethodNamingConvention">Method Naming Convention</h2><p>As an alternative to the use of annotations, you may name your event handling methods following a certain convention, and Tapestry will find and invoke your methods just as if they were annotated.</p><p>This style of event handler methods start with the prefix "on", followed by the name of the event. You may then continue by adding "From" and a capitalized component id (remember that Tapestry is case insensitive about event names and component IDs). So, for example, a method named onValidateFromSave() will be invoked whenever a "Validate" event is triggered by a component whose component ID is "save".</p><p>The previous example may be rewritten as:</p><parameter ac:name="language">java</parameter><plain-text-body>void onActionFromEdit(int docId)
+</pre>
+</div></div><p>For the OnEvent annotation, the <em><code>value</code></em> attribute identifies the name of the event to match. We specified "action" because the ActionLink component triggers the "action" event, as noted in the Component Events section of its <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/ActionLink.html">javadocs</a>.</p><p>Alternatively, we can use the EventLink component, in which case the name of the event is determined by us &#8211; either through the "event" parameter or the element's ID:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>An EventLink that emits the "delete" event</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;t:eventlink event="delete" context="document.id"&gt; ${document.name} &lt;/t:eventlink&gt;</pre>
+</div></div><p>which is equivalent to:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>An EventLink that emits the "delete" event</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;a t:type="eventlink" t:id="delete" context="document.id"&gt; ${document.name} &lt;/a&gt;</pre>
+</div></div><p>Note that if you omit the <code>component</code> part of the OnEvent annotation, then you'll receive notifications from <em>all</em> contained components, possibly including nested components (due to event bubbling).</p><div class="confluence-information-macro confluence-information-macro-tip"><span class="aui-icon aui-icon-small aui-iconfont-approve confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>You should usually specify exactly which component(s) you wish to receive events from. Using @OnEvent on a method and not specifying a specific component ID means that the method will be invoked for events from <em>any</em> component.</p></div></div><p>To support testing, it's a common practice to give event handler methods <em>package-private</em> visibility, as in the examples on this page, although technically they may have any visibility (even private).</p><p>A single event handler method may receive notifications from many dif
 ferent components.</p><p>As elsewhere, the comparison of event type and component ID is case-insensitive.</p><h2 id="ComponentEvents-MethodNamingConvention">Method Naming Convention</h2><p>As an alternative to the use of annotations, you may name your event handling methods following a certain convention, and Tapestry will find and invoke your methods just as if they were annotated.</p><p>This style of event handler methods start with the prefix "on", followed by the name of the event. You may then continue by adding "From" and a capitalized component id (remember that Tapestry is case insensitive about event names and component IDs). So, for example, a method named onValidateFromSave() will be invoked whenever a "Validate" event is triggered by a component whose component ID is "save".</p><p>The previous example may be rewritten as:</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 onActionFromEdit(int docId)
 {
     this.selectedId = docId;
     // do something with the document here
 }
-</plain-text-body><rich-text-body><p>Many people prefer the naming convention approach, reserving the annotation just for situations that don't otherwise fit.</p></rich-text-body><h2 id="ComponentEvents-MethodReturnValues">Method Return Values</h2><p>Main Article: <a  href="page-navigation.html">Page Navigation</a></p><p>For page navigation events (originating in components such as EventLink, ActionLink and Form), the value returned from an event handler method determines how Tapestry will render a response.</p><ul><li><strong>Null</strong>: For no value, or null, the current page (the page containing the component) will render the response.</li><li><strong>Page</strong>: For the name of a page, or a page class or page instance, a render request URL will be constructed and sent to the client as a redirect to that page.</li><li><strong>URL</strong>: For a java.net.URL, a redirect will be sent to the client. (In Tapestry 5.3.x and earlier, this only works for non-Ajax requests.)</li><
 li><strong>Zone body</strong>: In the case of an Ajax request to update a zone, the component event handler will return the new zone body, typically via an injected component or block.</li><li><strong>HttpError</strong>: For an <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpError.html">HttpError</a>, an error response is sent to the client.</li><li><strong>Link</strong>: For a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Link.html">Link</a>, a redirect is sent to the client.</li><li><strong>Stream</strong>: For a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/StreamResponse.html">StreamResponse</a>, a stream of data is sent to the client</li><li><strong>boolean:</strong> <em>true</em> prevents the event from bubbling up further; <em>false</em> lets it bubble up. See Event Bubbling, below.</li></ul><p>See <a  href="page-navi
 gation.html">Page Navigation</a> for more details.</p><h2 id="ComponentEvents-MultipleMethodMatches">Multiple Method Matches</h2><p>In some cases, there may be multiple event handler methods matching a single event. In that case, Tapestry invokes them in the following order:</p><ul><li>Base class methods before sub-class methods.</li><li>Matching methods within a class in alphabetical order.</li><li>For a single method name with multiple overrides, by number of parameters, descending.</li></ul><p>Of course, ordinarily would you <em>not</em> want to create more than one method to handle an event.</p><p>When a sub-class overrides an event handler method of a base class, the event handler method is only invoked once, along with any other base class methods. The subclass can change the <em>implementation</em> of the base class method via an override, but can't change the <em>timing</em> of when that method is invoked. See <a  class="external-link" href="https://issues.apache.org/jira/br
 owse/TAP5-51">issue TAP5-51</a>.</p><h2 id="ComponentEvents-EventContext">Event Context</h2><p>The context values (the context parameter to the EventLink or ActionLink component) can be any object. However, only a simple conversion to string occurs. (This is in contrast to Tapestry 4, which had an elaborate type mechanism with the odd name "DataSqueezer".)</p><p>Again, whatever your value is (string, number, date), it is converted into a plain string. This results in a more readable URL.</p><p>If you have multiple context values (by binding a list or array of objects to the <em>context</em> parameter of the EventLink or ActionLink), then each one, in order, will be added to the URL.</p><p>When an event handler method is invoked, the strings are converted back into values, or even objects. A <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a> is used to convert between client-side strings and server-side 
 objects. The <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ValueEncoderSource.html">ValueEncoderSource</a> service provides the necessary value encoders.</p><p>As shown in the example above, most of the parameters passed to the event handler method are derived from the values provided in the event context. Each successive method parameter matches against a value provided in the event context (the context parameter of the ActionLink component; though many components have a similar context parameter).</p><p>In many cases it is helpful to have direct access to the context (for example, to adapt to cases where there are a variable number of context values). The context values may be passed to an event handler method as parameter of the following types:</p><ul><li><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/EventContext.html">EventContext</a></li><li>Object[]</li><li>List&lt;Obj
 ect&gt;</li></ul><p>The latter two should be avoided, they may be removed in a future release. In all of these cases, the context parameter acts as a freebie; it doesn't match against a context value as it represents <em>all</em> context values.</p><plain-text-body>Object onActionFromEdit(EventContext context)
+</pre>
+</div></div><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>Many people prefer the naming convention approach, reserving the annotation just for situations that don't otherwise fit.</p></div></div><h2 id="ComponentEvents-MethodReturnValues">Method Return Values</h2><p>Main Article: <a  href="page-navigation.html">Page Navigation</a></p><p>For page navigation events (originating in components such as EventLink, ActionLink and Form), the value returned from an event handler method determines how Tapestry will render a response.</p><ul><li><strong>Null</strong>: For no value, or null, the current page (the page containing the component) will render the response.</li><li><strong>Page</strong>: For the name of a page, or a page class or page instance, a render request URL will be constructed and sent to the c
 lient as a redirect to that page.</li><li><strong>URL</strong>: For a java.net.URL, a redirect will be sent to the client. (In Tapestry 5.3.x and earlier, this only works for non-Ajax requests.)</li><li><strong>Zone body</strong>: In the case of an Ajax request to update a zone, the component event handler will return the new zone body, typically via an injected component or block.</li><li><strong>HttpError</strong>: For an <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpError.html">HttpError</a>, an error response is sent to the client.</li><li><strong>Link</strong>: For a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Link.html">Link</a>, a redirect is sent to the client.</li><li><strong>Stream</strong>: For a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/StreamResponse.html">StreamResponse</a>, a stream of data is sent to 
 the client</li><li><strong>boolean:</strong> <em>true</em> prevents the event from bubbling up further; <em>false</em> lets it bubble up. See Event Bubbling, below.</li></ul><p>See <a  href="page-navigation.html">Page Navigation</a> for more details.</p><h2 id="ComponentEvents-MultipleMethodMatches">Multiple Method Matches</h2><p>In some cases, there may be multiple event handler methods matching a single event. In that case, Tapestry invokes them in the following order:</p><ul><li>Base class methods before sub-class methods.</li><li>Matching methods within a class in alphabetical order.</li><li>For a single method name with multiple overrides, by number of parameters, descending.</li></ul><p>Of course, ordinarily would you <em>not</em> want to create more than one method to handle an event.</p><p>When a sub-class overrides an event handler method of a base class, the event handler method is only invoked once, along with any other base class methods. The subclass can change the <em>
 implementation</em> of the base class method via an override, but can't change the <em>timing</em> of when that method is invoked. See <a  class="external-link" href="https://issues.apache.org/jira/browse/TAP5-51">issue TAP5-51</a>.</p><h2 id="ComponentEvents-EventContext">Event Context</h2><p>The context values (the context parameter to the EventLink or ActionLink component) can be any object. However, only a simple conversion to string occurs. (This is in contrast to Tapestry 4, which had an elaborate type mechanism with the odd name "DataSqueezer".)</p><p>Again, whatever your value is (string, number, date), it is converted into a plain string. This results in a more readable URL.</p><p>If you have multiple context values (by binding a list or array of objects to the <em>context</em> parameter of the EventLink or ActionLink), then each one, in order, will be added to the URL.</p><p>When an event handler method is invoked, the strings are converted back into values, or even object
 s. A <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a> is used to convert between client-side strings and server-side objects. The <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ValueEncoderSource.html">ValueEncoderSource</a> service provides the necessary value encoders.</p><p>As shown in the example above, most of the parameters passed to the event handler method are derived from the values provided in the event context. Each successive method parameter matches against a value provided in the event context (the context parameter of the ActionLink component; though many components have a similar context parameter).</p><p>In many cases it is helpful to have direct access to the context (for example, to adapt to cases where there are a variable number of context values). The context values may be passed to an event handler method as parameter of 
 the following types:</p><ul><li><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/EventContext.html">EventContext</a></li><li>Object[]</li><li>List&lt;Object&gt;</li></ul><p>The latter two should be avoided, they may be removed in a future release. In all of these cases, the context parameter acts as a freebie; it doesn't match against a context value as it represents <em>all</em> context values.</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;">Object onActionFromEdit(EventContext context)
 {
     if (context.getCount() &gt; 0) {
         this.selectedId = context.get(0);
@@ -105,7 +197,9 @@ void editDocument(int docId)
         alertManager.warn("Please select a document.");
         return null;
     }
-}</plain-text-body><h2 id="ComponentEvents-AccessingRequestQueryParameters">Accessing Request Query Parameters</h2><p>A parameter may be annotated with the @RequestParameter annotation; this allows query parameters (?name1=value1&amp;name2=value2, etc) to be extracted from the request, converted to the correct type, and passed to the method. Again, this doesn't count against the event context values.</p><p>See the example in the <a  href="link-components-faq.html">Link Components FAQ</a>.</p><h2 id="ComponentEvents-MethodMatching">Method Matching</h2><p>An event handler method will only be invoked <em>if the context contains at least as many values as the method has parameters</em>. Methods with too many parameters will be silently skipped.</p><p>Tapestry will silently skip over a method if there are insufficient values in the context to satisfy the number of parameters requested.</p><p>EventContext parameters, and parameters annotated with @RequestParameter, do not count against th
 is limit.</p><h2 id="ComponentEvents-MethodOrdering">Method Ordering</h2><p>When multiple methods match within the same class, Tapestry will invoke them in ascending alphabetical order. When there are multiple overrides of the same method name, Tapestry invokes them in descending order by number of parameters. In general, these situations don't happen ... in most cases, only a single method is required to handle a specific event form a specific component.</p><p>An event handler method may return the value <code>true</code> to indicate that the event has been handled; this immediately stops the search for additional methods in the same class (or in base classes) or in containing components.</p><h1 id="ComponentEvents-EventBubbling">Event Bubbling</h1><p>The event will bubble up the component hierarchy, first to the containing component, then <em>that</em> component's containing component or page, and so on, until it is <em>aborted</em> by an event handler method returning <em>true</e
 m> or a non-null value.</p><p>Returning a boolean value from an event handler method is special. Returning <em>true</em> will abort the event with no result; use this when the event is fully handled without a return value and no further event handlers (in the same component, or in containing components) should be invoked.</p><p>Returning <em>false</em> is the same as returning null; event processing will continue to look for more event handlers, in the same component or its parent.</p><p>When an event bubbles up from a component to its container, the origin of the event is changed to be the component. For example, a Form component inside a BeanEditForm component may trigger a success event. The page containing the BeanEditForm may listen for that event, but it will be from the BeanEditForm component (which makes sense, because the id of the Form inside the BeanEditForm is part of the BeanEditForm's implementation, not its public interface).</p><p>If you want to handle events that ha
 ve bubbled up from nested component, you'll soon find that you don't have easy access to the component ID of the firing component. In practical terms this means that you'll want to trigger custom events for the events triggered by those nested components (see Triggering Events, below), and use that custom event name in your event handler method.</p><h1 id="ComponentEvents-EventMethodExceptions">Event Method Exceptions</h1><p>Event methods are allowed to throw any exception (not just runtime exceptions). If an event method does throw an exception, Tapestry will catch the thrown exception and ultimately display the exception report page.</p><p>In other words, there's no need to do this:</p><parameter ac:name="language">java</parameter><plain-text-body>  void onActionFromRunQuery()
+}</pre>
+</div></div><h2 id="ComponentEvents-AccessingRequestQueryParameters">Accessing Request Query Parameters</h2><p>A parameter may be annotated with the @RequestParameter annotation; this allows query parameters (?name1=value1&amp;name2=value2, etc) to be extracted from the request, converted to the correct type, and passed to the method. Again, this doesn't count against the event context values.</p><p>See the example in the <a  href="link-components-faq.html">Link Components FAQ</a>.</p><h2 id="ComponentEvents-MethodMatching">Method Matching</h2><p>An event handler method will only be invoked <em>if the context contains at least as many values as the method has parameters</em>. Methods with too many parameters will be silently skipped.</p><p>Tapestry will silently skip over a method if there are insufficient values in the context to satisfy the number of parameters requested.</p><p>EventContext parameters, and parameters annotated with @RequestParameter, do not count against this limi
 t.</p><h2 id="ComponentEvents-MethodOrdering">Method Ordering</h2><p>When multiple methods match within the same class, Tapestry will invoke them in ascending alphabetical order. When there are multiple overrides of the same method name, Tapestry invokes them in descending order by number of parameters. In general, these situations don't happen ... in most cases, only a single method is required to handle a specific event form a specific component.</p><p>An event handler method may return the value <code>true</code> to indicate that the event has been handled; this immediately stops the search for additional methods in the same class (or in base classes) or in containing components.</p><h1 id="ComponentEvents-EventBubbling">Event Bubbling</h1><p>The event will bubble up the component hierarchy, first to the containing component, then <em>that</em> component's containing component or page, and so on, until it is <em>aborted</em> by an event handler method returning <em>true</em> or a
  non-null value.</p><p>Returning a boolean value from an event handler method is special. Returning <em>true</em> will abort the event with no result; use this when the event is fully handled without a return value and no further event handlers (in the same component, or in containing components) should be invoked.</p><p>Returning <em>false</em> is the same as returning null; event processing will continue to look for more event handlers, in the same component or its parent.</p><p>When an event bubbles up from a component to its container, the origin of the event is changed to be the component. For example, a Form component inside a BeanEditForm component may trigger a success event. The page containing the BeanEditForm may listen for that event, but it will be from the BeanEditForm component (which makes sense, because the id of the Form inside the BeanEditForm is part of the BeanEditForm's implementation, not its public interface).</p><p>If you want to handle events that have bubb
 led up from nested component, you'll soon find that you don't have easy access to the component ID of the firing component. In practical terms this means that you'll want to trigger custom events for the events triggered by those nested components (see Triggering Events, below), and use that custom event name in your event handler method.</p><h1 id="ComponentEvents-EventMethodExceptions">Event Method Exceptions</h1><p>Event methods are allowed to throw any exception (not just runtime exceptions). If an event method does throw an exception, Tapestry will catch the thrown exception and ultimately display the exception report page.</p><p>In other words, there's no need to do this:</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 onActionFromRunQuery()
   {
     try
     {
@@ -116,23 +210,27 @@ void editDocument(int docId)
       throw new RuntimeException(ex);
     }
   }
-</plain-text-body><p>Instead, you may simply say:</p><parameter ac:name="language">java</parameter><plain-text-body>  void onActionFromRunQuery() throws JDBCException
+</pre>
+</div></div><p>Instead, you may simply say:</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 onActionFromRunQuery() throws JDBCException
   {
     dao.executeQuery();
   }
-</plain-text-body><p>Your event handler method may even declare that it "throws Exception" if that is more convenient.</p><h1 id="ComponentEvents-InterceptingEventExceptions">Intercepting Event Exceptions</h1><p>When an event handler method throws an exception (checked or runtime), Tapestry gives the component and its containing page a chance to handle the exception, before continuing on to report the exception.<plain-text-body>{float:right|background=#eee|padding=0 1em}
-    *JumpStart Demo:*
-    [Handling A Bad Context|http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/handlingabadcontext/1]
-{float}</plain-text-body>Tapestry triggers a new event, of type "exception", passing the thrown exception as the context. In fact, the exception is wrapped inside a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/runtime/ComponentEventException.html">ComponentEventException</a>, from which you may extract the event type and context.</p><p>Thus:</p><parameter ac:name="language">java</parameter><plain-text-body>  Object onException(Throwable cause)
+</pre>
+</div></div><p>Your event handler method may even declare that it "throws Exception" if that is more convenient.</p><h1 id="ComponentEvents-InterceptingEventExceptions">Intercepting Event Exceptions</h1><p>When an event handler method throws an exception (checked or runtime), Tapestry gives the component and its containing page a chance to handle the exception, before continuing on to report the exception.</p><div class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em">
+<p>    <strong>JumpStart Demo:</strong><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>Tapestry triggers a new event, of type "exception", passing the thrown exception as the context. In fact, the exception is wrapped inside a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/runtime/ComponentEventException.html">ComponentEventException</a>, from which you may extract the event type and context.<p>Thus:</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;">  Object onException(Throwable cause)
   {
     message = cause.getMessage();
 
     return this;
   }
-</plain-text-body><p>The return value of the exception event handler <em>replaces</em> the return value of original event handler method. For the typical case (an exception thrown by an "activate" or "action" event), this will be a <a  href="page-navigation.html">navigational response</a> such as a page instance or page name.</p><p>This can be handy for handling cases where the data in the URL is incorrectly formatted.</p><p>In the above example, the navigational response is the page itself.</p><p>If there is no exception event handler, or the exception event handler returns null (or is void), then the exception will be passed to the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestExceptionHandler.html">RequestExceptionHandler</a> service, which (in the default configuration) will render the exception page.</p><h1 id="ComponentEvents-TriggeringEvents">Triggering Events</h1><p><plain-text-body>{float:right|background=#ee
 e|padding=0 1em}
-    *JumpStart Demo:*
-    [AJAX Components CRUD|http://jumpstart.doublenegative.com.au/jumpstart/together/ajaxcomponentscrud/persons]
-{float}</plain-text-body>If you want your own component to trigger events, just call the <a  rel="nofollow">triggerEvent</a> method of <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ComponentResources.html">ComponentResources</a> from within the component class.</p><p>For example, the following triggers an "updateAll" event. A containing component can then respond to it, if desired, with an "onUpdateAll()" method in its own component class.</p><parameter ac:name="language">java</parameter><parameter ac:name="title">Your component class (partial)</parameter><plain-text-body>@Inject
+</pre>
+</div></div><p>The return value of the exception event handler <em>replaces</em> the return value of original event handler method. For the typical case (an exception thrown by an "activate" or "action" event), this will be a <a  href="page-navigation.html">navigational response</a> such as a page instance or page name.</p><p>This can be handy for handling cases where the data in the URL is incorrectly formatted.</p><p>In the above example, the navigational response is the page itself.</p><p>If there is no exception event handler, or the exception event handler returns null (or is void), then the exception will be passed to the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestExceptionHandler.html">RequestExceptionHandler</a> service, which (in the default configuration) will render the exception page.</p><h1 id="ComponentEvents-TriggeringEvents">Triggering Events</h1><p></p><div class="navmenu" style="float:right; backg
 round:#eee; margin:3px; padding:0 1em">
+<p>    <strong>JumpStart Demo:</strong><br clear="none">
+    <a  class="external-link" href="http://jumpstart.doublenegative.com.au/jumpstart/together/ajaxcomponentscrud/persons" rel="nofollow">AJAX Components CRUD</a></p></div>If you want your own component to trigger events, just call the <a  rel="nofollow">triggerEvent</a> method of <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ComponentResources.html">ComponentResources</a> from within the component class.<p>For example, the following triggers an "updateAll" event. A containing component can then respond to it, if desired, with an "onUpdateAll()" method in its own component class.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Your component class (partial)</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@Inject
 ComponentResources componentResources;
 &#160;...
 private void timeToUpdate() {
@@ -140,7 +238,8 @@ private void timeToUpdate() {
     if (wasHandled) {
         ...
     }
-} </plain-text-body><p>The third parameter to triggerEvent is a ComponentEventCallback, which you'll only need to implement if you want to get the return value of the handler method. The return value of <span class="il">triggerEvent</span>() says if the <span class="il">event</span> was handled or not.</p><p>&#160;</p></div>
+} </pre>
+</div></div><p>The third parameter to triggerEvent is a ComponentEventCallback, which you'll only need to implement if you want to get the return value of the handler method. The return value of <span class="il">triggerEvent</span>() says if the <span class="il">event</span> was handled or not.</p><p>&#160;</p></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/component-libraries.html
==============================================================================
--- websites/production/tapestry/content/component-libraries.html (original)
+++ websites/production/tapestry/content/component-libraries.html Sat Sep 16 01:54:19 2017
@@ -27,6 +27,15 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -67,7 +76,41 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>&#160;</p><parameter ac:name="hidden">true</parameter><parameter ac:name="atlassian-macro-output-type">BLOCK</parameter><rich-text-body><p>How to create a library of your custom components</p></rich-text-body><rich-text-body><p>This page has not yet been fully updated for Tapestry 5.4. Things are different and simpler in 5.4 than in previous releases.</p></rich-text-body><h1 id="ComponentLibraries-CreatingComponentLibraries">Creating Component Libraries</h1><p>Nearly every Tapestry application includes a least a couple of custom components, specific to the application. What's exciting about Tapestry is how easy it is to package components for reuse across many applications ... and the fact that applications using a component library need no special configuration.</p><parameter ac:name="style">float:right</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="class">aui-label</parameter><rich-text-body><par
 ameter ac:name="showLabels">false</parameter><parameter ac:name="showSpace">false</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="cql">label = "components" and space = currentSpace()</parameter></rich-text-body><p>A Tapestry component library consists of components (and optionally mixins, pages and component base classes). In addition, a component library will have a module that can define new services (needed by the components) or configure other services present in Tapestry. Finally, components can be packaged with <em>assets</em>: resources such as images, stylesheets and JavaScript libraries that need to be provided to the client web browser.</p><p>We're going to create a somewhat insipid component that displays a large happy face icon.</p><p>Tapestry doesn't mandate that you use any build system, but we'll assume for the moment that you are using Maven 2. In that case, you'll have a pom.xml file something like the following:</p><parameter a
 c:name="language">xml</parameter><parameter ac:name="title">pom.xml</parameter><plain-text-body>&lt;project&gt;
+                <div id="ConfluenceContent"><p>&#160;</p><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>This page has not yet been fully updated for Tapestry 5.4. Things are different and simpler in 5.4 than in previous releases.</p></div></div><h1 id="ComponentLibraries-CreatingComponentLibraries">Creating Component Libraries</h1><p>Nearly every Tapestry application includes a least a couple of custom components, specific to the application. What's exciting about Tapestry is how easy it is to package components for reuse across many applications ... and the fact that applications using a component library need no special configuration.</p><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="component-reference.html">Component Reference</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-libraries.html">Component Libraries</a>
+                
+                        
+                    </div>
+    </li></ul>
+</div>
+
+
+<p>A Tapestry component library consists of components (and optionally mixins, pages and component base classes). In addition, a component library will have a module that can define new services (needed by the components) or configure other services present in Tapestry. Finally, components can be packaged with <em>assets</em>: resources such as images, stylesheets and JavaScript libraries that need to be provided to the client web browser.</p><p>We're going to create a somewhat insipid component that displays a large happy face icon.</p><p>Tapestry doesn't mandate that you use any build system, but we'll assume for the moment that you are using Maven 2. In that case, you'll have a pom.xml file something like the following:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>pom.xml</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;project&gt;
   &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
   &lt;groupId&gt;org.example&lt;/groupId&gt;
   &lt;artifactId&gt;happylib&lt;/artifactId&gt;
@@ -134,7 +177,9 @@
     &lt;tapestry-release-version&gt;5.4-beta-28&lt;/tapestry-release-version&gt;
   &lt;/properties&gt;
 &lt;/project&gt;
-</plain-text-body><p>You will need to modify the Tapestry release version number ("5.2.0" in the listing above) to reflect the current version of Tapestry when you create your component library.</p><p>We'll go into more detail about the relevant portions of this POM in the later sections.</p><h2 id="ComponentLibraries-Step1:Chooseabasepackagename">Step 1: Choose a base package name</h2><p>Just as with Tapestry applications, Tapestry component libraries should have a <em>unique</em> base package name. In this example, we'll use <code>org.examples.happylib</code>.</p><p>As with an application, we'll follow the conventions: we'll place the module for this library inside the services package, and place pages and components under their respective packages.</p><h2 id="ComponentLibraries-Step2:Createyourpagesand/orcomponents">Step 2: Create your pages and/or components</h2><p>Our component is very simple:</p><parameter ac:name="language">java</parameter><parameter ac:name="title">HappyIcon
 .java</parameter><plain-text-body>package org.example.happylib.components;
+</pre>
+</div></div><p>You will need to modify the Tapestry release version number ("5.2.0" in the listing above) to reflect the current version of Tapestry when you create your component library.</p><p>We'll go into more detail about the relevant portions of this POM in the later sections.</p><h2 id="ComponentLibraries-Step1:Chooseabasepackagename">Step 1: Choose a base package name</h2><p>Just as with Tapestry applications, Tapestry component libraries should have a <em>unique</em> base package name. In this example, we'll use <code>org.examples.happylib</code>.</p><p>As with an application, we'll follow the conventions: we'll place the module for this library inside the services package, and place pages and components under their respective packages.</p><h2 id="ComponentLibraries-Step2:Createyourpagesand/orcomponents">Step 2: Create your pages and/or components</h2><p>Our component is very simple:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeade
 r pdl" style="border-bottom-width: 1px;"><b>HappyIcon.java</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">package org.example.happylib.components;
 
 import org.apache.tapestry5.Asset;
 import org.apache.tapestry5.MarkupWriter;
@@ -155,7 +200,9 @@ public class HappyIcon
         return false;
     }
 }
-</plain-text-body><p>HappyIcon appears inside the components sub-package. The happyIcon field is injected with the the Asset for the file <code>happy.jpg</code>. The path specified with the @Path annotation is relative to the <code>HappyIcon.class</code> file; it should be stored in the project under <code>src/main/resources/org/example/happylib/components</code>.</p><p>Tapestry ensures that the <code>happy.jpg</code> asset can be accessed from the client web browser; the src attribute of the &lt;img&gt; tag will be a URL that directly accesses the image file ... there's no need to unpackage the <code>happy.jpg</code> file. This works for any asset file stored under the library's root package.</p><p>This component renders out an <code>&lt;img&gt;</code> tag for the icon.</p><p>Often, a component library will have many different components, or even pages.</p><h2 id="ComponentLibraries-Step3:Chooseavirtualfoldername">Step 3: Choose a virtual folder name</h2><p>In Tapestry, components 
 that have been packaged in a library are referenced using a virtual folder name. It's effectively as if the application had a new root-level folder containing the components.</p><p>In our example, we'll use "happy" as the folder name. That means the application can include the HappyIcon component in the template using any of the following, which are all equivalent:</p><ul><li>&lt;t:happy.happyicon/&gt;</li><li>&lt;t:happy.icon/&gt;</li><li>&lt;img t:type="happy.happyicon"/&gt;</li><li>&lt;img t:type="happy/icon"/&gt;</li></ul><p>Why "icon" vs. "happyicon"? Tapestry notices that the folder name, "happy" is a prefix or suffix of the class name ("HappyIcon") and creates an alias that strips off the prefix (or suffix). To Tapestry, they are completely identical: two different aliases for the same component class name.</p><p>The above naming is somewhat clumsy, and can be improved by introducing an additional namespace into the template:</p><parameter ac:name="language">xml</parameter><p
 lain-text-body>&lt;html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
+</pre>
+</div></div><p>HappyIcon appears inside the components sub-package. The happyIcon field is injected with the the Asset for the file <code>happy.jpg</code>. The path specified with the @Path annotation is relative to the <code>HappyIcon.class</code> file; it should be stored in the project under <code>src/main/resources/org/example/happylib/components</code>.</p><p>Tapestry ensures that the <code>happy.jpg</code> asset can be accessed from the client web browser; the src attribute of the &lt;img&gt; tag will be a URL that directly accesses the image file ... there's no need to unpackage the <code>happy.jpg</code> file. This works for any asset file stored under the library's root package.</p><p>This component renders out an <code>&lt;img&gt;</code> tag for the icon.</p><p>Often, a component library will have many different components, or even pages.</p><h2 id="ComponentLibraries-Step3:Chooseavirtualfoldername">Step 3: Choose a virtual folder name</h2><p>In Tapestry, components that h
 ave been packaged in a library are referenced using a virtual folder name. It's effectively as if the application had a new root-level folder containing the components.</p><p>In our example, we'll use "happy" as the folder name. That means the application can include the HappyIcon component in the template using any of the following, which are all equivalent:</p><ul><li>&lt;t:happy.happyicon/&gt;</li><li>&lt;t:happy.icon/&gt;</li><li>&lt;img t:type="happy.happyicon"/&gt;</li><li>&lt;img t:type="happy/icon"/&gt;</li></ul><p>Why "icon" vs. "happyicon"? Tapestry notices that the folder name, "happy" is a prefix or suffix of the class name ("HappyIcon") and creates an alias that strips off the prefix (or suffix). To Tapestry, they are completely identical: two different aliases for the same component class name.</p><p>The above naming is somewhat clumsy, and can be improved by introducing an additional namespace into the template:</p><div class="code panel pdl" style="border-width: 1px;
 "><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
   xmlns:h="tapestry-library:happy"&gt;
 
   ...
@@ -164,7 +211,9 @@ public class HappyIcon
 
   ...
 &lt;/html&gt;
-</plain-text-body><p>The special namespace mapping for sets up namespace prefix "h:" to mean the same as "happy/". It then becomes possible to reference components within the happy virtual folder directly.</p><h2 id="ComponentLibraries-Step4:Configurethevirtualfolder">Step 4: Configure the virtual folder</h2><p>Tapestry needs to know where to search for your component class. This is accomplished in your library's IoC module class, by making a <em>contribution</em> to the ComponentClassResolver service configuration.</p><p>At application startup, Tapestry will read the library module along with all other modules and configure the ComponentClassResolver service using information in the module:</p><parameter ac:name="language">java</parameter><parameter ac:name="title">HappyModule.java</parameter><plain-text-body>package org.example.happylib.services;
+</pre>
+</div></div><p>The special namespace mapping for sets up namespace prefix "h:" to mean the same as "happy/". It then becomes possible to reference components within the happy virtual folder directly.</p><h2 id="ComponentLibraries-Step4:Configurethevirtualfolder">Step 4: Configure the virtual folder</h2><p>Tapestry needs to know where to search for your component class. This is accomplished in your library's IoC module class, by making a <em>contribution</em> to the ComponentClassResolver service configuration.</p><p>At application startup, Tapestry will read the library module along with all other modules and configure the ComponentClassResolver service using information in the module:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>HappyModule.java</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">package org.example.happylib.services;
 
 import org.apache.tapestry5.ioc.Configuration;
 import org.apache.tapestry5.services.LibraryMapping;
@@ -176,7 +225,9 @@ public class HappyModule
         configuration.add(new LibraryMapping("happy", "org.example.happylib"));
     }
 }
-</plain-text-body><p>The ComponentClassResolver service is responsible for mapping libraries to packages; it takes as a contribution a collection of these LibraryMapping objects. Every module may make its own contribution to the ComponentClassResolver service, mapping its own package ("org.example.happylib") to its own folder ("happy").</p><p>This module class is also where you would define new services that can be accessed by your components (or other parts of the application).</p><rich-text-body><p>It is possible to add a mapping for "core", the core library for Tapestry components; all the built-in Tapestry components (TextField, BeanEditForm, Grid, etc.) are actually in the core library. When Tapestry doesn't find a component in your application, it next searches inside the "core" library. Contributing an additional package as "core" simply extends the number of packages searched for core components (it doesn't replace Tapestry's default package, org.apache.tapestry5.corelib). A
 dding to "core" is sometimes reasonable, if you ensure that there is virtually no chance of a naming conflict (via different modules contributing packages to core with conflicting class names).</p></rich-text-body><h2 id="ComponentLibraries-Step5:Configurethemoduletoautoload">Step 5: Configure the module to autoload</h2><p>For Tapestry to load your module at application startup, it is necessary to put an entry in the JAR manifest. This is taken care of in the pom.xml above:</p><parameter ac:name="language">xml</parameter><parameter ac:name="title">pom.xml (partial)</parameter><plain-text-body>      &lt;plugin&gt;
+</pre>
+</div></div><p>The ComponentClassResolver service is responsible for mapping libraries to packages; it takes as a contribution a collection of these LibraryMapping objects. Every module may make its own contribution to the ComponentClassResolver service, mapping its own package ("org.example.happylib") to its own folder ("happy").</p><p>This module class is also where you would define new services that can be accessed by your components (or other parts of the application).</p><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>It is possible to add a mapping for "core", the core library for Tapestry components; all the built-in Tapestry components (TextField, BeanEditForm, Grid, etc.) are actually in the core library. When Tapestry doesn't find a component in your application, it next searches inside the "core" 
 library. Contributing an additional package as "core" simply extends the number of packages searched for core components (it doesn't replace Tapestry's default package, org.apache.tapestry5.corelib). Adding to "core" is sometimes reasonable, if you ensure that there is virtually no chance of a naming conflict (via different modules contributing packages to core with conflicting class names).</p></div></div><h2 id="ComponentLibraries-Step5:Configurethemoduletoautoload">Step 5: Configure the module to autoload</h2><p>For Tapestry to load your module at application startup, it is necessary to put an entry in the JAR manifest. This is taken care of in the pom.xml above:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>pom.xml (partial)</b></div><div class="codeContent panelContent pdl">
+<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">      &lt;plugin&gt;
            &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
            &lt;artifactId&gt;maven-jar-plugin&lt;/artifactId&gt;
            &lt;configuration&gt;
@@ -187,15 +238,20 @@ public class HappyModule
            &lt;/archive&gt;
            &lt;/configuration&gt;
        &lt;/plugin&gt;
-</plain-text-body><h2 id="ComponentLibraries-Step6:ExtendingClientAccess">Step 6: Extending Client Access</h2><p>As of Tapestry 5.2, a new step is needed: extending access for the assets. This is accomplished in your library's module class, HappyModule:</p><parameter ac:name="language">java</parameter><plain-text-body>public static void contributeRegexAuthorizer(Configuration&lt;String&gt; configuration)
+</pre>
+</div></div><h2 id="ComponentLibraries-Step6:ExtendingClientAccess">Step 6: Extending Client Access</h2><p>As of Tapestry 5.2, a new step is needed: extending access for the assets. This is accomplished in your library's module class, HappyModule:</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 static void contributeRegexAuthorizer(Configuration&lt;String&gt; configuration)
 {
     configuration.add("^org/example/happylib/.*\\.jpg$");
 }
-</plain-text-body><p>This contribution uses a regular expression to identify that any resource on the classpath under the org/example/happylib folder with a jpg extension is allowed. If you had a mix of different image types, you could replace jpg with (jpg|gif|png).</p><h2 id="ComponentLibraries-Step7:VersioningAssets">Step 7: Versioning Assets</h2><p>Classpath assets, those packaged in JAR files (such as the happy.jpg asset) are retrieved by the client web browser using a URL that reflects the package name. Tapestry users a special virtual folder, /assets, under the context folder for this purpose.</p><p>The image file here is exposed to the web browser via the URL /happyapp/assets/org/example/happylib/components/happy.jpg (this assumes that the application was deployed as happyapp.war).</p><p>Tapestry uses a far-future expiration date for classpath assets; this allows browsers to aggressively cache the file, but in Tapestry 5.1 and earlier this causes a problem when a later versi
 on of the library changes the file. This is discussed in detail in <a  class="external-link" href="http://developer.yahoo.com/performance/rules.html#expires" rel="nofollow">Yahoo's Performance Best Practices</a>.</p><p>To handle this problem in Tapestry 5.1 and earlier, you should map your library assets to a versioned folder. This can be accomplished using another contribution from the HappyModule, this time to the ClasspathAssetAliasManager service whose configuration maps a virtual folder underneath /assets to a package:</p><parameter ac:name="language">java</parameter><plain-text-body>public static void contributeClasspathAssetAliasManager(MappedConfiguration&lt;String, String&gt; configuration)
+</pre>
+</div></div><p>This contribution uses a regular expression to identify that any resource on the classpath under the org/example/happylib folder with a jpg extension is allowed. If you had a mix of different image types, you could replace jpg with (jpg|gif|png).</p><h2 id="ComponentLibraries-Step7:VersioningAssets">Step 7: Versioning Assets</h2><p>Classpath assets, those packaged in JAR files (such as the happy.jpg asset) are retrieved by the client web browser using a URL that reflects the package name. Tapestry users a special virtual folder, /assets, under the context folder for this purpose.</p><p>The image file here is exposed to the web browser via the URL /happyapp/assets/org/example/happylib/components/happy.jpg (this assumes that the application was deployed as happyapp.war).</p><p>Tapestry uses a far-future expiration date for classpath assets; this allows browsers to aggressively cache the file, but in Tapestry 5.1 and earlier this causes a problem when a later version of 
 the library changes the file. This is discussed in detail in <a  class="external-link" href="http://developer.yahoo.com/performance/rules.html#expires" rel="nofollow">Yahoo's Performance Best Practices</a>.</p><p>To handle this problem in Tapestry 5.1 and earlier, you should map your library assets to a versioned folder. This can be accomplished using another contribution from the HappyModule, this time to the ClasspathAssetAliasManager service whose configuration maps a virtual folder underneath /assets to a package:</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 static void contributeClasspathAssetAliasManager(MappedConfiguration&lt;String, String&gt; configuration)
 {
     configuration.add("happylib/1.0", "org/example/happylib");
 }
-</plain-text-body><p>With this in place, and the library and applications rebuilt and redeployed, the URL for happy.jpg becomes /happyapp/assets/happylib/1.0/components/happy.jpg. This is shorter, but also incorporates a version number ("1.0") that can be changed in a later release.</p>
+</pre>
+</div></div><p>With this in place, and the library and applications rebuilt and redeployed, the URL for happy.jpg becomes /happyapp/assets/happylib/1.0/components/happy.jpg. This is shorter, but also incorporates a version number ("1.0") that can be changed in a later release.</p>
 
 <div class="confluence-information-macro confluence-information-macro-information"><p class="title">Added in 5.2</p><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body">
 </div></div>