83 lines
2.7 KiB
TypeScript
83 lines
2.7 KiB
TypeScript
import { Directive, HostListener, inject } from '@angular/core';
|
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
import { FormGroup } from '@angular/forms';
|
|
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
|
import { IconButtonTypes } from '../buttons';
|
|
import { hasFormChanged, IqserEventTarget } from '../utils';
|
|
|
|
const DIALOG_CONTAINER = 'mat-dialog-container';
|
|
const DATA_TYPE_SYMBOL = Symbol.for('DATA_TYPE');
|
|
const RETURN_TYPE_SYMBOL = Symbol.for('RETURN_TYPE');
|
|
|
|
export type DATA_TYPE = typeof DATA_TYPE_SYMBOL;
|
|
export type RETURN_TYPE = typeof RETURN_TYPE_SYMBOL;
|
|
|
|
@Directive()
|
|
export abstract class IqserDialogComponent<ComponentType, DataType = null, ReturnType = void> {
|
|
readonly [DATA_TYPE_SYMBOL]!: DataType;
|
|
readonly [RETURN_TYPE_SYMBOL]!: ReturnType;
|
|
|
|
readonly iconButtonTypes = IconButtonTypes;
|
|
readonly dialogRef = inject(MatDialogRef<ComponentType, ReturnType>);
|
|
readonly data = inject<DataType>(MAT_DIALOG_DATA);
|
|
readonly dialog = inject(MatDialog);
|
|
readonly form?: FormGroup;
|
|
readonly ignoredKeys: string[] = [];
|
|
|
|
initialFormValue: Record<string, unknown> = {};
|
|
|
|
constructor(private readonly _editMode = false) {
|
|
this.dialogRef
|
|
.backdropClick()
|
|
.pipe(takeUntilDestroyed())
|
|
// eslint-disable-next-line rxjs/no-ignored-subscription
|
|
.subscribe(() => this.dialogRef.close());
|
|
}
|
|
|
|
get valid(): boolean {
|
|
return !this.form || this.form.valid;
|
|
}
|
|
|
|
get changed(): boolean {
|
|
return !this.form || hasFormChanged(this.form, this.initialFormValue, this.ignoredKeys);
|
|
}
|
|
|
|
get disabled(): boolean {
|
|
return !this.valid || !this.changed;
|
|
}
|
|
|
|
@HostListener('window:keydown.Escape', ['$event'])
|
|
onEscape(): void {
|
|
if (this.dialog.openDialogs.length === 1) {
|
|
this.dialogRef.close();
|
|
}
|
|
}
|
|
|
|
@HostListener('window:keydown.Enter', ['$event'])
|
|
onEnter(event: KeyboardEvent): void {
|
|
event?.stopImmediatePropagation();
|
|
if (this.onEnterValidator(event)) {
|
|
this.close();
|
|
}
|
|
}
|
|
|
|
onEnterValidator(event: KeyboardEvent) {
|
|
const targetElement = (event.target as IqserEventTarget).localName?.trim()?.toLowerCase();
|
|
const canClose = targetElement === DIALOG_CONTAINER && this.valid;
|
|
if (this._editMode) {
|
|
return canClose && this.changed;
|
|
}
|
|
return canClose;
|
|
}
|
|
|
|
close(dialogResult?: ReturnType) {
|
|
this.dialogRef.close(dialogResult);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This is for testing only
|
|
*/
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
class DialogComponentImpl extends IqserDialogComponent<DialogComponentImpl, unknown, unknown> {}
|