dees-catalog/ts_web/elements/dees-contextmenu.ts

190 lines
5.3 KiB
TypeScript
Raw Normal View History

2024-01-18 01:08:19 +00:00
import * as colors from './00colors.js';
2024-01-15 18:42:15 +00:00
import * as plugins from './00plugins.js';
2024-01-18 01:08:19 +00:00
import { demoFunc } from './dees-contextmenu.demo.js';
2023-01-12 17:14:59 +00:00
import {
customElement,
html,
DeesElement,
property,
2023-08-07 18:02:18 +00:00
type TemplateResult,
2023-01-12 17:14:59 +00:00
cssManager,
css,
2023-08-07 23:10:02 +00:00
type CSSResult,
2023-01-12 17:14:59 +00:00
unsafeCSS,
2023-08-07 17:13:29 +00:00
} from '@design.estate/dees-element';
2023-01-12 17:14:59 +00:00
2023-08-07 17:13:29 +00:00
import * as domtools from '@design.estate/dees-domtools';
2023-01-12 23:30:56 +00:00
import { DeesWindowLayer } from './dees-windowlayer.js';
2023-01-12 17:14:59 +00:00
declare global {
interface HTMLElementTagNameMap {
'dees-contextmenu': DeesContextmenu;
}
}
@customElement('dees-contextmenu')
export class DeesContextmenu extends DeesElement {
2023-01-12 23:30:56 +00:00
// DEMO
2023-09-09 11:34:46 +00:00
public static demo = demoFunc
2023-01-12 17:14:59 +00:00
2023-01-12 23:30:56 +00:00
// STATIC
2023-10-24 12:18:03 +00:00
// This will store all the accumulated menu items
public static contextMenuDeactivated = false;
public static accumulatedMenuItems: plugins.tsclass.website.IMenuItem[] = [];
// Add a global event listener for the right-click context menu
public static initializeGlobalListener() {
document.addEventListener('contextmenu', (event: MouseEvent) => {
if (this.contextMenuDeactivated) {
return;
}
event.preventDefault();
// Get the target element of the right-click
let target: EventTarget | null = event.target;
// Clear previously accumulated items
DeesContextmenu.accumulatedMenuItems = [];
// Traverse up the DOM tree to accumulate menu items
while (target) {
if ((target as any).getContextMenuItems) {
DeesContextmenu.accumulatedMenuItems.push(...(target as any).getContextMenuItems());
}
target = (target as Node).parentNode;
}
// Open the context menu with the accumulated items
DeesContextmenu.openContextMenuWithOptions(event, DeesContextmenu.accumulatedMenuItems);
});
}
// allows opening of a contextmenu with options
2023-01-13 01:15:30 +00:00
public static async openContextMenuWithOptions(eventArg: MouseEvent, menuItemsArg: plugins.tsclass.website.IMenuItem[]) {
2023-10-24 12:18:03 +00:00
if (this.contextMenuDeactivated) {
return;
}
2023-01-13 01:15:30 +00:00
eventArg.preventDefault();
2023-09-08 09:44:03 +00:00
eventArg.stopPropagation();
2023-01-12 23:30:56 +00:00
const contextMenu = new DeesContextmenu();
2023-09-12 23:37:02 +00:00
contextMenu.style.position = 'fixed';
2023-09-04 17:28:50 +00:00
contextMenu.style.zIndex = '2000';
2023-01-13 01:15:30 +00:00
contextMenu.style.top = `${eventArg.clientY.toString()}px`;
contextMenu.style.left = `${eventArg.clientX.toString()}px`;
contextMenu.style.opacity = '0';
contextMenu.style.transform = 'scale(0.95,0.95)';
contextMenu.style.transformOrigin = 'top left';
contextMenu.menuItems = menuItemsArg;
2023-09-04 17:28:50 +00:00
contextMenu.windowLayer = await DeesWindowLayer.createAndShow();
contextMenu.windowLayer.addEventListener('click', async () => {
await contextMenu.destroy();
})
2023-01-13 01:15:30 +00:00
document.body.append(contextMenu);
await domtools.plugins.smartdelay.delayFor(0);
contextMenu.style.opacity = '1';
contextMenu.style.transform = 'scale(1,1)';
2023-01-12 23:30:56 +00:00
}
2023-10-24 12:18:03 +00:00
// INSTANCE
2023-01-12 23:30:56 +00:00
@property({
type: Array,
})
public menuItems: plugins.tsclass.website.IMenuItem[] = [];
2023-09-04 17:28:50 +00:00
windowLayer: DeesWindowLayer;
2023-01-12 17:14:59 +00:00
constructor() {
super();
}
2023-10-24 12:18:03 +00:00
/**
* STATIC STYLES
*/
2023-01-12 17:14:59 +00:00
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
2023-01-13 01:15:30 +00:00
transition: all 0.1s;
2023-01-12 17:14:59 +00:00
}
.mainbox {
2023-01-12 23:30:56 +00:00
color: ${cssManager.bdTheme('#222', '#ccc')};
font-size: 14px;
width: 200px;
2024-01-18 01:08:19 +00:00
border: 1px solid ${cssManager.bdTheme('#fff', '#ffffff10')};
2023-09-09 11:34:46 +00:00
min-height: 34px;
2023-01-12 23:30:56 +00:00
border-radius: 3px;
2023-09-16 12:31:03 +00:00
background: ${cssManager.bdTheme('#fff', '#222')};
box-shadow: 0px 1px 4px ${cssManager.bdTheme('#00000020', '#000000')};
2023-01-12 23:30:56 +00:00
user-select: none;
2024-01-18 01:08:19 +00:00
padding: 4px;
2023-01-12 23:30:56 +00:00
}
.mainbox .menuitem {
2024-01-18 01:08:19 +00:00
padding: 4px 8px;
border-radius: 3px;
2023-01-12 23:30:56 +00:00
}
.mainbox .menuitem dees-icon {
display: inline-block;
margin-right: 8px;
width: 14px;
transform: translateY(2px);
2023-01-12 17:14:59 +00:00
}
2023-01-12 23:30:56 +00:00
.mainbox .menuitem:hover {
2024-01-18 01:08:19 +00:00
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
2023-01-12 23:30:56 +00:00
}
.mainbox .menuitem:active {
background: #ffffff05;
}
2023-01-12 17:14:59 +00:00
`,
];
public render(): TemplateResult {
return html`
<div class="mainbox">
2023-01-12 23:30:56 +00:00
${this.menuItems.map((menuItemArg) => {
return html`
2023-01-13 01:15:30 +00:00
<div class="menuitem" @click=${() => this.handleClick(menuItemArg)}>
2023-01-12 23:30:56 +00:00
<dees-icon .iconFA=${(menuItemArg.iconName as any) || 'minus'}></dees-icon
>${menuItemArg.name}
</div>
`;
})}
2023-09-09 11:34:46 +00:00
${this.menuItems.length === 0 ? html`
<div class="menuitem" @click=${() => {
2023-10-24 12:18:03 +00:00
DeesContextmenu.contextMenuDeactivated = true;
this.destroy();
2023-09-09 11:34:46 +00:00
}}>
<dees-icon .iconFA=${'xmark'}></dees-icon
2024-01-21 00:12:57 +00:00
>allow native context
2023-09-09 11:34:46 +00:00
</div>
` : html``}
2023-01-12 17:14:59 +00:00
</div>
`;
}
public async firstUpdated() {
2023-09-09 11:34:46 +00:00
2023-01-12 17:14:59 +00:00
}
2023-01-13 01:15:30 +00:00
public async handleClick(menuItem: plugins.tsclass.website.IMenuItem) {
menuItem.action();
await this.destroy();
}
public async destroy() {
2023-09-04 17:28:50 +00:00
if (this.windowLayer) {
this.windowLayer.destroy();
}
2023-01-13 01:15:30 +00:00
this.style.opacity = '0';
this.style.transform = 'scale(0.95,0,95)';
await domtools.plugins.smartdelay.delayFor(100);
this.parentElement.removeChild(this);
}
2023-01-12 17:14:59 +00:00
}
2023-10-24 12:18:03 +00:00
DeesContextmenu.initializeGlobalListener();