lowcode-engine/packages/shell/src/model/document-model.ts

381 lines
10 KiB
TypeScript
Raw Normal View History

2022-01-25 15:30:17 +08:00
import {
2023-01-12 11:37:22 +08:00
IDocumentModel as InnerDocumentModel,
INode as InnerNode,
2022-01-25 15:30:17 +08:00
} from '@alilc/lowcode-designer';
2022-03-30 15:08:26 +08:00
import {
2022-12-22 12:10:00 +08:00
IPublicEnumTransformStage,
IPublicTypeRootSchema,
2022-03-30 15:08:26 +08:00
GlobalEvent,
IPublicModelDocumentModel,
2023-01-05 16:54:11 +08:00
IPublicTypeOnChangeOptions,
2022-12-22 12:10:00 +08:00
IPublicTypeDragNodeObject,
IPublicTypeDragNodeDataObject,
IPublicModelNode,
IPublicModelSelection,
IPublicModelDetecting,
IPublicModelHistory,
IPublicApiProject,
IPublicModelModalNodesManager,
2022-12-22 12:10:00 +08:00
IPublicTypePropChangeOptions,
IPublicModelDropLocation,
IPublicApiCanvas,
IPublicTypeDisposable,
2023-01-12 11:37:22 +08:00
IPublicModelEditor,
2023-02-27 19:59:54 +08:00
IPublicTypeNodeSchema,
2022-03-30 15:08:26 +08:00
} from '@alilc/lowcode-types';
2023-01-12 11:37:22 +08:00
import { isDragNodeObject } from '@alilc/lowcode-utils';
import { Node as ShellNode } from './node';
import { Selection as ShellSelection } from './selection';
import { Detecting as ShellDetecting } from './detecting';
import { History as ShellHistory } from './history';
import { DropLocation as ShellDropLocation } from './drop-location';
import { Project as ShellProject, Canvas as ShellCanvas } from '../api';
import { Prop as ShellProp } from './prop';
2022-12-22 12:10:00 +08:00
import { ModalNodesManager } from './modal-nodes-manager';
import { documentSymbol, editorSymbol, nodeSymbol } from '../symbols';
const shellDocSymbol = Symbol('shellDocSymbol');
2022-12-22 12:10:00 +08:00
export class DocumentModel implements IPublicModelDocumentModel {
2022-01-25 15:30:17 +08:00
private readonly [documentSymbol]: InnerDocumentModel;
2023-01-12 11:37:22 +08:00
private readonly [editorSymbol]: IPublicModelEditor;
private _focusNode: IPublicModelNode | null;
selection: IPublicModelSelection;
detecting: IPublicModelDetecting;
history: IPublicModelHistory;
2023-01-05 16:54:11 +08:00
2022-12-22 12:10:00 +08:00
/**
* @deprecated use canvas API instead
2022-12-22 12:10:00 +08:00
*/
canvas: IPublicApiCanvas;
2022-01-25 15:30:17 +08:00
constructor(document: InnerDocumentModel) {
this[documentSymbol] = document;
2023-01-12 11:37:22 +08:00
this[editorSymbol] = document.designer?.editor as IPublicModelEditor;
this.selection = new ShellSelection(document);
this.detecting = new ShellDetecting(document);
this.history = new ShellHistory(document);
this.canvas = new ShellCanvas(this[editorSymbol]);
2022-03-30 15:08:26 +08:00
2023-01-12 11:37:22 +08:00
this._focusNode = ShellNode.create(this[documentSymbol].focusNode);
2022-01-25 15:30:17 +08:00
}
static create(document: InnerDocumentModel | undefined | null): IPublicModelDocumentModel | null {
if (!document) {
return null;
}
// @ts-ignore 直接返回已挂载的 shell doc 实例
if (document[shellDocSymbol]) {
return (document as any)[shellDocSymbol];
}
const shellDoc = new DocumentModel(document);
// @ts-ignore 直接返回已挂载的 shell doc 实例
document[shellDocSymbol] = shellDoc;
return shellDoc;
2022-01-25 15:30:17 +08:00
}
/**
* id
*/
get id(): string {
return this[documentSymbol].id;
}
2022-05-26 14:54:41 +08:00
set id(id) {
this[documentSymbol].id = id;
}
2022-01-25 15:30:17 +08:00
/**
* project
* @returns
*/
get project(): IPublicApiProject {
2023-04-13 11:33:39 +08:00
return ShellProject.create(this[documentSymbol].project, true);
2022-01-25 15:30:17 +08:00
}
/**
*
* root node of this documentModel
2022-01-25 15:30:17 +08:00
* @returns
*/
get root(): IPublicModelNode | null {
2023-01-12 11:37:22 +08:00
return ShellNode.create(this[documentSymbol].rootNode);
2022-01-25 15:30:17 +08:00
}
get focusNode(): IPublicModelNode | null {
return this._focusNode || this.root;
2022-03-30 15:08:26 +08:00
}
set focusNode(node: IPublicModelNode | null) {
2022-03-30 15:08:26 +08:00
this._focusNode = node;
2022-12-22 12:10:00 +08:00
this[editorSymbol].eventBus.emit(
'shell.document.focusNodeChanged',
2022-12-22 12:10:00 +08:00
{ document: this, focusNode: node },
);
2022-03-30 15:08:26 +08:00
}
2022-01-25 15:30:17 +08:00
/**
* Map, key nodeId
* get map of all nodes , using node.id as key
2022-01-25 15:30:17 +08:00
*/
get nodesMap(): Map<string, IPublicModelNode> {
const map = new Map<string, IPublicModelNode>();
2022-01-25 15:30:17 +08:00
for (let id of this[documentSymbol].nodesMap.keys()) {
map.set(id, this.getNodeById(id)!);
}
return map;
}
/**
*
*/
get modalNodesManager(): IPublicModelModalNodesManager | null {
2022-01-25 15:30:17 +08:00
return ModalNodesManager.create(this[documentSymbol].modalNodesManager);
}
get dropLocation(): IPublicModelDropLocation | null {
2023-01-12 11:37:22 +08:00
return ShellDropLocation.create(this[documentSymbol].dropLocation);
2022-03-30 15:08:26 +08:00
}
2022-12-22 12:10:00 +08:00
set dropLocation(loc: IPublicModelDropLocation | null) {
this[documentSymbol].dropLocation = loc;
}
2023-01-05 16:54:11 +08:00
2022-01-25 15:30:17 +08:00
/**
* nodeId Node
* get node instance by nodeId
* @param {string} nodeId
2022-01-25 15:30:17 +08:00
*/
getNodeById(nodeId: string): IPublicModelNode | null {
2023-01-12 11:37:22 +08:00
return ShellNode.create(this[documentSymbol].getNode(nodeId));
2022-01-25 15:30:17 +08:00
}
/**
* schema
* @param schema
*/
2022-12-22 12:10:00 +08:00
importSchema(schema: IPublicTypeRootSchema): void {
2022-01-25 15:30:17 +08:00
this[documentSymbol].import(schema);
this[editorSymbol].eventBus.emit('shell.document.importSchema', schema);
2022-01-25 15:30:17 +08:00
}
/**
* schema
* @param stage
* @returns
*/
2022-12-22 12:10:00 +08:00
exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render): any {
2022-01-25 15:30:17 +08:00
return this[documentSymbol].export(stage);
}
/**
*
* @param parent
* @param thing
* @param at
* @param copy
* @returns
*/
insertNode(
parent: IPublicModelNode,
thing: IPublicModelNode,
2022-01-25 15:30:17 +08:00
at?: number | null | undefined,
copy?: boolean | undefined,
): IPublicModelNode | null {
2022-01-25 15:30:17 +08:00
const node = this[documentSymbol].insertNode(
(parent as any)[nodeSymbol] ? (parent as any)[nodeSymbol] : parent,
(thing as any)?.[nodeSymbol] ? (thing as any)[nodeSymbol] : thing,
2022-01-25 15:30:17 +08:00
at,
copy,
);
2023-01-12 11:37:22 +08:00
return ShellNode.create(node);
2022-01-25 15:30:17 +08:00
}
/**
*
* @param data
* @returns
*/
createNode<IPublicModelNode>(data: IPublicTypeNodeSchema): IPublicModelNode | null {
2023-01-12 11:37:22 +08:00
return ShellNode.create(this[documentSymbol].createNode(data));
2022-01-25 15:30:17 +08:00
}
/**
* /id
* @param idOrNode
*/
removeNode(idOrNode: string | IPublicModelNode): void {
2022-01-25 15:30:17 +08:00
this[documentSymbol].removeNode(idOrNode as any);
}
/**
* componentsMap of documentModel
* @param extraComps
* @returns
*/
getComponentsMap(extraComps?: string[]): any {
return this[documentSymbol].getComponentsMap(extraComps);
}
/**
*
* @param dropTarget
* @param dragObject
* @returns boolean
*/
checkNesting(
dropTarget: IPublicModelNode,
2022-12-22 12:10:00 +08:00
dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject,
): boolean {
let innerDragObject = dragObject;
if (isDragNodeObject(dragObject)) {
innerDragObject.nodes = innerDragObject.nodes?.map(
(node: IPublicModelNode) => ((node as any)[nodeSymbol] || node),
);
}
return this[documentSymbol].checkNesting(
((dropTarget as any)[nodeSymbol] || dropTarget) as any,
innerDragObject as any,
);
}
2022-01-25 15:30:17 +08:00
/**
* document
*/
onAddNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable {
2022-03-30 15:08:26 +08:00
return this[documentSymbol].onNodeCreate((node: InnerNode) => {
2023-01-12 11:37:22 +08:00
fn(ShellNode.create(node)!);
2022-01-25 15:30:17 +08:00
});
}
/**
* document document
*/
onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable {
2022-12-22 12:10:00 +08:00
this[editorSymbol].eventBus.on('node.add', fn as any);
return () => {
2022-12-22 12:10:00 +08:00
this[editorSymbol].eventBus.off('node.add', fn as any);
};
}
2022-01-25 15:30:17 +08:00
/**
* document
*/
onRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable {
2022-03-30 15:08:26 +08:00
return this[documentSymbol].onNodeDestroy((node: InnerNode) => {
2023-01-12 11:37:22 +08:00
fn(ShellNode.create(node)!);
2022-01-25 15:30:17 +08:00
});
}
/**
* document hover
*/
onChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable {
return this[documentSymbol].designer.detecting.onDetectingChange((node: InnerNode) => {
2023-01-12 11:37:22 +08:00
fn(ShellNode.create(node)!);
2022-01-25 15:30:17 +08:00
});
}
/**
* document
*/
onChangeSelection(fn: (ids: string[]) => void): IPublicTypeDisposable {
return this[documentSymbol].selection.onSelectionChange((ids: string[]) => {
2022-01-25 15:30:17 +08:00
fn(ids);
});
}
/**
* document
* @param fn
*/
onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable {
2023-02-27 19:59:54 +08:00
return this[documentSymbol].onChangeNodeVisible((node: InnerNode, visible: boolean) => {
2023-01-12 11:37:22 +08:00
fn(ShellNode.create(node)!, visible);
2022-01-25 15:30:17 +08:00
});
}
/**
* document children
* @param fn
*/
onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable {
return this[documentSymbol].onChangeNodeChildren((info?: IPublicTypeOnChangeOptions<InnerNode>) => {
if (!info) {
return;
}
fn({
type: info.type,
2023-01-12 11:37:22 +08:00
node: ShellNode.create(info.node)!,
2022-01-25 15:30:17 +08:00
});
});
}
/**
* document
* @param fn
*/
onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable {
const callback = (info: GlobalEvent.Node.Prop.ChangeOptions) => {
fn({
key: info.key,
oldValue: info.oldValue,
newValue: info.newValue,
prop: ShellProp.create(info.prop)!,
node: ShellNode.create(info.node as any)!,
});
};
2022-01-25 15:30:17 +08:00
this[editorSymbol].on(
GlobalEvent.Node.Prop.InnerChange,
callback,
2022-01-25 15:30:17 +08:00
);
return () => {
this[editorSymbol].off(
GlobalEvent.Node.Prop.InnerChange,
callback,
);
};
2022-01-25 15:30:17 +08:00
}
/**
* import schema event
* @param fn
*/
onImportSchema(fn: (schema: IPublicTypeRootSchema) => void): IPublicTypeDisposable {
return this[editorSymbol].eventBus.on('shell.document.importSchema', fn as any);
2022-12-22 12:10:00 +08:00
}
isDetectingNode(node: IPublicModelNode): boolean {
return this.detecting.current === node;
}
onFocusNodeChanged(
fn: (doc: IPublicModelDocumentModel, focusNode: IPublicModelNode) => void,
): IPublicTypeDisposable {
if (!fn) {
return () => {};
}
return this[editorSymbol].eventBus.on(
'shell.document.focusNodeChanged',
(payload) => {
const { document, focusNode } = payload;
fn(document, focusNode);
},
);
}
onDropLocationChanged(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable {
if (!fn) {
return () => {};
}
return this[editorSymbol].eventBus.on(
'document.dropLocation.changed',
(payload) => {
const { document } = payload;
fn(document);
},
);
}
2022-01-25 15:30:17 +08:00
}