ngx-modialog
Version:
Modal / Dialog for Angular
303 lines (302 loc) • 11.3 kB
JavaScript
import * as tslib_1 from "tslib";
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
import { Component, ElementRef, ViewChild, ViewContainerRef, ViewEncapsulation, Renderer2, TemplateRef } from '@angular/core';
import { PromiseCompleter, supportsKey } from '../framework/utils';
import { DialogRef } from '../models/dialog-ref';
import { BaseDynamicComponent } from '../components/index';
// TODO: use DI factory for this.
// TODO: consolidate dup code
var /** @type {?} */ isDoc = !(typeof document === 'undefined' || !document);
/**
* @record
*/
export function EmbedComponentConfig() { }
function EmbedComponentConfig_tsickle_Closure_declarations() {
/** @type {?} */
EmbedComponentConfig.prototype.component;
/** @type {?|undefined} */
EmbedComponentConfig.prototype.projectableNodes;
}
/**
* Represents the modal overlay.
*/
var ModalOverlay = /** @class */ (function (_super) {
tslib_1.__extends(ModalOverlay, _super);
/**
* @param {?} dialogRef
* @param {?} vcr
* @param {?} el
* @param {?} renderer
*/
function ModalOverlay(dialogRef, vcr, el, renderer) {
var _this = _super.call(this, el, renderer) || this;
_this.dialogRef = dialogRef;
_this.vcr = vcr;
_this.activateAnimationListener();
return _this;
}
/**
* \@internal
* @template T
* @param {?} content
* @return {?}
*/
ModalOverlay.prototype.getProjectables = function (content) {
var /** @type {?} */ nodes;
if (typeof content === 'string') {
nodes = [[this.renderer.createText("" + content)]];
}
else if (content instanceof TemplateRef) {
nodes = [this.vcr.createEmbeddedView(content, { $implicit: this.dialogRef.context, dialogRef: this.dialogRef }).rootNodes];
}
else {
nodes = [this.embedComponent({ component: content }).rootNodes];
}
return nodes;
};
/**
* @param {?} config
* @return {?}
*/
ModalOverlay.prototype.embedComponent = function (config) {
var /** @type {?} */ ctx = (config);
return this.vcr.createEmbeddedView(this.template, /** @type {?} */ ({
$implicit: ctx
}));
};
/**
* @template T
* @param {?} type
* @param {?=} projectableNodes
* @return {?}
*/
ModalOverlay.prototype.addComponent = function (type, projectableNodes) {
if (projectableNodes === void 0) { projectableNodes = []; }
return _super.prototype._addComponent.call(this, {
component: type,
vcRef: this.innerVcr,
projectableNodes: projectableNodes
});
};
/**
* @return {?}
*/
ModalOverlay.prototype.fullscreen = function () {
var _this = this;
var /** @type {?} */ style = {
position: 'fixed',
top: 0,
left: 0,
bottom: 0,
right: 0,
'z-index': 1500
};
Object.keys(style).forEach(function (k) { return _this.setStyle(k, style[k]); });
};
/**
* @return {?}
*/
ModalOverlay.prototype.insideElement = function () {
var _this = this;
var /** @type {?} */ style = {
position: 'absolute',
overflow: 'hidden',
width: '100%',
height: '100%',
top: 0,
left: 0,
bottom: 0,
right: 0
};
Object.keys(style).forEach(function (k) { return _this.setStyle(k, style[k]); });
};
/**
* Set a specific inline style for the container of the whole dialog component
* The dialog component root element is the host of this component, it contains only 1 direct
* child which is the container.
*
* Structure:
*
* ```html
* <modal-overlay>
* <div>
* <!-- BACKDROP ELEMENT -->
* <!-- DIALOG CONTAINER ELEMENT -->
* </div>
* </modal-overlay>
* ```
*
* @param {?} prop The style key
* @param {?} value The value, undefined to remove
* @return {?}
*/
ModalOverlay.prototype.setContainerStyle = function (prop, value) {
this.renderer.setStyle(this.container.nativeElement, prop, value);
return this;
};
/**
* Define an element that click inside it will not trigger modal close.
* Since events bubble, clicking on a dialog will bubble up to the overlay, a plugin
* must define an element that represent the dialog, the overlay will make sure no to close when
* it was clicked.
* @param {?} element
* @return {?}
*/
ModalOverlay.prototype.setClickBoundary = function (element) {
var _this = this;
var /** @type {?} */ target;
var /** @type {?} */ elListener = function (event) { return target = /** @type {?} */ (event.target); };
var /** @type {?} */ docListener = function (event) {
if (_this.dialogRef.context.isBlocking || !_this.dialogRef.overlay.isTopMost(_this.dialogRef)) {
return;
}
var /** @type {?} */ current = event.target;
// on click, this will hit.
if (current === target)
return;
// on mouse down -> drag -> release the current might not be 'target', it might be
// a sibling or a child (i.e: not part of the tree-up direction). It might also be a release
// outside the dialog... so we compare to the boundary element
do {
if (current === element) {
return;
}
} while (current.parentNode && (current = current.parentNode));
_this.dialogRef.dismiss();
};
if (isDoc) {
this.dialogRef.onDestroy.subscribe(function () {
element.removeEventListener('click', elListener, false);
element.removeEventListener('touchstart', elListener, false);
document.removeEventListener('click', docListener, false);
document.removeEventListener('touchend', docListener, false);
});
setTimeout(function () {
element.addEventListener('mousedown', elListener, false);
element.addEventListener('touchstart', docListener, false);
document.addEventListener('click', docListener, false);
document.addEventListener('touchend', docListener, false);
});
}
};
/**
* Temp workaround for animation where destruction of the top level component does not
* trigger child animations. Solution should be found either in animation module or in design
* of the modal component tree.
* @return {?}
*/
ModalOverlay.prototype.canDestroy = function () {
var /** @type {?} */ completer = new PromiseCompleter();
if (!Array.isArray(this.beforeDestroyHandlers)) {
completer.resolve();
}
else {
// run destroy notification but protect against halt.
var /** @type {?} */ id_1 = setTimeout(function () {
id_1 = null;
completer.reject();
}, 1000);
var /** @type {?} */ resolve = function () {
if (id_1 === null)
return;
clearTimeout(id_1);
completer.resolve();
};
Promise.all(this.beforeDestroyHandlers.map(function (fn) { return fn(); }))
.then(resolve)
.catch(resolve);
}
return completer.promise;
};
/**
* A handler running before destruction of the overlay
* use to delay destruction due to animation.
* This is part of the workaround for animation, see canDestroy.
*
* NOTE: There is no guarantee that the listeners will fire, use dialog.onDestory for that.
* @param {?} fn
* @return {?}
*/
ModalOverlay.prototype.beforeDestroy = function (fn) {
if (!this.beforeDestroyHandlers) {
this.beforeDestroyHandlers = [];
}
this.beforeDestroyHandlers.push(fn);
};
/**
* @param {?} event
* @return {?}
*/
ModalOverlay.prototype.documentKeypress = function (event) {
// check that this modal is the last in the stack.
if (!this.dialogRef.overlay.isTopMost(this.dialogRef))
return;
if (supportsKey(event.keyCode, /** @type {?} */ (this.dialogRef.context.keyboard))) {
this.dialogRef.dismiss();
}
};
/**
* @return {?}
*/
ModalOverlay.prototype.ngOnDestroy = function () {
_super.prototype.ngOnDestroy.call(this);
if (this.dialogRef.destroyed !== true) {
// if we're here the overlay is destroyed by an external event that is not user invoked.
// i.e: The user did no call dismiss or close and dialogRef.destroy() did not invoke.
// this will happen when routing or killing an element containing a blocked overlay (ngIf)
// we bail out, i.e gracefully shutting down.
this.dialogRef.bailOut();
}
};
return ModalOverlay;
}(BaseDynamicComponent));
export { ModalOverlay };
ModalOverlay.decorators = [
{ type: Component, args: [{
selector: 'modal-overlay',
host: {
'(body:keydown)': 'documentKeypress($event)'
},
encapsulation: ViewEncapsulation.None,
template: "<div #container>\n <ng-template #innerView></ng-template>\n</div>\n<ng-template #template let-ctx>\n <ng-container *ngComponentOutlet=\"ctx.component; injector: ctx.injector; content: ctx.projectableNodes\"></ng-container>\n</ng-template>"
},] },
];
/** @nocollapse */
ModalOverlay.ctorParameters = function () { return [
{ type: DialogRef, },
{ type: ViewContainerRef, },
{ type: ElementRef, },
{ type: Renderer2, },
]; };
ModalOverlay.propDecorators = {
"container": [{ type: ViewChild, args: ['container', { read: ElementRef },] },],
"innerVcr": [{ type: ViewChild, args: ['innerView', { read: ViewContainerRef },] },],
"template": [{ type: ViewChild, args: ['template',] },],
};
function ModalOverlay_tsickle_Closure_declarations() {
/** @type {!Array<{type: !Function, args: (undefined|!Array<?>)}>} */
ModalOverlay.decorators;
/**
* @nocollapse
* @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array<?>)}>)})>}
*/
ModalOverlay.ctorParameters;
/** @type {!Object<string,!Array<{type: !Function, args: (undefined|!Array<?>)}>>} */
ModalOverlay.propDecorators;
/** @type {?} */
ModalOverlay.prototype.beforeDestroyHandlers;
/** @type {?} */
ModalOverlay.prototype.container;
/** @type {?} */
ModalOverlay.prototype.innerVcr;
/** @type {?} */
ModalOverlay.prototype.template;
/** @type {?} */
ModalOverlay.prototype.dialogRef;
/** @type {?} */
ModalOverlay.prototype.vcr;
}
//# sourceMappingURL=overlay.component.js.map