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 2008/01/18 02:48:13 UTC

svn commit: r613037 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry/corelib/base/ main/java/org/apache/tapestry/corelib/components/ main/java/org/apache/tapestry/internal/services/ test/java/org/apache/tapestry/internal/...

Author: hlship
Date: Thu Jan 17 17:48:12 2008
New Revision: 613037

URL: http://svn.apache.org/viewvc?rev=613037&view=rev
Log:
TAPESTRY-2057: Add EventLink component that can create a link that triggers an arbitrarily named event in its container

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractComponentActionLink.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/EventLink.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractLink.java
    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/GridColumns.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/PageLink.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/RequestPathOptimizerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/RequestPathOptimizerImplTest.java

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractComponentActionLink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractComponentActionLink.java?rev=613037&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractComponentActionLink.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractComponentActionLink.java Thu Jan 17 17:48:12 2008
@@ -0,0 +1,91 @@
+// Copyright 2008 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.corelib.base;
+
+import org.apache.tapestry.*;
+import org.apache.tapestry.annotations.Environmental;
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.internal.services.ZoneSetup;
+import org.apache.tapestry.ioc.annotations.Inject;
+
+import java.util.List;
+
+public abstract class AbstractComponentActionLink extends AbstractLink implements ClientElement
+{
+    /**
+     * The context for the link (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.
+     */
+    @Parameter
+    private List<?> _context;
+
+    /**
+     * Binding zone turns the link into a an Ajax control that causes the related zone to be updated.
+     */
+    @Parameter(defaultPrefix = TapestryConstants.LITERAL_BINDING_PREFIX)
+    private String _zone;
+
+    @Inject
+    private ComponentResources _resources;
+
+    @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.
+     */
+    @Parameter("false")
+    private boolean _disabled;
+
+    private String _clientId;
+
+    void beginRender(MarkupWriter writer)
+    {
+        if (_disabled) return;
+
+        _clientId = _support.allocateClientId(_resources.getId());
+
+        Object[] contextArray = _context == null ? new Object[0] : _context.toArray();
+
+        Link link = createLink(contextArray);
+
+        writeLink(writer, _clientId, link);
+
+        if (_zone != null) _zoneSetup.linkZone(_clientId, _zone);
+    }
+
+    /**
+     * Invoked to create the Link that will become the href attribute of the output.
+     */
+    protected abstract Link createLink(Object[] eventContext);
+
+
+    void afterRender(MarkupWriter writer)
+    {
+        if (_disabled) return;
+
+        writer.end(); // <a>
+    }
+
+    public String getClientId()
+    {
+        return _clientId;
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractLink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractLink.java?rev=613037&r1=613036&r2=613037&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractLink.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractLink.java Thu Jan 17 17:48:12 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 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.
@@ -19,6 +19,7 @@
 import org.apache.tapestry.MarkupWriter;
 import static org.apache.tapestry.TapestryConstants.LITERAL_BINDING_PREFIX;
 import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.annotations.SupportsInformalParameters;
 import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.internal.services.ComponentInvocationMap;
 import org.apache.tapestry.ioc.annotations.Inject;
@@ -26,6 +27,7 @@
 /**
  * Provides base utilities for classes that generate clickable links.
  */
+@SupportsInformalParameters
 public abstract class AbstractLink
 {
     @Inject
@@ -50,16 +52,16 @@
     }
 
     /**
-     * Writes an &lt;a&gt; element with the provided link as the href attribute.  A call to
-     * {@link org.apache.tapestry.MarkupWriter#end()} is <em>not</em> provided.            Automatically appends
-     * an anchor if the component's anchor parameter is non-null.  Informal parameters are rendered as well.
+     * Writes an &lt;a&gt; element with the provided link as the href attribute.  A call to {@link
+     * org.apache.tapestry.MarkupWriter#end()} is <em>not</em> provided.            Automatically appends an anchor if
+     * the component's anchor parameter is non-null.  Informal parameters are rendered as well.
      *
      * @param writer         to write markup to
      * @param clientId       value written as the id attribute
      * @param link           the link that will form the href
      * @param namesAndValues additional attributes to write
      */
-    protected void writeLink(MarkupWriter writer, String clientId, Link link, Object... namesAndValues)
+    protected final void writeLink(MarkupWriter writer, String clientId, Link link, Object... namesAndValues)
     {
         Element e = writer.element("a", "href", buildHref(link), "id", clientId);
 
@@ -73,7 +75,7 @@
     /**
      * Used for testing.
      */
-    void inject(String anchor, ComponentInvocationMap map, ComponentResources resources)
+    final void inject(String anchor, ComponentInvocationMap map, ComponentResources resources)
     {
         _anchor = anchor;
         _componentInvocationMap = map;

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=613037&r1=613036&r2=613037&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 Thu Jan 17 17:48:12 2008
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007 The Apache Software Foundation
+// Copyright 2006, 2007, 2008 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,81 +14,23 @@
 
 package org.apache.tapestry.corelib.components;
 
-import org.apache.tapestry.*;
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.Link;
 import static org.apache.tapestry.TapestryConstants.ACTION_EVENT;
-import org.apache.tapestry.annotations.Environmental;
-import org.apache.tapestry.annotations.Parameter;
-import org.apache.tapestry.annotations.SupportsInformalParameters;
-import org.apache.tapestry.corelib.base.AbstractLink;
-import org.apache.tapestry.internal.services.ZoneSetup;
+import org.apache.tapestry.corelib.base.AbstractComponentActionLink;
 import org.apache.tapestry.ioc.annotations.Inject;
 
-import java.util.List;
-
 /**
  * Component that triggers an action on the server with a subsequent full page refresh.
  */
-@SupportsInformalParameters
-public class ActionLink extends AbstractLink implements ClientElement
+public class ActionLink extends AbstractComponentActionLink
 {
-    /**
-     * The context for the link (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.
-     */
-    @Parameter
-    private List<?> _context;
-
     @Inject
     private ComponentResources _resources;
 
-    @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.
-     */
-    @Parameter("false")
-    private boolean _disabled;
-
-    private String _clientId;
-
-
-    /**
-     * Binding zone turns the link into a an Ajax control that causes the
-     * related zone to be updated.
-     */
-    @Parameter(defaultPrefix = TapestryConstants.LITERAL_BINDING_PREFIX)
-    private String _zone;
-
-    void beginRender(MarkupWriter writer)
+    protected Link createLink(Object[] contextArray)
     {
-        if (_disabled) return;
-
-        _clientId = _support.allocateClientId(_resources.getId());
-
-        Object[] contextArray = _context == null ? new Object[0] : _context.toArray();
-
-        Link link = _resources.createActionLink(ACTION_EVENT, false, contextArray);
-
-        writeLink(writer, _clientId, link);
-
-        if (_zone != null) _zoneSetup.linkZone(_clientId, _zone);
+        return _resources.createActionLink(ACTION_EVENT, false, contextArray);
     }
 
-    void afterRender(MarkupWriter writer)
-    {
-        if (_disabled) return;
-
-        writer.end(); // <a>
-    }
-
-    public String getClientId()
-    {
-        return _clientId;
-    }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/EventLink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/EventLink.java?rev=613037&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/EventLink.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/EventLink.java Thu Jan 17 17:48:12 2008
@@ -0,0 +1,53 @@
+// Copyright 2008 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.corelib.components;
+
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.Link;
+import org.apache.tapestry.TapestryConstants;
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.corelib.base.AbstractComponentActionLink;
+import org.apache.tapestry.ioc.annotations.Inject;
+
+/**
+ * A close relative of {@link org.apache.tapestry.corelib.components.ActionLink} except in two ways.
+ * <p/>
+ * First, the event that it triggers is explicitly controlled, rather than always "action".
+ * <p/>
+ * Second, the event is triggered in its container.
+ * <p/>
+ * This allows slightly shorter URLs but also allows multiple components within the same container to generate identical
+ * URLs for common actions.
+ */
+public class EventLink extends AbstractComponentActionLink
+{
+    /**
+     * The name of the event to be triggered in the parent component.  An {@link org.apache.tapestry.corelib.components.ActionLink}
+     * triggers an "action" event on itself, and EventLink component triggers any arbitrary event on <em>its
+     * container</em>.
+     */
+    @Parameter(required = true, defaultPrefix = TapestryConstants.LITERAL_BINDING_PREFIX)
+    private String _event;
+
+    @Inject
+    private ComponentResources _resources;
+
+    protected Link createLink(Object[] eventContext)
+    {
+        ComponentResources containerResources = _resources.getContainerResources();
+
+        return containerResources.createActionLink(_event, false, eventContext);
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java?rev=613037&r1=613036&r2=613037&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/GridColumns.java Thu Jan 17 17:48:12 2008
@@ -26,30 +26,29 @@
 import java.util.List;
 
 /**
- * Renders out the column headers for the grid. Eventually, this will include control over column
- * sorting, perhaps even column ordering.
+ * Renders out the column headers for the grid. Eventually, this will include control over column sorting, perhaps even
+ * column ordering.
  */
 public class GridColumns
 {
     /**
-     * The object that provides access to bean and data models, which is typically the enclosing
-     * Grid component.
+     * The object that provides access to bean and data models, which is typically the enclosing Grid component.
      */
     @Parameter(value = "componentResources.container")
     private GridModelProvider _dataProvider;
 
     /**
-     * If true, then the CSS class on each &lt;TH&gt; cell will be omitted, which can reduce
-     * the amount of output from the component overall by a considerable amount. Leave this as false, the
-     * default, when you are leveraging the CSS to customize the look and feel of particular columns.
+     * If true, then the CSS class on each &lt;TH&gt; cell will be omitted, which can reduce the amount of output from
+     * the component overall by a considerable amount. Leave this as false, the default, when you are leveraging the CSS
+     * to customize the look and feel of particular columns.
      */
     @Parameter
     private boolean _lean;
 
     /**
-     * The column which is currently being sorted. This value is the column's
-     * {@link PropertyModel#getId() id}, not its {@link PropertyModel#getPropertyName() name}.
-     * This parameter may be null, in which case no column is being used for sorting.
+     * The column which is currently being sorted. This value is the column's {@link PropertyModel#getId() id}, not its
+     * {@link PropertyModel#getPropertyName() name}. This parameter may be null, in which case no column is being used
+     * for sorting.
      */
     @Parameter(required = true)
     private String _sortColumnId;
@@ -61,8 +60,8 @@
     private boolean _sortAscending;
 
     @SuppressWarnings("unused")
-    @Component(parameters = {"disabled=sortDisabled", "context=columnModel.id", "class=sortLinkClass"})
-    private ActionLink _sort, _sort2;
+    @Component(parameters = {"event=sort", "disabled=sortDisabled", "context=columnModel.id", "class=sortLinkClass"})
+    private EventLink _sort, _sort2;
 
     @Inject
     @Path("sort-asc.png")
@@ -105,7 +104,7 @@
         return _columnModel.getId().equals(_sortColumnId);
     }
 
-    void onActionFromSort(String columnId)
+    void onSort(String columnId)
     {
         if (columnId.equals(_sortColumnId))
         {
@@ -116,11 +115,6 @@
             _sortColumnId = columnId;
             _sortAscending = true;
         }
-    }
-
-    void onActionFromSort2(String columnId)
-    {
-        onActionFromSort(columnId);
     }
 
     public Asset getIcon()

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/PageLink.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/PageLink.java?rev=613037&r1=613036&r2=613037&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/PageLink.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/PageLink.java Thu Jan 17 17:48:12 2008
@@ -1,4 +1,4 @@
-// Copyright 2007 The Apache Software Foundation
+// Copyright 2007, 2008 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -17,23 +17,19 @@
 import org.apache.tapestry.*;
 import org.apache.tapestry.annotations.Environmental;
 import org.apache.tapestry.annotations.Parameter;
-import org.apache.tapestry.annotations.SupportsInformalParameters;
 import org.apache.tapestry.corelib.base.AbstractLink;
 import org.apache.tapestry.ioc.annotations.Inject;
 
 import java.util.List;
 
 /**
- * Generates a render request link to some other page in the application. If an activation context
- * is supplied (as the context parameter), then the context values will be encoded into the URL. If
- * no context is supplied, then the target page itself will supply the context via a passivate
- * event.
+ * Generates a render request link to some other page in the application. If an activation context is supplied (as the
+ * context parameter), then the context values will be encoded into the URL. If no context is supplied, then the target
+ * page itself will supply the context via a passivate event.
  * <p/>
- * Pages are not required to have an activation context. When a page does have an activation
- * context, the value typically represents the identity of some object displayed or otherwise
- * manipulated by the page.
+ * Pages are not required to have an activation context. When a page does have an activation context, the value
+ * typically represents the identity of some object displayed or otherwise manipulated by the page.
  */
-@SupportsInformalParameters
 public class PageLink extends AbstractLink implements ClientElement
 {
     /**
@@ -49,8 +45,8 @@
     private PageRenderSupport _support;
 
     /**
-     * If true, then then no link element is rendered (and no informal parameters as well). The body
-     * is, however, still rendered.
+     * If true, then then no link element is rendered (and no informal parameters as well). The body is, however, still
+     * rendered.
      */
     @Parameter("false")
     private boolean _disabled;
@@ -58,9 +54,8 @@
     private String _clientId;
 
     /**
-     * If provided, this is the activation context for the target page (the information will be
-     * encoded into the URL). If not provided, then the target page will provide its own activation
-     * context.
+     * If provided, this is the activation context for the target page (the information will be encoded into the URL).
+     * If not provided, then the target page will provide its own activation context.
      */
     @Parameter
     private List _context;

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/RequestPathOptimizerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/RequestPathOptimizerImpl.java?rev=613037&r1=613036&r2=613037&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/RequestPathOptimizerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/RequestPathOptimizerImpl.java Thu Jan 17 17:48:12 2008
@@ -27,8 +27,8 @@
     private final boolean _forceFull;
 
     /**
-     * Used to split a URI up into individual folder/file names. Any number of consecutive slashes is treated as
-     * a single slash.
+     * Used to split a URI up into individual folder/file names. Any number of consecutive slashes is treated as a
+     * single slash.
      */
     private final Pattern SLASH_PATTERN = Pattern.compile("/+");
 
@@ -95,6 +95,21 @@
             builder.append(pathTerms[j]);
 
             sep = "/";
+        }
+
+        // A colon before the first slash confuses the browser; it thinks its a really long
+        // protocol specifier (like "http:").
+
+        int firstColon = builder.indexOf(":");
+        if (firstColon > 0)
+        {
+            int slashx = builder.indexOf("/");
+
+            // Prefixing with "./" disambiguates the path and the colon, though
+            // most likely we're going to end up choosing the full path rather than
+            // the relative one.
+
+            if (slashx > firstColon) builder.insert(0, "./");
         }
 
         if (builder.length() < path.length()) return builder.toString();

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/RequestPathOptimizerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/RequestPathOptimizerImplTest.java?rev=613037&r1=613036&r2=613037&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/RequestPathOptimizerImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/services/RequestPathOptimizerImplTest.java Thu Jan 17 17:48:12 2008
@@ -68,9 +68,12 @@
 
                               {"/verylongcontextname", "/eventhandlerdemo.barney/one",
                                "/verylongcontextname/eventhandlerdemo.clear/anything",
-                               "../eventhandlerdemo.clear/anything"}
+                               "../eventhandlerdemo.clear/anything"},
 
-        };
+                              {"/verylongcontextname", "/page", "/verylongcontextname/page:sort/foo",
+                               "./page:sort/foo"},
+
+                              {"", "/page", "/page:sort/foo", "/page:sort/foo"}};
     }
 
     @Test(dataProvider = "uri_optimization")