You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by bu...@apache.org on 2018/02/03 17:21:22 UTC

svn commit: r1024783 [2/8] - in /websites/production/tapestry/content: ./ cache/

Modified: websites/production/tapestry/content/client-side-javascript.html
==============================================================================
--- websites/production/tapestry/content/client-side-javascript.html (original)
+++ websites/production/tapestry/content/client-side-javascript.html Sat Feb  3 17:21:22 2018
@@ -44,13 +44,26 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div></div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div>
+
+</div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html"> 
- <input type="text" name="q"> 
- <input type="submit" value="Search"> 
-</form></div><div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div><div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Client-Side JavaScript</h1></div></div>
+            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
+<form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html">
+  <input type="text" name="q">
+  <input type="submit" value="Search">
+</form>
+
+</div>
+
+
+<div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div>
+
+
+<div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Client-Side JavaScript</h1></div>
+
+</div>
       <div class="clearer"></div>
       </div>
 
@@ -62,61 +75,103 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>Perhaps nothing in Tapestry has changed over the years so much as the way client-side JavaScript is supported. From the get go, the goal was to make JavaScript a first-class citizen in the Tapestry world, and make it easy to encapsulate JavaScript within components.</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="ajax-and-zones.html">Ajax and Zones</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="legacy-javascript.html">Legacy JavaScript</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="coffeescript.html">CoffeeScript</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="client-side-javascript.html">Client-Side JavaScript</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="javascript-modules.html">JavaScript Modules</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="javascript-faq.html">JavaScript 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="ajax-components-faq.html">Ajax Components 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="component-cheat-sheet.html">Component Cheat Sheet</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="assets.html">Assets</a> 
-  </div> </li></ul></div><p>The <a  href="legacy-javascript.html">legacy JavaScript</a> page discusses the earlier approaches; the main feature of Tapestry 5.4 is a total rewrite of all things client-side, with the following goals:</p><ul><li>Break the hard linkage of Tapestry to <a  class="external-link" href="http://prototypejs.org/" rel="nofollow">Prototype</a> and <a  class="external-link" href="http://script.aculo.us/" rel="nofollow">Scriptaculous</a>, by introducing an abstraction layer</li><li>Remove the clumsy <code>Tapestry</code> and <code>T5</code> "namespaces"</li><li>Reduce the amount of page-specific JavaScript initialization</li><li>Make it easier to override behavior associated with client elements</li><li>Support CoffeeScript and (potentially) other languages that target JavaScript</li><li>Organize client-side JavaScript using <a  href="javascript-modules.html">modules</a></li><li>Make pages load faster</li><li>Integrate <a  class="external-link" href="http://getboo
 tstrap.com/" rel="nofollow">Bootstrap</a></li><li>Make it easier for rich client libraries such as&#160;<a  class="external-link" href="http://backbonejs.org/" rel="nofollow">Backbone</a> or&#160;<a  class="external-link" href="https://angularjs.org/" rel="nofollow">AngularJS</a> to operate within a page</li><li>Properly document Tapestry's client support</li></ul><h3 id="Client-SideJavaScript-TheOverallVision">The Overall Vision</h3><p>The overall vision for the client-side in Tapestry is encapsulation, at several different levels.</p><p>On the server-side, a Tapestry component (or mixin) exposes configurable parameters. The component writes DOM elements or attributes, as well as some amount of JavaScript initialization. The encapsulation here allows developers with little or no knowledge of client-side JavaScript to enjoy the benefits (as consumers of components created by developers who are versed in client-side coding and Tapestry components).</p><p>On the client-side, the JavaS
 cript combines with the special markup to produce the behaviors that are desired ... anything from controlling the initial focus field, to performing client-side input field validation, to running complex Ajax workflows.</p><p>Where possible, all of this behavior is driven by <code>data-</code> attributes on the elements, combined with top-level event handlers. On the client side, events are used not only to respond directly to user actions (with "click", "mouseOver", "submit", or other event listeners) but also to allow elements to collaborate in various ways. &#160;For example, input validation is based on triggering a specific custom event on each form control element, and top-level event handlers can then manage the validation for any number of fields.</p><h3 id="Client-SideJavaScript-Prototypevs.jQuery">Prototype vs. jQuery</h3><p>For several years, it has been obvious that Tapestry "backed the wrong horse" with respect to Prototype and jQuery. When the first code was being lai
 d down in 2007 or 2008, it wasn't so clear that jQuery with its odd abstractions and unfamiliar approach, would go on to conquer the world. Meanwhile, Prototype was very strongly integrated into Ruby on Rails and had first class documentation and books.</p><p>That being said, jQuery is not the be-all and end-all either. Tapestry 5.4 introduces an abstraction layer, that allows many components to write code that doesn't care whether the foundation framework is Prototype or jQuery or something else. If<span style="font-size: 14.0px;">&#160;you like jQuery then there's no problem: write your application using just jQuery and you can ignore a lot of the features in the abstraction layer. Your code will likely be just a bit more efficient.</span></p><p>If you are building a reusable component or library, writing to the abstraction layer may be worth the effort; it is entirely possible that someone may write a replacement for the abstraction layer that targets your favorite foundation fra
 mework, such as ExtJS, MooTools, or something not even known of today.</p><h3 id="Client-SideJavaScript-Heavyvs.Light">Heavy vs. Light</h3><p>Earlier Tapestry JavaScript was&#160;<em>heavy</em>. Essentially, each component would write some very specific JavaScript initialization that would include the component's DOM id and many other details. This initialization would reference a function on the <code>T5.inits</code> namespace.</p><p>The function there would typically locate the specific element by its client DOM id, then attach event handlers to the one element. It might also create some form of client-side controller object. There were issues due to this: for complex pages (or perhaps even typical pages), the "blob" of JavaScript initialization at the bottom of the page could be quite large.</p><p>The use of individual event handlers meant that Tapestry applications would use more client-side objects that a bespoke jQuery solution ... because the normal approach in jQuery is to a
 ttach a single event handler to the document or body that handles any events that bubble up to the top&#160;<em>and</em> match a CSS selector.</p><p>In Tapestry 5.4, the goal is to make things&#160;<em>light</em>. In most cases, there isn't a specific initialization function; instead a <a  href="javascript-modules.html">JavaScript module</a>&#160;is loaded, and it installs one or more top-level event handlers; the elements has data-<a  class="external-link" href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes" rel="nofollow">&#160;attributes</a> that are used by those top level handlers to recognize which elements they are responsible for.</p><p>This is more of a full lifecycle approach; adding or removing page content (such as with a&#160;<a  href="ajax-and-zones.html">Zone</a> component) is both cheaper and less error prone using top-level event handlers than per-element event handlers; there's also less of a chance of memory leaks under Internet Exp
 lorer.</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>Internet Explorer is pretty well known for memory leaks; its DOM and JavaScript run in different kinds of memory, which are garbage collected individually. This means that a reference from JavaScript to a DOM element will keep the DOM element live, even if that's the only reference to the DOM element anywhere. Meanwhile, event handler JavaScript functions are kept live from the DOM element, making a cycle that can't be broken. Libraries like Prototype and jQuery have to expend some effort to break this link by unregistering event handlers from DOM elements when removing them from the DOM.</p></div></div><p>A specific example of this approach is how client-side validation now works; in the past, there was a complex system of classes and event listeners
  that were specific to each individual field. Field controllers had to register with Form controllers. Validators had to register with Field controllers.</p><p>Under 5.4, there are a number of&#160;<code>data-</code> attributes that can be attached to any DOM element. A form searches for elements with a non-blank value for&#160;<code>data-validation</code>; each such element has a series of custom events triggered on it. The top-level handlers for those events receive notifications for elements throughout the document.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>t5/core/validation.coffee (partial)</b></div><div class="codeContent panelContent pdl">
