Making a component Layout with Tapestry 5 is really simple.
An example is given at: http://tapestry.apache.org/tapestry5/guide/layout.html in the official tapestry 5 documentation but I propose a more sophisticated component with content fallback, able for instance to override its left column content if needed.
We'll finish with something that will look like a bit like the Tiles Template system (Struts), but much much simpler than Tiles.
In the package components, create a Layout component and template
Layout.java :
1 import org.apache.tapestry.annotations.Parameter;
2 import org.apache.tapestry.ioc.annotations.Inject;
3 import org.apache.tapestry.services.Request;
4
5 /**
6 * @author Michael Courcy
7 *
8 * This component aims to provide layout service for a page
9 *
10 */
11 @IncludeStylesheet("context:layout.css")
12 public class Layout {
13
14 @Parameter
15 private String title = "My Tapestry powered site";
16
17 @Inject
18 private Request request;
19
20 public String getTitle() {
21 return title;
22 }
23
24 public void setTitle(String title) {
25 this.title = title;
26 }
27
28 public Request getRequest() {
29 return request;
30 }
31
32 public void setRequest(Request request) {
33 this.request = request;
34 }
35 }
Layout.tml
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>${title}</title>
</head>
<body>
<table id="main">
<tr>
<td id="header" colspan="2">
The header
</td>
</tr>
<tr>
<td id="left">
Here come the left content
</td>
<td id="content">
<t:body/>
</td>
</tr>
<tr>
<td id="footer" colspan="2">
Tapestry powered Site
</td>
</tr>
</table>
</body>
</html>Then add this css file in the root context of your webapp.
layout.css
table#main {
width: 700px;
margin-left:auto;
margin-right:auto;
}
td#header {
height: 120x;
border: 1px solid blue;
padding: 10px;
margin: 10px;
}
td#footer {
height: 120x;
border: 1px solid blue;
padding: 10px;
margin: 10px;
}
td#left{
width: 200px;
border: 1px solid red;
padding: 10px;
margin: 10px;
}
td#content{
border: 1px solid red;
padding: 10px;
margin: 10px;
}Let's try it! In the package page, create a page TestLayout.java which does ot do anything as its only purpose is to test the component.
1 public class TestLayout {
2
3 }
and in the root context of your webapp, create the template TestLayout.tml :
<t:layout title="literal:My first use of layout component" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> My content </t:layout>
You should get this:
Note that the title of the page is passed as a parameter.
But could we regard this solution as fulfilling our requirements?
Not really, because the content of the left column is now static and we're about 100% sure that for some pages we'll have to override it.
Let's change the component using Delegate, Block, Parameter and a component of our own : Left.
Left.java (in the components package)
1 /**
2 * @author Michael Courcy
3 *
4 * This component is just a content holder to fill the left column of the layout component
5 *
6 */
7 public class Left {
8
9 }
Really simple, isn't it? That's barely a container.
Now let's change Layout.tml.
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>${title}</title>
<link href="${request.contextPath}/layout.css" rel="stylesheet" type="text/css" />
</head>
<body>
<table id="main">
<tr>
<td id="header" colspan="2">
The header
</td>
</tr>
<tr>
<td id="left">
<t:delegate to="leftContent" />
<t:block>
<div t:id="leftRegularContent">
Here come the left regular content
</div>
</t:block>
</td>
<td id="content">
<t:body/>
</td>
</tr>
<tr>
<td id="footer" colspan="2">
Tapestry powered Site
</td>
</tr>
</table>
</body>
</html>What you have to focus on is the change done in the left column, the content of the component leftRegularContent will be a "content fallback".
You have to change Layout.java as well
1 package org.apache.tutorial.tapestrySpringHibernate.components;
2
3 import org.apache.tapestry.Block;
4 import org.apache.tapestry.annotations.Component;
5 import org.apache.tapestry.annotations.Parameter;
6 import org.apache.tapestry.ioc.annotations.Inject;
7 import org.apache.tapestry.services.Request;
8
9 /**
10 * @author Michael Courcy
11 *
12 * This component aims to create a layout around the main content
13 * You can optionnaly defines left content that overrides the regular left
14 * content if needed through the <t:parameter name="left">some overiding left content</t:parameter>
15 *
16 */
17 public class Layout {
18
19 @Parameter
20 private String title = "My Tapestry powered site";
21
22 @Parameter
23 private Block left;
24
25 @Component
26 private Left leftRegularContent;
27
28 @Inject
29 private Request request;
30
31 /**
32 * This method check if the left parameter has been set by the user
33 * if not the regular content is shown otherwise the content of this parameter
34 *
35 * @return the component we want to display
36 */
37 public Object getLeftContent(){
38 return left==null ? leftRegularContent : left;
39 }
40
41 public String getTitle() {
42 return title;
43 }
44
45 public void setTitle(String title) {
46 this.title = title;
47 }
48
49 public Request getRequest() {
50 return request;
51 }
52
53 public void setRequest(Request request) {
54 this.request = request;
55 }
56 }
Et voila !! Without defining a left parameter :
1 <t:layout title="literal:My first use of layout component" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
2 My content
3 </t:layout>
you get this:
With a left parameter defined :
<t:layout title="literal:My first use of layout component" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd"> My content <t:parameter name="left"> Other left content </t:parameter> </t:layout>
You get this:
(originally posted on Michael Courcy's blog - the images only work if you right click and view image, if anyone can fix this or can host the images where they'll work inline - please do so )
NOTE: Inline images have now been fixed (11/23/2008)