@deepkit/desktop-ui
Version:
Library for desktop UI widgets in Angular 10+
240 lines (204 loc) • 7.36 kB
text/typescript
/*
* Deepkit Framework
* Copyright (C) 2021 Deepkit UG, Marc J. Schmidt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the MIT License.
*
* You should have received a copy of the MIT License along with this program.
*/
import {
ApplicationRef,
ChangeDetectorRef,
Component,
ComponentFactoryResolver,
ComponentRef,
Directive,
ElementRef,
Inject,
Injectable,
Injector,
Input,
OnDestroy,
Type,
ViewContainerRef,
} from '@angular/core';
import { DialogComponent } from './dialog.component';
import { isTargetChildOf } from '../../core/utils';
import { DuiDialogProgress, ProgressDialogState } from './progress-dialog.component';
import { DOCUMENT } from '@angular/common';
import { WindowRegistry } from '../window/window-state';
import { Overlay } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
export class DuiDialogConfirm {
title: string = 'Confirm';
content: string = '';
static dialogDefaults = {
maxWidth: '700px'
};
}
export class DuiDialogAlert {
title: string = 'Alert';
content: string = '';
static dialogDefaults = {
maxWidth: '700px'
};
}
export class DuiDialogPrompt {
title: string = 'Alert';
content: string = '';
value: string = '';
static dialogDefaults = {
maxWidth: '700px'
};
constructor(public dialog: DialogComponent) {
}
}
export class DuiDialog {
constructor(
protected resolver: ComponentFactoryResolver,
protected app: ApplicationRef,
protected injector: Injector,
protected registry: WindowRegistry,
protected overlay: Overlay,
) {
}
protected getComponentRef(viewContainerRef: ViewContainerRef | null = null): ComponentRef<DialogComponent> {
if (!viewContainerRef && !this.registry.activeWindow) {
//create portal
const overlayRef = this.overlay.create();
const portal = new ComponentPortal(DialogComponent);
const comp = overlayRef.attach(portal);
comp.instance.closed.subscribe((v) => {
overlayRef.dispose();
});
return comp;
}
if (!viewContainerRef) {
viewContainerRef = this.registry.getCurrentViewContainerRef();
}
const factory = this.resolver.resolveComponentFactory(DialogComponent);
return viewContainerRef.createComponent(factory);
}
public open<T>(
component: Type<T>,
inputs: { [name in keyof T]?: any } = {},
dialogInputs: Partial<DialogComponent> = {},
viewContainerRef: ViewContainerRef | null = null,
): { dialog: DialogComponent, close: Promise<any>, component: T } {
const comp = this.getComponentRef(viewContainerRef);
comp.instance.visible = true;
comp.instance.component = component;
comp.instance.componentInputs = inputs;
if ((component as any).dialogDefaults) {
for (const [i, v] of Object.entries((component as any).dialogDefaults)) {
(comp.instance as any)[i] = v;
}
}
for (const [i, v] of Object.entries(dialogInputs)) {
(comp.instance as any)[i] = v;
}
comp.instance.show();
comp.changeDetectorRef.detectChanges();
const close = new Promise((resolve) => {
comp.instance.closed.subscribe((v) => {
comp.destroy();
resolve(v);
});
});
return {
dialog: comp.instance,
close,
component: comp.instance.wrapperComponentRef!.instance!.renderComponentDirective!.component!.instance,
};
}
public async alert(title: string, content?: string, dialodInputs: { [name: string]: any } = {}): Promise<boolean> {
const { dialog } = this.open(DuiDialogAlert, { title, content }, dialodInputs);
return dialog.toPromise();
}
public async confirm(title: string, content?: string, dialodInputs: { [name: string]: any } = {}): Promise<boolean> {
const { dialog } = this.open(DuiDialogConfirm, { title, content }, dialodInputs);
return dialog.toPromise();
}
public async prompt(title: string, value: string, content?: string, dialodInputs: { [name: string]: any } = {}): Promise<false | string> {
const { dialog } = this.open(DuiDialogPrompt, { title, value, content }, dialodInputs);
return dialog.toPromise();
}
public progress(): ProgressDialogState {
const state$ = new ProgressDialogState;
this.open(DuiDialogProgress, { state$ });
return state$;
}
}
export class DuiDialogConfirmDirective implements OnDestroy {
confirm!: string;
ignoreNextClick = false;
callback = async (event: MouseEvent) => {
if (isTargetChildOf(event.target, this.element.nativeElement)) {
if (this.ignoreNextClick) {
this.ignoreNextClick = false;
return;
}
event.stopPropagation();
event.preventDefault();
const [title, text] = this.confirm.split('\n');
const a = await this.dialog.confirm(title, text, {});
if (a) {
this.ignoreNextClick = true;
this.element.nativeElement.dispatchEvent(event);
}
this.cd.detectChanges();
}
};
constructor(
protected element: ElementRef<HTMLElement>,
protected dialog: DuiDialog,
protected cd: ChangeDetectorRef,
protected document: any,
) {
this.document.body!.addEventListener('click', this.callback, true);
}
ngOnDestroy() {
this.document.body!.removeEventListener('click', this.callback, true);
}
}