You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by bo...@apache.org on 2024/02/09 18:10:27 UTC

(myfaces-tobago) branch tobago-5.x updated: fix(behavior): Avoid error msg when using cc:clientBehavior with target attribute

This is an automated email from the ASF dual-hosted git repository.

bommel pushed a commit to branch tobago-5.x
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git


The following commit(s) were added to refs/heads/tobago-5.x by this push:
     new f4b7bc1586 fix(behavior): Avoid error msg when using cc:clientBehavior with target attribute
f4b7bc1586 is described below

commit f4b7bc1586a8e18b7df7c511cc5fbd9b8e20dab1
Author: Bernd Bohmann <bo...@apache.org>
AuthorDate: Fri Feb 9 19:10:21 2024 +0100

    fix(behavior): Avoid error msg when using cc:clientBehavior with target attribute
    
    fix(behavior): Avoid error msg when using cc:clientBehavior with target attribute and f:ajax and @this
    issue: TOBAGO-2287
    
    (cherry picked from commit 4057d8ad65666cd0c419159eca4fb30bdcc37ba6)
    
    (cherry picked from commit d3d12c8e790aaecc1d9b060ef1257bc371719041)
---
 .../renderer/TobagoClientBehaviorRenderer.java     |  6 +--
 .../apache/myfaces/tobago/util/ComponentUtils.java | 44 +++++++++++++++++++---
 .../src/test/resources/renderer/button/ajax.html   |  2 +-
 .../Composite_Components.xhtml                     |  6 +++
 .../resources/demo-components/inputAsText.xhtml    |  1 +
 ...xhtml => inputsWithClientBehaviorTargets.xhtml} | 13 ++++---
 6 files changed, 58 insertions(+), 14 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TobagoClientBehaviorRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TobagoClientBehaviorRenderer.java
index 4f3243f42b..cc934ab963 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TobagoClientBehaviorRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TobagoClientBehaviorRenderer.java
@@ -105,10 +105,10 @@ public class TobagoClientBehaviorRenderer extends javax.faces.render.ClientBehav
       }
 
       executeIds = ComponentUtils.evaluateClientIds(facesContext, uiComponent, execute.toArray(new String[0]));
