angular-text-input-autocomplete
Version:
A angular 6+ directive for adding autocomplete functionality to text input elements, built around composability
354 lines (353 loc) • 32.7 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
import { ComponentFactoryResolver, Directive, ElementRef, EventEmitter, HostListener, Injector, Input, Output, ViewContainerRef } from '@angular/core';
import getCaretCoordinates from 'textarea-caret';
import { takeUntil } from 'rxjs/operators';
import { TextInputAutocompleteMenuComponent } from './text-input-autocomplete-menu.component';
import { Subject } from 'rxjs';
import toPX from 'to-px';
/**
* @record
*/
export function ChoiceSelectedEvent() { }
function ChoiceSelectedEvent_tsickle_Closure_declarations() {
/** @type {?} */
ChoiceSelectedEvent.prototype.choice;
/** @type {?} */
ChoiceSelectedEvent.prototype.insertedAt;
}
var TextInputAutocompleteDirective = /** @class */ (function () {
function TextInputAutocompleteDirective(componentFactoryResolver, viewContainerRef, injector, elm) {
this.componentFactoryResolver = componentFactoryResolver;
this.viewContainerRef = viewContainerRef;
this.injector = injector;
this.elm = elm;
/**
* The character that will trigger the menu to appear
*/
this.triggerCharacter = '@';
/**
* The regular expression that will match the search text after the trigger character
*/
this.searchRegexp = /^\w*$/;
/**
* Whether to close the menu when the host textarea loses focus
*/
this.closeMenuOnBlur = false;
/**
* The menu component to show with available options.
* You can extend the built in `TextInputAutocompleteMenuComponent` component to use a custom template
*/
this.menuComponent = TextInputAutocompleteMenuComponent;
/**
* Called when the options menu is shown
*/
this.menuShown = new EventEmitter();
/**
* Called when the options menu is hidden
*/
this.menuHidden = new EventEmitter();
/**
* Called when a choice is selected
*/
this.choiceSelected = new EventEmitter();
/**
* A function that formats the selected choice once selected.
*/
this.getChoiceLabel = function (choice) { return choice; };
this.menuHidden$ = new Subject();
this.usingShortcut = false;
}
/**
* @param {?} key
* @return {?}
*/
TextInputAutocompleteDirective.prototype.onKeypress = /**
* @param {?} key
* @return {?}
*/
function (key) {
if (key === this.triggerCharacter) {
this.usingShortcut = false;
this.showMenu();
}
};
/**
* @param {?} event
* @return {?}
*/
TextInputAutocompleteDirective.prototype.onKeyDown = /**
* @param {?} event
* @return {?}
*/
function (event) {
if (this.keyboardShortcut && this.keyboardShortcut(event)) {
this.usingShortcut = true;
this.showMenu();
this.onChange('');
}
};
/**
* @param {?} value
* @return {?}
*/
TextInputAutocompleteDirective.prototype.onChange = /**
* @param {?} value
* @return {?}
*/
function (value) {
var _this = this;
if (this.menu) {
if (value[this.menu.triggerCharacterPosition] !== this.triggerCharacter &&
!this.usingShortcut) {
this.hideMenu();
}
else {
var /** @type {?} */ cursor = this.elm.nativeElement.selectionStart;
if (cursor < this.menu.triggerCharacterPosition) {
this.hideMenu();
}
else {
if (this.usingShortcut && !this.menu) {
value = this.triggerCharacter;
}
var /** @type {?} */ offset = this.usingShortcut ? 0 : 1;
var /** @type {?} */ searchText = value.slice(this.menu.triggerCharacterPosition + offset, cursor);
if (!searchText.match(this.searchRegexp)) {
this.hideMenu();
}
else {
this.menu.component.instance.searchText = searchText;
this.menu.component.instance.choices = [];
this.menu.component.instance.choiceLoadError = undefined;
this.menu.component.instance.choiceLoading = true;
this.menu.component.changeDetectorRef.detectChanges();
Promise.resolve(this.findChoices(searchText))
.then(function (choices) {
if (_this.menu) {
_this.menu.component.instance.choices = choices;
_this.menu.component.instance.choiceLoading = false;
_this.menu.component.changeDetectorRef.detectChanges();
}
})
.catch(function (err) {
if (_this.menu) {
_this.menu.component.instance.choiceLoading = false;
_this.menu.component.instance.choiceLoadError = err;
_this.menu.component.changeDetectorRef.detectChanges();
}
});
}
}
}
}
};
/**
* @return {?}
*/
TextInputAutocompleteDirective.prototype.onBlur = /**
* @return {?}
*/
function () {
if (this.menu) {
this.menu.lastCaretPosition = this.elm.nativeElement.selectionStart;
if (this.closeMenuOnBlur === true) {
this.hideMenu();
}
}
};
/**
* @return {?}
*/
TextInputAutocompleteDirective.prototype.showMenu = /**
* @return {?}
*/
function () {
var _this = this;
if (!this.menu) {
var /** @type {?} */ menuFactory = this.componentFactoryResolver.resolveComponentFactory(this.menuComponent);
this.menu = {
component: this.viewContainerRef.createComponent(menuFactory, 0, this.injector),
triggerCharacterPosition: this.elm.nativeElement.selectionStart
};
var /** @type {?} */ lineHeight = this.getLineHeight(this.elm.nativeElement);
var _a = getCaretCoordinates(this.elm.nativeElement, this.elm.nativeElement.selectionStart), top_1 = _a.top, left = _a.left;
this.menu.component.instance.position = {
top: top_1 + lineHeight,
left: left
};
this.menu.component.changeDetectorRef.detectChanges();
this.menu.component.instance.selectChoice
.pipe(takeUntil(this.menuHidden$))
.subscribe(function (choice) {
var /** @type {?} */ label = _this.getChoiceLabel(choice);
var /** @type {?} */ textarea = _this.elm.nativeElement;
var /** @type {?} */ value = textarea.value;
var /** @type {?} */ startIndex = /** @type {?} */ ((_this.menu)).triggerCharacterPosition;
var /** @type {?} */ start = value.slice(0, startIndex);
var /** @type {?} */ caretPosition = /** @type {?} */ ((_this.menu)).lastCaretPosition || textarea.selectionStart;
var /** @type {?} */ end = value.slice(caretPosition);
textarea.value = start + label + end;
// force ng model / form control to update
textarea.dispatchEvent(new Event('input'));
_this.hideMenu();
var /** @type {?} */ setCursorAt = (start + label).length;
textarea.setSelectionRange(setCursorAt, setCursorAt);
textarea.focus();
_this.choiceSelected.emit({
choice: choice,
insertedAt: {
start: startIndex,
end: startIndex + label.length
}
});
});
this.menuShown.emit();
}
};
/**
* @param {?} elm
* @return {?}
*/
TextInputAutocompleteDirective.prototype.getLineHeight = /**
* @param {?} elm
* @return {?}
*/
function (elm) {
var /** @type {?} */ lineHeightStr = getComputedStyle(elm).lineHeight || '';
var /** @type {?} */ fontSizeStr = getComputedStyle(elm).fontSize || '';
var /** @type {?} */ fontSize = +toPX(fontSizeStr);
var /** @type {?} */ normal = 1.2;
var /** @type {?} */ lineHeightNum = parseFloat(lineHeightStr);
if (lineHeightStr === lineHeightNum + '') {
return fontSize * lineHeightNum;
}
if (lineHeightStr.toLowerCase() === 'normal') {
return fontSize * normal;
}
return toPX(lineHeightStr);
};
/**
* @return {?}
*/
TextInputAutocompleteDirective.prototype.hideMenu = /**
* @return {?}
*/
function () {
if (this.menu) {
this.menu.component.destroy();
this.menuHidden$.next();
this.menuHidden.emit();
this.menu = undefined;
}
};
/**
* @return {?}
*/
TextInputAutocompleteDirective.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
this.hideMenu();
};
TextInputAutocompleteDirective.decorators = [
{ type: Directive, args: [{
selector: 'textarea[mwlTextInputAutocomplete],input[type="text"][mwlTextInputAutocomplete]'
},] },
];
/** @nocollapse */
TextInputAutocompleteDirective.ctorParameters = function () { return [
{ type: ComponentFactoryResolver },
{ type: ViewContainerRef },
{ type: Injector },
{ type: ElementRef }
]; };
TextInputAutocompleteDirective.propDecorators = {
triggerCharacter: [{ type: Input }],
keyboardShortcut: [{ type: Input }],
searchRegexp: [{ type: Input }],
closeMenuOnBlur: [{ type: Input }],
menuComponent: [{ type: Input }],
menuShown: [{ type: Output }],
menuHidden: [{ type: Output }],
choiceSelected: [{ type: Output }],
findChoices: [{ type: Input }],
getChoiceLabel: [{ type: Input }],
onKeypress: [{ type: HostListener, args: ['keypress', ['$event.key'],] }],
onKeyDown: [{ type: HostListener, args: ['keydown', ['$event'],] }],
onChange: [{ type: HostListener, args: ['input', ['$event.target.value'],] }],
onBlur: [{ type: HostListener, args: ['blur',] }]
};
return TextInputAutocompleteDirective;
}());
export { TextInputAutocompleteDirective };
function TextInputAutocompleteDirective_tsickle_Closure_declarations() {
/**
* The character that will trigger the menu to appear
* @type {?}
*/
TextInputAutocompleteDirective.prototype.triggerCharacter;
/**
* An optional keyboard shortcut that will trigger the menu to appear
* @type {?}
*/
TextInputAutocompleteDirective.prototype.keyboardShortcut;
/**
* The regular expression that will match the search text after the trigger character
* @type {?}
*/
TextInputAutocompleteDirective.prototype.searchRegexp;
/**
* Whether to close the menu when the host textarea loses focus
* @type {?}
*/
TextInputAutocompleteDirective.prototype.closeMenuOnBlur;
/**
* The menu component to show with available options.
* You can extend the built in `TextInputAutocompleteMenuComponent` component to use a custom template
* @type {?}
*/
TextInputAutocompleteDirective.prototype.menuComponent;
/**
* Called when the options menu is shown
* @type {?}
*/
TextInputAutocompleteDirective.prototype.menuShown;
/**
* Called when the options menu is hidden
* @type {?}
*/
TextInputAutocompleteDirective.prototype.menuHidden;
/**
* Called when a choice is selected
* @type {?}
*/
TextInputAutocompleteDirective.prototype.choiceSelected;
/**
* A function that accepts a search string and returns an array of choices. Can also return a promise.
* @type {?}
*/
TextInputAutocompleteDirective.prototype.findChoices;
/**
* A function that formats the selected choice once selected.
* @type {?}
*/
TextInputAutocompleteDirective.prototype.getChoiceLabel;
/** @type {?} */
TextInputAutocompleteDirective.prototype.menu;
/** @type {?} */
TextInputAutocompleteDirective.prototype.menuHidden$;
/** @type {?} */
TextInputAutocompleteDirective.prototype.usingShortcut;
/** @type {?} */
TextInputAutocompleteDirective.prototype.componentFactoryResolver;
/** @type {?} */
TextInputAutocompleteDirective.prototype.viewContainerRef;
/** @type {?} */
TextInputAutocompleteDirective.prototype.injector;
/** @type {?} */
TextInputAutocompleteDirective.prototype.elm;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGV4dC1pbnB1dC1hdXRvY29tcGxldGUuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6Im5nOi8vYW5ndWxhci10ZXh0LWlucHV0LWF1dG9jb21wbGV0ZS8iLCJzb3VyY2VzIjpbInRleHQtaW5wdXQtYXV0b2NvbXBsZXRlLmRpcmVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUNMLHdCQUF3QixFQUV4QixTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixZQUFZLEVBQ1osUUFBUSxFQUNSLEtBQUssRUFFTCxNQUFNLEVBQ04sZ0JBQWdCLEVBQ2pCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sbUJBQW1CLE1BQU0sZ0JBQWdCLENBQUM7QUFDakQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzNDLE9BQU8sRUFBRSxrQ0FBa0MsRUFBRSxNQUFNLDBDQUEwQyxDQUFDO0FBQzlGLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFL0IsT0FBTyxJQUFJLE1BQU0sT0FBTyxDQUFDOzs7Ozs7Ozs7Ozs7SUErRXZCLHdDQUNVLDBCQUNBLGtCQUNBLFVBQ0E7UUFIQSw2QkFBd0IsR0FBeEIsd0JBQXdCO1FBQ3hCLHFCQUFnQixHQUFoQixnQkFBZ0I7UUFDaEIsYUFBUSxHQUFSLFFBQVE7UUFDUixRQUFHLEdBQUgsR0FBRzs7OztnQ0FqRWUsR0FBRzs7Ozs0QkFVUCxPQUFPOzs7OytCQUtKLEtBQUs7Ozs7OzZCQU1QLGtDQUFrQzs7Ozt5QkFLckMsSUFBSSxZQUFZLEVBQUU7Ozs7MEJBS2pCLElBQUksWUFBWSxFQUFFOzs7OzhCQUtkLElBQUksWUFBWSxFQUF1Qjs7Ozs4QkFVZixVQUFBLE1BQU0sSUFBSSxPQUFBLE1BQU0sRUFBTixDQUFNOzJCQVc3QyxJQUFJLE9BQU8sRUFBRTs2QkFFWCxLQUFLO0tBT3pCOzs7OztJQUdKLG1EQUFVOzs7O0lBRFYsVUFDVyxHQUFXO1FBQ3BC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Q0FBQzsyQkFTbEMsWUFBWSxTQUFDLE9BQU8sRUFBRSxDQUFDLHFCQUFxQixDQUFDO3lCQW1EN0MsWUFBWSxTQUFDLE1BQU07O3lDQTVLdEI7O1NBZ0NhLDhCQUE4QiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudEZhY3RvcnlSZXNvbHZlcixcbiAgQ29tcG9uZW50UmVmLFxuICBEaXJlY3RpdmUsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgSG9zdExpc3RlbmVyLFxuICBJbmplY3RvcixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT3V0cHV0LFxuICBWaWV3Q29udGFpbmVyUmVmXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IGdldENhcmV0Q29vcmRpbmF0ZXMgZnJvbSAndGV4dGFyZWEtY2FyZXQnO1xuaW1wb3J0IHsgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgVGV4dElucHV0QXV0b2NvbXBsZXRlTWVudUNvbXBvbmVudCB9IGZyb20gJy4vdGV4dC1pbnB1dC1hdXRvY29tcGxldGUtbWVudS5jb21wb25lbnQnO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuLy8gQHRzLWlnbm9yZVxuaW1wb3J0IHRvUFggZnJvbSAndG8tcHgnO1xuXG5leHBvcnQgaW50ZXJmYWNlIENob2ljZVNlbGVjdGVkRXZlbnQge1xuICBjaG9pY2U6IGFueTtcbiAgaW5zZXJ0ZWRBdDoge1xuICAgIHN0YXJ0OiBudW1iZXI7XG4gICAgZW5kOiBudW1iZXI7XG4gIH07XG59XG5cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjpcbiAgICAndGV4dGFyZWFbbXdsVGV4dElucHV0QXV0b2NvbXBsZXRlXSxpbnB1dFt0eXBlPVwidGV4dFwiXVttd2xUZXh0SW5wdXRBdXRvY29tcGxldGVdJ1xufSlcbmV4cG9ydCBjbGFzcyBUZXh0SW5wdXRBdXRvY29tcGxldGVEaXJlY3RpdmUgaW1wbGVtZW50cyBPbkRlc3Ryb3kge1xuICAvKipcbiAgICogVGhlIGNoYXJhY3RlciB0aGF0IHdpbGwgdHJpZ2dlciB0aGUgbWVudSB0byBhcHBlYXJcbiAgICovXG4gIEBJbnB1dCgpIHRyaWdnZXJDaGFyYWN0ZXIgPSAnQCc7XG5cbiAgLyoqXG4gICAqIEFuIG9wdGlvbmFsIGtleWJvYXJkIHNob3J0Y3V0IHRoYXQgd2lsbCB0cmlnZ2VyIHRoZSBtZW51IHRvIGFwcGVhclxuICAgKi9cbiAgQElucHV0KCkga2V5Ym9hcmRTaG9ydGN1dDogKGV2ZW50OiBLZXlib2FyZEV2ZW50KSA9PiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBUaGUgcmVndWxhciBleHByZXNzaW9uIHRoYXQgd2lsbCBtYXRjaCB0aGUgc2VhcmNoIHRleHQgYWZ0ZXIgdGhlIHRyaWdnZXIgY2hhcmFjdGVyXG4gICAqL1xuICBASW5wdXQoKSBzZWFyY2hSZWdleHAgPSAvXlxcdyokLztcblxuICAvKipcbiAgICogV2hldGhlciB0byBjbG9zZSB0aGUgbWVudSB3aGVuIHRoZSBob3N0IHRleHRhcmVhIGxvc2VzIGZvY3VzXG4gICAqL1xuICBASW5wdXQoKSBjbG9zZU1lbnVPbkJsdXIgPSBmYWxzZTtcblxuICAvKipcbiAgICogVGhlIG1lbnUgY29tcG9uZW50IHRvIHNob3cgd2l0aCBhdmFpbGFibGUgb3B0aW9ucy5cbiAgICogWW91IGNhbiBleHRlbmQgdGhlIGJ1aWx0IGluIGBUZXh0SW5wdXRBdXRvY29tcGxldGVNZW51Q29tcG9uZW50YCBjb21wb25lbnQgdG8gdXNlIGEgY3VzdG9tIHRlbXBsYXRlXG4gICAqL1xuICBASW5wdXQoKSBtZW51Q29tcG9uZW50ID0gVGV4dElucHV0QXV0b2NvbXBsZXRlTWVudUNvbXBvbmVudDtcblxuICAvKipcbiAgICogQ2FsbGVkIHdoZW4gdGhlIG9wdGlvbnMgbWVudSBpcyBzaG93blxuICAgKi9cbiAgQE91dHB1dCgpIG1lbnVTaG93biA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAvKipcbiAgICogQ2FsbGVkIHdoZW4gdGhlIG9wdGlvbnMgbWVudSBpcyBoaWRkZW5cbiAgICovXG4gIEBPdXRwdXQoKSBtZW51SGlkZGVuID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIC8qKlxuICAgKiBDYWxsZWQgd2hlbiBhIGNob2ljZSBpcyBzZWxlY3RlZFxuICAgKi9cbiAgQE91dHB1dCgpIGNob2ljZVNlbGVjdGVkID0gbmV3IEV2ZW50RW1pdHRlcjxDaG9pY2VTZWxlY3RlZEV2ZW50PigpO1xuXG4gIC8qKlxuICAgKiBBIGZ1bmN0aW9uIHRoYXQgYWNjZXB0cyBhIHNlYXJjaCBzdHJpbmcgYW5kIHJldHVybnMgYW4gYXJyYXkgb2YgY2hvaWNlcy4gQ2FuIGFsc28gcmV0dXJuIGEgcHJvbWlzZS5cbiAgICovXG4gIEBJbnB1dCgpIGZpbmRDaG9pY2VzOiAoc2VhcmNoVGV4dDogc3RyaW5nKSA9PiBhbnlbXSB8IFByb21pc2U8YW55W10+O1xuXG4gIC8qKlxuICAgKiBBIGZ1bmN0aW9uIHRoYXQgZm9ybWF0cyB0aGUgc2VsZWN0ZWQgY2hvaWNlIG9uY2Ugc2VsZWN0ZWQuXG4gICAqL1xuICBASW5wdXQoKSBnZXRDaG9pY2VMYWJlbDogKGNob2ljZTogYW55KSA9PiBzdHJpbmcgPSBjaG9pY2UgPT4gY2hvaWNlO1xuXG4gIC8qIHRzbGludDpkaXNhYmxlIG1lbWJlci1vcmRlcmluZyAqL1xuICBwcml2YXRlIG1lbnU6XG4gICAgfCB7XG4gICAgICAgIGNvbXBvbmVudDogQ29tcG9uZW50UmVmPFRleHRJbnB1dEF1dG9jb21wbGV0ZU1lbnVDb21wb25lbnQ+O1xuICAgICAgICB0cmlnZ2VyQ2hhcmFjdGVyUG9zaXRpb246IG51bWJlcjtcbiAgICAgICAgbGFzdENhcmV0UG9zaXRpb24/OiBudW1iZXI7XG4gICAgICB9XG4gICAgfCB1bmRlZmluZWQ7XG5cbiAgcHJpdmF0ZSBtZW51SGlkZGVuJCA9IG5ldyBTdWJqZWN0KCk7XG5cbiAgcHJpdmF0ZSB1c2luZ1Nob3J0Y3V0ID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBjb21wb25lbnRGYWN0b3J5UmVzb2x2ZXI6IENvbXBvbmVudEZhY3RvcnlSZXNvbHZlcixcbiAgICBwcml2YXRlIHZpZXdDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWYsXG4gICAgcHJpdmF0ZSBpbmplY3RvcjogSW5qZWN0b3IsXG4gICAgcHJpdmF0ZSBlbG06IEVsZW1lbnRSZWZcbiAgKSB7fVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2tleXByZXNzJywgWyckZXZlbnQua2V5J10pXG4gIG9uS2V5cHJlc3Moa2V5OiBzdHJpbmcpIHtcbiAgICBpZiAoa2V5ID09PSB0aGlzLnRyaWdnZXJDaGFyYWN0ZXIpIHtcbiAgICAgIHRoaXMudXNpbmdTaG9ydGN1dCA9IGZhbHNlO1xuICAgICAgdGhpcy5zaG93TWVudSgpO1xuICAgIH1cbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2tleWRvd24nLCBbJyRldmVudCddKVxuICBvbktleURvd24oZXZlbnQ6IEtleWJvYXJkRXZlbnQpIHtcbiAgICBpZiAodGhpcy5rZXlib2FyZFNob3J0Y3V0ICYmIHRoaXMua2V5Ym9hcmRTaG9ydGN1dChldmVudCkpIHtcbiAgICAgIHRoaXMudXNpbmdTaG9ydGN1dCA9IHRydWU7XG4gICAgICB0aGlzLnNob3dNZW51KCk7XG4gICAgICB0aGlzLm9uQ2hhbmdlKCcnKTtcbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdpbnB1dCcsIFsnJGV2ZW50LnRhcmdldC52YWx1ZSddKVxuICBvbkNoYW5nZSh2YWx1ZTogc3RyaW5nKSB7XG4gICAgaWYgKHRoaXMubWVudSkge1xuICAgICAgaWYgKFxuICAgICAgICB2YWx1ZVt0aGlzLm1lbnUudHJpZ2dlckNoYXJhY3RlclBvc2l0aW9uXSAhPT0gdGhpcy50cmlnZ2VyQ2hhcmFjdGVyICYmXG4gICAgICAgICF0aGlzLnVzaW5nU2hvcnRjdXRcbiAgICAgICkge1xuICAgICAgICB0aGlzLmhpZGVNZW51KCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBjdXJzb3IgPSB0aGlzLmVsbS5uYXRpdmVFbGVtZW50LnNlbGVjdGlvblN0YXJ0O1xuICAgICAgICBpZiAoY3Vyc29yIDwgdGhpcy5tZW51LnRyaWdnZXJDaGFyYWN0ZXJQb3NpdGlvbikge1xuICAgICAgICAgIHRoaXMuaGlkZU1lbnUoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZiAodGhpcy51c2luZ1Nob3J0Y3V0ICYmICF0aGlzLm1lbnUpIHtcbiAgICAgICAgICAgIHZhbHVlID0gdGhpcy50cmlnZ2VyQ2hhcmFjdGVyO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBvZmZzZXQgPSB0aGlzLnVzaW5nU2hvcnRjdXQgPyAwIDogMTtcbiAgICAgICAgICBjb25zdCBzZWFyY2hUZXh0ID0gdmFsdWUuc2xpY2UoXG4gICAgICAgICAgICB0aGlzLm1lbnUudHJpZ2dlckNoYXJhY3RlclBvc2l0aW9uICsgb2Zmc2V0LFxuICAgICAgICAgICAgY3Vyc29yXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIGlmICghc2VhcmNoVGV4dC5tYXRjaCh0aGlzLnNlYXJjaFJlZ2V4cCkpIHtcbiAgICAgICAgICAgIHRoaXMuaGlkZU1lbnUoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5pbnN0YW5jZS5zZWFyY2hUZXh0ID0gc2VhcmNoVGV4dDtcbiAgICAgICAgICAgIHRoaXMubWVudS5jb21wb25lbnQuaW5zdGFuY2UuY2hvaWNlcyA9IFtdO1xuICAgICAgICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5pbnN0YW5jZS5jaG9pY2VMb2FkRXJyb3IgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICB0aGlzLm1lbnUuY29tcG9uZW50Lmluc3RhbmNlLmNob2ljZUxvYWRpbmcgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgICAgICBQcm9taXNlLnJlc29sdmUodGhpcy5maW5kQ2hvaWNlcyhzZWFyY2hUZXh0KSlcbiAgICAgICAgICAgICAgLnRoZW4oY2hvaWNlcyA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMubWVudSkge1xuICAgICAgICAgICAgICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5pbnN0YW5jZS5jaG9pY2VzID0gY2hvaWNlcztcbiAgICAgICAgICAgICAgICAgIHRoaXMubWVudS5jb21wb25lbnQuaW5zdGFuY2UuY2hvaWNlTG9hZGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5tZW51KSB7XG4gICAgICAgICAgICAgICAgICB0aGlzLm1lbnUuY29tcG9uZW50Lmluc3RhbmNlLmNob2ljZUxvYWRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgIHRoaXMubWVudS5jb21wb25lbnQuaW5zdGFuY2UuY2hvaWNlTG9hZEVycm9yID0gZXJyO1xuICAgICAgICAgICAgICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdibHVyJylcbiAgb25CbHVyKCkge1xuICAgIGlmICh0aGlzLm1lbnUpIHtcbiAgICAgIHRoaXMubWVudS5sYXN0Q2FyZXRQb3NpdGlvbiA9IHRoaXMuZWxtLm5hdGl2ZUVsZW1lbnQuc2VsZWN0aW9uU3RhcnQ7XG5cbiAgICAgIGlmICh0aGlzLmNsb3NlTWVudU9uQmx1ciA9PT0gdHJ1ZSkge1xuICAgICAgICB0aGlzLmhpZGVNZW51KCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzaG93TWVudSgpIHtcbiAgICBpZiAoIXRoaXMubWVudSkge1xuICAgICAgY29uc3QgbWVudUZhY3RvcnkgPSB0aGlzLmNvbXBvbmVudEZhY3RvcnlSZXNvbHZlci5yZXNvbHZlQ29tcG9uZW50RmFjdG9yeTxcbiAgICAgICAgVGV4dElucHV0QXV0b2NvbXBsZXRlTWVudUNvbXBvbmVudFxuICAgICAgPih0aGlzLm1lbnVDb21wb25lbnQpO1xuICAgICAgdGhpcy5tZW51ID0ge1xuICAgICAgICBjb21wb25lbnQ6IHRoaXMudmlld0NvbnRhaW5lclJlZi5jcmVhdGVDb21wb25lbnQoXG4gICAgICAgICAgbWVudUZhY3RvcnksXG4gICAgICAgICAgMCxcbiAgICAgICAgICB0aGlzLmluamVjdG9yXG4gICAgICAgICksXG4gICAgICAgIHRyaWdnZXJDaGFyYWN0ZXJQb3NpdGlvbjogdGhpcy5lbG0ubmF0aXZlRWxlbWVudC5zZWxlY3Rpb25TdGFydFxuICAgICAgfTtcblxuICAgICAgY29uc3QgbGluZUhlaWdodCA9IHRoaXMuZ2V0TGluZUhlaWdodCh0aGlzLmVsbS5uYXRpdmVFbGVtZW50KTtcbiAgICAgIGNvbnN0IHsgdG9wLCBsZWZ0IH0gPSBnZXRDYXJldENvb3JkaW5hdGVzKFxuICAgICAgICB0aGlzLmVsbS5uYXRpdmVFbGVtZW50LFxuICAgICAgICB0aGlzLmVsbS5uYXRpdmVFbGVtZW50LnNlbGVjdGlvblN0YXJ0XG4gICAgICApO1xuICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5pbnN0YW5jZS5wb3NpdGlvbiA9IHtcbiAgICAgICAgdG9wOiB0b3AgKyBsaW5lSGVpZ2h0LFxuICAgICAgICBsZWZ0XG4gICAgICB9O1xuICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICB0aGlzLm1lbnUuY29tcG9uZW50Lmluc3RhbmNlLnNlbGVjdENob2ljZVxuICAgICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5tZW51SGlkZGVuJCkpXG4gICAgICAgIC5zdWJzY3JpYmUoY2hvaWNlID0+IHtcbiAgICAgICAgICBjb25zdCBsYWJlbCA9IHRoaXMuZ2V0Q2hvaWNlTGFiZWwoY2hvaWNlKTtcbiAgICAgICAgICBjb25zdCB0ZXh0YXJlYTogSFRNTFRleHRBcmVhRWxlbWVudCA9IHRoaXMuZWxtLm5hdGl2ZUVsZW1lbnQ7XG4gICAgICAgICAgY29uc3QgdmFsdWU6IHN0cmluZyA9IHRleHRhcmVhLnZhbHVlO1xuICAgICAgICAgIGNvbnN0IHN0YXJ0SW5kZXggPSB0aGlzLm1lbnUhLnRyaWdnZXJDaGFyYWN0ZXJQb3NpdGlvbjtcbiAgICAgICAgICBjb25zdCBzdGFydCA9IHZhbHVlLnNsaWNlKDAsIHN0YXJ0SW5kZXgpO1xuICAgICAgICAgIGNvbnN0IGNhcmV0UG9zaXRpb24gPVxuICAgICAgICAgICAgdGhpcy5tZW51IS5sYXN0Q2FyZXRQb3NpdGlvbiB8fCB0ZXh0YXJlYS5zZWxlY3Rpb25TdGFydDtcbiAgICAgICAgICBjb25zdCBlbmQgPSB2YWx1ZS5zbGljZShjYXJldFBvc2l0aW9uKTtcbiAgICAgICAgICB0ZXh0YXJlYS52YWx1ZSA9IHN0YXJ0ICsgbGFiZWwgKyBlbmQ7XG4gICAgICAgICAgLy8gZm9yY2UgbmcgbW9kZWwgLyBmb3JtIGNvbnRyb2wgdG8gdXBkYXRlXG4gICAgICAgICAgdGV4dGFyZWEuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoJ2lucHV0JykpO1xuICAgICAgICAgIHRoaXMuaGlkZU1lbnUoKTtcbiAgICAgICAgICBjb25zdCBzZXRDdXJzb3JBdCA9IChzdGFydCArIGxhYmVsKS5sZW5ndGg7XG4gICAgICAgICAgdGV4dGFyZWEuc2V0U2VsZWN0aW9uUmFuZ2Uoc2V0Q3Vyc29yQXQsIHNldEN1cnNvckF0KTtcbiAgICAgICAgICB0ZXh0YXJlYS5mb2N1cygpO1xuICAgICAgICAgIHRoaXMuY2hvaWNlU2VsZWN0ZWQuZW1pdCh7XG4gICAgICAgICAgICBjaG9pY2UsXG4gICAgICAgICAgICBpbnNlcnRlZEF0OiB7XG4gICAgICAgICAgICAgIHN0YXJ0OiBzdGFydEluZGV4LFxuICAgICAgICAgICAgICBlbmQ6IHN0YXJ0SW5kZXggKyBsYWJlbC5sZW5ndGhcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB0aGlzLm1lbnVTaG93bi5lbWl0KCk7XG4gICAgfVxuICB9XG5cbiAgZ2V0TGluZUhlaWdodChlbG06IEhUTUxFbGVtZW50KTogbnVtYmVyIHtcbiAgICBjb25zdCBsaW5lSGVpZ2h0U3RyID0gZ2V0Q29tcHV0ZWRTdHlsZShlbG0pLmxpbmVIZWlnaHQgfHwgJyc7XG4gICAgY29uc3QgZm9udFNpemVTdHIgPSBnZXRDb21wdXRlZFN0eWxlKGVsbSkuZm9udFNpemUgfHwgJyc7XG4gICAgY29uc3QgZm9udFNpemUgPSArdG9QWChmb250U2l6ZVN0cik7XG4gICAgY29uc3Qgbm9ybWFsID0gMS4yO1xuICAgIGNvbnN0IGxpbmVIZWlnaHROdW0gPSBwYXJzZUZsb2F0KGxpbmVIZWlnaHRTdHIpO1xuXG4gICAgaWYgKGxpbmVIZWlnaHRTdHIgPT09IGxpbmVIZWlnaHROdW0gKyAnJykge1xuICAgICAgcmV0dXJuIGZvbnRTaXplICogbGluZUhlaWdodE51bTtcbiAgICB9XG5cbiAgICBpZiAobGluZUhlaWdodFN0ci50b0xvd2VyQ2FzZSgpID09PSAnbm9ybWFsJykge1xuICAgICAgcmV0dXJuIGZvbnRTaXplICogbm9ybWFsO1xuICAgIH1cblxuICAgIHJldHVybiB0b1BYKGxpbmVIZWlnaHRTdHIpO1xuICB9XG5cbiAgcHJpdmF0ZSBoaWRlTWVudSgpIHtcbiAgICBpZiAodGhpcy5tZW51KSB7XG4gICAgICB0aGlzLm1lbnUuY29tcG9uZW50LmRlc3Ryb3koKTtcbiAgICAgIHRoaXMubWVudUhpZGRlbiQubmV4dCgpO1xuICAgICAgdGhpcy5tZW51SGlkZGVuLmVtaXQoKTtcbiAgICAgIHRoaXMubWVudSA9IHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICB0aGlzLmhpZGVNZW51KCk7XG4gIH1cbn1cbiJdfQ==