UNPKG

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
/** * @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=