+                <div id="ConfluenceContent"><p>Perhaps nothing in Tapestry has changed over the years so much as the way client-side JavaScript is supported. From the get go, the goal was to make JavaScript a first-class citizen in the Tapestry world, and make it easy to encapsulate JavaScript within components.</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="ajax-and-zones.html">Ajax and Zones</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="legacy-javascript.html">Legacy JavaScript</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="coffeescript.html">CoffeeScript</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="client-side-javascript.html">Client-Side JavaScript</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="javascript-modules.html">JavaScript Modules</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="javascript-faq.html">JavaScript 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="ajax-components-faq.html">Ajax Components 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="component-cheat-sheet.html">Component Cheat Sheet</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="assets.html">Assets</a>
+                
+                        
+                    </div>
+    </li></ul>
+</div>
+
+
+<p>The <a  href="client-side-javascript.html">legacy JavaScript</a> page discusses the earlier approaches; the main feature of Tapestry 5.4 is a total rewrite of all things client-side, with the following goals:</p><ul><li>Break the hard linkage of Tapestry to <a  class="external-link" href="http://prototypejs.org/" rel="nofollow">Prototype</a> and <a  class="external-link" href="http://script.aculo.us/" rel="nofollow">Scriptaculous</a>, by introducing an abstraction layer</li><li>Remove the clumsy <code>Tapestry</code> and <code>T5</code> "namespaces"</li><li>Reduce the amount of page-specific JavaScript initialization</li><li>Make it easier to override behavior associated with client elements</li><li>Support CoffeeScript and (potentially) other languages that target JavaScript</li><li>Organize client-side JavaScript using <a  href="client-side-javascript.html">modules</a></li><li>Make pages load faster</li><li>Integrate <a  class="external-link" href="http://getbootstrap.com/" rel
 ="nofollow">Bootstrap</a></li><li>Make it easier for rich client libraries such as&#160;<a  class="external-link" href="http://backbonejs.org/" rel="nofollow">Backbone</a> or&#160;<a  class="external-link" href="https://angularjs.org/" rel="nofollow">AngularJS</a> to operate within a page</li><li>Properly document Tapestry's client support</li></ul><h3 id="Client-SideJavaScript-TheOverallVision">The Overall Vision</h3><p>The overall vision for the client-side in Tapestry is encapsulation, at several different levels.</p><p>On the server-side, a Tapestry component (or mixin) exposes configurable parameters. The component writes DOM elements or attributes, as well as some amount of JavaScript initialization. The encapsulation here allows developers with little or no knowledge of client-side JavaScript to enjoy the benefits (as consumers of components created by developers who are versed in client-side coding and Tapestry components).</p><p>On the client-side, the JavaScript combines w
 ith the special markup to produce the behaviors that are desired ... anything from controlling the initial focus field, to performing client-side input field validation, to running complex Ajax workflows.</p><p>Where possible, all of this behavior is driven by <code>data-</code> attributes on the elements, combined with top-level event handlers. On the client side, events are used not only to respond directly to user actions (with "click", "mouseOver", "submit", or other event listeners) but also to allow elements to collaborate in various ways. &#160;For example, input validation is based on triggering a specific custom event on each form control element, and top-level event handlers can then manage the validation for any number of fields.</p><h3 id="Client-SideJavaScript-Prototypevs.jQuery">Prototype vs. jQuery</h3><p>For several years, it has been obvious that Tapestry "backed the wrong horse" with respect to Prototype and jQuery. When the first code was being laid down in 2007 o
 r 2008, it wasn't so clear that jQuery with its odd abstractions and unfamiliar approach, would go on to conquer the world. Meanwhile, Prototype was very strongly integrated into Ruby on Rails and had first class documentation and books.</p><p>That being said, jQuery is not the be-all and end-all either. Tapestry 5.4 introduces an abstraction layer, that allows many components to write code that doesn't care whether the foundation framework is Prototype or jQuery or something else. If<span>&#160;you like jQuery then there's no problem: write your application using just jQuery and you can ignore a lot of the features in the abstraction layer. Your code will likely be just a bit more efficient.</span></p><p>If you are building a reusable component or library, writing to the abstraction layer may be worth the effort; it is entirely possible that someone may write a replacement for the abstraction layer that targets your favorite foundation framework, such as ExtJS, MooTools, or somethi
 ng not even known of today.</p><h3 id="Client-SideJavaScript-Heavyvs.Light">Heavy vs. Light</h3><p>Earlier Tapestry JavaScript was&#160;<em>heavy</em>. Essentially, each component would write some very specific JavaScript initialization that would include the component's DOM id and many other details. This initialization would reference a function on the <code>T5.inits</code> namespace.</p><p>The function there would typically locate the specific element by its client DOM id, then attach event handlers to the one element. It might also create some form of client-side controller object. There were issues due to this: for complex pages (or perhaps even typical pages), the "blob" of JavaScript initialization at the bottom of the page could be quite large.</p><p>The use of individual event handlers meant that Tapestry applications would use more client-side objects that a bespoke jQuery solution ... because the normal approach in jQuery is to attach a single event handler to the documen
 t or body that handles any events that bubble up to the top&#160;<em>and</em> match a CSS selector.</p><p>In Tapestry 5.4, the goal is to make things&#160;<em>light</em>. In most cases, there isn't a specific initialization function; instead a <a  href="client-side-javascript.html">JavaScript module</a>&#160;is loaded, and it installs one or more top-level event handlers; the elements has data-<a  class="external-link" href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes" rel="nofollow">&#160;attributes</a> that are used by those top level handlers to recognize which elements they are responsible for.</p><p>This is more of a full lifecycle approach; adding or removing page content (such as with a&#160;<a  href="client-side-javascript.html">Zone</a> component) is both cheaper and less error prone using top-level event handlers than per-element event handlers; there's also less of a chance of memory leaks under Internet Explorer.</p><div class="confluenc
 e-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>Internet Explorer is pretty well known for memory leaks; its DOM and JavaScript run in different kinds of memory, which are garbage collected individually. This means that a reference from JavaScript to a DOM element will keep the DOM element live, even if that's the only reference to the DOM element anywhere. Meanwhile, event handler JavaScript functions are kept live from the DOM element, making a cycle that can't be broken. Libraries like Prototype and jQuery have to expend some effort to break this link by unregistering event handlers from DOM elements when removing them from the DOM.</p></div></div><p>A specific example of this approach is how client-side validation now works; in the past, there was a complex system of classes and event listeners that were specific to each ind
 ividual field. Field controllers had to register with Form controllers. Validators had to register with Field controllers.</p><p>Under 5.4, there are a number of&#160;<code>data-</code> attributes that can be attached to any DOM element. A form searches for elements with a non-blank value for&#160;<code>data-validation</code>; each such element has a series of custom events triggered on it. The top-level handlers for those events receive notifications for elements throughout the document.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>t5/core/validation.coffee (partial)</b></div><div class="codeContent panelContent pdl">
 <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">define ["underscore", "./dom", "./events", "./utils", "./messages", "./fields"],
   (_, dom, events, utils, messages) -&gt;
 
