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