Repository: tapestry-5 Updated Branches: refs/heads/master e294e9958 -> e6eb63c57
Fixes tests broken by the original implementation of TAP5-2331 Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/c2458058 Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/c2458058 Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/c2458058 Branch: refs/heads/master Commit: c24580586ce521e5bcbe09e7fba27e16f15cce9a Parents: b4fd568 Author: Thiago H. de Paula Figueiredo <[email protected]> Authored: Fri May 30 19:11:31 2014 -0300 Committer: Thiago H. de Paula Figueiredo <[email protected]> Committed: Fri May 30 19:11:31 2014 -0300 ---------------------------------------------------------------------- .../tapestry5/corelib/base/AbstractField.java | 66 +++++++++++++++++--- .../tapestry5/corelib/components/Form.java | 6 +- .../corelib/pages/PropertyEditBlocks.java | 18 +++--- .../services/PreSelectedFormNamesService.java | 41 ++++++++++++ .../PreSelectedFormNamesServiceImpl.java | 47 ++++++++++++++ .../tapestry5/modules/InternalModule.java | 3 + .../tapestry5/integration/app1/ZoneTests.java | 4 +- 7 files changed, 162 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c2458058/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java index 2c9fa9d..dc400d2 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java @@ -14,12 +14,29 @@ package org.apache.tapestry5.corelib.base; -import org.apache.tapestry5.*; -import org.apache.tapestry5.annotations.*; +import java.io.Serializable; + +import org.apache.tapestry5.BindingConstants; +import org.apache.tapestry5.ComponentAction; +import org.apache.tapestry5.ComponentResources; +import org.apache.tapestry5.Field; +import org.apache.tapestry5.FieldValidationSupport; +import org.apache.tapestry5.SymbolConstants; +import org.apache.tapestry5.ValidationDecorator; +import org.apache.tapestry5.ValidationTracker; +import org.apache.tapestry5.Validator; +import org.apache.tapestry5.annotations.AfterRender; +import org.apache.tapestry5.annotations.BeginRender; +import org.apache.tapestry5.annotations.Environmental; +import org.apache.tapestry5.annotations.Mixin; +import org.apache.tapestry5.annotations.Parameter; +import org.apache.tapestry5.annotations.SetupRender; +import org.apache.tapestry5.annotations.SupportsInformalParameters; import org.apache.tapestry5.corelib.mixins.DiscardBody; import org.apache.tapestry5.corelib.mixins.RenderInformals; import org.apache.tapestry5.internal.BeanValidationContext; import org.apache.tapestry5.internal.InternalComponentResources; +import org.apache.tapestry5.internal.services.PreSelectedFormNamesService; import org.apache.tapestry5.ioc.annotations.Inject; import org.apache.tapestry5.ioc.annotations.Symbol; import org.apache.tapestry5.services.ComponentDefaultProvider; @@ -28,8 +45,6 @@ import org.apache.tapestry5.services.FormSupport; import org.apache.tapestry5.services.Request; import org.apache.tapestry5.services.javascript.JavaScriptSupport; -import java.io.Serializable; - /** * Provides initialization of the clientId and elementName properties. In addition, adds the {@link RenderInformals}, * and {@link DiscardBody} mixins. @@ -115,15 +130,37 @@ public abstract class AbstractField implements Field private static final ProcessSubmission PROCESS_SUBMISSION_ACTION = new ProcessSubmission(); /** - * The id used to generate a page-unique client-side identifier for the component. If this parameter is not bound - * and a component renders multiple times, a suffix will be appended to the to id to ensure uniqueness. Either way, + * The id used to generate a page-unique client-side identifier for the component. + * If this parameter is not bound and this component is rendered multiple times in a request + * and <code>forceClientAllocation</code> is false (the default), + * a suffix will be appended to the to id to ensure uniqueness. Either way, * its value may be accessed via the {@link #getClientId() clientId property}. * When this parameter is bound, Tapestry considers the user (developer) is taking care of * providing unique client-side identifiers. Special care should be taken when the * field is inside a Zone. + * <br> + * <strong>Default value: the component's t:id</strong>. + * <br> + * <em>This parameter will be ignored if it receives any of these values:</em> + * <ul> + * <li>reset</li> + * <li>submit</li> + * <li>id</li> + * <li>method</li> + * <li>action</li> + * <li>onsubmit</li> + * <li>cancel</li> + * </ul> */ - @Parameter(value = "prop:componentResources.id", defaultPrefix = BindingConstants.LITERAL) + @Parameter(defaultPrefix = BindingConstants.LITERAL) protected String clientId; + + /** + * When true, it forces the clientId to be passed through the id allocator to avoid repeated ids + * even when the clientId parameter is bound. + */ + @Parameter("false") + private boolean forceClientIdAllocation; private String assignedClientId; @@ -149,13 +186,20 @@ public abstract class AbstractField implements Field @Inject protected FieldValidationSupport fieldValidationSupport; - + + @Inject + private PreSelectedFormNamesService preSelectedFormNamesService; final String defaultLabel() { return defaultProvider.defaultLabel(resources); } + final String defaultClientId() + { + return resources.getId(); + } + public final String getLabel() { return label; @@ -176,8 +220,10 @@ public abstract class AbstractField implements Field if (formSupport == null) throw new RuntimeException(String.format("Component %s must be enclosed by a Form component.", resources.getCompleteId())); - - assignedClientId = resources.isBound("clientId") ? clientId : javaScriptSupport.allocateClientId(id); + + final boolean avoidAllocation = resources.isBound("clientId") && !forceClientIdAllocation && !preSelectedFormNamesService.isPreselected(clientId); + assignedClientId = avoidAllocation ? clientId : javaScriptSupport.allocateClientId(id); + String controlName = formSupport.allocateControlName(id); formSupport.storeAndExecute(this, new Setup(controlName)); http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c2458058/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java index a4a0f4d..bb8d6a0 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java @@ -23,6 +23,7 @@ import org.apache.tapestry5.corelib.internal.InternalFormSupport; import org.apache.tapestry5.dom.Element; import org.apache.tapestry5.internal.*; import org.apache.tapestry5.internal.services.HeartbeatImpl; +import org.apache.tapestry5.internal.services.PreSelectedFormNamesService; import org.apache.tapestry5.internal.util.AutofocusValidationDecorator; import org.apache.tapestry5.ioc.Location; import org.apache.tapestry5.ioc.Messages; @@ -222,8 +223,7 @@ public class Form implements ClientElement, FormValidationControl private ComponentSource source; @Inject - @Symbol(InternalSymbols.PRE_SELECTED_FORM_NAMES) - private String preselectedFormNames; + private PreSelectedFormNamesService preSelectedFormNamesService; /** @@ -741,7 +741,7 @@ public class Form implements ClientElement, FormValidationControl private void preallocateNames(IdAllocator idAllocator) { - for (String name : TapestryInternalUtils.splitAtCommas(preselectedFormNames)) + for (String name : preSelectedFormNamesService.getNames()) { idAllocator.allocateId(name); // See https://issues.apache.org/jira/browse/TAP5-1632 http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c2458058/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PropertyEditBlocks.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PropertyEditBlocks.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PropertyEditBlocks.java index 9ab91e9..0b92f4b 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PropertyEditBlocks.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/PropertyEditBlocks.java @@ -44,51 +44,53 @@ public class PropertyEditBlocks @Component( parameters = {"value=context.propertyValue", "label=prop:context.label", "translate=prop:textFieldTranslator", "validate=prop:textFieldValidator", - "clientId=prop:context.propertyId", "annotationProvider=context"}) + "clientId=prop:context.propertyId", "annotationProvider=context", + "forceClientIdAllocation=true"}) private TextField textField; @Component( parameters = {"value=context.propertyValue", "label=prop:context.label", "translate=prop:numberFieldTranslator", "validate=prop:numberFieldValidator", - "clientId=prop:context.propertyId", "annotationProvider=context"}) + "clientId=prop:context.propertyId", "annotationProvider=context", + "forceClientIdAllocation=true"}) private TextField numberField; @Component( parameters = {"value=context.propertyValue", "label=prop:context.label", "encoder=valueEncoderForProperty", "model=selectModelForProperty", "validate=prop:selectValidator", - "clientId=prop:context.propertyId"}) + "clientId=prop:context.propertyId", "forceClientIdAllocation=true"}) private Select select; @SuppressWarnings("unused") @Component( parameters = {"value=context.propertyValue", "label=prop:context.label", - "clientId=prop:context.propertyId"}) + "clientId=prop:context.propertyId", "forceClientIdAllocation=true"}) private Checkbox checkboxField; @SuppressWarnings("unused") @Component( parameters = {"value=context.propertyValue", "label=prop:context.label", "clientId=prop:context.propertyid", - "validate=prop:dateFieldValidator"}) + "validate=prop:dateFieldValidator", "forceClientIdAllocation=true"}) private DateField dateField; @SuppressWarnings("unused") @Component( parameters = {"value=context.propertyValue", "label=prop:context.label", "clientId=prop:context.propertyid", - "validate=prop:calendarFieldValidator"}) + "validate=prop:calendarFieldValidator", "forceClientIdAllocation=true"}) private DateField calendarField; @Component( parameters = {"value=context.propertyValue", "label=prop:context.label", "translate=prop:passwordFieldTranslator", "validate=prop:passwordFieldValidator", - "clientId=prop:context.propertyId", "annotationProvider=context"}) + "clientId=prop:context.propertyId", "annotationProvider=context", "forceClientIdAllocation=true"}) private PasswordField passwordField; @Component( parameters = {"value=context.propertyValue", "label=prop:context.label", "translate=prop:textAreaTranslator", "validate=prop:textAreaValidator", "clientId=prop:context.propertyId", - "annotationProvider=context"}) + "annotationProvider=context", "forceClientIdAllocation=true"}) private TextArea textArea; http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c2458058/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PreSelectedFormNamesService.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PreSelectedFormNamesService.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PreSelectedFormNamesService.java new file mode 100644 index 0000000..fc00ba6 --- /dev/null +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PreSelectedFormNamesService.java @@ -0,0 +1,41 @@ +// Copyright 2014 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License.package org.apache.tapestry5.internal.services; +package org.apache.tapestry5.internal.services; + +import java.util.Set; + +import org.apache.tapestry5.internal.InternalSymbols; + +/** + * Service provinding methods related to names that shouldn't be used as HTML elements client ids. + * + * @see InternalSymbols.PRE_SELECTED_FORM_NAMES + */ +public interface PreSelectedFormNamesService +{ + /** + * Returns the set of pre-selected form names (ones that shouldn't be used as HTML elements + * client ids. + * @return a {@link Set} of {@link String}s. + */ + Set<String> getNames(); + + /** + * Tells whether a given name is pre-selected. + * @param string + * @return + */ + boolean isPreselected(String name); + +} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c2458058/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PreSelectedFormNamesServiceImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PreSelectedFormNamesServiceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PreSelectedFormNamesServiceImpl.java new file mode 100644 index 0000000..6056976 --- /dev/null +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PreSelectedFormNamesServiceImpl.java @@ -0,0 +1,47 @@ +// Copyright 2014 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License.package org.apache.tapestry5.internal.services; +package org.apache.tapestry5.internal.services; + +import java.util.Collections; +import java.util.Set; + +import org.apache.tapestry5.internal.InternalSymbols; +import org.apache.tapestry5.internal.TapestryInternalUtils; +import org.apache.tapestry5.ioc.annotations.Symbol; +import org.apache.tapestry5.ioc.internal.util.CollectionFactory; + +public class PreSelectedFormNamesServiceImpl implements PreSelectedFormNamesService +{ + + final private Set<String> names; + + public PreSelectedFormNamesServiceImpl( + @Symbol(InternalSymbols.PRE_SELECTED_FORM_NAMES) String preselectedFormNames) + { + this.names = Collections.unmodifiableSet(CollectionFactory.newSet(TapestryInternalUtils.splitAtCommas(preselectedFormNames))); + } + + @Override + public Set<String> getNames() + { + return names; + } + + @Override + public boolean isPreselected(String name) + { + return names.contains(name.toLowerCase()); + } + +} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c2458058/tapestry-core/src/main/java/org/apache/tapestry5/modules/InternalModule.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/InternalModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/InternalModule.java index 5067a33..32473ac 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/InternalModule.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/InternalModule.java @@ -29,6 +29,7 @@ import org.apache.tapestry5.services.*; import org.apache.tapestry5.services.transform.ControlledPackageType; import javax.servlet.http.Cookie; + import java.util.Map; /** @@ -71,6 +72,8 @@ public class InternalModule binder.bind(PageLoader.class, PageLoaderImpl.class).preventReloading(); binder.bind(UnknownActivationContextHandler.class, UnknownActivationContextHandlerImpl.class); binder.bind(ReloadHelper.class, ReloadHelperImpl.class); + binder.bind(PreSelectedFormNamesService.class, PreSelectedFormNamesServiceImpl.class); + } public static CookieSource buildCookieSource(final RequestGlobals requestGlobals) http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/c2458058/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java index b997e03..1ec0c75 100644 --- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java +++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java @@ -233,9 +233,9 @@ public class ZoneTests extends App1TestCase select("selectValue1", "3 pre ajax"); - waitForElementToAppear("select2ValueZone"); + waitForAjaxRequestsToComplete(); - select("//div[@id='select2ValueZone']//select", "4 post ajax"); + select("//div[@id='select2ValueZone']//select", "4 post ajax, number 013, retention policy RUNTIME"); } @Test
