angular-confirmation-popover
Version:
An angular 15.0+ bootstrap confirmation popover
370 lines (360 loc) • 20.6 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Directive, Input, Component, EventEmitter, Injector, Output, HostListener, InjectionToken, NgModule } from '@angular/core';
import * as i2 from '@angular/common';
import { CommonModule } from '@angular/common';
import { positionElements } from 'positioning';
class ConfirmationPopoverOptions {
constructor() {
this.confirmText = 'Confirm';
this.cancelText = 'Cancel';
this.confirmButtonType = 'success';
this.cancelButtonType = 'outline-secondary';
this.placement = 'top';
this.hideConfirmButton = false;
this.hideCancelButton = false;
this.popoverClass = '';
this.appendToBody = false;
this.reverseButtonOrder = false;
this.closeOnOutsideClick = true;
}
}
ConfirmationPopoverOptions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverOptions, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
ConfirmationPopoverOptions.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverOptions });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverOptions, decorators: [{
type: Injectable
}] });
/**
* @internal
*/
class ConfirmationPopoverWindowOptions extends ConfirmationPopoverOptions {
}
ConfirmationPopoverWindowOptions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverWindowOptions, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
ConfirmationPopoverWindowOptions.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverWindowOptions });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverWindowOptions, decorators: [{
type: Injectable
}] });
/**
* A helper directive to focus buttons. You will only need this if using a custom template
*/
class FocusDirective {
constructor(elm) {
this.elm = elm;
}
ngOnChanges(changes) {
if (changes.mwlFocus && this.mwlFocus === true) {
this.elm.nativeElement.focus();
}
}
}
FocusDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: FocusDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
FocusDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.8", type: FocusDirective, selector: "[mwlFocus]", inputs: { mwlFocus: "mwlFocus" }, usesOnChanges: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: FocusDirective, decorators: [{
type: Directive,
args: [{
selector: '[mwlFocus]',
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { mwlFocus: [{
type: Input
}] } });
/**
* @internal
*/
class ConfirmationPopoverWindowComponent {
constructor(options) {
this.options = options;
}
ngAfterViewInit() {
this.options.onAfterViewInit();
}
}
ConfirmationPopoverWindowComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverWindowComponent, deps: [{ token: ConfirmationPopoverWindowOptions }], target: i0.ɵɵFactoryTarget.Component });
ConfirmationPopoverWindowComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.8", type: ConfirmationPopoverWindowComponent, selector: "mwl-confirmation-popover-window", ngImport: i0, template: "<ng-template #defaultTemplate let-options=\"options\">\n <div\n [ngClass]=\"[\n 'popover',\n options.placement,\n 'popover-' + options.placement,\n 'bs-popover-' + options.placement,\n options.popoverClass\n ]\"\n >\n <div class=\"popover-arrow arrow\"></div>\n <h3\n class=\"popover-title popover-header\"\n [innerHTML]=\"options.popoverTitle\"\n ></h3>\n <div class=\"popover-content popover-body\">\n <p [innerHTML]=\"options.popoverMessage\"></p>\n <div\n class=\"confirm-btns\"\n [class.confirm-btns-reversed]=\"options.reverseButtonOrder\"\n >\n <div class=\"confirm-btn-container\" *ngIf=\"!options.hideCancelButton\">\n <button\n type=\"button\"\n [mwlFocus]=\"options.focusButton === 'cancel'\"\n [class]=\"'btn btn-block btn-' + options.cancelButtonType\"\n (click)=\"options.onCancel({ clickEvent: $event })\"\n [innerHtml]=\"options.cancelText\"\n ></button>\n </div>\n <div class=\"confirm-btn-container\" *ngIf=\"!options.hideConfirmButton\">\n <button\n type=\"button\"\n [mwlFocus]=\"options.focusButton === 'confirm'\"\n [class]=\"'btn btn-block btn-' + options.confirmButtonType\"\n (click)=\"options.onConfirm({ clickEvent: $event })\"\n [innerHtml]=\"options.confirmText\"\n ></button>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n<ng-template\n [ngTemplateOutlet]=\"options.customTemplate || defaultTemplate\"\n [ngTemplateOutletContext]=\"{ options: options }\"\n>\n</ng-template>\n", styles: [".popover{display:block}.bs-popover-top .arrow,.bs-popover-bottom .arrow{left:50%}.bs-popover-left .arrow,.bs-popover-right .arrow{top:calc(50% - 8px)}.btn{transition:none}.confirm-btns{display:flex;justify-content:space-around}.confirm-btn-container{flex-basis:50%}.confirm-btn-container:not(:first-child){margin-left:4px}.confirm-btn-container:not(:last-child){margin-right:4px}.confirm-btns-reversed{flex-direction:row-reverse}.confirm-btns-reversed .confirm-btn-container:not(:first-child){margin-right:4px;margin-left:0}.confirm-btns-reversed .confirm-btn-container:not(:last-child){margin-right:0;margin-left:4px}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: FocusDirective, selector: "[mwlFocus]", inputs: ["mwlFocus"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverWindowComponent, decorators: [{
type: Component,
args: [{ selector: 'mwl-confirmation-popover-window', template: "<ng-template #defaultTemplate let-options=\"options\">\n <div\n [ngClass]=\"[\n 'popover',\n options.placement,\n 'popover-' + options.placement,\n 'bs-popover-' + options.placement,\n options.popoverClass\n ]\"\n >\n <div class=\"popover-arrow arrow\"></div>\n <h3\n class=\"popover-title popover-header\"\n [innerHTML]=\"options.popoverTitle\"\n ></h3>\n <div class=\"popover-content popover-body\">\n <p [innerHTML]=\"options.popoverMessage\"></p>\n <div\n class=\"confirm-btns\"\n [class.confirm-btns-reversed]=\"options.reverseButtonOrder\"\n >\n <div class=\"confirm-btn-container\" *ngIf=\"!options.hideCancelButton\">\n <button\n type=\"button\"\n [mwlFocus]=\"options.focusButton === 'cancel'\"\n [class]=\"'btn btn-block btn-' + options.cancelButtonType\"\n (click)=\"options.onCancel({ clickEvent: $event })\"\n [innerHtml]=\"options.cancelText\"\n ></button>\n </div>\n <div class=\"confirm-btn-container\" *ngIf=\"!options.hideConfirmButton\">\n <button\n type=\"button\"\n [mwlFocus]=\"options.focusButton === 'confirm'\"\n [class]=\"'btn btn-block btn-' + options.confirmButtonType\"\n (click)=\"options.onConfirm({ clickEvent: $event })\"\n [innerHtml]=\"options.confirmText\"\n ></button>\n </div>\n </div>\n </div>\n </div>\n</ng-template>\n<ng-template\n [ngTemplateOutlet]=\"options.customTemplate || defaultTemplate\"\n [ngTemplateOutletContext]=\"{ options: options }\"\n>\n</ng-template>\n", styles: [".popover{display:block}.bs-popover-top .arrow,.bs-popover-bottom .arrow{left:50%}.bs-popover-left .arrow,.bs-popover-right .arrow{top:calc(50% - 8px)}.btn{transition:none}.confirm-btns{display:flex;justify-content:space-around}.confirm-btn-container{flex-basis:50%}.confirm-btn-container:not(:first-child){margin-left:4px}.confirm-btn-container:not(:last-child){margin-right:4px}.confirm-btns-reversed{flex-direction:row-reverse}.confirm-btns-reversed .confirm-btn-container:not(:first-child){margin-right:4px;margin-left:0}.confirm-btns-reversed .confirm-btn-container:not(:last-child){margin-right:0;margin-left:4px}\n"] }]
}], ctorParameters: function () { return [{ type: ConfirmationPopoverWindowOptions }]; } });
/**
All properties can be set on the directive as attributes like so (use `ConfirmationPopoverModule.forRoot()` to configure them globally):
```html
<button
class="btn btn-outline-secondary"
mwlConfirmationPopover
[popoverTitle]="popoverTitle"
[popoverMessage]="popoverMessage"
placement="left"
(confirm)="confirmClicked = true"
(cancel)="cancelClicked = true"
[(isOpen)]="isOpen">
Show confirm popover!
</button>
```
*/
class ConfirmationPopoverDirective {
/**
* @internal
*/
constructor(viewContainerRef, elm, defaultOptions, renderer) {
this.viewContainerRef = viewContainerRef;
this.elm = elm;
this.defaultOptions = defaultOptions;
this.renderer = renderer;
/**
* Whether to disable showing the popover. Default `false`.
*/
this.isDisabled = false;
/**
* Will open or show the popover when changed.
* Can be sugared with `isOpenChange` to emulate 2-way binding like so `[(isOpen)]="isOpen"`
*/
this.isOpen = false;
/**
* Will emit when the popover is opened or closed
*/
this.isOpenChange = new EventEmitter(true);
/**
* An expression that is called when the confirm button is clicked.
*/
this.confirm = new EventEmitter();
/**
* An expression that is called when the cancel button is clicked.
*/
this.cancel = new EventEmitter();
this.eventListeners = [];
}
/**
* @internal
*/
ngOnInit() {
this.isOpenChange.emit(false);
}
/**
* @internal
*/
ngOnChanges(changes) {
if (changes.isOpen) {
if (changes.isOpen.currentValue === true) {
this.showPopover();
}
else {
this.hidePopover();
}
}
}
/**
* @internal
*/
ngOnDestroy() {
this.hidePopover();
}
/**
* @internal
*/
onConfirm(event) {
this.confirm.emit(event);
this.hidePopover();
}
/**
* @internal
*/
onCancel(event) {
this.cancel.emit(event);
this.hidePopover();
}
/**
* @internal
*/
togglePopover() {
if (!this.popover) {
this.showPopover();
}
else {
this.hidePopover();
}
}
onDocumentClick(event) {
const closeOnOutsideClick = typeof this.closeOnOutsideClick !== 'undefined'
? this.closeOnOutsideClick
: this.defaultOptions.closeOnOutsideClick;
if (this.popover &&
!this.elm.nativeElement.contains(event.target) &&
!this.popover.location.nativeElement.contains(event.target) &&
closeOnOutsideClick) {
this.hidePopover();
}
}
showPopover() {
if (!this.popover && !this.isDisabled) {
// work around for https://github.com/mattlewis92/angular-confirmation-popover/issues/65
// otherwise the document click event gets fired after the click event
// that triggered the popover to open (no idea why this is so)
setTimeout(() => {
this.eventListeners = [
this.renderer.listen('document', 'click', (event) => this.onDocumentClick(event)),
this.renderer.listen('document', 'touchend', (event) => this.onDocumentClick(event)),
this.renderer.listen('window', 'resize', () => this.positionPopover()),
];
});
const options = new ConfirmationPopoverWindowOptions();
Object.assign(options, this.defaultOptions, {
onConfirm: (event) => {
this.onConfirm(event);
},
onCancel: (event) => {
this.onCancel(event);
},
onAfterViewInit: () => {
this.positionPopover();
},
});
const optionalParams = [
'confirmText',
'cancelText',
'placement',
'confirmButtonType',
'cancelButtonType',
'focusButton',
'hideConfirmButton',
'hideCancelButton',
'popoverClass',
'appendToBody',
'customTemplate',
'reverseButtonOrder',
'popoverTitle',
'popoverMessage',
];
optionalParams.forEach((param) => {
if (typeof this[param] !== 'undefined') {
options[param] = this[param];
}
});
const childInjector = Injector.create({
providers: [
{
provide: ConfirmationPopoverWindowOptions,
useValue: options,
},
],
});
this.popover = this.viewContainerRef.createComponent(ConfirmationPopoverWindowComponent, { injector: childInjector });
if (options.appendToBody) {
document.body.appendChild(this.popover.location.nativeElement);
}
this.isOpenChange.emit(true);
}
}
positionPopover() {
if (this.popover) {
const popoverElement = this.popover.location.nativeElement.children[0];
positionElements(this.elm.nativeElement, popoverElement, this.placement || this.defaultOptions.placement, this.appendToBody || this.defaultOptions.appendToBody);
}
}
hidePopover() {
if (this.popover) {
this.popover.destroy();
delete this.popover;
this.isOpenChange.emit(false);
this.eventListeners.forEach((fn) => fn());
this.eventListeners = [];
}
}
}
ConfirmationPopoverDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverDirective, deps: [{ token: i0.ViewContainerRef }, { token: i0.ElementRef }, { token: ConfirmationPopoverOptions }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
ConfirmationPopoverDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.8", type: ConfirmationPopoverDirective, selector: "[mwlConfirmationPopover]", inputs: { popoverTitle: "popoverTitle", popoverMessage: "popoverMessage", confirmText: "confirmText", cancelText: "cancelText", placement: "placement", confirmButtonType: "confirmButtonType", cancelButtonType: "cancelButtonType", focusButton: "focusButton", hideConfirmButton: "hideConfirmButton", hideCancelButton: "hideCancelButton", isDisabled: "isDisabled", isOpen: "isOpen", customTemplate: "customTemplate", popoverClass: "popoverClass", appendToBody: "appendToBody", reverseButtonOrder: "reverseButtonOrder", closeOnOutsideClick: "closeOnOutsideClick" }, outputs: { isOpenChange: "isOpenChange", confirm: "confirm", cancel: "cancel" }, host: { listeners: { "click": "togglePopover()" } }, usesOnChanges: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverDirective, decorators: [{
type: Directive,
args: [{
selector: '[mwlConfirmationPopover]',
}]
}], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ElementRef }, { type: ConfirmationPopoverOptions }, { type: i0.Renderer2 }]; }, propDecorators: { popoverTitle: [{
type: Input
}], popoverMessage: [{
type: Input
}], confirmText: [{
type: Input
}], cancelText: [{
type: Input
}], placement: [{
type: Input
}], confirmButtonType: [{
type: Input
}], cancelButtonType: [{
type: Input
}], focusButton: [{
type: Input
}], hideConfirmButton: [{
type: Input
}], hideCancelButton: [{
type: Input
}], isDisabled: [{
type: Input
}], isOpen: [{
type: Input
}], customTemplate: [{
type: Input
}], isOpenChange: [{
type: Output
}], confirm: [{
type: Output
}], cancel: [{
type: Output
}], popoverClass: [{
type: Input
}], appendToBody: [{
type: Input
}], reverseButtonOrder: [{
type: Input
}], closeOnOutsideClick: [{
type: Input
}], togglePopover: [{
type: HostListener,
args: ['click']
}] } });
const USER_OPTIONS = new InjectionToken('confirmation popover user options');
function optionsFactory(userOptions) {
const options = new ConfirmationPopoverOptions();
Object.assign(options, userOptions);
return options;
}
class ConfirmationPopoverModule {
static forRoot(options = {}) {
return {
ngModule: ConfirmationPopoverModule,
providers: [
{
provide: USER_OPTIONS,
useValue: options,
},
{
provide: ConfirmationPopoverOptions,
useFactory: optionsFactory,
deps: [USER_OPTIONS],
},
],
};
}
}
ConfirmationPopoverModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
ConfirmationPopoverModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverModule, declarations: [ConfirmationPopoverDirective,
ConfirmationPopoverWindowComponent,
FocusDirective], imports: [CommonModule], exports: [ConfirmationPopoverDirective, FocusDirective] });
ConfirmationPopoverModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverModule, imports: [CommonModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: ConfirmationPopoverModule, decorators: [{
type: NgModule,
args: [{
declarations: [
ConfirmationPopoverDirective,
ConfirmationPopoverWindowComponent,
FocusDirective,
],
imports: [CommonModule],
exports: [ConfirmationPopoverDirective, FocusDirective]
}]
}] });
/*
* Public API Surface of angular-confirmation-popover
*/
/**
* Generated bundle index. Do not edit.
*/
export { ConfirmationPopoverDirective, ConfirmationPopoverModule, FocusDirective };
//# sourceMappingURL=angular-confirmation-popover.mjs.map