carbon-components-angular
Version:
Next generation components
296 lines • 29.3 kB
JavaScript
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==