You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by jw...@apache.org on 2008/02/14 19:01:30 UTC

svn commit: r627816 - in /myfaces/trinidad/branches/jwaldman_1.2-issue936: trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/ trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ trinidad-api/src/test/java/org/apache/myfaces/trinida...

Author: jwaldman
Date: Thu Feb 14 10:01:21 2008
New Revision: 627816

URL: http://svn.apache.org/viewvc?rev=627816&view=rev
Log:
change RenderUtils.java's getRelativeId method to work the same way as ComponentUtils's findRelativeComponent method in that '::' pops out one naming container, ':::' pops out two, etc.

Also added a render/RenderUtilsTest.java test

Added:
    myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/test/java/org/apache/myfaces/trinidad/render/
    myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/test/java/org/apache/myfaces/trinidad/render/RenderUtilsTest.java
Modified:
    myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/RenderUtils.java
    myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ComponentUtils.java
    myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-examples/trinidad-demo/src/main/webapp/demos/testRelativePartialTriggers.jspx

Modified: myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/RenderUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/RenderUtils.java?rev=627816&r1=627815&r2=627816&view=diff
==============================================================================
--- myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/RenderUtils.java (original)
+++ myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/main/java/org/apache/myfaces/trinidad/render/RenderUtils.java Thu Feb 14 10:01:21 2008
@@ -24,6 +24,7 @@
 import javax.faces.component.NamingContainer;
 import javax.faces.component.UIComponent;
 import javax.faces.component.UIForm;
+import javax.faces.component.UIViewRoot;
 import javax.faces.context.FacesContext;
 
 import org.apache.myfaces.trinidad.component.UIXForm;
@@ -102,67 +103,125 @@
   }
 
   /**
-   * Returns a relative ID for use at rendering time, e.g. "for"
-   * attributes on components.  It does not assume that the target
-   * component can be located.  A relative ID starting with
+   * Given a 'from' component and a relativeId, 
+   * return an ID for use at rendering time that will identify the
+   * id of the component you are referencing on the client.
+   * This is used for attributes like e.g. "for" and "chooseId".
+   * 
+   * <p>
+   * e.g., given this hierarchy
+   * 
+   *  <f:subview id="aaa">
+        <f:subview id="xxx">
+           <tr:chooseColor id="cp1" .../>
+            <f:subview id="yyy">
+               <tr:inputColor id="sic1" chooseId="::cp1" .../>
+            </f:subview>
+         </f:subview>
+      </f:subview>
+   * The 'from' component is the inputColor component
+   * The 'relativeId' is "::cp1". ('::' pops up one naming container)
+   * The return value is 'aaa:xxx:cp1' when
+   * the clientId of the 'xxx' component is 'aaa:xxx'.
+   * *
+   * </p>
+   * <p>
+   * It does not assume that the target component can be located.
+   * 
+   * A relativeId starting with
    * NamingContainer.SEPARATOR_CHAR (that is, ':') will be
    * treated as absolute (after dropping that character).
+   * A relativeId with no colons means it is within the same naming container
+   * as the 'from' component (this is within the 'from' component if 'from'
+   * is a naming container).
+   * A relativeId starting with '::' pops out of the 'from' component's
+   * naming container. A relativeId with ':::' pops up two naming containers, etc.
+   * ComponentUtils.findRelativeComponent finds the component, whereas
+   * this method returns a relativeId that can be used during renderering 
+   * so the component can be found in javascript on the client.
+   * 
+   * </p>
+   * @param context
+   * @param from       
+   * @param relativeId
+   * @return
    */
   public static String getRelativeId(
     FacesContext context,
     UIComponent  from,
     String       relativeId)
   {
+    if (from == null)
+        return null;
+    
     if ((relativeId == null) || (relativeId.length() == 0))
       return null;
     
-    UIComponent parentNC;
-    if (relativeId.charAt(0) == NamingContainer.SEPARATOR_CHAR)
+    int idLength = relativeId.length();
+    // Figure out how many colons
+    int colonCount = 0;
+    while (colonCount < idLength)
     {
-      if (relativeId.length() > 1 && relativeId.charAt(1)
-        == NamingContainer.SEPARATOR_CHAR)
-      {
-        parentNC = _getParentNamingContainer(from.getParent());
-        int index = 2;
-        for (; index < relativeId.length() && relativeId.charAt(index) 
-          == NamingContainer.SEPARATOR_CHAR && parentNC != null; ++index)
-        {
-          parentNC = _getParentNamingContainer(parentNC.getParent());
-        }
-        if (parentNC == null || index >= relativeId.length())
-        {
-          // TODO: would it be better to return null from here?
-          return relativeId;
-        }
-        relativeId = relativeId.substring(index);
-      }
-      else
-      {
-        return relativeId.substring(1);
-      }
+      if (relativeId.charAt(colonCount) != NamingContainer.SEPARATOR_CHAR)
+        break;
+      colonCount++;
     }
+
+    // colonCount == 0: fully relative
+    // colonCount == 1: absolute 
+    // colonCount > 1: for each extra colon after 1, pop out of
+    // the naming container (to the view root, if naming containers run out)
+    if (colonCount == 1)
+      return relativeId.substring(1);
+    else if (colonCount > 1)
+    {
+      relativeId = relativeId.substring(colonCount);
+    }
+      
+    // if the component is not a NamingContainer, then we need to 
+    // get the component's naming container and set this as the 'from'.
+
+    if (!(from instanceof NamingContainer))
+    {
+      from = _getParentNamingContainer(from);
+    }
+    
+    // pop out of the naming containers if there are multiple colons
+    // from will be null if there are no more naming containers
+    for (int j = 1; j < colonCount; j++)
+    {
+      from = _getParentNamingContainer(from);
+    }
+
+
+    if (from == null)
+      return relativeId;
     else
     {
-      parentNC = _getParentNamingContainer(from.getParent());
-      if (parentNC == null)
-      {
-        return relativeId;
-      }
+      return (from.getClientId(context) +
+              NamingContainer.SEPARATOR_CHAR + relativeId);
     }
 
-    return (parentNC.getClientId(context) +
-            NamingContainer.SEPARATOR_CHAR + relativeId);
   }
 
