@ckeditor/ckeditor5-angular
Version:
Official Angular 2+ component for CKEditor 5 – the best browser-based rich text editor.
508 lines • 36.4 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import * as tslib_1 from "tslib";
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/
import { Component, Input, Output, NgZone, EventEmitter, forwardRef, ElementRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
var CKEditorComponent = /** @class */ (function () {
function CKEditorComponent(elementRef, ngZone) {
/**
* The configuration of the editor.
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorconfig-EditorConfig.html
* to learn more.
*/
this.config = {};
/**
* The initial data of the editor. Useful when not using the ngModel.
* See https://angular.io/api/forms/NgModel to learn more.
*/
this.data = '';
/**
* Tag name of the editor component.
*
* The default tag is 'div'.
*/
this.tagName = 'div';
/**
* Fires when the editor is ready. It corresponds with the `editor#ready`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#event-ready
* event.
*/
this.ready = new EventEmitter();
/**
* Fires when the content of the editor has changed. It corresponds with the `editor.model.document#change`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_model_document-Document.html#event-change
* event.
*/
this.change = new EventEmitter();
/**
* Fires when the editing view of the editor is blurred. It corresponds with the `editor.editing.view.document#blur`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_view_document-Document.html#event-event:blur
* event.
*/
this.blur = new EventEmitter();
/**
* Fires when the editing view of the editor is focused. It corresponds with the `editor.editing.view.document#focus`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_view_document-Document.html#event-event:focus
* event.
*/
this.focus = new EventEmitter();
/**
* The instance of the editor created by this component.
*/
this.editorInstance = null;
/**
* If the component is read–only before the editor instance is created, it remembers that state,
* so the editor can become read–only once it is ready.
*/
this.initialIsDisabled = false;
this.ngZone = ngZone;
this.elementRef = elementRef;
}
Object.defineProperty(CKEditorComponent.prototype, "disabled", {
get: /**
* @return {?}
*/
function () {
if (this.editorInstance) {
return this.editorInstance.isReadOnly;
}
return this.initialIsDisabled;
},
/**
* When set `true`, the editor becomes read-only.
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-isReadOnly
* to learn more.
*/
set: /**
* When set `true`, the editor becomes read-only.
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-isReadOnly
* to learn more.
* @param {?} isDisabled
* @return {?}
*/
function (isDisabled) {
this.setDisabledState(isDisabled);
},
enumerable: true,
configurable: true
});
// Implementing the AfterViewInit interface.
// Implementing the AfterViewInit interface.
/**
* @return {?}
*/
CKEditorComponent.prototype.ngAfterViewInit =
// Implementing the AfterViewInit interface.
/**
* @return {?}
*/
function () {
var _this = this;
this.ngZone.runOutsideAngular((/**
* @return {?}
*/
function () {
_this.createEditor();
}));
};
// Implementing the OnDestroy interface.
// Implementing the OnDestroy interface.
/**
* @return {?}
*/
CKEditorComponent.prototype.ngOnDestroy =
// Implementing the OnDestroy interface.
/**
* @return {?}
*/
function () {
if (this.editorInstance) {
this.editorInstance.destroy();
this.editorInstance = null;
}
};
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
/**
* @param {?} value
* @return {?}
*/
CKEditorComponent.prototype.writeValue =
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
/**
* @param {?} value
* @return {?}
*/
function (value) {
// This method is called with the `null` value when the form resets.
// A component's responsibility is to restore to the initial state.
if (value === null) {
value = '';
}
// If already initialized.
if (this.editorInstance) {
this.editorInstance.setData(value);
}
// If not, wait for it to be ready; store the data.
else {
this.data = value;
// If the editor element is already available, then update its content.
// If the ngModel is used then the editor element should be updated directly here.
if (this.editorElement) {
this.editorElement.innerHTML = this.data;
}
}
};
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
/**
* @param {?} callback
* @return {?}
*/
CKEditorComponent.prototype.registerOnChange =
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
/**
* @param {?} callback
* @return {?}
*/
function (callback) {
this.cvaOnChange = callback;
};
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
/**
* @param {?} callback
* @return {?}
*/
CKEditorComponent.prototype.registerOnTouched =
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
/**
* @param {?} callback
* @return {?}
*/
function (callback) {
this.cvaOnTouched = callback;
};
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
/**
* @param {?} isDisabled
* @return {?}
*/
CKEditorComponent.prototype.setDisabledState =
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
/**
* @param {?} isDisabled
* @return {?}
*/
function (isDisabled) {
// If already initialized
if (this.editorInstance) {
this.editorInstance.isReadOnly = isDisabled;
}
// If not, wait for it to be ready; store the state.
else {
this.initialIsDisabled = isDisabled;
}
};
/**
* Creates the editor instance, sets initial editor data, then integrates
* the editor with the Angular component. This method does not use the `editor.setData()`
* because of the issue in the collaboration mode (#6).
*/
/**
* Creates the editor instance, sets initial editor data, then integrates
* the editor with the Angular component. This method does not use the `editor.setData()`
* because of the issue in the collaboration mode (#6).
* @private
* @return {?}
*/
CKEditorComponent.prototype.createEditor = /**
* Creates the editor instance, sets initial editor data, then integrates
* the editor with the Angular component. This method does not use the `editor.setData()`
* because of the issue in the collaboration mode (#6).
* @private
* @return {?}
*/
function () {
var _this = this;
/** @type {?} */
var element = document.createElement(this.tagName);
this.editorElement = element;
if (this.data && this.config.initialData) {
throw new Error('Editor data should be provided either using `config.initialData` or `data` properties.');
}
// Merge two possible ways of providing data into the `config.initialData` field.
/** @type {?} */
var config = tslib_1.__assign({}, this.config, { initialData: this.config.initialData || this.data || '' });
this.elementRef.nativeElement.appendChild(element);
return (/** @type {?} */ (this.editor)).create(element, config)
.then((/**
* @param {?} editor
* @return {?}
*/
function (editor) {
_this.editorInstance = editor;
if (_this.initialIsDisabled) {
editor.isReadOnly = _this.initialIsDisabled;
}
_this.ngZone.run((/**
* @return {?}
*/
function () {
_this.ready.emit(editor);
}));
_this.setUpEditorEvents(editor);
}))
.catch((/**
* @param {?} err
* @return {?}
*/
function (err) {
console.error(err.stack);
}));
};
/**
* Integrates the editor with the component by attaching related event listeners.
*/
/**
* Integrates the editor with the component by attaching related event listeners.
* @private
* @param {?} editor
* @return {?}
*/
CKEditorComponent.prototype.setUpEditorEvents = /**
* Integrates the editor with the component by attaching related event listeners.
* @private
* @param {?} editor
* @return {?}
*/
function (editor) {
var _this = this;
/** @type {?} */
var modelDocument = editor.model.document;
/** @type {?} */
var viewDocument = editor.editing.view.document;
modelDocument.on('change:data', (/**
* @param {?} evt
* @return {?}
*/
function (evt) {
_this.ngZone.run((/**
* @return {?}
*/
function () {
if (_this.cvaOnChange) {
/** @type {?} */
var data = editor.getData();
_this.cvaOnChange(data);
}
_this.change.emit({ event: evt, editor: editor });
}));
}));
viewDocument.on('focus', (/**
* @param {?} evt
* @return {?}
*/
function (evt) {
_this.ngZone.run((/**
* @return {?}
*/
function () {
_this.focus.emit({ event: evt, editor: editor });
}));
}));
viewDocument.on('blur', (/**
* @param {?} evt
* @return {?}
*/
function (evt) {
_this.ngZone.run((/**
* @return {?}
*/
function () {
if (_this.cvaOnTouched) {
_this.cvaOnTouched();
}
_this.blur.emit({ event: evt, editor: editor });
}));
}));
};
CKEditorComponent.decorators = [
{ type: Component, args: [{
selector: 'ckeditor',
template: '<ng-template></ng-template>',
// Integration with @angular/forms.
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
function () { return CKEditorComponent; })),
multi: true,
}
]
}] }
];
/** @nocollapse */
CKEditorComponent.ctorParameters = function () { return [
{ type: ElementRef },
{ type: NgZone }
]; };
CKEditorComponent.propDecorators = {
editor: [{ type: Input }],
config: [{ type: Input }],
data: [{ type: Input }],
tagName: [{ type: Input }],
disabled: [{ type: Input }],
ready: [{ type: Output }],
change: [{ type: Output }],
blur: [{ type: Output }],
focus: [{ type: Output }]
};
return CKEditorComponent;
}());
export { CKEditorComponent };
if (false) {
/**
* The reference to the DOM element created by the component.
* @type {?}
* @private
*/
CKEditorComponent.prototype.elementRef;
/**
* The constructor of the editor to be used for the instance of the component.
* It can be e.g. the `ClassicEditorBuild`, `InlineEditorBuild` or some custom editor.
* @type {?}
*/
CKEditorComponent.prototype.editor;
/**
* The configuration of the editor.
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorconfig-EditorConfig.html
* to learn more.
* @type {?}
*/
CKEditorComponent.prototype.config;
/**
* The initial data of the editor. Useful when not using the ngModel.
* See https://angular.io/api/forms/NgModel to learn more.
* @type {?}
*/
CKEditorComponent.prototype.data;
/**
* Tag name of the editor component.
*
* The default tag is 'div'.
* @type {?}
*/
CKEditorComponent.prototype.tagName;
/**
* Fires when the editor is ready. It corresponds with the `editor#ready`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#event-ready
* event.
* @type {?}
*/
CKEditorComponent.prototype.ready;
/**
* Fires when the content of the editor has changed. It corresponds with the `editor.model.document#change`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_model_document-Document.html#event-change
* event.
* @type {?}
*/
CKEditorComponent.prototype.change;
/**
* Fires when the editing view of the editor is blurred. It corresponds with the `editor.editing.view.document#blur`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_view_document-Document.html#event-event:blur
* event.
* @type {?}
*/
CKEditorComponent.prototype.blur;
/**
* Fires when the editing view of the editor is focused. It corresponds with the `editor.editing.view.document#focus`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_view_document-Document.html#event-event:focus
* event.
* @type {?}
*/
CKEditorComponent.prototype.focus;
/**
* The instance of the editor created by this component.
* @type {?}
*/
CKEditorComponent.prototype.editorInstance;
/**
* If the component is read–only before the editor instance is created, it remembers that state,
* so the editor can become read–only once it is ready.
* @type {?}
* @private
*/
CKEditorComponent.prototype.initialIsDisabled;
/**
* An instance of https://angular.io/api/core/NgZone to allow the interaction with the editor
* withing the Angular event loop.
* @type {?}
* @private
*/
CKEditorComponent.prototype.ngZone;
/**
* A callback executed when the content of the editor changes. Part of the
* `ControlValueAccessor` (https://angular.io/api/forms/ControlValueAccessor) interface.
*
* Note: Unset unless the component uses the `ngModel`.
* @type {?}
* @private
*/
CKEditorComponent.prototype.cvaOnChange;
/**
* A callback executed when the editor has been blurred. Part of the
* `ControlValueAccessor` (https://angular.io/api/forms/ControlValueAccessor) interface.
*
* Note: Unset unless the component uses the `ngModel`.
* @type {?}
* @private
*/
CKEditorComponent.prototype.cvaOnTouched;
/**
* Reference to the source element used by the editor.
* @type {?}
* @private
*/
CKEditorComponent.prototype.editorElement;
}
/**
* @record
*/
export function BlurEvent() { }
if (false) {
/** @type {?} */
BlurEvent.prototype.event;
/** @type {?} */
BlurEvent.prototype.editor;
}
/**
* @record
*/
export function FocusEvent() { }
if (false) {
/** @type {?} */
FocusEvent.prototype.event;
/** @type {?} */
FocusEvent.prototype.editor;
}
/**
* @record
*/
export function ChangeEvent() { }
if (false) {
/** @type {?} */
ChangeEvent.prototype.event;
/** @type {?} */
ChangeEvent.prototype.editor;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2tlZGl0b3IuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vQGNrZWRpdG9yL2NrZWRpdG9yNS1hbmd1bGFyLyIsInNvdXJjZXMiOlsiY2tlZGl0b3IuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUtBLE9BQU8sRUFDTixTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sRUFDTixNQUFNLEVBQ04sWUFBWSxFQUNaLFVBQVUsRUFFVixVQUFVLEVBQ1YsTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUVOLGlCQUFpQixFQUNqQixNQUFNLGdCQUFnQixDQUFDO0FBSXhCO0lBZ0lDLDJCQUFhLFVBQXNCLEVBQUUsTUFBYzs7Ozs7O1FBbEcxQyxXQUFNLEdBQXFCLEVBQUUsQ0FBQzs7Ozs7UUFNOUIsU0FBSSxHQUFHLEVBQUUsQ0FBQzs7Ozs7O1FBT1YsWUFBTyxHQUFHLEtBQUssQ0FBQzs7Ozs7O1FBd0JmLFVBQUssR0FBRyxJQUFJLFlBQVksRUFBb0IsQ0FBQzs7Ozs7O1FBTzdDLFdBQU0sR0FBOEIsSUFBSSxZQUFZLEVBQWUsQ0FBQzs7Ozs7O1FBT3BFLFNBQUksR0FBNEIsSUFBSSxZQUFZLEVBQWEsQ0FBQzs7Ozs7O1FBTzlELFVBQUssR0FBNkIsSUFBSSxZQUFZLEVBQWMsQ0FBQzs7OztRQUtwRSxtQkFBYyxHQUE0QixJQUFJLENBQUM7Ozs7O1FBTTlDLHNCQUFpQixHQUFHLEtBQUssQ0FBQztRQThCakMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7SUFDOUIsQ0FBQztJQWpGRCxzQkFBYSx1Q0FBUTs7OztRQUlyQjtZQUNDLElBQUssSUFBSSxDQUFDLGNBQWMsRUFBRztnQkFDMUIsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDLFVBQVUsQ0FBQzthQUN0QztZQUVELE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDO1FBQy9CLENBQUM7UUFm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Q0FBOEM7Ozs7Ozs7SUFPOUMsbUNBQXVDOzs7Ozs7SUFNdkMsaUNBQW1COzs7Ozs7O0lBT25CLG9DQUF5Qjs7Ozs7OztJQXdCekIsa0NBQXVEOzs7Ozs7O0lBT3ZELG1DQUE4RTs7Ozs7OztJQU85RSxpQ0FBd0U7Ozs7Ozs7SUFPeEUsa0NBQTJFOzs7OztJQUszRSwyQ0FBc0Q7Ozs7Ozs7SUFNdEQsOENBQWtDOzs7Ozs7O0lBTWxDLG1DQUF1Qjs7Ozs7Ozs7O0lBUXZCLHdDQUErQzs7Ozs7Ozs7O0lBUS9DLHlDQUFrQzs7Ozs7O0lBS2xDLDBDQUFvQzs7Ozs7QUFpSnJDLCtCQUdDOzs7SUFGQSwwQkFBbUM7O0lBQ25DLDJCQUF5Qjs7Ozs7QUFHMUIsZ0NBR0M7OztJQUZBLDJCQUFvQzs7SUFDcEMsNEJBQXlCOzs7OztBQUcxQixpQ0FHQzs7O0lBRkEsNEJBQTBDOztJQUMxQyw2QkFBeUIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlIENvcHlyaWdodCAoYykgMjAwMy0yMDE5LCBDS1NvdXJjZSAtIEZyZWRlcmljbyBLbmFiYmVuLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogRm9yIGxpY2Vuc2luZywgc2VlIExJQ0VOU0UubWQuXG4gKi9cblxuaW1wb3J0IHtcblx0Q29tcG9uZW50LFxuXHRJbnB1dCxcblx0T3V0cHV0LFxuXHROZ1pvbmUsXG5cdEV2ZW50RW1pdHRlcixcblx0Zm9yd2FyZFJlZixcblx0QWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95LFxuXHRFbGVtZW50UmVmXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQge1xuXHRDb250cm9sVmFsdWVBY2Nlc3Nvcixcblx0TkdfVkFMVUVfQUNDRVNTT1Jcbn0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuXG5pbXBvcnQgeyBDS0VkaXRvcjUgfSBmcm9tICcuL2NrZWRpdG9yJztcblxuQENvbXBvbmVudCgge1xuXHRzZWxlY3RvcjogJ2NrZWRpdG9yJyxcblx0dGVtcGxhdGU6ICc8bmctdGVtcGxhdGU+PC9uZy10ZW1wbGF0ZT4nLFxuXG5cdC8vIEludGVncmF0aW9uIHdpdGggQGFuZ3VsYXIvZm9ybXMuXG5cdHByb3ZpZGVyczogW1xuXHRcdHtcblx0XHRcdHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuXHRcdFx0dXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoICgpID0+IENLRWRpdG9yQ29tcG9uZW50ICksXG5cdFx0XHRtdWx0aTogdHJ1ZSxcblx0XHR9XG5cdF1cbn0gKVxuZXhwb3J0IGNsYXNzIENLRWRpdG9yQ29tcG9uZW50IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95LCBDb250cm9sVmFsdWVBY2Nlc3NvciB7XG5cdC8qKlxuXHQgKiBUaGUgcmVmZXJlbmNlIHRvIHRoZSBET00gZWxlbWVudCBjcmVhdGVkIGJ5IHRoZSBjb21wb25lbnQuXG5cdCAqL1xuXHRwcml2YXRlIGVsZW1lbnRSZWYhOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcblxuXHQvKipcblx0ICogVGhlIGNvbnN0cnVjdG9yIG9mIHRoZSBlZGl0b3IgdG8gYmUgdXNlZCBmb3IgdGhlIGluc3RhbmNlIG9mIHRoZSBjb21wb25lbnQuXG5cdCAqIEl0IGNhbiBiZSBlLmcuIHRoZSBgQ2xhc3NpY0VkaXRvckJ1aWxkYCwgYElubGluZUVkaXRvckJ1aWxkYCBvciBzb21lIGN1c3RvbSBlZGl0b3IuXG5cdCAqL1xuXHRASW5wdXQoKSBlZGl0b3I/OiBDS0VkaXRvcjUuRWRpdG9yQ29uc3RydWN0b3I7XG5cblx0LyoqXG5cdCAqIFRoZSBjb25maWd1cmF0aW9uIG9mIHRoZSBlZGl0b3IuXG5cdCAqIFNlZSBodHRwczovL2NrZWRpdG9yLmNvbS9kb2NzL2NrZWRpdG9yNS9sYXRlc3QvYXBpL21vZHVsZV9jb3JlX2VkaXRvcl9lZGl0b3Jjb25maWctRWRpdG9yQ29uZmlnLmh0bWxcblx0ICogdG8gbGVhcm4gbW9yZS5cblx0ICovXG5cdEBJbnB1dCgpIGNvbmZpZzogQ0tFZGl0b3I1LkNvbmZpZyA9IHt9O1xuXG5cdC8qKlxuXHQgKiBUaGUgaW5pdGlhbCBkYXRhIG9mIHRoZSBlZGl0b3IuIFVzZWZ1bCB3aGVuIG5vdCB1c2luZyB0aGUgbmdNb2RlbC5cblx0ICogU2VlIGh0dHBzOi8vYW5ndWxhci5pby9hcGkvZm9ybXMvTmdNb2RlbCB0byBsZWFybiBtb3JlLlxuXHQgKi9cblx0QElucHV0KCkgZGF0YSA9ICcnO1xuXG5cdC8qKlxuXHQgKiBUYWcgbmFtZSBvZiB0aGUgZWRpdG9yIGNvbXBvbmVudC5cblx0ICpcblx0ICogVGhlIGRlZmF1bHQgdGFnIGlzICdkaXYnLlxuXHQgKi9cblx0QElucHV0KCkgdGFnTmFtZSA9ICdkaXYnO1xuXG5cdC8qKlxuXHQgKiBXaGVuIHNldCBgdHJ1ZWAsIHRoZSBlZGl0b3IgYmVjb21lcyByZWFkLW9ubHkuXG5cdCAqIFNlZSBodHRwczovL2NrZWRpdG9yLmNvbS9kb2NzL2NrZWRpdG9yNS9sYXRlc3QvYXBpL21vZHVsZV9jb3JlX2VkaXRvcl9lZGl0b3ItRWRpdG9yLmh0bWwjbWVtYmVyLWlzUmVhZE9ubHlcblx0ICogdG8gbGVhcm4gbW9yZS5cblx0ICovXG5cdEBJbnB1dCgpIHNldCBkaXNhYmxlZCggaXNEaXNhYmxlZDogYm9vbGVhbiApIHtcblx0XHR0aGlzLnNldERpc2FibGVkU3RhdGUoIGlzRGlzYWJsZWQgKTtcblx0fVxuXG5cdGdldCBkaXNhYmxlZCgpIHtcblx0XHRpZiAoIHRoaXMuZWRpdG9ySW5zdGFuY2UgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5lZGl0b3JJbnN0YW5jZS5pc1JlYWRPbmx5O1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmluaXRpYWxJc0Rpc2FibGVkO1xuXHR9XG5cblx0LyoqXG5cdCAqIEZpcmVzIHdoZW4gdGhlIGVkaXRvciBpcyByZWFkeS4gSXQgY29ycmVzcG9uZHMgd2l0aCB0aGUgYGVkaXRvciNyZWFkeWBcblx0ICogaHR0cHM6Ly9ja2VkaXRvci5jb20vZG9jcy9ja2VkaXRvcjUvbGF0ZXN0L2FwaS9tb2R1bGVfY29yZV9lZGl0b3JfZWRpdG9yLUVkaXRvci5odG1sI2V2ZW50LXJlYWR5XG5cdCAqIGV2ZW50LlxuXHQgKi9cblx0QE91dHB1dCgpIHJlYWR5ID0gbmV3IEV2ZW50RW1pdHRlcjxDS0VkaXRvcjUuRWRpdG9yPigpO1xuXG5cdC8qKlxuXHQgKiBGaXJlcyB3aGVuIHRoZSBjb250ZW50IG9mIHRoZSBlZGl0b3IgaGFzIGNoYW5nZWQuIEl0IGNvcnJlc3BvbmRzIHdpdGggdGhlIGBlZGl0b3IubW9kZWwuZG9jdW1lbnQjY2hhbmdlYFxuXHQgKiBodHRwczovL2NrZWRpdG9yLmNvbS9kb2NzL2NrZWRpdG9yNS9sYXRlc3QvYXBpL21vZHVsZV9lbmdpbmVfbW9kZWxfZG9jdW1lbnQtRG9jdW1lbnQuaHRtbCNldmVudC1jaGFuZ2Vcblx0ICogZXZlbnQuXG5cdCAqL1xuXHRAT3V0cHV0KCkgY2hhbmdlOiBFdmVudEVtaXR0ZXI8Q2hhbmdlRXZlbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxDaGFuZ2VFdmVudD4oKTtcblxuXHQvKipcblx0ICogRmlyZXMgd2hlbiB0aGUgZWRpdGluZyB2aWV3IG9mIHRoZSBlZGl0b3IgaXMgYmx1cnJlZC4gSXQgY29ycmVzcG9uZHMgd2l0aCB0aGUgYGVkaXRvci5lZGl0aW5nLnZpZXcuZG9jdW1lbnQjYmx1cmBcblx0ICogaHR0cHM6Ly9ja2VkaXRvci5jb20vZG9jcy9ja2VkaXRvcjUvbGF0ZXN0L2FwaS9tb2R1bGVfZW5naW5lX3ZpZXdfZG9jdW1lbnQtRG9jdW1lbnQuaHRtbCNldmVudC1ldmVudDpibHVyXG5cdCAqIGV2ZW50LlxuXHQgKi9cblx0QE91dHB1dCgpIGJsdXI6IEV2ZW50RW1pdHRlcjxCbHVyRXZlbnQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxCbHVyRXZlbnQ+KCk7XG5cblx0LyoqXG5cdCAqIEZpcmVzIHdoZW4gdGhlIGVkaXRpbmcgdmlldyBvZiB0aGUgZWRpdG9yIGlzIGZvY3VzZWQuIEl0IGNvcnJlc3BvbmRzIHdpdGggdGhlIGBlZGl0b3IuZWRpdGluZy52aWV3LmRvY3VtZW50I2ZvY3VzYFxuXHQgKiBodHRwczovL2NrZWRpdG9yLmNvbS9kb2NzL2NrZWRpdG9yNS9sYXRlc3QvYXBpL21vZHVsZV9lbmdpbmVfdmlld19kb2N1bWVudC1Eb2N1bWVudC5odG1sI2V2ZW50LWV2ZW50OmZvY3VzXG5cdCAqIGV2ZW50LlxuXHQgKi9cblx0QE91dHB1dCgpIGZvY3VzOiBFdmVudEVtaXR0ZXI8Rm9jdXNFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyPEZvY3VzRXZlbnQ+KCk7XG5cblx0LyoqXG5cdCAqIFRoZSBpbnN0YW5jZSBvZiB0aGUgZWRpdG9yIGNyZWF0ZWQgYnkgdGhpcyBjb21wb25lbnQuXG5cdCAqL1xuXHRwdWJsaWMgZWRpdG9ySW5zdGFuY2U6IENLRWRpdG9yNS5FZGl0b3IgfCBudWxsID0gbnVsbDtcblxuXHQvKipcblx0ICogSWYgdGhlIGNvbXBvbmVudCBpcyByZWFk4oCTb25seSBiZWZvcmUgdGhlIGVkaXRvciBpbnN0YW5jZSBpcyBjcmVhdGVkLCBpdCByZW1lbWJlcnMgdGhhdCBzdGF0ZSxcblx0ICogc28gdGhlIGVkaXRvciBjYW4gYmVjb21lIHJlYWTigJNvbmx5IG9uY2UgaXQgaXMgcmVhZHkuXG5cdCAqL1xuXHRwcml2YXRlIGluaXRpYWxJc0Rpc2FibGVkID0gZmFsc2U7XG5cblx0LyoqXG5cdCAqIEFuIGluc3RhbmNlIG9mIGh0dHBzOi8vYW5ndWxhci5pby9hcGkvY29yZS9OZ1pvbmUgdG8gYWxsb3cgdGhlIGludGVyYWN0aW9uIHdpdGggdGhlIGVkaXRvclxuXHQgKiB3aXRoaW5nIHRoZSBBbmd1bGFyIGV2ZW50IGxvb3AuXG5cdCAqL1xuXHRwcml2YXRlIG5nWm9uZTogTmdab25lO1xuXG5cdC8qKlxuXHQgKiBBIGNhbGxiYWNrIGV4ZWN1dGVkIHdoZW4gdGhlIGNvbnRlbnQgb2YgdGhlIGVkaXRvciBjaGFuZ2VzLiBQYXJ0IG9mIHRoZVxuXHQgKiBgQ29udHJvbFZhbHVlQWNjZXNzb3JgIChodHRwczovL2FuZ3VsYXIuaW8vYXBpL2Zvcm1zL0NvbnRyb2xWYWx1ZUFjY2Vzc29yKSBpbnRlcmZhY2UuXG5cdCAqXG5cdCAqIE5vdGU6IFVuc2V0IHVubGVzcyB0aGUgY29tcG9uZW50IHVzZXMgdGhlIGBuZ01vZGVsYC5cblx0ICovXG5cdHByaXZhdGUgY3ZhT25DaGFuZ2U/OiAoIGRhdGE6IHN0cmluZyApID0+IHZvaWQ7XG5cblx0LyoqXG5cdCAqIEEgY2FsbGJhY2sgZXhlY3V0ZWQgd2hlbiB0aGUgZWRpdG9yIGhhcyBiZWVuIGJsdXJyZWQuIFBhcnQgb2YgdGhlXG5cdCAqIGBDb250cm9sVmFsdWVBY2Nlc3NvcmAgKGh0dHBzOi8vYW5ndWxhci5pby9hcGkvZm9ybXMvQ29udHJvbFZhbHVlQWNjZXNzb3IpIGludGVyZmFjZS5cblx0ICpcblx0ICogTm90ZTogVW5zZXQgdW5sZXNzIHRoZSBjb21wb25lbnQgdXNlcyB0aGUgYG5nTW9kZWxgLlxuXHQgKi9cblx0cHJpdmF0ZSBjdmFPblRvdWNoZWQ/OiAoKSA9PiB2b2lkO1xuXG5cdC8qKlxuXHQgKiBSZWZlcmVuY2UgdG8gdGhlIHNvdXJjZSBlbGVtZW50IHVzZWQgYnkgdGhlIGVkaXRvci5cblx0ICovXG5cdHByaXZhdGUgZWRpdG9yRWxlbWVudD86IEhUTUxFbGVtZW50O1xuXG5cdGNvbnN0cnVjdG9yKCBlbGVtZW50UmVmOiBFbGVtZW50UmVmLCBuZ1pvbmU6IE5nWm9uZSApIHtcblx0XHR0aGlzLm5nWm9uZSA9IG5nWm9uZTtcblx0XHR0aGlzLmVsZW1lbnRSZWYgPSBlbGVtZW50UmVmO1xuXHR9XG5cblx0Ly8gSW1wbGVtZW50aW5nIHRoZSBBZnRlclZpZXdJbml0IGludGVyZmFjZS5cblx0bmdBZnRlclZpZXdJbml0KCkge1xuXHRcdHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCAoKSA9PiB7XG5cdFx0XHR0aGlzLmNyZWF0ZUVkaXRvcigpO1xuXHRcdH0gKTtcblx0fVxuXG5cdC8vIEltcGxlbWVudGluZyB0aGUgT25EZXN0cm95IGludGVyZmFjZS5cblx0bmdPbkRlc3Ryb3koKSB7XG5cdFx0aWYgKCB0aGlzLmVkaXRvckluc3RhbmNlICkge1xuXHRcdFx0dGhpcy5lZGl0b3JJbnN0YW5jZS5kZXN0cm95KCk7XG5cdFx0XHR0aGlzLmVkaXRvckluc3RhbmNlID0gbnVsbDtcblx0XHR9XG5cdH1cblxuXHQvLyBJbXBsZW1lbnRpbmcgdGhlIENvbnRyb2xWYWx1ZUFjY2Vzc29yIGludGVyZmFjZSAob25seSB3aGVuIGJpbmRpbmcgdG8gbmdNb2RlbCkuXG5cdHdyaXRlVmFsdWUoIHZhbHVlOiBzdHJpbmcgfCBudWxsICk6IHZvaWQge1xuXHRcdC8vIFRoaXMgbWV0aG9kIGlzIGNhbGxlZCB3aXRoIHRoZSBgbnVsbGAgdmFsdWUgd2hlbiB0aGUgZm9ybSByZXNldHMuXG5cdFx0Ly8gQSBjb21wb25lbnQncyByZXNwb25zaWJpbGl0eSBpcyB0byByZXN0b3JlIHRvIHRoZSBpbml0aWFsIHN0YXRlLlxuXHRcdGlmICggdmFsdWUgPT09IG51bGwgKSB7XG5cdFx0XHR2YWx1ZSA9ICcnO1xuXHRcdH1cblxuXHRcdC8vIElmIGFscmVhZHkgaW5pdGlhbGl6ZWQuXG5cdFx0aWYgKCB0aGlzLmVkaXRvckluc3RhbmNlICkge1xuXHRcdFx0dGhpcy5lZGl0b3JJbnN0YW5jZS5zZXREYXRhKCB2YWx1ZSApO1xuXHRcdH1cblx0XHQvLyBJZiBub3QsIHdhaXQgZm9yIGl0IHRvIGJlIHJlYWR5OyBzdG9yZSB0aGUgZGF0YS5cblx0XHRlbHNlIHtcblx0XHRcdHRoaXMuZGF0YSA9IHZhbHVlO1xuXG5cdFx0XHQvLyBJZiB0aGUgZWRpdG9yIGVsZW1lbnQgaXMgYWxyZWFkeSBhdmFpbGFibGUsIHRoZW4gdXBkYXRlIGl0cyBjb250ZW50LlxuXHRcdFx0Ly8gSWYgdGhlIG5nTW9kZWwgaXMgdXNlZCB0aGVuIHRoZSBlZGl0b3IgZWxlbWVudCBzaG91bGQgYmUgdXBkYXRlZCBkaXJlY3RseSBoZXJlLlxuXHRcdFx0aWYgKCB0aGlzLmVkaXRvckVsZW1lbnQgKSB7XG5cdFx0XHRcdHRoaXMuZWRpdG9yRWxlbWVudC5pbm5lckhUTUwgPSB0aGlzLmRhdGE7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gSW1wbGVtZW50aW5nIHRoZSBDb250cm9sVmFsdWVBY2Nlc3NvciBpbnRlcmZhY2UgKG9ubHkgd2hlbiBiaW5kaW5nIHRvIG5nTW9kZWwpLlxuXHRyZWdpc3Rlck9uQ2hhbmdlKCBjYWxsYmFjazogKCBkYXRhOiBzdHJpbmcgKSA9PiB2b2lkICk6IHZvaWQge1xuXHRcdHRoaXMuY3ZhT25DaGFuZ2UgPSBjYWxsYmFjaztcblx0fVxuXG5cdC8vIEltcGxlbWVudGluZyB0aGUgQ29udHJvbFZhbHVlQWNjZXNzb3IgaW50ZXJmYWNlIChvbmx5IHdoZW4gYmluZGluZyB0byBuZ01vZGVsKS5cblx0cmVnaXN0ZXJPblRvdWNoZWQoIGNhbGxiYWNrOiAoKSA9PiB2b2lkICk6IHZvaWQge1xuXHRcdHRoaXMuY3ZhT25Ub3VjaGVkID0gY2FsbGJhY2s7XG5cdH1cblxuXHQvLyBJbXBsZW1lbnRpbmcgdGhlIENvbnRyb2xWYWx1ZUFjY2Vzc29yIGludGVyZmFjZSAob25seSB3aGVuIGJpbmRpbmcgdG8gbmdNb2RlbCkuXG5cdHNldERpc2FibGVkU3RhdGUoIGlzRGlzYWJsZWQ6IGJvb2xlYW4gKTogdm9pZCB7XG5cdFx0Ly8gSWYgYWxyZWFkeSBpbml0aWFsaXplZFxuXHRcdGlmICggdGhpcy5lZGl0b3JJbnN0YW5jZSApIHtcblx0XHRcdHRoaXMuZWRpdG9ySW5zdGFuY2UuaXNSZWFkT25seSA9IGlzRGlzYWJsZWQ7XG5cdFx0fVxuXHRcdC8vIElmIG5vdCwgd2FpdCBmb3IgaXQgdG8gYmUgcmVhZHk7IHN0b3JlIHRoZSBzdGF0ZS5cblx0XHRlbHNlIHtcblx0XHRcdHRoaXMuaW5pdGlhbElzRGlzYWJsZWQgPSBpc0Rpc2FibGVkO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGVzIHRoZSBlZGl0b3IgaW5zdGFuY2UsIHNldHMgaW5pdGlhbCBlZGl0b3IgZGF0YSwgdGhlbiBpbnRlZ3JhdGVzXG5cdCAqIHRoZSBlZGl0b3Igd2l0aCB0aGUgQW5ndWxhciBjb21wb25lbnQuIFRoaXMgbWV0aG9kIGRvZXMgbm90IHVzZSB0aGUgYGVkaXRvci5zZXREYXRhKClgXG5cdCAqIGJlY2F1c2Ugb2YgdGhlIGlzc3VlIGluIHRoZSBjb2xsYWJvcmF0aW9uIG1vZGUgKCM2KS5cblx0ICovXG5cdHByaXZhdGUgY3JlYXRlRWRpdG9yKCk6IFByb21pc2U8dm9pZD4ge1xuXHRcdGNvbnN0IGVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCB0aGlzLnRhZ05hbWUgKTtcblx0XHR0aGlzLmVkaXRvckVsZW1lbnQgPSBlbGVtZW50O1xuXG5cdFx0aWYgKCB0aGlzLmRhdGEgJiYgdGhpcy5jb25maWcuaW5pdGlhbERhdGEgKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdFZGl0b3IgZGF0YSBzaG91bGQgYmUgcHJvdmlkZWQgZWl0aGVyIHVzaW5nIGBjb25maWcuaW5pdGlhbERhdGFgIG9yIGBkYXRhYCBwcm9wZXJ0aWVzLicgKTtcblx0XHR9XG5cblx0XHQvLyBNZXJnZSB0d28gcG9zc2libGUgd2F5cyBvZiBwcm92aWRpbmcgZGF0YSBpbnRvIHRoZSBgY29uZmlnLmluaXRpYWxEYXRhYCBmaWVsZC5cblx0XHRjb25zdCBjb25maWcgPSB7XG5cdFx0XHQuLi50aGlzLmNvbmZpZyxcblx0XHRcdGluaXRpYWxEYXRhOiB0aGlzLmNvbmZpZy5pbml0aWFsRGF0YSB8fCB0aGlzLmRhdGEgfHwgJydcblx0XHR9O1xuXG5cdFx0dGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQuYXBwZW5kQ2hpbGQoIGVsZW1lbnQgKTtcblxuXHRcdHJldHVybiB0aGlzLmVkaXRvciEuY3JlYXRlKCBlbGVtZW50LCBjb25maWcgKVxuXHRcdFx0LnRoZW4oIGVkaXRvciA9PiB7XG5cdFx0XHRcdHRoaXMuZWRpdG9ySW5zdGFuY2UgPSBlZGl0b3I7XG5cblx0XHRcdFx0aWYgKCB0aGlzLmluaXRpYWxJc0Rpc2FibGVkICkge1xuXHRcdFx0XHRcdGVkaXRvci5pc1JlYWRPbmx5ID0gdGhpcy5pbml0aWFsSXNEaXNhYmxlZDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRoaXMubmdab25lLnJ1biggKCkgPT4ge1xuXHRcdFx0XHRcdHRoaXMucmVhZHkuZW1pdCggZWRpdG9yICk7XG5cdFx0XHRcdH0gKTtcblxuXHRcdFx0XHR0aGlzLnNldFVwRWRpdG9yRXZlbnRzKCBlZGl0b3IgKTtcblx0XHRcdH0gKVxuXHRcdFx0LmNhdGNoKCAoIGVycjogRXJyb3IgKSA9PiB7XG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoIGVyci5zdGFjayApO1xuXHRcdFx0fSApO1xuXHR9XG5cblx0LyoqXG5cdCAqIEludGVncmF0ZXMgdGhlIGVkaXRvciB3aXRoIHRoZSBjb21wb25lbnQgYnkgYXR0YWNoaW5nIHJlbGF0ZWQgZXZlbnQgbGlzdGVuZXJzLlxuXHQgKi9cblx0cHJpdmF0ZSBzZXRVcEVkaXRvckV2ZW50cyggZWRpdG9yOiBDS0VkaXRvcjUuRWRpdG9yICk6IHZvaWQge1xuXHRcdGNvbnN0IG1vZGVsRG9jdW1lbnQgPSBlZGl0b3IubW9kZWwuZG9jdW1lbnQ7XG5cdFx0Y29uc3Qgdmlld0RvY3VtZW50ID0gZWRpdG9yLmVkaXRpbmcudmlldy5kb2N1bWVudDtcblxuXHRcdG1vZGVsRG9jdW1lbnQub24oICdjaGFuZ2U6ZGF0YScsICggZXZ0OiBDS0VkaXRvcjUuRXZlbnRJbmZvPCdjaGFuZ2U6ZGF0YSc+ICkgPT4ge1xuXHRcdFx0dGhpcy5uZ1pvbmUucnVuKCAoKSA9PiB7XG5cdFx0XHRcdGlmICggdGhpcy5jdmFPbkNoYW5nZSApIHtcblx0XHRcdFx0XHRjb25zdCBkYXRhID0gZWRpdG9yLmdldERhdGEoKTtcblxuXHRcdFx0XHRcdHRoaXMuY3ZhT25DaGFuZ2UoIGRhdGEgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRoaXMuY2hhbmdlLmVtaXQoIHsgZXZlbnQ6IGV2dCwgZWRpdG9yIH0gKTtcblx0XHRcdH0gKTtcblx0XHR9ICk7XG5cblx0XHR2aWV3RG9jdW1lbnQub24oICdmb2N1cycsICggZXZ0OiBDS0VkaXRvcjUuRXZlbnRJbmZvPCdmb2N1cyc+ICkgPT4ge1xuXHRcdFx0dGhpcy5uZ1pvbmUucnVuKCAoKSA9PiB7XG5cdFx0XHRcdHRoaXMuZm9jdXMuZW1pdCggeyBldmVudDogZXZ0LCBlZGl0b3IgfSApO1xuXHRcdFx0fSApO1xuXHRcdH0gKTtcblxuXHRcdHZpZXdEb2N1bWVudC5vbiggJ2JsdXInLCAoIGV2dDogQ0tFZGl0b3I1LkV2ZW50SW5mbzwnYmx1cic+ICkgPT4ge1xuXHRcdFx0dGhpcy5uZ1pvbmUucnVuKCAoKSA9PiB7XG5cdFx0XHRcdGlmICggdGhpcy5jdmFPblRvdWNoZWQgKSB7XG5cdFx0XHRcdFx0dGhpcy5jdmFPblRvdWNoZWQoKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRoaXMuYmx1ci5lbWl0KCB7IGV2ZW50OiBldnQsIGVkaXRvciB9ICk7XG5cdFx0XHR9ICk7XG5cdFx0fSApO1xuXHR9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmx1ckV2ZW50IHtcblx0ZXZlbnQ6IENLRWRpdG9yNS5FdmVudEluZm88J2JsdXInPjtcblx0ZWRpdG9yOiBDS0VkaXRvcjUuRWRpdG9yO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEZvY3VzRXZlbnQge1xuXHRldmVudDogQ0tFZGl0b3I1LkV2ZW50SW5mbzwnZm9jdXMnPjtcblx0ZWRpdG9yOiBDS0VkaXRvcjUuRWRpdG9yO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENoYW5nZUV2ZW50IHtcblx0ZXZlbnQ6IENLRWRpdG9yNS5FdmVudEluZm88J2NoYW5nZTpkYXRhJz47XG5cdGVkaXRvcjogQ0tFZGl0b3I1LkVkaXRvcjtcbn1cbiJdfQ==