angular-text-input-autocomplete
Version:
A angular 6+ directive for adding autocomplete functionality to text input elements, built around composability
328 lines (327 loc) • 31.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;
}
export class TextInputAutocompleteDirective {
/**
* @param {?} componentFactoryResolver
* @param {?} viewContainerRef
* @param {?} injector
* @param {?} elm
*/
constructor(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 = choice => choice;
this.menuHidden$ = new Subject();
this.usingShortcut = false;
}
/**
* @param {?} key
* @return {?}
*/
onKeypress(key) {
if (key === this.triggerCharacter) {
this.usingShortcut = false;
this.showMenu();
}
}
/**
* @param {?} event
* @return {?}
*/
onKeyDown(event) {
if (this.keyboardShortcut && this.keyboardShortcut(event)) {
this.usingShortcut = true;
this.showMenu();
this.onChange('');
}
}
/**
* @param {?} value
* @return {?}
*/
onChange(value) {
if (this.menu) {
if (value[this.menu.triggerCharacterPosition] !== this.triggerCharacter &&
!this.usingShortcut) {
this.hideMenu();
}
else {
const /** @type {?} */ cursor = this.elm.nativeElement.selectionStart;
if (cursor < this.menu.triggerCharacterPosition) {
this.hideMenu();
}
else {
if (this.usingShortcut && !this.menu) {
value = this.triggerCharacter;
}
const /** @type {?} */ offset = this.usingShortcut ? 0 : 1;
const /** @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(choices => {
if (this.menu) {
this.menu.component.instance.choices = choices;
this.menu.component.instance.choiceLoading = false;
this.menu.component.changeDetectorRef.detectChanges();
}
})
.catch(err => {
if (this.menu) {
this.menu.component.instance.choiceLoading = false;
this.menu.component.instance.choiceLoadError = err;
this.menu.component.changeDetectorRef.detectChanges();
}
});
}
}
}
}
}
/**
* @return {?}
*/
onBlur() {
if (this.menu) {
this.menu.lastCaretPosition = this.elm.nativeElement.selectionStart;
if (this.closeMenuOnBlur === true) {
this.hideMenu();
}
}
}
/**
* @return {?}
*/
showMenu() {
if (!this.menu) {
const /** @type {?} */ menuFactory = this.componentFactoryResolver.resolveComponentFactory(this.menuComponent);
this.menu = {
component: this.viewContainerRef.createComponent(menuFactory, 0, this.injector),
triggerCharacterPosition: this.elm.nativeElement.selectionStart
};
const /** @type {?} */ lineHeight = this.getLineHeight(this.elm.nativeElement);
const { top, left } = getCaretCoordinates(this.elm.nativeElement, this.elm.nativeElement.selectionStart);
this.menu.component.instance.position = {
top: top + lineHeight,
left
};
this.menu.component.changeDetectorRef.detectChanges();
this.menu.component.instance.selectChoice
.pipe(takeUntil(this.menuHidden$))
.subscribe(choice => {
const /** @type {?} */ label = this.getChoiceLabel(choice);
const /** @type {?} */ textarea = this.elm.nativeElement;
const /** @type {?} */ value = textarea.value;
const /** @type {?} */ startIndex = /** @type {?} */ ((this.menu)).triggerCharacterPosition;
const /** @type {?} */ start = value.slice(0, startIndex);
const /** @type {?} */ caretPosition = /** @type {?} */ ((this.menu)).lastCaretPosition || textarea.selectionStart;
const /** @type {?} */ end = value.slice(caretPosition);
textarea.value = start + label + end;
// force ng model / form control to update
textarea.dispatchEvent(new Event('input'));
this.hideMenu();
const /** @type {?} */ setCursorAt = (start + label).length;
textarea.setSelectionRange(setCursorAt, setCursorAt);
textarea.focus();
this.choiceSelected.emit({
choice,
insertedAt: {
start: startIndex,
end: startIndex + label.length
}
});
});
this.menuShown.emit();
}
}
/**
* @param {?} elm
* @return {?}
*/
getLineHeight(elm) {
const /** @type {?} */ lineHeightStr = getComputedStyle(elm).lineHeight || '';
const /** @type {?} */ fontSizeStr = getComputedStyle(elm).fontSize || '';
const /** @type {?} */ fontSize = +toPX(fontSizeStr);
const /** @type {?} */ normal = 1.2;
const /** @type {?} */ lineHeightNum = parseFloat(lineHeightStr);
if (lineHeightStr === lineHeightNum + '') {
return fontSize * lineHeightNum;
}
if (lineHeightStr.toLowerCase() === 'normal') {
return fontSize * normal;
}
return toPX(lineHeightStr);
}
/**
* @return {?}
*/
hideMenu() {
if (this.menu) {
this.menu.component.destroy();
this.menuHidden$.next();
this.menuHidden.emit();
this.menu = undefined;
}
}
/**
* @return {?}
*/
ngOnDestroy() {
this.hideMenu();
}
}
TextInputAutocompleteDirective.decorators = [
{ type: Directive, args: [{
selector: 'textarea[mwlTextInputAutocomplete],input[type="text"][mwlTextInputAutocomplete]'
},] },
];
/** @nocollapse */
TextInputAutocompleteDirective.ctorParameters = () => [
{ 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',] }]
};
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGV4dC1pbnB1dC1hdXRvY29tcGxldGUuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6Im5nOi8vYW5ndWxhci10ZXh0LWlucHV0LWF1dG9jb21wbGV0ZS8iLCJzb3VyY2VzIjpbInRleHQtaW5wdXQtYXV0b2NvbXBsZXRlLmRpcmVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUNMLHdCQUF3QixFQUV4QixTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixZQUFZLEVBQ1osUUFBUSxFQUNSLEtBQUssRUFFTCxNQUFNLEVBQ04sZ0JBQWdCLEVBQ2pCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sbUJBQW1CLE1BQU0sZ0JBQWdCLENBQUM7QUFDakQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzNDLE9BQU8sRUFBRSxrQ0FBa0MsRUFBRSxNQUFNLDBDQUEwQyxDQUFDO0FBQzlGLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFL0IsT0FBTyxJQUFJLE1BQU0sT0FBTyxDQUFDOzs7Ozs7Ozs7OztBQWN6QixNQUFNOzs7Ozs7O0lBaUVKLFlBQ1UsMEJBQ0Esa0JBQ0EsVUFDQTtRQUhBLDZCQUF3QixHQUF4Qix3QkFBd0I7UUFDeEIscUJBQWdCLEdBQWhCLGdCQUFnQjtRQUNoQixhQUFRLEdBQVIsUUFBUTtRQUNSLFFBQUcsR0FBSCxHQUFHOzs7O2dDQWpFZSxHQUFHOzs7OzRCQVVQLE9BQU87Ozs7K0JBS0osS0FBSzs7Ozs7NkJBTVAsa0NBQWtDOzs7O3lCQUtyQyxJQUFJLFlBQVksRUFBRTs7OzswQkFLakIsSUFBSSxZQUFZLEVBQUU7Ozs7OEJBS2QsSUFBSSxZQUFZLEVBQXVCOzs7OzhCQVVmLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTTsyQkFXN0MsSUFBSSxPQUFPLEVBQUU7NkJBRVgsS0FBSztLQU96Qjs7Ozs7SUFHSixVQUFVLENBQUMsR0FBVztRQUNwQixFQUFF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WUFBWSxTQUFDLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQzt1QkFTbEMsWUFBWSxTQUFDLE9BQU8sRUFBRSxDQUFDLHFCQUFxQixDQUFDO3FCQW1EN0MsWUFBWSxTQUFDLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnRGYWN0b3J5UmVzb2x2ZXIsXG4gIENvbXBvbmVudFJlZixcbiAgRGlyZWN0aXZlLFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgSW5qZWN0b3IsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE91dHB1dCxcbiAgVmlld0NvbnRhaW5lclJlZlxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCBnZXRDYXJldENvb3JkaW5hdGVzIGZyb20gJ3RleHRhcmVhLWNhcmV0JztcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IFRleHRJbnB1dEF1dG9jb21wbGV0ZU1lbnVDb21wb25lbnQgfSBmcm9tICcuL3RleHQtaW5wdXQtYXV0b2NvbXBsZXRlLW1lbnUuY29tcG9uZW50JztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbi8vIEB0cy1pZ25vcmVcbmltcG9ydCB0b1BYIGZyb20gJ3RvLXB4JztcblxuZXhwb3J0IGludGVyZmFjZSBDaG9pY2VTZWxlY3RlZEV2ZW50IHtcbiAgY2hvaWNlOiBhbnk7XG4gIGluc2VydGVkQXQ6IHtcbiAgICBzdGFydDogbnVtYmVyO1xuICAgIGVuZDogbnVtYmVyO1xuICB9O1xufVxuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6XG4gICAgJ3RleHRhcmVhW213bFRleHRJbnB1dEF1dG9jb21wbGV0ZV0saW5wdXRbdHlwZT1cInRleHRcIl1bbXdsVGV4dElucHV0QXV0b2NvbXBsZXRlXSdcbn0pXG5leHBvcnQgY2xhc3MgVGV4dElucHV0QXV0b2NvbXBsZXRlRGlyZWN0aXZlIGltcGxlbWVudHMgT25EZXN0cm95IHtcbiAgLyoqXG4gICAqIFRoZSBjaGFyYWN0ZXIgdGhhdCB3aWxsIHRyaWdnZXIgdGhlIG1lbnUgdG8gYXBwZWFyXG4gICAqL1xuICBASW5wdXQoKSB0cmlnZ2VyQ2hhcmFjdGVyID0gJ0AnO1xuXG4gIC8qKlxuICAgKiBBbiBvcHRpb25hbCBrZXlib2FyZCBzaG9ydGN1dCB0aGF0IHdpbGwgdHJpZ2dlciB0aGUgbWVudSB0byBhcHBlYXJcbiAgICovXG4gIEBJbnB1dCgpIGtleWJvYXJkU2hvcnRjdXQ6IChldmVudDogS2V5Ym9hcmRFdmVudCkgPT4gYm9vbGVhbjtcblxuICAvKipcbiAgICogVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiB0aGF0IHdpbGwgbWF0Y2ggdGhlIHNlYXJjaCB0ZXh0IGFmdGVyIHRoZSB0cmlnZ2VyIGNoYXJhY3RlclxuICAgKi9cbiAgQElucHV0KCkgc2VhcmNoUmVnZXhwID0gL15cXHcqJC87XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gY2xvc2UgdGhlIG1lbnUgd2hlbiB0aGUgaG9zdCB0ZXh0YXJlYSBsb3NlcyBmb2N1c1xuICAgKi9cbiAgQElucHV0KCkgY2xvc2VNZW51T25CbHVyID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIFRoZSBtZW51IGNvbXBvbmVudCB0byBzaG93IHdpdGggYXZhaWxhYmxlIG9wdGlvbnMuXG4gICAqIFlvdSBjYW4gZXh0ZW5kIHRoZSBidWlsdCBpbiBgVGV4dElucHV0QXV0b2NvbXBsZXRlTWVudUNvbXBvbmVudGAgY29tcG9uZW50IHRvIHVzZSBhIGN1c3RvbSB0ZW1wbGF0ZVxuICAgKi9cbiAgQElucHV0KCkgbWVudUNvbXBvbmVudCA9IFRleHRJbnB1dEF1dG9jb21wbGV0ZU1lbnVDb21wb25lbnQ7XG5cbiAgLyoqXG4gICAqIENhbGxlZCB3aGVuIHRoZSBvcHRpb25zIG1lbnUgaXMgc2hvd25cbiAgICovXG4gIEBPdXRwdXQoKSBtZW51U2hvd24gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgLyoqXG4gICAqIENhbGxlZCB3aGVuIHRoZSBvcHRpb25zIG1lbnUgaXMgaGlkZGVuXG4gICAqL1xuICBAT3V0cHV0KCkgbWVudUhpZGRlbiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAvKipcbiAgICogQ2FsbGVkIHdoZW4gYSBjaG9pY2UgaXMgc2VsZWN0ZWRcbiAgICovXG4gIEBPdXRwdXQoKSBjaG9pY2VTZWxlY3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8Q2hvaWNlU2VsZWN0ZWRFdmVudD4oKTtcblxuICAvKipcbiAgICogQSBmdW5jdGlvbiB0aGF0IGFjY2VwdHMgYSBzZWFyY2ggc3RyaW5nIGFuZCByZXR1cm5zIGFuIGFycmF5IG9mIGNob2ljZXMuIENhbiBhbHNvIHJldHVybiBhIHByb21pc2UuXG4gICAqL1xuICBASW5wdXQoKSBmaW5kQ2hvaWNlczogKHNlYXJjaFRleHQ6IHN0cmluZykgPT4gYW55W10gfCBQcm9taXNlPGFueVtdPjtcblxuICAvKipcbiAgICogQSBmdW5jdGlvbiB0aGF0IGZvcm1hdHMgdGhlIHNlbGVjdGVkIGNob2ljZSBvbmNlIHNlbGVjdGVkLlxuICAgKi9cbiAgQElucHV0KCkgZ2V0Q2hvaWNlTGFiZWw6IChjaG9pY2U6IGFueSkgPT4gc3RyaW5nID0gY2hvaWNlID0+IGNob2ljZTtcblxuICAvKiB0c2xpbnQ6ZGlzYWJsZSBtZW1iZXItb3JkZXJpbmcgKi9cbiAgcHJpdmF0ZSBtZW51OlxuICAgIHwge1xuICAgICAgICBjb21wb25lbnQ6IENvbXBvbmVudFJlZjxUZXh0SW5wdXRBdXRvY29tcGxldGVNZW51Q29tcG9uZW50PjtcbiAgICAgICAgdHJpZ2dlckNoYXJhY3RlclBvc2l0aW9uOiBudW1iZXI7XG4gICAgICAgIGxhc3RDYXJldFBvc2l0aW9uPzogbnVtYmVyO1xuICAgICAgfVxuICAgIHwgdW5kZWZpbmVkO1xuXG4gIHByaXZhdGUgbWVudUhpZGRlbiQgPSBuZXcgU3ViamVjdCgpO1xuXG4gIHByaXZhdGUgdXNpbmdTaG9ydGN1dCA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgY29tcG9uZW50RmFjdG9yeVJlc29sdmVyOiBDb21wb25lbnRGYWN0b3J5UmVzb2x2ZXIsXG4gICAgcHJpdmF0ZSB2aWV3Q29udGFpbmVyUmVmOiBWaWV3Q29udGFpbmVyUmVmLFxuICAgIHByaXZhdGUgaW5qZWN0b3I6IEluamVjdG9yLFxuICAgIHByaXZhdGUgZWxtOiBFbGVtZW50UmVmXG4gICkge31cblxuICBASG9zdExpc3RlbmVyKCdrZXlwcmVzcycsIFsnJGV2ZW50LmtleSddKVxuICBvbktleXByZXNzKGtleTogc3RyaW5nKSB7XG4gICAgaWYgKGtleSA9PT0gdGhpcy50cmlnZ2VyQ2hhcmFjdGVyKSB7XG4gICAgICB0aGlzLnVzaW5nU2hvcnRjdXQgPSBmYWxzZTtcbiAgICAgIHRoaXMuc2hvd01lbnUoKTtcbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdrZXlkb3duJywgWyckZXZlbnQnXSlcbiAgb25LZXlEb3duKGV2ZW50OiBLZXlib2FyZEV2ZW50KSB7XG4gICAgaWYgKHRoaXMua2V5Ym9hcmRTaG9ydGN1dCAmJiB0aGlzLmtleWJvYXJkU2hvcnRjdXQoZXZlbnQpKSB7XG4gICAgICB0aGlzLnVzaW5nU2hvcnRjdXQgPSB0cnVlO1xuICAgICAgdGhpcy5zaG93TWVudSgpO1xuICAgICAgdGhpcy5vbkNoYW5nZSgnJyk7XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignaW5wdXQnLCBbJyRldmVudC50YXJnZXQudmFsdWUnXSlcbiAgb25DaGFuZ2UodmFsdWU6IHN0cmluZykge1xuICAgIGlmICh0aGlzLm1lbnUpIHtcbiAgICAgIGlmIChcbiAgICAgICAgdmFsdWVbdGhpcy5tZW51LnRyaWdnZXJDaGFyYWN0ZXJQb3NpdGlvbl0gIT09IHRoaXMudHJpZ2dlckNoYXJhY3RlciAmJlxuICAgICAgICAhdGhpcy51c2luZ1Nob3J0Y3V0XG4gICAgICApIHtcbiAgICAgICAgdGhpcy5oaWRlTWVudSgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgY3Vyc29yID0gdGhpcy5lbG0ubmF0aXZlRWxlbWVudC5zZWxlY3Rpb25TdGFydDtcbiAgICAgICAgaWYgKGN1cnNvciA8IHRoaXMubWVudS50cmlnZ2VyQ2hhcmFjdGVyUG9zaXRpb24pIHtcbiAgICAgICAgICB0aGlzLmhpZGVNZW51KCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaWYgKHRoaXMudXNpbmdTaG9ydGN1dCAmJiAhdGhpcy5tZW51KSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHRoaXMudHJpZ2dlckNoYXJhY3RlcjtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3Qgb2Zmc2V0ID0gdGhpcy51c2luZ1Nob3J0Y3V0ID8gMCA6IDE7XG4gICAgICAgICAgY29uc3Qgc2VhcmNoVGV4dCA9IHZhbHVlLnNsaWNlKFxuICAgICAgICAgICAgdGhpcy5tZW51LnRyaWdnZXJDaGFyYWN0ZXJQb3NpdGlvbiArIG9mZnNldCxcbiAgICAgICAgICAgIGN1cnNvclxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBpZiAoIXNlYXJjaFRleHQubWF0Y2godGhpcy5zZWFyY2hSZWdleHApKSB7XG4gICAgICAgICAgICB0aGlzLmhpZGVNZW51KCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubWVudS5jb21wb25lbnQuaW5zdGFuY2Uuc2VhcmNoVGV4dCA9IHNlYXJjaFRleHQ7XG4gICAgICAgICAgICB0aGlzLm1lbnUuY29tcG9uZW50Lmluc3RhbmNlLmNob2ljZXMgPSBbXTtcbiAgICAgICAgICAgIHRoaXMubWVudS5jb21wb25lbnQuaW5zdGFuY2UuY2hvaWNlTG9hZEVycm9yID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5pbnN0YW5jZS5jaG9pY2VMb2FkaW5nID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMubWVudS5jb21wb25lbnQuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHRoaXMuZmluZENob2ljZXMoc2VhcmNoVGV4dCkpXG4gICAgICAgICAgICAgIC50aGVuKGNob2ljZXMgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLm1lbnUpIHtcbiAgICAgICAgICAgICAgICAgIHRoaXMubWVudS5jb21wb25lbnQuaW5zdGFuY2UuY2hvaWNlcyA9IGNob2ljZXM7XG4gICAgICAgICAgICAgICAgICB0aGlzLm1lbnUuY29tcG9uZW50Lmluc3RhbmNlLmNob2ljZUxvYWRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgIHRoaXMubWVudS5jb21wb25lbnQuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgLmNhdGNoKGVyciA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMubWVudSkge1xuICAgICAgICAgICAgICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5pbnN0YW5jZS5jaG9pY2VMb2FkaW5nID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICB0aGlzLm1lbnUuY29tcG9uZW50Lmluc3RhbmNlLmNob2ljZUxvYWRFcnJvciA9IGVycjtcbiAgICAgICAgICAgICAgICAgIHRoaXMubWVudS5jb21wb25lbnQuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignYmx1cicpXG4gIG9uQmx1cigpIHtcbiAgICBpZiAodGhpcy5tZW51KSB7XG4gICAgICB0aGlzLm1lbnUubGFzdENhcmV0UG9zaXRpb24gPSB0aGlzLmVsbS5uYXRpdmVFbGVtZW50LnNlbGVjdGlvblN0YXJ0O1xuXG4gICAgICBpZiAodGhpcy5jbG9zZU1lbnVPbkJsdXIgPT09IHRydWUpIHtcbiAgICAgICAgdGhpcy5oaWRlTWVudSgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc2hvd01lbnUoKSB7XG4gICAgaWYgKCF0aGlzLm1lbnUpIHtcbiAgICAgIGNvbnN0IG1lbnVGYWN0b3J5ID0gdGhpcy5jb21wb25lbnRGYWN0b3J5UmVzb2x2ZXIucmVzb2x2ZUNvbXBvbmVudEZhY3Rvcnk8XG4gICAgICAgIFRleHRJbnB1dEF1dG9jb21wbGV0ZU1lbnVDb21wb25lbnRcbiAgICAgID4odGhpcy5tZW51Q29tcG9uZW50KTtcbiAgICAgIHRoaXMubWVudSA9IHtcbiAgICAgICAgY29tcG9uZW50OiB0aGlzLnZpZXdDb250YWluZXJSZWYuY3JlYXRlQ29tcG9uZW50KFxuICAgICAgICAgIG1lbnVGYWN0b3J5LFxuICAgICAgICAgIDAsXG4gICAgICAgICAgdGhpcy5pbmplY3RvclxuICAgICAgICApLFxuICAgICAgICB0cmlnZ2VyQ2hhcmFjdGVyUG9zaXRpb246IHRoaXMuZWxtLm5hdGl2ZUVsZW1lbnQuc2VsZWN0aW9uU3RhcnRcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGxpbmVIZWlnaHQgPSB0aGlzLmdldExpbmVIZWlnaHQodGhpcy5lbG0ubmF0aXZlRWxlbWVudCk7XG4gICAgICBjb25zdCB7IHRvcCwgbGVmdCB9ID0gZ2V0Q2FyZXRDb29yZGluYXRlcyhcbiAgICAgICAgdGhpcy5lbG0ubmF0aXZlRWxlbWVudCxcbiAgICAgICAgdGhpcy5lbG0ubmF0aXZlRWxlbWVudC5zZWxlY3Rpb25TdGFydFxuICAgICAgKTtcbiAgICAgIHRoaXMubWVudS5jb21wb25lbnQuaW5zdGFuY2UucG9zaXRpb24gPSB7XG4gICAgICAgIHRvcDogdG9wICsgbGluZUhlaWdodCxcbiAgICAgICAgbGVmdFxuICAgICAgfTtcbiAgICAgIHRoaXMubWVudS5jb21wb25lbnQuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5pbnN0YW5jZS5zZWxlY3RDaG9pY2VcbiAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMubWVudUhpZGRlbiQpKVxuICAgICAgICAuc3Vic2NyaWJlKGNob2ljZSA9PiB7XG4gICAgICAgICAgY29uc3QgbGFiZWwgPSB0aGlzLmdldENob2ljZUxhYmVsKGNob2ljZSk7XG4gICAgICAgICAgY29uc3QgdGV4dGFyZWE6IEhUTUxUZXh0QXJlYUVsZW1lbnQgPSB0aGlzLmVsbS5uYXRpdmVFbGVtZW50O1xuICAgICAgICAgIGNvbnN0IHZhbHVlOiBzdHJpbmcgPSB0ZXh0YXJlYS52YWx1ZTtcbiAgICAgICAgICBjb25zdCBzdGFydEluZGV4ID0gdGhpcy5tZW51IS50cmlnZ2VyQ2hhcmFjdGVyUG9zaXRpb247XG4gICAgICAgICAgY29uc3Qgc3RhcnQgPSB2YWx1ZS5zbGljZSgwLCBzdGFydEluZGV4KTtcbiAgICAgICAgICBjb25zdCBjYXJldFBvc2l0aW9uID1cbiAgICAgICAgICAgIHRoaXMubWVudSEubGFzdENhcmV0UG9zaXRpb24gfHwgdGV4dGFyZWEuc2VsZWN0aW9uU3RhcnQ7XG4gICAgICAgICAgY29uc3QgZW5kID0gdmFsdWUuc2xpY2UoY2FyZXRQb3NpdGlvbik7XG4gICAgICAgICAgdGV4dGFyZWEudmFsdWUgPSBzdGFydCArIGxhYmVsICsgZW5kO1xuICAgICAgICAgIC8vIGZvcmNlIG5nIG1vZGVsIC8gZm9ybSBjb250cm9sIHRvIHVwZGF0ZVxuICAgICAgICAgIHRleHRhcmVhLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KCdpbnB1dCcpKTtcbiAgICAgICAgICB0aGlzLmhpZGVNZW51KCk7XG4gICAgICAgICAgY29uc3Qgc2V0Q3Vyc29yQXQgPSAoc3RhcnQgKyBsYWJlbCkubGVuZ3RoO1xuICAgICAgICAgIHRleHRhcmVhLnNldFNlbGVjdGlvblJhbmdlKHNldEN1cnNvckF0LCBzZXRDdXJzb3JBdCk7XG4gICAgICAgICAgdGV4dGFyZWEuZm9jdXMoKTtcbiAgICAgICAgICB0aGlzLmNob2ljZVNlbGVjdGVkLmVtaXQoe1xuICAgICAgICAgICAgY2hvaWNlLFxuICAgICAgICAgICAgaW5zZXJ0ZWRBdDoge1xuICAgICAgICAgICAgICBzdGFydDogc3RhcnRJbmRleCxcbiAgICAgICAgICAgICAgZW5kOiBzdGFydEluZGV4ICsgbGFiZWwubGVuZ3RoXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgdGhpcy5tZW51U2hvd24uZW1pdCgpO1xuICAgIH1cbiAgfVxuXG4gIGdldExpbmVIZWlnaHQoZWxtOiBIVE1MRWxlbWVudCk6IG51bWJlciB7XG4gICAgY29uc3QgbGluZUhlaWdodFN0ciA9IGdldENvbXB1dGVkU3R5bGUoZWxtKS5saW5lSGVpZ2h0IHx8ICcnO1xuICAgIGNvbnN0IGZvbnRTaXplU3RyID0gZ2V0Q29tcHV0ZWRTdHlsZShlbG0pLmZvbnRTaXplIHx8ICcnO1xuICAgIGNvbnN0IGZvbnRTaXplID0gK3RvUFgoZm9udFNpemVTdHIpO1xuICAgIGNvbnN0IG5vcm1hbCA9IDEuMjtcbiAgICBjb25zdCBsaW5lSGVpZ2h0TnVtID0gcGFyc2VGbG9hdChsaW5lSGVpZ2h0U3RyKTtcblxuICAgIGlmIChsaW5lSGVpZ2h0U3RyID09PSBsaW5lSGVpZ2h0TnVtICsgJycpIHtcbiAgICAgIHJldHVybiBmb250U2l6ZSAqIGxpbmVIZWlnaHROdW07XG4gICAgfVxuXG4gICAgaWYgKGxpbmVIZWlnaHRTdHIudG9Mb3dlckNhc2UoKSA9PT0gJ25vcm1hbCcpIHtcbiAgICAgIHJldHVybiBmb250U2l6ZSAqIG5vcm1hbDtcbiAgICB9XG5cbiAgICByZXR1cm4gdG9QWChsaW5lSGVpZ2h0U3RyKTtcbiAgfVxuXG4gIHByaXZhdGUgaGlkZU1lbnUoKSB7XG4gICAgaWYgKHRoaXMubWVudSkge1xuICAgICAgdGhpcy5tZW51LmNvbXBvbmVudC5kZXN0cm95KCk7XG4gICAgICB0aGlzLm1lbnVIaWRkZW4kLm5leHQoKTtcbiAgICAgIHRoaXMubWVudUhpZGRlbi5lbWl0KCk7XG4gICAgICB0aGlzLm1lbnUgPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgdGhpcy5oaWRlTWVudSgpO1xuICB9XG59XG4iXX0=