UNPKG

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