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 2019/07/25 14:40:34 UTC

[myfaces-tobago] 01/02: TOBAGO-1633: TS refactoring: progress on tree

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

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

commit 38d737f1833518d164e5b34538e89ecbb0ba8bea
Author: Udo Schnurpfeil <lo...@apache.org>
AuthorDate: Thu Jul 25 16:37:02 2019 +0200

    TOBAGO-1633: TS refactoring: progress on tree
    
    removing tc:treeMenu
---
 .../myfaces/tobago/component/RendererTypes.java    |  10 -
 .../org/apache/myfaces/tobago/component/Tags.java  |   6 -
 .../internal/component/AbstractUITreeMenu.java     |  33 ----
 .../renderkit/renderer/TreeMenuRenderer.java       |  27 ---
 .../renderkit/renderer/TreeNodeRenderer.java       |  24 ---
 .../taglib/component/TreeMenuTagDeclaration.java   |  74 --------
 .../tobago/example/demo/EventController.java       |   2 -
 .../src/main/npm/js/tobago-polyfill.js             |  21 ++
 .../src/main/npm/ts/tobago-tree.ts                 | 211 ++++++++++-----------
 .../src/main/npm/ts/tobago-utils.ts                |  31 +++
 10 files changed, 147 insertions(+), 292 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
