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 2021/01/27 14:51:04 UTC

[myfaces-tobago] branch master updated: use bootstrap-dropdown.js

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


The following commit(s) were added to refs/heads/master by this push:
     new 26fefde  use bootstrap-dropdown.js
26fefde is described below

commit 26fefdeb8b9e20fdba5c02c9ae10a00b7bd0c18e
Author: Henning Noeth <hn...@apache.org>
AuthorDate: Tue Jan 26 17:02:57 2021 +0100

    use bootstrap-dropdown.js
    
    * tobago-dropdown.ts only move the dropdown-menu to page-menu-store
    * html rendering changed to bootstrap5
    * adjust styles
    * adjust tests
---
 tobago-core/npm/scss/_tobago.scss                  |   2 +
 .../renderkit/renderer/CommandRendererBase.java    |   3 +-
 .../renderer/buttons/separator-inside-buttons.html |   2 +-
 .../renderer/in/input-group-dropdown-after.html    |   2 +-
 .../renderer/in/input-group-dropdown-before.html   |   2 +-
 .../resources/renderer/link/booleanInsideLink.html |   2 +-
 .../resources/renderer/link/manyInsideLink.html    |   4 +-
 .../resources/renderer/link/radioInsideLink.html   |   2 +-
 .../renderer/link/separatorInsideLink.html         |   2 +-
 .../renderer/links/link-inside-links-sub.html      |   4 +-
 .../010-input/50-input-group/Group.test.js         |  72 +++---
 .../npm/ts/tobago-dropdown.ts                      | 280 +--------------------
 12 files changed, 65 insertions(+), 312 deletions(-)

