tapestry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > JavaScript Rewrite
Date Wed, 06 Jun 2012 00:17:00 GMT
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/12/_/styles/combined.css?spaceKey=TAPESTRY&amp;forWysiwyg=true"
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/TAPESTRY/JavaScript+Rewrite">JavaScript
    <h4>Page  <b>added</b> by             <a href="https://cwiki.apache.org/confluence/display/~hlship">Howard
M. Lewis Ship</a>
    <div class="notificationGreySide">
         <h1><a name="JavaScriptRewrite-TapestryandJavaScript"></a>Tapestry
and JavaScript</h1>

<p>Tapestry 5 has had a interesting mix of characteristics.</p>

<p>On the one hand, it has had a large number of features that work, and work well,
right out of the box, with no special configuration or setup. This includes client-side validation,
dynamic content updates, simple animations, progressive enhancement, and other standard Ajax
and DHTML use cases.</p>

<p>In addition, Tapestry has evolved, from Tapestry 5.0 through 5.3, into a quite capable
<em>provisioning</em> framework:</p>

	<li>JavaScript libraries may be combined into <em>stacks</em> that are
combined (in production) into a single virtual file</li>
	<li>JavaScript libraries and CSS files may be minified</li>
	<li>Libraries, stacks, and other resources are exposed to the browser with a versioned
URL and far-future expires header, to support aggressive client-caching</li>
	<li>Resources, including JavaScript and CSS, can be distributed inside JARs (as part
of reusable component libraries)</li>
	<li>Compressible resources will be automatically GZip compressed if the client supports

<h1><a name="JavaScriptRewrite-TapestryJavaScriptLimitations%28through5.3%29"></a>Tapestry
JavaScript Limitations (through 5.3)</h1>

<h2><a name="JavaScriptRewrite-DependenceonPrototype%2FScriptaculous"></a>Dependence
on Prototype/Scriptaculous</h2>

<p>Tapestry made an early choice to embrace Prototype and Scriptaculous at a time when
this made sense, circa 2006-2007.</p>

<p>The goal was to have Tapestry provide a client-side API, the <tt>Tapestry</tt>
namespace, that in turn would delegate complex behaviors (including DOM element selection,
event management, and XmlHttpRequest processing) to a <em>foundational framework</em>.
The goal was to isolate all the direct dependencies on Prototype in such a way that it would
be possible, in the future, to swap out for a different foundational framework, such as jQuery
or ExtJS. Unfortunately, expediency has proven to make this goal even less reachable!</p>

<h2><a name="JavaScriptRewrite-LackofDocumentation"></a>Lack of Documentation</h2>

<p>There has not, to date, been an adequate documentation of the <tt>Tapestry</tt>
namespaces, beyond the code itself.</p>

<h2><a name="JavaScriptRewrite-LackofModuleStructure"></a>Lack of Module

<p>Beyond the basic use of namespaces, Tapestry has not embraced modern JavaScript usage;
specifically, it makes limited use of <em>hygenic functions</em> to form modules.
 Hygenic functions are JavaScript functions that exist as a way to encapsulate private properties
and functions.  Tapestry 5.3 makes more use of this pattern than previous releases.</p>

<h2><a name="JavaScriptRewrite-ComplexInitialization"></a>Complex Initialization</h2>

<p>Many users are perplexed by how Tapestry performs initialization: in a typical application,
the developer will create a <tt>&lt;script&gt;</tt> block at the bottom
of the page, and do initializations there. In Tapestry, it can be much more complex:</p>

	<li>A JavaScript library, containing one or more <em>initialization functions</em>,
is created</li>
	<li>The initialization functions must be <em>monkey patched</em> into the
<tt>Tapestry.Initializers</tt> namespace</li>
	<li>The JavaScriptSupport environmental must be used to invoke the function, by name,
passing it a JSONObject to configure itself (the "specification")</li>

<p>This often feels like overkill. It is necessary for a number of desirable characteristics:</p>

	<li>Initialization code occurs in a single <tt>&lt;script&gt;</tt>
block at the end of the page (just before the <tt>&lt;/body&gt;</tt> tag)</li>
	<li>There is limited support for structuring the order of initialization</li>
	<li>The mechanism works transparently in both full-page render (traditional) and partial-page
renders (Ajax)</li>

