Merge pull request #3122 from ceruleandeep/feature/compactererQRContextMenus Make QR context menu display options more consistent with QR bar
Signed| @@ -19,7 +19,7 @@ export class ContextMenu { | |||
| 19 | this.itemList = this.build(qr).children; | 19 | this.itemList = this.build(qr).children; |
| 20 | this.itemList.forEach(item => { | 20 | this.itemList.forEach(item => { |
| 21 | item.onExpand = () => { | 21 | item.onExpand = () => { |
| 22 | this.itemList.filter(it => it != item) | 22 | this.itemList.filter(it => it !== item) |
| 23 | .forEach(it => it.collapse()); | 23 | .forEach(it => it.collapse()); |
| 24 | }; | 24 | }; |
| 25 | }); | 25 | }); |
| @@ -36,7 +36,9 @@ export class ContextMenu { | |||
| 36 | icon: qr.icon, | 36 | icon: qr.icon, |
| 37 | showLabel: qr.showLabel, | 37 | showLabel: qr.showLabel, |
| 38 | label: qr.label, | 38 | label: qr.label, |
| 39 | title: qr.title, | ||
| 39 | message: (chainedMessage && qr.message ? `${chainedMessage} | ` : '') + qr.message, | 40 | message: (chainedMessage && qr.message ? `${chainedMessage} | ` : '') + qr.message, |
| 41 | isHidden: qr.isHidden, | ||
| 40 | children: [], | 42 | children: [], |
| 41 | }; | 43 | }; |
| 42 | qr.contextList.forEach((cl) => { | 44 | qr.contextList.forEach((cl) => { |
| @@ -51,7 +53,9 @@ export class ContextMenu { | |||
| 51 | subTree.icon, | 53 | subTree.icon, |
| 52 | subTree.showLabel, | 54 | subTree.showLabel, |
| 53 | subTree.label, | 55 | subTree.label, |
| 56 | subTree.title, | ||
| 54 | subTree.message, | 57 | subTree.message, |
| 58 | subTree.isHidden, | ||
| 55 | (evt) => { | 59 | (evt) => { |
| 56 | evt.stopPropagation(); | 60 | evt.stopPropagation(); |
| 57 | const finalQr = Object.assign(new QuickReply(), subQr); | 61 | const finalQr = Object.assign(new QuickReply(), subQr); |
| @@ -2,7 +2,7 @@ import { MenuItem } from './MenuItem.js'; | |||
| 2 | 2 | ||
| 3 | export class MenuHeader extends MenuItem { | 3 | export class MenuHeader extends MenuItem { |
| 4 | constructor(/**@type {String}*/label) { | 4 | constructor(/**@type {String}*/label) { |
| 5 | super(null, null, label, null, null); | 5 | super(null, null, label, null, null, false, null, []); |
| 6 | } | 6 | } |
| 7 | 7 | ||
| 8 | 8 | ||
| @@ -4,11 +4,12 @@ export class MenuItem { | |||
| 4 | /**@type {string}*/ icon; | 4 | /**@type {string}*/ icon; |
| 5 | /**@type {boolean}*/ showLabel; | 5 | /**@type {boolean}*/ showLabel; |
| 6 | /**@type {string}*/ label; | 6 | /**@type {string}*/ label; |
| 7 | /**@type {string}*/ title; | ||
| 7 | /**@type {object}*/ value; | 8 | /**@type {object}*/ value; |
| 9 | /**@type {boolean}*/ isHidden = false; | ||
| 8 | /**@type {function}*/ callback; | 10 | /**@type {function}*/ callback; |
| 9 | /**@type {MenuItem[]}*/ childList = []; | 11 | /**@type {MenuItem[]}*/ childList = []; |
| 10 | /**@type {SubMenu}*/ subMenu; | 12 | /**@type {SubMenu}*/ subMenu; |
| 11 | /**@type {boolean}*/ isForceExpanded = false; | ||
| 12 | 13 | ||
| 13 | /**@type {HTMLElement}*/ root; | 14 | /**@type {HTMLElement}*/ root; |
| 14 | 15 | ||
| @@ -19,35 +20,67 @@ export class MenuItem { | |||
| 19 | 20 | ||
| 20 | /** | 21 | /** |
| 21 | * | 22 | * |
| 22 | * @param {string} icon | 23 | * @param {?string} icon |
| 23 | * @param {boolean} showLabel | 24 | * @param {?boolean} showLabel |
| 24 | * @param {string} label | 25 | * @param {string} label |
| 26 | * @param {?string} title Tooltip | ||
| 25 | * @param {object} value | 27 | * @param {object} value |
| 28 | * @param {boolean} isHidden QR is Invisible (auto-execute only) | ||
| 26 | * @param {function} callback | 29 | * @param {function} callback |
| 27 | * @param {MenuItem[]} children | 30 | * @param {MenuItem[]} children |
| 28 | */ | 31 | */ |
| 29 | constructor(icon, showLabel, label, value, callback, children = []) { | 32 | constructor(icon, showLabel, label, title, value, isHidden, callback, children = []) { |
| 30 | this.icon = icon; | 33 | this.icon = icon; |
| 31 | this.showLabel = showLabel; | 34 | this.showLabel = showLabel; |
| 32 | this.label = label; | 35 | this.label = label; |
| 36 | this.title = title; | ||
| 33 | this.value = value; | 37 | this.value = value; |
| 38 | this.isHidden = isHidden; | ||
| 34 | this.callback = callback; | 39 | this.callback = callback; |
| 35 | this.childList = children; | 40 | this.childList = children; |
| 36 | } | 41 | } |
| 37 | 42 | ||
| 38 | 43 | ||
| 44 | /** | ||
| 45 | * Renders the MenuItem | ||
| 46 | * | ||
| 47 | * A .qr--hidden class is added to: | ||
| 48 | * - the item if it is "Invisible (auto-execute only)" | ||
| 49 | * - the icon if no icon is set | ||
| 50 | * - the label if an icon is set and showLabel is false | ||
| 51 | * | ||
| 52 | * There is no .qr--hidden class defined in default CSS, since having items | ||
| 53 | * that are invisible on the QR bar but visible in the context menu, | ||
| 54 | * or icon-only on the QR bar but labelled in the context menu, is a valid use case. | ||
| 55 | * | ||
| 56 | * To hide optional labels when icons are present, add this user CSS: | ||
| 57 | * .ctx-menu .ctx-item .qr--button-label.qr--hidden {display: none;} | ||
| 58 | * To hide icons when no icon is present (removes unwanted padding): | ||
| 59 | * .ctx-menu .ctx-item .qr--button-icon.qr--hidden {display: none;} | ||
| 60 | * To hide items that are set "invisible": | ||
| 61 | * .ctx-menu .ctx-item.qr--hidden {display: none;} | ||
| 62 | * To target submenus only, use .ctx-menu .ctx-sub-menu .qr--hidden {display: none;} | ||
| 63 | * | ||
| 64 | * @returns {HTMLElement} | ||
| 65 | */ | ||
| 39 | render() { | 66 | render() { |
| 40 | if (!this.root) { | 67 | if (!this.root) { |
| 41 | const item = document.createElement('li'); { | 68 | const item = document.createElement('li'); { |
| 42 | this.root = item; | 69 | this.root = item; |
| 43 | item.classList.add('list-group-item'); | 70 | item.classList.add('list-group-item'); |
| 44 | item.classList.add('ctx-item'); | 71 | item.classList.add('ctx-item'); |
| 45 | item.title = this.value; | 72 | |
| 73 | // if this item is Invisible, add the hidden class | ||
| 74 | if (this.isHidden) item.classList.add('qr--hidden'); | ||
| 75 | |||
| 76 | // if a title/tooltip is set, add it, otherwise use the QR content | ||
| 77 | // same as for the main QR list | ||
| 78 | item.title = this.title || this.value; | ||
| 79 | |||
| 46 | if (this.callback) { | 80 | if (this.callback) { |
| 47 | item.addEventListener('click', (evt) => this.callback(evt, this)); | 81 | item.addEventListener('click', (evt) => this.callback(evt, this)); |
| 48 | } | 82 | } |
| 49 | const icon = document.createElement('div'); { | 83 | const icon = document.createElement('div'); { |
| 50 | this.domIcon = icon; | ||
| 51 | icon.classList.add('qr--button-icon'); | 84 | icon.classList.add('qr--button-icon'); |
| 52 | icon.classList.add('fa-solid'); | 85 | icon.classList.add('fa-solid'); |
| 53 | if (!this.icon) icon.classList.add('qr--hidden'); | 86 | if (!this.icon) icon.classList.add('qr--hidden'); |
| @@ -55,7 +88,6 @@ export class MenuItem { | |||
| 55 | item.append(icon); | 88 | item.append(icon); |
| 56 | } | 89 | } |
| 57 | const lbl = document.createElement('div'); { | 90 | const lbl = document.createElement('div'); { |
| 58 | this.domLabel = lbl; | ||
| 59 | lbl.classList.add('qr--button-label'); | 91 | lbl.classList.add('qr--button-label'); |
| 60 | if (this.icon && !this.showLabel) lbl.classList.add('qr--hidden'); | 92 | if (this.icon && !this.showLabel) lbl.classList.add('qr--hidden'); |
| 61 | lbl.textContent = this.label; | 93 | lbl.textContent = this.label; |