UNPKG

@mmuscat/angular-error-boundary

Version:
336 lines (328 loc) 13.1 kB
import { Subscriber, Subject, isObservable } from 'rxjs'; import * as i0 from '@angular/core'; import { EventEmitter, ErrorHandler, Component, SkipSelf, Output, Directive, Input, ContentChildren, Injectable, TemplateRef, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; class ValueSubscriber extends Subscriber { constructor(boundary, observer) { super(observer); this.boundary = boundary; boundary.subscription.add(this); } next() { super.complete(); this.unsubscribe(); } error(error) { super.error(error); this.unsubscribe(); } complete() { super.complete(); this.unsubscribe(); } unsubscribe() { this.boundary.subscription.remove(this); super.unsubscribe(); } } class CloakObserver { constructor(boundary) { this.boundary = boundary; } next(source) { const subscriber = new ValueSubscriber(this.boundary, this); subscriber.add(source.subscribe(subscriber)); } error(error) { this.boundary.handleError(error); } complete() { const { boundary } = this; if (boundary.refCount > 0) { boundary.refCount--; if (boundary.refCount === 0) { boundary.cloak(false); } } } } class NgCloak { constructor(elementRef, errorHandler, changeDetectorRef) { this.elementRef = elementRef; this.errorHandler = errorHandler; this.changeDetectorRef = changeDetectorRef; this.cloaked = false; this.refCount = 0; this.observer = new CloakObserver(this); this.queue = new Subject(); this.subscription = this.subscribe(); this.cloakChange = new EventEmitter(); } get element() { return this.elementRef.nativeElement; } register(parent) { this.parent = parent; } handleError(value) { if (isObservable(value)) { this.refCount++; this.queue.next(value); this.cloak(true); } else { this.refCount = 0; this.subscription.unsubscribe(); this.subscription = this.subscribe(); this.cloak(false); this.errorHandler.handleError(value); } } cloak(cloaked) { this.cloaked = cloaked; if (cloaked) this.changeDetectorRef.detach(); else this.changeDetectorRef.reattach(); if (!this.parent) this.render(); } render() { this.changeDetectorRef.detectChanges(); } subscribe() { return this.queue.subscribe(this.observer); } ngAfterContentInit() { this.cloak(this.refCount > 0); } ngOnDestroy() { this.subscription.unsubscribe(); } } NgCloak.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: NgCloak, deps: [{ token: i0.ElementRef }, { token: i0.ErrorHandler, skipSelf: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); NgCloak.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.0", type: NgCloak, selector: "ng-cloak", outputs: { cloakChange: "cloakChange" }, providers: [ { provide: ErrorHandler, useExisting: NgCloak, }, ], ngImport: i0, template: ` <ng-content select="fallback, [fallback]" *ngIf="cloaked; else content" ></ng-content> <ng-template #content> <ng-content></ng-content> </ng-template> `, isInline: true, directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: NgCloak, decorators: [{ type: Component, args: [{ selector: "ng-cloak", template: ` <ng-content select="fallback, [fallback]" *ngIf="cloaked; else content" ></ng-content> <ng-template #content> <ng-content></ng-content> </ng-template> `, providers: [ { provide: ErrorHandler, useExisting: NgCloak, }, ], }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ErrorHandler, decorators: [{ type: SkipSelf }] }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { cloakChange: [{ type: Output }] } }); class CloakListObserver { constructor(list, child, children) { this.list = list; this.child = child; this.children = children; } next() { this.list.render(this.children); } } class NgCloakList { constructor(elementRef, renderer) { this.elementRef = elementRef; this.renderer = renderer; this.revealOrder = "together"; } render(children) { const { elementRef: { nativeElement }, renderer, revealOrder, tail, } = this; let child; let previous = null; let renderChildren = children.slice(); if (revealOrder === "reverse") { renderChildren = renderChildren.reverse(); } while ((child = renderChildren.shift())) { if (tail === "hidden" && child.cloaked) break; if (revealOrder === "reverse") { renderer.insertBefore(nativeElement, child, previous); } else { renderer.appendChild(nativeElement, child.element); } previous = child; child.render(); if (tail === "collapsed" && child.cloaked) break; } while ((child = renderChildren.shift())) { renderer.removeChild(nativeElement, child.element); } } subscribe(children) { for (const child of children) { child.cloakChange.subscribe(new CloakListObserver(this, child, children)); } } ngAfterContentInit() { if (this.children) { this.subscribe(this.children.toArray()); } } } NgCloakList.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: NgCloakList, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); NgCloakList.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.0.0", type: NgCloakList, selector: "cloak-list", inputs: { revealOrder: "revealOrder", tail: "tail" }, queries: [{ propertyName: "children", predicate: NgCloak, descendants: true }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: NgCloakList, decorators: [{ type: Directive, args: [{ selector: "cloak-list", }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { revealOrder: [{ type: Input }], tail: [{ type: Input }], children: [{ type: ContentChildren, args: [NgCloak, { descendants: true }] }] } }); class ErrorLogger { error(error) { console.error(error); } } ErrorLogger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: ErrorLogger, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ErrorLogger.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: ErrorLogger, providedIn: "root" }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: ErrorLogger, decorators: [{ type: Injectable, args: [{ providedIn: "root" }] }] }); class ErrorBoundary { constructor(changeDetectorRef, logger, errorHandler) { this.changeDetectorRef = changeDetectorRef; this.logger = logger; this.errorHandler = errorHandler; this.hasError = false; this.error = new EventEmitter(); } ngDoCheck() { if (this.hasError) return; try { this.changeDetectorRef.detectChanges(); } catch (error) { this.handleError(error); } } ngAfterViewInit() { this.changeDetectorRef.detach(); } handleError(fault) { try { this.hasError = true; this.changeDetectorRef.detectChanges(); this.logger.error(fault); this.error.emit(new ErrorEvent("ErrorBoundary", { error: fault, })); } catch (doubleFault) { this.errorHandler.handleError(fault); if (fault !== doubleFault) { this.errorHandler.handleError(doubleFault); } } } retry() { this.hasError = false; this.changeDetectorRef.detectChanges(); } } ErrorBoundary.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: ErrorBoundary, deps: [{ token: i0.ChangeDetectorRef }, { token: ErrorLogger }, { token: i0.ErrorHandler, skipSelf: true }], target: i0.ɵɵFactoryTarget.Component }); ErrorBoundary.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.0", type: ErrorBoundary, selector: "error-boundary", outputs: { error: "error" }, providers: [ { provide: ErrorHandler, useExisting: ErrorBoundary, }, ], queries: [{ propertyName: "template", predicate: TemplateRef }], ngImport: i0, template: ` <ng-container *ngIf="hasError; else template?.first ?? null"> <ng-content select="fallback, [fallback]"></ng-content> </ng-container> `, isInline: true, directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: ErrorBoundary, decorators: [{ type: Component, args: [{ selector: "error-boundary", template: ` <ng-container *ngIf="hasError; else template?.first ?? null"> <ng-content select="fallback, [fallback]"></ng-content> </ng-container> `, providers: [ { provide: ErrorHandler, useExisting: ErrorBoundary, }, ], }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: ErrorLogger }, { type: i0.ErrorHandler, decorators: [{ type: SkipSelf }] }]; }, propDecorators: { error: [{ type: Output }], template: [{ type: ContentChildren, args: [TemplateRef, { descendants: false }] }] } }); class Fallback { } Fallback.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: Fallback, deps: [], target: i0.ɵɵFactoryTarget.Directive }); Fallback.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.0.0", type: Fallback, selector: "fallback, [fallback]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: Fallback, decorators: [{ type: Directive, args: [{ selector: "fallback, [fallback]" }] }] }); class BoundaryModule { } BoundaryModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: BoundaryModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); BoundaryModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: BoundaryModule, declarations: [ErrorBoundary, NgCloakList, NgCloak, Fallback], imports: [CommonModule], exports: [ErrorBoundary, NgCloakList, NgCloak, Fallback] }); BoundaryModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: BoundaryModule, imports: [[CommonModule]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.0", ngImport: i0, type: BoundaryModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [ErrorBoundary, NgCloakList, NgCloak, Fallback], exports: [ErrorBoundary, NgCloakList, NgCloak, Fallback], }] }] }); /* * Public API Surface of boundary */ /** * Generated bundle index. Do not edit. */ export { BoundaryModule, ErrorBoundary, ErrorLogger, Fallback, NgCloak, NgCloakList }; //# sourceMappingURL=mmuscat-angular-error-boundary.mjs.map