UNPKG

@bespunky/angular-zen

Version:

The Angular tools you always wished were there.

229 lines (223 loc) 11 kB
import * as i0 from '@angular/core'; import { NgModule, Injectable } from '@angular/core'; import * as i1 from '@bespunky/angular-zen/core'; import { CoreModule } from '@bespunky/angular-zen/core'; import * as i2 from '@bespunky/angular-zen/universal'; import { UniversalModule } from '@bespunky/angular-zen/universal'; import { of, Observable } from 'rxjs'; class AsyncModule { } AsyncModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AsyncModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); AsyncModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.12", ngImport: i0, type: AsyncModule, imports: [CoreModule, UniversalModule], exports: [CoreModule] }); AsyncModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AsyncModule, imports: [CoreModule, UniversalModule, CoreModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: AsyncModule, decorators: [{ type: NgModule, args: [{ declarations: [], imports: [CoreModule, UniversalModule], exports: [CoreModule] }] }] }); /** * Provides methods for lazy loading scripts and styles programatically. * The service keeps track of loaded files to skip reloading unless specified otherwise in the options of `loadScript()` or `loadStyle()`. */ class LazyLoaderService { constructor(head, universal) { this.head = head; this.universal = universal; /** * Defines the default options when calling the `LazyLoaderService.loadScript()` method. */ this.defaultScriptOptions = { async: true, defer: true, alreadyLoaded: (url) => this.isCached(url) || this.isScriptPresent(url), force: false }; /** * Defines the default options when calling the `LazyLoaderService.loadStyle()` method. */ this.defaultStyleOptions = { alreadyLoaded: (url) => this.isCached(url) || this.isStylePresent(url), force: false }; this.cache = {}; } /** * Checks whether the file from the specified url has already been cached. * @param url The url for the file to check. * @returns A value indicating whether the file from the specified url has already been cached. */ isCached(url) { return !!this.cache[url]; } /** * Checks whether a script element is already present in `<head>` for the given url. * This doesn't guarantee that the script has been loaded. * * @param {string} url The url of the loaded script. * @returns {boolean} `true` if an element matching the url is present in `<head>`; otherwise `false. */ isScriptPresent(url) { return this.head.contains('script', { src: url }); } /** * Checks whether a link element is already present in `<head>` for the given style url. * This doesn't guarantee that the style has been loaded. * * @param {string} url The url of the loaded link. * @returns {boolean} `true` if an element matching the url is present in `<head>`; otherwise `false. */ isStylePresent(url) { return this.head.contains('link', { rel: 'stylesheet', href: url }); } /** * Loads a script programatically. * * @param url The full url of the script to load. * @param options (Optional) Specifies custom options to override default behaviour. * @returns An observable object which allows subscribers to know when the script has been loaded and access its associated `<script>` element. * The observable will complete immediately in case the script was already previously loaded. * If the script was already loaded outside of the service, the observable will stream `undefined`. */ loadScript(url, options = this.defaultScriptOptions) { // Set default options if not specified by caller options.async = options.async === undefined ? this.defaultScriptOptions.async : options.async; options.defer = options.defer === undefined ? this.defaultScriptOptions.defer : options.defer; options.alreadyLoaded = options.alreadyLoaded === undefined ? this.defaultScriptOptions.alreadyLoaded : options.alreadyLoaded; options.force = options.force === undefined ? this.defaultScriptOptions.force : options.force; return this.loadFile(url, 'script', options, this.createScriptElement.bind(this)); } /** * Loads a style programatically. * * @param url The full url of the style to load. * @param options (Optional) Specifies custom options to override default behaviour. * @returns An observable object which allows subscribers to know when the style has been loaded and access its associated `<link>` element. * The observable will complete immediately in case the style was already previously loaded. * If the style was already loaded outside of the service, the observable will stream `undefined`. */ loadStyle(url, options = this.defaultStyleOptions) { // Set default options if not specified by caller options.alreadyLoaded = options.alreadyLoaded === undefined ? this.defaultStyleOptions.alreadyLoaded : options.alreadyLoaded; options.force = options.force === undefined ? this.defaultStyleOptions.force : options.force; return this.loadFile(url, 'style', options, this.createLinkElement.bind(this)); } loadFile(url, type, options, createElement) { if (!this.universal.isPlatformBrowser) return of(null); // If the script should be loaded, load it if (!options.alreadyLoaded(url) || options.force) { // Initialize a base object to store the data later const lazyFile = { url, type, completed: false, element: null }; // Create an observable that waits until the script has been loaded and executed const observable = new Observable(observer => { // Create the callback that will mark the script as completed and notify the subscriber const onLoad = () => { lazyFile.completed = true; observer.next(lazyFile); observer.complete(); }; // Create the actual file tag, start downloading and store the element reference lazyFile.element = createElement(url, onLoad, observer.error.bind(observer), options); }); // Cache the file and the observable for later use this.cache[url] = { lazyFile: lazyFile, observable }; return observable; } // If the file was already loaded and it shouldn't be downloaded again, complete immediately with the previous link data. // If the file was already loaded outside of the service, the observable will stream `undefined` as there is nothing cached. return of(this.cache[url]?.lazyFile); } /** * Creates a `<script>` tag for the given url and adds it to the `<head>` tag to start downloading the script. * * @param url The url for the script to download. * @param onLoad The callback to execute when the script has been downloaded and executed. * @param onError The callback to execute when script download or execution has failed. * @param options The options to add to the script. * @returns A reference to the `<script>` element that was added to the DOM. */ createScriptElement(url, onLoad, onError, options) { return this.head.addScriptElement('text/javascript', url, { async: options.async, defer: options.defer, onload: onLoad, onerror: onError }); } /** * Creates a `<link>` tag for the given url and adds it to the `<head>` tag to start downloading the link. * * @param url The url for the link to download. * @param onLoad The callback to execute when the script has been downloaded and executed. * @param onError The callback to execute when script download or execution has failed. * @returns A reference to the `<link>` element that was added to the DOM. */ createLinkElement(url, onLoad, onError) { return this.head.addLinkElement('stylesheet', { type: 'text/css', href: url, onload: onLoad, onerror: onError }); } } LazyLoaderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LazyLoaderService, deps: [{ token: i1.HeadService }, { token: i2.UniversalService }], target: i0.ɵɵFactoryTarget.Injectable }); LazyLoaderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LazyLoaderService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LazyLoaderService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: i1.HeadService }, { type: i2.UniversalService }]; } }); /** * Creates a promise without which doesn't have the actual async code to resolve, and extracts its `resolve()` and `reject()` methods for later use. * Use this when you have to create a promise for an async code that runs in a place different to the one where you create the promise, and it will * allow you full control of the promise from other parts of your code. * * @example * import { promiseLater } from '@bespunky/angular-zen/core'; * // Other imports... * * export class SomeDirective implements OnInit, OnChanges * { * private const waitForInit: Promise<SomeType>; * * constructor() * { * this.waitForInit = promiseLater(); * } * * ngOnInit() * { * this.waitForInit.resolve(); * } * * ngOnChanges(changes: SimpleChanges) * { * this.waitForInit.promise.then(() => { * // ... Some code * }); * } * } * * @export * @template T The type of the value promised after resolving the async operation. * @returns An object containing the promise, anlong with its `resolve()` and `reject()` methods. */ function promiseLater() { const latePromise = {}; const promise = new Promise((resolve, reject) => { latePromise.resolve = resolve; latePromise.reject = reject; }); latePromise.promise = promise; return latePromise; } /** * Generated bundle index. Do not edit. */ export { AsyncModule, LazyLoaderService, promiseLater }; //# sourceMappingURL=bespunky-angular-zen-async.mjs.map