ngx-modialog-11
Version:
Modal / Dialog for Angular
80 lines • 11.2 kB
JavaScript
// heavily inspired by:
// http://www.bennadel.com/blog/3025-creating-custom-dom-and-host-event-bindings-in-angular-2-beta-6.htm
import { Injectable } from '@angular/core';
import { noop } from '../framework/utils';
// TODO: use DI factory for this.
// TODO: consolidate dup code
const isDoc = !(typeof document === 'undefined' || !document);
const eventMap = {
clickOutside: 'click',
mousedownOutside: 'mousedown',
mouseupOutside: 'mouseup',
mousemoveOutside: 'mousemove'
};
/**
* An event handler factory for event handlers that bubble the event to a given handler
* if the event target is not an ancestor of the given element.
* @param element
* @param handler
*/
function bubbleNonAncestorHandlerFactory(element, handler) {
return (event) => {
let current = event.target;
do {
if (current === element) {
return;
}
} while (current.parentNode && (current = current.parentNode));
handler(event);
};
}
export class DOMOutsideEventPlugin {
constructor() {
if (!isDoc || typeof document.addEventListener !== 'function') {
this.addEventListener = noop;
}
}
supports(eventName) {
return eventMap.hasOwnProperty(eventName);
}
addEventListener(element, eventName, handler) {
const zone = this.manager.getZone();
// A Factory that registers the event on the document, instead of the element.
// the handler is created at runtime, and it acts as a propagation/bubble predicate, it will
// bubble up the event (i.e: execute our original event handler) only if the event targer
// is an ancestor of our element.
// The event is fired inside the angular zone so change detection can kick into action.
const onceOnOutside = () => {
const listener = bubbleNonAncestorHandlerFactory(element, evt => zone.runGuarded(() => handler(evt)));
// mimic BrowserDomAdapter.onAndCancel
document.addEventListener(eventMap[eventName], listener, false);
return () => document.removeEventListener(eventMap[eventName], listener, false);
};
// we run the event registration for the document in a different zone, this will make sure
// change detection is off.
// It turns out that if a component that use DOMOutsideEventPlugin is built from a click
// event, we might get here before the event reached the document, causing a quick false
// positive handling (when stopPropagation() was'nt invoked). To workaround this we wait
// for the next vm turn and register.
// Event registration returns a dispose function for that event, angular use it to clean
// up after component get's destroyed. Since we need to return a dispose function
// synchronously we have to put a wrapper for it since we will get it asynchronously,
// i.e: after we need to return it.
//
return zone.runOutsideAngular(() => {
let fn;
setTimeout(() => fn = onceOnOutside(), 0);
return () => {
if (fn) {
fn();
}
};
});
}
}
DOMOutsideEventPlugin.decorators = [
{ type: Injectable }
];
/** @nocollapse */
DOMOutsideEventPlugin.ctorParameters = () => [];
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0c2lkZS1ldmVudC1wbHVnaW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtbW9kaWFsb2ctMTEvc3JjL2xpYi9wcm92aWRlcnMvb3V0c2lkZS1ldmVudC1wbHVnaW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsdUJBQXVCO0FBQ3ZCLHdHQUF3RztBQUV4RyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRTNDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUUxQyxpQ0FBaUM7QUFDakMsNkJBQTZCO0FBQzdCLE1BQU0sS0FBSyxHQUFZLENBQUMsQ0FBQyxPQUFPLFFBQVEsS0FBSyxXQUFXLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUV2RSxNQUFNLFFBQVEsR0FBRztJQUNiLFlBQVksRUFBRSxPQUFPO0lBQ3JCLGdCQUFnQixFQUFFLFdBQVc7SUFDN0IsY0FBYyxFQUFFLFNBQVM7SUFDekIsZ0JBQWdCLEVBQUUsV0FBVztDQUNoQyxDQUFDO0FBRUY7Ozs7O0dBS0c7QUFDSCxTQUFTLCtCQUErQixDQUFDLE9BQW9CLEVBQUUsT0FBd0I7SUFDbkYsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFO1FBQ2IsSUFBSSxPQUFPLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQztRQUMzQixHQUFHO1lBQ0MsSUFBSSxPQUFPLEtBQUssT0FBTyxFQUFFO2dCQUNyQixPQUFPO2FBQ1Y7U0FDSixRQUFRLE9BQU8sQ0FBQyxVQUFVLElBQUksQ0FBRSxPQUFPLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBRSxFQUFFO1FBRWpFLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNuQixDQUFDLENBQUM7QUFDTixDQUFDO0FBR0QsTUFBTSxPQUFPLHFCQUFxQjtJQUc5QjtRQUNBLElBQUksQ0FBQyxLQUFLLElBQUksT0FBTyxRQUFRLENBQUMsZ0JBQWdCLEtBQUssVUFBVSxFQUFFO1lBQzNELElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFXLENBQUM7U0FDdkM7SUFDRCxDQUFDO0lBRUQsUUFBUSxDQUFDLFNBQWlCO1FBQ3RCLE9BQU8sUUFBUSxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUM5QyxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsT0FBb0IsRUFBRSxTQUFpQixFQUFFLE9BQWlCO1FBQ3ZFLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFcEMsOEVBQThFO1FBQzlFLDRGQUE0RjtRQUM1Rix5RkFBeUY7UUFDekYsaUNBQWlDO1FBQ2pDLHVGQUF1RjtRQUN2RixNQUFNLGFBQWEsR0FBRyxHQUFHLEVBQUU7WUFDdkIsTUFBTSxRQUFRLEdBQ1osK0JBQStCLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRXZGLHNDQUFzQztZQUN0QyxRQUFRLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNoRSxPQUFPLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3BGLENBQUMsQ0FBQztRQUVGLDBGQUEwRjtRQUMxRiwyQkFBMkI7UUFDM0Isd0ZBQXdGO1FBQ3hGLHdGQUF3RjtRQUN4Rix3RkFBd0Y7UUFDeEYscUNBQXFDO1FBQ3JDLHdGQUF3RjtRQUN4RixpRkFBaUY7UUFDakYscUZBQXFGO1FBQ3JGLG1DQUFtQztRQUNuQyxFQUFFO1FBQ0YsT0FBTyxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxFQUFFO1lBQy9CLElBQUksRUFBWSxDQUFDO1lBQ2pCLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEdBQUcsYUFBYSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDMUMsT0FBTyxHQUFHLEVBQUU7Z0JBQ1IsSUFBSSxFQUFFLEVBQUU7b0JBQUUsRUFBRSxFQUFFLENBQUM7aUJBQUU7WUFDckIsQ0FBQyxDQUFDO1FBQ04sQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDOzs7WUFqREosVUFBVSIsInNvdXJjZXNDb250ZW50IjpbIi8vIGhlYXZpbHkgaW5zcGlyZWQgYnk6XHJcbi8vIGh0dHA6Ly93d3cuYmVubmFkZWwuY29tL2Jsb2cvMzAyNS1jcmVhdGluZy1jdXN0b20tZG9tLWFuZC1ob3N0LWV2ZW50LWJpbmRpbmdzLWluLWFuZ3VsYXItMi1iZXRhLTYuaHRtXHJcblxyXG5pbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEV2ZW50TWFuYWdlciB9IGZyb20gJ0Bhbmd1bGFyL3BsYXRmb3JtLWJyb3dzZXInO1xyXG5pbXBvcnQgeyBub29wIH0gZnJvbSAnLi4vZnJhbWV3b3JrL3V0aWxzJztcclxuXHJcbi8vIFRPRE86IHVzZSBESSBmYWN0b3J5IGZvciB0aGlzLlxyXG4vLyBUT0RPOiBjb25zb2xpZGF0ZSBkdXAgY29kZVxyXG5jb25zdCBpc0RvYzogYm9vbGVhbiA9ICEodHlwZW9mIGRvY3VtZW50ID09PSAndW5kZWZpbmVkJyB8fCAhZG9jdW1lbnQpO1xyXG5cclxuY29uc3QgZXZlbnRNYXAgPSB7XHJcbiAgICBjbGlja091dHNpZGU6ICdjbGljaycsXHJcbiAgICBtb3VzZWRvd25PdXRzaWRlOiAnbW91c2Vkb3duJyxcclxuICAgIG1vdXNldXBPdXRzaWRlOiAnbW91c2V1cCcsXHJcbiAgICBtb3VzZW1vdmVPdXRzaWRlOiAnbW91c2Vtb3ZlJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEFuIGV2ZW50IGhhbmRsZXIgZmFjdG9yeSBmb3IgZXZlbnQgaGFuZGxlcnMgdGhhdCBidWJibGUgdGhlIGV2ZW50IHRvIGEgZ2l2ZW4gaGFuZGxlclxyXG4gKiBpZiB0aGUgZXZlbnQgdGFyZ2V0IGlzIG5vdCBhbiBhbmNlc3RvciBvZiB0aGUgZ2l2ZW4gZWxlbWVudC5cclxuICogQHBhcmFtIGVsZW1lbnRcclxuICogQHBhcmFtIGhhbmRsZXJcclxuICovXHJcbmZ1bmN0aW9uIGJ1YmJsZU5vbkFuY2VzdG9ySGFuZGxlckZhY3RvcnkoZWxlbWVudDogSFRNTEVsZW1lbnQsIGhhbmRsZXI6IChldmVudCkgPT4gdm9pZCkge1xyXG4gICAgcmV0dXJuIChldmVudCkgPT4ge1xyXG4gICAgICAgIGxldCBjdXJyZW50ID0gZXZlbnQudGFyZ2V0O1xyXG4gICAgICAgIGRvIHtcclxuICAgICAgICAgICAgaWYgKGN1cnJlbnQgPT09IGVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0gd2hpbGUgKGN1cnJlbnQucGFyZW50Tm9kZSAmJiAoIGN1cnJlbnQgPSBjdXJyZW50LnBhcmVudE5vZGUgKSk7XHJcblxyXG4gICAgICAgIGhhbmRsZXIoZXZlbnQpO1xyXG4gICAgfTtcclxufVxyXG5cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgRE9NT3V0c2lkZUV2ZW50UGx1Z2luIHsgLy8gZXh0ZW5kcyBFdmVudE1hbmFnZXJQbHVnaW5cclxuICAgIG1hbmFnZXI6IEV2ZW50TWFuYWdlcjtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcigpIHtcclxuICAgIGlmICghaXNEb2MgfHwgdHlwZW9mIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIgIT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXIgPSBub29wIGFzIGFueTtcclxuICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBzdXBwb3J0cyhldmVudE5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xyXG4gICAgICAgIHJldHVybiBldmVudE1hcC5oYXNPd25Qcm9wZXJ0eShldmVudE5hbWUpO1xyXG4gICAgfVxyXG5cclxuICAgIGFkZEV2ZW50TGlzdGVuZXIoZWxlbWVudDogSFRNTEVsZW1lbnQsIGV2ZW50TmFtZTogc3RyaW5nLCBoYW5kbGVyOiBGdW5jdGlvbik6IEZ1bmN0aW9uIHtcclxuICAgICAgICBjb25zdCB6b25lID0gdGhpcy5tYW5hZ2VyLmdldFpvbmUoKTtcclxuXHJcbiAgICAgICAgLy8gQSBGYWN0b3J5IHRoYXQgcmVnaXN0ZXJzIHRoZSBldmVudCBvbiB0aGUgZG9jdW1lbnQsIGluc3RlYWQgb2YgdGhlIGVsZW1lbnQuXHJcbiAgICAgICAgLy8gdGhlIGhhbmRsZXIgaXMgY3JlYXRlZCBhdCBydW50aW1lLCBhbmQgaXQgYWN0cyBhcyBhIHByb3BhZ2F0aW9uL2J1YmJsZSBwcmVkaWNhdGUsIGl0IHdpbGxcclxuICAgICAgICAvLyBidWJibGUgdXAgdGhlIGV2ZW50IChpLmU6IGV4ZWN1dGUgb3VyIG9yaWdpbmFsIGV2ZW50IGhhbmRsZXIpIG9ubHkgaWYgdGhlIGV2ZW50IHRhcmdlclxyXG4gICAgICAgIC8vIGlzIGFuIGFuY2VzdG9yIG9mIG91ciBlbGVtZW50LlxyXG4gICAgICAgIC8vIFRoZSBldmVudCBpcyBmaXJlZCBpbnNpZGUgdGhlIGFuZ3VsYXIgem9uZSBzbyBjaGFuZ2UgZGV0ZWN0aW9uIGNhbiBraWNrIGludG8gYWN0aW9uLlxyXG4gICAgICAgIGNvbnN0IG9uY2VPbk91dHNpZGUgPSAoKSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IGxpc3RlbmVyID1cclxuICAgICAgICAgICAgICBidWJibGVOb25BbmNlc3RvckhhbmRsZXJGYWN0b3J5KGVsZW1lbnQsIGV2dCA9PiB6b25lLnJ1bkd1YXJkZWQoKCkgPT4gaGFuZGxlcihldnQpKSk7XHJcblxyXG4gICAgICAgICAgICAvLyBtaW1pYyBCcm93c2VyRG9tQWRhcHRlci5vbkFuZENhbmNlbFxyXG4gICAgICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKGV2ZW50TWFwW2V2ZW50TmFtZV0sIGxpc3RlbmVyLCBmYWxzZSk7XHJcbiAgICAgICAgICAgIHJldHVybiAoKSA9PiBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKGV2ZW50TWFwW2V2ZW50TmFtZV0sIGxpc3RlbmVyLCBmYWxzZSk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgLy8gd2UgcnVuIHRoZSBldmVudCByZWdpc3RyYXRpb24gZm9yIHRoZSBkb2N1bWVudCBpbiBhIGRpZmZlcmVudCB6b25lLCB0aGlzIHdpbGwgbWFrZSBzdXJlXHJcbiAgICAgICAgLy8gY2hhbmdlIGRldGVjdGlvbiBpcyBvZmYuXHJcbiAgICAgICAgLy8gSXQgdHVybnMgb3V0IHRoYXQgaWYgYSBjb21wb25lbnQgdGhhdCB1c2UgRE9NT3V0c2lkZUV2ZW50UGx1Z2luIGlzIGJ1aWx0IGZyb20gYSBjbGlja1xyXG4gICAgICAgIC8vIGV2ZW50LCB3ZSBtaWdodCBnZXQgaGVyZSBiZWZvcmUgdGhlIGV2ZW50IHJlYWNoZWQgdGhlIGRvY3VtZW50LCBjYXVzaW5nIGEgcXVpY2sgZmFsc2VcclxuICAgICAgICAvLyBwb3NpdGl2ZSBoYW5kbGluZyAod2hlbiBzdG9wUHJvcGFnYXRpb24oKSB3YXMnbnQgaW52b2tlZCkuIFRvIHdvcmthcm91bmQgdGhpcyB3ZSB3YWl0XHJcbiAgICAgICAgLy8gZm9yIHRoZSBuZXh0IHZtIHR1cm4gYW5kIHJlZ2lzdGVyLlxyXG4gICAgICAgIC8vIEV2ZW50IHJlZ2lzdHJhdGlvbiByZXR1cm5zIGEgZGlzcG9zZSBmdW5jdGlvbiBmb3IgdGhhdCBldmVudCwgYW5ndWxhciB1c2UgaXQgdG8gY2xlYW5cclxuICAgICAgICAvLyB1cCBhZnRlciBjb21wb25lbnQgZ2V0J3MgZGVzdHJveWVkLiBTaW5jZSB3ZSBuZWVkIHRvIHJldHVybiBhIGRpc3Bvc2UgZnVuY3Rpb25cclxuICAgICAgICAvLyBzeW5jaHJvbm91c2x5IHdlIGhhdmUgdG8gcHV0IGEgd3JhcHBlciBmb3IgaXQgc2luY2Ugd2Ugd2lsbCBnZXQgaXQgYXN5bmNocm9ub3VzbHksXHJcbiAgICAgICAgLy8gaS5lOiBhZnRlciB3ZSBuZWVkIHRvIHJldHVybiBpdC5cclxuICAgICAgICAvL1xyXG4gICAgICAgIHJldHVybiB6b25lLnJ1bk91dHNpZGVBbmd1bGFyKCgpID0+IHtcclxuICAgICAgICAgICAgbGV0IGZuOiBGdW5jdGlvbjtcclxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiBmbiA9IG9uY2VPbk91dHNpZGUoKSwgMCk7XHJcbiAgICAgICAgICAgIHJldHVybiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBpZiAoZm4pIHsgZm4oKTsgfVxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxufVxyXG4iXX0=