UNPKG

ng-busy

Version:
437 lines (425 loc) 20.9 kB
import * as i0 from '@angular/core'; import { Injectable, Component, Inject, Optional, EventEmitter, Injector, TemplateRef, Directive, Input, Output, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; import { Subject, BehaviorSubject, takeUntil, concatAll, take, timer, map, combineLatest, filter, from, tap, Observable, skip, distinctUntilChanged, Subscription } from 'rxjs'; import { style, trigger, transition, animate } from '@angular/animations'; class InstanceConfigHolderService { constructor() { } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: InstanceConfigHolderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: InstanceConfigHolderService, providedIn: 'any' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: InstanceConfigHolderService, decorators: [{ type: Injectable, args: [{ providedIn: 'any' }] }], ctorParameters: function () { return []; } }); class BusyConfig { constructor(config = {}) { for (const option of Object.keys(BUSY_CONFIG_DEFAULTS)) { this[option] = config[option] !== undefined ? config[option] : BUSY_CONFIG_DEFAULTS[option]; } } } class DefaultBusyComponent { constructor(instanceConfigHolder) { this.instanceConfigHolder = instanceConfigHolder; } get message() { return this.instanceConfigHolder.config.message; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: DefaultBusyComponent, deps: [{ token: 'instanceConfigHolder' }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.1", type: DefaultBusyComponent, selector: "default-busy", ngImport: i0, template: ` <div class="ng-busy-default-wrapper"> <div class="ng-busy-default-sign"> <div class="ng-busy-default-spinner"> <div class="bar1"></div> <div class="bar2"></div> <div class="bar3"></div> <div class="bar4"></div> <div class="bar5"></div> <div class="bar6"></div> <div class="bar7"></div> <div class="bar8"></div> <div class="bar9"></div> <div class="bar10"></div> <div class="bar11"></div> <div class="bar12"></div> </div> <div class="ng-busy-default-text">{{message}}</div> </div> </div> `, isInline: true }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: DefaultBusyComponent, decorators: [{ type: Component, args: [{ selector: 'default-busy', template: ` <div class="ng-busy-default-wrapper"> <div class="ng-busy-default-sign"> <div class="ng-busy-default-spinner"> <div class="bar1"></div> <div class="bar2"></div> <div class="bar3"></div> <div class="bar4"></div> <div class="bar5"></div> <div class="bar6"></div> <div class="bar7"></div> <div class="bar8"></div> <div class="bar9"></div> <div class="bar10"></div> <div class="bar11"></div> <div class="bar12"></div> </div> <div class="ng-busy-default-text">{{message}}</div> </div> </div> `, }] }], ctorParameters: function () { return [{ type: InstanceConfigHolderService, decorators: [{ type: Inject, args: ['instanceConfigHolder'] }] }]; } }); const BUSY_CONFIG_DEFAULTS = { template: DefaultBusyComponent, templateNgStyle: {}, delay: 0, minDuration: 0, backdrop: true, message: 'Please wait...', wrapperClass: 'ng-busy', disableAnimation: false }; function isPromise(value) { return value && typeof value.subscribe !== 'function' && typeof value.then === 'function'; } class BusyTrackerService { get isActive() { return this.active.value; } get busyList() { return [...this.busyQueue]; } get isBusy() { return this.busyQueue.filter(b => !b.closed).length > 0; } constructor() { this.busyQueue = []; this.operations = new Subject(); this.busyDone = new Subject(); this.destroyIndicator = new Subject(); this.checkSubject = new Subject(); this.processingIndicator = new BehaviorSubject(false); this.active = new BehaviorSubject(false); this.reset(); this.operations.pipe(takeUntil(this.destroyIndicator), concatAll()).subscribe(); this.checkSubject.pipe(takeUntil(this.destroyIndicator)).subscribe((options) => { this.processingIndicator.pipe(take(1)).subscribe((isProcessing) => { if (isProcessing === false && this.isBusy) { this.processingIndicator.next(true); timer(options.delay || 0).pipe(map(() => this.isBusy)).subscribe((stillBusy) => { if (stillBusy) { this.active.next(stillBusy); combineLatest([this.busyDone, timer(options.minDuration || 0)]) .pipe(takeUntil(this.active.pipe(filter(a => a === false)))) .subscribe(() => { if (!this.isBusy) { this.reset(); } }); } else { this.processingIndicator.next(false); } }); } }); }); } load(options) { this.operations.next(from(options.busyList).pipe(filter(busy => busy !== null && busy !== undefined && !busy.hasOwnProperty('__loaded_mark_by_ng_busy')), tap((busy) => Object.defineProperty(busy, '__loaded_mark_by_ng_busy', { value: true, configurable: false, enumerable: false, writable: false })), map((busy) => isPromise(busy) ? from(busy).subscribe() : busy), tap(subscription => this.appendToQueue(subscription)))); this.checkSubject.next(options); } updateActiveStatus() { this.busyQueue = this.busyQueue.filter((cur) => cur && !cur.closed); if (this.busyQueue.length === 0) { this.busyDone.next(true); } } reset() { this.active.next(false); this.busyQueue = []; this.processingIndicator.next(false); } appendToQueue(busy) { this.busyQueue.push(busy); busy.add(() => { this.operations.next(new Observable((subscriber) => { this.updateActiveStatus(); subscriber.complete(); })); }); } ngOnDestroy() { this.destroyIndicator.next(null); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: BusyTrackerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: BusyTrackerService, providedIn: 'any' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: BusyTrackerService, decorators: [{ type: Injectable, args: [{ providedIn: 'any' }] }], ctorParameters: function () { return []; } }); class BusyConfigHolderService { constructor(config) { this.config = Object.assign({}, BUSY_CONFIG_DEFAULTS, config || new BusyConfig()); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: BusyConfigHolderService, deps: [{ token: BusyConfig, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: BusyConfigHolderService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: BusyConfigHolderService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: BusyConfig, decorators: [{ type: Optional }] }]; } }); const inactiveStyle = style({ opacity: 0, transform: 'translateY(-40px)' }); const timing = '.3s ease'; class NgBusyComponent { constructor(instanceConfigHolder, busyEmitter, vcr, cdr) { this.instanceConfigHolder = instanceConfigHolder; this.busyEmitter = busyEmitter; this.vcr = vcr; this.cdr = cdr; this.disableAnimation = false; this.showBackdrop = true; this.destroyIndicator = new Subject(); this.show = new Subject(); this.show.pipe(takeUntil(this.destroyIndicator)).subscribe(() => { this.cdr.detectChanges(); }); this.busyEmitter.pipe(takeUntil(this.destroyIndicator)) .subscribe((isActive) => { if (isActive === true) { const config = this.instanceConfigHolder.config; this.wrapperClass = config.wrapperClass; this.showBackdrop = config.backdrop; this.disableAnimation = config.disableAnimation; } this.show.next(isActive); }); } ngOnDestroy() { this.destroyIndicator.next(null); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: NgBusyComponent, deps: [{ token: 'instanceConfigHolder' }, { token: 'busyEmitter' }, { token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.1", type: NgBusyComponent, selector: "lib-ng-busy", ngImport: i0, template: "<ng-container *ngIf=\"show | async\">\r\n <div [class]=\"wrapperClass\" @flyInOut [@.disabled]=\"disableAnimation\">\r\n <ng-content></ng-content>\r\n </div>\r\n <div class=\"ng-busy-backdrop\" @flyInOut [@.disabled]=\"disableAnimation\" *ngIf=\"showBackdrop\">\r\n </div>\r\n</ng-container>\r\n", styles: [""], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], animations: [ trigger('flyInOut', [ transition('void => *', [ inactiveStyle, animate(timing) ]), transition('* => void', [ animate(timing, inactiveStyle) ]) ]) ] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: NgBusyComponent, decorators: [{ type: Component, args: [{ selector: 'lib-ng-busy', animations: [ trigger('flyInOut', [ transition('void => *', [ inactiveStyle, animate(timing) ]), transition('* => void', [ animate(timing, inactiveStyle) ]) ]) ], template: "<ng-container *ngIf=\"show | async\">\r\n <div [class]=\"wrapperClass\" @flyInOut [@.disabled]=\"disableAnimation\">\r\n <ng-content></ng-content>\r\n </div>\r\n <div class=\"ng-busy-backdrop\" @flyInOut [@.disabled]=\"disableAnimation\" *ngIf=\"showBackdrop\">\r\n </div>\r\n</ng-container>\r\n" }] }], ctorParameters: function () { return [{ type: InstanceConfigHolderService, decorators: [{ type: Inject, args: ['instanceConfigHolder'] }] }, { type: i0.EventEmitter, decorators: [{ type: Inject, args: ['busyEmitter'] }] }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } }); class NgBusyDirective { set options(op) { this._option = op; } get options() { return this._option; } get trackerService() { return this.tracker; } constructor(configHolder, instanceConfigHolder, tracker, cdr, vcr, renderer, injector) { this.configHolder = configHolder; this.instanceConfigHolder = instanceConfigHolder; this.tracker = tracker; this.cdr = cdr; this.vcr = vcr; this.renderer = renderer; this.injector = injector; this.busyStart = new EventEmitter(); this.busyStop = new EventEmitter(); this.destroyIndicator = new Subject(); this.configLoader = new Subject(); this.busyEmitter = new EventEmitter(); tracker.active.pipe(skip(1), takeUntil(this.destroyIndicator), distinctUntilChanged()).subscribe((status) => { if (status === true) { this.recreateBusyIfNecessary(); this.busyStart.emit(); } else { this.busyStop.emit(); } this.busyEmitter.next(status); }); this.configLoader.pipe(takeUntil(this.destroyIndicator)).subscribe((config) => { const busyList = config.busy.filter(b => b?.['closed'] !== true && !b?.hasOwnProperty?.('__loaded_mark_by_ng_busy')); this.optionsNorm = config; this.instanceConfigHolder.config = this.optionsNorm; if (busyList.length > 0) { this.tracker.load({ busyList, delay: this.optionsNorm.delay, minDuration: this.optionsNorm.minDuration }); } }); } ngDoCheck() { this.configLoader.next(this.normalizeOptions(this.options)); } ngOnDestroy() { this.destroyIndicator.next(null); } recreateBusyIfNecessary() { this.destroyComponents(); this.template = this.optionsNorm.template; this.templateNgStyle = this.optionsNorm.templateNgStyle; this.createBusy(); } normalizeOptions(options) { if (!options) { options = { busy: [] }; } else if (Array.isArray(options)) { options = { busy: options }; } else if (isPromise(options) || options instanceof Subscription) { options = { busy: [options] }; } options = Object.assign({}, this.configHolder.config, options); if (!Array.isArray(options.busy)) { options.busy = [options.busy]; } return options; } destroyComponents() { if (this.busyRef) { this.busyRef.destroy(); } } createBusy() { const injector = Injector.create({ providers: [ { provide: 'instanceConfigHolder', useValue: this.instanceConfigHolder }, { provide: 'busyEmitter', useValue: this.busyEmitter } ], parent: this.injector }); this.template = this.optionsNorm.template; this.busyRef = this.vcr.createComponent(NgBusyComponent, { injector, projectableNodes: this.generateNgContent(injector) }); this.busyRef.onDestroy(() => { this.busyRef.instance.ngOnDestroy(); }); this.cdr.markForCheck(); this.busyRef.hostView.detectChanges(); } generateNgContent(injector) { if (typeof this.template === 'string') { const element = this.renderer.createText(this.template); return [[element]]; } if (this.template instanceof TemplateRef) { const context = {}; const viewRef = this.template.createEmbeddedView(context); return [viewRef.rootNodes]; } if (typeof this.template === 'function') { const factory = this.vcr.createComponent(this.template, { injector }); factory.onDestroy(() => { factory?.instance?.ngOnDestroy?.(); }); factory.changeDetectorRef.markForCheck(); return [[factory.location.nativeElement]]; } return [[]]; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: NgBusyDirective, deps: [{ token: BusyConfigHolderService }, { token: InstanceConfigHolderService }, { token: BusyTrackerService }, { token: i0.ChangeDetectorRef }, { token: i0.ViewContainerRef }, { token: i0.Renderer2 }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.1.1", type: NgBusyDirective, selector: "[ngBusy]", inputs: { options: ["ngBusy", "options"] }, outputs: { busyStart: "busyStart", busyStop: "busyStop" }, providers: [BusyTrackerService, InstanceConfigHolderService], exportAs: ["ngBusy"], ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: NgBusyDirective, decorators: [{ type: Directive, args: [{ selector: '[ngBusy]', providers: [BusyTrackerService, InstanceConfigHolderService], exportAs: 'ngBusy' }] }], ctorParameters: function () { return [{ type: BusyConfigHolderService }, { type: InstanceConfigHolderService }, { type: BusyTrackerService }, { type: i0.ChangeDetectorRef }, { type: i0.ViewContainerRef }, { type: i0.Renderer2 }, { type: i0.Injector }]; }, propDecorators: { options: [{ type: Input, args: ['ngBusy'] }], busyStart: [{ type: Output }], busyStop: [{ type: Output }] } }); class NgBusyModule { static forRoot(config) { return { ngModule: NgBusyModule, providers: [ { provide: BusyConfig, useValue: config } ] }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: NgBusyModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.1.1", ngImport: i0, type: NgBusyModule, declarations: [DefaultBusyComponent, NgBusyDirective, NgBusyComponent], imports: [CommonModule], exports: [NgBusyDirective] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: NgBusyModule, providers: [BusyConfigHolderService, BusyTrackerService], imports: [CommonModule] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: NgBusyModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [DefaultBusyComponent, NgBusyDirective, NgBusyComponent], providers: [BusyConfigHolderService, BusyTrackerService], exports: [NgBusyDirective] }] }] }); /* * Public API Surface of ng-busy */ /** * Generated bundle index. Do not edit. */ export { BUSY_CONFIG_DEFAULTS, BusyConfig, BusyTrackerService, DefaultBusyComponent, InstanceConfigHolderService, NgBusyComponent, NgBusyDirective, NgBusyModule, isPromise }; //# sourceMappingURL=ng-busy.mjs.map