You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2012/10/24 01:42:02 UTC

[1/3] git commit: Update AjaxFormLoop, AddRowLink, and RemoveRowLink to the new system - AjaxFormLoop no longer uses FormInjector internally - FormInjector is probably broken

Updated Branches:
  refs/heads/5.4-js-rewrite 3c451a767 -> 78aeeb430


Update AjaxFormLoop, AddRowLink, and RemoveRowLink to the new system
- AjaxFormLoop no longer uses FormInjector internally
- FormInjector is probably broken


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/78aeeb43
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/78aeeb43
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/78aeeb43

Branch: refs/heads/5.4-js-rewrite
Commit: 78aeeb430aca1f9cd1d83e707ac91c799d6f65ca
Parents: 2a69240
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Tue Oct 23 16:40:55 2012 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Tue Oct 23 16:40:55 2012 -0700

----------------------------------------------------------------------
 .../META-INF/modules/core/ajaxformloop.coffee      |   82 +++++++++
 .../tapestry5/corelib/components/AddRowLink.java   |    9 +-
 .../tapestry5/corelib/components/AjaxFormLoop.java |  131 +++++----------
 .../tapestry5/corelib/components/FormInjector.java |    4 +-
 .../corelib/components/RemoveRowLink.java          |   16 +--
 .../corelib/internal/AjaxFormLoopContext.java      |   20 +--
 .../tapestry5/corelib/components/AjaxFormLoop.tml  |   27 ++--
 .../resources/org/apache/tapestry5/tapestry.js     |  107 ------------
 tapestry-core/src/test/app1/FormInjectorDemo.tml   |   39 +++--
 9 files changed, 184 insertions(+), 251 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/78aeeb43/tapestry-core/src/main/coffeescript/META-INF/modules/core/ajaxformloop.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/core/ajaxformloop.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/core/ajaxformloop.coffee
