carbon-components-angular
Version:
Next generation components
328 lines • 37.7 kB
JavaScript
import { Component, Input, HostListener, HostBinding, ViewChild, ContentChildren, ViewChildren } from "@angular/core";
import { BaseTabHeader } from "./base-tab-header.component";
import { Tab } from "./tab.component";
import * as i0 from "@angular/core";
import * as i1 from "carbon-components-angular/utils";
import * as i2 from "carbon-components-angular/i18n";
import * as i3 from "@angular/common";
const VERTICAL_TAB_HEIGHT = 64;
/**
* The `TabHeadersVertical` component renders tab headers in a vertical
* orientation. It contains the `Tab` items and supports keyboard navigation
* via ArrowUp/ArrowDown/Home/End.
*/
export class TabHeadersVertical extends BaseTabHeader {
constructor(elementRef, changeDetectorRef, eventService, renderer, i18n) {
super(elementRef, changeDetectorRef, eventService, renderer);
this.elementRef = elementRef;
this.changeDetectorRef = changeDetectorRef;
this.eventService = eventService;
this.renderer = renderer;
this.i18n = i18n;
/**
* i18n strings for the tab list `aria-label` fallback.
*/
this.translations = this.i18n.get().TABS;
this.verticalClass = true;
/**
* Focused tab index when `followFocus` is false (manual activation)
*/
this.activeIndex = null;
/**
* Whether the tab list is overflowing at the top (some tabs are clipped).
*/
this.isOverflowingTop = false;
/**
* Whether the tab list is overflowing at the bottom (some tabs are clipped).
*/
this.isOverflowingBottom = false;
this.listScrollHandler = () => this.updateOverflowState();
this.type = "contained";
}
keyboardInput(event) {
if (!this.tabs) {
return;
}
const tabsArray = this.tabs.toArray();
const enabledTabs = tabsArray.filter(tab => !tab.disabled);
if (enabledTabs.length === 0) {
return;
}
const referenceIndex = this.followFocus ?
this.currentSelectedTab :
(this.activeIndex !== null ? this.activeIndex : this.currentSelectedTab);
const currentEnabledIndex = Math.max(0, enabledTabs.indexOf(tabsArray[referenceIndex]));
let nextEnabledIndex = currentEnabledIndex;
let handled = false;
if (event.key === "ArrowDown") {
nextEnabledIndex = (currentEnabledIndex + 1) % enabledTabs.length;
handled = true;
}
else if (event.key === "ArrowUp") {
nextEnabledIndex = (enabledTabs.length + currentEnabledIndex - 1) % enabledTabs.length;
handled = true;
}
else if (event.key === "Home") {
nextEnabledIndex = 0;
handled = true;
}
else if (event.key === "End") {
nextEnabledIndex = enabledTabs.length - 1;
handled = true;
}
if (handled) {
event.preventDefault();
const nextTab = enabledTabs[nextEnabledIndex];
const nextIndex = tabsArray.indexOf(nextTab);
if (this.followFocus) {
this.selectTab(nextTab, nextIndex);
}
else {
this.activeIndex = nextIndex;
}
this.allTabHeaders.toArray()[nextIndex].nativeElement.focus();
return;
}
if ((event.key === " " || event.key === "Spacebar") && !this.followFocus) {
const focusIndex = this.activeIndex !== null ? this.activeIndex : this.currentSelectedTab;
this.selectTab(tabsArray[focusIndex], focusIndex);
}
}
handleBlur(event) {
const relatedTarget = event.relatedTarget;
const container = this.headerContainer?.nativeElement;
if (container && relatedTarget && container.contains(relatedTarget)) {
return;
}
if (!this.followFocus) {
this.activeIndex = this.currentSelectedTab;
}
}
ngOnInit() {
this.resizeObserver = new ResizeObserver(() => {
this.updateOverflowState();
this.changeDetectorRef.detectChanges();
});
this.resizeObserver.observe(this.headerContainer.nativeElement);
this.headerContainer.nativeElement.addEventListener("scroll", this.listScrollHandler);
}
ngOnDestroy() {
this.resizeObserver?.unobserve(this.headerContainer.nativeElement);
this.headerContainer.nativeElement.removeEventListener("scroll", this.listScrollHandler);
}
ngAfterContentInit() {
if (!this.tabInput) {
this.tabs = this.tabQuery;
}
else {
this.tabs = this.tabInput;
}
this.tabs.forEach(tab => tab.cacheActive = this.cacheActive);
this.tabs.changes.subscribe(() => {
this.setFirstTab();
this.changeDetectorRef.markForCheck();
});
this.setFirstTab();
}
ngOnChanges(changes) {
if (this.tabs && changes.cacheActive) {
this.tabs.forEach(tab => tab.cacheActive = this.cacheActive);
}
}
onTabFocus(index) {
if (this.followFocus) {
this.currentSelectedTab = index;
}
else {
this.activeIndex = index;
}
this.scrollSelectedTabIntoView();
}
selectTab(tab, tabIndex) {
if (tab.disabled) {
return;
}
this.currentSelectedTab = tabIndex;
this.activeIndex = tabIndex;
this.tabs.forEach(_tab => _tab.active = false);
tab.active = true;
tab.doSelect();
this.scrollSelectedTabIntoView();
}
getSelectedTab() {
const selected = this.tabs.find(tab => tab.active);
if (selected) {
return selected;
}
return { headingIsTemplate: false, heading: "" };
}
updateOverflowState() {
const element = this.headerContainer?.nativeElement;
if (!element) {
return;
}
const halfTabHeight = VERTICAL_TAB_HEIGHT / 2;
this.isOverflowingBottom =
element.scrollTop + element.clientHeight + halfTabHeight <= element.scrollHeight;
this.isOverflowingTop = element.scrollTop > halfTabHeight;
this.changeDetectorRef.markForCheck();
}
scrollSelectedTabIntoView() {
const container = this.headerContainer?.nativeElement;
if (!container) {
return;
}
const selectedHeader = this.allTabHeaders?.toArray()[this.currentSelectedTab]?.nativeElement;
if (!selectedHeader) {
return;
}
const containerRect = container.getBoundingClientRect();
const selectedRect = selectedHeader.getBoundingClientRect();
const halfTabHeight = VERTICAL_TAB_HEIGHT / 2;
if (selectedRect.top - halfTabHeight < containerRect.top ||
selectedRect.top - containerRect.top + VERTICAL_TAB_HEIGHT + halfTabHeight > containerRect.height) {
container.scrollTo({
top: Math.max(0, (this.currentSelectedTab - 1) * VERTICAL_TAB_HEIGHT),
behavior: "smooth"
});
}
}
setFirstTab() {
setTimeout(() => {
let firstTab = this.tabs.find(tab => tab.active);
if (!firstTab && this.tabs.first) {
firstTab = this.tabs.first;
firstTab.active = true;
}
if (firstTab) {
this.currentSelectedTab = this.tabs.toArray().indexOf(firstTab);
this.activeIndex = this.currentSelectedTab;
firstTab.doSelect();
this.updateOverflowState();
}
});
}
}
TabHeadersVertical.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TabHeadersVertical, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i1.EventService }, { token: i0.Renderer2 }, { token: i2.I18n }], target: i0.ɵɵFactoryTarget.Component });
TabHeadersVertical.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: TabHeadersVertical, selector: "cds-tab-headers-vertical, ibm-tab-headers-vertical", inputs: { tabInput: ["tabs", "tabInput"], translations: "translations" }, host: { listeners: { "keydown": "keyboardInput($event)", "blur": "handleBlur($event)" }, properties: { "class.cds--tabs--vertical": "this.verticalClass" } }, queries: [{ propertyName: "tabQuery", predicate: Tab }], viewQueries: [{ propertyName: "headerContainer", first: true, predicate: ["tabList"], descendants: true, static: true }, { propertyName: "allTabHeaders", predicate: ["tabItem"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
<div *ngIf="isOverflowingTop" class="cds--tab--list-gradient_top"></div>
<div
#tabList
class="cds--tab--list"
role="tablist"
[attr.aria-label]="ariaLabel || translations.HEADER_ARIA_LABEL"
[attr.aria-labelledby]="ariaLabelledby || null">
<ng-container [ngTemplateOutlet]="contentBefore"></ng-container>
<button
*ngFor="let tab of tabs; let i = index;"
#tabItem
role="tab"
[attr.aria-selected]="tab.active"
[attr.tabindex]="(tab.active?0:-1)"
[attr.aria-controls]="tab.id"
[attr.aria-disabled]="tab.disabled"
[disabled]="tab.disabled"
[ngClass]="{
'cds--tabs__nav-item--selected': tab.active,
'cds--tabs__nav-item--disabled': tab.disabled
}"
class="cds--tabs__nav-item cds--tabs__nav-link"
type="button"
draggable="false"
id="{{tab.id}}-header"
[attr.title]="tab.title || (!tab.headingIsTemplate ? tab.heading : null)"
(focus)="onTabFocus(i)"
(click)="selectTab(tab, i)">
<div class="cds--tabs__nav-item-label-wrapper">
<span class="cds--tabs__nav-item-label">
<ng-container *ngIf="!tab.headingIsTemplate">
{{ tab.heading }}
</ng-container>
<ng-template
*ngIf="tab.headingIsTemplate"
[ngTemplateOutlet]="tab.heading"
[ngTemplateOutletContext]="{$implicit: tab.context}">
</ng-template>
</span>
</div>
</button>
<ng-container [ngTemplateOutlet]="contentAfter"></ng-container>
</div>
<div *ngIf="isOverflowingBottom" class="cds--tab--list-gradient_bottom"></div>
`, isInline: true, dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TabHeadersVertical, decorators: [{
type: Component,
args: [{
selector: "cds-tab-headers-vertical, ibm-tab-headers-vertical",
template: `
<div *ngIf="isOverflowingTop" class="cds--tab--list-gradient_top"></div>
<div
#tabList
class="cds--tab--list"
role="tablist"
[attr.aria-label]="ariaLabel || translations.HEADER_ARIA_LABEL"
[attr.aria-labelledby]="ariaLabelledby || null">
<ng-container [ngTemplateOutlet]="contentBefore"></ng-container>
<button
*ngFor="let tab of tabs; let i = index;"
#tabItem
role="tab"
[attr.aria-selected]="tab.active"
[attr.tabindex]="(tab.active?0:-1)"
[attr.aria-controls]="tab.id"
[attr.aria-disabled]="tab.disabled"
[disabled]="tab.disabled"
[ngClass]="{
'cds--tabs__nav-item--selected': tab.active,
'cds--tabs__nav-item--disabled': tab.disabled
}"
class="cds--tabs__nav-item cds--tabs__nav-link"
type="button"
draggable="false"
id="{{tab.id}}-header"
[attr.title]="tab.title || (!tab.headingIsTemplate ? tab.heading : null)"
(focus)="onTabFocus(i)"
(click)="selectTab(tab, i)">
<div class="cds--tabs__nav-item-label-wrapper">
<span class="cds--tabs__nav-item-label">
<ng-container *ngIf="!tab.headingIsTemplate">
{{ tab.heading }}
</ng-container>
<ng-template
*ngIf="tab.headingIsTemplate"
[ngTemplateOutlet]="tab.heading"
[ngTemplateOutletContext]="{$implicit: tab.context}">
</ng-template>
</span>
</div>
</button>
<ng-container [ngTemplateOutlet]="contentAfter"></ng-container>
</div>
<div *ngIf="isOverflowingBottom" class="cds--tab--list-gradient_bottom"></div>
`
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: i1.EventService }, { type: i0.Renderer2 }, { type: i2.I18n }]; }, propDecorators: { tabInput: [{
type: Input,
args: ["tabs"]
}], translations: [{
type: Input
}], verticalClass: [{
type: HostBinding,
args: ["class.cds--tabs--vertical"]
}], headerContainer: [{
type: ViewChild,
args: ["tabList", { static: true }]
}], tabQuery: [{
type: ContentChildren,
args: [Tab]
}], allTabHeaders: [{
type: ViewChildren,
args: ["tabItem"]
}], keyboardInput: [{
type: HostListener,
args: ["keydown", ["$event"]]
}], handleBlur: [{
type: HostListener,
args: ["blur", ["$event"]]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFiLWhlYWRlcnMtdmVydGljYWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RhYnMvdGFiLWhlYWRlcnMtdmVydGljYWwuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTixTQUFTLEVBRVQsS0FBSyxFQUNMLFlBQVksRUFDWixXQUFXLEVBQ1gsU0FBUyxFQUNULGVBQWUsRUFFZixZQUFZLEVBUVosTUFBTSxlQUFlLENBQUM7QUFJdkIsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzVELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7Ozs7QUFFdEMsTUFBTSxtQkFBbUIsR0FBRyxFQUFFLENBQUM7QUFFL0I7Ozs7R0FJRztBQWtESCxNQUFNLE9BQU8sa0JBQW1CLFNBQVEsYUFBYTtJQXlDcEQsWUFDVyxVQUFzQixFQUN0QixpQkFBb0MsRUFDcEMsWUFBMEIsRUFDMUIsUUFBbUIsRUFDbkIsSUFBVTtRQUVwQixLQUFLLENBQUMsVUFBVSxFQUFFLGlCQUFpQixFQUFFLFlBQVksRUFBRSxRQUFRLENBQUMsQ0FBQztRQU5uRCxlQUFVLEdBQVYsVUFBVSxDQUFZO1FBQ3RCLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBbUI7UUFDcEMsaUJBQVksR0FBWixZQUFZLENBQWM7UUFDMUIsYUFBUSxHQUFSLFFBQVEsQ0FBVztRQUNuQixTQUFJLEdBQUosSUFBSSxDQUFNO1FBdENyQjs7V0FFRztRQUNNLGlCQUFZLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUM7UUFFSCxrQkFBYSxHQUFHLElBQUksQ0FBQztRQVkvRDs7V0FFRztRQUNILGdCQUFXLEdBQWtCLElBQUksQ0FBQztRQUVsQzs7V0FFRztRQUNILHFCQUFnQixHQUFHLEtBQUssQ0FBQztRQUN6Qjs7V0FFRztRQUNILHdCQUFtQixH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QUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcblx0Q29tcG9uZW50LFxyXG5cdFF1ZXJ5TGlzdCxcclxuXHRJbnB1dCxcclxuXHRIb3N0TGlzdGVuZXIsXHJcblx0SG9zdEJpbmRpbmcsXHJcblx0Vmlld0NoaWxkLFxyXG5cdENvbnRlbnRDaGlsZHJlbixcclxuXHRBZnRlckNvbnRlbnRJbml0LFxyXG5cdFZpZXdDaGlsZHJlbixcclxuXHRFbGVtZW50UmVmLFxyXG5cdE9uQ2hhbmdlcyxcclxuXHRTaW1wbGVDaGFuZ2VzLFxyXG5cdE9uRGVzdHJveSxcclxuXHRPbkluaXQsXHJcblx0Q2hhbmdlRGV0ZWN0b3JSZWYsXHJcblx0UmVuZGVyZXIyXHJcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcclxuaW1wb3J0IHsgRXZlbnRTZXJ2aWNlIH0gZnJvbSBcImNhcmJvbi1jb21wb25lbnRzLWFuZ3VsYXIvdXRpbHNcIjtcclxuaW1wb3J0IHsgSTE4biB9IGZyb20gXCJjYXJib24tY29tcG9uZW50cy1hbmd1bGFyL2kxOG5cIjtcclxuXHJcbmltcG9ydCB7IEJhc2VUYWJIZWFkZXIgfSBmcm9tIFwiLi9iYXNlLXRhYi1oZWFkZXIuY29tcG9uZW50XCI7XHJcbmltcG9ydCB7IFRhYiB9IGZyb20gXCIuL3RhYi5jb21wb25lbnRcIjtcclxuXHJcbmNvbnN0IFZFUlRJQ0FMX1RBQl9IRUlHSFQgPSA2NDtcclxuXHJcbi8qKlxyXG4gKiBUaGUgYFRhYkhlYWRlcnNWZXJ0aWNhbGAgY29tcG9uZW50IHJlbmRlcnMgdGFiIGhlYWRlcnMgaW4gYSB2ZXJ0aWNhbFxyXG4gKiBvcmllbnRhdGlvbi4gSXQgY29udGFpbnMgdGhlIGBUYWJgIGl0ZW1zIGFuZCBzdXBwb3J0cyBrZXlib2FyZCBuYXZpZ2F0aW9uXHJcbiAqIHZpYSBBcnJvd1VwL0Fycm93RG93bi9Ib21lL0VuZC5cclxuICovXHJcbkBDb21wb25lbnQoe1xyXG5cdHNlbGVjdG9yOiBcImNkcy10YWItaGVhZGVycy12ZXJ0aWNhbCwgaWJtLXRhYi1oZWFkZXJzLXZlcnRpY2FsXCIsXHJcblx0dGVtcGxhdGU6IGBcclxuXHRcdDxkaXYgKm5nSWY9XCJpc092ZXJmbG93aW5nVG9wXCIgY2xhc3M9XCJjZHMtLXRhYi0tbGlzdC1ncmFkaWVudF90b3BcIj48L2Rpdj5cclxuXHRcdDxkaXZcclxuXHRcdFx0I3RhYkxpc3RcclxuXHRcdFx0Y2xhc3M9XCJjZHMtLXRhYi0tbGlzdFwiXHJcblx0XHRcdHJvbGU9XCJ0YWJsaXN0XCJcclxuXHRcdFx0W2F0dHIuYXJpYS1sYWJlbF09XCJhcmlhTGFiZWwgfHwgdHJhbnNsYXRpb25zLkhFQURFUl9BUklBX0xBQkVMXCJcclxuXHRcdFx0W2F0dHIuYXJpYS1sYWJlbGxlZGJ5XT1cImFyaWFMYWJlbGxlZGJ5IHx8IG51bGxcIj5cclxuXHRcdFx0PG5nLWNvbnRhaW5lciBbbmdUZW1wbGF0ZU91dGxldF09XCJjb250ZW50QmVmb3JlXCI+PC9uZy1jb250YWluZXI+XHJcblx0XHRcdDxidXR0b25cclxuXHRcdFx0XHQqbmdGb3I9XCJsZXQgdGFiIG9mIHRhYnM7IGxldCBpID0gaW5kZXg7XCJcclxuXHRcdFx0XHQjdGFiSXRlbVxyXG5cdFx0XHRcdHJvbGU9XCJ0YWJcIlxyXG5cdFx0XHRcdFthdHRyLmFyaWEtc2VsZWN0ZWRdPVwidGFiLmFjdGl2ZVwiXHJcblx0XHRcdFx0W2F0dHIudGFiaW5kZXhdPVwiKHRhYi5hY3RpdmU/MDotMSlcIlxyXG5cdFx0XHRcdFthdHRyLmFyaWEtY29udHJvbHNdPVwidGFiLmlkXCJcclxuXHRcdFx0XHRbYXR0ci5hcmlhLWRpc2FibGVkXT1cInRhYi5kaXNhYmxlZFwiXHJcblx0XHRcdFx0W2Rpc2FibGVkXT1cInRhYi5kaXNhYmxlZFwiXHJcblx0XHRcdFx0W25nQ2xhc3NdPVwie1xyXG5cdFx0XHRcdFx0J2Nkcy0tdGFic19fbmF2LWl0ZW0tLXNlbGVjdGVkJzogdGFiLmFjdGl2ZSxcclxuXHRcdFx0XHRcdCdjZHMtLXRhYnNfX25hdi1pdGVtLS1kaXNhYmxlZCc6IHRhYi5kaXNhYmxlZFxyXG5cdFx0XHRcdH1cIlxyXG5cdFx0XHRcdGNsYXNzPVwiY2RzLS10YWJzX19uYXYtaXRlbSBjZHMtLXRhYnNfX25hdi1saW5rXCJcclxuXHRcdFx0XHR0eXBlPVwiYnV0dG9uXCJcclxuXHRcdFx0XHRkcmFnZ2FibGU9XCJmYWxzZVwiXHJcblx0XHRcdFx0aWQ9XCJ7e3RhYi5pZH19LWhlYWRlclwiXHJcblx0XHRcdFx0W2F0dHIudGl0bGVdPVwidGFiLnRpdGxlIHx8ICghdGFiLmhlYWRpbmdJc1RlbXBsYXRlID8gdGFiLmhlYWRpbmcgOiBudWxsKVwiXHJcblx0XHRcdFx0KGZvY3VzKT1cIm9uVGFiRm9jdXMoaSlcIlxyXG5cdFx0XHRcdChjbGljayk9XCJzZWxlY3RUYWIodGFiLCBpKVwiPlxyXG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJjZHMtLXRhYnNfX25hdi1pdGVtLWxhYmVsLXdyYXBwZXJcIj5cclxuXHRcdFx0XHRcdDxzcGFuIGNsYXNzPVwiY2RzLS10YWJzX19uYXYtaXRlbS1sYWJlbFwiPlxyXG5cdFx0XHRcdFx0XHQ8bmctY29udGFpbmVyICpuZ0lmPVwiIXRhYi5oZWFkaW5nSXNUZW1wbGF0ZVwiPlxyXG5cdFx0XHRcdFx0XHRcdHt7IHRhYi5oZWFkaW5nIH19XHJcblx0XHRcdFx0XHRcdDwvbmctY29udGFpbmVyPlxyXG5cdFx0XHRcdFx0XHQ8bmctdGVtcGxhdGVcclxuXHRcdFx0XHRcdFx0XHQqbmdJZj1cInRhYi5oZWFkaW5nSXNUZW1wbGF0ZVwiXHJcblx0XHRcdFx0XHRcdFx0W25nVGVtcGxhdGVPdXRsZXRdPVwidGFiLmhlYWRpbmdcIlxyXG5cdFx0XHRcdFx0XHRcdFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09XCJ7JGltcGxpY2l0OiB0YWIuY29udGV4dH1cIj5cclxuXHRcdFx0XHRcdFx0PC9uZy10ZW1wbGF0ZT5cclxuXHRcdFx0XHRcdDwvc3Bhbj5cclxuXHRcdFx0XHQ8L2Rpdj5cclxuXHRcdFx0PC9idXR0b24+XHJcblx0XHRcdDxuZy1jb250YWluZXIgW25nVGVtcGxhdGVPdXRsZXRdPVwiY29udGVudEFmdGVyXCI+PC9uZy1jb250YWluZXI+XHJcblx0XHQ8L2Rpdj5cclxuXHRcdDxkaXYgKm5nSWY9XCJpc092ZXJmbG93aW5nQm90dG9tXCIgY2xhc3M9XCJjZHMtLXRhYi0tbGlzdC1ncmFkaWVudF9ib3R0b21cIj48L2Rpdj5cclxuXHRgXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBUYWJIZWFkZXJzVmVydGljYWwgZXh0ZW5kcyBCYXNlVGFiSGVhZGVyIGltcGxlbWVudHMgQWZ0ZXJDb250ZW50SW5pdCwgT25DaGFuZ2VzLCBPbkRlc3Ryb3ksIE9uSW5pdCB7XHJcblx0LyoqXHJcblx0ICogTGlzdCBvZiBgVGFiYCBjb21wb25lbnRzLlxyXG5cdCAqL1xyXG5cdC8vIGRpc2FibGUgdGhlIG5leHQgbGluZSBiZWNhdXNlIHdlIG5lZWQgdG8gcmVuYW1lIHRoZSBpbnB1dFxyXG5cdC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZVxyXG5cdEBJbnB1dChcInRhYnNcIikgdGFiSW5wdXQ6IFF1ZXJ5TGlzdDxUYWI+O1xyXG5cclxuXHQvKipcclxuXHQgKiBpMThuIHN0cmluZ3MgZm9yIHRoZSB0YWIgbGlzdCBgYXJpYS1sYWJlbGAgZmFsbGJhY2suXHJcblx0ICovXHJcblx0QElucHV0KCkgdHJhbnNsYXRpb25zID0gdGhpcy5pMThuLmdldCgpLlRBQlM7XHJcblxyXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tdGFicy0tdmVydGljYWxcIikgdmVydGljYWxDbGFzcyA9IHRydWU7XHJcblxyXG5cdEBWaWV3Q2hpbGQoXCJ0YWJMaXN0XCIsIHsgc3RhdGljOiB0cnVlIH0pIGhlYWRlckNvbnRhaW5lcjogRWxlbWVudFJlZjxIVE1MRWxlbWVudD47XHJcblxyXG5cdC8qKlxyXG5cdCAqIENvbnRlbnRDaGlsZCBvZiBhbGwgdGhlIHRhYnNcclxuXHQgKi9cclxuXHRAQ29udGVudENoaWxkcmVuKFRhYikgdGFiUXVlcnk6IFF1ZXJ5TGlzdDxUYWI+O1xyXG5cdHRhYnM6IFF1ZXJ5TGlzdDxUYWI+O1xyXG5cclxuXHRAVmlld0NoaWxkcmVuKFwidGFiSXRlbVwiKSBhbGxUYWJIZWFkZXJzOiBRdWVyeUxpc3Q8RWxlbWVudFJlZj47XHJcblxyXG5cdC8qKlxyXG5cdCAqIEZvY3VzZWQgdGFiIGluZGV4IHdoZW4gYGZvbGxvd0ZvY3VzYCBpcyBmYWxzZSAobWFudWFsIGFjdGl2YXRpb24pXHJcblx0ICovXHJcblx0YWN0aXZlSW5kZXg6IG51bWJlciB8IG51bGwgPSBudWxsO1xyXG5cclxuXHQvKipcclxuXHQgKiBXaGV0aGVyIHRoZSB0YWIgbGlzdCBpcyBvdmVyZmxvd2luZyBhdCB0aGUgdG9wIChzb21lIHRhYnMgYXJlIGNsaXBwZWQpLlxyXG5cdCAqL1xyXG5cdGlzT3ZlcmZsb3dpbmdUb3AgPSBmYWxzZTtcclxuXHQvKipcclxuXHQgKiBXaGV0aGVyIHRoZSB0YWIgbGlzdCBpcyBvdmVyZmxvd2luZyBhdCB0aGUgYm90dG9tIChzb21lIHRhYnMgYXJlIGNsaXBwZWQpLlxyXG5cdCAqL1xyXG5cdGlzT3ZlcmZsb3dpbmdCb3R0b20gPSBmYWxzZTtcclxuXHJcblx0cHJpdmF0ZSByZXNpemVPYnNlcnZlcjogUmVzaXplT2JzZXJ2ZXI7XHJcblxyXG5cdGNvbnN0cnVjdG9yKFxyXG5cdFx0cHJvdGVjdGVkIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWYsXHJcblx0XHRwcm90ZWN0ZWQgY2hhbmdlRGV0ZWN0b3JSZWY6IENoYW5nZURldGVjdG9yUmVmLFxyXG5cdFx0cHJvdGVjdGVkIGV2ZW50U2VydmljZTogRXZlbnRTZXJ2aWNlLFxyXG5cdFx0cHJvdGVjdGVkIHJlbmRlcmVyOiBSZW5kZXJlcjIsXHJcblx0XHRwcm90ZWN0ZWQgaTE4bjogSTE4blxyXG5cdCkge1xyXG5cdFx0c3VwZXIoZWxlbWVudFJlZiwgY2hhbmdlRGV0ZWN0b3JSZWYsIGV2ZW50U2VydmljZSwgcmVuZGVyZXIpO1xyXG5cdFx0dGhpcy50eXBlID0gXCJjb250YWluZWRcIjtcclxuXHR9XHJcblxyXG5cdEBIb3N0TGlzdGVuZXIoXCJrZXlkb3duXCIsIFtcIiRldmVudFwiXSlcclxuXHRrZXlib2FyZElucHV0KGV2ZW50OiBLZXlib2FyZEV2ZW50KSB7XHJcblx0XHRpZiAoIXRoaXMudGFicykge1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblx0XHRjb25zdCB0YWJzQXJyYXkgPSB0aGlzLnRhYnMudG9BcnJheSgpO1xyXG5cdFx0Y29uc3QgZW5hYmxlZFRhYnMgPSB0YWJzQXJyYXkuZmlsdGVyKHRhYiA9PiAhdGFiLmRpc2FibGVkKTtcclxuXHRcdGlmIChlbmFibGVkVGFicy5sZW5ndGggPT09IDApIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHJlZmVyZW5jZUluZGV4ID0gdGhpcy5mb2xsb3dGb2N1cyA/XHJcblx0XHRcdHRoaXMuY3VycmVudFNlbGVjdGVkVGFiIDpcclxuXHRcdFx0KHRoaXMuYWN0aXZlSW5kZXggIT09IG51bGwgPyB0aGlzLmFjdGl2ZUluZGV4IDogdGhpcy5jdXJyZW50U2VsZWN0ZWRUYWIpO1xyXG5cdFx0Y29uc3QgY3VycmVudEVuYWJsZWRJbmRleCA9IE1hdGgubWF4KDAsIGVuYWJsZWRUYWJzLmluZGV4T2YodGFic0FycmF5W3JlZmVyZW5jZUluZGV4XSkpO1xyXG5cclxuXHRcdGxldCBuZXh0RW5hYmxlZEluZGV4ID0gY3VycmVudEVuYWJsZWRJbmRleDtcclxuXHRcdGxldCBoYW5kbGVkID0gZmFsc2U7XHJcblxyXG5cdFx0aWYgKGV2ZW50LmtleSA9PT0gXCJBcnJvd0Rvd25cIikge1xyXG5cdFx0XHRuZXh0RW5hYmxlZEluZGV4ID0gKGN1cnJlbnRFbmFibGVkSW5kZXggKyAxKSAlIGVuYWJsZWRUYWJzLmxlbmd0aDtcclxuXHRcdFx0aGFuZGxlZCA9IHRydWU7XHJcblx0XHR9IGVsc2UgaWYgKGV2ZW50LmtleSA9PT0gXCJBcnJvd1VwXCIpIHtcclxuXHRcdFx0bmV4dEVuYWJsZWRJbmRleCA9IChlbmFibGVkVGFicy5sZW5ndGggKyBjdXJyZW50RW5hYmxlZEluZGV4IC0gMSkgJSBlbmFibGVkVGFicy5sZW5ndGg7XHJcblx0XHRcdGhhbmRsZWQgPSB0cnVlO1xyXG5cdFx0fSBlbHNlIGlmIChldmVudC5rZXkgPT09IFwiSG9tZVwiKSB7XHJcblx0XHRcdG5leHRFbmFibGVkSW5kZXggPSAwO1xyXG5cdFx0XHRoYW5kbGVkID0gdHJ1ZTtcclxuXHRcdH0gZWxzZSBpZiAoZXZlbnQua2V5ID09PSBcIkVuZFwiKSB7XHJcblx0XHRcdG5leHRFbmFibGVkSW5kZXggPSBlbmFibGVkVGFicy5sZW5ndGggLSAxO1xyXG5cdFx0XHRoYW5kbGVkID0gdHJ1ZTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoaGFuZGxlZCkge1xyXG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cdFx0XHRjb25zdCBuZXh0VGFiID0gZW5hYmxlZFRhYnNbbmV4dEVuYWJsZWRJbmRleF07XHJcblx0XHRcdGNvbnN0IG5leHRJbmRleCA9IHRhYnNBcnJheS5pbmRleE9mKG5leHRUYWIpO1xyXG5cclxuXHRcdFx0aWYgKHRoaXMuZm9sbG93Rm9jdXMpIHtcclxuXHRcdFx0XHR0aGlzLnNlbGVjdFRhYihuZXh0VGFiLCBuZXh0SW5kZXgpO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdHRoaXMuYWN0aXZlSW5kZXggPSBuZXh0SW5kZXg7XHJcblx0XHRcdH1cclxuXHRcdFx0dGhpcy5hbGxUYWJIZWFkZXJzLnRvQXJyYXkoKVtuZXh0SW5kZXhdLm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICgoZXZlbnQua2V5ID09PSBcIiBcIiB8fCBldmVudC5rZXkgPT09IFwiU3BhY2ViYXJcIikgJiYgIXRoaXMuZm9sbG93Rm9jdXMpIHtcclxuXHRcdFx0Y29uc3QgZm9jdXNJbmRleCA9IHRoaXMuYWN0aXZlSW5kZXggIT09IG51bGwgPyB0aGlzLmFjdGl2ZUluZGV4IDogdGhpcy5jdXJyZW50U2VsZWN0ZWRUYWI7XHJcblx0XHRcdHRoaXMuc2VsZWN0VGFiKHRhYnNBcnJheVtmb2N1c0luZGV4XSwgZm9jdXNJbmRleCk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRASG9zdExpc3RlbmVyKFwiYmx1clwiLCBbXCIkZXZlbnRcIl0pXHJcblx0aGFuZGxlQmx1cihldmVudDogRm9jdXNFdmVudCkge1xyXG5cdFx0Y29uc3QgcmVsYXRlZFRhcmdldCA9IGV2ZW50LnJlbGF0ZWRUYXJnZXQgYXMgTm9kZSB8IG51bGw7XHJcblx0XHRjb25zdCBjb250YWluZXIgPSB0aGlzLmhlYWRlckNvbnRhaW5lcj8ubmF0aXZlRWxlbWVudDtcclxuXHRcdGlmIChjb250YWluZXIgJiYgcmVsYXRlZFRhcmdldCAmJiBjb250YWluZXIuY29udGFpbnMocmVsYXRlZFRhcmdldCkpIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCF0aGlzLmZvbGxvd0ZvY3VzKSB7XHJcblx0XHRcdHRoaXMuYWN0aXZlSW5kZXggPSB0aGlzLmN1cnJlbnRTZWxlY3RlZFRhYjtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdG5nT25Jbml0KCk6IHZvaWQge1xyXG5cdFx0dGhpcy5yZXNpemVPYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcigoKSA9PiB7XHJcblx0XHRcdHRoaXMudXBkYXRlT3ZlcmZsb3dTdGF0ZSgpO1xyXG5cdFx0XHR0aGlzLmNoYW5nZURldGVjdG9yUmVmLmRldGVjdENoYW5nZXMoKTtcclxuXHRcdH0pO1xyXG5cdFx0dGhpcy5yZXNpemVPYnNlcnZlci5vYnNlcnZlKHRoaXMuaGVhZGVyQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQpO1xyXG5cdFx0dGhpcy5oZWFkZXJDb250YWluZXIubmF0aXZlRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKFwic2Nyb2xsXCIsIHRoaXMubGlzdFNjcm9sbEhhbmRsZXIpO1xyXG5cdH1cclxuXHJcblx0bmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcblx0XHR0aGlzLnJlc2l6ZU9ic2VydmVyPy51bm9ic2VydmUodGhpcy5oZWFkZXJDb250YWluZXIubmF0aXZlRWxlbWVudCk7XHJcblx0XHR0aGlzLmhlYWRlckNvbnRhaW5lci5uYXRpdmVFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJzY3JvbGxcIiwgdGhpcy5saXN0U2Nyb2xsSGFuZGxlcik7XHJcblx0fVxyXG5cclxuXHRuZ0FmdGVyQ29udGVudEluaXQoKSB7XHJcblx0XHRpZiAoIXRoaXMudGFiSW5wdXQpIHtcclxuXHRcdFx0dGhpcy50YWJzID0gdGhpcy50YWJRdWVyeTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHRoaXMudGFicyA9IHRoaXMudGFiSW5wdXQ7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy50YWJzLmZvckVhY2godGFiID0+IHRhYi5jYWNoZUFjdGl2ZSA9IHRoaXMuY2FjaGVBY3RpdmUpO1xyXG5cdFx0dGhpcy50YWJzLmNoYW5nZXMuc3Vic2NyaWJlKCgpID0+IHtcclxuXHRcdFx0dGhpcy5zZXRGaXJzdFRhYigpO1xyXG5cdFx0XHR0aGlzLmNoYW5nZURldGVjdG9yUmVmLm1hcmtGb3JDaGVjaygpO1xyXG5cdFx0fSk7XHJcblx0XHR0aGlzLnNldEZpcnN0VGFiKCk7XHJcblx0fVxyXG5cclxuXHRuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XHJcblx0XHRpZiAodGhpcy50YWJzICYmIGNoYW5nZXMuY2FjaGVBY3RpdmUpIHtcclxuXHRcdFx0dGhpcy50YWJzLmZvckVhY2godGFiID0+IHRhYi5jYWNoZUFjdGl2ZSA9IHRoaXMuY2FjaGVBY3RpdmUpO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0b25UYWJGb2N1cyhpbmRleDogbnVtYmVyKSB7XHJcblx0XHRpZiAodGhpcy5mb2xsb3dGb2N1cykge1xyXG5cdFx0XHR0aGlzLmN1cnJlbnRTZWxlY3RlZFRhYiA9IGluZGV4O1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0dGhpcy5hY3RpdmVJbmRleCA9IGluZGV4O1xyXG5cdFx0fVxyXG5cdFx0dGhpcy5zY3JvbGxTZWxlY3RlZFRhYkludG9WaWV3KCk7XHJcblx0fVxyXG5cclxuXHRzZWxlY3RUYWIodGFiOiBUYWIsIHRhYkluZGV4OiBudW1iZXIpIHtcclxuXHRcdGlmICh0YWIuZGlzYWJsZWQpIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cdFx0dGhpcy5jdXJyZW50U2VsZWN0ZWRUYWIgPSB0YWJJbmRleDtcclxuXHRcdHRoaXMuYWN0aXZlSW5kZXggPSB0YWJJbmRleDtcclxuXHRcdHRoaXMudGFicy5mb3JFYWNoKF90YWIgPT4gX3RhYi5hY3RpdmUgPSBmYWxzZSk7XHJcblx0XHR0YWIuYWN0aXZlID0gdHJ1ZTtcclxuXHRcdHRhYi5kb1NlbGVjdCgpO1xyXG5cdFx0dGhpcy5zY3JvbGxTZWxlY3RlZFRhYkludG9WaWV3KCk7XHJcblx0fVxyXG5cclxuXHRnZXRTZWxlY3RlZFRhYigpOiBhbnkge1xyXG5cdFx0Y29uc3Qgc2VsZWN0ZWQgPSB0aGlzLnRhYnMuZmluZCh0YWIgPT4gdGFiLmFjdGl2ZSk7XHJcblx0XHRpZiAoc2VsZWN0ZWQpIHtcclxuXHRcdFx0cmV0dXJuIHNlbGVjdGVkO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHsgaGVhZGluZ0lzVGVtcGxhdGU6IGZhbHNlLCBoZWFkaW5nOiBcIlwiIH07XHJcblx0fVxyXG5cclxuXHRwcm90ZWN0ZWQgdXBkYXRlT3ZlcmZsb3dTdGF0ZSgpIHtcclxuXHRcdGNvbnN0IGVsZW1lbnQgPSB0aGlzLmhlYWRlckNvbnRhaW5lcj8ubmF0aXZlRWxlbWVudDtcclxuXHRcdGlmICghZWxlbWVudCkge1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblx0XHRjb25zdCBoYWxmVGFiSGVpZ2h0ID0gVkVSVElDQUxfVEFCX0hFSUdIVCAvIDI7XHJcblx0XHR0aGlzLmlzT3ZlcmZsb3dpbmdCb3R0b20gPVxyXG5cdFx0XHRlbGVtZW50LnNjcm9sbFRvcCArIGVsZW1lbnQuY2xpZW50SGVpZ2h0ICsgaGFsZlRhYkhlaWdodCA8PSBlbGVtZW50LnNjcm9sbEhlaWdodDtcclxuXHRcdHRoaXMuaXNPdmVyZmxvd2luZ1RvcCA9IGVsZW1lbnQuc2Nyb2xsVG9wID4gaGFsZlRhYkhlaWdodDtcclxuXHRcdHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYubWFya0ZvckNoZWNrKCk7XHJcblx0fVxyXG5cclxuXHRwcm90ZWN0ZWQgc2Nyb2xsU2VsZWN0ZWRUYWJJbnRvVmlldygpIHtcclxuXHRcdGNvbnN0IGNvbnRhaW5lciA9IHRoaXMuaGVhZGVyQ29udGFpbmVyPy5uYXRpdmVFbGVtZW50O1xyXG5cdFx0aWYgKCFjb250YWluZXIpIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cdFx0Y29uc3Qgc2VsZWN0ZWRIZWFkZXIgPSB0aGlzLmFsbFRhYkhlYWRlcnM/LnRvQXJyYXkoKVt0aGlzLmN1cnJlbnRTZWxlY3RlZFRhYl0/Lm5hdGl2ZUVsZW1lbnQ7XHJcblx0XHRpZiAoIXNlbGVjdGVkSGVhZGVyKSB7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHRcdGNvbnN0IGNvbnRhaW5lclJlY3QgPSBjb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcblx0XHRjb25zdCBzZWxlY3RlZFJlY3QgPSBzZWxlY3RlZEhlYWRlci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuXHRcdGNvbnN0IGhhbGZUYWJIZWlnaHQgPSBWRVJUSUNBTF9UQUJfSEVJR0hUIC8gMjtcclxuXHJcblx0XHRpZiAoXHJcblx0XHRcdHNlbGVjdGVkUmVjdC50b3AgLSBoYWxmVGFiSGVpZ2h0IDwgY29udGFpbmVyUmVjdC50b3AgfHxcclxuXHRcdFx0c2VsZWN0ZWRSZWN0LnRvcCAtIGNvbnRhaW5lclJlY3QudG9wICsgVkVSVElDQUxfVEFCX0hFSUdIVCArIGhhbGZUYWJIZWlnaHQgPiBjb250YWluZXJSZWN0LmhlaWdodFxyXG5cdFx0KSB7XHJcblx0XHRcdGNvbnRhaW5lci5zY3JvbGxUbyh7XHJcblx0XHRcdFx0dG9wOiBNYXRoLm1heCgwLCAodGhpcy5jdXJyZW50U2VsZWN0ZWRUYWIgLSAxKSAqIFZFUlRJQ0FMX1RBQl9IRUlHSFQpLFxyXG5cdFx0XHRcdGJlaGF2aW9yOiBcInNtb290aFwiXHJcblx0XHRcdH0pO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0cHJvdGVjdGVkIHNldEZpcnN0VGFiKCkge1xyXG5cdFx0c2V0VGltZW91dCgoKSA9PiB7XHJcblx0XHRcdGxldCBmaXJzdFRhYiA9IHRoaXMudGFicy5maW5kKHRhYiA9PiB0YWIuYWN0aXZlKTtcclxuXHRcdFx0aWYgKCFmaXJzdFRhYiAmJiB0aGlzLnRhYnMuZmlyc3QpIHtcclxuXHRcdFx0XHRmaXJzdFRhYiA9IHRoaXMudGFicy5maXJzdDtcclxuXHRcdFx0XHRmaXJzdFRhYi5hY3RpdmUgPSB0cnVlO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmIChmaXJzdFRhYikge1xyXG5cdFx0XHRcdHRoaXMuY3VycmVudFNlbGVjdGVkVGFiID0gdGhpcy50YWJzLnRvQXJyYXkoKS5pbmRleE9mKGZpcnN0VGFiKTtcclxuXHRcdFx0XHR0aGlzLmFjdGl2ZUluZGV4ID0gdGhpcy5jdXJyZW50U2VsZWN0ZWRUYWI7XHJcblx0XHRcdFx0Zmlyc3RUYWIuZG9TZWxlY3QoKTtcclxuXHRcdFx0XHR0aGlzLnVwZGF0ZU92ZXJmbG93U3RhdGUoKTtcclxuXHRcdFx0fVxyXG5cdFx0fSk7XHJcblx0fVxyXG5cdHByaXZhdGUgbGlzdFNjcm9sbEhhbmRsZXIgPSAoKSA9PiB0aGlzLnVwZGF0ZU92ZXJmbG93U3RhdGUoKTtcclxufVxyXG4iXX0=