<p>Despite this, the Tapestry approach can feel very "heavy".  In a bespoke<style
.FootnoteMarker, .FootnoteNum a {
  background: transparent url(/confluence/download/resources/com.adaptavist.confluence.footnoteMacros:footnote/gfx/footnote.png)
no-repeat top right;
  padding: 1px 2px 0px 1px;
  border-left: 1px solid #8898B8;
  border-bottom: 1px solid #6B7C9B;
  margin: 1px;
  text-decoration: none;
.FootnoteNum a {
  margin-top: 2px;
  margin-right: 0px;
.FootnoteNum {
  font-size: x-small;
  text-align: right;
  padding-bottom: 4px;
.footnote-th1 {
  text-align: right;
.Footnote {
  padding-left: 7px;
  margin-bottom: 4px;
  border: 1px none #DDDDDD;
  writingMode: tb-rl;
.accessibility {
     display: none;
     visibility: hidden;
@media aural,braille,embossed {
        .FootnoteMarker, .FootnoteNum a {
         border: 1px solid #000000;
         background: #ffffff none;
    .accessibility {
         display: run-in;
         visibility: visible;
<script type='text/javascript' language='JavaScript'>
var effectInProgress = {};
var despamEffect = function (id,effectType,duration) {
  if ((effectInProgress[id]) || (typeof(Effect)=="undefined") || (typeof(Effect[effectType])=="undefined"))
  new Effect[effectType](id);
var oldFootnoteId = '';
var footnoteHighlight = function(id,pulsateNum) {
  if (oldFootnoteId!='') document.getElementById('Footnote'+oldFootnoteId).style['borderStyle']
= 'none';
  oldFootnoteId = id;
  document.getElementById('Footnote'+id).style['borderStyle'] = 'solid';
  if (pulsateNum) despamEffect('FootnoteNum'+id,'Pulsate',3)
var footnoteMarkerHighlight = function(id) {
  if (oldFootnoteId!='') document.getElementById('Footnote'+oldFootnoteId).style['borderStyle']
= 'none';
  oldFootnoteId = '';

<sup id='FootnoteMarker1'>
    <a name='FootnoteMarker1'
        alt='Footnote: Click here to display the footnote'
        title='Footnote: Click here to display the footnote'
 page, initialization takes the form of a single event handler, often attached to the <tt>&lt;body&gt;</tt>
element, that caches events that bubble up from much lower in the DOM.  The single handler
function identifies the applicable elements using CSS selectors, including those that are
based on HTML5 data- attributes.  Additional data- attributes will define additional behavior
... for example, a URL for a triggered request.  This is "light" because:</p>

	<li>There's a single event handler function</li>
	<li>The event handler may be anonymous (there's no name, or possibility of collision)</li>
	<li>Elements are identified by DOM structure and CSS rather than their unique id</li>
	<li>Additional additional necessary configuration is directly attached to the element</li>
	<li>As the page is dynamically updated, there is no extra "bookkeeping" for added or
removed elements; new elements inserted into the DOM dynamically are recognized as easily
as those that were present on the initial render</li>

<p>By contrast, Tapestry is heavy:</p>

	<li>The initialization must have a unique name</li>
	<li>The element must have a unique id</li>
	<li>The event handlers are attached directly to the element</li>
	<li>Duplicated elements will have duplicated event handlers</li>
	<li>Additional behavior is specified as a JSON object passed to the initialization
	<li>Injecting new elements into the DOM requires invoking initialization functions
to wire up the necessary event handlers</li>
	<li>On older versions of Internet Explorer, removing elements may leave memory leaks
as JavaScript objects retain references to DOM objects</li>

<h1><a name="JavaScriptRewrite-JavaScriptEvolution%285.0to5.3%29"></a>JavaScript
Evolution (5.0 to 5.3)</h1>

<h1><a name="JavaScriptRewrite-JavaScriptImprovementsfor5.4"></a>JavaScript
Improvements for 5.4</h1>

<hr />

<p><table class='Footnotes' style='width: 100%; border:none;' cellspacing='0' cellpadding='0'
summary='This table contains one or more notes for references made elsewhere on the page.'>
  <caption class='accessibility'>Footnotes</caption>
  <thead class='accessibility'>
    <tr class='accessibility'>
      <th class='accessibility' id='footnote-th1'>Reference</th>
      <th class='accessibility' id='footnote-th2'>Notes</th>
    <tr name='Footnote1'>
      <td valign='top' class='FootnoteNum' headings='footnote-th1'>
        <a href='#FootnoteMarker1'
          alt='Footnote: Click to return to reference in text'
          title='Footnote: Click to return to reference in text'
      <td id='Footnote1'
          By "bespoke", we mean a non-component-based, manually created page; a standalone
static HTML page.
    <div id="commentsSection" class="wiki-content pageSection">
       <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
       <a href="https://cwiki.apache.org/confluence/display/TAPESTRY/JavaScript+Rewrite">View

View raw message