new file mode 100644
index 0000000..e3e3860
--- /dev/null
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/core/ajaxformloop.coffee
@@ -0,0 +1,82 @@
+# Copyright 2012 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.
+
+# ## core/ajaxformloop
+#
+# Provides handlers related to the core/AjaxFormLoop component (as well as core/AddRowLink and
+# core/RemoveRowLink.
+define ["core/spi", "core/events", "core/console", "core/ajax", "core/builder"],
+  (spi, events, console, ajax, builder) ->
+
+    # "afl" is short for "AjaxFormLoop".
+    AFL_SELECTOR = "[data-container-type=core/ajaxformloop]"
+    FRAGMENT_TYPE = "core/ajaxformloop-fragment"
+
+    spi.onDocument "click", "#{AFL_SELECTOR} [data-afl-behavior=remove]", ->
+
+      afl = this.findContainer AFL_SELECTOR
+
+      unless afl
+        console.error "Enclosing element for AjaxFormLoop remove row link not found."
+        return false
+
+      url = afl.attribute "data-remove-row-url"
+
+      ajax url,
+        parameters:
+          "t:rowvalue": this.attribute "data-afl-row-value"
+        onsuccess: =>
+          # The server has removed the row from persistent storage, lets
+          # do the same on the UI.
+
+          fragment = this.findContainer "[data-container-type=#{FRAGMENT_TYPE}]"
+
+          # TODO: Fire some before & after events, so allow for animation.
+
+          # The fragment takes with it the hidden fields that control form submission
+          # for its portion of the form.
+          fragment.remove()
+
+      return false
+
+    spi.onDocument "click", "#{AFL_SELECTOR} [data-afl-behavior=insert-before]", ->
+
+      afl = this.findContainer AFL_SELECTOR
+
+      unless afl
+        console.error "Enclosing element for AjaxFormLoop inject row link not found."
+        return false
+
+      url = afl.attribute "data-inject-row-url"
+
+      ajax url,
+        onsuccess: (response) =>
+          content = response.responseJSON?.content
+
+          insertionPoint = this.findContainer "[data-container-type=#{FRAGMENT_TYPE}]"
+
+          # Create a new element with the same type (usually "div") and class as this element.
+          # It will contain the new content.
+          newElement = builder insertionPoint.element.tagName,
+              class: insertionPoint.element.class,
+              "data-container-type": FRAGMENT_TYPE
+
+          newElement.update content
+
+          insertionPoint.insertBefore newElement
+
+      return false
+
+    # This module is all event handlers, and no exported functions.
+    return null
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/78aeeb43/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AddRowLink.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AddRowLink.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AddRowLink.java
index 61435c4..b9ef3c5 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AddRowLink.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AddRowLink.java
@@ -27,7 +27,7 @@ import org.apache.tapestry5.services.javascript.JavaScriptSupport;
  * row. Triggers a server-side {@linkplain org.apache.tapestry5.EventConstants#ADD_ROW addRow} event on the
  * AjaxFormLoop, which must return the newly added object, which will be rendered in the body of the AjaxFormLoop and
  * sent to the client web browser.
- * 
+ *
  * @tapestrydoc
  */
 @SupportsInformalParameters
@@ -44,12 +44,13 @@ public class AddRowLink
 
     void beginRender(MarkupWriter writer)
     {
-        String id = jsSupport.allocateClientId(resources);
+        writer.element("a",
+                "href", "#",
+                "data-afl-behavior", "insert-before");
 
-        writer.element("a", "id", id, "href", "#");
         resources.renderInformalParameters(writer);
 
-        context.addAddRowTrigger(id);
+
     }
 
     void afterRender(MarkupWriter writer)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/78aeeb43/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
index 4371830..6e0936f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/AjaxFormLoop.java
@@ -1,4 +1,4 @@
-// Copyright 2008, 2009, 2010, 2011 The Apache Software Foundation
+// Copyright 2008, 2009, 2010, 2011, 2012 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,31 +14,20 @@
 
 package org.apache.tapestry5.corelib.components;
 
-import java.util.Collections;
-import java.util.Iterator;
-
 import org.apache.tapestry5.*;
-import org.apache.tapestry5.annotations.Environmental;
-import org.apache.tapestry5.annotations.Events;
-import org.apache.tapestry5.annotations.InjectComponent;
-import org.apache.tapestry5.annotations.Log;
-import org.apache.tapestry5.annotations.Parameter;
-import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.annotations.*;
 import org.apache.tapestry5.corelib.internal.AjaxFormLoopContext;
-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.InternalUtils;
 import org.apache.tapestry5.ioc.services.TypeCoercer;
-import org.apache.tapestry5.json.JSONArray;
 import org.apache.tapestry5.json.JSONObject;
-import org.apache.tapestry5.services.ComponentDefaultProvider;
-import org.apache.tapestry5.services.Environment;
-import org.apache.tapestry5.services.FormSupport;
-import org.apache.tapestry5.services.Heartbeat;
-import org.apache.tapestry5.services.PartialMarkupRenderer;
-import org.apache.tapestry5.services.PartialMarkupRendererFilter;
+import org.apache.tapestry5.services.*;
+import org.apache.tapestry5.services.ajax.AjaxResponseRenderer;
 import org.apache.tapestry5.services.javascript.JavaScriptSupport;
 
+import java.util.Collections;
+import java.util.Iterator;
+
 /**
  * A special form of the {@link org.apache.tapestry5.corelib.components.Loop}
  * component that adds Ajax support to handle adding new rows and removing
@@ -56,17 +45,18 @@ import org.apache.tapestry5.services.javascript.JavaScriptSupport;
  * The addRow event will receive the context specified by the context parameter.
  * <p/>
  * The removeRow event will receive the client-side value for the row being iterated.
- * 
+ *
+ * @tapestrydoc
  * @see EventConstants#ADD_ROW
  * @see EventConstants#REMOVE_ROW
- * @tapestrydoc
  * @see AddRowLink
  * @see RemoveRowLink
  * @see Loop
  * @see FormInjector
  */
 @Events(
-{ EventConstants.ADD_ROW, EventConstants.REMOVE_ROW })
+        {EventConstants.ADD_ROW, EventConstants.REMOVE_ROW})
+@Import(modules = "core/ajaxformloop")
 public class AjaxFormLoop
 {
     /**
@@ -100,7 +90,9 @@ public class AjaxFormLoop
     /**
      * The context for the form loop (optional parameter). This list of values will be converted into strings and
      * included in the URI. The strings will be coerced back to whatever their values are and made available to event
-     * handler methods.
+     * handler methods. Note that the context is only encoded and available to the {@linkplain EventConstants#ADD_ROW addRow}
+     * event; for the {@linkplain EventConstants#REMOVE_ROW} event, the context passed to event handlers
+     * is simply the decoded value for the row that is to be removed.
      */
     @Parameter
     private Object[] context;
@@ -125,15 +117,12 @@ public class AjaxFormLoop
      * "source" parameter) into unique client-side strings (typically IDs) and
      * back. Note: this parameter may be OMITTED if Tapestry is configured to
      * provide a ValueEncoder automatically for the type of property bound to
