Author: buildbot
Date: Mon Jun 23 17:19:39 2014
New Revision: 913400
Log:
Production update by buildbot for tapestry
Modified:
websites/production/tapestry/content/cache/main.pageCache
websites/production/tapestry/content/client-side-javascript.html
websites/production/tapestry/content/javascript-modules.html
websites/production/tapestry/content/user-guide.html
Modified: websites/production/tapestry/content/cache/main.pageCache
==============================================================================
Binary files - no diff available.
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 Mon Jun 23
17:19:39 2014
@@ -25,6 +25,14 @@
</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 type="text/javascript">
+ SyntaxHighlighter.defaults['toolbar'] = false;
+ SyntaxHighlighter.all();
+ </script>
<link href="/styles/style.css" rel="stylesheet" type="text/css"/>
@@ -61,7 +69,32 @@
</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><p>The
<a shape="rect" 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 shape="rect" class="external-link"
href="http://prototypejs.org/" >Prototype</a> and <a shape="rect"
class="external-link" href="http://script.aculo.us/" >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 clien
t elements</li><li>Support CoffeeScript and (potentially) other languages that
target JavaScript</li><li>Organize client-side JavaScript using <a shape="rect"
href="javascript-modules.html">modules</a></li><li>Make pages load
faster</li><li>Integrate <a shape="rect" class="external-link"
href="http://getbootstrap.com/" >Bootstrap</a></li><li>Make it easier for rich
client libraries such as <a shape="rect" class="external-link"
href="http://backbonejs.org/" >Backbone</a> or <a shape="rect"
class="external-link" href="https://angularjs.org/" >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)
will exposes configurable parameters. The component will write DOM elements or
attributes, as well as some amo
unt 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 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.  For example, input validation is based on
triggering a specific custom event on each form control element, and top-level
eve
nt 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 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 may not be the be-all and end-all.
Tapestry 5.4 introduces an abstraction layer, that allows many components to
write code that doesn't care whether the foundation framework in Prototype or
jQuery. This is especially useful during the arduous process of moving Tapestry
5.3 client-side code forward to 5.4.</p><p>If you like jQuery then there's no
problem: write your application using just jQuery and you can igno
re a lot of the features in the abstraction layer. Your code will likely be
just a bit more efficient.</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 something not even known of today.</p><h3
id="Client-SideJavaScript-Heavyvs.Light">Heavy vs. Light</h3><p>Earlier
Tapestry JavaScript was <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 is
sues 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 document or body that handles any events that bubble up to the
top <em>and</em> match a CSS selector.</p><p>In Tapestry 5.4, the goal is
to make things <em>light</em>. In most cases, there will not be a specific
initialization function; instead a <a shape="rect"
href="javascript-modules.html">JavaScript module</a> will be loaded, and it
will install one or more top-level event handlers; the elements will have <a
shape="rect" class="external-link"
href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes"
><code>data-</code> 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; there's no danger
of </p><p> </p></div>
+<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><p>The
<a shape="rect" 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 shape="rect" class="external-link"
href="http://prototypejs.org/" >Prototype</a> and <a shape="rect"
class="external-link" href="http://script.aculo.us/" >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 clien
t elements</li><li>Support CoffeeScript and (potentially) other languages that
target JavaScript</li><li>Organize client-side JavaScript using <a shape="rect"
href="javascript-modules.html">modules</a></li><li>Make pages load
faster</li><li>Integrate <a shape="rect" class="external-link"
href="http://getbootstrap.com/" >Bootstrap</a></li><li>Make it easier for rich
client libraries such as <a shape="rect" class="external-link"
href="http://backbonejs.org/" >Backbone</a> or <a shape="rect"
class="external-link" href="https://angularjs.org/" >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)
will exposes configurable parameters. The component will write DOM elements or
attributes, as well as some amo
unt 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 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.  For example, input validation is based on
triggering a specific custom event on each form control element, and top-level
eve
nt 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 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 may not be the be-all and end-all.
Tapestry 5.4 introduces an abstraction layer, that allows many components to
write code that doesn't care whether the foundation framework in Prototype or
jQuery. This is especially useful during the arduous process of moving Tapestry
5.3 client-side code forward to 5.4.</p><p>If you like jQuery then there's no
problem: write your application using just jQuery and you can igno
re a lot of the features in the abstraction layer. Your code will likely be
just a bit more efficient.</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 something not even known of today.</p><h3
id="Client-SideJavaScript-Heavyvs.Light">Heavy vs. Light</h3><p>Earlier
Tapestry JavaScript was <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 is
sues 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 document or body that handles any events that bubble up to the
top <em>and</em> match a CSS selector.</p><p>In Tapestry 5.4, the goal is
to make things <em>light</em>. In most cases, there will not be a specific
initialization function; instead a <a shape="rect"
href="javascript-modules.html">JavaScript module</a> will be loaded, and it
will install one or more top-level event handlers; the elements will have <a
shape="rect" class="external-link"
href="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes"
><code>data-</code> 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 <a shape="rect" 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 Explorer.</p> <div class="aui-message warning shadowed
information-macro">
+ <span class="aui-icon icon-warning">Icon</span>
+ <div class="message-content">
+ <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 <code>data-</code>
attributes that can be attached to any DOM element. A form will search for
elements with a non-blank value for <code>data-validation</code>; each
such element has a series of custom events triggered on it. The top-level
handlers for those events will 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">
+<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[define ["underscore",
"./dom", "./events", "./utils",
"./messages", "./fields"],
+ (_, dom, events, utils, messages) ->
+
+
+ ...
+Â
+ dom.onDocument events.field.optional,
"[data-optionality=required]", (event, memo) ->
+ if utils.isBlank memo.value
+ memo.error = (@attr "data-required-message") or
"REQUIRED"
+
+
+ ...
+Â
+ dom.onDocument events.field.validate,
"[data-validate-min-length]", (event, memo) ->
+ min = parseInt @attr "data-validate-min-length"
+ if memo.translated.length < min
+ memo.error = (@attr "data-min-length-message") or "TOO
SHORT"
+ return false]]></script>
+</div></div><p>The <code>t5/core/events</code> module defines constants
for different custom event name, it's also a handy place to hang <a
shape="rect" class="external-link"
href="http://tapestry.apache.org/5.4/coffeescript/events.html">hang
documentation</a> about those events.</p><p>The <code>t5/core/dom</code>
namespace is the abstraction layer.  <code>onDocument</code> is a handy
way to attach a top-level event handler.</p><p>Fields that are required will
have the attribute <code>data-optionality=required</code>; the event
handler is passed a <em>memo</em> object that includes
a <code>value</code> property, the value from the field. This makes it
easier to generate an error if the value is blank.  Because the exact
error message may be customized or localized, it is provided in the element as
well, as the <code>data-required-message</code> attribute.
Setting <code>memo.error</code> to a validation error string will cause
the fie
ld to be decorated with the error message and will indicate that the form
itself is in error and not ready for submission.</p><p>A different event is
triggered after the optionality check; The <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 <code>error</code> property is set, and the <code>return
false</code> ensures that the event will stop bubbling to containing elements
or event handlers.</p></div>
</div>
<div class="clearer"></div>
Modified: websites/production/tapestry/content/javascript-modules.html
==============================================================================
--- websites/production/tapestry/content/javascript-modules.html (original)
+++ websites/production/tapestry/content/javascript-modules.html Mon Jun 23
17:19:39 2014
@@ -70,7 +70,7 @@
</div>
<div id="content">
-<div id="ConfluenceContent"><p>As web applications have evolved, the use of
JavaScript in the client has expanded almost exponentially. This has caused all
kinds of growing pains, since the original design of the web browser, and the
initial design of JavaScript, was never intended for this level of complexity.
Unlike Java, JavaScript has no native concept of a "package" or "namespace" and
has the undesirable tendency to make everything a global.</p><p>In the earliest
days, client-side JavaScript was constructed as libraries that define simple
functions and variables:</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
+<div id="ConfluenceContent"><p>As web applications have evolved, the use of
JavaScript in the client has expanded almost exponentially. This has caused all
kinds of growing pains, since the original design of the web browser, and the
initial design of JavaScript, was never intended for this level of complexity.
Unlike Java, JavaScript has no native concept of a "package" or "namespace" and
has the undesirable tendency to make everything a global.</p><p>In the earliest
days, client-side JavaScript was constructed as libraries that would define
simple functions and variables:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
<script class="theme: Default; brush: js; gutter: false"
type="syntaxhighlighter"><![CDATA[Â
function onclickHelp(event) {
if (helpModal === undefined) {
@@ -124,7 +124,7 @@ $("#helpButton").click(onClick
<p>With AMD, the JavaScript libraries may be
loaded in parallel by the browser (that's the <em>asynchronous</em> part of
AMD); RequireJS manages the dependency graph and invokes each function just
once, as soon as its dependencies are ready, as libraries are loaded. In some
cases, a module may be loaded just for its side effects; such modules will be
listed last in the dependency array, and will not have a corresponding
parameter in the dependent module's constructor function. In
<code>confirm-click</code>, the <code>bootstrap/modal</code> module is loaded
for side-effects.</p>
</div>
</div>
-<p><code>confirm-click</code> defines a local function,
<code>runDialog</code>. It performs some side-effects, attaching event handlers
to the body and the document. It's export is a JavaScript object containing a
function that allows other modules to raise the modal dialog.</p><p>If a module
truly exports only a single function and is unlikely to change, then it is
acceptable to just return the function itself, not an object containing the
function. However, returning an object makes it easier to expand the
responsibilities of <code>confirm-click</code> in the future; perhaps to add a
<code>dismissDialog</code> function.</p><h3
id="JavaScriptModules-LocationofModules">Location of Modules</h3><p>Modules are
stored as a special kind of Tapestry <a shape="rect"
href="assets.html">asset</a>. On the server, modules are stored on the class
path under <code>META-INF/modules</code>. In a typical environment, that means
the sources will be in <code>src/main/resources/META-INF/modules</code>
.</p><p>Typically, your application will place it's modules directly in this
folder. If you are writing a reusable library, you will put modules for that
library into a subfolder to prevent naming conflicts. Tapestry's own modules
are prefixed with <code>t5/core</code>.</p><p>If you are using the
optional <code>tapestry-web-resources</code> module (that's a server-side
module, not an AMD module), then you can write your modules as CoffeeScript
files; Tapestry will take care of compiling them to JavaScript as
necessary.</p><p>The service <a shape="rect" class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/javascript/ModuleManager.html">ModuleManager</a>
is the central piece of server-side support for modules. It
supports <em>overriding</em> of existing modules by contributing
overriding <a shape="rect" class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/javascript/JavaScriptModuleConfig
uration.html">module definitions</a>. This can be useful to <a shape="rect"
class="external-link" href="http://en.wikipedia.org/wiki/Monkey_patch" >monkey
patch</a> an existing module supplied with Tapestry, or as part of a
third-party library.</p><h3
id="JavaScriptModules-LoadingModulesfromTapestryCode">Loading Modules from
Tapestry Code</h3><p>Often, you will have a Tapestry page or component that
defines client-side behavior; such a component will need to load a
module.</p><p>The simplest approach is to use the <a shape="rect"
class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/annotations/Import.html">Import</a>
annotation:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+<p><code>confirm-click</code> defines a local function,
<code>runDialog</code>. It performs some side-effects, attaching event handlers
to the body and the document. The module's export is a JavaScript object
containing a function that allows other modules to raise the modal
dialog.</p><p>If a module truly exports only a single function and is unlikely
to change, then it is acceptable to just return the function itself, not an
object containing the function. However, returning an object makes it easier to
expand the responsibilities of <code>confirm-click</code> in the future;
perhaps to add a <code>dismissDialog</code> function.</p><h3
id="JavaScriptModules-LocationofModules">Location of Modules</h3><p>Modules are
stored as a special kind of Tapestry <a shape="rect"
href="assets.html">asset</a>. On the server, modules are stored on the class
path under <code>META-INF/modules</code>. In a typical environment, that means
the sources will be in <code>src/main/resources/META-INF/module
s</code>.</p><p>Typically, your application will place it's modules directly
in this folder. If you are writing a reusable library, you will put modules for
that library into a subfolder to prevent naming conflicts. Tapestry's own
modules are prefixed with <code>t5/core</code>.</p><p>If you are using the
optional <code>tapestry-web-resources</code> module (that's a server-side
module, not an AMD module), then you can write your modules as CoffeeScript
files; Tapestry will take care of compiling them to JavaScript as
necessary.</p><p>The service <a shape="rect" class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/javascript/ModuleManager.html">ModuleManager</a>
is the central piece of server-side support for modules. It
supports <em>overriding</em> of existing modules by contributing
overriding <a shape="rect" class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/javascript/JavaScriptModu
leConfiguration.html">module definitions</a>. This can be useful to <a
shape="rect" class="external-link"
href="http://en.wikipedia.org/wiki/Monkey_patch" >monkey patch</a> an existing
module supplied with Tapestry, or as part of a third-party library.</p><h3
id="JavaScriptModules-LoadingModulesfromTapestryCode">Loading Modules from
Tapestry Code</h3><p>Often, you will have a Tapestry page or component that
defines client-side behavior; such a component will need to load a
module.</p><p>The simplest approach is to use the <a shape="rect"
class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/annotations/Import.html">Import</a>
annotation:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[@Import(module =
"t5/core/confirm-click")
public class Confirm
{
@@ -141,14 +141,20 @@ public class Confirm
...
Â
javaScriptSupport.require("my-module").invoke("setup").with(clientId,
actionUrl);]]></script>
-</div></div><p>In the first example, <code>my-module</code> exports a single
function of two parameters. In the second example, <code>my-module</code>
exports an object and the <code>setup</code> key is the function that is
invoked.</p><h3 id="JavaScriptModules-DevelopmentMode">Development
Mode</h3><p>In development mode, Tapestry will write details into the
client-side console.</p><p><img class="confluence-embedded-image"
src="https://cwiki.apache.org/confluence/download/attachments/41813130/Tapestry_Integration_Test_Application_and_JavaScriptSupport__Tapestry_API_Documentation_.png?version=1&modificationDate=1401727827255&api=v2"
data-image-src="/confluence/download/attachments/41813130/Tapestry_Integration_Test_Application_and_JavaScriptSupport__Tapestry_API_Documentation_.png?version=1&modificationDate=1401727827255&api=v2"></p><p>This
lists modules <em>explicitly</em> loaded (for initialization), but does
not include modules loaded only as dependencies. You
can see more details about what was actually loaded using <em>view
source</em>; RequireJS adds <code><script></code> tags to the document to
load libraries and modules.</p><h3
id="JavaScriptModules-Librariesvs.Modules">Libraries vs.
Modules</h3><p>Tapestry still supports JavaScript libraries.  When the
page is loading, all libraries are loaded before any modules.</p><p>Libraries
are loaded sequentially, so if you can avoid using libraries, so much the
better in terms of page load time.</p><p>Libraries work in both normal page
rendering, and Ajax partial page updates. Even in partial page updates, the
libraries will be loaded sequentially before modules are loaded or exported
functions invoked.</p><h3 id="JavaScriptModules-AggregatingModules">Aggregating
Modules</h3><p>An important part of performance for production applications is
JavaScript aggregation.</p><p>In development mode, you want your modules and
other assets to load individually. Unlike assets, modules ca
n't be fingerprinted, so on each page load, the client browser must ask the
server for the module again (typically getting a 304 Not Modified
response).</p><p>This is acceptable in development mode, but quite undesirable
in production.</p><p>With JavaScript aggregation, the module can be included in
the single virtual JavaScript library that represents a <a shape="rect"
class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/javascript/JavaScriptStack.html">JavaScript
stack</a>. This significantly cuts down on both the number of requests from
the client to the server, and the overall number of bytes
transferred.</p><p>Adding a module to the stack is not the same as
<code>require</code>-ing it. In fact, you must still use
<code>JavaScriptSupport.require()</code> regardless.</p><p>What adding a module
to a stack accomplishes is that the module's code is downloaded in the first,
initial JavaScript download; the download of the stack's virtual li
brary. When (and if) the module is required as a dependency, the code will
already be present in the browser and ready to
execute.</p><p>Tapestry <strong>does not</strong> attempt to do dependency
analysis; that is left as a manual exercise. Typically, if you aggregate a
module, your should look at its dependencies, and aggregate those as well.
Failure to do so will cause unwanted requests back to the Tapestry server for
the dependency modules, even though the aggregated module's code is
present.</p><p>Because Tapestry is open, it is possible to contribute modules
even into the <strong>core</strong> JavaScript stack.  This is done
using your application's module:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>In the first example, <code>my-module</code> exports a single
function of two parameters. In the second example, <code>my-module</code>
exports an object and the <code>setup</code> key is the function that is
invoked.</p><h3 id="JavaScriptModules-DevelopmentMode">Development
Mode</h3><p>In development mode, Tapestry will write details into the
client-side console.</p><p><img class="confluence-embedded-image"
src="https://cwiki.apache.org/confluence/download/attachments/41813130/Tapestry_Integration_Test_Application_and_JavaScriptSupport__Tapestry_API_Documentation_.png?version=1&modificationDate=1401727827000&api=v2"
data-image-src="/confluence/download/attachments/41813130/Tapestry_Integration_Test_Application_and_JavaScriptSupport__Tapestry_API_Documentation_.png?version=1&modificationDate=1401727827000&api=v2"></p><p>This
lists modules <em>explicitly</em> loaded (for initialization), but does
not include modules loaded only as dependencies. You
can see more details about what was actually loaded using <em>view
source</em>; RequireJS adds <code><script></code> tags to the document to
load libraries and modules.</p><h3
id="JavaScriptModules-Librariesvs.Modules">Libraries vs.
Modules</h3><p>Tapestry still supports JavaScript libraries.  When the
page is loading, all libraries are loaded before any modules.</p><p>Libraries
are loaded sequentially, so if you can avoid using libraries, so much the
better in terms of page load time.</p><p>Libraries work in both normal page
rendering, and Ajax partial page updates. Even in partial page updates, the
libraries will be loaded sequentially before modules are loaded or exported
functions invoked.</p><h3 id="JavaScriptModules-AggregatingModules">Aggregating
Modules</h3><p>An important part of performance for production applications is
JavaScript aggregation.</p><p>In development mode, you want your modules and
other assets to load individually. For both CSS and JavaScri
pt, smaller files that align with corresponding server-side files makes it
much easier to debug problems.</p><p>Unlike assets, modules can't be
fingerprinted, so on each page load, the client browser must ask the server for
the module's contents frequently (typically getting a 304 Not Modified
response).</p> <div class="aui-message warning shadowed information-macro">
+ <span class="aui-icon icon-warning">Icon</span>
+ <div class="message-content">
+ <p>By default, Tapestry sets a max age of 60
(seconds) on modules, so you won't see module requests on every page load. This
is configurable and you may want a much higher value in production. If you are
rapidly iterating on the source of a module, you may need to force the browser
to reload after clearing local cache. Chrome has an option to disable the
client-side cache when its developer tools are open.</p>
+ </div>
+ </div>
+<p><span style="line-height: 1.4285715;">This is acceptable in development
mode, but quite undesirable in production.</span></p><p>With JavaScript
aggregation, the module can be included in the single virtual JavaScript
library that represents a <a shape="rect" class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/javascript/JavaScriptStack.html">JavaScript
stack</a>. This significantly cuts down on both the number of requests from
the client to the server, and the overall number of bytes
transferred.</p><p>Adding a module to the stack is not the same as
<code>require</code>-ing it. In fact, you must still use
<code>JavaScriptSupport.require()</code> regardless.</p><p>What adding a module
to a stack accomplishes is that the module's code is downloaded in the first,
initial JavaScript download; the download of the stack's virtual library. When
(and if) the module is required as a dependency, the code will already be
present in the browser an
d ready to execute.</p><p>Tapestry <strong>does not</strong> attempt to
do dependency analysis; that is left as a manual exercise. Typically, if you
aggregate a module, your should look at its dependencies, and aggregate those
as well. Failure to do so will cause unwanted requests back to the Tapestry
server for the dependency modules, even though the aggregated module's code is
present.</p><p>Because Tapestry is open, it is possible to contribute modules
even into the <strong>core</strong> JavaScript stack.  This is done
using your application's module:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[ @Contribute(JavaScriptStack.class)
@Core
public static void
addAppModules(OrderedConfiguration<StackExtension> configuration) {
configuration.add("tree-viewer",
StackExtension.module("tree-viewer"));
configuration.add("app-utils",
StackExtension.module("app-utils"));
}]]></script>
-</div></div><p>To break this down:</p><ul><li>@Contribute indicates we are
contributing to a JavaScriptStack service</li><li>Since there are (or at least,
could be) multiple services that implement JavaScriptStack, we provide
the @Core annotation to indicate which one we are contributing
to</li><li>It is possible to contribute libraries, CSS files, other stacks, and
modules; here we are contributing modules</li><li>Each contribution has a
unique id and a <a shape="rect" class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/javascript/StackExtension.html">StackExtension</a>
value</li></ul><p>The core stack includes several libraries and modules; the
exact configuration is subject to a number of factors (such as whether
Prototype or jQuery is being used as the underlying framework). That being
said, this is the <em>current</em> list of modules aggregated into the
core stack:</p><ul><li>jquery</li><li>underscore</li><li>t5/core/<ul><
li>alert</li><li>ajax</li><li>bootstrap</li><li>console</li><li>dom</li><li>events</li><li>exception-frame</li><li>fields</li><li>pageinit</li><li>messages</li><li>util</li><li>validation</li></ul></li></ul><p>The
optimum configuration is always a balancing act between including too little
and including too much. Generally speaking, including too much is less costly
than including too little. It is up to you to analyze the requests coming into
your application and determine what modules should be aggregated.</p></div>
+</div></div><p>To break this down:</p><ul><li>@Contribute indicates we are
contributing to a JavaScriptStack service</li><li>Since there are (or at least,
could be) multiple services that implement JavaScriptStack, we provide
the @Core annotation to indicate which one we are contributing to (this is
a marker annotation, which exists for this exact purpose)</li><li>It is
possible to contribute libraries, CSS files, other stacks, and modules; here we
are contributing modules</li><li>Each contribution has a unique id and a <a
shape="rect" class="external-link"
href="http://tapestry.apache.org/5.4/apidocs/org/apache/tapestry5/services/javascript/StackExtension.html">StackExtension</a>
value</li></ul><p>The core stack includes several libraries and modules; the
exact configuration is subject to a number of factors (such as whether
Prototype or jQuery is being used as the underlying framework). That being
said, this is the <em>current</em> list of modules aggregated into the cor
e
stack:</p><ul><li>jquery</li><li>underscore</li><li>t5/core/<ul><li>alert</li><li>ajax</li><li>bootstrap</li><li>console</li><li>dom</li><li>events</li><li>exception-frame</li><li>fields</li><li>pageinit</li><li>messages</li><li>util</li><li>validation</li></ul></li></ul><p>The
optimum configuration is always a balancing act between including too little
and including too much. Generally speaking, including too much is less costly
than including too little. It is up to you to analyze the requests coming into
your application and determine what modules should be aggregated.</p></div>
</div>
<div class="clearer"></div>
Modified: websites/production/tapestry/content/user-guide.html
==============================================================================
--- websites/production/tapestry/content/user-guide.html (original)
+++ websites/production/tapestry/content/user-guide.html Mon Jun 23 17:19:39
2014
@@ -61,7 +61,7 @@
</div>
<div id="content">
-<div id="ConfluenceContent"><p>This <strong>User Guide</strong> serves as the
encyclopedia for Tapestry concepts, capabilities and practices.</p><div
class="sectionColumnWrapper"><div class="sectionMacro"><div
class="sectionMacroRow"><div class="columnMacro"
style="width:30%;min-width:30%;max-width:30%;"><h2
id="UserGuide-TapestryBasics">Tapestry Basics</h2><p>Going beyond <a
shape="rect" href="getting-started.html">Getting Started</a> and the <a
shape="rect" href="tapestry-tutorial.html">Tutorial</a>, these topics will dive
into basic Tapestry capabilities that you'll want to understand
first.</p><ul><li><a shape="rect" href="project-layout.html">Project
Layout</a></li><li><a shape="rect"
href="configuration.html">Configuration</a></li><li><a shape="rect"
href="class-reloading.html">Class Reloading</a></li><li><a shape="rect"
href="component-reference.html">Component Reference</a></li><li><a shape="rect"
href="annotations.html">Annotations</a></li></ul><h3 id="UserGuide-PagesandCom
ponents">Pages and Components</h3><ul><li><a shape="rect"
href="component-classes.html">Component Classes</a></li><li><a shape="rect"
href="component-templates.html">Component Templates</a></li><li><a shape="rect"
href="property-expressions.html">Property Expressions</a></li><li><a
shape="rect" href="component-parameters.html">Component
Parameters</a></li><li><a shape="rect" href="type-coercion.html">Type
Coercion</a></li><li><a shape="rect" href="layout-component.html">Layout
Component</a></li><li><a shape="rect" href="component-mixins.html">Component
Mixins</a></li><li><a shape="rect" href="page-navigation.html">Page
Navigation</a></li><li><a shape="rect"
href="localization.html">Localization</a></li></ul><h3
id="UserGuide-Request/ResponseProcessing">Request/Response
Processing</h3><ul><li><a shape="rect" href="page-life-cycle.html">Page Life
Cycle</a></li><li><a shape="rect" href="request-processing.html">Request
Processing</a></li><li><a shape="rect" href="component-rendering.ht
ml">Component Rendering</a></li><li><a shape="rect"
href="component-events.html">Component Events</a></li><li><a shape="rect"
href="url-rewriting.html">URL Rewriting</a></li><li><a shape="rect"
href="dom.html">Document Object Model</a> (DOM)</li><li><a shape="rect"
href="response-compression.html">Response Compression</a></li><li><a
shape="rect" href="https.html">Securing your application with
HTTPS</a></li><li><a shape="rect" href="content-type-and-markup.html">Content
Type and Markup</a></li></ul><h3 id="UserGuide-Datapersistence">Data
persistence</h3><ul><li><a shape="rect"
href="persistent-page-data.html">Persistent Page Data</a></li><li><a
shape="rect" href="session-storage.html">Session Storage</a></li></ul><h3
id="UserGuide-Interactingwithcomponents">Interacting with
components</h3><ul><li><a shape="rect"
href="injection.html">Injection</a></li><li><a shape="rect"
href="environmental-services.html">Environmental Services</a></li></ul><h3
id="UserGuide-JavaScript,AJAX,CSS&
BinaryData">JavaScript, AJAX, CSS & Binary Data</h3><ul><li><span
style="font-size: 14.0px;line-height: 1.4285715;"><a shape="rect"
href="javascript.html">Client-Side JavaScript</a></span></li><li><span
style="font-size: 14.0px;line-height: 1.4285715;"><a shape="rect"
href="javascript-modules.html">JavaScript Modules</a></span></li><li><span
style="font-size: 14.0px;line-height:
1.4285715;">CoffeeScript</span></li><li><a shape="rect"
href="ajax-and-zones.html">Ajax and Zones</a></li><li><a shape="rect"
href="css.html">Cascading Style Sheets</a> (CSS)</li><li><a shape="rect"
href="assets.html">Assets</a></li><li><a shape="rect"
href="legacy-javascript.html">Legacy JavaScript</a> (prior to Tapestry
5.4)</li></ul><h3 id="UserGuide-Workingwithforms">Working with
forms</h3><ul><li><a shape="rect" href="forms-and-validation.html">Forms and
Validation</a></li><li><a shape="rect"
href="beaneditform-guide.html">BeanEditForm Guide</a></li><li><a shape="rect"
href="uploading-files.html">Up
loading files</a></li></ul><h3
id="UserGuide-Debugging,Testing&Tooling">Debugging, Testing &
Tooling</h3><ul><li><a shape="rect" href="logging.html">Logging &
Debugging</a></li><li><a shape="rect"
href="unit-testing-pages-or-components.html">Unit testing pages or
components</a></li><li><a shape="rect"
href="integration-testing.html">Integration testing with
Selenium</a></li><li><a shape="rect" href="service-status.html">Service
Status</a></li></ul></div><div class="columnMacro"
style="width:30%;min-width:30%;max-width:30%;"><h2
id="UserGuide-TapestryIOC">Tapestry IOC</h2><p>As with Tapestry 5 in general,
the goal of Tapestry Inversion of Control (IoC) is greater simplicity and
power--without XML. You'll want to explore Tapestry IoC to make full use of the
extensibility of the framework.</p><h3
id="UserGuide-Architecture">Architecture</h3><ul><li><a shape="rect"
href="ioc.html">Introduction</a></li><li><a shape="rect"
href="tapestry-ioc-overview.html">Overview</a></li><li
><a shape="rect" href="tapestry-ioc-modules.html">Modules</a></li></ul><h3
>id="UserGuide-Features">Features</h3><ul><li><a shape="rect"
>href="defining-tapestry-ioc-services.html">Services</a></li><li><a
>shape="rect" href="service-advisors.html">Advisors</a></li><li><a
>shape="rect" href="tapestry-ioc-decorators.html">Decorators</a></li></ul><h3
>id="UserGuide-Configuration">Configuration</h3><ul><li><a shape="rect"
>href="tapestry-ioc-configuration.html">Configuration</a></li><li><a
>shape="rect" href="case-insensitivity.html">Case Insensitivity</a></li><li><a
>shape="rect" href="autoloading-modules.html">Module
>Autoloading</a></li><li><a shape="rect"
>href="service-implementation-reloading.html">Service Implementation
>Reloading</a></li><li><a shape="rect"
>href="ordering-by-constraints.html">Ordering by Constraints</a></li><li><a
>shape="rect" href="symbols.html">Symbols</a></li></ul><h3
>id="UserGuide-ServiceBuilders">Service Builders</h3><p>Tapestry provides a
>set of ready-to-use service
builders for common design patterns:</p><ul><li><a shape="rect"
href="chainbuilder-service.html">Chain of Command</a> (the ChainBuilder
service)</li><li><a shape="rect"
href="pipelinebuilder-service.html">Pipeline</a> (the PipelineBuilder
service)</li><li><a shape="rect" href="shadowbuilder-service.html">Shadow
Properties</a> (the PropertyShadowBuilder service)</li><li><a shape="rect"
href="strategybuilder-service.html">Strategy</a> (the StrategyBuilder
service)</li></ul><h3 id="UserGuide-Usage">Usage</h3><ul><li><a shape="rect"
href="injection-in-detail.html">Injection in detail</a></li><li><a shape="rect"
href="object-providers.html">Object providers</a></li><li><a shape="rect"
href="service-serialization.html">Service Serialization</a></li></ul><h3
id="UserGuide-Built-inservices">Built-in services</h3><ul><li><a shape="rect"
href="typecoercer-service.html">Type Coercer</a></li></ul><h3
id="UserGuide-Registrystartup&shutdown">Registry startup &
shutdown</h3><ul><li><a shap
e="rect" href="starting-the-ioc-registry.html">Starting and stopping the
registry</a></li><li><a shape="rect" href="registry-startup.html">Listening for
registry startup</a></li></ul><h3 id="UserGuide-Tooling">Tooling</h3><ul><li><a
shape="rect" href="parallel-execution.html">Parallel Execution</a></li><li><a
shape="rect" href="logging-in-tapestry.html">Logging</a></li></ul></div><div
class="columnMacro" style="width:30%;min-width:30%;max-width:30%;"><h2
id="UserGuide-Built-inmodules">Built-in modules</h2>Tapestry comes with a
collection of add-on modules to let you extend the framework beyond its core.
+<div id="ConfluenceContent"><p>This <strong>User Guide</strong> serves as the
encyclopedia for Tapestry concepts, capabilities and practices.</p><div
class="sectionColumnWrapper"><div class="sectionMacro"><div
class="sectionMacroRow"><div class="columnMacro"
style="width:30%;min-width:30%;max-width:30%;"><h2
id="UserGuide-TapestryBasics">Tapestry Basics</h2><p>Going beyond <a
shape="rect" href="getting-started.html">Getting Started</a> and the <a
shape="rect" href="tapestry-tutorial.html">Tutorial</a>, these topics will dive
into basic Tapestry capabilities that you'll want to understand
first.</p><ul><li><a shape="rect" href="project-layout.html">Project
Layout</a></li><li><a shape="rect"
href="configuration.html">Configuration</a></li><li><a shape="rect"
href="class-reloading.html">Class Reloading</a></li><li><a shape="rect"
href="component-reference.html">Component Reference</a></li><li><a shape="rect"
href="annotations.html">Annotations</a></li></ul><h3 id="UserGuide-PagesandCom
ponents">Pages and Components</h3><ul><li><a shape="rect"
href="component-classes.html">Component Classes</a></li><li><a shape="rect"
href="component-templates.html">Component Templates</a></li><li><a shape="rect"
href="property-expressions.html">Property Expressions</a></li><li><a
shape="rect" href="component-parameters.html">Component
Parameters</a></li><li><a shape="rect" href="type-coercion.html">Type
Coercion</a></li><li><a shape="rect" href="layout-component.html">Layout
Component</a></li><li><a shape="rect" href="component-mixins.html">Component
Mixins</a></li><li><a shape="rect" href="page-navigation.html">Page
Navigation</a></li><li><a shape="rect"
href="localization.html">Localization</a></li></ul><h3
id="UserGuide-Request/ResponseProcessing">Request/Response
Processing</h3><ul><li><a shape="rect" href="page-life-cycle.html">Page Life
Cycle</a></li><li><a shape="rect" href="request-processing.html">Request
Processing</a></li><li><a shape="rect" href="component-rendering.ht
ml">Component Rendering</a></li><li><a shape="rect"
href="component-events.html">Component Events</a></li><li><a shape="rect"
href="url-rewriting.html">URL Rewriting</a></li><li><a shape="rect"
href="dom.html">Document Object Model</a> (DOM)</li><li><a shape="rect"
href="response-compression.html">Response Compression</a></li><li><a
shape="rect" href="https.html">Securing your application with
HTTPS</a></li><li><a shape="rect" href="content-type-and-markup.html">Content
Type and Markup</a></li></ul><h3 id="UserGuide-Datapersistence">Data
persistence</h3><ul><li><a shape="rect"
href="persistent-page-data.html">Persistent Page Data</a></li><li><a
shape="rect" href="session-storage.html">Session Storage</a></li></ul><h3
id="UserGuide-Interactingwithcomponents">Interacting with
components</h3><ul><li><a shape="rect"
href="injection.html">Injection</a></li><li><a shape="rect"
href="environmental-services.html">Environmental Services</a></li></ul><h3
id="UserGuide-JavaScript,AJAX,CSS&
BinaryData">JavaScript, AJAX, CSS & Binary Data</h3><ul><li><span
style="font-size: 14.0px;line-height: 1.4285715;"><a shape="rect"
href="client-side-javascript.html">Client-Side
JavaScript</a></span></li><li><span style="font-size: 14.0px;line-height:
1.4285715;"><a shape="rect" href="javascript-modules.html">JavaScript
Modules</a></span></li><li><span style="font-size: 14.0px;line-height:
1.4285715;"><a shape="rect" class="unresolved"
href="#">CoffeeScript</a></span></li><li><a shape="rect"
href="ajax-and-zones.html">Ajax and Zones</a></li><li><a shape="rect"
href="css.html">Cascading Style Sheets</a> (CSS)</li><li><a shape="rect"
href="assets.html">Assets</a></li><li><a shape="rect"
href="legacy-javascript.html">Legacy JavaScript</a> (prior to Tapestry
5.4)</li></ul><h3 id="UserGuide-Workingwithforms">Working with
forms</h3><ul><li><a shape="rect" href="forms-and-validation.html">Forms and
Validation</a></li><li><a shape="rect"
href="beaneditform-guide.html">BeanEditForm Guid
e</a></li><li><a shape="rect" href="uploading-files.html">Uploading
files</a></li></ul><h3 id="UserGuide-Debugging,Testing&Tooling">Debugging,
Testing & Tooling</h3><ul><li><a shape="rect" href="logging.html">Logging
& Debugging</a></li><li><a shape="rect"
href="unit-testing-pages-or-components.html">Unit testing pages or
components</a></li><li><a shape="rect"
href="integration-testing.html">Integration testing with
Selenium</a></li><li><a shape="rect" href="service-status.html">Service
Status</a></li></ul></div><div class="columnMacro"
style="width:30%;min-width:30%;max-width:30%;"><h2
id="UserGuide-TapestryIOC">Tapestry IOC</h2><p>As with Tapestry 5 in general,
the goal of Tapestry Inversion of Control (IoC) is greater simplicity and
power--without XML. You'll want to explore Tapestry IoC to make full use of the
extensibility of the framework.</p><h3
id="UserGuide-Architecture">Architecture</h3><ul><li><a shape="rect"
href="ioc.html">Introduction</a></li><li><a shape="
rect" href="tapestry-ioc-overview.html">Overview</a></li><li><a shape="rect"
href="tapestry-ioc-modules.html">Modules</a></li></ul><h3
id="UserGuide-Features">Features</h3><ul><li><a shape="rect"
href="defining-tapestry-ioc-services.html">Services</a></li><li><a shape="rect"
href="service-advisors.html">Advisors</a></li><li><a shape="rect"
href="tapestry-ioc-decorators.html">Decorators</a></li></ul><h3
id="UserGuide-Configuration">Configuration</h3><ul><li><a shape="rect"
href="tapestry-ioc-configuration.html">Configuration</a></li><li><a
shape="rect" href="case-insensitivity.html">Case Insensitivity</a></li><li><a
shape="rect" href="autoloading-modules.html">Module Autoloading</a></li><li><a
shape="rect" href="service-implementation-reloading.html">Service
Implementation Reloading</a></li><li><a shape="rect"
href="ordering-by-constraints.html">Ordering by Constraints</a></li><li><a
shape="rect" href="symbols.html">Symbols</a></li></ul><h3
id="UserGuide-ServiceBuilders">Service Buil
ders</h3><p>Tapestry provides a set of ready-to-use service builders for
common design patterns:</p><ul><li><a shape="rect"
href="chainbuilder-service.html">Chain of Command</a> (the ChainBuilder
service)</li><li><a shape="rect"
href="pipelinebuilder-service.html">Pipeline</a> (the PipelineBuilder
service)</li><li><a shape="rect" href="shadowbuilder-service.html">Shadow
Properties</a> (the PropertyShadowBuilder service)</li><li><a shape="rect"
href="strategybuilder-service.html">Strategy</a> (the StrategyBuilder
service)</li></ul><h3 id="UserGuide-Usage">Usage</h3><ul><li><a shape="rect"
href="injection-in-detail.html">Injection in detail</a></li><li><a shape="rect"
href="object-providers.html">Object providers</a></li><li><a shape="rect"
href="service-serialization.html">Service Serialization</a></li></ul><h3
id="UserGuide-Built-inservices">Built-in services</h3><ul><li><a shape="rect"
href="typecoercer-service.html">Type Coercer</a></li></ul><h3
id="UserGuide-Registrystartup&s
hutdown">Registry startup & shutdown</h3><ul><li><a shape="rect"
href="starting-the-ioc-registry.html">Starting and stopping the
registry</a></li><li><a shape="rect" href="registry-startup.html">Listening for
registry startup</a></li></ul><h3 id="UserGuide-Tooling">Tooling</h3><ul><li><a
shape="rect" href="parallel-execution.html">Parallel Execution</a></li><li><a
shape="rect" href="logging-in-tapestry.html">Logging</a></li></ul></div><div
class="columnMacro" style="width:30%;min-width:30%;max-width:30%;"><h2
id="UserGuide-Built-inmodules">Built-in modules</h2>Tapestry comes with a
collection of add-on modules to let you extend the framework beyond its core.
<h3 id="UserGuide-HibernateIntegration">Hibernate Integration</h3>