@@ -135,7 +190,7 @@
       if memo.translated.length &lt; min
         memo.error = (@attr "data-min-length-message") or "TOO SHORT"
         return false</pre>
-</div></div><p>The&#160;<code>t5/core/events</code> module defines constants for different custom event name, it's also a handy place to <a  class="external-link" href="http://tapestry.apache.org/5.4/coffeescript/events.html">hang documentation</a> about those events.</p><p>The&#160;<code>t5/core/dom</code> namespace is the abstraction layer. &#160;<code>onDocument</code> is a handy way to attach a top-level event handler.</p><p>Fields that are required have the attribute&#160;<code>data-optionality=required</code>; the event handler is passed a&#160;<em>memo</em> object that includes a&#160;<code>value</code> property, the value from the field. This makes it easier to generate an error if the value is blank. &#160;Because the exact error message may be customized or localized, it is provided in the element as well, as the&#160;<code>data-required-message</code> attribute. Setting&#160;<code>memo.error</code> to a validation error string causes the field to be decorated with the err
 or message and indicates that the form itself is in error and not ready for submission.</p><p>A different event is triggered after the optionality check; The&#160;<code>memo.translated</code> property is the value translated before validation (for a numeric field, it would be translated from a string to a number, for example). Again, the&#160;<code>error</code> property is set, and the&#160;<code>return false</code> ensures that the event will stop bubbling to containing elements or event handlers.</p><p>What's very useful in this overall approach is that it no longer matters whether the fields were rendered by Tapestry on the server, or rendered locally (perhaps using Backbone or AngularJS) on the client. As long as they have the correct&#160;<code>data-</code> attributes, then they can participate in Tapestry's overall form validation and submission cycle, and even leverage the default validation decoration behavior.</p><h3 id="Client-SideJavaScript-TheAbstractionLayer">The Abstra
 ction Layer</h3><p>The abstraction layer is defined by the&#160;<code>t5/core/dom</code> module. This module currently has two different implementations - one is a wrapper around Prototype, and the other is a wrapper around jQuery.</p><p>The resulting abstraction layer is a bit of a hybrid; it mostly looks like jQuery, but events look a bit more like Prototype. It also doesn't have jQuery's concept of operating on a matched set of elements.</p><p>The abstraction is both transitional and permanent. It is transitional in that it is about allowing existing sites with a heavy investment in Prototype to continue to operate with Prototype in the mix. It is permanent &#160;in that it is desirable for third party library developers to keep an abstraction layer between Tapestry's client-side code and any underlying framework, so that particular applications can provide their own abstraction layer and operate without breaking built-in components.</p><p>Most applications should transition to j
 Query and feel free to use jQuery directly. &#160;It is still best to inject module <span style="font-family: monospace;">jquery</span>&#160;into your own modules (usually as parameter&#160;<code>$</code>).&#160;</p><p>If you are writing a third-party application and want to maximize re-use, then use the abstraction layer.</p><p>It is often easier to use the abstraction layer to respond correctly to custom Tapestry events.</p></div>
