ngx-editor
Version:
Rich Text Editor for angular using ProseMirror
123 lines • 22.2 kB
JavaScript
import { Component, HostListener, } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import Icon from '../../../icons';
import { Link as LinkCommand } from '../MenuCommands';
import * as i0 from "@angular/core";
import * as i1 from "../../../editor.service";
import * as i2 from "../menu.service";
import * as i3 from "@angular/common";
import * as i4 from "@angular/forms";
import * as i5 from "../../../pipes/sanitize/sanitize-html.pipe";
export class LinkComponent {
constructor(el, ngxeService, menuService) {
this.el = el;
this.ngxeService = ngxeService;
this.menuService = menuService;
this.showPopup = false;
this.isActive = false;
this.canExecute = true;
this.form = new FormGroup({
href: new FormControl('', [
Validators.required,
Validators.pattern('(https?://)?([\\da-z.-]+)\\.([a-z.]{2,6})[/\\w .-]*/??([^#\n\r]*)?#?([^\n\r]*)'),
]),
text: new FormControl('', [Validators.required]),
openInNewTab: new FormControl(true),
});
this.setText = () => {
const { state: { selection, doc } } = this.editorView;
const { empty, from, to } = selection;
const selectedText = !empty ? doc.textBetween(from, to) : '';
if (selectedText) {
this.text.patchValue(selectedText);
this.text.disable();
}
};
this.update = (view) => {
const { state } = view;
this.isActive = LinkCommand.isActive(state, { strict: false });
this.canExecute = LinkCommand.canExecute(state);
};
}
get icon() {
return Icon.get(this.isActive ? 'unlink' : 'link');
}
get title() {
return this.ngxeService.locals.get(this.isActive ? 'removeLink' : 'insertLink');
}
get href() {
return this.form.get('href');
}
get text() {
return this.form.get('text');
}
onDocumentClick(e) {
if (!this.el.nativeElement.contains(e.target) && this.showPopup) {
this.hideForm();
}
}
getLabel(key) {
return this.ngxeService.locals.get(key);
}
hideForm() {
this.showPopup = false;
this.form.reset({
href: '',
text: '',
openInNewTab: true,
});
this.text.enable();
}
onMouseDown(e) {
if (e.button !== 0) {
return;
}
const { state, dispatch } = this.editorView;
if (this.isActive) {
LinkCommand.remove(state, dispatch);
return;
}
this.showPopup = !this.showPopup;
if (this.showPopup) {
this.setText();
}
}
insertLink(e) {
e.preventDefault();
const { text, href, openInNewTab } = this.form.getRawValue();
const { dispatch, state } = this.editorView;
const { selection } = state;
const attrs = {
title: href,
href,
target: openInNewTab ? '_blank' : '_self',
};
if (selection.empty) {
LinkCommand.insert(text, attrs)(state, dispatch);
this.editorView.focus();
}
else {
LinkCommand.update(attrs)(state, dispatch);
}
this.hideForm();
}
ngOnInit() {
this.editorView = this.menuService.editor.view;
this.updateSubscription = this.menuService.editor.update.subscribe((view) => {
this.update(view);
});
}
ngOnDestroy() {
this.updateSubscription.unsubscribe();
}
}
LinkComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: LinkComponent, deps: [{ token: i0.ElementRef }, { token: i1.NgxEditorService }, { token: i2.MenuService }], target: i0.ɵɵFactoryTarget.Component });
LinkComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.7", type: LinkComponent, selector: "ngx-link", host: { listeners: { "document:mousedown": "onDocumentClick($event)" } }, ngImport: i0, template: "<div class=\"NgxEditor__MenuItem--IconContainer\" [class.NgxEditor__MenuItem--Active]=\"isActive || showPopup\"\n [class.NgxEditor--Disabled]=\"!canExecute\" [innerHTML]=\"icon | sanitizeHtml\" (mousedown)=\"onMouseDown($event)\"\n [title]=\"title\">\n</div>\n\n<!-- popup -->\n<div *ngIf=\"showPopup\" class=\"NgxEditor__Popup\">\n <form class=\"NgxEditor__Popup--Form\" [formGroup]=\"form\" (ngSubmit)=\"insertLink($event)\">\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label class=\"NgxEditor__Popup--Label\">{{getLabel('url')}}</label>\n <input type=\"href\" id=\"href\" formControlName=\"href\" autofocus autocomplete=\"off\" />\n <div *ngIf=\"href.touched && href.invalid\" class=\"NgxEditor__HelpText NgxEditor__HelpText--Error\">\n {{ href.errors?.['pattern'] && 'Please enter valid url.' }}\n </div>\n </div>\n </div>\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label class=\"NgxEditor__Popup--Label\">{{getLabel('text')}}</label>\n <input type=\"text\" formControlName=\"text\" autocomplete=\"off\" />\n <div *ngIf=\"text.touched && text.invalid\" class=\"NgxEditor__HelpText NgxEditor__HelpText--Error\">\n {{ text.errors?.['required'] && 'This is required' }}\n </div>\n </div>\n </div>\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label>\n <input type=\"checkbox\" formControlName=\"openInNewTab\" />\n {{getLabel('openInNewTab')}}\n </label>\n </div>\n </div>\n\n <button type=\"submit\" [disabled]=\"!form.valid\">{{getLabel('insert')}}</button>\n\n </form>\n</div>\n", styles: [""], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }], pipes: { "sanitizeHtml": i5.SanitizeHtmlPipe } });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: LinkComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-link', template: "<div class=\"NgxEditor__MenuItem--IconContainer\" [class.NgxEditor__MenuItem--Active]=\"isActive || showPopup\"\n [class.NgxEditor--Disabled]=\"!canExecute\" [innerHTML]=\"icon | sanitizeHtml\" (mousedown)=\"onMouseDown($event)\"\n [title]=\"title\">\n</div>\n\n<!-- popup -->\n<div *ngIf=\"showPopup\" class=\"NgxEditor__Popup\">\n <form class=\"NgxEditor__Popup--Form\" [formGroup]=\"form\" (ngSubmit)=\"insertLink($event)\">\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label class=\"NgxEditor__Popup--Label\">{{getLabel('url')}}</label>\n <input type=\"href\" id=\"href\" formControlName=\"href\" autofocus autocomplete=\"off\" />\n <div *ngIf=\"href.touched && href.invalid\" class=\"NgxEditor__HelpText NgxEditor__HelpText--Error\">\n {{ href.errors?.['pattern'] && 'Please enter valid url.' }}\n </div>\n </div>\n </div>\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label class=\"NgxEditor__Popup--Label\">{{getLabel('text')}}</label>\n <input type=\"text\" formControlName=\"text\" autocomplete=\"off\" />\n <div *ngIf=\"text.touched && text.invalid\" class=\"NgxEditor__HelpText NgxEditor__HelpText--Error\">\n {{ text.errors?.['required'] && 'This is required' }}\n </div>\n </div>\n </div>\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label>\n <input type=\"checkbox\" formControlName=\"openInNewTab\" />\n {{getLabel('openInNewTab')}}\n </label>\n </div>\n </div>\n\n <button type=\"submit\" [disabled]=\"!form.valid\">{{getLabel('insert')}}</button>\n\n </form>\n</div>\n", styles: [""] }]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.NgxEditorService }, { type: i2.MenuService }]; }, propDecorators: { onDocumentClick: [{
type: HostListener,
args: ['document:mousedown', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGluay5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZWRpdG9yL3NyYy9saWIvbW9kdWxlcy9tZW51L2xpbmsvbGluay5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZWRpdG9yL3NyYy9saWIvbW9kdWxlcy9tZW51L2xpbmsvbGluay5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFlBQVksR0FDYixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQW1CLFdBQVcsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFNckYsT0FBTyxJQUFJLE1BQU0sZ0JBQWdCLENBQUM7QUFDbEMsT0FBTyxFQUFFLElBQUksSUFBSSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7Ozs7OztBQVF0RCxNQUFNLE9BQU8sYUFBYTtJQWlCeEIsWUFDVSxFQUFjLEVBQ2QsV0FBNkIsRUFDN0IsV0FBd0I7UUFGeEIsT0FBRSxHQUFGLEVBQUUsQ0FBWTtRQUNkLGdCQUFXLEdBQVgsV0FBVyxDQUFrQjtRQUM3QixnQkFBVyxHQUFYLFdBQVcsQ0FBYTtRQW5CbEMsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUNsQixhQUFRLEdBQUcsS0FBSyxDQUFDO1FBQ2pCLGVBQVUsR0FBRyxJQUFJLENBQUM7UUFLbEIsU0FBSSxHQUFHLElBQUksU0FBUyxDQUFDO1lBQ25CLElBQUksRUFBRSxJQUFJLFdBQVcsQ0FBQyxFQUFFLEVBQUU7Z0JBQ3hCLFVBQVUsQ0FBQyxRQUFRO2dCQUNuQixVQUFVLENBQUMsT0FBTyxDQUFDLGdGQUFnRixDQUFDO2FBQ3JHLENBQUM7WUFDRixJQUFJLEVBQUUsSUFBSSxXQUFXLENBQUMsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FB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QUM7UUFFL0MsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFnQixFQUFFLEVBQUU7WUFDdEYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwQixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxXQUFXO1FBQ1QsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3hDLENBQUM7OzBHQTdIVSxhQUFhOzhGQUFiLGFBQWEsMEhDbkIxQix5dkRBMENBOzJGRHZCYSxhQUFhO2tCQU56QixTQUFTOytCQUNFLFVBQVU7MEpBNEM0QixlQUFlO3NCQUE5RCxZQUFZO3VCQUFDLG9CQUFvQixFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LCBFbGVtZW50UmVmLFxuICBIb3N0TGlzdGVuZXIsIE9uRGVzdHJveSwgT25Jbml0LFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgRm9ybUNvbnRyb2wsIEZvcm1Hcm91cCwgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IEVkaXRvclZpZXcgfSBmcm9tICdwcm9zZW1pcnJvci12aWV3JztcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBOZ3hFZGl0b3JTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vZWRpdG9yLnNlcnZpY2UnO1xuaW1wb3J0IHsgTWVudVNlcnZpY2UgfSBmcm9tICcuLi9tZW51LnNlcnZpY2UnO1xuaW1wb3J0IEljb24gZnJvbSAnLi4vLi4vLi4vaWNvbnMnO1xuaW1wb3J0IHsgTGluayBhcyBMaW5rQ29tbWFuZCB9IGZyb20gJy4uL01lbnVDb21tYW5kcyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25neC1saW5rJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2xpbmsuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9saW5rLmNvbXBvbmVudC5zY3NzJ10sXG59KVxuXG5leHBvcnQgY2xhc3MgTGlua0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgc2hvd1BvcHVwID0gZmFsc2U7XG4gIGlzQWN0aXZlID0gZmFsc2U7XG4gIGNhbkV4ZWN1dGUgPSB0cnVlO1xuXG4gIHByaXZhdGUgZWRpdG9yVmlldzogRWRpdG9yVmlldztcbiAgcHJpdmF0ZSB1cGRhdGVTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcblxuICBmb3JtID0gbmV3IEZvcm1Hcm91cCh7XG4gICAgaHJlZjogbmV3IEZvcm1Db250cm9sKCcnLCBbXG4gICAgICBWYWxpZGF0b3JzLnJlcXVpcmVkLFxuICAgICAgVmFsaWRhdG9ycy5wYXR0ZXJuKCcoaHR0cHM/Oi8vKT8oW1xcXFxkYS16Li1dKylcXFxcLihbYS16Ll17Miw2fSlbL1xcXFx3IC4tXSovPz8oW14jXFxuXFxyXSopPyM/KFteXFxuXFxyXSopJyksXG4gICAgXSksXG4gICAgdGV4dDogbmV3IEZvcm1Db250cm9sKCcnLCBbVmFsaWRhdG9ycy5yZXF1aXJlZF0pLFxuICAgIG9wZW5Jbk5ld1RhYjogbmV3IEZvcm1Db250cm9sKHRydWUpLFxuICB9KTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGVsOiBFbGVtZW50UmVmLFxuICAgIHByaXZhdGUgbmd4ZVNlcnZpY2U6IE5neEVkaXRvclNlcnZpY2UsXG4gICAgcHJpdmF0ZSBtZW51U2VydmljZTogTWVudVNlcnZpY2UsXG4gICkgeyB9XG5cbiAgZ2V0IGljb24oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gSWNvbi5nZXQodGhpcy5pc0FjdGl2ZSA/ICd1bmxpbmsnIDogJ2xpbmsnKTtcbiAgfVxuXG4gIGdldCB0aXRsZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm5neGVTZXJ2aWNlLmxvY2Fscy5nZXQodGhpcy5pc0FjdGl2ZSA/ICdyZW1vdmVMaW5rJyA6ICdpbnNlcnRMaW5rJyk7XG4gIH1cblxuICBnZXQgaHJlZigpOiBBYnN0cmFjdENvbnRyb2wge1xuICAgIHJldHVybiB0aGlzLmZvcm0uZ2V0KCdocmVmJyk7XG4gIH1cblxuICBnZXQgdGV4dCgpOiBBYnN0cmFjdENvbnRyb2wge1xuICAgIHJldHVybiB0aGlzLmZvcm0uZ2V0KCd0ZXh0Jyk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdkb2N1bWVudDptb3VzZWRvd24nLCBbJyRldmVudCddKSBvbkRvY3VtZW50Q2xpY2soZTogTW91c2VFdmVudCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5lbC5uYXRpdmVFbGVtZW50LmNvbnRhaW5zKGUudGFyZ2V0KSAmJiB0aGlzLnNob3dQb3B1cCkge1xuICAgICAgdGhpcy5oaWRlRm9ybSgpO1xuICAgIH1cbiAgfVxuXG4gIGdldExhYmVsKGtleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5uZ3hlU2VydmljZS5sb2NhbHMuZ2V0KGtleSk7XG4gIH1cblxuICBwcml2YXRlIGhpZGVGb3JtKCk6IHZvaWQge1xuICAgIHRoaXMuc2hvd1BvcHVwID0gZmFsc2U7XG4gICAgdGhpcy5mb3JtLnJlc2V0KHtcbiAgICAgIGhyZWY6ICcnLFxuICAgICAgdGV4dDogJycsXG4gICAgICBvcGVuSW5OZXdUYWI6IHRydWUsXG4gICAgfSk7XG4gICAgdGhpcy50ZXh0LmVuYWJsZSgpO1xuICB9XG5cbiAgb25Nb3VzZURvd24oZTogTW91c2VFdmVudCk6IHZvaWQge1xuICAgIGlmIChlLmJ1dHRvbiAhPT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHsgc3RhdGUsIGRpc3BhdGNoIH0gPSB0aGlzLmVkaXRvclZpZXc7XG5cbiAgICBpZiAodGhpcy5pc0FjdGl2ZSkge1xuICAgICAgTGlua0NvbW1hbmQucmVtb3ZlKHN0YXRlLCBkaXNwYXRjaCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5zaG93UG9wdXAgPSAhdGhpcy5zaG93UG9wdXA7XG4gICAgaWYgKHRoaXMuc2hvd1BvcHVwKSB7XG4gICAgICB0aGlzLnNldFRleHQoKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHNldFRleHQgPSAoKSA9PiB7XG4gICAgY29uc3QgeyBzdGF0ZTogeyBzZWxlY3Rpb24sIGRvYyB9IH0gPSB0aGlzLmVkaXRvclZpZXc7XG4gICAgY29uc3QgeyBlbXB0eSwgZnJvbSwgdG8gfSA9IHNlbGVjdGlvbjtcbiAgICBjb25zdCBzZWxlY3RlZFRleHQgPSAhZW1wdHkgPyBkb2MudGV4dEJldHdlZW4oZnJvbSwgdG8pIDogJyc7XG5cbiAgICBpZiAoc2VsZWN0ZWRUZXh0KSB7XG4gICAgICB0aGlzLnRleHQucGF0Y2hWYWx1ZShzZWxlY3RlZFRleHQpO1xuICAgICAgdGhpcy50ZXh0LmRpc2FibGUoKTtcbiAgICB9XG4gIH07XG5cbiAgcHJpdmF0ZSB1cGRhdGUgPSAodmlldzogRWRpdG9yVmlldykgPT4ge1xuICAgIGNvbnN0IHsgc3RhdGUgfSA9IHZpZXc7XG4gICAgdGhpcy5pc0FjdGl2ZSA9IExpbmtDb21tYW5kLmlzQWN0aXZlKHN0YXRlLCB7IHN0cmljdDogZmFsc2UgfSk7XG4gICAgdGhpcy5jYW5FeGVjdXRlID0gTGlua0NvbW1hbmQuY2FuRXhlY3V0ZShzdGF0ZSk7XG4gIH07XG5cbiAgaW5zZXJ0TGluayhlOiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGNvbnN0IHsgdGV4dCwgaHJlZiwgb3BlbkluTmV3VGFiIH0gPSB0aGlzLmZvcm0uZ2V0UmF3VmFsdWUoKTtcbiAgICBjb25zdCB7IGRpc3BhdGNoLCBzdGF0ZSB9ID0gdGhpcy5lZGl0b3JWaWV3O1xuICAgIGNvbnN0IHsgc2VsZWN0aW9uIH0gPSBzdGF0ZTtcblxuICAgIGNvbnN0IGF0dHJzID0ge1xuICAgICAgdGl0bGU6IGhyZWYsXG4gICAgICBocmVmLFxuICAgICAgdGFyZ2V0OiBvcGVuSW5OZXdUYWIgPyAnX2JsYW5rJyA6ICdfc2VsZicsXG4gICAgfTtcblxuICAgIGlmIChzZWxlY3Rpb24uZW1wdHkpIHtcbiAgICAgIExpbmtDb21tYW5kLmluc2VydCh0ZXh0LCBhdHRycykoc3RhdGUsIGRpc3BhdGNoKTtcbiAgICAgIHRoaXMuZWRpdG9yVmlldy5mb2N1cygpO1xuICAgIH0gZWxzZSB7XG4gICAgICBMaW5rQ29tbWFuZC51cGRhdGUoYXR0cnMpKHN0YXRlLCBkaXNwYXRjaCk7XG4gICAgfVxuICAgIHRoaXMuaGlkZUZvcm0oKTtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuZWRpdG9yVmlldyA9IHRoaXMubWVudVNlcnZpY2UuZWRpdG9yLnZpZXc7XG5cbiAgICB0aGlzLnVwZGF0ZVN1YnNjcmlwdGlvbiA9IHRoaXMubWVudVNlcnZpY2UuZWRpdG9yLnVwZGF0ZS5zdWJzY3JpYmUoKHZpZXc6IEVkaXRvclZpZXcpID0+IHtcbiAgICAgIHRoaXMudXBkYXRlKHZpZXcpO1xuICAgIH0pO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy51cGRhdGVTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cIk5neEVkaXRvcl9fTWVudUl0ZW0tLUljb25Db250YWluZXJcIiBbY2xhc3MuTmd4RWRpdG9yX19NZW51SXRlbS0tQWN0aXZlXT1cImlzQWN0aXZlIHx8IHNob3dQb3B1cFwiXG4gIFtjbGFzcy5OZ3hFZGl0b3ItLURpc2FibGVkXT1cIiFjYW5FeGVjdXRlXCIgW2lubmVySFRNTF09XCJpY29uIHwgc2FuaXRpemVIdG1sXCIgKG1vdXNlZG93bik9XCJvbk1vdXNlRG93bigkZXZlbnQpXCJcbiAgW3RpdGxlXT1cInRpdGxlXCI+XG48L2Rpdj5cblxuPCEtLSBwb3B1cCAtLT5cbjxkaXYgKm5nSWY9XCJzaG93UG9wdXBcIiBjbGFzcz1cIk5neEVkaXRvcl9fUG9wdXBcIj5cbiAgPGZvcm0gY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Gb3JtXCIgW2Zvcm1Hcm91cF09XCJmb3JtXCIgKG5nU3VibWl0KT1cImluc2VydExpbmsoJGV2ZW50KVwiPlxuXG4gICAgPGRpdiBjbGFzcz1cIk5neEVkaXRvcl9fUG9wdXAtLUZvcm1Hcm91cFwiPlxuICAgICAgPGRpdiBjbGFzcz1cIk5neEVkaXRvcl9fUG9wdXAtLUNvbFwiPlxuICAgICAgICA8bGFiZWwgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1MYWJlbFwiPnt7Z2V0TGFiZWwoJ3VybCcpfX08L2xhYmVsPlxuICAgICAgICA8aW5wdXQgdHlwZT1cImhyZWZcIiBpZD1cImhyZWZcIiBmb3JtQ29udHJvbE5hbWU9XCJocmVmXCIgYXV0b2ZvY3VzIGF1dG9jb21wbGV0ZT1cIm9mZlwiIC8+XG4gICAgICAgIDxkaXYgKm5nSWY9XCJocmVmLnRvdWNoZWQgJiYgaHJlZi5pbnZhbGlkXCIgY2xhc3M9XCJOZ3hFZGl0b3JfX0hlbHBUZXh0IE5neEVkaXRvcl9fSGVscFRleHQtLUVycm9yXCI+XG4gICAgICAgICAge3sgaHJlZi5lcnJvcnM/LlsncGF0dGVybiddICYmICdQbGVhc2UgZW50ZXIgdmFsaWQgdXJsLicgfX1cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Gb3JtR3JvdXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Db2xcIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tTGFiZWxcIj57e2dldExhYmVsKCd0ZXh0Jyl9fTwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIGZvcm1Db250cm9sTmFtZT1cInRleHRcIiBhdXRvY29tcGxldGU9XCJvZmZcIiAvPlxuICAgICAgICA8ZGl2ICpuZ0lmPVwidGV4dC50b3VjaGVkICYmIHRleHQuaW52YWxpZFwiIGNsYXNzPVwiTmd4RWRpdG9yX19IZWxwVGV4dCBOZ3hFZGl0b3JfX0hlbHBUZXh0LS1FcnJvclwiPlxuICAgICAgICAgIHt7IHRleHQuZXJyb3JzPy5bJ3JlcXVpcmVkJ10gJiYgJ1RoaXMgaXMgcmVxdWlyZWQnIH19XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8ZGl2IGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tRm9ybUdyb3VwXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tQ29sXCI+XG4gICAgICAgIDxsYWJlbD5cbiAgICAgICAgICA8aW5wdXQgdHlwZT1cImNoZWNrYm94XCIgZm9ybUNvbnRyb2xOYW1lPVwib3BlbkluTmV3VGFiXCIgLz5cbiAgICAgICAgICB7e2dldExhYmVsKCdvcGVuSW5OZXdUYWInKX19XG4gICAgICAgIDwvbGFiZWw+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiIFtkaXNhYmxlZF09XCIhZm9ybS52YWxpZFwiPnt7Z2V0TGFiZWwoJ2luc2VydCcpfX08L2J1dHRvbj5cblxuICA8L2Zvcm0+XG48L2Rpdj5cbiJdfQ==