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 2023/11/16 13:33:17 UTC
(myfaces-tobago) branch main updated: feat(sheet): custom event support for sheet row selection (#4408)
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 653eb4fa32 feat(sheet): custom event support for sheet row selection (#4408)
653eb4fa32 is described below
commit 653eb4fa322427c5617b2018b1e95148afd445ca
Author: Bernd Bohmann <bo...@apache.org>
AuthorDate: Thu Nov 16 14:33:11 2023 +0100
feat(sheet): custom event support for sheet row selection (#4408)
issue: TOBAGO-2239
---
.../myfaces/tobago/component/ClientBehaviors.java | 55 +++++++++++++++-------
.../myfaces/tobago/facelets/EventHandler.java | 2 +-
.../renderer/TobagoClientBehaviorRenderer.java | 2 +-
.../taglib/component/SheetTagDeclaration.java | 3 +-
.../myfaces/tobago/renderkit/RendererBase.java | 2 +-
.../apache/myfaces/tobago/util/EnumUnitTest.java | 6 ++-
.../tobago/example/demo/SheetController.java | 8 ++++
.../25-selection/Sheet_Selectionchange.xhtml | 51 ++++++++++++++++++++
.../tobago-theme-standard/src/main/js/tobago.js | 6 +--
.../src/main/js/tobago.js.map | 2 +-
.../src/main/ts/tobago-client-behaviors.ts | 37 +++++++++++++++
.../src/main/ts/tobago-sheet.ts | 18 ++++++-
12 files changed, 165 insertions(+), 27 deletions(-)
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java
index ef47f2c572..7503936ec3 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/ClientBehaviors.java
@@ -21,23 +21,43 @@ package org.apache.myfaces.tobago.component;
public enum ClientBehaviors {
- action, // pure JSF (not a JavaScript event
- blur,
- change,
- click,
- complete,
- dblclick,
- focus,
- keydown,
- keypress,
- keyup,
- input,
- load,
- mouseover,
- mouseout,
- reload, // tbd - may be called timeout?
- resize,
- suggest; // tbd
+ action("action"), // pure JSF (not a JavaScript event
+ blur("blur"),
+ change("change"),
+ click("click"),
+ complete("complete"),
+ dblclick("dblclick"),
+ focus("focus"),
+ keydown("keydown"),
+ keypress("keypress"),
+ keyup("keyup"),
+ input("input"),
+ load("load"),
+ mouseover("mouseover"),
+ mouseout("mouseout"),
+ reload("reload"), // tbd - may be called timeout?
+ resize("resize"),
+ suggest("suggest"),
+ rowSelectionChange("tobago.sheet.rowSelectionChange");
+
+ private final String jsEvent;
+
+ ClientBehaviors(final String value) {
+ this.jsEvent = value;
+ }
+
+ public String getJsEvent() {
+ return jsEvent;
+ }
+
+ public static ClientBehaviors getEnum(String value) {
+ for (ClientBehaviors clientBehavior : ClientBehaviors.values()) {
+ if (clientBehavior.getJsEvent() != null && clientBehavior.getJsEvent().equals(value)) {
+ return clientBehavior;
+ }
+ }
+ return ClientBehaviors.valueOf(value);
+ }
public static final String ACTION = "action";
public static final String BLUR = "blur";
@@ -56,5 +76,6 @@ public enum ClientBehaviors {
public static final String RELOAD = "reload"; // tbd - may be called timeout?
public static final String RESIZE = "resize";
public static final String SUGGEST = "suggest"; // tbd
+ public static final String ROW_SELECTION_CHANGE = "tobago.sheet.rowSelectionChange";
}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/EventHandler.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/EventHandler.java
index 871b71ec50..1bfa2fec55 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/EventHandler.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/facelets/EventHandler.java
@@ -173,7 +173,7 @@ public class EventHandler extends TobagoComponentHandler implements BehaviorHold
final AbstractUIEvent uiEvent = (AbstractUIEvent) component;
if (uiEvent.getEvent() == null) {
final ClientBehaviorHolder holder = (ClientBehaviorHolder) parent;
- uiEvent.setEvent(ClientBehaviors.valueOf(holder.getDefaultEventName()));
+ uiEvent.setEvent(ClientBehaviors.getEnum(holder.getDefaultEventName()));
}
}
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 f3490890ca..6820a0df5f 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
@@ -65,7 +65,7 @@ public class TobagoClientBehaviorRenderer extends jakarta.faces.render.ClientBeh
final FacesContext facesContext = behaviorContext.getFacesContext();
final UIComponent uiComponent = behaviorContext.getComponent();
- final ClientBehaviors eventName = ClientBehaviors.valueOf(behaviorContext.getEventName());
+ final ClientBehaviors eventName = ClientBehaviors.getEnum(behaviorContext.getEventName());
//// TBD: is this nice? May be implemented with a JSF behavior?
Collapse collapse = createCollapsible(facesContext, uiComponent);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SheetTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SheetTagDeclaration.java
index 7f30da6e91..74cbb8de76 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SheetTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/SheetTagDeclaration.java
@@ -62,7 +62,8 @@ import jakarta.faces.component.UIData;
behaviors = {
@Behavior(
name = ClientBehaviors.RELOAD, // XXX replace by click
- isDefault = true)
+ isDefault = true),
+ @Behavior(name = ClientBehaviors.ROW_SELECTION_CHANGE)
},
markups = {
@Markup(
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 4f9ec75316..968028ccc0 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
@@ -256,7 +256,7 @@ public abstract class RendererBase<T extends UIComponent> extends Renderer {
final TobagoResponseWriter writer, final ClientBehaviors behaviors, final Command command)
throws IOException {
writer.startElement(HtmlElements.TOBAGO_BEHAVIOR);
- writer.writeAttribute(CustomAttributes.EVENT, behaviors.name(), false);
+ writer.writeAttribute(CustomAttributes.EVENT, behaviors.getJsEvent(), false);
writer.writeAttribute(CustomAttributes.CLIENT_ID, command.getClientId(), false);
if (StringUtils.notEquals(command.getClientId(), command.getFieldId())) {
writer.writeAttribute(CustomAttributes.FIELD_ID, command.getFieldId(), false);
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/util/EnumUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/util/EnumUnitTest.java
index 9ccbba823f..cacbb784ae 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/util/EnumUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/util/EnumUnitTest.java
@@ -47,8 +47,12 @@ public abstract class EnumUnitTest {
final String fieldName = field.getName();
if (object instanceof String) {
// case String constant
- final String value = (String) object;
+ String value = (String) object;
final String expected = constantCaseToEnum(fieldName);
+ int index = value.lastIndexOf('.');
+ if (index > 0) {
+ value = value.substring(index+1);
+ }
Assertions.assertEquals(expected, value);
Assertions.assertNotNull(enumType.getField(value), "exists");
} else if (object.getClass().isAssignableFrom(enumType)) {
diff --git a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java
index 2edf3a215b..c4b305d8f2 100644
--- a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java
+++ b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/SheetController.java
@@ -161,4 +161,12 @@ public class SheetController implements Serializable {
public SelectItem[] getSelectableModes() {
return SHEET_SELECTABLE;
}
+
+ public String getSelectedRows() {
+ if (sheetState != null) {
+ return sheetState.getSelectedRows().stream().map(Object::toString).collect(Collectors.joining(", "));
+ } else {
+ return "";
+ }
+ }
}
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/080-sheet/25-selection/Sheet_Selectionchange.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/080-sheet/25-selection/Sheet_Selectionchange.xhtml
new file mode 100644
index 0000000000..c5ea7b5eb2
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/080-sheet/25-selection/Sheet_Selectionchange.xhtml
@@ -0,0 +1,51 @@
+<?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:f="jakarta.faces.core"
+ xmlns:tc="http://myfaces.apache.org/tobago/component"
+ xmlns:ui="jakarta.faces.facelets">
+
+ <tc:panel id="panel">
+ <tc:out label="Timestamp" value="#{eventController.currentTimestamp}"/>
+ <tc:out label="selectedRows" value="#{sheetController.selectedRows}"/>
+ </tc:panel>
+
+ <tc:sheet id="s1" value="#{sheetController.solarList}" var="object" rows="4" state="#{sheetController.sheetState}">
+ <tc:style maxHeight="500px"/>
+ <f:ajax event="tobago.sheet.rowSelectionChange" render="::panel"/>
+ <tc:columnSelector/>
+ <tc:column label="Name">
+ <tc:out value="#{object.name}" labelLayout="skip"/>
+ </tc:column>
+ <tc:column label="Orbit">
+ <tc:out value="#{object.orbit}" labelLayout="skip"/>
+ </tc:column>
+ <tc:column label="Period (Days)">
+ <tc:out value="#{object.period}" labelLayout="skip"/>
+ </tc:column>
+ <tc:column label="Discoverer">
+ <tc:out value="#{object.discoverer}" labelLayout="skip"/>
+ </tc:column>
+ <tc:column label="Year">
+ <tc:out value="#{object.discoverYear}" labelLayout="skip"/>
+ </tc:column>
+ </tc:sheet>
+</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 64cb51018a..40eaab7aea 100644
--- a/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
+++ b/tobago-theme/tobago-theme-standard/src/main/js/tobago.js
@@ -1,10 +1,10 @@
-!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";var e;!function(e){e.ACTIVE="active",e.AUTOCOMPLETE="autocomplete",e.AUTOCOMPLETE_INPUT="autocomplete-input",e.BOTTOM_0="bottom-0",e.COLLAPSE="collapse",e.COLLAPSING="collapsing",e.D_NONE="d-none",e.DISABLED="disabled",e.DROPDOWN="dropdown",e.DROPDOWN_ITEM="dropdown-item",e.DROPDOWN_MENU="dropdown-menu",e.DROPDOWN_MENU_END="dropdown-menu-end",e.END_0="end-0",e.FADE="fade",e.FIXED_BOTTOM="fixed-bott [...]
+!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";var e;!function(e){e.ACTIVE="active",e.AUTOCOMPLETE="autocomplete",e.AUTOCOMPLETE_INPUT="autocomplete-input",e.BOTTOM_0="bottom-0",e.COLLAPSE="collapse",e.COLLAPSING="collapsing",e.D_NONE="d-none",e.DISABLED="disabled",e.DROPDOWN="dropdown",e.DROPDOWN_ITEM="dropdown-item",e.DROPDOWN_MENU="dropdown-menu",e.DROPDOWN_MENU_END="dropdown-menu-end",e.END_0="end-0",e.FADE="fade",e.FIXED_BOTTOM="fixed-bott [...]
/*!
* Bootstrap v5.3.2 (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
-const $e=new Map,Me={set(e,t,s){$e.has(e)||$e.set(e,new Map);const n=$e.get(e);n.has(t)||0===n.size?n.set(t,s):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(e,t)=>$e.has(e)&&$e.get(e).get(t)||null,remove(e,t){if(!$e.has(e))return;const s=$e.get(e);s.delete(t),0===s.size&&$e.delete(e)}},Pe="transitionend",Be=e=>(e&&window.CSS&&window.CSS.escape&&(e=e.replace(/#([^\s"#']+)/g,((e,t)=>`#${CSS.escape(t)}`))),e),H [...]
+const $e=new Map,Me={set(e,t,s){$e.has(e)||$e.set(e,new Map);const n=$e.get(e);n.has(t)||0===n.size?n.set(t,s):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(e,t)=>$e.has(e)&&$e.get(e).get(t)||null,remove(e,t){if(!$e.has(e))return;const s=$e.get(e);s.delete(t),0===s.size&&$e.delete(e)}},Pe="transitionend",Be=e=>(e&&window.CSS&&window.CSS.escape&&(e=e.replace(/#([^\s"#']+)/g,((e,t)=>`#${CSS.escape(t)}`))),e),H [...]
/**
* @license
* Copyright 2017 Google LLC
@@ -15,5 +15,5 @@ const $e=new Map,Me={set(e,t,s){$e.has(e)||$e.set(e,new Map);const n=$e.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){const t=e.target.closest(".btn-group").dataset.tobagoValue,s=this.hiddenSelect.querySelector(`[value="${t}"]`);s.selected=!1;const n=this.selectField.querySelector(`[data-tobago-value="${t}"]`),i=n.previousElementSibling,o="SPAN"===n.nextElementSibling.tagName?n.nextElementSibling:null;i?i.querySelector("button.btn.badge").focus():o?o.querySelector("button.btn.badge").focus():(this.filterInput.dis [...]
+ @blur="${this.blurEvent.bind(this)}"><i class='bi-x-lg'></i></button>`}removeBadge(e){const t=e.target.closest(".btn-group").dataset.tobagoValue,s=this.hiddenSelect.querySelector(`[value="${t}"]`);s.selected=!1;const n=this.selectField.querySelector(`[data-tobago-value="${t}"]`),i=n.previousElementSibling,o="SPAN"===n.nextElementSibling.tagName?n.nextElementSibling:null;i?i.querySelector("button.btn.badge").focus():o?o.querySelector("button.btn.badge").focus():(this.filterInput.dis [...]
//# 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 3c381411a7..25b4ff49ee 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-bar.ts","../../../../node_modules/@popperjs/core/lib/enums.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../../../node_modules/@popperjs/core/lib/utils/getBasePlacement.j [...]
\ No newline at end of file
+{"version":3,"file":"tobago.js","sources":["../ts/tobago-css.ts","../ts/tobago-bar.ts","../../../../node_modules/@popperjs/core/lib/enums.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../../../node_modules/@popperjs/core/lib/utils/getBasePlacement.j [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-client-behaviors.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-client-behaviors.ts
new file mode 100644
index 0000000000..84f743571d
--- /dev/null
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-client-behaviors.ts
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+export enum ClientBehaviors {
+ ACTION = "action",
+ BLUR = "blur",
+ CHANGE = "change",
+ CLICK = "click",
+ COMPLETE = "complete",
+ DBLCLICK = "dblclick",
+ FOCUS = "focus",
+ KEYDOWN = "keydown",
+ KEYPRESS = "keypress",
+ KEYUP = "keyup",
+ INPUT = "input",
+ LOAD = "load",
+ MOUSEOVER = "mouseover",
+ MOUSEOUT = "mouseout",
+ RELOAD = "reload",
+ RESIZE = "resize",
+ SUGGEST = "suggest",
+ ROW_SELECTION_CHANGE = "tobago.sheet.rowSelectionChange"
+}
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-sheet.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-sheet.ts
index ea9a05ea9c..58cfee636c 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-sheet.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-sheet.ts
@@ -18,6 +18,7 @@
import {Page} from "./tobago-page";
import {Key} from "./tobago-key";
import {Css} from "./tobago-css";
+import {ClientBehaviors} from "./tobago-client-behaviors";
interface MousemoveData {
columnIndex: number;
@@ -613,6 +614,7 @@ Type: ${data.type}`);
clickOnCheckboxForAll(event: MouseEvent): void {
const selectedSet = new Set<number>(JSON.parse(this.getHiddenSelected().value));
+ const oldSelectedSet = new Set<number>(selectedSet);
const checkbox = event.currentTarget as HTMLInputElement;
if (checkbox.checked) {
this.selectAll(selectedSet);
@@ -620,6 +622,7 @@ Type: ${data.type}`);
this.deselectAll(selectedSet);
}
this.getHiddenSelected().value = JSON.stringify(Array.from(selectedSet)); // write back to element
+ this.fireSelectionChange(oldSelectedSet, selectedSet);
}
clickOnRow(event: MouseEvent): void {
@@ -639,7 +642,7 @@ Type: ${data.type}`);
const selector = this.getSelectorCheckbox(row);
const selectionMode = this.dataset.tobagoSelectionMode;
const selectedSet = new Set<number>(JSON.parse(this.getHiddenSelected().value));
-
+ const oldSelectedSet = new Set<number>(selectedSet);
if ((!event.ctrlKey && !event.metaKey && !selector)
|| selectionMode === "single" || selectionMode === "singleOrNone") {
this.deselectAll(selectedSet);
@@ -659,6 +662,19 @@ Type: ${data.type}`);
this.toggleSelection(selectedSet, row, selector);
}
this.getHiddenSelected().value = JSON.stringify(Array.from(selectedSet)); // write back to element
+ this.fireSelectionChange(oldSelectedSet, selectedSet);
+ }
+ }
+
+ private fireSelectionChange(oldSelectedSet: Set<number>, newSelectedSet: Set<number>) {
+ const fireEvent = (oldSelectedSet, newSelectedSet) =>
+ oldSelectedSet.size == newSelectedSet.size && [...oldSelectedSet].every((x) => newSelectedSet.has(x));
+ if (fireEvent) {
+ this.dispatchEvent(new CustomEvent(ClientBehaviors.ROW_SELECTION_CHANGE, {
+ detail: {
+ selection: newSelectedSet,
+ },
+ }));
}
}