+</div></div><p>The&#160;<code>t5/core/events</code> module defines constants for different custom event name, it's also a handy place to <a  class="external-link" href="http://tapestry.apache.org/5.4/coffeescript/events.html">hang documentation</a> about those events.</p><p>The&#160;<code>t5/core/dom</code> namespace is the abstraction layer. &#160;<code>onDocument</code> is a handy way to attach a top-level event handler.</p><p>Fields that are required have the attribute&#160;<code>data-optionality=required</code>; the event handler is passed a&#160;<em>memo</em> object that includes a&#160;<code>value</code> property, the value from the field. This makes it easier to generate an error if the value is blank. &#160;Because the exact error message may be customized or localized, it is provided in the element as well, as the&#160;<code>data-required-message</code> attribute. Setting&#160;<code>memo.error</code> to a validation error string causes the field to be decorated with the err
 or message and indicates that the form itself is in error and not ready for submission.</p><p>A different event is triggered after the optionality check; The&#160;<code>memo.translated</code> property is the value translated before validation (for a numeric field, it would be translated from a string to a number, for example). Again, the&#160;<code>error</code> property is set, and the&#160;<code>return false</code> ensures that the event will stop bubbling to containing elements or event handlers.</p><p>What's very useful in this overall approach is that it no longer matters whether the fields were rendered by Tapestry on the server, or rendered locally (perhaps using Backbone or AngularJS) on the client. As long as they have the correct&#160;<code>data-</code> attributes, then they can participate in Tapestry's overall form validation and submission cycle, and even leverage the default validation decoration behavior.</p><h3 id="Client-SideJavaScript-TheAbstractionLayer">The Abstra
 ction Layer</h3><p>The abstraction layer is defined by the&#160;<code>t5/core/dom</code> module. This module currently has two different implementations - one is a wrapper around Prototype, and the other is a wrapper around jQuery.</p><p>The resulting abstraction layer is a bit of a hybrid; it mostly looks like jQuery, but events look a bit more like Prototype. It also doesn't have jQuery's concept of operating on a matched set of elements.</p><p>The abstraction is both transitional and permanent. It is transitional in that it is about allowing existing sites with a heavy investment in Prototype to continue to operate with Prototype in the mix. It is permanent &#160;in that it is desirable for third party library developers to keep an abstraction layer between Tapestry's client-side code and any underlying framework, so that particular applications can provide their own abstraction layer and operate without breaking built-in components.</p><p>Most applications should transition to j
 Query and feel free to use jQuery directly. &#160;It is still best to inject module <span>jquery</span>&#160;into your own modules (usually as parameter&#160;<code>$</code>).&#160;</p><p>If you are writing a third-party application and want to maximize re-use, then use the abstraction layer.</p><p>It is often easier to use the abstraction layer to respond correctly to custom Tapestry events.</p></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/coffeescript.html
==============================================================================
--- websites/production/tapestry/content/coffeescript.html (original)
+++ websites/production/tapestry/content/coffeescript.html Sat Feb  3 17:21:22 2018
@@ -44,13 +44,26 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div></div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div>
+
+</div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html"> 
- <input type="text" name="q"> 
- <input type="submit" value="Search"> 
-</form></div><div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div><div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">CoffeeScript</h1></div></div>
+            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
+<form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html">
+  <input type="text" name="q">
+  <input type="submit" value="Search">
+</form>
+
+</div>
+
+
+<div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div>
+
+
+<div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">CoffeeScript</h1></div>
+
+</div>
       <div class="clearer"></div>
       </div>
 
