/
qwiklly
/
cms
Обзор
Документация
Войти
/
qwiklly
/
cms
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
trunk
packages/cms-extensions/src/lib/mybuilder.component.ts
177 строк
5 KB
Дарья Игоревна
Lib tests
11 окт 2023, 20:23
11 окт 2023, 20:23
c3e7128
Код
Авторство
О чём код?
import { Component, Input, ViewChild, ViewContainerRef, Injector, NgModuleRef, Type, AfterViewInit, } from '@angular/core'; export interface Block { tagName: string; childNodes?: Block[]; attributes?: { [key: string]: string; }; text?: string; } interface MyModule { decorators: [ { args: [ { declarations: []; } ]; } ]; ɵmod: { imports: []; declarations: []; }; } interface MyComponent { decorators: [{ args: [{ selector: string }] }]; ɵmod: { imports: []; }; prototype: { constructor: { ɵcmp: { selectors: [] } } }; } interface CompName_to_CompType { [key: string]: unknown; } @Component({ selector: 'app-mybuilder', templateUrl: './mybuilder.component.html', }) export class MyBuilderComponent implements AfterViewInit { @Input() get myJson(): Block[] | null { return this._myJson ? this._myJson : null; } set myJson(val: Block[] | null) { this._myJson = val; if (this._myJson != null && this.isInitialized) this.loadComponent(); } isInitialized = false; private _myJson: Block[] | null = null; constructor(private injector: Injector) {} @ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) private container: ViewContainerRef | undefined; private lastElement: ViewContainerRef | undefined; private CompName_to_Comp: CompName_to_CompType = {}; ngAfterViewInit() { // console.error(MybuilderModule); const parentModuleRef = this.injector.get(NgModuleRef); const constructor: MyModule = ( Object.getPrototypeOf(parentModuleRef.instance) as { constructor: unknown; } ).constructor as MyModule; const modules: MyModule[] = []; function AddModule(module: MyModule) { if (module.ɵmod) { modules.push(module); module.ɵmod.imports.forEach(AddModule); } } AddModule(constructor); const declarations: [] = []; modules.forEach((module: MyModule) => { declarations.push(...module.ɵmod.declarations); if (!!module.decorators && !!module.decorators[0].args[0].declarations) { declarations.push(...module.decorators[0].args[0].declarations); } }); this.CompName_to_Comp = declarations.reduce( (acc: CompName_to_CompType, cur: MyComponent) => { if (!!cur.decorators && !!cur.decorators[0].args[0].selector) { cur.decorators[0].args[0].selector .split(',') .forEach((name: string) => { acc[name.trim()] = cur; }); } else if (cur.prototype && cur.prototype.constructor.ɵcmp) { cur.prototype.constructor.ɵcmp.selectors.forEach((name: string) => { acc[name] = cur; }); } return acc; }, {} ); this.lastElement = this.container; this.isInitialized=true; this.loadComponent(); } loadComponent() { if (this.myJson && this.myJson.length == 0) { return; } const parent = this.container?.element.nativeElement as HTMLElement; if (!parent) { console.error('there is no block for displaying html.'); return; } parent.innerHTML=""; const createChildNodes = (elem: Block) => { const comp = this.CompName_to_Comp[elem.tagName] as Type<unknown>; const childs: Node[] = []; if (elem.childNodes) { elem.childNodes.forEach((child: Block) => childs.push(createChildNodes(child)) ); } if (comp) { const ref = this.lastElement?.createComponent(comp, { projectableNodes: [childs], }); this.lastElement = ref?.injector.get(ViewContainerRef); if (elem.text) { let cont: Element = ref?.location.nativeElement as Element; const text = document.createTextNode(elem.text); // проброс текста while (cont.firstElementChild) { cont = cont.firstElementChild; } cont.append(text); } if (elem.attributes) { const inst = ref?.instance as { [key: string]: string }; for (const attr of Object.keys(elem.attributes)) { inst[attr] = elem.attributes[attr]; // inst.disabled = true; } } // parent.appendChild(ref?.location.nativeElement); // ref?.changeDetectorRef.detectChanges(); return ref?.location.nativeElement as Node; } else { if (elem.text) childs.push(document.createTextNode(elem.text)); const comp: HTMLElement = document.createElement(elem.tagName); if (elem.attributes) for (const attr of Object.keys(elem.attributes)) { comp.setAttribute(attr, elem.attributes[attr]); } childs.forEach((child) => { comp.appendChild(child); }); return comp as Node; } }; this.myJson?.forEach((elem) => { parent.appendChild(createChildNodes(elem)); }); } }