UNPKG

carbon-components-angular

Version:
281 lines 27.9 kB
import { Component, EventEmitter, HostListener, Input, Output, ViewChild, Inject } from "@angular/core"; import { DOCUMENT } from "@angular/common"; import { cycleTabs, getFocusElementList } from "carbon-components-angular/common"; import * as i0 from "@angular/core"; import * as i1 from "./base-modal.service"; import * as i2 from "@angular/common"; import * as i3 from "./overlay.component"; /** * Component to create modals for presenting content. * * [See demo](../../?path=/story/components-modal--basic) * * Using a modal in your application requires `cds-placeholder` which would generally be * placed near the end of your app component template (app.component.ts or app.component.html) as: * ```html <cds-placeholder></cds-placeholder> ``` * * A more complete example for `Modal` is given as follows: * * Example modal definition: * ```typescript @Component({ selector: "app-sample-modal", template: ` <cds-modal size="xl" (overlaySelected)="closeModal()"> <cds-modal-header (closeSelect)="closeModal()">Header text</cds-modal-header> <section class="modal-body"> <h1>Sample modal works.</h1> <button class="btn--icon-link" nPopover="Hello there" title="Popover title" placement="right" appendInline="true"> <svg cdsIcon="info" size="sm"></svg> </button> {{modalText}} </section> <cds-modal-footer><button cdsButton="primary" (click)="closeModal()">Close</button></cds-modal-footer> </cds-modal>`, styleUrls: ["./sample-modal.component.scss"] }) export class SampleModal extends BaseModal { modalText: string; constructor(protected injector: Injector) { super(); this.modalText = this.injector.get("modalText"); } } ``` * * Example of opening the modal: * ```typescript @Component({ selector: "app-modal-demo", template: ` <button cdsButton="primary" (click)="openModal('drill')">Drill-down modal</button> <cds-placeholder></cds-placeholder>` }) export class ModalDemo { openModal() { this.modalService.create({component: SampleModal, inputs: {modalText: "Hello universe."}}); } } ``` */ export class Modal { /** * Creates an instance of `Modal`. */ constructor(modalService, document, renderer) { this.modalService = modalService; this.document = document; this.renderer = renderer; /** * Size of the modal to display. */ this.size = "md"; /** * Classification of the modal. */ this.theme = "default"; /** * Label for the modal. */ this.ariaLabel = "default"; /** * Controls the visibility of the modal when used directly in a template */ this.open = false; /** * Specify whether the modal contains scrolling content. This property overrides the automatic * detection of the existence of scrolling content. Set this property to `true` to force * overflow indicator to show up or to `false` to force overflow indicator to disappear. * It is set to `null` by default which indicates not to override automatic detection. */ this.hasScrollingContent = null; /** * Emits event when click occurs within `n-overlay` element. This is to track click events occurring outside bounds of the `Modal` object. */ this.overlaySelected = new EventEmitter(); /** * To emit the closing event of the modal window. */ this.close = new EventEmitter(); /** * An element should have 'modal-primary-focus' as an attribute to receive initial focus within the `Modal` component. */ this.selectorPrimaryFocus = "[modal-primary-focus]"; } ngOnChanges({ open, hasScrollingContent }) { if (open) { if (open.currentValue) { // `100` is just enough time to allow the modal // to become visible, so that we can set focus setTimeout(() => this.focusInitialElement(), 100); // Prevent scrolling on open this.renderer.addClass(this.document.body, "cds--body--with-modal-open"); } else if (!open.currentValue) { // Enable scrolling on close this.renderer.removeClass(this.document.body, "cds--body--with-modal-open"); } else if (this.trigger) { this.trigger.focus(); } } if (hasScrollingContent) { this.updateScrollbar(); } } /** * Set document focus to be on the modal component after it is initialized. */ ngAfterViewInit() { this.focusInitialElement(); this.updateScrollbar(); } /** * Handle keyboard events to close modal and tab through the content within the modal. */ handleKeyboardEvent(event) { switch (event.key) { case "Escape": { event.stopImmediatePropagation(); // prevents events being fired for multiple modals if more than 2 open // Manually close modal this.open = false; this.close.emit(); this.modalService.destroy(); // destroy top (latest) modal break; } case "Tab": { cycleTabs(event, this.modal.nativeElement); break; } } } /** * This detects whether or not the modal contains scrolling content. * * To force trigger a detection (ie. on window resize), change or reset the value of the modal content. * * Use the `hasScrollingContent` input to manually override the overflow indicator. */ get shouldShowScrollbar() { const modalContent = this.modal ? this.modal.nativeElement.querySelector(".cds--modal-content") : null; if (modalContent) { // get rounded value from height to match integer returned from scrollHeight const modalContentHeight = Math.ceil(modalContent.getBoundingClientRect().height); const modalContentScrollHeight = modalContent.scrollHeight; return modalContentScrollHeight > modalContentHeight; } else { return false; } } // Remove class preventing scrolling ngOnDestroy() { this.renderer.removeClass(this.document.body, "cds--body--with-modal-open"); } focusInitialElement() { const primaryFocusElement = this.modal.nativeElement.querySelector(this.selectorPrimaryFocus); if (primaryFocusElement && primaryFocusElement.focus) { setTimeout(() => primaryFocusElement.focus()); } else if (getFocusElementList(this.modal.nativeElement).length > 0) { setTimeout(() => getFocusElementList(this.modal.nativeElement)[0].focus()); } else { setTimeout(() => this.modal.nativeElement.focus()); } } updateScrollbar() { const modalContent = this.modal ? this.modal.nativeElement.querySelector(".cds--modal-content") : null; const showScrollbar = this.hasScrollingContent !== null ? this.hasScrollingContent : this.shouldShowScrollbar; if (modalContent) { if (showScrollbar) { this.renderer.addClass(modalContent, "cds--modal-scroll-content"); } else { this.renderer.removeClass(modalContent, "cds--modal-scroll-content"); } } } } Modal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Modal, deps: [{ token: i1.BaseModalService }, { token: DOCUMENT }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component }); Modal.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: Modal, selector: "cds-modal, ibm-modal", inputs: { size: "size", theme: "theme", ariaLabel: "ariaLabel", open: "open", trigger: "trigger", hasScrollingContent: "hasScrollingContent" }, outputs: { overlaySelected: "overlaySelected", close: "close" }, host: { listeners: { "keydown": "handleKeyboardEvent($event)" } }, viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: ` <cds-overlay [theme]="theme" [open]="open" (overlaySelect)="overlaySelected.emit()"> <div class="cds--modal-container" [ngClass]="{ 'cds--modal-container--xs': size === 'xs', 'cds--modal-container--sm': size === 'sm', 'cds--modal-container--md': size === 'md', 'cds--modal-container--lg': size === 'lg' }" role="dialog" aria-modal="true" style="z-index:1;" [attr.aria-label]="ariaLabel" #modal> <ng-content></ng-content> </div> </cds-overlay> `, isInline: true, dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i3.Overlay, selector: "cds-overlay, ibm-overlay", inputs: ["theme", "open"], outputs: ["overlaySelect"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Modal, decorators: [{ type: Component, args: [{ selector: "cds-modal, ibm-modal", template: ` <cds-overlay [theme]="theme" [open]="open" (overlaySelect)="overlaySelected.emit()"> <div class="cds--modal-container" [ngClass]="{ 'cds--modal-container--xs': size === 'xs', 'cds--modal-container--sm': size === 'sm', 'cds--modal-container--md': size === 'md', 'cds--modal-container--lg': size === 'lg' }" role="dialog" aria-modal="true" style="z-index:1;" [attr.aria-label]="ariaLabel" #modal> <ng-content></ng-content> </div> </cds-overlay> ` }] }], ctorParameters: function () { return [{ type: i1.BaseModalService }, { type: Document, decorators: [{ type: Inject, args: [DOCUMENT] }] }, { type: i0.Renderer2 }]; }, propDecorators: { size: [{ type: Input }], theme: [{ type: Input }], ariaLabel: [{ type: Input }], open: [{ type: Input }], trigger: [{ type: Input }], hasScrollingContent: [{ type: Input }], overlaySelected: [{ type: Output }], close: [{ type: Output }], modal: [{ type: ViewChild, args: ["modal", { static: true }] }], handleKeyboardEvent: [{ type: HostListener, args: ["keydown", ["$event"]] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kYWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21vZGFsL21vZGFsLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRU4sU0FBUyxFQUNULFlBQVksRUFDWixZQUFZLEVBQ1osS0FBSyxFQUNMLE1BQU0sRUFFTixTQUFTLEVBSVQsTUFBTSxFQUVOLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMzQyxPQUFPLEVBQUUsU0FBUyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7Ozs7O0FBR2xGOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5REc7QUEwQkgsTUFBTSxPQUFPLEtBQUs7SUFtRGpCOztPQUVHO0lBQ0gsWUFDUSxZQUE4QixFQUNYLFFBQWtCLEVBQ3BDLFFBQW1CO1FBRnBCLGlCQUFZLEdBQVosWUFBWSxDQUFrQjtRQUNYLGFBQVEsR0FBUixRQUFRLENBQVU7UUFDcEMsYUFBUSxHQUFSLFFBQVEsQ0FBVztRQXhENUI7O1dBRUc7UUFDTSxTQUFJLEdBQTZCLElBQUksQ0FBQztRQUMvQzs7V0FFRztRQUNNLFVBQUssR0FBeUIsU0FBUyxDQUFDO1FBRWpEOztXQUVHO1FBQ00sY0FBUyxHQUFHLFNBQVMsQ0FBQztRQUUvQjs7V0FFRztRQUNNLFNBQUksR0FBRyxLQUFLLENBQUM7UUFPdEI7Ozs7O1dBS0c7UUFDTSx3QkFBbUIsR0FBWSxJQUFJLENBQUM7UUFFN0M7O1dBRUc7UUFDTyxvQkFBZSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFDL0M7O1dBRUc7UUFDTyxVQUFLLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQU1yQzs7V0FFRztRQUNILHlCQUFvQixHQUFHLHVCQUF1QixDQUFDO0lBUzNDLENBQUM7SUFFTCxX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RUFBRSxzQkFBc0I7b0JBQ2hDLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBcUJUO2lCQUNEOzswQkF5REUsTUFBTTsyQkFBQyxRQUFRO29FQXBEUixJQUFJO3NCQUFaLEtBQUs7Z0JBSUcsS0FBSztzQkFBYixLQUFLO2dCQUtHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBS0csSUFBSTtzQkFBWixLQUFLO2dCQUtHLE9BQU87c0JBQWYsS0FBSztnQkFRRyxtQkFBbUI7c0JBQTNCLEtBQUs7Z0JBS0ksZUFBZTtzQkFBeEIsTUFBTTtnQkFJRyxLQUFLO3NCQUFkLE1BQU07Z0JBSStCLEtBQUs7c0JBQTFDLFNBQVM7dUJBQUMsT0FBTyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFnRHBDLG1CQUFtQjtzQkFEbEIsWUFBWTt1QkFBQyxTQUFTLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuXHRBZnRlclZpZXdJbml0LFxuXHRDb21wb25lbnQsXG5cdEV2ZW50RW1pdHRlcixcblx0SG9zdExpc3RlbmVyLFxuXHRJbnB1dCxcblx0T3V0cHV0LFxuXHRFbGVtZW50UmVmLFxuXHRWaWV3Q2hpbGQsXG5cdFNpbXBsZUNoYW5nZXMsXG5cdE9uQ2hhbmdlcyxcblx0UmVuZGVyZXIyLFxuXHRJbmplY3QsXG5cdE9uRGVzdHJveVxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHsgRE9DVU1FTlQgfSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uXCI7XG5pbXBvcnQgeyBjeWNsZVRhYnMsIGdldEZvY3VzRWxlbWVudExpc3QgfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci9jb21tb25cIjtcbmltcG9ydCB7IEJhc2VNb2RhbFNlcnZpY2UgfSBmcm9tIFwiLi9iYXNlLW1vZGFsLnNlcnZpY2VcIjtcblxuLyoqXG4gKiBDb21wb25lbnQgdG8gY3JlYXRlIG1vZGFscyBmb3IgcHJlc2VudGluZyBjb250ZW50LlxuICpcbiAqIFtTZWUgZGVtb10oLi4vLi4vP3BhdGg9L3N0b3J5L2NvbXBvbmVudHMtbW9kYWwtLWJhc2ljKVxuICpcbiAqIFVzaW5nIGEgbW9kYWwgaW4geW91ciBhcHBsaWNhdGlvbiByZXF1aXJlcyBgY2RzLXBsYWNlaG9sZGVyYCB3aGljaCB3b3VsZCBnZW5lcmFsbHkgYmVcbiAqIHBsYWNlZCBuZWFyIHRoZSBlbmQgb2YgeW91ciBhcHAgY29tcG9uZW50IHRlbXBsYXRlIChhcHAuY29tcG9uZW50LnRzIG9yIGFwcC5jb21wb25lbnQuaHRtbCkgYXM6XG4gKlxuYGBgaHRtbFxuPGNkcy1wbGFjZWhvbGRlcj48L2Nkcy1wbGFjZWhvbGRlcj5cbmBgYFxuICpcbiAqIEEgbW9yZSBjb21wbGV0ZSBleGFtcGxlIGZvciBgTW9kYWxgIGlzIGdpdmVuIGFzIGZvbGxvd3M6XG4gKlxuICogRXhhbXBsZSBtb2RhbCBkZWZpbml0aW9uOlxuICpcbmBgYHR5cGVzY3JpcHRcbkBDb21wb25lbnQoe1xuXHRzZWxlY3RvcjogXCJhcHAtc2FtcGxlLW1vZGFsXCIsXG5cdHRlbXBsYXRlOiBgXG5cdFx0XHRcdDxjZHMtbW9kYWwgc2l6ZT1cInhsXCIgKG92ZXJsYXlTZWxlY3RlZCk9XCJjbG9zZU1vZGFsKClcIj5cblx0XHRcdFx0XHQ8Y2RzLW1vZGFsLWhlYWRlciAoY2xvc2VTZWxlY3QpPVwiY2xvc2VNb2RhbCgpXCI+SGVhZGVyIHRleHQ8L2Nkcy1tb2RhbC1oZWFkZXI+XG5cdFx0XHRcdFx0XHQ8c2VjdGlvbiBjbGFzcz1cIm1vZGFsLWJvZHlcIj5cblx0XHRcdFx0XHRcdFx0PGgxPlNhbXBsZSBtb2RhbCB3b3Jrcy48L2gxPlxuXHRcdFx0XHRcdFx0XHQ8YnV0dG9uIGNsYXNzPVwiYnRuLS1pY29uLWxpbmtcIiBuUG9wb3Zlcj1cIkhlbGxvIHRoZXJlXCIgdGl0bGU9XCJQb3BvdmVyIHRpdGxlXCIgcGxhY2VtZW50PVwicmlnaHRcIiBhcHBlbmRJbmxpbmU9XCJ0cnVlXCI+XG5cdFx0XHRcdFx0XHRcdFx0PHN2ZyBjZHNJY29uPVwiaW5mb1wiIHNpemU9XCJzbVwiPjwvc3ZnPlxuXHRcdFx0XHRcdFx0XHQ8L2J1dHRvbj5cblx0XHRcdFx0XHRcdFx0e3ttb2RhbFRleHR9fVxuXHRcdFx0XHRcdFx0PC9zZWN0aW9uPlxuXHRcdFx0XHRcdDxjZHMtbW9kYWwtZm9vdGVyPjxidXR0b24gY2RzQnV0dG9uPVwicHJpbWFyeVwiIChjbGljayk9XCJjbG9zZU1vZGFsKClcIj5DbG9zZTwvYnV0dG9uPjwvY2RzLW1vZGFsLWZvb3Rlcj5cblx0XHRcdFx0PC9jZHMtbW9kYWw+YCxcblx0c3R5bGVVcmxzOiBbXCIuL3NhbXBsZS1tb2RhbC5jb21wb25lbnQuc2Nzc1wiXVxufSlcbmV4cG9ydCBjbGFzcyBTYW1wbGVNb2RhbCBleHRlbmRzIEJhc2VNb2RhbCB7XG5cdG1vZGFsVGV4dDogc3RyaW5nO1xuXHRjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgaW5qZWN0b3I6IEluamVjdG9yKSB7XG5cdFx0c3VwZXIoKTtcblx0XHR0aGlzLm1vZGFsVGV4dCA9IHRoaXMuaW5qZWN0b3IuZ2V0KFwibW9kYWxUZXh0XCIpO1xuXHR9XG59XG5gYGBcbiAqXG4gKiBFeGFtcGxlIG9mIG9wZW5pbmcgdGhlIG1vZGFsOlxuICpcbmBgYHR5cGVzY3JpcHRcbkBDb21wb25lbnQoe1xuXHRzZWxlY3RvcjogXCJhcHAtbW9kYWwtZGVtb1wiLFxuXHR0ZW1wbGF0ZTogYFxuXHRcdFx0XHQ8YnV0dG9uIGNkc0J1dHRvbj1cInByaW1hcnlcIiAoY2xpY2spPVwib3Blbk1vZGFsKCdkcmlsbCcpXCI+RHJpbGwtZG93biBtb2RhbDwvYnV0dG9uPlxuXHRcdFx0XHQ8Y2RzLXBsYWNlaG9sZGVyPjwvY2RzLXBsYWNlaG9sZGVyPmBcbn0pXG5leHBvcnQgY2xhc3MgTW9kYWxEZW1vIHtcblx0b3Blbk1vZGFsKCkge1xuXHRcdHRoaXMubW9kYWxTZXJ2aWNlLmNyZWF0ZSh7Y29tcG9uZW50OiBTYW1wbGVNb2RhbCwgaW5wdXRzOiB7bW9kYWxUZXh0OiBcIkhlbGxvIHVuaXZlcnNlLlwifX0pO1xuXHR9XG59XG5gYGBcbiAqL1xuQENvbXBvbmVudCh7XG5cdHNlbGVjdG9yOiBcImNkcy1tb2RhbCwgaWJtLW1vZGFsXCIsXG5cdHRlbXBsYXRlOiBgXG5cdFx0PGNkcy1vdmVybGF5XG5cdFx0XHRbdGhlbWVdPVwidGhlbWVcIlxuXHRcdFx0W29wZW5dPVwib3BlblwiXG5cdFx0XHQob3ZlcmxheVNlbGVjdCk9XCJvdmVybGF5U2VsZWN0ZWQuZW1pdCgpXCI+XG5cdFx0XHQ8ZGl2XG5cdFx0XHRcdGNsYXNzPVwiY2RzLS1tb2RhbC1jb250YWluZXJcIlxuXHRcdFx0XHRbbmdDbGFzc109XCJ7XG5cdFx0XHRcdFx0J2Nkcy0tbW9kYWwtY29udGFpbmVyLS14cyc6IHNpemUgPT09ICd4cycsXG5cdFx0XHRcdFx0J2Nkcy0tbW9kYWwtY29udGFpbmVyLS1zbSc6IHNpemUgPT09ICdzbScsXG5cdFx0XHRcdFx0J2Nkcy0tbW9kYWwtY29udGFpbmVyLS1tZCc6IHNpemUgPT09ICdtZCcsXG5cdFx0XHRcdFx0J2Nkcy0tbW9kYWwtY29udGFpbmVyLS1sZyc6IHNpemUgPT09ICdsZydcblx0XHRcdFx0fVwiXG5cdFx0XHRcdHJvbGU9XCJkaWFsb2dcIlxuXHRcdFx0XHRhcmlhLW1vZGFsPVwidHJ1ZVwiXG5cdFx0XHRcdHN0eWxlPVwiei1pbmRleDoxO1wiXG5cdFx0XHRcdFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsXCJcblx0XHRcdFx0I21vZGFsPlxuXHRcdFx0XHQ8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG5cdFx0XHQ8L2Rpdj5cblx0XHQ8L2Nkcy1vdmVybGF5PlxuXHRgXG59KVxuZXhwb3J0IGNsYXNzIE1vZGFsIGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25DaGFuZ2VzLCBPbkRlc3Ryb3kge1xuXHQvKipcblx0ICogU2l6ZSBvZiB0aGUgbW9kYWwgdG8gZGlzcGxheS5cblx0ICovXG5cdEBJbnB1dCgpIHNpemU6IFwieHNcIiB8IFwic21cInwgXCJtZFwiIHwgXCJsZ1wiID0gXCJtZFwiO1xuXHQvKipcblx0ICogQ2xhc3NpZmljYXRpb24gb2YgdGhlIG1vZGFsLlxuXHQgKi9cblx0QElucHV0KCkgdGhlbWU6IFwiZGVmYXVsdFwiIHwgXCJkYW5nZXJcIiA9IFwiZGVmYXVsdFwiO1xuXG5cdC8qKlxuXHQgKiBMYWJlbCBmb3IgdGhlIG1vZGFsLlxuXHQgKi9cblx0QElucHV0KCkgYXJpYUxhYmVsID0gXCJkZWZhdWx0XCI7XG5cblx0LyoqXG5cdCAqIENvbnRyb2xzIHRoZSB2aXNpYmlsaXR5IG9mIHRoZSBtb2RhbCB3aGVuIHVzZWQgZGlyZWN0bHkgaW4gYSB0ZW1wbGF0ZVxuXHQgKi9cblx0QElucHV0KCkgb3BlbiA9IGZhbHNlO1xuXG5cdC8qKlxuXHQgKiBUaGUgZWxlbWVudCB0aGF0IHRyaWdnZXJzIHRoZSBtb2RhbCwgd2hpY2ggc2hvdWxkIHJlY2VpdmUgZm9jdXMgd2hlbiB0aGUgbW9kYWwgY2xvc2VzXG5cdCAqL1xuXHRASW5wdXQoKSB0cmlnZ2VyOiBIVE1MRWxlbWVudDtcblxuXHQvKipcblx0ICogU3BlY2lmeSB3aGV0aGVyIHRoZSBtb2RhbCBjb250YWlucyBzY3JvbGxpbmcgY29udGVudC4gVGhpcyBwcm9wZXJ0eSBvdmVycmlkZXMgdGhlIGF1dG9tYXRpY1xuXHQgKiBkZXRlY3Rpb24gb2YgdGhlIGV4aXN0ZW5jZSBvZiBzY3JvbGxpbmcgY29udGVudC4gU2V0IHRoaXMgcHJvcGVydHkgdG8gYHRydWVgIHRvIGZvcmNlXG5cdCAqIG92ZXJmbG93IGluZGljYXRvciB0byBzaG93IHVwIG9yIHRvIGBmYWxzZWAgdG8gZm9yY2Ugb3ZlcmZsb3cgaW5kaWNhdG9yIHRvIGRpc2FwcGVhci5cblx0ICogSXQgaXMgc2V0IHRvIGBudWxsYCBieSBkZWZhdWx0IHdoaWNoIGluZGljYXRlcyBub3QgdG8gb3ZlcnJpZGUgYXV0b21hdGljIGRldGVjdGlvbi5cblx0ICovXG5cdEBJbnB1dCgpIGhhc1Njcm9sbGluZ0NvbnRlbnQ6IGJvb2xlYW4gPSBudWxsO1xuXG5cdC8qKlxuXHQgKiBFbWl0cyBldmVudCB3aGVuIGNsaWNrIG9jY3VycyB3aXRoaW4gYG4tb3ZlcmxheWAgZWxlbWVudC4gVGhpcyBpcyB0byB0cmFjayBjbGljayBldmVudHMgb2NjdXJyaW5nIG91dHNpZGUgYm91bmRzIG9mIHRoZSBgTW9kYWxgIG9iamVjdC5cblx0ICovXG5cdEBPdXRwdXQoKSBvdmVybGF5U2VsZWN0ZWQgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cdC8qKlxuXHQgKiBUbyBlbWl0IHRoZSBjbG9zaW5nIGV2ZW50IG9mIHRoZSBtb2RhbCB3aW5kb3cuXG5cdCAqL1xuXHRAT3V0cHV0KCkgY2xvc2UgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cdC8qKlxuXHQgKiBNYWludGFpbnMgYSByZWZlcmVuY2UgdG8gdGhlIHZpZXcgRE9NIGVsZW1lbnQgb2YgdGhlIGBNb2RhbGAuXG5cdCAqL1xuXHRAVmlld0NoaWxkKFwibW9kYWxcIiwgeyBzdGF0aWM6IHRydWUgfSkgbW9kYWw6IEVsZW1lbnRSZWY7XG5cblx0LyoqXG5cdCAqIEFuIGVsZW1lbnQgc2hvdWxkIGhhdmUgJ21vZGFsLXByaW1hcnktZm9jdXMnIGFzIGFuIGF0dHJpYnV0ZSB0byByZWNlaXZlIGluaXRpYWwgZm9jdXMgd2l0aGluIHRoZSBgTW9kYWxgIGNvbXBvbmVudC5cblx0ICovXG5cdHNlbGVjdG9yUHJpbWFyeUZvY3VzID0gXCJbbW9kYWwtcHJpbWFyeS1mb2N1c11cIjtcblxuXHQvKipcblx0ICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBgTW9kYWxgLlxuXHQgKi9cblx0Y29uc3RydWN0b3IoXG5cdFx0cHVibGljIG1vZGFsU2VydmljZTogQmFzZU1vZGFsU2VydmljZSxcblx0XHRASW5qZWN0KERPQ1VNRU5UKSBwcml2YXRlIGRvY3VtZW50OiBEb2N1bWVudCxcblx0XHRwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjJcblx0KSB7IH1cblxuXHRuZ09uQ2hhbmdlcyh7IG9wZW4sIGhhc1Njcm9sbGluZ0NvbnRlbnQgfTogU2ltcGxlQ2hhbmdlcykge1xuXHRcdGlmIChvcGVuKSB7XG5cdFx0XHRpZiAob3Blbi5jdXJyZW50VmFsdWUpIHtcblx0XHRcdFx0Ly8gYDEwMGAgaXMganVzdCBlbm91Z2ggdGltZSB0byBhbGxvdyB0aGUgbW9kYWxcblx0XHRcdFx0Ly8gdG8gYmVjb21lIHZpc2libGUsIHNvIHRoYXQgd2UgY2FuIHNldCBmb2N1c1xuXHRcdFx0XHRzZXRUaW1lb3V0KCgpID0+IHRoaXMuZm9jdXNJbml0aWFsRWxlbWVudCgpLCAxMDApO1xuXHRcdFx0XHQvLyBQcmV2ZW50IHNjcm9sbGluZyBvbiBvcGVuXG5cdFx0XHRcdHRoaXMucmVuZGVyZXIuYWRkQ2xhc3ModGhpcy5kb2N1bWVudC5ib2R5LCBcImNkcy0tYm9keS0td2l0aC1tb2RhbC1vcGVuXCIpO1xuXHRcdFx0fSBlbHNlIGlmICghb3Blbi5jdXJyZW50VmFsdWUpIHtcblx0XHRcdFx0Ly8gRW5hYmxlIHNjcm9sbGluZyBvbiBjbG9zZVxuXHRcdFx0XHR0aGlzLnJlbmRlcmVyLnJlbW92ZUNsYXNzKHRoaXMuZG9jdW1lbnQuYm9keSwgXCJjZHMtLWJvZHktLXdpdGgtbW9kYWwtb3BlblwiKTtcblx0XHRcdH0gZWxzZSBpZiAodGhpcy50cmlnZ2VyKSB7XG5cdFx0XHRcdHRoaXMudHJpZ2dlci5mb2N1cygpO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRpZiAoaGFzU2Nyb2xsaW5nQ29udGVudCkge1xuXHRcdFx0dGhpcy51cGRhdGVTY3JvbGxiYXIoKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogU2V0IGRvY3VtZW50IGZvY3VzIHRvIGJlIG9uIHRoZSBtb2RhbCBjb21wb25lbnQgYWZ0ZXIgaXQgaXMgaW5pdGlhbGl6ZWQuXG5cdCAqL1xuXHRuZ0FmdGVyVmlld0luaXQoKSB7XG5cdFx0dGhpcy5mb2N1c0luaXRpYWxFbGVtZW50KCk7XG5cdFx0dGhpcy51cGRhdGVTY3JvbGxiYXIoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBIYW5kbGUga2V5Ym9hcmQgZXZlbnRzIHRvIGNsb3NlIG1vZGFsIGFuZCB0YWIgdGhyb3VnaCB0aGUgY29udGVudCB3aXRoaW4gdGhlIG1vZGFsLlxuXHQgKi9cblx0QEhvc3RMaXN0ZW5lcihcImtleWRvd25cIiwgW1wiJGV2ZW50XCJdKVxuXHRoYW5kbGVLZXlib2FyZEV2ZW50KGV2ZW50OiBLZXlib2FyZEV2ZW50KSB7XG5cdFx0c3dpdGNoIChldmVudC5rZXkpIHtcblx0XHRcdGNhc2UgXCJFc2NhcGVcIjoge1xuXHRcdFx0XHRldmVudC5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTsgIC8vIHByZXZlbnRzIGV2ZW50cyBiZWluZyBmaXJlZCBmb3IgbXVsdGlwbGUgbW9kYWxzIGlmIG1vcmUgdGhhbiAyIG9wZW5cblx0XHRcdFx0Ly8gTWFudWFsbHkgY2xvc2UgbW9kYWxcblx0XHRcdFx0dGhpcy5vcGVuID0gZmFsc2U7XG5cdFx0XHRcdHRoaXMuY2xvc2UuZW1pdCgpO1xuXHRcdFx0XHR0aGlzLm1vZGFsU2VydmljZS5kZXN0cm95KCk7ICAvLyBkZXN0cm95IHRvcCAobGF0ZXN0KSBtb2RhbFxuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblxuXHRcdFx0Y2FzZSBcIlRhYlwiOiB7XG5cdFx0XHRcdGN5Y2xlVGFicyhldmVudCwgdGhpcy5tb2RhbC5uYXRpdmVFbGVtZW50KTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFRoaXMgZGV0ZWN0cyB3aGV0aGVyIG9yIG5vdCB0aGUgbW9kYWwgY29udGFpbnMgc2Nyb2xsaW5nIGNvbnRlbnQuXG5cdCAqXG5cdCAqIFRvIGZvcmNlIHRyaWdnZXIgYSBkZXRlY3Rpb24gKGllLiBvbiB3aW5kb3cgcmVzaXplKSwgY2hhbmdlIG9yIHJlc2V0IHRoZSB2YWx1ZSBvZiB0aGUgbW9kYWwgY29udGVudC5cblx0ICpcblx0ICogVXNlIHRoZSBgaGFzU2Nyb2xsaW5nQ29udGVudGAgaW5wdXQgdG8gbWFudWFsbHkgb3ZlcnJpZGUgdGhlIG92ZXJmbG93IGluZGljYXRvci5cblx0ICovXG5cdGdldCBzaG91bGRTaG93U2Nyb2xsYmFyKCkge1xuXHRcdGNvbnN0IG1vZGFsQ29udGVudCA9IHRoaXMubW9kYWwgPyB0aGlzLm1vZGFsLm5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3RvcihcIi5jZHMtLW1vZGFsLWNvbnRlbnRcIikgOiBudWxsO1xuXHRcdGlmIChtb2RhbENvbnRlbnQpIHtcblx0XHRcdC8vIGdldCByb3VuZGVkIHZhbHVlIGZyb20gaGVpZ2h0IHRvIG1hdGNoIGludGVnZXIgcmV0dXJuZWQgZnJvbSBzY3JvbGxIZWlnaHRcblx0XHRcdGNvbnN0IG1vZGFsQ29udGVudEhlaWdodCA9IE1hdGguY2VpbChtb2RhbENvbnRlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0KTtcblx0XHRcdGNvbnN0IG1vZGFsQ29udGVudFNjcm9sbEhlaWdodCA9IG1vZGFsQ29udGVudC5zY3JvbGxIZWlnaHQ7XG5cdFx0XHRyZXR1cm4gbW9kYWxDb250ZW50U2Nyb2xsSGVpZ2h0ID4gbW9kYWxDb250ZW50SGVpZ2h0O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXHR9XG5cblx0Ly8gUmVtb3ZlIGNsYXNzIHByZXZlbnRpbmcgc2Nyb2xsaW5nXG5cdG5nT25EZXN0cm95KCkge1xuXHRcdHRoaXMucmVuZGVyZXIucmVtb3ZlQ2xhc3ModGhpcy5kb2N1bWVudC5ib2R5LCBcImNkcy0tYm9keS0td2l0aC1tb2RhbC1vcGVuXCIpO1xuXHR9XG5cblx0cHJvdGVjdGVkIGZvY3VzSW5pdGlhbEVsZW1lbnQoKSB7XG5cdFx0Y29uc3QgcHJpbWFyeUZvY3VzRWxlbWVudCA9IHRoaXMubW9kYWwubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuc2VsZWN0b3JQcmltYXJ5Rm9jdXMpO1xuXHRcdGlmIChwcmltYXJ5Rm9jdXNFbGVtZW50ICYmIHByaW1hcnlGb2N1c0VsZW1lbnQuZm9jdXMpIHtcblx0XHRcdHNldFRpbWVvdXQoKCkgPT4gcHJpbWFyeUZvY3VzRWxlbWVudC5mb2N1cygpKTtcblx0XHR9IGVsc2UgaWYgKGdldEZvY3VzRWxlbWVudExpc3QodGhpcy5tb2RhbC5uYXRpdmVFbGVtZW50KS5sZW5ndGggPiAwKSB7XG5cdFx0XHRzZXRUaW1lb3V0KCgpID0+IGdldEZvY3VzRWxlbWVudExpc3QodGhpcy5tb2RhbC5uYXRpdmVFbGVtZW50KVswXS5mb2N1cygpKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0c2V0VGltZW91dCgoKSA9PiB0aGlzLm1vZGFsLm5hdGl2ZUVsZW1lbnQuZm9jdXMoKSk7XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSB1cGRhdGVTY3JvbGxiYXIoKSB7XG5cdFx0Y29uc3QgbW9kYWxDb250ZW50ID0gdGhpcy5tb2RhbCA/IHRoaXMubW9kYWwubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKFwiLmNkcy0tbW9kYWwtY29udGVudFwiKSA6IG51bGw7XG5cdFx0Y29uc3Qgc2hvd1Njcm9sbGJhciA9IHRoaXMuaGFzU2Nyb2xsaW5nQ29udGVudCAhPT0gbnVsbCA/IHRoaXMuaGFzU2Nyb2xsaW5nQ29udGVudCA6IHRoaXMuc2hvdWxkU2hvd1Njcm9sbGJhcjtcblx0XHRpZiAobW9kYWxDb250ZW50KSB7XG5cdFx0XHRpZiAoc2hvd1Njcm9sbGJhcikge1xuXHRcdFx0XHR0aGlzLnJlbmRlcmVyLmFkZENsYXNzKG1vZGFsQ29udGVudCwgXCJjZHMtLW1vZGFsLXNjcm9sbC1jb250ZW50XCIpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5yZW5kZXJlci5yZW1vdmVDbGFzcyhtb2RhbENvbnRlbnQsIFwiY2RzLS1tb2RhbC1zY3JvbGwtY29udGVudFwiKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn1cbiJdfQ==