@dbg-riskit/angular-view
Version:
1 lines • 89 kB
Source Map (JSON)
{"version":3,"file":"dbg-riskit-angular-view.mjs","sources":["../../../../pkg/dbg-riskit/angular-view/src/lib/message.component.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/message.component.html","../../../../pkg/dbg-riskit/angular-view/src/lib/base.component.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/flex.component.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/flex.spacer.component.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/loader.component.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/message.dialog.component.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/message.dialog.component.html","../../../../pkg/dbg-riskit/angular-view/src/lib/percent.pipe.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/progress.loader.component.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/dialog.service.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/match.media.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/layout.component.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/layout.component.html","../../../../pkg/dbg-riskit/angular-view/src/lib/sub.link.directive.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/link.active.directive.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/toolbar.component.ts","../../../../pkg/dbg-riskit/angular-view/src/lib/common.view.module.ts","../../../../pkg/dbg-riskit/angular-view/src/dbg-riskit-angular-view.ts"],"sourcesContent":["import {ChangeDetectionStrategy, Component, ElementRef, Input} from '@angular/core';\n\nexport const RISK_ERROR_SELECTOR = 'risk-error';\nexport const RISK_GOOD_SELECTOR = 'risk-good';\nexport const RISK_INFO_SELECTOR = 'risk-info';\nexport const RISK_MESSAGE_SELECTOR = 'risk-message';\nexport const RISK_WARN_SELECTOR = 'risk-warn';\n\nexport const RISK_INITIAL_LOAD_SELECTOR = 'risk-initial-load';\nexport const RISK_NO_DATA_SELECTOR = 'risk-no-data';\nexport const RISK_UPDATE_FAILED_SELECTOR = 'risk-update-failed';\n\nexport const COMPONENT_SELECTOR = RISK_ERROR_SELECTOR + ', ' + RISK_GOOD_SELECTOR + ', ' + RISK_INFO_SELECTOR + ', '\n + RISK_MESSAGE_SELECTOR + ', ' + RISK_WARN_SELECTOR + ', '\n + RISK_INITIAL_LOAD_SELECTOR + ', ' + RISK_NO_DATA_SELECTOR + ', '\n + RISK_UPDATE_FAILED_SELECTOR;\n\nconst COLOR_EQUALS = 'color === \"';\n\n@Component({\n selector : COMPONENT_SELECTOR,\n templateUrl : 'message.component.html',\n styleUrls : [\n '../../../component.scss',\n 'message.component.scss'\n ],\n host : {\n '[class.risk-message]' : 'true',\n '[class.risk-message-error]' : COLOR_EQUALS + RISK_ERROR_SELECTOR + '\"',\n '[class.risk-message-warn]' : COLOR_EQUALS + RISK_WARN_SELECTOR + '\"',\n '[class.risk-message-good]' : COLOR_EQUALS + RISK_GOOD_SELECTOR + '\"',\n '[class.risk-message-info]' : COLOR_EQUALS + RISK_INFO_SELECTOR + '\"',\n '[class.risk-message-initial-load]': 'initialLoad',\n '[class.risk-message-no-data]' : 'noData',\n '[class.risk-message-update-error]': 'updateError'\n },\n changeDetection : ChangeDetectionStrategy.OnPush,\n preserveWhitespaces: false\n})\nexport class MessageComponent {\n\n private readonly _initialLoad: boolean;\n private readonly _noData: boolean;\n private readonly _updateError: boolean;\n private readonly _color: typeof RISK_GOOD_SELECTOR\n | typeof RISK_INFO_SELECTOR\n | typeof RISK_ERROR_SELECTOR\n | typeof RISK_WARN_SELECTOR\n | null;\n\n @Input('message')\n public message?: string;\n\n public constructor(elementRef: ElementRef) {\n const tagName = elementRef.nativeElement.tagName.toLowerCase();\n this._initialLoad = tagName === RISK_INITIAL_LOAD_SELECTOR;\n this._noData = tagName === RISK_NO_DATA_SELECTOR;\n this._updateError = tagName === RISK_UPDATE_FAILED_SELECTOR;\n switch (tagName) {\n case RISK_INFO_SELECTOR:\n case RISK_NO_DATA_SELECTOR:\n this._color = RISK_INFO_SELECTOR;\n break;\n case RISK_WARN_SELECTOR:\n case RISK_INITIAL_LOAD_SELECTOR:\n this._color = RISK_WARN_SELECTOR;\n break;\n case RISK_ERROR_SELECTOR:\n case RISK_UPDATE_FAILED_SELECTOR:\n this._color = RISK_ERROR_SELECTOR;\n break;\n case RISK_GOOD_SELECTOR:\n this._color = RISK_GOOD_SELECTOR;\n break;\n default:\n this._color = null;\n }\n }\n\n public get color(): string | null {\n return this._color;\n }\n\n public get initialLoad(): boolean {\n return this._initialLoad;\n }\n\n public get noData(): boolean {\n return this._noData;\n }\n\n public get updateError(): boolean {\n return this._updateError;\n }\n}\n","<mat-card [ngClass]=\"color\">\n <ng-template [ngIf]=\"initialLoad\">\n <mat-spinner [diameter]=\"50\"></mat-spinner>\n Loading...\n </ng-template>\n <ng-template [ngIf]=\"noData\">No data available.</ng-template>\n <ng-template [ngIf]=\"updateError\">Failed to update the data: {{message}}.</ng-template>\n <ng-template [ngIf]=\"!initialLoad && !noData && !updateError\">{{message}}</ng-template>\n <ng-content></ng-content>\n</mat-card>","import {Directive, OnDestroy} from '@angular/core';\n\nimport {Observable, Subject} from 'rxjs';\n\n@Directive()\nexport class BaseComponent implements OnDestroy {\n private readonly _destroyed = new Subject<void>();\n\n public ngOnDestroy(): void {\n this._destroyed.next();\n this._destroyed.complete();\n }\n\n public get destroyed(): Observable<void> {\n return this._destroyed.asObservable();\n }\n}\n","import {ChangeDetectionStrategy, Component, Input} from '@angular/core';\n\n@Component({\n selector : 'risk-flex',\n template : '<ng-content></ng-content>',\n styleUrls : [\n '../../../component.scss',\n 'flex.component.scss'\n ],\n host : {\n '[class.risk-flex]' : '!wrapContent',\n '[class.risk-flex-wrap]': 'wrapContent'\n },\n changeDetection : ChangeDetectionStrategy.OnPush,\n preserveWhitespaces: false\n})\nexport class FlexComponent {\n\n @Input()\n public wrapContent = false;\n}\n","import {ChangeDetectionStrategy, Component} from '@angular/core';\n\n@Component({\n selector : 'risk-flex-spacer',\n template : '',\n styleUrls : [\n '../../../component.scss'\n ],\n host : {\n '[class.risk-flex-spacer]': 'true'\n },\n changeDetection : ChangeDetectionStrategy.OnPush,\n preserveWhitespaces: false\n})\nexport class FlexSpacerComponent {\n}\n","import {ChangeDetectionStrategy, Component, Inject} from '@angular/core';\nimport {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';\nimport {DialogComponent} from './dialog.service';\n\nexport interface DialogData {\n title?: string;\n cancel?: () => void;\n}\n\n@Component({\n template : `\n <risk-flex [wrapContent]=\"true\">\n <risk-flex-spacer></risk-flex-spacer>\n <mat-spinner></mat-spinner>\n <risk-flex-spacer></risk-flex-spacer>\n </risk-flex>\n <risk-flex *ngIf=\"dialogData.title\" [wrapContent]=\"true\">\n <risk-flex-spacer></risk-flex-spacer>\n <h3>{{ dialogData.title }}</h3>\n <risk-flex-spacer></risk-flex-spacer>\n </risk-flex>\n <risk-flex *ngIf=\"dialogData.cancel != null\" [wrapContent]=\"true\">\n <risk-flex-spacer></risk-flex-spacer>\n <button mat-button color=\"warn\" (click)=\"dialogData.cancel()\">Cancel</button>\n <risk-flex-spacer></risk-flex-spacer>\n </risk-flex>\n `,\n styles : [\n `\n h3 {\n margin-bottom: 0;\n }`\n ],\n host : {\n '[class.risk-loader-dialog]': 'true'\n },\n changeDetection : ChangeDetectionStrategy.OnPush,\n preserveWhitespaces: false\n})\nexport class LoaderComponent implements DialogComponent<DialogData, void> {\n\n public constructor(private readonly dialogRef: MatDialogRef<LoaderComponent, void>,\n @Inject(MAT_DIALOG_DATA) private readonly data: DialogData) {\n }\n\n public get dialogData(): DialogData {\n return this.data;\n }\n\n public close() {\n this.dialogRef.close();\n }\n}\n","import {ChangeDetectionStrategy, Component, Inject} from '@angular/core';\nimport {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';\nimport {MatColorTheme} from '@dbg-riskit/angular-common';\nimport {DialogComponent} from './dialog.service';\n\nexport interface DialogConfig<R> {\n dialogType: DialogType;\n buttons?: Array<DialogButton<R>>;\n title?: string;\n message: string;\n note?: string;\n icon?: string;\n}\n\nexport type DialogType = 'error' | 'warning' | 'info' | 'success' | 'question';\n\nexport interface DialogButton<R> {\n label: string;\n value?: R;\n primary?: boolean;\n}\n\n@Component({\n templateUrl : 'message.dialog.component.html',\n styleUrls : [\n '../../../component.scss',\n 'message.dialog.component.scss'\n ],\n host : {\n '[class.risk-message-dialog]': 'true'\n },\n changeDetection : ChangeDetectionStrategy.OnPush,\n preserveWhitespaces: false\n})\nexport class MessageDialogComponent<R> implements DialogComponent<DialogConfig<R>, R> {\n\n public get customIcon() {\n return this.dialogData.icon;\n }\n\n public get dialogType(): DialogType {\n return this.dialogData.dialogType || 'info';\n }\n\n public get buttons(): Array<DialogButton<R>> {\n return this.dialogData.buttons || [\n {\n label: 'OK'\n }\n ];\n }\n\n public constructor(public readonly dialogRef: MatDialogRef<MessageDialogComponent<R>, R>,\n @Inject(MAT_DIALOG_DATA) private readonly data: DialogConfig<R>) {\n }\n\n public get color(): MatColorTheme {\n switch (this.dialogType) {\n case 'error':\n return 'warn';\n case 'warning':\n return 'warn';\n case 'info':\n return 'accent';\n case 'question':\n return 'accent';\n case 'success':\n return 'primary';\n }\n return null;\n }\n\n public get icon(): string {\n if (this.customIcon) {\n return this.customIcon;\n }\n switch (this.dialogType) {\n case 'error':\n return 'error';\n case 'warning':\n return 'warning';\n case 'info':\n return 'info';\n case 'question':\n return 'help';\n case 'success':\n return 'check';\n }\n return 'info';\n }\n\n public get dialogData(): DialogConfig<R> {\n return this.data;\n }\n\n public close(button: DialogButton<R>) {\n this.dialogRef.close(button.value);\n }\n}\n","<div class=\"risk-message-dialog-message\">\n <h3 *ngIf=\"dialogData.title\">\n <mat-icon [color]=\"color\">{{ icon }}</mat-icon>\n <strong>{{dialogData.title}}</strong>\n </h3>\n <h3>\n <mat-icon *ngIf=\"!dialogData.title\" [color]=\"color\">{{ icon }}</mat-icon>\n {{dialogData.message}}\n </h3>\n <small *ngIf=\"dialogData.note\">NOTE: {{dialogData.note}}</small>\n</div>\n<a *ngFor=\"let button of buttons\"\n mat-button\n [color]=\"button.primary ? color : null\"\n (click)=\"close(button)\">{{ button.label }}</a>\n","import {DecimalPipe} from '@angular/common';\nimport {Pipe, PipeTransform} from '@angular/core';\nimport {Maybe} from '@dbg-riskit/common';\n\n@Pipe({\n name: 'percent'\n})\nexport class PercentPipe implements PipeTransform {\n\n public constructor(private readonly decimalPipe: DecimalPipe) {\n }\n\n public transform(value: Maybe<number | string>, digits?: string): string | undefined {\n const transformedNumber = this.decimalPipe.transform(value, digits);\n if (transformedNumber) {\n return transformedNumber + '%';\n }\n\n return undefined;\n }\n}\n","import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, PipeTransform} from '@angular/core';\nimport {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';\nimport {DialogComponent} from './dialog.service';\n\nexport interface DialogData {\n title?: string;\n value?: number;\n total?: number;\n valueFormatter?: PipeTransform;\n cancel?: () => void;\n}\n\n@Component({\n template : `\n <risk-flex [wrapContent]=\"true\">\n <risk-flex-spacer></risk-flex-spacer>\n <mat-progress-spinner\n [mode]=\"mode\"\n [value]=\"value / (total || 1) * 100\">\n </mat-progress-spinner>\n <risk-flex-spacer></risk-flex-spacer>\n </risk-flex>\n <risk-flex *ngIf=\"dialogData.title\" [wrapContent]=\"true\">\n <risk-flex-spacer></risk-flex-spacer>\n <h3>{{ dialogData.title }}</h3>\n <risk-flex-spacer></risk-flex-spacer>\n </risk-flex>\n <risk-flex [wrapContent]=\"true\">\n <risk-flex-spacer></risk-flex-spacer>\n <h5 *ngIf=\"total != null && total > 0; else valueOnly\">{{ valueFormatter.transform(value) }}\n /{{ valueFormatter.transform(total) }}\n - {{ value / total * 100 | percent:'.1-1' }}</h5>\n <ng-template #valueOnly><h5>{{ valueFormatter.transform(value) }}</h5></ng-template>\n <risk-flex-spacer></risk-flex-spacer>\n </risk-flex>\n <risk-flex *ngIf=\"dialogData.cancel != null\" [wrapContent]=\"true\">\n <risk-flex-spacer></risk-flex-spacer>\n <button mat-button color=\"warn\" (click)=\"dialogData.cancel()\">Cancel</button>\n <risk-flex-spacer></risk-flex-spacer>\n </risk-flex>\n `,\n styles : [\n `\n h3 {\n margin-bottom: 0;\n }`\n ],\n host : {\n '[class.risk-progress-loader-dialog]': 'true'\n },\n changeDetection : ChangeDetectionStrategy.OnPush,\n preserveWhitespaces: false\n})\nexport class ProgressLoaderComponent implements DialogComponent<DialogData, void> {\n\n public get value(): number {\n if (this.dialogData.value == null || this.dialogData.value < 0) {\n return 0;\n }\n return this.dialogData.value;\n }\n\n public set value(value: number) {\n this.dialogData.value = value;\n this.changeDetector.markForCheck();\n }\n\n public get total(): number | undefined {\n return this.dialogData.total;\n }\n\n public set total(value: number | undefined) {\n this.dialogData.total = value;\n this.changeDetector.markForCheck();\n }\n\n public constructor(private readonly dialogRef: MatDialogRef<ProgressLoaderComponent, void>,\n @Inject(MAT_DIALOG_DATA) private readonly data: DialogData,\n private readonly changeDetector: ChangeDetectorRef) {\n }\n\n public get dialogData(): DialogData {\n return this.data;\n }\n\n public get valueFormatter(): PipeTransform {\n return this.data.valueFormatter || {transform: (data) => data};\n }\n\n public get mode(): 'indeterminate' | 'determinate' {\n switch (true) {\n case this.total == null:\n case this.total != null && this.total <= 0:\n case this.value <= 0:\n case this.value === this.total:\n return 'indeterminate';\n default:\n return 'determinate';\n }\n }\n\n public close() {\n this.dialogRef.close();\n }\n}\n","import {Injectable, Type} from '@angular/core';\nimport {MatDialog} from '@angular/material/dialog';\nimport {first} from 'rxjs/operators';\nimport {DialogData as LoaderConfig, LoaderComponent} from './loader.component';\nimport {\n DialogButton,\n DialogConfig as MessageDialogConfig,\n DialogType,\n MessageDialogComponent\n} from './message.dialog.component';\nimport {DialogData as ProgressLoaderConfig, ProgressLoaderComponent} from './progress.loader.component';\n\nexport interface DialogConfig<T> {\n /** Custom class for the overlay pane. */\n readonly panelClass?: string;\n /** Whether the dialog has a backdrop. */\n readonly hasBackdrop?: boolean;\n /** Custom class for the backdrop, */\n readonly backdropClass?: string;\n /** Whether the user can use escape or clicking outside to close a modal. */\n readonly disableClose?: boolean;\n\n readonly data?: T;\n}\n\nexport interface DialogComponent<T, R = unknown> {\n readonly dialogData: T;\n}\n\n@Injectable()\nexport class DialogService {\n\n public constructor(public readonly dialog: MatDialog) {\n }\n\n public showWarnDialog(message: string, note?: string) {\n return this.showMessageDialog({\n dialogType: 'warning',\n message,\n note\n });\n }\n\n public showWarnQuestionDialog(destroyCallback: () => void,\n destructiveButtonLabel: string,\n message: string,\n note?: string) {\n return this.showMessageDialog({\n dialogType: 'warning',\n message,\n note,\n buttons : [\n {\n label : destructiveButtonLabel,\n value : true,\n primary: true\n },\n {\n label: 'Cancel',\n value: false\n }\n ],\n answerCallback(result?: boolean) {\n if (result) {\n destroyCallback();\n }\n }\n });\n }\n\n public showErrorDialog(message: string, note?: string) {\n return this.showMessageDialog({\n dialogType: 'error',\n message,\n note\n });\n }\n\n public showInfoDialog(message: string, note?: string) {\n return this.showMessageDialog({\n dialogType: 'info',\n message,\n note\n });\n }\n\n public showSuccessDialog(message: string, note?: string) {\n return this.showMessageDialog({\n dialogType: 'success',\n message,\n note\n });\n }\n\n public showQuestionDialog<R>(buttons: Array<DialogButton<R>>,\n answerCallback: (value?: R) => void,\n message: string,\n note?: string) {\n return this.showMessageDialog({\n dialogType: 'question',\n message,\n note,\n buttons,\n answerCallback\n });\n }\n\n public showMessageDialog<R>(config: {\n dialogType: DialogType;\n buttons?: Array<DialogButton<R>>;\n answerCallback?: (value?: R) => void;\n config?: DialogConfig<undefined>;\n title?: string,\n message: string;\n note?: string;\n icon?: string;\n }) {\n return this.showDialog(MessageDialogComponent, {\n ...config.config,\n data: {\n dialogType: config.dialogType,\n buttons : config.buttons,\n title : config.title,\n message : config.message,\n note : config.note,\n icon : config.icon\n } as MessageDialogConfig<R>\n },\n config.answerCallback);\n }\n\n /* eslint-disable @typescript-eslint/unified-signatures */\n public showLoaderDialog(title: string): LoaderComponent;\n public showLoaderDialog(data: LoaderConfig): LoaderComponent;\n /* eslint-enable */\n public showLoaderDialog(data: string | LoaderConfig): LoaderComponent {\n if (typeof data === 'string') {\n data = {\n title: data\n };\n }\n return this.showDialog(LoaderComponent, {\n disableClose: true,\n hasBackdrop : true,\n data\n });\n }\n\n /* eslint-disable @typescript-eslint/unified-signatures */\n public showProgressLoaderDialog(title: string): ProgressLoaderComponent;\n public showProgressLoaderDialog(data: ProgressLoaderConfig): ProgressLoaderComponent;\n /* eslint-enable */\n public showProgressLoaderDialog(data: string | ProgressLoaderConfig): ProgressLoaderComponent {\n if (typeof data === 'string') {\n data = {\n title: data\n };\n }\n\n return this.showDialog(ProgressLoaderComponent, {\n disableClose: true,\n hasBackdrop : true,\n data\n });\n }\n\n /* eslint-disable @typescript-eslint/unified-signatures */\n public showDialog<T extends DialogComponent<D, R>, D, R>(dialogClass: Type<T>): T;\n public showDialog<T extends DialogComponent<D, R>, D, R>(dialogClass: Type<T>,\n config?: DialogConfig<D>): T;\n public showDialog<T extends DialogComponent<D, R>, D, R>(dialogClass: Type<T>,\n callback?: (result?: R) => void): T;\n public showDialog<T extends DialogComponent<D, R>, D, R>(dialogClass: Type<T>,\n config?: DialogConfig<D>,\n callback?: (result?: R) => void): T;\n /* eslint-enable */\n public showDialog<T extends DialogComponent<D, R>, D, R>(dialogClass: Type<T>,\n configOrCallback?: DialogConfig<D>\n | ((result?: R) => void),\n callback?: (result?: R) => void): T {\n let config: DialogConfig<D> | undefined;\n if (typeof configOrCallback === 'function') {\n callback = configOrCallback;\n } else {\n config = configOrCallback;\n }\n const dialogRef = this.dialog.open(dialogClass, config);\n\n dialogRef.afterClosed().pipe(\n first()\n ).subscribe((result?: R) => {\n if (callback) {\n callback(result);\n }\n });\n\n return dialogRef.componentInstance;\n }\n}\n","import {Injectable, NgZone} from '@angular/core';\nimport {CONTENT_TYPE, Logger} from '@dbg-riskit/common';\nimport {BehaviorSubject, Observable} from 'rxjs';\nimport {filter} from 'rxjs/operators';\n\n/**\n * Class instances emitted [to observers] for each mql notification\n */\nexport class MediaChange {\n public constructor(public readonly mediaQuery = 'all') {\n }\n}\n\n/**\n * MediaMonitor configures listeners to mediaQuery changes and publishes an Observable facade to\n * convert mediaQuery change callbacks to subscriber notifications. These notifications will be\n * performed within the ng Zone to trigger change detections and component updates.\n *\n * NOTE: both mediaQuery activations and de-activations are announced in notifications\n */\n@Injectable()\nexport class MatchMedia {\n protected readonly _registry: Map<string, MediaQueryList>;\n protected readonly _source: BehaviorSubject<MediaChange>;\n protected readonly _observable$: Observable<MediaChange>;\n\n public constructor(protected readonly ngZone: NgZone,\n private readonly logger: Logger) {\n this._registry = new Map<string, MediaQueryList>();\n this._source = new BehaviorSubject<MediaChange>(new MediaChange());\n this._observable$ = this._source.asObservable();\n }\n\n /**\n * For the specified mediaQuery?\n */\n public isActive(mediaQuery: string): boolean {\n if (this._registry.has(mediaQuery)) {\n const mql = this._registry.get(mediaQuery);\n return mql!.matches;\n }\n return false;\n }\n\n /**\n * External observers can watch for all (or a specific) mql changes.\n * Typically used by the MediaQueryAdaptor; optionally available to components\n * who wish to use the MediaMonitor as mediaMonitor$ observable service.\n *\n * NOTE: if a mediaQuery is not specified, then ALL mediaQuery activations will\n * be announced.\n */\n public observe(mediaQuery?: string): Observable<MediaChange> {\n this.registerQuery(mediaQuery);\n\n return this._observable$.pipe(\n filter((change: MediaChange) => {\n return mediaQuery ? (change.mediaQuery === mediaQuery) : true;\n })\n );\n }\n\n /**\n * Based on the BreakPointRegistry provider, register internal listeners for each unique\n * mediaQuery. Each listener emits specific MediaChange data to observers\n */\n private registerQuery(mediaQuery?: string | string[]) {\n const list = normalizeQuery(mediaQuery);\n\n if (list.length > 0) {\n prepareQueryCSS(list, this.logger);\n\n list.forEach((query) => {\n let mql = this._registry.get(query);\n const onMQLEvent = () => {\n this.ngZone.run(() => {\n const change = new MediaChange(query);\n this._source.next(change);\n });\n };\n\n if (!mql) {\n mql = this._buildMQL(query);\n mql.addEventListener('change', onMQLEvent);\n this._registry.set(query, mql);\n }\n\n if (mql.matches) {\n onMQLEvent(); // Announce activate range for initial subscribers\n }\n });\n }\n }\n\n /**\n * Call window.matchMedia() to build a MediaQueryList; which\n * supports 0..n listeners for activation/deactivation\n */\n protected _buildMQL(query: string): MediaQueryList {\n const canListen = !!window.matchMedia('all').addEventListener;\n return canListen ? window.matchMedia(query) : {\n matches : query === 'all' || query === '',\n media : query,\n addListener : () => undefined,\n addEventListener : () => undefined,\n removeListener : () => undefined,\n removeEventListener: () => undefined,\n dispatchEvent : () => false,\n onchange : () => undefined\n } as MediaQueryList;\n }\n}\n\n/**\n * Private global registry for all dynamically-created, injected style tags\n * @see prepare(query)\n */\nconst ALL_STYLES: { [key: string]: HTMLStyleElement } = {};\n\n/**\n * For Webkit engines that only trigger the MediaQueryList Listener\n * when there is at least one CSS selector for the respective media query.\n *\n * @param mediaQueries string[] The mediaQueries used to create a faux CSS selector\n *\n */\nfunction prepareQueryCSS(mediaQueries: string[], logger: Logger) {\n const list = mediaQueries.filter((it) => !ALL_STYLES[it]);\n if (list.length > 0) {\n const query = list.join(', ');\n try {\n const style: HTMLStyleElement = document.createElement('style');\n\n style.setAttribute('type', CONTENT_TYPE.TEXT_CSS);\n // Older IEs\n if (!(style as any).styleSheet) {\n const cssText = `/*\n @angular/flex-layout - workaround for possible browser quirk with mediaQuery listeners\n see http://bit.ly/2sd4HMP\n*/\n@media ${query} {.fx-query-test{ }}`;\n style.appendChild(document.createTextNode(cssText));\n }\n\n document.getElementsByTagName('head')[0].appendChild(style);\n\n // Store in private global registry\n list.forEach((mq) => ALL_STYLES[mq] = style);\n\n } catch (e) {\n logger.error(e);\n }\n }\n}\n\n/**\n * Always convert to unique list of queries; for iteration in ::registerQuery()\n */\nfunction normalizeQuery(mediaQuery?: string | string[]): string[] {\n return (typeof mediaQuery === 'undefined') ? [] :\n (typeof mediaQuery === 'string') ? [mediaQuery] : unique(mediaQuery);\n}\n\n/**\n * Filter duplicate mediaQueries in the list\n */\nfunction unique(list: string[]): string[] {\n const seen: { [key: string]: boolean } = {};\n return list.filter((item) => {\n return seen.hasOwnProperty(item) ? false : (seen[item] = true);\n });\n}\n","import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n Directive,\n Inject,\n Input,\n OnChanges,\n Optional,\n SimpleChanges\n} from '@angular/core';\nimport {MatSidenav} from '@angular/material/sidenav';\nimport {AUTH_PROVIDER, MAIN_LOGO} from '@dbg-riskit/angular-common';\nimport {AuthProvider} from '@dbg-riskit/common';\nimport {Observable, of, Subscription} from 'rxjs';\nimport {takeUntil} from 'rxjs/operators';\nimport {BaseComponent} from './base.component';\nimport {MatchMedia} from './match.media';\n\nconst SMALL_SCREEN_MEDIA_QUERY = (width: number) => `screen and (max-width:${width}px)`;\n\n@Directive({\n selector: 'risk-layout-vertical',\n host : {\n '[class]': '\"risk-layout-vertical\"'\n }\n})\nexport class VerticalLayoutDirective {\n}\n\n@Directive({\n selector: 'risk-layout-vertical-title',\n host : {\n '[class]': '\"risk-layout-vertical-title\"'\n }\n})\nexport class VerticalLayoutTitleDirective {\n}\n\n@Directive({\n selector: 'risk-layout-vertical-icon',\n host : {\n '[class]': '\"risk-layout-vertical-icon\"'\n }\n})\nexport class VerticalLayoutIconDirective {\n}\n\n@Directive({\n selector: 'risk-layout-horizontal',\n host : {\n '[class]': '\"mat-toolbar-row mat-toolbar-single-row risk-layout-horizontal\"'\n }\n})\nexport class HorizontalLayoutDirective {\n}\n\n@Directive({\n selector: 'risk-layout-footer',\n host : {\n '[class]': '\"risk-layout-footer\"'\n }\n})\nexport class FooterLayoutDirective {\n}\n\n@Component({\n selector : 'risk-layout',\n templateUrl : 'layout.component.html',\n styleUrls : [\n '../../../component.scss',\n 'layout.component.scss'\n ],\n host : {\n '[class.risk-layout]': 'true'\n },\n changeDetection : ChangeDetectionStrategy.OnPush,\n preserveWhitespaces: false\n})\nexport class LayoutComponent extends BaseComponent implements OnChanges {\n\n @Input()\n public smallScreenMenuVisible = true;\n\n @Input()\n public smallScreenWidth = 600;\n\n private smallScreenWidthObserver?: Subscription;\n\n @Input()\n public footerVisible = true;\n\n @Input()\n public toolbarBackgroundColor?: string;\n\n @Input()\n public backgroundColor?: string;\n\n public constructor(@Optional() @Inject(AUTH_PROVIDER) private readonly authProvider: AuthProvider,\n @Inject(MAIN_LOGO) private readonly mainLogo: string,\n public readonly changeDetectorRef: ChangeDetectorRef,\n private readonly matchMedia: MatchMedia) {\n super();\n\n // Detect changes once logged-in/out\n if (authProvider) {\n authProvider.loggedInStream.pipe(\n takeUntil(this.destroyed)\n ).subscribe(() => changeDetectorRef.markForCheck());\n }\n\n this.observeSmallScreenWidth();\n }\n\n public ngOnChanges(changes: SimpleChanges): void {\n if ('smallScreenWidth' in changes) {\n this.observeSmallScreenWidth();\n }\n }\n\n public get authStatus(): Observable<boolean> {\n if (!this.authProvider) {\n return of(true);\n }\n return this.authProvider.loggedIn;\n }\n\n private observeSmallScreenWidth() {\n if (this.smallScreenWidthObserver != null) {\n this.smallScreenWidthObserver.unsubscribe();\n }\n\n this.smallScreenWidthObserver = this.matchMedia.observe(SMALL_SCREEN_MEDIA_QUERY(this.smallScreenWidth)).pipe(\n takeUntil(this.destroyed)\n ).subscribe(() => this.changeDetectorRef.markForCheck());\n }\n\n public get mediaSmall(): boolean {\n return this.matchMedia.isActive(SMALL_SCREEN_MEDIA_QUERY(this.smallScreenWidth));\n }\n\n public get logo(): string {\n return this.mainLogo;\n }\n\n public closeSideNav(sidenav: MatSidenav): void {\n this.authStatus.subscribe((res: boolean) => {\n if (!res) {\n sidenav.close();\n this.changeDetectorRef.markForCheck();\n }\n });\n }\n}\n","<mat-toolbar class=\"mat-elevation-z2\"\n [style.backgroundColor]=\"toolbarBackgroundColor\">\n <div class=\"risk-layout-logo\">\n <img [src]=\"logo\" alt=\"Company logo\">\n </div>\n\n <ng-template [ngIf]=\"authStatus | async\">\n <ng-template [ngIf]=\"!mediaSmall\">\n <ng-content select=\"[menu-horizontal], risk-layout-horizontal > *\"></ng-content>\n </ng-template>\n\n <ng-template [ngIf]=\"mediaSmall\">\n <ng-content select=\"[menu-vertical-title], risk-layout-vertical-title > *\"></ng-content>\n\n <risk-flex-spacer></risk-flex-spacer>\n\n <ng-content select=\"[menu-vertical-icon], risk-layout-vertical-icon > *\"></ng-content>\n\n <button mat-icon-button\n (click)=\"sidenav.toggle()\"\n type=\"button\"\n *ngIf=\"smallScreenMenuVisible\">\n <mat-icon>menu</mat-icon>\n </button>\n </ng-template>\n </ng-template>\n</mat-toolbar>\n\n<mat-sidenav-container [class.risk-layout-with-footer]=\"footerVisible\"\n [style.backgroundColor]=\"backgroundColor\">\n <mat-sidenav #sidenav=\"matSidenav\" (click)=\"closeSideNav(sidenav)\">\n <ng-content select=\"[menu-vertical], risk-layout-vertical > *\"></ng-content>\n </mat-sidenav>\n\n <div class=\"risk-layout-content\">\n <ng-content></ng-content>\n </div>\n</mat-sidenav-container>\n\n<div class=\"risk-layout-footer\" *ngIf=\"footerVisible\">\n <ng-content select=\"risk-layout-footer > *\"></ng-content>\n</div>\n","import {Directive, Input} from '@angular/core';\nimport {ActivatedRoute, Router, UrlTree} from '@angular/router';\n\n@Directive({selector: '[riskSubLink]'})\nexport class SubLinkDirective {\n\n private commands: unknown[] = [];\n\n public constructor(private readonly router: Router,\n private readonly route: ActivatedRoute) {\n }\n\n @Input('riskSubLink')\n public set subLink(commands: unknown[] | string) {\n if (commands == null) {\n this.commands = [];\n } else {\n this.commands = Array.isArray(commands) ? commands : [commands];\n }\n }\n\n public get urlTree(): UrlTree {\n return this.router.createUrlTree(this.commands, {\n relativeTo: this.route\n });\n }\n}\n","import {\n AfterContentInit,\n ChangeDetectorRef,\n ContentChildren,\n Directive,\n ElementRef,\n Input,\n OnChanges,\n OnDestroy,\n QueryList,\n Renderer2,\n SimpleChanges\n} from '@angular/core';\nimport {NavigationEnd, Router, RouterLink, RouterLinkWithHref} from '@angular/router';\nimport {Subscription} from 'rxjs';\nimport {SubLinkDirective} from './sub.link.directive';\n\n@Directive({\n selector: '[riskLinkActive]',\n exportAs: 'riskLinkActive'\n})\nexport class LinkActiveDirective implements OnChanges, OnDestroy, AfterContentInit {\n\n @ContentChildren(RouterLink, {descendants: true})\n public links?: QueryList<RouterLink>;\n\n @ContentChildren(RouterLinkWithHref, {descendants: true})\n public linksWithHrefs?: QueryList<RouterLinkWithHref>;\n\n @ContentChildren(SubLinkDirective, {descendants: true})\n public subLinks?: QueryList<SubLinkDirective>;\n\n private classes: string[] = [];\n private readonly subscription: Subscription;\n public readonly isActive: boolean = false;\n\n @Input('riskLinkActiveOptions')\n public routerLinkActiveOptions: { exact: boolean } = {exact: false};\n\n public constructor(private readonly router: Router,\n private readonly element: ElementRef,\n private readonly renderer: Renderer2,\n private readonly changeDetectorRef: ChangeDetectorRef) {\n this.subscription = router.events.subscribe((s) => {\n if (s instanceof NavigationEnd) {\n this.update();\n }\n });\n }\n\n public ngAfterContentInit(): void {\n this.links!.changes.subscribe((_) => this.update());\n this.linksWithHrefs!.changes.subscribe((_) => this.update());\n this.subLinks!.changes.subscribe((_) => this.update());\n this.update();\n }\n\n @Input('riskLinkActive')\n public set menuLinkActive(data: string[] | string) {\n const classes = Array.isArray(data) ? data : data.split(' ');\n this.classes = classes.filter((c) => !!c);\n }\n\n public ngOnChanges(changes: SimpleChanges): void {\n this.update();\n }\n\n public ngOnDestroy(): void {\n this.subscription.unsubscribe();\n }\n\n private update(): void {\n if (!this.links || !this.linksWithHrefs || !this.subLinks || !this.router.navigated) {\n return;\n }\n const hasActiveLinks = this.hasActiveLinks();\n\n // react only when status has changed to prevent unnecessary dom updates\n if (this.isActive !== hasActiveLinks) {\n this.classes.forEach((c) => {\n if (hasActiveLinks) {\n this.renderer.addClass(this.element.nativeElement, c);\n } else {\n this.renderer.removeClass(this.element.nativeElement, c);\n }\n });\n Promise.resolve(hasActiveLinks).then((active) => {\n (this as {\n isActive: boolean\n }).isActive = active;\n this.changeDetectorRef.detectChanges();\n });\n }\n }\n\n private isLinkActive(router: Router): (link: (SubLinkDirective | RouterLink | RouterLinkWithHref)) => boolean {\n return (link: SubLinkDirective | RouterLink | RouterLinkWithHref) =>\n link.urlTree ? router.isActive(link.urlTree, this.routerLinkActiveOptions.exact) : false;\n }\n\n private hasActiveLinks(): boolean {\n return this.links!.some(this.isLinkActive(this.router))\n || this.linksWithHrefs!.some(this.isLinkActive(this.router))\n || this.subLinks!.some(this.isLinkActive(this.router));\n }\n\n}\n","import {ChangeDetectionStrategy, Component, Input} from '@angular/core';\n\n@Component({\n selector : 'risk-toolbar',\n template : '<mat-toolbar class=\"mat-elevation-z1\"><ng-content></ng-content></mat-toolbar>',\n styleUrls : [\n '../../../component.scss',\n 'toolbar.component.scss'\n ],\n host : {\n '[class.risk-toolbar]': 'true'\n },\n changeDetection : ChangeDetectionStrategy.OnPush,\n preserveWhitespaces: false\n})\nexport class ToolbarComponent {\n\n @Input()\n public wrapContent = false;\n}\n","import {CommonModule, DatePipe, DecimalPipe} from '@angular/common';\nimport {ChangeDetectionStrategy, Component, Inject, Injectable, NgModule} from '@angular/core';\nimport {MatAutocompleteModule} from '@angular/material/autocomplete';\nimport {MatBadgeModule} from '@angular/material/badge';\nimport {MatBottomSheetModule} from '@angular/material/bottom-sheet';\nimport {MatButtonModule} from '@angular/material/button';\nimport {MatButtonToggleModule} from '@angular/material/button-toggle';\nimport {MatCardModule} from '@angular/material/card';\nimport {MatCheckboxModule} from '@angular/material/checkbox';\nimport {MatChipsModule} from '@angular/material/chips';\nimport {MatDatepickerModule} from '@angular/material/datepicker';\nimport {MatDialogModule} from '@angular/material/dialog';\nimport {MatDividerModule} from '@angular/material/divider';\nimport {MatExpansionModule} from '@angular/material/expansion';\nimport {MatFormFieldModule} from '@angular/material/form-field';\nimport {MatGridListModule} from '@angular/material/grid-list';\nimport {MatIconModule} from '@angular/material/icon';\nimport {MatInputModule} from '@angular/material/input';\nimport {MatListModule} from '@angular/material/list';\nimport {MatMenuModule} from '@angular/material/menu';\nimport {MatPaginatorModule} from '@angular/material/paginator';\nimport {MatProgressBarModule} from '@angular/material/progress-bar';\nimport {MatProgressSpinnerModule, MatSpinner} from '@angular/material/progress-spinner';\nimport {MatRadioModule} from '@angular/material/radio';\nimport {MatSelectModule} from '@angular/material/select';\nimport {MatSidenavModule} from '@angular/material/sidenav';\nimport {MatSlideToggleModule} from '@angular/material/slide-toggle';\nimport {MatSliderModule} from '@angular/material/slider';\nimport {MatSnackBarModule} from '@angular/material/snack-bar';\nimport {MatSortModule} from '@angular/material/sort';\nimport {MatStepperModule} from '@angular/material/stepper';\nimport {MatTableModule} from '@angular/material/table';\nimport {MatTabsModule} from '@angular/material/tabs';\nimport {MatToolbarModule} from '@angular/material/toolbar';\nimport {MatTooltipModule} from '@angular/material/tooltip';\nimport {MatTreeModule} from '@angular/material/tree';\nimport {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations';\nimport {RouterModule} from '@angular/router';\nimport {DATE_FORMAT} from '@dbg-riskit/angular-common';\nimport {LoggingModule} from '@dbg-riskit/angular-logging';\nimport {DialogService} from './dialog.service';\nimport {FlexComponent} from './flex.component';\nimport {FlexSpacerComponent} from './flex.spacer.component';\nimport {\n FooterLayoutDirective,\n HorizontalLayoutDirective,\n LayoutComponent,\n VerticalLayoutDirective,\n VerticalLayoutIconDirective,\n VerticalLayoutTitleDirective\n} from './layout.component';\nimport {LinkActiveDirective} from './link.active.directive';\nimport {LoaderComponent} from './loader.component';\nimport {MatchMedia} from './match.media';\nimport {COMPONENT_SELECTOR, MessageComponent} from './message.component';\nimport {MessageDialogComponent} from './message.dialog.component';\nimport {PercentPipe} from './percent.pipe';\nimport {ProgressLoaderComponent} from './progress.loader.component';\nimport {SubLinkDirective} from './sub.link.directive';\nimport {ToolbarComponent} from './toolbar.component';\n\n@Injectable()\nexport class DateFormatter {\n\n public constructor(@Inject(DATE_FORMAT) private readonly format: string,\n private readonly datePipe: DatePipe) {\n }\n\n public transform(value: Date): string | null {\n return this.datePipe.transform(value, this.format);\n }\n}\n\n@NgModule({\n imports : [\n // Angular modules\n CommonModule,\n RouterModule,\n\n // Our modules\n LoggingModule,\n\n // Material modules\n MatAutocompleteModule,\n MatBadgeModule,\n MatBottomSheetModule,\n MatButtonModule,\n MatButtonToggleModule,\n MatCardModule,\n MatCheckboxModule,\n MatChipsModule,\n MatDatepickerModule,\n MatDialogModule,\n MatDividerModule,\n MatExpansionModule,\n MatFormFieldModule,\n MatGridListModule,\n MatIconModule,\n MatInputModule,\n MatListModule,\n MatMenuModule,\n MatPaginatorModule,\n MatProgressBarModule,\n MatProgressSpinnerModule,\n MatRadioModule,\n MatSelectModule,\n MatSidenavModule,\n MatSliderModule,\n MatSlideToggleModule,\n MatSnackBarModule,\n MatSortModule,\n MatStepperModule,\n MatTableModule,\n MatTabsModule,\n MatToolbarModule,\n MatTooltipModule,\n MatTreeModule\n ],\n declarations : [\n // Layout component\n LayoutComponent,\n VerticalLayoutDirective,\n VerticalLayoutTitleDirective,\n VerticalLayoutIconDirective,\n HorizontalLayoutDirective,\n FooterLayoutDirective,\n\n // Dialogs\n MessageDialogComponent,\n LoaderComponent,\n ProgressLoaderComponent,\n\n // Pipes\n PercentPipe,\n\n // Flex components\n FlexComponent,\n FlexSpacerComponent,\n\n // Router links and sublinks\n LinkActiveDirective,\n SubLinkDirective,\n\n // Toolbar\n ToolbarComponent\n ],\n exports : [\n // Material modules\n MatAutocompleteModule,\n MatBadgeModule,\n MatBottomSheetModule,\n MatButtonModule,\n MatButtonToggleModule,\n MatCardModule,\n MatCheckboxModule,\n MatChipsModule,\n MatDatepickerModule,\n MatDialogModule,\n MatDividerModule,\n MatExpansionModule,\n MatFormFieldModule,\n MatGridListModule,\n MatIconModule,\n MatInputModule,\n MatListModule,\n MatMenuModule,\n MatPaginatorModule,\n MatProgressBarModule,\n MatRadioModule,\n MatSelectModule,\n MatSidenavModule,\n MatSliderModule,\n MatSlideToggleModule,\n MatSnackBarModule,\n MatSortModule,\n MatStepperModule,\n MatTableModule,\n MatTabsModule,\n MatToolbarModule,\n MatTooltipModule,\n MatTreeModule,\n\n // Layout component\n LayoutComponent,\n VerticalLayoutDirective,\n VerticalLayoutTitleDirective,\n VerticalLayoutIconDirective,\n HorizontalLayoutDirective,\n FooterLayoutDirective,\n\n // Dialogs\n MessageDialogComponent,\n LoaderComponent,\n ProgressLoaderComponent,\n\n // Pipes\n PercentPipe,\n\n // Flex components\n FlexComponent,\n FlexSpacerComponent,\n\n // Router links and sublinks\n LinkActiveDirective,\n SubLinkDirective,\n\n // Toolbar\n ToolbarComponent\n ],\n entryComponents: [\n MessageDialogComponent,\n LoaderComponent,\n ProgressLoaderComponent\n ],\n providers : [\n // Pipes and formatters so we can inject these\n DateFormatter,\n DecimalPipe,\n DatePipe,\n PercentPipe,\n\n // Services\n DialogService,\n MatchMedia\n ]\n})\nexport class CommonViewModulePrivate {\n}\n\n@NgModule({\n imports : [\n CommonModule,\n BrowserAnimationsModule,\n CommonViewModulePrivate,\n MatProgressSpinnerModule\n ],\n declarations: [\n MessageComponent\n ],\n exports : [\n MessageComponent,\n CommonViewModulePrivate,\n MatProgressSpinnerModule\n ]\n})\nexport class CommonViewModule {\n}\n\n@Component({\n /* eslint-disable @angular-eslint/component-selector */\n selector: 'mat-spinner, mat-progress-spinner',\n /* eslint-enable */\n template : '',\n changeDetection : ChangeDetectionStrategy.OnPush,\n preserveWhitespaces: false,\n // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property\n inputs: [\n 'diameter'\n ]\n})\nexport class SpinnerStubComponent extends MatSpinner {\n}\n\n@Component({\n selector : COMPONENT_SELECTOR,\n templateUrl : 'message.component.html',\n styleUrls : [\n '../../../component.scss',\n 'message.component.scss'\n ],\n changeDetection : ChangeDetectionStrategy.OnPush,\n preserveWhitespaces: false\n})\nexport class NoopAnimationMessageComponent extends MessageComponent {\n}\n\n@NgModule({\n imports : [\n CommonModule,\n NoopAnimationsModule,\n CommonViewModulePrivate\n ],\n declarations: [\n NoopAnimationMessageComponent,\n SpinnerStubComponent\n ],\n exports : [\n NoopAnimationMessageComponent,\n SpinnerStubComponent,\n CommonViewModulePrivate\n ]\n})\nexport class NoopAnimationsCommonViewModule {\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":["i2","i3","i2.FlexComponent","i3.FlexSpacerComponent","i6","i4","i1","i7.Percen