Improve JavaScript handling to prevent the user from clicking Ajax-oriented 
links and forms befor the page is "ready"
---------------------------------------------------------------------------------------------------------------------

                 Key: TAP5-544
                 URL: https://issues.apache.org/jira/browse/TAP5-544
             Project: Tapestry 5
          Issue Type: Improvement
          Components: tapestry-core
    Affects Versions: 5.1.0.1
            Reporter: Howard M. Lewis Ship


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.

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.  

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to