import './dropdown.css'; import { Ut } from '../../utils/Ut'; import { El } from '../../utils/dom'; import { Boot } from '../../core/Boot'; export class Dropdown { #isOpen = false; #hasRendered = false; constructor(target, opts) { this.target = target; if (this.target.dxData('dropdown')) { return; } this.target.dxData('dropdown', this); Boot.addWidget(this); this.opts = { ... { items: [] }, ... opts }; this.el = null; this.ekey = Ut.nextKey(); this.#bindTargetEvents(); } #bindTargetEvents() { const that = this; this.target.dxOn('focus.dropdown', e => { e.stopPropagation(); Ut.trigger(that.opts.onFocus, this); if (!that.#hasRendered) { this.#render(); } if (!that.#isOpen) { that.show(); return; } that.hide(); }); } #bindUiEvents() { const that = this; // Click on Item Handler this.el.dxOn('click', 'li', (_, t) => { that.hide(); Ut.trigger(that.opts.items[ t.dxIndex(that.items) ].handler); Ut.trigger(that.opts.onChange, t.dataset.id, this); }); // PointerDown Handler document.dxOn('pointerdown.dropdown', e => !this.target.contains(e.target) && !this.el.contains(e.target) && this.hide() ); let tm = null; // Resize & Orientation Handler window.dxOn(`resize.dropdown.${this.ekey} orientationchange.dropdown.${this.ekey}`, _ => { if (tm) { clearTimeout(tm); tm = null; } tm = setTimeout(_ => that.#reposition(), 100); }); } #render() { this.el = El('div', { className: 'sp-dropdown hide' }); if (this.opts.cls) { this.el.classList.add(this.opts.cls); } const list = El('ul'); if (this.opts.items.length) { this.el.append(list); } this.items = []; this.opts.items.forEach(item => { this.items.push( list.appendChild( El('li', { className: 'color-'+ (item.color || 'black'), 'data-id': item.id }, (item.icon ? El('i', { className: 'fa fa-'+ item.icon }) : null), item.name )) ); }); document.body.append(this.el); this.#bindUiEvents(); this.#hasRendered = true; Ut.trigger(this.opts.onInit, this); } #reposition() { const r = this.target.getBoundingClientRect(); const scrollX = window.scrollX || 0; const scrollY = window.scrollY || 0; this.el.style.left = Math.round(r.left + scrollX) + 'px'; this.el.style.top = Math.round(r.bottom + scrollY + 2) + 'px'; } show() { if (this.#isOpen) { return; } this.#reposition(); this.el.classList.remove('hide'); this.el.classList.add('opened'); this.#isOpen = true; Ut.trigger(this.opts.onShow, this); } hide() { if (!this.#isOpen) { return; } this.el.addEventListener('transitionend', _ => this.el.classList.add('hide'), { once: true } ); this.el.classList.remove('opened'); this.#isOpen = false; Ut.trigger(this.opts.onHide, this); }; destroy() { if (this.#hasRendered) { this.el.remove(); document.dxOff(`pointerdown.dropdown.${this.ekey}`); window.dxOff(`resize.dropdown.${this.ekey} orientationchange.dropdown.${this.ekey}`); } this.target.dxOff(`focus.dropdown.${this.ekey}`); this.target.dxRemoveData('dropdown'); Ut.trigger(this.opts.onDestroy, this); } }