You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2025/05/09 10:12:13 UTC
(myfaces-tobago) branch tobago-5.x updated: fix: no client validation while immediate (#6421)
This is an automated email from the ASF dual-hosted git repository.
lofwyr 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 7f6856271e fix: no client validation while immediate (#6421)
7f6856271e is described below
commit 7f6856271e46d480dda7e5b6912779f68ccbc5bb
Author: Udo Schnurpfeil <lo...@apache.org>
AuthorDate: Fri May 9 12:12:07 2025 +0200
fix: no client validation while immediate (#6421)
issue: TOBAGO-2418
---
.../myfaces/tobago/internal/renderkit/Command.java | 28 +++++++++++++++++
.../renderkit/renderer/TabGroupRenderer.java | 3 ++
.../renderer/TobagoClientBehaviorRenderer.java | 6 +++-
.../myfaces/tobago/internal/util/RenderUtils.java | 3 +-
.../myfaces/tobago/renderkit/RendererBase.java | 4 ++-
.../tobago/renderkit/html/CustomAttributes.java | 1 +
.../tobago/internal/renderkit/CommandUnitTest.java | 6 ++--
.../tobago/internal/util/JsonUtilsUnitTest.java | 15 ++++-----
.../2510-tab-file/TabGroup_Immediate_File.xhtml | 36 ++++++++++++++++++++++
.../tobago-theme-standard/src/main/js/tobago.js | 2 +-
.../src/main/js/tobago.js.map | 2 +-
.../src/main/ts/tobago-behavior.ts | 21 +++++++++++--
12 files changed, 109 insertions(+), 18 deletions(-)
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/Command.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/Command.java
index b65d330fb4..81ddf1af81 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/Command.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/Command.java
@@ -39,7 +39,24 @@ public class Command {
private Boolean resetValues;
private Boolean stopPropagation;
private String customEventName;
+ private Boolean immediate;
+ public Command(
+ final String clientId, final String fieldId, final Boolean transition, final String target, final String execute,
+ final String render, final String confirmation, final Integer delay,
+ final Collapse collapse, final Boolean omit, final Boolean stopPropagation, final String customEventName,
+ final Boolean immediate) {
+ this(clientId, fieldId, transition, target, execute, render, confirmation, delay, collapse, omit, stopPropagation,
+ customEventName);
+ this.immediate = immediate;
+ }
+
+ /**
+ * @deprecated Please use
+ * {@link Command#Command(String, String, Boolean, String, String, String, String, Integer, Collapse, Boolean,
+ * Boolean, String, Boolean)}
+ */
+ @Deprecated(since = "6.7.2")
public Command(
final String clientId, final String fieldId, final Boolean transition, final String target, final String execute,
final String render, final String confirmation, final Integer delay,
@@ -158,6 +175,14 @@ public String getCustomEventName() {
return customEventName;
}
+ public Boolean getImmediate() {
+ return immediate;
+ }
+
+ public void setImmediate(Boolean immediate) {
+ this.immediate = immediate;
+ }
+
public void merge(final Command c) {
//XXX TBD: check if this is okay.
@@ -210,5 +235,8 @@ public void merge(final Command c) {
if (customEventName == null) {
customEventName = c.customEventName;
}
+ if (immediate == null) {
+ immediate = c.immediate;
+ }
}
}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java
index 36f58b594f..7ac5fa89ce 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TabGroupRenderer.java
@@ -79,6 +79,7 @@ public void processEvent(final ComponentSystemEvent event) {
final AbstractUITabGroup tabGroup = (AbstractUITabGroup) event.getComponent();
final FacesContext facesContext = FacesContext.getCurrentInstance();
final ClientBehaviors tabChange = ClientBehaviors.tabChange;
+ final boolean immediate = tabGroup.isImmediate();
switch (tabGroup.getSwitchType()) {
case none:
break;
@@ -91,6 +92,7 @@ public void processEvent(final ComponentSystemEvent event) {
UINamingContainer.getSeparatorChar(facesContext) + tabGroup.getClientId(facesContext));
ajaxBehavior.setExecute(ids);
ajaxBehavior.setRender(ids);
+ ajaxBehavior.setImmediate(immediate);
tabGroup.addClientBehavior(tabChange.getJsEvent(), ajaxBehavior);
break;
case reloadPage:
@@ -100,6 +102,7 @@ public void processEvent(final ComponentSystemEvent event) {
tabGroup.getChildren().add(component);
final EventBehavior eventBehavior = new EventBehavior();
eventBehavior.setFor(component.getId());
+ eventBehavior.setImmediate(immediate);
tabGroup.addClientBehavior(tabChange.getJsEvent(), eventBehavior);
break;
default:
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 416cf0ac6f..427004027a 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
@@ -81,6 +81,7 @@ public String getScript(final ClientBehaviorContext behaviorContext, final Clien
Integer delay = null;
Boolean stopPropagation = null;
String customEventName = null;
+ boolean immediate = false;
final String confirmation = ComponentUtils.getConfirmation(uiComponent);
if (behavior instanceof AjaxBehavior) {
@@ -120,6 +121,7 @@ public String getScript(final ClientBehaviorContext behaviorContext, final Clien
omit = command.isOmit() || StringUtils.isNotBlank(RenderUtils.generateUrl(facesContext, command));
}
renderIds = ComponentUtils.evaluateClientIds(facesContext, uiComponent, render.toArray(new String[0]));
+ immediate = ajaxBehavior.isImmediate();
} else if (behavior instanceof EventBehavior) { // <tc:event>
final EventBehavior eventBehavior = (EventBehavior) behavior;
final AbstractUIEvent event = RenderUtils.getAbstractUIEvent(uiComponent, eventBehavior);
@@ -137,6 +139,7 @@ public String getScript(final ClientBehaviorContext behaviorContext, final Clien
omit = event.isOmit() || StringUtils.isNotBlank(RenderUtils.generateUrl(facesContext, event));
stopPropagation = event.getStopPropagation();
customEventName = event.getCustomEventName();
+ immediate = event.isImmediate();
}
}
} else {
@@ -155,7 +158,8 @@ public String getScript(final ClientBehaviorContext behaviorContext, final Clien
collapse,
omit,
stopPropagation,
- customEventName);
+ customEventName,
+ immediate);
if (resetValues) {
command.setResetValues(true);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/RenderUtils.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/RenderUtils.java
index 07ec1b058c..0027dd9528 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/RenderUtils.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/RenderUtils.java
@@ -340,7 +340,8 @@ public static CommandMap getBehaviorCommands(
TobagoClientBehaviorRenderer.createCollapsible(facesContext, holder),
holder.isOmit(),
null,
- null));
+ null,
+ holder.isImmediate()));
}
return commandMap;
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java
index 55b5c57f6d..162c886d9d 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/RendererBase.java
@@ -308,6 +308,7 @@ private void encodeBehavior(
}
writer.writeAttribute(CustomAttributes.CUSTOM_EVENT_NAME, command.getCustomEventName(), true);
// todo: all the other attributes
+ writer.writeAttribute(CustomAttributes.IMMEDIATE, command.getImmediate());
writer.endElement(HtmlElements.TOBAGO_BEHAVIOR);
}
@@ -359,7 +360,8 @@ protected CommandMap getBehaviorCommands(
TobagoClientBehaviorRenderer.createCollapsible(facesContext, holder),
holder.isOmit(),
null,
- null));
+ null,
+ holder.isImmediate()));
}
return commandMap;
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/CustomAttributes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/CustomAttributes.java
index 0fb69ef669..d3e3c02403 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/CustomAttributes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/CustomAttributes.java
@@ -44,6 +44,7 @@ public enum CustomAttributes implements MarkupLanguageAttributes {
* Internationalization strings for e.g. date specific labels, e.g. January or Monday.
*/
I18N("i18n"),
+ IMMEDIATE("immediate"),
/**
* The index of the tab inside the tab group.
*/
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/CommandUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/CommandUnitTest.java
index f48784cee4..a6f34bb83c 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/CommandUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/renderkit/CommandUnitTest.java
@@ -30,11 +30,11 @@ public void test() {
final Command a = new Command(
"a client id", "a field id", null, null, "a execute", null, "a conf", null,
- new Collapse(Collapse.Operation.show, "a collapse"), false, false, "dummy");
+ new Collapse(Collapse.Operation.show, "a collapse"), false, false, "dummy", false);
final Command b = new Command(
"b client id", "b field id", null, null, "b execute", null, "b conf", null,
- new Collapse(Collapse.Operation.show, "b collapse"), false, false, "dummy");
+ new Collapse(Collapse.Operation.show, "b collapse"), false, false, "dummy", true);
a.merge(b);
@@ -50,7 +50,7 @@ public void test() {
final Command c = new Command(
null, null, null, null, null, null, null, null,
- null, false, false, "dummy");
+ null, false, false, "dummy", false);
c.merge(b);
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/util/JsonUtilsUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/util/JsonUtilsUnitTest.java
index 5fcb3a0367..20ebd59332 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/util/JsonUtilsUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/util/JsonUtilsUnitTest.java
@@ -56,7 +56,7 @@ public void empty() {
@Test
public void click() {
final CommandMap map = new CommandMap();
- map.setClick(new Command(null, null, null, null, "", null, null, null, null, null, false, "dummy"));
+ map.setClick(new Command(null, null, null, null, "", null, null, null, null, null, false, "dummy", false));
final String expected = "{'click':{}}".replaceAll("'", "\"");
Assertions.assertEquals(expected, JsonUtils.encode(map));
}
@@ -65,7 +65,7 @@ public void click() {
public void change() {
final CommandMap map = new CommandMap();
map.addCommand(ClientBehaviors.change,
- new Command(null, null, null, null, null, null, null, null, null, null, false, "dummy"));
+ new Command(null, null, null, null, null, null, null, null, null, null, false, "dummy", false));
final String expected = "{'change':{}}".replaceAll("'", "\"");
Assertions.assertEquals(expected, JsonUtils.encode(map));
}
@@ -74,9 +74,9 @@ public void change() {
public void two() {
final CommandMap map = new CommandMap();
map.addCommand(ClientBehaviors.click,
- new Command(null, null, null, "target", null, null, null, null, null, null, false, "dummy"));
+ new Command(null, null, null, "target", null, null, null, null, null, null, false, "dummy", true));
map.addCommand(ClientBehaviors.change,
- new Command(null, null, null, null, null, null, null, null, null, null, false, "dummy"));
+ new Command(null, null, null, null, null, null, null, null, null, null, false, "dummy", false));
final String expected = "{'click':{'target':'target'},'change':{}}".replaceAll("'", "\"");
Assertions.assertEquals(expected, JsonUtils.encode(map));
}
@@ -84,7 +84,8 @@ public void two() {
@Test
public void transition() {
final CommandMap commandMap = new CommandMap();
- commandMap.setClick(new Command(null, null, false, null, null, null, null, null, null, null, false, "dummy"));
+ commandMap.setClick(new Command(null, null, false, null, null, null, null, null, null, null, false, "dummy",
+ false));
final String expected = "{'click':{'transition':false}}".replaceAll("'", "\"");
Assertions.assertEquals(expected, JsonUtils.encode(commandMap));
}
@@ -103,7 +104,7 @@ public void more() {
"_blank",
StringUtils.join(Arrays.asList("id1", "id2"), ' '),
StringUtils.join(Arrays.asList("id1", "id2"), ' '),
- "Really?", 1000, new Collapse(Collapse.Operation.show, "myId"), true, false, "dummy");
+ "Really?", 1000, new Collapse(Collapse.Operation.show, "myId"), true, false, "dummy", false);
click.setResetValues(true);
map.setClick(click);
final String expected = (
@@ -179,7 +180,7 @@ public void testCommandMap() {
ClientBehaviors.blur,
new Command(
"doit", null, false, "field", "execute", "render", "Do \"you\" want?", 100,
- new Collapse(Collapse.Operation.hide, "box"), false, false, "dummy"));
+ new Collapse(Collapse.Operation.hide, "box"), false, false, "dummy", false));
final String expected
= ("{'blur':"
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/2510-tab-file/TabGroup_Immediate_File.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/2510-tab-file/TabGroup_Immediate_File.xhtml
new file mode 100644
index 0000000000..33c875d203
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/2510-tab-file/TabGroup_Immediate_File.xhtml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * 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.
+-->
+
+<ui:composition template="/main.xhtml"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tc="http://myfaces.apache.org/tobago/component"
+ xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
+
+ <tc:tabGroup switchType="reloadTab" immediate="true">
+ <tc:tab id="nt1" label="One">
+ <tc:file required="true"/>
+ </tc:tab>
+ <tc:tab id="nt2" label="Two">
+ Two
+ </tc:tab>
+ </tc:tabGroup>
+
+ <tc:button action="ok" label="ok"/>
+
+</ui:composition>
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
index 9491cfb99f..d742d5ff37 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
@@ -15,5 +15,5 @@ const st=new Map,nt={set(e,t,s){st.has(e)||st.set(e,new Map);const n=st.get(e);n
${s>0?" tabindex='"+String(s)+"'":""}
@click="${this.removeBadge.bind(this)}"
@focus="${this.focusEvent.bind(this)}"
- @blur="${this.blurEvent.bind(this)}"><i class='bi-x-lg'></i></button>`}removeBadge(e){var t;const s=e.target.closest(".btn-group").dataset.tobagoValue,n=this.hiddenSelect.querySelector(`[value="${s}"]`);n.selected=!1;const i=this.badges.querySelector(`[data-tobago-value="${s}"]`),o=i.previousElementSibling,r="SPAN"===(null===(t=i.nextElementSibling)||void 0===t?void 0:t.tagName)?i.nextElementSibling:null;o?o.querySelector("button.btn.badge").focus():r?r.querySelector("button.btn.ba [...]
+ @blur="${this.blurEvent.bind(this)}"><i class='bi-x-lg'></i></button>`}removeBadge(e){var t;const s=e.target.closest(".btn-group").dataset.tobagoValue,n=this.hiddenSelect.querySelector(`[value="${s}"]`);n.selected=!1;const i=this.badges.querySelector(`[data-tobago-value="${s}"]`),o=i.previousElementSibling,r="SPAN"===(null===(t=i.nextElementSibling)||void 0===t?void 0:t.tagName)?i.nextElementSibling:null;o?o.querySelector("button.btn.badge").focus():r?r.querySelector("button.btn.ba [...]
//# sourceMappingURL=tobago.js.map
diff --git a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
index f479b37eca..e9199d6793 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago.js","sources":["../ts/tobago-css.ts","../ts/tobago-key.ts","../ts/tobago-client-behaviors.ts","../ts/tobago-dropdown-menu.ts","../ts/tobago-bar.ts","../ts/tobago-date.ts","../ts/tobago-menu-store.ts","../ts/tobago-dropdown-item-factory.ts","../ts/tobago-dropdown-item.ts","../ts/tobago-dropdown.ts","../ts/tobago-overlay-type.ts","../ts/tobago-suggest-filter.ts","../ts/tobago-page-static.ts","../ts/tobago-page.ts","../ts/tobago-overlay.ts","../ts/tobago-file.ts" [...]
\ No newline at end of file
+{"version":3,"file":"tobago.js","sources":["../ts/tobago-css.ts","../ts/tobago-key.ts","../ts/tobago-client-behaviors.ts","../ts/tobago-dropdown-menu.ts","../ts/tobago-bar.ts","../ts/tobago-date.ts","../ts/tobago-menu-store.ts","../ts/tobago-dropdown-item-factory.ts","../ts/tobago-dropdown-item.ts","../ts/tobago-dropdown.ts","../ts/tobago-overlay-type.ts","../ts/tobago-suggest-filter.ts","../ts/tobago-page-static.ts","../ts/tobago-page.ts","../ts/tobago-overlay.ts","../ts/tobago-file.ts" [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-behavior.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-behavior.ts
index 3f2e8b3a67..1d217fbeba 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-behavior.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-behavior.ts
@@ -77,9 +77,12 @@ class Behavior extends HTMLElement {
switch (this.mode) {
case BehaviorMode.ajax:
- if (!this.validate(this.execute)) {
- console.warn("Validation failed! No request will be sent.");
- return;
+ if (!this.immediate) {
+ const valid = this.validate(this.execute);
+ if (!valid) {
+ console.warn("Validation failed! No request will be sent.");
+ return;
+ }
}
break;
case BehaviorMode.full:
@@ -385,6 +388,18 @@ class Behavior extends HTMLElement {
}
}
+ get immediate(): boolean {
+ return this.hasAttribute("immediate");
+ }
+
+ set immediate(immediate: boolean) {
+ if (immediate) {
+ this.setAttribute("immediate", "");
+ } else {
+ this.removeAttribute("immediate");
+ }
+ }
+
get stopPropagation(): boolean {
return this.hasAttribute("stop-propagation");
}