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:42 UTC

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

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;
     }