UNPKG

ngx-modialog

Version:
550 lines (539 loc) 17.7 kB
import { Component, ViewEncapsulation, Input, Output, EventEmitter, ElementRef, ViewChild, Injectable, NgModule } from '@angular/core'; import { DialogRef, ModalOpenContext, ModalOpenContextBuilder, privateKey, extend, arrayUnion, DROP_IN_TYPE, CSSDialogContainer, Overlay, Modal, CSSBackdrop, PromiseCompleter, ModalModule } from 'ngx-modialog'; import { combineLatest } from 'rxjs'; import { CommonModule } from '@angular/common'; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * A Dialog is a */ class VEXDialogButtons { constructor() { /** * Emitted when a button was clicked */ this.onButtonClick = new EventEmitter(); } /** * @param {?} btn * @param {?} $event * @return {?} */ 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>` },] }, ]; /** @nocollapse */ VEXDialogButtons.propDecorators = { "buttons": [{ type: Input },], "onButtonClick": [{ type: Output },], }; /** * A Dialog with customized buttons wrapped in a form. * */ class DialogFormModal { /** * @param {?} dialog */ constructor(dialog) { this.dialog = dialog; this.context = dialog.context; } /** * @param {?} $event * @return {?} */ 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 { /** * @param {?} dialog */ 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, }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ const /** @type {?} */ DEFAULT_VALUES = { className: /** @type {?} */ ('default'), overlayClassName: 'vex-overlay', contentClassName: 'vex-content', closeClassName: 'vex-close' }; const /** @type {?} */ DEFAULT_SETTERS = [ 'className', 'overlayClassName', 'contentClassName', 'closeClassName', 'showCloseButton' ]; class VEXModalContext extends ModalOpenContext { /** * @return {?} */ 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(); } } // unsupported: template constraints. /** * @template T */ class VEXModalContextBuilder extends ModalOpenContextBuilder { /** * @param {?=} defaultValues * @param {?=} initialSetters * @param {?=} baseType */ constructor(defaultValues = undefined, initialSetters = undefined, baseType = undefined) { super(extend(DEFAULT_VALUES, defaultValues || {}), arrayUnion(DEFAULT_SETTERS, initialSetters || []), baseType || /** @type {?} */ (VEXModalContext // https://github.com/Microsoft/TypeScript/issues/7234 ) // https://github.com/Microsoft/TypeScript/issues/7234 ); } /** * * \@aliasFor isBlocking * @param {?} value * @return {?} */ overlayClosesOnClick(value) { this[privateKey('isBlocking')] = !value; return this; } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ const /** @type {?} */ DEFAULT_SETTERS$1 = [ 'content' ]; /** * Data definition */ class DialogPreset extends VEXModalContext { } // unsupported: template constraints. /** * A Preset representing the configuration needed to open MessageModal. * This is an abstract implementation with no concrete behaviour. * Use derived implementation. * @template T */ class DialogPresetBuilder extends VEXModalContextBuilder { /** * @param {?} modal * @param {?=} defaultValues * @param {?=} initialSetters * @param {?=} baseType */ constructor(modal, defaultValues = undefined, initialSetters = undefined, baseType = undefined) { super(extend({ modal, component: DialogFormModal, buttons: [], defaultResult: true }, defaultValues || {}), arrayUnion(DEFAULT_SETTERS$1, initialSetters || []), baseType || /** @type {?} */ (DialogPreset // https://github.com/Microsoft/TypeScript/issues/7234 ) // https://github.com/Microsoft/TypeScript/issues/7234 ); } /** * @param {?} css * @param {?} caption * @param {?} onClick * @return {?} */ addButton(css, caption, onClick) { let /** @type {?} */ btn = { cssClass: css, caption: caption, onClick: onClick }; let /** @type {?} */ key = privateKey('buttons'); (/** @type {?} */ (this[key])).push(btn); return this; } /** * @param {?=} text * @return {?} */ 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; } /** * @param {?=} text * @return {?} */ addCancelButton(text = 'CANCEL') { this.addButton('vex-dialog-button-secondary vex-dialog-button vex-last', text, (cmp, $event) => cmp.dialog.dismiss()); return this; } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ const /** @type {?} */ DEFAULT_VALUES$1 = { component: DialogFormModal, content: FormDropIn, okBtn: 'OK', cancelBtn: 'Cancel' }; const /** @type {?} */ DEFAULT_SETTERS$2 = [ 'okBtn', 'cancelBtn', 'placeholder' ]; /** * Data definition */ class DropInPreset extends DialogPreset { /** * @return {?} */ get showInput() { return this.dropInType === DROP_IN_TYPE.prompt; } } /** * A Preset representing all 3 drop ins (alert, prompt, confirm) */ class DropInPresetBuilder extends DialogPresetBuilder { /** * @param {?} modal * @param {?} dropInType * @param {?=} defaultValues */ constructor(modal, dropInType, defaultValues = undefined) { super(modal, extend(extend({ modal, dropInType }, DEFAULT_VALUES$1), defaultValues || {}), DEFAULT_SETTERS$2, DropInPreset); } /** * @param {?} config * @return {?} */ $$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; } } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * A component that acts as a top level container for an open modal window. */ class VexCSSDialogContainer extends CSSDialogContainer { /** * @param {?} overlay * @return {?} */ 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>` },] }, ]; /** @nocollapse */ VexCSSDialogContainer.propDecorators = { "vexContentContainer": [{ type: ViewChild, args: ['clickBoundary', { read: ElementRef },] },], }; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ // TODO: use DI factory for this. // TODO: consolidate dup code const /** @type {?} */ isDoc = !(typeof document === 'undefined' || !document); let /** @type {?} */ vexV3 = false; /** * Execute this method to flag that you are working with VEX version 3. * @return {?} */ function vexV3Mode() { vexV3 = true; } class Modal$1 extends Modal { /** * @param {?} overlay */ constructor(overlay) { super(overlay); } /** * @return {?} */ alert() { return new DropInPresetBuilder(this, DROP_IN_TYPE.alert, /** @type {?} */ ({ isBlocking: false })); } /** * @return {?} */ prompt() { return new DropInPresetBuilder(this, DROP_IN_TYPE.prompt, /** @type {?} */ ({ isBlocking: true, keyboard: null })); } /** * @return {?} */ confirm() { return new DropInPresetBuilder(this, DROP_IN_TYPE.confirm, /** @type {?} */ ({ isBlocking: true, keyboard: null })); } /** * @param {?} dialogRef * @param {?} content * @return {?} */ create(dialogRef, content) { if (vexV3 === true) { return this.createV3(dialogRef, content); } const /** @type {?} */ backdropRef = this.createBackdrop(dialogRef, CSSBackdrop); const /** @type {?} */ containerRef = this.createContainer(dialogRef, VexCSSDialogContainer, content); let /** @type {?} */ overlay = dialogRef.overlayRef.instance; let /** @type {?} */ backdrop = backdropRef.instance; let /** @type {?} */ 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 /** @type {?} */ completer = new PromiseCompleter(); let /** @type {?} */ 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; } /** * @param {?} dialogRef * @param {?} content * @return {?} */ createV3(dialogRef, content) { const /** @type {?} */ backdropRef = this.createBackdrop(dialogRef, CSSBackdrop); const /** @type {?} */ containerRef = this.createContainer(dialogRef, CSSDialogContainer, content); let /** @type {?} */ overlay = dialogRef.overlayRef.instance; let /** @type {?} */ backdrop = backdropRef.instance; let /** @type {?} */ 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 /** @type {?} */ completer = new PromiseCompleter(); let /** @type {?} */ 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$1.decorators = [ { type: Injectable }, ]; /** @nocollapse */ Modal$1.ctorParameters = () => [ { type: Overlay, }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ const /** @type {?} */ providers = [ { provide: Modal, useClass: Modal$1 }, { provide: Modal$1, useClass: Modal$1 } ]; class VexModalModule { /** * @return {?} */ static getProviders() { return providers; } } VexModalModule.decorators = [ { type: NgModule, args: [{ imports: [ModalModule, CommonModule], declarations: [ VexCSSDialogContainer, VEXDialogButtons, FormDropIn, DialogFormModal ], providers, entryComponents: [ VexCSSDialogContainer, DialogFormModal, FormDropIn ] },] }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ export { Modal$1 as Modal, vexV3Mode, VEXModalContext, VEXModalContextBuilder, DropInPreset, DropInPresetBuilder, DialogFormModal, FormDropIn, VEXDialogButtons, DialogPreset, DialogPresetBuilder, VexModalModule, providers, VexCSSDialogContainer as ɵa }; //# sourceMappingURL=ngx-modialog-plugins-vex.js.map