index 31abbcb..4ca29b4 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/RendererTypes.java
@@ -107,11 +107,6 @@ public enum RendererTypes {
   TreeIndent,
   TreeLabel,
   TreeListbox,
-  /**
-   * @deprecated since 4.2.1
-   */
-  @Deprecated
-  TreeMenu,
   TreeNode,
   TreeSelect;
 
@@ -198,11 +193,6 @@ public enum RendererTypes {
   public static final String TREE_INDENT = "TreeIndent";
   public static final String TREE_LABEL = "TreeLabel";
   public static final String TREE_LISTBOX = "TreeListbox";
-  /**
-   * @deprecated since 4.2.1
-   */
-  @Deprecated
-  public static final String TREE_MENU = "TreeMenu";
   public static final String TREE_NODE = "TreeNode";
   public static final String TREE_SELECT = "TreeSelect";
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Tags.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Tags.java
index caadd37..9fb85bd 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Tags.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/component/Tags.java
@@ -95,11 +95,6 @@ public enum Tags {
   treeIndent,
   treeLabel,
   treeListbox,
-  /**
-   * @deprecated since 4.4.0
-   */
-  @Deprecated
-  treeMenu,
   treeNode,
   treeSelect;
 
@@ -171,7 +166,6 @@ public enum Tags {
   public static final String TREE_INDENT = "treeIndent";
   public static final String TREE_LABEL = "treeLabel";
   public static final String TREE_LISTBOX = "treeListbox";
-  public static final String TREE_MENU = "treeMenu";
   public static final String TREE_NODE = "treeNode";
   public static final String TREE_SELECT = "treeSelect";
 
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUITreeMenu.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUITreeMenu.java
deleted file mode 100644
index 29bf10a..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/component/AbstractUITreeMenu.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.
- */
-
-package org.apache.myfaces.tobago.internal.component;
-
-import org.apache.myfaces.tobago.model.Selectable;
-
-/**
- * {@link org.apache.myfaces.tobago.internal.taglib.component.TreeMenuTagDeclaration}
- */
-public abstract class AbstractUITreeMenu extends AbstractUITree {
-
-  @Override
-  public Selectable getSelectable() {
-    return Selectable.none;
-  }
-}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeMenuRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeMenuRenderer.java
deleted file mode 100644
index c40d214..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeMenuRenderer.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.
- */
-
-package org.apache.myfaces.tobago.internal.renderkit.renderer;
-
-/**
- * @deprecated since 4.2.1, please user {@link TreeRenderer} instead.
- */
-@Deprecated
-public class TreeMenuRenderer extends TreeRenderer {
-}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java
index 27d7251..0d03b14 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/TreeNodeRenderer.java
@@ -23,7 +23,6 @@ import org.apache.myfaces.tobago.context.Markup;
 import org.apache.myfaces.tobago.internal.component.AbstractUIData;
 import org.apache.myfaces.tobago.internal.component.AbstractUITree;
 import org.apache.myfaces.tobago.internal.component.AbstractUITreeListbox;
-import org.apache.myfaces.tobago.internal.component.AbstractUITreeMenu;
 import org.apache.myfaces.tobago.internal.component.AbstractUITreeNode;
 import org.apache.myfaces.tobago.internal.component.AbstractUITreeNodeBase;
 import org.apache.myfaces.tobago.internal.component.AbstractUITreeSelect;
@@ -184,7 +183,6 @@ public class TreeNodeRenderer extends RendererBase {
     final int level = node.getLevel();
     final boolean folder = node.isFolder();
     final boolean expanded = folder && data.getExpandedState().isExpanded(node.getPath()) || level == 0;
-    final boolean isMenu = data instanceof AbstractUITreeMenu;
 
     final TobagoResponseWriter writer = getResponseWriter(facesContext);
 
@@ -194,29 +192,7 @@ public class TreeNodeRenderer extends RendererBase {
       }
       writer.endElement(HtmlElements.OPTION);
     } else {
-      if (isMenu && folder) {
-        encodeIcon(facesContext, writer, expanded, node);
-      }
       writer.endElement(HtmlElements.DIV);
     }
   }
-
-  private void encodeIcon(
-      final FacesContext facesContext, final TobagoResponseWriter writer, final boolean expanded,
-      final AbstractUITreeNodeBase node)
-      throws IOException {
-//    LOG.warn("todo: font-awesome icons");
-/* XXX
-    final String srcOpen = ResourceManagerUtils.getImage(facesContext, "image/treeMenuOpen");
-    final String srcClose = ResourceManagerUtils.getImage(facesContext, "image/treeMenuClose");
-    final String src = expanded ? srcOpen : srcClose;
-    writer.startElement(HtmlElements.IMG);
-    writer.writeClassAttribute(Classes.create(node, "toggle"));
-    writer.writeAttribute(HtmlAttributes.SRC, src, false);
-    writer.writeAttribute(DataAttributes.OPEN, srcOpen, false);
-    writer.writeAttribute(DataAttributes.SRC_CLOSED, srcClose, false);
-    writer.writeAttribute(HtmlAttributes.ALT, "", false);
-    writer.endElement(HtmlElements.IMG);
-*/
-  }
 }
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/TreeMenuTagDeclaration.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/TreeMenuTagDeclaration.java
deleted file mode 100644
index 81134c1..0000000
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/taglib/component/TreeMenuTagDeclaration.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- */
-
-package org.apache.myfaces.tobago.internal.taglib.component;
-
-import org.apache.myfaces.tobago.apt.annotation.BodyContentDescription;
-import org.apache.myfaces.tobago.apt.annotation.DynamicExpression;
-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.HasValue;
-import org.apache.myfaces.tobago.internal.taglib.declaration.HasVar;
-import org.apache.myfaces.tobago.internal.taglib.declaration.IsShowRoot;
-import org.apache.myfaces.tobago.internal.taglib.declaration.IsVisual;
-
-import javax.faces.component.UIData;
-
-/**
- * A tree which will be displayed like a flat menu.
- * This menu is often used for navigation on the left side of an application.
- *
- * @deprecated since 4.2.1. Please use {@link TreeTagDeclaration} or &lt;tc:tree&gt; instead.
- */
-@Deprecated
-@Tag(name = "treeMenu")
-@BodyContentDescription(anyTagOf = "<tc:treeNode>")
-@UIComponentTag(
-    uiComponent = "org.apache.myfaces.tobago.component.UITreeMenu",
-    uiComponentFacesClass = "javax.faces.component.UIData",
-    componentFamily = UIData.COMPONENT_FAMILY,
-    rendererType = RendererTypes.TREE_MENU,
-    interfaces = {
-        // As long as no behavior event names are defined, ClientBehaviorHolder must be implemented for Mojarra.
-        "javax.faces.component.behavior.ClientBehaviorHolder"
-    },
-    allowedChildComponenents = {
-        "org.apache.myfaces.tobago.TreeNode"
-        })
-public interface TreeMenuTagDeclaration
-    extends HasIdBindingAndRendered, HasValue, HasVar, IsVisual,
-    IsShowRoot {
-
-  /**
-   *
-   * <strong>ValueBindingExpression</strong> pointing to a object to save the
-   * component's state.
-   */
-  @TagAttribute
-  @UIComponentTagAttribute(
-      type = "org.apache.myfaces.tobago.model.TreeState",
-      expression = DynamicExpression.VALUE_EXPRESSION_REQUIRED,
-      generate = false)
-  void setState(String state);
-
-}
diff --git a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/EventController.java b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/EventController.java
index 5aee1de..74d083e 100644
--- a/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/EventController.java
+++ b/tobago-example/tobago-example-demo/src/main/java/org/apache/myfaces/tobago/example/demo/EventController.java
@@ -71,7 +71,6 @@ import org.apache.myfaces.tobago.component.UITreeIcon;
 import org.apache.myfaces.tobago.component.UITreeIndent;
 import org.apache.myfaces.tobago.component.UITreeLabel;
 import org.apache.myfaces.tobago.component.UITreeListbox;
-import org.apache.myfaces.tobago.component.UITreeMenu;
 import org.apache.myfaces.tobago.component.UITreeSelect;
 import org.apache.myfaces.tobago.util.ComponentUtils;
 
@@ -156,7 +155,6 @@ public class EventController implements Serializable {
     eventsOnComponents.add(new EventsOnComponent(new UITreeIndent()));
     eventsOnComponents.add(new EventsOnComponent(new UITreeLabel()));
     eventsOnComponents.add(new EventsOnComponent(new UITreeListbox()));
-    eventsOnComponents.add(new EventsOnComponent(new UITreeMenu()));
     eventsOnComponents.add(new EventsOnComponent(new UITreeSelect()));
 
 
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/js/tobago-polyfill.js b/tobago-theme/tobago-theme-standard/src/main/npm/js/tobago-polyfill.js
index bcc623d..8eedfe9 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/js/tobago-polyfill.js
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/js/tobago-polyfill.js
@@ -19,3 +19,24 @@
 if (window.NodeList && !NodeList.prototype.forEach) {
   NodeList.prototype.forEach = Array.prototype.forEach;
 }
+
+
+// from https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
+// todo: check, if this is needed for Tobago 5
+// for ie
+if (!Element.prototype.matches) {
+  Element.prototype.matches
+      = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
+}
+
+// for ie
+if (!Element.prototype.closest) {
+  Element.prototype.closest = function (s) {
+    let el = this;
+    do {
+      if (el.matches(s)) return el;
+      el = el.parentElement || el.parentNode;
+    } while (el !== null && el.nodeType === 1);
+    return null;
+  };
+}
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tree.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tree.ts
index 49cf70d..104aa46 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tree.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-tree.ts
@@ -16,63 +16,61 @@
  */
 
 import {Listener, Phase} from "./tobago-listener";
-import {Tobago4Utils} from "./tobago-utils";
+import {DomUtils, Tobago4Utils} from "./tobago-utils";
 
 class Tree {
-  static toggleNode = function ($element, event) {
-    var src;
-    var $node = $element.closest(".tobago-treeNode, .tobago-treeMenuNode");
-    var $data = $node.closest(".tobago-treeMenu, .tobago-tree, .tobago-sheet");
-    const expanded: HTMLInputElement
-        = $data.children(".tobago-treeMenu-expanded, .tobago-tree-expanded, .tobago-sheet-expanded").get(0);
-    var $toggles = $node.find(".tobago-treeMenuNode-toggle, .tobago-treeNode-toggle");
-    var rowIndex = Tree.rowIndex($node.get(0));
-    if (Tree.isExpanded($node.get(0), expanded)) {
-      Tree.hideChildren($node.get(0));
-      $toggles.find("i").each(function () {
-        var $toggle = jQuery(this);
-        $toggle.removeClass($toggle.data("tobago-open")).addClass($toggle.data("tobago-closed"));
-      });
-      $toggles.find("img").each(function () {
-        var $toggle = jQuery(this);
-        src = $toggle.data("tobago-closed");
-        if (src === undefined) { // use the open icon if there is no close icon
-          src = $toggle.data("tobago-open");
+
+  static toggleNode = function (event: MouseEvent) {
+    const element = event.currentTarget as HTMLElement;
+    const node = element.closest(".tobago-treeNode");
+    const data = node.closest(".tobago-tree, .tobago-sheet") as HTMLElement;
+    const expanded = DomUtils.childrenQuerySelector(data,
+        ".tobago-tree-expanded, .tobago-sheet-expanded") as HTMLInputElement;
+    const togglesIcon = node.querySelectorAll(".tobago-treeNode-toggle i") as NodeListOf<HTMLElement>;
+    const togglesImage = node.querySelectorAll(".tobago-treeNode-toggle img") as NodeListOf<HTMLImageElement>;
+    const rowIndex = Tree.rowIndex(node);
+    if (Tree.isExpanded(node, expanded)) {
+      Tree.hideChildren(node);
+      for (const icon of togglesIcon) {
+        icon.classList.remove(icon.dataset["tobagoOpen"]);
+        icon.classList.add(icon.dataset["tobagoClosed"]);
+      }
+      for (const image of togglesImage) {
+        let src = image.dataset["tobagoClosed"];
+        if (!src) { // use the open icon if there is no closed icon
+          src = image.dataset["tobagoOpen"];
         }
-        $toggle.attr("src", src);
-      });
+        image.setAttribute("src", src);
+      }
       const set = Tree.getSet(expanded);
       set.delete(rowIndex);
       Tree.setSet(expanded, set);
-      $node.filter(".tobago-treeNode").removeClass("tobago-treeNode-markup-expanded");
-      $node.filter(".tobago-treeMenuNode").removeClass("tobago-treeMenuNode-markup-expanded");
+      node.classList.remove("tobago-treeNode-markup-expanded");
     } else {
-      const reload = Tree.showChildren($node.get(0), expanded);
+      const reload = Tree.showChildren(node, expanded);
       Tree.setSet(expanded, Tree.getSet(expanded).add(rowIndex));
       if (reload) {
         jsf.ajax.request(
-            $toggles.parent().attr("id"),
+            node.id,
             event,
             {
               //"javax.faces.behavior.event": "click",
-              execute: $data.attr("id"),
-              render: $data.attr("id")
+              execute: data.id,
+              render: data.id
             });
       } else {
-        $toggles.find("i").each(function () {
-          var $toggle = jQuery(this);
-          $toggle.removeClass($toggle.data("tobago-closed")).addClass($toggle.data("tobago-open"));
-        });
-        $toggles.find("img").each(function () {
-          var $toggle = jQuery(this);
-          src = $toggle.data("tobago-open");
-          if (src === undefined) { // use the close icon if there is no open icon
-            src = $toggle.data("tobago-closed");
+        for (const icon of togglesIcon) {
+          icon.classList.remove(icon.dataset["tobagoClosed"]);
+          icon.classList.add(icon.dataset["tobagoOpen"]);
+        }
+        for (const image of togglesImage) {
+          let src = image.dataset["tobagoOpen"];
+          if (!src) { // use the open icon if there is no closed icon
+            src = image.dataset["tobagoClosed"];
           }
-          $toggle.attr("src", src);
-        });
-        $node.filter(".tobago-treeNode").addClass("tobago-treeNode-markup-expanded");
-        $node.filter(".tobago-treeMenuNode").addClass("tobago-treeMenuNode-markup-expanded");
+          image.setAttribute("src", src);
+        }
+        node.classList.add("tobago-treeNode-markup-expanded");
       }
     }
   };
@@ -81,16 +79,16 @@ class Tree {
    * Hide all children of the node recursively.
    * @param node A jQuery-Object as a node of the tree.
    */
-  static hideChildren = function (node: HTMLElement) {
-    var inSheet = Tree.isInSheet(node);
-    var children = Tree.findChildren(node);
+  static hideChildren = function (node: Element) {
+    const children = Tree.findChildren(node);
     children.each(function () {
-      if (inSheet) {
-        jQuery(this).parent().parent().hide();
+      const child = this;
+      if (Tree.isInSheet(node)) {
+        child.parentNode.parentNode.classList.add("d-none");
       } else {
-        jQuery(this).hide();
+        child.classList.add("d-none");
       }
-      Tree.hideChildren(this);
+      Tree.hideChildren(child);
     });
   };
 
@@ -100,22 +98,21 @@ class Tree {
    * @param expanded The hidden field which contains the expanded state.
    * @return is reload needed (to get all nodes from the server)
    */
-  static showChildren = function (node: HTMLElement, expanded: HTMLInputElement) {
-    var inSheet = Tree.isInSheet(node);
-    var children = Tree.findChildren(node);
+  static showChildren = function (node: Element, expanded: HTMLInputElement) {
+    const children = Tree.findChildren(node);
     if (children.length == 0) {
       // no children in DOM, reload it from the server
       return true;
     }
     children.each(function () {
-      var $child = jQuery(this);
-      if (inSheet) {
-        $child.parent().parent().show();
+      const child = this;
+      if (Tree.isInSheet(node)) {
+        this.parentNode.parentNode.classList.remove("d-none");
       } else {
-        $child.show();
+        this.classList.remove("d-none");
       }
-      if (Tree.isExpanded($child.get(0), expanded)) {
-        var reload = Tree.showChildren($child.get(0), expanded);
+      if (Tree.isExpanded(child, expanded)) {
+        const reload = Tree.showChildren(child, expanded);
         if (reload) {
           return true;
         }
@@ -124,47 +121,41 @@ class Tree {
     return false;
   };
 
-  static init = function (elements) {
-    elements = elements.jQuery ? elements : jQuery(elements); // fixme jQuery -> ES5
-    Tobago4Utils.selectWithJQuery(elements, ".tobago-treeNode-markup-folder .tobago-treeNode-toggle").click(function (event) {
-      Tree.toggleNode(jQuery(this), event);
-      return false;
-    });
+  static commandFocus = function (event: FocusEvent) {
+    const command = event.currentTarget as HTMLElement;
+    const node = command.parentElement;
+    const tree = node.closest(".tobago-tree");
+    const selected = DomUtils.childrenQuerySelector(tree, ".tobago-tree-selected") as HTMLInputElement;
+    selected.value = String(Tree.rowIndex(node));
+    for (const otherNode of tree.querySelectorAll(".tobago-treeNode-markup-selected")) {
+      if (otherNode !== node) {
+        otherNode.classList.remove("tobago-treeNode-markup-selected");
+      }
+    }
+    node.classList.add("tobago-treeNode-markup-selected");
+    console.info("-----------------> focus ---> " + node.id); // remove
+  };
 
-    Tobago4Utils.selectWithJQuery(elements, ".tobago-treeMenuNode-markup-folder .tobago-treeMenuNode-toggle")
-        .parent().each(function () {
-      // if there is no command, than the whole node element should be the toggle
-      var toggle = jQuery(this).children(".tobago-treeMenuCommand").length === 0
-          ? jQuery(this)
-          : jQuery(this).find(".tobago-treeMenuNode-toggle");
-      toggle.click(function (event) {
-        Tree.toggleNode(jQuery(this), event);
-      });
-    });
+  static init = function (element: HTMLElement) {
 
-    // normal hover effect (not possible with CSS in IE 6)
-    Tobago4Utils.selectWithJQuery(elements, ".tobago-treeMenuNode").hover(function () {
-      jQuery(this).toggleClass("tobago-treeMenuNode-markup-hover");
-    });
+    for (const toggle of DomUtils.selfOrQuerySelectorAll(element, ".tobago-treeNode-markup-folder .tobago-treeNode-toggle")) {
+      toggle.addEventListener("click", Tree.toggleNode);
+    }
 
     // selected for treeNode
-    Tobago4Utils.selectWithJQuery(elements, ".tobago-treeCommand").focus(function () {
-      var command = jQuery(this);
-      var $node = command.parent(".tobago-treeNode");
-      var tree = $node.closest(".tobago-tree");
-      var selected = tree.children(".tobago-tree-selected");
-      selected.val(Tree.rowIndex($node.get(0)));
-      tree.find(".tobago-treeNode").removeClass("tobago-treeNode-markup-selected");
-      $node.addClass("tobago-treeNode-markup-selected");
-    });
+    for (const command of DomUtils.selfOrQuerySelectorAll(element, ".tobago-treeCommand")) {
+      command.addEventListener("focus", Tree.commandFocus);
+    }
+
+    var elements = jQuery(elements); // fixme remove!
 
     // selected for treeSelect
     Tobago4Utils.selectWithJQuery(elements, ".tobago-treeSelect > input").change(function () {
       var select = jQuery(this);
       var selected = select.prop("checked");
-      var data = select.closest(".tobago-treeMenu, .tobago-tree, .tobago-sheet");
+      var data = select.closest(".tobago-tree, .tobago-sheet");
       const hidden: HTMLInputElement
-          = data.children(".tobago-treeMenu-selected, .tobago-tree-selected, .tobago-sheet-selected").get(0);
+          = data.children(".tobago-tree-selected, .tobago-sheet-selected").get(0);
       let value: Set<number>;
       // todo may use an class attribute for this value
       if (select.attr("type") === "radio") {
@@ -180,37 +171,25 @@ class Tree {
       Tree.setSet(hidden, value);
     });
 
-    // selected for treeMenuNode
-    Tobago4Utils.selectWithJQuery(elements, ".tobago-treeMenuCommand").focus(function () {
-      var command = jQuery(this);
-      var $node = command.parent(".tobago-treeMenuNode");
-      var tree = $node.closest(".tobago-treeMenu");
-      const selected: HTMLInputElement = tree.children(".tobago-treeMenu-selected").get(0);
-      const set = new Set<number>();
-      set.add(Tree.rowIndex($node.get(0)));
-      Tree.setSet(selected, set);
-      tree.find(".tobago-treeMenuNode").removeClass("tobago-treeMenuNode-markup-selected");
-      $node.addClass("tobago-treeMenuNode-markup-selected");
-    });
-
     // init selected field
-    Tobago4Utils.selectWithJQuery(elements, ".tobago-treeMenu, .tobago-tree, .tobago-sheet").each(function () {
-      const hidden: HTMLInputElement = jQuery(this).children(".tobago-treeMenu-selected, .tobago-tree-selected, .tobago-sheet-selected").get(0);
+    Tobago4Utils.selectWithJQuery(elements, ".tobago-tree, .tobago-sheet").each(function () {
+      const data: HTMLElement = this;
+      const hidden = DomUtils.childrenQuerySelector(data, ".tobago-tree-selected, .tobago-sheet-selected");
       if (hidden) {
         const value = new Set<number>();
-        jQuery(this).find(".tobago-treeMenuNode-markup-selected, .tobago-treeNode-markup-selected").each(function () {
-          value.add(Tree.rowIndex(this));
-        });
+        for (const selected of data.querySelectorAll(".tobago-treeNode-markup-selected")) {
+          value.add(Tree.rowIndex(selected));
+        }
         Tree.setSet(hidden, value);
       }
     });
 
     // init expanded field
-    Tobago4Utils.selectWithJQuery(elements, ".tobago-treeMenu, .tobago-tree, .tobago-sheet").each(function () {
-      const hidden: HTMLInputElement = jQuery(this).children(".tobago-treeMenu-expanded, .tobago-tree-expanded, .tobago-sheet-expanded").get(0);
+    Tobago4Utils.selectWithJQuery(elements, ".tobago-tree, .tobago-sheet").each(function () {
+      const hidden: HTMLInputElement = jQuery(this).children(".tobago-tree-expanded, .tobago-sheet-expanded").get(0);
       if (hidden) {
         const value = new Set<number>();
-        jQuery(this).find(".tobago-treeMenuNode-markup-expanded, .tobago-treeNode-markup-expanded").each(function () {
+        jQuery(this).find(".tobago-treeNode-markup-expanded").each(function () {
           value.add(Tree.rowIndex(this));
         });
         Tree.setSet(hidden, value);
@@ -244,18 +223,18 @@ class Tree {
     return element.value = JSON.stringify(Array.from(set));
   }
 
-  static isExpanded = function (node: HTMLElement, expanded: HTMLInputElement) {
+  static isExpanded = function (node: Element, expanded: HTMLInputElement) {
     const rowIndex = Tree.rowIndex(node);
     return Tree.getSet(expanded).has(rowIndex);
   };
 
-  static rowIndex = function (node: HTMLElement): number { // todo: use attribute data-tobago-row-index
+  static rowIndex = function (node: Element): number { // todo: use attribute data-tobago-row-index
     return parseInt(node.id.replace(/.+\:(\d+)(\:\w+)+/, '$1'));
   };
 
-  static findChildren = function (node: HTMLElement) {
-    var treeParentSelector = "[data-tobago-tree-parent='" + node.id + "']";
-    var children;
+  static findChildren = function (node: Element) {
+    const treeParentSelector = "[data-tobago-tree-parent='" + node.id + "']";
+    let children;
     if (Tree.isInSheet(node)) {
       children = jQuery(node).parent("td").parent("tr").nextAll().children().children(treeParentSelector);
     } else { // normal tree
@@ -264,8 +243,8 @@ class Tree {
     return children;
   };
 
-  static isInSheet = function (node: HTMLElement) {
-    return jQuery(node).parent("td").length === 1;
+  static isInSheet = function (node: Element) {
+    return node.parentElement.tagName === "TD";
   };
 }
 
diff --git a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-utils.ts b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-utils.ts
index 0605945..db7de6c 100644
--- a/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-utils.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/npm/ts/tobago-utils.ts
@@ -77,6 +77,37 @@ export class DomUtils {
   }
 
   /**
+   * Find all children which matches the selector.
+   * @param element Parent element in DOM to collect.
+   * @param selectors Name of the matcher of the elements to find.
+   */
+// todo: may return NodeListOf<HTMLElementTagNameMap[K]> or something like that.
+  static childrenQuerySelectorAll(element: HTMLElement, selectors: string): Array<HTMLElement> {
+    const result: Array<HTMLElement> = new Array<HTMLElement>();
+    for (const child of element.children) {
+      if (child.matches(selectors)) {
+        result.push(<HTMLElement>child);
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Find one children which matches the selector.
+   * @param element Parent element in DOM to collect.
+   * @param selectors Name of the matcher of the elements to find.
+   */
+// todo: may return NodeListOf<HTMLElementTagNameMap[K]> or something like that.
+  static childrenQuerySelector(element: Element, selectors: string): HTMLElement {
+    for (const child of element.children) {
+      if (child.matches(selectors)) {
+        return child as HTMLElement;
+      }
+    }
+    return null;
+  }
+
+  /**
    * Get the previous sibling element (without <style> elements).
    */
   static previousElementSibling(element: HTMLElement): HTMLElement {