@looorent/ngx-simple-modal
Version:
A simple unopinionated framework to implement simple modal based behaviour in angular (v2+) projects.
222 lines • 27 kB
JavaScript
import { Component, Inject, ViewContainerRef, ViewChild } from '@angular/core';
import { of } from 'rxjs';
import { DefaultSimpleModalOptionConfig } from './simple-modal-options';
import { SimpleModalWrapperComponent } from './simple-modal-wrapper.component';
import { DraggableDirective } from './simple-modal-draggable.directive';
import * as i0 from "@angular/core";
/**
* View container manager which manages a list of modals currently active
* inside the viewvontainer
*/
class SimpleModalHolderComponent {
resolver;
renderer;
ngZone;
defaultSimpleModalOptions;
/**
* Target viewContainer to insert modals
*/
viewContainer;
/**
* modal collection, maintained by addModal and removeModal
* @type {Array<SimpleModalComponent> }
*/
modals = [];
/**
* if auto focus is on and no element focused, store it here to be restored back after close
*/
previousActiveElement = null;
/**
* Constructor
* @param {ComponentFactoryResolver} resolver
* @param renderer
* @param ngZone
* @param defaultSimpleModalOptions
*/
constructor(resolver, renderer, ngZone, defaultSimpleModalOptions) {
this.resolver = resolver;
this.renderer = renderer;
this.ngZone = ngZone;
this.defaultSimpleModalOptions = defaultSimpleModalOptions;
}
/**
* Configures then adds modal to the modals array, and populates with data passed in
* @param {Type<SimpleModalComponent>} component
* @param {object?} data
* @param {SimpleModalOptionsOverrides?} options
* @return {Observable<*>}
*/
addModal(component, data, options) {
// create component
if (!this.viewContainer) {
return of(null);
}
const factory = this.resolver.resolveComponentFactory(SimpleModalWrapperComponent);
const componentRef = this.viewContainer.createComponent(factory);
const modalWrapper = (componentRef.instance);
const { ref: _componentRef, component: _component } = modalWrapper.addComponent(component);
// assign options refs
_component.options = options = Object.assign({}, this.defaultSimpleModalOptions, options);
// set base classes for wrapper
modalWrapper.modalClasses = options.wrapperDefaultClasses;
// add to stack
this.modals.push(_component);
// wait a tick then setup the following while adding a modal
this.wait().then(() => {
this.toggleWrapperClass(modalWrapper.wrapper, options.wrapperClass);
this.toggleBodyClass(options.bodyClass);
if (options.draggable) {
this.setDraggable(_componentRef, options);
}
this.wait(options.animationDuration).then(() => {
this.autoFocusFirstElement(_component.wrapper, options.autoFocus);
_component.markAsReady();
});
});
// when closing modal remove it
_component.onClosing(modal => this.removeModal(modal));
// if clicking on background closes modal
this.configureCloseOnClickOutside(modalWrapper);
// map and return observable
_component.mapDataObject(data);
return _component.setupObserver();
}
/**
* triggers components close function
* to take effect
* @returns {Promise<void>}
* @param closingModal
*/
removeModal(closingModal) {
const options = closingModal.options;
this.toggleWrapperClass(closingModal.wrapper, options.wrapperClass);
return this.wait(options.animationDuration).then(() => {
this.removeModalFromArray(closingModal);
this.toggleBodyClass(options.bodyClass);
this.restorePreviousFocus();
});
}
/**
* Instructs all open modals to
*/
removeAllModals() {
return Promise.all(this.modals.map(modal => this.removeModal(modal)));
}
/**
* Bind a body class 'modal-open' to a condition of modals in pool > 0
* @param bodyClass - string to add and remove from body in document
*/
toggleBodyClass(bodyClass) {
if (!bodyClass) {
return;
}
const body = document.getElementsByTagName('body')[0];
const bodyClassItems = bodyClass.split(' ');
if (!this.modals.length) {
body.classList.remove(...bodyClassItems);
}
else {
body.classList.add(...bodyClassItems);
}
}
/**
* if the option to close on background click is set, then hook up a callback
* @param modalWrapper
*/
configureCloseOnClickOutside(modalWrapper) {
modalWrapper.onClickOutsideModalContent(() => {
if (modalWrapper.content.options.closeOnClickOutside) {
modalWrapper.content.close();
}
});
}
/**
* Auto focus o the first element if autofocus is on
* @param componentWrapper
* @param autoFocus
*/
autoFocusFirstElement(componentWrapper, autoFocus) {
if (autoFocus) {
const focusable = componentWrapper.nativeElement.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
if (focusable && focusable.length) {
this.previousActiveElement = document.activeElement;
focusable[0].focus();
}
}
}
/**
* Restores the last focus is there was one
*/
restorePreviousFocus() {
if (this.previousActiveElement) {
this.previousActiveElement.focus();
this.previousActiveElement = null;
}
}
/**
* Configure the adding and removal of a wrapper class - predominantly animation focused
* @param modalWrapperEl
* @param wrapperClass
*/
toggleWrapperClass(modalWrapperEl, wrapperClass) {
const wrapperClassList = modalWrapperEl.nativeElement.classList;
const wrapperClassItems = wrapperClass.split(' ');
if (wrapperClassList.toString().indexOf(wrapperClass) !== -1) {
wrapperClassList.remove(...wrapperClassItems);
}
else {
wrapperClassList.add(...wrapperClassItems);
}
}
/**
* Enables the drag option on the modal if the options have it enabled
* @param component
* @param options
* @private
*/
setDraggable(component, options) {
const draggableDirective = new DraggableDirective(component.location, this.ngZone, this.renderer);
draggableDirective.dragTarget = component.location.nativeElement;
draggableDirective.dragHandle = component.instance.handle ? component.instance.handle.nativeElement : undefined;
draggableDirective.ngAfterViewInit();
component.location.nativeElement.classList.add(options.draggableClass);
}
/**
* Helper function for a more readable timeout
* @param ms
*/
wait(ms = 0) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(undefined), ms);
});
}
/**
* Instructs the holder to remove the modal and
* removes this component from the collection
* @param {SimpleModalComponent} component
*/
removeModalFromArray(component) {
const index = this.modals.indexOf(component);
if (index > -1) {
this.viewContainer.remove(index);
this.modals.splice(index, 1);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: SimpleModalHolderComponent, deps: [{ token: i0.ComponentFactoryResolver }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: DefaultSimpleModalOptionConfig }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.3", type: SimpleModalHolderComponent, selector: "simple-modal-holder", viewQueries: [{ propertyName: "viewContainer", first: true, predicate: ["viewContainer"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: '<ng-template #viewContainer></ng-template>', isInline: true });
}
export { SimpleModalHolderComponent };
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.3", ngImport: i0, type: SimpleModalHolderComponent, decorators: [{
type: Component,
args: [{
selector: 'simple-modal-holder',
template: '<ng-template #viewContainer></ng-template>',
}]
}], ctorParameters: function () { return [{ type: i0.ComponentFactoryResolver }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: undefined, decorators: [{
type: Inject,
args: [DefaultSimpleModalOptionConfig]
}] }]; }, propDecorators: { viewContainer: [{
type: ViewChild,
args: ['viewContainer', { read: ViewContainerRef, static: true }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2ltcGxlLW1vZGFsLWhvbGRlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2ltcGxlLW1vZGFsL3NpbXBsZS1tb2RhbC1ob2xkZXIuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQXdDLE1BQU0sRUFBUSxnQkFBZ0IsRUFBRSxTQUFTLEVBQW1DLE1BQU0sZUFBZSxDQUFDO0FBQzVKLE9BQU8sRUFBYyxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdEMsT0FBTyxFQUFFLDhCQUE4QixFQUFtRCxNQUFNLHdCQUF3QixDQUFDO0FBQ3pILE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBRS9FLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDOztBQUV4RTs7O0dBR0c7QUFDSCxNQUlhLDBCQUEwQjtJQXlCM0I7SUFDQTtJQUNBO0lBQ3dDO0lBM0JsRDs7T0FFRztJQUNtRSxhQUFhLENBQUM7SUFFcEY7OztPQUdHO0lBQ0gsTUFBTSxHQUEwQyxFQUFFLENBQUM7SUFFbkQ7O09BRUc7SUFDSCxxQkFBcUIsR0FBRyxJQUFJLENBQUM7SUFFN0I7Ozs7OztPQU1HO0lBQ0gsWUFDVSxRQUFrQyxFQUNsQyxRQUFtQixFQUNuQixNQUFjLEVBQzBCLHlCQUE2QztRQUhyRixhQUFRLEdBQVIsUUFBUSxDQUEwQjtRQUNsQyxhQUFRLEdBQVIsUUFBUSxDQUFXO1FBQ25CLFdBQU0sR0FBTixNQUFNLENBQVE7UUFDMEIsOEJBQXlCLEdBQXpCLHlCQUF5QixDQUFvQjtJQUUvRixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsUUFBUSxDQUNOLFNBQTRDLEVBQzVDLElBQVEsRUFDUixPQUFxQztRQUVyQyxtQkFBbUI7UUFDbkIsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUU7WUFDdkIsT0FBTyxFQUFFLENBQUMsSUFB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UmVzb2x2ZXIsIEVsZW1lbnRSZWYsIEluamVjdCwgVHlwZSwgVmlld0NvbnRhaW5lclJlZiwgVmlld0NoaWxkLCBSZW5kZXJlcjIsIENvbXBvbmVudFJlZiwgTmdab25lIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgRGVmYXVsdFNpbXBsZU1vZGFsT3B0aW9uQ29uZmlnLCBTaW1wbGVNb2RhbE9wdGlvbnMsIFNpbXBsZU1vZGFsT3B0aW9uc092ZXJyaWRlcyB9IGZyb20gJy4vc2ltcGxlLW1vZGFsLW9wdGlvbnMnO1xuaW1wb3J0IHsgU2ltcGxlTW9kYWxXcmFwcGVyQ29tcG9uZW50IH0gZnJvbSAnLi9zaW1wbGUtbW9kYWwtd3JhcHBlci5jb21wb25lbnQnO1xuaW1wb3J0IHsgU2ltcGxlTW9kYWxDb21wb25lbnQgfSBmcm9tICcuL3NpbXBsZS1tb2RhbC5jb21wb25lbnQnO1xuaW1wb3J0IHsgRHJhZ2dhYmxlRGlyZWN0aXZlIH0gZnJvbSAnLi9zaW1wbGUtbW9kYWwtZHJhZ2dhYmxlLmRpcmVjdGl2ZSc7XG5cbi8qKlxuICogVmlldyBjb250YWluZXIgbWFuYWdlciB3aGljaCBtYW5hZ2VzIGEgbGlzdCBvZiBtb2RhbHMgY3VycmVudGx5IGFjdGl2ZVxuICogaW5zaWRlIHRoZSB2aWV3dm9udGFpbmVyXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3NpbXBsZS1tb2RhbC1ob2xkZXInLFxuICB0ZW1wbGF0ZTogJzxuZy10ZW1wbGF0ZSAjdmlld0NvbnRhaW5lcj48L25nLXRlbXBsYXRlPicsXG59KVxuZXhwb3J0IGNsYXNzIFNpbXBsZU1vZGFsSG9sZGVyQ29tcG9uZW50IHtcbiAgLyoqXG4gICAqIFRhcmdldCB2aWV3Q29udGFpbmVyIHRvIGluc2VydCBtb2RhbHNcbiAgICovXG4gIEBWaWV3Q2hpbGQoJ3ZpZXdDb250YWluZXInLCB7IHJlYWQ6IFZpZXdDb250YWluZXJSZWYsIHN0YXRpYzogdHJ1ZSB9KSB2aWV3Q29udGFpbmVyO1xuXG4gIC8qKlxuICAgKiBtb2RhbCBjb2xsZWN0aW9uLCBtYWludGFpbmVkIGJ5IGFkZE1vZGFsIGFuZCByZW1vdmVNb2RhbFxuICAgKiBAdHlwZSB7QXJyYXk8U2ltcGxlTW9kYWxDb21wb25lbnQ+IH1cbiAgICovXG4gIG1vZGFsczogQXJyYXk8U2ltcGxlTW9kYWxDb21wb25lbnQ8YW55LCBhbnk+PiA9IFtdO1xuXG4gIC8qKlxuICAgKiBpZiBhdXRvIGZvY3VzIGlzIG9uIGFuZCBubyBlbGVtZW50IGZvY3VzZWQsIHN0b3JlIGl0IGhlcmUgdG8gYmUgcmVzdG9yZWQgYmFjayBhZnRlciBjbG9zZVxuICAgKi9cbiAgcHJldmlvdXNBY3RpdmVFbGVtZW50ID0gbnVsbDtcblxuICAvKipcbiAgICogQ29uc3RydWN0b3JcbiAgICogQHBhcmFtIHtDb21wb25lbnRGYWN0b3J5UmVzb2x2ZXJ9IHJlc29sdmVyXG4gICAqIEBwYXJhbSByZW5kZXJlclxuICAgKiBAcGFyYW0gbmdab25lXG4gICAqIEBwYXJhbSBkZWZhdWx0U2ltcGxlTW9kYWxPcHRpb25zXG4gICAqL1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlc29sdmVyOiBDb21wb25lbnRGYWN0b3J5UmVzb2x2ZXIsXG4gICAgcHJpdmF0ZSByZW5kZXJlcjogUmVuZGVyZXIyLFxuICAgIHByaXZhdGUgbmdab25lOiBOZ1pvbmUsXG4gICAgQEluamVjdChEZWZhdWx0U2ltcGxlTW9kYWxPcHRpb25Db25maWcpIHByaXZhdGUgZGVmYXVsdFNpbXBsZU1vZGFsT3B0aW9uczogU2ltcGxlTW9kYWxPcHRpb25zLFxuICApIHtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb25maWd1cmVzIHRoZW4gYWRkcyBtb2RhbCB0byB0aGUgbW9kYWxzIGFycmF5LCBhbmQgcG9wdWxhdGVzIHdpdGggZGF0YSBwYXNzZWQgaW5cbiAgICogQHBhcmFtIHtUeXBlPFNpbXBsZU1vZGFsQ29tcG9uZW50Pn0gY29tcG9uZW50XG4gICAqIEBwYXJhbSB7b2JqZWN0P30gZGF0YVxuICAgKiBAcGFyYW0ge1NpbXBsZU1vZGFsT3B0aW9uc092ZXJyaWRlcz99IG9wdGlvbnNcbiAgICogQHJldHVybiB7T2JzZXJ2YWJsZTwqPn1cbiAgICovXG4gIGFkZE1vZGFsPFQsIFQxPihcbiAgICBjb21wb25lbnQ6IFR5cGU8U2ltcGxlTW9kYWxDb21wb25lbnQ8VCwgVDE+PixcbiAgICBkYXRhPzogVCxcbiAgICBvcHRpb25zPzogU2ltcGxlTW9kYWxPcHRpb25zT3ZlcnJpZGVzLFxuICApOiBPYnNlcnZhYmxlPFQxPiB7XG4gICAgLy8gY3JlYXRlIGNvbXBvbmVudFxuICAgIGlmICghdGhpcy52aWV3Q29udGFpbmVyKSB7XG4gICAgICByZXR1cm4gb2YobnVsbCk7XG4gICAgfVxuICAgIGNvbnN0IGZhY3RvcnkgPSB0aGlzLnJlc29sdmVyLnJlc29sdmVDb21wb25lbnRGYWN0b3J5KFNpbXBsZU1vZGFsV3JhcHBlckNvbXBvbmVudCk7XG4gICAgY29uc3QgY29tcG9uZW50UmVmID0gdGhpcy52aWV3Q29udGFpbmVyLmNyZWF0ZUNvbXBvbmVudChmYWN0b3J5KTtcbiAgICBjb25zdCBtb2RhbFdyYXBwZXI6IFNpbXBsZU1vZGFsV3JhcHBlckNvbXBvbmVudCA9IDxTaW1wbGVNb2RhbFdyYXBwZXJDb21wb25lbnQ+KFxuICAgICAgY29tcG9uZW50UmVmLmluc3RhbmNlXG4gICAgKTtcbiAgICBjb25zdCB7IHJlZjogX2NvbXBvbmVudFJlZiwgY29tcG9uZW50OiBfY29tcG9uZW50IH0gPSBtb2RhbFdyYXBwZXIuYWRkQ29tcG9uZW50KGNvbXBvbmVudCk7XG5cbiAgICAvLyBhc3NpZ24gb3B0aW9ucyByZWZzXG4gICAgX2NvbXBvbmVudC5vcHRpb25zID0gb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMuZGVmYXVsdFNpbXBsZU1vZGFsT3B0aW9ucywgb3B0aW9ucykgYXMgU2ltcGxlTW9kYWxPcHRpb25zO1xuXG4gICAgLy8gc2V0IGJhc2UgY2xhc3NlcyBmb3Igd3JhcHBlclxuICAgIG1vZGFsV3JhcHBlci5tb2RhbENsYXNzZXMgPSBvcHRpb25zLndyYXBwZXJEZWZhdWx0Q2xhc3NlcztcblxuICAgIC8vIGFkZCB0byBzdGFja1xuICAgIHRoaXMubW9kYWxzLnB1c2goX2NvbXBvbmVudCk7XG5cbiAgICAvLyB3YWl0IGEgdGljayB0aGVuIHNldHVwIHRoZSBmb2xsb3dpbmcgd2hpbGUgYWRkaW5nIGEgbW9kYWxcbiAgICB0aGlzLndhaXQoKS50aGVuKCgpID0+IHtcbiAgICAgIHRoaXMudG9nZ2xlV3JhcHBlckNsYXNzKG1vZGFsV3JhcHBlci53cmFwcGVyLCBvcHRpb25zLndyYXBwZXJDbGFzcyk7XG4gICAgICB0aGlzLnRvZ2dsZUJvZHlDbGFzcyhvcHRpb25zLmJvZHlDbGFzcyk7XG4gICAgICBpZiAob3B0aW9ucy5kcmFnZ2FibGUpIHtcbiAgICAgICAgdGhpcy5zZXREcmFnZ2FibGUoX2NvbXBvbmVudFJlZiwgb3B0aW9ucyk7XG4gICAgICB9XG4gICAgICB0aGlzLndhaXQob3B0aW9ucy5hbmltYXRpb25EdXJhdGlvbikudGhlbigoKSA9PiB7XG4gICAgICAgIHRoaXMuYXV0b0ZvY3VzRmlyc3RFbGVtZW50KF9jb21wb25lbnQud3JhcHBlciwgb3B0aW9ucy5hdXRvRm9jdXMpO1xuICAgICAgICBfY29tcG9uZW50Lm1hcmtBc1JlYWR5KCk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIHdoZW4gY2xvc2luZyBtb2RhbCByZW1vdmUgaXRcbiAgICBfY29tcG9uZW50Lm9uQ2xvc2luZyhtb2RhbCA9PiB0aGlzLnJlbW92ZU1vZGFsKG1vZGFsKSk7XG5cbiAgICAvLyBpZiBjbGlja2luZyBvbiBiYWNrZ3JvdW5kIGNsb3NlcyBtb2RhbFxuICAgIHRoaXMuY29uZmlndXJlQ2xvc2VPbkNsaWNrT3V0c2lkZShtb2RhbFdyYXBwZXIpO1xuXG4gICAgLy8gbWFwIGFuZCByZXR1cm4gb2JzZXJ2YWJsZVxuICAgIF9jb21wb25lbnQubWFwRGF0YU9iamVjdChkYXRhKTtcblxuICAgIHJldHVybiBfY29tcG9uZW50LnNldHVwT2JzZXJ2ZXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiB0cmlnZ2VycyBjb21wb25lbnRzIGNsb3NlIGZ1bmN0aW9uXG4gICAqIHRvIHRha2UgZWZmZWN0XG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKiBAcGFyYW0gY2xvc2luZ01vZGFsXG4gICAqL1xuICByZW1vdmVNb2RhbChjbG9zaW5nTW9kYWw6IFNpbXBsZU1vZGFsQ29tcG9uZW50PGFueSwgYW55Pik6IFByb21pc2U8YW55PiB7XG4gICAgY29uc3Qgb3B0aW9ucyA9IGNsb3NpbmdNb2RhbC5vcHRpb25zO1xuICAgIHRoaXMudG9nZ2xlV3JhcHBlckNsYXNzKGNsb3NpbmdNb2RhbC53cmFwcGVyLCBvcHRpb25zLndyYXBwZXJDbGFzcyk7XG4gICAgcmV0dXJuIHRoaXMud2FpdChvcHRpb25zLmFuaW1hdGlvbkR1cmF0aW9uKS50aGVuKCgpID0+IHtcbiAgICAgIHRoaXMucmVtb3ZlTW9kYWxGcm9tQXJyYXkoY2xvc2luZ01vZGFsKTtcbiAgICAgIHRoaXMudG9nZ2xlQm9keUNsYXNzKG9wdGlvbnMuYm9keUNsYXNzKTtcbiAgICAgIHRoaXMucmVzdG9yZVByZXZpb3VzRm9jdXMoKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnN0cnVjdHMgYWxsIG9wZW4gbW9kYWxzIHRvXG4gICAqL1xuICByZW1vdmVBbGxNb2RhbHMoKTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gUHJvbWlzZS5hbGwodGhpcy5tb2RhbHMubWFwKG1vZGFsID0+IHRoaXMucmVtb3ZlTW9kYWwobW9kYWwpKSk7XG4gIH1cblxuICAvKipcbiAgICogQmluZCBhIGJvZHkgY2xhc3MgJ21vZGFsLW9wZW4nIHRvIGEgY29uZGl0aW9uIG9mIG1vZGFscyBpbiBwb29sID4gMFxuICAgKiBAcGFyYW0gYm9keUNsYXNzIC0gc3RyaW5nIHRvIGFkZCBhbmQgcmVtb3ZlIGZyb20gYm9keSBpbiBkb2N1bWVudFxuICAgKi9cbiAgcHJpdmF0ZSB0b2dnbGVCb2R5Q2xhc3MoYm9keUNsYXNzOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAoIWJvZHlDbGFzcykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBib2R5ID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2JvZHknKVswXTtcbiAgICBjb25zdCBib2R5Q2xhc3NJdGVtcyA9IGJvZHlDbGFzcy5zcGxpdCgnICcpO1xuICAgIGlmICghdGhpcy5tb2RhbHMubGVuZ3RoKSB7XG4gICAgICBib2R5LmNsYXNzTGlzdC5yZW1vdmUoLi4uYm9keUNsYXNzSXRlbXMpO1xuICAgIH0gZWxzZSB7XG4gICAgICBib2R5LmNsYXNzTGlzdC5hZGQoLi4uYm9keUNsYXNzSXRlbXMpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBpZiB0aGUgb3B0aW9uIHRvIGNsb3NlIG9uIGJhY2tncm91bmQgY2xpY2sgaXMgc2V0LCB0aGVuIGhvb2sgdXAgYSBjYWxsYmFja1xuICAgKiBAcGFyYW0gbW9kYWxXcmFwcGVyXG4gICAqL1xuICBwcml2YXRlIGNvbmZpZ3VyZUNsb3NlT25DbGlja091dHNpZGUobW9kYWxXcmFwcGVyOiBTaW1wbGVNb2RhbFdyYXBwZXJDb21wb25lbnQpIHtcbiAgICBtb2RhbFdyYXBwZXIub25DbGlja091dHNpZGVNb2RhbENvbnRlbnQoKCkgPT4ge1xuICAgICAgaWYgKG1vZGFsV3JhcHBlci5jb250ZW50Lm9wdGlvbnMuY2xvc2VPbkNsaWNrT3V0c2lkZSkge1xuICAgICAgICBtb2RhbFdyYXBwZXIuY29udGVudC5jbG9zZSgpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEF1dG8gZm9jdXMgbyB0aGUgZmlyc3QgZWxlbWVudCBpZiBhdXRvZm9jdXMgaXMgb25cbiAgICogQHBhcmFtIGNvbXBvbmVudFdyYXBwZXJcbiAgICogQHBhcmFtIGF1dG9Gb2N1c1xuICAgKi9cbiAgcHJpdmF0ZSBhdXRvRm9jdXNGaXJzdEVsZW1lbnQoY29tcG9uZW50V3JhcHBlcjogRWxlbWVudFJlZiwgYXV0b0ZvY3VzOiBib29sZWFuKSB7XG4gICAgaWYgKGF1dG9Gb2N1cykge1xuICAgICAgY29uc3QgZm9jdXNhYmxlID0gY29tcG9uZW50V3JhcHBlci5uYXRpdmVFbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXG4gICAgICAgICdidXR0b24sIFtocmVmXSwgaW5wdXQsIHNlbGVjdCwgdGV4dGFyZWEsIFt0YWJpbmRleF06bm90KFt0YWJpbmRleD1cIi0xXCJdKScsXG4gICAgICApO1xuICAgICAgaWYgKGZvY3VzYWJsZSAmJiBmb2N1c2FibGUubGVuZ3RoKSB7XG4gICAgICAgIHRoaXMucHJldmlvdXNBY3RpdmVFbGVtZW50ID0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudDtcbiAgICAgICAgZm9jdXNhYmxlWzBdLmZvY3VzKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlc3RvcmVzIHRoZSBsYXN0IGZvY3VzIGlzIHRoZXJlIHdhcyBvbmVcbiAgICovXG4gIHByaXZhdGUgcmVzdG9yZVByZXZpb3VzRm9jdXMoKSB7XG4gICAgaWYgKHRoaXMucHJldmlvdXNBY3RpdmVFbGVtZW50KSB7XG4gICAgICB0aGlzLnByZXZpb3VzQWN0aXZlRWxlbWVudC5mb2N1cygpO1xuICAgICAgdGhpcy5wcmV2aW91c0FjdGl2ZUVsZW1lbnQgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDb25maWd1cmUgdGhlIGFkZGluZyBhbmQgcmVtb3ZhbCBvZiBhIHdyYXBwZXIgY2xhc3MgLSBwcmVkb21pbmFudGx5IGFuaW1hdGlvbiBmb2N1c2VkXG4gICAqIEBwYXJhbSBtb2RhbFdyYXBwZXJFbFxuICAgKiBAcGFyYW0gd3JhcHBlckNsYXNzXG4gICAqL1xuICBwcml2YXRlIHRvZ2dsZVdyYXBwZXJDbGFzcyhtb2RhbFdyYXBwZXJFbDogRWxlbWVudFJlZiwgd3JhcHBlckNsYXNzOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCB3cmFwcGVyQ2xhc3NMaXN0ID0gbW9kYWxXcmFwcGVyRWwubmF0aXZlRWxlbWVudC5jbGFzc0xpc3Q7XG4gICAgY29uc3Qgd3JhcHBlckNsYXNzSXRlbXMgPSB3cmFwcGVyQ2xhc3Muc3BsaXQoJyAnKTtcbiAgICBpZiAod3JhcHBlckNsYXNzTGlzdC50b1N0cmluZygpLmluZGV4T2Yod3JhcHBlckNsYXNzKSAhPT0gLTEpIHtcbiAgICAgIHdyYXBwZXJDbGFzc0xpc3QucmVtb3ZlKC4uLndyYXBwZXJDbGFzc0l0ZW1zKTtcbiAgICB9IGVsc2Uge1xuICAgICAgd3JhcHBlckNsYXNzTGlzdC5hZGQoLi4ud3JhcHBlckNsYXNzSXRlbXMpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBFbmFibGVzIHRoZSBkcmFnIG9wdGlvbiBvbiB0aGUgbW9kYWwgaWYgdGhlIG9wdGlvbnMgaGF2ZSBpdCBlbmFibGVkXG4gICAqIEBwYXJhbSBjb21wb25lbnRcbiAgICogQHBhcmFtIG9wdGlvbnNcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgc2V0RHJhZ2dhYmxlKGNvbXBvbmVudDogQ29tcG9uZW50UmVmPFNpbXBsZU1vZGFsQ29tcG9uZW50PGFueSwgYW55Pj4sIG9wdGlvbnM6IFNpbXBsZU1vZGFsT3B0aW9uc092ZXJyaWRlcyk6IHZvaWQge1xuICAgIGNvbnN0IGRyYWdnYWJsZURpcmVjdGl2ZSA9IG5ldyBEcmFnZ2FibGVEaXJlY3RpdmUoY29tcG9uZW50LmxvY2F0aW9uLCB0aGlzLm5nWm9uZSwgdGhpcy5yZW5kZXJlcik7XG4gICAgZHJhZ2dhYmxlRGlyZWN0aXZlLmRyYWdUYXJnZXQgPSBjb21wb25lbnQubG9jYXRpb24ubmF0aXZlRWxlbWVudDtcbiAgICBkcmFnZ2FibGVEaXJlY3RpdmUuZHJhZ0hhbmRsZSA9IGNvbXBvbmVudC5pbnN0YW5jZS5oYW5kbGUgPyBjb21wb25lbnQuaW5zdGFuY2UuaGFuZGxlLm5hdGl2ZUVsZW1lbnQgOiB1bmRlZmluZWQ7XG4gICAgZHJhZ2dhYmxlRGlyZWN0aXZlLm5nQWZ0ZXJWaWV3SW5pdCgpO1xuICAgIGNvbXBvbmVudC5sb2NhdGlvbi5uYXRpdmVFbGVtZW50LmNsYXNzTGlzdC5hZGQob3B0aW9ucy5kcmFnZ2FibGVDbGFzcyk7XG4gIH1cblxuICAvKipcbiAgICogSGVscGVyIGZ1bmN0aW9uIGZvciBhIG1vcmUgcmVhZGFibGUgdGltZW91dFxuICAgKiBAcGFyYW0gbXNcbiAgICovXG4gIHByaXZhdGUgd2FpdChtczogbnVtYmVyID0gMCk6IFByb21pc2U8dW5rbm93bj4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZTx1bmtub3duPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHJlc29sdmUodW5kZWZpbmVkKSwgbXMpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEluc3RydWN0cyB0aGUgaG9sZGVyIHRvIHJlbW92ZSB0aGUgbW9kYWwgYW5kXG4gICAqIHJlbW92ZXMgdGhpcyBjb21wb25lbnQgZnJvbSB0aGUgY29sbGVjdGlvblxuICAgKiBAcGFyYW0ge1NpbXBsZU1vZGFsQ29tcG9uZW50fSBjb21wb25lbnRcbiAgICovXG4gIHByaXZhdGUgcmVtb3ZlTW9kYWxGcm9tQXJyYXkoY29tcG9uZW50KTogdm9pZCB7XG4gICAgY29uc3QgaW5kZXggPSB0aGlzLm1vZGFscy5pbmRleE9mKGNvbXBvbmVudCk7XG4gICAgaWYgKGluZGV4ID4gLTEpIHtcbiAgICAgIHRoaXMudmlld0NvbnRhaW5lci5yZW1vdmUoaW5kZXgpO1xuICAgICAgdGhpcy5tb2RhbHMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==