UNPKG

ngx-modialog-11

Version:
419 lines (409 loc) 15.1 kB
import { combineLatest } from 'rxjs'; import { EventEmitter, Component, ViewEncapsulation, Input, Output, ViewChild, ElementRef, Injectable, NgModule } from '@angular/core'; import { DialogRef, ModalOpenContext, ModalOpenContextBuilder, extend, arrayUnion, privateKey, DROP_IN_TYPE, CSSDialogContainer, Modal as Modal$1, CSSBackdrop, PromiseCompleter, Overlay, ModalModule } from 'ngx-modialog-11'; import { CommonModule } from '@angular/common'; /** * A Dialog is a */ class VEXDialogButtons { constructor() { /** * Emitted when a button was clicked */ this.onButtonClick = new EventEmitter(); } onClick(btn, $event) { $event.stopPropagation(); this.onButtonClick.emit({ btn, $event }); } } VEXDialogButtons.decorators = [ { type: Component, args: [{ selector: 'vex-dialog-buttons', encapsulation: ViewEncapsulation.None, template: `<div class="vex-dialog-buttons"> <button type="button" *ngFor="let btn of buttons;" [class]="btn.cssClass" (click)="onClick(btn, $event)">{{btn.caption}}</button> </div>` },] } ]; VEXDialogButtons.propDecorators = { buttons: [{ type: Input }], onButtonClick: [{ type: Output }] }; /** * A Dialog with customized buttons wrapped in a form. * */ class DialogFormModal { constructor(dialog) { this.dialog = dialog; this.context = dialog.context; } onButtonClick($event) { $event.btn.onClick(this, $event.$event); } } DialogFormModal.decorators = [ { type: Component, args: [{ selector: 'modal-dialog', encapsulation: ViewEncapsulation.None, template: `<form class="vex-dialog-form"> <ng-container *ngComponentOutlet="context.content"></ng-container> <vex-dialog-buttons [buttons]="context.buttons" (onButtonClick)="onButtonClick($event)"></vex-dialog-buttons> </form>` },] } ]; /** @nocollapse */ DialogFormModal.ctorParameters = () => [ { type: DialogRef } ]; class FormDropIn { constructor(dialog) { this.dialog = dialog; this.context = dialog.context; } } FormDropIn.decorators = [ { type: Component, args: [{ selector: 'drop-in-dialog', encapsulation: ViewEncapsulation.None, template: `<div class="vex-dialog-message">{{context.message}}</div> <div *ngIf="context.showInput" class="vex-dialog-input"> <input #input autofocus name="vex" type="text" class="vex-dialog-prompt-input" (change)="context.defaultResult = input.value" placeholder="{{context.placeholder}}"> </div> <div *ngIf="context.showCloseButton" [class]="context.closeClassName" (click)="dialog.dismiss()"></div>` },] } ]; /** @nocollapse */ FormDropIn.ctorParameters = () => [ { type: DialogRef } ]; const DEFAULT_VALUES = { className: 'default', overlayClassName: 'vex-overlay', contentClassName: 'vex-content', closeClassName: 'vex-close' }; const DEFAULT_SETTERS = [ 'className', 'overlayClassName', 'contentClassName', 'closeClassName', 'showCloseButton' ]; class VEXModalContext extends ModalOpenContext { normalize() { if (!this.className) { this.className = DEFAULT_VALUES.className; } if (!this.overlayClassName) { this.overlayClassName = DEFAULT_VALUES.overlayClassName; } if (!this.contentClassName) { this.contentClassName = DEFAULT_VALUES.contentClassName; } if (!this.closeClassName) { this.closeClassName = DEFAULT_VALUES.closeClassName; } super.normalize(); } } class VEXModalContextBuilder extends ModalOpenContextBuilder { constructor(defaultValues = undefined, initialSetters = undefined, baseType = undefined) { super(extend(DEFAULT_VALUES, defaultValues || {}), arrayUnion(DEFAULT_SETTERS, initialSetters || []), baseType || VEXModalContext // https://github.com/Microsoft/TypeScript/issues/7234 ); } /** * * @aliasFor isBlocking */ overlayClosesOnClick(value) { this[privateKey('isBlocking')] = !value; return this; } } const DEFAULT_SETTERS$1 = [ 'content' ]; /** * Data definition */ class DialogPreset extends VEXModalContext { } /** * A Preset representing the configuration needed to open MessageModal. * This is an abstract implementation with no concrete behaviour. * Use derived implementation. */ class DialogPresetBuilder extends VEXModalContextBuilder { constructor(modal, defaultValues = undefined, initialSetters = undefined, baseType = undefined) { super(extend({ modal, component: DialogFormModal, buttons: [], defaultResult: true }, defaultValues || {}), arrayUnion(DEFAULT_SETTERS$1, initialSetters || []), baseType || DialogPreset // https://github.com/Microsoft/TypeScript/issues/7234 ); } addButton(css, caption, onClick) { let btn = { cssClass: css, caption: caption, onClick: onClick }; let key = privateKey('buttons'); this[key].push(btn); return this; } addOkButton(text = 'OK') { this.addButton('vex-dialog-button-primary vex-dialog-button vex-first', text, (cmp, $event) => cmp.dialog.close(cmp.dialog.context.defaultResult)); return this; } addCancelButton(text = 'CANCEL') { this.addButton('vex-dialog-button-secondary vex-dialog-button vex-last', text, (cmp, $event) => cmp.dialog.dismiss()); return this; } } const DEFAULT_VALUES$1 = { component: DialogFormModal, content: FormDropIn, okBtn: 'OK', cancelBtn: 'Cancel' }; const DEFAULT_SETTERS$2 = [ 'okBtn', 'cancelBtn', 'placeholder' ]; /** * Data definition */ class DropInPreset extends DialogPreset { get showInput() { return this.dropInType === DROP_IN_TYPE.prompt; } } /** * A Preset representing all 3 drop ins (alert, prompt, confirm) */ class DropInPresetBuilder extends DialogPresetBuilder { constructor(modal, dropInType, defaultValues = undefined) { super(modal, extend(extend({ modal, dropInType }, DEFAULT_VALUES$1), defaultValues || {}), DEFAULT_SETTERS$2, DropInPreset); } $$beforeOpen(config) { super.$$beforeOpen(config); if (config.okBtn) { this.addOkButton(config.okBtn); } switch (config.dropInType) { case DROP_IN_TYPE.prompt: config.defaultResult = undefined; break; case DROP_IN_TYPE.confirm: if (config.cancelBtn) { this.addCancelButton(config.cancelBtn); } break; } } } /** * A component that acts as a top level container for an open modal window. */ class VexCSSDialogContainer extends CSSDialogContainer { apply(overlay) { overlay.setClickBoundary(this.vexContentContainer.nativeElement); if (this.dialog.inElement) { this.setStyle('padding', '20px 0 0 0'); if (this.dialog.context.className === 'bottom-right-corner') { this.setStyle('overflow-y', 'hidden'); this.renderer.setStyle(this.vexContentContainer.nativeElement, 'position', 'absolute'); } } } } VexCSSDialogContainer.decorators = [ { type: Component, args: [{ selector: 'css-dialog-container', host: { 'tabindex': '-1', 'role': 'dialog' }, encapsulation: ViewEncapsulation.None, template: `<div #clickBoundary class="{{dialog.context.contentClassName}}"><ng-content></ng-content></div>` },] } ]; VexCSSDialogContainer.propDecorators = { vexContentContainer: [{ type: ViewChild, args: ['clickBoundary', { read: ElementRef, static: true },] }] }; // TODO: use DI factory for this. // TODO: consolidate dup code const isDoc = !(typeof document === 'undefined' || !document); let vexV3 = false; /** * Execute this method to flag that you are working with VEX version 3. */ function vexV3Mode() { vexV3 = true; } class Modal extends Modal$1 { constructor(overlay) { super(overlay); } alert() { return new DropInPresetBuilder(this, DROP_IN_TYPE.alert, { isBlocking: false }); } prompt() { return new DropInPresetBuilder(this, DROP_IN_TYPE.prompt, { isBlocking: true, keyboard: null }); } confirm() { return new DropInPresetBuilder(this, DROP_IN_TYPE.confirm, { isBlocking: true, keyboard: null }); } create(dialogRef, content) { if (vexV3 === true) { return this.createV3(dialogRef, content); } const backdropRef = this.createBackdrop(dialogRef, CSSBackdrop); const containerRef = this.createContainer(dialogRef, VexCSSDialogContainer, content); let overlay = dialogRef.overlayRef.instance; let backdrop = backdropRef.instance; let container = containerRef.instance; if (dialogRef.inElement) { overlay.insideElement(); overlay.setContainerStyle('position', 'relative') .setContainerStyle('height', '100%') .setContainerStyle('width', '100%'); backdrop.setStyle('position', 'absolute') .setStyle('display', 'block') .setStyle('height', '100%') .setStyle('width', '100%'); container.setStyle('position', 'relative') .setStyle('display', 'block') .setStyle('height', '100%') .setStyle('width', '100%'); } else { overlay.fullscreen(); } // add body class if this is the only dialog in the stack if (isDoc && !document.body.classList.contains('vex-open')) { document.body.classList.add('vex-open'); } backdrop.addClass('vex-overlay'); container.addClass(`vex vex-theme-${dialogRef.context.className}`); container.setStyle('display', 'block'); if (containerRef.location.nativeElement) { containerRef.location.nativeElement.focus(); } overlay.beforeDestroy(() => { backdrop.addClass('vex-closing'); container.addClass('vex-closing'); const completer = new PromiseCompleter(); let animationEnd$ = backdrop.myAnimationEnd$(); // TODO: the child element inside the container (vex-content) is the one with animation // need to also wait for it to end, but this requires a reference to to it. // the container itself is its parent, won't do. // animationEnd$ = combineLatest.call(animationEnd$, container.myAnimationEnd$(), (s1, s2) => [s1,s2] ); animationEnd$.subscribe(sources => { isDoc && this.overlay.groupStackLength(dialogRef) === 1 && document.body.classList.remove('vex-open'); completer.resolve(); }); return completer.promise; }); container.apply(overlay); return dialogRef; } createV3(dialogRef, content) { const backdropRef = this.createBackdrop(dialogRef, CSSBackdrop); const containerRef = this.createContainer(dialogRef, CSSDialogContainer, content); let overlay = dialogRef.overlayRef.instance; let backdrop = backdropRef.instance; let container = containerRef.instance; dialogRef.inElement ? overlay.insideElement() : overlay.fullscreen(); // add body class if this is the only dialog in the stack if (isDoc && !document.body.classList.contains('vex-open')) { document.body.classList.add('vex-open'); } overlay.addClass(`vex vex-theme-${dialogRef.context.className}`); backdrop.addClass('vex-overlay'); container.addClass(dialogRef.context.contentClassName); container.setStyle('display', 'block'); if (dialogRef.inElement) { overlay.setStyle('padding', '0'); container.setStyle('margin-top', '20px'); } if (containerRef.location.nativeElement) { containerRef.location.nativeElement.focus(); } if (dialogRef.context.className === 'bottom-right-corner') { overlay.setStyle('overflow-y', 'hidden'); container.setStyle('position', 'absolute'); } overlay.beforeDestroy(() => { overlay.addClass('vex-closing'); const completer = new PromiseCompleter(); let animationEnd$ = container.myAnimationEnd$(); if (dialogRef.context.className !== 'bottom-right-corner') { animationEnd$ = combineLatest.call(animationEnd$, backdrop.myAnimationEnd$(), (s1, s2) => [s1, s2]); } animationEnd$.subscribe(sources => { isDoc && this.overlay.groupStackLength(dialogRef) === 1 && document.body.classList.remove('vex-open'); completer.resolve(); }); return completer.promise; }); overlay.setClickBoundary(containerRef.location.nativeElement); return dialogRef; } } Modal.decorators = [ { type: Injectable } ]; /** @nocollapse */ Modal.ctorParameters = () => [ { type: Overlay } ]; const providers = [ { provide: Modal$1, useClass: Modal }, { provide: Modal, useClass: Modal } ]; class VexModalModule { static getProviders() { return providers; } } VexModalModule.decorators = [ { type: NgModule, args: [{ imports: [ModalModule, CommonModule], declarations: [ VexCSSDialogContainer, VEXDialogButtons, FormDropIn, DialogFormModal ], providers, entryComponents: [ VexCSSDialogContainer, DialogFormModal, FormDropIn ] },] } ]; /** * Generated bundle index. Do not edit. */ export { DialogFormModal, DialogPreset, DialogPresetBuilder, DropInPreset, DropInPresetBuilder, FormDropIn, Modal, VEXDialogButtons, VEXModalContext, VEXModalContextBuilder, VexModalModule, providers, vexV3Mode, VexCSSDialogContainer as ɵa }; //# sourceMappingURL=ngx-modialog-11-plugins-vex.js.map