UNPKG

ngx-smart-loader

Version:

Smart loader handler to manage loaders everywhere in Angular apps.

483 lines (473 loc) 14.2 kB
/** * @license ngx-smart-loader * MIT license */ import { ChangeDetectorRef, Component, EventEmitter, Injectable, Input, NgModule, Output } from '@angular/core'; import { CommonModule } from '@angular/common'; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class NgxSmartLoaderService { constructor() { this._loaderStack = []; this._actions = []; } /** * Add a new loader instance. This step is essential and allows to retrieve any loader at any time. * It stores an object that contains the given loader identifier and the loader itself directly in the `loaderStack`. * * @param {?} loaderInstance The object that contains the given loader identifier and the loader itself. * @param {?=} force Optional parameter that forces the overriding of loader instance if it already exists. * @return {?} Returns nothing special. */ addLoader(loaderInstance, force) { if (force) { const /** @type {?} */ i = this._loaderStack.findIndex((o) => { return o.id === loaderInstance.id; }); if (i > -1) { this._loaderStack[i].component = loaderInstance.component; } else { this._loaderStack.push(loaderInstance); } return; } let /** @type {?} */ loader; if (loader = this._getLoader(loaderInstance.id)) { throw (new Error('Loader with ' + loaderInstance.id + ' identifier already exist')); } else { this._loaderStack.push(loaderInstance); } } /** * Remove a loader instance from the loader stack. * * @param {?} id The loader identifier. * @return {?} */ removeLoader(id) { this._loaderStack = this._loaderStack.filter((loader) => loader.id !== id); this._removeAction(id, '*'); } /** * Retrieve all the created loaders. * * @return {?} Returns an array that contains all loader instances. */ getLoaderStack() { return this._loaderStack; } /** * It gives the number of loader instances. It's helpful to know if the loader stack is empty or not. * * @return {?} Returns the number of loader instances. */ getLoaderStackCount() { return this._loaderStack.length; } /** * Retrieve all the opened loaders. It looks for all loader instances with their `visible` property set to `true`. * * @return {?} Returns an array that contains all the opened loaders. */ getOpenedLoaders() { return this._loaderStack.filter((loader) => loader.component.visible); } /** * Retrieve all the active loaders. It looks for all loader instances with their `loading` property set to `true`. * * @return {?} Returns an array that contains all the active loaders. */ getActiveLoaders() { return this._loaderStack.filter((loader) => loader.component.loading); } /** * Get the higher `z-index` value between all the loader instances. It iterates over the `LoaderStack` array and * calculates a higher value (it takes the highest index value between all the loader instances and adds 1). * Use it to make a loader appear foreground. * * @return {?} Returns a higher index from all the existing loader instances. */ getHigherIndex() { const /** @type {?} */ index = this.getOpenedLoaders().map((loader) => loader.component.layerPosition); return Math.max(...index) + 1; } /** * Enable loading state to one or several loaders. * * @param {?} id The loader identifier. * @return {?} */ start(id) { let /** @type {?} */ loader; if (Array.isArray(id)) { id.forEach((i) => { this.start(i); }); } else if (loader = this._getLoader(id)) { loader.component.start(); this._removeAction(id, 'start'); } else { this._addAction(id, 'start'); } } /** * Enable loading state to all loaders. * @return {?} */ startAll() { this._loaderStack.forEach((loader) => this.start(loader.id)); } /** * Disable loading state to one or several loaders. * * @param {?} id The loader identifier. * @return {?} */ stop(id) { let /** @type {?} */ loader; if (Array.isArray(id)) { id.forEach((i) => { this.stop(i); }); } else if (loader = this._getLoader(id)) { loader.component.stop(); this._removeAction(id, 'stop'); } else { this._addAction(id, 'stop'); } } /** * Disable loading state to all loaders. * @return {?} */ stopAll() { this._loaderStack.forEach((loader) => this.stop(loader.id)); } /** * @param {?} id * @return {?} */ isLoading(id) { let /** @type {?} */ loader; if (Array.isArray(id)) { const /** @type {?} */ tmp = []; id.forEach((i) => { this._loaderStack.forEach((load) => { if (load.id === i) { tmp.push(load.component.loading); } }); }); return tmp.indexOf(false) === -1; } else if (loader = this._getLoader(id)) { return loader.component.loading; } else { return false; } } /** * Execute an action on loaders * * @param {?} id The loader identifier. * @param {?} action Name of the action. * @return {?} */ executeAction(id, action) { if (this._actions.find((act) => act.identifier === id && act.action === action)) { switch (action) { case 'start': this.start(id); break; case 'stop': this.stop(id); break; } } } /** * Retrieve a loader instance by its identifier. * If there's several loaders with same identifier, the first is returned. * * @param {?} id The loader identifier used at creation time. * @return {?} */ _getLoader(id) { return this._loaderStack.find((load) => load.id === id) || null; } /** * Adds an action on one or more loaders * * @param {?} id The loader identifier. * @param {?} action Name of the action. * @return {?} */ _addAction(id, action) { if (Array.isArray(id)) { id.forEach((i) => { this._addAction(i, action); }); } else { this._actions.push({ identifier: id, action: action }); } } /** * Remove an action on one or more loaders * * @param {?} id The loader identifier. * @param {?} action Name of the action. * @return {?} */ _removeAction(id, action) { if (Array.isArray(id)) { id.forEach((i) => { this._removeAction(i, action); }); } else { this._actions = this._actions.filter((act) => act.identifier !== id || (act.action !== action && action !== '*')); } } } NgxSmartLoaderService.decorators = [ { type: Injectable }, ]; /** @nocollapse */ NgxSmartLoaderService.ctorParameters = () => []; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class LoaderInstance { /** * @param {?} component */ constructor(component) { this.id = component.identifier; this.component = component; } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class NgxSmartLoaderComponent { /** * @param {?} ngxSmartLoaderService * @param {?} changeDetectorRef */ constructor(ngxSmartLoaderService, changeDetectorRef) { this.ngxSmartLoaderService = ngxSmartLoaderService; this.changeDetectorRef = changeDetectorRef; this.identifier = ''; this.customClass = ''; this.force = false; this.delayIn = 0; this.delayOut = 0; this.autostart = false; this.onStart = new EventEmitter(); this.onStop = new EventEmitter(); this.onVisibleChange = new EventEmitter(); this.loading = false; this.visible = false; this.layerPosition = 999; this._isProcessing = false; this._loaderBodyClass = 'loader-open'; this._enterClass = 'enter'; this._leaveClass = 'leave'; } /** * @return {?} */ ngOnInit() { try { const /** @type {?} */ loader = new LoaderInstance(this); this.ngxSmartLoaderService.addLoader(loader, this.force); this.layerPosition += this.ngxSmartLoaderService.getLoaderStackCount(); this.addCustomClass(this.identifier.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()); if (this.autostart) { this.ngxSmartLoaderService.start(this.identifier); } else { this.ngxSmartLoaderService.executeAction(this.identifier, 'start'); } } catch (/** @type {?} */ error) { throw (error); } } /** * @return {?} */ ngOnDestroy() { this.ngxSmartLoaderService.removeLoader(this.identifier); } /** * @param {?=} top * @return {?} */ start(top) { this._isProcessing = true; clearInterval(this._debouncer); this.visible = true; setTimeout(() => { this.addCustomClass(this._enterClass); }); this._debouncer = setTimeout(() => { if (top) { this.layerPosition = this.ngxSmartLoaderService.getHigherIndex(); } if (!document.body.classList.contains(this._loaderBodyClass)) { document.body.classList.add(this._loaderBodyClass); } this.loading = true; this.onStart.emit(this); this.onVisibleChange.emit(this); this.removeCustomClass(this._enterClass); this._isProcessing = false; }, this.delayIn); } /** * @return {?} */ stop() { if (this._isProcessing) { this.visible = false; this.loading = false; } clearInterval(this._debouncer); this.addCustomClass(this._leaveClass); this.loading = false; this._debouncer = setTimeout(() => { if (document.body.classList.contains(this._loaderBodyClass)) { document.body.classList.remove(this._loaderBodyClass); } this.visible = false; this.onStop.emit(this); this.onVisibleChange.emit(this); this.removeCustomClass(this._leaveClass); setTimeout(() => { this.changeDetectorRef.markForCheck(); }); }, this.delayOut); } /** * @param {?} className * @return {?} */ addCustomClass(className) { if (!this.customClass.length) { this.customClass = className; } else { if (this.customClass.indexOf(className) === -1) { this.customClass += ' ' + className; } } } /** * @param {?=} className * @return {?} */ removeCustomClass(className) { if (className) { this.customClass = this.customClass.replace(className, '').trim(); } else { this.customClass = ''; } } } NgxSmartLoaderComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-smart-loader', template: ` <div class="loader-container {{customClass}}" [ngClass]="{'active': loading}" [style.z-index]="layerPosition - 1" *ngIf="visible"> <ng-content></ng-content> </div> ` },] }, ]; /** @nocollapse */ NgxSmartLoaderComponent.ctorParameters = () => [ { type: NgxSmartLoaderService, }, { type: ChangeDetectorRef, }, ]; NgxSmartLoaderComponent.propDecorators = { "identifier": [{ type: Input },], "customClass": [{ type: Input },], "force": [{ type: Input },], "delayIn": [{ type: Input },], "delayOut": [{ type: Input },], "autostart": [{ type: Input },], "onStart": [{ type: Output },], "onStop": [{ type: Output },], "onVisibleChange": [{ type: Output },], }; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class NgxSmartLoaderModule { /** * Use in AppModule: new instance of NgxSmartLoader. * @return {?} */ static forRoot() { return { ngModule: NgxSmartLoaderModule, providers: [NgxSmartLoaderService] }; } /** * Use in features modules with lazy loading: new instance of NgxSmartLoader. * @return {?} */ static forChild() { return { ngModule: NgxSmartLoaderModule, providers: [NgxSmartLoaderService] }; } } NgxSmartLoaderModule.decorators = [ { type: NgModule, args: [{ declarations: [NgxSmartLoaderComponent], exports: [NgxSmartLoaderComponent], imports: [CommonModule] },] }, ]; /** @nocollapse */ NgxSmartLoaderModule.ctorParameters = () => []; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ // Public classes. /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * Entry point for all public APIs of the package. */ /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * Generated bundle index. Do not edit. */ export { NgxSmartLoaderService, NgxSmartLoaderComponent, NgxSmartLoaderModule }; //# sourceMappingURL=ngx-smart-loader.js.map