Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fix for AjaxFormLoop

  • Loading branch information...
commit ec59e21df75a06561c77c37e1aca096e360843e3 1 parent 440d999
François Facon ffacon authored
153 src/main/java/org/apache/tapestry5/portlet/services/PortletModule.java 100755 → 100644
View
@@ -1,4 +1,4 @@
-// Copyright 2005 The Apache Software Foundation
+// Copyright 20012 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.
@@ -186,8 +186,7 @@ public PortletApplicationInitializer build(
@InjectService("PipelineBuilder") PipelineBuilder builder) {
PortletApplicationInitializer terminator = new PortletApplicationInitializer() {
public void initializeApplication(PortletContext context) {
- initializer.initializeApplication(new PortletContextImpl(
- context));
+ initializer.initializeApplication(new PortletContextImpl(context));
}
};
@@ -213,13 +212,10 @@ public boolean service(ActionRequest request,
String pageName = pageResolver.resolve(request);
log.info("PORTLET ACTION REQUEST HANDLER for page " + pageName);
- Request portletRequest = PortletUtilities.buildPortlet(request,
- pageName, analyzer);
- Response portletResponse = new PortletResponseImpl(response,
- portletRequest);
+ Request portletRequest = PortletUtilities.buildPortlet(request,pageName, analyzer);
+ Response portletResponse = new PortletResponseImpl(response,portletRequest);
- requestGlobals.storeRequestResponse(portletRequest,
- portletResponse);
+ requestGlobals.storeRequestResponse(portletRequest, portletResponse);
portletRequestGlobals.store(request, response);
return handler.service(portletRequest, portletResponse);
@@ -255,22 +251,15 @@ public boolean service(RenderRequest request,
PortletConstants.LAST_ACTION_EXCEPTION) != null) {
pageName = exceptionPage;
Page page = pageCache.get(exceptionPage);
- ExceptionReporter rootComponent = (ExceptionReporter) page
- .getRootComponent();
- rootComponent.reportException((Throwable) request
- .getPortletSession().getAttribute(
- PortletConstants.LAST_ACTION_EXCEPTION));
- request.getPortletSession().removeAttribute(
- PortletConstants.LAST_ACTION_EXCEPTION);
+ ExceptionReporter rootComponent = (ExceptionReporter) page.getRootComponent();
+ rootComponent.reportException((Throwable) request.getPortletSession().getAttribute(PortletConstants.LAST_ACTION_EXCEPTION));
+ request.getPortletSession().removeAttribute(PortletConstants.LAST_ACTION_EXCEPTION);
}
- Request portletRequest = PortletUtilities.buildPortlet(request,
- pageName, analyzer);
- Response portletResponse = new PortletRenderResponseImpl(
- response);
+ Request portletRequest = PortletUtilities.buildPortlet(request, pageName, analyzer);
+ Response portletResponse = new PortletRenderResponseImpl(response);
- requestGlobals.storeRequestResponse(portletRequest,
- portletResponse);
+ requestGlobals.storeRequestResponse(portletRequest, portletResponse);
portletRequestGlobals.store(request, response);
return handler.service(portletRequest, portletResponse);
@@ -296,16 +285,12 @@ public boolean service(ResourceRequest request,
ResourceResponse response) throws IOException,
PortletException {
String pageName = pageResolver.resolve(request);
- log.info("PORTLET RESSOURCES REQUEST HANDLER for page "
- + pageName);
+ log.info("PORTLET RESSOURCES REQUEST HANDLER for page " + pageName);
- Request portletRequest = PortletUtilities.buildPortlet(request,
- pageName, analyzer);
- Response portletResponse = new PortletResourceResponseImpl(
- response);
+ Request portletRequest = PortletUtilities.buildPortlet(request, pageName, analyzer);
+ Response portletResponse = new PortletResourceResponseImpl( response);
- requestGlobals.storeRequestResponse(portletRequest,
- portletResponse);
+ requestGlobals.storeRequestResponse(portletRequest,portletResponse);
portletRequestGlobals.store(request, response);
return handler.service(portletRequest, portletResponse);
@@ -340,11 +325,9 @@ public boolean service(EventRequest request, EventResponse response)
pageName + ":" + request.getEvent().getName() + "/"
+ request.getEvent().getValue().toString(),
analyzer);
- Response portletResponse = new PortletResponseImpl(response,
- portletRequest);
+ Response portletResponse = new PortletResponseImpl(response,portletRequest);
- requestGlobals.storeRequestResponse(portletRequest,
- portletResponse);
+ requestGlobals.storeRequestResponse(portletRequest, portletResponse);
portletRequestGlobals.store(request, response);
return handler.service(portletRequest, portletResponse);
@@ -445,11 +428,9 @@ public void renderMarkup(MarkupWriter writer, JSONObject reply,
String namespace = "_" + uid;
- IdAllocator idAllocator = iaFactory
- .getNewPortletIdAllocator(namespace);
+ IdAllocator idAllocator = iaFactory.getNewPortletIdAllocator(namespace);
- DocumentLinker linker = environment
- .peekRequired(DocumentLinker.class);
+ DocumentLinker linker = environment.peekRequired(DocumentLinker.class);
JavaScriptSupportImpl support = new JavaScriptSupportImpl(
linker, javascriptStackSource,
@@ -520,8 +501,7 @@ public ComponentEventRequestHandler buildPortletComponentEventRequestHandler(
public ComponentEventResultProcessor buildPorletComponentEventResultProcessor(
Map<Class, ComponentEventResultProcessor> configuration,
StrategyBuilder strategyBuilder) {
- return constructComponentEventResultProcessor(configuration,
- strategyBuilder);
+ return constructComponentEventResultProcessor(configuration,strategyBuilder);
}
/**
@@ -532,20 +512,13 @@ public ComponentEventResultProcessor buildPorletComponentEventResultProcessor(
public void contributePorletComponentEventResultProcessor(
MappedConfiguration<Class, ComponentEventResultProcessor> configuration,
final PortletRequestGlobals portletGlobals) {
- configuration.addInstance(PortletRenderable.class,
- PortletActionResultProcessor.class);
- configuration.addInstance(Event.class,
- PortletEventResultProcessor.class);
- configuration.addInstance(StreamResponse.class,
- StreamResponseResultProcessor.class);
- configuration.addInstance(Class.class,
- PortletClassResultProcessor.class);
- configuration.addInstance(String.class,
- PortletPageNameComponentEventResultProcessor.class);
- configuration.addInstance(Component.class,
- PortletComponentInstanceEventResultProcessor.class);
- configuration.addInstance(PortalPage.class,
- PortalPageNameComponentEventResultProcessor.class);
+ configuration.addInstance(PortletRenderable.class,PortletActionResultProcessor.class);
+ configuration.addInstance(Event.class,PortletEventResultProcessor.class);
+ configuration.addInstance(StreamResponse.class, StreamResponseResultProcessor.class);
+ configuration.addInstance(Class.class,PortletClassResultProcessor.class);
+ configuration.addInstance(String.class,PortletPageNameComponentEventResultProcessor.class);
+ configuration.addInstance(Component.class,PortletComponentInstanceEventResultProcessor.class);
+ configuration.addInstance(PortalPage.class,PortalPageNameComponentEventResultProcessor.class);
/**
* Explicit redirect is done through URL
@@ -561,15 +534,12 @@ public void processResultValue(URL value) throws IOException {
new ComponentEventResultProcessor<Link>() {
public void processResultValue(Link value)
throws IOException {
- StateAwareResponse response = (StateAwareResponse) portletGlobals
- .getPortletResponse();
+ StateAwareResponse response = (StateAwareResponse) portletGlobals.getPortletResponse();
for (String name : value.getParameterNames()) {
response.setRenderParameter(name,
value.getParameterValue(name));
}
- response.setRenderParameter(
- PortletConstants.PORTLET_PAGE, PortletUtilities
- .stripQueryString(value.toURI()));
+ response.setRenderParameter(PortletConstants.PORTLET_PAGE, PortletUtilities.stripQueryString(value.toURI()));
}
});
@@ -694,52 +664,36 @@ public static void contributePortletResourceResponseIdentifier(
Configuration<DeclaredResourceResponseSender> configuration) {
// declare core component that will return resource response form ajax
// call
- configuration.add(new DeclaredResourceResponseSender(DateField.class
- .getName()));
- configuration.add(new DeclaredResourceResponseSender(FormInjector.class
- .getName()));
- configuration.add(new DeclaredResourceResponseSender(BeanEditForm.class
- .getName()));
+ configuration.add(new DeclaredResourceResponseSender(DateField.class.getName()));
+ configuration.add(new DeclaredResourceResponseSender(FormInjector.class.getName()));
+ configuration.add(new DeclaredResourceResponseSender(BeanEditForm.class.getName()));
// ajaxFormLoop
- DeclaredResourceResponseSender ajaxFormLoop = new DeclaredResourceResponseSender(
- AjaxFormLoop.class.getName());
- ajaxFormLoop.addEvent(EventConstants.ADD_ROW);
- ajaxFormLoop.addEvent(EventConstants.REMOVE_ROW);
+ DeclaredResourceResponseSender ajaxFormLoop = new DeclaredResourceResponseSender(
+ AjaxFormLoop.class.getName());
+ ajaxFormLoop.addEvent(EventConstants.ADD_ROW);
+ ajaxFormLoop.addEvent(EventConstants.REMOVE_ROW);
+ ajaxFormLoop.addEvent("triggerRemoveRow"); //See AjaxFormLoop.formLoopContext for more details
configuration.add(ajaxFormLoop);
// declare core mixin that will return resource response form ajax call
- configuration.add(new DeclaredResourceResponseSender(Autocomplete.class
- .getName(), true));
+ configuration.add(new DeclaredResourceResponseSender(Autocomplete.class.getName(), true));
// declare tapestry-jquery component that will return resource response
// form ajax call
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.components.AjaxUpload"));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.components.CarouselItem"));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.components.DataTable"));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.components.DialogAjaxLink"));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.components.InPlaceEditor"));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.components.ProgressiveDisplay"));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.components.RangeSlider"));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.components.Slider"));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.components.Tabs"));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.components.TwitterView"));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.components.AjaxUpload"));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.components.CarouselItem"));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.components.DataTable"));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.components.DialogAjaxLink"));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.components.InPlaceEditor"));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.components.ProgressiveDisplay"));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.components.RangeSlider"));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.components.Slider"));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.components.Tabs"));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.components.TwitterView"));
// declare tapestry-jquery mixin that will return resource response form
// ajax call
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.mixins.Autocomplete", true));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.mixins.ZoneDroppable", true));
- configuration.add(new DeclaredResourceResponseSender(
- "org.got5.tapestry5.jquery.mixins.ZoneRefresh", true));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.mixins.Autocomplete", true));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.mixins.ZoneDroppable", true));
+ configuration.add(new DeclaredResourceResponseSender("org.got5.tapestry5.jquery.mixins.ZoneRefresh", true));
// for page or mixin like org.got5.tapestry5.jquery.mixins.Bind you have
// to declare the full pagename
// and the eventname that should be treat as resource URL
@@ -758,10 +712,9 @@ public static void contributePortletResourceResponseIdentifier(
public void contributePersistentFieldManager(
MappedConfiguration<String, PersistentFieldStrategy> configuration,
@InjectService("PortletRequestGlobals") PortletRequestGlobals globals) {
- configuration.add(
- PortletPersistenceConstants.PORTLET_SESSION_APPLICATION_SCOPE,
+ configuration.add(PortletPersistenceConstants.PORTLET_SESSION_APPLICATION_SCOPE,
new PortletApplicationScopePersistentFieldStrategy(globals));
}
-}
+}
26 src/main/webapp/WEB-INF/plugin-web-testng.xml
View
@@ -129,6 +129,24 @@
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
+<servlet-name>Grid</servlet-name>
+<servlet-class>org.apache.pluto.container.driver.PortletServlet</servlet-class>
+<init-param>
+<param-name>portlet-name</param-name>
+<param-value>Grid</param-value>
+</init-param>
+<load-on-startup>1</load-on-startup>
+</servlet>
+<servlet>
+<servlet-name>AjaxFormLoopExample</servlet-name>
+<servlet-class>org.apache.pluto.container.driver.PortletServlet</servlet-class>
+<init-param>
+<param-name>portlet-name</param-name>
+<param-value>AjaxFormLoopExample</param-value>
+</init-param>
+<load-on-startup>1</load-on-startup>
+</servlet>
+<servlet>
<servlet-name>AboutPortlet</servlet-name>
<servlet-class>org.apache.pluto.container.driver.PortletServlet</servlet-class>
<init-param>
@@ -198,6 +216,14 @@
<url-pattern>/PlutoInvoker/About</url-pattern>
</servlet-mapping>
<servlet-mapping>
+<servlet-name>Grid</servlet-name>
+<url-pattern>/PlutoInvoker/Grid</url-pattern>
+</servlet-mapping>
+<servlet-mapping>
+<servlet-name>AjaxFormLoopExample</servlet-name>
+<url-pattern>/PlutoInvoker/AjaxFormLoopExample</url-pattern>
+</servlet-mapping>
+<servlet-mapping>
<servlet-name>AboutPortlet</servlet-name>
<url-pattern>/PlutoInvoker/AboutPortlet</url-pattern>
</servlet-mapping>
7 src/main/webapp/WEB-INF/plugin-web.xml
View
@@ -128,6 +128,13 @@
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
+<servlet-class>org.apache.pluto.container.driver.PortletServlet</servlet-class>
+<init-param>
+<param-name>portlet-name</param-name>
+<param-value>Grid</param-value>
+</init-param>
+<load-on-startup>1</load-on-startup>
+</servlet>
<servlet>
<servlet-name>AboutPortlet</servlet-name>
<servlet-class>org.apache.pluto.container.driver.PortletServlet</servlet-class>
2  src/main/webapp/WEB-INF/pluto-portal-driver-config.xml
View
@@ -54,10 +54,12 @@ limitations under the License.
<page name="About" uri="/WEB-INF/themes/pluto-default-theme.jsp">
<portlet context="/tapestry5-portlet" name="About"/>
<portlet context="/tapestry5-portlet" name="EventReceiver"/>
+ <portlet context="/tapestry5-portlet" name="AjaxFormLoopExample"/>
</page>
<page name="Grid" uri="/WEB-INF/themes/pluto-default-theme.jsp">
<portlet context="/tapestry5-portlet" name="Grid"/>
<portlet context="/tapestry5-portlet" name="Grid"/>
+ <portlet context="/tapestry5-portlet" name="About"/>
</page>
</render-config>
18 src/main/webapp/WEB-INF/portlet.xml
View
@@ -82,6 +82,24 @@
<value>true</value>
</container-runtime-option>
</portlet>
+
+ <portlet>
+ <portlet-name>AjaxFormLoopExample</portlet-name>
+ <portlet-class>org.apache.tapestry5.portlet.ApplicationPortlet</portlet-class>
+ <supports>
+ <mime-type>text/html</mime-type>
+ <portlet-mode>VIEW</portlet-mode>
+ </supports>
+ <portlet-info>
+ <title>Tapestry Porlet AjaxFormLoop</title>
+ <short-title>T5 Portlet AjaxFormLoop</short-title>
+ <keywords>Portlet Tapestry AjaxFormLoop</keywords>
+ </portlet-info>
+ <container-runtime-option>
+ <name>javax.portlet.renderHeaders</name>
+ <value>true</value>
+ </container-runtime-option>
+ </portlet>
<portlet>
<description>AboutPortletDescription</description>
69 src/test/java/org/apache/tapestry5/portlet/IndexPortletTests.java
View
@@ -19,6 +19,8 @@
import org.apache.tapestry5.test.SeleniumTestCase;
import org.testng.annotations.Test;
+import com.thoughtworks.selenium.Wait;
+
/**
* Tests related to the Index Portlet.
*/
@@ -26,7 +28,8 @@
{
String indexLocation = "/tapestry5-portlet/portal/Index";
String AboutLocation = "/tapestry5-portlet/portal/About";
-
+ String GridLocation = "/tapestry5-portlet/portal/Grid";
+
@Test
public void PublishEvent()
{
@@ -105,8 +108,10 @@ public void cookies_test()
{
open(AboutLocation);
+ waitForPageToLoad();
click("link=resetCount");
- waitForAjaxRequestsToComplete("1000");
+ waitForPageToLoad();
+ //waitForAjaxRequestsToComplete("1000");
assertTextPresent("nb view = 1");
open(AboutLocation);
@@ -114,4 +119,64 @@ public void cookies_test()
}
+
+ @Test
+ public void AjaxFormLoop_test()
+ {
+ String InputName = "//input[starts-with(@id,'nom')]";
+ String InputId = "//input[starts-with(@id,'id')]";
+ String addRow = "//*[starts-with(@id,'addrowlink')]";
+ String textarea = "//textarea[starts-with(@id,'texte')]";
+
+ open(AboutLocation);
+
+
+ new Wait()
+ {
+ @Override
+ public boolean until()
+ {
+ return getXpathCount("//input[contains(@id,'nom')]").equals(1);
+ }
+ }.wait("We should have just one input with id nom.", 1000);
+
+
+ type(InputName, "AjaxFormLoop");
+
+ click("xpath=//a[contains(@id,'addrowlink')]");
+
+
+ new Wait()
+ {
+ @Override
+ public boolean until()
+ {
+ return getXpathCount("//fieldset[starts-with(@id,'rowInjector_')]").equals(1);
+ }
+ }.wait("We should have just one row.", 1000);
+
+
+ type(InputId, "1");
+ type(textarea, "MyAjaxFormLoopTexte");
+ click("//input[starts-with(@id,'save')]");
+ waitForPageToLoad();
+
+ assertTextPresent("MyAjaxFormLoopTexte");
+
+
+ click("xpath=//a[contains(@id,'removerowlink')]");
+
+ new Wait()
+ {
+ @Override
+ public boolean until()
+ {
+ return getXpathCount("//fieldset[starts-with(@id,'rowInjector_')]").equals(0);
+ }
+ }.wait("The first row should be deleted.", 1000);
+
+
+
+ }
+
}
23 src/test/java/org/apache/tapestry5/portlet/model/ListObject.java
View
@@ -0,0 +1,23 @@
+package org.apache.tapestry5.portlet.model;
+
+public class ListObject {
+ private Long id;
+ private String texte;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getTexte() {
+ return texte;
+ }
+
+ public void setTexte(String texte) {
+ this.texte = texte;
+ }
+
+}
27 src/test/java/org/apache/tapestry5/portlet/model/ModelObject.java
View
@@ -0,0 +1,27 @@
+package org.apache.tapestry5.portlet.model;
+
+import java.util.List;
+
+public class ModelObject {
+
+ private String nom;
+
+ private List<ListObject> items;
+
+ public String getNom() {
+ return nom;
+ }
+
+ public void setNom(String nom) {
+ this.nom = nom;
+ }
+
+ public List<ListObject> getItems() {
+ return items;
+ }
+
+ public void setItems(List<ListObject> items) {
+ this.items = items;
+ }
+
+}
72 src/test/java/org/apache/tapestry5/portlet/pages/AjaxFormLoopExample.java
View
@@ -0,0 +1,72 @@
+package org.apache.tapestry5.portlet.pages;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tapestry5.EventConstants;
+import org.apache.tapestry5.ValueEncoder;
+import org.apache.tapestry5.annotations.OnEvent;
+import org.apache.tapestry5.annotations.Persist;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.annotations.SetupRender;
+import org.apache.tapestry5.portlet.model.ListObject;
+import org.apache.tapestry5.portlet.model.ModelObject;
+
+
+
+
+public class AjaxFormLoopExample {
+
+ @Persist
+ @Property
+ private ModelObject modelObject;
+
+ @Property
+ private ListObject currentItem;
+
+ @SetupRender
+ public void initForm() {
+ if (modelObject == null) {
+ modelObject = new ModelObject();
+ List<ListObject> items = new ArrayList<ListObject>();
+ modelObject.setItems(items);
+ }
+ }
+
+ @OnEvent(value = "addRow", component = "items")
+ private Object ajouteCommentaire() {
+ ListObject item = new ListObject();
+ modelObject.getItems().add(item);
+ return item;
+ }
+
+ @OnEvent(value = "removeRow", component = "items")
+ private void supprimeCommentaire(ListObject item) {
+ int index = modelObject.getItems().indexOf(item);
+ if(index!=-1) modelObject.getItems().remove(index);
+ }
+
+ @OnEvent(value = EventConstants.SUCCESS, component = "exampleForm")
+ public void enregistrerForm() {
+ System.out.println(">> Enregistrement du formulaire");
+ System.out.println(">> Nom = " + modelObject.getNom());
+ for (ListObject item : modelObject.getItems()) {
+ if(item!=null)
+ System.out.println(">> Item = " + item.getId() + " ; " + item.getTexte());
+
+ }
+ }
+
+ public ValueEncoder<ListObject> getEncoder() {
+ return new ValueEncoder<ListObject>() {
+
+ public String toClient(ListObject value) {
+ return String.valueOf(modelObject.getItems().indexOf(value));
+ }
+
+ public ListObject toValue(String clientValue) {
+ return modelObject.getItems().get(Integer.parseInt(clientValue));
+ }
+ };
+ }
+}
0  src/main/resources/log4j.properties → src/test/resources/log4j.properties 100755 → 100644
View
File renamed without changes
32 src/test/resources/org/apache/tapestry5/portlet/pages/AjaxFormLoopExample.tml
View
@@ -0,0 +1,32 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter">
+
+<body>
+ <t:form t:id="exampleForm" t:clientValidation="none">
+ <p>
+ <t:errors />
+ <t:label for="nom" />
+ <t:textfield t:id="nom" value="modelObject.nom" validate="required,maxLength=100"/>
+ </p>
+ <fieldset t:type="ajaxformloop" t:id="items" source="modelObject.items"
+ value="currentItem" formState="none" encoder="encoder">
+ <p>
+ <t:label for="id" />
+ <t:textfield t:id="id" value="currentItem.id"
+ type="number" min="0" validate="required" />
+ </p>
+ <p>
+ <t:label for="texte" />
+ <t:textarea t:id="texte" value="currentItem.texte"
+ validate="required,maxLength=500" />
+ </p>
+ <p>
+ <t:removerowlink>Supprimer cet item</t:removerowlink>
+ </p>
+ </fieldset>
+ <p>
+ <input t:type="submit" t:id="save" value="Enregistrer" />
+ </p>
+ </t:form>
+
+</body>
+</html>
Please sign in to comment.
Something went wrong with that request. Please try again.