Loading presentation...
Java based web framework centered around writing re-usable components.
The hugely popular Dojo javascript toolkit comes bundled in Tapestry 4.1 by default.
The overall design of the AJAX related features are about providing you the right kind of support to develop AJAX enhanced components / applications - not just a set of pre-canned AJAX components.
var url="http://localhost:8080/app";
var content={chosenBook:"Cryptonomicon",numberOfCopies:"10"};
tapestry.bind(url, content);
Simple list of albums that you may "choose".
Two main components to choose from - Shell or ScriptIncludes. Shell writes out additional things like <head> / <title> tags.
<html>
<head>
<title>Getting Started - Javascript includes</title>
</head>
<span jwcid="@Shell" title="Demo - Album Chooser">
<body jwcid="@Body">
<ul>
<li>Step 1 - Include javascript</li>
<li>Step 2 - Write components</li>
<li>Step 3 .....</li>
<li>Profit!</li>
</ul>
</body>
</span>
</html>
Majority of work done in OGNL statements. Simple XHR update of a single dom element.
<h2>Album Chooser</h2>
<p>
Select one of the albums below to view more..
</p>
<ul>
<li jwcid="@For" source="ognl:@demo.page.Home@ALBUMS" value="ognl:album">
<a jwcid="@DirectLink" listener="listener:chooseAlbum" parameters="ognl:album.id"
updateComponents="albumDetail">
<span jwcid="@Insert" value="ognl:album.name + ' - ' + album.artist" />
</a>
</li>
</ul>
<div jwcid="albumDetail@Any" >
<span jwcid="@If" condition="ognl:selectedAlbum" renderTag="false">
<h2>Album Selected</h2>
<b>Artist :</b> <span jwcid="@Insert" value="ognl:selectedAlbum.artist" /><br/>
<b>Name :</b> <span jwcid="@Insert" value="ognl:selectedAlbum.name" /><br/>
<b>Year :</b> <span jwcid="@Insert" value="ognl:selectedAlbum.year" /><br/>
<p>
<img jwcid="@Any" src="ognl:selectedAlbum.imageUrl" />
</p>
</span>
</div>
By the time you get to the java code most of the work is already done..
public abstract class Home extends BasePage {
public static final List ALBUMS = new ArrayList();
static {
ALBUMS.add(new Album(0, "Gorillaz", "Gorillaz", ...
ALBUMS.add(new Album(1, "Bumblebeez 81", "The printz", ....
ALBUMS.add(new Album(2, "The Avalanches", "Since I Left You", ...
ALBUMS.add(new Album(3, "Peter Bjorn and John", "Writer's Block", ...
ALBUMS.add(new Album(4, "The Boards of Canada", "Music Has the Right to.."
}
public abstract Album getAlbum();
public abstract Album getSelectedAlbum();
public abstract void setSelectedAlbum(Album album);
/** Invoked by link */
public void chooseAlbum(int id)
{
setSelectedAlbum(ALBUMS.get(id));
}
}
When we take it out of the oven an hour later..
Take an existing Dojo widget and wrap it via one of the handy base Dojo widget component classes in Tapestry. The Toaster widget is a simple notification display of a textual message.
public abstract class Toaster extends AbstractWidget {
public abstract void setMessage(String message);
@InjectScript("Toaster.script") // injected js template
public abstract IScript getScript();
public void renderWidget(IMarkupWriter writer, IRequestCycle cycle)
{
writer.begin(getTemplateTagName());
renderIdAttribute(writer, cycle);
renderInformalParameters(writer, cycle);
writer.end(); // close out tag opened
JSONObject props = new JSONObject(); // widget parameters
Map parms = new HashMap();
parms.put("component", this);
parms.put("props", props.toString());
getScript().execute(this, cycle,
TapestryUtils.getPageRenderSupport(cycle, this), parms);
}
}
Executed like a velocity template, properties come in a map. OGNL does most of the work here again.
<script>
<input-symbol key="component" required="yes"/>
<input-symbol key="props" required="yes"/>
<body>
<unique>
dojo.require("tapestry.widget.Widget");
</unique>
</body>
<initialization>
tapestry.widget.synchronizeWidgetState("${component.clientId}",
"Toaster", ${props}, ${component.destroy});
<if expression="component.message">
var toaster=dojo.widget.byId("${component.clientId}");
toaster.setContent("${component.message}");
</if>
</initialization>
</script>
That's it! Time to use the component. .
Integrate component into page class and html.
..
public void chooseAlbum(int id)
{
setSelectedAlbum(ALBUMS.get(id));
getToaster().setMessage("Successfully selected album '"
+ ALBUMS.get(id).getName() + "'");
}
// our new component
@Component
public abstract Toaster getToaster();
<div jwcid="toaster" />
Demonstration of the newly integrated Toaster widget.
Connects Tapestry listener method invocations to client side
events via the AOP-like
dojo.event.connect() api.
@EventListener(targets = "link", events = "onclick")
public void chooseAlbum(int id)
{
setSelectedAlbum(ALBUMS.get(id));
getToaster().setMessage("Successfully selected album '"
+ ALBUMS.get(id).getName() + "'");
getResponse().updateComponent("albumDetail");
getResponse().updateComponent("toaster");
}
// IoC autowiring
public abstract ResponseBuilder getResponse();
..
<a jwcid="link@DirectLink" listener="listener:chooseAlbum"
parameters="ognl:album.id">
<span jwcid="@Insert" value="ognl:album.name + ' - ' + album.artist" />
</a>
Couldn't think of a good conlusion so maybe just Q&A.