Table of Contents
Building cutting edge Web applications is not entirely about the server side. A significant amount of work must be done on the client side to support truly dynamic user experiences. Typically, this scripting is done using the JavaScript language embedded into major web browsers such as Internet Explorer and Netscape Navigator.
These effects range from simple effects such as image rollovers (changing the icon used for a link whent he cursor is over it) to more involved patterns such as client side validation of forms or even complex animations.
In traditional, static web page development, the author is completely responsible for this aspect of development, usually aided by a web page authoring tool, such as Dreamweaver. Ultimately, though, the web page developer assigns unique names or ids to various elements on the page, and attaches JavaScript event handlers to the elements.
Example 12.1. Traditional JavaScript usage
var preload = new Array(); preload[0] = new Image(); preload[0].src = "/images/button.gif"; preload[1] = new Image(); preload[1].src "/images/button-highlight.gif"; function rollover(image, index) { image.src = preload[index].src; } . . . <a href="..." onMouseOver="javascript:rollover(document.button, 1);" onMouseOut="javascript:rollover(document.button, 0);"> <img name="button" src="/images/button.gif"> </a> |
The preloading business is all about forcing the browser to load the image before it is needed, so that it is already in memory when the mouseover event handler needs it.
From here, adding additional rollovers means extending the preload array, providing names for the additional <img> elements and writing the additional event handlers for the <a> elements.
Now, envision a running Tapestry application. With everything so dynamic (especially when you account for things like the Foreach component), it's all but impossible to even know how many links and buttons will be on the page, never mind what they'll all be named. At first glance, it may appear that Tapestry prevents the use of this kind of scripting.
In fact, Tapestry is structured to enhance this kind of scripting. This is faciliated by the Body component, which replaces the <body> element of the page. Virtually all of a page's content will be wrapped by the Body component, including everything that has need for dynamic scripting.
The Body component provides a number of services to the components it wraps. It handles preloading of images. It provides the ability to add arbitrary JavaScript to the page, to include an external static JavaScript document, or to the <body> element's onload event handler. Finally, it provides an easy way to generate unique identifiers needed for things like image names.
When the Body component renders, it registers itself as an attribute of the IRequestCycle. This allows components wrapped by the Body component, directly or indirectly, to locate it and invoke methods on it. These methods are used to define preloaded images, and add JavaScript code to the response HTML.
When rendering is complete, the Body component will have produced four distinct portions of the HTML response:
<script language="JavaScript" src="..."></script> |
![]() | Any number of included static scripts may be added to the page. |
![]() | This script block is only emitted when necessary; that is, because some component needed to generate scripting or initialization (or preloaded images). The block is properly "commented" so that older browsers, those that fail to support scripting, will not be confused by the JavaScript code. |
![]() | The onload event handler function is only generated if some component requests some onload initialization. |
![]() | The <body> tag only specfies a onload event handler function if one is needed. |
![]() | The content of the <body> element is defined by the Tapestry components it wraps. Importantly, the rollovers, JavaScript, event handlers and the content are all generated in parallel (the Body component uses buffering so that the JavaScript portion is written out first). |