Nearly all Tapestry components combine static HTML [2] from a template with additional dynamic content (some few components are just dynamic content). Often, a Tapestry component embeds other Tapestry components. These inner components are referenced in the containing component's template.
Templates look like standard HTML files, though they are rarely complete HTML documents; usually they are snippets.
Identifying a Tapestry component is accomplished by adding a jwcid attribute to a tag.
or
Most often, the HTML element chosen is <span>, though (in fact) Tapestry completely ignores the element, except to make sure the open and close tags balance.
The parser used by Tapestry is relatively forgiving about case and white space. Also, the component id (and any other attributes) can be enclosed in double quotes (as above), single quotes, or be left unquoted.
When using the jwcid attribute, you are free to specify additional attributes. These attributes will become informal parameters for the Tapestry component.
An alternative to using the jwcid attribute is to use the <jwc> element. The <jwc> element has two forms:
or
![]() | Note |
---|---|
Through Tapestry release 1.0.1, only the <jwc> tag was supported in HTML templates. Support for the jwcid attribute in arbitrary elements was added in release 1.0.2. |
When using the <jwc> tag, you may only specify the id attribute. You may not specify any additional informal parameters, as you can when using the standard notation.
The ability to convert static HTML tags into dynamic tags is really to streamline the integration process, the process whereby the efforts of HTML designers are converted into Tapestry components and templates.
The start and end tags for Tapestry components must balance properly. This includes cases where the end tag is normally ommitted, such as <input> elements. Either a closing tag must be supplied, or the XML-style syntax for an empty element must be used (that is, a slash before the end of the tag).
Tapestry divides the contents of the HTML template into two categories:
The body listed above can be either static HTML or other Tapestry components or both. Elements in the body of a component are wrapped by the containing component. The containing component controls the rendering of the elements it wraps in its body. For example, the Conditional component may decide not to render its body and the Foreach component may render its body multiple times.
Not all Tapestry components should have a body. For example, the TextField component creates an <input type=text> form element and it makes no sense for it to contain anything else. Whether a component can have a body (and wrap other elements) is defined in the component's specification.
Tapestry includes a special component, InsertWrapped, which is used to render the body of a component. It makes it easy to create components that wrap other components.
In many scripting systems, scripting constructs are one-dimensional.... they appear at a certain point on the page and dynamically insert some content into a stream of HTML that eventually ends up on the client web browser.
Tapestry components are more powerful ... they have open and close tags and thus can contain a body. This body is made up of static HTML from the template and other Tapestry components. The outer component wraps the inner elements.
An example of this is the Border component in the Tapestry Tutorial [3]. It shows how a component can wrap the entire content of a page.
Here, the border component provides the application title ("Reusable Component Tutorial", in the title bar of the window), the page title (upper left corner) and navigation controls (left side). The page provides the content in the light gray box in the center. In this example, the page content is simply static HTML but in a real application the content would include other components.
The Home page component has the following HTML template:
Figure 4.2. Home Page HTML Template
<jwc id="border">; Nothing much doing here on the <b>home</b> page. Visit one of our other fine pages. </jwc> |
In other words, the border component gets to produce HTML first. At some point, the page's content (wrapped inside the border component) will be produced. Afterwards, the border component will have an opportunity to produce more HTML. The Border component has a much larger HTML template:
Figure 4.3. Border component HTML template
<HTML>
<head>
<title>Reusable Component Tutorial</title>
</head>
<body>
<table border=0 bgcolor=gray cellspacing=0>
<tr valign=top>
<td colspan=3 align=left>
<font size=5 color="White"><jwc id="insertPageTitle"/>;</font>
</td>
</tr>
<tr valign=top>
<td align=right>
<font color=white>
<jwc id="e">;
<br><jwc id="link"><jwc id="insertName"></jwc>
</jwc>
</font>
</td>
<td valign=top bgcolor=silver>
<jwc id="wrapped"/>;
</td>
<td> </td>
</tr>
<tr>
<td colspan=3> </td>
</tr>
</table>
</body>
</HTML>
|
The Border component contains five components:
The e component wraps some static HTML and the link component. The link component wraps the insertName component.
When it comes time to render, Tapestry parses the HTML template and breaks them into blocks of static HTML, component starts (the <jwc> tag) and component ends (the </jwc> tag).
The framework determines what each component wraps. For components with their own templates, such as Home and Border, it figures out what the outer elements are, the outermost static HTML and components that aren't wrapped by other components.
This information turns into a data structure:
The left side shows how the components are embedded. The Home page contains the border component. The border component contains the other components.
The outermost elements for the Home page is a list of one item: the border component. There's no text before or after the border component's <jwc> tag, and the remaining text in the template is wrapped by the border component.
The border component is more complicated; it has several outer elements, representing static HTML text and components. The other components don't have templates, so they don't have outer elements, but some do wrap other components.
When it's time to render, the process starts in the Home page, since a page is always the outermost component. It iterates through its outer list, which contains a single element: the border component. The process then recursively renders the border component. Its outer list is rendered in order. Each component decides where it will render its wrapped elements (if it has any). The e component is a Foreach; it will render its wrapped elements any number of times.
Eventually, the process reaches the wrapped component, which is of type InsertWrapped. This is a special component; it jumps up one level to its container (the border component) and renders the border's wrapped elements ... the text from the Home page template.
It may seem complicated, but ultimately its very natural from a markup language point of view; the <jwc> tags continue to act like HTML elements, wrapping around and controlling their contents, just exactly like a <table> wraps its <tr>'s or a <form> wraps its <input>'s.
[2] The initial relase of Tapestry is specifically oriented around HTML. Some support for non-HTML languages, such as XML, XHTML or WML is already present and will be expanded in the future.
[3] The Border tutorial has changed slightly since this was initially written, but the basic ideas still hold.