Files
bim_engine/src/managers/right-key-manager.ts

103 lines
3.4 KiB
TypeScript
Raw Normal View History

import { BimComponent } from '../core/component';
import { BimEngine } from '../bim-engine';
import { BimRightKey } from '../components/right-key';
import { BimMenu } from '../components/menu';
import { MenuItemConfig } from '../components/menu/item';
/**
* (RightKeyManager)
*
* 1. Canvas/ contextmenu
* 2. (Handler)
* 3. Menu RightKey
*/
export class RightKeyManager extends BimComponent {
private container: HTMLElement;
private rightKeyPanel: BimRightKey;
// 存储注册的上下文处理器
// 每个处理器接收鼠标事件,返回一组菜单项(如果没有对应菜单则返回 null
private contextHandlers: Array<(e: MouseEvent) => MenuItemConfig[] | null> = [];
constructor(engine: BimEngine, container: HTMLElement) {
super(engine);
this.container = container;
// 初始化右键容器,设置极高的层级以覆盖所有 UI
// 将事件监听和触发逻辑下放给 BimRightKey 组件
this.rightKeyPanel = new BimRightKey({
zIndex: 9000,
container: this.container,
onContext: this.handleContextMenu
});
this.rightKeyPanel.init();
}
public destroy(): void {
this.rightKeyPanel.destroy();
}
/**
*
* @param handler
*/
public registerHandler(handler: (e: MouseEvent) => MenuItemConfig[] | null): void {
this.contextHandlers.push(handler);
}
/**
*
*
* @param x X
* @param y Y
* @param items
* @param groupOrder
*/
public showMenu(x: number, y: number, items: MenuItemConfig[], groupOrder?: string[]): void {
if (!items || items.length === 0) return;
// 1. 创建菜单内容组件
const menu = new BimMenu({ items, groupOrder });
menu.init(); // 必须初始化以生成 DOM
// 2. 将菜单挂载到右键容器
this.rightKeyPanel.mount(menu);
// 3. 显示容器
this.rightKeyPanel.show(x, y);
}
/**
*
*/
public hide(): void {
this.rightKeyPanel.hide();
}
/**
*
* BimRightKey
*/
private handleContextMenu = (e: MouseEvent): void => {
// 1. 确定上下文项
// 遍历所有注册的处理器,找到第一个返回非空结果的处理器
// 这种责任链模式允许插件优先处理特定对象的右键
let items: MenuItemConfig[] | null = null;
for (const handler of this.contextHandlers) {
const result = handler(e);
if (result && result.length > 0) {
if (!items) items = [];
items = items.concat(result);
}
}
// 2. 如果有菜单项,则显示
if (items && items.length > 0) {
this.showMenu(e.clientX, e.clientY, items);
} else {
// 如果没有任何内容,则关闭可能存在的菜单
this.hide();
}
};
}