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 2020/06/24 09:31:40 UTC

[myfaces-tobago] branch jsf23+quarkus updated (7d4f0aa -> 64b5e51)

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

lofwyr pushed a change to branch jsf23+quarkus
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git.


    from 7d4f0aa  TOBAGO-2045: Go for JavaEE 8 servers and Quarkus * quick start
     new 7ad914f  slightly better naming for setup function of Jasmine test tools
     new 48b934c  tobago-tree-listbox: custom elements
     new 2ca08e1  tobago-focus: custom elements
     new 64b5e51  add disable attribute for tc:buttons and tc:links

The 4 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:
 ...upportsAccessKey.java => SupportsDisabled.java} |   6 +-
 .../internal/component/AbstractUIButtons.java      |   8 +-
 .../internal/component/AbstractUICommandBase.java  |   8 +
 .../tobago/internal/component/AbstractUILinks.java |   8 +-
 .../internal/renderkit/renderer/LinksRenderer.java |   1 +
 .../internal/renderkit/renderer/PageRenderer.java  |   8 +-
 .../renderer/SelectManyListboxRenderer.java        |   2 +-
 .../renderer/SelectOneChoiceRenderer.java          |   2 +-
 .../renderkit/renderer/TextareaRenderer.java       |   2 +-
 .../taglib/component/ButtonsTagDeclaration.java    |   8 +
 .../taglib/component/LinksTagDeclaration.java      |   9 +
 .../tobago/renderkit/html/HtmlElements.java        |   4 +
 tobago-core/src/main/resources/scss/_tobago.scss   |  13 ++
 .../040-command/20-buttons/Button_Group.xhtml      |  15 ++
 .../040-command/25-links/Link_Group.xhtml          |  15 ++
 .../090-tree/04-listbox/Tree_Listbox.test.js       | 215 +++++++++++++++++++++
 .../090-tree/04-listbox/Tree_Listbox.xhtml         |   9 +-
 .../src/main/npm/ts/tobago-all.ts                  |   4 +
 .../src/main/npm/ts/tobago-focus.ts                | 144 ++++++++------
 .../src/main/npm/ts/tobago-in.ts                   |  19 ++
 .../src/main/npm/ts/tobago-popup.ts                |   6 +
 .../main/npm/ts/tobago-select-boolean-checkbox.ts  |   3 +
 .../src/main/npm/ts/tobago-select-many-checkbox.ts |   4 +
 ...bago-panel.ts => tobago-select-many-listbox.ts} |   6 +-
 .../src/main/npm/ts/tobago-select-many-shuttle.ts  |   5 +
 ...ean-checkbox.ts => tobago-select-one-choice.ts} |  17 +-
 ...an-checkbox.ts => tobago-select-one-listbox.ts} |  17 +-
 .../src/main/npm/ts/tobago-select-one-radio.ts     |   3 +
 ...lect-boolean-checkbox.ts => tobago-textarea.ts} |  17 +-
 .../src/main/npm/ts/tobago-tree-listbox.ts         |  11 +-
 .../resources/tobago/test/tobago-test-tool.js      |  18 +-
 31 files changed, 479 insertions(+), 128 deletions(-)
 copy tobago-core/src/main/java/org/apache/myfaces/tobago/component/{SupportsAccessKey.java => SupportsDisabled.java} (89%)
 create mode 100644 tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/04-listbox/Tree_Listbox.test.js
 copy tobago-theme/tobago-theme-standard/src/main/npm/ts/{tobago-panel.ts => tobago-select-many-listbox.ts} (82%)
 copy tobago-theme/tobago-theme-standard/src/main/npm/ts/{tobago-select-boolean-checkbox.ts => tobago-select-one-choice.ts} (70%)
 copy tobago-theme/tobago-theme-standard/src/main/npm/ts/{tobago-select-boolean-checkbox.ts => tobago-select-one-listbox.ts} (70%)
 copy tobago-theme/tobago-theme-standard/src/main/npm/ts/{tobago-select-boolean-checkbox.ts => tobago-textarea.ts} (70%)


[myfaces-tobago] 03/04: tobago-focus: custom elements

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

lofwyr pushed a commit to branch jsf23+quarkus
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git

commit 2ca08e18ff2789c389e99a96b429644a2e72c3cb
Author: Henning Nöth <hn...@apache.org>
AuthorDate: Thu Jun 4 21:58:23 2020 +0200

    tobago-focus: custom elements
    
    Added tobago-focus web element.
    The focusListener to set the lastFocusId must be implemented in the appropriate web elements. For this, several web elements are implemented or improved.
    The executing of [autofocus] within a popup is now handled in the tobago-popup web element.
    
    Issue: TOBAGO-1633
---
 .../internal/renderkit/renderer/PageRenderer.java  |   8 +-
 .../renderer/SelectManyListboxRenderer.java        |   2 +-
 .../renderer/SelectOneChoiceRenderer.java          |   2 +-
 .../renderkit/renderer/TextareaRenderer.java       |   2 +-
 .../tobago/renderkit/html/HtmlElements.java        |   4 +
 tobago-core/src/main/resources/scss/_tobago.scss   |  13 ++
 .../src/main/npm/ts/tobago-all.ts                  |   4 +
 .../src/main/npm/ts/tobago-focus.ts                | 144 ++++++++++++---------
 .../src/main/npm/ts/tobago-in.ts                   |  19 +++
 .../src/main/npm/ts/tobago-popup.ts                |   6 +
 .../main/npm/ts/tobago-select-boolean-checkbox.ts  |   3 +
 .../src/main/npm/ts/tobago-select-many-checkbox.ts |   4 +
 ...y-checkbox.ts => tobago-select-many-listbox.ts} |  25 +---
 .../src/main/npm/ts/tobago-select-many-shuttle.ts  |   5 +
 ...ean-checkbox.ts => tobago-select-one-choice.ts} |  17 +--
 ...an-checkbox.ts => tobago-select-one-listbox.ts} |  17 +--
 .../src/main/npm/ts/tobago-select-one-radio.ts     |   3 +
 ...lect-boolean-checkbox.ts => tobago-textarea.ts} |  17 +--
 18 files changed, 170 insertions(+), 125 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
