tapestry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Howard M. Lewis Ship (JIRA)" <j...@apache.org>
Subject [jira] Updated: (TAP5-544) Improve JavaScript handling to prevent the user from clicking Ajax-oriented links and forms befor the page is "ready"
Date Sat, 28 Feb 2009 00:13:12 GMT

     [ https://issues.apache.org/jira/browse/TAP5-544?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Howard M. Lewis Ship updated TAP5-544:
--------------------------------------

    Description: 
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.  

  was:
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.  


> 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.  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.  

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


Mime
View raw message