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/08 13:28:26 UTC
(myfaces-tobago) branch main updated: fix(behavior): Avoid error msg when using cc:clientBehavior with targ… (#4858)
This is an automated email from the ASF dual-hosted git repository.
bommel pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
The following commit(s) were added to refs/heads/main by this push:
new 4057d8ad65 fix(behavior): Avoid error msg when using cc:clientBehavior with targ… (#4858)
4057d8ad65 is described below
commit 4057d8ad65666cd0c419159eca4fb30bdcc37ba6
Author: Bernd Bohmann <bo...@apache.org>
AuthorDate: Thu Feb 8 14:28:21 2024 +0100
fix(behavior): Avoid error msg when using cc:clientBehavior with targ… (#4858)
* fix(behavior): Avoid error msg when using cc:clientBehavior with target attribute and f:ajax and @this
issue: TOBAGO-2287
---
.../renderer/TobagoClientBehaviorRenderer.java | 6 ++--
.../apache/myfaces/tobago/util/ComponentUtils.java | 41 +++++++++++++++++++---
.../src/test/resources/renderer/button/ajax.html | 2 +-
.../Composite_Components.xhtml | 6 ++++
.../resources/demo-components/inputAsText.xhtml | 1 +
5 files changed, 47 insertions(+), 9 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 7d307edca4..a100c11a12 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
@@ -106,10 +106,10 @@ public class TobagoClientBehaviorRenderer extends jakarta.faces.render.ClientBeh
}
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 442f775601..8c8c5aee66 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
@@ -648,6 +648,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 > 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();
@@ -659,8 +683,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++;
@@ -692,9 +717,15 @@ 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:") && id.endsWith(component.getId())) {
+ // case for cc:clientBehavior with targets attribute
+ // @this:<id>)
+ result.add(component.getClientId(context));
+ } else {
+ final String clientId = evaluateClientId(context, component, id);
+ if (clientId != null) {
+ result.add(clientId);
+ }
}
}
}
@@ -710,7 +741,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 5e4493256e..095fd84321 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="jakarta.faces.composite/demo-components"
xmlns:tc="http://myfaces.apache.org/tobago/component"
xmlns:ui="jakarta.faces.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:inputAsText id="clientBehavior">
+ <f:ajax event="change" execute="@this" render="clientBehavior" />
+ </dc:inputAsText>
+ </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 4e68353cae..a4fb244863 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}"/>