mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-19 05:48:17 +00:00
Merge branch 'fix/pageHistory' into 'release/0.9.0'
Fix/page history See merge request !864869
This commit is contained in:
commit
f463fe8c6b
@ -1,5 +1,6 @@
|
|||||||
import { computed, obx } from '@ali/lowcode-editor-core';
|
import { computed, obx } from '@ali/lowcode-editor-core';
|
||||||
import { NodeData, isJSExpression, isDOMText, NodeSchema, isNodeSchema, RootSchema } from '@ali/lowcode-types';
|
import { NodeData, isJSExpression, isDOMText, NodeSchema, isNodeSchema, RootSchema } from '@ali/lowcode-types';
|
||||||
|
import { EventEmitter } from 'events';
|
||||||
import { Project } from '../project';
|
import { Project } from '../project';
|
||||||
import { ISimulatorHost } from '../simulator';
|
import { ISimulatorHost } from '../simulator';
|
||||||
import { ComponentMeta } from '../component-meta';
|
import { ComponentMeta } from '../component-meta';
|
||||||
@ -26,7 +27,7 @@ export class DocumentModel {
|
|||||||
/**
|
/**
|
||||||
* 文档编号
|
* 文档编号
|
||||||
*/
|
*/
|
||||||
readonly id: string = uniqueId('doc');
|
id: string = uniqueId('doc');
|
||||||
/**
|
/**
|
||||||
* 选区控制
|
* 选区控制
|
||||||
*/
|
*/
|
||||||
@ -40,6 +41,8 @@ export class DocumentModel {
|
|||||||
@obx.val private nodes = new Set<Node>();
|
@obx.val private nodes = new Set<Node>();
|
||||||
private seqId = 0;
|
private seqId = 0;
|
||||||
private _simulator?: ISimulatorHost;
|
private _simulator?: ISimulatorHost;
|
||||||
|
private emitter: EventEmitter;
|
||||||
|
private rootNodeVisitorMap: { [visitorName: string]: any } = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模拟器
|
* 模拟器
|
||||||
@ -75,6 +78,7 @@ export class DocumentModel {
|
|||||||
console.info(this.willPurgeSpace);
|
console.info(this.willPurgeSpace);
|
||||||
}, true);
|
}, true);
|
||||||
*/
|
*/
|
||||||
|
this.emitter = new EventEmitter();
|
||||||
|
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
this._blank = true;
|
this._blank = true;
|
||||||
@ -194,9 +198,14 @@ export class DocumentModel {
|
|||||||
this.nodesMap.set(node.id, node);
|
this.nodesMap.set(node.id, node);
|
||||||
this.nodes.add(node);
|
this.nodes.add(node);
|
||||||
|
|
||||||
|
this.emitter.emit('nodecreate', node);
|
||||||
return node as any;
|
return node as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public destroyNode(node: Node) {
|
||||||
|
this.emitter.emit('nodedestroy', node);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插入一个节点
|
* 插入一个节点
|
||||||
*/
|
*/
|
||||||
@ -406,7 +415,7 @@ export class DocumentModel {
|
|||||||
/**
|
/**
|
||||||
* 打开,已载入,默认建立时就打开状态,除非手动关闭
|
* 打开,已载入,默认建立时就打开状态,除非手动关闭
|
||||||
*/
|
*/
|
||||||
open(): void {
|
open(): DocumentModel {
|
||||||
const originState = this._opened;
|
const originState = this._opened;
|
||||||
this._opened = true;
|
this._opened = true;
|
||||||
if (originState === false) {
|
if (originState === false) {
|
||||||
@ -417,6 +426,7 @@ export class DocumentModel {
|
|||||||
} else {
|
} else {
|
||||||
this.project.checkExclusive(this);
|
this.project.checkExclusive(this);
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -499,6 +509,52 @@ export class DocumentModel {
|
|||||||
get root() {
|
get root() {
|
||||||
return this.rootNode;
|
return this.rootNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onRendererReady(fn: (args: any) => void): () => void {
|
||||||
|
this.emitter.on('lowcode_engine_renderer_ready', fn);
|
||||||
|
return () => {
|
||||||
|
this.emitter.removeListener('lowcode_engine_renderer_ready', fn);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
setRendererReady(renderer) {
|
||||||
|
this.emitter.emit('lowcode_engine_renderer_ready', renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptRootNodeVisitor(
|
||||||
|
visitorName: string = 'default',
|
||||||
|
visitorFn: (node: RootNode) => any ) {
|
||||||
|
let visitorResult = {};
|
||||||
|
if (!visitorName) {
|
||||||
|
/* tslint:disable no-console */
|
||||||
|
console.warn('Invalid or empty RootNodeVisitor name.');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
visitorResult = visitorFn.call(this, this.rootNode);
|
||||||
|
this.rootNodeVisitorMap[visitorName] = visitorResult;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('RootNodeVisitor is not valid.');
|
||||||
|
}
|
||||||
|
return visitorResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRootNodeVisitor(name: string) {
|
||||||
|
return this.rootNodeVisitorMap[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
onNodeCreate(func: (node: Node) => void) {
|
||||||
|
this.emitter.on('nodecreate', func);
|
||||||
|
return () => {
|
||||||
|
this.emitter.removeListener('nodecreate', func);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onNodeDestroy(func: (node: Node) => void) {
|
||||||
|
this.emitter.on('nodedestroy', func);
|
||||||
|
return () => {
|
||||||
|
this.emitter.removeListener('nodedestroy', func);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isDocumentModel(obj: any): obj is DocumentModel {
|
export function isDocumentModel(obj: any): obj is DocumentModel {
|
||||||
|
|||||||
@ -637,6 +637,8 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
|||||||
this.autoruns?.forEach((dispose) => dispose());
|
this.autoruns?.forEach((dispose) => dispose());
|
||||||
this.props.purge();
|
this.props.purge();
|
||||||
this.document.internalRemoveAndPurgeNode(this);
|
this.document.internalRemoveAndPurgeNode(this);
|
||||||
|
|
||||||
|
this.document.destroyNode(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======= compatible apis ====
|
// ======= compatible apis ====
|
||||||
|
|||||||
@ -122,7 +122,7 @@ export class Project {
|
|||||||
if (data) {
|
if (data) {
|
||||||
doc = new DocumentModel(this, data);
|
doc = new DocumentModel(this, data);
|
||||||
this.documents.push(doc);
|
this.documents.push(doc);
|
||||||
doc.open();
|
return doc.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -134,7 +134,7 @@ export class Project {
|
|||||||
|
|
||||||
doc = new DocumentModel(this, doc);
|
doc = new DocumentModel(this, doc);
|
||||||
this.documents.push(doc);
|
this.documents.push(doc);
|
||||||
doc.open();
|
return doc.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
checkExclusive(actived: DocumentModel) {
|
checkExclusive(actived: DocumentModel) {
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import { Designer, LiveEditing, TransformStage, Node } from '@ali/lowcode-design
|
|||||||
import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
|
import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane';
|
||||||
import { toCss } from '@ali/vu-css-style';
|
import { toCss } from '@ali/vu-css-style';
|
||||||
import logger from '@ali/vu-logger';
|
import logger from '@ali/vu-logger';
|
||||||
|
import bus from './bus';
|
||||||
|
import { VE_EVENTS } from './base/const';
|
||||||
|
|
||||||
import DesignerPlugin from '@ali/lowcode-plugin-designer';
|
import DesignerPlugin from '@ali/lowcode-plugin-designer';
|
||||||
import { Skeleton, SettingsPrimaryPane } from '@ali/lowcode-editor-skeleton';
|
import { Skeleton, SettingsPrimaryPane } from '@ali/lowcode-editor-skeleton';
|
||||||
@ -23,6 +25,12 @@ export const designer = new Designer({ editor: editor });
|
|||||||
editor.set(Designer, designer);
|
editor.set(Designer, designer);
|
||||||
editor.set('designer', designer);
|
editor.set('designer', designer);
|
||||||
|
|
||||||
|
designer.project.onCurrentDocumentChange((doc) => {
|
||||||
|
doc.onRendererReady(() => {
|
||||||
|
bus.emit(VE_EVENTS.VE_PAGE_PAGE_READY);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// 节点 props 初始化
|
// 节点 props 初始化
|
||||||
designer.addPropsReducer((props, node) => {
|
designer.addPropsReducer((props, node) => {
|
||||||
// run initials
|
// run initials
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { designer } from './editor';
|
import { designer } from './editor';
|
||||||
import { RootSchema } from '@ali/lowcode-types';
|
import { RootSchema } from '@ali/lowcode-types';
|
||||||
import { DocumentModel } from '@ali/lowcode-designer';
|
import { DocumentModel } from '@ali/lowcode-designer';
|
||||||
|
import NodeCacheVisitor from './rootNodeVisitor';
|
||||||
|
|
||||||
const { project } = designer;
|
const { project } = designer;
|
||||||
|
|
||||||
@ -96,4 +97,15 @@ Object.defineProperty(pages, 'currentPage', {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
pages.onCurrentPageChange((page: DocumentModel) => {
|
||||||
|
if (!page) { return; }
|
||||||
|
page.acceptRootNodeVisitor('NodeCache', (rootNode) => {
|
||||||
|
const visitor: NodeCacheVisitor = page.getRootNodeVisitor('NodeCache');
|
||||||
|
if (visitor) {
|
||||||
|
visitor.destroy();
|
||||||
|
}
|
||||||
|
return new NodeCacheVisitor(page, rootNode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
export default pages;
|
export default pages;
|
||||||
|
|||||||
91
packages/editor-preset-vision/src/rootNodeVisitor.ts
Normal file
91
packages/editor-preset-vision/src/rootNodeVisitor.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import { findIndex } from 'lodash';
|
||||||
|
import { DocumentModel, Node, Root } from '@ali/lowcode-designer';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RootNodeVisitor for VisualEngine Page
|
||||||
|
*
|
||||||
|
* - store / cache node
|
||||||
|
* - quickly find / search or do operations on Node
|
||||||
|
*/
|
||||||
|
export default class RootNodeVisitor {
|
||||||
|
public nodeIdMap: {[id: string]: Node} = {};
|
||||||
|
public nodeFieldIdMap: {[fieldId: string]: Node} = {};
|
||||||
|
public nodeList: Node[] = [];
|
||||||
|
|
||||||
|
private page: DocumentModel;
|
||||||
|
private root: RootNode;
|
||||||
|
private cancelers: Function[] = [];
|
||||||
|
|
||||||
|
constructor(page: DocumentModel, rootNode: RootNode) {
|
||||||
|
this.page = page;
|
||||||
|
this.root = rootNode;
|
||||||
|
|
||||||
|
this._findNode(this.root);
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getNodeList() {
|
||||||
|
return this.nodeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getNodeIdMap() {
|
||||||
|
return this.nodeIdMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getNodeFieldIdMap() {
|
||||||
|
return this.nodeFieldIdMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getNodeById(id?: string) {
|
||||||
|
if (!id) { return this.nodeIdMap; }
|
||||||
|
return this.nodeIdMap[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public getNodeByFieldId(fieldId?: string) {
|
||||||
|
if (!fieldId) { return this.nodeFieldIdMap; }
|
||||||
|
return this.nodeFieldIdMap[fieldId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
this.cancelers.forEach((canceler) => canceler());
|
||||||
|
}
|
||||||
|
|
||||||
|
private _init() {
|
||||||
|
this.cancelers.push(
|
||||||
|
this.page.onNodeCreate((node) => {
|
||||||
|
this.nodeList.push(node);
|
||||||
|
this.nodeIdMap[node.id] = node;
|
||||||
|
if (node.getPropValue('fieldId')) {
|
||||||
|
this.nodeFieldIdMap[node.getPropValue('fieldId')] = node;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.cancelers.push(
|
||||||
|
this.page.onNodeDestroy((node) => {
|
||||||
|
const idx = findIndex(this.nodeList, (n) => node.id === n.id);
|
||||||
|
this.nodeList.splice(idx, 1);
|
||||||
|
delete this.nodeIdMap[node.id];
|
||||||
|
if (node.getPropValue('fieldId')) {
|
||||||
|
delete this.nodeFieldIdMap[node.getPropValue('fieldId')];
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _findNode(node: Node) {
|
||||||
|
const props = node.getProps();
|
||||||
|
const fieldId = props && props.getPropValue('fieldId');
|
||||||
|
|
||||||
|
this.nodeIdMap[node.getId()] = node;
|
||||||
|
this.nodeList.push(node);
|
||||||
|
if (fieldId) {
|
||||||
|
this.nodeFieldIdMap[fieldId] = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
const children = node.getChildren();
|
||||||
|
if (children) {
|
||||||
|
children.forEach((child) => this._findNode(child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,10 +17,12 @@ import Leaf from './builtin-components/leaf';
|
|||||||
export class SimulatorRenderer implements BuiltinSimulatorRenderer {
|
export class SimulatorRenderer implements BuiltinSimulatorRenderer {
|
||||||
readonly isSimulatorRenderer = true;
|
readonly isSimulatorRenderer = true;
|
||||||
private dispose?: () => void;
|
private dispose?: () => void;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if (!host) {
|
if (!host) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dispose = host.connect(this, () => {
|
this.dispose = host.connect(this, () => {
|
||||||
// sync layout config
|
// sync layout config
|
||||||
|
|
||||||
@ -286,6 +288,7 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
|
|||||||
document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends
|
document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends
|
||||||
|
|
||||||
reactRender(createElement(SimulatorRendererView, { renderer: this }), container);
|
reactRender(createElement(SimulatorRendererView, { renderer: this }), container);
|
||||||
|
host.document.setRendererReady(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user