2020-07-29 20:38:43 +08:00

339 lines
8.0 KiB
TypeScript

import { obx, computed } from '@ali/lowcode-editor-core';
import { Node, ParentalNode } from './node';
import { TransformStage } from './transform-stage';
import { NodeData, isNodeSchema } from '@ali/lowcode-types';
import { shallowEqual } from '@ali/lowcode-utils';
import { EventEmitter } from 'events';
export class NodeChildren {
@obx.val private children: Node[];
private emitter = new EventEmitter();
constructor(readonly owner: ParentalNode, data: NodeData | NodeData[]) {
this.children = (Array.isArray(data) ? data : [data]).map(child => {
return this.owner.document.createNode(child);
});
}
interalInitParent() {
this.children.forEach(child => child.internalSetParent(this.owner));
}
/**
* 导出 schema
*/
export(stage: TransformStage = TransformStage.Save): NodeData[] {
return this.children.map(node => {
const data = node.export(stage);
if (node.isLeaf() && TransformStage.Save === stage) {
// FIXME: filter empty
return data.children as NodeData;
}
return data;
});
}
import(data?: NodeData | NodeData[], checkId = false) {
data = data ? (Array.isArray(data) ? data : [data]) : [];
const originChildren = this.children.slice();
this.children.forEach(child => child.internalSetParent(null));
const children = new Array<Node>(data.length);
for (let i = 0, l = data.length; i < l; i++) {
const child = originChildren[i];
const item = data[i];
let node: Node | undefined;
if (isNodeSchema(item) && !checkId && child && child.componentName === item.componentName) {
node = child;
node.import(item);
} else {
node = this.owner.document.createNode(item);
}
children[i] = node;
}
this.children = children;
this.interalInitParent();
if (!shallowEqual(children, originChildren)) {
this.emitter.emit('change');
}
}
/**
* @deprecated
* @param nodes
*/
concat(nodes: Node[]) {
return this.children.concat(nodes);
}
/**
* 元素个数
*/
@computed get size(): number {
return this.children.length;
}
/**
* 是否空
*/
@computed isEmpty() {
return this.size < 1;
}
@computed notEmpty() {
return this.size > 0;
}
@computed length() {
return this.children.length;
}
/**
* 删除一个节点
*/
delete(node: Node, purge = false, useMutator = true): boolean {
const i = this.children.indexOf(node);
if (i < 0) {
return false;
}
const deleted = this.children.splice(i, 1)[0];
if (purge) {
// should set parent null
deleted.internalSetParent(null, useMutator);
deleted.purge(useMutator);
}
this.emitter.emit('change');
if (useMutator) {
this.reportModified(node, this.owner, {type: 'remove', removeIndex: i, removeNode: node});
}
return false;
}
/**
* 插入一个节点,返回新长度
*/
insert(node: Node, at?: number | null, useMutator = true): void {
const children = this.children;
let index = at == null || at === -1 ? children.length : at;
const i = children.indexOf(node);
if (i < 0) {
if (index < children.length) {
children.splice(index, 0, node);
} else {
children.push(node);
}
node.internalSetParent(this.owner, useMutator);
} else {
if (index > i) {
index -= 1;
}
if (index === i) {
return;
}
children.splice(i, 1);
children.splice(index, 0, node);
}
this.emitter.emit('change');
// this.reportModified(node, this.owner, { type: 'insert' });
// check condition group
if (node.conditionGroup) {
if (
!(
// just sort at condition group
(
(node.prevSibling && node.prevSibling.conditionGroup === node.conditionGroup) ||
(node.nextSibling && node.nextSibling.conditionGroup === node.conditionGroup)
)
)
) {
node.setConditionGroup(null);
}
}
if (node.prevSibling && node.nextSibling) {
const conditionGroup = node.prevSibling.conditionGroup;
// insert at condition group
if (conditionGroup && conditionGroup === node.nextSibling.conditionGroup) {
node.setConditionGroup(conditionGroup);
}
}
}
/**
* 取得节点索引编号
*/
indexOf(node: Node): number {
return this.children.indexOf(node);
}
/**
*
*/
splice(start: number, deleteCount: number, node: Node): Node[] {
return this.children.splice(start, deleteCount, node);
}
/**
* 根据索引获得节点
*/
get(index: number): Node | null {
return this.children[index] || null;
}
/**
* 是否存在节点
*/
has(node: Node) {
return this.indexOf(node) > -1;
}
/**
* 迭代器
*/
[Symbol.iterator](): { next(): { value: Node } } {
let index = 0;
const children = this.children;
const length = children.length || 0;
return {
next() {
if (index < length) {
return {
value: children[index++],
done: false,
};
}
return {
value: undefined as any,
done: true,
};
},
};
}
/**
* 遍历
*/
forEach(fn: (item: Node, index: number) => void): void {
this.children.forEach((child, index) => {
return fn(child, index);
});
}
/**
* 遍历
*/
map<T>(fn: (item: Node, index: number) => T): T[] | null {
return this.children.map((child, index) => {
return fn(child, index);
});
}
every(fn: (item: Node, index: number) => any): boolean {
return this.children.every((child, index) => fn(child, index));
}
some(fn: (item: Node, index: number) => any): boolean {
return this.children.some((child, index) => fn(child, index));
}
filter(fn: (item: Node, index: number) => any) {
return this.children.filter(fn);
}
mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) {
let changed = false;
if (remover) {
const willRemove = this.children.filter(remover);
if (willRemove.length > 0) {
willRemove.forEach((node) => {
const i = this.children.indexOf(node);
if (i > -1) {
this.children.splice(i, 1);
node.remove(false);
}
});
changed = true;
}
}
if (adder) {
const items = adder(this.children);
if (items && items.length > 0) {
items.forEach((child: NodeData) => {
const node = this.owner.document.createNode(child);
this.children.push(node);
node.internalSetParent(this.owner);
});
changed = true;
}
}
if (sorter) {
this.children = this.children.sort(sorter);
changed = true;
}
if (changed) {
this.emitter.emit('change');
}
}
onChange(fn: () => void) {
this.emitter.on('change', fn);
return () => {
this.emitter.removeListener('change', fn);
};
}
private purged = false;
/**
* 回收销毁
*/
purge(useMutator = true) {
if (this.purged) {
return;
}
this.purged = true;
this.children.forEach((child) => child.purge(useMutator));
}
get [Symbol.toStringTag]() {
// 保证向前兼容性
return 'Array';
}
// /**
// * @deprecated
// * 为了兼容vision体系存量api
// */
// getChildrenArray() {
// return this.children;
// }
private reportModified(node: Node, owner: Node, options = {}) {
if (!node) {
return;
}
if (node.isRoot()) {
return;
}
const callbacks = owner.componentMeta.getMetadata().experimental?.callbacks;
if (callbacks?.onSubtreeModified) {
try {
callbacks?.onSubtreeModified.call(node, owner, options);
} catch (e) {
console.error('error when excute experimental.callbacks.onNodeAdd', e);
}
}
if (owner.parent && !owner.parent.isRoot()) {
this.reportModified(node, owner.parent, options);
}
}
}