You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2010/04/26 01:22:15 UTC
svn commit: r937906 - in /tapestry/tapestry5/trunk/tapestry-core/src:
main/java/org/apache/tapestry5/corelib/components/
main/java/org/apache/tapestry5/corelib/internal/
main/java/org/apache/tapestry5/internal/services/
main/java/org/apache/tapestry5/i...
Author: hlship
Date: Sun Apr 25 23:22:14 2010
New Revision: 937906
URL: http://svn.apache.org/viewvc?rev=937906&view=rev
Log:
TAP5-1109: Updating multiple zones within a Form creates anomalous empty text fields
Added:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateController.java (with props)
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateControllerImpl.java (with props)
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/MultiZoneUpdateInsideForm.tml
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateInsideForm.java (with props)
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Select.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Zone.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/ComponentActionSink.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/HiddenFieldPositioner.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderCommandComponentEventResultProcessor.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateFilter.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/StructureMessages.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/MultiZoneUpdateEventResultProcessor.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/SingleZonePartialRendererFilter.java
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/structure/StructureStrings.properties
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng-limited.xml
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Select.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Select.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Select.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Select.java Sun Apr 25 23:22:14 2010
@@ -15,27 +15,30 @@
package org.apache.tapestry5.corelib.components;
import org.apache.tapestry5.*;
-import org.apache.tapestry5.annotations.*;
+import org.apache.tapestry5.annotations.BeforeRenderTemplate;
+import org.apache.tapestry5.annotations.Environmental;
+import org.apache.tapestry5.annotations.Events;
+import org.apache.tapestry5.annotations.Mixin;
+import org.apache.tapestry5.annotations.Parameter;
+import org.apache.tapestry5.annotations.QueryParameter;
import org.apache.tapestry5.corelib.base.AbstractField;
import org.apache.tapestry5.corelib.data.BlankOption;
-import org.apache.tapestry5.corelib.internal.ComponentActionSink;
-import org.apache.tapestry5.corelib.internal.HiddenFieldPositioner;
import org.apache.tapestry5.corelib.mixins.RenderDisabled;
import org.apache.tapestry5.internal.TapestryInternalUtils;
-import org.apache.tapestry5.internal.services.PageRenderQueue;
-import org.apache.tapestry5.internal.util.Holder;
+import org.apache.tapestry5.internal.util.CaptureResultCallback;
import org.apache.tapestry5.internal.util.SelectModelRenderer;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.ioc.internal.util.IdAllocator;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.json.JSONArray;
import org.apache.tapestry5.json.JSONObject;
-import org.apache.tapestry5.services.*;
+import org.apache.tapestry5.services.ComponentDefaultProvider;
+import org.apache.tapestry5.services.FieldValidatorDefaultSource;
+import org.apache.tapestry5.services.FormSupport;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.services.ValueEncoderFactory;
+import org.apache.tapestry5.services.ValueEncoderSource;
+import org.apache.tapestry5.services.javascript.JavascriptSupport;
import org.apache.tapestry5.util.EnumSelectModel;
-import org.slf4j.Logger;
-
-import java.util.Locale;
/**
* Select an item from a list of values, using an [X]HTML <select> element on the client side. An validation
@@ -51,7 +54,6 @@ import java.util.Locale;
{ EventConstants.VALIDATE, EventConstants.VALUE_CHANGED + " when 'zone' parameter is bound" })
public class Select extends AbstractField
{
- public static final String FORM_COMPONENTID_PARAMETER = "t:formcomponentid";
public static final String CHANGE_EVENT = "change";
private class Renderer extends SelectModelRenderer
@@ -81,9 +83,6 @@ public class Select extends AbstractFiel
@Inject
private ComponentDefaultProvider defaultProvider;
- @Inject
- private Locale locale;
-
// 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
@@ -120,7 +119,6 @@ public class Select extends AbstractFiel
* Performs input validation on the value supplied by the user in the form submission.
*/
@Parameter(defaultPrefix = BindingConstants.VALIDATE)
- @SuppressWarnings("unchecked")
private FieldValidator<Object> validate;
/**
@@ -135,7 +133,7 @@ public class Select extends AbstractFiel
* indicated zone. The component will trigger the event {@link EventConstants#VALUE_CHANGED} to inform its
* container that Select's value has changed.
*
- * @since 5.2.0.0
+ * @since 5.2.0
*/
@Parameter(defaultPrefix = BindingConstants.LITERAL)
private String zone;
@@ -147,25 +145,7 @@ public class Select extends AbstractFiel
private FormSupport formSupport;
@Inject
- private Environment environment;
-
- @Inject
- private RenderSupport renderSupport;
-
- @Inject
- private HiddenFieldLocationRules rules;
-
- @Inject
- private Logger logger;
-
- @Inject
- private ClientDataEncoder clientDataEncoder;
-
- @Inject
- private ComponentSource componentSource;
-
- @Inject
- private PageRenderQueue pageRenderQueue;
+ private JavascriptSupport javascriptSupport;
@SuppressWarnings("unused")
@Mixin
@@ -226,83 +206,30 @@ public class Select extends AbstractFiel
if (this.zone != null)
{
- final Link link = this.resources.createEventLink(CHANGE_EVENT);
+ Link link = resources.createEventLink(CHANGE_EVENT);
- link.addParameter(FORM_COMPONENTID_PARAMETER, this.formSupport.getFormComponentId());
+ JSONObject spec = new JSONObject("selectId", getClientId(), "zoneId", zone, "url", link.toURI());
- final JSONArray spec = new JSONArray();
- spec.put("change");
- spec.put(getClientId());
- spec.put(this.zone);
- spec.put(link.toAbsoluteURI());
-
- this.renderSupport.addInit("updateZoneOnEvent", spec);
+ javascriptSupport.addInitializerCall("linkSelectToZone", spec);
}
}
- Object onChange(
-
- @QueryParameter(FORM_COMPONENTID_PARAMETER)
- final String formId,
-
- @QueryParameter(value = "t:selectvalue", allowBlank = true)
- final String changedValue)
+ Object onChange(@QueryParameter(value = "t:selectvalue", allowBlank = true)
+ final String selectValue)
{
- final Object newValue = toValue(changedValue);
-
- final Holder<Object> holder = Holder.create();
-
- final ComponentEventCallback callback = new ComponentEventCallback()
- {
- public boolean handleResult(final Object result)
- {
-
- holder.put(result);
+ final Object newValue = toValue(selectValue);
- Select.this.value = newValue;
-
- return true;
- }
- };
+ CaptureResultCallback<Object> callback = new CaptureResultCallback<Object>();
this.resources.triggerEvent(EventConstants.VALUE_CHANGED, new Object[]
{ newValue }, callback);
- final PartialMarkupRendererFilter filter = new PartialMarkupRendererFilter()
- {
- public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
- {
-
- HiddenFieldPositioner hiddenFieldPositioner = new HiddenFieldPositioner(writer, Select.this.rules);
-
- final ComponentActionSink actionSink = new ComponentActionSink(Select.this.logger,
- Select.this.clientDataEncoder);
-
- final Form form = (Form) Select.this.componentSource.getComponent(formId);
-
- FormSupport formSupport = form.createRenderTimeFormSupport(form.getClientId(), actionSink,
- new IdAllocator());
-
- Select.this.environment.push(FormSupport.class, formSupport);
- Select.this.environment.push(ValidationTracker.class, new ValidationTrackerImpl());
-
- renderer.renderMarkup(writer, reply);
-
- Select.this.environment.pop(ValidationTracker.class);
- Select.this.environment.pop(FormSupport.class);
-
- hiddenFieldPositioner.getElement().attributes("type", "hidden", "name", Form.FORM_DATA, "value",
- actionSink.getClientData());
-
- }
- };
-
- this.pageRenderQueue.addPartialMarkupRendererFilter(filter);
+ this.value = newValue;
- return holder.get();
+ return callback.getResult();
}
- protected Object toValue(final String submittedValue)
+ protected Object toValue(String submittedValue)
{
return InternalUtils.isBlank(submittedValue) ? null : this.encoder.toValue(submittedValue);
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Zone.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Zone.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Zone.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Zone.java Sun Apr 25 23:22:14 2010
@@ -18,6 +18,7 @@ import org.apache.tapestry5.BindingConst
import org.apache.tapestry5.Block;
import org.apache.tapestry5.CSSClassConstants;
import org.apache.tapestry5.ClientElement;
+import org.apache.tapestry5.ComponentAction;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.QueryParameterConstants;
@@ -25,11 +26,19 @@ import org.apache.tapestry5.annotations.
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.SupportsInformalParameters;
+import org.apache.tapestry5.corelib.internal.ComponentActionSink;
+import org.apache.tapestry5.corelib.internal.FormSupportAdapter;
+import org.apache.tapestry5.corelib.internal.HiddenFieldPositioner;
import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.ClientBehaviorSupport;
+import org.apache.tapestry5.services.ClientDataEncoder;
+import org.apache.tapestry5.services.Environment;
+import org.apache.tapestry5.services.FormSupport;
import org.apache.tapestry5.services.Heartbeat;
+import org.apache.tapestry5.services.HiddenFieldLocationRules;
import org.apache.tapestry5.services.javascript.JavascriptSupport;
+import org.slf4j.Logger;
/**
* A Zone is portion of the output page designed for easy dynamic updating via Ajax or other client-side effects. A
@@ -108,6 +117,9 @@ public class Zone implements ClientEleme
@Environmental
private ClientBehaviorSupport clientBehaviorSupport;
+ @Inject
+ private Environment environment;
+
/**
* If true (the default) then the zone will render normally. If false, then the "t-invisible" CSS class is added,
* which will make the zone initially invisible.
@@ -121,8 +133,23 @@ public class Zone implements ClientEleme
@Inject
private Heartbeat heartbeat;
+ @Inject
+ private Logger logger;
+
+ @Inject
+ private ClientDataEncoder clientDataEncoder;
+
+ @Inject
+ private HiddenFieldLocationRules rules;
+
private String clientId;
+ private boolean insideForm;
+
+ private HiddenFieldPositioner hiddenFieldPositioner;
+
+ private ComponentActionSink actionSink;
+
String defaultElementName()
{
return resources.getElementName("div");
@@ -143,6 +170,35 @@ public class Zone implements ClientEleme
clientBehaviorSupport.addZone(clientId, show, update);
+ FormSupport existingFormSupport = environment.peek(FormSupport.class);
+
+ insideForm = existingFormSupport != null;
+
+ if (insideForm)
+ {
+ hiddenFieldPositioner = new HiddenFieldPositioner(writer, rules);
+
+ actionSink = new ComponentActionSink(logger, clientDataEncoder);
+
+ environment.push(FormSupport.class, new FormSupportAdapter(existingFormSupport)
+ {
+ @Override
+ public <T> void store(T component, ComponentAction<T> action)
+ {
+ actionSink.store(component, action);
+ }
+
+ @Override
+ public <T> void storeAndExecute(T component, ComponentAction<T> action)
+ {
+ store(component, action);
+
+ action.execute(component);
+ }
+
+ });
+ }
+
heartbeat.begin();
}
@@ -150,6 +206,24 @@ public class Zone implements ClientEleme
{
heartbeat.end();
+ if (insideForm)
+ {
+ environment.pop(FormSupport.class);
+
+ if (actionSink.isEmpty())
+ {
+ hiddenFieldPositioner.discard();
+ }
+ else
+ {
+ hiddenFieldPositioner.getElement().attributes("type", "hidden",
+
+ "name", Form.FORM_DATA,
+
+ "value", actionSink.getClientData());
+ }
+ }
+
writer.end(); // div
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/ComponentActionSink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/ComponentActionSink.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/ComponentActionSink.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/ComponentActionSink.java Sun Apr 25 23:22:14 2010
@@ -4,7 +4,7 @@
// 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
+// 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,
@@ -36,6 +36,8 @@ public class ComponentActionSink
private final ClientDataSink sink;
+ private boolean empty = true;
+
public ComponentActionSink(Logger logger, ClientDataEncoder encoder)
{
this.logger = logger;
@@ -65,8 +67,15 @@ public class ComponentActionSink
{
throw new RuntimeException(InternalMessages.componentActionNotSerializable(completeId, ex), ex);
}
+
+ empty = false;
}
+ /** @since 5.2.0 */
+ public boolean isEmpty()
+ {
+ return empty;
+ }
public String getClientData()
{
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/HiddenFieldPositioner.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/HiddenFieldPositioner.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/HiddenFieldPositioner.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/HiddenFieldPositioner.java Sun Apr 25 23:22:14 2010
@@ -76,7 +76,7 @@ public class HiddenFieldPositioner
*
* @return the element
* @throws IllegalStateException
- * if the element was not placed.
+ * if the element was not positioned
*/
public Element getElement()
{
@@ -93,4 +93,21 @@ public class HiddenFieldPositioner
return hiddenFieldElement;
}
+ /**
+ * Discard this positioner (an alternative to invoking {@link #getElement()}).
+ * If an {@link Element} has been created for the hidden field, that
+ * element is removed.
+ *
+ * @since 5.2.0
+ */
+ public void discard()
+ {
+ lock.lock();
+
+ if (hiddenFieldElement != null)
+ hiddenFieldElement.remove();
+
+ writer.removeListener(listener);
+ }
+
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java Sun Apr 25 23:22:14 2010
@@ -18,6 +18,7 @@ import javax.servlet.http.Cookie;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.internal.pageload.PageLoaderImpl;
+import org.apache.tapestry5.internal.services.ajax.AjaxFormUpdateController;
import org.apache.tapestry5.internal.services.javascript.JavascriptStackPathConstructor;
import org.apache.tapestry5.internal.structure.ComponentPageElementResourcesSource;
import org.apache.tapestry5.internal.structure.ComponentPageElementResourcesSourceImpl;
@@ -86,6 +87,7 @@ public class InternalModule
binder.bind(ComponentModelSource.class);
binder.bind(AssetResourceLocator.class);
binder.bind(JavascriptStackPathConstructor.class);
+ binder.bind(AjaxFormUpdateController.class);
}
/**
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderCommandComponentEventResultProcessor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderCommandComponentEventResultProcessor.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderCommandComponentEventResultProcessor.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RenderCommandComponentEventResultProcessor.java Sun Apr 25 23:22:14 2010
@@ -1,10 +1,10 @@
-// Copyright 2007, 2008 The Apache Software Foundation
+// Copyright 2007, 2008, 2010 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
+// 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,
@@ -14,27 +14,61 @@
package org.apache.tapestry5.internal.services;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.internal.services.ajax.AjaxFormUpdateController;
import org.apache.tapestry5.runtime.RenderCommand;
+import org.apache.tapestry5.runtime.RenderQueue;
import org.apache.tapestry5.services.ComponentEventResultProcessor;
import java.io.IOException;
/**
- * Processor for objects that implement {@link RenderCommand} (such as {@link org.apache.tapestry5.internal.structure.BlockImpl}).
- *
+ * Processor for objects that implement {@link RenderCommand} (such as
+ * {@link org.apache.tapestry5.internal.structure.BlockImpl}).
+ *
* @see AjaxPartialResponseRenderer#renderPartialPageMarkup()
*/
public class RenderCommandComponentEventResultProcessor implements ComponentEventResultProcessor<RenderCommand>
{
- private PageRenderQueue pageRenderQueue;
+ private final PageRenderQueue pageRenderQueue;
- public RenderCommandComponentEventResultProcessor(PageRenderQueue pageRenderQueue)
+ private final AjaxFormUpdateController ajaxFormUpdateController;
+
+ private final RenderCommand setup = new RenderCommand()
+ {
+ public void render(MarkupWriter writer, RenderQueue queue)
+ {
+ ajaxFormUpdateController.setupBeforePartialZoneRender(writer);
+ }
+ };
+
+ private final RenderCommand cleanup = new RenderCommand()
+ {
+ public void render(MarkupWriter writer, RenderQueue queue)
+ {
+ ajaxFormUpdateController.cleanupAfterPartialZoneRender();
+ }
+ };
+
+ public RenderCommandComponentEventResultProcessor(PageRenderQueue pageRenderQueue,
+ AjaxFormUpdateController ajaxFormUpdateController)
{
this.pageRenderQueue = pageRenderQueue;
+ this.ajaxFormUpdateController = ajaxFormUpdateController;
}
- public void processResultValue(RenderCommand value) throws IOException
+ public void processResultValue(final RenderCommand value) throws IOException
{
- pageRenderQueue.initializeForPartialPageRender(value);
+ RenderCommand wrapper = new RenderCommand()
+ {
+ public void render(MarkupWriter writer, RenderQueue queue)
+ {
+ queue.push(cleanup);
+ queue.push(value);
+ queue.push(setup);
+ }
+ };
+
+ pageRenderQueue.initializeForPartialPageRender(wrapper);
}
}
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateController.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateController.java?rev=937906&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateController.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateController.java Sun Apr 25 23:22:14 2010
@@ -0,0 +1,46 @@
+// Copyright 2010 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.ajax;
+
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.ValidationTracker;
+import org.apache.tapestry5.ajax.MultiZoneUpdate;
+import org.apache.tapestry5.services.FormSupport;
+
+/**
+ * Coordinates the rendering of page partials in the context of an
+ * Ajax update to an existing Form.
+ *
+ * @see AjaxFormUpdateFilter
+ * @see MultiZoneUpdate
+ * @since 5.2.0
+ */
+public interface AjaxFormUpdateController
+{
+ void initializeForForm(String formComponentId, String formClientId);
+
+ /**
+ * Called before starting to render a zone's content; initializes
+ * the {@link FormSupport} and {@link ValidationTracker} environmentals
+ * and starts a heartbeat.
+ */
+ void setupBeforePartialZoneRender(MarkupWriter writer);
+
+ /**
+ * Ends the heartbeat, executes deferred Form actions,
+ * and cleans up the environmentals.
+ */
+ void cleanupAfterPartialZoneRender();
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateController.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateControllerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateControllerImpl.java?rev=937906&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateControllerImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateControllerImpl.java Sun Apr 25 23:22:14 2010
@@ -0,0 +1,152 @@
+// Copyright 2010 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.ajax;
+
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.ValidationTracker;
+import org.apache.tapestry5.ValidationTrackerImpl;
+import org.apache.tapestry5.corelib.components.Form;
+import org.apache.tapestry5.corelib.internal.ComponentActionSink;
+import org.apache.tapestry5.corelib.internal.HiddenFieldPositioner;
+import org.apache.tapestry5.corelib.internal.InternalFormSupport;
+import org.apache.tapestry5.internal.util.CaptureResultCallback;
+import org.apache.tapestry5.ioc.ScopeConstants;
+import org.apache.tapestry5.ioc.annotations.Scope;
+import org.apache.tapestry5.ioc.internal.util.IdAllocator;
+import org.apache.tapestry5.runtime.Component;
+import org.apache.tapestry5.services.ClientDataEncoder;
+import org.apache.tapestry5.services.ComponentSource;
+import org.apache.tapestry5.services.Environment;
+import org.apache.tapestry5.services.FormSupport;
+import org.apache.tapestry5.services.Heartbeat;
+import org.apache.tapestry5.services.HiddenFieldLocationRules;
+import org.slf4j.Logger;
+
+@Scope(ScopeConstants.PERTHREAD)
+public class AjaxFormUpdateControllerImpl implements AjaxFormUpdateController
+{
+ private final ComponentSource componentSource;
+
+ private final HiddenFieldLocationRules rules;
+
+ private final Environment environment;
+
+ private final Heartbeat heartbeat;
+
+ private final ClientDataEncoder clientDataEncoder;
+
+ private final Logger logger;
+
+ private String formComponentId;
+
+ private String formClientId;
+
+ private HiddenFieldPositioner hiddenFieldPositioner;
+
+ private ComponentActionSink actionSink;
+
+ private InternalFormSupport formSupport;
+
+ public AjaxFormUpdateControllerImpl(ComponentSource componentSource, HiddenFieldLocationRules rules,
+ Environment environment, Heartbeat heartbeat, ClientDataEncoder clientDataEncoder, Logger logger)
+ {
+ this.componentSource = componentSource;
+ this.rules = rules;
+ this.environment = environment;
+ this.heartbeat = heartbeat;
+ this.clientDataEncoder = clientDataEncoder;
+ this.logger = logger;
+ }
+
+ public void initializeForForm(String formComponentId, String formClientId)
+ {
+ this.formComponentId = formComponentId;
+ this.formClientId = formClientId;
+ }
+
+ public void setupBeforePartialZoneRender(MarkupWriter writer)
+ {
+ if (formComponentId == null)
+ return;
+
+ hiddenFieldPositioner = new HiddenFieldPositioner(writer, rules);
+
+ actionSink = new ComponentActionSink(logger, clientDataEncoder);
+
+ formSupport = createInternalFormSupport(formClientId, formComponentId, actionSink);
+
+ environment.push(FormSupport.class, formSupport);
+ environment.push(ValidationTracker.class, new ValidationTrackerImpl());
+
+ heartbeat.begin();
+ }
+
+ public void cleanupAfterPartialZoneRender()
+ {
+ if (formComponentId == null)
+ return;
+
+ heartbeat.end();
+
+ formSupport.executeDeferred();
+
+ environment.pop(ValidationTracker.class);
+ environment.pop(FormSupport.class);
+
+ // If the Zone didn't actually contain any form control elements, then
+ // nothing will have been written to the action sink. In that case,
+ // get rid of the hidden field, if one was even added.
+
+ if (actionSink.isEmpty())
+ {
+ hiddenFieldPositioner.discard();
+
+ return;
+ }
+
+ // We've collected some hidden data that needs to be placed inside the Zone.
+ // This will raise an exception if the content of the zone didn't provide such a position.
+
+ hiddenFieldPositioner.getElement().attributes("type", "hidden",
+
+ "name", Form.FORM_DATA,
+
+ "value", actionSink.getClientData());
+ }
+
+ private InternalFormSupport createInternalFormSupport(String formClientId, String formComponentId,
+ ComponentActionSink actionSink)
+ {
+ // Kind of ugly, but the only way to ensure we don't have name collisions on the
+ // client side is to force a unique id into each name (as well as each id, but that's
+ // JavascriptSupport's job). It would be nice if we could agree on the uid, but
+ // not essential.
+
+ String uid = Long.toHexString(System.currentTimeMillis());
+
+ IdAllocator idAllocator = new IdAllocator("_" + uid);
+
+ Component formComponent = componentSource.getComponent(formComponentId);
+
+ CaptureResultCallback<InternalFormSupport> callback = CaptureResultCallback.create();
+
+ // This is a bit of a back-door to access a non-public method!
+
+ formComponent.getComponentResources().triggerEvent("internalCreateRenderTimeFormSupport", new Object[]
+ { formClientId, actionSink, idAllocator }, callback);
+
+ return callback.getResult();
+ }
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateControllerImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateFilter.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateFilter.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateFilter.java Sun Apr 25 23:22:14 2010
@@ -16,30 +16,19 @@ package org.apache.tapestry5.internal.se
import java.io.IOException;
-import org.apache.tapestry5.MarkupWriter;
-import org.apache.tapestry5.ValidationTracker;
-import org.apache.tapestry5.ValidationTrackerImpl;
-import org.apache.tapestry5.corelib.components.Form;
-import org.apache.tapestry5.corelib.components.Zone;
-import org.apache.tapestry5.corelib.internal.ComponentActionSink;
-import org.apache.tapestry5.corelib.internal.HiddenFieldPositioner;
-import org.apache.tapestry5.corelib.internal.InternalFormSupport;
-import org.apache.tapestry5.internal.services.PageRenderQueue;
import org.apache.tapestry5.internal.services.RequestConstants;
-import org.apache.tapestry5.internal.util.CaptureResultCallback;
-import org.apache.tapestry5.ioc.internal.util.IdAllocator;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.json.JSONObject;
-import org.apache.tapestry5.runtime.Component;
-import org.apache.tapestry5.services.*;
-import org.slf4j.Logger;
+import org.apache.tapestry5.services.Ajax;
+import org.apache.tapestry5.services.ComponentEventRequestFilter;
+import org.apache.tapestry5.services.ComponentEventRequestHandler;
+import org.apache.tapestry5.services.ComponentEventRequestParameters;
+import org.apache.tapestry5.services.Request;
/**
- * Filter for the {@link Ajax} {@link ComponentEventRequestHandler} pipeline that may
- * contribute a {@link PartialMarkupRendererFilter} into the {@link PageRenderQueue}.
- * The contributed filter detects the case of a a client-side Tapestry.ZoneManager (i.e., a {@link Zone} component) and,
- * if it indicates the containing {@link Form} component, sets up a {@link PartialMarkupRendererFilter} to re-establish
- * the Form so that it will all mesh together on the client side.
+ * Filter for the {@link Ajax} {@link ComponentEventRequestHandler} that informs the {@link AjaxFormUpdateController}
+ * about the form's client id and component id. Partial renders work with the
+ * AjaxFormUpdateController to ensure that the Form data, if any, is collected and rendered
+ * as part of the response.
*
* @since 5.2.0
*/
@@ -47,32 +36,12 @@ public class AjaxFormUpdateFilter implem
{
private final Request request;
- private final ComponentSource componentSource;
+ private final AjaxFormUpdateController ajaxFormUpdateController;
- private final HiddenFieldLocationRules rules;
-
- private final Environment environment;
-
- private final Heartbeat heartbeat;
-
- private final ClientDataEncoder clientDataEncoder;
-
- private final PageRenderQueue queue;
-
- private final Logger logger;
-
- public AjaxFormUpdateFilter(Request request, ComponentSource componentSource, HiddenFieldLocationRules rules,
- Environment environment, Heartbeat heartbeat, ClientDataEncoder clientDataEncoder, PageRenderQueue queue,
- Logger logger)
+ public AjaxFormUpdateFilter(Request request, AjaxFormUpdateController ajaxFormUpdateController)
{
this.request = request;
- this.componentSource = componentSource;
- this.rules = rules;
- this.environment = environment;
- this.heartbeat = heartbeat;
- this.clientDataEncoder = clientDataEncoder;
- this.queue = queue;
- this.logger = logger;
+ this.ajaxFormUpdateController = ajaxFormUpdateController;
}
public void handle(ComponentEventRequestParameters parameters, ComponentEventRequestHandler handler)
@@ -82,89 +51,8 @@ public class AjaxFormUpdateFilter implem
String formComponentId = request.getParameter(RequestConstants.FORM_COMPONENTID_PARAMETER);
if (InternalUtils.isNonBlank(formClientId) && InternalUtils.isNonBlank(formComponentId))
- addFilterToPartialRenderQueue(formClientId, formComponentId);
+ ajaxFormUpdateController.initializeForForm(formComponentId, formClientId);
handler.handle(parameters);
}
-
- private void addFilterToPartialRenderQueue(String formClientId, String formComponentId)
- {
- queue.addPartialMarkupRendererFilter(createFilter(formClientId, formComponentId));
- }
-
- private PartialMarkupRendererFilter createFilter(final String formClientId, final String formComponentId)
- {
- return new PartialMarkupRendererFilter()
- {
- public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
- {
- HiddenFieldPositioner hiddenFieldPositioner = new HiddenFieldPositioner(writer, rules);
-
- ComponentActionSink actionSink = new ComponentActionSink(logger, clientDataEncoder);
-
- InternalFormSupport formSupport = createInternalFormSupport(formClientId, formComponentId, actionSink);
-
- setupBeforeRender(formSupport);
-
- renderer.renderMarkup(writer, reply);
-
- cleanupAfterRender(formSupport);
-
- injectHiddenFieldIntoDOM(hiddenFieldPositioner, actionSink);
- }
-
- private void setupBeforeRender(InternalFormSupport formSupport)
- {
- environment.push(FormSupport.class, formSupport);
- environment.push(ValidationTracker.class, new ValidationTrackerImpl());
-
- heartbeat.begin();
- }
-
- private void cleanupAfterRender(InternalFormSupport formSupport)
- {
- formSupport.executeDeferred();
-
- heartbeat.end();
-
- environment.pop(ValidationTracker.class);
- environment.pop(FormSupport.class);
- }
-
- private void injectHiddenFieldIntoDOM(HiddenFieldPositioner hiddenFieldPositioner,
- ComponentActionSink actionSink)
- {
- hiddenFieldPositioner.getElement().attributes("type", "hidden",
-
- "name", Form.FORM_DATA,
-
- "value", actionSink.getClientData());
- }
-
- private InternalFormSupport createInternalFormSupport(String formClientId, String formComponentId,
- ComponentActionSink actionSink)
- {
- // Kind of ugly, but the only way to ensure we don't have name collisions on the
- // client side is to force a unique id into each name (as well as each id, but that's
- // JavascriptSupport's job). It would be nice if we could agree on the uid, but
- // not essential.
-
- String uid = Long.toHexString(System.currentTimeMillis());
-
- IdAllocator idAllocator = new IdAllocator("_" + uid);
-
- Component formComponent = componentSource.getComponent(formComponentId);
-
- CaptureResultCallback<InternalFormSupport> callback = CaptureResultCallback.create();
-
- // This is a bit of a back-door to access a non-public method!
-
- formComponent.getComponentResources().triggerEvent("internalCreateRenderTimeFormSupport", new Object[]
- { formClientId, actionSink, idAllocator }, callback);
-
- return callback.getResult();
- }
-
- };
- }
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java Sun Apr 25 23:22:14 2010
@@ -54,6 +54,8 @@ import org.apache.tapestry5.ioc.internal
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.ioc.internal.util.Orderer;
import org.apache.tapestry5.ioc.internal.util.TapestryException;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
import org.apache.tapestry5.model.ComponentModel;
import org.apache.tapestry5.model.ParameterModel;
import org.apache.tapestry5.runtime.Component;
@@ -870,7 +872,8 @@ public class ComponentPageElementImpl ex
{
Set<String> ids = InternalUtils.keys(children);
- throw new TapestryException(StructureMessages.noSuchComponent(this, embeddedId, ids), this, null);
+ throw new UnknownValueException(String.format("Component %s does not contain embedded component '%s'.",
+ getCompleteId(), embeddedId), new AvailableValues("embedded components", ids));
}
return embeddedElement;
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/StructureMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/StructureMessages.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/StructureMessages.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/StructureMessages.java Sun Apr 25 23:22:14 2010
@@ -38,13 +38,7 @@ final class StructureMessages
return MESSAGES.format("missing-parameters", InternalUtils.joinSorted(parameters), element
.getComponentResources().getComponentModel().getComponentClassName());
}
-
- static String noSuchComponent(ComponentPageElement parent, String embeddedId, Set<String> components)
- {
- return MESSAGES.format("no-such-component", parent.getCompleteId(), embeddedId,
- InternalUtils.joinSorted(components));
- }
-
+
static String unknownMixin(String componentId, String mixinClassName)
{
return MESSAGES.format("unknown-mixin", componentId, mixinClassName);
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/MultiZoneUpdateEventResultProcessor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/MultiZoneUpdateEventResultProcessor.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/MultiZoneUpdateEventResultProcessor.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/MultiZoneUpdateEventResultProcessor.java Sun Apr 25 23:22:14 2010
@@ -1,4 +1,4 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2010 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.
@@ -17,6 +17,7 @@ package org.apache.tapestry5.services.aj
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.ajax.MultiZoneUpdate;
import org.apache.tapestry5.internal.services.PageRenderQueue;
+import org.apache.tapestry5.internal.services.ajax.AjaxFormUpdateController;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.runtime.RenderCommand;
@@ -43,10 +44,14 @@ public class MultiZoneUpdateEventResultP
private final TypeCoercer typeCoercer;
- public MultiZoneUpdateEventResultProcessor(PageRenderQueue queue, TypeCoercer typeCoercer)
+ private final AjaxFormUpdateController ajaxFormUpdateController;
+
+ public MultiZoneUpdateEventResultProcessor(PageRenderQueue queue, TypeCoercer typeCoercer,
+ AjaxFormUpdateController ajaxFormUpdateController)
{
this.queue = queue;
this.typeCoercer = typeCoercer;
+ this.ajaxFormUpdateController = ajaxFormUpdateController;
}
public void processResultValue(final MultiZoneUpdate value) throws IOException
@@ -69,7 +74,8 @@ public class MultiZoneUpdateEventResultP
RenderCommand zoneRenderCommand = toRenderer(zoneId, provided);
- queue.addPartialMarkupRendererFilter(new SingleZonePartialRendererFilter(zoneId, zoneRenderCommand, queue));
+ queue.addPartialMarkupRendererFilter(new SingleZonePartialRendererFilter(zoneId, zoneRenderCommand, queue,
+ ajaxFormUpdateController));
}
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/SingleZonePartialRendererFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/SingleZonePartialRendererFilter.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/SingleZonePartialRendererFilter.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/SingleZonePartialRendererFilter.java Sun Apr 25 23:22:14 2010
@@ -1,4 +1,4 @@
-// Copyright 2009 The Apache Software Foundation
+// Copyright 2009, 2010 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.
@@ -17,6 +17,7 @@ package org.apache.tapestry5.services.aj
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.internal.services.PageRenderQueue;
+import org.apache.tapestry5.internal.services.ajax.AjaxFormUpdateController;
import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.runtime.RenderCommand;
import org.apache.tapestry5.runtime.RenderQueue;
@@ -37,11 +38,15 @@ public class SingleZonePartialRendererFi
private final PageRenderQueue queue;
- public SingleZonePartialRendererFilter(String zoneId, RenderCommand zoneRenderCommand, PageRenderQueue queue)
+ private final AjaxFormUpdateController ajaxFormUpdateController;
+
+ public SingleZonePartialRendererFilter(String zoneId, RenderCommand zoneRenderCommand, PageRenderQueue queue,
+ AjaxFormUpdateController ajaxFormUpdateController)
{
this.zoneId = zoneId;
this.zoneRenderCommand = zoneRenderCommand;
this.queue = queue;
+ this.ajaxFormUpdateController = ajaxFormUpdateController;
}
public void renderMarkup(MarkupWriter writer, final JSONObject reply, PartialMarkupRenderer renderer)
@@ -55,12 +60,18 @@ public class SingleZonePartialRendererFi
final Element zoneContainer = writer.element("zone-update", "zoneId", zoneId);
+ ajaxFormUpdateController.setupBeforePartialZoneRender(writer);
+
queue.push(new RenderCommand()
{
public void render(MarkupWriter writer, RenderQueue queue)
{
writer.end(); // the zoneContainer element
+ // Need to do this Ajax Form-related cleanup here, before we extract the zone content.
+
+ ajaxFormUpdateController.cleanupAfterPartialZoneRender();
+
String zoneUpdateContent = zoneContainer.getChildMarkup();
zoneContainer.remove();
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/structure/StructureStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/structure/StructureStrings.properties?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/structure/StructureStrings.properties (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/structure/StructureStrings.properties Sun Apr 25 23:22:14 2010
@@ -13,7 +13,6 @@
# limitations under the License.
missing-parameters=Parameter(s) '%s' are required for %s, but have not been bound.
-no-such-component=Component %s does not contain an embedded component with id '%s'. Available components: %s.
unknown-mixin=Component %s does not contain a mixin of type %s.
detach-failure=Listener %s failed during page detach: %s
wrong-phase-result-type=The return value from a render phase event method was not compatible with the expected return type. Expected is a component, a block or an instance of %s. \
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js Sun Apr 25 23:22:14 2010
@@ -378,8 +378,9 @@ var Tapestry = {
if (Tapestry.windowUnloaded)
return;
- /* Prototype treats status == 0 as success, even though it seems to mean
- * the server didn't respond.
+ /*
+ * Prototype treats status == 0 as success, even though it seems
+ * to mean the server didn't respond.
*/
if (!response.getStatus() || !response.request.success()) {
Tapestry.error(Tapestry.Messages.ajaxRequestUnsuccessful);
@@ -832,6 +833,22 @@ Tapestry.Initializer = {
spec.zoneId, spec.url);
},
+ /**
+ * Converts a link into an Ajax update of a Zone. The url includes the
+ * information to reconnect with the server-side Form.
+ *
+ * @param spec.selectId
+ * id or instance of <select>
+ * @param spec.zoneId
+ * id of element to update when select is changed
+ * @param spec.url
+ * component event request URL
+ */
+ linkSelectToZone : function(spec) {
+ Tapestry.Initializer.updateZoneOnEvent("change", spec.selectId,
+ spec.zoneId, spec.url);
+ },
+
updateZoneOnEvent : function(eventName, element, zoneId, url) {
element = $(element);
@@ -888,20 +905,21 @@ Tapestry.Initializer = {
if (!zoneObject)
return;
- var newUrl = url;
-
/*
* A hack related to allowing a Select to perform an Ajax update of
* the page.
*/
+ var parameters = {};
+
if (element.tagName == "SELECT" && element.value) {
- newUrl += '&t:selectvalue=' + element.value;
+ parameters["t:selectvalue"] = element.value;
}
- zoneObject.updateFromURL(newUrl);
+ zoneObject.updateFromURL(url, parameters);
});
},
+
/**
* Keys in the masterSpec are ids of field control elements. Value is a list
* of validation specs. Each validation spec is a 2 or 3 element array.
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/app1/MultiZoneUpdateInsideForm.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/app1/MultiZoneUpdateInsideForm.tml?rev=937906&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/app1/MultiZoneUpdateInsideForm.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/app1/MultiZoneUpdateInsideForm.tml Sun Apr 25 23:22:14 2010
@@ -0,0 +1,16 @@
+<t:border xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter">
+
+ <h1>Multi Zone Update Inside Form Demo</h1>
+
+ <form t:type="Form" t:id="form" t:clientValidation="false" action="#">
+ <t:label for="selectValue1"/>
+ <select t:type="Select" t:id="selectValue1" t:validate="required" t:zone="select1ValueZone"/>
+ <t:zone t:id="select1ValueZone" visible="false">Show</t:zone>
+ <t:zone t:id="select2ValueZone">
+ <t:label for="selectValue2"/>
+ <select t:type="Select" t:id="selectValue2" t:validate="required"/>
+ </t:zone>
+ <br/>
+ <input type="submit" value="Upate Form"/>
+ </form>
+</t:border>
\ No newline at end of file
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng-limited.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng-limited.xml?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng-limited.xml (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/conf/testng-limited.xml Sun Apr 25 23:22:14 2010
@@ -11,9 +11,7 @@
<class name="org.apache.tapestry5.test.SeleniumLauncher"/>
<!-- Modify classes below as needed. -->
- <class name="org.apache.tapestry5.integration.app1.AjaxTests"/>
- <class name="org.apache.tapestry5.integration.app1.FormTests"/>
- <class name="org.apache.tapestry5.integration.app1.GridTests"/>
+ <class name="org.apache.tapestry5.integration.app1.ZoneTests"/>
</classes>
</test>
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java?rev=937906&r1=937905&r2=937906&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/ZoneTests.java Sun Apr 25 23:22:14 2010
@@ -32,7 +32,7 @@ public class ZoneTests extends TapestryC
{
clickThru("Select Zone Demo");
- type("carMaker", "BMW");
+ select("carMaker", "Bmw");
waitForElementToAppear("carModelContainer");
@@ -44,7 +44,9 @@ public class ZoneTests extends TapestryC
assertText(String.format("//div[@class='%s']/span", "t-error-popup"), "You must provide a value for Car Model.");
- type("carModel", "7 Series");
+ String selectLocator = "//div[@id='modelZone']//select";
+
+ select(selectLocator, "7 Series");
clickAndWait(SUBMIT);
@@ -52,13 +54,11 @@ public class ZoneTests extends TapestryC
assertTextPresent("Car Model: 7 Series");
- waitForElementToDisappear("carModelContainer");
-
- type("carMaker", "MERCEDES");
+ select("carMaker", "Mercedes");
waitForElementToAppear("carModelContainer");
- type("carModel", "E-Class");
+ select(selectLocator, "E-Class");
clickAndWait(SUBMIT);
@@ -206,7 +206,6 @@ public class ZoneTests extends TapestryC
/**
* TAP5-707
*/
-
@Test
public void zone_fade_back_backgroundcolor()
{
@@ -238,10 +237,23 @@ public class ZoneTests extends TapestryC
waitForElementToAppear("updated");
type("//INPUT[@type='text']", "Tapestry 5.2");
-
+
clickAndWait(SUBMIT);
assertText("output", "Tapestry 5.2");
}
+ /** TAP5-1109 */
+ @Test
+ public void update_to_zone_inside_form()
+ {
+ clickThru("MultiZone Update inside a Form");
+
+ select("selectValue1", "3 pre ajax");
+
+ waitForElementToAppear("select1ValueZone");
+
+ select("//div[@id='select2ValueZone']//select", "4 post ajax");
+ }
+
}
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=937906&r1=937905&r2=937906&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 Sun Apr 25 23:22:14 2010
@@ -67,6 +67,9 @@ public class Index
private static final List<Item> ITEMS = CollectionFactory
.newList(
+ new Item("MultiZoneUpdateInsideForm", "MultiZone Update inside a Form",
+ "Update multiple zones within a single Form."),
+
new Item("ZoneFormUpdateDemo", "Zone/Form Update Demo", "Updating a Zone inside a Form"),
new Item("RenderNotificationDemo", "RenderNotification Demo", "Use of RenderNotification mixin"),
@@ -425,8 +428,8 @@ public class Index
new Item("BeanDisplayEnumDemo", "BeanDisplay Enum Demo",
"User represenation of enum values is correctly read from messages"),
-
- new Item("unavailablecomponentdemo", "Report Location of Unavailable Component",
+
+ new Item("unavailablecomponentdemo", "Report Location of Unavailable Component",
"Report Location of Unavailable Component")
);
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateInsideForm.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateInsideForm.java?rev=937906&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateInsideForm.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateInsideForm.java Sun Apr 25 23:22:14 2010
@@ -0,0 +1,185 @@
+// Copyright 2010 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.integration.app1.pages;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tapestry5.AbstractOptionModel;
+import org.apache.tapestry5.EventContext;
+import org.apache.tapestry5.OptionGroupModel;
+import org.apache.tapestry5.OptionModel;
+import org.apache.tapestry5.SelectModel;
+import org.apache.tapestry5.ValueEncoder;
+import org.apache.tapestry5.ajax.MultiZoneUpdate;
+import org.apache.tapestry5.annotations.Component;
+import org.apache.tapestry5.annotations.Log;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.corelib.components.Select;
+import org.apache.tapestry5.corelib.components.Zone;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.internal.util.Func;
+import org.apache.tapestry5.ioc.services.Coercion;
+import org.apache.tapestry5.services.Request;
+import org.apache.tapestry5.util.AbstractSelectModel;
+
+public class MultiZoneUpdateInsideForm
+{
+ @Inject
+ private Request request;
+
+ @Component(id = "selectValue1", parameters =
+ { "model=select1Model", "encoder=select1Model" })
+ private Select select1;
+
+ @Property
+ private SelectModel select1Model;
+
+ @Property
+ private SelectObj selectValue1;
+
+ @Component(id = "selectValue2", parameters =
+ { "model=select2Model", "encoder=select2Model" })
+ private Select select2;
+
+ @Property
+ private SelectModel select2Model;
+
+ @Property
+ private SelectObj selectValue2;
+
+ @Component(id = "select1ValueZone")
+ private Zone select1ValueZone;
+
+ @Component(id = "select2ValueZone")
+ private Zone select2ValueZone;
+
+ public class SelectObj
+ {
+ final int id;
+ final String label;
+
+ public SelectObj(int id, String label)
+ {
+ this.id = id;
+ this.label = label;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public String getLabel()
+ {
+ return label;
+ }
+ }
+
+ public class SelectObjModel extends AbstractSelectModel implements ValueEncoder<SelectObj>
+ {
+ private final List<SelectObj> options;
+
+ public SelectObjModel(List<SelectObj> options)
+ {
+ this.options = options;
+ }
+
+ public List<OptionGroupModel> getOptionGroups()
+ {
+ return null;
+ }
+
+ public List<OptionModel> getOptions()
+ {
+ return Func.map(options, new Coercion<SelectObj, OptionModel>()
+ {
+ public OptionModel coerce(final SelectObj input)
+ {
+ return new AbstractOptionModel()
+ {
+ public Object getValue()
+ {
+ return input;
+ }
+
+ public String getLabel()
+ {
+ return input.getLabel();
+ }
+ };
+ }
+ });
+ }
+
+ public String toClient(SelectObj value)
+ {
+ return String.valueOf(value.getId());
+ }
+
+ public SelectObj toValue(String clientValue)
+ {
+ int id = Integer.parseInt(clientValue);
+
+ for (SelectObj so : options)
+ {
+ if (so.id == id)
+ return so;
+ }
+
+ return null;
+ }
+ }
+
+ void onActivate(EventContext ctx)
+ {
+ List<SelectObj> select1List = new ArrayList();
+ select1List.add(new SelectObj(0, "0 pre ajax"));
+ select1List.add(new SelectObj(1, "1 pre ajax"));
+ select1List.add(new SelectObj(2, "2 pre ajax"));
+ select1List.add(new SelectObj(3, "3 pre ajax"));
+ select1List.add(new SelectObj(4, "4 pre ajax"));
+ select1Model = new SelectObjModel(select1List);
+
+ List<SelectObj> select2List = new ArrayList();
+ select2List.add(new SelectObj(0, "0 pre ajax"));
+ select2List.add(new SelectObj(1, "1 pre ajax"));
+ select2List.add(new SelectObj(2, "2 pre ajax"));
+ select2List.add(new SelectObj(3, "3 pre ajax"));
+ select2Model = new SelectObjModel(select2List);
+ }
+
+ @Log
+ public Object onValueChangedFromSelectValue1(SelectObj selectObj)
+ {
+ List<SelectObj> select2List = new ArrayList();
+ select2List.add(new SelectObj(4, "4 post ajax"));
+ select2List.add(new SelectObj(5, "5 post ajax"));
+ select2List.add(new SelectObj(6, "6 post ajax"));
+ select2List.add(new SelectObj(7, "7 post ajax"));
+ select2Model = new SelectObjModel(select2List);
+
+ if (request.isXHR())
+ {
+ return new MultiZoneUpdate("select1ValueZone", select1ValueZone.getBody()).add("select2ValueZone",
+ select2ValueZone.getBody());
+ }
+ else
+ {
+ return this;
+ }
+ }
+
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/MultiZoneUpdateInsideForm.java
------------------------------------------------------------------------------
svn:eol-style = native