@iget/editor
Version:
WYSIWYG Editor for Angular Material applications
159 lines • 24.1 kB
JavaScript
import { Component, Input, Output, ViewChild, EventEmitter, forwardRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { DefaultIgetEditorConfig } from './common/default-iget-editor-config';
import * as Utils from './common/utils/iget-editor.utils';
import * as i0 from "@angular/core";
import * as i1 from "@angular/platform-browser";
import * as i2 from "./common/services/message.service";
import * as i3 from "./common/services/command-executor.service";
import * as i4 from "./iget-editor-toolbar/iget-editor-toolbar.component";
import * as i5 from "./iget-editor-message/iget-editor-message.component";
import * as i6 from "./iget-editor-grippie/iget-editor-grippie.component";
import * as i7 from "@angular/common";
export class IgetEditorComponent {
/**
* @param sanitizer Dom Sanitizer
* @param _messageService service to send message to the editor message component
* @param _commandExecutor executes command from the toolbar
* @param _renderer access and manipulate the dom element
*/
constructor(sanitizer, _messageService, _commandExecutor, _renderer) {
this.sanitizer = sanitizer;
this._messageService = _messageService;
this._commandExecutor = _commandExecutor;
this._renderer = _renderer;
/** emits `blured` event when focused out from the textarea */
this.blured = new EventEmitter();
/** emits `focused` event when focused in to the textarea */
this.focused = new EventEmitter();
this.Utils = Utils;
this.showPlaceholder = true;
}
/**
* events
*/
onTextAreaFocus() {
this.focused.emit('focus');
}
/** focus the text area when the editor is focussed */
onEditorFocus() {
this.textArea.nativeElement.focus();
}
/**
* Executed from the contenteditable section while the input property changes
*/
onContentChange($event) {
const innerHtml = $event.target.innerHTML;
if (typeof this.onChange === 'function') {
this.onChange(innerHtml);
this.togglePlaceholder(innerHtml);
}
}
onTextAreaBlur() {
/** save selection if focussed out */
this._commandExecutor.savedSelection = Utils.saveSelection();
if (typeof this.onTouched === 'function') {
this.onTouched();
}
this.blured.emit('blur');
}
/**
* resizing text area
*
* @param offsetY vertical height of the editable portion of the editor
*/
resizeTextArea(offsetY) {
const oldHeight = parseInt(getComputedStyle(this.textArea.nativeElement).height, 10);
this.textArea.nativeElement.style.height = (oldHeight + offsetY) + 'px';
}
/**
* editor actions, i.e., executes command from toolbar
*
* @param commandName name of the command to be executed
*/
executeCommand(commandName) {
try {
this._commandExecutor.execute(commandName);
}
catch (error) {
this._messageService.sendMessage(error.message);
}
}
/**
* Write a new value to the element.
*
* @param value value to be executed when there is a change in contenteditable
*/
writeValue(value) {
this.togglePlaceholder(value);
if (value === null || value === undefined || value === '' || value === '<br>') {
value = null;
}
this.value = this.sanitizer.bypassSecurityTrustHtml(value);
}
/**
* Set the function to be called
* when the control receives a change event.
*
* @param fn a function
*/
registerOnChange(fn) {
this.onChange = fn;
}
/**
* Set the function to be called
* when the control receives a touch event.
*
* @param fn a function
*/
registerOnTouched(fn) {
this.onTouched = fn;
}
/**
* toggles placeholder based on input string
*
* @param value A HTML string from the editor
*/
togglePlaceholder(value) {
if (!value || value === '<br>' || value === '') {
this.showPlaceholder = true;
}
else {
this.showPlaceholder = false;
}
}
ngOnInit() {
// this.height = this.height || this.textArea.nativeElement.offsetHeight;
this.executeCommand('enableObjectResizing');
}
ngOnChanges() {
this.config = Object.assign({}, DefaultIgetEditorConfig, this.config);
}
}
IgetEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: IgetEditorComponent, deps: [{ token: i1.DomSanitizer }, { token: i2.MessageService }, { token: i3.CommandExecutorService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
IgetEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: IgetEditorComponent, selector: "iget-editor", inputs: { config: "config" }, outputs: { blured: "blured", focused: "focused" }, providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => IgetEditorComponent),
multi: true
}], viewQueries: [{ propertyName: "textArea", first: true, predicate: ["igetEditorTextArea"], descendants: true }, { propertyName: "wrapper", first: true, predicate: ["igetEditorWrapper"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"iget-editor\"\n tabindex=\"0\"\n [style.width]=\"config.width\"\n [style.minWidth]=\"config.minWidth\"\n [class.toolbar-before]=\"config.toolbarPosition === 'before'\"\n (focus)=\"onEditorFocus()\">\n\n <!-- text area -->\n <div class=\"iget-editor-wrapper\" #igetEditorWrapper>\n <div class=\"iget-editor-textarea\" [class.show-placeholder]=\"showPlaceholder\" [attr.contenteditable]=\"config.editable\" (input)=\"onContentChange($event)\"\n [attr.translate]=\"config['translate']\" [attr.spellcheck]=\"config.spellcheck\" [style.height]=\"config.height\"\n [style.minHeight]=\"config['minHeight']\" [style.resize]=\"'none'\" (focus)=\"onTextAreaFocus()\"\n (blur)=\"onTextAreaBlur()\" [innerHTML]=\"value\" #igetEditorTextArea></div>\n\n <span class=\"iget-editor-placeholder\">{{ config.placeholder }}</span>\n </div>\n\n <iget-editor-toolbar\n [config]=\"config.toolbar\"\n (execute)=\"executeCommand($event)\">\n </iget-editor-toolbar>\n\n <iget-editor-message></iget-editor-message>\n <iget-editor-grippie *ngIf=\"config.resizable\" (resized)=\"resizeTextArea($event)\"></iget-editor-grippie>\n</div>\n", styles: [".iget-editor{position:relative;border:1px solid #e0e0e0;display:flex;flex-direction:column}.iget-editor ::ng-deep [contenteditable=true]:empty:before{content:attr(placeholder);display:block;color:#868e96;opacity:1}.iget-editor .iget-editor-wrapper{position:relative}.iget-editor .iget-editor-wrapper .iget-editor-textarea{min-height:5rem;padding:.5rem .8rem 1rem;background-color:transparent;overflow-x:hidden;overflow-y:auto;z-index:2;position:relative}.iget-editor .iget-editor-wrapper .iget-editor-textarea:focus,.iget-editor .iget-editor-wrapper .iget-editor-textarea.focus{outline:0}.iget-editor .iget-editor-wrapper .iget-editor-textarea ::ng-deep blockquote{margin-left:1rem;border-left:.2em solid #dfe2e5;padding-left:.5rem}.iget-editor .iget-editor-wrapper ::ng-deep p{margin-bottom:0}.iget-editor .iget-editor-wrapper .iget-editor-placeholder{display:none;position:absolute;top:0;padding:.5rem .8rem 1rem .9rem;z-index:1;color:#6c757d;opacity:1}.iget-editor .iget-editor-wrapper.show-placeholder .iget-editor-placeholder{display:block}.iget-editor.toolbar-before iget-editor-toolbar{order:-1;margin-bottom:0}.iget-editor iget-editor-toolbar{margin:1rem}\n"], components: [{ type: i4.IgetEditorToolbarComponent, selector: "iget-editor-toolbar", inputs: ["config"], outputs: ["execute"] }, { type: i5.IgetEditorMessageComponent, selector: "iget-editor-message" }, { type: i6.IgetEditorGrippieComponent, selector: "iget-editor-grippie", outputs: ["resized"] }], directives: [{ type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: IgetEditorComponent, decorators: [{
type: Component,
args: [{ selector: 'iget-editor', providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => IgetEditorComponent),
multi: true
}], template: "<div class=\"iget-editor\"\n tabindex=\"0\"\n [style.width]=\"config.width\"\n [style.minWidth]=\"config.minWidth\"\n [class.toolbar-before]=\"config.toolbarPosition === 'before'\"\n (focus)=\"onEditorFocus()\">\n\n <!-- text area -->\n <div class=\"iget-editor-wrapper\" #igetEditorWrapper>\n <div class=\"iget-editor-textarea\" [class.show-placeholder]=\"showPlaceholder\" [attr.contenteditable]=\"config.editable\" (input)=\"onContentChange($event)\"\n [attr.translate]=\"config['translate']\" [attr.spellcheck]=\"config.spellcheck\" [style.height]=\"config.height\"\n [style.minHeight]=\"config['minHeight']\" [style.resize]=\"'none'\" (focus)=\"onTextAreaFocus()\"\n (blur)=\"onTextAreaBlur()\" [innerHTML]=\"value\" #igetEditorTextArea></div>\n\n <span class=\"iget-editor-placeholder\">{{ config.placeholder }}</span>\n </div>\n\n <iget-editor-toolbar\n [config]=\"config.toolbar\"\n (execute)=\"executeCommand($event)\">\n </iget-editor-toolbar>\n\n <iget-editor-message></iget-editor-message>\n <iget-editor-grippie *ngIf=\"config.resizable\" (resized)=\"resizeTextArea($event)\"></iget-editor-grippie>\n</div>\n", styles: [".iget-editor{position:relative;border:1px solid #e0e0e0;display:flex;flex-direction:column}.iget-editor ::ng-deep [contenteditable=true]:empty:before{content:attr(placeholder);display:block;color:#868e96;opacity:1}.iget-editor .iget-editor-wrapper{position:relative}.iget-editor .iget-editor-wrapper .iget-editor-textarea{min-height:5rem;padding:.5rem .8rem 1rem;background-color:transparent;overflow-x:hidden;overflow-y:auto;z-index:2;position:relative}.iget-editor .iget-editor-wrapper .iget-editor-textarea:focus,.iget-editor .iget-editor-wrapper .iget-editor-textarea.focus{outline:0}.iget-editor .iget-editor-wrapper .iget-editor-textarea ::ng-deep blockquote{margin-left:1rem;border-left:.2em solid #dfe2e5;padding-left:.5rem}.iget-editor .iget-editor-wrapper ::ng-deep p{margin-bottom:0}.iget-editor .iget-editor-wrapper .iget-editor-placeholder{display:none;position:absolute;top:0;padding:.5rem .8rem 1rem .9rem;z-index:1;color:#6c757d;opacity:1}.iget-editor .iget-editor-wrapper.show-placeholder .iget-editor-placeholder{display:block}.iget-editor.toolbar-before iget-editor-toolbar{order:-1;margin-bottom:0}.iget-editor iget-editor-toolbar{margin:1rem}\n"] }]
}], ctorParameters: function () { return [{ type: i1.DomSanitizer }, { type: i2.MessageService }, { type: i3.CommandExecutorService }, { type: i0.Renderer2 }]; }, propDecorators: { config: [{
type: Input
}], blured: [{
type: Output
}], focused: [{
type: Output
}], textArea: [{
type: ViewChild,
args: ['igetEditorTextArea']
}], wrapper: [{
type: ViewChild,
args: ['igetEditorWrapper']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWdldC1lZGl0b3IuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9pZ2V0LWVkaXRvci9pZ2V0LWVkaXRvci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9zcmMvYXBwL2lnZXQtZWRpdG9yL2lnZXQtZWRpdG9yLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQVUsS0FBSyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQzNDLFlBQVksRUFBYSxVQUFVLEVBQ3BDLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxpQkFBaUIsRUFBd0IsTUFBTSxnQkFBZ0IsQ0FBQztBQUt6RSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUM5RSxPQUFPLEtBQUssS0FBSyxNQUFNLGtDQUFrQyxDQUFDOzs7Ozs7Ozs7QUFlMUQsTUFBTSxPQUFPLG1CQUFtQjtJQWtCOUI7Ozs7O09BS0c7SUFDSCxZQUNVLFNBQXVCLEVBQ3ZCLGVBQStCLEVBQy9CLGdCQUF3QyxFQUN4QyxTQUFvQjtRQUhwQixjQUFTLEdBQVQsU0FBUyxDQUFjO1FBQ3ZCLG9CQUFlLEdBQWYsZUFBZSxDQUFnQjtRQUMvQixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQXdCO1FBQ3hDLGNBQVMsR0FBVCxTQUFTLENBQVc7UUF6QjlCLDhEQUE4RDtRQUNwRCxXQUFNLEdBQXlCLElBQUksWUFBWSxFQUFVLENBQUM7UUFDcEUsNERBQTREO1FBQ2xELFlBQU8sR0FBeUIsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUtyRSxVQUFLLEdBQVEsS0FBSyxDQUFDO1FBRW5CLG9CQUFlLEdBQUcsSUFBSSxDQUFDO0lBZVcsQ0FBQztJQUVuQzs7T0FFRztJQUNILGVBQWU7UUFDYixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM3QixD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TSxDQUFDLENBQUM7SUFDeEUsQ0FBQzs7Z0hBL0lVLG1CQUFtQjtvR0FBbkIsbUJBQW1CLHVIQVBuQixDQUFDO1lBQ1YsT0FBTyxFQUFFLGlCQUFpQjtZQUMxQixXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLG1CQUFtQixDQUFDO1lBQ2xELEtBQUssRUFBRSxJQUFJO1NBQ1osQ0FBQyw4UEN0QkosNnBDQXlCQTsyRkRBYSxtQkFBbUI7a0JBWC9CLFNBQVM7K0JBQ0UsYUFBYSxhQUdaLENBQUM7NEJBQ1YsT0FBTyxFQUFFLGlCQUFpQjs0QkFDMUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsb0JBQW9CLENBQUM7NEJBQ2xELEtBQUssRUFBRSxJQUFJO3lCQUNaLENBQUM7NkxBSU8sTUFBTTtzQkFBZCxLQUFLO2dCQUdJLE1BQU07c0JBQWYsTUFBTTtnQkFFRyxPQUFPO3NCQUFoQixNQUFNO2dCQUUwQixRQUFRO3NCQUF4QyxTQUFTO3VCQUFDLG9CQUFvQjtnQkFDQyxPQUFPO3NCQUF0QyxTQUFTO3VCQUFDLG1CQUFtQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCwgT25Jbml0LCBJbnB1dCwgT3V0cHV0LCBWaWV3Q2hpbGQsXG4gIEV2ZW50RW1pdHRlciwgUmVuZGVyZXIyLCBmb3J3YXJkUmVmLCBPbkNoYW5nZXNcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBOR19WQUxVRV9BQ0NFU1NPUiwgQ29udHJvbFZhbHVlQWNjZXNzb3IgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB7IENvbW1hbmRFeGVjdXRvclNlcnZpY2UgfSBmcm9tICcuL2NvbW1vbi9zZXJ2aWNlcy9jb21tYW5kLWV4ZWN1dG9yLnNlcnZpY2UnO1xuaW1wb3J0IHsgTWVzc2FnZVNlcnZpY2UgfSBmcm9tICcuL2NvbW1vbi9zZXJ2aWNlcy9tZXNzYWdlLnNlcnZpY2UnO1xuXG5pbXBvcnQgeyBEZWZhdWx0SWdldEVkaXRvckNvbmZpZyB9IGZyb20gJy4vY29tbW9uL2RlZmF1bHQtaWdldC1lZGl0b3ItY29uZmlnJztcbmltcG9ydCAqIGFzIFV0aWxzIGZyb20gJy4vY29tbW9uL3V0aWxzL2lnZXQtZWRpdG9yLnV0aWxzJztcbmltcG9ydCB7RG9tU2FuaXRpemVyLCBTYWZlSHRtbH0gZnJvbSAnQGFuZ3VsYXIvcGxhdGZvcm0tYnJvd3Nlcic7XG5pbXBvcnQge0lnZXRFZGl0b3JDdXN0b21Db25maWd9IGZyb20gJy4vaWdldC1lZGl0b3ItY3VzdG9tLWNvbmZpZyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2lnZXQtZWRpdG9yJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2lnZXQtZWRpdG9yLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vaWdldC1lZGl0b3IuY29tcG9uZW50LnNjc3MnXSxcbiAgcHJvdmlkZXJzOiBbe1xuICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IElnZXRFZGl0b3JDb21wb25lbnQpLFxuICAgIG11bHRpOiB0cnVlXG4gIH1dXG59KVxuXG5leHBvcnQgY2xhc3MgSWdldEVkaXRvckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzLCBDb250cm9sVmFsdWVBY2Nlc3NvciB7XG4gIEBJbnB1dCgpIGNvbmZpZzogSWdldEVkaXRvckN1c3RvbUNvbmZpZztcblxuICAvKiogZW1pdHMgYGJsdXJlZGAgZXZlbnQgd2hlbiBmb2N1c2VkIG91dCBmcm9tIHRoZSB0ZXh0YXJlYSAqL1xuICBAT3V0cHV0KCkgYmx1cmVkOiBFdmVudEVtaXR0ZXI8c3RyaW5nPiA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuICAvKiogZW1pdHMgYGZvY3VzZWRgIGV2ZW50IHdoZW4gZm9jdXNlZCBpbiB0byB0aGUgdGV4dGFyZWEgKi9cbiAgQE91dHB1dCgpIGZvY3VzZWQ6IEV2ZW50RW1pdHRlcjxzdHJpbmc+ID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XG5cbiAgQFZpZXdDaGlsZCgnaWdldEVkaXRvclRleHRBcmVhJykgdGV4dEFyZWE6IGFueTtcbiAgQFZpZXdDaGlsZCgnaWdldEVkaXRvcldyYXBwZXInKSB3cmFwcGVyOiBhbnk7XG5cbiAgVXRpbHM6IGFueSA9IFV0aWxzO1xuICB2YWx1ZTogU2FmZUh0bWw7XG4gIHNob3dQbGFjZWhvbGRlciA9IHRydWU7XG5cbiAgcHJpdmF0ZSBvbkNoYW5nZTogKHZhbHVlOiBzdHJpbmcpID0+IHZvaWQ7XG4gIHByaXZhdGUgb25Ub3VjaGVkOiAoKSA9PiB2b2lkO1xuXG4gIC8qKlxuICAgKiBAcGFyYW0gc2FuaXRpemVyIERvbSBTYW5pdGl6ZXJcbiAgICogQHBhcmFtIF9tZXNzYWdlU2VydmljZSBzZXJ2aWNlIHRvIHNlbmQgbWVzc2FnZSB0byB0aGUgZWRpdG9yIG1lc3NhZ2UgY29tcG9uZW50XG4gICAqIEBwYXJhbSBfY29tbWFuZEV4ZWN1dG9yIGV4ZWN1dGVzIGNvbW1hbmQgZnJvbSB0aGUgdG9vbGJhclxuICAgKiBAcGFyYW0gX3JlbmRlcmVyIGFjY2VzcyBhbmQgbWFuaXB1bGF0ZSB0aGUgZG9tIGVsZW1lbnRcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgc2FuaXRpemVyOiBEb21TYW5pdGl6ZXIsXG4gICAgcHJpdmF0ZSBfbWVzc2FnZVNlcnZpY2U6IE1lc3NhZ2VTZXJ2aWNlLFxuICAgIHByaXZhdGUgX2NvbW1hbmRFeGVjdXRvcjogQ29tbWFuZEV4ZWN1dG9yU2VydmljZSxcbiAgICBwcml2YXRlIF9yZW5kZXJlcjogUmVuZGVyZXIyKSB7IH1cblxuICAvKipcbiAgICogZXZlbnRzXG4gICAqL1xuICBvblRleHRBcmVhRm9jdXMoKTogdm9pZCB7XG4gICAgdGhpcy5mb2N1c2VkLmVtaXQoJ2ZvY3VzJyk7XG4gIH1cblxuICAvKiogZm9jdXMgdGhlIHRleHQgYXJlYSB3aGVuIHRoZSBlZGl0b3IgaXMgZm9jdXNzZWQgKi9cbiAgb25FZGl0b3JGb2N1cygpIHtcbiAgICB0aGlzLnRleHRBcmVhLm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeGVjdXRlZCBmcm9tIHRoZSBjb250ZW50ZWRpdGFibGUgc2VjdGlvbiB3aGlsZSB0aGUgaW5wdXQgcHJvcGVydHkgY2hhbmdlc1xuICAgKi9cbiAgb25Db250ZW50Q2hhbmdlKCRldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBpbm5lckh0bWwgPSAoJGV2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudCkuaW5uZXJIVE1MO1xuICAgIGlmICh0eXBlb2YgdGhpcy5vbkNoYW5nZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgdGhpcy5vbkNoYW5nZShpbm5lckh0bWwpO1xuICAgICAgdGhpcy50b2dnbGVQbGFjZWhvbGRlcihpbm5lckh0bWwpO1xuICAgIH1cbiAgfVxuXG4gIG9uVGV4dEFyZWFCbHVyKCk6IHZvaWQge1xuICAgIC8qKiBzYXZlIHNlbGVjdGlvbiBpZiBmb2N1c3NlZCBvdXQgKi9cbiAgICB0aGlzLl9jb21tYW5kRXhlY3V0b3Iuc2F2ZWRTZWxlY3Rpb24gPSBVdGlscy5zYXZlU2VsZWN0aW9uKCk7XG5cbiAgICBpZiAodHlwZW9mIHRoaXMub25Ub3VjaGVkID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aGlzLm9uVG91Y2hlZCgpO1xuICAgIH1cbiAgICB0aGlzLmJsdXJlZC5lbWl0KCdibHVyJyk7XG4gIH1cblxuICAvKipcbiAgICogcmVzaXppbmcgdGV4dCBhcmVhXG4gICAqXG4gICAqIEBwYXJhbSBvZmZzZXRZIHZlcnRpY2FsIGhlaWdodCBvZiB0aGUgZWRpdGFibGUgcG9ydGlvbiBvZiB0aGUgZWRpdG9yXG4gICAqL1xuICByZXNpemVUZXh0QXJlYShvZmZzZXRZOiBudW1iZXIpOiB2b2lkIHtcbiAgICBjb25zdCBvbGRIZWlnaHQgPSBwYXJzZUludChnZXRDb21wdXRlZFN0eWxlKHRoaXMudGV4dEFyZWEubmF0aXZlRWxlbWVudCkuaGVpZ2h0LCAxMCk7XG5cbiAgICB0aGlzLnRleHRBcmVhLm5hdGl2ZUVsZW1lbnQuc3R5bGUuaGVpZ2h0ID0gKG9sZEhlaWdodCArIG9mZnNldFkpICsgJ3B4JztcbiAgfVxuXG4gIC8qKlxuICAgKiBlZGl0b3IgYWN0aW9ucywgaS5lLiwgZXhlY3V0ZXMgY29tbWFuZCBmcm9tIHRvb2xiYXJcbiAgICpcbiAgICogQHBhcmFtIGNvbW1hbmROYW1lIG5hbWUgb2YgdGhlIGNvbW1hbmQgdG8gYmUgZXhlY3V0ZWRcbiAgICovXG4gIGV4ZWN1dGVDb21tYW5kKGNvbW1hbmROYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgdGhpcy5fY29tbWFuZEV4ZWN1dG9yLmV4ZWN1dGUoY29tbWFuZE5hbWUpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLl9tZXNzYWdlU2VydmljZS5zZW5kTWVzc2FnZShlcnJvci5tZXNzYWdlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogV3JpdGUgYSBuZXcgdmFsdWUgdG8gdGhlIGVsZW1lbnQuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSB2YWx1ZSB0byBiZSBleGVjdXRlZCB3aGVuIHRoZXJlIGlzIGEgY2hhbmdlIGluIGNvbnRlbnRlZGl0YWJsZVxuICAgKi9cbiAgd3JpdGVWYWx1ZSh2YWx1ZTogYW55KTogdm9pZCB7XG4gICAgdGhpcy50b2dnbGVQbGFjZWhvbGRlcih2YWx1ZSk7XG5cbiAgICBpZiAodmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gJycgfHwgdmFsdWUgPT09ICc8YnI+Jykge1xuICAgICAgdmFsdWUgPSBudWxsO1xuICAgIH1cblxuICAgIHRoaXMudmFsdWUgPSB0aGlzLnNhbml0aXplci5ieXBhc3NTZWN1cml0eVRydXN0SHRtbCh2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSBmdW5jdGlvbiB0byBiZSBjYWxsZWRcbiAgICogd2hlbiB0aGUgY29udHJvbCByZWNlaXZlcyBhIGNoYW5nZSBldmVudC5cbiAgICpcbiAgICogQHBhcmFtIGZuIGEgZnVuY3Rpb25cbiAgICovXG4gIHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSk6IHZvaWQge1xuICAgIHRoaXMub25DaGFuZ2UgPSBmbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgdGhlIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZFxuICAgKiB3aGVuIHRoZSBjb250cm9sIHJlY2VpdmVzIGEgdG91Y2ggZXZlbnQuXG4gICAqXG4gICAqIEBwYXJhbSBmbiBhIGZ1bmN0aW9uXG4gICAqL1xuICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7XG4gICAgdGhpcy5vblRvdWNoZWQgPSBmbjtcbiAgfVxuXG4gIC8qKlxuICAgKiB0b2dnbGVzIHBsYWNlaG9sZGVyIGJhc2VkIG9uIGlucHV0IHN0cmluZ1xuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgQSBIVE1MIHN0cmluZyBmcm9tIHRoZSBlZGl0b3JcbiAgICovXG4gIHRvZ2dsZVBsYWNlaG9sZGVyKHZhbHVlOiBhbnkpOiB2b2lkIHtcbiAgICBpZiAoIXZhbHVlIHx8IHZhbHVlID09PSAnPGJyPicgfHwgdmFsdWUgPT09ICcnKSB7XG4gICAgICB0aGlzLnNob3dQbGFjZWhvbGRlciA9IHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2hvd1BsYWNlaG9sZGVyID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgLy8gdGhpcy5oZWlnaHQgPSB0aGlzLmhlaWdodCB8fCB0aGlzLnRleHRBcmVhLm5hdGl2ZUVsZW1lbnQub2Zmc2V0SGVpZ2h0O1xuXG4gICAgdGhpcy5leGVjdXRlQ29tbWFuZCgnZW5hYmxlT2JqZWN0UmVzaXppbmcnKTtcbiAgfVxuXG4gIG5nT25DaGFuZ2VzKCk6IHZvaWQge1xuICAgIHRoaXMuY29uZmlnID0gT2JqZWN0LmFzc2lnbih7fSwgRGVmYXVsdElnZXRFZGl0b3JDb25maWcsIHRoaXMuY29uZmlnKTtcbiAgfVxuXG59XG4iLCI8ZGl2IGNsYXNzPVwiaWdldC1lZGl0b3JcIlxuICAgICB0YWJpbmRleD1cIjBcIlxuICAgICBbc3R5bGUud2lkdGhdPVwiY29uZmlnLndpZHRoXCJcbiAgICAgW3N0eWxlLm1pbldpZHRoXT1cImNvbmZpZy5taW5XaWR0aFwiXG4gICAgIFtjbGFzcy50b29sYmFyLWJlZm9yZV09XCJjb25maWcudG9vbGJhclBvc2l0aW9uID09PSAnYmVmb3JlJ1wiXG4gICAgIChmb2N1cyk9XCJvbkVkaXRvckZvY3VzKClcIj5cblxuICA8IS0tIHRleHQgYXJlYSAtLT5cbiAgPGRpdiBjbGFzcz1cImlnZXQtZWRpdG9yLXdyYXBwZXJcIiAjaWdldEVkaXRvcldyYXBwZXI+XG4gICAgPGRpdiBjbGFzcz1cImlnZXQtZWRpdG9yLXRleHRhcmVhXCIgW2NsYXNzLnNob3ctcGxhY2Vob2xkZXJdPVwic2hvd1BsYWNlaG9sZGVyXCIgW2F0dHIuY29udGVudGVkaXRhYmxlXT1cImNvbmZpZy5lZGl0YWJsZVwiIChpbnB1dCk9XCJvbkNvbnRlbnRDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICBbYXR0ci50cmFuc2xhdGVdPVwiY29uZmlnWyd0cmFuc2xhdGUnXVwiIFthdHRyLnNwZWxsY2hlY2tdPVwiY29uZmlnLnNwZWxsY2hlY2tcIiBbc3R5bGUuaGVpZ2h0XT1cImNvbmZpZy5oZWlnaHRcIlxuICAgICAgW3N0eWxlLm1pbkhlaWdodF09XCJjb25maWdbJ21pbkhlaWdodCddXCIgW3N0eWxlLnJlc2l6ZV09XCInbm9uZSdcIiAoZm9jdXMpPVwib25UZXh0QXJlYUZvY3VzKClcIlxuICAgICAgKGJsdXIpPVwib25UZXh0QXJlYUJsdXIoKVwiIFtpbm5lckhUTUxdPVwidmFsdWVcIiAjaWdldEVkaXRvclRleHRBcmVhPjwvZGl2PlxuXG4gICAgPHNwYW4gY2xhc3M9XCJpZ2V0LWVkaXRvci1wbGFjZWhvbGRlclwiPnt7IGNvbmZpZy5wbGFjZWhvbGRlciB9fTwvc3Bhbj5cbiAgPC9kaXY+XG5cbiAgPGlnZXQtZWRpdG9yLXRvb2xiYXJcbiAgICAgIFtjb25maWddPVwiY29uZmlnLnRvb2xiYXJcIlxuICAgICAgKGV4ZWN1dGUpPVwiZXhlY3V0ZUNvbW1hbmQoJGV2ZW50KVwiPlxuICA8L2lnZXQtZWRpdG9yLXRvb2xiYXI+XG5cbiAgPGlnZXQtZWRpdG9yLW1lc3NhZ2U+PC9pZ2V0LWVkaXRvci1tZXNzYWdlPlxuICA8aWdldC1lZGl0b3ItZ3JpcHBpZSAqbmdJZj1cImNvbmZpZy5yZXNpemFibGVcIiAocmVzaXplZCk9XCJyZXNpemVUZXh0QXJlYSgkZXZlbnQpXCI+PC9pZ2V0LWVkaXRvci1ncmlwcGllPlxuPC9kaXY+XG4iXX0=