-     * the "value" parameter. 
+     * the "value" parameter.
      */
     @Parameter(required = true, allowNull = false)
     private ValueEncoder<Object> encoder;
 
     @InjectComponent
-    private ClientElement rowInjector;
-
-    @InjectComponent
     private FormFragment fragment;
 
     @Inject
@@ -154,8 +143,6 @@ public class AjaxFormLoop
     @Inject
     private JavaScriptSupport jsSupport;
 
-    private JSONArray addRowTriggers;
-
     private Iterator iterator;
 
     @Inject
@@ -164,10 +151,9 @@ public class AjaxFormLoop
     @Inject
     private ComponentDefaultProvider defaultProvider;
 
-    @Inject
-    private PageRenderQueue pageRenderQueue;
 
-    private boolean renderingInjector;
+    @Inject
+    private AjaxResponseRenderer ajaxResponseRenderer;
 
     ValueEncoder defaultEncoder()
     {
@@ -176,31 +162,10 @@ public class AjaxFormLoop
 
     private final AjaxFormLoopContext formLoopContext = new AjaxFormLoopContext()
     {
-        public void addAddRowTrigger(String clientId)
-        {
-            assert InternalUtils.isNonBlank(clientId);
-            addRowTriggers.put(clientId);
-        }
-
-        private String currentFragmentId()
-        {
-            ClientElement element = renderingInjector ? rowInjector : fragment;
-
-            return element.getClientId();
-        }
-
-        public void addRemoveRowTrigger(String clientId)
+        @Override
+        public String encodedRowValue()
         {
-            Link link = resources.createEventLink("triggerRemoveRow", toClientValue());
-
-            String asURI = link.toURI();
-
-            JSONObject spec = new JSONObject();
-            spec.put("link", clientId);
-            spec.put("fragment", currentFragmentId());
-            spec.put("url", asURI);
-
-            jsSupport.addInitializerCall("formLoopRemoveLink", spec);
+            return encoder.toClient(value);
         }
     };
 
@@ -299,8 +264,7 @@ public class AjaxFormLoop
     };
 
     @SuppressWarnings(
-    { "unchecked" })
-    @Log
+            {"unchecked"})
     private void syncValue(String clientValue)
     {
         Object value = encoder.toValue(clientValue);
@@ -336,21 +300,28 @@ public class AjaxFormLoop
      * value.
      */
     @SuppressWarnings(
-    { "unchecked" })
+            {"unchecked"})
     private String toClientValue()
     {
         return encoder.toClient(value);
     }
 
-    void setupRender()
+    void setupRender(MarkupWriter writer)
     {
-        addRowTriggers = new JSONArray();
-
         pushContext();
 
         iterator = source == null ? Collections.EMPTY_LIST.iterator() : source.iterator();
 
-        renderingInjector = false;
+        Link removeRowLink = resources.createEventLink("triggerRemoveRow", context);
+        Link injectRowLink = resources.createEventLink("injectRow", context);
+
+        injectRowLink.addParameter(RequestConstants.FORM_CLIENTID_PARAMETER, formSupport.getClientId());
+        injectRowLink.addParameter(RequestConstants.FORM_COMPONENTID_PARAMETER, formSupport.getFormComponentId());
+
+        writer.element("div",
+                "data-container-type", "core/ajaxformloop",
+                "data-remove-row-url", removeRowLink,
+                "data-inject-row-url", injectRowLink);
     }
 
     private void pushContext()
