@turbox3d/command-manager
Version:
Large-scale productivity application command management library
84 lines (74 loc) • 2.93 kB
text/typescript
import { ViewEntity, SceneEvent, EventType } from '@turbox3d/event-manager';
import { CommandManager } from './CommandManager';
import { Interaction } from './Interaction';
import { SceneTool } from './type';
export abstract class Command extends Interaction {
protected $children: { [key: string]: Command } = {};
private activeChildren: Command[] = [];
constructor(protected holder: CommandManager, private parent?: Command) {
super();
const activeFunc = this.active.bind(this);
const disposeFunc = this.dispose.bind(this);
this.active = (...args) => {
if (this.parent && !this.holder.isCommandActive(this)) {
// 仅作为激活的子 Command 记录在父 Command 上
this.parent.onChildActive(this);
}
// 先执行自定义的 active 的相关工作
activeFunc(...args);
};
this.dispose = (...args) => {
// 如果自身是应用在 Mgr 上的 Command,则要清理掉
if (this.holder.isCommandActive(this)) {
this.holder.clearCommand();
} else {
// 将自己改为注销状态
this.parent?.onChildDispose(this);
}
// 便利激活的子节点,置为注销状态
[...this.activeChildren].forEach(child => child.dispose(...args));
// 处理自定义工作
disposeFunc(...args);
};
}
/**
* 应用当前 Command 及其子级,该方法不仅会强制激活当前 Command 及其子级,还会使它们的交互事件生效
* 同时只能有一个 Command 节点处于应用状态(兄弟节点的交互事件是互斥的)
* 永远不用重写该方法,相关初始化逻辑请在 active 接口中编码
*/
apply(...args: any[]) {
this.holder.toggleCommand(this);
this.active(...args);
}
/**
* 激活当前 Command 及其子级,为即将到来的交互事件做好准备
*/
active(...args: any[]): void {
// 将子 command 也激活
Object.values(this.$children).forEach(command => command.active(...args));
}
/**
* 注销当前 Command 及其子级,同时将停止响应该指令及子级的交互事件
*/
dispose(...args: any[]) {
//
}
distributeEvent(eventType: EventType, ev: ViewEntity, event: SceneEvent, tools: SceneTool) {
// step 1 先让子 Commands 处理事件
// Object.values(this.$children).forEach(command => command.distributeEvent(eventType, ev, event));
this.activeChildren.forEach(command => command.distributeEvent(eventType, ev, event, tools));
// step2 自身处理事件
this.distributeToSelf(eventType, ev, event, tools);
}
private onChildActive(command: Command) {
if (this.activeChildren.indexOf(command) === -1) {
this.activeChildren.push(command);
}
}
private onChildDispose(command: Command) {
const index = this.activeChildren.indexOf(command);
if (index !== -1) {
this.activeChildren.splice(index, 1);
}
}
}