diff --git a/tobago-core/npm/scss/_tobago.scss b/tobago-core/npm/scss/_tobago.scss
index 7847094..779e3b0 100644
--- a/tobago-core/npm/scss/_tobago.scss
+++ b/tobago-core/npm/scss/_tobago.scss
@@ -287,6 +287,8 @@ workaround for Bootstrap Modal (Popup) with vanillajs-datepicker
 
 /* dropdown ------------------------------------------------------- */
 tobago-dropdown {
+  display: inline-block; //make tobago-dropdown height the same the inner button. Important for dropdown-menu position
+
   @include dropdownMenuFormCheckComponents();
 
   &.tobago-dropdown-submenu {
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java
index 0ec670f..05c2b45 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/CommandRendererBase.java
@@ -107,7 +107,8 @@ public abstract class CommandRendererBase<T extends AbstractUICommand> extends D
     HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
 
     if (parentOfCommands) {
-      writer.writeAttribute(DataAttributes.TOGGLE, "dropdown", false);
+      writer.writeAttribute(DataAttributes.BS_TOGGLE, "dropdown", false);
+      writer.writeAttribute(Arias.EXPANDED, Boolean.FALSE.toString(), false);
     }
     final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
     writer.writeAttribute(HtmlAttributes.TITLE, title, true);
diff --git a/tobago-core/src/test/resources/renderer/buttons/separator-inside-buttons.html b/tobago-core/src/test/resources/renderer/buttons/separator-inside-buttons.html
index 16d33ff..a958501 100644
--- a/tobago-core/src/test/resources/renderer/buttons/separator-inside-buttons.html
+++ b/tobago-core/src/test/resources/renderer/buttons/separator-inside-buttons.html
@@ -19,7 +19,7 @@ CSS class of "tobago-dropdown" has changed from btn-group to dropdown
 -->
 <tobago-buttons id='list' class='btn-group' role='group'>
   <tobago-dropdown id='id' class='dropdown btn-group'>
-    <button type='button' id='id::command' name='id' data-toggle='dropdown' class='tobago-button btn btn-secondary dropdown-toggle'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>button</span></button>
+    <button type='button' id='id::command' name='id' data-bs-toggle='dropdown' aria-expanded='false' class='tobago-button btn btn-secondary dropdown-toggle'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>button</span></button>
     <div class='dropdown-menu' aria-labelledby='id::command' name='id'>
       <button type='button' id='sub1' name='sub1' class='tobago-link dropdown-item'><tobago-behavior event='click' client-id='sub1'></tobago-behavior><span>sub1</span></button>
       <tobago-separator id='separator1' class='dropdown-divider'>
diff --git a/tobago-core/src/test/resources/renderer/in/input-group-dropdown-after.html b/tobago-core/src/test/resources/renderer/in/input-group-dropdown-after.html
index 3a62574..c356f12 100644
--- a/tobago-core/src/test/resources/renderer/in/input-group-dropdown-after.html
+++ b/tobago-core/src/test/resources/renderer/in/input-group-dropdown-after.html
@@ -22,7 +22,7 @@ dropdown-menu-right is temporarily not here (in the div with dropdown-menu), XXX
     <div class='input-group'>
       <input type='text' name='id' id='id::field' class='tobago-in form-control'>
       <tobago-dropdown id='button' class='dropdown'>
-        <button type='button' id='button::command' name='button' data-toggle='dropdown' class='tobago-button btn btn-secondary dropdown-toggle'><tobago-behavior event='click' client-id='button' field-id='button::command' omit='omit'></tobago-behavior><span>dropdown</span></button>
+        <button type='button' id='button::command' name='button' data-bs-toggle='dropdown' aria-expanded='false' class='tobago-button btn btn-secondary dropdown-toggle'><tobago-behavior event='click' client-id='button' field-id='button::command' omit='omit'></tobago-behavior><span>dropdown</span></button>
         <div class='dropdown-menu' aria-labelledby='button::command' name='button'>
           <button type='button' id='l1' name='l1' class='tobago-link dropdown-item'><tobago-behavior event='click' client-id='l1'></tobago-behavior><span>Link 1</span></button>
           <button type='button' id='l2' name='l2' class='tobago-link dropdown-item'><tobago-behavior event='click' client-id='l2'></tobago-behavior><span>Link 2</span></button>
diff --git a/tobago-core/src/test/resources/renderer/in/input-group-dropdown-before.html b/tobago-core/src/test/resources/renderer/in/input-group-dropdown-before.html
index 911125a..b42a3ec 100644
--- a/tobago-core/src/test/resources/renderer/in/input-group-dropdown-before.html
+++ b/tobago-core/src/test/resources/renderer/in/input-group-dropdown-before.html
@@ -19,7 +19,7 @@
   <div class='tobago-input-group-outer'>
     <div class='input-group'>
       <tobago-dropdown id='button' class='dropdown'>
-        <button type='button' id='button::command' name='button' data-toggle='dropdown' class='tobago-button btn btn-secondary dropdown-toggle'><tobago-behavior event='click' client-id='button' field-id='button::command' omit='omit'></tobago-behavior><span>dropdown</span></button>
+        <button type='button' id='button::command' name='button' data-bs-toggle='dropdown' aria-expanded='false' class='tobago-button btn btn-secondary dropdown-toggle'><tobago-behavior event='click' client-id='button' field-id='button::command' omit='omit'></tobago-behavior><span>dropdown</span></button>
         <div class='dropdown-menu' aria-labelledby='button::command' name='button'>
           <button type='button' id='l1' name='l1' class='tobago-link dropdown-item'><tobago-behavior event='click' client-id='l1'></tobago-behavior><span>Link 1</span></button>
           <button type='button' id='l2' name='l2' class='tobago-link dropdown-item'><tobago-behavior event='click' client-id='l2'></tobago-behavior><span>Link 2</span></button>
diff --git a/tobago-core/src/test/resources/renderer/link/booleanInsideLink.html b/tobago-core/src/test/resources/renderer/link/booleanInsideLink.html
index 3e2a0d0..e6235ae 100644
--- a/tobago-core/src/test/resources/renderer/link/booleanInsideLink.html
+++ b/tobago-core/src/test/resources/renderer/link/booleanInsideLink.html
@@ -16,7 +16,7 @@
 -->
 
 <tobago-dropdown id='id' class='dropdown'>
-  <button type='button' id='id::command' name='id' data-toggle='dropdown' class='tobago-link btn btn-link dropdown-toggle'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>dropdown</span></button>
+  <button type='button' id='id::command' name='id' data-bs-toggle='dropdown' aria-expanded='false' class='tobago-link btn btn-link dropdown-toggle'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>dropdown</span></button>
   <div class='dropdown-menu' aria-labelledby='id::command' name='id'>
     <tobago-select-boolean-checkbox id='id' class='form-check dropdown-item'>
       <input class='form-check-input' type='checkbox' value='true' name='id' id='id::field'>
diff --git a/tobago-core/src/test/resources/renderer/link/manyInsideLink.html b/tobago-core/src/test/resources/renderer/link/manyInsideLink.html
index 9601fe6..89e669b 100644
--- a/tobago-core/src/test/resources/renderer/link/manyInsideLink.html
+++ b/tobago-core/src/test/resources/renderer/link/manyInsideLink.html
@@ -16,7 +16,7 @@
 -->
 
 <tobago-dropdown id='id' class='dropdown'>
-  <button type='button' id='id::command' name='id' data-toggle='dropdown' class='tobago-link btn btn-link dropdown-toggle'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>dropdown</span></button>
+  <button type='button' id='id::command' name='id' data-bs-toggle='dropdown' aria-expanded='false' class='tobago-link btn btn-link dropdown-toggle'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>dropdown</span></button>
   <div class='dropdown-menu' aria-labelledby='id::command' name='id'>
     <tobago-select-many-checkbox>
       <div class='form-check dropdown-item'>
@@ -29,4 +29,4 @@
       </div>
     </tobago-select-many-checkbox>
   </div>
-</tobago-dropdown>
\ No newline at end of file
+</tobago-dropdown>
diff --git a/tobago-core/src/test/resources/renderer/link/radioInsideLink.html b/tobago-core/src/test/resources/renderer/link/radioInsideLink.html
index f3e71c6..9bfa0eb 100644
--- a/tobago-core/src/test/resources/renderer/link/radioInsideLink.html
+++ b/tobago-core/src/test/resources/renderer/link/radioInsideLink.html
@@ -16,7 +16,7 @@
 -->
 
 <tobago-dropdown id='id' class='dropdown'>
-  <button type='button' id='id::command' name='id' data-toggle='dropdown' class='tobago-link btn btn-link dropdown-toggle'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>dropdown</span></button>
+  <button type='button' id='id::command' name='id' data-bs-toggle='dropdown' aria-expanded='false' class='tobago-link btn btn-link dropdown-toggle'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>dropdown</span></button>
   <div class='dropdown-menu' aria-labelledby='id::command' name='id'>
     <tobago-select-one-radio>
       <div class='form-check dropdown-item'>
diff --git a/tobago-core/src/test/resources/renderer/link/separatorInsideLink.html b/tobago-core/src/test/resources/renderer/link/separatorInsideLink.html
index 43674b2..a945d81 100644
--- a/tobago-core/src/test/resources/renderer/link/separatorInsideLink.html
+++ b/tobago-core/src/test/resources/renderer/link/separatorInsideLink.html
@@ -16,7 +16,7 @@
 -->
 
 <tobago-dropdown id='id' class='dropdown'>
-  <button type='button' id='id::command' name='id' data-toggle='dropdown' class='tobago-link btn btn-link dropdown-toggle'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>dropdown</span></button>
+  <button type='button' id='id::command' name='id' data-bs-toggle='dropdown' aria-expanded='false' class='tobago-link btn btn-link dropdown-toggle'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>dropdown</span></button>
   <div class='dropdown-menu' aria-labelledby='id::command' name='id'>
     <a id='link1' name='link1' href='https://www.apache.org/' class='tobago-link dropdown-item'><tobago-behavior event='click' client-id='link1' omit='omit'></tobago-behavior><span>Link 1</span></a>
     <tobago-separator id='separator' class='dropdown-divider'>
diff --git a/tobago-core/src/test/resources/renderer/links/link-inside-links-sub.html b/tobago-core/src/test/resources/renderer/links/link-inside-links-sub.html
index 9a04122..1c4d575 100644
--- a/tobago-core/src/test/resources/renderer/links/link-inside-links-sub.html
+++ b/tobago-core/src/test/resources/renderer/links/link-inside-links-sub.html
@@ -21,11 +21,11 @@ CSS class nav-item has moved from "tobago-dropdown" to "li"
   <ul class='nav'>
     <li class='nav-item'>
       <tobago-dropdown id='id' class='dropdown'>
-        <button type='button' id='id::command' name='id' data-toggle='dropdown' class='tobago-link btn btn-link dropdown-toggle nav-link'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>apache</span></button>
+        <button type='button' id='id::command' name='id' data-bs-toggle='dropdown' aria-expanded='false' class='tobago-link btn btn-link dropdown-toggle nav-link'><tobago-behavior event='click' client-id='id' field-id='id::command'></tobago-behavior><span>apache</span></button>
         <div class='dropdown-menu' aria-labelledby='id::command' name='id'>
           <a id='sub' name='sub' href='https://www.apache.org/' class='tobago-link dropdown-item nav-link'><tobago-behavior event='click' client-id='sub' omit='omit'></tobago-behavior><span>sub</span></a>
         </div>
       </tobago-dropdown>
     </li>
   </ul>
-</tobago-links>
\ No newline at end of file
+</tobago-links>
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/50-input-group/Group.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/50-input-group/Group.test.js
index 851b425..63e881f 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/50-input-group/Group.test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/20-component/010-input/50-input-group/Group.test.js
@@ -37,36 +37,36 @@ it("ajax: chat send button", function (done) {
 it("ajax: dropdown button", function (done) {
   let buttonFn = querySelectorFn("#page\\:mainForm\\:lsendtoc\\:\\:command");
   let buttonLabelFn = querySelectorFn("#page\\:mainForm\\:lsendtoc\\:\\:command span");
+  let dropdownMenu = querySelectorFn(".dropdown-menu[name='page:mainForm:lsendtoc']");
   let sendToPeterFn = querySelectorFn("#page\\:mainForm\\:sendToPeter");
   let sendToBobFn = querySelectorFn("#page\\:mainForm\\:sendToBob");
   let sendToAllFn = querySelectorFn("#page\\:mainForm\\:sendToAll");
 
   const test = new JasmineTestTool(done);
-  test.do(() => fail("not implemented yet; fix dropdown first"));
-  /*TTT.action(function () {
-    buttonFn().dispatchEvent(new Event("click", {bubbles: true}));
-    sendToPeterFn().dispatchEvent(new Event("click", {bubbles: true}));
-  });
-  TTT.waitForResponse();
-  TTT.asserts(1, function () {
-    assert.equal(buttonLabelFn().textContent, "SendTo: Peter");
-  });
-  TTT.action(function () {
-    buttonFn().dispatchEvent(new Event("click", {bubbles: true}));
-    sendToBobFn().dispatchEvent(new Event("click", {bubbles: true}));
-  });
-  TTT.waitForResponse();
-  TTT.asserts(1, function () {
-    assert.equal(buttonLabelFn().textContent, "SendTo: Bob");
-  });
-  TTT.action(function () {
-    buttonFn().dispatchEvent(new Event("click", {bubbles: true}));
-    sendToAllFn().dispatchEvent(new Event("click", {bubbles: true}));
-  });
-  TTT.waitForResponse();
-  TTT.asserts(1, function () {
-    assert.equal(buttonLabelFn().textContent, "SendTo: All");
-  });*/
+  test.setup(() => !dropdownMenu().parentElement.classList.contains("tobago-page-menuStore"),
+      null, "click", buttonFn);
+  test.setup(() => buttonLabelFn().textContent !== "SendTo: Peter",
+      null, "click", sendToAllFn);
+  test.do(() => expect(dropdownMenu().parentElement.classList).not.toContain("tobago-page-menuStore"));
+  test.do(() => expect(buttonLabelFn().textContent).not.toBe("SendTo: Peter"));
+
+  test.event("click", buttonFn, () => dropdownMenu().parentElement.classList.contains("tobago-page-menuStore"));
+  test.do(() => expect(dropdownMenu().parentElement.classList).toContain("tobago-page-menuStore"));
+  test.event("click", sendToPeterFn, () => buttonLabelFn().textContent === "SendTo: Peter");
+  test.do(() => expect(dropdownMenu().parentElement.classList).not.toContain("tobago-page-menuStore"));
+  test.do(() => expect(buttonLabelFn().textContent).toBe("SendTo: Peter"));
+
+  test.event("click", buttonFn, () => dropdownMenu().parentElement.classList.contains("tobago-page-menuStore"));
+  test.do(() => expect(dropdownMenu().parentElement.classList).toContain("tobago-page-menuStore"));
+  test.event("click", sendToBobFn, () => buttonLabelFn().textContent === "SendTo: Bob");
+  test.do(() => expect(dropdownMenu().parentElement.classList).not.toContain("tobago-page-menuStore"));
+  test.do(() => expect(buttonLabelFn().textContent).toBe("SendTo: Bob"));
+
+  test.event("click", buttonFn, () => dropdownMenu().parentElement.classList.contains("tobago-page-menuStore"));
+  test.do(() => expect(dropdownMenu().parentElement.classList).toContain("tobago-page-menuStore"));
+  test.event("click", sendToAllFn, () => buttonLabelFn().textContent === "SendTo: All");
+  test.do(() => expect(dropdownMenu().parentElement.classList).not.toContain("tobago-page-menuStore"));
+  test.do(() => expect(buttonLabelFn().textContent).toBe("SendTo: All"));
   test.start();
 });
 
@@ -77,8 +77,7 @@ it("ajax: currency change event", function (done) {
   let outputFn = querySelectorFn("#page\\:mainForm\\:valueInEuro tobago-out");
 
   const test = new JasmineTestTool(done);
-  test.setup(() => parseInt(inputFn().value.replaceAll(".", "")) === 1000
-      && outputFn().textContent === "1.000,00",
+  test.setup(() => convertInt(outputFn().textContent) === 100000,
       () => {
         inputFn().value = "1000";
         optionsFn().item(0).selected = false; // Yen
@@ -93,23 +92,30 @@ it("ajax: currency change event", function (done) {
   test.do(() => optionsFn().item(1).selected = false); // Trinidad-Tobago Dollar
   test.do(() => optionsFn().item(2).selected = false); // US Dollar
   test.do(() => optionsFn().item(3).selected = false); // Euro
-  test.event("change", selectFn, () => outputFn().textContent === "8,85");
-  test.do(() => expect(outputFn().textContent).toBe("8,85"));
+  test.event("change", selectFn, () => convertInt(outputFn().textContent) === 885);
+  test.do(() => expect(convertInt(outputFn().textContent)).toBe(885));
 
   test.do(() => inputFn().value = "2000");
   test.do(() => optionsFn().item(0).selected = false); // Yen
   test.do(() => optionsFn().item(1).selected = true); // Trinidad-Tobago Dollar
   test.do(() => optionsFn().item(2).selected = false); // US Dollar
   test.do(() => optionsFn().item(3).selected = false); // Euro
-  test.event("change", selectFn, () => outputFn().textContent === "267,50");
-  test.do(() => expect(outputFn().textContent).toBe("267,50"));
+  test.event("change", selectFn, () => convertInt(outputFn().textContent) === 26750);
+  test.do(() => expect(convertInt(outputFn().textContent)).toBe(26750));
 
   test.do(() => inputFn().value = "3000");
   test.do(() => optionsFn().item(0).selected = false); // Yen
   test.do(() => optionsFn().item(1).selected = false); // Trinidad-Tobago Dollar
   test.do(() => optionsFn().item(2).selected = true); // US Dollar
   test.do(() => optionsFn().item(3).selected = false); // Euro
-  test.event("change", selectFn, () => outputFn().textContent === "2.688,29");
-  test.do(() => expect(outputFn().textContent).toBe("2.688,29"));
+  test.event("change", selectFn, () => convertInt(outputFn().textContent) === 268829);
+  test.do(() => expect(convertInt(outputFn().textContent)).toBe(268829));
   test.start();
 });
+
+/**
+ * need this function, because chrome displays "1.000,00" and firefox displays "1,000.00"
+ */
+function convertInt(string) {
+  return parseInt(string.replaceAll(",", "").replaceAll(".", ""));
+}
diff --git a/tobago-theme/tobago-theme-standard/npm/ts/tobago-dropdown.ts b/tobago-theme/tobago-theme-standard/npm/ts/tobago-dropdown.ts
index 7b03c73..df26fe2 100644
--- a/tobago-theme/tobago-theme-standard/npm/ts/tobago-dropdown.ts
+++ b/tobago-theme/tobago-theme-standard/npm/ts/tobago-dropdown.ts
@@ -15,10 +15,9 @@
  * limitations under the License.
  */
 
-import {createPopper} from "@popperjs/core";
 // import {createPopper} from "@popperjs/core/dist/esm/popper";
 
-const Event = {
+const TobagoDropdownEvent = {
   HIDE: "tobago.dropdown.hide",
   HIDDEN: "tobago.dropdown.hidden",
   SHOW: "tobago.dropdown.show",
@@ -26,142 +25,38 @@ const Event = {
 };
 
 /**
- * The dropdown implementation of Bootstrap does not support submenus. Therefore we need an own dropdown implementation.
+ * The dropdown implementation of Bootstrap does not move the menu to the tobago-page-menuStore. This behavior is
+ * implemented in this class.
  */
 class Dropdown extends HTMLElement {
 
-  private dropdownEntries: DropdownEntry[] = [];
-
   constructor() {
     super();
     if (!this.classList.contains("tobago-dropdown-submenu")) { // ignore submenus
-      const root = this.getRootNode() as ShadowRoot | Document;
-
-      this.createDropdownEntries(this.dropdownMenu, null);
-
-      this.toggleButton.addEventListener("click", this.toggleDropdown.bind(this));
-      root.addEventListener("mouseup", this.mouseupOnDocument.bind(this));
-      root.addEventListener("keydown", this.keydownOnDocument.bind(this));
+      this.addEventListener("shown.bs.dropdown", this.openDropdown.bind(this));
+      this.addEventListener("hidden.bs.dropdown", this.closeDropdown.bind(this));
     }
   }
 
   connectedCallback(): void {
   }
 
-  toggleDropdown(event: Event): void {
-    event.preventDefault();
-    event.stopPropagation();
-    if (this.dropdownVisible()) {
-      this.closeDropdown();
-    } else {
-      this.openDropdown();
-    }
-  }
-
-  mouseupOnDocument(event: MouseEvent): void {
-    if (!this.toggleButtonSelected(event) && this.dropdownVisible()
-        && !this.dropdownMenu.contains(event.target as HTMLElement)) {
-      this.closeDropdown();
-    }
-  }
-
-  keydownOnDocument(event: KeyboardEvent): void {
-    if (this.toggleButtonSelected(event) && !this.dropdownVisible()
-        && (event.code === "ArrowUp" || event.code === "ArrowDown")) {
-      event.preventDefault();
-      event.stopPropagation();
-      this.openDropdown();
-
-      const interval = setInterval(() => {
-        if (this.dropdownVisible()) {
-
-          if (this.activeDropdownEntry) {
-            this.activeDropdownEntry.focus();
-          } else {
-            this.dropdownEntries[0].focus();
-          }
-          clearInterval(interval);
-        }
-      }, 0);
-    } else if (this.dropdownVisible()
-        && (event.code === "ArrowUp" || event.code === "ArrowDown"
-            || event.code === "ArrowLeft" || event.code === "ArrowRight"
-            || event.code === "Tab")) {
-      event.preventDefault();
-      event.stopPropagation();
-
-      if (!this.activeDropdownEntry) {
-        this.dropdownEntries[0].focus();
-      } else if (event.code === "ArrowUp" && this.activeDropdownEntry.previous) {
-        this.activeDropdownEntry.previous.focus();
-      } else if (event.code === "ArrowDown" && this.activeDropdownEntry.next) {
-        this.activeDropdownEntry.next.focus();
-      } else if (event.code === "ArrowRight" && this.activeDropdownEntry.children.length > 0) {
-        this.activeDropdownEntry.children[0].focus();
-      } else if (event.code === "ArrowLeft" && this.activeDropdownEntry.parent) {
-        this.activeDropdownEntry.parent.focus();
-      } else if (!event.shiftKey && event.code === "Tab") {
-        if (this.activeDropdownEntry.children.length > 0) {
-          this.activeDropdownEntry.children[0].focus();
-        } else if (this.activeDropdownEntry.next) {
-          this.activeDropdownEntry.next.focus();
-        } else {
-          let parent: DropdownEntry = this.activeDropdownEntry.parent;
-          while (parent) {
-            if (parent.next) {
-              this.activeDropdownEntry.clear();
-              parent.next.focus();
-              break;
-            } else {
-              parent = parent.parent;
-            }
-          }
-        }
-      } else if (event.shiftKey && event.code === "Tab") {
-        if (this.activeDropdownEntry.previous) {
-          this.activeDropdownEntry.previous.focus();
-        } else if (this.activeDropdownEntry.parent) {
-          this.activeDropdownEntry.parent.focus();
-        }
-      }
-    } else if (this.dropdownVisible() && event.code === "Escape") {
-      event.preventDefault();
-      event.stopPropagation();
-      this.closeDropdown();
-    }
-  }
-
   openDropdown(): void {
-    this.dispatchEvent(new CustomEvent(Event.SHOW));
+    this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.SHOW));
 
     if (!this.inStickyHeader()) {
       this.menuStore.appendChild(this.dropdownMenu);
-      createPopper(this.toggleButton, this.dropdownMenu, {
-        placement: "bottom-start"
-      });
     }
 
-    for (const dropdownEntry of this.dropdownEntries) {
-      dropdownEntry.clear();
-    }
-
-    this.dropdownMenu.classList.add("show");
-    this.dispatchEvent(new CustomEvent(Event.SHOWN));
+    this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.SHOWN));
   }
 
   closeDropdown(): void {
-    this.dispatchEvent(new CustomEvent(Event.HIDE));
-    this.dropdownMenu.classList.remove("show");
-    this.appendChild(this.dropdownMenu);
-    this.dispatchEvent(new CustomEvent(Event.HIDDEN));
-  }
-
-  private get toggleButton(): HTMLElement {
-    return this.querySelector(":scope > button[data-toggle='dropdown']");
-  }
-
-  private toggleButtonSelected(event: Event): boolean {
-    return this.toggleButton.contains(event.target as HTMLElement);
+    this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.HIDE));
+    if (!this.inStickyHeader()) {
+      this.appendChild(this.dropdownMenu);
+    }
+    this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.HIDDEN));
   }
 
   private inStickyHeader(): boolean {
@@ -173,161 +68,10 @@ class Dropdown extends HTMLElement {
     return root.querySelector(".dropdown-menu[name='" + this.id + "']");
   }
 
-  private dropdownVisible(): boolean {
-    return this.dropdownMenu.classList.contains("show");
-  }
-
   private get menuStore(): HTMLDivElement {
     const root = this.getRootNode() as ShadowRoot | Document;
     return root.querySelector(".tobago-page-menuStore");
   }
-
-  private get activeDropdownEntry(): DropdownEntry {
-    for (const dropdownEntry of this.dropdownEntries) {
-      if (dropdownEntry.active) {
-        return dropdownEntry;
-      }
-    }
-    return null;
-  }
-
-  private createDropdownEntries(dropdownMenu: HTMLDivElement, parent: DropdownEntry): void {
-    let lastDropdownEntry: DropdownEntry = null;
-
-    for (const dropdownItem of dropdownMenu.children) {
-      if (dropdownItem.classList.contains("dropdown-item")) {
-        const entry = this.createDropdownEntry(dropdownItem as HTMLElement, parent, lastDropdownEntry);
-
-        lastDropdownEntry = entry;
-        this.dropdownEntries.push(entry);
-
-        if (dropdownItem.classList.contains("tobago-dropdown-submenu")) {
-          this.createDropdownEntries(dropdownItem.querySelector(".dropdown-menu"), entry);
-        }
-      } else {
-        const dropdownItems: NodeListOf<HTMLElement> = dropdownItem.querySelectorAll(".dropdown-item");
-        for (const dropdownItem of dropdownItems) {
-          const entry = this.createDropdownEntry(dropdownItem, parent, lastDropdownEntry);
-
-          lastDropdownEntry = entry;
-          this.dropdownEntries.push(entry);
-        }
-      }
-    }
-  }
-
-  private createDropdownEntry(
-      dropdownItem: HTMLElement, parent: DropdownEntry, previous: DropdownEntry): DropdownEntry {
-
-    const entry = new DropdownEntry(dropdownItem);
-    if (parent) {
-      entry.parent = parent;
-      parent.children.push(entry);
-    }
-
-    if (previous) {
-      previous.next = entry;
-      entry.previous = previous;
-    }
-
-    return entry;
-  }
-}
-
-class DropdownEntry {
-
-  private _previous: DropdownEntry;
-  private _next: DropdownEntry;
-  private _parent: DropdownEntry;
-  private _children: DropdownEntry[] = [];
-  private readonly _baseElement: HTMLElement;
-  private readonly focusElement: HTMLElement;
-  private _active: boolean;
-
-  constructor(dropdownItem: HTMLElement) {
-    this._baseElement = dropdownItem;
-    if (dropdownItem.classList.contains("tobago-dropdown-submenu")) {
-      this.focusElement = dropdownItem.querySelector(".tobago-link");
-    } else if (dropdownItem.tagName === "LABEL") {
-      const root = dropdownItem.getRootNode() as ShadowRoot | Document;
-      this.focusElement = root.getElementById(dropdownItem.getAttribute("for"));
-    } else {
-      this.focusElement = dropdownItem;
-    }
-
-    this._baseElement.addEventListener("mouseenter", this.activate.bind(this));
-    this._baseElement.addEventListener("mouseleave", this.deactivate.bind(this));
-  }
-
-  activate(event: MouseEvent): void {
-    this.active = true;
-  }
-
-  deactivate(event: MouseEvent): void {
-    this.active = false;
-  }
-
-  get previous(): DropdownEntry {
-    return this._previous;
-  }
-
-  set previous(value: DropdownEntry) {
-    this._previous = value;
-  }
-
-  get next(): DropdownEntry {
-    return this._next;
-  }
-
-  set next(value: DropdownEntry) {
-    this._next = value;
-  }
-
-  get parent(): DropdownEntry {
-    return this._parent;
-  }
-
-  set parent(value: DropdownEntry) {
-    this._parent = value;
-  }
-
-  get children(): DropdownEntry[] {
-    return this._children;
-  }
-
-  set children(value: DropdownEntry[]) {
-    this._children = value;
-  }
-
-  get active(): boolean {
-    return this._active;
-  }
-
-  set active(value: boolean) {
-    this._active = value;
-  }
-
-  public focus(): void {
-    this.previous?.clear();
-    this.next?.clear();
-    if (this.parent) {
-      this.parent.active = false;
-      this.parent._baseElement.classList.add("tobago-dropdown-open");
-    }
-    for (const child of this.children) {
-      child.clear();
-    }
-    this._baseElement.classList.remove("tobago-dropdown-open");
-    this._baseElement.classList.add("tobago-dropdown-selected");
-    this.active = true;
-    this.focusElement.focus();
-  }
-
-  public clear(): void {
-    this._baseElement.classList.remove("tobago-dropdown-open");
-    this._baseElement.classList.remove("tobago-dropdown-selected");
-    this.active = false;
-  }
 }
 
 document.addEventListener("tobago.init", function (event: Event): void {