@@ -62,55 +75,94 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p><strong>CoffeeScript</strong> (<a  class="external-link" href="http://coffeescript.org" rel="nofollow">http://coffeescript.org</a>) is a language that compiles down to JavaScript.</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="coffeescript.html">CoffeeScript</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="client-side-javascript.html">Client-Side JavaScript</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="javascript-modules.html">JavaScript Modules</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="javascript-faq.html">JavaScript 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="ajax-and-zones.html">Ajax and Zones</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-cheat-sheet.html">Component Cheat Sheet</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="legacy-javascript.html">Legacy JavaScript</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="assets.html">Assets</a> 
-  </div> </li></ul></div><p><em>Starting with version 5.4,</em> Tapestry can automatically compile your CoffeeScript code into JavaScript on the fly. This is done with the optional tapestry-webresources module. It is highly recommended for anyone who wants to use CoffeeScript in their application ... just let Tapestry do the compilation at runtime (with access to Tapestry's full exception reporting capabilities).</p><p>To use the tapestry-webresources module, just add the JAR to your project. For example, if you're using Maven:</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">
+                <div id="ConfluenceContent"><p><strong>CoffeeScript</strong> (<a  class="external-link" href="http://coffeescript.org" rel="nofollow">http://coffeescript.org</a>) is a language that compiles down to JavaScript.</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="coffeescript.html">CoffeeScript</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="client-side-javascript.html">Client-Side JavaScript</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="javascript-modules.html">JavaScript Modules</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="javascript-faq.html">JavaScript 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="ajax-and-zones.html">Ajax and Zones</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-cheat-sheet.html">Component Cheat Sheet</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="legacy-javascript.html">Legacy JavaScript</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="assets.html">Assets</a>
+                
+                        
+                    </div>
+    </li></ul>
+</div>
+
+
+<p><em>Starting with version 5.4,</em> Tapestry can automatically compile your CoffeeScript code into JavaScript on the fly. This is done with the optional tapestry-webresources module. It is highly recommended for anyone who wants to use CoffeeScript in their application ... just let Tapestry do the compilation at runtime (with access to Tapestry's full exception reporting capabilities).</p><p>To use the tapestry-webresources module, just add the JAR to your project. For example, if you're using Maven:</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;dependency&gt;
     &lt;groupId&gt;org.apache.tapestry&lt;/groupId&gt;
     &lt;artifactId&gt;tapestry-webresources&lt;/artifactId&gt;

Modified: websites/production/tapestry/content/component-report.html
==============================================================================
--- websites/production/tapestry/content/component-report.html (original)
+++ websites/production/tapestry/content/component-report.html Sat Feb  3 17:21:22 2018
@@ -98,7 +98,7 @@
         &lt;rootPackage&gt;org.example.myapp&lt;/rootPackage&gt;
     &lt;/configuration&gt;
 &lt;/plugin&gt;</pre>
-</div></div><p>Be sure the update the <em>&lt;version&gt;</em> element with the current version of the Maven plugin, and update the <em>&lt;rootPackage&gt;</em> element with the value for your application (this will match the value you configure inside your <a  href="configuration.html">web.xml</a>).</p>
+</div></div><p>Be sure the update the <em>&lt;version&gt;</em> element with the current version of the Maven plugin, and update the <em>&lt;rootPackage&gt;</em> element with the value for your application (this will match the value you configure inside your <a  href="component-report.html">web.xml</a>).</p>
 
 <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>

Modified: websites/production/tapestry/content/defining-tapestry-ioc-services.html
==============================================================================
--- websites/production/tapestry/content/defining-tapestry-ioc-services.html (original)
+++ websites/production/tapestry/content/defining-tapestry-ioc-services.html Sat Feb  3 17:21:22 2018
@@ -44,13 +44,26 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div></div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div>
+
+</div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html"> 
- <input type="text" name="q"> 
- <input type="submit" value="Search"> 
-</form></div><div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div><div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Defining Tapestry IOC Services</h1></div></div>
+            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
+<form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html">
+  <input type="text" name="q">
+  <input type="submit" value="Search">
+</form>
+
+</div>
+
+
+<div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div>
+
+
+<div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Defining Tapestry IOC Services</h1></div>
+
+</div>
       <div class="clearer"></div>
       </div>
 
@@ -139,7 +152,7 @@ public class MyAppModule
 
     return indexer;
   }</pre>
-</div></div><p>If you find yourself injecting the same dependencies into multiple service builder (or service decorator) methods, you can <a  href="tapestry-ioc-modules.html">cache dependency injections</a> in your module, by defining a constructor. This reduces duplication in your module.</p><h1 id="DefiningTapestryIOCServices-DisambiguationwithMarkerAnnotations">Disambiguation with Marker Annotations</h1><p>In the previous example we were faced with a problem: multiple versions of the JobScheduler service. They had the same service interface but unique service ids. If you try to inject based on type, the service to inject will be ambiguous. Tapestry will throw an exception (identifying the parameter type and the matching services that implement that type).</p><p>The problem is that when injecting a JobScheduler into some other service we need to know which <em>one</em> to inject. Rather than using the service id, another approach is to use a <em>marker annotation</em>.</p><p>You m
 ay optionally link a service implementation with a marker annotation.</p><p>For example, maybe you have one JobScheduler implementation where the jobs are spread across a number of nodes in a cluster, and you have another JobScheduler where the jobs are all executed exclusively in the current process.</p><p>We can associate those two JobSchedulers with two annotations.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>If you find yourself injecting the same dependencies into multiple service builder (or service decorator) methods, you can <a  href="defining-tapestry-ioc-services.html">cache dependency injections</a> in your module, by defining a constructor. This reduces duplication in your module.</p><h1 id="DefiningTapestryIOCServices-DisambiguationwithMarkerAnnotations">Disambiguation with Marker Annotations</h1><p>In the previous example we were faced with a problem: multiple versions of the JobScheduler service. They had the same service interface but unique service ids. If you try to inject based on type, the service to inject will be ambiguous. Tapestry will throw an exception (identifying the parameter type and the matching services that implement that type).</p><p>The problem is that when injecting a JobScheduler into some other service we need to know which <em>one</em> to inject. Rather than using the service id, another approach is to use a <em>marker annotation</em>.</
 p><p>You may optionally link a service implementation with a marker annotation.</p><p>For example, maybe you have one JobScheduler implementation where the jobs are spread across a number of nodes in a cluster, and you have another JobScheduler where the jobs are all executed exclusively in the current process.</p><p>We can associate those two JobSchedulers with two annotations.</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;">@Target(
 { PARAMETER, FIELD })
 @Retention(RUNTIME)
@@ -221,7 +234,7 @@ public class IndexerImpl implements Inde
 
   . . .
 }</pre>
-</div></div><p>Understanding why this is a bad idea involves a long detour into inner details of the Java Memory Model. The short form is that other threads may end up invoking methods on the IndexerImpl instance, and its fields (even though they are final, even though they appear to already have been set) may be uninitialized.</p><h1 id="DefiningTapestryIOCServices-FieldInjection">Field Injection</h1><p>The @<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">Inject</a> and @<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html">InjectService</a> annotations may be used on instance fields of a service implementation class, as an alternative to passing dependencies of the service implementation in via the constructor.</p><p>Note that only dependencies are settable this way; if you want resources, including the service's <a  href="tapes
 try-ioc-configuration.html">configuration</a>, you must pass those through the constructor. You <em>are</em> free to mix and match, injecting partially with field injection and partially with constructor injection.</p><p>Caution: injection via fields uses reflection to make the fields accessible. In addition, it may not be as thread-safe as using the constructor to assign to final fields.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>Understanding why this is a bad idea involves a long detour into inner details of the Java Memory Model. The short form is that other threads may end up invoking methods on the IndexerImpl instance, and its fields (even though they are final, even though they appear to already have been set) may be uninitialized.</p><h1 id="DefiningTapestryIOCServices-FieldInjection">Field Injection</h1><p>The @<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/Inject.html">Inject</a> and @<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/InjectService.html">InjectService</a> annotations may be used on instance fields of a service implementation class, as an alternative to passing dependencies of the service implementation in via the constructor.</p><p>Note that only dependencies are settable this way; if you want resources, including the service's <a  href="defin
 ing-tapestry-ioc-services.html">configuration</a>, you must pass those through the constructor. You <em>are</em> free to mix and match, injecting partially with field injection and partially with constructor injection.</p><p>Caution: injection via fields uses reflection to make the fields accessible. In addition, it may not be as thread-safe as using the constructor to assign to final fields.</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;">package org.example.myapp.services;
 
 import org.apache.tapestry5.ioc.annotations.InjectService;
@@ -237,7 +250,7 @@ public class IndexerImpl implements Inde
 <pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">  bind(MyServiceInterface.class, MyServiceImpl.class).scope(ScopeConstants.PERTHREAD);</pre>
 </div></div><h1 id="DefiningTapestryIOCServices-EagerLoadingServices">Eager Loading Services</h1><p>Services are normally created only as needed (per the scope discussion above).</p><p>This can be tweaked slightly; by adding the @<a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/annotations/EagerLoad.html">EagerLoad</a> annotation to the service builder method, Tapestry will instantiate the service when the Registry is first created.</p><p>This will cause the service builder method to be invoked, as well as any service decorator methods.</p><p>This feature is used when a service manages a resource, such as a thread, that needs to be created as soon as the application starts up. Another common example is a service that listens for events produced by a second service; the first service may need to be created, and start listening, before any of its service methods are invoked (which would normally trigger the instantiation of the servic
 e).</p><p>Many services may be annotated with @EagerLoad; the order in which services are created is not defined.</p><p>With the perthread scope, the service builder method will not be invoked (this won't happen until a service method is invoked), but the decorators for the service will be created.</p><h1 id="DefiningTapestryIOCServices-EagerLoadingAutobuiltServices">Eager Loading Autobuilt Services</h1><p>As with service scope, there are two options for indicating that an autobuilt service should be eagerly loaded.</p><p>The service implementation class may include the @EagerLoad annotation.</p><p>You may also specify eager loading explicitly when binding the service:</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;">  bind(MyServiceInterface.class, MyServiceImpl.class).eagerLoad();</pre>
-</div></div><h1 id="DefiningTapestryIOCServices-InjectingResources">Injecting Resources</h1><p>In addition to injecting services, Tapestry will key off of the parameter type to allow other things to be injected.</p><ul><li>java.lang.String: unique id for the service</li><li><a  class="external-link" href="http://www.slf4j.org/api/org/slf4j/Logger.html" rel="nofollow">org.slf4j.Logger</a>: logger for the service</li><li>java.lang.Class: service interface implemented by the service to be constructed</li><li><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceResources.html">ServiceResources</a>: access to other services</li></ul><p>No annotation is needed for these cases.</p><p>See also <a  href="tapestry-ioc-configuration.html">service configuration</a> for additional special cases of resources that can be injected.</p><p>Note: resources may not be injected into fields, they are injectable only via method or constructor parameter
 s.</p><p>Example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><h1 id="DefiningTapestryIOCServices-InjectingResources">Injecting Resources</h1><p>In addition to injecting services, Tapestry will key off of the parameter type to allow other things to be injected.</p><ul><li>java.lang.String: unique id for the service</li><li><a  class="external-link" href="http://www.slf4j.org/api/org/slf4j/Logger.html" rel="nofollow">org.slf4j.Logger</a>: logger for the service</li><li>java.lang.Class: service interface implemented by the service to be constructed</li><li><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceResources.html">ServiceResources</a>: access to other services</li></ul><p>No annotation is needed for these cases.</p><p>See also <a  href="defining-tapestry-ioc-services.html">service configuration</a> for additional special cases of resources that can be injected.</p><p>Note: resources may not be injected into fields, they are injectable only via method or constructor param
 eters.</p><p>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 static Indexer build(String serviceId, Log serviceLog,
      JobScheduler scheduler, FileSystem fileSystem)
   {
@@ -256,7 +269,7 @@ public class IndexerImpl implements Inde
 
     return indexer;
   }</pre>
-</div></div><p>This works the exact same way with autobuilt services, except that the parameters of the service implementation constructor are considered, rather than the parameters of the service builder method.</p><p>The @InjectService annotation takes precedence over these resources.</p><p>If the @InjectService annotation is not present, and the parameter type does not exactly match a resource type, then <a  href="object-providers.html">object injection</a> occurs. Object injection will find the correct object to inject based on a number of (extensible) factors, including the parameter type and any additional annotations on the parameter.</p><p>Every once and a while, you'll have a conflict between a resource type and an object injection. For example, the following does not work as expected:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>This works the exact same way with autobuilt services, except that the parameters of the service implementation constructor are considered, rather than the parameters of the service builder method.</p><p>The @InjectService annotation takes precedence over these resources.</p><p>If the @InjectService annotation is not present, and the parameter type does not exactly match a resource type, then <a  href="defining-tapestry-ioc-services.html">object injection</a> occurs. Object injection will find the correct object to inject based on a number of (extensible) factors, including the parameter type and any additional annotations on the parameter.</p><p>Every once and a while, you'll have a conflict between a resource type and an object injection. For example, the following does not work as expected:</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 Indexer build(String serviceId, Log serviceLog,
      JobScheduler scheduler, FileSystem fileSystem,
      @Value("${index-alerts-email}")
@@ -280,7 +293,7 @@ public class IndexerImpl implements Inde
 
     return indexer;
   }</pre>
-</div></div><p>Here, the alertEmail parameter will receive the configured alerts email (see <a  href="symbols.html">the symbols documentation</a> for more about this syntax) rather than the service id.</p><h1 id="DefiningTapestryIOCServices-BindingServiceBuilders">Binding ServiceBuilders</h1><p>Yet another option is available: instead of binding an interface to a implemention class, you can bind a service to a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBuilder.html">ServiceBuilder</a>, a callback used to create the service implementation. This is very useful in very rare circumstances.</p><h1 id="DefiningTapestryIOCServices-BuiltinServices">Builtin Services</h1><p>A few services within the Tapestry IOC Module are "builtin"; there is no service builder method in the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/TapestryIOCModule.html">TapestryIOCModule</a> cl
 ass.</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd"><p><strong>Service Id</strong></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><strong>Service Interface</strong></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>ClassFactory</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/ClassFactory.html">ClassFactory</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>LoggerSource</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/LoggerSource.html">LoggerSource</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>RegistryShutdownHub</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="ht
 tp://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/RegistryShutdownHub.html">RegistryShutdownHub</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>PerthreadManager</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/PerthreadManager.html">PerthreadManager</a></p></td></tr></tbody></table></div><p>Consult the JavaDoc for each of these services to identify under what circumstances you'll need to use them.</p><h1 id="DefiningTapestryIOCServices-MutuallyDependentServices">Mutually Dependent Services</h1><p>One of the benefits of Tapestry IoC's proxy-based approach to just-in-time instantiation is the automatic support for mutually dependent services. For example, suppose that the Indexer and the FileSystem needed to talk directly to each other. Normally, this would cause a "chicken-and-the-egg" problem: which one to create fi
 rst?</p><p>With Tapestry IoC, this is not even considered a special case:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>Here, the alertEmail parameter will receive the configured alerts email (see <a  href="defining-tapestry-ioc-services.html">the symbols documentation</a> for more about this syntax) rather than the service id.</p><h1 id="DefiningTapestryIOCServices-BindingServiceBuilders">Binding ServiceBuilders</h1><p>Yet another option is available: instead of binding an interface to a implemention class, you can bind a service to a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/ServiceBuilder.html">ServiceBuilder</a>, a callback used to create the service implementation. This is very useful in very rare circumstances.</p><h1 id="DefiningTapestryIOCServices-BuiltinServices">Builtin Services</h1><p>A few services within the Tapestry IOC Module are "builtin"; there is no service builder method in the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/TapestryIOCModule.html">T
 apestryIOCModule</a> class.</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><td colspan="1" rowspan="1" class="confluenceTd"><p><strong>Service Id</strong></p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><strong>Service Interface</strong></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>ClassFactory</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/ClassFactory.html">ClassFactory</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>LoggerSource</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/LoggerSource.html">LoggerSource</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>RegistryShutdownHub</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="
 external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/RegistryShutdownHub.html">RegistryShutdownHub</a></p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>PerthreadManager</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ioc/services/PerthreadManager.html">PerthreadManager</a></p></td></tr></tbody></table></div><p>Consult the JavaDoc for each of these services to identify under what circumstances you'll need to use them.</p><h1 id="DefiningTapestryIOCServices-MutuallyDependentServices">Mutually Dependent Services</h1><p>One of the benefits of Tapestry IoC's proxy-based approach to just-in-time instantiation is the automatic support for mutually dependent services. For example, suppose that the Indexer and the FileSystem needed to talk directly to each other. Normally, this would cause a "chicken-and-the-egg" problem:
  which one to create first?</p><p>With Tapestry IoC, this is not even considered a special case:</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 Indexer buildIndexer(JobScheduler scheduler, FileSystem fileSystem)
   {
     IndexerImpl indexer = new IndexerImpl(fileSystem);

Modified: websites/production/tapestry/content/development-dashboard.html
==============================================================================
--- websites/production/tapestry/content/development-dashboard.html (original)
+++ websites/production/tapestry/content/development-dashboard.html Sat Feb  3 17:21:22 2018
@@ -67,7 +67,7 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>The <strong>development dashboard</strong> is a built-in Tapestry page that can help identify and resolve problems in your application.</p><p>The dashboard is typically only available to requests from localhost (the page is whitelist access only, see <a  href="development-dashboard.html">Development Dashboard</a>).</p><p><span>Some features of the dashboard are only available in development mode.</span></p><p>The dashboard is available via the URI "core/t5dashboard", or can be accessed by the <a  class="external-link" href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/DevTool.html">DevTool</a> component's dropdown menu.</p><p><span>&#160;<span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image image-center" width="500" src="development-dashboard.data/Tapestry_5_Dashboard_-_pages.png"></span></span></p><p>By default, there a
 re three tabs (this is extensible).</p><h2 id="DevelopmentDashboard-Pages">Pages</h2><p>The pages tab shows what pages are currently loaded into the application. Tapestry only loads a page when it is first needed.</p><p>It is possible to clear out Tapestry's caches, forcing a reload. You can also run a garbage collection (GC).</p><p>It is possible to load any individual page, or attempt to load all pages. This can be a good way to see if all pages (and templates) are error free ... loading all will catch quite a few potential errors.</p><h2 id="DevelopmentDashboard-Services">Services</h2><p>When using Tapestry there will often be a large number of services defined in the registry; a mix of the built-in services provided by the framework and your own.</p><p>Services are usually only instantiated once they are needed.</p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image image-center" width="500"
  src="development-dashboard.data/Tapestry_5_Dashboard.png"></span></p><p>&#160;</p><p>Services may be builtin, defined, virtual or real.</p><p><strong>Builtin</strong> only applies to a few special services that are part of Tapestry IoC.</p><p><strong>Defined</strong> services are defined in some module, but have not yet been referenced in any way.</p><p><strong>Virtual</strong> services have been referenced and have gotten as far as creating a service proxy.</p><p><strong>Real</strong> services have had methods invoked, this forces the <em>realization</em> of the service which includes instantiating the service, injecting dependencies, and decorating with any applicable interceptors.</p><h2 id="DevelopmentDashboard-ComponentLibraries">Component Libraries</h2><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image confluence-external-resource confluence-content-image-border image-center" width="500"
  src="https://cwiki-test.apache.org/confluence/download/attachments/22872137/Tapestry_5_Dashboard_-_libs.png?version=1&amp;modificationDate=1428090505000&amp;api=v2" data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/22872137/Tapestry_5_Dashboard_-_libs.png?version=1&amp;modificationDate=1428090505000&amp;api=v2"></span></p><p>This page gives a summary of all component libraries used in the current application.</p></div>
+                <div id="ConfluenceContent"><p>The <strong>development dashboard</strong> is a built-in Tapestry page that can help identify and resolve problems in your application.</p><p>The dashboard is typically only available to requests from localhost (the page is whitelist access only, see <a  href="development-dashboard.html">Development Dashboard</a>).</p><p><span>Some features of the dashboard are only available in development mode.</span></p><p>The dashboard is available via the URI "core/t5dashboard", or can be accessed by the <a  class="external-link" href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/corelib/components/DevTool.html">DevTool</a> component's dropdown menu.</p><p><span>&#160;<span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image image-center" width="500" src="development-dashboard.data/Tapestry_5_Dashboard_-_pages.png"></span></span></p><p>By default, there a
 re three tabs (this is extensible).</p><h2 id="DevelopmentDashboard-Pages">Pages</h2><p>The pages tab shows what pages are currently loaded into the application. Tapestry only loads a page when it is first needed.</p><p>It is possible to clear out Tapestry's caches, forcing a reload. You can also run a garbage collection (GC).</p><p>It is possible to load any individual page, or attempt to load all pages. This can be a good way to see if all pages (and templates) are error free ... loading all will catch quite a few potential errors.</p><h2 id="DevelopmentDashboard-Services">Services</h2><p>When using Tapestry there will often be a large number of services defined in the registry; a mix of the built-in services provided by the framework and your own.</p><p>Services are usually only instantiated once they are needed.</p><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image image-center" width="500"
  src="development-dashboard.data/Tapestry_5_Dashboard.png"></span></p><p>&#160;</p><p>Services may be builtin, defined, virtual or real.</p><p><strong>Builtin</strong> only applies to a few special services that are part of Tapestry IoC.</p><p><strong>Defined</strong> services are defined in some module, but have not yet been referenced in any way.</p><p><strong>Virtual</strong> services have been referenced and have gotten as far as creating a service proxy.</p><p><strong>Real</strong> services have had methods invoked, this forces the <em>realization</em> of the service which includes instantiating the service, injecting dependencies, and decorating with any applicable interceptors.</p><h2 id="DevelopmentDashboard-ComponentLibraries">Component Libraries</h2><p><span class="confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size"><img class="confluence-embedded-image image-center" width="500" src="development-dashboard.data/Tapestry_5_Dashboard_-_libs.
 png"></span></p><p>This page gives a summary of all component libraries used in the current application.</p></div>
       </div>
 
       <div class="clearer"></div>