@@ -360,6 +331,8 @@ public class AjaxFormLoop
 
     boolean beginRender(MarkupWriter writer)
     {
+        writer.element("div", "data-container-type", "core/ajaxformloop-fragment");
+
         if (!iterator.hasNext())
             return false;
 
@@ -370,12 +343,13 @@ public class AjaxFormLoop
 
     Object afterRender(MarkupWriter writer)
     {
+        writer.end();
+
         // When out of source items to render, switch over to the addRow block (either the default,
         // or from the addRow parameter) before proceeding to cleanup render.
 
         if (!iterator.hasNext())
         {
-            renderingInjector = true;
             return tail;
         }
 
@@ -384,16 +358,11 @@ public class AjaxFormLoop
         return false;
     }
 
-    void cleanupRender()
+    void cleanupRender(MarkupWriter writer)
     {
-        popContext();
-
-        JSONObject spec = new JSONObject();
-
-        spec.put("rowInjector", rowInjector.getClientId());
-        spec.put("addRowTriggers", addRowTriggers);
+        writer.end();
 
-        jsSupport.addInitializerCall("ajaxFormLoop", spec);
+        popContext();
     }
 
     private void popContext()
@@ -401,12 +370,7 @@ public class AjaxFormLoop
         environment.pop(AjaxFormLoopContext.class);
     }
 
-    /**
-     * When the action event arrives from the FormInjector, we fire our own event, "addRow" to tell the container to add
-     * a new row, and to return that new entity for rendering.
-     */
-    @Log
-    Object onActionFromRowInjector(EventContext context)
+    Object onInjectRow(EventContext context)
     {
         ComponentEventCallback callback = new ComponentEventCallback()
         {
@@ -425,9 +389,7 @@ public class AjaxFormLoop
                     "Event handler for event 'addRow' from %s should have returned a non-null value.",
                     resources.getCompleteId()));
 