-  private static UIComponent _getParentNamingContainer(UIComponent from)
+  // Given a component, get its naming container. If the component
+  // is a naming container, it will get its naming container.
+  // This is different than the one in ComponentUtils. This one
+  // returns null if there are no more NamingContainers. The other one
+  // returns the ViewRoot.
+  private static UIComponent _getParentNamingContainer (
+    UIComponent from)
   {
-    while (from != null)
+
+    while (from != null && from.getParent() != null)
     {
+      from = from.getParent();
       if (from instanceof NamingContainer)
         return from;
-      from = from.getParent();
     }
 
     return null;
   }
+
+
 }

Modified: myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ComponentUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ComponentUtils.java?rev=627816&r1=627815&r2=627816&view=diff
==============================================================================
--- myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ComponentUtils.java (original)
+++ myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ComponentUtils.java Thu Feb 14 10:01:21 2008
@@ -395,6 +395,7 @@
   
   // given a component, get its naming container. If the component
   // is a naming container, it will get its naming container.
+  // if no parent naming containers exist, it stops at the ViewRoot.
   private static UIComponent _getParentNamingContainer (
     UIComponent from)
   {

Added: myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/test/java/org/apache/myfaces/trinidad/render/RenderUtilsTest.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/test/java/org/apache/myfaces/trinidad/render/RenderUtilsTest.java?rev=627816&view=auto
==============================================================================
--- myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/test/java/org/apache/myfaces/trinidad/render/RenderUtilsTest.java (added)
+++ myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-api/src/test/java/org/apache/myfaces/trinidad/render/RenderUtilsTest.java Thu Feb 14 10:01:21 2008
@@ -0,0 +1,199 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.myfaces.trinidad.component;
+
+
+import javax.faces.component.NamingContainer;
+
+import javax.faces.context.FacesContext;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.myfaces.trinidad.render.RenderUtils;
+
+
+public class RenderUtilsTest extends TestCase
+{
+  public static final Test suite()
+  {
+    return new TestSuite(RenderUtilsTest.class);
+  }
+
+  public static void main(String[] args) throws Throwable
+  {
+    junit.textui.TestRunner.run(suite());
+  }
+
+  public RenderUtilsTest(
+    String testName)
+  {
+    super(testName);
+  }
+
+  static private class TestNamingContainer extends UIXPanel
+                                           implements NamingContainer
+  {
+    @Override
+    public String getClientId(FacesContext context)
+    {
+      // NOTE - client ids cannot be cached because the generated
+      // value has to be dynamically calculated in some cases (UIData)
+
+      String clientId = getId() + "_Client";
+      return clientId;
+    }
+  }
+  
+  static private class TestUIXPanel extends UIXPanel
+  {
+    @Override
+    public String getClientId(FacesContext context)
+    {
+      // NOTE - client ids cannot be cached because the generated
+      // value has to be dynamically calculated in some cases (UIData)
+
+      String clientId = getId() + "_Client";
+      return clientId;
+    }
+  }
+
+
+  // Test sibling components where one is a table and one is a button
+  @SuppressWarnings("unchecked")
+  public void testButtonAndNamingContainerSiblings()
+  {
+      // set up a button and a table that are siblings
+      // under a rootPanel (not a naming container)
+      // no naming containers above these components.
+      UIXCommand button1 = new UIXCommand();
+      button1.setId("commandButton1");
+
+      TestNamingContainer table1 = new TestNamingContainer();
+      table1.setId("table1");
+      TestUIXPanel rootPanel = new TestUIXPanel();
+      rootPanel.setId("rootPanel");
+      rootPanel.getChildren().add(button1);
+      rootPanel.getChildren().add(table1);
+    
+    String relativeId = 
+      RenderUtils.getRelativeId(null, button1, "table1");
+    assertEquals("table1", relativeId);
+    
+    // to get to the commandButton from the table, you need to pop out of the 
+    // table.
+    relativeId = 
+      RenderUtils.getRelativeId(null, table1, "::commandButton1");
+    assertEquals("commandButton1", relativeId);
+    
+    relativeId = 
+      RenderUtils.getRelativeId(null, table1, ":commandButton1");
+    assertEquals("commandButton1", relativeId); 
+    
+    relativeId = 
+      RenderUtils.getRelativeId(null, button1, ":table1");
+    assertEquals("table1", relativeId);
+
+
+  }
+
+
+
+  @SuppressWarnings("unchecked")
+  public void testRelativeSearch()
+  {
+    /*<f:subview id="ncRoot">
+     *  <commandButton1>
+     *  <commandButton2>
+     *   <f:subview id="nc1">
+     *     <tr:inputText id="inputA" pT="::commandButton1"/>
+           <tr:panelGroupLayout>
+             <tr:inputText
+             id="input1"
+             for="::commandButton1"/>
+           </tr:panelGroupLayout>
+          </f:subview>
+       </f:subview>
+     */
+
+      // set up component hierarchy
+      UIXForm form = new UIXForm(); form.setId("formId");
+      TestNamingContainer ncRoot = new TestNamingContainer(); ncRoot.setId("ncRoot");
+      UIXCommand button1 = new UIXCommand();
+      button1.setId("button1");
+      UIXCommand button2 = new UIXCommand();
+      button2.setId("button2");
+
+      form.getChildren().add(ncRoot);
+      ncRoot.getChildren().add(button1);
+      ncRoot.getChildren().add(button2);
+
+      TestNamingContainer nc = new TestNamingContainer(); 
+      nc.setId("nc1");
+
+          
+      UIXInput inputA = new UIXInput(); inputA.setId("inputA");
+      UIXPanel panel1 = new UIXPanel(); panel1.setId("panel1");
+      UIXInput input1 = new UIXInput(); input1.setId("input1");
+      ncRoot.getChildren().add(nc);
+      nc.getChildren().add(inputA);
+      nc.getChildren().add(panel1);
+      panel1.getChildren().add(input1);
+      
+    
+    String relativeId = 
+      RenderUtils.getRelativeId(null, input1, "::button1");
+    // old way
+    //assertEquals("nc1_Client:button1", relativeId);
+    
+    // new way should pop OUT of this with two ::
+    assertEquals("ncRoot_Client:button1", relativeId); 
+    
+ 
+    relativeId = 
+      RenderUtils.getRelativeId(null, input1, ":::button1");
+    // old way
+    //assertEquals("ncRoot_Client:button1", relativeId);
+    
+    // new way should pop OUT of both NC with two :::
+    assertEquals("button1", relativeId); 
+    
+    relativeId = 
+      RenderUtils.getRelativeId(null, input1, "::::button1");
+    
+    // old way returns the original id (THIS IS A BUG).
+    //assertEquals(":::::button1", relativeId);
+    
+    // new way should return this
+    assertEquals("button1", relativeId);
+    
+    relativeId = 
+      RenderUtils.getRelativeId(null, input1, ":::::button1");
+    
+    // old way returns the original id (THIS IS A BUG).
+    //assertEquals(":::::button1", relativeId);
+    
+    // new way should return this
+    assertEquals("button1", relativeId);
+  }
+
+
+
+}

Modified: myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-examples/trinidad-demo/src/main/webapp/demos/testRelativePartialTriggers.jspx
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-examples/trinidad-demo/src/main/webapp/demos/testRelativePartialTriggers.jspx?rev=627816&r1=627815&r2=627816&view=diff
==============================================================================
--- myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-examples/trinidad-demo/src/main/webapp/demos/testRelativePartialTriggers.jspx (original)
+++ myfaces/trinidad/branches/jwaldman_1.2-issue936/trinidad-examples/trinidad-demo/src/main/webapp/demos/testRelativePartialTriggers.jspx Thu Feb 14 10:01:21 2008
@@ -135,7 +135,9 @@
           <tr:inputText partialTriggers="inputText5" label="value submitted" id="xxxxx" readOnly="true"
                          value="#{testTriggers.inputText5Value}"/>
           <tr:inputText partialTriggers="::autosf:inputText5" label="value submitted" id="xxxxxy" readOnly="true"
-                         value="#{testTriggers.inputText5Value}"/>                             
+                         value="#{testTriggers.inputText5Value}"/>   
+          <tr:inputText partialTriggers=":::::::autosf:inputText5" label="value submitted" id="xxxxxz" readOnly="true"
+                         value="#{testTriggers.inputText5Value}"/>                           
         </tr:subform>