You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2008/01/19 01:27:23 UTC
svn commit: r613323 - in /tapestry/tapestry5/trunk/tapestry-core/src:
main/java/org/apache/tapestry/corelib/base/
main/java/org/apache/tapestry/corelib/components/
main/java/org/apache/tapestry/internal/util/
main/java/org/apache/tapestry/test/ test/ja...
Author: hlship
Date: Fri Jan 18 16:27:22 2008
New Revision: 613323
URL: http://svn.apache.org/viewvc?rev=613323&view=rev
Log:
TAPESTRY-1941: ValidationTracker retaining field values inconsistently
Added:
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/corelib/components/current_selection_from_validation_tracker.txt
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/DateField.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Radio.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/RadioGroup.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/util/SelectModelRenderer.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java?rev=613323&r1=613322&r2=613323&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java Fri Jan 18 16:27:22 2008
@@ -26,25 +26,23 @@
import java.io.Serializable;
/**
- * Provides initialization of the clientId and elementName properties. In addition, adds the
- * {@link RenderInformals}, {@link RenderDisabled} and {@link DiscardBody} mixins.
+ * Provides initialization of the clientId and elementName properties. In addition, adds the {@link RenderInformals},
+ * {@link RenderDisabled} and {@link DiscardBody} mixins.
*/
@SupportsInformalParameters
public abstract class AbstractField implements Field
{
/**
- * The user presentable label for the field. If not provided, a reasonable label is generated
- * from the component's id, first by looking for a message key named "id-label" (substituting
- * the component's actual id), then by converting the actual id to a presentable string (for
- * example, "userId" to "User Id").
+ * The user presentable label for the field. If not provided, a reasonable label is generated from the component's
+ * id, first by looking for a message key named "id-label" (substituting the component's actual id), then by
+ * converting the actual id to a presentable string (for example, "userId" to "User Id").
*/
@Parameter(defaultPrefix = "literal")
private String _label;
/**
- * If true, then the field will render out with a disabled attribute (to turn off client-side
- * behavior). Further, a disabled field ignores any value in the request when the form is
- * submitted.
+ * If true, then the field will render out with a disabled attribute (to turn off client-side behavior). Further, a
+ * disabled field ignores any value in the request when the form is submitted.
*/
@Parameter("false")
private boolean _disabled;
@@ -101,12 +99,11 @@
private static final ProcessSubmissionAction PROCESS_SUBMISSION_ACTION = new ProcessSubmissionAction();
/**
- * The id used to generate a page-unique client-side identifier for the component. If a
- * component renders multiple times, a suffix will be appended to the to id to ensure
- * uniqueness. The uniqued value may be accessed via the
+ * The id used to generate a page-unique client-side identifier for the component. If a component renders multiple
+ * times, a suffix will be appended to the to id to ensure uniqueness. The uniqued value may be accessed via the
* {@link #getClientId() clientId property}.
*/
- @Parameter(value = "prop:componentResources.id", defaultPrefix = "literal")
+ @Parameter(value = "prop:componentResources.id", defaultPrefix = TapestryConstants.LITERAL_BINDING_PREFIX)
private String _clientId;
private String _assignedClientId;
@@ -183,11 +180,9 @@
}
/**
- * Used by subclasses to create a default binding to a property of the container matching the
- * component id.
+ * Used by subclasses to create a default binding to a property of the container matching the component id.
*
- * @return a binding to the property, or null if the container does not have a corresponding
- * property
+ * @return a binding to the property, or null if the container does not have a corresponding property
*/
protected final Binding createDefaultParameterBinding(String parameterName)
{
@@ -195,9 +190,9 @@
}
/**
- * Method implemented by subclasses to actually do the work of processing the submission of the
- * form. The element's elementName property will already have been set. This method is only
- * invoked if the field is <strong>not {@link #isDisabled() disabled}</strong>.
+ * Method implemented by subclasses to actually do the work of processing the submission of the form. The element's
+ * elementName property will already have been set. This method is only invoked if the field is <strong>not {@link
+ * #isDisabled() disabled}</strong>.
*
* @param elementName the name of the element (used to find the correct parameter in the request)
*/
@@ -213,8 +208,7 @@
}
/**
- * Allows the validation decorator to write markup after the field has written all of its
- * markup.
+ * Allows the validation decorator to write markup after the field has written all of its markup.
*/
@AfterRender
final void afterDecorator()
@@ -223,9 +217,8 @@
}
/**
- * Invoked from subclasses after they have written their tag and (where appropriate) their
- * informal parameters <em>and</em> have allowed their {@link Validator} to write markup as
- * well.
+ * Invoked from subclasses after they have written their tag and (where appropriate) their informal parameters
+ * <em>and</em> have allowed their {@link Validator} to write markup as well.
*/
protected final void decorateInsideField()
{
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java?rev=613323&r1=613322&r2=613323&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Checkbox.java Fri Jan 18 16:27:22 2008
@@ -17,10 +17,8 @@
import org.apache.tapestry.Binding;
import org.apache.tapestry.ComponentResources;
import org.apache.tapestry.MarkupWriter;
-import org.apache.tapestry.annotations.AfterRender;
-import org.apache.tapestry.annotations.BeginRender;
-import org.apache.tapestry.annotations.Mixin;
-import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.ValidationTracker;
+import org.apache.tapestry.annotations.*;
import org.apache.tapestry.corelib.base.AbstractField;
import org.apache.tapestry.corelib.mixins.RenderDisabled;
import org.apache.tapestry.ioc.annotations.Inject;
@@ -39,8 +37,8 @@
private RenderDisabled _renderDisabled;
/**
- * The value to be read or updated. If not bound, the Checkbox will attempt to edit a property
- * of its container whose name matches the component's id.
+ * The value to be read or updated. If not bound, the Checkbox will attempt to edit a property of its container
+ * whose name matches the component's id.
*/
@Parameter(required = true)
private boolean _value;
@@ -48,6 +46,9 @@
@Inject
private ComponentResources _resources;
+ @Environmental
+ private ValidationTracker _tracker;
+
Binding defaultValue()
{
return createDefaultParameterBinding("value");
@@ -56,13 +57,17 @@
@BeginRender
void begin(MarkupWriter writer)
{
+ String asSubmitted = _tracker.getInput(this);
+
+ boolean checked = asSubmitted != null ? Boolean.parseBoolean(asSubmitted) : _value;
+
writer.element("input", "type", "checkbox",
"name", getElementName(),
"id", getClientId(),
- "checked", _value ? "checked" : null);
+ "checked", checked ? "checked" : null);
_resources.renderInformalParameters(writer);
@@ -79,6 +84,10 @@
protected void processSubmission(String elementName)
{
String postedValue = _request.getParameter(elementName);
+
+ // record as "true" or "false"
+
+ _tracker.recordInput(this, Boolean.toString(postedValue != null));
_value = postedValue != null;
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/DateField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/DateField.java?rev=613323&r1=613322&r2=613323&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/DateField.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/DateField.java Fri Jan 18 16:27:22 2008
@@ -49,8 +49,8 @@
private String _format = "%m/%d/%y";
/**
- * The object that will perform input validation (which occurs after translation). The translate
- * binding prefix is generally used to provide this object in a declarative fashion.
+ * The object that will perform input validation (which occurs after translation). The translate binding prefix is
+ * generally used to provide this object in a declarative fashion.
*/
@Parameter(defaultPrefix = "validate")
@SuppressWarnings("unchecked")
@@ -58,8 +58,8 @@
/**
- * If true, then the client-side calendar will show the time as well as the date. You will probably
- * need to bind the format parameter as well when this is true, say to <code>%m/%d/%y %H:%M</code>.
+ * If true, then the client-side calendar will show the time as well as the date. You will probably need to bind
+ * the format parameter as well when this is true, say to <code>%m/%d/%y %H:%M</code>.
*/
@Parameter
private boolean _editTime;
@@ -113,9 +113,12 @@
@Inject
private FieldValidatorDefaultSource _fieldValidatorDefaultSource;
+ @Inject
+ private FieldValidationSupport _fieldValidationSupport;
+
/**
- * The default value is a property of the container whose name matches the component's id. May
- * return null if the container does not have a matching property.
+ * The default value is a property of the container whose name matches the component's id. May return null if the
+ * container does not have a matching property.
*/
final Binding defaultValue()
{
@@ -123,8 +126,7 @@
}
/**
- * Computes a default value for the "validate" parameter using
- * {@link FieldValidatorDefaultSource}.
+ * Computes a default value for the "validate" parameter using {@link FieldValidatorDefaultSource}.
*/
final FieldValidator defaultValidate()
{
@@ -212,10 +214,9 @@
}
/**
- * Invoked to allow subclasses to further configure the parameters passed to the JavaScript
- * Calendar.setup() function. The values inputField, ifFormat and button are pre-configured.
- * Subclasses may override this method to configure additional features of the client-side
- * Calendar. This implementation does nothing.
+ * Invoked to allow subclasses to further configure the parameters passed to the JavaScript Calendar.setup()
+ * function. The values inputField, ifFormat and button are pre-configured. Subclasses may override this method to
+ * configure additional features of the client-side Calendar. This implementation does nothing.
*
* @param setup parameters object
*/
@@ -224,7 +225,7 @@
}
- String formatCurrentValue()
+ private String formatCurrentValue()
{
if (_value == null) return "";
@@ -234,26 +235,33 @@
@Override
protected void processSubmission(String elementName)
{
- // TODO: Validation
-
String value = _request.getParameter(elementName);
- if (InternalUtils.isBlank(value))
- {
- _value = null;
- return;
- }
+ _tracker.recordInput(this, value);
+
+ Date parsedValue = null;
try
{
- _value = toJavaDateFormat().parse(value);
+ if (InternalUtils.isNonBlank(value)) parsedValue = toJavaDateFormat().parse(value);
}
catch (ParseException ex)
{
_tracker.recordError(this, "Date value is not parseable.");
+ return;
}
+ try
+ {
+ _fieldValidationSupport.validate(parsedValue, _resources, _validate);
+
+ _value = parsedValue;
+ }
+ catch (ValidationException ex)
+ {
+ _tracker.recordError(this, ex.getMessage());
+ }
}
SimpleDateFormat toJavaDateFormat()
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Radio.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Radio.java?rev=613323&r1=613322&r2=613323&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Radio.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Radio.java Fri Jan 18 16:27:22 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -25,11 +25,11 @@
import org.apache.tapestry.services.ComponentDefaultProvider;
/**
- * A radio button (i.e., <input type="radio">). Radio buttons <strong>must</strong> operate
- * within a {@link RadioContainer} (normally, the {@link RadioGroup} component).
+ * A radio button (i.e., <input type="radio">). Radio buttons <strong>must</strong> operate within a {@link
+ * RadioContainer} (normally, the {@link RadioGroup} component).
* <p/>
- * If the value parameter is not bound, then the default value is a property of the container
- * component whose name matches the Radio component's id.
+ * If the value parameter is not bound, then the default value is a property of the container component whose name
+ * matches the Radio component's id.
*/
public class Radio implements Field
{
@@ -37,18 +37,16 @@
private RadioContainer _container;
/**
- * The user presentable label for the field. If not provided, a reasonable label is generated
- * from the component's id, first by looking for a message key named "id-label" (substituting
- * the component's actual id), then by converting the actual id to a presentable string (for
- * example, "userId" to "User Id").
+ * The user presentable label for the field. If not provided, a reasonable label is generated from the component's
+ * id, first by looking for a message key named "id-label" (substituting the component's actual id), then by
+ * converting the actual id to a presentable string (for example, "userId" to "User Id").
*/
- @Parameter(defaultPrefix = "literal")
+ @Parameter(defaultPrefix = TapestryConstants.LITERAL_BINDING_PREFIX)
private String _label;
/**
- * The value associated with this radio button. This is used to determine which radio button
- * will be selected when the page is rendered, and also becomes the value assigned when the form
- * is submitted.
+ * The value associated with this radio button. This is used to determine which radio button will be selected when
+ * the page is rendered, and also becomes the value assigned when the form is submitted.
*/
@Parameter(required = true, principal = true)
private Object _value;
@@ -79,9 +77,8 @@
private String _elementName;
/**
- * If true, then the field will render out with a disabled attribute (to turn off client-side
- * behavior). Further, a disabled field ignores any value in the request when the form is
- * submitted.
+ * If true, then the field will render out with a disabled attribute (to turn off client-side behavior). Further, a
+ * disabled field ignores any value in the request when the form is submitted.
*/
@Parameter("false")
private boolean _disabled;
@@ -107,8 +104,8 @@
}
/**
- * Returns true if this component has been expressly disabled (via its disabled parameter), or
- * if the {@link RadioContainer container} has been disabled.
+ * Returns true if this component has been expressly disabled (via its disabled parameter), or if the {@link
+ * RadioContainer container} has been disabled.
*/
public boolean isDisabled()
{
@@ -127,16 +124,7 @@
_clientId = _pageRenderSupport.allocateClientId(_resources.getId());
_elementName = _container.getElementName();
- writer.element(
- "input",
- "type",
- "radio",
- "id",
- _clientId,
- "name",
- _elementName,
- "value",
- value);
+ writer.element("input", "type", "radio", "id", _clientId, "name", _elementName, "value", value);
if (_container.isSelected(_value)) writer.attributes("checked", "checked");
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/RadioGroup.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/RadioGroup.java?rev=613323&r1=613322&r2=613323&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/RadioGroup.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/RadioGroup.java Fri Jan 18 16:27:22 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -21,7 +21,7 @@
import org.apache.tapestry.ioc.annotations.Inject;
import org.apache.tapestry.services.*;
-public class RadioGroup
+public class RadioGroup implements Field
{
/**
* The property read and updated by the group as a whole.
@@ -30,16 +30,15 @@
private Object _value;
/**
- * If true, then the field will render out with a disabled attribute (to turn off client-side
- * behavior). Further, a disabled field ignores any value in the request when the form is
- * submitted.
+ * If true, then the field will render out with a disabled attribute (to turn off client-side behavior). Further, a
+ * disabled field ignores any value in the request when the form is submitted.
*/
@Parameter("false")
private boolean _disabled;
/**
- * Allows a specific implementation of {@link ValueEncoder} to be supplied. This is used to
- * create client-side string values for the different radio button values.
+ * Allows a specific implementation of {@link ValueEncoder} to be supplied. This is used to create client-side
+ * string values for the different radio button values.
*
* @see ValueEncoderSource
*/
@@ -64,6 +63,9 @@
@Inject
private Request _request;
+ @Environmental
+ private ValidationTracker _tracker;
+
private String _elementName;
final Binding defaultValue()
@@ -112,12 +114,14 @@
{
String clientValue = _request.getParameter(_elementName);
+ _tracker.recordInput(this, clientValue);
+
_value = _encoder.toValue(clientValue);
}
/**
- * Obtains the element name for the group, and stores a {@link RadioContainer} into the
- * {@link Environment} (so that the {@link Radio} components can find it).
+ * Obtains the element name for the group, and stores a {@link RadioContainer} into the {@link Environment} (so that
+ * the {@link Radio} components can find it).
*/
final void setupRender()
{
@@ -127,6 +131,11 @@
_formSupport.storeAndExecute(this, action);
+ String submittedValue = _tracker.getInput(this);
+
+ final String selectedValue = submittedValue != null ? submittedValue : _encoder.toClient(_value);
+
+
_environment.push(RadioContainer.class, new RadioContainer()
{
public String getElementName()
@@ -149,7 +158,7 @@
public boolean isSelected(Object value)
{
- return TapestryInternalUtils.isEqual(value, _value);
+ return TapestryInternalUtils.isEqual(_encoder.toClient(value), selectedValue);
}
});
@@ -165,4 +174,33 @@
_environment.pop(RadioContainer.class);
}
+ public String getElementName()
+ {
+ return _elementName;
+ }
+
+ /**
+ * Always returns null; individual {@link org.apache.tapestry.corelib.components.Radio} components may have their
+ * own label.
+ */
+ public String getLabel()
+ {
+ return null;
+ }
+
+ public boolean isDisabled()
+ {
+ return _disabled;
+ }
+
+ /**
+ * Returns null; the radio group does not render as a tag and so doesn't have an id to share. RadioGroup implements
+ * {@link org.apache.tapestry.Field} only so it can interact with the {@link org.apache.tapestry.ValidationTracker}.
+ *
+ * @return null
+ */
+ public String getClientId()
+ {
+ return null;
+ }
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java?rev=613323&r1=613322&r2=613323&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java Fri Jan 18 16:27:22 2008
@@ -21,23 +21,26 @@
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.corelib.base.AbstractField;
import org.apache.tapestry.corelib.mixins.RenderDisabled;
+import org.apache.tapestry.internal.TapestryInternalUtils;
import org.apache.tapestry.internal.util.SelectModelRenderer;
import org.apache.tapestry.ioc.annotations.Inject;
-import org.apache.tapestry.services.*;
+import org.apache.tapestry.services.FieldValidatorDefaultSource;
+import org.apache.tapestry.services.Request;
+import org.apache.tapestry.services.ValueEncoderFactory;
+import org.apache.tapestry.services.ValueEncoderSource;
import org.apache.tapestry.util.EnumSelectModel;
import java.util.Locale;
/**
- * Select an item from a list of values, using an [X]HTML <select> element on the client side.
- * An validation decorations will go around the entire <select> element.
+ * Select an item from a list of values, using an [X]HTML <select> element on the client side. An validation
+ * decorations will go around the entire <select> element.
* <p/>
- * A core part of this component is the {@link ValueEncoder} (the encoder parameter) that is used to
- * convert between server-side values and client-side strings. In many cases, a {@link ValueEncoder}
- * can be generated automatically from the type of the value parameter. The
- * {@link ValueEncoderSource} service provides an encoder in these situations; it can be overriden
- * by binding the encoder parameter, or extended by contributing a {@link ValueEncoderFactory} into
- * the service's configuration.
+ * A core part of this component is the {@link ValueEncoder} (the encoder parameter) that is used to convert between
+ * server-side values and client-side strings. In many cases, a {@link ValueEncoder} can be generated automatically from
+ * the type of the value parameter. The {@link ValueEncoderSource} service provides an encoder in these situations; it
+ * can be overriden by binding the encoder parameter, or extended by contributing a {@link ValueEncoderFactory} into the
+ * service's configuration.
*/
public final class Select extends AbstractField
{
@@ -50,17 +53,15 @@
}
@Override
- protected boolean isOptionSelected(OptionModel optionModel)
+ protected boolean isOptionSelected(OptionModel optionModel, String clientValue)
{
- Object value = optionModel.getValue();
-
- return value == _value || (value != null && value.equals(_value));
+ return isSelected(clientValue);
}
}
/**
- * Allows a specific implementation of {@link ValueEncoder} to be supplied. This is used to
- * create client-side string values for the different options.
+ * Allows a specific implementation of {@link ValueEncoder} to be supplied. This is used to create client-side
+ * string values for the different options.
*
* @see ValueEncoderSource
*/
@@ -75,8 +76,8 @@
// Maybe this should default to property "<componentId>Model"?
/**
- * The model used to identify the option groups and options to be presented to the user. This
- * can be generated automatically for Enum types.
+ * The model used to identify the option groups and options to be presented to the user. This can be generated
+ * automatically for Enum types.
*/
@Parameter(required = true)
private SelectModel _model;
@@ -113,13 +114,22 @@
@Mixin
private RenderDisabled _renderDisabled;
+ private String _selectedClientValue;
+
+ private boolean isSelected(String clientValue)
+ {
+ return TapestryInternalUtils.isEqual(clientValue, _selectedClientValue);
+ }
+
@SuppressWarnings({"unchecked"})
@Override
protected void processSubmission(String elementName)
{
- String primaryKey = _request.getParameter(elementName);
+ String submittedValue = _request.getParameter(elementName);
+
+ _tracker.recordInput(this, submittedValue);
- Object selectedValue = _encoder.toValue(primaryKey);
+ Object selectedValue = _encoder.toValue(submittedValue);
try
{
@@ -145,6 +155,9 @@
_resources.renderInformalParameters(writer);
// Disabled via mixin
+
+ // Figure out
+
}
@SuppressWarnings("unchecked")
@@ -167,8 +180,7 @@
}
/**
- * Computes a default value for the "validate" parameter using
- * {@link FieldValidatorDefaultSource}.
+ * Computes a default value for the "validate" parameter using {@link FieldValidatorDefaultSource}.
*/
FieldValidator defaultValidate()
{
@@ -189,6 +201,14 @@
@BeforeRenderTemplate
void options(MarkupWriter writer)
{
+ _selectedClientValue = _tracker.getInput(this);
+
+ // Use the value passed up in the form submission, if available.
+ // Failing that, see if there is a current value (via the value parameter), and
+ // convert that to a client value for later comparison.
+
+ if (_selectedClientValue == null) _selectedClientValue = _value == null ? null : _encoder.toClient(_value);
+
SelectModelVisitor renderer = new Renderer(writer);
_model.visit(renderer);
@@ -209,5 +229,10 @@
void setValueEncoder(ValueEncoder encoder)
{
_encoder = encoder;
+ }
+
+ void setValidationTracker(ValidationTracker tracker)
+ {
+ _tracker = tracker;
}
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/util/SelectModelRenderer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/util/SelectModelRenderer.java?rev=613323&r1=613322&r2=613323&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/util/SelectModelRenderer.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/util/SelectModelRenderer.java Fri Jan 18 16:27:22 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -52,7 +52,7 @@
_writer.element("option", "value", clientValue);
- if (isOptionSelected(optionModel)) _writer.attributes("selected", "selected");
+ if (isOptionSelected(optionModel, clientValue)) _writer.attributes("selected", "selected");
writeDisabled(optionModel.isDisabled());
writeAttributes(optionModel.getAttributes());
@@ -76,10 +76,9 @@
}
/**
- * If true, then the selected attribute will be written. This implementation always returns
- * false.
+ * If true, then the selected attribute will be written. This implementation always returns false.
*/
- protected boolean isOptionSelected(OptionModel optionModel)
+ protected boolean isOptionSelected(OptionModel optionModel, String clientValue)
{
return false;
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/test/TapestryTestCase.java?rev=613323&r1=613322&r2=613323&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/test/TapestryTestCase.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/test/TapestryTestCase.java Fri Jan 18 16:27:22 2008
@@ -974,4 +974,9 @@
{
expect(manager.get(asoClass)).andReturn(aso);
}
+
+ protected final void train_getInput(ValidationTracker tracker, Field field, String input)
+ {
+ expect(tracker.getInput(field)).andReturn(input);
+ }
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java?rev=613323&r1=613322&r2=613323&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/components/SelectTest.java Fri Jan 18 16:27:22 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -14,10 +14,7 @@
package org.apache.tapestry.corelib.components;
-import org.apache.tapestry.MarkupWriter;
-import org.apache.tapestry.OptionGroupModel;
-import org.apache.tapestry.OptionModel;
-import org.apache.tapestry.SelectModel;
+import org.apache.tapestry.*;
import org.apache.tapestry.dom.XMLMarkupModel;
import org.apache.tapestry.internal.OptionGroupModelImpl;
import org.apache.tapestry.internal.OptionModelImpl;
@@ -39,8 +36,8 @@
import java.util.Map;
/**
- * Mostly, this is about how the Select component renders its {@link SelectModel}. The real nuts
- * and bolts are tested in the integration tests.
+ * Mostly, this is about how the Select component renders its {@link SelectModel}. The real nuts and bolts are tested in
+ * the integration tests.
*/
public class SelectTest extends InternalBaseTestCase
{
@@ -48,11 +45,21 @@
@Test
public void empty_model()
{
+ ValidationTracker tracker = mockValidationTracker();
+
Select select = new Select();
+ train_getInput(tracker, select, null);
+
+ replay();
+
+
select.setModel(new SelectModelImpl(null, null));
+ select.setValidationTracker(tracker);
select.options(null);
+
+ verify();
}
private String read(String file) throws Exception
@@ -80,14 +87,22 @@
@Test
public void just_options() throws Exception
{
+ ValidationTracker tracker = mockValidationTracker();
+
List<OptionModel> options = TapestryInternalUtils
.toOptionModels("fred=Fred Flintstone,barney=Barney Rubble");
Select select = new Select();
+ train_getInput(tracker, select, null);
+
+ replay();
+
+
select.setModel(new SelectModelImpl(null, options));
select.setValueEncoder(new StringValueEncoder());
select.setValue("barney");
+ select.setValidationTracker(tracker);
MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel());
@@ -98,11 +113,51 @@
writer.end();
assertEquals(writer.toString(), read("just_options.txt"));
+
+ verify();
+ }
+
+ @Test
+ public void current_selection_from_validation_tracker() throws Exception
+ {
+ ValidationTracker tracker = mockValidationTracker();
+
+ List<OptionModel> options = TapestryInternalUtils
+ .toOptionModels("fred=Fred Flintstone,barney=Barney Rubble");
+
+ Select select = new Select();
+
+ train_getInput(tracker, select, "fred");
+
+ replay();
+
+
+ select.setModel(new SelectModelImpl(null, options));
+ select.setValueEncoder(new StringValueEncoder());
+ select.setValue("barney");
+ select.setValidationTracker(tracker);
+
+ MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel());
+
+ writer.element("select");
+
+ select.options(writer);
+
+ writer.end();
+
+ // fred will be selected, not barney, because the validation tracker
+ // takes precendence.
+
+ assertEquals(writer.toString(), read("current_selection_from_validation_tracker.txt"));
+
+ verify();
}
@Test
public void option_attributes() throws Exception
{
+ ValidationTracker tracker = mockValidationTracker();
+
// Extra cast needed for Sun compiler, not Eclipse compiler.
List<OptionModel> options = Arrays.asList(
@@ -110,9 +165,14 @@
Select select = new Select();
+ train_getInput(tracker, select, null);
+
+ replay();
+
select.setModel(new SelectModelImpl(null, options));
select.setValueEncoder(new StringValueEncoder());
select.setValue("barney");
+ select.setValidationTracker(tracker);
MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel());
@@ -123,11 +183,15 @@
writer.end();
assertEquals(writer.toString(), read("option_attributes.txt"));
+
+ verify();
}
@Test
public void disabled_option() throws Exception
{
+ ValidationTracker tracker = mockValidationTracker();
+
// Extra cast needed for Sun compiler, not Eclipse compiler.
List<OptionModel> options = CollectionFactory.newList(
@@ -135,9 +199,14 @@
Select select = new Select();
+ train_getInput(tracker, select, null);
+
+ replay();
+
select.setModel(new SelectModelImpl(null, options));
select.setValueEncoder(new StringValueEncoder());
select.setValue("barney");
+ select.setValidationTracker(tracker);
MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel());
@@ -149,11 +218,14 @@
assertEquals(writer.toString(), read("disabled_option.txt"));
+ verify();
}
@Test
public void option_groups() throws Exception
{
+ ValidationTracker tracker = mockValidationTracker();
+
OptionGroupModel husbands = new OptionGroupModelImpl("Husbands", false,
TapestryInternalUtils.toOptionModels("Fred,Barney"));
OptionGroupModel wives = new OptionGroupModelImpl("Wives", true, TapestryInternalUtils
@@ -162,9 +234,14 @@
Select select = new Select();
+ train_getInput(tracker, select, null);
+
+ replay();
+
select.setModel(new SelectModelImpl(groupModels, null));
select.setValueEncoder(new StringValueEncoder());
select.setValue("Fred");
+ select.setValidationTracker(tracker);
MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel());
@@ -175,20 +252,29 @@
writer.end();
assertEquals(writer.toString(), read("option_groups.txt"));
+
+ verify();
}
@Test
public void option_groups_precede_ungroup_options() throws Exception
{
+ ValidationTracker tracker = mockValidationTracker();
+
OptionGroupModel husbands = new OptionGroupModelImpl("Husbands", false,
TapestryInternalUtils.toOptionModels("Fred,Barney"));
Select select = new Select();
+ train_getInput(tracker, select, null);
+
+ replay();
+
select.setModel(new SelectModelImpl(Collections.singletonList(husbands),
TapestryInternalUtils.toOptionModels("Wilma,Betty")));
select.setValueEncoder(new StringValueEncoder());
select.setValue("Fred");
+ select.setValidationTracker(tracker);
MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel());
@@ -199,11 +285,15 @@
writer.end();
assertEquals(writer.toString(), read("option_groups_precede_ungroup_options.txt"));
+
+ verify();
}
@Test
public void option_group_attributes() throws Exception
{
+ ValidationTracker tracker = mockValidationTracker();
+
Map<String, String> attributes = Collections.singletonMap("class", "pixie");
OptionGroupModel husbands = new OptionGroupModelImpl("Husbands", false,
@@ -212,9 +302,14 @@
Select select = new Select();
+ train_getInput(tracker, select, null);
+
+ replay();
+
select.setModel(new SelectModelImpl(Collections.singletonList(husbands), null));
select.setValueEncoder(new StringValueEncoder());
select.setValue("Fred");
+ select.setValidationTracker(tracker);
MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel());
@@ -225,5 +320,7 @@
writer.end();
assertEquals(writer.toString(), read("option_group_attributes.txt"));
+
+ verify();
}
}
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/corelib/components/current_selection_from_validation_tracker.txt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/corelib/components/current_selection_from_validation_tracker.txt?rev=613323&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/corelib/components/current_selection_from_validation_tracker.txt (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry/corelib/components/current_selection_from_validation_tracker.txt Fri Jan 18 16:27:22 2008
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<select><option selected="selected" value="fred">Fred Flintstone</option><option value="barney">Barney Rubble</option></select>
\ No newline at end of file