import { injectable, inject } from 'inversify'; import { KV } from 'ts-toolset'; import { mergeListToMap } from 'ts-toolset/dist/common/map'; import { buildTreeByJoinNode } from 'ts-toolset/dist/tree/tree/utils'; import { MapStore, EventBus } from '../../../services'; import { ServicesIoc, WorkbenchIoc } from '../../../ioc'; import { MapStoreKeys, globalStoreKeys } from './common/signature'; import { getSchemaRootNode, getSchemaRootData } from './common/utils'; import { HtmlSchemaNodeTypeEnum, HtmlSchemaNode, HtmlSchemaNodeRaw, HtmlSchemaTree, InterfaceEvents, HtmlConstraintFields } from './common'; import { IHtmlSchemaRecord, IHtmlTemplateEntity, IFunctionalEntity, IHtmlComponentEntity, IHtmlSchemaNode, IPageFactorEntity, IHtmlSchemaData } from '../../../models/html'; import { StyleAccess } from '../../parts/styleAccess'; import { Functional } from '../../parts/functional'; import { isEmptyObject } from 'ts-toolset/dist/common/types'; export interface IHtmlDatasetIntegrator { } @injectable() export class HtmlDatasetIntegrator implements IHtmlDatasetIntegrator { private readonly _schemaTree: HtmlSchemaTree; //private readonly _schemaSlots: Map; private readonly _componentStore: Map; private readonly _pageSchemaStore: Map; private readonly _templateSchemaStore: Map; constructor( // services @inject(ServicesIoc.Identifier.MapStore) private _mapStore: MapStore, @inject(ServicesIoc.Identifier.EventBus) private _eventBus: EventBus, // parts @inject(WorkbenchIoc.PartsIdentifier.Functional) private _functional: Functional, //@inject(WorkbenchIoc.PartsIdentifier.HtmlSchema) private _htmlSchema: HtmlSchema @inject(WorkbenchIoc.PartsIdentifier.StyleAccess) private _styleAccess: StyleAccess ) { const globalStore = this._mapStore.get(MapStoreKeys.globalStore)!; this._schemaTree = globalStore.get(globalStoreKeys.schemaTree); //this._schemaSlots = globalStore.get(globalStoreKeys.schemaSlots); //this._schemaRootNode = globalStore.get(globalStoreKeys.schemaRootNode); this._componentStore = this._mapStore.get(MapStoreKeys.componentStore)!; this._pageSchemaStore = this._mapStore.get(MapStoreKeys.pageSchemaStore)!; this._templateSchemaStore = this._mapStore.get(MapStoreKeys.templateSchemaStore)!; this._eventBus .register(InterfaceEvents.HtmlSchema.loadSchema, this._loadSchemaRecord, { scope: this }); } get schemaTree() { return this._schemaTree; } //get schemaSlot() { return this._schemaSlots; } get componentStore() { return this._componentStore; } /** 获取一个协议根节点 */ public getSchemaRootNode() { return getSchemaRootNode(); } /** 解析线性数据为树形数据 */ private _buildTreeData(data: IHtmlSchemaData) { // 为了把服务的的计算压力分摊到客户端,数据的构造计算放到这里来做,如果已经构建过的数据直接返回即可 if (data.isBuild) return data.schemaNodes; let nodes = data.schemaNodes as IHtmlSchemaNode[]; // 处理每个根节点(isSchemaRoot==true)的数据 // 确定每个节点各自的连接关系 const treeMap = new Map(); mergeListToMap(treeMap, nodes, 'id'); nodes.forEach(v => { if (v.slotData) { if (v.type === HtmlSchemaNodeTypeEnum.template) { let temlateSchema = this._templateSchemaStore.get(v.key); if (temlateSchema) { let id = v.slotData.template as any; v.slotData.template = { data: getSchemaRootData(id) as any, children: this._buildTreeData(temlateSchema) }; } } if (v.slotData.children) { let id = v.slotData.children as any; v.slotData.children = treeMap.get(id); } if (v.slotData.slots) { Object.keys(v.slotData.slots).forEach(key => { let node = treeMap.get(v.slotData!.slots![key]) node && (v.slotData!.slots![key] = node); // key === '_slot' 时为插槽用法 }); } if (v.slotData.customs) { Object.keys(v.slotData.customs).forEach(key => { Object.keys(v.slotData!.customs![key]).forEach(cus_key => { let node = treeMap.get(v.slotData!.customs![key][cus_key]); node && (v.slotData!.customs![key][cus_key] = node); // key === '_slot' 时为插槽用法 }); }) } } }); // 将线性节点转换为树形结构的数据 let treeData = buildTreeByJoinNode(nodes, { key: 'id', joinNodeKey: '_node', wrapField: 'data', clearJoinNode: false }) as HtmlSchemaNodeRaw[]; // 标识数据已经构建过 data.isBuild = true; // isSchemaRoot==true 的数据说明是 插槽 或 者模版 需要过滤 data.schemaNodes = treeData.filter(v => !v.data.isSchemaRootNode); return data.schemaNodes; } /** 加载页面数据 */ private _loadSchemaRecord(id: string) { const record = this._pageSchemaStore.get(id); if (record) { this._loadPageFactor(record, true); this._schemaTree.dispose().setRoot(getSchemaRootNode() as any).import(this._buildTreeData(record)); this._parseSchemaTree(this._schemaTree.root); this._eventBus.emit(InterfaceEvents.Stage.renderStage); } } //#region -- SchemaTree private _loadPageFactor(factor: IPageFactorEntity, clear: boolean = false) { this._loadFunctionalData(factor.functional, { clear }); this._styleAccess.dispose(); //this._styleAccess.insertRules(this); } /** 加载函数功能数据 */ private _loadFunctionalData(data: IFunctionalEntity = {}, options: { storeKey?: string, clear?: boolean } = {}) { options.clear && this._functional.dispose(); data.variables && this._functional.appendVariable(data.variables, options.storeKey); data.functions && this._functional.appendFunction(data.functions, options.storeKey); } /** 解析协议主体数据 */ private _parseSchemaTree(target: HtmlSchemaNode) { this._schemaTree.map(target, (node) => { const slots: any = { slots: {}, customs: {}, children: undefined, template: undefined }; if (node.data.slotData) { if (node.data.slotData.children) { slots.children = getSchemaRootNode(node.data.slotData.children.data) as any; this.schemaTree.import(node.data.slotData.children, { sourceNode: slots.children! }); this._parseSchemaTree(slots.children!); } if (node.data.slotData.slots && !isEmptyObject(node.data.slotData.slots)) { Object.keys(node.data.slotData.slots).forEach(key => { if (key === HtmlConstraintFields._slot) { slots.slots[key] = node.data.slotData!.slots![key]; } else if (node.data.slotData!.slots![key].data) { slots.slots[key] = getSchemaRootNode(node.data.slotData!.slots![key].data) as any; this._schemaTree.import(node.data.slotData!.slots![key], { sourceNode: slots.slots[key] }); this._parseSchemaTree(slots.slots[key]); } }); } if (node.data.slotData.customs && !isEmptyObject(node.data.slotData.customs)) { Object.keys(node.data.slotData.customs).forEach(key => { let customData: any = {}, customs = node.data.slotData!.customs![key]; Object.keys(customs).forEach(cus_key => { if (cus_key === HtmlConstraintFields._slot) { customData[cus_key] = customs[cus_key]; } else if (customs[cus_key].data) { customData[cus_key] = getSchemaRootNode(customs[cus_key].data); this._schemaTree.import(customs[cus_key], { sourceNode: customData[cus_key] }); this._parseSchemaTree(customData[cus_key]); customs[cus_key] = customData[cus_key]; } }); !isEmptyObject(customData) && (slots.customs[key] = customData); }); } if (node.data.slotData.template) { slots.template = getSchemaRootNode(node.data.slotData.template.data) as any; this.schemaTree.import(node.data.slotData.template, { sourceNode: slots.template }); this._parseSchemaTree(slots.template!); // 这个方法的数据是经过 _buildTreeData 解析的,模版必定有值,不然不会出现在 slotData 里 // 解析模版的变量和函数 let template = this._templateSchemaStore.get(node.data.key)!; this._loadFunctionalData(template.functional, { storeKey: node.data.id }); } node.data.slotData = slots; } }); } //#endregion }