Warning | ||
---|---|---|
| ||
This page describes JavaScript usage in Tapestry versions up through 5.3.x. For version 5.4 and later, see Client-Side JavaScript. |
JavaScript is a first-class concept in Tapestry, and sophisticated JavaScript support is provided right out of the box, including rich
...
Ajax and Zones, download optimization, client-side logging, and localization.
Div | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
|
In production mode, by default, Tapestry will merge JavaScript libraries, add version numbering, and set a far-future expires header to encourage aggressive browser caching. Starting with version 5.3, Tapestry can also automatically minify (compress) JavaScript libraries when in production mode.
...
Tapestry provides several ways to add a link to a JavaScript library within your page or component. Although you can use direct <script type="text/javascript" src="xxx.js"></script>
approach, you should only use it for JavaScript that resides outside of your application. For JavaScript within your app, Tapestry provides much better ways to do the same thing. Most users choose the simplest, the @Import annotation approach.{
Div | ||
---|---|---|
|
...
| |||||||||
|
Approach 1: @Import
Use the @Import annotation (or @IncludeJavaScriptLibrary in Tapestry 5.0 and 5.1) to include links to JavaScript (and CSS) files in your page or component. Tapestry ensures that each such file is only referenced once in your page.
Section | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
...
|
...
|
@Import may also be applied to individual methods, in which case the import operation only occurs when the method is invoked.
Note: When specifying a file to import, you'll often use the context: binding prefix to indicate that the file is stored in the web application context, and not on the classpath. Relative paths will be on the classpath, relative to the Java class. See See Component Parameters for other binding prefix options.
...
Alternatively, you can use JavaScriptSupport (for Tapestry 5.2 or later) or RenderSupport (for Tapestry 5.0 and 5.1) to include a JavaScript library in your page or component. JavaScriptSupport and RenderSupport are environmental services that include a number of methods that will be used by components, or by services that are called from components. For example:
...
The importJavaScriptLibrary
method (or addScriptLink
for Tapestry 5.0 and 5.1) adds a link to a JavaScript library. A component can inject such a script and pass one or more of assets to this method:
Section | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Tapestry will ensure that the necessary <link> elements are added to the top of the document (in the <head> element). With Tapestry 5.3 and later the new elements are inserted at the bottom of the <head> element; in versions before 5.3 they appear at the top of the <head> element).
...
The setupRender
method (the name is specifically linked to a render phase) is the correct place to inform the JavaScriptSupport (or RenderSupport) service that the library is needed.{
Div | ||
---|---|---|
|
...
| |||||||||
|
The addScript
method
The addScript
method is used when you need to add some JavaScript code directly to the page. This will be inserted at the bottom of the document, and will only be executed when the document has finished loading on the client (i.e., from the window.onload event handler).
Section | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
When calling the method, the format string can include standard substitutions (such as '%s') for arguments. This saves you the trouble of calling String.format() yourself. (For Tapestry 5.1 and earlier, you must call String.format() yourself.) In any case, the formatted JavaScript is added to the script block in the rendered output.
...
JavaScriptSupport (like RenderSupport before it) is an environmental object, so you will normally inject it via the @Environmental annotation:
Section | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
The @Environmental annotation only works inside components, but occasionally you may want to inject JavaScriptSupport (or RenderSupport) into a service. Fortunately, a proxy has been set up to allow the use of @Inject instead:
Section | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
...
|
...
|
... or, in a service implementation constructor:
Section | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Inside a component, you should use @Environmental, to highlight the fact that RenderSupport (like most environmental objects) is only available during rendering, not during action requests.
...
This is a very useful feature, as it reduces the number of requests needed to present a page to the user. It can be disabled, however, by setting the SymbolConstants.COMBINE_SCRIPTS configuration symbol to false in your application's module class (normally AppModule.java). By default it is enabled when in production mode and disabled otherwise.
...
IMPORTANT NOTE: The tapestry-core module only provides the empty infrastructure for supporting minification; the actual logic is supplied in the tapestry-yuicompressor module. To use it, you'll need to update your dependencies to include this module.
Code Block | ||||
---|---|---|---|---|
| ||||
<dependency> <groupId>org.apache.tapestry</groupId> <artifactId>tapestry-yuicompressor</artifactId> <version>${tapestry-release-version}</version> </dependency> |
Gradle would be similar, of course. If you aren't using something like Maven or Gradle, you'll have to download the jar and its dependency (com.yahoo.platform.yui: yuicompressor) yourself.
Minification can be disabled by setting the SymbolConstants.MINIFICATION_ENABLED the tapestry.enable-minification configuration symbol to false in your application's module class (usually AppModule.java). By default it is enabled when in production mode and disabled otherwise.
...
In versions prior to 5.3, Tapestry uses used a modified version of the Blackbird JavaScript console. The Tapestry object includes three functions: debug, warn and error.
Each of these functions take a message and an optional pattern; if the pattern is provided, the message is interpolated on the pattern. The final message is displayed in the Blackbird console, which will make itself visible automatically.
In production mode, debug messages will be filtered out (they will not be visible until the user presses F2 to display the console, and then clicks the grayed out icon for debug messages). In development mode, debug messages are not filtered out.
Example usage:
Code Block | ||
---|---|---|
| ||
Tapestry.debug("Field id is #{id}, value is #{value}", field); Tapestry.error("Server is not available."); |
With Tapestry 5.3 and later the Blackbird console has been removed; just use the standard console logging features (e.g. console.log()
) built into modern browsers.
...
The client-side function Tapestry.waitForPage()
can be used in an element's onclick handler to force a wait for the page to fully load. In this race condition, the screen will dim and a message will appear advising the user to wait a moment; once the page is fully loaded, this modal dialog will be removed.
The correct usage is:
Code Block | ||
---|---|---|
| ||
<a href="..." onclick="javascript:Tapestry.waitForPage(event);"> ... </a> |
The constant MarkupConstants.WAIT_FOR_PAGE contains the part of this snippet inside the quotes.
...
For example, you might store a value for an element in one place:
Code Block | ||
---|---|---|
| ||
$T(myid).fadeDuration = .5; |
Then use it somewhere else:
Code Block | ||
---|---|---|
| ||
new Effect.Fade($(myId), { duration: $T(myid).fadeDuration }); |
Ajax Components and Mixins
Tapestry provides easy-to-use support for Ajax, the technique of using JavaScript to dynamically updating parts of a web page with content from the server without redrawing the whole page.
...
See Ajax and Zones for details.
Built-in Libraries
Div | |
---|---|
|
...
|
...
|
...
| |||||||||
|
Tapestry 5.4 and earlier come with the Prototype and Scriptaculous libraries ... no extra download is required. Tapestry will automatically link into your pages the prototype.js, scriptaculous.js, and effects.js libraries, as well as the Tapestry library, tapestry.js (which largely consists of support for form input validation). Starting with Tapestry 5.3, Underscore is also included.
Prototype and Scriptaculous Versions
Tapestry included only Prototype and Scriptaculous in versions prior to Tapestry 5.4. See Supported Environments and Versions for a matrix of prototype and scriptaculous versions supported by Tapestry.
In versions before 5.4, Tapestry used
...
Prototype and Scriptaculous Versions
Tapestry 5.3.5 | Prototype 1.7.1 | Scriptaculous 1.9 | Underscore 1.1.7 |
---|---|---|---|
Tapestry 5.3+ | Prototype 1.7 | Scriptaculous 1.9 | Underscore 1.1.7 |
Tapestry 5.2.6 | Prototype 1.7 | Scriptaculous 1.9 | |
Tapestry 5.2 | Prototype 1.6.1 | Scriptaculous 1.8.2 | |
Tapestry 5.1 | Prototype 1.6.0.3 | Scriptaculous 1.8.2 | |
Tapestry 5.0 | Prototype 1.6.0 | Scriptaculous 1.8.0 |
Tapestry uses a modified version of the main Scriptaculous library, scriptaculous.js, with the library's default autoloading behavior turned off. This lets Tapestry and Tapestry components control which Scriptaculus scripts are loaded, rather than having all of them loaded unnecessarily.
If you need access to other Scriptaculous libraries, you can provide them as follows:
Code Block | ||
---|---|---|
| ||
@Inject @Path("${tapestry.scriptaculous}/dragdrop.js") private Asset dragDropLibrary; @Environmental private JavaScriptSupport javaScriptSupport; void setupRender() { javaScriptSupport.addScriptLink(dragDropLibrary); } |
The Asset is injected, using the ${tapestry.scriptaculous} configuration symbol to reference the location of the Scriptaculous library.
...
- getInitialization : this method makes it possible to call a JavaScript initialization for the stack. Tapestry will automatically add this initialization to the page that imports the stacks.
Code Block | ||||
---|---|---|---|---|
| ||||
public class myStack implements JavaScriptStack { private final AssetSource assetSource; public myStack (final AssetSource assetSource) { this.assetSource = assetSource; } public String getInitialization() { return null; } public List<Asset> getJavaScriptLibraries( |
...
) { List<Asset> ret = new ArrayList<Asset>(); ret.add(assetSource.getContextAsset("static/js/jquery.js", null)); ret.add(assetSource.getContextAsset("static/js/jquery.ui.core.js", null)); return ret; } public List<StylesheetLink> getStylesheets() { List<StylesheetLink> ret = new ArrayList<StylesheetLink>(); ret.add(new StylesheetLink(assetSource.getContextAsset("static/css/style.css", null))); return ret; } public List<String> getStacks() { return Collections.emptyList(); } } |
When your new Stack is created, you have to define it in your AppModule.
Code Block | ||||
---|---|---|---|---|
| ||||
@Contribute(JavaScriptStackSource.class) public static void addMyStack (MappedConfiguration<String, JavaScriptStack> configuration) { configuration.addInstance("MyNewStack", myStack.class); } |
You can now use it in your pages and components, by using the @Import annotation or the JavaScriptSupport service :
Section | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|