UNPKG

ngx-text-editor

Version:
218 lines 25.9 kB
import { Component, Input, Output, ViewChild, EventEmitter, Renderer2, forwardRef } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { CommandExecutorService } from '../common/services/command-executor.service'; import { MessageService } from '../common/services/message.service'; import { ngxTextEditorConfig } from '../common/ngx-text-editor.defaults'; import * as Utils from '../common/utils/ngx-text-editor.utils'; export class NgxTextEditorComponent { /** * @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(_messageService, _commandExecutor, _renderer) { this._messageService = _messageService; this._commandExecutor = _commandExecutor; this._renderer = _renderer; /** * The editor can be resized vertically. * * `basic` resizer enables the html5 reszier. Check here https://www.w3schools.com/cssref/css3_pr_resize.asp * * `stack` resizer enable a resizer that looks like as if in https://stackoverflow.com */ this.resizer = 'stack'; /** * The config property is a JSON object * * All avaibale inputs inputs can be provided in the configuration as JSON * inputs provided directly are considered as top priority */ this.config = ngxTextEditorConfig; /** emits `blur` event when focused out from the textarea */ this.blur = new EventEmitter(); /** emits `focus` event when focused in to the textarea */ this.focus = new EventEmitter(); /** emits `uploadImage` event when image is selected */ this.uploadImage = new EventEmitter(); this.Utils = Utils; } /** * events */ onTextAreaFocus() { this.focus.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 * @param event html string from contentEditable */ onContentChange(event) { const innerHTML = event.target.value; 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.blur.emit('blur'); } /** * Executed when the image from the disc is selected * @param image uploaded file object */ onUploadImage(image) { this.uploadImage.emit(image); } /** * resizing text area * * @param offsetY vertical height of the eidtable portion of the editor */ resizeTextArea(offsetY) { let newHeight = parseInt(this.height, 10); newHeight += offsetY; this.height = newHeight + 'px'; this.textArea.nativeElement.style.height = this.height; } /** * 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.refreshView(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; } /** * refresh view/HTML of the editor * * @param value html string from the editor */ refreshView(value) { const normalizedValue = value === null ? '' : value; this._renderer.setProperty(this.textArea.nativeElement, 'innerHTML', normalizedValue); } /** * toggles placeholder based on input string * * @param value A HTML string from the editor */ togglePlaceholder(value) { if (!value || value === '<br>' || value === '') { this._renderer.addClass(this.ngxWrapper.nativeElement, 'show-placeholder'); } else { this._renderer.removeClass(this.ngxWrapper.nativeElement, 'show-placeholder'); } } /** * returns a json containing input params */ getCollectiveParams() { return { editable: this.editable, spellcheck: this.spellcheck, placeholder: this.placeholder, translate: this.translate, height: this.height, minHeight: this.minHeight, width: this.width, minWidth: this.minWidth, enableToolbar: this.enableToolbar, showToolbar: this.showToolbar, imageEndPoint: this.imageEndPoint, toolbar: this.toolbar }; } ngOnInit() { /** * set configuration */ this.config = this.Utils.getEditorConfiguration(this.config, ngxTextEditorConfig, this.getCollectiveParams()); this.height = this.height || this.textArea.nativeElement.offsetHeight; this.executeCommand('enableObjectResizing'); } } NgxTextEditorComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-text-editor', template: "<div class=\"ngx-text-editor\"\n id=\"ngxTextEditor\"\n [style.width]=\"config['width']\"\n [style.minWidth]=\"config['minWidth']\"\n tabindex=\"0\"\n (focus)=\"onEditorFocus()\">\n\n <ngx-text-editor-toolbar [config]=\"config\"\n (execute)=\"executeCommand($event)\"\n (uploadImage)=\"onUploadImage($event)\"></ngx-text-editor-toolbar>\n\n <div #ngxWrapper\n class=\"ngx-wrapper\">\n <textarea #ngxTextArea\n class=\"ngx-text-editor-textarea\"\n [placeholder]=\"placeholder || config['placeholder']\"\n [attr.contenteditable]=\"config['editable']\"\n (input)=\"onContentChange($event)\"\n [attr.translate]=\"config['translate']\"\n [attr.spellcheck]=\"config['spellcheck']\"\n [style.height]=\"config['height']\"\n [style.minHeight]=\"config['minHeight']\"\n [style.resize]=\"Utils?.canResize(resizer)\"\n (focus)=\"onTextAreaFocus()\"\n (blur)=\"onTextAreaBlur()\"></textarea>\n </div>\n\n <ngx-text-editor-message></ngx-text-editor-message>\n\n <ngx-grippie *ngIf=\"resizer === 'stack'\"></ngx-grippie>\n</div>\n", providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxTextEditorComponent), multi: true }], styles: [".ngx-text-editor{position:relative}.ngx-text-editor ::ng-deep [contenteditable=true]:empty:before{content:attr(placeholder);display:block;color:#868e96;opacity:1}.ngx-text-editor .ngx-wrapper{position:relative}.ngx-text-editor .ngx-wrapper .ngx-text-editor-textarea{min-height:5rem;padding:.5rem .8rem 1rem;border:1px solid #ddd;background-color:transparent;overflow-x:hidden;overflow-y:auto;z-index:2;position:relative;width:100%;max-width:100%;min-width:100%}.ngx-text-editor .ngx-wrapper .ngx-text-editor-textarea:focus,.ngx-text-editor .ngx-wrapper .ngx-text-editor-textarea.focus{outline:0}.ngx-text-editor .ngx-wrapper .ngx-text-editor-textarea ::ng-deep blockquote{margin-left:1rem;border-left:.2em solid #dfe2e5;padding-left:.5rem}.ngx-text-editor .ngx-wrapper ::ng-deep p{margin-bottom:0}.ngx-text-editor .ngx-wrapper .ngx-text-editor-placeholder{display:none;position:absolute;top:0;padding:.5rem .8rem 1rem .9rem;z-index:1;color:#6c757d;opacity:1}.ngx-text-editor .ngx-wrapper.show-placeholder .ngx-text-editor-placeholder{display:block}\n"] },] } ]; NgxTextEditorComponent.ctorParameters = () => [ { type: MessageService }, { type: CommandExecutorService }, { type: Renderer2 } ]; NgxTextEditorComponent.propDecorators = { editable: [{ type: Input }], spellcheck: [{ type: Input }], placeholder: [{ type: Input }], translate: [{ type: Input }], height: [{ type: Input }], minHeight: [{ type: Input }], width: [{ type: Input }], minWidth: [{ type: Input }], toolbar: [{ type: Input }], resizer: [{ type: Input }], config: [{ type: Input }], showToolbar: [{ type: Input }], enableToolbar: [{ type: Input }], imageEndPoint: [{ type: Input }], blur: [{ type: Output }], focus: [{ type: Output }], uploadImage: [{ type: Output }], textArea: [{ type: ViewChild, args: ['ngxTextArea', { static: true },] }], ngxWrapper: [{ type: ViewChild, args: ['ngxWrapper', { static: true },] }] }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXRleHQtZWRpdG9yLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9uZ3gtdGV4dC1lZGl0b3Ivbmd4LXRleHQtZWRpdG9yLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsU0FBUyxFQUFVLEtBQUssRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFhLE1BQU0sZUFBZSxDQUFDO0FBQzNILE9BQU8sRUFBQyxpQkFBaUIsRUFBdUIsTUFBTSxnQkFBZ0IsQ0FBQztBQUV2RSxPQUFPLEVBQUMsc0JBQXNCLEVBQUMsTUFBTSw2Q0FBNkMsQ0FBQztBQUNuRixPQUFPLEVBQUMsY0FBYyxFQUFDLE1BQU0sb0NBQW9DLENBQUM7QUFFbEUsT0FBTyxFQUFDLG1CQUFtQixFQUFDLE1BQU0sb0NBQW9DLENBQUM7QUFDdkUsT0FBTyxLQUFLLEtBQUssTUFBTSx1Q0FBdUMsQ0FBQztBQWMvRCxNQUFNLE9BQU8sc0JBQXNCO0lBaUZqQzs7OztPQUlHO0lBQ0gsWUFDVSxlQUE4QixFQUM5QixnQkFBdUMsRUFDdkMsU0FBbUI7UUFGbkIsb0JBQWUsR0FBZixlQUFlLENBQWU7UUFDOUIscUJBQWdCLEdBQWhCLGdCQUFnQixDQUF1QjtRQUN2QyxjQUFTLEdBQVQsU0FBUyxDQUFVO1FBbkQ3Qjs7Ozs7O1dBTUc7UUFDTSxZQUFPLEdBQUcsT0FBTyxDQUFDO1FBRTNCOzs7OztXQUtHO1FBQ00sV0FBTSxHQUFHLG1CQUFtQixDQUFDO1FBV3RDLDREQUE0RDtRQUNsRCxTQUFJLEdBQXdCLElBQUksWUFBWSxFQUFVLENBQUM7UUFFakUsMERBQTBEO1FBQ2hELFVBQUssR0FBd0IsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUVsRSx1REFBdUQ7UUFDN0MsZ0JBQVcsR0FBa0MsSUFBSSxZQUFZLEVBQW9CLENBQUM7UUFLckYsVUFBSyxHQUFPLEtBQUss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TUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDO1FBRXRFLElBQUksQ0FBQyxjQUFjLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUM5QyxDQUFDOzs7WUFuUUYsU0FBUyxTQUFDO2dCQUNULFFBQVEsRUFBSyxpQkFBaUI7Z0JBQzlCLHd1Q0FBK0M7Z0JBSS9DLFNBQVMsRUFBQyxDQUFDO3dCQUNULE9BQU8sRUFBTSxpQkFBaUI7d0JBQzlCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsc0JBQXNCLENBQUM7d0JBQ3JELEtBQUssRUFBUSxJQUFJO3FCQUNsQixDQUFDOzthQUNIOzs7WUFoQk8sY0FBYztZQURkLHNCQUFzQjtZQUhxQyxTQUFTOzs7dUJBdUJ6RSxLQUFLO3lCQUdMLEtBQUs7MEJBR0wsS0FBSzt3QkFPTCxLQUFLO3FCQUdMLEtBQUs7d0JBR0wsS0FBSztvQkFHTCxLQUFLO3VCQUdMLEtBQUs7c0JBU0wsS0FBSztzQkFTTCxLQUFLO3FCQVFMLEtBQUs7MEJBR0wsS0FBSzs0QkFHTCxLQUFLOzRCQUdMLEtBQUs7bUJBR0wsTUFBTTtvQkFHTixNQUFNOzBCQUdOLE1BQU07dUJBRU4sU0FBUyxTQUFDLGFBQWEsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUU7eUJBQ3pDLFNBQVMsU0FBQyxZQUFZLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtDb21wb25lbnQsIE9uSW5pdCwgSW5wdXQsIE91dHB1dCwgVmlld0NoaWxkLCBFdmVudEVtaXR0ZXIsIFJlbmRlcmVyMiwgZm9yd2FyZFJlZiwgRWxlbWVudFJlZn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge05HX1ZBTFVFX0FDQ0VTU09SLCBDb250cm9sVmFsdWVBY2Nlc3Nvcn0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG5pbXBvcnQge0NvbW1hbmRFeGVjdXRvclNlcnZpY2V9IGZyb20gJy4uL2NvbW1vbi9zZXJ2aWNlcy9jb21tYW5kLWV4ZWN1dG9yLnNlcnZpY2UnO1xuaW1wb3J0IHtNZXNzYWdlU2VydmljZX0gZnJvbSAnLi4vY29tbW9uL3NlcnZpY2VzL21lc3NhZ2Uuc2VydmljZSc7XG5cbmltcG9ydCB7bmd4VGV4dEVkaXRvckNvbmZpZ30gZnJvbSAnLi4vY29tbW9uL25neC10ZXh0LWVkaXRvci5kZWZhdWx0cyc7XG5pbXBvcnQgKiBhcyBVdGlscyBmcm9tICcuLi9jb21tb24vdXRpbHMvbmd4LXRleHQtZWRpdG9yLnV0aWxzJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAgICAnbmd4LXRleHQtZWRpdG9yJyxcbiAgdGVtcGxhdGVVcmw6ICcuL25neC10ZXh0LWVkaXRvci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczpbXG4gICAgJy4vbmd4LXRleHQtZWRpdG9yLmNvbXBvbmVudC5zY3NzJ1xuICBdLFxuICBwcm92aWRlcnM6W3tcbiAgICBwcm92aWRlOiAgICAgTkdfVkFMVUVfQUNDRVNTT1IsXG4gICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gTmd4VGV4dEVkaXRvckNvbXBvbmVudCksXG4gICAgbXVsdGk6ICAgICAgIHRydWVcbiAgfV1cbn0pXG5leHBvcnQgY2xhc3MgTmd4VGV4dEVkaXRvckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xuICAvKiogU3BlY2lmaWVzIHdlYXRoZXIgdGhlIHRleHRhcmVhIHRvIGJlIGVkaXRhYmxlIG9yIG5vdCAqL1xuICBASW5wdXQoKSBlZGl0YWJsZTpib29sZWFuO1xuXG4gIC8qKiBUaGUgc3BlbGxjaGVjayBwcm9wZXJ0eSBzcGVjaWZpZXMgd2hldGhlciB0aGUgZWxlbWVudCBpcyB0byBoYXZlIGl0cyBzcGVsbGluZyBhbmQgZ3JhbW1hciBjaGVja2VkIG9yIG5vdC4gKi9cbiAgQElucHV0KCkgc3BlbGxjaGVjazpib29sZWFuO1xuXG4gIC8qKiBQbGFjZWhvbGRlciBmb3IgdGhlIHRleHRBcmVhICovXG4gIEBJbnB1dCgpIHBsYWNlaG9sZGVyOnN0cmluZztcblxuICAvKipcbiAgICogVGhlIHRyYW5zbGF0ZSBwcm9wZXJ0eSBzcGVjaWZpZXMgd2hldGhlciB0aGUgY29udGVudCBvZiBhbiBlbGVtZW50IHNob3VsZCBiZSB0cmFuc2xhdGVkIG9yIG5vdC5cbiAgICpcbiAgICogQ2hlY2sgaHR0cHM6Ly93d3cudzNzY2hvb2xzLmNvbS90YWdzL2F0dF9nbG9iYWxfdHJhbnNsYXRlLmFzcCBmb3IgbW9yZSBpbmZvcm1hdGlvbiBhbmQgYnJvd3NlciBzdXBwb3J0XG4gICAqL1xuICBASW5wdXQoKSB0cmFuc2xhdGU6c3RyaW5nO1xuXG4gIC8qKiBTZXRzIGhlaWdodCBvZiB0aGUgZWRpdG9yICovXG4gIEBJbnB1dCgpIGhlaWdodDpzdHJpbmc7XG5cbiAgLyoqIFNldHMgbWluaW11bSBoZWlnaHQgZm9yIHRoZSBlZGl0b3IgKi9cbiAgQElucHV0KCkgbWluSGVpZ2h0OnN0cmluZztcblxuICAvKiogU2V0cyBXaWR0aCBvZiB0aGUgZWRpdG9yICovXG4gIEBJbnB1dCgpIHdpZHRoOnN0cmluZztcblxuICAvKiogU2V0cyBtaW5pbXVtIHdpZHRoIG9mIHRoZSBlZGl0b3IgKi9cbiAgQElucHV0KCkgbWluV2lkdGg6c3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUb29sYmFyIGFjY2VwdHMgYW4gYXJyYXkgd2hpY2ggc3BlY2lmaWVzIHRoZSBvcHRpb25zIHRvIGJlIGVuYWJsZWQgZm9yIHRoZSB0b29sYmFyXG4gICAqXG4gICAqIENoZWNrIG5neFRleHRFZGl0b3JDb25maWcgZm9yIHRvb2xiYXIgY29uZmlndXJhdGlvblxuICAgKlxuICAgKiBQYXNzaW5nIGFuIGVtcHR5IGFycmF5IHdpbGwgZW5hYmxlIGFsbCB0b29sYmFyXG4gICAqL1xuICBASW5wdXQoKSB0b29sYmFyOk9iamVjdDtcblxuICAvKipcbiAgICogVGhlIGVkaXRvciBjYW4gYmUgcmVzaXplZCB2ZXJ0aWNhbGx5LlxuICAgKlxuICAgKiBgYmFzaWNgIHJlc2l6ZXIgZW5hYmxlcyB0aGUgaHRtbDUgcmVzemllci4gQ2hlY2sgaGVyZSBodHRwczovL3d3dy53M3NjaG9vbHMuY29tL2Nzc3JlZi9jc3MzX3ByX3Jlc2l6ZS5hc3BcbiAgICpcbiAgICogYHN0YWNrYCByZXNpemVyIGVuYWJsZSBhIHJlc2l6ZXIgdGhhdCBsb29rcyBsaWtlIGFzIGlmIGluIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb21cbiAgICovXG4gIEBJbnB1dCgpIHJlc2l6ZXIgPSAnc3RhY2snO1xuXG4gIC8qKlxuICAgKiBUaGUgY29uZmlnIHByb3BlcnR5IGlzIGEgSlNPTiBvYmplY3RcbiAgICpcbiAgICogQWxsIGF2YWliYWxlIGlucHV0cyBpbnB1dHMgY2FuIGJlIHByb3ZpZGVkIGluIHRoZSBjb25maWd1cmF0aW9uIGFzIEpTT05cbiAgICogaW5wdXRzIHByb3ZpZGVkIGRpcmVjdGx5IGFyZSBjb25zaWRlcmVkIGFzIHRvcCBwcmlvcml0eVxuICAgKi9cbiAgQElucHV0KCkgY29uZmlnID0gbmd4VGV4dEVkaXRvckNvbmZpZztcblxuICAvKiogV2VhdGhlciB0byBzaG93IG9yIGhpZGUgdG9vbGJhciAqL1xuICBASW5wdXQoKSBzaG93VG9vbGJhcjpib29sZWFuO1xuXG4gIC8qKiBXZWF0aGVyIHRvIGVuYWJsZSBvciBkaXNhYmxlIHRoZSB0b29sYmFyICovXG4gIEBJbnB1dCgpIGVuYWJsZVRvb2xiYXI6Ym9vbGVhbjtcblxuICAvKiogRW5kcG9pbnQgZm9yIHdoaWNoIHRoZSBpbWFnZSB0byBiZSB1cGxvYWRlZCAqL1xuICBASW5wdXQoKSBpbWFnZUVuZFBvaW50OnN0cmluZztcblxuICAvKiogZW1pdHMgYGJsdXJgIGV2ZW50IHdoZW4gZm9jdXNlZCBvdXQgZnJvbSB0aGUgdGV4dGFyZWEgKi9cbiAgQE91dHB1dCgpIGJsdXI6RXZlbnRFbWl0dGVyPHN0cmluZz4gPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcblxuICAvKiogZW1pdHMgYGZvY3VzYCBldmVudCB3aGVuIGZvY3VzZWQgaW4gdG8gdGhlIHRleHRhcmVhICovXG4gIEBPdXRwdXQoKSBmb2N1czpFdmVudEVtaXR0ZXI8c3RyaW5nPiA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuXG4gIC8qKiBlbWl0cyBgdXBsb2FkSW1hZ2VgIGV2ZW50IHdoZW4gaW1hZ2UgaXMgc2VsZWN0ZWQgKi9cbiAgQE91dHB1dCgpIHVwbG9hZEltYWdlOkV2ZW50RW1pdHRlcjxIVE1MSW5wdXRFbGVtZW50PiA9IG5ldyBFdmVudEVtaXR0ZXI8SFRNTElucHV0RWxlbWVudD4oKTtcblxuICBAVmlld0NoaWxkKCduZ3hUZXh0QXJlYScsIHsgc3RhdGljOiB0cnVlIH0pIHRleHRBcmVhOmFueTtcbiAgQFZpZXdDaGlsZCgnbmd4V3JhcHBlcicsIHsgc3RhdGljOiB0cnVlIH0pIG5neFdyYXBwZXI6YW55O1xuXG4gIHB1YmxpYyBVdGlsczphbnkgPSBVdGlscztcblxuICBwcml2YXRlIG9uQ2hhbmdlOih2YWx1ZTpzdHJpbmcpID0+IHZvaWQ7XG4gIHByaXZhdGUgb25Ub3VjaGVkOigpID0+IHZvaWQ7XG5cbiAgLyoqXG4gICAqIEBwYXJhbSBfbWVzc2FnZVNlcnZpY2Ugc2VydmljZSB0byBzZW5kIG1lc3NhZ2UgdG8gdGhlIGVkaXRvciBtZXNzYWdlIGNvbXBvbmVudFxuICAgKiBAcGFyYW0gX2NvbW1hbmRFeGVjdXRvciBleGVjdXRlcyBjb21tYW5kIGZyb20gdGhlIHRvb2xiYXJcbiAgICogQHBhcmFtIF9yZW5kZXJlciBhY2Nlc3MgYW5kIG1hbmlwdWxhdGUgdGhlIGRvbSBlbGVtZW50XG4gICAqL1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIF9tZXNzYWdlU2VydmljZTpNZXNzYWdlU2VydmljZSxcbiAgICBwcml2YXRlIF9jb21tYW5kRXhlY3V0b3I6Q29tbWFuZEV4ZWN1dG9yU2VydmljZSxcbiAgICBwcml2YXRlIF9yZW5kZXJlcjpSZW5kZXJlcjIpIHsgfVxuXG4gIC8qKlxuICAgKiBldmVudHNcbiAgICovXG4gIG9uVGV4dEFyZWFGb2N1cygpOnZvaWQge1xuICAgIHRoaXMuZm9jdXMuZW1pdCgnZm9jdXMnKTtcbiAgfVxuXG4gIC8qKiBmb2N1cyB0aGUgdGV4dCBhcmVhIHdoZW4gdGhlIGVkaXRvciBpcyBmb2N1c3NlZCAqL1xuICBvbkVkaXRvckZvY3VzKCkge1xuICAgIHRoaXMudGV4dEFyZWEubmF0aXZlRWxlbWVudC5mb2N1cygpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4ZWN1dGVkIGZyb20gdGhlIGNvbnRlbnRFZGl0YWJsZSBzZWN0aW9uIHdoaWxlIHRoZSBpbnB1dCBwcm9wZXJ0eSBjaGFuZ2VzXG4gICAqIEBwYXJhbSBldmVudCBodG1sIHN0cmluZyBmcm9tIGNvbnRlbnRFZGl0YWJsZVxuICAgKi9cbiAgb25Db250ZW50Q2hhbmdlKGV2ZW50KTp2b2lkIHtcbiAgICBjb25zdCBpbm5lckhUTUwgPSBldmVudC50YXJnZXQudmFsdWU7XG4gICAgaWYgKHR5cGVvZiB0aGlzLm9uQ2hhbmdlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aGlzLm9uQ2hhbmdlKGlubmVySFRNTCk7XG4gICAgICB0aGlzLnRvZ2dsZVBsYWNlaG9sZGVyKGlubmVySFRNTCk7XG4gICAgfVxuICB9XG5cbiAgb25UZXh0QXJlYUJsdXIoKTp2b2lkIHtcbiAgICAvKiogc2F2ZSBzZWxlY3Rpb24gaWYgZm9jdXNzZWQgb3V0ICovXG4gICAgdGhpcy5fY29tbWFuZEV4ZWN1dG9yLnNhdmVkU2VsZWN0aW9uID0gVXRpbHMuc2F2ZVNlbGVjdGlvbigpO1xuXG4gICAgaWYgKHR5cGVvZiB0aGlzLm9uVG91Y2hlZCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgdGhpcy5vblRvdWNoZWQoKTtcbiAgICB9XG4gICAgdGhpcy5ibHVyLmVtaXQoJ2JsdXInKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeGVjdXRlZCB3aGVuIHRoZSBpbWFnZSBmcm9tIHRoZSBkaXNjIGlzIHNlbGVjdGVkXG4gICAqIEBwYXJhbSBpbWFnZSB1cGxvYWRlZCBmaWxlIG9iamVjdFxuICAgKi9cbiAgb25VcGxvYWRJbWFnZShpbWFnZTpIVE1MSW5wdXRFbGVtZW50KTp2b2lkIHtcbiAgICB0aGlzLnVwbG9hZEltYWdlLmVtaXQoaW1hZ2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIHJlc2l6aW5nIHRleHQgYXJlYVxuICAgKlxuICAgKiBAcGFyYW0gb2Zmc2V0WSB2ZXJ0aWNhbCBoZWlnaHQgb2YgdGhlIGVpZHRhYmxlIHBvcnRpb24gb2YgdGhlIGVkaXRvclxuICAgKi9cbiAgcmVzaXplVGV4dEFyZWEob2Zmc2V0WTpudW1iZXIpOnZvaWQge1xuICAgIGxldCBuZXdIZWlnaHQgPSBwYXJzZUludCh0aGlzLmhlaWdodCwgMTApO1xuICAgIG5ld0hlaWdodCArPSBvZmZzZXRZO1xuXG4gICAgdGhpcy5oZWlnaHQgPSBuZXdIZWlnaHQgKyAncHgnO1xuICAgIHRoaXMudGV4dEFyZWEubmF0aXZlRWxlbWVudC5zdHlsZS5oZWlnaHQgPSB0aGlzLmhlaWdodDtcbiAgfVxuXG4gIC8qKlxuICAgKiBlZGl0b3IgYWN0aW9ucywgaS5lLiwgZXhlY3V0ZXMgY29tbWFuZCBmcm9tIHRvb2xiYXJcbiAgICpcbiAgICogQHBhcmFtIGNvbW1hbmROYW1lIG5hbWUgb2YgdGhlIGNvbW1hbmQgdG8gYmUgZXhlY3V0ZWRcbiAgICovXG4gIGV4ZWN1dGVDb21tYW5kKGNvbW1hbmROYW1lOnN0cmluZyk6dm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuX2NvbW1hbmRFeGVjdXRvci5leGVjdXRlKGNvbW1hbmROYW1lKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5fbWVzc2FnZVNlcnZpY2Uuc2VuZE1lc3NhZ2UoZXJyb3IubWVzc2FnZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFdyaXRlIGEgbmV3IHZhbHVlIHRvIHRoZSBlbGVtZW50LlxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgdmFsdWUgdG8gYmUgZXhlY3V0ZWQgd2hlbiB0aGVyZSBpcyBhIGNoYW5nZSBpbiBjb250ZW50ZWRpdGFibGVcbiAgICovXG4gIHdyaXRlVmFsdWUodmFsdWU6YW55KTp2b2lkIHtcbiAgICB0aGlzLnRvZ2dsZVBsYWNlaG9sZGVyKHZhbHVlKTtcblxuICAgIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSAnJyB8fCB2YWx1ZSA9PT0gJzxicj4nKSB7XG4gICAgICB2YWx1ZSA9IG51bGw7XG4gICAgfVxuXG4gICAgdGhpcy5yZWZyZXNoVmlldyh2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSBmdW5jdGlvbiB0byBiZSBjYWxsZWRcbiAgICogd2hlbiB0aGUgY29udHJvbCByZWNlaXZlcyBhIGNoYW5nZSBldmVudC5cbiAgICpcbiAgICogQHBhcmFtIGZuIGEgZnVuY3Rpb25cbiAgICovXG4gIHJlZ2lzdGVyT25DaGFuZ2UoZm46YW55KTp2b2lkIHtcbiAgICB0aGlzLm9uQ2hhbmdlID0gZm47XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSBmdW5jdGlvbiB0byBiZSBjYWxsZWRcbiAgICogd2hlbiB0aGUgY29udHJvbCByZWNlaXZlcyBhIHRvdWNoIGV2ZW50LlxuICAgKlxuICAgKiBAcGFyYW0gZm4gYSBmdW5jdGlvblxuICAgKi9cbiAgcmVnaXN0ZXJPblRvdWNoZWQoZm46YW55KTp2b2lkIHtcbiAgICB0aGlzLm9uVG91Y2hlZCA9IGZuO1xuICB9XG5cbiAgLyoqXG4gICAqIHJlZnJlc2ggdmlldy9IVE1MIG9mIHRoZSBlZGl0b3JcbiAgICpcbiAgICogQHBhcmFtIHZhbHVlIGh0bWwgc3RyaW5nIGZyb20gdGhlIGVkaXRvclxuICAgKi9cbiAgcmVmcmVzaFZpZXcodmFsdWU6c3RyaW5nKTp2b2lkIHtcbiAgICBjb25zdCBub3JtYWxpemVkVmFsdWUgPSB2YWx1ZSA9PT0gbnVsbCA/ICcnIDogdmFsdWU7XG5cbiAgICB0aGlzLl9yZW5kZXJlci5zZXRQcm9wZXJ0eSh0aGlzLnRleHRBcmVhLm5hdGl2ZUVsZW1lbnQsICdpbm5lckhUTUwnLCBub3JtYWxpemVkVmFsdWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIHRvZ2dsZXMgcGxhY2Vob2xkZXIgYmFzZWQgb24gaW5wdXQgc3RyaW5nXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSBBIEhUTUwgc3RyaW5nIGZyb20gdGhlIGVkaXRvclxuICAgKi9cbiAgdG9nZ2xlUGxhY2Vob2xkZXIodmFsdWU6YW55KTp2b2lkIHtcbiAgICBpZiAoIXZhbHVlIHx8IHZhbHVlID09PSAnPGJyPicgfHwgdmFsdWUgPT09ICcnKSB7XG4gICAgICB0aGlzLl9yZW5kZXJlci5hZGRDbGFzcyh0aGlzLm5neFdyYXBwZXIubmF0aXZlRWxlbWVudCwgJ3Nob3ctcGxhY2Vob2xkZXInKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5fcmVuZGVyZXIucmVtb3ZlQ2xhc3ModGhpcy5uZ3hXcmFwcGVyLm5hdGl2ZUVsZW1lbnQsICdzaG93LXBsYWNlaG9sZGVyJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIHJldHVybnMgYSBqc29uIGNvbnRhaW5pbmcgaW5wdXQgcGFyYW1zXG4gICAqL1xuICBnZXRDb2xsZWN0aXZlUGFyYW1zKCk6YW55IHtcbiAgICByZXR1cm4ge1xuICAgICAgZWRpdGFibGU6dGhpcy5lZGl0YWJsZSxcbiAgICAgIHNwZWxsY2hlY2s6dGhpcy5zcGVsbGNoZWNrLFxuICAgICAgcGxhY2Vob2xkZXI6dGhpcy5wbGFjZWhvbGRlcixcbiAgICAgIHRyYW5zbGF0ZTp0aGlzLnRyYW5zbGF0ZSxcbiAgICAgIGhlaWdodDp0aGlzLmhlaWdodCxcbiAgICAgIG1pbkhlaWdodDp0aGlzLm1pbkhlaWdodCxcbiAgICAgIHdpZHRoOnRoaXMud2lkdGgsXG4gICAgICBtaW5XaWR0aDp0aGlzLm1pbldpZHRoLFxuICAgICAgZW5hYmxlVG9vbGJhcjp0aGlzLmVuYWJsZVRvb2xiYXIsXG4gICAgICBzaG93VG9vbGJhcjp0aGlzLnNob3dUb29sYmFyLFxuICAgICAgaW1hZ2VFbmRQb2ludDp0aGlzLmltYWdlRW5kUG9pbnQsXG4gICAgICB0b29sYmFyOnRoaXMudG9vbGJhclxuICAgIH07XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICAvKipcbiAgICAgKiBzZXQgY29uZmlndXJhdGlvblxuICAgICAqL1xuICAgIHRoaXMuY29uZmlnID0gdGhpcy5VdGlscy5nZXRFZGl0b3JDb25maWd1cmF0aW9uKHRoaXMuY29uZmlnLCBuZ3hUZXh0RWRpdG9yQ29uZmlnLCB0aGlzLmdldENvbGxlY3RpdmVQYXJhbXMoKSk7XG5cbiAgICB0aGlzLmhlaWdodCA9IHRoaXMuaGVpZ2h0IHx8IHRoaXMudGV4dEFyZWEubmF0aXZlRWxlbWVudC5vZmZzZXRIZWlnaHQ7XG5cbiAgICB0aGlzLmV4ZWN1dGVDb21tYW5kKCdlbmFibGVPYmplY3RSZXNpemluZycpO1xuICB9XG59XG4iXX0=