-        renderingInjector = true;
-
-        pageRenderQueue.addPartialMarkupRendererFilter(new PartialMarkupRendererFilter()
+        ajaxResponseRenderer.addFilter(new PartialMarkupRendererFilter()
         {
             public void renderMarkup(MarkupWriter writer, JSONObject reply, PartialMarkupRenderer renderer)
             {
@@ -442,13 +404,12 @@ public class AjaxFormLoop
         return ajaxResponse;
     }
 
-    @Log
-    Object onTriggerRemoveRow(String rowId)
+    Object onTriggerRemoveRow(@RequestParameter("t:rowvalue") String encodedValue)
     {
-        Object value = encoder.toValue(rowId);
+        syncValue(encodedValue);
 
         resources.triggerEvent(EventConstants.REMOVE_ROW, new Object[]
-        { value }, null);
+                {value}, null);
 
         return new JSONObject();
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/78aeeb43/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java
index 7feab3a..1330be7 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/FormInjector.java
@@ -108,7 +108,9 @@ public class FormInjector implements ClientElement
     {
         clientId = javascriptSupport.allocateClientId(resources);
 
-        clientElement = writer.element(element, "id", clientId);
+        clientElement = writer.element(element,
+                "id", clientId,
+                "data-container-type", "core/ajaxformloop/fragment");
 
         resources.renderInformalParameters(writer);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/78aeeb43/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/RemoveRowLink.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/RemoveRowLink.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/RemoveRowLink.java
index 683194d..34b63c9 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/RemoveRowLink.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/RemoveRowLink.java
@@ -20,13 +20,12 @@ import org.apache.tapestry5.annotations.Environmental;
 import org.apache.tapestry5.annotations.SupportsInformalParameters;
 import org.apache.tapestry5.corelib.internal.AjaxFormLoopContext;
 import org.apache.tapestry5.ioc.annotations.Inject;
-import org.apache.tapestry5.services.javascript.JavaScriptSupport;
 
 /**
  * Used inside a {@link org.apache.tapestry5.corelib.components.AjaxFormLoop} to remove the current row from the loop.
  * This fires a server-side event (from the AjaxFormLoop component); the event context is the object to be removed. On
  * the client-side, the element for the row is hidden, then removed altogether.
- * 
+ *
  * @tapestrydoc
  */
 @SupportsInformalParameters
@@ -38,22 +37,17 @@ public class RemoveRowLink
     @Environmental
     private AjaxFormLoopContext context;
 
-    @Environmental
-    private JavaScriptSupport jsSupport;
-
     void beginRender(MarkupWriter writer)
     {
-        String clientId = jsSupport.allocateClientId(resources);
-
         writer.element("a",
 
-        "href", "#",
+                "href", "#",
 
-        "id", clientId);
+                "data-afl-behavior", "remove",
 
-        resources.renderInformalParameters(writer);
+                "data-afl-row-value", context.encodedRowValue());
 
-        context.addRemoveRowTrigger(clientId);
+        resources.renderInformalParameters(writer);
     }
 
     void afterRender(MarkupWriter writer)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/78aeeb43/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/AjaxFormLoopContext.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/AjaxFormLoopContext.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/AjaxFormLoopContext.java
index 33768d1..90d7569 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/AjaxFormLoopContext.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/internal/AjaxFormLoopContext.java
@@ -14,8 +14,6 @@
 
 package org.apache.tapestry5.corelib.internal;
 
-import org.apache.tapestry5.services.javascript.JavaScriptSupport;
-
 /**
  * Interface that allows an enclosing {@link org.apache.tapestry5.corelib.components.AjaxFormLoop} to work with enclosed
  * components such as {@link org.apache.tapestry5.corelib.components.AddRowLink} or
@@ -24,18 +22,10 @@ import org.apache.tapestry5.services.javascript.JavaScriptSupport;
 public interface AjaxFormLoopContext
 {
     /**
-     * Adds a clientId to the list of client-side elements that trigger the addition of a new row.
-     * 
-     * @param clientId
-     *            unique id (typically via
-     *            {@link JavaScriptSupport#allocateClientId(org.apache.tapestry5.ComponentResources)})
-     */
-    void addAddRowTrigger(String clientId);
-
-    /**
-     * Used by {@link org.apache.tapestry5.corelib.components.RemoveRowLink} to
-     * 
-     * @param clientId
+     * Returns the {@linkplain org.apache.tapestry5.ValueEncoder encoded} version of the data for the current row.
+     *
+     * @return current row's value, encoded and ready to store in an element attribute
+     * @since 5.4
      */
-    void addRemoveRowTrigger(String clientId);
+    String encodedRowValue();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/78aeeb43/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/AjaxFormLoop.tml
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/AjaxFormLoop.tml b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/AjaxFormLoop.tml
index 1900276..bad4199 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/AjaxFormLoop.tml
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/AjaxFormLoop.tml
@@ -1,21 +1,24 @@
-<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
 
     <t:formfragment t:id="fragment" element="prop:element" visible="true">
         <t:delegate to="block:ajaxResponse"/>
     </t:formfragment>
 
     <t:block id="tail">
-        <t:forminjector element="prop:element" t:id="rowInjector" show="inherit:show" context="inherit:context">
-            <t:delegate to="prop:addRow"/>
-            <t:block id="defaultAddRow">
-                <t:addrowlink>Add row</t:addrowlink>
-            </t:block>
-        </t:forminjector>
+        <div data-container-type="core/ajaxformloop-fragment">
+            <t:any element="prop:element" data-afl-behavior="insert-before">
+                <t:delegate to="prop:addRow"/>
+            </t:any>
+        </div>
+    </t:block>
+
+    <t:block id="defaultAddRow">
+        <t:addrowlink class="btn"><i class="icon-add"/> Add row</t:addrowlink>
+    </t:block>
 
-        <t:block id="ajaxResponse">
-            <t:delegate to="beforeBody"/>
-            <t:body/>
-            <t:delegate to="afterBody"/>
-        </t:block>
+    <t:block id="ajaxResponse">
+        <t:delegate to="beforeBody"/>
+        <t:body/>
+        <t:delegate to="afterBody"/>
     </t:block>
 </t:container>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/78aeeb43/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js b/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
index 46605ee..d9f8db2 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/tapestry.js
@@ -569,113 +569,6 @@ define("core/compat/tapestry", [
 
 
         /**
-         * Used by other initializers to connect an element (either a link
-         * or a form) to a zone.
-         *
-         * @param eventName
-         *            the event on the element to observe
-         * @param element
-         *            the element to observe for events
-         * @param zoneId
-         *            identified a Zone by its clientId. Alternately, the
-         *            special value '^' indicates that the Zone is a
-         *            container of the element (the first container with the
-         *            't-zone' CSS class).
-         * @param url
-         *            The request URL to be triggered when the event is
-         *            observed. Ultimately, a partial page update JSON
-         *            response will be passed to the Zone's ZoneManager.
-         */
-        updateZoneOnEvent: function (eventName, element, zoneId, url) {
-            element = $(element);
-
-            $T(element).zoneUpdater = true;
-
-            var zoneElement = zoneId == '^' ? $(element).up('.t-zone')
-                    : $(zoneId);
-
-            if (!zoneElement) {
-                Tapestry
-                        .error(
-                        "Could not find zone element '#{zoneId}' to update on #{eventName} of element '#{elementId}'.",
-                        {
-                            zoneId: zoneId,
-                            eventName: eventName,
-                            elementId: element.id
-                        });
-                return;
-            }
-
-            /*
-             * Update the element with the id of zone div. This may be
-             * changed dynamically on the client side.
-             */
-
-            $T(element).zoneId = zoneElement.id;
-
-            if (element.tagName == "FORM") {
-
-                // Create the FEM if necessary.
-                element.addClassName(Tapestry.PREVENT_SUBMISSION);
-
-                /*
-                 * After the form is validated and prepared, this code will
-                 * process the form submission via an Ajax call. The
-                 * original submit event will have been cancelled.
-                 */
-
-                element
-                        .observe(
-                        Tapestry.FORM_PROCESS_SUBMIT_EVENT,
-                        function () {
-                            var mgr = Tapestry.findZoneManager(element);
-
-                            if (!mgr) {return;}
-
-                            var successHandler = function (transport) {
-                                mgr.processReply(transport);
-                            };
-
-                            element.sendAjaxRequest(url, {
-                                parameters: {
-                                    "t:zoneid": zoneId
-                                },
-                                onSuccess: successHandler
-                            });
-                        });
-
-                return;
-            }
-
-            /* Otherwise, assume it's just an ordinary link or input field. */
-
-            element.observeAction(eventName, function (event) {
-                element.fire(Tapestry.TRIGGER_ZONE_UPDATE_EVENT);
-            });
-
-            element.observe(Tapestry.TRIGGER_ZONE_UPDATE_EVENT, function () {
-
-                var zoneObject = Tapestry.findZoneManager(element);
-
-                if (!zoneObject)
-                    return;
-
-                /*
-                 * A hack related to allowing a Select to perform an Ajax
-                 * update of the page.
-                 */
-
-                var parameters = {};
-
-                if (element.tagName == "SELECT" && element.value) {
-                    parameters["t:selectvalue"] = element.value;
-                }
-
-                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.

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/78aeeb43/tapestry-core/src/test/app1/FormInjectorDemo.tml
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/app1/FormInjectorDemo.tml b/tapestry-core/src/test/app1/FormInjectorDemo.tml
index cd971fd..99ab2e9 100644
--- a/tapestry-core/src/test/app1/FormInjectorDemo.tml
+++ b/tapestry-core/src/test/app1/FormInjectorDemo.tml
@@ -1,35 +1,42 @@
 <html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
 
-  <h1>FormInjector Demo (now including AjaxFormLoop)</h1>
+<h1>FormInjector Demo (now including AjaxFormLoop)</h1>
 
-  <t:form>
+<t:form>
+
+    <div class="well span8" t:id="loop" t:type="AjaxFormLoop" source="doubleItems" value="item"
+         encoder="doubleItemEncoder" context="demoContextValue">
 
-    <ul>
-      <li t:id="loop" t:type="AjaxFormLoop" source="doubleItems" value="item" encoder="doubleItemEncoder" context="demoContextValue">
         <t:submitnotifier>
-          <t:textfield t:id="value" value="item.value"/>
-          <t:removerowlink>remove</t:removerowlink>
+            <div class="control-group">
+                <div class="controls">
+                    <div class="input-append">
+                        <t:textfield t:id="value" value="item.value"/>
+                        <t:removerowlink class="btn btn-warning addon">remove</t:removerowlink>
+                    </div>
+                </div>
+            </div>
         </t:submitnotifier>
+
         <t:parameter name="addRow">
-          <t:addrowlink>Add a row</t:addrowlink>
+            <t:addrowlink class="btn btn-mini">Add another value</t:addrowlink>
         </t:parameter>
-      </li>
-    </ul>
+    </div>
 
-    <div class="t-beaneditor-row">
-      <input type="submit" value="Sum up the values"/>
+    <div class="form-actions">
+        <input type="submit" class="btn btn-primary" value="Sum up the values"/>
     </div>
 
-  </t:form>
+</t:form>
 
-  <p>
+<p>
     Current sum:
     <span id="sum">${sum}</span>
-  </p>
+</p>
 
-  <h2>Data</h2>
+<h2>Data</h2>
 
-  <t:grid source="doubleItems"/>
+<t:grid source="doubleItems"/>
 
 
 </html>
\ No newline at end of file