index 21fa0ab..f570c41 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
@@ -280,12 +280,16 @@ public class PageRenderer extends RendererBase {
     writer.writeAttribute(HtmlAttributes.DISABLED, true);
     writer.endElement(HtmlElements.INPUT);
 
+    final String lastFocusId = clientId + ComponentUtils.SUB_SEPARATOR + "lastFocusId";
+    writer.startElement(HtmlElements.TOBAGO_FOCUS);
+    writer.writeIdAttribute(lastFocusId);
     writer.startElement(HtmlElements.INPUT);
     writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN);
-    writer.writeNameAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "lastFocusId");
-    writer.writeIdAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "lastFocusId");
+    writer.writeNameAttribute(lastFocusId);
+    writer.writeIdAttribute(lastFocusId + ComponentUtils.SUB_SEPARATOR + "field");
     writer.writeAttribute(HtmlAttributes.VALUE, tobagoContext.getFocusId(), true);
     writer.endElement(HtmlElements.INPUT);
+    writer.endElement(HtmlElements.TOBAGO_FOCUS);
 
     if (tobagoConfig.isCheckSessionSecret()) {
       writer.startElement(HtmlElements.INPUT);
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListboxRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListboxRenderer.java
index a2d431a..5bc4c6d 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListboxRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyListboxRenderer.java
@@ -40,7 +40,7 @@ public class SelectManyListboxRenderer extends SelectManyRendererBase {
 
   @Override
   public HtmlElements getComponentTag() {
-    return HtmlElements.DIV;
+    return HtmlElements.TOBAGO_SELECT_MANY_LISTBOX;
   }
 
   @Override
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java
index 86f49da..4e3c7a0 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectOneChoiceRenderer.java
@@ -40,7 +40,7 @@ public class SelectOneChoiceRenderer extends SelectOneRendererBase {
 
   @Override
   public HtmlElements getComponentTag() {
-    return HtmlElements.DIV;
+    return HtmlElements.TOBAGO_SELECT_ONE_CHOICE;
   }
 
   @Override
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TextareaRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TextareaRenderer.java
index ff90914..5f42d3b 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TextareaRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TextareaRenderer.java
@@ -50,7 +50,7 @@ public class TextareaRenderer extends MessageLayoutRendererBase {
 
   @Override
   public HtmlElements getComponentTag() {
-    return HtmlElements.DIV;
+    return HtmlElements.TOBAGO_TEXTAREA;
   }
 
   private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlElements.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlElements.java
index 0cf0900..46304f7 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlElements.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/renderkit/html/HtmlElements.java
@@ -138,6 +138,7 @@ public enum HtmlElements {
   TOBAGO_DATE("tobago-date"),
   TOBAGO_DROPDOWN("tobago-dropdown"),
   TOBAGO_FILE("tobago-file"),
+  TOBAGO_FOCUS("tobago-focus"),
   TOBAGO_FOOTER("tobago-footer"),
   TOBAGO_LABEL("tobago-label"),
   TOBAGO_HEADER("tobago-header"),
@@ -151,7 +152,9 @@ public enum HtmlElements {
   TOBAGO_SELECT_BOOLEAN_CHECKBOX("tobago-select-boolean-checkbox"),
   TOBAGO_SELECT_BOOLEAN_TOGGLE("tobago-select-boolean-toggle"),
   TOBAGO_SELECT_MANY_CHECKBOX("tobago-select-many-checkbox"),
+  TOBAGO_SELECT_MANY_LISTBOX("tobago-select-many-listbox"),
   TOBAGO_SELECT_MANY_SHUTTLE("tobago-select-many-shuttle"),
+  TOBAGO_SELECT_ONE_CHOICE("tobago-select-one-choice"),
   TOBAGO_SELECT_ONE_LISTBOX("tobago-select-one-listbox"),
   TOBAGO_SELECT_ONE_RADIO("tobago-select-one-radio"),
   TOBAGO_SHEET("tobago-sheet"),
@@ -160,6 +163,7 @@ public enum HtmlElements {
   TOBAGO_TAB("tobago-tab"),
   TOBAGO_TAB_CONTENT("tobago-tab-content"),
   TOBAGO_TAB_GROUP("tobago-tab-group"),
+  TOBAGO_TEXTAREA("tobago-textarea"),
   TOBAGO_TREE("tobago-tree"),
   TOBAGO_TREE_LISTBOX("tobago-tree-listbox"),
   TOBAGO_TREE_NODE("tobago-tree-node"),
diff --git a/tobago-core/src/main/resources/scss/_tobago.scss b/tobago-core/src/main/resources/scss/_tobago.scss
index e81e455..2fdb039 100644
--- a/tobago-core/src/main/resources/scss/_tobago.scss
+++ b/tobago-core/src/main/resources/scss/_tobago.scss
@@ -326,6 +326,11 @@ tobago-file {
 .tobago-flowLayout {
 }
 
+/* focus --------------------------------------------------------------- */
+tobago-focus {
+  display: none;
+}
+
 /* footer -------------------------------------------------------------- */
 
 tobago-footer {
@@ -1041,6 +1046,11 @@ tobago-select-boolean-toggle {
   @include adjustCustomControlLabel();
 }
 
+/* selectOneChoice --------------------------------------------------------- */
+tobago-select-one-choice {
+
+}
+
 /* selectOneListbox -------------------------------------------------------- */
 tobago-select-one-listbox {
   display: block;
@@ -1081,6 +1091,9 @@ tobago-select-many-checkbox {
 }
 
 /* selectManyListbox ----------------------------------------------------------- */
+tobago-select-many-listbox {
+
+}
 .tobago-selectManyListbox,
 .tobago-selectManyListbox-option {
 }
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-all.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-all.ts
index 99281d5..d87e181 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-all.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-all.ts
@@ -38,13 +38,17 @@ import "./tobago-scroll";
 import "./tobago-select-boolean-checkbox";
 import "./tobago-select-boolean-toggle";
 import "./tobago-select-many-checkbox";
+import "./tobago-select-many-listbox";
 import "./tobago-select-many-shuttle";
+import "./tobago-select-one-choice";
+import "./tobago-select-one-listbox";
 import "./tobago-select-one-radio";
 import "./tobago-sheet";
 import "./tobago-split-layout";
 import "./tobago-stars";
 import "./tobago-suggest";
 import "./tobago-tab";
+import "./tobago-textarea";
 import "./tobago-tree";
 import "./tobago-tree-listbox";
 import "./tobago-tree-node";
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-focus.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-focus.ts
index eba35a2..beab956 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-focus.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-focus.ts
@@ -15,22 +15,32 @@
  * limitations under the License.
  */
 
-import {DomUtils} from "./tobago-utils";
-import {Listener, Phase} from "./tobago-listener";
 import {Page} from "./tobago-page";
+import {DomUtils} from "./tobago-utils";
 
-export class Focus {
-
-  private static getHidden(): HTMLInputElement {
-    return document.getElementById(Page.page().id + DomUtils.SUB_COMPONENT_SEP + "lastFocusId") as HTMLInputElement;
-  }
+export class Focus extends HTMLElement {
 
-  static setLastFocusId(id: string): void {
-    this.getHidden().value = id;
+  /**
+   * The focusListener to set the lastFocusId must be implemented in the appropriate web elements.
+   * @param event
+   */
+  static setLastFocusId(event: FocusEvent): void {
+    const target = event.target as HTMLElement;
+    let computedStyle = getComputedStyle(target);
+
+    if (target.getAttribute("type") !== "hidden"
+        && target.getAttributeNames().indexOf("disabled") === -1
+        && target.getAttribute("tabindex") !== "-1"
+        && computedStyle.visibility !== "hidden"
+        && computedStyle.display !== "none") {
+      const root = target.getRootNode() as ShadowRoot | Document;
+      const tobagoFocus = root.getElementById(Page.page().id + DomUtils.SUB_COMPONENT_SEP + "lastFocusId");
+      tobagoFocus.querySelector("input").value = target.id;
+    }
   }
 
-  static getLastFocusId(): string {
-    return this.getHidden().value;
+  constructor() {
+    super();
   }
 
   /**
@@ -43,75 +53,85 @@ export class Focus {
    * - last (the element from the last request with same id gets the focus, not AJAX)
    * - first (the first input element (without tabindex=-1) gets the focus, not AJAX)
    */
-  static init = function (element: HTMLElement): void {
-
-    const activeInputs = Focus.activeInputs(element);
-
-    for (const focusable of activeInputs) {
-      focusable.addEventListener("focus", function (event: FocusEvent): void {
-        const target = event.target as HTMLElement;
-        if (target.style.visibility !== "hidden" && target.style.display != "none") {
-          // remember the last focused element, for later
-          Focus.setLastFocusId(target.id);
-        }
-      });
-    }
-
-    // autofocus in popups doesn't work automatically... so we fix that here
-    const modals = document.getElementsByClassName("modal");
-    for (let i = 0; i < modals.length; i++) {
-      modals.item(i).addEventListener("shown.bs.modal", Focus.initAutoFocus);
-    }
-
-    for (const hasDanger of DomUtils.selfOrElementsByClassName(element, ".has-danger")) {
-      const activeInputsInsideDanger = Focus.activeInputs(hasDanger);
-      if (activeInputsInsideDanger.length > 0) {
-        activeInputsInsideDanger[0].focus();
-        return;
-      }
+  connectedCallback(): void {
+    const errorElement = this.errorElement;
+    if (errorElement) {
+      errorElement.focus();
+      return;
     }
 
-    const autoFocus = element.querySelector("[autofocus]");
-    if (autoFocus) {
+    if (this.autofocusElements.length > 0) {
       // nothing to do, because the browser make the work.
       return;
     }
 
-    if (element.parentElement) {
-      // seems to be AJAX, so end here
+    const lastFocusedElement = this.lastFocusedElement;
+    if (lastFocusedElement) {
+      lastFocusedElement.focus();
       return;
     }
 
-    const lastFocusId = Focus.getLastFocusId();
-    if (lastFocusId) {
-      const element = document.getElementById(lastFocusId);
-      if (element) {
-        element.focus();
-      }
+    const focusableElement = this.focusableElement;
+    if (focusableElement) {
+      focusableElement.focus();
       return;
     }
+  }
 
-    if (activeInputs.length > 0) {
-      activeInputs[0].focus();
-      return;
+  private get errorElement(): HTMLElement {
+    const root = this.getRootNode() as ShadowRoot | Document;
+    const elements = root.querySelectorAll(
+        ".tobago-messages-container .border-danger:not([disabled]):not([tabindex='-1'])") as NodeListOf<HTMLElement>;
+
+    for (const element of elements) {
+      const computedStyle = getComputedStyle(element);
+      if (computedStyle.display !== "none" && computedStyle.visibility !== "hidden") {
+        return element;
+      }
     }
-  };
+  }
+
+  private get autofocusElements(): NodeListOf<HTMLElement> {
+    const root = this.getRootNode() as ShadowRoot | Document;
+    return root.querySelectorAll("[autofocus]");
+  }
+
+  private get lastFocusedElement(): HTMLElement {
+    const lastFocusId: string = this.hiddenInput.value;
+    const root = this.getRootNode() as ShadowRoot | Document;
+    return root.getElementById(lastFocusId);
+  }
+
+  private get hiddenInput(): HTMLInputElement {
+    return this.querySelector("input");
+  }
 
-  private static activeInputs(element: HTMLElement): Array<HTMLElement> {
-    return DomUtils.selfOrQuerySelectorAll(element,
+  private get focusableElement(): HTMLElement {
+    const root = this.getRootNode() as ShadowRoot | Document;
+    const elements = root.querySelectorAll(
         "input:not([type='hidden']):not([disabled]):not([tabindex='-1'])," +
         "select:not([disabled]):not([tabindex='-1'])," +
-        "textarea:not([disabled]):not([tabindex='-1'])")
-        .filter((element) =>
-            element.style.visibility !== "hidden"
-            && element.style.display != "none");
+        "textarea:not([disabled]):not([tabindex='-1'])") as NodeListOf<HTMLElement>;
+
+    for (const element of elements) {
+      if (this.isVisible(element)) {
+        return element;
+      }
+    }
   }
 
-  private static initAutoFocus(event): void {
-    const modal = event.currentTarget as HTMLElement;
-    (modal.querySelector("[autofocus]") as HTMLElement).focus();
+  private isVisible(element: HTMLElement): boolean {
+    const computedStyle = getComputedStyle(element);
+    if (computedStyle.display === "none" || computedStyle.visibility === "hidden") {
+      return false;
+    } else if (element.parentElement) {
+      return this.isVisible(element.parentElement);
+    } else {
+      return true;
+    }
   }
 }
 
-Listener.register(Focus.init, Phase.DOCUMENT_READY);
-Listener.register(Focus.init, Phase.AFTER_UPDATE);
+document.addEventListener("DOMContentLoaded", function (event: Event): void {
+  window.customElements.define("tobago-focus", Focus);
+});
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-in.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-in.ts
index 1c9f316..02c421d 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-in.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-in.ts
@@ -17,6 +17,25 @@
 
 import {Listener, Phase} from "./tobago-listener";
 import {DomUtils} from "./tobago-utils";
+import {Focus} from "./tobago-focus";
+
+export class In extends HTMLElement {
+  constructor() {
+    super();
+  }
+
+  connectedCallback(): void {
+    this.input.addEventListener("focus", Focus.setLastFocusId);
+  }
+
+  get input(): HTMLInputElement {
+    return this.querySelector(DomUtils.escapeClientId(this.id + DomUtils.SUB_COMPONENT_SEP + "field"));
+  }
+}
+
+document.addEventListener("DOMContentLoaded", function (event: Event): void {
+  window.customElements.define("tobago-in", In);
+});
 
 // XXX regexp example only - blueprint
 class RegExpTest {
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-popup.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-popup.ts
index 7a215bf..0a86c80 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-popup.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-popup.ts
@@ -312,6 +312,12 @@ export class Popup extends HTMLElement {
     // } else {
     //   transitionComplete()
     // }
+
+    this.dispatchEvent(new CustomEvent(Event.SHOWN));
+    const autofocusElement = this.querySelector("[autofocus]") as HTMLElement;
+    if (autofocusElement) {
+      autofocusElement.focus();
+    }
   }
 /*
   _enforceFocus() {
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts
index 8cd46ba..a6a3593 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts
@@ -16,6 +16,7 @@
  */
 
 import {DomUtils} from "./tobago-utils";
+import {Focus} from "./tobago-focus";
 
 export class SelectBooleanCheckbox extends HTMLElement {
 
@@ -24,6 +25,8 @@ export class SelectBooleanCheckbox extends HTMLElement {
   }
 
   connectedCallback(): void {
+    this.input.addEventListener("focus", Focus.setLastFocusId);
+
     if (this.input.readOnly) {
       this.input.addEventListener("click", preventClick);
     }
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-checkbox.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-checkbox.ts
index 36b69e5..05fbc64 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-checkbox.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-checkbox.ts
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+import {Focus} from "./tobago-focus";
+
 class SelectManyCheckbox extends HTMLElement {
 
   constructor() {
@@ -23,6 +25,8 @@ class SelectManyCheckbox extends HTMLElement {
 
   connectedCallback(): void {
     for (const input of this.inputs) {
+      input.addEventListener("focus", Focus.setLastFocusId);
+
       if (input.readOnly) {
         input.addEventListener("click", preventClick);
       }
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-checkbox.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-listbox.ts
similarity index 57%
copy from tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-checkbox.ts
copy to tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-listbox.ts
index 36b69e5..28cea87 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-checkbox.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-listbox.ts
@@ -15,30 +15,11 @@
  * limitations under the License.
  */
 
-class SelectManyCheckbox extends HTMLElement {
+import {SelectOneListbox} from "./tobago-select-one-listbox";
 
-  constructor() {
-    super();
-  }
-
-  connectedCallback(): void {
-    for (const input of this.inputs) {
-      if (input.readOnly) {
-        input.addEventListener("click", preventClick);
-      }
-
-      function preventClick(event: MouseEvent): void {
-        // in the "readonly" case, prevent the default, which is changing the "checked" state
-        event.preventDefault();
-      }
-    }
-  }
-
-  get inputs(): NodeListOf<HTMLInputElement> {
-    return this.querySelectorAll("input[name='" + this.id + "']");
-  }
+class SelectManyListbox extends SelectOneListbox {
 }
 
 document.addEventListener("DOMContentLoaded", function (event: Event): void {
-  window.customElements.define("tobago-select-many-checkbox", SelectManyCheckbox);
+  window.customElements.define("tobago-select-many-listbox", SelectManyListbox);
 });
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-shuttle.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-shuttle.ts
index 1cf4161..2e8bd48 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-shuttle.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-many-shuttle.ts
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+import {Focus} from "./tobago-focus";
+
 class SelectManyShuttle extends HTMLElement {
 
   constructor() {
@@ -22,6 +24,9 @@ class SelectManyShuttle extends HTMLElement {
   }
 
   connectedCallback(): void {
+    this.unselectedSelect.addEventListener("focus", Focus.setLastFocusId);
+    this.selectedSelect.addEventListener("focus", Focus.setLastFocusId);
+
     if (this.unselectedSelect.getAttribute("readonly") !== "readonly" && !this.unselectedSelect.disabled) {
       this.unselectedSelect.addEventListener("dblclick", this.addSelectedItems.bind(this));
     }
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-one-choice.ts
similarity index 70%
copy from tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts
copy to tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-one-choice.ts
index 8cd46ba..fff94da 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-one-choice.ts
@@ -16,29 +16,22 @@
  */
 
 import {DomUtils} from "./tobago-utils";
+import {Focus} from "./tobago-focus";
 
-export class SelectBooleanCheckbox extends HTMLElement {
-
+class SelectOneChoice extends HTMLElement {
   constructor() {
     super();
   }
 
   connectedCallback(): void {
-    if (this.input.readOnly) {
-      this.input.addEventListener("click", preventClick);
-    }
-
-    function preventClick(event: MouseEvent): void {
-      // in the "readonly" case, prevent the default, which is changing the "checked" state
-      event.preventDefault();
-    }
+    this.field.addEventListener("focus", Focus.setLastFocusId);
   }
 
-  get input(): HTMLInputElement {
+  get field(): HTMLInputElement {
     return this.querySelector(DomUtils.escapeClientId(this.id + DomUtils.SUB_COMPONENT_SEP + "field"));
   }
 }
 
 document.addEventListener("DOMContentLoaded", function (event: Event): void {
-  window.customElements.define("tobago-select-boolean-checkbox", SelectBooleanCheckbox);
+  window.customElements.define("tobago-select-one-choice", SelectOneChoice);
 });
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-one-listbox.ts
similarity index 70%
copy from tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts
copy to tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-one-listbox.ts
index 8cd46ba..8b3eac8 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-one-listbox.ts
@@ -16,29 +16,22 @@
  */
 
 import {DomUtils} from "./tobago-utils";
+import {Focus} from "./tobago-focus";
 
-export class SelectBooleanCheckbox extends HTMLElement {
-
+export class SelectOneListbox extends HTMLElement {
   constructor() {
     super();
   }
 
   connectedCallback(): void {
-    if (this.input.readOnly) {
-      this.input.addEventListener("click", preventClick);
-    }
-
-    function preventClick(event: MouseEvent): void {
-      // in the "readonly" case, prevent the default, which is changing the "checked" state
-      event.preventDefault();
-    }
+    this.field.addEventListener("focus", Focus.setLastFocusId);
   }
 
-  get input(): HTMLInputElement {
+  get field(): HTMLInputElement {
     return this.querySelector(DomUtils.escapeClientId(this.id + DomUtils.SUB_COMPONENT_SEP + "field"));
   }
 }
 
 document.addEventListener("DOMContentLoaded", function (event: Event): void {
-  window.customElements.define("tobago-select-boolean-checkbox", SelectBooleanCheckbox);
+  window.customElements.define("tobago-select-one-listbox", SelectOneListbox);
 });
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-one-radio.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-one-radio.ts
index bb2138f..b3a46e4 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-one-radio.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-one-radio.ts
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+import {Focus} from "./tobago-focus";
+
 class SelectOneRadio extends HTMLElement {
 
   private oldCheckedId: string = "";
@@ -26,6 +28,7 @@ class SelectOneRadio extends HTMLElement {
   connectedCallback(): void {
     this.saveSelection();
     for (const radio of this.radioGroup) {
+      radio.addEventListener("focus", Focus.setLastFocusId);
       radio.addEventListener("click", this.clickSelection.bind(this));
     }
   }
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-textarea.ts
similarity index 70%
copy from tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts
copy to tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-textarea.ts
index 8cd46ba..fc522b5 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-select-boolean-checkbox.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-textarea.ts
@@ -16,29 +16,22 @@
  */
 
 import {DomUtils} from "./tobago-utils";
+import {Focus} from "./tobago-focus";
 
-export class SelectBooleanCheckbox extends HTMLElement {
-
+class Textarea extends HTMLElement {
   constructor() {
     super();
   }
 
   connectedCallback(): void {
-    if (this.input.readOnly) {
-      this.input.addEventListener("click", preventClick);
-    }
-
-    function preventClick(event: MouseEvent): void {
-      // in the "readonly" case, prevent the default, which is changing the "checked" state
-      event.preventDefault();
-    }
+    this.textarea.addEventListener("focus", Focus.setLastFocusId);
   }
 
-  get input(): HTMLInputElement {
+  get textarea(): HTMLInputElement {
     return this.querySelector(DomUtils.escapeClientId(this.id + DomUtils.SUB_COMPONENT_SEP + "field"));
   }
 }
 
 document.addEventListener("DOMContentLoaded", function (event: Event): void {
-  window.customElements.define("tobago-select-boolean-checkbox", SelectBooleanCheckbox);
+  window.customElements.define("tobago-textarea", Textarea);
 });


[myfaces-tobago] 01/04: slightly better naming for setup function of Jasmine test tools

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

lofwyr pushed a commit to branch jsf23+quarkus
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git

commit 7ad914f43be15d7d2373d2e021f7f37754866521
Author: Henning Nöth <hn...@apache.org>
AuthorDate: Fri Jun 12 15:59:09 2020 +0200

    slightly better naming for setup function of Jasmine test tools
---
 .../META-INF/resources/tobago/test/tobago-test-tool.js | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/tobago-tool/tobago-tool-test/src/main/resources/META-INF/resources/tobago/test/tobago-test-tool.js b/tobago-tool/tobago-tool-test/src/main/resources/META-INF/resources/tobago/test/tobago-test-tool.js
index 19131ac..13e6d73 100644
--- a/tobago-tool/tobago-tool-test/src/main/resources/META-INF/resources/tobago/test/tobago-test-tool.js
+++ b/tobago-tool/tobago-tool-test/src/main/resources/META-INF/resources/tobago/test/tobago-test-tool.js
@@ -250,19 +250,19 @@ class JasmineTestTool {
   }
 
   /**
-   * The condition function (fn1) defines the desired state before the main test starts. The do function (fn2) will be
-   * executed if the condition function returns false.
-   * @param fn1 condition function
-   * @param fn2 do function
+   * The require function (require) defines the desired state before the main test starts. The fix function (fix)
+   * will be executed if the require function returns false.
+   * @param require function
+   * @param fix function
    */
-  setup(fn1, fn2) {
+  setup(require, fix) {
     this.do(() => {
-      if (!fn1()) {
-        console.debug("[JasmineTestTool] fn1() returns false, execute fn2()");
-        fn2();
+      if (!require()) {
+        console.debug("[JasmineTestTool] require() returns false, execute fix()");
+        fix();
       }
     })
-    this.wait(fn1);
+    this.wait(require);
   }
 
   /**


[myfaces-tobago] 02/04: tobago-tree-listbox: custom elements

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

lofwyr pushed a commit to branch jsf23+quarkus
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git

commit 48b934cd6c023a7a262cc506e5b3cea910d3aa3e
Author: Henning Nöth <hn...@apache.org>
AuthorDate: Fri Jun 12 15:56:50 2020 +0200

    tobago-tree-listbox: custom elements
    
    * fix: default listbox are not displayed if parent have no children
    * add test
    
    Issue: TOBAGO-1633
---
 .../090-tree/04-listbox/Tree_Listbox.test.js       | 215 +++++++++++++++++++++
 .../090-tree/04-listbox/Tree_Listbox.xhtml         |   9 +-
 .../src/main/npm/ts/tobago-tree-listbox.ts         |  11 +-
 3 files changed, 226 insertions(+), 9 deletions(-)

diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/04-listbox/Tree_Listbox.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/04-listbox/Tree_Listbox.test.js
new file mode 100644
index 0000000..e507905
--- /dev/null
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/04-listbox/Tree_Listbox.test.js
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+
+import {elementByIdFn, querySelectorFn} from "/script/tobago-test.js";
+import {JasmineTestTool} from "/tobago/test/tobago-test-tool.js";
+
+it("Select 2,2,0 and submit", function (done) {
+  const hiddenInput = elementByIdFn("page:mainForm:listbox::selected");
+  const submit = elementByIdFn("page:mainForm:submit");
+  const output = querySelectorFn("#page\\:mainForm\\:output span");
+  const node1 = elementByIdFn("page:mainForm:listbox:1:node");
+  const node3 = elementByIdFn("page:mainForm:listbox:3:node"); // 2
+  const node6 = elementByIdFn("page:mainForm:listbox:6:node"); // 2,2
+  const node7 = elementByIdFn("page:mainForm:listbox:7:node"); // 2,2,0
+
+  const test = new JasmineTestTool(done);
+  test.setup(() => isLevelSelectVisible(2, 1),
+      () => {
+        node1().selected = true;
+        node1().dispatchEvent(new Event("change", {bubbles: true}));
+      });
+  test.setup(() => output().textContent !== "[[2, 2, 0]]",
+      () => submit().dispatchEvent(new Event("click", {bubbles: true})));
+
+  test.do(() => node3().selected = true);
+  test.event("change", node3,
+      () => hiddenInput().value === "[2]" && isLevelSelectVisible(2, 2));
+
+  test.do(() => expect(isLevelSelectVisible(1, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 2)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(3, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 4)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(4, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(4, 2)).toBeFalse());
+
+  test.do(() => node6().selected = true);
+  test.event("change", node6,
+      () => hiddenInput().value === "[2,2]" && isLevelSelectVisible(3, 2));
+
+  test.do(() => expect(isLevelSelectVisible(1, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 2)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 2)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(3, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 4)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(4, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(4, 2)).toBeFalse());
+
+  test.do(() => node7().selected = true);
+  test.event("change", node7, () => hiddenInput().value === "[2,2,0]");
+
+  test.do(() => expect(isLevelSelectVisible(1, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 2)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 2)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(3, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 4)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(4, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(4, 2)).toBeFalse());
+
+  test.event("click", submit, () => output().textContent === "[[2, 2, 0]]");
+  test.do(() => expect(output().textContent).toBe("[[2, 2, 0]]"));
+
+  test.start();
+});
+
+
+it("Select 3 and submit", function (done) {
+  const hiddenInput = elementByIdFn("page:mainForm:listbox::selected");
+  const submit = elementByIdFn("page:mainForm:submit");
+  const output = querySelectorFn("#page\\:mainForm\\:output span");
+  const node1 = elementByIdFn("page:mainForm:listbox:1:node");
+  const node9 = elementByIdFn("page:mainForm:listbox:9:node"); // 3
+
+  const test = new JasmineTestTool(done);
+  test.setup(() => isLevelSelectVisible(2, 1),
+      () => {
+        node1().selected = true;
+        node1().dispatchEvent(new Event("change", {bubbles: true}));
+      });
+  test.setup(() => output().textContent !== "[[3]]",
+      () => submit().dispatchEvent(new Event("click", {bubbles: true})));
+
+  test.do(() => node9().selected = true);
+  test.event("change", node9,
+      () => hiddenInput().value === "[3]" && isLevelSelectVisible(2, 1));
+
+  test.do(() => expect(isLevelSelectVisible(1, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(3, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 4)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(4, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(4, 2)).toBeFalse());
+
+  test.event("click", submit, () => output().textContent === "[[3]]");
+  test.do(() => expect(output().textContent).toBe("[[3]]"));
+
+  test.start();
+});
+
+it("Select 4,2,1,1 and submit", function (done) {
+  const hiddenInput = elementByIdFn("page:mainForm:listbox::selected");
+  const submit = elementByIdFn("page:mainForm:submit");
+  const output = querySelectorFn("#page\\:mainForm\\:output span");
+  const node1 = elementByIdFn("page:mainForm:listbox:1:node");
+  const node10 = elementByIdFn("page:mainForm:listbox:10:node"); // 4
+  const node15 = elementByIdFn("page:mainForm:listbox:15:node"); // 4,2
+  const node17 = elementByIdFn("page:mainForm:listbox:17:node"); // 4,2,1
+  const node19 = elementByIdFn("page:mainForm:listbox:19:node"); // 4,2,1,1
+
+  const test = new JasmineTestTool(done);
+  test.setup(() => isLevelSelectVisible(2, 1),
+      () => {
+        node1().selected = true;
+        node1().dispatchEvent(new Event("change", {bubbles: true}));
+      });
+  test.setup(() => output().textContent !== "[[4, 2, 1, 1]]",
+      () => submit().dispatchEvent(new Event("click", {bubbles: true})));
+
+  test.do(() => node10().selected = true);
+  test.event("change", node10,
+      () => hiddenInput().value === "[4]" && isLevelSelectVisible(2, 3));
+
+  test.do(() => expect(isLevelSelectVisible(1, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 3)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(3, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(3, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 4)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(4, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(4, 2)).toBeFalse());
+
+  test.do(() => node15().selected = true);
+  test.event("change", node15,
+      () => hiddenInput().value === "[4,2]" && isLevelSelectVisible(3, 4));
+
+  test.do(() => expect(isLevelSelectVisible(1, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 3)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(3, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 4)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(4, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(4, 2)).toBeFalse());
+
+  test.do(() => node17().selected = true);
+  test.event("change", node17,
+      () => hiddenInput().value === "[4,2,1]" && isLevelSelectVisible(4, 2));
+
+  test.do(() => expect(isLevelSelectVisible(1, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 3)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(3, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 4)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(4, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(4, 2)).toBeTrue());
+
+  test.do(() => node19().selected = true);
+  test.event("change", node19, () => hiddenInput().value === "[4,2,1,1]");
+
+  test.do(() => expect(isLevelSelectVisible(1, 1)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(2, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(2, 3)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(3, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 2)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 3)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(3, 4)).toBeTrue());
+  test.do(() => expect(isLevelSelectVisible(4, 1)).toBeFalse());
+  test.do(() => expect(isLevelSelectVisible(4, 2)).toBeTrue());
+
+  test.event("click", submit, () => output().textContent === "[[4, 2, 1, 1]]");
+  test.do(() => expect(output().textContent).toBe("[[4, 2, 1, 1]]"));
+
+  test.start();
+});
+
+function isLevelSelectVisible(level, select) {
+  const selectElement = querySelectorFn("#page\\:mainForm\\:listbox .tobago-treeListbox-level:nth-of-type("
+      + level + ") .tobago-treeListbox-select:nth-of-type(" + select + ")");
+  return !selectElement().classList.contains("d-none");
+}
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/04-listbox/Tree_Listbox.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/04-listbox/Tree_Listbox.xhtml
index b002c07..dadb93c 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/04-listbox/Tree_Listbox.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/090-tree/04-listbox/Tree_Listbox.xhtml
@@ -29,15 +29,16 @@
 
   <tc:section label="Example">
     <pre><code class="language-markup">&lt;tc:treeListbox value="\#{treeListboxController.sample}" ...></code></pre>
-    <tc:treeListbox id="listbox" value="#{treeListboxController.sample}" var="node" state="#{treeListboxController.state}">
+    <tc:treeListbox id="listbox" value="#{treeListboxController.sample}" var="node"
+                    state="#{treeListboxController.state}">
       <tc:treeNode id="node">
         <tc:treeLabel id="label" value="#{node.userObject.name}"/>
       </tc:treeNode>
     </tc:treeListbox>
 
-    <tc:button label="Submit" action="#{treeListboxController.submit}"/>
+    <tc:button id="submit" label="Submit" action="#{treeListboxController.submit}"/>
 
-    <tc:in readonly="true" label="Selection" tip="as set of tree pathes" value="#{treeListboxController.state.selectedState}"/>
-<!--    <tc:in readonly="true" label="Selection" value="#{treeListboxController.selectedNodes}"/>-->
+    <tc:out id="output" label="Selection" tip="as set of tree pathes"
+            value="#{treeListboxController.state.selectedState}"/>
   </tc:section>
 </ui:composition>
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tree-listbox.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tree-listbox.ts
index 0eb5659..b55f275 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tree-listbox.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tree-listbox.ts
@@ -68,17 +68,18 @@ class TreeListbox extends HTMLElement {
 
   private applySelected(): void {
     const selected: number[] = JSON.parse(this.hiddenInput.value);
-    let nextActiveSelectId: string = this.querySelector(".tobago-treeListbox-select").id;
+    let nextActiveSelect: HTMLSelectElement = this.querySelector(".tobago-treeListbox-select");
 
     const levelElements = this.levelElements;
     for (let i = 0; i < levelElements.length; i++) {
       const level = levelElements[i];
 
       for (const select of this.getSelectElements(level)) {
-        if (select.id === nextActiveSelectId || (nextActiveSelectId === null && select.disabled)) {
+        if ((nextActiveSelect !== null && select.id === nextActiveSelect.id)
+            || (nextActiveSelect === null && select.disabled)) {
           const check: number = i < selected.length ? selected[i] : null;
           this.show(select, check);
-          nextActiveSelectId = this.getNextActiveSelectId(select, check);
+          nextActiveSelect = this.getNextActiveSelect(select, check);
         } else {
           this.hide(select);
         }
@@ -90,10 +91,10 @@ class TreeListbox extends HTMLElement {
     return level.querySelectorAll<HTMLSelectElement>(".tobago-treeListbox-select");
   }
 
-  private getNextActiveSelectId(select: HTMLSelectElement, check: number): string {
+  private getNextActiveSelect(select: HTMLSelectElement, check: number): HTMLSelectElement {
     if (check !== null) {
       const option = select.querySelectorAll("option")[check];
-      return option.id + DomUtils.SUB_COMPONENT_SEP + "parent";
+      return this.querySelector(DomUtils.escapeClientId(option.id + DomUtils.SUB_COMPONENT_SEP + "parent"));
     } else {
       return null;
     }


[myfaces-tobago] 04/04: add disable attribute for tc:buttons and tc:links

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

lofwyr pushed a commit to branch jsf23+quarkus
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git

commit 64b5e51708e4937f095dc2a51df2a8c861f949f5
Author: Jasmin Kroeger <ja...@irian.eu>
AuthorDate: Tue Jun 9 10:46:15 2020 +0200

    add disable attribute for tc:buttons and tc:links
    
    * add setter for disable attribute in ButtonsTagDeclaration and LinksTagDeclaration
    * create Interface to set and get disabled
    * adjust Renderer to write disabled attribute in tag
    * adjust isDisabled in AbstractUICommandBase to check if the parent is disabled. If the parent is disabled all all children are disabled. If a child has the disabled attribute set, than the child is not disabled.
    * create example in demo
    
    ISSUE: TOBAGO-1997
---
 .../SupportsDisabled.java}                                | 11 ++++-------
 .../tobago/internal/component/AbstractUIButtons.java      |  8 +++++++-
 .../tobago/internal/component/AbstractUICommandBase.java  |  8 ++++++++
 .../tobago/internal/component/AbstractUILinks.java        |  8 +++++++-
 .../tobago/internal/renderkit/renderer/LinksRenderer.java |  1 +
 .../internal/taglib/component/ButtonsTagDeclaration.java  |  8 ++++++++
 .../internal/taglib/component/LinksTagDeclaration.java    |  9 +++++++++
 .../040-command/20-buttons/Button_Group.xhtml             | 15 +++++++++++++++
 .../20-component/040-command/25-links/Link_Group.xhtml    | 15 +++++++++++++++
 9 files changed, 74 insertions(+), 9 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUILinks.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/SupportsDisabled.java
similarity index 72%
copy from tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUILinks.java
copy to tobago-core/src/main/java/org/apache/myfaces/tobago/component/SupportsDisabled.java
index 8de772a..ab39327 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUILinks.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/SupportsDisabled.java
@@ -17,14 +17,11 @@
  * under the License.
  */
 
-package org.apache.myfaces.tobago.internal.component;
+package org.apache.myfaces.tobago.component;
 
-import org.apache.myfaces.tobago.layout.Orientation;
+public interface SupportsDisabled {
 
-/**
- * {@link org.apache.myfaces.tobago.internal.taglib.component.LinksTagDeclaration}
- */
-public abstract class AbstractUILinks extends AbstractUIPanelBase {
+  boolean isDisabled();
 
-  public abstract Orientation getOrientation();
+  void setDisabled(final boolean disabled);
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIButtons.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIButtons.java
index 30396e5..357ff5f 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIButtons.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUIButtons.java
@@ -19,12 +19,18 @@
 
 package org.apache.myfaces.tobago.internal.component;
 
+import org.apache.myfaces.tobago.component.SupportsDisabled;
 import org.apache.myfaces.tobago.layout.Orientation;
 
 /**
  * {@link org.apache.myfaces.tobago.internal.taglib.component.ButtonsTagDeclaration}
  */
-public abstract class AbstractUIButtons extends AbstractUIPanelBase {
+public abstract class AbstractUIButtons extends AbstractUIPanelBase implements SupportsDisabled {
+
+  enum PropertyKeys {
+    disabled,
+  }
 
   public abstract Orientation getOrientation();
+
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommandBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommandBase.java
index 1045901..7321b2e 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommandBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUICommandBase.java
@@ -19,6 +19,7 @@
 
 package org.apache.myfaces.tobago.internal.component;
 
+import org.apache.myfaces.tobago.component.SupportsDisabled;
 import org.apache.myfaces.tobago.config.TobagoConfig;
 import org.apache.myfaces.tobago.event.CollapsibleActionListener;
 import org.apache.myfaces.tobago.internal.config.SecurityAnnotation;
@@ -108,6 +109,13 @@ public abstract class AbstractUICommandBase extends UICommand
     final FacesContext facesContext = getFacesContext();
     final TobagoConfig tobagoConfig = TobagoConfig.getInstance(facesContext);
     final Boolean disabled = (Boolean) getStateHelper().eval(AbstractUICommand.PropertyKeys.disabled);
+    if (disabled == null) {
+      SupportsDisabled parent =
+          ComponentUtils.findAncestor(getCurrentComponent(facesContext), SupportsDisabled.class);
+      if (parent != null && parent.isDisabled()) {
+        return true;
+      }
+    }
     return disabled != null && disabled
         || (tobagoConfig.getSecurityAnnotation() == SecurityAnnotation.disable && !isAllowed());
   }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUILinks.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUILinks.java
index 8de772a..b0c9789 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUILinks.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUILinks.java
@@ -19,12 +19,18 @@
 
 package org.apache.myfaces.tobago.internal.component;
 
+import org.apache.myfaces.tobago.component.SupportsDisabled;
 import org.apache.myfaces.tobago.layout.Orientation;
 
 /**
  * {@link org.apache.myfaces.tobago.internal.taglib.component.LinksTagDeclaration}
  */
-public abstract class AbstractUILinks extends AbstractUIPanelBase {
+public abstract class AbstractUILinks extends AbstractUIPanelBase implements SupportsDisabled {
+
+  enum PropertyKeys {
+    disabled,
+  }
 
   public abstract Orientation getOrientation();
+
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinksRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinksRenderer.java
index 9baede8..5678943 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinksRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/LinksRenderer.java
@@ -27,6 +27,7 @@ import org.apache.myfaces.tobago.renderkit.RendererBase;
 import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
 import org.apache.myfaces.tobago.renderkit.css.CssItem;
 import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
+import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ButtonsTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ButtonsTagDeclaration.java
index 313b432..e7d2556 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ButtonsTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/ButtonsTagDeclaration.java
@@ -20,7 +20,9 @@
 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.HasOrientation;
@@ -46,4 +48,10 @@ import javax.faces.component.UIPanel;
 public interface ButtonsTagDeclaration
     extends HasIdBindingAndRendered, IsVisual, HasTip, HasOrientation {
 
+  /**
+   * Flag indicating that this element and all children are disabled.
+   */
+  @TagAttribute()
+  @UIComponentTagAttribute(type = "boolean")
+  void setDisabled(String disabled);
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/LinksTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/LinksTagDeclaration.java
index 75f3673..a16adff 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/LinksTagDeclaration.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/LinksTagDeclaration.java
@@ -20,7 +20,9 @@
 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.HasOrientation;
@@ -43,4 +45,11 @@ import javax.faces.component.UIPanel;
     },
     rendererType = {RendererTypes.LINKS, RendererTypes.LINKS_INSIDE_BAR})
 public interface LinksTagDeclaration extends HasIdBindingAndRendered, IsVisual, HasTip, HasOrientation {
+
+  /**
+   * Flag indicating that this element and all children are disabled.
+   */
+  @TagAttribute()
+  @UIComponentTagAttribute(type = "boolean")
+  void setDisabled(String disabled);
 }
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/040-command/20-buttons/Button_Group.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/040-command/20-buttons/Button_Group.xhtml
index 244f0e4..97a9742 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/040-command/20-buttons/Button_Group.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/040-command/20-buttons/Button_Group.xhtml
@@ -94,4 +94,19 @@
       <tc:button label="Right"/>
     </tc:buttons>
   </tc:section>
+
+  <tc:section label="Disable">
+    <p>This example shows how to disable all buttons in a button group.
+      It's also possible to set disable to false e.g. for one button.</p>
+    <pre><code class="language-markup">&lt;tc:buttons disabled="true">
+  &lt;c:button label="Left" disabled="false"/>
+  &lt;tc:button label="Center"/>
+  &lt;tc:button label="Right"/>
+&lt;/tc:buttons></code></pre>
+    <tc:buttons disabled="true">
+      <tc:button label="Left" disabled="false"/>
+      <tc:button label="Center"/>
+      <tc:button label="Right"/>
+    </tc:buttons>
+  </tc:section>
 </ui:composition>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/040-command/25-links/Link_Group.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/040-command/25-links/Link_Group.xhtml
index 65bc576..6e0f8bc 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/040-command/25-links/Link_Group.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/040-command/25-links/Link_Group.xhtml
@@ -87,4 +87,19 @@
       <tc:link label="Right"/>
     </tc:links>
   </tc:section>
+
+  <tc:section label="Disable">
+    <p>This example shows how to disable all links in a link group.
+      It's also possible to set disable to false e.g. for one link.</p>
+    <pre><code class="language-markup">&lt;tc:links disabled="true">
+  &lt;c:link label="Left" disabled="false"/>
+  &lt;tc:link label="Center"/>
+  &lt;tc:link label="Right"/>
+&lt;/tc:links></code></pre>
+    <tc:links disabled="true">
+      <tc:link label="Left" disabled="false"/>
+      <tc:link label="Center"/>
+      <tc:link label="Right"/>
+    </tc:links>
+  </tc:section>
 </ui:composition>