Author: drobiazko Date: Thu Jun 16 20:49:21 2011 New Revision: 1136668 URL: http://svn.apache.org/viewvc?rev=1136668&view=rev Log: TAP5-1550: Provide a multiple selection component that renders check boxes for available selection options
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Checklist.java (with props) tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Checklist.tml tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ChecklistDemo.tml tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ChecklistDemo.java (with props) Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/default.css tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/FormTests.java tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Checklist.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Checklist.java?rev=1136668&view=auto ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Checklist.java (added) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Checklist.java Thu Jun 16 20:49:21 2011 @@ -0,0 +1,190 @@ +package org.apache.tapestry5.corelib.components; + +import org.apache.tapestry5.*; +import org.apache.tapestry5.annotations.Environmental; +import org.apache.tapestry5.annotations.Parameter; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.corelib.base.AbstractField; +import org.apache.tapestry5.dom.Element; +import org.apache.tapestry5.ioc.annotations.Inject; +import org.apache.tapestry5.ioc.internal.util.CollectionFactory; +import org.apache.tapestry5.services.ComponentDefaultProvider; +import org.apache.tapestry5.services.Request; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public class Checklist extends AbstractField +{ + + /** + * Model used to define the values and labels used when rendering the + * checklist. + */ + @Parameter(required = true) + private SelectModel model; + + /** + * The list of selected values from the + * {@link org.apache.tapestry5.SelectModel}. This will be updated when the + * form is submitted. If the value for the parameter is null, a new list + * will be created, otherwise the existing list will be cleared. If unbound, + * defaults to a property of the container matching this component's id. + */ + @Parameter(required = true, autoconnect = true) + private List<Object> selected; + + /** + * Encoder used to translate between server-side objects and client-side + * strings. + */ + @Parameter(required = true, allowNull = false) + private ValueEncoder<Object> encoder; + + /** + * The object that will perform input validation. The validate binding prefix is generally used to provide + * this object in a declarative fashion. + */ + @Parameter(defaultPrefix = BindingConstants.VALIDATE) + @SuppressWarnings("unchecked") + private FieldValidator<Object> validate; + + @Inject + private Request request; + + @Inject + private FieldValidationSupport fieldValidationSupport; + + @Environmental + private ValidationTracker tracker; + + @Inject + private ComponentResources componentResources; + + @Inject + private ComponentDefaultProvider defaultProvider; + + @Property + private List<Renderable> availableOptions; + + private MarkupWriter markupWriter; + + private final class RenderRadio implements Renderable + { + private final OptionModel model; + + private RenderRadio(final OptionModel model) + { + this.model = model; + } + + public void render(MarkupWriter writer) + { + writer.element("label"); + writer.write(model.getLabel()); + writer.end(); + + final String clientValue = encoder.toClient(model.getValue()); + + final Element checkbox = writer.element("input", "type", "checkbox", "name", getControlName(), "value", clientValue); + + if (getSelected().contains(model.getValue())) + { + checkbox.attribute("checked", "checked"); + } + writer.end(); + } + } + + void setupRender(final MarkupWriter writer) + { + markupWriter = writer; + + availableOptions = CollectionFactory.newList(); + + final SelectModelVisitor visitor = new SelectModelVisitor() + { + public void beginOptionGroup(final OptionGroupModel groupModel) + { + } + + public void option(final OptionModel optionModel) + { + availableOptions.add(new RenderRadio(optionModel)); + } + + public void endOptionGroup(final OptionGroupModel groupModel) + { + } + + }; + + model.visit(visitor); + } + + @Override + protected void processSubmission(final String elementName) + { + + final String[] parameters = request.getParameters(elementName); + + List<Object> selected = this.selected; + + if (selected == null) + { + selected = CollectionFactory.newList(); + } else + { + selected.clear(); + } + + if (parameters != null) + { + for (final String value : parameters) + { + final Object objectValue = encoder.toValue(value); + + selected.add(objectValue); + } + + } + + try + { + this.fieldValidationSupport.validate(selected, this.componentResources, this.validate); + + this.selected = selected; + } catch (final ValidationException e) + { + this.tracker.recordError(this, e.getMessage()); + } + } + + Set<Object> getSelected() + { + if (selected == null) + { + return Collections.emptySet(); + } + + return CollectionFactory.newSet(selected); + } + + /** + * Computes a default value for the "validate" parameter using + * {@link org.apache.tapestry5.services.FieldValidatorDefaultSource}. + */ + + Binding defaultValidate() + { + return this.defaultProvider.defaultValidatorBinding("selected", this.componentResources); + } + + @Override + public boolean isRequired() + { + return validate.isRequired(); + } +} + Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Checklist.java ------------------------------------------------------------------------------ svn:eol-style = native Added: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Checklist.tml URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Checklist.tml?rev=1136668&view=auto ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Checklist.tml (added) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Checklist.tml Thu Jun 16 20:49:21 2011 @@ -0,0 +1,5 @@ +<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"> + <div t:type="loop" source="availableOptions" value="var:currentOption" class="t-checklist-row"> + <t:delegate to="var:currentOption"/> + </div> +</t:container> \ No newline at end of file Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/default.css URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/default.css?rev=1136668&r1=1136667&r2=1136668&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/default.css (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/default.css Thu Jun 16 20:49:21 2011 @@ -205,6 +205,20 @@ DIV.t-beaneditor-row LABEL { vertical-align: middle; } +DIV.t-checklist-row { + padding: 4px 0px 2px 0px; +} + +DIV.t-checklist-row LABEL { + width: 150px; + display: block; + float: left; + text-align: right; + clear: left; + padding-right: 3px; + vertical-align: middle; +} + INPUT.t-number { text-align: right; } Added: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ChecklistDemo.tml URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ChecklistDemo.tml?rev=1136668&view=auto ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ChecklistDemo.tml (added) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/ChecklistDemo.tml Thu Jun 16 20:49:21 2011 @@ -0,0 +1,20 @@ +<t:border xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"> + <t:form clientValidation="false"> + <p> + <t:errors /> + </p> + <p> + <t:label for="selected" /> + : + <t:checklist t:id="selected" validate="required" model="literal:Red,Green,Blue" encoder="encoder" label="Color"/> + + </p> + + <p> + <t:submit value="literal:Submit" /> + </p> + </t:form> + + <p>Selected colors: ${sorted}</p> + +</t:border> \ No newline at end of file Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/FormTests.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/FormTests.java?rev=1136668&r1=1136667&r2=1136668&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/FormTests.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/FormTests.java Thu Jun 16 20:49:21 2011 @@ -937,4 +937,32 @@ public class FormTests extends TapestryC assertTextPresent("Password: ab"); assertTextPresent("Password2: xyz"); } + + @Test + public void checklist_select() throws Exception + { + openLinks("Checklist Demo"); + + clickAndWait(SUBMIT); + assertTextPresent("You must provide a value for Color."); + + check("//input[@value='Green']"); + + clickAndWait(SUBMIT); + + assertTextPresent("Selected colors: [Green]"); + + check("//input[@value='Red']"); + + clickAndWait(SUBMIT); + + assertTextPresent("Selected colors: [Green, Red]"); + + check("//input[@value='Blue']"); + uncheck("//input[@value='Green']"); + + clickAndWait(SUBMIT); + + assertTextPresent("Selected colors: [Blue, Red]"); + } } Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ChecklistDemo.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ChecklistDemo.java?rev=1136668&view=auto ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ChecklistDemo.java (added) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ChecklistDemo.java Thu Jun 16 20:49:21 2011 @@ -0,0 +1,34 @@ +package org.apache.tapestry5.integration.app1.pages; + +import org.apache.tapestry5.ValueEncoder; +import org.apache.tapestry5.annotations.Persist; +import org.apache.tapestry5.annotations.Property; +import org.apache.tapestry5.internal.services.StringValueEncoder; +import org.apache.tapestry5.ioc.internal.util.CollectionFactory; + +import java.util.Collections; +import java.util.List; + +public class ChecklistDemo +{ + @Property + @Persist + private List<String> selected; + + public ValueEncoder getEncoder() + { + return new StringValueEncoder(); + } + + public List<String> getSorted() + { + if(selected == null) + return null; + + final List<String> result = CollectionFactory.newList(selected); + + Collections.sort(result); + + return result; + } +} Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ChecklistDemo.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java?rev=1136668&r1=1136667&r2=1136668&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java Thu Jun 16 20:49:21 2011 @@ -472,7 +472,10 @@ public class Index new Item("AtInjectDemo", "@javax.inject.Inject Demo", "Using @javax.inject.Inject for injection"), new Item("LinkQueryParameters", "Link Query Parameters Demo", - "Providing Query Parameters directly to link components as a map of key=parameter name, value=parameter values") + "Providing Query Parameters directly to link components as a map of key=parameter name, value=parameter values") , + + new Item("ChecklistDemo", "Checklist Demo", + "Use Checklist component") );