mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-24 06:48:40 +01:00
Speed up nextmatch context menus by creating them once & reuse them
This commit is contained in:
parent
2b5f15855b
commit
290dc59a09
@ -1,5 +1,5 @@
|
||||
import {css, html, LitElement, nothing, PropertyValues} from "lit";
|
||||
import {SlIcon, SlMenu, SlMenuItem} from "@shoelace-style/shoelace";
|
||||
import {css, html, LitElement, nothing} from "lit";
|
||||
import {SlMenu, SlMenuItem} from "@shoelace-style/shoelace";
|
||||
import {egwMenuItem} from "./egw_menu";
|
||||
import {customElement} from "lit/decorators/custom-element.js";
|
||||
import {repeat} from "lit/directives/repeat.js";
|
||||
@ -26,6 +26,12 @@ export class EgwMenuShoelace extends LitElement
|
||||
box-shadow: var(--sl-shadow-x-large);
|
||||
}
|
||||
|
||||
/* sl-menu-item:host overrides display */
|
||||
|
||||
sl-menu-item[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
sl-menu-item::part(base) {
|
||||
height: 1.7em;
|
||||
line-height: var(--sl-line-height-dense);
|
||||
@ -60,7 +66,7 @@ export class EgwMenuShoelace extends LitElement
|
||||
|
||||
private structure = [];
|
||||
private popup = null;
|
||||
private removeCallback = null;
|
||||
private hideCallback = null;
|
||||
|
||||
private get menu() : SlMenu { return this.shadowRoot?.querySelector("sl-menu");}
|
||||
|
||||
@ -91,16 +97,16 @@ export class EgwMenuShoelace extends LitElement
|
||||
this.popup.remove();
|
||||
this.popup = null;
|
||||
}
|
||||
if(this.removeCallback)
|
||||
if(this.hideCallback)
|
||||
{
|
||||
this.removeCallback.call();
|
||||
this.hideCallback.call();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public showAt(_x, _y, _onHide)
|
||||
{
|
||||
this.removeCallback = _onHide;
|
||||
this.hideCallback = _onHide;
|
||||
if(this.popup == null)
|
||||
{
|
||||
this.popup = Object.assign(document.createElement("sl-popup"), {
|
||||
@ -111,7 +117,10 @@ export class EgwMenuShoelace extends LitElement
|
||||
});
|
||||
this.popup.append(this);
|
||||
this.popup.classList.add("egw_menu");
|
||||
document.body.append(this.popup);
|
||||
}
|
||||
|
||||
// Open where instructed
|
||||
let menu = this;
|
||||
this.popup.anchor = {
|
||||
getBoundingClientRect()
|
||||
@ -129,7 +138,6 @@ export class EgwMenuShoelace extends LitElement
|
||||
}
|
||||
};
|
||||
this.popup.active = true;
|
||||
document.body.append(this.popup);
|
||||
Promise.all([this.updateComplete, this.popup.updateComplete]).then(() =>
|
||||
{
|
||||
// Causes scroll issues if we don't position
|
||||
@ -138,15 +146,34 @@ export class EgwMenuShoelace extends LitElement
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the menu items with current disabled / visible settings
|
||||
*
|
||||
* @param _links
|
||||
*/
|
||||
public applyContext(_links)
|
||||
{
|
||||
Object.keys(_links).forEach((actionId) =>
|
||||
{
|
||||
const menuItem = <SlMenuItem>this.shadowRoot.querySelector("[data-action-id='" + actionId + "']");
|
||||
if(!menuItem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
menuItem.disabled = !_links[actionId].enabled;
|
||||
menuItem.hidden = !_links[actionId].visible;
|
||||
});
|
||||
}
|
||||
public hide()
|
||||
{
|
||||
if(this.popup)
|
||||
{
|
||||
this.popup.active = false;
|
||||
}
|
||||
|
||||
// egw_menu always creates a new menu
|
||||
this.remove();
|
||||
if(this.hideCallback)
|
||||
{
|
||||
this.hideCallback.call();
|
||||
}
|
||||
}
|
||||
|
||||
handleSelect(event)
|
||||
@ -230,14 +257,16 @@ export class EgwMenuShoelace extends LitElement
|
||||
{
|
||||
item.iconUrl = item.checked ? "toggle-on" : "toggle-off";
|
||||
}
|
||||
const id = CSS.escape(item.id);
|
||||
|
||||
return html`
|
||||
<sl-menu-item
|
||||
class=${classMap({
|
||||
"default-item": item.default
|
||||
})}
|
||||
id=${item.id}
|
||||
id=${id}
|
||||
type="${item.checkbox ? "checkbox" : "normal"}"
|
||||
data-action-id="${item.id}"
|
||||
?checked=${item.checkbox && item.checked}
|
||||
?disabled=${!item.enabled}
|
||||
.value=${item}
|
||||
|
@ -116,10 +116,24 @@ export class EgwPopupActionImplementation implements EgwActionImplementation {
|
||||
_context = {"posx": x, "posy": y};
|
||||
}
|
||||
|
||||
const menu = this._buildMenu(_links, _selected, _target);
|
||||
menu.showAt(_context.posx, _context.posy);
|
||||
let menu = null;
|
||||
// Special handling for nextmatch context menu - reuse the same menu
|
||||
if(!_target && !_context.menu && _selected[0].parent.manager.data.menu)
|
||||
{
|
||||
menu = _selected[0].parent.manager.data.menu
|
||||
}
|
||||
if(!menu)
|
||||
{
|
||||
menu = this._buildMenu(_links, _selected, _target);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.applyContext(_links, _selected, _target);
|
||||
}
|
||||
|
||||
return true;
|
||||
menu.showAt(_context.posx, _context.posy);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
const defaultAction = this._getDefaultLink(_links);
|
||||
if (defaultAction) {
|
||||
@ -303,6 +317,13 @@ export class EgwPopupActionImplementation implements EgwActionImplementation {
|
||||
*/
|
||||
private _registerContext = (_node, _callback, _context) => {
|
||||
|
||||
// Special handling for nextmatch: only build the menu once and just re-use it.
|
||||
if(!_context.menu && _context.actionLinks && _context.parent?.manager?.data?.nextmatch && !_context.parent.manager.data.menu)
|
||||
{
|
||||
_context.parent.manager.data.menu = this._buildMenu(_context.actionLinks.filter(l => l.actionObj.type == "popup"), [_context], null);
|
||||
_context.parent.manager.data.menu.showAt(0, 0);
|
||||
_context.parent.manager.data.menu.hide();
|
||||
}
|
||||
const contextHandler = (e) => {
|
||||
const x = _node
|
||||
//use different node and context for callback if event happens on parent
|
||||
@ -526,7 +547,7 @@ export class EgwPopupActionImplementation implements EgwActionImplementation {
|
||||
const tree = {"root": []};
|
||||
|
||||
// Automatically add in Drag & Drop actions
|
||||
if(this.auto_paste && !window.egwIsMobile() && !this._context.event?.type.match(/touch/))
|
||||
if(this.auto_paste && !window.egwIsMobile() && this._context?.event && !this._context.event?.type.match(/touch/))
|
||||
{
|
||||
this._addCopyPaste(_links, _selected);
|
||||
}
|
||||
@ -828,6 +849,7 @@ export class EgwPopupActionImplementation implements EgwActionImplementation {
|
||||
}
|
||||
};
|
||||
private _context: any;
|
||||
private menu : EgwMenu;
|
||||
|
||||
}
|
||||
|
||||
|
@ -9,15 +9,6 @@
|
||||
*
|
||||
*/
|
||||
import {EgwMenuShoelace} from "./EgwMenuShoelace";
|
||||
import {egw_registeredShortcuts, egw_shortcutIdx} from './egw_keymanager';
|
||||
import {
|
||||
EGW_KEY_ARROW_DOWN,
|
||||
EGW_KEY_ARROW_LEFT,
|
||||
EGW_KEY_ARROW_RIGHT,
|
||||
EGW_KEY_ARROW_UP,
|
||||
EGW_KEY_ENTER,
|
||||
EGW_KEY_ESCAPE
|
||||
} from "./egw_action_constants";
|
||||
|
||||
//Global variable which is used to store the currently active menu so that it
|
||||
//may be closed when another menu opens
|
||||
@ -160,7 +151,6 @@ export class egwMenu
|
||||
if (this.instance != null)
|
||||
{
|
||||
this.instance.hide();
|
||||
this.instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,18 +186,38 @@ export class egwMenu
|
||||
//Obtain a new egwMenuImpl object and pass this instance to it
|
||||
this.instance = new EgwMenuShoelace(this.children);
|
||||
|
||||
_egw_active_menu = this;
|
||||
|
||||
this.instance.showAt(_x, _y, () => {
|
||||
this.instance = null;
|
||||
_egw_active_menu = null;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
_egw_active_menu = this;
|
||||
|
||||
this.instance.showAt(_x, _y, () =>
|
||||
{
|
||||
_egw_active_menu = null;
|
||||
});
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable / disable menu items for the given selection & target
|
||||
*
|
||||
* @param _context
|
||||
* @param _links
|
||||
* @param _selected
|
||||
* @param _target
|
||||
* @private
|
||||
*/
|
||||
public applyContext(_links, _selected, _target)
|
||||
{
|
||||
if(!this.instance)
|
||||
{
|
||||
this.instance = new EgwMenuShoelace(this.children);
|
||||
}
|
||||
this.instance.applyContext(_links);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new menu item to the list and returns a reference to that object.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user