I think it's well time to open a discussion about Tapestry 5 and
JavaScript. I think Tapestry is getting a large number of things
right, but also a small number of things wrong. This is not a
discussion about jQuery vs. Prototype (that's a separate area), but
more about the behavior of Tapestry JavaScript, within the constrains
of the browser.

In standard usage, the JavaScript for a page is collected together and
moved to the bottom of the page: first a series of <script> tags to
load JavaScript libraries, then a single block of code to perform all
kinds of initialization; this block executes, ultimately, when the
page is fully loaded: after all HTML and JavaScript (but, depending on
the browser, before all images have fully loaded).

This is good and bad; the good part is that we are following Yahoo's
performance guidelines: JavaScript at the bottom of the page, so it
doesn't slow down rendering of the markup.  However, this means that
common practices, such as using the "javascript:" psuedo-scheme (i.e.
<a src="javascript:...">) are not possible, since the referenced
JavaScript would not have been loaded yet.  In fact, many users must
configure Tapestry to move the scripts back up to the top of the page
(inside the <head>) to meet external demands (of third-party URL
trackers and advertising solutions).

Further, on a page that loads slowly (one that has a large number of
external scripts, is accsessed via a slow-bandwidth pipe, or has a
very complex layout), this means that JavaScript event handlers are
not wired up until all JavaScript has been downloaded and parsed.  The
end result it that you can "outrace" Tapestry, click a link that
should update a zone and get incorrect behavior or even a runtime
exception. I actually see this when using Formo's time-tracking
application from home through a slow pipe, exacerbated by HTTPS, where
I get the error that "Block is not a valid response type". What should
have been an Ajax request was processed instead as a traditional page
render request, because the JavaScript was not ready.

An earlier version of Tapestry 5 approached this problem by disabling
the link components when the zone parameter was in use; that is, the
href parameter was written out a "#", so the only way the link would
be active is via an attached onclick event handler.

This solution was weak, because there was no graceful degradation:
clients without JavaScript would have a non-functioning application.
Thus it was changed to render the href normally AND add an onclick
event handler, which leads to the race conditions described above.

What I really would like to see is the following:

The page renders normally.  If a user submits a form or clicks a link
before all initialization code has executed, then a popup dialog will
appear to inform the user that the page is still loading.  When the
load is complete, the message changes and the dialog fades out.

Possibly, when a page is loading a more subtle floating "Loading ..."
dialog would appear and disappear once the page is, in fact, loaded.

What would it take to accomplish this?

Firstly, JavaScript libraries would have to move (back) to the <head>,
permanently, no configuration (well, short of replacing some internal
services).  We can't have inline javascript unless the javascript
being referenced loads first. Hopefully, we'll be able to make up the
performance difference (if measurable) with the future plans to
minimize and combine JavaScript for the page.  JavaScript
initialization would still occur at the bottom.

Next, Ajax-y links and forms would have something like
onclick="javascript:Tapestry.waitForPageLoad();" written into their
HTML; this would be the logic that would raise the dialog if you
clicked a link too early.

Once the Prototype dom:loaded event is fired, and all the normal
JavaScript initialization takes place (from what I gather about IE,
it's still a good idea to wait for dom:loaded, rather than simply
putting the code at the bottom of the page), part of the process would
be to a) fade out the dialog if showing and b) remove the onclick
handler for any elements. This is tricky, because the initialization
code often adds onclick event handlers. Perhaps the handlers can stay,
but will be inactive because the page has loaded.

Anyway, this is how I think we should proceed.

I think this would keep compatibility with existing applications.

The cost would be:

- Slightly uglier HTML output (use of the "javascript:" psuedo-scheme)

- Possibly slower render of page, as the browser waits for JavaScript to load

- Increment increase in size of tapestry.js

The advantage is less confusion on the client side and server side
between normal requests and Ajax partial render requests. The user
can't "outrace" the application anymore.

I'd like to see what people think of this plan and collect any
comments or observations I've missed.



I've also added the above text as:

https://issues.apache.org/jira/browse/TAP5-544




-- 
Howard M. Lewis Ship

Creator Apache Tapestry and Apache HiveMind

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org

Reply via email to