You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by hn...@apache.org on 2022/11/02 16:00:58 UTC

[myfaces-tobago] branch t5_selectMany updated (97887ef54d -> ad1a0aa7d3)

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

hnoeth pushed a change to branch t5_selectMany
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git


    from 97887ef54d feat(selectMany): fix tobago-dropdown.ts
     new 71a071e555 feat(selectMany): hide dropdown-menu manually
     new ad1a0aa7d3 feat(selectMany): focus

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../myfaces/tobago/renderkit/css/TobagoClass.java  |   1 +
 tobago-theme/src/main/scss/_tobago.scss            |  31 +++++
 .../src/main/ts/tobago-select-many.ts              | 133 ++++++++++++++++-----
 3 files changed, 136 insertions(+), 29 deletions(-)


[myfaces-tobago] 02/02: feat(selectMany): focus

Posted by hn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit ad1a0aa7d30f5b1ab6df4c55f43e9032c5e91d85
Author: Henning Noeth <hn...@apache.org>
AuthorDate: Wed Nov 2 16:37:29 2022 +0100

    feat(selectMany): focus
    
    Issue: TOBAGO-2159
---
 .../myfaces/tobago/renderkit/css/TobagoClass.java  |  1 +
 tobago-theme/src/main/scss/_tobago.scss            | 31 +++++++
 .../src/main/ts/tobago-select-many.ts              | 95 ++++++++++++++++++----
 3 files changed, 113 insertions(+), 14 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java
index 8d503c4eee..1d9d4b4fb3 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/css/TobagoClass.java
@@ -54,6 +54,7 @@ public enum TobagoClass implements CssItem {
   EXPANDED("tobago-expanded"),
 //  FILE("tobago-file"),
 //  FIGURE("tobago-figure"),
+  FOCUS("tobago-focus"),
   FOLDER("tobago-folder"),
   FILTER("tobago-filter"),
   FILTER__WRAPPER("tobago-filter-wrapper"),
diff --git a/tobago-theme/src/main/scss/_tobago.scss b/tobago-theme/src/main/scss/_tobago.scss
index 882bc1337e..8d66f11cd9 100644
--- a/tobago-theme/src/main/scss/_tobago.scss
+++ b/tobago-theme/src/main/scss/_tobago.scss
@@ -118,6 +118,20 @@ $tobago-flex-layout-spacing: 0.5rem;
   }
 }
 
