UNPKG

carbon-components-angular

Version:
296 lines 29.3 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"; /** * Render the modal in full-width layout (applies the * `cds--modal-container--full-width` modifier). */ this.isFullWidth = false; /** * 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", isFullWidth: "isFullWidth", open: "open", trigger: "trigger", hasScrollingContent: "hasScrollingContent", decorator: "decorator", selectorPrimaryFocus: "selectorPrimaryFocus" }, 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" [hasModalDecorator]="!!decorator" (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', 'cds--modal-container--full-width': isFullWidth }" 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", "hasModalDecorator"], 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" [hasModalDecorator]="!!decorator" (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', 'cds--modal-container--full-width': isFullWidth }" 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 }], isFullWidth: [{ type: Input }], open: [{ type: Input }], trigger: [{ type: Input }], hasScrollingContent: [{ type: Input }], decorator: [{ type: Input }], overlaySelected: [{ type: Output }], close: [{ type: Output }], modal: [{ type: ViewChild, args: ["modal", { static: true }] }], selectorPrimaryFocus: [{ type: Input }], handleKeyboardEvent: [{ type: HostListener, args: ["keydown", ["$event"]] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kYWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21vZGFsL21vZGFsLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRU4sU0FBUyxFQUNULFlBQVksRUFDWixZQUFZLEVBQ1osS0FBSyxFQUNMLE1BQU0sRUFFTixTQUFTLEVBSVQsTUFBTSxFQUdOLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMzQyxPQUFPLEVBQUUsU0FBUyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7Ozs7O0FBR2xGOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5REc7QUE0QkgsTUFBTSxPQUFPLEtBQUs7SUE2RGpCOztPQUVHO0lBQ0gsWUFDUSxZQUE4QixFQUNYLFFBQWtCLEVBQ3BDLFFBQW1CO1FBRnBCLGlCQUFZLEdBQVosWUFBWSxDQUFrQjtRQUNYLGFBQVEsR0FBUixRQUFRLENBQVU7UUFDcEMsYUFBUSxHQUFSLFFBQVEsQ0FBVztRQWxFNUI7O1dBRUc7UUFDTSxTQUFJLEdBQTZCLElBQUksQ0FBQztRQUMvQzs7V0FFRztRQUNNLFVBQUssR0FBeUIsU0FBUyxDQUFDO1FBRWpEOztXQUVHO1FBQ00sY0FBUyxHQUFHLFNBQVMsQ0FBQztRQUUvQjs7O1dBR0c7UUFDTSxnQkFBVyxHQUFHLEtBQUssQ0FBQztRQUU3Qjs7V0FFRztRQUNNLFNBQUksR0FBRyxLQUFLLENBQUM7UUFPdEI7Ozs7O1dBS0c7UUFDTSx3QkFBbUIsR0FBWSxJQUFJLENBQUM7UUFNN0M7O1dBRUc7UUFDTyxvQkFBZSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFDL0M7O1dBRUc7UUFDTyxVQUFLLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQU1yQzs7V0FFRztRQUNNLHlC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OzJGQUVXLEtBQUs7a0JBM0JqQixTQUFTO21CQUFDO29CQUNWLFFBQVEsRUFBRSxzQkFBc0I7b0JBQ2hDLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUF1QlQ7aUJBQ0Q7OzBCQW1FRSxNQUFNOzJCQUFDLFFBQVE7b0VBOURSLElBQUk7c0JBQVosS0FBSztnQkFJRyxLQUFLO3NCQUFiLEtBQUs7Z0JBS0csU0FBUztzQkFBakIsS0FBSztnQkFNRyxXQUFXO3NCQUFuQixLQUFLO2dCQUtHLElBQUk7c0JBQVosS0FBSztnQkFLRyxPQUFPO3NCQUFmLEtBQUs7Z0JBUUcsbUJBQW1CO3NCQUEzQixLQUFLO2dCQUlHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBS0ksZUFBZTtzQkFBeEIsTUFBTTtnQkFJRyxLQUFLO3NCQUFkLE1BQU07Z0JBSStCLEtBQUs7c0JBQTFDLFNBQVM7dUJBQUMsT0FBTyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFLM0Isb0JBQW9CO3NCQUE1QixLQUFLO2dCQTJDTixtQkFBbUI7c0JBRGxCLFlBQVk7dUJBQUMsU0FBUyxFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0QWZ0ZXJWaWV3SW5pdCxcblx0Q29tcG9uZW50LFxuXHRFdmVudEVtaXR0ZXIsXG5cdEhvc3RMaXN0ZW5lcixcblx0SW5wdXQsXG5cdE91dHB1dCxcblx0RWxlbWVudFJlZixcblx0Vmlld0NoaWxkLFxuXHRTaW1wbGVDaGFuZ2VzLFxuXHRPbkNoYW5nZXMsXG5cdFJlbmRlcmVyMixcblx0SW5qZWN0LFxuXHRPbkRlc3Ryb3ksXG5cdFRlbXBsYXRlUmVmXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gXCJAYW5ndWxhci9jb21tb25cIjtcbmltcG9ydCB7IGN5Y2xlVGFicywgZ2V0Rm9jdXNFbGVtZW50TGlzdCB9IGZyb20gXCJjYXJib24tY29tcG9uZW50cy1hbmd1bGFyL2NvbW1vblwiO1xuaW1wb3J0IHsgQmFzZU1vZGFsU2VydmljZSB9IGZyb20gXCIuL2Jhc2UtbW9kYWwuc2VydmljZVwiO1xuXG4vKipcbiAqIENvbXBvbmVudCB0byBjcmVhdGUgbW9kYWxzIGZvciBwcmVzZW50aW5nIGNvbnRlbnQuXG4gKlxuICogW1NlZSBkZW1vXSguLi8uLi8/cGF0aD0vc3RvcnkvY29tcG9uZW50cy1tb2RhbC0tYmFzaWMpXG4gKlxuICogVXNpbmcgYSBtb2RhbCBpbiB5b3VyIGFwcGxpY2F0aW9uIHJlcXVpcmVzIGBjZHMtcGxhY2Vob2xkZXJgIHdoaWNoIHdvdWxkIGdlbmVyYWxseSBiZVxuICogcGxhY2VkIG5lYXIgdGhlIGVuZCBvZiB5b3VyIGFwcCBjb21wb25lbnQgdGVtcGxhdGUgKGFwcC5jb21wb25lbnQudHMgb3IgYXBwLmNvbXBvbmVudC5odG1sKSBhczpcbiAqXG5gYGBodG1sXG48Y2RzLXBsYWNlaG9sZGVyPjwvY2RzLXBsYWNlaG9sZGVyPlxuYGBgXG4gKlxuICogQSBtb3JlIGNvbXBsZXRlIGV4YW1wbGUgZm9yIGBNb2RhbGAgaXMgZ2l2ZW4gYXMgZm9sbG93czpcbiAqXG4gKiBFeGFtcGxlIG1vZGFsIGRlZmluaXRpb246XG4gKlxuYGBgdHlwZXNjcmlwdFxuQENvbXBvbmVudCh7XG5cdHNlbGVjdG9yOiBcImFwcC1zYW1wbGUtbW9kYWxcIixcblx0dGVtcGxhdGU6IGBcblx0XHRcdFx0PGNkcy1tb2RhbCBzaXplPVwieGxcIiAob3ZlcmxheVNlbGVjdGVkKT1cImNsb3NlTW9kYWwoKVwiPlxuXHRcdFx0XHRcdDxjZHMtbW9kYWwtaGVhZGVyIChjbG9zZVNlbGVjdCk9XCJjbG9zZU1vZGFsKClcIj5IZWFkZXIgdGV4dDwvY2RzLW1vZGFsLWhlYWRlcj5cblx0XHRcdFx0XHRcdDxzZWN0aW9uIGNsYXNzPVwibW9kYWwtYm9keVwiPlxuXHRcdFx0XHRcdFx0XHQ8aDE+U2FtcGxlIG1vZGFsIHdvcmtzLjwvaDE+XG5cdFx0XHRcdFx0XHRcdDxidXR0b24gY2xhc3M9XCJidG4tLWljb24tbGlua1wiIG5Qb3BvdmVyPVwiSGVsbG8gdGhlcmVcIiB0aXRsZT1cIlBvcG92ZXIgdGl0bGVcIiBwbGFjZW1lbnQ9XCJyaWdodFwiIGFwcGVuZElubGluZT1cInRydWVcIj5cblx0XHRcdFx0XHRcdFx0XHQ8c3ZnIGNkc0ljb249XCJpbmZvXCIgc2l6ZT1cInNtXCI+PC9zdmc+XG5cdFx0XHRcdFx0XHRcdDwvYnV0dG9uPlxuXHRcdFx0XHRcdFx0XHR7e21vZGFsVGV4dH19XG5cdFx0XHRcdFx0XHQ8L3NlY3Rpb24+XG5cdFx0XHRcdFx0PGNkcy1tb2RhbC1mb290ZXI+PGJ1dHRvbiBjZHNCdXR0b249XCJwcmltYXJ5XCIgKGNsaWNrKT1cImNsb3NlTW9kYWwoKVwiPkNsb3NlPC9idXR0b24+PC9jZHMtbW9kYWwtZm9vdGVyPlxuXHRcdFx0XHQ8L2Nkcy1tb2RhbD5gLFxuXHRzdHlsZVVybHM6IFtcIi4vc2FtcGxlLW1vZGFsLmNvbXBvbmVudC5zY3NzXCJdXG59KVxuZXhwb3J0IGNsYXNzIFNhbXBsZU1vZGFsIGV4dGVuZHMgQmFzZU1vZGFsIHtcblx0bW9kYWxUZXh0OiBzdHJpbmc7XG5cdGNvbnN0cnVjdG9yKHByb3RlY3RlZCBpbmplY3RvcjogSW5qZWN0b3IpIHtcblx0XHRzdXBlcigpO1xuXHRcdHRoaXMubW9kYWxUZXh0ID0gdGhpcy5pbmplY3Rvci5nZXQoXCJtb2RhbFRleHRcIik7XG5cdH1cbn1cbmBgYFxuICpcbiAqIEV4YW1wbGUgb2Ygb3BlbmluZyB0aGUgbW9kYWw6XG4gKlxuYGBgdHlwZXNjcmlwdFxuQENvbXBvbmVudCh7XG5cdHNlbGVjdG9yOiBcImFwcC1tb2RhbC1kZW1vXCIsXG5cdHRlbXBsYXRlOiBgXG5cdFx0XHRcdDxidXR0b24gY2RzQnV0dG9uPVwicHJpbWFyeVwiIChjbGljayk9XCJvcGVuTW9kYWwoJ2RyaWxsJylcIj5EcmlsbC1kb3duIG1vZGFsPC9idXR0b24+XG5cdFx0XHRcdDxjZHMtcGxhY2Vob2xkZXI+PC9jZHMtcGxhY2Vob2xkZXI+YFxufSlcbmV4cG9ydCBjbGFzcyBNb2RhbERlbW8ge1xuXHRvcGVuTW9kYWwoKSB7XG5cdFx0dGhpcy5tb2RhbFNlcnZpY2UuY3JlYXRlKHtjb21wb25lbnQ6IFNhbXBsZU1vZGFsLCBpbnB1dHM6IHttb2RhbFRleHQ6IFwiSGVsbG8gdW5pdmVyc2UuXCJ9fSk7XG5cdH1cbn1cbmBgYFxuICovXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6IFwiY2RzLW1vZGFsLCBpYm0tbW9kYWxcIixcblx0dGVtcGxhdGU6IGBcblx0XHQ8Y2RzLW92ZXJsYXlcblx0XHRcdFt0aGVtZV09XCJ0aGVtZVwiXG5cdFx0XHRbb3Blbl09XCJvcGVuXCJcblx0XHRcdFtoYXNNb2RhbERlY29yYXRvcl09XCIhIWRlY29yYXRvclwiXG5cdFx0XHQob3ZlcmxheVNlbGVjdCk9XCJvdmVybGF5U2VsZWN0ZWQuZW1pdCgpXCI+XG5cdFx0XHQ8ZGl2XG5cdFx0XHRcdGNsYXNzPVwiY2RzLS1tb2RhbC1jb250YWluZXJcIlxuXHRcdFx0XHRbbmdDbGFzc109XCJ7XG5cdFx0XHRcdFx0J2Nkcy0tbW9kYWwtY29udGFpbmVyLS14cyc6IHNpemUgPT09ICd4cycsXG5cdFx0XHRcdFx0J2Nkcy0tbW9kYWwtY29udGFpbmVyLS1zbSc6IHNpemUgPT09ICdzbScsXG5cdFx0XHRcdFx0J2Nkcy0tbW9kYWwtY29udGFpbmVyLS1tZCc6IHNpemUgPT09ICdtZCcsXG5cdFx0XHRcdFx0J2Nkcy0tbW9kYWwtY29udGFpbmVyLS1sZyc6IHNpemUgPT09ICdsZycsXG5cdFx0XHRcdFx0J2Nkcy0tbW9kYWwtY29udGFpbmVyLS1mdWxsLXdpZHRoJzogaXNGdWxsV2lkdGhcblx0XHRcdFx0fVwiXG5cdFx0XHRcdHJvbGU9XCJkaWFsb2dcIlxuXHRcdFx0XHRhcmlhLW1vZGFsPVwidHJ1ZVwiXG5cdFx0XHRcdHN0eWxlPVwiei1pbmRleDoxO1wiXG5cdFx0XHRcdFthdHRyLmFyaWEtbGFiZWxdPVwiYXJpYUxhYmVsXCJcblx0XHRcdFx0I21vZGFsPlxuXHRcdFx0XHQ8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG5cdFx0XHQ8L2Rpdj5cblx0XHQ8L2Nkcy1vdmVybGF5PlxuXHRgXG59KVxuZXhwb3J0IGNsYXNzIE1vZGFsIGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25DaGFuZ2VzLCBPbkRlc3Ryb3kge1xuXHQvKipcblx0ICogU2l6ZSBvZiB0aGUgbW9kYWwgdG8gZGlzcGxheS5cblx0ICovXG5cdEBJbnB1dCgpIHNpemU6IFwieHNcIiB8IFwic21cInwgXCJtZFwiIHwgXCJsZ1wiID0gXCJtZFwiO1xuXHQvKipcblx0ICogQ2xhc3NpZmljYXRpb24gb2YgdGhlIG1vZGFsLlxuXHQgKi9cblx0QElucHV0KCkgdGhlbWU6IFwiZGVmYXVsdFwiIHwgXCJkYW5nZXJcIiA9IFwiZGVmYXVsdFwiO1xuXG5cdC8qKlxuXHQgKiBMYWJlbCBmb3IgdGhlIG1vZGFsLlxuXHQgKi9cblx0QElucHV0KCkgYXJpYUxhYmVsID0gXCJkZWZhdWx0XCI7XG5cblx0LyoqXG5cdCAqIFJlbmRlciB0aGUgbW9kYWwgaW4gZnVsbC13aWR0aCBsYXlvdXQgKGFwcGxpZXMgdGhlXG5cdCAqIGBjZHMtLW1vZGFsLWNvbnRhaW5lci0tZnVsbC13aWR0aGAgbW9kaWZpZXIpLlxuXHQgKi9cblx0QElucHV0KCkgaXNGdWxsV2lkdGggPSBmYWxzZTtcblxuXHQvKipcblx0ICogQ29udHJvbHMgdGhlIHZpc2liaWxpdHkgb2YgdGhlIG1vZGFsIHdoZW4gdXNlZCBkaXJlY3RseSBpbiBhIHRlbXBsYXRlXG5cdCAqL1xuXHRASW5wdXQoKSBvcGVuID0gZmFsc2U7XG5cblx0LyoqXG5cdCAqIFRoZSBlbGVtZW50IHRoYXQgdHJpZ2dlcnMgdGhlIG1vZGFsLCB3aGljaCBzaG91bGQgcmVjZWl2ZSBmb2N1cyB3aGVuIHRoZSBtb2RhbCBjbG9zZXNcblx0ICovXG5cdEBJbnB1dCgpIHRyaWdnZXI6IEhUTUxFbGVtZW50O1xuXG5cdC8qKlxuXHQgKiBTcGVjaWZ5IHdoZXRoZXIgdGhlIG1vZGFsIGNvbnRhaW5zIHNjcm9sbGluZyBjb250ZW50LiBUaGlzIHByb3BlcnR5IG92ZXJyaWRlcyB0aGUgYXV0b21hdGljXG5cdCAqIGRldGVjdGlvbiBvZiB0aGUgZXhpc3RlbmNlIG9mIHNjcm9sbGluZyBjb250ZW50LiBTZXQgdGhpcyBwcm9wZXJ0eSB0byBgdHJ1ZWAgdG8gZm9yY2Vcblx0ICogb3ZlcmZsb3cgaW5kaWNhdG9yIHRvIHNob3cgdXAgb3IgdG8gYGZhbHNlYCB0byBmb3JjZSBvdmVyZmxvdyBpbmRpY2F0b3IgdG8gZGlzYXBwZWFyLlxuXHQgKiBJdCBpcyBzZXQgdG8gYG51bGxgIGJ5IGRlZmF1bHQgd2hpY2ggaW5kaWNhdGVzIG5vdCB0byBvdmVycmlkZSBhdXRvbWF0aWMgZGV0ZWN0aW9uLlxuXHQgKi9cblx0QElucHV0KCkgaGFzU2Nyb2xsaW5nQ29udGVudDogYm9vbGVhbiA9IG51bGw7XG5cdC8qKlxuXHQgKiAqKkV4cGVyaW1lbnRhbCoqOiBPcHRpb25hbCBkZWNvcmF0b3IgKGUuZy4gQUkgbGFiZWwpLlxuXHQgKi9cblx0QElucHV0KCkgZGVjb3JhdG9yOiBUZW1wbGF0ZVJlZjxhbnk+O1xuXG5cdC8qKlxuXHQgKiBFbWl0cyBldmVudCB3aGVuIGNsaWNrIG9jY3VycyB3aXRoaW4gYG4tb3ZlcmxheWAgZWxlbWVudC4gVGhpcyBpcyB0byB0cmFjayBjbGljayBldmVudHMgb2NjdXJyaW5nIG91dHNpZGUgYm91bmRzIG9mIHRoZSBgTW9kYWxgIG9iamVjdC5cblx0ICovXG5cdEBPdXRwdXQoKSBvdmVybGF5U2VsZWN0ZWQgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cdC8qKlxuXHQgKiBUbyBlbWl0IHRoZSBjbG9zaW5nIGV2ZW50IG9mIHRoZSBtb2RhbCB3aW5kb3cuXG5cdCAqL1xuXHRAT3V0cHV0KCkgY2xvc2UgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cdC8qKlxuXHQgKiBNYWludGFpbnMgYSByZWZlcmVuY2UgdG8gdGhlIHZpZXcgRE9NIGVsZW1lbnQgb2YgdGhlIGBNb2RhbGAuXG5cdCAqL1xuXHRAVmlld0NoaWxkKFwibW9kYWxcIiwgeyBzdGF0aWM6IHRydWUgfSkgbW9kYWw6IEVsZW1lbnRSZWY7XG5cblx0LyoqXG5cdCAqIEFuIGVsZW1lbnQgc2hvdWxkIGhhdmUgJ21vZGFsLXByaW1hcnktZm9jdXMnIGFzIGFuIGF0dHJpYnV0ZSB0byByZWNlaXZlIGluaXRpYWwgZm9jdXMgd2l0aGluIHRoZSBgTW9kYWxgIGNvbXBvbmVudC5cblx0ICovXG5cdEBJbnB1dCgpIHNlbGVjdG9yUHJpbWFyeUZvY3VzID0gXCJbbW9kYWwtcHJpbWFyeS1mb2N1c11cIjtcblxuXHQvKipcblx0ICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBgTW9kYWxgLlxuXHQgKi9cblx0Y29uc3RydWN0b3IoXG5cdFx0cHVibGljIG1vZGFsU2VydmljZTogQmFzZU1vZGFsU2VydmljZSxcblx0XHRASW5qZWN0KERPQ1VNRU5UKSBwcml2YXRlIGRvY3VtZW50OiBEb2N1bWVudCxcblx0XHRwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjJcblx0KSB7IH1cblxuXHRuZ09uQ2hhbmdlcyh7IG9wZW4sIGhhc1Njcm9sbGluZ0NvbnRlbnQgfTogU2ltcGxlQ2hhbmdlcykge1xuXHRcdGlmIChvcGVuKSB7XG5cdFx0XHRpZiAob3Blbi5jdXJyZW50VmFsdWUpIHtcblx0XHRcdFx0Ly8gYDEwMGAgaXMganVzdCBlbm91Z2ggdGltZSB0byBhbGxvdyB0aGUgbW9kYWxcblx0XHRcdFx0Ly8gdG8gYmVjb21lIHZpc2libGUsIHNvIHRoYXQgd2UgY2FuIHNldCBmb2N1c1xuXHRcdFx0XHRzZXRUaW1lb3V0KCgpID0+IHRoaXMuZm9jdXNJbml0aWFsRWxlbWVudCgpLCAxMDApO1xuXHRcdFx0XHQvLyBQcmV2ZW50IHNjcm9sbGluZyBvbiBvcGVuXG5cdFx0XHRcdHRoaXMucmVuZGVyZXIuYWRkQ2xhc3ModGhpcy5kb2N1bWVudC5ib2R5LCBcImNkcy0tYm9keS0td2l0aC1tb2RhbC1vcGVuXCIpO1xuXHRcdFx0fSBlbHNlIGlmICghb3Blbi5jdXJyZW50VmFsdWUpIHtcblx0XHRcdFx0Ly8gRW5hYmxlIHNjcm9sbGluZyBvbiBjbG9zZVxuXHRcdFx0XHR0aGlzLnJlbmRlcmVyLnJlbW92ZUNsYXNzKHRoaXMuZG9jdW1lbnQuYm9keSwgXCJjZHMtLWJvZHktLXdpdGgtbW9kYWwtb3BlblwiKTtcblx0XHRcdH0gZWxzZSBpZiAodGhpcy50cmlnZ2VyKSB7XG5cdFx0XHRcdHRoaXMudHJpZ2dlci5mb2N1cygpO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRpZiAoaGFzU2Nyb2xsaW5nQ29udGVudCkge1xuXHRcdFx0dGhpcy51cGRhdGVTY3JvbGxiYXIoKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogU2V0IGRvY3VtZW50IGZvY3VzIHRvIGJlIG9uIHRoZSBtb2RhbCBjb21wb25lbnQgYWZ0ZXIgaXQgaXMgaW5pdGlhbGl6ZWQuXG5cdCAqL1xuXHRuZ0FmdGVyVmlld0luaXQoKSB7XG5cdFx0dGhpcy5mb2N1c0luaXRpYWxFbGVtZW50KCk7XG5cdFx0dGhpcy51cGRhdGVTY3JvbGxiYXIoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBIYW5kbGUga2V5Ym9hcmQgZXZlbnRzIHRvIGNsb3NlIG1vZGFsIGFuZCB0YWIgdGhyb3VnaCB0aGUgY29udGVudCB3aXRoaW4gdGhlIG1vZGFsLlxuXHQgKi9cblx0QEhvc3RMaXN0ZW5lcihcImtleWRvd25cIiwgW1wiJGV2ZW50XCJdKVxuXHRoYW5kbGVLZXlib2FyZEV2ZW50KGV2ZW50OiBLZXlib2FyZEV2ZW50KSB7XG5cdFx0c3dpdGNoIChldmVudC5rZXkpIHtcblx0XHRcdGNhc2UgXCJFc2NhcGVcIjoge1xuXHRcdFx0XHRldmVudC5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTsgIC8vIHByZXZlbnRzIGV2ZW50cyBiZWluZyBmaXJlZCBmb3IgbXVsdGlwbGUgbW9kYWxzIGlmIG1vcmUgdGhhbiAyIG9wZW5cblx0XHRcdFx0Ly8gTWFudWFsbHkgY2xvc2UgbW9kYWxcblx0XHRcdFx0dGhpcy5vcGVuID0gZmFsc2U7XG5cdFx0XHRcdHRoaXMuY2xvc2UuZW1pdCgpO1xuXHRcdFx0XHR0aGlzLm1vZGFsU2VydmljZS5kZXN0cm95KCk7ICAvLyBkZXN0cm95IHRvcCAobGF0ZXN0KSBtb2RhbFxuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblxuXHRcdFx0Y2FzZSBcIlRhYlwiOiB7XG5cdFx0XHRcdGN5Y2xlVGFicyhldmVudCwgdGhpcy5tb2RhbC5uYXRpdmVFbGVtZW50KTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFRoaXMgZGV0ZWN0cyB3aGV0aGVyIG9yIG5vdCB0aGUgbW9kYWwgY29udGFpbnMgc2Nyb2xsaW5nIGNvbnRlbnQuXG5cdCAqXG5cdCAqIFRvIGZvcmNlIHRyaWdnZXIgYSBkZXRlY3Rpb24gKGllLiBvbiB3aW5kb3cgcmVzaXplKSwgY2hhbmdlIG9yIHJlc2V0IHRoZSB2YWx1ZSBvZiB0aGUgbW9kYWwgY29udGVudC5cblx0ICpcblx0ICogVXNlIHRoZSBgaGFzU2Nyb2xsaW5nQ29udGVudGAgaW5wdXQgdG8gbWFudWFsbHkgb3ZlcnJpZGUgdGhlIG92ZXJmbG93IGluZGljYXRvci5cblx0ICovXG5cdGdldCBzaG91bGRTaG93U2Nyb2xsYmFyKCkge1xuXHRcdGNvbnN0IG1vZGFsQ29udGVudCA9IHRoaXMubW9kYWwgPyB0aGlzLm1vZGFsLm5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3RvcihcIi5jZHMtLW1vZGFsLWNvbnRlbnRcIikgOiBudWxsO1xuXHRcdGlmIChtb2RhbENvbnRlbnQpIHtcblx0XHRcdC8vIGdldCByb3VuZGVkIHZhbHVlIGZyb20gaGVpZ2h0IHRvIG1hdGNoIGludGVnZXIgcmV0dXJuZWQgZnJvbSBzY3JvbGxIZWlnaHRcblx0XHRcdGNvbnN0IG1vZGFsQ29udGVudEhlaWdodCA9IE1hdGguY2VpbChtb2RhbENvbnRlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0KTtcblx0XHRcdGNvbnN0IG1vZGFsQ29udGVudFNjcm9sbEhlaWdodCA9IG1vZGFsQ29udGVudC5zY3JvbGxIZWlnaHQ7XG5cdFx0XHRyZXR1cm4gbW9kYWxDb250ZW50U2Nyb2xsSGVpZ2h0ID4gbW9kYWxDb250ZW50SGVpZ2h0O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXHR9XG5cblx0Ly8gUmVtb3ZlIGNsYXNzIHByZXZlbnRpbmcgc2Nyb2xsaW5nXG5cdG5nT25EZXN0cm95KCkge1xuXHRcdHRoaXMucmVuZGVyZXIucmVtb3ZlQ2xhc3ModGhpcy5kb2N1bWVudC5ib2R5LCBcImNkcy0tYm9keS0td2l0aC1tb2RhbC1vcGVuXCIpO1xuXHR9XG5cblx0cHJvdGVjdGVkIGZvY3VzSW5pdGlhbEVsZW1lbnQoKSB7XG5cdFx0Y29uc3QgcHJpbWFyeUZvY3VzRWxlbWVudCA9IHRoaXMubW9kYWwubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuc2VsZWN0b3JQcmltYXJ5Rm9jdXMpO1xuXHRcdGlmIChwcmltYXJ5Rm9jdXNFbGVtZW50ICYmIHByaW1hcnlGb2N1c0VsZW1lbnQuZm9jdXMpIHtcblx0XHRcdHNldFRpbWVvdXQoKCkgPT4gcHJpbWFyeUZvY3VzRWxlbWVudC5mb2N1cygpKTtcblx0XHR9IGVsc2UgaWYgKGdldEZvY3VzRWxlbWVudExpc3QodGhpcy5tb2RhbC5uYXRpdmVFbGVtZW50KS5sZW5ndGggPiAwKSB7XG5cdFx0XHRzZXRUaW1lb3V0KCgpID0+IGdldEZvY3VzRWxlbWVudExpc3QodGhpcy5tb2RhbC5uYXRpdmVFbGVtZW50KVswXS5mb2N1cygpKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0c2V0VGltZW91dCgoKSA9PiB0aGlzLm1vZGFsLm5hdGl2ZUVsZW1lbnQuZm9jdXMoKSk7XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSB1cGRhdGVTY3JvbGxiYXIoKSB7XG5cdFx0Y29uc3QgbW9kYWxDb250ZW50ID0gdGhpcy5tb2RhbCA/IHRoaXMubW9kYWwubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKFwiLmNkcy0tbW9kYWwtY29udGVudFwiKSA6IG51bGw7XG5cdFx0Y29uc3Qgc2hvd1Njcm9sbGJhciA9IHRoaXMuaGFzU2Nyb2xsaW5nQ29udGVudCAhPT0gbnVsbCA/IHRoaXMuaGFzU2Nyb2xsaW5nQ29udGVudCA6IHRoaXMuc2hvdWxkU2hvd1Njcm9sbGJhcjtcblx0XHRpZiAobW9kYWxDb250ZW50KSB7XG5cdFx0XHRpZiAoc2hvd1Njcm9sbGJhcikge1xuXHRcdFx0XHR0aGlzLnJlbmRlcmVyLmFkZENsYXNzKG1vZGFsQ29udGVudCwgXCJjZHMtLW1vZGFsLXNjcm9sbC1jb250ZW50XCIpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5yZW5kZXJlci5yZW1vdmVDbGFzcyhtb2RhbENvbnRlbnQsIFwiY2RzLS1tb2RhbC1zY3JvbGwtY29udGVudFwiKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn1cbiJdfQ==