fundamental-ngx
Version:
SAP Fundamentals, implemented in Angular
450 lines • 31.9 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Component, ElementRef, EventEmitter, forwardRef, Input, Output, QueryList, TemplateRef, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { MenuItemDirective } from '../menu/menu-item.directive';
import { MenuKeyboardService } from '../menu/menu-keyboard.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
/**
* Allows users to filter through results and select a value.
*
* Supports Angular Forms.
*/
export class ComboboxComponent {
/**
* @param {?} menuKeyboardService
*/
constructor(menuKeyboardService) {
this.menuKeyboardService = menuKeyboardService;
/**
* Values to be filtered in the search input.
*/
this.dropdownValues = [];
/**
* Filter function. Accepts an array of objects and a search term as arguments
* and returns a string. See search input examples for details.
*/
this.filterFn = this.defaultFilter;
/**
* Icon to display in the right-side button.
*/
this.glyph = 'navigation-down-arrow';
/**
* Max height of the popover. Any overflowing elements will be accessible through scrolling.
*/
this.maxHeight = '200px';
/**
* Whether the search input should be displayed in compact mode.
*/
this.compact = false;
/**
* Whether the matching string should be highlighted during filtration.
*/
this.highlighting = true;
/**
* Whether the popover should close when a user selects a result.
*/
this.closeOnSelect = true;
/**
* Whether the input field should be populated with the result picked by the user.
*/
this.fillOnSelect = true;
/**
* Display function. Accepts an object of the same type as the
* items passed to dropdownValues as argument, and outputs a string.
* An arrow function can be used to access the *this* keyword in the calling component.
* See search input examples for details.
*/
this.displayFn = this.defaultDisplay;
/**
* Event emitted when an item is clicked. Use *$event* to retrieve it.
*/
this.itemClicked = new EventEmitter();
/**
* @hidden
*/
this.displayedValues = [];
/**
* @hidden
*/
this.isOpen = false;
/**
* @hidden
*/
this.onDestroy$ = new Subject();
/**
* @hidden
*/
this.onChange = (/**
* @return {?}
*/
() => { });
/**
* @hidden
*/
this.onTouched = (/**
* @return {?}
*/
() => { });
}
/**
* @hidden
* @return {?}
*/
ngOnInit() {
if (this.dropdownValues) {
this.displayedValues = this.dropdownValues;
}
}
/**
* @hidden
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
if (this.dropdownValues && (changes.dropdownValues || changes.searchTerm)) {
if (this.inputText) {
this.displayedValues = this.filterFn(this.dropdownValues, this.inputText);
}
else {
this.displayedValues = this.dropdownValues;
}
}
}
/**
* @return {?}
*/
ngOnDestroy() {
this.onDestroy$.next();
this.onDestroy$.complete();
}
/**
* @hidden
* @return {?}
*/
ngAfterViewInit() {
this.menuKeyboardService.itemClicked
.pipe(takeUntil(this.onDestroy$))
.subscribe((/**
* @param {?} index
* @return {?}
*/
index => this.onMenuClickHandler(index)));
this.menuKeyboardService.focusEscapeBeforeList = (/**
* @return {?}
*/
() => this.searchInputElement.nativeElement.focus());
this.menuKeyboardService.focusEscapeAfterList = (/**
* @return {?}
*/
() => { });
}
/**
* @hidden
* @param {?} event
* @return {?}
*/
onInputKeydownHandler(event) {
if (event.code === 'Enter' && this.searchFunction) {
this.searchFunction();
}
else if (event.code === 'ArrowDown') {
event.preventDefault();
if (this.menuItems && this.menuItems.first) {
this.menuItems.first.focus();
}
}
}
/**
* @hidden
* @return {?}
*/
onInputKeyupHandler() {
if (this.inputText && this.inputText.length) {
this.isOpen = true;
}
}
/**
* @hidden
* @param {?} event
* @param {?} index
* @return {?}
*/
onMenuKeydownHandler(event, index) {
this.menuKeyboardService.keyDownHandler(event, index, this.menuItems.toArray());
}
/**
* @hidden
* @param {?} index
* @return {?}
*/
onMenuClickHandler(index) {
/** @type {?} */
const selectedItem = this.displayedValues[index];
if (selectedItem) {
this.handleClickActions(selectedItem);
this.itemClicked.emit({ item: selectedItem, index: index });
}
}
/**
* Get the input text of the input.
* @return {?}
*/
get inputText() {
return this.inputTextValue;
}
/**
* Set the input text of the input.
* @param {?} value
* @return {?}
*/
set inputText(value) {
this.inputTextValue = value;
this.onChange(value);
this.onTouched();
}
/**
* @hidden
* @param {?} value
* @return {?}
*/
writeValue(value) {
this.inputTextValue = value;
}
/**
* @hidden
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this.onChange = fn;
}
/**
* @hidden
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) {
this.onTouched = fn;
}
/**
* @hidden
* @return {?}
*/
handleSearchTermChange() {
this.displayedValues = this.filterFn(this.dropdownValues, this.inputText);
}
/**
* @private
* @param {?} str
* @return {?}
*/
defaultDisplay(str) {
return str;
}
/**
* @private
* @param {?} contentArray
* @param {?} searchTerm
* @return {?}
*/
defaultFilter(contentArray, searchTerm) {
/** @type {?} */
const searchLower = searchTerm.toLocaleLowerCase();
return contentArray.filter((/**
* @param {?} item
* @return {?}
*/
item => {
if (item) {
return this.displayFn(item).toLocaleLowerCase().includes(searchLower);
}
}));
}
/**
* @private
* @param {?} term
* @return {?}
*/
handleClickActions(term) {
if (this.closeOnSelect) {
this.isOpen = false;
}
if (this.fillOnSelect) {
this.inputText = this.displayFn(term);
this.handleSearchTermChange();
}
}
}
ComboboxComponent.decorators = [
{ type: Component, args: [{
selector: 'fd-combobox',
template: "<fd-popover [(isOpen)]=\"isOpen\"\n [fillControlMode]=\"'at-least'\"\n [disabled]=\"disabled\"\n class=\"fd-combobox-popover-custom\"\n [ngClass]=\"{'fd-popover-body--display-none': displayedValues && !displayedValues.length}\">\n <fd-popover-control>\n <div class=\"fd-combobox-control\">\n <div class=\"fd-input-group fd-input-group--after\" [ngClass]=\"{'fd-input-group--compact': compact}\">\n <input #searchInputElement type=\"text\" class=\"fd-input\" [ngClass]=\"{'fd-input--compact': compact}\"\n (keydown)=\"onInputKeydownHandler($event)\"\n (keyup)=\"onInputKeyupHandler()\"\n [disabled]=\"disabled\"\n [(ngModel)]=\"inputText\"\n (ngModelChange)=\"handleSearchTermChange()\"\n placeholder=\"{{placeholder}}\">\n <span class=\"fd-input-group__addon fd-input-group__addon--after fd-input-group__addon--button\">\n <button fd-button\n tabindex=\"-1\"\n type=\"button\"\n [fdType]=\"'light'\"\n [glyph]=\"glyph\"\n [disabled]=\"disabled\">\n </button>\n </span>\n </div>\n </div>\n </fd-popover-control>\n <fd-popover-body *ngIf=\"displayedValues && displayedValues.length\">\n <fd-menu class=\"fd-combobox-input-menu-overflow\"\n [style.maxHeight]=\"maxHeight\">\n <ng-content></ng-content>\n <ul fd-menu-list>\n <li *ngFor=\"let term of displayedValues; let index = index;\"\n (click)=\"onMenuClickHandler(index)\"\n (keydown)=\"onMenuKeydownHandler($event, index)\"\n fd-menu-item\n tabindex=\"0\">\n <span *ngIf=\"!itemTemplate\"\n [innerHTML]=\"term | displayFnPipe:displayFn | highlight:inputText:highlighting\"\n ></span>\n <ng-container *ngIf=\"itemTemplate\">\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: {$implicit: term}\"></ng-container>\n </ng-container>\n </li>\n </ul>\n </fd-menu>\n </fd-popover-body>\n</fd-popover>\n\n",
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => ComboboxComponent)),
multi: true
},
MenuKeyboardService
],
host: {
'[class.fd-combobox-custom-class]': 'true',
'[class.fd-combobox-input]': 'true'
},
encapsulation: ViewEncapsulation.None,
styles: [".fd-combobox-custom-class,.fd-combobox-custom-class .fd-combobox-popover-custom{display:block}.fd-combobox-custom-class .fd-combobox-input-menu-overflow{overflow:auto}"]
}] }
];
/** @nocollapse */
ComboboxComponent.ctorParameters = () => [
{ type: MenuKeyboardService }
];
ComboboxComponent.propDecorators = {
dropdownValues: [{ type: Input }],
filterFn: [{ type: Input }],
disabled: [{ type: Input }],
placeholder: [{ type: Input }],
glyph: [{ type: Input }],
itemTemplate: [{ type: Input }],
maxHeight: [{ type: Input }],
searchFunction: [{ type: Input }],
compact: [{ type: Input }],
highlighting: [{ type: Input }],
closeOnSelect: [{ type: Input }],
fillOnSelect: [{ type: Input }],
displayFn: [{ type: Input }],
itemClicked: [{ type: Output }],
menuItems: [{ type: ViewChildren, args: [MenuItemDirective,] }],
searchInputElement: [{ type: ViewChild, args: ['searchInputElement',] }]
};
if (false) {
/**
* Values to be filtered in the search input.
* @type {?}
*/
ComboboxComponent.prototype.dropdownValues;
/**
* Filter function. Accepts an array of objects and a search term as arguments
* and returns a string. See search input examples for details.
* @type {?}
*/
ComboboxComponent.prototype.filterFn;
/**
* Whether the search input is disabled. *
* @type {?}
*/
ComboboxComponent.prototype.disabled;
/**
* Placeholder of the search input. *
* @type {?}
*/
ComboboxComponent.prototype.placeholder;
/**
* Icon to display in the right-side button.
* @type {?}
*/
ComboboxComponent.prototype.glyph;
/**
* The template with which to display the individual listed items.
* Use it by passing an ng-template with implicit content. See examples for more info.
* @type {?}
*/
ComboboxComponent.prototype.itemTemplate;
/**
* Max height of the popover. Any overflowing elements will be accessible through scrolling.
* @type {?}
*/
ComboboxComponent.prototype.maxHeight;
/**
* Search function to execute when the Enter key is pressed on the main input.
* @type {?}
*/
ComboboxComponent.prototype.searchFunction;
/**
* Whether the search input should be displayed in compact mode.
* @type {?}
*/
ComboboxComponent.prototype.compact;
/**
* Whether the matching string should be highlighted during filtration.
* @type {?}
*/
ComboboxComponent.prototype.highlighting;
/**
* Whether the popover should close when a user selects a result.
* @type {?}
*/
ComboboxComponent.prototype.closeOnSelect;
/**
* Whether the input field should be populated with the result picked by the user.
* @type {?}
*/
ComboboxComponent.prototype.fillOnSelect;
/**
* Display function. Accepts an object of the same type as the
* items passed to dropdownValues as argument, and outputs a string.
* An arrow function can be used to access the *this* keyword in the calling component.
* See search input examples for details.
* @type {?}
*/
ComboboxComponent.prototype.displayFn;
/**
* Event emitted when an item is clicked. Use *$event* to retrieve it.
* @type {?}
*/
ComboboxComponent.prototype.itemClicked;
/**
* @hidden
* @type {?}
*/
ComboboxComponent.prototype.menuItems;
/**
* @hidden
* @type {?}
*/
ComboboxComponent.prototype.searchInputElement;
/**
* @hidden
* @type {?}
*/
ComboboxComponent.prototype.displayedValues;
/**
* @hidden
* @type {?}
*/
ComboboxComponent.prototype.isOpen;
/**
* @hidden
* @type {?}
*/
ComboboxComponent.prototype.inputTextValue;
/**
* @hidden
* @type {?}
* @private
*/
ComboboxComponent.prototype.onDestroy$;
/**
* @hidden
* @type {?}
*/
ComboboxComponent.prototype.onChange;
/**
* @hidden
* @type {?}
*/
ComboboxComponent.prototype.onTouched;
/**
* @type {?}
* @private
*/
ComboboxComponent.prototype.menuKeyboardService;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tYm9ib3guY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vZnVuZGFtZW50YWwtbmd4LyIsInNvdXJjZXMiOlsibGliL2NvbWJvYm94L2NvbWJvYm94LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUVILFNBQVMsRUFDVCxVQUFVLEVBQ1YsWUFBWSxFQUNaLFVBQVUsRUFDVixLQUFLLEVBR0wsTUFBTSxFQUNOLFNBQVMsRUFDTSxXQUFXLEVBQzFCLFNBQVMsRUFDVCxZQUFZLEVBQ1osaUJBQWlCLEVBQ3BCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBd0IsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUVoRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNwRSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQy9CLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7Ozs7O0FBeUIzQyxNQUFNLE9BQU8saUJBQWlCOzs7O0lBMkYxQixZQUFvQixtQkFBd0M7UUFBeEMsd0JBQW1CLEdBQW5CLG1CQUFtQixDQUFxQjs7OztRQXZGNUQsbUJBQWMsR0FBVSxFQUFFLENBQUM7Ozs7O1FBSzNCLGFBQVEsR0FBYSxJQUFJLENBQUMsYUFBYSxDQUFDOzs7O1FBWXhDLFVBQUssR0FBVyx1QkFBdUIsQ0FBQzs7OztRQVd4QyxjQUFTLEdBQVcsT0FBTyxDQUFDOzs7O1FBUTVCLFlBQU8sR0FBWSxLQUFLLENBQUM7Ozs7UUFJekIsaUJBQVksR0FBWSxJQUFJLENBQUM7Ozs7UUFJN0Isa0JBQWEsR0FBWSxJQUFJLENBQUM7Ozs7UUFJOUIsaUJBQVksR0FBWSxJQUFJLENBQUM7Ozs7Ozs7UUFPN0IsY0FBUyxHQUFhLElBQUksQ0FBQyxjQUFjLENBQUM7Ozs7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QUFpQjtpQ0FJOUIsU0FBUyxTQUFDLG9CQUFvQjs7Ozs7OztJQW5FL0IsMkNBQzJCOzs7Ozs7SUFJM0IscUNBQ3dDOzs7OztJQUd4QyxxQ0FDa0I7Ozs7O0lBR2xCLHdDQUNvQjs7Ozs7SUFHcEIsa0NBQ3dDOzs7Ozs7SUFNeEMseUNBQytCOzs7OztJQUcvQixzQ0FDNEI7Ozs7O0lBRzVCLDJDQUN5Qjs7Ozs7SUFHekIsb0NBQ3lCOzs7OztJQUd6Qix5Q0FDNkI7Ozs7O0lBRzdCLDBDQUM4Qjs7Ozs7SUFHOUIseUNBQzZCOzs7Ozs7OztJQU03QixzQ0FDMEM7Ozs7O0lBRzFDLHdDQUMyRTs7Ozs7SUFHM0Usc0NBQ3dDOzs7OztJQUd4QywrQ0FDK0I7Ozs7O0lBRy9CLDRDQUE0Qjs7Ozs7SUFHNUIsbUNBQXdCOzs7OztJQUd4QiwyQ0FBdUI7Ozs7OztJQUd2Qix1Q0FBaUU7Ozs7O0lBR2pFLHFDQUF5Qjs7Ozs7SUFHekIsc0NBQTBCOzs7OztJQUVkLGdEQUFnRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gICAgQWZ0ZXJWaWV3SW5pdCxcbiAgICBDb21wb25lbnQsXG4gICAgRWxlbWVudFJlZixcbiAgICBFdmVudEVtaXR0ZXIsXG4gICAgZm9yd2FyZFJlZixcbiAgICBJbnB1dCxcbiAgICBPbkNoYW5nZXMsIE9uRGVzdHJveSxcbiAgICBPbkluaXQsXG4gICAgT3V0cHV0LFxuICAgIFF1ZXJ5TGlzdCxcbiAgICBTaW1wbGVDaGFuZ2VzLCBUZW1wbGF0ZVJlZixcbiAgICBWaWV3Q2hpbGQsXG4gICAgVmlld0NoaWxkcmVuLFxuICAgIFZpZXdFbmNhcHN1bGF0aW9uXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29udHJvbFZhbHVlQWNjZXNzb3IsIE5HX1ZBTFVFX0FDQ0VTU09SIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgTWVudUl0ZW1EaXJlY3RpdmUgfSBmcm9tICcuLi9tZW51L21lbnUtaXRlbS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgQ29tYm9ib3hJdGVtIH0gZnJvbSAnLi9jb21ib2JveC1pdGVtJztcbmltcG9ydCB7IE1lbnVLZXlib2FyZFNlcnZpY2UgfSBmcm9tICcuLi9tZW51L21lbnUta2V5Ym9hcmQuc2VydmljZSc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbi8qKlxuICogQWxsb3dzIHVzZXJzIHRvIGZpbHRlciB0aHJvdWdoIHJlc3VsdHMgYW5kIHNlbGVjdCBhIHZhbHVlLlxuICpcbiAqIFN1cHBvcnRzIEFuZ3VsYXIgRm9ybXMuXG4gKi9cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnZmQtY29tYm9ib3gnLFxuICAgIHRlbXBsYXRlVXJsOiAnLi9jb21ib2JveC5jb21wb25lbnQuaHRtbCcsXG4gICAgc3R5bGVVcmxzOiBbJy4vY29tYm9ib3guY29tcG9uZW50LnNjc3MnXSxcbiAgICBwcm92aWRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXG4gICAgICAgICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBDb21ib2JveENvbXBvbmVudCksXG4gICAgICAgICAgICBtdWx0aTogdHJ1ZVxuICAgICAgICB9LFxuICAgICAgICBNZW51S2V5Ym9hcmRTZXJ2aWNlXG4gICAgXSxcbiAgICBob3N0OiB7XG4gICAgICAgICdbY2xhc3MuZmQtY29tYm9ib3gtY3VzdG9tLWNsYXNzXSc6ICd0cnVlJyxcbiAgICAgICAgJ1tjbGFzcy5mZC1jb21ib2JveC1pbnB1dF0nOiAndHJ1ZSdcbiAgICB9LFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmVcbn0pXG5leHBvcnQgY2xhc3MgQ29tYm9ib3hDb21wb25lbnQgaW1wbGVtZW50cyBDb250cm9sVmFsdWVBY2Nlc3NvciwgT25Jbml0LCBPbkNoYW5nZXMsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG5cbiAgICAvKiogVmFsdWVzIHRvIGJlIGZpbHRlcmVkIGluIHRoZSBzZWFyY2ggaW5wdXQuICovXG4gICAgQElucHV0KClcbiAgICBkcm9wZG93blZhbHVlczogYW55W10gPSBbXTtcblxuICAgIC8qKiBGaWx0ZXIgZnVuY3Rpb24uIEFjY2VwdHMgYW4gYXJyYXkgb2Ygb2JqZWN0cyBhbmQgYSBzZWFyY2ggdGVybSBhcyBhcmd1bWVudHNcbiAgICAgKiBhbmQgcmV0dXJucyBhIHN0cmluZy4gU2VlIHNlYXJjaCBpbnB1dCBleGFtcGxlcyBmb3IgZGV0YWlscy4gKi9cbiAgICBASW5wdXQoKVxuICAgIGZpbHRlckZuOiBGdW5jdGlvbiA9IHRoaXMuZGVmYXVsdEZpbHRlcjtcblxuICAgIC8qKiBXaGV0aGVyIHRoZSBzZWFyY2ggaW5wdXQgaXMgZGlzYWJsZWQuICoqL1xuICAgIEBJbnB1dCgpXG4gICAgZGlzYWJsZWQ6IGJvb2xlYW47XG5cbiAgICAvKiogUGxhY2Vob2xkZXIgb2YgdGhlIHNlYXJjaCBpbnB1dC4gKiovXG4gICAgQElucHV0KClcbiAgICBwbGFjZWhvbGRlcjogc3RyaW5nO1xuXG4gICAgLyoqIEljb24gdG8gZGlzcGxheSBpbiB0aGUgcmlnaHQtc2lkZSBidXR0b24uICovXG4gICAgQElucHV0KClcbiAgICBnbHlwaDogc3RyaW5nID0gJ25hdmlnYXRpb24tZG93bi1hcnJvdyc7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGVtcGxhdGUgd2l0aCB3aGljaCB0byBkaXNwbGF5IHRoZSBpbmRpdmlkdWFsIGxpc3RlZCBpdGVtcy5cbiAgICAgKiBVc2UgaXQgYnkgcGFzc2luZyBhbiBuZy10ZW1wbGF0ZSB3aXRoIGltcGxpY2l0IGNvbnRlbnQuIFNlZSBleGFtcGxlcyBmb3IgbW9yZSBpbmZvLlxuICAgICAqL1xuICAgIEBJbnB1dCgpXG4gICAgaXRlbVRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xuXG4gICAgLyoqIE1heCBoZWlnaHQgb2YgdGhlIHBvcG92ZXIuIEFueSBvdmVyZmxvd2luZyBlbGVtZW50cyB3aWxsIGJlIGFjY2Vzc2libGUgdGhyb3VnaCBzY3JvbGxpbmcuICovXG4gICAgQElucHV0KClcbiAgICBtYXhIZWlnaHQ6IHN0cmluZyA9ICcyMDBweCc7XG5cbiAgICAvKiogU2VhcmNoIGZ1bmN0aW9uIHRvIGV4ZWN1dGUgd2hlbiB0aGUgRW50ZXIga2V5IGlzIHByZXNzZWQgb24gdGhlIG1haW4gaW5wdXQuICovXG4gICAgQElucHV0KClcbiAgICBzZWFyY2hGdW5jdGlvbjogRnVuY3Rpb247XG5cbiAgICAvKiogV2hldGhlciB0aGUgc2VhcmNoIGlucHV0IHNob3VsZCBiZSBkaXNwbGF5ZWQgaW4gY29tcGFjdCBtb2RlLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgY29tcGFjdDogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgLyoqIFdoZXRoZXIgdGhlIG1hdGNoaW5nIHN0cmluZyBzaG91bGQgYmUgaGlnaGxpZ2h0ZWQgZHVyaW5nIGZpbHRyYXRpb24uICovXG4gICAgQElucHV0KClcbiAgICBoaWdobGlnaHRpbmc6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgLyoqIFdoZXRoZXIgdGhlIHBvcG92ZXIgc2hvdWxkIGNsb3NlIHdoZW4gYSB1c2VyIHNlbGVjdHMgYSByZXN1bHQuICovXG4gICAgQElucHV0KClcbiAgICBjbG9zZU9uU2VsZWN0OiBib29sZWFuID0gdHJ1ZTtcblxuICAgIC8qKiBXaGV0aGVyIHRoZSBpbnB1dCBmaWVsZCBzaG91bGQgYmUgcG9wdWxhdGVkIHdpdGggdGhlIHJlc3VsdCBwaWNrZWQgYnkgdGhlIHVzZXIuICovXG4gICAgQElucHV0KClcbiAgICBmaWxsT25TZWxlY3Q6IGJvb2xlYW4gPSB0cnVlO1xuXG4gICAgLyoqIERpc3BsYXkgZnVuY3Rpb24uIEFjY2VwdHMgYW4gb2JqZWN0IG9mIHRoZSBzYW1lIHR5cGUgYXMgdGhlXG4gICAgICogaXRlbXMgcGFzc2VkIHRvIGRyb3Bkb3duVmFsdWVzIGFzIGFyZ3VtZW50LCBhbmQgb3V0cHV0cyBhIHN0cmluZy5cbiAgICAgKiBBbiBhcnJvdyBmdW5jdGlvbiBjYW4gYmUgdXNlZCB0byBhY2Nlc3MgdGhlICp0aGlzKiBrZXl3b3JkIGluIHRoZSBjYWxsaW5nIGNvbXBvbmVudC5cbiAgICAgKiBTZWUgc2VhcmNoIGlucHV0IGV4YW1wbGVzIGZvciBkZXRhaWxzLiAqL1xuICAgIEBJbnB1dCgpXG4gICAgZGlzcGxheUZuOiBGdW5jdGlvbiA9IHRoaXMuZGVmYXVsdERpc3BsYXk7XG5cbiAgICAvKiogRXZlbnQgZW1pdHRlZCB3aGVuIGFuIGl0ZW0gaXMgY2xpY2tlZC4gVXNlICokZXZlbnQqIHRvIHJldHJpZXZlIGl0LiAqL1xuICAgIEBPdXRwdXQoKVxuICAgIGl0ZW1DbGlja2VkOiBFdmVudEVtaXR0ZXI8Q29tYm9ib3hJdGVtPiA9IG5ldyBFdmVudEVtaXR0ZXI8Q29tYm9ib3hJdGVtPigpO1xuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBAVmlld0NoaWxkcmVuKE1lbnVJdGVtRGlyZWN0aXZlKVxuICAgIG1lbnVJdGVtczogUXVlcnlMaXN0PE1lbnVJdGVtRGlyZWN0aXZlPjtcblxuICAgIC8qKiBAaGlkZGVuICovXG4gICAgQFZpZXdDaGlsZCgnc2VhcmNoSW5wdXRFbGVtZW50JylcbiAgICBzZWFyY2hJbnB1dEVsZW1lbnQ6IEVsZW1lbnRSZWY7XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIGRpc3BsYXllZFZhbHVlczogYW55W10gPSBbXTtcblxuICAgIC8qKiBAaGlkZGVuICovXG4gICAgaXNPcGVuOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIGlucHV0VGV4dFZhbHVlOiBzdHJpbmc7XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgb25EZXN0cm95JDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG9uQ2hhbmdlOiBhbnkgPSAoKSA9PiB7fTtcblxuICAgIC8qKiBAaGlkZGVuICovXG4gICAgb25Ub3VjaGVkOiBhbnkgPSAoKSA9PiB7fTtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgbWVudUtleWJvYXJkU2VydmljZTogTWVudUtleWJvYXJkU2VydmljZSkge31cblxuICAgIC8qKiBAaGlkZGVuICovXG4gICAgbmdPbkluaXQoKSB7XG4gICAgICAgIGlmICh0aGlzLmRyb3Bkb3duVmFsdWVzKSB7XG4gICAgICAgICAgICB0aGlzLmRpc3BsYXllZFZhbHVlcyA9IHRoaXMuZHJvcGRvd25WYWx1ZXM7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpIHtcbiAgICAgICAgaWYgKHRoaXMuZHJvcGRvd25WYWx1ZXMgJiYgKGNoYW5nZXMuZHJvcGRvd25WYWx1ZXMgfHwgY2hhbmdlcy5zZWFyY2hUZXJtKSkge1xuICAgICAgICAgICAgaWYgKHRoaXMuaW5wdXRUZXh0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwbGF5ZWRWYWx1ZXMgPSB0aGlzLmZpbHRlckZuKHRoaXMuZHJvcGRvd25WYWx1ZXMsIHRoaXMuaW5wdXRUZXh0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwbGF5ZWRWYWx1ZXMgPSB0aGlzLmRyb3Bkb3duVmFsdWVzO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIHRoaXMub25EZXN0cm95JC5uZXh0KCk7XG4gICAgICAgIHRoaXMub25EZXN0cm95JC5jb21wbGV0ZSgpO1xuICAgIH1cblxuICAgIC8qKiBAaGlkZGVuICovXG4gICAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLm1lbnVLZXlib2FyZFNlcnZpY2UuaXRlbUNsaWNrZWRcbiAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLm9uRGVzdHJveSQpKVxuICAgICAgICAgICAgLnN1YnNjcmliZShpbmRleCA9PiB0aGlzLm9uTWVudUNsaWNrSGFuZGxlcihpbmRleCkpO1xuICAgICAgICB0aGlzLm1lbnVLZXlib2FyZFNlcnZpY2UuZm9jdXNFc2NhcGVCZWZvcmVMaXN0ID0gKCkgPT4gdGhpcy5zZWFyY2hJbnB1dEVsZW1lbnQubmF0aXZlRWxlbWVudC5mb2N1cygpO1xuICAgICAgICB0aGlzLm1lbnVLZXlib2FyZFNlcnZpY2UuZm9jdXNFc2NhcGVBZnRlckxpc3QgPSAoKSA9PiB7fTtcbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG9uSW5wdXRLZXlkb3duSGFuZGxlcihldmVudCkge1xuICAgICAgICBpZiAoZXZlbnQuY29kZSA9PT0gJ0VudGVyJyAmJiB0aGlzLnNlYXJjaEZ1bmN0aW9uKSB7XG4gICAgICAgICAgICB0aGlzLnNlYXJjaEZ1bmN0aW9uKCk7XG4gICAgICAgIH0gZWxzZSBpZiAoZXZlbnQuY29kZSA9PT0gJ0Fycm93RG93bicpIHtcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICBpZiAodGhpcy5tZW51SXRlbXMgJiYgdGhpcy5tZW51SXRlbXMuZmlyc3QpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm1lbnVJdGVtcy5maXJzdC5mb2N1cygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBvbklucHV0S2V5dXBIYW5kbGVyKCkge1xuICAgICAgICBpZiAodGhpcy5pbnB1dFRleHQgJiYgdGhpcy5pbnB1dFRleHQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLmlzT3BlbiA9IHRydWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIG9uTWVudUtleWRvd25IYW5kbGVyKGV2ZW50OiBLZXlib2FyZEV2ZW50LCBpbmRleDogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMubWVudUtleWJvYXJkU2VydmljZS5rZXlEb3duSGFuZGxlcihldmVudCwgaW5kZXgsIHRoaXMubWVudUl0ZW1zLnRvQXJyYXkoKSk7XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBvbk1lbnVDbGlja0hhbmRsZXIoaW5kZXg6IG51bWJlcikge1xuICAgICAgICBjb25zdCBzZWxlY3RlZEl0ZW0gPSB0aGlzLmRpc3BsYXllZFZhbHVlc1tpbmRleF07XG4gICAgICAgIGlmIChzZWxlY3RlZEl0ZW0pIHtcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlQ2xpY2tBY3Rpb25zKHNlbGVjdGVkSXRlbSk7XG4gICAgICAgICAgICB0aGlzLml0ZW1DbGlja2VkLmVtaXQoeyBpdGVtOiBzZWxlY3RlZEl0ZW0sIGluZGV4OiBpbmRleCB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBHZXQgdGhlIGlucHV0IHRleHQgb2YgdGhlIGlucHV0LiAqL1xuICAgIGdldCBpbnB1dFRleHQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmlucHV0VGV4dFZhbHVlO1xuICAgIH1cblxuICAgIC8qKiBTZXQgdGhlIGlucHV0IHRleHQgb2YgdGhlIGlucHV0LiAqL1xuICAgIHNldCBpbnB1dFRleHQodmFsdWUpIHtcbiAgICAgICAgdGhpcy5pbnB1dFRleHRWYWx1ZSA9IHZhbHVlO1xuICAgICAgICB0aGlzLm9uQ2hhbmdlKHZhbHVlKTtcbiAgICAgICAgdGhpcy5vblRvdWNoZWQoKTtcbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIHdyaXRlVmFsdWUodmFsdWU6IGFueSkge1xuICAgICAgICB0aGlzLmlucHV0VGV4dFZhbHVlID0gdmFsdWU7XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICByZWdpc3Rlck9uQ2hhbmdlKGZuKSB7XG4gICAgICAgIHRoaXMub25DaGFuZ2UgPSBmbjtcbiAgICB9XG5cbiAgICAvKiogQGhpZGRlbiAqL1xuICAgIHJlZ2lzdGVyT25Ub3VjaGVkKGZuKSB7XG4gICAgICAgIHRoaXMub25Ub3VjaGVkID0gZm47XG4gICAgfVxuXG4gICAgLyoqIEBoaWRkZW4gKi9cbiAgICBoYW5kbGVTZWFyY2hUZXJtQ2hhbmdlKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmRpc3BsYXllZFZhbHVlcyA9IHRoaXMuZmlsdGVyRm4odGhpcy5kcm9wZG93blZhbHVlcywgdGhpcy5pbnB1dFRleHQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgZGVmYXVsdERpc3BsYXkoc3RyOiBhbnkpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gc3RyO1xuICAgIH1cblxuICAgIHByaXZhdGUgZGVmYXVsdEZpbHRlcihjb250ZW50QXJyYXk6IGFueVtdLCBzZWFyY2hUZXJtOiBzdHJpbmcpOiBhbnlbXSB7XG4gICAgICAgIGNvbnN0IHNlYXJjaExvd2VyID0gc2VhcmNoVGVybS50b0xvY2FsZUxvd2VyQ2FzZSgpO1xuICAgICAgICByZXR1cm4gY29udGVudEFycmF5LmZpbHRlcihpdGVtID0+IHtcbiAgICAgICAgICAgIGlmIChpdGVtKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGlzcGxheUZuKGl0ZW0pLnRvTG9jYWxlTG93ZXJDYXNlKCkuaW5jbHVkZXMoc2VhcmNoTG93ZXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGhhbmRsZUNsaWNrQWN0aW9ucyh0ZXJtKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmNsb3NlT25TZWxlY3QpIHtcbiAgICAgICAgICAgIHRoaXMuaXNPcGVuID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuZmlsbE9uU2VsZWN0KSB7XG4gICAgICAgICAgICB0aGlzLmlucHV0VGV4dCA9IHRoaXMuZGlzcGxheUZuKHRlcm0pO1xuICAgICAgICAgICAgdGhpcy5oYW5kbGVTZWFyY2hUZXJtQ2hhbmdlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbn1cbiJdfQ==