| <!-- $Id$ --> |
| <!-- |
| Copyright 2004 The Apache Software Foundation |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <chapter id="template"> |
| <title>Page and component templates</title> |
| |
| <para> |
| Unlike many other web frameworks, such as |
| &Struts; or &WebWork;, |
| Tapestry does not "plug into" an external templating system such as JavaServer Pages or |
| &Velocity;. Instead, Tapestry integrates its own templating system. |
| |
| </para> |
| |
| <para> |
| Tapestry templates are designed to look like valid HTML files (component HTML templates |
| will just be snippets of HTML rather than complete pages). |
| Tapestry "hides" its extensions into special attributes of ordinary HTML elements. |
| |
| </para> |
| |
| <para> |
| Don't be fooled by the terminology; we say "HTML templates" because that is the prevalent use of Tapestry ... but |
| Tapestry is equally adept at WML or XML. |
| </para> |
| |
| <section id="template.locations"> |
| <title>Template locations</title> |
| |
| |
| <para> |
| The general rule of thumb is that a page's HTML template is simply an HTML file, stored in the context root directory. |
| That is, you'll have a <filename><replaceable>MyPage</replaceable>.html</filename> HTML template, |
| a <filename>WEB-INF/<replaceable>MyPage</replaceable>.page</filename> page specification, |
| and a <classname>MyPage</classname> class, in some Java package. |
| </para> |
| |
| <para> |
| Tapestry always starts knowing the name of the page and the location of the page's specification when it |
| searches for the page's HTML template. Starting with this, it performs the following search: |
| </para> |
| |
| <itemizedlist> |
| <listitem> |
| <para> |
| In the same location as the specification |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| In the web application's context root directory (if the page is an application page, not a page from a component |
| library) |
| </para> |
| </listitem> |
| </itemizedlist> |
| |
| <para> |
| In addition, any HTML template in the web application context is considered a page, even if there is no matching |
| page specification. For simple pages that don't need to have any page-specific logic or properties, there's no need |
| for a page specification. Such a page may still use the special Tapestry attributes |
| (described in the following sections). |
| </para> |
| |
| <para> |
| Finally, with some <link linkend="configuration.search-path">minor configuration</link> |
| it is possible to change the extension used for templates. For example, if you are developing a WML |
| application, you may wish to name your files with the extension <filename>.wml</filename>. |
| </para> |
| |
| </section> <!-- template.locations --> |
| |
| <section id="template.contents"> |
| <title>Template Contents</title> |
| |
| <para> |
| Tapestry templates contain a mix of the following elements: |
| </para> |
| |
| <itemizedlist> |
| <listitem> |
| <para>Static HTML markup</para> |
| </listitem> |
| <listitem> |
| <para>Tapestry components</para> |
| </listitem> |
| <listitem> |
| <para>Localized messages</para> |
| </listitem> |
| <listitem> |
| <para>Special template directives</para> |
| </listitem> |
| </itemizedlist> |
| |
| <para> |
| Usually, about 90% of a template is ordinary HTML markup. Hidden inside that markup are particular tags that |
| are placeholders for Tapestry components; these tags are recognized by the presence of the &jwcid; attribute. "JWC" |
| is short for "Java Web Component", and was chosen as the "magic" attribute so as not to conflict with any real HTML attribute. |
| </para> |
| |
| |
| <para> |
| Tapestry's parser is quite flexible, accepting all kinds of invalid HTML markup. That is, attributes don't <emphasis>have</emphasis> to be |
| quoted. Start and end tags don't have to balance. Case is ignored when matching start and end tags. Basically, |
| the kind of ugly HTML you'll find "in the field" is accepted. |
| </para> |
| |
| <para> |
| The goal is to allow you to preview your HTML templates using a WYSIWYG HTML editor (or even an ordinary web browser). |
| The editor will ignore the undefined HTML attributes (such as &jwcid;). |
| </para> |
| |
| <para> |
| A larger goal is to support real project teams: The special markup for Tapestry is unobtrusive, even invisible. |
| This allows an HTML designer to work on a template without breaking the dynamic portions of it. This is completely unlike |
| JSPs, where the changes to support dynamic output are extremelyobtrusive and result in a file that is meaningless to an HTML |
| editor. |
| </para> |
| |
| </section> <!-- template.contents --> |
| |
| <section id="template.components"> |
| <title>Components in templates</title> |
| |
| <para> |
| Components can be placed anywhere inside a template, simply by adding the &jwcid; attribute to |
| any existing tag. For example: |
| |
| <example> |
| <title>Example HTML template containing components</title> |
| <programlisting><![CDATA[ |
| <html> |
| <head> |
| <title>Example HTML Template</title> |
| </head> |
| <body>]]> |
| <span jwcid="border"> <co id="template.components.border"/> |
| |
| Hello, |
| <span jwcid="@&Insert;" value="ognl:user.name">Joe User</span> <co id="template.components.insert"/> |
| <![CDATA[ |
| </span> |
| </body> |
| </html>]]> |
| </programlisting> |
| </example> |
| |
| <calloutlist> |
| <callout arearefs="template.components.border"> |
| <para> |
| This is a reference to a <emphasis>declared component</emphasis>; the type and parameters |
| of the component are in the page's specification. |
| </para> |
| </callout> |
| <callout arearefs="template.components.insert"> |
| This is a <emphasis>implicit component</emphasis>; the type of the component is &Insert;. The |
| value parameter is bound to the &OGNL; expression <literal>user.name</literal>. |
| </callout> |
| </calloutlist> |
| </para> |
| |
| <para> |
| The point of all this is that the HTML template should preview properly in a WYSIWYG HTML editor. Unlike |
| &Velocity; or JSPs, there are no strange directives to get in the way of a preview (or necessitate |
| a special editting tool), Tapestry hides what's needed inside existing tags; at worst, it adds |
| a few non-standard attributes (such as &jwcid;) to tags. This rarely causes a problem with most HTML editors. |
| </para> |
| |
| <para> |
| Templates may contain components using two different styles. <emphasis>Declared components</emphasis> are |
| little more than a placeholder; the type of the component is defined elsewhere, in the page (or component) |
| specification. |
| </para> |
| |
| <para> |
| Alternately, an <emphasis>implicit component</emphasis> can be defined in place, by preceding |
| the component type with an "@" symbol. Tapestry includes over forty components with the framework, additional components |
| may be created as part of your application, or may be provided inside a component library. |
| </para> |
| |
| <para> |
| In the above example, a &span; was used for both components. Tapestry |
| doesn't care what tag is used for a component, as long as the start and end tags for components balance (it doesn't |
| even care if the case of the start tag matches the case of the end tag). The example could just |
| as easily use <sgmltag class="starttag">div</sgmltag> or <sgmltag class="starttag">fred</sgmltag>, the |
| rendered page sent back to the client web browser will be the same. |
| </para> |
| |
| <section id="templates.components.body"> |
| <title>Component bodies</title> |
| |
| <para> |
| In Tapestry, each component is responsible for rendering itself and its <emphasis>body</emphasis>. |
| A component's body is the portion of its page's template |
| <footnote> |
| <para> |
| More correct would be to say "its container's template" as a component may be contained within |
| another component. For simplicities sake, we'll describe this as if it was always a simple two-level |
| heirarchy even though practical Tapestry applications can be many levels deep. |
| </para> |
| </footnote> |
| that its tags encloses. The Tapestry HTML template parser is responsible for dividing up the template |
| into chunks: blocks of static HTML, component start tags (recognized by the &jwcid; attribute) and matching |
| component end tags. It is quite forgiving about case, quotes (which may be single quotes, double quotes, or even |
| omitted), and missing close tags (except for components, which must be balanced). |
| </para> |
| |
| <figure> |
| <title>Component templates and bodies</title> |
| <mediaobject> |
| <imageobject> |
| <imagedata fileref="images/component-body.png" format="PNG"/> |
| </imageobject> |
| <caption> |
| <para> |
| The template is broken into small chunks that are each slotted into a particular |
| component's body. |
| </para> |
| </caption> |
| </mediaobject> |
| </figure> |
| |
| |
| <para> |
| In most cases, a component will make use of its body; it simply controls if, when and how often its body |
| is rendered (when rendering the HTML response sent to the client). Other components, such as &Insert;, |
| have no use for their bodies, which they discard. Each component declares in its own specification (the |
| <literal>allow-body</literal> attribute of the &spec.component-specification;) whether is allows or |
| discards its body. |
| </para> |
| |
| <para> |
| In the previous example, the &Insert; component had a body, the text "Joe User". This supports WYSIWYG preview; the text |
| will be displayed when previewing. Since the &Insert; component discards its body, |
| this text will not be used at runtime, instead the OGNL expression <literal>user.name</literal> will be evaluated |
| and the result inserted into the response. |
| </para> |
| |
| <warning> |
| <title>No components in discarded blocks</title> |
| <para> |
| If you put a component inside the body of an &Insert; (or any other component that discards |
| its body), then Tapestry will throw an exception. You aren't allowed to create a component |
| simply to discard it. |
| </para> |
| </warning> |
| |
| </section> <!-- templates.components.body --> |
| |
| <section id="templates.components.ids"> |
| <title>Component ids</title> |
| |
| <para> |
| Every component in Tapestry has its own id. In the above example, the first component has the id "border". The second component |
| is anonymous; the framework provides a unique id for the component since one was not supplied in the HTML template. The |
| framework provided id is built from the component's type; this component would have an id of |
| <literal>$Insert</literal>; other &Insert; components |
| would have ids <literal>$Insert$0</literal>, <literal>$Insert$1</literal>, etc. |
| </para> |
| |
| <para> |
| A component's id must only be unique within its immediate container. Pages are top-level containers, but |
| components can also contain other components. |
| </para> |
| |
| |
| <para> |
| Implicit components can also have a specific id, by placing the id in front of the "@" symbol: |
| |
| <informalexample> |
| <programlisting> |
| <span jwcid="insert@&Insert;" value="ognl:user.name">Joe User</span> |
| </programlisting> |
| </informalexample> |
| </para> |
| |
| <para> |
| The component is still implicit; nothing about the component would go in the specification, but the id |
| of the component would be "insert". |
| </para> |
| |
| <para> |
| Providing explicit ids for your components is rarely required, but often beneficial. It is especially |
| useful for form control components, |
| </para> |
| |
| <para> |
| Each component may only appear <emphasis>once</emphasis> in the template. You simply can't |
| use the same component |
| repatedly ... but you can duplicate a component fairly easily; make the component a declared component, |
| then use the <literal>copy-of</literal> attribute of the &spec.component; element to create clones of |
| the component with new ids. |
| </para> |
| |
| |
| </section> <!-- templates.components.ids --> |
| |
| <section id="templates.components.parameters"> |
| <title>Specifying parameters</title> |
| |
| <para> |
| Component parameters may always be specified in the page or component |
| specification, using the |
| &spec.binding;, &spec.static-binding; and &spec.message-binding; elements. Prior to Tapestry 3.0, that |
| was the only way ... but with 3.0, it is possible to specify parameters directly within the |
| HTML template. |
| </para> |
| |
| <para> |
| Using either style of component (declared or implicit), parameters of the component may be <emphasis>bound</emphasis> |
| by adding attributes to the tag. |
| Most attributes bind parameters to a static (unchanging) value, equivalent to using |
| the &spec.static-binding; element in the specification. Static bindings are just the |
| literal text, the attribute value from the HTML template. |
| </para> |
| |
| <para> |
| Prefixing an attribute value with <literal>ognl:</literal> indicates that the value |
| is really an &OGNL; expression, equivalent to using the &spec.binding; element in the specification. |
| </para> |
| |
| <para> |
| Finally, prefixing an attribute value with <literal>message:</literal> indicates that the value |
| is really a key used to get a localized message, equivalent to the &spec.message-binding; element |
| in the specification. Every page, and every component, is allowed to have its own set of messages (stored |
| in a set of <literal>.properties</literal> files), and the <literal>message:</literal> prefix allows access |
| to the localized messages stored in the files. |
| </para> |
| |
| <tip> |
| <title>Seperation of Concerns</title> |
| |
| <para> |
| Before Tapestry 3.0, there was a more clear separation of concerns. The template could only have declared |
| components (not implicit), and any informal attributes in the template were always static values. The type |
| of the component and all its formal parameters were always expressed in the specification. The template was very much |
| focused on presentation, and the specification was very much focused on business logic. There were |
| always minor exceptions to the rules, but in general, seperation of concerns was very good. |
| </para> |
| |
| <para> |
| With Tapestry 3.0, you can do more in the HTML template, and the specification file is much less |
| important ... but the seperation of concerns is much more blurred together. It is very much acceptible to |
| mix and match these approaches, even within a single page. In general, when learning Tapestry, or when prototyping, it |
| is completely appopriate to do as much as possible in the HTML template. For large and complex |
| applications, there are benefits to moving as much of the dynamic logic as possible out |
| of the template and into the specification. |
| </para> |
| |
| </tip> |
| |
| </section> <!-- templates.components.parameters --> |
| |
| <section id="template.components.formal"> |
| <title>Formal and informal parameters</title> |
| |
| <para> |
| Components may accept two types of parameters: <emphasis>formal</emphasis> |
| and <emphasis>informal</emphasis>. Formal parameters are those defined in the |
| component's specification, using the &spec.parameter; element. |
| Informal parameters are <emphasis>additional</emphasis> parameters, beyond those |
| known when the component was created. |
| </para> |
| |
| <para> |
| The majority of components that accept informal parameters simply emit the informal |
| parameters as additional attributes. Why is that useful? Because it allows you to |
| specify common HTML attributes such as <literal>class</literal> or <literal>id</literal>, |
| or JavaScript event handlers, without requiring that each component define each possible |
| HTML attribute (the list of which expands all the time). |
| </para> |
| |
| <sidebar> |
| <para> |
| If you are used to developing with JSPs and JSP tags, this will be quite a difference. JSP tags have |
| the equivalent of formal parameters (they are called "tag attributes"), but nothing like informal parameters. Often a relatively |
| simply JSP tag must be bloated with dozens of extra attributes, to support arbitrary |
| HTML attributes. |
| </para> |
| </sidebar> |
| |
| <para> |
| Informal and formal parameters can be specified in either the specification or in the template. |
| Informal parameters <emphasis>are not</emphasis> limited to literal strings, you may use |
| the <literal>ognl:</literal> and <literal>message:</literal> prefixes with them as well. |
| </para> |
| |
| |
| <para> |
| Not all components allow informal parameters; this is controlled by the |
| <literal>allow-informal-parameters</literal> attribute of the |
| &spec.component-specification; element. Many components do not map directly to an HTML element, |
| those are the ones that do not allow informal parameters. If a component forbids informal parameters, |
| then any informal parameters in the specification or the template will result in errors, with one exception: |
| static strings in the HTML template are simply ignored when informal parameters are forbidden; they |
| are presumed to be there only to support WYSIWYG preview. |
| </para> |
| |
| <para> |
| Another conflict can occur when the HTML template specified an attribute that the component needs |
| to render itself. For example, the &DirectLink; component generates a <literal><a></literal> tag, |
| and needs to control the <literal>href</literal> attribute. However, for preview purposes, it often will |
| be written into the HTML template as: |
| |
| <informalexample> |
| <programlisting> |
| <a jwcid="@DirectLink" listener=". . ." href="#"> . . . </a> |
| </programlisting> |
| </informalexample> |
| |
| </para> |
| |
| <para> |
| This creates a conflict: will the template <literal>href</literal> be used, |
| or the dynamically generated value produced by the &DirectLink; component, or both? The answer is: |
| the component wins. The <literal>href</literal> attribute in the template is ignored. |
| </para> |
| |
| <para> |
| Each component declares a list of reserved names using the &spec.reserved-parameter; element; these |
| are names which are not allowed as informal parameters, because the component generates |
| the named attribute itself, and doesn't want the value it writes to be overriden by an informal |
| parameter. Case is ignored when comparing attribute names to reserved names. |
| </para> |
| |
| </section> <!-- template.components.formal --> |
| |
| |
| |
| </section> <!-- template.components --> |
| |
| <section id="template.directives"> |
| <title>Template directives</title> |
| |
| <para> |
| For the most part, a Tapestry page or component template consists of |
| just static HTML intermixed with tags representing components (containing the &jwcid; attribute). |
| The overarching goal is to make the Tapestry extensions completely invisible. |
| </para> |
| |
| <para> |
| Tapestry supports a limited number of additional directives that are not about component placement, but |
| instead address other concerns about integrating the |
| efforts of HTML developers with the Java developers responsible |
| for the running application. |
| </para> |
| |
| <section id="template.directives.l10n"> |
| <title>Localization</title> |
| |
| <para> |
| Tapestry includes a number of <link linkend="configuration.character-sets">localization features</link>. An important part of which |
| is to allow each page or component to have its own catalog of localized messages (modeled after the Java |
| &ResourceBundle; class). |
| </para> |
| |
| <para> |
| The page (or component) message catalog is a collection of <filename>.properties</filename> files |
| that are stored with the page or component specification. They follow the same naming conventions |
| as for &ResourceBundle;s, so component <classname>MyComponent</classname> (whose specification file |
| is <filename>MyComponent.jwc</filename>) might have a default |
| message file of <filename>MyComponent.properties</filename>, and a French translation as |
| <filename>MyComponent_fr.properties</filename>. |
| </para> |
| |
| <note> |
| <title>No global message catalog</title> |
| <para> |
| On oft-requested feature for Tapestry is to have a global message catalog, and a way to |
| access that catalog from the individual pages and components. This would allow common messages |
| to be written (and translated) just once. This is a feature that may be added to Tapestry 3.1. |
| </para> |
| </note> |
| |
| <para> |
| As we've seen, it is possible to access the messages for a page or component using the |
| <literal>message:</literal> prefix on a component parameter (or use |
| the &spec.message-binding; element in a page or component specification). |
| </para> |
| |
| <para> |
| What about the static text in the template itself? How does that get translated? One possibility |
| would be to make use of the Insert component for each piece of text to be displayed, for example: |
| <informalexample> |
| <programlisting> |
| <span jwcid="@&Insert;" value="message:hello">Hello</span> |
| </programlisting> |
| </informalexample> |
| </para> |
| |
| <para> |
| This snippet will get the <literal>hello</literal> message from the page's message catalog |
| and insert it into the response. The text inside the &span; |
| tag is useful for WYSIWYG preview, but will be discarded at runtime in favor of a message string |
| from the catalog, such as "Hello", "Hola" or "Bonjour" (depending on the selected locale). |
| </para> |
| |
| <para> |
| Because, in an internationalized application, this scenario |
| will occur with great frequency, Tapestry includes |
| a special directive to perform the equivalent function: |
| <informalexample> |
| <programlisting> |
| <span key="hello">Hello</span> |
| </programlisting> |
| </informalexample> |
| </para> |
| |
| <para> |
| This is not an &Insert; component, but behaves in a similar way. The tag used must be |
| &span;. You do not use the <literal>message:</literal> prefix |
| on the message key (<literal>hello</literal>). You can't use OGNL expressions. |
| </para> |
| |
| <para> |
| Normally, the &span; does not render, just the message. |
| However, if you specify any additional attributes in the &span; tag (such as, commonly, |
| <literal>id</literal> or <literal>class</literal> to specify a CSS style), |
| then the &span; will render around the message> For example, the template: |
| <informalexample> |
| <programlisting> |
| <span class="error" key="invalid-access">Invalid Access</span> |
| </programlisting> |
| </informalexample> |
| |
| might render as: |
| |
| <informalexample> |
| <programlisting> |
| <span class="error">You do not have the necessary access.</span> |
| </programlisting> |
| </informalexample> |
| |
| In this example, the placeholder text "Invalid Access" was replaced with a much |
| longer message acquired from the message catalog. |
| |
| </para> |
| |
| <para> |
| In rare cases, your message may have pre-formatted HTML inside it. Normally, output is |
| filtered, so that any reserved |
| HTML characters in a message string are expanded to HTML entities. For example, |
| a <literal><</literal> will be expanded to <literal>&lt;</literal>. If this is not desired, |
| add <literal>raw="true"</literal> to the &span;. This defeats the filtering, and text in the message |
| is passed through as-is. |
| </para> |
| |
| |
| </section> <!-- template.directives.l10n --> |
| |
| <section id="template.directives.remove"> |
| <title><literal>$remove$ jwcid</literal> |
| </title> |
| |
| <para> |
| HTML templates in Tapestry serve two purposes. On the one hand, they are used to dynamically render |
| pages that end up in client web browsers. On the other hand, they allow HTML developers to use WYSIWYG editors |
| to modify the pages without running the full application. |
| </para> |
| |
| <para> |
| We've already seen two ways in which Tapestry accomidates WYSIWYG preview. Informal component |
| parameters may be quietly dropped |
| if they conflict with reserved names defined by the component. Components that discard their body may enclose |
| static text used for WYSIWYG prefix. |
| </para> |
| |
| <para> |
| In some cases, we need even more direct control over the content of the template. Consider, for example, |
| the following HTML template: |
| </para> |
| |
| <example> |
| <title>HTML template with repetative blocks (partial)</title> |
| <programlisting><![CDATA[ |
| <table> |
| <tr> |
| <th>First Name</th> |
| <th>Last Name</th> |
| </tr> |
| <tr jwcid="loop"> |
| <td><span jwcid="insertFirstName">John</span></td> |
| <td><span jwcid="insertLastName">Doe</span></td> |
| </tr> |
| <tr> |
| <td>Frank</td> |
| <td>Smith</td> |
| </tr> |
| <tr> |
| <td>Jane</td> |
| <td>Jones</td> |
| </tr> |
| </table> |
| ]]></programlisting> |
| </example> |
| |
| <para> |
| This is part of the HTML template that writes out the names of a list of people, perhaps from some kind of database. |
| When this page renders, the <literal>loop</literal> component (presumably a &Foreach;, such details |
| being in the page's specification) |
| will render its body zero or more times. So we might see rows for "Frank Miller", "Alan Moore" and so forth |
| (depending on the content of the database). |
| However, every listing will also include "Frank Smith" and "Jane Jones" ... because the HTML developer left those |
| two rows in, to ensure that the layout of the table was correct with more than one row. |
| </para> |
| |
| <para> |
| Tapestry allows a special &jwcid;, <literal>$remove$</literal>, for this case. A tag so marked is |
| not a component, but is instead eliminated from the |
| template. It is used, as in this case, to mark sections of the template that are just there for WYSIWYG preview. |
| </para> |
| |
| <sidebar> |
| Normally, <literal>$remove$</literal> would not be a valid component id, because it contains a dollar sign. |
| </sidebar> |
| |
| <para> |
| With this in mind, the template can be rewritten: |
| </para> |
| |
| |
| <example> |
| <title>Updated HTML template (partial)</title> |
| <programlisting><![CDATA[ |
| <table> |
| <tr> |
| <th>First Name</th> |
| <th>Last Name</th> |
| </tr> |
| <tr jwcid="loop"> |
| <td><span jwcid="insertFirstName">John</span></td> |
| <td><span jwcid="insertLastName">Doe</span></td> |
| </tr> |
| <tr jwcid="$remove$"> |
| <td>Frank</td> |
| <td>Smith</td> |
| </tr> |
| <tr jwcid="$remove$"> |
| <td>Jane</td> |
| <td>Jones</td> |
| </tr> |
| </table> |
| ]]></programlisting> |
| </example> |
| |
| <para> |
| With the <literal>$remove$</literal> blocks in place, the output is as expected, one row for each |
| row read from the database, |
| and "Frank Smith" and "Jane Jones" nowhere to be seen. |
| </para> |
| |
| <warning> |
| <title>No components in removed blocks</title> |
| <para> |
| It's not allowed to put components inside a removed block. This is effectively the same rule that prevents |
| components from being put inside discarded component bodies. Tapestry will throw an exception if a template |
| violates this rule. |
| </para> |
| </warning> |
| |
| |
| </section> <!-- template.directives.remove --> |
| |
| <section id="template.directives.content"> |
| <title><literal>$content$ jwcid</literal></title> |
| |
| <para> |
| In Tapestry, components can have their own templates. Because of how components integrate their own templates |
| with their bodies (the portion from their container's template), you can do a lot ofn iteresting things. It is very |
| common for a Tapestry application to have a Border component: a component that produces the &html;, |
| &head;, and &body; tags (along with additional tags |
| to reference stylesheets), plus some form of navigational control (typically, a nested table and a collection of links and images). |
| </para> |
| |
| <para> |
| Once again, maintaining the ability to use WYSIWYG preview is a problem. Consider the following: |
| <informalexample> |
| <programlisting><![CDATA[ |
| <html> |
| <head> |
| <title>Home page</title> |
| <link rel="stylesheet" href="style.css" type="text/css"> |
| </head> |
| <body> |
| |
| <span jwcid="border"> |
| |
| <!-- Page specific content: --> |
| |
| <form jwcid=". . ."> |
| . . . |
| </form> |
| |
| </span> |
| </body> |
| ]]></programlisting> |
| </informalexample> |
| </para> |
| |
| <para> |
| It is quite common for Tapestry applications to have a <emphasis>Border</emphasis> |
| component, a component that is used by pages to provide the |
| &html;, &head;, and |
| &body; tags, plus common navigational features (menus, |
| copyrights, and so forth). In this example, it is presumed that the <literal>border</literal> |
| component is a reference to just such as component. |
| </para> |
| |
| <para> |
| When this page renders, the page template will provide the &html;, &head; and &body; tags. |
| Then when the <literal>border</literal> component renders, it will <emphasis>again</emphasis> |
| render those tags (possibly with different attributes, and mixed in to much other stuff). |
| </para> |
| |
| <para> |
| If we put a <literal>$remove$</literal> on the &html; tag in the page template, the entire page will |
| be removed, causing runtime exceptions. |
| |
| Instead, we want to identify that the portion of the template <emphasis>inside</emphasis> |
| the &body; tag (on the page template) is the only part that counts). The <literal>$content$</literal> |
| component id is used for this purpose: |
| <informalexample> |
| <programlisting><![CDATA[ |
| <html> |
| <head> |
| <title>Home page</title> |
| <link rel="stylesheet" href="style.css" type="text/css"> |
| </head> |
| <body jwcid="$content$"> |
| |
| <span jwcid="border"> |
| |
| <!-- Page specific content: --> |
| |
| <form jwcid=". . ."> |
| . . . |
| </form> |
| |
| </span> |
| </body> |
| ]]></programlisting> |
| </informalexample> |
| </para> |
| |
| <para> |
| The &body; tag, the text preceding its open tag, the <sgmltag class="endtag">body</sgmltag> tag, and the text following |
| it are all removed. It's as if the template consisted only of the &span; tag for the <literal>border</literal> component. |
| </para> |
| |
| </section> <!-- template.directives.content --> |
| |
| |
| </section> <!-- template.directives --> |
| |
| </chapter> |