import {NgModule,Component,ElementRef,OnDestroy,Input,EventEmitter,Renderer2,ContentChild,NgZone,ViewChild,ChangeDetectorRef,ChangeDetectionStrategy, ViewEncapsulation, ContentChildren, QueryList, TemplateRef, AfterContentInit} from '@angular/core';
import {trigger,style,transition,animate,AnimationEvent, useAnimation, animation} from '@angular/animations';
import {CommonModule} from '@angular/common';
import {DomHandler} from 'mirra-ui/dom';
import {Footer,SharedModule, PrimeTemplate} from 'mirra-ui/api';
import {ButtonModule} from 'mirra-ui/button';
import {Confirmation} from 'mirra-ui/api';
import {ConfirmationService} from 'mirra-ui/api';
import {Subscription} from 'rxjs';
const showAnimation = animation([
style({ transform: '{{transform}}', opacity: 0 }),
animate('{{transition}}', style({ transform: 'none', opacity: 1 }))
]);
const hideAnimation = animation([
animate('{{transition}}', style({ transform: '{{transform}}', opacity: 0 }))
]);
@Component({
selector: 'p-confirmDialog',
template: `
`,
animations: [
trigger('animation', [
transition('void => visible', [
useAnimation(showAnimation)
]),
transition('visible => void', [
useAnimation(hideAnimation)
])
])
],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
styleUrls: ['../dialog/dialog.scss']
})
export class ConfirmDialog implements AfterContentInit,OnDestroy {
@Input() header: string;
@Input() icon: string;
@Input() message: string;
@Input() style: any;
@Input() styleClass: string;
@Input() maskStyleClass: string;
@Input() acceptIcon: string = 'far fa-check';
@Input() acceptLabel: string = 'Yes';
@Input() acceptVisible: boolean = true;
@Input() rejectIcon: string = 'far fa-times';
@Input() rejectLabel: string = 'No';
@Input() rejectVisible: boolean = true;
@Input() acceptButtonStyleClass: string;
@Input() rejectButtonStyleClass: string;
@Input() closeOnEscape: boolean = true;
@Input() blockScroll: boolean = true;
@Input() rtl: boolean;
@Input() closable: boolean = true;
@Input() appendTo: any;
@Input() key: string;
@Input() autoZIndex: boolean = true;
@Input() baseZIndex: number = 0;
@Input() transitionOptions: string = '150ms cubic-bezier(0, 0, 0.2, 1)';
@Input() focusTrap: boolean = true;
@Input() defaultFocus: string = 'accept';
@Input() get visible(): any {
return this._visible;
}
set visible(value:any) {
this._visible = value;
if (this._visible && !this.maskVisible) {
this.maskVisible = true;
}
this.cd.markForCheck();
}
@Input() get position(): string {
return this._position;
};
set position(value: string) {
this._position = value;
switch (value) {
case 'topleft':
case 'bottomleft':
case 'left':
this.transformOptions = "translate3d(-100%, 0px, 0px)";
break;
case 'topright':
case 'bottomright':
case 'right':
this.transformOptions = "translate3d(100%, 0px, 0px)";
break;
case 'bottom':
this.transformOptions = "translate3d(0px, 100%, 0px)";
break;
case 'top':
this.transformOptions = "translate3d(0px, -100%, 0px)";
break;
default:
this.transformOptions = "scale(0.7)";
break;
}
}
@ContentChild(Footer) footer;
@ViewChild('content') contentViewChild: ElementRef;
@ContentChildren(PrimeTemplate) templates: QueryList;
ngAfterContentInit() {
this.templates.forEach((item) => {
switch(item.getType()) {
case 'footerTemplate':
this.footerTemplate = item.template;
break;
}
});
}
footerTemplate: TemplateRef;
confirmation: Confirmation;
_visible: boolean;
maskVisible: boolean;
documentEscapeListener: any;
container: HTMLDivElement;
wrapper: HTMLElement;
contentContainer: HTMLDivElement;
subscription: Subscription;
preWidth: number;
_position: string = "center";
transformOptions: any = "scale(0.7)";
confirmationOptions: Confirmation;
constructor(public el: ElementRef, public renderer: Renderer2, private confirmationService: ConfirmationService, public zone: NgZone, private cd: ChangeDetectorRef) {
this.subscription = this.confirmationService.requireConfirmation$.subscribe(confirmation => {
if (!confirmation) {
this.hide();
return;
}
if (confirmation.key === this.key) {
this.confirmation = confirmation;
this.confirmationOptions = {
message: this.confirmation.message||this.message,
icon: this.confirmation.icon||this.icon,
header: this.confirmation.header||this.header,
rejectVisible: this.confirmation.rejectVisible == null ? this.rejectVisible : this.confirmation.rejectVisible,
acceptVisible: this.confirmation.acceptVisible == null ? this.acceptVisible : this.confirmation.acceptVisible,
acceptLabel: this.confirmation.acceptLabel||this.acceptLabel,
rejectLabel: this.confirmation.rejectLabel||this.rejectLabel,
acceptIcon: this.confirmation.acceptIcon || this.acceptIcon,
rejectIcon: this.confirmation.rejectIcon || this.rejectIcon,
acceptButtonStyleClass: this.confirmation.acceptButtonStyleClass || this.acceptButtonStyleClass,
rejectButtonStyleClass: this.confirmation.rejectButtonStyleClass || this.rejectButtonStyleClass,
defaultFocus: this.confirmation.defaultFocus || this.defaultFocus,
blockScroll: (this.confirmation.blockScroll === false || this.confirmation.blockScroll === true) ? this.confirmation.blockScroll : this.blockScroll
};
if (this.confirmation.accept) {
this.confirmation.acceptEvent = new EventEmitter();
this.confirmation.acceptEvent.subscribe(this.confirmation.accept);
}
if (this.confirmation.reject) {
this.confirmation.rejectEvent = new EventEmitter();
this.confirmation.rejectEvent.subscribe(this.confirmation.reject);
}
this.visible = true;
}
});
}
option(name: string) {
const source = this.confirmationOptions || this;
if (source.hasOwnProperty(name)) {
return source[name];
}
return undefined;
}
onAnimationStart(event: AnimationEvent) {
switch(event.toState) {
case 'visible':
this.container = event.element;
this.wrapper = this.container.parentElement;
this.contentContainer = DomHandler.findSingle(this.container, '.p-dialog-content');
const element = this.getElementToFocus();
if (element) {
element.focus();
}
this.appendContainer();
this.moveOnTop();
this.bindGlobalListeners();
this.enableModality();
break;
}
}
onAnimationEnd(event: AnimationEvent) {
switch(event.toState) {
case 'void':
this.onOverlayHide();
break;
}
}
getElementToFocus() {
switch(this.option('defaultFocus')) {
case 'accept':
return DomHandler.findSingle(this.container, '.p-confirm-dialog-accept');
case 'reject':
return DomHandler.findSingle(this.container, '.p-confirm-dialog-reject');
case 'close':
return DomHandler.findSingle(this.container, '.p-dialog-header-close');
case 'none':
return null;
//backward compatibility
default:
return DomHandler.findSingle(this.container, '.p-confirm-dialog-accept');
}
}
appendContainer() {
if (this.appendTo) {
if (this.appendTo === 'body')
document.body.appendChild(this.wrapper);
else
DomHandler.appendChild(this.wrapper, this.appendTo);
}
}
restoreAppend() {
if (this.wrapper && this.appendTo) {
this.el.nativeElement.appendChild(this.wrapper);
}
}
enableModality() {
if (this.option('blockScroll')) {
DomHandler.addClass(document.body, 'p-overflow-hidden');
}
}
disableModality() {
this.maskVisible = false;
if (this.option('blockScroll')) {
DomHandler.removeClass(document.body, 'p-overflow-hidden');
}
if (this.container) {
this.cd.detectChanges();
}
}
close(event: Event) {
if (this.confirmation.rejectEvent) {
this.confirmation.rejectEvent.emit();
}
this.hide();
event.preventDefault();
}
hide() {
this.visible = false;
this.confirmation = null;
this.confirmationOptions = null;
}
moveOnTop() {
if (this.autoZIndex) {
this.container.style.zIndex = String(this.baseZIndex + (++DomHandler.zindex));
this.wrapper.style.zIndex = String(this.baseZIndex + (DomHandler.zindex - 1));
}
}
getMaskClass() {
let maskClass = {'p-dialog-mask p-component-overlay': true, 'p-dialog-mask-scrollblocker': this.blockScroll};
maskClass[this.getPositionClass().toString()] = true;
return maskClass;
}
getPositionClass() {
const positions = ['left', 'right', 'top', 'topleft', 'topright', 'bottom', 'bottomleft', 'bottomright'];
const pos = positions.find(item => item === this.position);
return pos ? `p-dialog-${pos}` : '';
}
bindGlobalListeners() {
if ((this.closeOnEscape && this.closable) || this.focusTrap && !this.documentEscapeListener) {
this.documentEscapeListener = this.renderer.listen('document', 'keydown', (event) => {
if (event.which == 27 && (this.closeOnEscape && this.closable)) {
if (parseInt(this.container.style.zIndex) === (DomHandler.zindex + this.baseZIndex) && this.visible) {
this.close(event);
}
}
if (event.which === 9 && this.focusTrap) {
event.preventDefault();
let focusableElements = DomHandler.getFocusableElements(this.container);
if (focusableElements && focusableElements.length > 0) {
if (!document.activeElement) {
focusableElements[0].focus();
}
else {
let focusedIndex = focusableElements.indexOf(document.activeElement);
if (event.shiftKey) {
if (focusedIndex == -1 || focusedIndex === 0)
focusableElements[focusableElements.length - 1].focus();
else
focusableElements[focusedIndex - 1].focus();
}
else {
if (focusedIndex == -1 || focusedIndex === (focusableElements.length - 1))
focusableElements[0].focus();
else
focusableElements[focusedIndex + 1].focus();
}
}
}
}
});
}
}
unbindGlobalListeners() {
if (this.documentEscapeListener) {
this.documentEscapeListener();
this.documentEscapeListener = null;
}
}
onOverlayHide() {
this.disableModality();
this.unbindGlobalListeners();
this.container = null;
}
ngOnDestroy() {
this.restoreAppend();
this.onOverlayHide();
this.subscription.unsubscribe();
}
accept() {
if (this.confirmation.acceptEvent) {
this.confirmation.acceptEvent.emit();
}
this.hide();
}
reject() {
if (this.confirmation.rejectEvent) {
this.confirmation.rejectEvent.emit();
}
this.hide();
}
}
@NgModule({
imports: [CommonModule,ButtonModule],
exports: [ConfirmDialog,ButtonModule,SharedModule],
declarations: [ConfirmDialog]
})
export class ConfirmDialogModule { }