...
For the most part, these templates are standard HTML/XHTML; Tapestry extensions to ordinary markup are provided in the form of a Tapestry namespace:
Code Block |
---|
language | xml |
---|
title | A template for a page | xml |
---|
|
<html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<h1>Bonjour from HelloWorld component.</h1>
</html>
|
We'll cover the specific content of templates shortly, but first a few details about connecting a component to its template.
...
The following are the most common (X)HTML doctypes:
Code Block |
---|
|
<!DOCTYPE html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
|
The first one is for HTML5 and is recommended for Tapestry 5.2.5 and later. In versions prior to Tapestry 5.2.5, Tapestry didn't support the HTML5 doctype directly (see TAP5-1040), but there's a partial work-around: just add the following to your page class (or your layout class, if you use one) instead of adding the doctype to your template (.tml) files:
Code Block |
---|
/**
* Output the HTML5 doctype, as a work-around to https://issues.apache.org/jira/browse/TAP5-1040
*/
@SetupRender
final void renderDocType(final MarkupWriter writer) {
writer.getDocument().raw("<!DOCTYPE html>");
}
|
...
Component templates should include the Tapestry namespace, defining it in the root element of the template.
Code Block |
---|
|
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<head>
<title>Hello World Page</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
|
...
The following example is a Layout component, which adds basic HTML elements around the page-specific content:
Code Block |
---|
|
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<head>
<title>My Tapestry Application</title>
</head>
<body>
<t:body/>
</body>
</html>
|
That "<t:body/>" element marks where the containing page's content will be inserted. A page would then use this component as follow:
Code Block |
---|
|
<html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
My Page Specific Content
</html>
|
When the page renders, the page's template and the Layout component's template are merged together:
Code Block |
---|
|
<html>
<head>
<title>My Tapestry Application</title>
</head>
<body>
My Page Specific Content
</body>
</html>
|
...
A <t:container> element contains markup without being considered part of the template. This is useful for components that render several top level tags, for example, a component that renders several columns within a table row:
Code Block |
---|
|
<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<td>${label}</td>
<td>${value}</td>
</t:container>
|
...
Another option when rendering output is the use of expansions. Expansions are special strings that may be embedded in template bodies, and borrow some syntax from the Ant build tool.
Code Block |
---|
|
Welcome, ${userId}!
|
Here, ${userId
} is the expansion. In this example, the userId property of the component is extracted, converted to a string, and streamed into the output.
Expansions are allowed inside text, and inside attributes of ordinary elements, and component elements. For example:
Code Block |
---|
|
<img src="${request.contextPath}/images/catalog/product_${productId}.png"/>
|
...
An embedded component is identified within the template as an element in the t: namespace. Example:
Code Block |
---|
|
You have ${cartItems.size()} items in your cart.
<t:actionlink t:id="clear">Remove All</t:actionlink>.
|
...
The open and close tags of a Tapestry component element define the body of the component. It is quite common for additional components to be enclosed in the body of another component:
Code Block |
---|
|
<t:form>
<t:errors/>
<t:label for="userId"/>
<t:textfield t:id="userId"/>
<br/>
<t:label for="password"/>
<t:passwordfield t:id="password"/>
<br/>
<input type="submit" value="Login"/>
</t:form>
|
...
Borrowing from the above example, all of the following are equivalent:
Code Block |
---|
|
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:a="tapestry-library:ajax">
<t:ajax.dialog/>
<span t:type="ajax/dialog"/>
<a:dialog/>
. . .
|
...
Invisible instrumentation involves using namespaced id or type attributes to mark an ordinary (X)HTML element as a component. For example:
Code Block |
---|
|
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<p>
Merry Christmas:
<span t:type="Count" end="3">
Ho!
</span>
</p>
|
...
In most cases, it is merely an aesthetic choice whether to use invisible instrumentation in your templates. However, in a very few cases the behavior of the component is influenced by your choice. For example, when your template includes the Loop component using the invisible instrumentation approach, the original tag (and its informal parameters) will render repeatedly around the body of the component. Thus, for example:
Code Block |
---|
|
<table>
<tr t:type="loop" source="items" value="item" class="prop:rowClass">
<td>${item.id}</td>
<td>${item.name}</td>
<td>${item.quantity}</td>
</tr>
</tabel>
|
...
You must define a special namespace, usually with the prefix "p":
Code Block |
---|
|
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter">
. . .
|
With the "tapestry:parameter" namespace defined, you can pass block using the "p:" prefix and an element name that matches the parameter name:
Code Block |
---|
|
<t:if test="loggedIn">
Hello, ${userName}!
<p:else>
Click <a t:type="actionlink" t:id="login">here</a> to log in.
</p:else>
</t:if>
|
...
The xml: namespace prefix is built into all XML documents, there is no special configuration (as there is with the Tapestry namespace).
For example:
Code Block |
---|
|
<ul class="navmenu" xml:space="preserve">
<li t:type="loop" t:source="pages" t:value="var:page">
<t:pagelink page="var:page">${var:page}</t:pagelink>
</li>
</ul>
|
This will preserve the whitespace between the <ul> and <li> elements, and between the (rendered) <li> elements and the nested <a> elements. For example, the output may look something like:
Code Block |
---|
|
<ul>
<li>
<a href="showcart>ShowCart</a>
</li>
<li>
<a href="viewaccount">ViewAccount</a>
</li>
</ul>
|
With normal whitespace compression, you would see the following rendered output:
Code Block |
---|
|
<ul><li><a href="showcart">ShowCart</a></li><li><a href="viewaccount">ViewAccount</li></ul>
|
...
Marks a point in a template that may be replaced. A unique id (case insensitive) is used in the template and its sub-templates to link extension points to possible overrides.
Code Block |
---|
|
<t:extension-point id="title">
<h1>${defaultTitle}</h1>
</t:extension-point>
|
...
Replaces an extension point from a parent template. <t:replace> may only appear as the immediate child of a root <t:extend> element.
Code Block |
---|
|
<t:extend xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
<t:replace id="title">
<h1><img src="${context:images/icon.jpg}"/>
Customer Service</h1>
</t:replace>
</t:extend>
|