@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
209 lines • 35.3 kB
JavaScript
import { coerceCssPixelValue } from '@angular/cdk/coercion';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, EventEmitter, forwardRef, inject, Input, Output, ViewChild } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { Subject } from 'rxjs';
import { MenuTriggerDirective } from '../menu/menu-trigger/menu-trigger.directive';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "@angular/forms";
import * as i3 from "../icon/icon.component";
import * as i4 from "../menu/menu/menu.component";
import * as i5 from "../menu/menu-trigger/menu-trigger.directive";
import * as i6 from "../../directives/accessibility/focus-indicator/default-focus-indicator.directive";
import * as i7 from "../../directives/accessibility/focus-indicator/focus-indicator.directive";
export class InputDropdownComponent {
constructor() {
this._changeDetector = inject(ChangeDetectorRef);
/** Filter text */
this.filter = '';
/** Controls the disabled state of the input-dropdown. */
this.disabled = false;
/** Define the placeholder for the filter input */
this.placeholder = 'Type to filter...';
/** Aria label of the filter field. If not specified, the placeholder will be used. */
this.ariaLabel = '';
/** Aria label of the search button icon. */
this.searchFilterButtonAriaLabel = 'Search';
/** Aria label of the clear button icon. */
this.clearFilterButtonAriaLabel = 'Clear';
/** Emit when the selected item is changed */
this.selectedChange = new EventEmitter();
/** Emit when the filter text is changed */
this.filterChange = new EventEmitter();
/** Emits when `dropdownOpen` changes. */
this.dropdownOpenChange = new EventEmitter();
/** The status of the dropdown. */
this.dropdownOpen = false;
/** Store the filter button aria label */
this._filterButtonAriaLabel = this.searchFilterButtonAriaLabel;
/** Store the change callback provided by Angular Forms */
// eslint-disable-next-line @typescript-eslint/no-empty-function
this.onChange = () => { };
/** Store the touched callback provided by Angular Forms */
// eslint-disable-next-line @typescript-eslint/no-empty-function
this.onTouched = () => { };
/** Unsubscribe from all observables on component destroy */
this._onDestroy$ = new Subject();
}
/** Define the max height of the dropdown */
set maxHeight(value) {
this._maxHeight = coerceCssPixelValue(value);
}
ngOnChanges(changes) {
// if the dropdownOpen state changes via the input we should show or hide the input accordingly
if (changes.dropdownOpen && !changes.dropdownOpen.firstChange && changes.dropdownOpen.currentValue !== changes.dropdownOpen.previousValue) {
changes.dropdownOpen.currentValue ? this.menuTrigger.openMenu() : this.menuTrigger.closeMenu();
}
if (changes.selected) {
// if an item is programmatically selected we should close the menu if it is open
if (this.menuTrigger && !changes.selected.firstChange) {
this.menuTrigger.closeMenu();
}
this.resetFilter();
this.selectedChange.emit(changes.selected.currentValue);
this.onChange(changes.selected.currentValue);
this.onTouched();
}
if (changes.filter) {
this.setFilterButtonAriaLabel();
}
}
ngAfterViewInit() {
// if the user has initially set the dropdownOpen input to true we should open the menu
// once we have access to the ViewChild menu trigger directive
if (this.dropdownOpen) {
// trigger menu open on the next tick to avoid expression changed issues)
Promise.resolve().then(() => this.menuTrigger.openMenu());
}
this._changeDetector.detectChanges();
}
ngOnDestroy() {
this._onDestroy$.next();
this._onDestroy$.complete();
}
resetFilter() {
this.filter = '';
this.filterChange.emit(this.filter);
this._focusFilter();
}
registerOnChange(onChange) {
this.onChange = onChange;
}
registerOnTouched(onTouched) {
this.onTouched = onTouched;
}
writeValue(value) {
this.selected = value;
this._changeDetector.markForCheck();
}
resetValue(event) {
if (this.disabled) {
return;
}
this.writeValue(undefined);
this.selectedChange.emit(undefined);
event.stopPropagation();
}
setDisabledState(isDisabled) {
this.disabled = isDisabled;
this._changeDetector.markForCheck();
}
onMenuOpen() {
if (this.dropdownOpen !== true) {
this.dropdownOpen = true;
this.dropdownOpenChange.emit(this.dropdownOpen);
this._focusFilter();
}
}
onMenuClose() {
if (this.dropdownOpen !== false) {
this.dropdownOpen = false;
this.dropdownOpenChange.emit(this.dropdownOpen);
}
}
_focusFilter() {
if (this.filterInputElement) {
this.filterInputElement.nativeElement.focus();
}
}
inputFocusHandler() {
if (!this.dropdownOpen) {
this.dropdownOpen = true;
this.dropdownOpenChange.emit(this.dropdownOpen);
}
}
toggleMenu() {
if (this.disabled) {
return;
}
this.dropdownOpen = !this.dropdownOpen;
this.dropdownOpenChange.emit(this.dropdownOpen);
this.menuTrigger.toggleMenu();
}
setFilterButtonAriaLabel() {
this._filterButtonAriaLabel = this.filter === ''
? this.searchFilterButtonAriaLabel : this.clearFilterButtonAriaLabel;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: InputDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.12", type: InputDropdownComponent, selector: "ux-input-dropdown", inputs: { selected: "selected", filter: "filter", hideFilter: "hideFilter", maxHeight: "maxHeight", disabled: "disabled", allowNull: "allowNull", placeholder: "placeholder", ariaLabel: ["aria-label", "ariaLabel"], ariaLabelledby: "ariaLabelledby", searchFilterButtonAriaLabel: "searchFilterButtonAriaLabel", clearFilterButtonAriaLabel: "clearFilterButtonAriaLabel", dropdownOpen: "dropdownOpen" }, outputs: { selectedChange: "selectedChange", filterChange: "filterChange", dropdownOpenChange: "dropdownOpenChange" }, host: { properties: { "class.ux-select-disabled": "disabled", "attr.aria-label": "null" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => InputDropdownComponent)
}
], queries: [{ propertyName: "displayContentRef", first: true, predicate: ["displayContent"], descendants: true }], viewQueries: [{ propertyName: "menuTrigger", first: true, predicate: MenuTriggerDirective, descendants: true }, { propertyName: "filterInputElement", first: true, predicate: ["filterInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"ux-select-container\">\n <button #button type=\"button\" class=\"form-control\"\n [uxMenuTriggerFor]=\"menu\"\n [disabled]=\"disabled\">\n <ng-template #defaultDisplayContent>{{selected ? (selected | json) : '-'}}</ng-template>\n <ng-container [ngTemplateOutlet]=\"displayContentRef || defaultDisplayContent\"></ng-container>\n </button>\n <div class=\"ux-select-icons\">\n @if (allowNull && selected) {\n <ux-icon name=\"close\"\n uxFocusIndicator\n class=\"ux-select-icon ux-select-clear-icon\"\n (click)=\"resetValue($event)\"\n (keydown.enter)=\"resetValue($event)\"\n tabindex=\"0\">\n </ux-icon>\n }\n <ux-icon name=\"chevron-down\"\n class=\"ux-select-icon ux-select-chevron-icon\"\n (click)=\"toggleMenu(); $event.stopPropagation()\">\n </ux-icon>\n </div>\n</div>\n\n<ux-menu #menu menuClass=\"select-menu\"\n (opened)=\"onMenuOpen()\"\n (closed)=\"onMenuClose()\">\n\n <div [style.max-height]=\"_maxHeight\"\n [style.width.px]=\"button.offsetWidth\">\n\n @if (!hideFilter) {\n <div\n class=\"filter-container\">\n <input #filterInput\n type=\"text\"\n [placeholder]=\"placeholder\"\n class=\"form-control\"\n [(ngModel)]=\"filter\"\n (input)=\"filterChange.emit(filter)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"ariaLabel || placeholder\"\n [attr.aria-labelledby]=\"ariaLabelledby\"\n (focus)=\"inputFocusHandler()\">\n <button type=\"button\"\n class=\"btn btn-flat filter-button\"\n [attr.aria-label]=\"_filterButtonAriaLabel\"\n (click)=\"resetFilter(); $event.stopPropagation();\"\n [tabindex]=\"filter.length > 0 ? 0 : -1\">\n <ux-icon [name]=\"filter.length === 0 ? 'search' : 'close'\"></ux-icon>\n </button>\n </div>\n }\n\n <ng-content></ng-content>\n\n </div>\n </ux-menu>\n", dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.IconComponent, selector: "ux-icon", inputs: ["name", "size", "rotate", "flipHorizontal", "flipVertical"] }, { kind: "component", type: i4.MenuComponent, selector: "ux-menu", inputs: ["id", "placement", "alignment", "animate", "menuClass"], outputs: ["opening", "opened", "closing", "closed"] }, { kind: "directive", type: i5.MenuTriggerDirective, selector: "[uxMenuTriggerFor]", inputs: ["uxMenuTriggerFor", "disabled", "uxMenuParent", "closeOnBlur"], outputs: ["closed"], exportAs: ["ux-menu-trigger"] }, { kind: "directive", type: i6.DefaultFocusIndicatorDirective, selector: ".btn:not([uxFocusIndicator]):not([uxMenuNavigationToggle]):not([uxMenuTriggerFor]), a[href]:not([uxFocusIndicator]):not([uxMenuNavigationToggle]):not([uxMenuTriggerFor])" }, { kind: "directive", type: i7.FocusIndicatorDirective, selector: "[uxFocusIndicator]", inputs: ["checkChildren", "mouseFocusIndicator", "touchFocusIndicator", "keyboardFocusIndicator", "programmaticFocusIndicator"], outputs: ["indicator"], exportAs: ["ux-focus-indicator"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.12", ngImport: i0, type: InputDropdownComponent, decorators: [{
type: Component,
args: [{ selector: 'ux-input-dropdown', changeDetection: ChangeDetectionStrategy.OnPush, providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => InputDropdownComponent)
}
], host: {
'[class.ux-select-disabled]': 'disabled',
'[attr.aria-label]': 'null'
}, template: "<div class=\"ux-select-container\">\n <button #button type=\"button\" class=\"form-control\"\n [uxMenuTriggerFor]=\"menu\"\n [disabled]=\"disabled\">\n <ng-template #defaultDisplayContent>{{selected ? (selected | json) : '-'}}</ng-template>\n <ng-container [ngTemplateOutlet]=\"displayContentRef || defaultDisplayContent\"></ng-container>\n </button>\n <div class=\"ux-select-icons\">\n @if (allowNull && selected) {\n <ux-icon name=\"close\"\n uxFocusIndicator\n class=\"ux-select-icon ux-select-clear-icon\"\n (click)=\"resetValue($event)\"\n (keydown.enter)=\"resetValue($event)\"\n tabindex=\"0\">\n </ux-icon>\n }\n <ux-icon name=\"chevron-down\"\n class=\"ux-select-icon ux-select-chevron-icon\"\n (click)=\"toggleMenu(); $event.stopPropagation()\">\n </ux-icon>\n </div>\n</div>\n\n<ux-menu #menu menuClass=\"select-menu\"\n (opened)=\"onMenuOpen()\"\n (closed)=\"onMenuClose()\">\n\n <div [style.max-height]=\"_maxHeight\"\n [style.width.px]=\"button.offsetWidth\">\n\n @if (!hideFilter) {\n <div\n class=\"filter-container\">\n <input #filterInput\n type=\"text\"\n [placeholder]=\"placeholder\"\n class=\"form-control\"\n [(ngModel)]=\"filter\"\n (input)=\"filterChange.emit(filter)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"ariaLabel || placeholder\"\n [attr.aria-labelledby]=\"ariaLabelledby\"\n (focus)=\"inputFocusHandler()\">\n <button type=\"button\"\n class=\"btn btn-flat filter-button\"\n [attr.aria-label]=\"_filterButtonAriaLabel\"\n (click)=\"resetFilter(); $event.stopPropagation();\"\n [tabindex]=\"filter.length > 0 ? 0 : -1\">\n <ux-icon [name]=\"filter.length === 0 ? 'search' : 'close'\"></ux-icon>\n </button>\n </div>\n }\n\n <ng-content></ng-content>\n\n </div>\n </ux-menu>\n" }]
}], propDecorators: { selected: [{
type: Input
}], filter: [{
type: Input
}], hideFilter: [{
type: Input
}], maxHeight: [{
type: Input
}], disabled: [{
type: Input
}], allowNull: [{
type: Input
}], placeholder: [{
type: Input
}], ariaLabel: [{
type: Input,
args: ['aria-label']
}], ariaLabelledby: [{
type: Input
}], searchFilterButtonAriaLabel: [{
type: Input
}], clearFilterButtonAriaLabel: [{
type: Input
}], selectedChange: [{
type: Output
}], filterChange: [{
type: Output
}], dropdownOpenChange: [{
type: Output
}], dropdownOpen: [{
type: Input
}], displayContentRef: [{
type: ContentChild,
args: ['displayContent', { static: false }]
}], menuTrigger: [{
type: ViewChild,
args: [MenuTriggerDirective, { static: false }]
}], filterInputElement: [{
type: ViewChild,
args: ['filterInput', { static: false }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5wdXQtZHJvcGRvd24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvaW5wdXQtZHJvcGRvd24vaW5wdXQtZHJvcGRvd24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvaW5wdXQtZHJvcGRvd24vaW5wdXQtZHJvcGRvd24uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDNUQsT0FBTyxFQUFpQix1QkFBdUIsRUFBRSxpQkFBaUIsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFjLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBd0IsTUFBTSxFQUE4QixTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDN08sT0FBTyxFQUF3QixpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sNkNBQTZDLENBQUM7Ozs7Ozs7OztBQWtCbkYsTUFBTSxPQUFPLHNCQUFzQjtJQWhCbkM7UUFpQnFCLG9CQUFlLEdBQUcsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFLN0Qsa0JBQWtCO1FBQ1QsV0FBTSxHQUFXLEVBQUUsQ0FBQztRQVU3Qix5REFBeUQ7UUFDaEQsYUFBUSxHQUFZLEtBQUssQ0FBQztRQUtuQyxrREFBa0Q7UUFDekMsZ0JBQVcsR0FBVyxtQkFBbUIsQ0FBQztRQUVuRCxzRkFBc0Y7UUFDakUsY0FBUyxHQUFXLEVBQUUsQ0FBQztRQUs1Qyw0Q0FBNEM7UUFDbkMsZ0NBQTJCLEdBQVcsUUFBUSxDQUFDO1FBRXhELDJDQUEyQztRQUNsQywrQkFBMEIsR0FBVyxPQUFPLENBQUM7UUFFdEQsNkNB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QUFzQjtrQkFoQmxDLFNBQVM7K0JBQ0ksbUJBQW1CLG1CQUVaLHVCQUF1QixDQUFDLE1BQU0sYUFDcEM7d0JBQ1A7NEJBQ0ksT0FBTyxFQUFFLGlCQUFpQjs0QkFDMUIsS0FBSyxFQUFFLElBQUk7NEJBQ1gsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsdUJBQXVCLENBQUM7eUJBQ3hEO3FCQUNKLFFBQ0s7d0JBQ0YsNEJBQTRCLEVBQUUsVUFBVTt3QkFDeEMsbUJBQW1CLEVBQUUsTUFBTTtxQkFDOUI7OEJBTVEsUUFBUTtzQkFBaEIsS0FBSztnQkFHRyxNQUFNO3NCQUFkLEtBQUs7Z0JBR0csVUFBVTtzQkFBbEIsS0FBSztnQkFHTyxTQUFTO3NCQUFyQixLQUFLO2dCQUtHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBR0csU0FBUztzQkFBakIsS0FBSztnQkFHRyxXQUFXO3NCQUFuQixLQUFLO2dCQUdlLFNBQVM7c0JBQTdCLEtBQUs7dUJBQUMsWUFBWTtnQkFHVixjQUFjO3NCQUF0QixLQUFLO2dCQUdHLDJCQUEyQjtzQkFBbkMsS0FBSztnQkFHRywwQkFBMEI7c0JBQWxDLEtBQUs7Z0JBR0ksY0FBYztzQkFBdkIsTUFBTTtnQkFHRyxZQUFZO3NCQUFyQixNQUFNO2dCQUdHLGtCQUFrQjtzQkFBM0IsTUFBTTtnQkFHRSxZQUFZO3NCQUFwQixLQUFLO2dCQUc2QyxpQkFBaUI7c0JBQW5FLFlBQVk7dUJBQUMsZ0JBQWdCLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO2dCQUdHLFdBQVc7c0JBQTlELFNBQVM7dUJBQUMsb0JBQW9CLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO2dCQUdMLGtCQUFrQjtzQkFBOUQsU0FBUzt1QkFBQyxhQUFhLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY29lcmNlQ3NzUGl4ZWxWYWx1ZSB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9jb2VyY2lvbic7XG5pbXBvcnQgeyBBZnRlclZpZXdJbml0LCBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ2hhbmdlRGV0ZWN0b3JSZWYsIENvbXBvbmVudCwgQ29udGVudENoaWxkLCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIGZvcndhcmRSZWYsIGluamVjdCwgSW5wdXQsIE9uQ2hhbmdlcywgT25EZXN0cm95LCBPdXRwdXQsIFNpbXBsZUNoYW5nZXMsIFRlbXBsYXRlUmVmLCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBOR19WQUxVRV9BQ0NFU1NPUiB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IE1lbnVUcmlnZ2VyRGlyZWN0aXZlIH0gZnJvbSAnLi4vbWVudS9tZW51LXRyaWdnZXIvbWVudS10cmlnZ2VyLmRpcmVjdGl2ZSc7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAndXgtaW5wdXQtZHJvcGRvd24nLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9pbnB1dC1kcm9wZG93bi5jb21wb25lbnQuaHRtbCcsXG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgICAgICAgICAgbXVsdGk6IHRydWUsXG4gICAgICAgICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBJbnB1dERyb3Bkb3duQ29tcG9uZW50KVxuICAgICAgICB9XG4gICAgXSxcbiAgICBob3N0OiB7XG4gICAgICAgICdbY2xhc3MudXgtc2VsZWN0LWRpc2FibGVkXSc6ICdkaXNhYmxlZCcsXG4gICAgICAgICdbYXR0ci5hcmlhLWxhYmVsXSc6ICdudWxsJ1xuICAgIH1cbn0pXG5leHBvcnQgY2xhc3MgSW5wdXREcm9wZG93bkNvbXBvbmVudDxUPiBpbXBsZW1lbnRzIENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBBZnRlclZpZXdJbml0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfY2hhbmdlRGV0ZWN0b3IgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuXG4gICAgLyoqIERlZmluZSB0aGUgc2VsZWN0ZWQgaXRlbSAqL1xuICAgIEBJbnB1dCgpIHNlbGVjdGVkOiBUO1xuXG4gICAgLyoqIEZpbHRlciB0ZXh0ICovXG4gICAgQElucHV0KCkgZmlsdGVyOiBzdHJpbmcgPSAnJztcblxuICAgIC8qKiBIaWRlIHRoZSBmaWx0ZXIgaW5wdXQgKi9cbiAgICBASW5wdXQoKSBoaWRlRmlsdGVyOiBib29sZWFuO1xuXG4gICAgLyoqIERlZmluZSB0aGUgbWF4IGhlaWdodCBvZiB0aGUgZHJvcGRvd24gKi9cbiAgICBASW5wdXQoKSBzZXQgbWF4SGVpZ2h0KHZhbHVlOiBzdHJpbmcgfCBudW1iZXIpIHtcbiAgICAgICAgdGhpcy5fbWF4SGVpZ2h0ID0gY29lcmNlQ3NzUGl4ZWxWYWx1ZSh2YWx1ZSk7XG4gICAgfVxuXG4gICAgLyoqIENvbnRyb2xzIHRoZSBkaXNhYmxlZCBzdGF0ZSBvZiB0aGUgaW5wdXQtZHJvcGRvd24uICovXG4gICAgQElucHV0KCkgZGlzYWJsZWQ6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAgIC8qKiBEZWZpbmUgaWYgbnVsbCB2YWx1ZXMgYXJlIGFsbG93ZWQgKi9cbiAgICBASW5wdXQoKSBhbGxvd051bGw6IGJvb2xlYW47XG5cbiAgICAvKiogRGVmaW5lIHRoZSBwbGFjZWhvbGRlciBmb3IgdGhlIGZpbHRlciBpbnB1dCAqL1xuICAgIEBJbnB1dCgpIHBsYWNlaG9sZGVyOiBzdHJpbmcgPSAnVHlwZSB0byBmaWx0ZXIuLi4nO1xuXG4gICAgLyoqIEFyaWEgbGFiZWwgb2YgdGhlIGZpbHRlciBmaWVsZC4gSWYgbm90IHNwZWNpZmllZCwgdGhlIHBsYWNlaG9sZGVyIHdpbGwgYmUgdXNlZC4gKi9cbiAgICBASW5wdXQoJ2FyaWEtbGFiZWwnKSBhcmlhTGFiZWw6IHN0cmluZyA9ICcnO1xuXG4gICAgLyoqIElEIG9mIHRoZSBlbGVtZW50IHdoaWNoIHNlcnZlcyBhcyBhIGxhYmVsIGZvciB0aGUgZmlsdGVyIGZpZWxkLiAqL1xuICAgIEBJbnB1dCgpIGFyaWFMYWJlbGxlZGJ5OiBzdHJpbmc7XG5cbiAgICAvKiogQXJpYSBsYWJlbCBvZiB0aGUgc2VhcmNoIGJ1dHRvbiBpY29uLiAqL1xuICAgIEBJbnB1dCgpIHNlYXJjaEZpbHRlckJ1dHRvbkFyaWFMYWJlbDogc3RyaW5nID0gJ1NlYXJjaCc7XG5cbiAgICAvKiogQXJpYSBsYWJlbCBvZiB0aGUgY2xlYXIgYnV0dG9uIGljb24uICovXG4gICAgQElucHV0KCkgY2xlYXJGaWx0ZXJCdXR0b25BcmlhTGFiZWw6IHN0cmluZyA9ICdDbGVhcic7XG5cbiAgICAvKiogRW1pdCB3aGVuIHRoZSBzZWxlY3RlZCBpdGVtIGlzIGNoYW5nZWQgKi9cbiAgICBAT3V0cHV0KCkgc2VsZWN0ZWRDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPFQ+KCk7XG5cbiAgICAvKiogRW1pdCB3aGVuIHRoZSBmaWx0ZXIgdGV4dCBpcyBjaGFuZ2VkICovXG4gICAgQE91dHB1dCgpIGZpbHRlckNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuXG4gICAgLyoqIEVtaXRzIHdoZW4gYGRyb3Bkb3duT3BlbmAgY2hhbmdlcy4gKi9cbiAgICBAT3V0cHV0KCkgZHJvcGRvd25PcGVuQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xuXG4gICAgLyoqIFRoZSBzdGF0dXMgb2YgdGhlIGRyb3Bkb3duLiAqL1xuICAgIEBJbnB1dCgpIGRyb3Bkb3duT3BlbjogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgLyoqIEFjY2VzcyB0aGUgZGlzcGxheSBjb250ZW50IHRlbXBsYXRlIGlmIHNwZWNpZmllZCAqL1xuICAgIEBDb250ZW50Q2hpbGQoJ2Rpc3BsYXlDb250ZW50JywgeyBzdGF0aWM6IGZhbHNlIH0pIGRpc3BsYXlDb250ZW50UmVmOiBUZW1wbGF0ZVJlZjx2b2lkPjtcblxuICAgIC8qKiBBY2Nlc3MgdGhlIGRyb3Bkb3duIG1lbnUgdHJpZ2dlciBkaXJlY3RpdmUgKi9cbiAgICBAVmlld0NoaWxkKE1lbnVUcmlnZ2VyRGlyZWN0aXZlLCB7IHN0YXRpYzogZmFsc2UgfSkgbWVudVRyaWdnZXI6IE1lbnVUcmlnZ2VyRGlyZWN0aXZlO1xuXG4gICAgLyoqIEFjY2VzcyB0aGUgZmlsdGVyIHRleHQgaW5wdXQgZWxlbWVudCAqL1xuICAgIEBWaWV3Q2hpbGQoJ2ZpbHRlcklucHV0JywgeyBzdGF0aWM6IGZhbHNlIH0pIGZpbHRlcklucHV0RWxlbWVudDogRWxlbWVudFJlZjxIVE1MSW5wdXRFbGVtZW50PjtcblxuICAgIC8qKiBTdG9yZSB0aGUgbWF4IGhlaWdodCAqL1xuICAgIF9tYXhIZWlnaHQ6IHN0cmluZztcblxuICAgIC8qKiBTdG9yZSB0aGUgZmlsdGVyIGJ1dHRvbiBhcmlhIGxhYmVsICovXG4gICAgX2ZpbHRlckJ1dHRvbkFyaWFMYWJlbDogc3RyaW5nID0gdGhpcy5zZWFyY2hGaWx0ZXJCdXR0b25BcmlhTGFiZWw7XG5cbiAgICAvKiogU3RvcmUgdGhlIGNoYW5nZSBjYWxsYmFjayBwcm92aWRlZCBieSBBbmd1bGFyIEZvcm1zICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1lbXB0eS1mdW5jdGlvblxuICAgIG9uQ2hhbmdlOiAoXzogVCkgPT4gdm9pZCA9ICgpID0+IHsgfTtcblxuICAgIC8qKiBTdG9yZSB0aGUgdG91Y2hlZCBjYWxsYmFjayBwcm92aWRlZCBieSBBbmd1bGFyIEZvcm1zICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1lbXB0eS1mdW5jdGlvblxuICAgIG9uVG91Y2hlZDogKCkgPT4gdm9pZCA9ICgpID0+IHsgfTtcblxuICAgIC8qKiBVbnN1YnNjcmliZSBmcm9tIGFsbCBvYnNlcnZhYmxlcyBvbiBjb21wb25lbnQgZGVzdHJveSAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX29uRGVzdHJveSQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuXG4gICAgICAgIC8vIGlmIHRoZSBkcm9wZG93bk9wZW4gc3RhdGUgY2hhbmdlcyB2aWEgdGhlIGlucHV0IHdlIHNob3VsZCBzaG93IG9yIGhpZGUgdGhlIGlucHV0IGFjY29yZGluZ2x5XG4gICAgICAgIGlmIChjaGFuZ2VzLmRyb3Bkb3duT3BlbiAmJiAhY2hhbmdlcy5kcm9wZG93bk9wZW4uZmlyc3RDaGFuZ2UgJiYgY2hhbmdlcy5kcm9wZG93bk9wZW4uY3VycmVudFZhbHVlICE9PSBjaGFuZ2VzLmRyb3Bkb3duT3Blbi5wcmV2aW91c1ZhbHVlKSB7XG4gICAgICAgICAgICBjaGFuZ2VzLmRyb3Bkb3duT3Blbi5jdXJyZW50VmFsdWUgPyB0aGlzLm1lbnVUcmlnZ2VyLm9wZW5NZW51KCkgOiB0aGlzLm1lbnVUcmlnZ2VyLmNsb3NlTWVudSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNoYW5nZXMuc2VsZWN0ZWQpIHtcblxuICAgICAgICAgICAgLy8gaWYgYW4gaXRlbSBpcyBwcm9ncmFtbWF0aWNhbGx5IHNlbGVjdGVkIHdlIHNob3VsZCBjbG9zZSB0aGUgbWVudSBpZiBpdCBpcyBvcGVuXG4gICAgICAgICAgICBpZiAodGhpcy5tZW51VHJpZ2dlciAmJiAhY2hhbmdlcy5zZWxlY3RlZC5maXJzdENoYW5nZSkge1xuICAgICAgICAgICAgICAgIHRoaXMubWVudVRyaWdnZXIuY2xvc2VNZW51KCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMucmVzZXRGaWx0ZXIoKTtcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0ZWRDaGFuZ2UuZW1pdChjaGFuZ2VzLnNlbGVjdGVkLmN1cnJlbnRWYWx1ZSk7XG4gICAgICAgICAgICB0aGlzLm9uQ2hhbmdlKGNoYW5nZXMuc2VsZWN0ZWQuY3VycmVudFZhbHVlKTtcbiAgICAgICAgICAgIHRoaXMub25Ub3VjaGVkKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2hhbmdlcy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0RmlsdGVyQnV0dG9uQXJpYUxhYmVsKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG5cbiAgICAgICAgLy8gaWYgdGhlIHVzZXIgaGFzIGluaXRpYWxseSBzZXQgdGhlIGRyb3Bkb3duT3BlbiBpbnB1dCB0byB0cnVlIHdlIHNob3VsZCBvcGVuIHRoZSBtZW51XG4gICAgICAgIC8vIG9uY2Ugd2UgaGF2ZSBhY2Nlc3MgdG8gdGhlIFZpZXdDaGlsZCBtZW51IHRyaWdnZXIgZGlyZWN0aXZlXG4gICAgICAgIGlmICh0aGlzLmRyb3Bkb3duT3Blbikge1xuICAgICAgICAgICAgLy8gdHJpZ2dlciBtZW51IG9wZW4gb24gdGhlIG5leHQgdGljayB0byBhdm9pZCBleHByZXNzaW9uIGNoYW5nZWQgaXNzdWVzKVxuICAgICAgICAgICAgUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiB0aGlzLm1lbnVUcmlnZ2VyLm9wZW5NZW51KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3IuZGV0ZWN0Q2hhbmdlcygpO1xuICAgIH1cblxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgICAgICB0aGlzLl9vbkRlc3Ryb3kkLm5leHQoKTtcbiAgICAgICAgdGhpcy5fb25EZXN0cm95JC5jb21wbGV0ZSgpO1xuICAgIH1cblxuICAgIHJlc2V0RmlsdGVyKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmZpbHRlciA9ICcnO1xuICAgICAgICB0aGlzLmZpbHRlckNoYW5nZS5lbWl0KHRoaXMuZmlsdGVyKTtcbiAgICAgICAgdGhpcy5fZm9jdXNGaWx0ZXIoKTtcbiAgICB9XG5cbiAgICByZWdpc3Rlck9uQ2hhbmdlKG9uQ2hhbmdlOiAodmFsdWU6IFQpID0+IHZvaWQpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5vbkNoYW5nZSA9IG9uQ2hhbmdlO1xuICAgIH1cblxuICAgIHJlZ2lzdGVyT25Ub3VjaGVkKG9uVG91Y2hlZDogKCkgPT4gdm9pZCk6IHZvaWQge1xuICAgICAgICB0aGlzLm9uVG91Y2hlZCA9IG9uVG91Y2hlZDtcbiAgICB9XG5cbiAgICB3cml0ZVZhbHVlKHZhbHVlOiBUKTogdm9pZCB7XG4gICAgICAgIHRoaXMuc2VsZWN0ZWQgPSB2YWx1ZTtcbiAgICAgICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3IubWFya0ZvckNoZWNrKCk7XG4gICAgfVxuXG4gICAgcmVzZXRWYWx1ZShldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuZGlzYWJsZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLndyaXRlVmFsdWUodW5kZWZpbmVkKTtcbiAgICAgICAgdGhpcy5zZWxlY3RlZENoYW5nZS5lbWl0KHVuZGVmaW5lZCk7XG4gICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIH1cblxuICAgIHNldERpc2FibGVkU3RhdGUoaXNEaXNhYmxlZDogYm9vbGVhbik6IHZvaWQge1xuICAgICAgICB0aGlzLmRpc2FibGVkID0gaXNEaXNhYmxlZDtcbiAgICAgICAgdGhpcy5fY2hhbmdlRGV0ZWN0b3IubWFya0ZvckNoZWNrKCk7XG4gICAgfVxuXG4gICAgb25NZW51T3BlbigpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuZHJvcGRvd25PcGVuICE9PSB0cnVlKSB7XG4gICAgICAgICAgICB0aGlzLmRyb3Bkb3duT3BlbiA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmRyb3Bkb3duT3BlbkNoYW5nZS5lbWl0KHRoaXMuZHJvcGRvd25PcGVuKTtcbiAgICAgICAgICAgIHRoaXMuX2ZvY3VzRmlsdGVyKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvbk1lbnVDbG9zZSgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuZHJvcGRvd25PcGVuICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgdGhpcy5kcm9wZG93bk9wZW4gPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMuZHJvcGRvd25PcGVuQ2hhbmdlLmVtaXQodGhpcy5kcm9wZG93bk9wZW4pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgX2ZvY3VzRmlsdGVyKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5maWx0ZXJJbnB1dEVsZW1lbnQpIHtcbiAgICAgICAgICAgIHRoaXMuZmlsdGVySW5wdXRFbGVtZW50Lm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlucHV0Rm9jdXNIYW5kbGVyKCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMuZHJvcGRvd25PcGVuKSB7XG4gICAgICAgICAgICB0aGlzLmRyb3Bkb3duT3BlbiA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmRyb3Bkb3duT3BlbkNoYW5nZS5lbWl0KHRoaXMuZHJvcGRvd25PcGVuKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHRvZ2dsZU1lbnUoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmRpc2FibGVkKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kcm9wZG93bk9wZW4gPSAhdGhpcy5kcm9wZG93bk9wZW47XG4gICAgICAgIHRoaXMuZHJvcGRvd25PcGVuQ2hhbmdlLmVtaXQodGhpcy5kcm9wZG93bk9wZW4pO1xuICAgICAgICB0aGlzLm1lbnVUcmlnZ2VyLnRvZ2dsZU1lbnUoKTtcbiAgICB9XG5cbiAgICBzZXRGaWx0ZXJCdXR0b25BcmlhTGFiZWwoKSB7XG4gICAgICAgIHRoaXMuX2ZpbHRlckJ1dHRvbkFyaWFMYWJlbCA9IHRoaXMuZmlsdGVyID09PSAnJ1xuICAgICAgICAgICAgPyB0aGlzLnNlYXJjaEZpbHRlckJ1dHRvbkFyaWFMYWJlbCA6IHRoaXMuY2xlYXJGaWx0ZXJCdXR0b25BcmlhTGFiZWw7XG4gICAgfVxufVxuIiwiPGRpdiBjbGFzcz1cInV4LXNlbGVjdC1jb250YWluZXJcIj5cbiAgPGJ1dHRvbiAjYnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgW3V4TWVudVRyaWdnZXJGb3JdPVwibWVudVwiXG4gICAgW2Rpc2FibGVkXT1cImRpc2FibGVkXCI+XG4gICAgPG5nLXRlbXBsYXRlICNkZWZhdWx0RGlzcGxheUNvbnRlbnQ+e3tzZWxlY3RlZCA/IChzZWxlY3RlZCB8IGpzb24pIDogJy0nfX08L25nLXRlbXBsYXRlPlxuICAgIDxuZy1jb250YWluZXIgW25nVGVtcGxhdGVPdXRsZXRdPVwiZGlzcGxheUNvbnRlbnRSZWYgfHwgZGVmYXVsdERpc3BsYXlDb250ZW50XCI+PC9uZy1jb250YWluZXI+XG4gIDwvYnV0dG9uPlxuICA8ZGl2IGNsYXNzPVwidXgtc2VsZWN0LWljb25zXCI+XG4gICAgQGlmIChhbGxvd051bGwgJiYgc2VsZWN0ZWQpIHtcbiAgICAgIDx1eC1pY29uIG5hbWU9XCJjbG9zZVwiXG4gICAgICAgIHV4Rm9jdXNJbmRpY2F0b3JcbiAgICAgICAgY2xhc3M9XCJ1eC1zZWxlY3QtaWNvbiB1eC1zZWxlY3QtY2xlYXItaWNvblwiXG4gICAgICAgIChjbGljayk9XCJyZXNldFZhbHVlKCRldmVudClcIlxuICAgICAgICAoa2V5ZG93bi5lbnRlcik9XCJyZXNldFZhbHVlKCRldmVudClcIlxuICAgICAgICB0YWJpbmRleD1cIjBcIj5cbiAgICAgIDwvdXgtaWNvbj5cbiAgICB9XG4gICAgPHV4LWljb24gbmFtZT1cImNoZXZyb24tZG93blwiXG4gICAgICBjbGFzcz1cInV4LXNlbGVjdC1pY29uIHV4LXNlbGVjdC1jaGV2cm9uLWljb25cIlxuICAgICAgKGNsaWNrKT1cInRvZ2dsZU1lbnUoKTsgJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCI+XG4gICAgPC91eC1pY29uPlxuICA8L2Rpdj5cbjwvZGl2PlxuXG48dXgtbWVudSAjbWVudSBtZW51Q2xhc3M9XCJzZWxlY3QtbWVudVwiXG4gIChvcGVuZWQpPVwib25NZW51T3BlbigpXCJcbiAgKGNsb3NlZCk9XCJvbk1lbnVDbG9zZSgpXCI+XG5cbiAgPGRpdiBbc3R5bGUubWF4LWhlaWdodF09XCJfbWF4SGVpZ2h0XCJcbiAgICBbc3R5bGUud2lkdGgucHhdPVwiYnV0dG9uLm9mZnNldFdpZHRoXCI+XG5cbiAgICBAaWYgKCFoaWRlRmlsdGVyKSB7XG4gICAgICA8ZGl2XG4gICAgICAgIGNsYXNzPVwiZmlsdGVyLWNvbnRhaW5lclwiPlxuICAgICAgICA8aW5wdXQgI2ZpbHRlcklucHV0XG4gICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCJwbGFjZWhvbGRlclwiXG4gICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgIFsobmdNb2RlbCldPVwiZmlsdGVyXCJcbiAgICAgICAgICAoaW5wdXQpPVwiZmlsdGVyQ2hhbmdlLmVtaXQoZmlsdGVyKVwiXG4gICAgICAgICAgKGNsaWNrKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiXG4gICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCJhcmlhTGFiZWwgfHwgcGxhY2Vob2xkZXJcIlxuICAgICAgICAgIFthdHRyLmFyaWEtbGFiZWxsZWRieV09XCJhcmlhTGFiZWxsZWRieVwiXG4gICAgICAgICAgKGZvY3VzKT1cImlucHV0Rm9jdXNIYW5kbGVyKClcIj5cbiAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWZsYXQgZmlsdGVyLWJ1dHRvblwiXG4gICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIl9maWx0ZXJCdXR0b25BcmlhTGFiZWxcIlxuICAgICAgICAgICAgKGNsaWNrKT1cInJlc2V0RmlsdGVyKCk7ICRldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcIlxuICAgICAgICAgICAgW3RhYmluZGV4XT1cImZpbHRlci5sZW5ndGggPiAwID8gMCA6IC0xXCI+XG4gICAgICAgICAgICA8dXgtaWNvbiBbbmFtZV09XCJmaWx0ZXIubGVuZ3RoID09PSAwID8gJ3NlYXJjaCcgOiAnY2xvc2UnXCI+PC91eC1pY29uPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIH1cblxuICAgICAgPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxuXG4gICAgPC9kaXY+XG4gIDwvdXgtbWVudT5cbiJdfQ==