]> BookStack Code Mirror - bookstack/blobdiff - resources/assets/js/components/dropdown.js
Update maintenance.php
[bookstack] / resources / assets / js / components / dropdown.js
index 400ddb576128bd1f1464700b923d4fc21012c3e5..3887e8432289d23e2f81cd01424c7476428c8e33 100644 (file)
@@ -6,24 +6,60 @@ class DropDown {
 
     constructor(elem) {
         this.container = elem;
-        this.menu = elem.querySelector('ul, [dropdown-menu]');
+        this.menu = elem.querySelector('.dropdown-menu, [dropdown-menu]');
+        this.moveMenu = elem.hasAttribute('dropdown-move-menu');
         this.toggle = elem.querySelector('[dropdown-toggle]');
+        this.body = document.body;
         this.setupListeners();
     }
 
-    show() {
+    show(event) {
+        this.hideAll();
+
         this.menu.style.display = 'block';
         this.menu.classList.add('anim', 'menuIn');
-        this.container.addEventListener('mouseleave', this.hide.bind(this));
+
+        if (this.moveMenu) {
+            // Move to body to prevent being trapped within scrollable sections
+            this.rect = this.menu.getBoundingClientRect();
+            this.body.appendChild(this.menu);
+            this.menu.style.position = 'fixed';
+            this.menu.style.left = `${this.rect.left}px`;
+            this.menu.style.top = `${this.rect.top}px`;
+            this.menu.style.width = `${this.rect.width}px`;
+        }
+
+        // Set listener to hide on mouse leave or window click
+        this.menu.addEventListener('mouseleave', this.hide.bind(this));
+        window.addEventListener('click', event => {
+            if (!this.menu.contains(event.target)) {
+                this.hide();
+            }
+        });
 
         // Focus on first input if existing
         let input = this.menu.querySelector('input');
         if (input !== null) input.focus();
+
+        event.stopPropagation();
+    }
+
+    hideAll() {
+        for (let dropdown of window.components.dropdown) {
+            dropdown.hide();
+        }
     }
 
     hide() {
         this.menu.style.display = 'none';
         this.menu.classList.remove('anim', 'menuIn');
+        if (this.moveMenu) {
+            this.menu.style.position = '';
+            this.menu.style.left = '';
+            this.menu.style.top = '';
+            this.menu.style.width = '';
+            this.container.appendChild(this.menu);
+        }
     }
 
     setupListeners() {