Filter out hidden items in context menus Add CSS to apply label show/hide settings to QRs in context menus Add provision for QR set applied to one of its own buttons as "burger" menu
| @@ -38,7 +38,6 @@ export class ContextMenu { | |||
| 38 | label: qr.label, | 38 | label: qr.label, |
| 39 | title: qr.title, | 39 | title: qr.title, |
| 40 | message: (chainedMessage && qr.message ? `${chainedMessage} | ` : '') + qr.message, | 40 | message: (chainedMessage && qr.message ? `${chainedMessage} | ` : '') + qr.message, |
| 41 | isHidden: qr.isHidden, | ||
| 42 | children: [], | 41 | children: [], |
| 43 | }; | 42 | }; |
| 44 | qr.contextList.forEach((cl) => { | 43 | qr.contextList.forEach((cl) => { |
| @@ -47,7 +46,23 @@ export class ContextMenu { | |||
| 47 | const nextHierarchy = [...hierarchy, cl.set]; | 46 | const nextHierarchy = [...hierarchy, cl.set]; |
| 48 | const nextLabelHierarchy = [...labelHierarchy, tree.label]; | 47 | const nextLabelHierarchy = [...labelHierarchy, tree.label]; |
| 49 | tree.children.push(new MenuHeader(cl.set.name)); | 48 | tree.children.push(new MenuHeader(cl.set.name)); |
| 50 | cl.set.qrList.forEach(subQr => { | 49 | |
| 50 | // If the Quick Reply's own set is added as a context menu, | ||
| 51 | // show only the sub-QRs that are Invisible but have an icon | ||
| 52 | // intent: allow a QR set to be assigned to one of its own QR buttons for a "burger" menu | ||
| 53 | // with "UI" QRs either in the bar or in the menu, and "library function" QRs still hidden. | ||
| 54 | // - QRs already visible on the bar are filtered out, | ||
| 55 | // - hidden QRs without an icon are filtered out, | ||
| 56 | // - hidden QRs **with an icon** are shown in the menu | ||
| 57 | // so everybody is happy | ||
| 58 | const qrsOwnSetAddedAsContextMenu = cl.set.qrList.includes(qr); | ||
| 59 | const visible = (subQr) => { | ||
| 60 | return qrsOwnSetAddedAsContextMenu | ||
| 61 | ? subQr.isHidden && !!subQr.icon // yes .isHidden gets inverted here | ||
| 62 | : !subQr.isHidden; | ||
| 63 | }; | ||
| 64 | |||
| 65 | cl.set.qrList.filter(visible).forEach(subQr => { | ||
| 51 | const subTree = this.build(subQr, cl.isChained ? tree.message : null, nextHierarchy, nextLabelHierarchy); | 66 | const subTree = this.build(subQr, cl.isChained ? tree.message : null, nextHierarchy, nextLabelHierarchy); |
| 52 | tree.children.push(new MenuItem( | 67 | tree.children.push(new MenuItem( |
| 53 | subTree.icon, | 68 | subTree.icon, |
| @@ -55,7 +70,6 @@ export class ContextMenu { | |||
| 55 | subTree.label, | 70 | subTree.label, |
| 56 | subTree.title, | 71 | subTree.title, |
| 57 | subTree.message, | 72 | subTree.message, |
| 58 | subTree.isHidden, | ||
| 59 | (evt) => { | 73 | (evt) => { |
| 60 | evt.stopPropagation(); | 74 | evt.stopPropagation(); |
| 61 | const finalQr = Object.assign(new QuickReply(), subQr); | 75 | 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, false, null, []); | 5 | super(null, null, label, null, null, null, []); |
| 6 | } | 6 | } |
| 7 | 7 | ||
| 8 | 8 | ||
| @@ -6,7 +6,6 @@ export class MenuItem { | |||
| 6 | /**@type {string}*/ label; | 6 | /**@type {string}*/ label; |
| 7 | /**@type {string}*/ title; | 7 | /**@type {string}*/ title; |
| 8 | /**@type {object}*/ value; | 8 | /**@type {object}*/ value; |
| 9 | /**@type {boolean}*/ isHidden = false; | ||
| 10 | /**@type {function}*/ callback; | 9 | /**@type {function}*/ callback; |
| 11 | /**@type {MenuItem[]}*/ childList = []; | 10 | /**@type {MenuItem[]}*/ childList = []; |
| 12 | /**@type {SubMenu}*/ subMenu; | 11 | /**@type {SubMenu}*/ subMenu; |
| @@ -25,44 +24,20 @@ export class MenuItem { | |||
| 25 | * @param {string} label | 24 | * @param {string} label |
| 26 | * @param {?string} title Tooltip | 25 | * @param {?string} title Tooltip |
| 27 | * @param {object} value | 26 | * @param {object} value |
| 28 | * @param {boolean} isHidden QR is Invisible (auto-execute only) | ||
| 29 | * @param {function} callback | 27 | * @param {function} callback |
| 30 | * @param {MenuItem[]} children | 28 | * @param {MenuItem[]} children |
| 31 | */ | 29 | */ |
| 32 | constructor(icon, showLabel, label, title, value, isHidden, callback, children = []) { | 30 | constructor(icon, showLabel, label, title, value, callback, children = []) { |
| 33 | this.icon = icon; | 31 | this.icon = icon; |
| 34 | this.showLabel = showLabel; | 32 | this.showLabel = showLabel; |
| 35 | this.label = label; | 33 | this.label = label; |
| 36 | this.title = title; | 34 | this.title = title; |
| 37 | this.value = value; | 35 | this.value = value; |
| 38 | this.isHidden = isHidden; | ||
| 39 | this.callback = callback; | 36 | this.callback = callback; |
| 40 | this.childList = children; | 37 | this.childList = children; |
| 41 | } | 38 | } |
| 42 | 39 | ||
| 43 | 40 | ||
| 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 | */ | ||
| 66 | render() { | 41 | render() { |
| 67 | if (!this.root) { | 42 | if (!this.root) { |
| 68 | const item = document.createElement('li'); { | 43 | const item = document.createElement('li'); { |
| @@ -70,9 +45,6 @@ export class MenuItem { | |||
| 70 | item.classList.add('list-group-item'); | 45 | item.classList.add('list-group-item'); |
| 71 | item.classList.add('ctx-item'); | 46 | item.classList.add('ctx-item'); |
| 72 | 47 | ||
| 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 | 48 | // if a title/tooltip is set, add it, otherwise use the QR content |
| 77 | // same as for the main QR list | 49 | // same as for the main QR list |
| 78 | item.title = this.title || this.value; | 50 | item.title = this.title || this.value; |
| @@ -174,6 +174,9 @@ | |||
| 174 | position: absolute; | 174 | position: absolute; |
| 175 | overflow: visible; | 175 | overflow: visible; |
| 176 | } | 176 | } |
| 177 | .ctx-menu .ctx-item .qr--hidden { | ||
| 178 | display: none; | ||
| 179 | } | ||
| 177 | .list-group .list-group-item.ctx-header { | 180 | .list-group .list-group-item.ctx-header { |
| 178 | font-weight: bold; | 181 | font-weight: bold; |
| 179 | cursor: default; | 182 | cursor: default; |
| @@ -176,6 +176,10 @@ | |||
| 176 | overflow: visible; | 176 | overflow: visible; |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | .ctx-menu .ctx-item .qr--hidden { | ||
| 180 | display: none; | ||
| 181 | } | ||
| 182 | |||
| 179 | .list-group .list-group-item.ctx-header { | 183 | .list-group .list-group-item.ctx-header { |
| 180 | font-weight: bold; | 184 | font-weight: bold; |
| 181 | cursor: default; | 185 | cursor: default; |