185 lines
5.3 KiB
TypeScript

import { isLocationChildrenDetail } from '@alilc/lowcode-utils';
import { IPublicModelPluginContext, IPublicTypeActiveTarget, IPublicModelNode, IPublicTypeDisposable, IPublicEnumPluginRegisterLevel } from '@alilc/lowcode-types';
import TreeNode from './tree-node';
import { Tree } from './tree';
import EventEmitter from 'events';
import { enUS, zhCN } from '../locale';
import { ReactNode } from 'react';
export interface ITreeBoard {
readonly at: string | symbol;
scrollToNode(treeNode: TreeNode, detail?: any): void;
}
enum EVENT_NAMES {
pluginContextChanged = 'pluginContextChanged',
}
export interface IOutlinePanelPluginContext extends IPublicModelPluginContext {
extraTitle?: string;
intlNode(id: string, params?: object): ReactNode;
intl(id: string, params?: object): string;
getLocale(): string;
}
export class TreeMaster {
pluginContext: IOutlinePanelPluginContext;
private boards = new Set<ITreeBoard>();
private treeMap = new Map<string, Tree>();
private disposeEvents: (IPublicTypeDisposable | undefined)[] = [];
event = new EventEmitter();
constructor(pluginContext: IPublicModelPluginContext, readonly options: {
extraTitle?: string;
}) {
this.setPluginContext(pluginContext);
const { workspace } = this.pluginContext;
this.initEvent();
if (pluginContext.registerLevel === IPublicEnumPluginRegisterLevel.Workspace) {
this.setPluginContext(workspace.window?.currentEditorView);
let dispose: IPublicTypeDisposable | undefined;
const windowViewTypeChangeEvent = () => {
dispose = workspace.window?.onChangeViewType(() => {
this.setPluginContext(workspace.window?.currentEditorView);
});
};
windowViewTypeChangeEvent();
workspace.onChangeActiveWindow(() => {
windowViewTypeChangeEvent();
this.setPluginContext(workspace.window?.currentEditorView);
dispose && dispose();
});
}
}
private setPluginContext(pluginContext: IPublicModelPluginContext | undefined | null) {
if (!pluginContext) {
return;
}
const { intl, intlNode, getLocale } = pluginContext.common.utils.createIntl({
'en-US': enUS,
'zh-CN': zhCN,
});
let _pluginContext: IOutlinePanelPluginContext = Object.assign(pluginContext, {
intl,
intlNode,
getLocale,
});
_pluginContext.extraTitle = this.options && this.options['extraTitle'];
this.pluginContext = _pluginContext;
this.disposeEvent();
this.initEvent();
this.emitPluginContextChange();
}
private disposeEvent() {
this.disposeEvents.forEach(d => {
d && d();
});
}
private initEvent() {
let startTime: any;
const { event, project, canvas } = this.pluginContext;
const setExpandByActiveTracker = (target: IPublicTypeActiveTarget) => {
const { node, detail } = target;
const tree = this.currentTree;
if (!tree/* || node.document !== tree.document */) {
return;
}
const treeNode = tree.getTreeNode(node);
if (detail && isLocationChildrenDetail(detail)) {
treeNode.expand(true);
} else {
treeNode.expandParents();
}
this.boards.forEach((board) => {
board.scrollToNode(treeNode, detail);
});
};
this.disposeEvents = [
canvas.dragon?.onDragstart(() => {
startTime = Date.now() / 1000;
// needs?
this.toVision();
}),
canvas.activeTracker?.onChange(setExpandByActiveTracker),
canvas.dragon?.onDragend(() => {
const endTime: any = Date.now() / 1000;
const nodes = project.currentDocument?.selection?.getNodes();
event.emit('outlinePane.dragend', {
selected: nodes
?.map((n) => {
if (!n) {
return;
}
const npm = n?.componentMeta?.npm;
return (
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') || n?.componentMeta?.componentName
);
})
.join('&'),
time: (endTime - startTime).toFixed(2),
});
}),
project.onRemoveDocument((data: {id: string}) => {
const { id } = data;
this.treeMap.delete(id);
}),
];
if (canvas.activeTracker?.target) {
setExpandByActiveTracker(canvas.activeTracker?.target);
}
}
private toVision() {
const tree = this.currentTree;
if (tree) {
const selection = this.pluginContext.project.getCurrentDocument()?.selection;
selection?.getTopNodes().forEach((node: IPublicModelNode) => {
tree.getTreeNode(node).setExpanded(false);
});
}
}
addBoard(board: ITreeBoard) {
this.boards.add(board);
}
removeBoard(board: ITreeBoard) {
this.boards.delete(board);
}
purge() {
// todo others purge
}
onPluginContextChange(fn: () => void) {
this.event.on(EVENT_NAMES.pluginContextChanged, fn);
}
emitPluginContextChange() {
this.event.emit(EVENT_NAMES.pluginContextChanged);
}
get currentTree(): Tree | null {
const doc = this.pluginContext.project.getCurrentDocument();
if (doc) {
const { id } = doc;
if (this.treeMap.has(id)) {
return this.treeMap.get(id)!;
}
const tree = new Tree(this);
this.treeMap.set(id, tree);
return tree;
}
return null;
}
}