+@mixin formControlFocus() {
+  //_form-control:focus from bootstrap
+  color: $input-focus-color;
+  background-color: $input-focus-bg;
+  border-color: $input-focus-border-color;
+  outline: 0;
+  @if $enable-shadows {
+    @include box-shadow($input-box-shadow, $input-focus-box-shadow);
+  } @else {
+    // Avoid using mixin so we can pass custom focus shadow properly
+    box-shadow: $input-focus-box-shadow;
+  }
+}
+
 @mixin formControlSelectListDisabled() {
   &:disabled option, option:disabled {
     color: rgba($input-color, $tobago-form-disabled-alpha);
@@ -1177,6 +1191,23 @@ tobago-select-one-radio {
 tobago-select-many {
   display: block;
 
+  &.list-group {
+    .tobago-options {
+      border-top: ($table-border-width * 2) solid $table-group-separator-color;
+      overflow: auto;
+    }
+  }
+
+  &.tobago-focus {
+    &.dropdown .tobago-filter-wrapper {
+      @include formControlFocus();
+    }
+
+    &.list-group {
+      @include formControlFocus();
+    }
+  }
+
   .tobago-filter-wrapper {
     display: flex;
     flex-wrap: wrap;
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many.ts
index bbea491888..cd2fef5fd8 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many.ts
@@ -23,6 +23,7 @@ class SelectMany extends HTMLElement {
   private readonly CssClass = {
     DROPDOWN_MENU: "dropdown-menu",
     SHOW: "show",
+    TOBAGO_FOCUS: "tobago-focus",
     TOBAGO_OPTIONS: "tobago-options"
   };
 
@@ -42,6 +43,10 @@ class SelectMany extends HTMLElement {
     return this.querySelector(".tobago-filter-wrapper");
   }
 
+  get badgeCloseButtons(): NodeListOf<HTMLButtonElement> {
+    return this.selectField.querySelectorAll("button.btn.badge");
+  }
+
   get filter(): string {
     return this.getAttribute("filter");
   }
@@ -72,13 +77,21 @@ class SelectMany extends HTMLElement {
 
     if (this.dropdownMenu) {
       window.addEventListener("resize", this.resizeEvent.bind(this));
-      document.addEventListener("click", this.clickEvent.bind(this));
       document.addEventListener("keydown", this.keydownEvent.bind(this));
       this.addEventListener(BootstrapEvents.DROPDOWN_SHOW, this.showDropdown.bind(this));
       this.addEventListener(BootstrapEvents.DROPDOWN_SHOWN, this.shownDropdown.bind(this));
       this.addEventListener(BootstrapEvents.DROPDOWN_HIDE, this.preventBootstrapHide.bind(this));
       this.addEventListener(BootstrapEvents.DROPDOWN_HIDDEN, this.hiddenDropdown.bind(this));
     }
+    document.addEventListener("click", this.clickEvent.bind(this));
+    this.filterInput.addEventListener("focus", this.focusEvent.bind(this));
+    this.filterInput.addEventListener("blur", this.blurEvent.bind(this));
+    this.badgeCloseButtons.forEach(
+      (closeButton) => {
+        closeButton.addEventListener("focus", this.focusEvent.bind(this));
+        closeButton.addEventListener("blur", this.blurEvent.bind(this));
+      }
+    );
 
     // init badges
     this.querySelectorAll("option:checked").forEach(
@@ -130,6 +143,8 @@ class SelectMany extends HTMLElement {
       // todo: nicer adding the @click with lit-html
       const current = this.filterInput.parentElement.querySelector(".btn-group[data-tobago-value='" + itemValue + "']");
       current.addEventListener("click", this.removeBadge.bind(this));
+      this.selectField.querySelector("button.btn.badge").addEventListener("focus", this.focusEvent.bind(this));
+      this.selectField.querySelector("button.btn.badge").addEventListener("blur", this.blurEvent.bind(this));
 
       // highlight list row
       row.classList.add("table-active");
@@ -137,7 +152,14 @@ class SelectMany extends HTMLElement {
       // remove badge
       const selectField1 = this.selectField;
       console.log("selectField1", selectField1);
-      selectField1.querySelector(`[data-tobago-value="${itemValue}"]`).remove();
+      const badge = selectField1.querySelector(`[data-tobago-value="${itemValue}"]`);
+      const previousElementSibling = badge.previousElementSibling;
+      badge.remove();
+      if (previousElementSibling) {
+        previousElementSibling.querySelector<HTMLButtonElement>("button.btn.badge").focus();
+      } else {
+        this.filterInput.focus();
+      }
 
       // remove highlight list row
       row.classList.remove("table-active");
@@ -185,26 +207,45 @@ class SelectMany extends HTMLElement {
   }
 
   private clickEvent(event: MouseEvent): void {
-    let hide = true;
+    if (this.isPartOfFilterWrapper(event.target as Element)) {
+      this.filterInput.focus();
+    } else if (this.isPartOfComponent(event.target as Element)) {
+      this.filterInput.focus();
+    } else {
+      this.hideDropdown();
+      this.setFocus(false);
+    }
+  }
 
-    for (const element of event.composedPath() as HTMLElement[]) {
+  private keydownEvent(event: KeyboardEvent) {
+    if (event.key === this.Key.ESCAPE) {
+      this.hideDropdown();
+    }
+  }
+
+  private isPartOfComponent(element: Element): boolean {
+    if (element) {
       if (this.id === element.id
         || (element.classList?.contains(this.CssClass.DROPDOWN_MENU)
           && this.id === element.getAttribute("name"))) {
-        hide = false;
-        break;
+        return true;
+      } else {
+        return element.parentElement ? this.isPartOfComponent(element.parentElement) : false;
       }
-    }
-
-    if (hide) {
-      this.hideDropdown();
+    } else {
+      return false;
     }
   }
 
-  private keydownEvent(event: KeyboardEvent) {
-    console.log("### keydownEvent");
-    if (event.key === this.Key.ESCAPE) {
-      this.hideDropdown();
+  private isPartOfFilterWrapper(element: Element): boolean {
+    if (element) {
+      if (this.selectField.id === element.id) {
+        return true;
+      } else {
+        return element.parentElement ? this.isPartOfFilterWrapper(element.parentElement) : false;
+      }
+    } else {
+      return false;
     }
   }
 
@@ -231,6 +272,32 @@ class SelectMany extends HTMLElement {
     }
   }
 
+  private focusEvent(event: FocusEvent): void {
+    this.setFocus(true);
+  }
+
+  private blurEvent(event: FocusEvent): void {
+    if (event.relatedTarget === null) {
+      //this must be a mouse click; if tabbed out the relatedTarget is the new focused element
+    } else {
+      if (this.isPartOfFilterWrapper(event.relatedTarget as Element)) {
+        //to nothing
+      } else if (this.isPartOfComponent(event.relatedTarget as Element)) {
+        this.filterInput.focus();
+      } else {
+        this.setFocus(false);
+      }
+    }
+  }
+
+  private setFocus(focus: boolean): void {
+    if (focus) {
+      this.classList.add(this.CssClass.TOBAGO_FOCUS);
+    } else {
+      this.classList.remove(this.CssClass.TOBAGO_FOCUS);
+    }
+  }
+
   private focusFilter(event: MouseEvent): void {
     // console.log("### focusFilter");
   }


[myfaces-tobago] 01/02: feat(selectMany): hide dropdown-menu manually

Posted by hn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 71a071e555213babd456eb6a09915c7384372ca2
Author: Henning Noeth <hn...@apache.org>
AuthorDate: Wed Nov 2 11:25:20 2022 +0100

    feat(selectMany): hide dropdown-menu manually
    
    * merge key events for filter and hiding
    
    Issue: TOBAGO-2159
---
 .../src/main/ts/tobago-select-many.ts              | 64 ++++++++++++----------
 1 file changed, 36 insertions(+), 28 deletions(-)

diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many.ts
index ef4516196c..bbea491888 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-select-many.ts
@@ -21,7 +21,9 @@ import {TobagoFilterRegistry} from "./tobago-filter-registry";
 class SelectMany extends HTMLElement {
 
   private readonly CssClass = {
-    SHOW: "show"
+    DROPDOWN_MENU: "dropdown-menu",
+    SHOW: "show",
+    TOBAGO_OPTIONS: "tobago-options"
   };
 
   private readonly Key = {
@@ -68,13 +70,15 @@ class SelectMany extends HTMLElement {
     // todo: implement select/deselect options
     // todo: implement remove badge
 
-    window.addEventListener("resize", this.resizeEvent.bind(this));
-    document.addEventListener("click", this.clickEvent.bind(this));
-    document.addEventListener("keydown", this.keydownEvent.bind(this));
-    this.addEventListener(BootstrapEvents.DROPDOWN_SHOW, this.showDropdown.bind(this));
-    this.addEventListener(BootstrapEvents.DROPDOWN_SHOWN, this.shownDropdown.bind(this));
-    this.addEventListener(BootstrapEvents.DROPDOWN_HIDE, this.preventBootstrapHide.bind(this));
-    this.addEventListener(BootstrapEvents.DROPDOWN_HIDDEN, this.HiddenDropdown.bind(this));
+    if (this.dropdownMenu) {
+      window.addEventListener("resize", this.resizeEvent.bind(this));
+      document.addEventListener("click", this.clickEvent.bind(this));
+      document.addEventListener("keydown", this.keydownEvent.bind(this));
+      this.addEventListener(BootstrapEvents.DROPDOWN_SHOW, this.showDropdown.bind(this));
+      this.addEventListener(BootstrapEvents.DROPDOWN_SHOWN, this.shownDropdown.bind(this));
+      this.addEventListener(BootstrapEvents.DROPDOWN_HIDE, this.preventBootstrapHide.bind(this));
+      this.addEventListener(BootstrapEvents.DROPDOWN_HIDDEN, this.hiddenDropdown.bind(this));
+    }
 
     // init badges
     this.querySelectorAll("option:checked").forEach(
@@ -166,17 +170,13 @@ class SelectMany extends HTMLElement {
     }
   }
 
-  private showDropdownMenu(event: MouseEvent): void {
-    this.dropdownMenu?.classList.add(this.CssClass.SHOW);
-  }
-
   private showDropdown(event: Event): void {
-    // console.log("### showDropdown");
+    console.log("### showDropdown");
   }
 
   private shownDropdown(event: Event): void {
     this.setDropdownMenuWidth();
-    // console.log("### shownDropdown");
+    console.log("### shownDropdown");
   }
 
   private preventBootstrapHide(event: CustomEvent): void {
@@ -185,32 +185,40 @@ class SelectMany extends HTMLElement {
   }
 
   private clickEvent(event: MouseEvent): void {
-    console.log("click auf this?");
-    event.composedPath().forEach(
-
-      (value, index, array) => {
-        if(value === this) {
-          console.log("yo");
-          return;
-        }
-        console.log("ding!");
-    });
+    let hide = true;
+
+    for (const element of event.composedPath() as HTMLElement[]) {
+      if (this.id === element.id
+        || (element.classList?.contains(this.CssClass.DROPDOWN_MENU)
+          && this.id === element.getAttribute("name"))) {
+        hide = false;
+        break;
+      }
+    }
 
-    console.log(`### clickEvent ${event.relatedTarget} ${event.target} ${event.currentTarget}`);
+    if (hide) {
+      this.hideDropdown();
+    }
   }
 
   private keydownEvent(event: KeyboardEvent) {
+    console.log("### keydownEvent");
     if (event.key === this.Key.ESCAPE) {
       this.hideDropdown();
     }
   }
 
   private hideDropdown(): void {
-    console.log("### hideDropdown");
+    if (this.dropdownMenu?.classList.contains(this.CssClass.SHOW)) {
+      this.selectField.classList.remove(this.CssClass.SHOW);
+      this.selectField.ariaExpanded = "false";
+      this.dropdownMenu.classList.remove(this.CssClass.SHOW);
+      console.log("### hideDropdown");
+    }
   }
 
-  private HiddenDropdown(event: Event): void {
-    // console.log("### HiddenDropdown");
+  private hiddenDropdown(event: Event): void {
+    console.log("### hiddenDropdown");
   }
 
   private resizeEvent(event: UIEvent): void {