feat: 补充 simulator-host 模块以及部分注释

This commit is contained in:
lihao.ylh 2021-12-21 20:45:23 +08:00
parent 9a4da20bf0
commit 81731866e1
7 changed files with 320 additions and 59 deletions

View File

@ -19,13 +19,13 @@ export class NodeChildren {
constructor(readonly owner: ParentalNode, data: NodeData | NodeData[], options: any = {}) { constructor(readonly owner: ParentalNode, data: NodeData | NodeData[], options: any = {}) {
makeObservable(this); makeObservable(this);
this.children = (Array.isArray(data) ? data : [data]).map(child => { this.children = (Array.isArray(data) ? data : [data]).map((child) => {
return this.owner.document.createNode(child, options.checkId); return this.owner.document.createNode(child, options.checkId);
}); });
} }
internalInitParent() { internalInitParent() {
this.children.forEach(child => child.internalSetParent(this.owner)); this.children.forEach((child) => child.internalSetParent(this.owner));
} }
/** /**
@ -33,7 +33,7 @@ export class NodeChildren {
*/ */
export(stage: TransformStage = TransformStage.Save): NodeData[] { export(stage: TransformStage = TransformStage.Save): NodeData[] {
stage = compatStage(stage); stage = compatStage(stage);
return this.children.map(node => { return this.children.map((node) => {
const data = node.export(stage); const data = node.export(stage);
if (node.isLeaf() && TransformStage.Save === stage) { if (node.isLeaf() && TransformStage.Save === stage) {
// FIXME: filter empty // FIXME: filter empty
@ -47,7 +47,7 @@ export class NodeChildren {
data = data ? (Array.isArray(data) ? data : [data]) : []; data = data ? (Array.isArray(data) ? data : [data]) : [];
const originChildren = this.children.slice(); const originChildren = this.children.slice();
this.children.forEach(child => child.internalSetParent(null)); this.children.forEach((child) => child.internalSetParent(null));
const children = new Array<Node>(data.length); const children = new Array<Node>(data.length);
for (let i = 0, l = data.length; i < l; i++) { for (let i = 0, l = data.length; i < l; i++) {
@ -134,12 +134,20 @@ export class NodeChildren {
delete(node: Node, purge = false, useMutator = true, options: NodeRemoveOptions = {}): boolean { delete(node: Node, purge = false, useMutator = true, options: NodeRemoveOptions = {}): boolean {
node.internalPurgeStart(); node.internalPurgeStart();
if (node.isParental()) { if (node.isParental()) {
foreachReverse(node.children, (subNode: Node) => { foreachReverse(
subNode.remove(useMutator, purge, options); node.children,
}, (iterable, idx) => (iterable as NodeChildren).get(idx)); (subNode: Node) => {
foreachReverse(node.slots, (slotNode: Node) => { subNode.remove(useMutator, purge, options);
slotNode.remove(useMutator, purge); },
}, (iterable, idx) => (iterable as [])[idx]); (iterable, idx) => (iterable as NodeChildren).get(idx),
);
foreachReverse(
node.slots,
(slotNode: Node) => {
slotNode.remove(useMutator, purge);
},
(iterable, idx) => (iterable as [])[idx],
);
} }
// 需要在从 children 中删除 node 前记录下 indexinternalSetParent 中会执行删除(unlink)操作 // 需要在从 children 中删除 node 前记录下 indexinternalSetParent 中会执行删除(unlink)操作
const i = this.children.indexOf(node); const i = this.children.indexOf(node);
@ -164,7 +172,13 @@ export class NodeChildren {
node, node,
}); });
if (useMutator) { if (useMutator) {
this.reportModified(node, this.owner, { type: 'remove', propagated: false, isSubDeleting: this.owner.isPurging, removeIndex: i, removeNode: node }); this.reportModified(node, this.owner, {
type: 'remove',
propagated: false,
isSubDeleting: this.owner.isPurging,
removeIndex: i,
removeNode: node,
});
} }
// purge 为 true 时,已在 internalSetParent 中删除了子节点 // purge 为 true 时,已在 internalSetParent 中删除了子节点
if (i > -1 && !purge) { if (i > -1 && !purge) {
@ -183,10 +197,11 @@ export class NodeChildren {
const i = children.indexOf(node); const i = children.indexOf(node);
if (node.parent) { if (node.parent) {
globalContext.has('editor') && globalContext.get('editor').emit('node.remove.topLevel', { globalContext.has('editor') &&
node, globalContext.get('editor').emit('node.remove.topLevel', {
index: node.index, node,
}); index: node.index,
});
} }
if (i < 0) { if (i < 0) {
@ -332,7 +347,11 @@ export class NodeChildren {
return this.children.find(fn); return this.children.find(fn);
} }
mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) { mergeChildren(
remover: (node: Node, idx: number) => boolean,
adder: (children: Node[]) => NodeData[] | null,
sorter: (firstNode: Node, secondNode: Node) => number,
) {
let changed = false; let changed = false;
if (remover) { if (remover) {
const willRemove = this.children.filter(remover); const willRemove = this.children.filter(remover);

View File

@ -13,7 +13,7 @@ import Detecting from './detecting';
import History from './history'; import History from './history';
import Project from './project'; import Project from './project';
import Prop from './prop'; import Prop from './prop';
import { documentSymbol, editorSymbol } from './symbols'; import { documentSymbol, editorSymbol, nodeSymbol } from './symbols';
type IOnChangeOptions = { type IOnChangeOptions = {
type: string; type: string;
@ -48,14 +48,26 @@ export default class DocumentModel {
return new DocumentModel(document); return new DocumentModel(document);
} }
/**
* project
* @returns
*/
getProject() { getProject() {
return Project.create(this[documentSymbol].project); return Project.create(this[documentSymbol].project);
} }
/**
*
* @returns
*/
getRoot() { getRoot() {
return Node.create(this[documentSymbol].getRoot()); return Node.create(this[documentSymbol].getRoot());
} }
/**
*
* @returns
*/
getNodesMap() { getNodesMap() {
const map = new Map<string, Node>(); const map = new Map<string, Node>();
for (let id in this[documentSymbol].nodesMap.keys()) { for (let id in this[documentSymbol].nodesMap.keys()) {
@ -64,30 +76,61 @@ export default class DocumentModel {
return map; return map;
} }
/**
* nodeId Node
* @param nodeId
* @returns
*/
getNodeById(nodeId: string) { getNodeById(nodeId: string) {
return Node.create(this[documentSymbol].getNode(nodeId)); return Node.create(this[documentSymbol].getNode(nodeId));
} }
/**
* schema
* @param schema
*/
importSchema(schema: RootSchema) { importSchema(schema: RootSchema) {
this[documentSymbol].import(schema); this[documentSymbol].import(schema);
} }
/**
* schema
* @param stage
* @returns
*/
exportSchema(stage?: TransformStage) { exportSchema(stage?: TransformStage) {
return this[documentSymbol].export(stage); return this[documentSymbol].export(stage);
} }
/**
*
* @param parent
* @param thing
* @param at
* @param copy
* @returns
*/
insertNode( insertNode(
parent: ParentalNode<NodeSchema>, parent: Node,
thing: InnerNode<NodeSchema> | NodeData, thing: Node,
at?: number | null | undefined, at?: number | null | undefined,
copy?: boolean | undefined, copy?: boolean | undefined,
) { ) {
const node = this[documentSymbol].insertNode(parent, thing, at, copy); const node = this[documentSymbol].insertNode(
parent[nodeSymbol] as any,
thing?.[nodeSymbol],
at,
copy,
);
return Node.create(node); return Node.create(node);
} }
removeNode(idOrNode: string | InnerNode<NodeSchema>) { /**
this[documentSymbol].removeNode(idOrNode); * /id
* @param idOrNode
*/
removeNode(idOrNode: string | Node) {
this[documentSymbol].removeNode(idOrNode as any);
} }
/** /**
@ -126,6 +169,10 @@ export default class DocumentModel {
}); });
} }
/**
* document
* @param fn
*/
onChangeNodeVisible(fn: (node: Node, visible: boolean) => void) { onChangeNodeVisible(fn: (node: Node, visible: boolean) => void) {
// TODO: history 变化时需要重新绑定 // TODO: history 变化时需要重新绑定
this[documentSymbol].nodesMap.forEach((node) => { this[documentSymbol].nodesMap.forEach((node) => {
@ -135,30 +182,40 @@ export default class DocumentModel {
}); });
} }
/**
* document children
* @param fn
*/
onChangeNodeChildren(fn: (info?: IOnChangeOptions) => void) { onChangeNodeChildren(fn: (info?: IOnChangeOptions) => void) {
// TODO: history 变化时需要重新绑定 // TODO: history 变化时需要重新绑定
this[documentSymbol].nodesMap.forEach((node) => { this[documentSymbol].nodesMap.forEach((node) => {
node.onChildrenChange((info?: InnerIOnChangeOptions) => { node.onChildrenChange((info?: InnerIOnChangeOptions) => {
return info ? fn({ return info
type: info.type, ? fn({
node: Node.create(node)!, type: info.type,
}) : fn(); node: Node.create(node)!,
})
: fn();
}); });
}); });
} }
/** /**
* document * document
* @param fn
*/ */
onChangeNodeProp(fn: (info: PropChangeOptions) => void) { onChangeNodeProp(fn: (info: PropChangeOptions) => void) {
this[editorSymbol].on(GlobalEvent.Node.Prop.InnerChange, (info: GlobalEvent.Node.Prop.ChangeOptions) => { this[editorSymbol].on(
fn({ GlobalEvent.Node.Prop.InnerChange,
key: info.key, (info: GlobalEvent.Node.Prop.ChangeOptions) => {
oldValue: info.oldValue, fn({
newValue: info.newValue, key: info.key,
prop: Prop.create(info.prop)!, oldValue: info.oldValue,
node: Node.create(info.node as any)!, newValue: info.newValue,
}); prop: Prop.create(info.prop)!,
}); node: Node.create(info.node as any)!,
});
},
);
} }
} }

View File

@ -1,7 +1,4 @@
import { import { NodeChildren as InnerNodeChildren, Node as InnerNode } from '@ali/lowcode-designer';
NodeChildren as InnerNodeChildren,
Node as InnerNode,
} from '@ali/lowcode-designer';
import { NodeSchema } from '@ali/lowcode-types'; import { NodeSchema } from '@ali/lowcode-types';
import Node from './node'; import Node from './node';
import { nodeSymbol, nodeChildrenSymbol } from './symbols'; import { nodeSymbol, nodeChildrenSymbol } from './symbols';
@ -18,6 +15,10 @@ export default class NodeChildren {
return new NodeChildren(nodeChldren); return new NodeChildren(nodeChldren);
} }
getOwner() {
return Node.create(this[nodeChildrenSymbol].owner);
}
get size() { get size() {
return this[nodeChildrenSymbol].size; return this[nodeChildrenSymbol].size;
} }
@ -89,4 +90,17 @@ export default class NodeChildren {
}), }),
); );
} }
mergeChildren(
remover: (node: Node, idx: number) => boolean,
adder: (children: Node[]) => any,
sorter: (firstNode: Node, secondNode: Node) => number,
) {
this[nodeChildrenSymbol].mergeChildren(
(node: InnerNode, idx: number) => remover(Node.create(node)!, idx),
(children: InnerNode[]) => adder(children.map((node) => Node.create(node)!)),
(firstNode: InnerNode, secondNode: InnerNode) =>
sorter(Node.create(firstNode)!, Node.create(secondNode)!),
);
}
} }

View File

@ -23,77 +23,170 @@ export default class Node {
return new Node(node); return new Node(node);
} }
/**
* id
*/
get id() { get id() {
return this[nodeSymbol].id; return this[nodeSymbol].id;
} }
/**
* componentName
*/
get componentName() { get componentName() {
return this[nodeSymbol].componentName; return this[nodeSymbol].componentName;
} }
/**
*
* @returns
*/
getDocumentModel() { getDocumentModel() {
return DocumentModel.create(this[documentSymbol]); return DocumentModel.create(this[documentSymbol]);
} }
/**
* path
* @param path a / a.b / a.0
* @returns
*/
getProp(path: string): Prop | null { getProp(path: string): Prop | null {
return Prop.create(this[nodeSymbol].getProp(path)); return Prop.create(this[nodeSymbol].getProp(path));
} }
/**
* path
* @param path a / a.b / a.0
* @returns
*/
getPropValue(path: string) { getPropValue(path: string) {
return this.getProp(path)?.getValue(); return this.getProp(path)?.getValue();
} }
/**
* path
* props props
* @param path a / a.b / a.0
* @returns
*/
getExtraProp(path: string): Prop | null { getExtraProp(path: string): Prop | null {
return Prop.create(this[nodeSymbol].getProp(getConvertedExtraKey(path))); return Prop.create(this[nodeSymbol].getProp(getConvertedExtraKey(path)));
} }
/**
* path
* props props
* @param path a / a.b / a.0
* @returns
*/
getExtraPropValue(path: string) { getExtraPropValue(path: string) {
return this.getExtraProp(path)?.getValue(); return this.getExtraProp(path)?.getValue();
} }
/**
* path
* @param path a / a.b / a.0
* @param value
* @returns
*/
setPropValue(path: string, value: CompositeValue) { setPropValue(path: string, value: CompositeValue) {
return this.getProp(path)?.setValue(value); return this.getProp(path)?.setValue(value);
} }
/**
* path
* @param path a / a.b / a.0
* @param value
* @returns
*/
setExtraPropValue(path: string, value: CompositeValue) { setExtraPropValue(path: string, value: CompositeValue) {
return this.getExtraProp(path)?.setValue(value); return this.getExtraProp(path)?.setValue(value);
} }
/**
*
* @returns
*/
getPrevSibling() { getPrevSibling() {
return Node.create(this[nodeSymbol].prevSibling); return Node.create(this[nodeSymbol].prevSibling);
} }
/**
*
* @returns
*/
getNextSibling() { getNextSibling() {
return Node.create(this[nodeSymbol].nextSibling); return Node.create(this[nodeSymbol].nextSibling);
} }
/**
*
* @returns
*/
getParent() { getParent() {
return Node.create(this[nodeSymbol].parent); return Node.create(this[nodeSymbol].parent);
} }
/**
*
* @returns
*/
getChildren() { getChildren() {
return NodeChildren.create(this[nodeSymbol].children); return NodeChildren.create(this[nodeSymbol].children);
} }
/**
*
* @param data
*/
importSchema(data: NodeSchema) { importSchema(data: NodeSchema) {
this[nodeSymbol].import(data); this[nodeSymbol].import(data);
} }
/**
*
* @param stage
* @param options
* @returns
*/
exportSchema(stage?: TransformStage, options?: any) { exportSchema(stage?: TransformStage, options?: any) {
return this[nodeSymbol].export(stage, options); return this[nodeSymbol].export(stage, options);
} }
insertBefore(node: InnerNode<NodeSchema>, ref?: InnerNode<NodeSchema> | undefined, useMutator?: boolean) { /**
this[nodeSymbol].insertBefore(node, ref, useMutator); *
* @param node
* @param ref
* @param useMutator
*/
insertBefore(node: Node, ref?: Node | undefined, useMutator?: boolean) {
this[nodeSymbol].insertBefore(node[nodeSymbol], ref?.[nodeSymbol], useMutator);
} }
insertAfter(node: InnerNode<NodeSchema>, ref?: InnerNode<NodeSchema> | undefined, useMutator?: boolean) { /**
this[nodeSymbol].insertAfter(node, ref, useMutator); *
* @param node
* @param ref
* @param useMutator
*/
insertAfter(node: Node, ref?: Node | undefined, useMutator?: boolean) {
this[nodeSymbol].insertAfter(node[nodeSymbol], ref?.[nodeSymbol], useMutator);
} }
replaceChild(node: InnerNode<NodeSchema>, data: any) { /**
return Node.create(this[nodeSymbol].replaceChild(node, data)); *
* @param node
* @param data
* @returns
*/
replaceChild(node: Node, data: any) {
return Node.create(this[nodeSymbol].replaceChild(node[nodeSymbol], data));
} }
/**
*
* @param schema
*/
replaceWith(schema: NodeSchema) { replaceWith(schema: NodeSchema) {
this[nodeSymbol].replaceWith(schema); this[nodeSymbol].replaceWith(schema);
} }

View File

@ -1,10 +1,18 @@
import { Project as InnerProject, PropsReducer, TransformStage } from '@ali/lowcode-designer'; import {
BuiltinSimulatorHost,
Project as InnerProject,
PropsReducer as PropsTransducer,
TransformStage,
} from '@ali/lowcode-designer';
import { RootSchema, ProjectSchema } from '@ali/lowcode-types'; import { RootSchema, ProjectSchema } from '@ali/lowcode-types';
import DocumentModel from './document-model'; import DocumentModel from './document-model';
import { projectSymbol } from './symbols'; import SimulatorHost from './simulator-host';
import { projectSymbol, simulatorHostSymbol, simulatorRendererSymbol } from './symbols';
export default class Project { export default class Project {
private readonly [projectSymbol]: InnerProject; private readonly [projectSymbol]: InnerProject;
private [simulatorHostSymbol]: BuiltinSimulatorHost;
private [simulatorRendererSymbol]: any;
constructor(project: InnerProject) { constructor(project: InnerProject) {
this[projectSymbol] = project; this[projectSymbol] = project;
@ -25,37 +33,73 @@ export default class Project {
return DocumentModel.create(documentModel); return DocumentModel.create(documentModel);
} }
/**
* document
* @param data
* @returns
*/
createDocument(data?: RootSchema): DocumentModel | null { createDocument(data?: RootSchema): DocumentModel | null {
const doc = this[projectSymbol].createDocument(data); const doc = this[projectSymbol].createDocument(data);
return DocumentModel.create(doc); return DocumentModel.create(doc);
} }
/**
* fileName document
* @param fileName
* @returns
*/
getDocumentByFileName(fileName: string): DocumentModel | null { getDocumentByFileName(fileName: string): DocumentModel | null {
return DocumentModel.create(this[projectSymbol].getDocumentByFileName(fileName)); return DocumentModel.create(this[projectSymbol].getDocumentByFileName(fileName));
} }
/**
* id document
* @param id
* @returns
*/
getDocumentById(id: string): DocumentModel | null { getDocumentById(id: string): DocumentModel | null {
return DocumentModel.create(this[projectSymbol].getDocument(id)); return DocumentModel.create(this[projectSymbol].getDocument(id));
} }
/**
* project documents
* @returns
*/
getDocuments(): DocumentModel[] { getDocuments(): DocumentModel[] {
return this[projectSymbol].documents.map((doc) => DocumentModel.create(doc)!); return this[projectSymbol].documents.map((doc) => DocumentModel.create(doc)!);
} }
/**
* project
* @returns
*/
exportSchema() { exportSchema() {
return this[projectSymbol].getSchema(); return this[projectSymbol].getSchema();
} }
/**
* project
* @param schema project
*/
importSchema(schema?: ProjectSchema) { importSchema(schema?: ProjectSchema) {
this[projectSymbol].load(schema, true); this[projectSymbol].load(schema, true);
} }
/**
* document
* @returns
*/
getCurrentDocument(): DocumentModel | null { getCurrentDocument(): DocumentModel | null {
return DocumentModel.create(this[projectSymbol].currentDocument); return DocumentModel.create(this[projectSymbol].currentDocument);
} }
addPropsTransducer(reducer: PropsReducer, stage: TransformStage) { /**
this[projectSymbol].designer.addPropsReducer(reducer, stage); *
* @param transducer
* @param stage
*/
addPropsTransducer(transducer: PropsTransducer, stage: TransformStage) {
this[projectSymbol].designer.addPropsReducer(transducer, stage);
} }
/** /**
@ -71,21 +115,28 @@ export default class Project {
/** /**
* project ready * project ready
*/ */
onSimulatorReady(fn: () => void) { onSimulatorHostReady(fn: (host: SimulatorHost) => void) {
// TODO: 补充 simulator 实例 if (this[simulatorHostSymbol]) {
// TODO: 思考一下是否要实现补偿触发能力 fn(SimulatorHost.create(this[simulatorHostSymbol])!);
return this[projectSymbol].onSimulatorReady(() => { return () => {};
fn(); }
return this[projectSymbol].onSimulatorReady((simulator: BuiltinSimulatorHost) => {
this[simulatorHostSymbol] = simulator;
fn(SimulatorHost.create(simulator)!);
}); });
} }
/** /**
* project ready * project ready
*/ */
onRendererReady(fn: () => void) { onSimulatorRendererReady(fn: () => void) {
if (this[simulatorRendererSymbol]) {
fn();
return () => {};
}
// TODO: 补充 renderer 实例 // TODO: 补充 renderer 实例
// TODO: 思考一下是否要实现补偿触发能力 return this[projectSymbol].onRendererReady((renderer: any) => {
return this[projectSymbol].onRendererReady(() => { this[simulatorRendererSymbol] = renderer;
fn(); fn();
}); });
} }

View File

@ -0,0 +1,25 @@
import {
BuiltinSimulatorHost,
} from '@ali/lowcode-designer';
import { simulatorHostSymbol } from './symbols';
export default class SimulatorHost {
private readonly [simulatorHostSymbol]: BuiltinSimulatorHost;
constructor(simulator: BuiltinSimulatorHost) {
this[simulatorHostSymbol] = simulator;
}
static create(host: BuiltinSimulatorHost) {
if (!host) return null;
return new SimulatorHost(host);
}
set(key: string, value: any) {
this[simulatorHostSymbol].set(key, value);
}
get(key: string) {
return this[simulatorHostSymbol].get(key);
}
}

View File

@ -1,5 +1,5 @@
/** /**
* symbol plugin context key * symbol shell key
*/ */
export const projectSymbol = Symbol('project'); export const projectSymbol = Symbol('project');
export const designerSymbol = Symbol('designer'); export const designerSymbol = Symbol('designer');
@ -12,4 +12,6 @@ export const propsSymbol = Symbol('props');
export const propSymbol = Symbol('prop'); export const propSymbol = Symbol('prop');
export const detectingSymbol = Symbol('detecting'); export const detectingSymbol = Symbol('detecting');
export const selectionSymbol = Symbol('selection'); export const selectionSymbol = Symbol('selection');
export const historySymbol = Symbol('history'); export const historySymbol = Symbol('history');
export const simulatorHostSymbol = Symbol('simulatorHost');
export const simulatorRendererSymbol = Symbol('simulatorRenderer');