]> BookStack Code Mirror - bookstack/blob - resources/assets/js/components/dropdown.js
ce797bbeb31976c351335888c92b80b30c8d2fdb
[bookstack] / resources / assets / js / components / dropdown.js
1 /**
2  * Dropdown
3  * Provides some simple logic to create simple dropdown menus.
4  */
5 class DropDown {
6
7     constructor(elem) {
8         this.container = elem;
9         this.menu = elem.querySelector('.dropdown-menu, [dropdown-menu]');
10         this.moveMenu = elem.hasAttribute('dropdown-move-menu');
11         this.toggle = elem.querySelector('[dropdown-toggle]');
12         this.body = document.body;
13         this.setupListeners();
14     }
15
16     show(event) {
17         this.hide();
18
19         this.menu.style.display = 'block';
20         this.menu.classList.add('anim', 'menuIn');
21
22         if (this.moveMenu) {
23             // Move to body to prevent being trapped within scrollable sections
24             this.rect = this.menu.getBoundingClientRect();
25             this.body.appendChild(this.menu);
26             this.menu.style.position = 'fixed';
27             this.menu.style.left = `${this.rect.left}px`;
28             this.menu.style.top = `${this.rect.top}px`;
29             this.menu.style.width = `${this.rect.width}px`;
30         }
31
32         // Set listener to hide on mouse leave or window click
33         this.menu.addEventListener('mouseleave', this.hide.bind(this));
34         window.addEventListener('click', event => {
35             if (!this.menu.contains(event.target)) {
36                 this.hide();
37             }
38         });
39
40         // Focus on first input if existing
41         let input = this.menu.querySelector('input');
42         if (input !== null) input.focus();
43
44         event.stopPropagation();
45     }
46
47     hide() {
48         this.menu.style.display = 'none';
49         this.menu.classList.remove('anim', 'menuIn');
50         if (this.moveMenu) {
51             this.menu.style.position = '';
52             this.menu.style.left = '';
53             this.menu.style.top = '';
54             this.menu.style.width = '';
55             this.container.appendChild(this.menu);
56         }
57     }
58
59     setupListeners() {
60         // Hide menu on option click
61         this.container.addEventListener('click', event => {
62              let possibleChildren = Array.from(this.menu.querySelectorAll('a'));
63              if (possibleChildren.indexOf(event.target) !== -1) this.hide();
64         });
65         // Show dropdown on toggle click
66         this.toggle.addEventListener('click', this.show.bind(this));
67         // Hide menu on enter press
68         this.container.addEventListener('keypress', event => {
69                 if (event.keyCode !== 13) return true;
70                 event.preventDefault();
71                 this.hide();
72                 return false;
73         });
74     }
75
76 }
77
78 export default DropDown;