| | import { QuickReply } from '../../QuickReply.js'; |
| | import { QuickReplySet } from '../../QuickReplySet.js'; |
| | import { MenuHeader } from './MenuHeader.js'; |
| | import { MenuItem } from './MenuItem.js'; |
| |
|
| | export class ContextMenu { |
| | itemList = []; |
| | isActive = false; |
| |
|
| | root; |
| | menu; |
| |
|
| |
|
| |
|
| |
|
| | constructor(qr) { |
| | |
| | this.itemList = this.build(qr).children; |
| | this.itemList.forEach(item => { |
| | item.onExpand = () => { |
| | this.itemList.filter(it => it !== item) |
| | .forEach(it => it.collapse()); |
| | }; |
| | }); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | build(qr, chainedMessage = null, hierarchy = [], labelHierarchy = []) { |
| | const tree = { |
| | icon: qr.icon, |
| | showLabel: qr.showLabel, |
| | label: qr.label, |
| | title: qr.title, |
| | message: (chainedMessage && qr.message ? `${chainedMessage} | ` : '') + qr.message, |
| | children: [], |
| | }; |
| | qr.contextList.forEach((cl) => { |
| | if (!cl.set) return; |
| | if (!hierarchy.includes(cl.set)) { |
| | const nextHierarchy = [...hierarchy, cl.set]; |
| | const nextLabelHierarchy = [...labelHierarchy, tree.label]; |
| | tree.children.push(new MenuHeader(cl.set.name)); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const qrsOwnSetAddedAsContextMenu = cl.set.qrList.includes(qr); |
| | const visible = (subQr) => { |
| | return qrsOwnSetAddedAsContextMenu |
| | ? subQr.isHidden && !!subQr.icon |
| | : !subQr.isHidden; |
| | }; |
| |
|
| | cl.set.qrList.filter(visible).forEach(subQr => { |
| | const subTree = this.build(subQr, cl.isChained ? tree.message : null, nextHierarchy, nextLabelHierarchy); |
| | tree.children.push(new MenuItem( |
| | subTree.icon, |
| | subTree.showLabel, |
| | subTree.label, |
| | subTree.title, |
| | subTree.message, |
| | (evt) => { |
| | evt.stopPropagation(); |
| | const finalQr = Object.assign(new QuickReply(), subQr); |
| | finalQr.message = subTree.message.replace(/%%parent(-\d+)?%%/g, (_, index) => { |
| | return nextLabelHierarchy.slice(parseInt(index ?? '-1'))[0]; |
| | }); |
| | cl.set.execute(finalQr); |
| | }, |
| | subTree.children, |
| | )); |
| | }); |
| | } |
| | }); |
| | return tree; |
| | } |
| |
|
| | render() { |
| | if (!this.root) { |
| | const blocker = document.createElement('div'); { |
| | this.root = blocker; |
| | blocker.classList.add('ctx-blocker'); |
| | blocker.addEventListener('click', () => this.hide()); |
| | const menu = document.createElement('ul'); { |
| | this.menu = menu; |
| | menu.classList.add('list-group'); |
| | menu.classList.add('ctx-menu'); |
| | this.itemList.forEach(it => menu.append(it.render())); |
| | blocker.append(menu); |
| | } |
| | } |
| | } |
| | return this.root; |
| | } |
| |
|
| |
|
| |
|
| |
|
| | show({ clientX, clientY }) { |
| | if (this.isActive) return; |
| | this.isActive = true; |
| | this.render(); |
| | this.menu.style.bottom = `${window.innerHeight - clientY}px`; |
| | this.menu.style.left = `${clientX}px`; |
| | document.body.append(this.root); |
| | } |
| | hide() { |
| | if (this.root) { |
| | this.root.remove(); |
| | } |
| | this.isActive = false; |
| | } |
| | toggle(evt) { |
| | if (this.isActive) { |
| | this.hide(); |
| | } else { |
| | this.show(evt); |
| | } |
| | } |
| | } |
| |
|