|
|
|
@ -11,19 +11,19 @@ import { |
|
|
|
ViewChild, |
|
|
|
ViewChildren |
|
|
|
} from '@angular/core'; |
|
|
|
import { fromEvent, Subject, timer } from 'rxjs'; |
|
|
|
import { filter, take, takeUntil, debounceTime } from 'rxjs/operators'; |
|
|
|
import { fromEvent, Subject } from 'rxjs'; |
|
|
|
import { debounceTime, filter, takeUntil } from 'rxjs/operators'; |
|
|
|
import { Toaster } from '../../models/toaster'; |
|
|
|
import { ConfirmationService } from '../../services/confirmation.service'; |
|
|
|
import { ConfirmationService } from '../../services'; |
|
|
|
import { ButtonComponent } from '../button/button.component'; |
|
|
|
import { backdropAnimation, dialogAnimation } from './modal.animations'; |
|
|
|
|
|
|
|
export type ModalSize = 'sm' | 'md' | 'lg' | 'xl'; |
|
|
|
|
|
|
|
const ANIMATION_TIMEOUT = 200; |
|
|
|
|
|
|
|
@Component({ |
|
|
|
selector: 'abp-modal', |
|
|
|
templateUrl: './modal.component.html' |
|
|
|
templateUrl: './modal.component.html', |
|
|
|
animations: [backdropAnimation, dialogAnimation] |
|
|
|
}) |
|
|
|
export class ModalComponent implements OnDestroy { |
|
|
|
@Input() |
|
|
|
@ -32,27 +32,14 @@ export class ModalComponent implements OnDestroy { |
|
|
|
} |
|
|
|
set visible(value: boolean) { |
|
|
|
if (typeof value !== 'boolean') return; |
|
|
|
|
|
|
|
if (!this.modalContent) { |
|
|
|
if (value) { |
|
|
|
setTimeout(() => { |
|
|
|
this.showModal = value; |
|
|
|
this.visible = value; |
|
|
|
}, 0); |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
this._visible = value; |
|
|
|
if (value) { |
|
|
|
this.setVisible(value); |
|
|
|
this.listen(); |
|
|
|
this.renderer.addClass(document.body, 'modal-open'); |
|
|
|
this.appear.emit(); |
|
|
|
} else { |
|
|
|
this.closable = false; |
|
|
|
this.renderer.addClass(this.modalContent.nativeElement, 'fade-out-top'); |
|
|
|
setTimeout(() => { |
|
|
|
this.setVisible(value); |
|
|
|
this.destroy$.next(); |
|
|
|
}, ANIMATION_TIMEOUT - 10); |
|
|
|
this.renderer.removeClass(document.body, 'modal-open'); |
|
|
|
this.disappear.emit(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -74,13 +61,8 @@ export class ModalComponent implements OnDestroy { |
|
|
|
|
|
|
|
@Input() size: ModalSize = 'lg'; |
|
|
|
|
|
|
|
@Input() height: number; |
|
|
|
|
|
|
|
@Input() minHeight: number; |
|
|
|
|
|
|
|
@Output() readonly visibleChange = new EventEmitter<boolean>(); |
|
|
|
|
|
|
|
@Output() readonly init = new EventEmitter<void>(); |
|
|
|
@ContentChild(ButtonComponent, { static: false, read: ButtonComponent }) |
|
|
|
abpSubmit: ButtonComponent; |
|
|
|
|
|
|
|
@ContentChild('abpHeader', { static: false }) abpHeader: TemplateRef<any>; |
|
|
|
|
|
|
|
@ -91,13 +73,14 @@ export class ModalComponent implements OnDestroy { |
|
|
|
@ContentChild('abpClose', { static: false, read: ElementRef }) |
|
|
|
abpClose: ElementRef<any>; |
|
|
|
|
|
|
|
@ContentChild(ButtonComponent, { static: false, read: ButtonComponent }) |
|
|
|
abpSubmit: ButtonComponent; |
|
|
|
|
|
|
|
@ViewChild('abpModalContent', { static: false }) modalContent: ElementRef; |
|
|
|
|
|
|
|
@ViewChildren('abp-button') abpButtons; |
|
|
|
|
|
|
|
@Output() readonly visibleChange = new EventEmitter<boolean>(); |
|
|
|
|
|
|
|
@Output() readonly init = new EventEmitter<void>(); |
|
|
|
|
|
|
|
@Output() readonly appear = new EventEmitter(); |
|
|
|
|
|
|
|
@Output() readonly disappear = new EventEmitter(); |
|
|
|
@ -106,11 +89,7 @@ export class ModalComponent implements OnDestroy { |
|
|
|
|
|
|
|
_busy = false; |
|
|
|
|
|
|
|
showModal = false; |
|
|
|
|
|
|
|
isOpenConfirmation = false; |
|
|
|
|
|
|
|
closable = false; |
|
|
|
isConfirmationOpen = false; |
|
|
|
|
|
|
|
destroy$ = new Subject<void>(); |
|
|
|
|
|
|
|
@ -120,22 +99,27 @@ export class ModalComponent implements OnDestroy { |
|
|
|
this.destroy$.next(); |
|
|
|
} |
|
|
|
|
|
|
|
setVisible(value: boolean) { |
|
|
|
this._visible = value; |
|
|
|
this.visibleChange.emit(value); |
|
|
|
this.showModal = value; |
|
|
|
close() { |
|
|
|
if (this.busy) return; |
|
|
|
|
|
|
|
if (value) { |
|
|
|
timer(ANIMATION_TIMEOUT + 100) |
|
|
|
.pipe(take(1)) |
|
|
|
.subscribe(_ => (this.closable = true)); |
|
|
|
const nodes = getFlatNodes( |
|
|
|
(this.modalContent.nativeElement.querySelector('#abp-modal-body') as HTMLElement).childNodes |
|
|
|
); |
|
|
|
|
|
|
|
this.renderer.addClass(document.body, 'modal-open'); |
|
|
|
this.appear.emit(); |
|
|
|
if (hasNgDirty(nodes)) { |
|
|
|
if (this.isConfirmationOpen) return; |
|
|
|
|
|
|
|
this.isConfirmationOpen = true; |
|
|
|
this.confirmationService |
|
|
|
.warn('AbpAccount::AreYouSureYouWantToCancelEditingWarningMessage', 'AbpAccount::AreYouSure') |
|
|
|
.subscribe((status: Toaster.Status) => { |
|
|
|
this.isConfirmationOpen = false; |
|
|
|
if (status === Toaster.Status.confirm) { |
|
|
|
this.visible = false; |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
this.closable = false; |
|
|
|
this.renderer.removeClass(document.body, 'modal-open'); |
|
|
|
this.disappear.emit(); |
|
|
|
this.visible = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -144,7 +128,7 @@ export class ModalComponent implements OnDestroy { |
|
|
|
.pipe( |
|
|
|
takeUntil(this.destroy$), |
|
|
|
debounceTime(150), |
|
|
|
filter((key: KeyboardEvent) => key && key.code === 'Escape' && this.closable) |
|
|
|
filter((key: KeyboardEvent) => key && key.code === 'Escape') |
|
|
|
) |
|
|
|
.subscribe(_ => { |
|
|
|
this.close(); |
|
|
|
@ -155,40 +139,13 @@ export class ModalComponent implements OnDestroy { |
|
|
|
fromEvent(this.abpClose.nativeElement, 'click') |
|
|
|
.pipe( |
|
|
|
takeUntil(this.destroy$), |
|
|
|
filter(() => !!(this.closable && this.modalContent)) |
|
|
|
filter(() => !!this.modalContent) |
|
|
|
) |
|
|
|
.subscribe(() => this.close()); |
|
|
|
}, 0); |
|
|
|
|
|
|
|
this.init.emit(); |
|
|
|
} |
|
|
|
|
|
|
|
close() { |
|
|
|
if (!this.closable || this.busy) return; |
|
|
|
|
|
|
|
const nodes = getFlatNodes( |
|
|
|
(this.modalContent.nativeElement.querySelector('#abp-modal-body') as HTMLElement).childNodes |
|
|
|
); |
|
|
|
|
|
|
|
if (hasNgDirty(nodes)) { |
|
|
|
if (this.isOpenConfirmation) return; |
|
|
|
|
|
|
|
this.isOpenConfirmation = true; |
|
|
|
this.confirmationService |
|
|
|
.warn('AbpAccount::AreYouSureYouWantToCancelEditingWarningMessage', 'AbpAccount::AreYouSure') |
|
|
|
.subscribe((status: Toaster.Status) => { |
|
|
|
timer(ANIMATION_TIMEOUT).subscribe(() => { |
|
|
|
this.isOpenConfirmation = false; |
|
|
|
}); |
|
|
|
|
|
|
|
if (status === Toaster.Status.confirm) { |
|
|
|
this.visible = false; |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
this.visible = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function getFlatNodes(nodes: NodeList): HTMLElement[] { |
|
|
|
|