UNPKG

carbon-components-angular

Version:
306 lines (304 loc) 31.7 kB
import { ChangeDetectionStrategy, Component, ContentChildren, EventEmitter, HostBinding, Input, Output, ViewChild } from "@angular/core"; import { autoUpdate, computePosition, flip } from "@floating-ui/dom"; import { ContextMenuItemComponent } from "carbon-components-angular/context-menu"; import * as i0 from "@angular/core"; import * as i1 from "carbon-components-angular/button"; import * as i2 from "carbon-components-angular/icon"; import * as i3 from "carbon-components-angular/context-menu"; export class ComboButtonComponent { constructor(ngZone, renderer, hostElement, viewContainerRef, changeDetectorRef) { this.ngZone = ngZone; this.renderer = renderer; this.hostElement = hostElement; this.viewContainerRef = viewContainerRef; this.changeDetectorRef = changeDetectorRef; this.comboId = `combo-button-${ComboButtonComponent.comboButtonCounter++}`; this.size = "lg"; this.disabled = false; this.menuAlignment = "bottom"; this.tooltipAutoAlign = false; this.tooltipPlacement = "bottom"; this.open = false; this.actionClick = new EventEmitter(); this.comboButtonContainer = true; this.documentClick = this.handleFocusOut.bind(this); this.subscriptions = []; this._alignment = "bottom"; } // Listen for click & determine if menu should close set projectedMenuItems(itemList) { // Reset in case user dynamically updates menu item this.subscriptions.forEach((sub) => sub?.unsubscribe()); this.subscriptions = []; itemList.forEach((item) => { this.subscriptions.push(item.itemClick.subscribe((clickEvent) => this.handleMenuItemClick(clickEvent))); }); } get sizeLg() { return this.size === "lg"; } get sizeMd() { return this.size === "md"; } get sizeSm() { return this.size === "sm"; } get sizeXs() { return this.size === "xs"; } get ariaOwns() { return this.open ? this.comboId : undefined; } /** * In case user updates alignment, store initial value. * This allows us to test user passed alignment on each open */ ngOnChanges(changes) { if (changes.menuAlignment) { this._alignment = changes.menuAlignment.currentValue; } } /** * If user has passed in true for open, we dynamically open the menu */ ngAfterViewInit() { if (this.open) { this.open = !this.open; this.toggleMenu(); } } /** * Clean up Floating-ui & subscriptions */ ngOnDestroy() { this.cleanUp(); this.subscriptions.forEach((sub) => sub.unsubscribe()); } /** * As of now, menu button does not support nexted menu, on button click it should close */ handleMenuItemClick(event) { // If event is not type radio/checkbox, we close the menu if (!event.type) { this.toggleMenu(); } } /** * On body click, close the menu * @param event */ handleFocusOut(event) { if (!this.hostElement.nativeElement.contains(event.target)) { this.toggleMenu(); } } /** * Clean up `autoUpdate` if auto alignment is enabled */ cleanUp() { document.removeEventListener("click", this.documentClick); if (this.unmountFloatingElement) { this.menuRef.remove(); this.viewContainerRef.clear(); this.unmountFloatingElement(); } this.unmountFloatingElement = undefined; // On all instances of menu closing, make sure icon direction is correct this.changeDetectorRef.markForCheck(); } /** * On action click, notify user * If the menu is open, close the menu * @param event */ onActionClick(event) { if (this.open) { this.toggleMenu(); } this.actionClick.emit(event); } /** * Handles emitting open/close event */ toggleMenu() { this.open = !this.open; if (this.open) { // Render the template & append to view const view = this.viewContainerRef.createEmbeddedView(this.menuTemplate); this.menuRef = document.body.appendChild(view.rootNodes[0]); // Assign button width to the menu ref to align with button Object.assign(this.menuRef.style, { width: `${this.hostElement.nativeElement.clientWidth}px`, top: "0", left: "0" }); // Reset & test alignment every open this.menuAlignment = this._alignment; document.addEventListener("click", this.documentClick); // Listen for events such as scrolling to keep menu aligned this.unmountFloatingElement = autoUpdate(this.hostElement.nativeElement, this.menuRef, this.recomputePosition.bind(this)); } else { this.cleanUp(); } } roundByDPR(value) { const dpr = window.devicePixelRatio || 1; return Math.round(value * dpr) / dpr; } /** * Compute position of menu */ recomputePosition() { if (this.menuTemplate && this.hostElement) { // Run outside of angular zone to avoid unnecessary change detection and rely on floating-ui this.ngZone.runOutsideAngular(async () => { const { x, y, placement } = await computePosition(this.hostElement.nativeElement, this.menuRef, { placement: this.menuAlignment, strategy: "fixed", middleware: [ flip({ crossAxis: false }) ] }); this.menuAlignment = placement; // Using CSSOM to manipulate CSS to avoid content security policy inline-src // https://github.com/w3c/webappsec-csp/issues/212 Object.assign(this.menuRef.style, { position: "fixed", // Using transform instead of top/left position to improve performance transform: `translate(${this.roundByDPR(x)}px,${this.roundByDPR(y)}px)` }); this.changeDetectorRef.markForCheck(); }); } } } ComboButtonComponent.comboButtonCounter = 0; ComboButtonComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ComboButtonComponent, deps: [{ token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); ComboButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: ComboButtonComponent, selector: "cds-combo-button", inputs: { comboId: "comboId", size: "size", label: "label", disabled: "disabled", menuAlignment: "menuAlignment", description: "description", tooltipAutoAlign: "tooltipAutoAlign", tooltipPlacement: "tooltipPlacement", open: "open" }, outputs: { actionClick: "actionClick" }, host: { properties: { "class.cds--combo-button__container--open": "this.open", "class.cds--combo-button__container": "this.comboButtonContainer", "class.cds--combo-button__container--lg": "this.sizeLg", "class.cds--combo-button__container--md": "this.sizeMd", "class.cds--combo-button__container--sm": "this.sizeSm", "class.cds--combo-button__container--xs": "this.sizeXs", "attr.aria-owns": "this.ariaOwns" } }, queries: [{ propertyName: "projectedMenuItems", predicate: ContextMenuItemComponent }], viewQueries: [{ propertyName: "menuTemplate", first: true, predicate: ["menuTemplate"], descendants: true }], usesOnChanges: true, ngImport: i0, template: ` <div class="cds--combo-button__primary-action" [attr.aria-owns]="open ? comboId : undefined"> <button cdsButton="primary" [size]="size" [attr.title]="label" [disabled]="disabled" type="button" (click)="onActionClick($event)"> {{label}} </button> </div> <cds-icon-button [buttonNgClass]="{ 'cds--combo-button__trigger': true }" [buttonAttributes]="{ 'aria-haspopup': true, 'aria-expanded': open, 'aria-controls': open ? comboId : undefined }" [size]="size" [description]="description" [disabled]="disabled" [autoAlign]="tooltipAutoAlign" [align]="tooltipPlacement" (click)="toggleMenu()"> <svg cdsIcon="chevron--down" size="16"> </svg> </cds-icon-button> <ng-template #menuTemplate> <cds-menu mode="basic" [size]="size" [open]="open" [attr.id]="comboId"> <ng-content select="cds-menu-item, cds-menu-divider"></ng-content> </cds-menu> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: i1.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "component", type: i1.IconButton, selector: "cds-icon-button, ibm-icon-button", inputs: ["buttonNgClass", "buttonAttributes", "buttonId", "kind", "size", "type", "isExpressive", "disabled", "description", "showTooltipWhenDisabled"], outputs: ["click", "focus", "blur", "tooltipClick"] }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "component", type: i3.ContextMenuComponent, selector: "cds-menu, cds-context-menu, ibm-context-menu", inputs: ["open", "position", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ComboButtonComponent, decorators: [{ type: Component, args: [{ selector: "cds-combo-button", template: ` <div class="cds--combo-button__primary-action" [attr.aria-owns]="open ? comboId : undefined"> <button cdsButton="primary" [size]="size" [attr.title]="label" [disabled]="disabled" type="button" (click)="onActionClick($event)"> {{label}} </button> </div> <cds-icon-button [buttonNgClass]="{ 'cds--combo-button__trigger': true }" [buttonAttributes]="{ 'aria-haspopup': true, 'aria-expanded': open, 'aria-controls': open ? comboId : undefined }" [size]="size" [description]="description" [disabled]="disabled" [autoAlign]="tooltipAutoAlign" [align]="tooltipPlacement" (click)="toggleMenu()"> <svg cdsIcon="chevron--down" size="16"> </svg> </cds-icon-button> <ng-template #menuTemplate> <cds-menu mode="basic" [size]="size" [open]="open" [attr.id]="comboId"> <ng-content select="cds-menu-item, cds-menu-divider"></ng-content> </cds-menu> </ng-template> `, changeDetection: ChangeDetectionStrategy.OnPush }] }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { comboId: [{ type: Input }], projectedMenuItems: [{ type: ContentChildren, args: [ContextMenuItemComponent] }], size: [{ type: Input }], label: [{ type: Input }], disabled: [{ type: Input }], menuAlignment: [{ type: Input }], description: [{ type: Input }], tooltipAutoAlign: [{ type: Input }], tooltipPlacement: [{ type: Input }], open: [{ type: Input }, { type: HostBinding, args: ["class.cds--combo-button__container--open"] }], actionClick: [{ type: Output }], comboButtonContainer: [{ type: HostBinding, args: ["class.cds--combo-button__container"] }], sizeLg: [{ type: HostBinding, args: ["class.cds--combo-button__container--lg"] }], sizeMd: [{ type: HostBinding, args: ["class.cds--combo-button__container--md"] }], sizeSm: [{ type: HostBinding, args: ["class.cds--combo-button__container--sm"] }], sizeXs: [{ type: HostBinding, args: ["class.cds--combo-button__container--xs"] }], ariaOwns: [{ type: HostBinding, args: ["attr.aria-owns"] }], menuTemplate: [{ type: ViewChild, args: ["menuTemplate"] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tYm8tYnV0dG9uLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb21iby1idXR0b24vY29tYm8tYnV0dG9uLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRU4sdUJBQXVCLEVBRXZCLFNBQVMsRUFDVCxlQUFlLEVBRWYsWUFBWSxFQUNaLFdBQVcsRUFDWCxLQUFLLEVBSUwsTUFBTSxFQUtOLFNBQVMsRUFFVCxNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQ04sVUFBVSxFQUNWLGVBQWUsRUFDZixJQUFJLEVBQ0osTUFBTSxrQkFBa0IsQ0FBQztBQUMxQixPQUFPLEVBQUUsd0JBQXdCLEVBQWtCLE1BQU0sd0NBQXdDLENBQUM7Ozs7O0FBaURsRyxNQUFNLE9BQU8sb0JBQW9CO0lBMkNoQyxZQUNXLE1BQWMsRUFDZCxRQUFtQixFQUNuQixXQUF1QixFQUN2QixnQkFBa0MsRUFDbEMsaUJBQW9DO1FBSnBDLFdBQU0sR0FBTixNQUFNLENBQVE7UUFDZCxhQUFRLEdBQVIsUUFBUSxDQUFXO1FBQ25CLGdCQUFXLEdBQVgsV0FBVyxDQUFZO1FBQ3ZCLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBa0I7UUFDbEMsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjtRQTlDdEMsWUFBTyxHQUFHLGdCQUFnQixvQkFBb0IsQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLENBQUM7UUFjdEUsU0FBSSxHQUE4QixJQUFJLENBQUM7UUFFdkMsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUNqQixrQkFBYSxHQUF5QixRQUFRLENBQUM7UUFFL0MscUJBQWdCLEdBQUcsS0FBSyxDQUFDO1FBQ3pCLHFCQUFnQixHQUFHLFFBQVEsQ0FBQztRQUM2QixTQUFJLEdBQUcsS0FBSyxDQUFDO1FBQ3JFLGdCQUFXLEdBQUcsSUFBSSxZQUFZLEVBQVMsQ0FBQztRQUNDLHlCQUFvQixHQUFHLElBQUksQ0FBQztRQVdy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O3NCQUFoRSxXQUFXO3VCQUFDLHdDQUF3QztnQkFDTSxNQUFNO3NCQUFoRSxXQUFXO3VCQUFDLHdDQUF3QztnQkFDTSxNQUFNO3NCQUFoRSxXQUFXO3VCQUFDLHdDQUF3QztnQkFDbEIsUUFBUTtzQkFBMUMsV0FBVzt1QkFBQyxnQkFBZ0I7Z0JBSUYsWUFBWTtzQkFBdEMsU0FBUzt1QkFBQyxjQUFjIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0QWZ0ZXJWaWV3SW5pdCxcblx0Q2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG5cdENoYW5nZURldGVjdG9yUmVmLFxuXHRDb21wb25lbnQsXG5cdENvbnRlbnRDaGlsZHJlbixcblx0RWxlbWVudFJlZixcblx0RXZlbnRFbWl0dGVyLFxuXHRIb3N0QmluZGluZyxcblx0SW5wdXQsXG5cdE5nWm9uZSxcblx0T25DaGFuZ2VzLFxuXHRPbkRlc3Ryb3ksXG5cdE91dHB1dCxcblx0UXVlcnlMaXN0LFxuXHRSZW5kZXJlcjIsXG5cdFNpbXBsZUNoYW5nZXMsXG5cdFRlbXBsYXRlUmVmLFxuXHRWaWV3Q2hpbGQsXG5cdFZpZXdDb250YWluZXJSZWZcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQge1xuXHRhdXRvVXBkYXRlLFxuXHRjb21wdXRlUG9zaXRpb24sXG5cdGZsaXBcbn0gZnJvbSBcIkBmbG9hdGluZy11aS9kb21cIjtcbmltcG9ydCB7IENvbnRleHRNZW51SXRlbUNvbXBvbmVudCwgSXRlbUNsaWNrRXZlbnQgfSBmcm9tIFwiY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhci9jb250ZXh0LW1lbnVcIjtcblxudHlwZSBDb21ib0J1dHRvblBsYWNlbWVudCA9IFwidG9wXCIgfCBcInRvcC1zdGFydFwiIHwgXCJ0b3AtZW5kXCIgfCBcImJvdHRvbVwiIHwgXCJib3R0b20tc3RhcnRcIiB8IFwiYm90dG9tLWVuZFwiO1xuXG5AQ29tcG9uZW50KHtcblx0c2VsZWN0b3I6IFwiY2RzLWNvbWJvLWJ1dHRvblwiLFxuXHR0ZW1wbGF0ZTogYFxuXHRcdDxkaXYgY2xhc3M9XCJjZHMtLWNvbWJvLWJ1dHRvbl9fcHJpbWFyeS1hY3Rpb25cIiBbYXR0ci5hcmlhLW93bnNdPVwib3BlbiA/IGNvbWJvSWQgOiB1bmRlZmluZWRcIj5cblx0XHRcdDxidXR0b25cblx0XHRcdFx0Y2RzQnV0dG9uPVwicHJpbWFyeVwiXG5cdFx0XHRcdFtzaXplXT1cInNpemVcIlxuXHRcdFx0XHRbYXR0ci50aXRsZV09XCJsYWJlbFwiXG5cdFx0XHRcdFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiXG5cdFx0XHRcdHR5cGU9XCJidXR0b25cIlxuXHRcdFx0XHQoY2xpY2spPVwib25BY3Rpb25DbGljaygkZXZlbnQpXCI+XG5cdFx0XHRcdHt7bGFiZWx9fVxuXHRcdFx0PC9idXR0b24+XG5cdFx0PC9kaXY+XG5cdFx0PGNkcy1pY29uLWJ1dHRvblxuXHRcdFx0W2J1dHRvbk5nQ2xhc3NdPVwieyAnY2RzLS1jb21iby1idXR0b25fX3RyaWdnZXInOiB0cnVlIH1cIlxuXHRcdFx0W2J1dHRvbkF0dHJpYnV0ZXNdPVwie1xuXHRcdFx0XHQnYXJpYS1oYXNwb3B1cCc6IHRydWUsXG5cdFx0XHRcdCdhcmlhLWV4cGFuZGVkJzogb3Blbixcblx0XHRcdFx0J2FyaWEtY29udHJvbHMnOiBvcGVuID8gY29tYm9JZCA6IHVuZGVmaW5lZFxuXHRcdFx0fVwiXG5cdFx0XHRbc2l6ZV09XCJzaXplXCJcblx0XHRcdFtkZXNjcmlwdGlvbl09XCJkZXNjcmlwdGlvblwiXG5cdFx0XHRbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIlxuXHRcdFx0W2F1dG9BbGlnbl09XCJ0b29sdGlwQXV0b0FsaWduXCJcblx0XHRcdFthbGlnbl09XCJ0b29sdGlwUGxhY2VtZW50XCJcblx0XHRcdChjbGljayk9XCJ0b2dnbGVNZW51KClcIj5cblx0XHRcdDxzdmdcblx0XHRcdFx0Y2RzSWNvbj1cImNoZXZyb24tLWRvd25cIlxuXHRcdFx0XHRzaXplPVwiMTZcIj5cblx0XHRcdDwvc3ZnPlxuXHRcdDwvY2RzLWljb24tYnV0dG9uPlxuXG5cdFx0PG5nLXRlbXBsYXRlICNtZW51VGVtcGxhdGU+XG5cdFx0XHQ8Y2RzLW1lbnVcblx0XHRcdFx0bW9kZT1cImJhc2ljXCJcblx0XHRcdFx0W3NpemVdPVwic2l6ZVwiXG5cdFx0XHRcdFtvcGVuXT1cIm9wZW5cIlxuXHRcdFx0XHRbYXR0ci5pZF09XCJjb21ib0lkXCI+XG5cdFx0XHRcdDxuZy1jb250ZW50IHNlbGVjdD1cImNkcy1tZW51LWl0ZW0sIGNkcy1tZW51LWRpdmlkZXJcIj48L25nLWNvbnRlbnQ+XG5cdFx0XHQ8L2Nkcy1tZW51PlxuXHRcdDwvbmctdGVtcGxhdGU+XG5cdGAsXG5cdGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoXG59KVxuZXhwb3J0IGNsYXNzIENvbWJvQnV0dG9uQ29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzLCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xuXHRzdGF0aWMgY29tYm9CdXR0b25Db3VudGVyID0gMDtcblx0QElucHV0KCkgY29tYm9JZCA9IGBjb21iby1idXR0b24tJHtDb21ib0J1dHRvbkNvbXBvbmVudC5jb21ib0J1dHRvbkNvdW50ZXIrK31gO1xuXG5cdC8vIExpc3RlbiBmb3IgY2xpY2sgJiBkZXRlcm1pbmUgaWYgbWVudSBzaG91bGQgY2xvc2Vcblx0QENvbnRlbnRDaGlsZHJlbihDb250ZXh0TWVudUl0ZW1Db21wb25lbnQpIHNldCBwcm9qZWN0ZWRNZW51SXRlbXMoaXRlbUxpc3Q6IFF1ZXJ5TGlzdDxDb250ZXh0TWVudUl0ZW1Db21wb25lbnQ+KSB7XG5cdFx0Ly8gUmVzZXQgaW4gY2FzZSB1c2VyIGR5bmFtaWNhbGx5IHVwZGF0ZXMgbWVudSBpdGVtXG5cdFx0dGhpcy5zdWJzY3JpcHRpb25zLmZvckVhY2goKHN1YikgPT4gc3ViPy51bnN1YnNjcmliZSgpKTtcblx0XHR0aGlzLnN1YnNjcmlwdGlvbnMgPSBbXTtcblx0XHRpdGVtTGlzdC5mb3JFYWNoKChpdGVtKSA9PiB7XG5cdFx0XHR0aGlzLnN1YnNjcmlwdGlvbnMucHVzaChcblx0XHRcdFx0aXRlbS5pdGVtQ2xpY2suc3Vic2NyaWJlKChjbGlja0V2ZW50KSA9PiB0aGlzLmhhbmRsZU1lbnVJdGVtQ2xpY2soY2xpY2tFdmVudCkpXG5cdFx0XHQpO1xuXHRcdH0pO1xuXHR9XG5cblx0QElucHV0KCkgc2l6ZTogXCJ4c1wiIHwgXCJzbVwiIHwgXCJtZFwiIHwgXCJsZ1wiID0gXCJsZ1wiO1xuXHRASW5wdXQoKSBsYWJlbDogc3RyaW5nO1xuXHRASW5wdXQoKSBkaXNhYmxlZCA9IGZhbHNlO1xuXHRASW5wdXQoKSBtZW51QWxpZ25tZW50OiBDb21ib0J1dHRvblBsYWNlbWVudCA9IFwiYm90dG9tXCI7XG5cdEBJbnB1dCgpIGRlc2NyaXB0aW9uOiBzdHJpbmc7XG5cdEBJbnB1dCgpIHRvb2x0aXBBdXRvQWxpZ24gPSBmYWxzZTtcblx0QElucHV0KCkgdG9vbHRpcFBsYWNlbWVudCA9IFwiYm90dG9tXCI7XG5cdEBJbnB1dCgpIEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tY29tYm8tYnV0dG9uX19jb250YWluZXItLW9wZW5cIikgb3BlbiA9IGZhbHNlO1xuXHRAT3V0cHV0KCkgYWN0aW9uQ2xpY2sgPSBuZXcgRXZlbnRFbWl0dGVyPEV2ZW50PigpO1xuXHRASG9zdEJpbmRpbmcoXCJjbGFzcy5jZHMtLWNvbWJvLWJ1dHRvbl9fY29udGFpbmVyXCIpIGNvbWJvQnV0dG9uQ29udGFpbmVyID0gdHJ1ZTtcblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1jb21iby1idXR0b25fX2NvbnRhaW5lci0tbGdcIikgZ2V0IHNpemVMZygpIHsgcmV0dXJuIHRoaXMuc2l6ZSA9PT0gXCJsZ1wiOyB9XG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tY29tYm8tYnV0dG9uX19jb250YWluZXItLW1kXCIpIGdldCBzaXplTWQoKSB7IHJldHVybiB0aGlzLnNpemUgPT09IFwibWRcIjsgfVxuXHRASG9zdEJpbmRpbmcoXCJjbGFzcy5jZHMtLWNvbWJvLWJ1dHRvbl9fY29udGFpbmVyLS1zbVwiKSBnZXQgc2l6ZVNtKCkgeyByZXR1cm4gdGhpcy5zaXplID09PSBcInNtXCI7IH1cblx0QEhvc3RCaW5kaW5nKFwiY2xhc3MuY2RzLS1jb21iby1idXR0b25fX2NvbnRhaW5lci0teHNcIikgZ2V0IHNpemVYcygpIHsgcmV0dXJuIHRoaXMuc2l6ZSA9PT0gXCJ4c1wiOyB9XG5cdEBIb3N0QmluZGluZyhcImF0dHIuYXJpYS1vd25zXCIpIGdldCBhcmlhT3ducygpIHtcblx0XHRyZXR1cm4gdGhpcy5vcGVuID8gdGhpcy5jb21ib0lkIDogdW5kZWZpbmVkO1xuXHR9XG5cblx0QFZpZXdDaGlsZChcIm1lbnVUZW1wbGF0ZVwiKSBtZW51VGVtcGxhdGU6IFRlbXBsYXRlUmVmPGFueT47XG5cblx0cHJvdGVjdGVkIGRvY3VtZW50Q2xpY2sgPSB0aGlzLmhhbmRsZUZvY3VzT3V0LmJpbmQodGhpcyk7XG5cdHByb3RlY3RlZCB1bm1vdW50RmxvYXRpbmdFbGVtZW50OiBGdW5jdGlvbjtcblxuXHRwcml2YXRlIHN1YnNjcmlwdGlvbnM6IFN1YnNjcmlwdGlvbltdID0gW107XG5cdHByaXZhdGUgX2FsaWdubWVudDogQ29tYm9CdXR0b25QbGFjZW1lbnQgPSBcImJvdHRvbVwiO1xuXHRwcml2YXRlIG1lbnVSZWY6IEhUTUxFbGVtZW50O1xuXG5cdGNvbnN0cnVjdG9yKFxuXHRcdHByb3RlY3RlZCBuZ1pvbmU6IE5nWm9uZSxcblx0XHRwcm90ZWN0ZWQgcmVuZGVyZXI6IFJlbmRlcmVyMixcblx0XHRwcm90ZWN0ZWQgaG9zdEVsZW1lbnQ6IEVsZW1lbnRSZWYsXG5cdFx0cHJvdGVjdGVkIHZpZXdDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWYsXG5cdFx0cHJvdGVjdGVkIGNoYW5nZURldGVjdG9yUmVmOiBDaGFuZ2VEZXRlY3RvclJlZlxuXHQpIHsgfVxuXG5cblx0LyoqXG5cdCAqIEluIGNhc2UgdXNlciB1cGRhdGVzIGFsaWdubWVudCwgc3RvcmUgaW5pdGlhbCB2YWx1ZS5cblx0ICogVGhpcyBhbGxvd3MgdXMgdG8gdGVzdCB1c2VyIHBhc3NlZCBhbGlnbm1lbnQgb24gZWFjaCBvcGVuXG5cdCAqL1xuXHRuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG5cdFx0aWYgKGNoYW5nZXMubWVudUFsaWdubWVudCkge1xuXHRcdFx0dGhpcy5fYWxpZ25tZW50ID0gY2hhbmdlcy5tZW51QWxpZ25tZW50LmN1cnJlbnRWYWx1ZTtcblx0XHR9XG5cdH1cblxuXG5cblx0LyoqXG5cdCAqIElmIHVzZXIgaGFzIHBhc3NlZCBpbiB0cnVlIGZvciBvcGVuLCB3ZSBkeW5hbWljYWxseSBvcGVuIHRoZSBtZW51XG5cdCAqL1xuXHRuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG5cdFx0aWYgKHRoaXMub3Blbikge1xuXHRcdFx0dGhpcy5vcGVuID0gIXRoaXMub3Blbjtcblx0XHRcdHRoaXMudG9nZ2xlTWVudSgpO1xuXHRcdH1cblx0fVxuXG5cblxuXHQvKipcblx0KiBDbGVhbiB1cCBGbG9hdGluZy11aSAmIHN1YnNjcmlwdGlvbnNcblx0Ki9cblx0bmdPbkRlc3Ryb3koKTogdm9pZCB7XG5cdFx0dGhpcy5jbGVhblVwKCk7XG5cdFx0dGhpcy5zdWJzY3JpcHRpb25zLmZvckVhY2goKHN1YikgPT4gc3ViLnVuc3Vic2NyaWJlKCkpO1xuXHR9XG5cblxuXHQvKipcblx0ICogQXMgb2Ygbm93LCBtZW51IGJ1dHRvbiBkb2VzIG5vdCBzdXBwb3J0IG5leHRlZCBtZW51LCBvbiBidXR0b24gY2xpY2sgaXQgc2hvdWxkIGNsb3NlXG5cdCAqL1xuXHRoYW5kbGVNZW51SXRlbUNsaWNrKGV2ZW50OiBJdGVtQ2xpY2tFdmVudCkge1xuXHRcdC8vIElmIGV2ZW50IGlzIG5vdCB0eXBlIHJhZGlvL2NoZWNrYm94LCB3ZSBjbG9zZSB0aGUgbWVudVxuXHRcdGlmICghZXZlbnQudHlwZSkge1xuXHRcdFx0dGhpcy50b2dnbGVNZW51KCk7XG5cdFx0fVxuXHR9XG5cblxuXG5cdC8qKlxuXHQgKiBPbiBib2R5IGNsaWNrLCBjbG9zZSB0aGUgbWVudVxuXHQgKiBAcGFyYW0gZXZlbnRcblx0ICovXG5cdGhhbmRsZUZvY3VzT3V0KGV2ZW50KSB7XG5cdFx0aWYgKCF0aGlzLmhvc3RFbGVtZW50Lm5hdGl2ZUVsZW1lbnQuY29udGFpbnMoZXZlbnQudGFyZ2V0KSkge1xuXHRcdFx0dGhpcy50b2dnbGVNZW51KCk7XG5cdFx0fVxuXHR9XG5cblxuXG5cdC8qKlxuXHQgKiBDbGVhbiB1cCBgYXV0b1VwZGF0ZWAgaWYgYXV0byBhbGlnbm1lbnQgaXMgZW5hYmxlZFxuXHQgKi9cblx0Y2xlYW5VcCgpIHtcblx0XHRkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgdGhpcy5kb2N1bWVudENsaWNrKTtcblx0XHRpZiAodGhpcy51bm1vdW50RmxvYXRpbmdFbGVtZW50KSB7XG5cdFx0XHR0aGlzLm1lbnVSZWYucmVtb3ZlKCk7XG5cdFx0XHR0aGlzLnZpZXdDb250YWluZXJSZWYuY2xlYXIoKTtcblx0XHRcdHRoaXMudW5tb3VudEZsb2F0aW5nRWxlbWVudCgpO1xuXHRcdH1cblx0XHR0aGlzLnVubW91bnRGbG9hdGluZ0VsZW1lbnQgPSB1bmRlZmluZWQ7XG5cdFx0Ly8gT24gYWxsIGluc3RhbmNlcyBvZiBtZW51IGNsb3NpbmcsIG1ha2Ugc3VyZSBpY29uIGRpcmVjdGlvbiBpcyBjb3JyZWN0XG5cdFx0dGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcblx0fVxuXG5cblx0LyoqXG5cdCAqIE9uIGFjdGlvbiBjbGljaywgbm90aWZ5IHVzZXJcblx0ICogSWYgdGhlIG1lbnUgaXMgb3BlbiwgY2xvc2UgdGhlIG1lbnVcblx0ICogQHBhcmFtIGV2ZW50XG5cdCAqL1xuXHRvbkFjdGlvbkNsaWNrKGV2ZW50OiBQb2ludGVyRXZlbnQpIHtcblx0XHRpZiAodGhpcy5vcGVuKSB7XG5cdFx0XHR0aGlzLnRvZ2dsZU1lbnUoKTtcblx0XHR9XG5cdFx0dGhpcy5hY3Rpb25DbGljay5lbWl0KGV2ZW50KTtcblx0fVxuXG5cblxuXHQvKipcblx0ICogSGFuZGxlcyBlbWl0dGluZyBvcGVuL2Nsb3NlIGV2ZW50XG5cdCAqL1xuXHR0b2dnbGVNZW51KCkge1xuXHRcdHRoaXMub3BlbiA9ICF0aGlzLm9wZW47XG5cdFx0aWYgKHRoaXMub3Blbikge1xuXHRcdFx0Ly8gUmVuZGVyIHRoZSB0ZW1wbGF0ZSAmIGFwcGVuZCB0byB2aWV3XG5cdFx0XHRjb25zdCB2aWV3ID0gdGhpcy52aWV3Q29udGFpbmVyUmVmLmNyZWF0ZUVtYmVkZGVkVmlldyh0aGlzLm1lbnVUZW1wbGF0ZSk7XG5cdFx0XHR0aGlzLm1lbnVSZWYgPSBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHZpZXcucm9vdE5vZGVzWzBdIGFzIEhUTUxFbGVtZW50KTtcblx0XHRcdC8vIEFzc2lnbiBidXR0b24gd2lkdGggdG8gdGhlIG1lbnUgcmVmIHRvIGFsaWduIHdpdGggYnV0dG9uXG5cdFx0XHRPYmplY3QuYXNzaWduKHRoaXMubWVudVJlZi5zdHlsZSwge1xuXHRcdFx0XHR3aWR0aDogYCR7dGhpcy5ob3N0RWxlbWVudC5uYXRpdmVFbGVtZW50LmNsaWVudFdpZHRofXB4YCxcblx0XHRcdFx0dG9wOiBcIjBcIixcblx0XHRcdFx0bGVmdDogXCIwXCJcblx0XHRcdH0pO1xuXG5cdFx0XHQvLyBSZXNldCAmIHRlc3QgYWxpZ25tZW50IGV2ZXJ5IG9wZW5cblx0XHRcdHRoaXMubWVudUFsaWdubWVudCA9IHRoaXMuX2FsaWdubWVudDtcblxuXHRcdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIHRoaXMuZG9jdW1lbnRDbGljayk7XG5cblx0XHRcdC8vIExpc3RlbiBmb3IgZXZlbnRzIHN1Y2ggYXMgc2Nyb2xsaW5nIHRvIGtlZXAgbWVudSBhbGlnbmVkXG5cdFx0XHR0aGlzLnVubW91bnRGbG9hdGluZ0VsZW1lbnQgPSBhdXRvVXBkYXRlKFxuXHRcdFx0XHR0aGlzLmhvc3RFbGVtZW50Lm5hdGl2ZUVsZW1lbnQsXG5cdFx0XHRcdHRoaXMubWVudVJlZixcblx0XHRcdFx0dGhpcy5yZWNvbXB1dGVQb3NpdGlvbi5iaW5kKHRoaXMpXG5cdFx0XHQpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmNsZWFuVXAoKTtcblx0XHR9XG5cdH1cblxuXG5cblx0cm91bmRCeURQUih2YWx1ZSkge1xuXHRcdGNvbnN0IGRwciA9IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvIHx8IDE7XG5cdFx0cmV0dXJuIE1hdGgucm91bmQodmFsdWUgKiBkcHIpIC8gZHByO1xuXHR9XG5cblxuXG5cdC8qKlxuXHQgKiBDb21wdXRlIHBvc2l0aW9uIG9mIG1lbnVcblx0ICovXG5cdHJlY29tcHV0ZVBvc2l0aW9uKCkge1xuXHRcdGlmICh0aGlzLm1lbnVUZW1wbGF0ZSAmJiB0aGlzLmhvc3RFbGVtZW50KSB7XG5cdFx0XHQvLyBSdW4gb3V0c2lkZSBvZiBhbmd1bGFyIHpvbmUgdG8gYXZvaWQgdW5uZWNlc3NhcnkgY2hhbmdlIGRldGVjdGlvbiBhbmQgcmVseSBvbiBmbG9hdGluZy11aVxuXHRcdFx0dGhpcy5uZ1pvbmUucnVuT3V0c2lkZUFuZ3VsYXIoYXN5bmMgKCkgPT4ge1xuXHRcdFx0XHRjb25zdCB7IHgsIHksIHBsYWNlbWVudCB9ID0gYXdhaXQgY29tcHV0ZVBvc2l0aW9uKFxuXHRcdFx0XHRcdHRoaXMuaG9zdEVsZW1lbnQubmF0aXZlRWxlbWVudCxcblx0XHRcdFx0XHR0aGlzLm1lbnVSZWYsXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0cGxhY2VtZW50OiB0aGlzLm1lbnVBbGlnbm1lbnQsXG5cdFx0XHRcdFx0XHRzdHJhdGVneTogXCJmaXhlZFwiLFxuXHRcdFx0XHRcdFx0bWlkZGxld2FyZTogW1xuXHRcdFx0XHRcdFx0XHRmbGlwKHsgY3Jvc3NBeGlzOiBmYWxzZSB9KVxuXHRcdFx0XHRcdFx0XVxuXHRcdFx0XHRcdH0pO1xuXG5cdFx0XHRcdHRoaXMubWVudUFsaWdubWVudCA9IHBsYWNlbWVudCBhcyBDb21ib0J1dHRvblBsYWNlbWVudDtcblxuXHRcdFx0XHQvLyBVc2luZyBDU1NPTSB0byBtYW5pcHVsYXRlIENTUyB0byBhdm9pZCBjb250ZW50IHNlY3VyaXR5IHBvbGljeSBpbmxpbmUtc3JjXG5cdFx0XHRcdC8vIGh0dHBzOi8vZ2l0aHViLmNvbS93M2Mvd2ViYXBwc2VjLWNzcC9pc3N1ZXMvMjEyXG5cdFx0XHRcdE9iamVjdC5hc3NpZ24odGhpcy5tZW51UmVmLnN0eWxlLCB7XG5cdFx0XHRcdFx0cG9zaXRpb246IFwiZml4ZWRcIixcblx0XHRcdFx0XHQvLyBVc2luZyB0cmFuc2Zvcm0gaW5zdGVhZCBvZiB0b3AvbGVmdCBwb3NpdGlvbiB0byBpbXByb3ZlIHBlcmZvcm1hbmNlXG5cdFx0XHRcdFx0dHJhbnNmb3JtOiBgdHJhbnNsYXRlKCR7dGhpcy5yb3VuZEJ5RFBSKHgpfXB4LCR7dGhpcy5yb3VuZEJ5RFBSKHkpfXB4KWBcblx0XHRcdFx0fSk7XG5cdFx0XHRcdHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYubWFya0ZvckNoZWNrKCk7XG5cdFx0XHR9KTtcblx0XHR9XG5cdH1cbn1cbiJdfQ==