UNPKG

@cisstech/nge

Version:

NG Essentials is a collection of libraries for Angular developers.

178 lines (171 loc) 7.93 kB
import * as i0 from '@angular/core'; import { InjectionToken, Injectable, Optional, Inject, Directive, NgModule } from '@angular/core'; import { createCustomElement } from '@angular/elements'; import { from } from 'rxjs'; import * as i1 from '@cisstech/nge/services'; import { CommonModule } from '@angular/common'; const NGE_ELEMENTS = new InjectionToken('NGE_ELEMENTS'); class NgeElementService { constructor(injector, compiler, elements) { this.injector = injector; this.compiler = compiler; this.registry = new Map(); this.defineds = new Set(); this.promises = new Map(); elements?.forEach((route) => { this.registry.set(route.selector.trim().toLowerCase(), route); }); } listUnloadeds() { return Array.from(this.registry.keys()).filter((s) => !this.defineds.has(s)); } /** * Allows to lazy load a element given it's selector (i.e. tagname). * If the element selector has been registered, it's according module * will be fetched lazily * @param selector selector of the element to load. */ loadElement(selector) { if (this.promises.has(selector)) { return this.promises.get(selector); } const definition = this.registry.get(selector); if (!definition) { throw new Error(`Unrecognized element "${selector}". Make sure it is registered in the registry`); } const promise = new Promise(async (resolve, reject) => { try { const type = definition.module ? await definition.module() : definition.component ? await definition.component() : null; if (!type) { throw new Error(`No module or component found for element "${selector}`); } const { component, injector } = await this.compiler.resolveComponent(type, this.injector); const customElement = createCustomElement(component, { injector }); customElements.define(selector, customElement); await customElements.whenDefined(selector); this.defineds.add(selector); resolve(); } catch (error) { reject(error); } }); this.promises.set(selector, promise); return promise; } loadElements(selectors) { selectors = selectors.map((e) => e.trim().toLowerCase()).filter((s) => this.registry.has(s)); return from(Promise.all(selectors.map((s) => this.loadElement(s)))); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeElementService, deps: [{ token: i0.Injector }, { token: i1.CompilerService }, { token: NGE_ELEMENTS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeElementService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeElementService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: () => [{ type: i0.Injector }, { type: i1.CompilerService }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [NGE_ELEMENTS] }] }] }); // TODO make angular universal compatible using Renderer2 class NgeElementDetectorDirective { constructor(elementService) { this.elementService = elementService; } async ngAfterViewInit() { let selectors = this.elementService.listUnloadeds(); for (const selector of selectors) { const tags = document.getElementsByTagName(selector); if (tags?.length) { await this.elementService.loadElement(selector); selectors = selectors.filter((e) => e !== selector); } } this.addMutationObserver(); } ngOnDestroy() { this.observer?.disconnect(); if (this.listener) { this.listener(); } } addMutationObserver() { const target = document.body; let unloadedTags = this.elementService.listUnloadeds(); this.observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node instanceof HTMLElement) { unloadedTags = this.checkElementsInNode(node, unloadedTags); } }); }); }); this.observer.observe(target, { subtree: true, childList: true, }); } checkElementsInNode(node, unloadedTags) { if (!unloadedTags.length) { return unloadedTags; } const tagName = node.tagName.toLowerCase(); if (unloadedTags.includes(tagName)) { unloadedTags = unloadedTags.filter((e) => e !== tagName); this.elementService.loadElement(tagName).catch(console.error); } for (const child of Array.from(node.childNodes)) { if (child instanceof HTMLElement) { unloadedTags = this.checkElementsInNode(child, unloadedTags); } } return unloadedTags; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeElementDetectorDirective, deps: [{ token: NgeElementService }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.1", type: NgeElementDetectorDirective, selector: "nge-element-detector, [nge-element-detector]", ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeElementDetectorDirective, decorators: [{ type: Directive, args: [{ // tslint:disable-next-line: directive-selector selector: 'nge-element-detector, [nge-element-detector]', }] }], ctorParameters: () => [{ type: NgeElementService }] }); class NgeElementModule { static forRoot(elements) { return { ngModule: NgeElementModule, providers: [ { provide: NGE_ELEMENTS, useValue: elements, }, ], }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeElementModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.1", ngImport: i0, type: NgeElementModule, declarations: [NgeElementDetectorDirective], imports: [CommonModule], exports: [NgeElementDetectorDirective] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeElementModule, imports: [CommonModule] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: NgeElementModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [NgeElementDetectorDirective], exports: [NgeElementDetectorDirective], }] }] }); /** * Generated bundle index. Do not edit. */ export { NGE_ELEMENTS, NgeElementDetectorDirective, NgeElementModule, NgeElementService }; //# sourceMappingURL=cisstech-nge-elements.mjs.map