To build a SPA application using Tapestry we can use the Zone's system. You have to keep in mind:
public class MyLinkTransformer implements PageRenderLinkTransformer {
...
@Override
public PageRenderRequestParameters decodePageRenderRequest(final Request request) {
...
final int spaIndex = requestPath.indexOf("/spa/");
if (spaIndex != -1) {
final String page = requestPath.substring(spaIndex + 5) + "page";
String enumPage = null;
for (final PAGES p : PAGES.values()) {
if (p.getPageClass().getSimpleName().toLowerCase().equals(page)) {
enumPage = p.toString();
break;
}
}
if (enumPage != null) {
return new PageRenderRequestParameters("specialPages/spa/Index",
new URLEventContext(contextValueEncoder, new String[] { enumPage }),
false);
}
}
...
}
}package es.carlosmontero.webapp.t5devutil.pages.specialpages.spa;
import org.apache.tapestry5.Block;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.InjectComponent;
import org.apache.tapestry5.annotations.InjectPage;
import org.apache.tapestry5.corelib.components.Zone;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.PageRenderLinkSource;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
import org.apache.tapestry5.services.ajax.JavaScriptCallback;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
public class IndexPage {
public enum PAGES {
PAGE1(Block1Page.class), PAGE2(Block2Page.class), PAGE3(Block3Page.class);
private final Class<?> clazz;
private PAGES(final Class<?> clazz) {
this.clazz = clazz;
}
public Class<?> getPageClass() {
return clazz;
}
}
@Environmental
private JavaScriptSupport javaScriptSupport;
@Inject
private PageRenderLinkSource pageRenderLinkSource;
@Inject
private AjaxResponseRenderer ajaxResponseRenderer;
@Inject
private ComponentResources componentResources;
@Inject
private Request request;
@InjectPage
private Block1Page block1;
@InjectPage
private Block2Page block2;
@InjectPage
private Block3Page block3;
@InjectComponent
private Zone contentZone;
private PAGES activePage;
public void onActivate(final PAGES page) {
activePage = page;
}
public Block getContentBlock() {
if (activePage == null) {
activePage = PAGES.PAGE1;
}
switch (activePage) {
case PAGE1:
return block1.getMainBlock();
case PAGE2:
return block2.getMainBlock();
case PAGE3:
return block3.getMainBlock();
}
return null;
}
public Object onBack(final PAGES page) {
if (request.isXHR()) {
activePage = page;
ajaxResponseRenderer.addRender(contentZone);
return null;
}
else {
return page.getPageClass();
}
}
public void onChangePage(final PAGES page) {
activePage = page;
ajaxResponseRenderer.addRender(contentZone);
ajaxResponseRenderer.addCallback(new JavaScriptCallback() {
@Override
public void run(final JavaScriptSupport javascriptSupport) {
final String restoreUrl = componentResources.createEventLink("back", page).toAbsoluteURI();
final String newUrl = pageRenderLinkSource.createPageRenderLink(page.getPageClass()).toAbsoluteURI();
javascriptSupport.require("spa").invoke("selectpage")
.with(
restoreUrl,
page + " title",
newUrl
);
}
});
}
public void setupRender() {
javaScriptSupport.require("spa").invoke("init");
}
}