import type { Able, AblePayload, AbleRegistry } from './able'; import type { AbleManager } from './able-manager'; import type { Entity } from './entity'; import type { EntityData, EntityDataRegistry } from './entity-data'; import { Disposable, DisposableImpl, Emitter } from '@gedit/utils'; import { getHandleParams } from './playground-decorator-helper'; type AbleTypes = string[]; export interface AbleChangedEvent { type: 'delete' | 'add' | 'update' ableTypes: AbleTypes entity: Entity } export class EntityAbles extends DisposableImpl { protected readonly ables: Map = new Map(); protected readonly ableIndex: WeakMap = new WeakMap(); /** * data数据和able的绑定数目关系, 当绑定able为空时,则自动删除entityData */ protected readonly dataBinds: Map = new Map(); protected onAbleChangedEmiter = new Emitter(); private _pauseChangedTimes = 0; readonly onAbleChanged = this.onAbleChangedEmiter.event; private _index = 0; constructor( protected entity: Entity, protected ableManager: AbleManager ) { super(); this.toDispose.push(this.onAbleChangedEmiter); this.pauseChanged = false; } /** * 暂停更新开关 */ protected get pauseChanged(): boolean { return this._pauseChangedTimes > 0; } protected set pauseChanged(pauseChanged) { this._pauseChangedTimes = pauseChanged ? (this._pauseChangedTimes + 1) : (this._pauseChangedTimes - 1); if (this._pauseChangedTimes < 0) this._pauseChangedTimes = 0; } add(Registry: AbleRegistry): Able { this.ableManager.registerAble(Registry); if (this.ables.has(Registry.type)) return this.ables.get(Registry.type)!; const params = getHandleParams(Registry); const datas: EntityData[] = params.map(r => { this.dataBinds.set(r, (this.dataBinds.get(r) || 0) + 1); return this.entity.addData(r); }); const newAble = this.ableManager.createAble(Registry, this.entity); // 关联的数据改变则触发able事件 newAble.toDispose.pushAll(datas.map(d => d.onDataChanged(() => { this.fireChanged('update', [Registry.type]); }))); newAble.toDispose.push(Disposable.create(() => { this.ables.delete(Registry.type); this.ableIndex.delete(newAble); })); this.ableIndex.set(newAble, this._index++); this.ables.set(Registry.type, newAble); this.fireChanged('add', [Registry.type]); return newAble; } remove(Registry: AbleRegistry): void { const able = this.ables.get(Registry.type); if (!able) return; able.dispose(); const params = getHandleParams(Registry); params.forEach(r => { const bindCount = this.dataBinds.get(r); if (!bindCount || bindCount <= 0) return; if (bindCount === 1) { this.entity.removeData(r); } this.dataBinds.set(r, bindCount - 1); }); this.fireChanged('delete', [Registry.type]); } has(able: AbleRegistry): boolean { return this.ables.has(able.type); } get(able: AbleRegistry): Able | undefined { return this.ables.get(able.type); } protected handle(able: Able, payload: AblePayload): AblePayload { this.entity.onBeforeAbleDispatchedEmitter.fire(able); if (able.before) { payload = able.before(payload); if (payload === undefined) return; } const entitDatas = getHandleParams(this.ableManager.getRegistryByType(able.type)!).map(Registry => this.entity.getData(Registry)!); able.payload = payload; able.handle(...entitDatas, payload); if (able.after) able.after(payload); this.entity.onAfterAbleDispatchedEmitter.fire(able); return payload; } toJSON(): string[] { const arr: string[] = []; for (const able of this.ables.values()) { arr.push(able.type); } return arr; } fromJSON(arr?: string[]): void { if (!arr || !Array.isArray(arr)) return; this.pauseChanged = true; const addChangeTypes: AbleTypes = []; const removeChangeTypes: AbleTypes = []; this.reset(); for (const ableType of this.ables.keys()) { if (!arr.includes(ableType)) { this.remove(this.ableManager.getRegistryByType(ableType)!); removeChangeTypes.push(ableType); } } arr.forEach(type => { const registry = this.ableManager.getRegistryByType(type); if (!registry) return; let able: Able | undefined = this.get(registry); if (!able) { able = this.add(registry); addChangeTypes.push(type); } }); this.pauseChanged = false; this.fireChanged('add', addChangeTypes); this.fireChanged('delete', removeChangeTypes); } reset(): void { for (const type of this.ables.keys()) { this.remove(this.ableManager.getRegistryByType(type)!); } } dispose(): void { this.reset(); super.dispose(); } fireChanged(type: AbleChangedEvent['type'], ableTypes: AbleTypes): void { if (ableTypes.length === 0 || this.pauseChanged) return; this.onAbleChangedEmiter.fire({ type, entity: this.entity, ableTypes, }); } dispatchAbles

(ables: AbleRegistry[], payload: P): AblePayload { ables .filter(r => this.has(r)) .map(r => this.get(r)) // 这里按照able的加入顺序进行排序,形成执行管道 .sort((r1, r2) => this.ableIndex.get(r1 as Able)! - this.ableIndex.get(r2 as Able)! ) .forEach((able: Able) => { payload = this.handle(able, payload); }); return payload; } }