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 2007/11/28 02:29:18 UTC

svn commit: r598842 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry/corelib/components/ main/java/org/apache/tapestry/corelib/mixins/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/json/ m...

Author: hlship
Date: Tue Nov 27 17:29:16 2007
New Revision: 598842

URL: http://svn.apache.org/viewvc?rev=598842&view=rev
Log:
Add client-side Tapestry.Zone object, to manage effects around hiding and updating Ajax zones.
Add ZoneSetup service, to collect all zone initialization in one place (helps to minimize JavaScript).

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetup.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetupImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetupImplTest.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Zone.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/mixins/Autocomplete.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/json/JSONArray.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/json/JSONObject.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/tapestry.js
    tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/ajax.apt

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java?rev=598842&r1=598841&r2=598842&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/ActionLink.java Tue Nov 27 17:29:16 2007
@@ -19,6 +19,7 @@
 import org.apache.tapestry.annotations.Environmental;
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.annotations.SupportsInformalParameters;
+import org.apache.tapestry.internal.services.ZoneSetup;
 import org.apache.tapestry.ioc.annotations.Inject;
 
 import java.util.List;
@@ -43,6 +44,9 @@
     @Environmental
     private PageRenderSupport _support;
 
+    @Environmental
+    private ZoneSetup _zoneSetup;
+
     /**
      * If true, then then no link element is rendered (and no informal parameters as well). The body
      * is, however, still rendered.
@@ -73,10 +77,7 @@
 
         _resources.renderInformalParameters(writer);
 
-        // TODO: Extend PRS or add a new environmental, to collect the link/zone connections
-        // and execute them as a single block (to generate less JavaScript).
-
-        if (_zone != null) _support.addScript("Tapestry.linkZone('%s', '%s');", _clientId, _zone);
+        if (_zone != null) _zoneSetup.linkZone(_clientId, _zone);
     }
 
     void afterRender(MarkupWriter writer)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Zone.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Zone.java?rev=598842&r1=598841&r2=598842&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Zone.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Zone.java Tue Nov 27 17:29:16 2007
@@ -22,7 +22,9 @@
 import org.apache.tapestry.annotations.Parameter;
 import org.apache.tapestry.annotations.SupportsInformalParameters;
 import org.apache.tapestry.dom.Element;
+import org.apache.tapestry.internal.services.ZoneSetup;
 import org.apache.tapestry.ioc.annotations.Inject;
+import org.apache.tapestry.json.JSONObject;
 
 
 /**
@@ -41,6 +43,9 @@
     @Environmental
     private PageRenderSupport _pageRenderSupport;
 
+    @Environmental
+    private ZoneSetup _zoneSetup;
+
     /**
      * 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.
@@ -64,6 +69,11 @@
         if (!_visible) e.addClassName("t-invisible");
 
         // And continue on to render the body
+
+        JSONObject spec = new JSONObject();
+        spec.put("div", _clientId);
+
+        _zoneSetup.addZone(_clientId, null, null);
     }
 
     void afterRender(MarkupWriter writer)

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/mixins/Autocomplete.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/mixins/Autocomplete.java?rev=598842&r1=598841&r2=598842&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/mixins/Autocomplete.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/mixins/Autocomplete.java Tue Nov 27 17:29:16 2007
@@ -22,7 +22,6 @@
 import org.apache.tapestry.internal.util.Holder;
 import org.apache.tapestry.ioc.annotations.Inject;
 import org.apache.tapestry.ioc.services.TypeCoercer;
-import org.apache.tapestry.json.JSONArray;
 import org.apache.tapestry.json.JSONObject;
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.services.MarkupWriterFactory;
@@ -161,13 +160,10 @@
 
         if (_resources.isBound("tokens"))
         {
-            JSONArray tokens = new JSONArray();
             for (int i = 0; i < _tokens.length(); i++)
             {
-                tokens.put(_tokens.substring(i, i + 1));
+                config.accumulate("tokens", _tokens.substring(i, i + 1));
             }
-
-            config.put("tokens", tokens);
         }
 
         _pageRenderSupport.addScript("new Ajax.Autocompleter('%s', '%s', '%s', %s);", id, menuId, link, config);

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetup.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetup.java?rev=598842&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetup.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetup.java Tue Nov 27 17:29:16 2007
@@ -0,0 +1,44 @@
+// Copyright 2007 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.tapestry.internal.services;
+
+/**
+ * Collects details about zone usage for effecient initialization on the client side.
+ */
+public interface ZoneSetup
+{
+    /**
+     * Adds a new client-side Tapestry.Zone object. Zones are linked to a
+     * an element (typically, a &lt;div&gt;).  A Zone may have handlers
+     * used to initially show it, or to highlight it when its content changes.
+     * Such handlers are referenced by name, as functions of the
+     * Tapestry.ZoneEffects object.
+     *
+     * @param clientId           client-side id of the element that will be updated by the zone
+     * @param showFunctionName   name of the function used to initially show the zone (if not visible), or null for default
+     * @param updateFunctionName name of function used to highlight the function after an update, or null for default
+     */
+    void addZone(String clientId, String showFunctionName, String updateFunctionName);
+
+    /**
+     * Sets the client-side onclick handler for an &lt;a&gt; element to perform an Ajax update
+     * of a zone.
+     *
+     * @param linkId    id of the link to Ajax enable
+     * @param elementId id of an element that has been previously registered as a Zone
+     */
+    void linkZone(String linkId, String elementId);
+}
+

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetupImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetupImpl.java?rev=598842&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetupImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetupImpl.java Tue Nov 27 17:29:16 2007
@@ -0,0 +1,70 @@
+// Copyright 2007 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.tapestry.internal.services;
+
+import org.apache.tapestry.PageRenderSupport;
+import org.apache.tapestry.json.JSONArray;
+import org.apache.tapestry.json.JSONObject;
+
+public class ZoneSetupImpl implements ZoneSetup
+{
+    static final String INITIALIZER_STRING = "Tapestry.initializeZones(%s, %s);";
+
+    private final PageRenderSupport _pageRenderSupport;
+
+    private final JSONArray _zones = new JSONArray();
+
+    private final JSONArray _links = new JSONArray();
+
+    private boolean _dirty;
+
+    public ZoneSetupImpl(PageRenderSupport pageRenderSupport)
+    {
+        _pageRenderSupport = pageRenderSupport;
+    }
+
+    public void addZone(String clientId, String showFunctionName, String updateFunctionName)
+    {
+        JSONObject spec = new JSONObject();
+        spec.put("div", clientId);
+
+        if (showFunctionName != null) spec.put("show", showFunctionName.toLowerCase());
+
+        if (updateFunctionName != null) spec.put("update", updateFunctionName.toLowerCase());
+
+        _zones.put(spec);
+
+        _dirty = true;
+    }
+
+    public void linkZone(String linkId, String elementId)
+    {
+        JSONArray spec = new JSONArray();
+        spec.put(linkId);
+        spec.put(elementId);
+
+        _links.put(spec);
+
+        _dirty = true;
+
+    }
+
+    public void writeInitializationScript()
+    {
+        if (!_dirty) return;
+
+        _pageRenderSupport.addScript(INITIALIZER_STRING, _zones, _links);
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetupImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetupImplTest.java?rev=598842&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetupImplTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ZoneSetupImplTest.java Tue Nov 27 17:29:16 2007
@@ -0,0 +1,125 @@
+// Copyright 2007 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.tapestry.internal.services;
+
+import org.apache.tapestry.PageRenderSupport;
+import static org.apache.tapestry.internal.services.ZoneSetupImpl.INITIALIZER_STRING;
+import org.apache.tapestry.json.JSONObject;
+import org.apache.tapestry.test.TapestryTestCase;
+import org.testng.annotations.Test;
+
+public class ZoneSetupImplTest extends TapestryTestCase
+{
+    @Test
+    public void no_changes()
+    {
+        PageRenderSupport support = mockPageRenderSupport();
+
+        replay();
+
+        ZoneSetupImpl setup = new ZoneSetupImpl(support);
+
+        setup.writeInitializationScript();
+
+        verify();
+    }
+
+    @Test
+    public void add_links()
+    {
+        PageRenderSupport support = mockPageRenderSupport();
+
+        JSONObject template = new JSONObject("{ zones: [], links: [['client1', 'zone1'], ['client2', 'zone2']] }");
+
+        support.addScript(INITIALIZER_STRING, template.getJSONArray("zones"), template.getJSONArray("links"));
+
+        replay();
+
+        ZoneSetupImpl setup = new ZoneSetupImpl(support);
+
+        setup.linkZone("client1", "zone1");
+        setup.linkZone("client2", "zone2");
+
+        setup.writeInitializationScript();
+
+        verify();
+    }
+
+    @Test
+    public void add_zones()
+    {
+        PageRenderSupport support = mockPageRenderSupport();
+
+        JSONObject template = new JSONObject("{ zones: [ {div:'client1'}, {div:'client2'} ], links:[] }");
+
+        support.addScript(INITIALIZER_STRING, template.getJSONArray("zones"), template.getJSONArray("links"));
+
+        replay();
+
+        ZoneSetupImpl setup = new ZoneSetupImpl(support);
+
+        setup.addZone("client1", null, null);
+        setup.addZone("client2", null, null);
+
+        setup.writeInitializationScript();
+
+        verify();
+    }
+
+    @Test
+    public void zones_with_functions()
+    {
+        PageRenderSupport support = mockPageRenderSupport();
+
+
+        JSONObject template = new JSONObject(
+                "{ zones: [ {div:'client1', show:'showme'}, {div:'client2', update:'updateme'} ], links:[] }");
+
+        support.addScript(INITIALIZER_STRING, template.getJSONArray("zones"), template.getJSONArray("links"));
+
+        replay();
+
+        ZoneSetupImpl setup = new ZoneSetupImpl(support);
+
+        setup.addZone("client1", "showme", null);
+        setup.addZone("client2", null, "updateme");
+
+        setup.writeInitializationScript();
+
+        verify();
+    }
+
+    @Test
+    public void zone_function_names_are_converted_to_lower_case()
+    {
+        PageRenderSupport support = mockPageRenderSupport();
+
+        JSONObject template = new JSONObject(
+                "{ zones: [ {div:'client1', show:'showme'}, {div:'client2', update:'updateme'} ], links:[] }");
+
+        support.addScript(INITIALIZER_STRING, template.getJSONArray("zones"), template.getJSONArray("links"));
+
+        replay();
+
+        ZoneSetupImpl setup = new ZoneSetupImpl(support);
+
+        setup.addZone("client1", "ShowMe", null);
+        setup.addZone("client2", null, "UpdateMe");
+
+        setup.writeInitializationScript();
+
+        verify();
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/json/JSONArray.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/json/JSONArray.java?rev=598842&r1=598841&r2=598842&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/json/JSONArray.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/json/JSONArray.java Tue Nov 27 17:29:16 2007
@@ -83,7 +83,7 @@
  * @author JSON.org
  * @version 2
  */
-public class JSONArray
+public final class JSONArray
 {
 
     /**
@@ -417,5 +417,17 @@
     Object[] toArray()
     {
         return _list.toArray();
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null) return false;
+
+        if (!(obj instanceof JSONArray)) return false;
+
+        JSONArray other = (JSONArray) obj;
+
+        return _list.equals(other._list);
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/json/JSONObject.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/json/JSONObject.java?rev=598842&r1=598841&r2=598842&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/json/JSONObject.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/json/JSONObject.java Tue Nov 27 17:29:16 2007
@@ -859,4 +859,22 @@
         }
         return quote(value.toString());
     }
+
+    /**
+     * Returns true if the other object is a JSONObject and its set of properties
+     * matches this object's properties.
+     * <p/>
+     * '
+     */
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null) return false;
+
+        if (!(obj instanceof JSONObject)) return false;
+
+        JSONObject other = (JSONObject) obj;
+
+        return _properties.equals(other._properties);
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java?rev=598842&r1=598841&r2=598842&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java Tue Nov 27 17:29:16 2007
@@ -1166,7 +1166,7 @@
      * <dt>{@link org.apache.tapestry.json.JSONObject}</dt>
      * <dd>The JSONObject is returned as a text/javascript response</dd>
      * <dt>{@link org.apache.tapestry.StreamResponse}</dt>
-     * <dd>The stream response is sent as the actual response</dd>*
+     * <dd>The stream response is sent as the actual response</dd>
      * </dl>
      */
 
@@ -1274,6 +1274,7 @@
      * Adds basic render initializers:
      * <dl>
      * <dt>PageRenderSupport</dt>  <dd>Provides {@link PageRenderSupport}</dd>
+     * <dt>ZoneSetup</dt> <dd>Provides {@link ZoneSetup}</dd>
      * <dt>Heartbeat</dt> <dd>Provides {@link org.apache.tapestry.services.Heartbeat}</dd>
      * <dt>DefaultValidationDecorator</dt>
      * <dd>Provides {@link org.apache.tapestry.ValidationDecorator} (as {@link org.apache.tapestry.internal.DefaultValidationDecorator})</dd>
@@ -1323,6 +1324,24 @@
             }
         };
 
+        MarkupRendererFilter zoneSetup = new MarkupRendererFilter()
+        {
+            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
+            {
+                PageRenderSupport pageRenderSupport = _environment.peekRequired(PageRenderSupport.class);
+
+                ZoneSetupImpl setup = new ZoneSetupImpl(pageRenderSupport);
+
+                _environment.push(ZoneSetup.class, setup);
+
+                renderer.renderMarkup(writer);
+
+                _environment.pop(ZoneSetup.class);
+
+                setup.writeInitializationScript();
+            }
+        };
+
         MarkupRendererFilter heartbeat = new MarkupRendererFilter()
         {
             public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
@@ -1360,6 +1379,7 @@
 
 
         configuration.add("PageRenderSupport", pageRenderSupport);
+        configuration.add("ZoneSetup", zoneSetup, "after:PageRenderSupport");
         configuration.add("Heartbeat", heartbeat);
         configuration.add("DefaultValidationDecorator", defaultValidationDecorator);
     }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/test/TapestryTestCase.java?rev=598842&r1=598841&r2=598842&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/test/TapestryTestCase.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/test/TapestryTestCase.java Tue Nov 27 17:29:16 2007
@@ -954,4 +954,9 @@
     {
         return newMock(FieldValidationSupport.class);
     }
+
+    protected final PageRenderSupport mockPageRenderSupport()
+    {
+        return newMock(PageRenderSupport.class);
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/tapestry.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/tapestry.js?rev=598842&r1=598841&r2=598842&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/tapestry.js (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry/tapestry.js Tue Nov 27 17:29:16 2007
@@ -14,6 +14,12 @@
 
 var Tapestry = {
 
+    FormEvent : Class.create(),
+
+    FieldEventManager : Class.create(),
+
+    Zone : Class.create(),
+
     registerForm : function(form, clientValidations)
     {
         form = $(form);
@@ -132,12 +138,12 @@
     },
 
     // Convert a link into a trigger of an Ajax update that
-    // updates the indicated zone.
+    // updates the indicated Zone.
 
-    linkZone : function(link, zone)
+    linkZone : function(link, zoneDiv)
     {
         link = $(link);
-        zone = $(zone);
+        var zone = $(zoneDiv).zone;
 
         var clickHandler = function(event)
         {
@@ -146,9 +152,7 @@
                 var response = transport.responseText;
                 var reply = eval("(" + response + ")");
 
-                zone.innerHTML = reply.content;
-
-                zone.show();
+                zone.show(reply.content);
             };
 
             var request = new Ajax.Request(link.href, { onSuccess : successHandler });
@@ -159,11 +163,23 @@
         link.onclick = clickHandler;
     },
 
+    initializeZones : function (zoneSpecs, linkSpecs)
+    {
+        // Each spec is a hash ready to pass to Tapestry.Zone
 
+        $A(zoneSpecs).each(function (spec)
+        {
+            new Tapestry.Zone(spec);
+        });
 
-    FormEvent : Class.create(),
+        // Each spec is a pair of values suitable for the linkZone method
+
+        $A(linkSpecs).each(function (spec)
+        {
+            Tapestry.linkZone.apply(null, spec);
+        });
+    },
 
-    FieldEventManager : Class.create(),
 
     // Adds a validator for a field.  A FieldEventManager is added, if necessary.
     // The validator will be called only for non-blank values, unless acceptBlank is
@@ -386,6 +402,52 @@
 
         if (! event.error)
             this.removeDecorations(event);
+    }
+};
+
+// Wrappers around Prototype and Scriptaculous effects, invoked from Tapestry.Zone.show().
+
+Tapestry.ZoneEffect = {
+
+    show : function(element)
+    {
+        element.show();
+    },
+
+    highlight : function(element)
+    {
+        new Effect.Highlight(element);
+    }
+};
+
+
+Tapestry.Zone.prototype = {
+    // spec are the parameters for the Zone:
+    // trigger: required -- name or instance of link.
+    // div: required -- name or instance of div element to be shown, hidden and updated
+    // show: name of Tapestry.ZoneEffect function used to reveal the zone if hidden
+    // update: name of Tapestry.ZoneEffect function used to highlight the zone after it is updated
+    initialize: function(spec)
+    {
+        this.div = $(spec.div);
+        this.showFunc = Tapestry.ZoneEffect[spec.show] || Tapestry.ZoneEffect.show;
+        this.updateFunc = Tapestry.ZoneEffect[spec.update] || Tapestry.ZoneEffect.highlight;
+
+        // Link the div back to this zone.
+
+        this.div.zone = this;
+    },
+
+    // Updates the content of the div controlled by this Zone, then
+    // invokes the show function (if not visible) or the update function (if visible).
+
+    show: function(content)
+    {
+        this.div.innerHTML = content;
+
+        var func = this.div.visible() ? this.updateFunc : this.showFunc;
+
+        func.call(this, this.div);
     }
 };
 

Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/ajax.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/ajax.apt?rev=598842&r1=598841&r2=598842&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/ajax.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/ajax.apt Tue Nov 27 17:29:16 2007
@@ -78,7 +78,7 @@
 
 +---+
 
-  The Asset is injected, using the ${tapestry.scriptaculous} symbol to reference the location
+  The Asset is injected, using the $\{tapestry.scriptaculous\} symbol to reference the location
   of the Scriptaculous library.
 
   The PageRenderSupport is accessed as an Environmental service.
@@ -132,7 +132,9 @@
   Inside a component, you should use Environmental, to highlight the fact that PageRenderSupport (like most
   environmental objects) is only available during rendering, not during action requests.
 
-Autocomplete Mixin
+Ajax Components and Mixins
+
+* Autocomplete Mixin
 
   The
   {{{../../apidocs/org/apache/tapestry/corelib/mixins/Autocomplete.html}Autocomplete}}
@@ -186,4 +188,39 @@
 
   You may override <<<DIV.t-autocomplete-menu UL>>> to change the main look and feel,
   <<<DIV.t-autocomplete-menu LI>>> for a normal item in the popup list, and
-   <<<DIV.t-autocomplete-menu LI.selected>>> for the element under the cursor (or selecting using the arrow keys).
\ No newline at end of file
+   <<<DIV.t-autocomplete-menu LI.selected>>> for the element under the cursor (or selecting using the arrow keys).
+
+* Zone
+
+  Details coming soon.
+
+Your own Ajax Components
+
+  A study of the Autocomplete mixin's code should be very helpful: it shows how to
+  ask the ComponentResources object to create a link.
+
+  The key part is the way Tapestry invokes a component event handler method on the component.
+
+  For an Ajax request, the return value from an event handler method is processed differently
+  than for a traditional action request.  In an normal request, the return value
+  is the normally name of a page (to redirect to), or the Class of a page to redirect to, or
+  an instance of a page to redirect to.
+
+  For an Ajax request, a redirect is not sent: any response is rendered as part of the same
+  request and sent back immediately.
+
+  The possible return values are:
+
+  * A Block or Component to render as the response.
+
+  * A {{{../../apidocs/org/apache/tapestry/json/JSONObject.html}JSONObject}}, which will be sent as the response.
+
+  * A {{{../../apidocs/org/apache/tapestry/StreamResponse.html}StreamResponse}}, which will be sent as the response.
+
+  []
+
+  In the case of a  Block or Component, the rendering occurs but is packaged up as a JSON response.
+  The JSON response contains a single map containing a single key: "content" whose value is the markup
+  generated from the component or block.
+
+