ngx-editor
Version:
Rich Text Editor for angular using ProseMirror
218 lines • 25.7 kB
JavaScript
import { Component, HostBinding, HostListener, Input, } from '@angular/core';
import { NodeSelection } from 'prosemirror-state';
import { asyncScheduler, fromEvent } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
import { computePosition, detectOverflow, offset, autoPlacement } from '@floating-ui/dom';
import * as i0 from "@angular/core";
import * as i1 from "../../../pipes/sanitize/sanitize-html.pipe";
import * as i2 from "../bubble/bubble.component";
import * as i3 from "@angular/common";
export class FloatingMenuComponent {
constructor(el, sanitizeHTML) {
this.el = el;
this.sanitizeHTML = sanitizeHTML;
this.autoPlace = false;
this.posLeft = 0;
this.posTop = 0;
this.showMenu = false;
this.dragging = false;
}
get display() {
return {
visibility: this.showMenu ? 'visible' : 'hidden',
opacity: this.showMenu ? '1' : '0',
top: `${this.posTop}px`,
left: `${this.posLeft}px`,
};
}
get view() {
return this.editor.view;
}
onMouseDown(e) {
const target = e.target;
if (this.el.nativeElement.contains(target) && target.nodeName !== 'INPUT') {
e.preventDefault();
return;
}
this.dragging = true;
}
onKeyDown(e) {
const target = e.target;
if (target.nodeName === 'INPUT') {
return;
}
this.dragging = true;
this.hide();
}
onMouseUp(e) {
const target = e.target;
if (this.el.nativeElement.contains(target) || target.nodeName === 'INPUT') {
e.preventDefault();
return;
}
this.dragging = false;
this.useUpdate();
}
onKeyUp(e) {
const target = e.target;
if (target.nodeName === 'INPUT') {
return;
}
this.dragging = false;
this.useUpdate();
}
useUpdate() {
if (!this.view) {
return;
}
this.update(this.view);
}
hide() {
this.showMenu = false;
}
show() {
this.showMenu = true;
}
async calculateBubblePosition(view) {
const { state: { selection } } = view;
const { from, to } = selection;
const start = view.coordsAtPos(from);
const end = view.coordsAtPos(to);
const selectionElement = {
getBoundingClientRect() {
if (selection instanceof NodeSelection) {
const node = view.nodeDOM(from);
return node.getBoundingClientRect();
}
const { top, left } = start;
const { bottom, right } = end;
return {
x: left,
y: top,
top,
bottom,
left,
right,
width: right - left,
height: bottom - top,
};
},
};
// the floating bubble itself
const bubbleEl = this.el.nativeElement;
const { x: left, y: top } = await computePosition(selectionElement, bubbleEl, {
placement: 'top',
middleware: [
offset(5),
this.autoPlace && autoPlacement({
boundary: view.dom,
padding: 5,
allowedPlacements: ['top', 'bottom'],
}),
{
// prevent overflow on right and left side
// since only top and bottom placements are allowed
// autoplacement can't handle overflows on the right and left
name: 'overflowMiddleware',
async fn(middlewareArgs) {
const overflow = await detectOverflow(middlewareArgs, {
boundary: view.dom,
padding: 5,
});
// overflows left
if (overflow.left > 0) {
return {
x: middlewareArgs.x + overflow.left,
};
}
// overflows right
if (overflow.right > 0) {
return {
x: middlewareArgs.x - overflow.right,
};
}
return {};
},
},
].filter(Boolean),
});
return {
left,
top,
};
}
canShowMenu(view) {
const { state } = view;
const { selection } = state;
const { empty } = selection;
if (selection instanceof NodeSelection) {
if (selection.node.type.name === 'image') {
return false;
}
}
const hasFocus = this.view.hasFocus();
if (!hasFocus || empty || this.dragging) {
this.hide();
return false;
}
return true;
}
update(view) {
const canShowMenu = this.canShowMenu(view);
if (!canShowMenu) {
this.hide();
return;
}
this.calculateBubblePosition(this.view).then(({ top, left }) => {
if (!this.canShowMenu) {
this.hide();
return;
}
this.posLeft = left;
this.posTop = top;
this.show();
});
}
ngOnInit() {
if (!this.editor) {
throw new Error('NgxEditor: Required editor instance');
}
this.updateSubscription = this.editor.update
.subscribe((view) => {
this.update(view);
});
this.resizeSubscription = fromEvent(window, 'resize').pipe(throttleTime(500, asyncScheduler, { leading: true, trailing: true })).subscribe(() => {
this.useUpdate();
});
}
ngOnDestroy() {
this.updateSubscription.unsubscribe();
this.resizeSubscription.unsubscribe();
}
}
FloatingMenuComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.5", ngImport: i0, type: FloatingMenuComponent, deps: [{ token: i0.ElementRef }, { token: i1.SanitizeHtmlPipe }], target: i0.ɵɵFactoryTarget.Component });
FloatingMenuComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.5", type: FloatingMenuComponent, selector: "ngx-editor-floating-menu", inputs: { editor: "editor", autoPlace: "autoPlace" }, host: { listeners: { "document:mousedown": "onMouseDown($event)", "document:keydown": "onKeyDown($event)", "document:mouseup": "onMouseUp($event)", "document:keyup": "onKeyUp($event)" }, properties: { "style": "this.display" } }, ngImport: i0, template: "<div #ref>\n <ng-content></ng-content>\n</div>\n<ng-container *ngIf=\"ref.children.length === 0\">\n <ngx-bubble [editor]=\"editor\"></ngx-bubble>\n</ng-container>\n", styles: ["*,*:before,*:after{box-sizing:border-box}:host{position:absolute;z-index:20;margin-bottom:5px;visibility:hidden;opacity:0}\n"], components: [{ type: i2.BubbleComponent, selector: "ngx-bubble", inputs: ["editor"] }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.5", ngImport: i0, type: FloatingMenuComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-editor-floating-menu', template: "<div #ref>\n <ng-content></ng-content>\n</div>\n<ng-container *ngIf=\"ref.children.length === 0\">\n <ngx-bubble [editor]=\"editor\"></ngx-bubble>\n</ng-container>\n", styles: ["*,*:before,*:after{box-sizing:border-box}:host{position:absolute;z-index:20;margin-bottom:5px;visibility:hidden;opacity:0}\n"] }]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.SanitizeHtmlPipe }]; }, propDecorators: { display: [{
type: HostBinding,
args: ['style']
}], editor: [{
type: Input
}], autoPlace: [{
type: Input
}], onMouseDown: [{
type: HostListener,
args: ['document:mousedown', ['$event']]
}], onKeyDown: [{
type: HostListener,
args: ['document:keydown', ['$event']]
}], onMouseUp: [{
type: HostListener,
args: ['document:mouseup', ['$event']]
}], onKeyUp: [{
type: HostListener,
args: ['document:keyup', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmxvYXRpbmctbWVudS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZWRpdG9yL3NyYy9saWIvbW9kdWxlcy9tZW51L2Zsb2F0aW5nLW1lbnUvZmxvYXRpbmctbWVudS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZWRpdG9yL3NyYy9saWIvbW9kdWxlcy9tZW51L2Zsb2F0aW5nLW1lbnUvZmxvYXRpbmctbWVudS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUFjLFdBQVcsRUFDbEMsWUFBWSxFQUFFLEtBQUssR0FDcEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRWxELE9BQU8sRUFBRSxjQUFjLEVBQUUsU0FBUyxFQUFnQixNQUFNLE1BQU0sQ0FBQztBQUMvRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFOUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxNQUFNLGtCQUFrQixDQUFDOzs7OztBQWUxRixNQUFNLE9BQU8scUJBQXFCO0lBQ2hDLFlBQW1CLEVBQTJCLEVBQVUsWUFBOEI7UUFBbkUsT0FBRSxHQUFGLEVBQUUsQ0FBeUI7UUFBVSxpQkFBWSxHQUFaLFlBQVksQ0FBa0I7UUFnQjdFLGNBQVMsR0FBRyxLQUFLLENBQUM7UUFFbkIsWUFBTyxHQUFHLENBQUMsQ0FBQztRQUNaLFdBQU0sR0FBRyxDQUFDLENBQUM7UUFDWCxhQUFRLEdBQUcsS0FBSyxDQUFDO1FBRWpCLGFBQVEsR0FBRyxLQUFLLENBQUM7SUF0QmlFLENBQUM7SUFFM0YsSUFBMEIsT0FBTztRQUMvQixPQUFPO1lBQ0wsVUFBVSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsUUFBUTtZQUNoRCxPQUFPLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHO1lBQ2xDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxNQUFNLElBQUk7WUFDdkIsSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLE9BQU8sSUFBSTtTQUMxQixDQUFDO0lBQ0osQ0FBQztJQUVELElBQVksSUFBSTtRQUNkLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUM7SUFDMUIsQ0FBQztJQVkrQyxXQUFXLENBQUMsQ0FBYTtRQUN2RSxNQUFNLE1BQU0sR0FBRyxDQUFDLENBQUMsTUFBYyxDQUFDO1FBRWhDLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssT0FBTyxFQUFFO1lBQ3pFLENBQUMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUNuQixPQUFPO1NBQ1I7UUFFRCxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztJQUN2QixDQUFDO0lBRTZDLFNBQVMsQ0FBQyxDQUFnQjtRQUN0RSxNQUFNLE1BQU0sR0FBRyxDQUFDLENBQUMsTUFBYyxDQUFDO1FBRWhDLElBQUksTUFBTSxDQUFDLFFBQVEsS0FBSyxPQUFPLEVBQUU7WUFDL0IsT0FBTztTQUNSO1FBRUQsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFDckIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztJQUU2QyxTQUFTLENBQUMsQ0FBYTtRQUNuRSxNQUFNLE1BQU0sR0FBRyxDQUFDLENBQUMsTUFBYyxDQUFDO1FBRWhDLElBQUksSUFBSSxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssT0FBTyxFQUFFO1lBQ3pFLENBQUMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUNuQixPQUFPO1NBQ1I7UUFFRCxJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztRQUN0QixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7SUFDbkIsQ0FBQztJQUUyQyxPQUFPLENBQUMsQ0FBZ0I7UUFDbEUsTUFBTSxNQUFNLEdBQUcsQ0FBQyxDQUFDLE1BQWMsQ0FBQztRQUVoQyxJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssT0FBTyxFQUFFO1lBQy9CLE9BQU87U0FDUjtRQUVELElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUNuQixDQUFDO0lBRU8sU0FBUztRQUNmLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFO1lBQ2QsT0FBTztTQUNSO1FBRUQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUVPLElBQUk7UUFDVixJQUFJLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUN4QixDQUFDO0lBRU8sSUFBSTtRQUNWLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO0lBQ3ZCLENBQUM7SUFFTyxLQUFLLENBQUMsdUJBQXVCLENBQUMsSUFBZ0I7UUFDcEQsTUFBTSxFQUFFLEtBQUssRUFBRSxFQUFFLFNBQVMsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFDO1FBQ3RDLE1BQU0sRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLEdBQUcsU0FBUyxDQUFDO1FBRS9CLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDckMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUVqQyxNQUFNLGdCQUFnQixHQUFtQjtZQUN2QyxxQkFBcUI7Z0JBQ25CLElBQUksU0FBUyxZQUFZLGFBQWEsRUFBRTtvQkFDdEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQWdCLENBQUM7b0JBQy9DLE9BQU8sSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7aUJBQ3JDO2dCQUVELE1BQU0sRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLEdBQUcsS0FBSyxDQUFDO2dCQUM1QixNQUFNLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLEdBQUcsQ0FBQztnQkFFOUIsT0FBTztvQkFDTCxDQUFDLEVBQUUsSUFBSTtvQkFDUCxDQUFDLEVBQUUsR0FBRztvQkFDTixHQUFHO29CQUNILE1BQU07b0JBQ04sSUFBSTtvQkFDSixLQUFLO29CQUNMLEtBQUssRUFBRSxLQUFLLEdBQUcsSUFBSTtvQkFDbkIsTUFBTSxFQUFFLE1BQU0sR0FBRyxHQUFHO2lCQUNyQixDQUFDO1lBQ0osQ0FBQztTQUNGLENBQUM7UUFFRiw2QkFBNkI7UUFDN0IsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUM7UUFFdkMsTUFBTSxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxFQUFFLEdBQUcsRUFBRSxHQUFHLE1BQU0sZUFBZSxDQUFDLGdCQUFnQixFQUFFLFFBQVEsRUFBRTtZQUM1RSxTQUFTLEVBQUUsS0FBSztZQUNoQixVQUFVLEVBQUU7Z0JBQ1YsTUFBTSxDQUFDLENBQUMsQ0FBQztnQkFDVCxJQUFJLENBQUMsU0FBUyxJQUFJLGFBQWEsQ0FBQztvQkFDOUIsUUFBUSxFQUFFLElBQUksQ0FBQyxHQUFHO29CQUNsQixPQUFPLEVBQUUsQ0FBQztvQkFDVixpQkFBaUIsRUFBRSxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUM7aUJBQ3JDLENBQUM7Z0JBQ0Y7b0JBQ0UsMENBQTBDO29CQUMxQyxtREFBbUQ7b0JBQ25ELDZEQUE2RDtvQkFDN0QsSUFBSSxFQUFFLG9CQUFvQjtvQkFDMUIsS0FBSyxDQUFDLEVBQUUsQ0FBQyxjQUFjO3dCQUNyQixNQUFNLFFBQVEsR0FBRyxNQUFNLGNBQWMsQ0FBQyxjQUFjLEVBQUU7NEJBQ3BELFFBQVEsRUFBRSxJQUFJLENBQUMsR0FBRzs0QkFDbEIsT0FBTyxFQUFFLENBQUM7eUJBQ1gsQ0FBQyxDQUFDO3dCQUVILGlCQUFpQjt3QkFDakIsSUFBSSxRQUFRLENBQUMsSUFBSSxHQUFHLENBQUMsRUFBRTs0QkFDckIsT0FBTztnQ0FDTCxDQUFDLEVBQUUsY0FBYyxDQUFDLENBQUMsR0FBRyxRQUFRLENBQUMsSUFBSTs2QkFDcEMsQ0FBQzt5QkFDSDt3QkFFRCxrQkFBa0I7d0JBQ2xCLElBQUksUUFBUSxDQUFDLEtBQUssR0FBRyxDQUFDLEVBQUU7NEJBQ3RCLE9BQU87Z0NBQ0wsQ0FBQyxFQUFFLGNBQWMsQ0FBQyxDQUFDLEdBQUcsUUFBUSxDQUFDLEtBQUs7NkJBQ3JDLENBQUM7eUJBQ0g7d0JBRUQsT0FBTyxFQUFFLENBQUM7b0JBQ1osQ0FBQztpQkFDRjthQUNGLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQztTQUNsQixDQUFDLENBQUM7UUFFSCxPQUFPO1lBQ0wsSUFBSTtZQUNKLEdBQUc7U0FDSixDQUFDO0lBQ0osQ0FBQztJQUVPLFdBQVcsQ0FBQyxJQUFnQjtRQUNsQyxNQUFNLEVBQUUsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDO1FBQ3ZCLE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxLQUFLLENBQUM7UUFDNUIsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLFNBQVMsQ0FBQztRQUU1QixJQUFJLFNBQVMsWUFBWSxhQUFhLEVBQUU7WUFDdEMsSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssT0FBTyxFQUFFO2dCQUN4QyxPQUFPLEtBQUssQ0FBQzthQUNkO1NBQ0Y7UUFFRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBRXRDLElBQUksQ0FBQyxRQUFRLElBQUksS0FBSyxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDdkMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ1osT0FBTyxLQUFLLENBQUM7U0FDZDtRQUVELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVPLE1BQU0sQ0FBQyxJQUFnQjtRQUM3QixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRTNDLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDaEIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ1osT0FBTztTQUNSO1FBRUQsSUFBSSxDQUFDLHVCQUF1QixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFO1lBQzdELElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFO2dCQUNyQixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ1osT0FBTzthQUNSO1lBRUQsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7WUFDcEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxHQUFHLENBQUM7WUFFbEIsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2QsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsUUFBUTtRQUNOLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ2hCLE1BQU0sSUFBSSxLQUFLLENBQUMscUNBQXFDLENBQUMsQ0FBQztTQUN4RDtRQUVELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU07YUFDekMsU0FBUyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUU7WUFDbEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwQixDQUFDLENBQUMsQ0FBQztRQUVMLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxTQUFTLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FDeEQsWUFBWSxDQUFDLEdBQUcsRUFBRSxjQUFjLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUNyRSxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7WUFDZixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDbkIsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN0QyxJQUFJLENBQUMsa0JBQWtCLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDeEMsQ0FBQzs7a0hBcE9VLHFCQUFxQjtzR0FBckIscUJBQXFCLDRWQ3hCbEMseUtBTUE7MkZEa0JhLHFCQUFxQjtrQkFMakMsU0FBUzsrQkFDRSwwQkFBMEI7Z0lBT1YsT0FBTztzQkFBaEMsV0FBVzt1QkFBQyxPQUFPO2dCQWFYLE1BQU07c0JBQWQsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQVMwQyxXQUFXO3NCQUExRCxZQUFZO3VCQUFDLG9CQUFvQixFQUFFLENBQUMsUUFBUSxDQUFDO2dCQVdBLFNBQVM7c0JBQXRELFlBQVk7dUJBQUMsa0JBQWtCLEVBQUUsQ0FBQyxRQUFRLENBQUM7Z0JBV0UsU0FBUztzQkFBdEQsWUFBWTt1QkFBQyxrQkFBa0IsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFZQSxPQUFPO3NCQUFsRCxZQUFZO3VCQUFDLGdCQUFnQixFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LCBFbGVtZW50UmVmLCBIb3N0QmluZGluZyxcbiAgSG9zdExpc3RlbmVyLCBJbnB1dCwgT25EZXN0cm95LCBPbkluaXQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTm9kZVNlbGVjdGlvbiB9IGZyb20gJ3Byb3NlbWlycm9yLXN0YXRlJztcbmltcG9ydCB7IEVkaXRvclZpZXcgfSBmcm9tICdwcm9zZW1pcnJvci12aWV3JztcbmltcG9ydCB7IGFzeW5jU2NoZWR1bGVyLCBmcm9tRXZlbnQsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgdGhyb3R0bGVUaW1lIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHR5cGUgeyBWaXJ0dWFsRWxlbWVudCB9IGZyb20gJ0BmbG9hdGluZy11aS9jb3JlJztcbmltcG9ydCB7IGNvbXB1dGVQb3NpdGlvbiwgZGV0ZWN0T3ZlcmZsb3csIG9mZnNldCwgYXV0b1BsYWNlbWVudCB9IGZyb20gJ0BmbG9hdGluZy11aS9kb20nO1xuXG5pbXBvcnQgRWRpdG9yIGZyb20gJy4uLy4uLy4uL0VkaXRvcic7XG5pbXBvcnQgeyBTYW5pdGl6ZUh0bWxQaXBlIH0gZnJvbSAnLi4vLi4vLi4vcGlwZXMvc2FuaXRpemUvc2FuaXRpemUtaHRtbC5waXBlJztcblxuaW50ZXJmYWNlIEJ1YmJsZVBvc2l0aW9uIHtcbiAgdG9wOiBudW1iZXI7XG4gIGxlZnQ6IG51bWJlcjtcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmd4LWVkaXRvci1mbG9hdGluZy1tZW51JyxcbiAgdGVtcGxhdGVVcmw6ICcuL2Zsb2F0aW5nLW1lbnUuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9mbG9hdGluZy1tZW51LmNvbXBvbmVudC5zY3NzJ10sXG59KVxuZXhwb3J0IGNsYXNzIEZsb2F0aW5nTWVudUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgY29uc3RydWN0b3IocHVibGljIGVsOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PiwgcHJpdmF0ZSBzYW5pdGl6ZUhUTUw6IFNhbml0aXplSHRtbFBpcGUpIHsgfVxuXG4gIEBIb3N0QmluZGluZygnc3R5bGUnKSBnZXQgZGlzcGxheSgpOiBQYXJ0aWFsPENTU1N0eWxlRGVjbGFyYXRpb24+IHtcbiAgICByZXR1cm4ge1xuICAgICAgdmlzaWJpbGl0eTogdGhpcy5zaG93TWVudSA/ICd2aXNpYmxlJyA6ICdoaWRkZW4nLFxuICAgICAgb3BhY2l0eTogdGhpcy5zaG93TWVudSA/ICcxJyA6ICcwJyxcbiAgICAgIHRvcDogYCR7dGhpcy5wb3NUb3B9cHhgLFxuICAgICAgbGVmdDogYCR7dGhpcy5wb3NMZWZ0fXB4YCxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBnZXQgdmlldygpOiBFZGl0b3JWaWV3IHtcbiAgICByZXR1cm4gdGhpcy5lZGl0b3IudmlldztcbiAgfVxuXG4gIEBJbnB1dCgpIGVkaXRvcjogRWRpdG9yO1xuICBASW5wdXQoKSBhdXRvUGxhY2UgPSBmYWxzZTtcblxuICBwcml2YXRlIHBvc0xlZnQgPSAwO1xuICBwcml2YXRlIHBvc1RvcCA9IDA7XG4gIHByaXZhdGUgc2hvd01lbnUgPSBmYWxzZTtcbiAgcHJpdmF0ZSB1cGRhdGVTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBkcmFnZ2luZyA9IGZhbHNlO1xuICBwcml2YXRlIHJlc2l6ZVN1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXG4gIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50Om1vdXNlZG93bicsIFsnJGV2ZW50J10pIG9uTW91c2VEb3duKGU6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCB0YXJnZXQgPSBlLnRhcmdldCBhcyBOb2RlO1xuXG4gICAgaWYgKHRoaXMuZWwubmF0aXZlRWxlbWVudC5jb250YWlucyh0YXJnZXQpICYmIHRhcmdldC5ub2RlTmFtZSAhPT0gJ0lOUFVUJykge1xuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuZHJhZ2dpbmcgPSB0cnVlO1xuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6a2V5ZG93bicsIFsnJGV2ZW50J10pIG9uS2V5RG93bihlOiBLZXlib2FyZEV2ZW50KTogdm9pZCB7XG4gICAgY29uc3QgdGFyZ2V0ID0gZS50YXJnZXQgYXMgTm9kZTtcblxuICAgIGlmICh0YXJnZXQubm9kZU5hbWUgPT09ICdJTlBVVCcpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmRyYWdnaW5nID0gdHJ1ZTtcbiAgICB0aGlzLmhpZGUoKTtcbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50Om1vdXNldXAnLCBbJyRldmVudCddKSBvbk1vdXNlVXAoZTogTW91c2VFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IHRhcmdldCA9IGUudGFyZ2V0IGFzIE5vZGU7XG5cbiAgICBpZiAodGhpcy5lbC5uYXRpdmVFbGVtZW50LmNvbnRhaW5zKHRhcmdldCkgfHwgdGFyZ2V0Lm5vZGVOYW1lID09PSAnSU5QVVQnKSB7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5kcmFnZ2luZyA9IGZhbHNlO1xuICAgIHRoaXMudXNlVXBkYXRlKCk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdkb2N1bWVudDprZXl1cCcsIFsnJGV2ZW50J10pIG9uS2V5VXAoZTogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xuICAgIGNvbnN0IHRhcmdldCA9IGUudGFyZ2V0IGFzIE5vZGU7XG5cbiAgICBpZiAodGFyZ2V0Lm5vZGVOYW1lID09PSAnSU5QVVQnKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5kcmFnZ2luZyA9IGZhbHNlO1xuICAgIHRoaXMudXNlVXBkYXRlKCk7XG4gIH1cblxuICBwcml2YXRlIHVzZVVwZGF0ZSgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMudmlldykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMudXBkYXRlKHRoaXMudmlldyk7XG4gIH1cblxuICBwcml2YXRlIGhpZGUoKTogdm9pZCB7XG4gICAgdGhpcy5zaG93TWVudSA9IGZhbHNlO1xuICB9XG5cbiAgcHJpdmF0ZSBzaG93KCk6IHZvaWQge1xuICAgIHRoaXMuc2hvd01lbnUgPSB0cnVlO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjYWxjdWxhdGVCdWJibGVQb3NpdGlvbih2aWV3OiBFZGl0b3JWaWV3KTogUHJvbWlzZTxCdWJibGVQb3NpdGlvbj4ge1xuICAgIGNvbnN0IHsgc3RhdGU6IHsgc2VsZWN0aW9uIH0gfSA9IHZpZXc7XG4gICAgY29uc3QgeyBmcm9tLCB0byB9ID0gc2VsZWN0aW9uO1xuXG4gICAgY29uc3Qgc3RhcnQgPSB2aWV3LmNvb3Jkc0F0UG9zKGZyb20pO1xuICAgIGNvbnN0IGVuZCA9IHZpZXcuY29vcmRzQXRQb3ModG8pO1xuXG4gICAgY29uc3Qgc2VsZWN0aW9uRWxlbWVudDogVmlydHVhbEVsZW1lbnQgPSB7XG4gICAgICBnZXRCb3VuZGluZ0NsaWVudFJlY3QoKSB7XG4gICAgICAgIGlmIChzZWxlY3Rpb24gaW5zdGFuY2VvZiBOb2RlU2VsZWN0aW9uKSB7XG4gICAgICAgICAgY29uc3Qgbm9kZSA9IHZpZXcubm9kZURPTShmcm9tKSBhcyBIVE1MRWxlbWVudDtcbiAgICAgICAgICByZXR1cm4gbm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHsgdG9wLCBsZWZ0IH0gPSBzdGFydDtcbiAgICAgICAgY29uc3QgeyBib3R0b20sIHJpZ2h0IH0gPSBlbmQ7XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB4OiBsZWZ0LFxuICAgICAgICAgIHk6IHRvcCxcbiAgICAgICAgICB0b3AsXG4gICAgICAgICAgYm90dG9tLFxuICAgICAgICAgIGxlZnQsXG4gICAgICAgICAgcmlnaHQsXG4gICAgICAgICAgd2lkdGg6IHJpZ2h0IC0gbGVmdCxcbiAgICAgICAgICBoZWlnaHQ6IGJvdHRvbSAtIHRvcCxcbiAgICAgICAgfTtcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIC8vIHRoZSBmbG9hdGluZyBidWJibGUgaXRzZWxmXG4gICAgY29uc3QgYnViYmxlRWwgPSB0aGlzLmVsLm5hdGl2ZUVsZW1lbnQ7XG5cbiAgICBjb25zdCB7IHg6IGxlZnQsIHk6IHRvcCB9ID0gYXdhaXQgY29tcHV0ZVBvc2l0aW9uKHNlbGVjdGlvbkVsZW1lbnQsIGJ1YmJsZUVsLCB7XG4gICAgICBwbGFjZW1lbnQ6ICd0b3AnLFxuICAgICAgbWlkZGxld2FyZTogW1xuICAgICAgICBvZmZzZXQoNSksXG4gICAgICAgIHRoaXMuYXV0b1BsYWNlICYmIGF1dG9QbGFjZW1lbnQoe1xuICAgICAgICAgIGJvdW5kYXJ5OiB2aWV3LmRvbSxcbiAgICAgICAgICBwYWRkaW5nOiA1LFxuICAgICAgICAgIGFsbG93ZWRQbGFjZW1lbnRzOiBbJ3RvcCcsICdib3R0b20nXSxcbiAgICAgICAgfSksXG4gICAgICAgIHtcbiAgICAgICAgICAvLyBwcmV2ZW50IG92ZXJmbG93IG9uIHJpZ2h0IGFuZCBsZWZ0IHNpZGVcbiAgICAgICAgICAvLyBzaW5jZSBvbmx5IHRvcCBhbmQgYm90dG9tIHBsYWNlbWVudHMgYXJlIGFsbG93ZWRcbiAgICAgICAgICAvLyBhdXRvcGxhY2VtZW50IGNhbid0IGhhbmRsZSBvdmVyZmxvd3Mgb24gdGhlIHJpZ2h0IGFuZCBsZWZ0XG4gICAgICAgICAgbmFtZTogJ292ZXJmbG93TWlkZGxld2FyZScsXG4gICAgICAgICAgYXN5bmMgZm4obWlkZGxld2FyZUFyZ3MpIHtcbiAgICAgICAgICAgIGNvbnN0IG92ZXJmbG93ID0gYXdhaXQgZGV0ZWN0T3ZlcmZsb3cobWlkZGxld2FyZUFyZ3MsIHtcbiAgICAgICAgICAgICAgYm91bmRhcnk6IHZpZXcuZG9tLFxuICAgICAgICAgICAgICBwYWRkaW5nOiA1LFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIG92ZXJmbG93cyBsZWZ0XG4gICAgICAgICAgICBpZiAob3ZlcmZsb3cubGVmdCA+IDApIHtcbiAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB4OiBtaWRkbGV3YXJlQXJncy54ICsgb3ZlcmZsb3cubGVmdCxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gb3ZlcmZsb3dzIHJpZ2h0XG4gICAgICAgICAgICBpZiAob3ZlcmZsb3cucmlnaHQgPiAwKSB7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgeDogbWlkZGxld2FyZUFyZ3MueCAtIG92ZXJmbG93LnJpZ2h0LFxuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIF0uZmlsdGVyKEJvb2xlYW4pLFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGxlZnQsXG4gICAgICB0b3AsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgY2FuU2hvd01lbnUodmlldzogRWRpdG9yVmlldyk6IEJvb2xlYW4ge1xuICAgIGNvbnN0IHsgc3RhdGUgfSA9IHZpZXc7XG4gICAgY29uc3QgeyBzZWxlY3Rpb24gfSA9IHN0YXRlO1xuICAgIGNvbnN0IHsgZW1wdHkgfSA9IHNlbGVjdGlvbjtcblxuICAgIGlmIChzZWxlY3Rpb24gaW5zdGFuY2VvZiBOb2RlU2VsZWN0aW9uKSB7XG4gICAgICBpZiAoc2VsZWN0aW9uLm5vZGUudHlwZS5uYW1lID09PSAnaW1hZ2UnKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBoYXNGb2N1cyA9IHRoaXMudmlldy5oYXNGb2N1cygpO1xuXG4gICAgaWYgKCFoYXNGb2N1cyB8fCBlbXB0eSB8fCB0aGlzLmRyYWdnaW5nKSB7XG4gICAgICB0aGlzLmhpZGUoKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlKHZpZXc6IEVkaXRvclZpZXcpOiB2b2lkIHtcbiAgICBjb25zdCBjYW5TaG93TWVudSA9IHRoaXMuY2FuU2hvd01lbnUodmlldyk7XG5cbiAgICBpZiAoIWNhblNob3dNZW51KSB7XG4gICAgICB0aGlzLmhpZGUoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmNhbGN1bGF0ZUJ1YmJsZVBvc2l0aW9uKHRoaXMudmlldykudGhlbigoeyB0b3AsIGxlZnQgfSkgPT4ge1xuICAgICAgaWYgKCF0aGlzLmNhblNob3dNZW51KSB7XG4gICAgICAgIHRoaXMuaGlkZSgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRoaXMucG9zTGVmdCA9IGxlZnQ7XG4gICAgICB0aGlzLnBvc1RvcCA9IHRvcDtcblxuICAgICAgdGhpcy5zaG93KCk7XG4gICAgfSk7XG4gIH1cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuZWRpdG9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05neEVkaXRvcjogUmVxdWlyZWQgZWRpdG9yIGluc3RhbmNlJyk7XG4gICAgfVxuXG4gICAgdGhpcy51cGRhdGVTdWJzY3JpcHRpb24gPSB0aGlzLmVkaXRvci51cGRhdGVcbiAgICAgIC5zdWJzY3JpYmUoKHZpZXcpID0+IHtcbiAgICAgICAgdGhpcy51cGRhdGUodmlldyk7XG4gICAgICB9KTtcblxuICAgIHRoaXMucmVzaXplU3Vic2NyaXB0aW9uID0gZnJvbUV2ZW50KHdpbmRvdywgJ3Jlc2l6ZScpLnBpcGUoXG4gICAgICB0aHJvdHRsZVRpbWUoNTAwLCBhc3luY1NjaGVkdWxlciwgeyBsZWFkaW5nOiB0cnVlLCB0cmFpbGluZzogdHJ1ZSB9KSxcbiAgICApLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLnVzZVVwZGF0ZSgpO1xuICAgIH0pO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy51cGRhdGVTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLnJlc2l6ZVN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICB9XG59XG4iLCI8ZGl2ICNyZWY+XG4gIDxuZy1jb250ZW50PjwvbmctY29udGVudD5cbjwvZGl2PlxuPG5nLWNvbnRhaW5lciAqbmdJZj1cInJlZi5jaGlsZHJlbi5sZW5ndGggPT09IDBcIj5cbiAgPG5neC1idWJibGUgW2VkaXRvcl09XCJlZGl0b3JcIj48L25neC1idWJibGU+XG48L25nLWNvbnRhaW5lcj5cbiJdfQ==