-      if (executeIds != null) {
-        executeIds = executeIds + " " + clientId;
-      } else {
+      if (executeIds == null) {
         executeIds = clientId;
+      } else if (!executeIds.contains(clientId)) {
+        executeIds = executeIds + " " + clientId;
       }
       if (uiComponent instanceof AbstractUICommand) { // <f:ajax> inside of a command
         final AbstractUICommand command = (AbstractUICommand) uiComponent;
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/util/ComponentUtils.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/util/ComponentUtils.java
index 1ad7ab3e82..2646b972ca 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/util/ComponentUtils.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/util/ComponentUtils.java
@@ -647,6 +647,30 @@ public final class ComponentUtils {
    * </p>
    */
   public static UIComponent findComponent(final UIComponent from, final String relativeId) {
+    return findComponent(FacesContext.getCurrentInstance(), from, relativeId);
+  }
+    /**
+     * <p>
+     * The search depends on the number of prefixed colons in the relativeId:
+     * </p>
+     * <dl>
+     * <dd>number of prefixed colons == 0</dd>
+     * <dt>fully relative</dt>
+     * <dd>number of prefixed colons == 1</dd>
+     * <dt>absolute (still normal findComponent syntax)</dt>
+     * <dd>number of prefixed colons == 2</dd>
+     * <dt>search in the current naming container (same as 0 colons)</dt>
+     * <dd>number of prefixed colons == 3</dd>
+     * <dt>search in the parent naming container of the current naming container</dt>
+     * <dd>number of prefixed colons &gt; 3</dd>
+     * <dt>go to the next parent naming container for each additional colon</dt>
+     * </dl>
+     * <p>
+     * If a literal is specified: to use more than one identifier the identifiers must be space delimited.
+     * </p>
+     */
+  public static UIComponent findComponent(
+      final FacesContext facesContext, final UIComponent from, final String relativeId) {
     UIComponent from1 = from;
     String relativeId1 = relativeId;
     final int idLength = relativeId1.length();
@@ -658,8 +682,9 @@ public final class ComponentUtils {
 
     // Figure out how many colons
     int colonCount = 0;
+    char separatorChar = UINamingContainer.getSeparatorChar(facesContext);
     while (colonCount < idLength) {
-      if (relativeId1.charAt(colonCount) != UINamingContainer.getSeparatorChar(FacesContext.getCurrentInstance())) {
+      if (relativeId1.charAt(colonCount) != separatorChar) {
         break;
       }
       colonCount++;
@@ -691,9 +716,18 @@ public final class ComponentUtils {
     final List<String> result = new ArrayList<>(componentIds.length);
     for (final String id : componentIds) {
       if (!StringUtils.isBlank(id)) {
-        final String clientId = evaluateClientId(context, component, id);
-        if (clientId != null) {
-          result.add(clientId);
+        if (id.startsWith("@this:")) {
+          if (id.endsWith(component.getId())) {
+            // case for cc:clientBehavior with targets attribute
+            // @this:<id>)
+            result.add(component.getClientId(context));
+          }
+          // skip the others clientBehavior targets
+        } else {
+          final String clientId = evaluateClientId(context, component, id);
+          if (clientId != null) {
+            result.add(clientId);
+          }
         }
       }
     }
@@ -709,7 +743,7 @@ public final class ComponentUtils {
    */
   public static String evaluateClientId(
       final FacesContext context, final UIComponent component, final String componentId) {
-    final UIComponent partiallyComponent = ComponentUtils.findComponent(component, componentId);
+    final UIComponent partiallyComponent = ComponentUtils.findComponent(context, component, componentId);
     if (partiallyComponent != null) {
       final String clientId = partiallyComponent.getClientId(context);
       if (partiallyComponent instanceof AbstractUISheet) {
diff --git a/tobago-core/src/test/resources/renderer/button/ajax.html b/tobago-core/src/test/resources/renderer/button/ajax.html
index aad008ba7b..d23b199efc 100644
--- a/tobago-core/src/test/resources/renderer/button/ajax.html
+++ b/tobago-core/src/test/resources/renderer/button/ajax.html
@@ -15,4 +15,4 @@
  * limitations under the License.
 -->
 
-<button type='button' id='id' name='id' class='tobago-button btn btn-secondary tobago-auto-spacing'><tobago-behavior event='click' client-id='id' execute='id id' render='id' reset-values='reset-values'></tobago-behavior><span>button</span></button>
+<button type='button' id='id' name='id' class='tobago-button btn btn-secondary tobago-auto-spacing'><tobago-behavior event='click' client-id='id' execute='id' render='id' reset-values='reset-values'></tobago-behavior><span>button</span></button>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/5500-compositeComponent/Composite_Components.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/5500-compositeComponent/Composite_Components.xhtml
index 2fd01b877d..64e491c3a0 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/5500-compositeComponent/Composite_Components.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/5500-compositeComponent/Composite_Components.xhtml
@@ -19,6 +19,7 @@
 
 <ui:composition template="/main.xhtml"
                 xmlns="http://www.w3.org/1999/xhtml"
+                xmlns:f="http://xmlns.jcp.org/jsf/core"
                 xmlns:dc="http://xmlns.jcp.org/jsf/composite/demo-components"
                 xmlns:tc="http://myfaces.apache.org/tobago/component"
                 xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
@@ -64,4 +65,9 @@
       <dc:inputAsTextPanelWrapper id="splitLayoutNotRendered" value="this should NOT be rendered" rendered="false"/>
     </tc:splitLayout>
   </tc:section>
+  <tc:section label="clientBehavior">
+    <dc:inputsWithClientBehaviorTargets id="clientBehavior" label="label" value="test">
+      <f:ajax event="change" execute="@this" render="clientBehavior" />
+    </dc:inputsWithClientBehaviorTargets>
+  </tc:section>
 </ui:composition>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/resources/demo-components/inputAsText.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/resources/demo-components/inputAsText.xhtml
index 84b829304c..5a14da14bc 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/resources/demo-components/inputAsText.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/resources/demo-components/inputAsText.xhtml
@@ -24,6 +24,7 @@
   <cc:attribute name="label"/>
   <cc:attribute name="value"/>
   <cc:attribute name="asText" default="false"/>
+  <cc:clientBehavior name="change" event="change" targets="in"/>
 </cc:interface>
 <cc:implementation>
   <tc:in id="in" label="#{cc.attrs.label}" value="#{cc.attrs.value}" rendered="#{!cc.attrs.asText}"/>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/resources/demo-components/inputAsText.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/resources/demo-components/inputsWithClientBehaviorTargets.xhtml
similarity index 72%
copy from tobago-example/tobago-example-demo/src/main/webapp/resources/demo-components/inputAsText.xhtml
copy to tobago-example/tobago-example-demo/src/main/webapp/resources/demo-components/inputsWithClientBehaviorTargets.xhtml
index 84b829304c..e170a54d21 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/resources/demo-components/inputAsText.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/resources/demo-components/inputsWithClientBehaviorTargets.xhtml
@@ -16,17 +16,20 @@
  * limitations under the License.
 -->
 <!DOCTYPE html
-        PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns:cc="http://xmlns.jcp.org/jsf/composite"
+      xmlns:f="http://xmlns.jcp.org/jsf/core"
       xmlns:tc="http://myfaces.apache.org/tobago/component">
 <cc:interface>
   <cc:attribute name="label"/>
   <cc:attribute name="value"/>
-  <cc:attribute name="asText" default="false"/>
+  <cc:clientBehavior name="change" event="change" targets="in1 in2"/>
 </cc:interface>
 <cc:implementation>
-  <tc:in id="in" label="#{cc.attrs.label}" value="#{cc.attrs.value}" rendered="#{!cc.attrs.asText}"/>
-  <tc:out id="out" label="#{cc.attrs.label}" value="#{cc.attrs.value}" rendered="#{cc.attrs.asText}"/>
+  <tc:in id="in1" label="#{cc.attrs.label}" value="#{cc.attrs.value}" >
+    <f:ajax execute="@this"/>
+  </tc:in>
+  <tc:in id="in2" label="#{cc.attrs.label}" value="#{cc.attrs.value}"/>
 </cc:implementation>
 </html>