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/01/17 16:27:47 UTC

(myfaces-tobago) branch main updated: feat: Allow selectionMode only for columnSelector (#4791)

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 c7ce0ecbc7 feat: Allow selectionMode only for columnSelector (#4791)
c7ce0ecbc7 is described below

commit c7ce0ecbc705d1edb71a3fd420abfd0e57975be9
Author: Bernd Bohmann <bo...@apache.org>
AuthorDate: Wed Jan 17 17:27:41 2024 +0100

    feat: Allow selectionMode only for columnSelector (#4791)
    
    * feat: Allow selectionMode only for columnSelector
    issue: TOBAGO-2276
---
 .../component/AbstractUIColumnSelector.java        |  4 ++
 .../internal/renderkit/renderer/SheetRenderer.java | 40 ++++++++++-----
 .../component/ColumnSelectorTagDeclaration.java    | 15 ++++++
 .../tobago-theme-standard/src/main/js/tobago.js    |  2 +-
 .../src/main/js/tobago.js.map                      |  2 +-
 .../src/main/ts/tobago-sheet.ts                    | 59 +++++++++++++++++-----
 6 files changed, 93 insertions(+), 29 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIColumnSelector.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIColumnSelector.java
index 9250ebd0f7..c9f8401ae2 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIColumnSelector.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIColumnSelector.java
@@ -19,6 +19,8 @@
 
 package org.apache.myfaces.tobago.internal.component;
 
+import org.apache.myfaces.tobago.model.Selectable;
+
 /**
  * {@link org.apache.myfaces.tobago.internal.taglib.component.ColumnSelectorTagDeclaration}
  */
@@ -32,4 +34,6 @@ public abstract class AbstractUIColumnSelector extends AbstractUIColumnBase {
 */
 
   public abstract boolean isDisabled();
+
+  public abstract Selectable getSelectable();
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
index 1f22bf79a5..e4c8921936 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SheetRenderer.java
@@ -346,11 +346,9 @@ public class SheetRenderer<T extends AbstractUISheet> extends RendererBase<T> {
         component.getState().getScrollPosition().encode(),
         component.getClientId(facesContext) + SUFFIX_SCROLL_POSITION);
 
-    if (selectable != Selectable.none) {
-      encodeHiddenInput(writer,
-          JsonUtils.encode(selectedRows),
-          sheetId + SUFFIX_SELECTED);
-    }
+    encodeHiddenInput(writer,
+        JsonUtils.encode(selectedRows),
+        sheetId + SUFFIX_SELECTED);
 
     if (component.isLazy()) {
       encodeHiddenInput(writer, null, sheetId + SUFFIX_LAZY);
@@ -700,7 +698,8 @@ public class SheetRenderer<T extends AbstractUISheet> extends RendererBase<T> {
               final AbstractUIColumnSelector selector = (AbstractUIColumnSelector) column;
               writer.startElement(HtmlElements.INPUT);
               writer.writeNameAttribute(sheetId + "_data_row_selector_" + rowIndex);
-              if (selectable.isSingle()) {
+              Selectable currentSelectable = getSelectionMode(selectable, selector);
+              if (currentSelectable.isSingle()) {
                 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.RADIO);
               } else {
                 writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.CHECKBOX);
@@ -782,6 +781,16 @@ public class SheetRenderer<T extends AbstractUISheet> extends RendererBase<T> {
 // END RENDER BODY CONTENT
   }
 
+  private static Selectable getSelectionMode(Selectable selectable, AbstractUIColumnSelector selector) {
+    if (selectable == Selectable.none) {
+      Selectable selectorSelectable = selector.getSelectable();
+      if (selectorSelectable != null) {
+        return selectorSelectable;
+      }
+    }
+    return selectable;
+  }
+
   private void encodeHiddenInput(final TobagoResponseWriter writer, final String value, final String idWithSuffix)
       throws IOException {
     writer.startElement(HtmlElements.INPUT);
@@ -959,15 +968,20 @@ public class SheetRenderer<T extends AbstractUISheet> extends RendererBase<T> {
             writer.writeAttribute(HtmlAttributes.TITLE, tip, true);
 
             encodeBehavior(writer, behaviorCommands);
-
-            if (column instanceof AbstractUIColumnSelector && selectable.isMulti()) {
+            if (column instanceof AbstractUIColumnSelector) {
+              Selectable currentSelectable = getSelectionMode(selectable, (AbstractUIColumnSelector) column);
               writer.startElement(HtmlElements.INPUT);
-              writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.CHECKBOX);
+              if (currentSelectable.isMulti()) {
+                writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.CHECKBOX);
+                writer.writeAttribute(
+                    HtmlAttributes.TITLE,
+                    ResourceUtils.getString(facesContext, "sheet.selectAll"),
+                    true);
+              } else {
+                writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN);
+              }
               writer.writeClassAttribute(TobagoClass.SELECTED);
-              writer.writeAttribute(
-                  HtmlAttributes.TITLE,
-                  ResourceUtils.getString(facesContext, "sheet.selectAll"),
-                  true);
+              writer.writeAttribute(DataAttributes.SELECTION_MODE, currentSelectable.name(), false);
               writer.endElement(HtmlElements.INPUT);
             } else {
               cellComponent.encodeAll(facesContext);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ColumnSelectorTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ColumnSelectorTagDeclaration.java
index b0ef9b97e5..ddd9df99a1 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ColumnSelectorTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ColumnSelectorTagDeclaration.java
@@ -20,11 +20,14 @@
 package org.apache.myfaces.tobago.internal.taglib.component;
 
 import org.apache.myfaces.tobago.apt.annotation.Tag;
+import org.apache.myfaces.tobago.apt.annotation.TagAttribute;
 import org.apache.myfaces.tobago.apt.annotation.UIComponentTag;
+import org.apache.myfaces.tobago.apt.annotation.UIComponentTagAttribute;
 import org.apache.myfaces.tobago.component.RendererTypes;
 import org.apache.myfaces.tobago.internal.taglib.declaration.HasIdBindingAndRendered;
 import org.apache.myfaces.tobago.internal.taglib.declaration.IsDisabled;
 import org.apache.myfaces.tobago.internal.taglib.declaration.IsVisual;
+import org.apache.myfaces.tobago.model.Selectable;
 
 import jakarta.faces.component.UIColumn;
 
@@ -44,4 +47,16 @@ import jakarta.faces.component.UIColumn;
     allowedChildComponenents = "NONE")
 public interface ColumnSelectorTagDeclaration
     extends HasIdBindingAndRendered, IsVisual, IsDisabled {
+
+  /**
+   * Indicating the selection mode of the columnSelector. Only effective if sheet selection mode is none.
+   * Use case: Show details with tc:row event and columnSelector for action on selected rows.
+   */
+  @TagAttribute
+  @UIComponentTagAttribute(
+      type = "org.apache.myfaces.tobago.model.Selectable",
+      allowedValues = {
+          Selectable.NONE, Selectable.SINGLE, Selectable.SINGLE_OR_NONE, Selectable.MULTI
+      })
+  void setSelectable(String selectable);
 }
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 edd60a6e1a..48c885db9f 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 $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 df8184bc28..6ca553315b 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-sheet.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-sheet.ts
index 3bb1ea9fac..34147152a5 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
@@ -188,12 +188,22 @@ export class Sheet extends HTMLElement {
     sheetBody.addEventListener("scroll", this.scrollAction.bind(this));
 
     // add selection listeners ------------------------------------------------------------------------------------ //
-    const selectionMode = this.dataset.tobagoSelectionMode;
-    for (const row of this.getRowElements()) {
-      this.initListeners(row);
+    let selectionMode = this.dataset.tobagoSelectionMode;
+    if (selectionMode !== "none") {
+      for (const row of this.getRowElements()) {
+        this.initTableRowForSelection(row, selectionMode);
+      }
+    } else {
+      selectionMode = this.getSelectorAllCheckbox()?.dataset.tobagoSelectionMode;
+      if (selectionMode) {
+        const cells: NodeListOf<HTMLTableCellElement> = this.getBodyTable().querySelectorAll("tbody>tr>td:first-child");
+        for (const cell of cells) {
+          this.initTableCellForSelection(cell, selectionMode);
+        }
+      }
     }
 
-    if (selectionMode === "multi" && this.getSelectorAllCheckbox()) {
+    if (selectionMode === "multi") {
       const selectedSet = new Set<number>(JSON.parse(this.getHiddenSelected().value));
       this.calculateSelectorAllChecked(selectedSet);
     }
@@ -259,13 +269,31 @@ export class Sheet extends HTMLElement {
     }
   }
 
-  private initListeners(row: HTMLTableRowElement): void {
-    const selectionMode = this.dataset.tobagoSelectionMode;
-    if (selectionMode === "single" || selectionMode === "singleOrNone" || selectionMode === "multi") {
+  private getSelectionMode() {
+    let selectionMode = this.dataset.tobagoSelectionMode;
+    if (selectionMode === "none") {
+      const selectorAllCheckbox = this.getSelectorAllCheckbox();
+      selectionMode = selectorAllCheckbox?.dataset.tobagoSelectionMode;
+    }
+    return selectionMode;
+  }
+
+  private initTableCellForSelection(cell: HTMLTableCellElement, columnSelectionMode: string) {
+    if (columnSelectionMode === "single" || columnSelectionMode === "singleOrNone" || columnSelectionMode === "multi") {
+      cell.addEventListener("mousedown", this.mousedownOnRow.bind(this));
+      cell.addEventListener("click", this.clickOnRow.bind(this));
+    }
+    const checkbox = cell.querySelector("input.tobago-selected");
+    checkbox?.addEventListener("click", (event) => {
+      event.preventDefault();
+    });
+  }
+
+  private initTableRowForSelection(row: HTMLTableRowElement, sheetSelectionMode: string): void {
+    if (sheetSelectionMode === "single" || sheetSelectionMode === "singleOrNone" || sheetSelectionMode === "multi") {
       row.addEventListener("mousedown", this.mousedownOnRow.bind(this));
       row.addEventListener("click", this.clickOnRow.bind(this));
     }
-
     const checkbox = row.querySelector("td > input.tobago-selected");
     checkbox?.addEventListener("click", (event) => {
       event.preventDefault();
@@ -439,15 +467,19 @@ export class Sheet extends HTMLElement {
           console.debug(`[tobago-sheet][success] Update after faces.ajax complete: #${id}`); // @DEV_ONLY
 
           const tbody = this.querySelector(".tobago-body tbody");
-
           const newRows = this.sheetLoader.querySelectorAll<HTMLTableRowElement>(".tobago-body tbody>tr");
+          const sheetSelectionMode = this.dataset.tobagoSelectionMode;
+          const columnSelectorSelectionMode = this.getSelectorAllCheckbox()?.dataset.tobagoSelectionMode;
           for (const newRow of newRows) {
             const rowIndex = Number(newRow.getAttribute("row-index"));
             const row = tbody.querySelector(`tr[row-index='${rowIndex}']`);
             row.insertAdjacentElement("afterend", newRow);
             row.remove();
-
-            this.initListeners(newRow);
+            if (sheetSelectionMode !== "none") {
+              this.initTableRowForSelection(newRow, sheetSelectionMode);
+            } else if (columnSelectorSelectionMode) {
+              this.initTableCellForSelection(row.querySelector("td:first-child"), columnSelectorSelectionMode);
+            }
           }
 
           this.sheetLoader.remove();
@@ -655,8 +687,7 @@ Type: ${data.type}`);
         clickElement = clickElement.parentElement;
       }
     }
-
-    const row = event.currentTarget as HTMLTableRowElement;
+    const row = clickElement as HTMLTableRowElement;
     if (row.classList.contains(Css.TOBAGO_SELECTED) || !Sheet.isInputElement(row)) {
 
       if (this.mousedownOnRowData) { // integration test: mousedownOnRowData may be 'null'
@@ -670,7 +701,7 @@ Type: ${data.type}`);
 
       const rows = this.getRowElements();
       const selector = this.getSelectorCheckbox(row);
-      const selectionMode = this.dataset.tobagoSelectionMode;
+      const selectionMode = this.getSelectionMode();
       const selectedSet = new Set<number>(JSON.parse(this.getHiddenSelected().value));
       const oldSelectedSet = new Set<number>(selectedSet);
       if ((!event.ctrlKey && !event.metaKey && !selector)