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/03/27 21:23:58 UTC
svn commit: r928260 - in /tapestry/tapestry5/trunk:
tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/
tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/
tapestry-core/src/main/java/org/apache/tapestry5/internal/servic...
Author: hlship
Date: Sat Mar 27 20:23:58 2010
New Revision: 928260
URL: http://svn.apache.org/viewvc?rev=928260&view=rev
Log:
TAP5-1084: Refactoring and reoganizing to make form logic inside FormInjector component general for any Ajax request that results in a partial page render request
Added:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateFilter.java (with props)
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/CaptureResultCallback.java (with props)
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.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/AjaxPartialResponseRendererImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderQueueImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupRendererTerminator.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.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/SetupZonesFilter.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/SingleZonePartialRendererFilter.java
tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/IdAllocator.java
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java?rev=928260&r1=928259&r2=928260&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Form.java Sat Mar 27 20:23:58 2010
@@ -23,6 +23,7 @@ import org.apache.tapestry5.annotations.
import org.apache.tapestry5.annotations.Events;
import org.apache.tapestry5.annotations.Log;
import org.apache.tapestry5.annotations.Mixin;
+import org.apache.tapestry5.annotations.OnEvent;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.corelib.internal.ComponentActionSink;
@@ -409,6 +410,8 @@ public class Form implements ClientEleme
* Creates an {@link org.apache.tapestry5.corelib.internal.InternalFormSupport} for
* this Form. This method is used
* by {@link org.apache.tapestry5.corelib.components.FormInjector}.
+ * <p>
+ * This method may also be invoked as the handler for the "internalCreateRenderTimeFormSupport" event.
*
* @param name
* the client-side name and client id for the rendered form
@@ -421,6 +424,7 @@ public class Form implements ClientEleme
* used to allocate unique ids
* @return form support object
*/
+ @OnEvent("internalCreateRenderTimeFormSupport")
InternalFormSupport createRenderTimeFormSupport(String name, ComponentActionSink actionSink, IdAllocator allocator)
{
return new FormSupportImpl(resources, name, actionSink, clientBehaviorSupport, clientValidation, allocator,
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java?rev=928260&r1=928259&r2=928260&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java Sat Mar 27 20:23:58 2010
@@ -28,6 +28,7 @@ import org.apache.tapestry5.corelib.inte
import org.apache.tapestry5.corelib.internal.InternalFormSupport;
import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.internal.services.PageRenderQueue;
+import org.apache.tapestry5.internal.services.RequestConstants;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.internal.util.IdAllocator;
import org.apache.tapestry5.json.JSONObject;
@@ -40,6 +41,7 @@ import org.apache.tapestry5.services.Hea
import org.apache.tapestry5.services.HiddenFieldLocationRules;
import org.apache.tapestry5.services.PartialMarkupRenderer;
import org.apache.tapestry5.services.PartialMarkupRendererFilter;
+import org.apache.tapestry5.services.javascript.JavascriptSupport;
import org.slf4j.Logger;
/**
@@ -57,9 +59,15 @@ public class FormInjector implements Cli
{
public static final String INJECT_EVENT = "inject";
- public static final String FORM_CLIENTID_PARAMETER = "t:formid";
+ /**
+ * @deprecated Use {@link RequestConstants#FORM_CLIENTID_PARAMETER} instead
+ */
+ public static final String FORM_CLIENTID_PARAMETER = RequestConstants.FORM_CLIENTID_PARAMETER;
- public static final String FORM_COMPONENTID_PARAMETER = "t:formcomponentid";
+ /**
+ * @deprecated Use {@link RequestConstants#FORM_COMPONENTID_PARAMETER} instead
+ */
+ public static final String FORM_COMPONENTID_PARAMETER = RequestConstants.FORM_COMPONENTID_PARAMETER;
/**
* The context for the link (optional parameter). This list of values will be converted into strings and included in
@@ -87,7 +95,7 @@ public class FormInjector implements Cli
private String element;
@Environmental
- private RenderSupport renderSupport;
+ private JavascriptSupport javascriptSupport;
@Environmental
private FormSupport formSupport;
@@ -95,9 +103,6 @@ public class FormInjector implements Cli
@Environmental
private ClientBehaviorSupport clientBehaviorSupport;
- @Environmental
- private Heartbeat heartbeat;
-
@SuppressWarnings("unchecked")
@Environmental
private TrackableComponentEventCallback eventCallback;
@@ -110,15 +115,6 @@ public class FormInjector implements Cli
@Inject
private ComponentResources resources;
- @Inject
- private Environment environment;
-
- @Inject
- private Logger logger;
-
- @Inject
- private ComponentSource componentSource;
-
private Element clientElement;
String defaultElement()
@@ -128,7 +124,7 @@ public class FormInjector implements Cli
void beginRender(MarkupWriter writer)
{
- clientId = renderSupport.allocateClientId(resources);
+ clientId = javascriptSupport.allocateClientId(resources);
clientElement = writer.element(element, "id", clientId);
@@ -138,8 +134,8 @@ public class FormInjector implements Cli
Link link = resources.createEventLink(INJECT_EVENT, context);
- link.addParameter(FORM_CLIENTID_PARAMETER, formSupport.getClientId());
- link.addParameter(FORM_COMPONENTID_PARAMETER, formSupport.getFormComponentId());
+ link.addParameter(RequestConstants.FORM_CLIENTID_PARAMETER, formSupport.getClientId());
+ link.addParameter(RequestConstants.FORM_COMPONENTID_PARAMETER, formSupport.getFormComponentId());
clientBehaviorSupport.addFormInjector(clientId, link, position, show);
}
@@ -163,82 +159,27 @@ public class FormInjector implements Cli
}
/**
- * Used during Ajax partial rendering to identify the hidden field that will hold the form data (component actions,
- * used when processing the form submission) for the injection.
- */
- private HiddenFieldPositioner hiddenFieldPositioner;
-
- @Inject
- private HiddenFieldLocationRules rules;
-
- @Inject
- private ClientDataEncoder clientDataEncoder;
-
- /**
* Invoked via an Ajax request. Triggers an action event and captures the return value. The return value from the
- * event notification is what will ultimately render (typically, its a Block). However, we do a <em>lot</em> of
- * tricks to provide the desired FormSupport around the what renders.
+ * event notification is what will ultimately render (typically, its a Block).
*/
- void onInject(EventContext context,
-
- @QueryParameter(FORM_CLIENTID_PARAMETER)
- final String formClientId,
-
- @QueryParameter(FORM_COMPONENTID_PARAMETER)
- String formComponentId) throws IOException
+ void onInject(EventContext context) throws IOException
{
resources.triggerContextEvent(EventConstants.ACTION, context, eventCallback);
if (!eventCallback.isAborted())
return;
- // Here's where it gets very, very tricky.
-
- final Form form = (Form) componentSource.getComponent(formComponentId);
-
- final ComponentActionSink actionSink = new ComponentActionSink(logger, clientDataEncoder);
+ // Before rendering, allocate a unique element id and record it into the JSON reply.
PartialMarkupRendererFilter filter = new PartialMarkupRendererFilter()
{
public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
{
- hiddenFieldPositioner = new HiddenFieldPositioner(writer, rules);
-
- // 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
- // RenderSupport'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);
-
- clientId = renderSupport.allocateClientId(resources);
+ clientId = javascriptSupport.allocateClientId(resources);
reply.put("elementId", clientId);
- InternalFormSupport formSupport = form.createRenderTimeFormSupport(formClientId, actionSink,
- idAllocator);
-
- environment.push(FormSupport.class, formSupport);
- environment.push(ValidationTracker.class, new ValidationTrackerImpl());
-
- heartbeat.begin();
-
renderer.renderMarkup(writer, reply);
-
- formSupport.executeDeferred();
-
- heartbeat.end();
-
- environment.pop(ValidationTracker.class);
- environment.pop(FormSupport.class);
-
- hiddenFieldPositioner.getElement().attributes("type", "hidden",
-
- "name", Form.FORM_DATA,
-
- "value", actionSink.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=928260&r1=928259&r2=928260&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 Sat Mar 27 20:23:58 2010
@@ -1,3 +1,17 @@
+// 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.
+// 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.corelib.internal;
import org.apache.tapestry5.MarkupWriter;
@@ -7,9 +21,10 @@ import org.apache.tapestry5.ioc.internal
import org.apache.tapestry5.services.HiddenFieldLocationRules;
/**
- * Used to position a hidden field (as part of a form-related component). Hidden fields are not allowed to go just
- * anywhere, there are rules, dicatated by the (X)HTML schema, about where they are allowed. We use the {@link
- * org.apache.tapestry5.MarkupWriterListener} interface to monitor elements as they are started and ended to find a
+ * Used to position a hidden field (as part of a form-related component). Hidden fields are not allowed to go just
+ * anywhere, there are rules, dictated by the (X)HTML schema, about where they are allowed. We use the
+ * {@link org.apache.tapestry5.MarkupWriterListener} interface to monitor elements as they are started and ended to find
+ * a
* place to put content.
*/
public class HiddenFieldPositioner
@@ -42,7 +57,7 @@ public class HiddenFieldPositioner
{
if (rules.placeHiddenFieldAfter(element))
{
- hiddenFieldElement = element.getParent().element(ELEMENT);
+ hiddenFieldElement = element.getContainer().element(ELEMENT);
writer.removeListener(this);
}
}
@@ -58,9 +73,10 @@ public class HiddenFieldPositioner
/**
* Returns the hidden field element, which can have its attributes filled in.
- *
+ *
* @return the element
- * @throws IllegalStateException if the element was not placed.
+ * @throws IllegalStateException
+ * if the element was not placed.
*/
public Element getElement()
{
@@ -74,7 +90,6 @@ public class HiddenFieldPositioner
throw new IllegalStateException(
"The rendered content did not include any elements that allow for the positioning of the hidden form field's element.");
-
return hiddenFieldElement;
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java?rev=928260&r1=928259&r2=928260&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/AjaxPartialResponseRendererImpl.java Sat Mar 27 20:23:58 2010
@@ -62,8 +62,8 @@ public class AjaxPartialResponseRenderer
public void renderPartialPageMarkup() throws IOException
{
// This is a complex area as we are trying to keep public and private services properly
- // seperated, and trying to keep stateless and stateful (i.e., perthread scope) services
- // seperated. So we inform the stateful queue service what it needs to do here ...
+ // separated, and trying to keep stateless and stateful (i.e., perthread scope) services
+ // separated. So we inform the stateful queue service what it needs to do here ...
ContentType pageContentType =
(ContentType) request.getAttribute(InternalConstants.CONTENT_TYPE_ATTRIBUTE_NAME);
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderQueueImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderQueueImpl.java?rev=928260&r1=928259&r2=928260&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderQueueImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageRenderQueueImpl.java Sat Mar 27 20:23:58 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,
@@ -31,7 +31,7 @@ import org.slf4j.Logger;
/**
* This services keeps track of the page being rendered and the root command for the partial render, it is therefore
- * request/thread scoped. There's a filter pipeline around the rendering, and that gets to be stateless because this
+ * request/thread scoped. There's a filter pipeline around the rendering, and that gets to be stateless because this
* service, at the end of the pipeline, is stateful.
*/
@Scope(ScopeConstants.PERTHREAD)
@@ -74,7 +74,6 @@ public class PageRenderQueueImpl impleme
rootCommand = page.getRootElement();
}
-
public void setRenderingPage(Page page)
{
Defense.notNull(page, "page");
@@ -91,7 +90,8 @@ public class PageRenderQueueImpl impleme
{
Defense.notNull(rootCommand, "rootCommand");
- if (page == null) throw new IllegalStateException("Page must be specified before root render command.");
+ if (page == null)
+ throw new IllegalStateException("Page must be specified before root render command.");
this.rootCommand = rootCommand;
}
@@ -149,19 +149,8 @@ public class PageRenderQueueImpl impleme
delegate = bridge;
}
- // The partial will quite often contain multiple elements (or just a block of plain text),
- // so those must be enclosed in a root element.
-
- Element root = writer.element("ajax-partial");
-
// The initialize methods will already have been invoked.
delegate.renderMarkup(writer, reply);
-
- writer.end();
-
- String content = root.getChildMarkup().trim();
-
- reply.put("content", content);
}
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupRendererTerminator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupRendererTerminator.java?rev=928260&r1=928259&r2=928260&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupRendererTerminator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PartialMarkupRendererTerminator.java Sat Mar 27 20:23:58 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,
@@ -15,14 +15,15 @@
package org.apache.tapestry5.internal.services;
import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.services.PartialMarkupRenderer;
/**
* Terminator for the {@link org.apache.tapestry5.services.PartialMarkupRenderer} pipeline, which ultimately invokes
- * {@link org.apache.tapestry5.internal.services.PageRenderQueue#renderPartial(org.apache.tapestry5.MarkupWriter,
- * org.apache.tapestry5.json.JSONObject)}.
- *
+ * {@link org.apache.tapestry5.internal.services.PageRenderQueue#renderPartial(org.apache.tapestry5.MarkupWriter, org.apache.tapestry5.json.JSONObject)}
+ * .
+ *
* @since 5.1.0.0
*/
public class PartialMarkupRendererTerminator implements PartialMarkupRenderer
@@ -36,6 +37,17 @@ public class PartialMarkupRendererTermin
public void renderMarkup(MarkupWriter writer, JSONObject reply)
{
+ // The partial will quite often contain multiple elements (or just a block of plain text),
+ // so those must be enclosed in a root element.
+
+ Element root = writer.element("ajax-partial");
+
renderQueue.renderPartial(writer, reply);
+
+ writer.end();
+
+ String content = root.getChildMarkup().trim();
+
+ reply.put("content", content);
}
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java?rev=928260&r1=928259&r2=928260&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/RequestConstants.java Sat Mar 27 20:23:58 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,
@@ -14,6 +14,9 @@
package org.apache.tapestry5.internal.services;
+import org.apache.tapestry5.corelib.components.Form;
+import org.apache.tapestry5.corelib.components.FormInjector;
+
/**
* Constants used when processing requests from the client web browser.
*/
@@ -25,22 +28,35 @@ public final class RequestConstants
*/
public static final String ASSET_PATH_PREFIX = "/assets/";
-
/**
* Virtual folder name for assets that are actually stored in the context, but are exposed (much like classpath
* assets) to gain far-future expires headers and automatic content compression. The application version number
* comes after this prefix and before the true path.
- *
+ *
* @since 5.1.0.0
*/
public static final String CONTEXT_FOLDER = "ctx/";
-
/**
* Folder for virtual assets: combined JavaScript files. The file name is actualy a compressed bytestream
* of the names of each file.
- *
+ *
* @since 5.1.0.2
*/
public static final String VIRTUAL_FOLDER = "virtual/";
+
+ /**
+ * Name of parameter, in an Ajax update, that identifies the client-side id of the {@link Form} being extended. Used
+ * with {@link Zone}, {@link FormInjector} and other similar components that may be contained within a form.
+ *
+ * @since 5.2.0
+ */
+ public static final String FORM_CLIENTID_PARAMETER = "t:formid";
+
+ /**
+ * The server-side part of {@link #FORM_CLIENTID_PARAMETER} identifying the server-side component id.
+ *
+ * @since 5.2.0
+ */
+ public static final String FORM_COMPONENTID_PARAMETER = "t:formcomponentid";
}
Added: 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=928260&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateFilter.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateFilter.java Sat Mar 27 20:23:58 2010
@@ -0,0 +1,170 @@
+// 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 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;
+
+/**
+ * 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.
+ *
+ * @since 5.2.0
+ */
+public class AjaxFormUpdateFilter implements ComponentEventRequestFilter
+{
+ private final Request request;
+
+ private final ComponentSource componentSource;
+
+ 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)
+ {
+ this.request = request;
+ this.componentSource = componentSource;
+ this.rules = rules;
+ this.environment = environment;
+ this.heartbeat = heartbeat;
+ this.clientDataEncoder = clientDataEncoder;
+ this.queue = queue;
+ this.logger = logger;
+ }
+
+ public void handle(ComponentEventRequestParameters parameters, ComponentEventRequestHandler handler)
+ throws IOException
+ {
+ String formClientId = request.getParameter(RequestConstants.FORM_CLIENTID_PARAMETER);
+ String formComponentId = request.getParameter(RequestConstants.FORM_COMPONENTID_PARAMETER);
+
+ if (InternalUtils.isNonBlank(formClientId) && InternalUtils.isNonBlank(formComponentId))
+ addFilterToPartialRenderQueue(formClientId, formComponentId);
+
+ 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();
+ }
+
+ };
+ }
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/AjaxFormUpdateFilter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/CaptureResultCallback.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/CaptureResultCallback.java?rev=928260&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/CaptureResultCallback.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/CaptureResultCallback.java Sat Mar 27 20:23:58 2010
@@ -0,0 +1,44 @@
+// 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.util;
+
+import org.apache.tapestry5.ComponentEventCallback;
+
+/**
+ * Implementation of {@link ComponentEventCallback} that simply captures the result value.
+ *
+ * @since 5.2.0
+ */
+public class CaptureResultCallback<T> implements ComponentEventCallback<T>
+{
+ private T result;
+
+ public boolean handleResult(T result)
+ {
+ this.result = result;
+
+ return true;
+ }
+
+ public T getResult()
+ {
+ return result;
+ }
+
+ public static <T> CaptureResultCallback<T> create()
+ {
+ return new CaptureResultCallback<T>();
+ }
+}
Propchange: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/util/CaptureResultCallback.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=928260&r1=928259&r2=928260&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Sat Mar 27 20:23:58 2010
@@ -73,6 +73,7 @@ import org.apache.tapestry5.internal.ren
import org.apache.tapestry5.internal.renderers.ObjectArrayRenderer;
import org.apache.tapestry5.internal.renderers.RequestRenderer;
import org.apache.tapestry5.internal.services.*;
+import org.apache.tapestry5.internal.services.ajax.AjaxFormUpdateFilter;
import org.apache.tapestry5.internal.services.ajax.JavascriptSupportImpl;
import org.apache.tapestry5.internal.services.messages.PropertiesFileParserImpl;
import org.apache.tapestry5.internal.transform.*;
@@ -151,7 +152,7 @@ public final class TapestryModule
* services are always lazy proxies). This isn't
* about efficiency (it may be slightly more efficient, but not in any
* noticable way), it's about eliminating the
- * need to keep injecting these dependencies into invividual service builder
+ * need to keep injecting these dependencies into individual service builder
* and contribution methods.
*/
public TapestryModule(PipelineBuilder pipelineBuilder,
@@ -2078,7 +2079,7 @@ public final class TapestryModule
{
String uid = Long.toHexString(System.currentTimeMillis());
- String namespace = "-" + uid;
+ String namespace = "_" + uid;
IdAllocator idAllocator = new IdAllocator(namespace);
@@ -2102,9 +2103,9 @@ public final class TapestryModule
public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
{
DocumentLinker linker = environment.peekRequired(DocumentLinker.class);
+ JavascriptSupport javascriptSupport = environment.peekRequired(JavascriptSupport.class);
- RenderSupportImpl support = new RenderSupportImpl(linker, symbolSource, assetSource, environment
- .peekRequired(JavascriptSupport.class));
+ RenderSupportImpl support = new RenderSupportImpl(linker, symbolSource, assetSource, javascriptSupport);
environment.push(RenderSupport.class, support);
@@ -2515,6 +2516,21 @@ public final class TapestryModule
}
/**
+ * Contributes:
+ * <dl>
+ * <dt>AjaxFormUpdate</dt>
+ * <dd>{@link AjaxFormUpdateFilter}</dd>
+ * </dl>
+ *
+ * @since 5.2.0
+ */
+ public static void contributeAjaxComponentEventRequestHandler(
+ OrderedConfiguration<ComponentEventRequestFilter> configuration)
+ {
+ configuration.addInstance("AjaxFormUpdate", AjaxFormUpdateFilter.class);
+ }
+
+ /**
* Contributes strategies accessible via the {@link NullFieldStrategySource} service.
* <p/>
* <dl>
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=928260&r1=928259&r2=928260&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 Sat Mar 27 20:23:58 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,
@@ -30,11 +30,11 @@ import java.util.Map;
* Handler for {@link org.apache.tapestry5.ajax.MultiZoneUpdate} responses from a component event handler method. Works
* by adding {@link org.apache.tapestry5.services.ajax.SingleZonePartialRendererFilter}s for each zone to the
* {@linkplain org.apache.tapestry5.internal.services.PageRenderQueue#addPartialMarkupRendererFilter(org.apache.tapestry5.services.PartialMarkupRendererFilter)
- * filter stack}. Each zone writes its content as a string in the zones object of the reply, keyed on its id.
- * JavaScript and CSS are collected for all zones rendered in the request (not for each individua zone). The final
- * repsonse will have some combination of "script", "scripts", "stylesheets", "content" (which is expected to be blank)
+ * filter stack}. Each zone writes its content as a string in the zones object of the reply, keyed on its id.
+ * JavaScript and CSS are collected for all zones rendered in the request (not for each individual zone). The final
+ * response will have some combination of "script", "scripts", "stylesheets", "content" (which is expected to be blank)
* and "zones".
- *
+ *
* @since 5.1.0.1
*/
public class MultiZoneUpdateEventResultProcessor implements ComponentEventResultProcessor<MultiZoneUpdate>
@@ -81,9 +81,8 @@ public class MultiZoneUpdateEventResultP
}
catch (Exception ex)
{
- throw new IllegalArgumentException(String.format("Failure converting renderer for zone '%s': %s",
- zoneId,
- InternalUtils.toMessage(ex)), ex);
+ throw new IllegalArgumentException(String.format("Failure converting renderer for zone '%s': %s", zoneId,
+ InternalUtils.toMessage(ex)), ex);
}
}
-}
\ No newline at end of file
+}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/SetupZonesFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/SetupZonesFilter.java?rev=928260&r1=928259&r2=928260&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/SetupZonesFilter.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ajax/SetupZonesFilter.java Sat Mar 27 20:23:58 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,
@@ -20,9 +20,10 @@ import org.apache.tapestry5.services.Par
import org.apache.tapestry5.services.PartialMarkupRendererFilter;
/**
- * Creates a "zones" object in the JSON reply, reading for the {@link org.apache.tapestry5.services.ajax.SingleZonePartialRendererFilter}s
+ * Creates a "zones" object in the JSON reply, ready for the
+ * {@link org.apache.tapestry5.services.ajax.SingleZonePartialRendererFilter}s
* to store values into.
- *
+ *
* @since 5.1.0.1
*/
public class SetupZonesFilter implements PartialMarkupRendererFilter
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=928260&r1=928259&r2=928260&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 Sat Mar 27 20:23:58 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,
@@ -25,7 +25,7 @@ import org.apache.tapestry5.services.Par
/**
* Responsible for capturing the content for a single zone and storing it into the JSON reply object.
- *
+ *
* @see org.apache.tapestry5.ajax.MultiZoneUpdate
* @since 5.1.0.1
*/
@@ -50,7 +50,7 @@ public class SingleZonePartialRendererFi
{
public void render(MarkupWriter writer, RenderQueue queue)
{
- // Create an element to contain the content for the zone. We give it a menumonic
+ // Create an element to contain the content for the zone. We give it a mnemonic
// element name and attribute just to help with debugging (the element itself is discarded).
final Element zoneContainer = writer.element("zone-update", "zoneId", zoneId);
Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/IdAllocator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/IdAllocator.java?rev=928260&r1=928259&r2=928260&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/IdAllocator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/IdAllocator.java Sat Mar 27 20:23:58 2010
@@ -58,7 +58,7 @@ public final class IdAllocator
}
/**
- * Clones this instance, returning an equivalent but seperate copy.
+ * Clones this instance, returning an equivalent but separate copy.
*/
@SuppressWarnings({ "CloneDoesntDeclareCloneNotSupportedException" })
@Override