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 = {}) {
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);
});
}
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[] {
stage = compatStage(stage);
return this.children.map(node => {
return this.children.map((node) => {
const data = node.export(stage);
if (node.isLeaf() && TransformStage.Save === stage) {
// FIXME: filter empty
@ -47,7 +47,7 @@ export class NodeChildren {
data = data ? (Array.isArray(data) ? data : [data]) : [];
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);
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 {
node.internalPurgeStart();
if (node.isParental()) {
foreachReverse(node.children, (subNode: Node) => {
subNode.remove(useMutator, purge, options);
}, (iterable, idx) => (iterable as NodeChildren).get(idx));
foreachReverse(node.slots, (slotNode: Node) => {
slotNode.remove(useMutator, purge);
}, (iterable, idx) => (iterable as [])[idx]);
foreachReverse(
node.children,
(subNode: Node) => {
subNode.remove(useMutator, purge, options);
},
(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)操作
const i = this.children.indexOf(node);
@ -164,7 +172,13 @@ export class NodeChildren {
node,
});
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 中删除了子节点
if (i > -1 && !purge) {
@ -183,10 +197,11 @@ export class NodeChildren {
const i = children.indexOf(node);
if (node.parent) {
globalContext.has('editor') && globalContext.get('editor').emit('node.remove.topLevel', {
node,
index: node.index,
});
globalContext.has('editor') &&
globalContext.get('editor').emit('node.remove.topLevel', {
node,
index: node.index,
});
}
if (i < 0) {
@ -332,7 +347,11 @@ export class NodeChildren {
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;
if (remover) {
const willRemove = this.children.filter(remover);

View File

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

View File

@ -1,7 +1,4 @@
import {
NodeChildren as InnerNodeChildren,
Node as InnerNode,
} from '@ali/lowcode-designer';
import { NodeChildren as InnerNodeChildren, Node as InnerNode } from '@ali/lowcode-designer';
import { NodeSchema } from '@ali/lowcode-types';
import Node from './node';
import { nodeSymbol, nodeChildrenSymbol } from './symbols';
@ -18,6 +15,10 @@ export default class NodeChildren {
return new NodeChildren(nodeChldren);
}
getOwner() {
return Node.create(this[nodeChildrenSymbol].owner);
}
get 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);
}
/**
* id
*/
get id() {
return this[nodeSymbol].id;
}
/**
* componentName
*/
get componentName() {
return this[nodeSymbol].componentName;
}
/**
*
* @returns
*/
getDocumentModel() {
return DocumentModel.create(this[documentSymbol]);
}
/**
* path
* @param path a / a.b / a.0
* @returns
*/
getProp(path: string): Prop | null {
return Prop.create(this[nodeSymbol].getProp(path));
}
/**
* path
* @param path a / a.b / a.0
* @returns
*/
getPropValue(path: string) {
return this.getProp(path)?.getValue();
}
/**
* path
* props props
* @param path a / a.b / a.0
* @returns
*/
getExtraProp(path: string): Prop | null {
return Prop.create(this[nodeSymbol].getProp(getConvertedExtraKey(path)));
}
/**
* path
* props props
* @param path a / a.b / a.0
* @returns
*/
getExtraPropValue(path: string) {
return this.getExtraProp(path)?.getValue();
}
/**
* path
* @param path a / a.b / a.0
* @param value
* @returns
*/
setPropValue(path: string, value: CompositeValue) {
return this.getProp(path)?.setValue(value);
}
/**
* path
* @param path a / a.b / a.0
* @param value
* @returns
*/
setExtraPropValue(path: string, value: CompositeValue) {
return this.getExtraProp(path)?.setValue(value);
}
/**
*
* @returns
*/
getPrevSibling() {
return Node.create(this[nodeSymbol].prevSibling);
}
/**
*
* @returns
*/
getNextSibling() {
return Node.create(this[nodeSymbol].nextSibling);
}
/**
*
* @returns
*/
getParent() {
return Node.create(this[nodeSymbol].parent);
}
/**
*
* @returns
*/
getChildren() {
return NodeChildren.create(this[nodeSymbol].children);
}
/**
*
* @param data
*/
importSchema(data: NodeSchema) {
this[nodeSymbol].import(data);
}
/**
*
* @param stage
* @param options
* @returns
*/
exportSchema(stage?: TransformStage, options?: any) {
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) {
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 DocumentModel from './document-model';
import { projectSymbol } from './symbols';
import SimulatorHost from './simulator-host';
import { projectSymbol, simulatorHostSymbol, simulatorRendererSymbol } from './symbols';
export default class Project {
private readonly [projectSymbol]: InnerProject;
private [simulatorHostSymbol]: BuiltinSimulatorHost;
private [simulatorRendererSymbol]: any;
constructor(project: InnerProject) {
this[projectSymbol] = project;
@ -25,37 +33,73 @@ export default class Project {
return DocumentModel.create(documentModel);
}
/**
* document
* @param data
* @returns
*/
createDocument(data?: RootSchema): DocumentModel | null {
const doc = this[projectSymbol].createDocument(data);
return DocumentModel.create(doc);
}
/**
* fileName document
* @param fileName
* @returns
*/
getDocumentByFileName(fileName: string): DocumentModel | null {
return DocumentModel.create(this[projectSymbol].getDocumentByFileName(fileName));
}
/**
* id document
* @param id
* @returns
*/
getDocumentById(id: string): DocumentModel | null {
return DocumentModel.create(this[projectSymbol].getDocument(id));
}
/**
* project documents
* @returns
*/
getDocuments(): DocumentModel[] {
return this[projectSymbol].documents.map((doc) => DocumentModel.create(doc)!);
}
/**
* project
* @returns
*/
exportSchema() {
return this[projectSymbol].getSchema();
}
/**
* project
* @param schema project
*/
importSchema(schema?: ProjectSchema) {
this[projectSymbol].load(schema, true);
}
/**
* document
* @returns
*/
getCurrentDocument(): DocumentModel | null {
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
*/
onSimulatorReady(fn: () => void) {
// TODO: 补充 simulator 实例
// TODO: 思考一下是否要实现补偿触发能力
return this[projectSymbol].onSimulatorReady(() => {
fn();
onSimulatorHostReady(fn: (host: SimulatorHost) => void) {
if (this[simulatorHostSymbol]) {
fn(SimulatorHost.create(this[simulatorHostSymbol])!);
return () => {};
}
return this[projectSymbol].onSimulatorReady((simulator: BuiltinSimulatorHost) => {
this[simulatorHostSymbol] = simulator;
fn(SimulatorHost.create(simulator)!);
});
}
/**
* project ready
*/
onRendererReady(fn: () => void) {
onSimulatorRendererReady(fn: () => void) {
if (this[simulatorRendererSymbol]) {
fn();
return () => {};
}
// TODO: 补充 renderer 实例
// TODO: 思考一下是否要实现补偿触发能力
return this[projectSymbol].onRendererReady(() => {
return this[projectSymbol].onRendererReady((renderer: any) => {
this[simulatorRendererSymbol] = renderer;
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 designerSymbol = Symbol('designer');
@ -12,4 +12,6 @@ export const propsSymbol = Symbol('props');
export const propSymbol = Symbol('prop');
export const detectingSymbol = Symbol('detecting');
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');