@talrace/ngx-noder 19.0.51 → 19.0.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/fesm2022/talrace-ngx-noder.mjs +1067 -653
  2. package/fesm2022/talrace-ngx-noder.mjs.map +1 -1
  3. package/lib/editor/display/layers/comment-highlight.layer.d.ts +0 -3
  4. package/lib/editor/display/layers/comment.layer.d.ts +2 -0
  5. package/lib/editor/display/renderer.d.ts +5 -3
  6. package/lib/editor/display/renderloop.d.ts +6 -3
  7. package/lib/editor/display/virtual.renderer.d.ts +6 -5
  8. package/lib/editor/execution/edit.session.d.ts +6 -2
  9. package/lib/editor/execution/editor.d.ts +14 -5
  10. package/lib/editor/execution/regulator.service.d.ts +3 -0
  11. package/lib/editor/gadgets/clipboard-handler/clipboard-handler.d.ts +23 -0
  12. package/lib/editor/gadgets/clipboard-handler/clipboard-slice.interface.d.ts +9 -0
  13. package/lib/editor/gadgets/comment/comment-render.service.d.ts +2 -1
  14. package/lib/editor/gadgets/history/operation-history.d.ts +5 -0
  15. package/lib/editor/gadgets/history/operation.type.d.ts +3 -1
  16. package/lib/editor/interaction/editor.service.d.ts +13 -0
  17. package/lib/editor/interaction/text-input.d.ts +0 -1
  18. package/lib/editor/operations/enums/command-type.enum.d.ts +3 -1
  19. package/lib/editor/operations/helpers/contents-operations.helper.d.ts +2 -0
  20. package/lib/editor/operations/helpers/format-operations.helper.d.ts +1 -0
  21. package/lib/editor/operations/helpers/indexed-element-operations.helper.d.ts +1 -0
  22. package/lib/editor/operations/helpers/link-operations.helper.d.ts +1 -0
  23. package/lib/editor/operations/helpers/range-element-operations.helper.d.ts +1 -0
  24. package/lib/editor/operations/operations-helper.helper.d.ts +2 -0
  25. package/lib/editor/operations/save-commands.helper.d.ts +4 -0
  26. package/lib/models/generated/command.model.d.ts +4 -0
  27. package/lib/models/generated/contents.model.d.ts +24 -0
  28. package/lib/models/generated/insert-contents.model.d.ts +6 -0
  29. package/lib/models/generated/replace-by-contents.model.d.ts +7 -0
  30. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Directive, Injectable, signal, inject, ChangeDetectorRef, HostBinding, Input, InjectionToken, Component, ChangeDetectionStrategy, Inject, ViewChild, EventEmitter, Output, HostListener, createComponent, ApplicationRef, Injector, input, computed, effect, NgModule, output } from '@angular/core';
3
- import { Subject, BehaviorSubject, distinctUntilChanged, debounceTime, filter, fromEvent, take, throttleTime, startWith, takeUntil, tap, map, catchError } from 'rxjs';
3
+ import { Subject, BehaviorSubject, distinctUntilChanged, debounceTime, filter, fromEvent, take, throttleTime, startWith, takeUntil, switchMap, from, tap, map, catchError } from 'rxjs';
4
4
  import * as i1$2 from '@angular/common/http';
5
5
  import { HttpHeaders } from '@angular/common/http';
6
6
  import { ComponentPortal } from '@angular/cdk/portal';
@@ -626,6 +626,7 @@ class PageFormatModel {
626
626
  class EditorService {
627
627
  constructor() {
628
628
  this._styles$ = new BehaviorSubject({});
629
+ this._revisionId$ = new BehaviorSubject(0);
629
630
  this._receiveTextStyle$ = new Subject();
630
631
  this._isViewOnly$ = new BehaviorSubject(false);
631
632
  this._isViewOnly = false;
@@ -719,6 +720,8 @@ class EditorService {
719
720
  this._setCommentsVisibility$ = new Subject();
720
721
  this._getCommentText$ = new Subject();
721
722
  this._replaceCommentText$ = new Subject();
723
+ this._requestContentsInsertion$ = new Subject();
724
+ this._insertContents$ = new Subject();
722
725
  this._startNewList$ = new Subject();
723
726
  this._continueNumbering$ = new Subject();
724
727
  this._setNumberingValue$ = new Subject();
@@ -732,6 +735,9 @@ class EditorService {
732
735
  get styles$() {
733
736
  return this._styles$.asObservable();
734
737
  }
738
+ get revisionId() {
739
+ return this._revisionId$.value;
740
+ }
735
741
  get receiveTextStyle$() {
736
742
  return this._receiveTextStyle$.asObservable();
737
743
  }
@@ -1024,6 +1030,12 @@ class EditorService {
1024
1030
  get replaceCommentText$() {
1025
1031
  return this._replaceCommentText$.asObservable();
1026
1032
  }
1033
+ get requestContentsInsertion$() {
1034
+ return this._requestContentsInsertion$.asObservable();
1035
+ }
1036
+ get insertContents$() {
1037
+ return this._insertContents$.asObservable();
1038
+ }
1027
1039
  get startNewList$() {
1028
1040
  return this._startNewList$.asObservable();
1029
1041
  }
@@ -1033,6 +1045,12 @@ class EditorService {
1033
1045
  get setNumberingValue$() {
1034
1046
  return this._setNumberingValue$.asObservable();
1035
1047
  }
1048
+ requestContentsInsertion(contents, from) {
1049
+ this._requestContentsInsertion$.next({ contents, from });
1050
+ }
1051
+ insertContents(contents) {
1052
+ this._insertContents$.next(contents);
1053
+ }
1036
1054
  startNewList() {
1037
1055
  this._startNewList$.next();
1038
1056
  }
@@ -1090,6 +1108,9 @@ class EditorService {
1090
1108
  }
1091
1109
  this._currentPage$.next(value);
1092
1110
  }
1111
+ setRevisionId(id) {
1112
+ this._revisionId$.next(id);
1113
+ }
1093
1114
  receiveTextStyle(component) {
1094
1115
  this._receiveTextStyle$.next(component);
1095
1116
  }
@@ -1666,6 +1687,8 @@ var CommandType;
1666
1687
  CommandType[CommandType["RemoveComment"] = 39] = "RemoveComment";
1667
1688
  CommandType[CommandType["ApplyNumberingLevels"] = 40] = "ApplyNumberingLevels";
1668
1689
  CommandType[CommandType["ApplyNewNumberingForParagraphs"] = 41] = "ApplyNewNumberingForParagraphs";
1690
+ CommandType[CommandType["InsertContents"] = 42] = "InsertContents";
1691
+ CommandType[CommandType["ReplaceByContents"] = 43] = "ReplaceByContents";
1669
1692
  })(CommandType || (CommandType = {}));
1670
1693
 
1671
1694
  class PageNumbersModel {
@@ -1824,6 +1847,112 @@ class BreakHelper {
1824
1847
  }
1825
1848
  }
1826
1849
 
1850
+ class ClipboardHandler {
1851
+ constructor(cdkClipboard) {
1852
+ this.cdkClipboard = cdkClipboard;
1853
+ this.sliceMime = 'application/x-noder-slice+json';
1854
+ this.webSliceMime = `web ${this.sliceMime}`;
1855
+ this.internalState = null;
1856
+ }
1857
+ copyEvent(event, text, slice, revisionId) {
1858
+ if (!event.clipboardData) {
1859
+ this.copyAsync(text, slice, revisionId).catch(() => { });
1860
+ return;
1861
+ }
1862
+ event.preventDefault();
1863
+ const sliceData = this.createSliceData(slice, revisionId);
1864
+ event.clipboardData.setData('text/plain', text);
1865
+ event.clipboardData.setData(this.webSliceMime, JSON.stringify(sliceData));
1866
+ this.internalState = { text, sliceData };
1867
+ this.copyAsync(text, slice, revisionId, false).catch(() => { }); // event not update navigation clipboard! Need update both!
1868
+ }
1869
+ readEvent(event) {
1870
+ if (!event.clipboardData) {
1871
+ return { text: null, sliceData: null };
1872
+ }
1873
+ event.preventDefault();
1874
+ const text = event.clipboardData.getData('text/plain');
1875
+ const sliceJson = event.clipboardData.getData(this.webSliceMime);
1876
+ const sliceData = this.getClipboardSlice(text, sliceJson);
1877
+ return { text: text || null, sliceData };
1878
+ }
1879
+ async copyAsync(text, slice, revisionId, useFallback = true) {
1880
+ const sliceData = this.createSliceData(slice, revisionId);
1881
+ try {
1882
+ const textBlob = new Blob([text], { type: 'text/plain' });
1883
+ const sliceBlob = new Blob([JSON.stringify(sliceData)], { type: this.webSliceMime });
1884
+ const clipboardItem = new ClipboardItem({
1885
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1886
+ 'text/plain': Promise.resolve(textBlob), // Promise for Safari
1887
+ [this.webSliceMime]: Promise.resolve(sliceBlob)
1888
+ });
1889
+ await navigator.clipboard.write([clipboardItem]);
1890
+ }
1891
+ catch {
1892
+ if (useFallback) {
1893
+ this.cdkClipboard.copy(text);
1894
+ }
1895
+ }
1896
+ this.internalState = { text, sliceData };
1897
+ }
1898
+ async readAsync() {
1899
+ try {
1900
+ const items = await navigator.clipboard.read();
1901
+ const item = items[0];
1902
+ if (!item) {
1903
+ return { text: null, sliceData: null };
1904
+ }
1905
+ let text = null;
1906
+ let jsonSliceData = null;
1907
+ if (item.types.includes(this.webSliceMime)) {
1908
+ const sliceBlob = await item.getType(this.webSliceMime);
1909
+ jsonSliceData = await sliceBlob.text();
1910
+ }
1911
+ if (item.types.includes('text/plain')) {
1912
+ const textBlob = await item.getType('text/plain');
1913
+ text = await textBlob.text();
1914
+ }
1915
+ const sliceData = this.getClipboardSlice(text || '', jsonSliceData || '');
1916
+ return { text, sliceData };
1917
+ }
1918
+ catch {
1919
+ return await this.readFallback();
1920
+ }
1921
+ }
1922
+ getClipboardSlice(clipboardText, clipboardSliceData) {
1923
+ if (this.internalState && this.internalState.text === clipboardText) {
1924
+ return this.internalState.sliceData;
1925
+ }
1926
+ if (!clipboardSliceData) {
1927
+ return null;
1928
+ }
1929
+ try {
1930
+ return JSON.parse(clipboardSliceData);
1931
+ }
1932
+ catch {
1933
+ return null;
1934
+ }
1935
+ }
1936
+ async readFallback() {
1937
+ try {
1938
+ const text = await navigator.clipboard.readText();
1939
+ const sliceData = this.getClipboardSlice(text, '');
1940
+ return { text, sliceData };
1941
+ }
1942
+ catch {
1943
+ return { text: null, sliceData: null };
1944
+ }
1945
+ }
1946
+ createSliceData(slice, revisionId) {
1947
+ return {
1948
+ type: 'NODER_SLICE',
1949
+ version: 1,
1950
+ source: { revisionId },
1951
+ data: slice
1952
+ };
1953
+ }
1954
+ }
1955
+
1827
1956
  const COMMENT_TYPES = new InjectionToken('COMMENT_TYPES');
1828
1957
 
1829
1958
  class OverlayService {
@@ -1957,77 +2086,7 @@ class ContentHelper {
1957
2086
  }
1958
2087
  }
1959
2088
 
1960
- const CONTEXT_MENU_HEIGHT = 210;
1961
- const CONTEXT_MENU_WIDTH = 320;
1962
- class ContextMenuComponent {
1963
- constructor(editorService, overlayService) {
1964
- this.editorService = editorService;
1965
- this.overlayService = overlayService;
1966
- }
1967
- ngOnDestroy() {
1968
- this.overlayService.close();
1969
- }
1970
- onCopy() {
1971
- this.editorService.copySelected();
1972
- this.overlayService.close();
1973
- }
1974
- onPaste() {
1975
- this.editorService.pasteFromClipboard();
1976
- this.overlayService.close();
1977
- }
1978
- onCut() {
1979
- this.editorService.cutSelected();
1980
- this.overlayService.close();
1981
- }
1982
- onStartNewList() {
1983
- this.editorService.startNewList();
1984
- this.overlayService.close();
1985
- }
1986
- onContinueNumbering() {
1987
- this.editorService.continueNumbering();
1988
- this.overlayService.close();
1989
- }
1990
- onSetNumberingValue() {
1991
- this.overlayService.close(AfterCloseOverlayActions.OpenSetNumberingValue);
1992
- }
1993
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ContextMenuComponent, deps: [{ token: EditorService }, { token: OverlayService }], target: i0.ɵɵFactoryTarget.Component }); }
1994
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: ContextMenuComponent, isStandalone: true, selector: "app-nod-context-menu", inputs: { hasNumbering: "hasNumbering", hasSelection: "hasSelection", disableContinueNumber: "disableContinueNumber" }, host: { properties: { "style.height.px": "210", "style.width.px": "320" } }, ngImport: i0, template: "<button\n mat-button\n (click)=\"onCopy()\"\n [disabled]=\"!hasSelection\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-copy\" />\n {{ 'NODER.LABEL.COPY' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onPaste()\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-paste\" />\n {{ 'NODER.LABEL.PASTE' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onCut()\"\n [disabled]=\"!hasSelection\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-cut\" />\n {{ 'NODER.LABEL.CUT' | translate }}\n</button>\n<div class=\"separator\"></div>\n<button\n mat-button\n (click)=\"onStartNewList()\"\n [disabled]=\"!hasNumbering\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-restart-numbering\" />\n {{ 'NODER.LABEL.START_NEW_LIST' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onContinueNumbering()\"\n [disabled]=\"!hasNumbering || disableContinueNumber\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-continue-numbering\" />\n {{ 'NODER.LABEL.CONTINUE_NUMBERING' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onSetNumberingValue()\"\n [disabled]=\"!hasNumbering\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-starting-value\" />\n {{ 'NODER.LABEL.SET_NUMBERING_VALUE' | translate }}\n</button>\n", styles: [":host{display:flex;padding:8px 16px;flex-direction:column;align-items:flex-start;gap:4px;border-radius:8px;box-shadow:2px 2px 8px #21212129}.separator{width:288px;height:1px}button{width:100%;justify-content:start;min-height:28px;height:28px}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i6.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1995
- }
1996
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ContextMenuComponent, decorators: [{
1997
- type: Component,
1998
- args: [{ selector: 'app-nod-context-menu', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatButtonModule, TranslateModule, MatIconModule], host: {
1999
- '[style.height.px]': `${CONTEXT_MENU_HEIGHT}`,
2000
- '[style.width.px]': `${CONTEXT_MENU_WIDTH}`
2001
- }, template: "<button\n mat-button\n (click)=\"onCopy()\"\n [disabled]=\"!hasSelection\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-copy\" />\n {{ 'NODER.LABEL.COPY' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onPaste()\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-paste\" />\n {{ 'NODER.LABEL.PASTE' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onCut()\"\n [disabled]=\"!hasSelection\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-cut\" />\n {{ 'NODER.LABEL.CUT' | translate }}\n</button>\n<div class=\"separator\"></div>\n<button\n mat-button\n (click)=\"onStartNewList()\"\n [disabled]=\"!hasNumbering\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-restart-numbering\" />\n {{ 'NODER.LABEL.START_NEW_LIST' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onContinueNumbering()\"\n [disabled]=\"!hasNumbering || disableContinueNumber\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-continue-numbering\" />\n {{ 'NODER.LABEL.CONTINUE_NUMBERING' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onSetNumberingValue()\"\n [disabled]=\"!hasNumbering\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-starting-value\" />\n {{ 'NODER.LABEL.SET_NUMBERING_VALUE' | translate }}\n</button>\n", styles: [":host{display:flex;padding:8px 16px;flex-direction:column;align-items:flex-start;gap:4px;border-radius:8px;box-shadow:2px 2px 8px #21212129}.separator{width:288px;height:1px}button{width:100%;justify-content:start;min-height:28px;height:28px}\n"] }]
2002
- }], ctorParameters: () => [{ type: EditorService }, { type: OverlayService }], propDecorators: { hasNumbering: [{
2003
- type: Input
2004
- }], hasSelection: [{
2005
- type: Input
2006
- }], disableContinueNumber: [{
2007
- type: Input
2008
- }] } });
2009
-
2010
- class CreateEdgesModel {
2011
- constructor(fields) {
2012
- if (fields) {
2013
- Object.assign(this, fields);
2014
- }
2015
- }
2016
- }
2017
-
2018
- const PARENT_TAG = 'APP-NOD-EDITOR';
2019
- const TABLE_CELL_TAG = 'APP-NOD-TABLE-CELL';
2020
- const EDGE_TAG = 'APP-NOD-EDGE';
2021
- const IMAGE_TAG = 'APP-NOD-IMAGE';
2022
- const CUSTOM_TAG = 'app-nod-custom-element';
2023
-
2024
- class CustomElementSearchResult {
2025
- constructor(init) {
2026
- Object.assign(this, init);
2027
- }
2028
- }
2029
-
2030
- class DeleteModel {
2089
+ class BreakModel {
2031
2090
  constructor(fields) {
2032
2091
  if (fields) {
2033
2092
  Object.assign(this, fields);
@@ -2035,98 +2094,24 @@ class DeleteModel {
2035
2094
  }
2036
2095
  }
2037
2096
 
2038
- class BaseHandler {
2039
- constructor() {
2040
- this.actions = {};
2041
- }
2042
- getKeyCombination(event) {
2043
- let result = event.metaKey ? 'Command-' : '';
2044
- if (event.ctrlKey) {
2045
- result = `${result}Ctrl-`;
2046
- }
2047
- if (event.altKey) {
2048
- result = `${result}Alt-`;
2049
- }
2050
- if (event.shiftKey) {
2051
- result = `${result}Shift-`;
2052
- }
2053
- return `${result}${event.code}`;
2054
- }
2055
- }
2056
-
2057
- class DocumentHandler extends BaseHandler {
2058
- constructor(editor) {
2059
- super();
2060
- this.documentKeyDown$ = fromEvent(document, 'keydown').subscribe((event) => this.onKeyDown(event));
2061
- this.contextMenu$ = fromEvent(document, 'contextmenu').subscribe(event => event.preventDefault());
2062
- this.fillActions(editor);
2063
- }
2064
- destroy() {
2065
- this.documentKeyDown$?.unsubscribe();
2066
- this.contextMenu$.unsubscribe();
2067
- }
2068
- onKeyDown(event) {
2069
- const keyCombination = this.getKeyCombination(event);
2070
- if (this.actions[keyCombination]) {
2071
- this.actions[keyCombination](event);
2072
- }
2073
- else {
2074
- return;
2075
- }
2076
- event.preventDefault();
2077
- }
2078
- fillActions(editor) {
2079
- this.actions['Ctrl-KeyP'] = () => editor.onPrint();
2080
- this.actions['Ctrl-KeyO'] = (event) => editor.onHotKeyDown(event);
2081
- }
2082
- }
2083
-
2084
- class DragAndDrop {
2085
- constructor(editorContainer) {
2086
- this.editorContainer = editorContainer;
2087
- this.onMove$ = new Subject();
2088
- this.onDrop$ = new Subject();
2089
- }
2090
- onStart(session, range) {
2091
- if (this.isDragging) {
2092
- return;
2093
- }
2094
- this.isDragging = true;
2095
- this.editorContainer.classList.add('drag-and-drop-progress');
2096
- this.sourceSession = session;
2097
- this.sourceRange = range;
2098
- this.initListeners();
2097
+ class ContentOperationsHelper {
2098
+ static removeContent(content, startIndex, count) {
2099
+ return `${content.slice(0, startIndex)}${content.slice(startIndex + count, content.length)}`;
2099
2100
  }
2100
- destroyListeners() {
2101
- this.mouseMove$?.unsubscribe();
2102
- this.mouseUp$?.unsubscribe();
2101
+ static sliceContent(content, startIndex, count) {
2102
+ return content.slice(startIndex, startIndex + count);
2103
2103
  }
2104
- onEnd() {
2105
- this.destroyListeners();
2106
- if (!this.isDragging) {
2107
- return;
2108
- }
2109
- this.isDragging = false;
2110
- this.editorContainer.classList.remove('drag-and-drop-progress');
2111
- this.onDrop$.next({ sourceSession: this.sourceSession, sourceRange: this.sourceRange });
2104
+ static insertContent(content, text, index) {
2105
+ const before = content.slice(0, index);
2106
+ const after = content.slice(index, content.length);
2107
+ return `${before}${text}${after}`;
2112
2108
  }
2113
- initListeners() {
2114
- this.destroyListeners();
2115
- this.mouseMove$ = fromEvent(document, 'mousemove')
2116
- .pipe(throttleTime(20))
2117
- .subscribe(event => this.onMove$.next(event));
2118
- this.mouseUp$ = fromEvent(document, 'mouseup')
2119
- .pipe(take(1))
2120
- .subscribe(() => this.onEnd());
2109
+ static replaceContent(content, startIndex, endIndex, text) {
2110
+ const reduced = this.removeContent(content, startIndex, endIndex - startIndex + 1);
2111
+ return this.insertContent(reduced, text, startIndex);
2121
2112
  }
2122
2113
  }
2123
2114
 
2124
- var EdgeType;
2125
- (function (EdgeType) {
2126
- EdgeType[EdgeType["Header"] = 0] = "Header";
2127
- EdgeType[EdgeType["Footer"] = 1] = "Footer";
2128
- })(EdgeType || (EdgeType = {}));
2129
-
2130
2115
  class ElementModel {
2131
2116
  constructor(fields) {
2132
2117
  if (fields) {
@@ -2162,58 +2147,504 @@ class FormatHelper {
2162
2147
  }
2163
2148
  }
2164
2149
 
2165
- class GrammarPopupComponent {
2166
- constructor(editorService, overlayService) {
2167
- this.editorService = editorService;
2168
- this.overlayService = overlayService;
2169
- }
2170
- onSuggestionClick(index) {
2171
- this.editorService.applyGrammarSuggestion(this.error, index, this.paragraphIndex);
2172
- this.overlayService.close();
2173
- }
2174
- onIgnoreClick() {
2175
- this.editorService.ignoreGrammarSuggestion(this.error);
2176
- this.overlayService.close();
2150
+ class BordersStyleModel {
2151
+ constructor(fields) {
2152
+ if (fields) {
2153
+ Object.assign(this, fields);
2154
+ }
2177
2155
  }
2178
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: GrammarPopupComponent, deps: [{ token: EditorService }, { token: OverlayService }], target: i0.ɵɵFactoryTarget.Component }); }
2179
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: GrammarPopupComponent, isStandalone: true, selector: "app-nod-grammar-popup", inputs: { error: "error", paragraphIndex: "paragraphIndex" }, ngImport: i0, template: "<span class=\"message\">{{ error.message }}</span>\n<div class=\"options\">\n @for (suggestion of error.replacements; track i; let i = $index) {\n <span\n class=\"suggestion\"\n (click)=\"onSuggestionClick(i)\">\n {{ suggestion }}\n </span>\n }\n</div>\n<button\n mat-button\n class=\"ignore\"\n (click)=\"onIgnoreClick()\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-ignore\"></mat-icon>\n <span>\n {{ 'NODER.LABEL.IGNORE' | translate }}\n </span>\n</button>\n", styles: [":host{border-radius:8px;display:flex;flex-direction:column;padding:8px;max-width:500px;gap:5px}.message{flex:1;display:flex;align-items:center;justify-content:center;text-align:center;font-size:12px}.options{display:flex;flex-flow:column wrap;justify-content:center;gap:5px;padding:10px 0;border-bottom-width:1px;border-bottom-style:solid}.suggestion{font-weight:600;font-size:14px;cursor:pointer;text-decoration:underline;padding:3px 8px}.ignore{margin-left:auto;font-size:12px;letter-spacing:0;cursor:pointer;height:32px}.ignore mat-icon{margin-right:4px}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i6.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2180
2156
  }
2181
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: GrammarPopupComponent, decorators: [{
2182
- type: Component,
2183
- args: [{ selector: 'app-nod-grammar-popup', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatButtonModule, MatIconModule, TranslateModule], standalone: true, template: "<span class=\"message\">{{ error.message }}</span>\n<div class=\"options\">\n @for (suggestion of error.replacements; track i; let i = $index) {\n <span\n class=\"suggestion\"\n (click)=\"onSuggestionClick(i)\">\n {{ suggestion }}\n </span>\n }\n</div>\n<button\n mat-button\n class=\"ignore\"\n (click)=\"onIgnoreClick()\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-ignore\"></mat-icon>\n <span>\n {{ 'NODER.LABEL.IGNORE' | translate }}\n </span>\n</button>\n", styles: [":host{border-radius:8px;display:flex;flex-direction:column;padding:8px;max-width:500px;gap:5px}.message{flex:1;display:flex;align-items:center;justify-content:center;text-align:center;font-size:12px}.options{display:flex;flex-flow:column wrap;justify-content:center;gap:5px;padding:10px 0;border-bottom-width:1px;border-bottom-style:solid}.suggestion{font-weight:600;font-size:14px;cursor:pointer;text-decoration:underline;padding:3px 8px}.ignore{margin-left:auto;font-size:12px;letter-spacing:0;cursor:pointer;height:32px}.ignore mat-icon{margin-right:4px}\n"] }]
2184
- }], ctorParameters: () => [{ type: EditorService }, { type: OverlayService }], propDecorators: { error: [{
2185
- type: Input
2186
- }], paragraphIndex: [{
2187
- type: Input
2188
- }] } });
2189
2157
 
2190
- class ImageDataModel {
2158
+ class ImageModel {
2191
2159
  constructor(fields) {
2192
2160
  if (fields) {
2161
+ if (fields.border) {
2162
+ fields.border = new BordersStyleModel(fields.border);
2163
+ }
2193
2164
  Object.assign(this, fields);
2194
2165
  }
2195
2166
  }
2196
2167
  }
2197
2168
 
2198
- class ImageHelper {
2199
- static getImageWithAllowedSize(imageData, maxWidth) {
2200
- if (imageData.width <= maxWidth) {
2201
- return imageData;
2202
- }
2203
- const aspectRatio = imageData.width / imageData.height;
2204
- const height = maxWidth / aspectRatio;
2205
- return new ImageDataModel({ width: Math.round(maxWidth), height: Math.round(height), content: imageData.content });
2169
+ class IndexedElementHelper {
2170
+ static sliceSection(elements, startIndex, endIndex) {
2171
+ return elements.filter(x => x.insertIndex >= startIndex && x.insertIndex <= endIndex);
2172
+ }
2173
+ static shiftIndexes(elements, offset) {
2174
+ for (const element of elements) {
2175
+ element.insertIndex += offset;
2176
+ }
2177
+ }
2178
+ }
2179
+
2180
+ class LinkModel {
2181
+ constructor(fields) {
2182
+ if (fields) {
2183
+ Object.assign(this, fields);
2184
+ }
2185
+ }
2186
+ }
2187
+
2188
+ class LinkHelper {
2189
+ static sliceSection(links, start, end) {
2190
+ return links.map(link => LinkHelper.getPartialLink(link, start, end)).filter(x => x !== null);
2191
+ }
2192
+ static shiftIndexes(links, offset) {
2193
+ for (const link of links) {
2194
+ link.startIndex += offset;
2195
+ link.endIndex += offset;
2196
+ }
2197
+ }
2198
+ static sliceFormats(links, startIndex, endIndex) {
2199
+ const result = [];
2200
+ for (const link of links) {
2201
+ const absoluteFormats = link.formats.map(x => new FormatModel({ ...x, startIndex: x.startIndex + link.startIndex, endIndex: x.endIndex + link.startIndex }));
2202
+ const slicedLinkFormats = FormatHelper.sliceSection(absoluteFormats, startIndex, endIndex);
2203
+ result.push(...slicedLinkFormats);
2204
+ }
2205
+ return result;
2206
+ }
2207
+ static getPartialLink(link, selectionStart, selectionEnd) {
2208
+ if (link.endIndex < selectionStart || link.startIndex > selectionEnd) {
2209
+ return null;
2210
+ }
2211
+ const newStart = Math.max(link.startIndex, selectionStart);
2212
+ const newEnd = Math.min(link.endIndex, selectionEnd);
2213
+ const formats = link.formats
2214
+ .map(format => {
2215
+ const formatStart = link.startIndex + format.startIndex;
2216
+ const formatEnd = link.startIndex + format.endIndex;
2217
+ if (formatEnd < newStart || formatStart > newEnd) {
2218
+ return null;
2219
+ }
2220
+ const newFormatStart = Math.max(formatStart, newStart) - newStart;
2221
+ const newFormatEnd = Math.min(formatEnd, newEnd) - newStart;
2222
+ const textStyle = new TextStyleModel(format.textStyle);
2223
+ return new FormatModel({ startIndex: newFormatStart, endIndex: newFormatEnd, textStyle });
2224
+ })
2225
+ .filter(x => x !== null);
2226
+ return new LinkModel({ ...link, startIndex: newStart, endIndex: newEnd, formats });
2227
+ }
2228
+ }
2229
+
2230
+ class PageFormatHelper {
2231
+ static sliceSection(content, start, end) {
2232
+ if (content instanceof DocxModel) {
2233
+ return content.pageFormats.filter(x => x.insertIndex !== 0 && x.insertIndex >= start && x.insertIndex <= end);
2234
+ }
2235
+ return [];
2236
+ }
2237
+ static shiftIndexes(pagesFormats, offset) {
2238
+ for (const pageFormat of pagesFormats) {
2239
+ if (pageFormat.insertIndex === 0) {
2240
+ return;
2241
+ }
2242
+ pageFormat.insertIndex += offset;
2243
+ }
2244
+ }
2245
+ }
2246
+
2247
+ class ParagraphModel {
2248
+ constructor(fields) {
2249
+ if (fields) {
2250
+ if (fields.paragraphStyle) {
2251
+ fields.paragraphStyle = new ParagraphStyleModel(fields.paragraphStyle);
2252
+ }
2253
+ Object.assign(this, fields);
2254
+ }
2255
+ }
2256
+ }
2257
+
2258
+ class RangeElementHelper {
2259
+ static removeContent(elements, startIndex, endIndex) {
2260
+ const length = endIndex - startIndex + 1;
2261
+ for (let i = elements.length - 1; i >= 0; i--) {
2262
+ const element = elements[i];
2263
+ if (element.endIndex < startIndex) {
2264
+ continue;
2265
+ }
2266
+ if (element.startIndex < startIndex) {
2267
+ if (element.endIndex > endIndex) {
2268
+ element.endIndex -= length;
2269
+ }
2270
+ else {
2271
+ element.endIndex = startIndex - 1;
2272
+ }
2273
+ continue;
2274
+ }
2275
+ if (element.startIndex >= startIndex && element.startIndex <= endIndex) {
2276
+ if (element.endIndex <= endIndex) {
2277
+ elements.splice(i, 1);
2278
+ continue;
2279
+ }
2280
+ element.startIndex -= element.startIndex - startIndex;
2281
+ element.endIndex -= endIndex - element.startIndex;
2282
+ continue;
2283
+ }
2284
+ element.startIndex -= length;
2285
+ element.endIndex -= length;
2286
+ }
2287
+ }
2288
+ static insertContent(elements, index, length) {
2289
+ for (const element of elements) {
2290
+ if (element.startIndex >= index) {
2291
+ element.startIndex += length;
2292
+ element.endIndex += length;
2293
+ }
2294
+ else if (element.endIndex > index) {
2295
+ element.endIndex += length;
2296
+ }
2297
+ }
2298
+ }
2299
+ static insertRelative(elements, insertIndex, insertLength, insertElements) {
2300
+ this.insertContent(elements, insertIndex, insertLength);
2301
+ if (insertElements.length === 0) {
2302
+ return;
2303
+ }
2304
+ for (const element of insertElements) {
2305
+ element.startIndex += insertIndex;
2306
+ element.endIndex += insertIndex;
2307
+ }
2308
+ const targetIndex = elements.findIndex(x => x.startIndex === insertIndex);
2309
+ if (targetIndex < 0) {
2310
+ elements.push(...insertElements);
2311
+ }
2312
+ else {
2313
+ elements.splice(targetIndex, 0, ...insertElements);
2314
+ }
2315
+ }
2316
+ static restore(elements, index, contentLength, newElements) {
2317
+ RangeElementHelper.insertContent(elements, index, contentLength);
2318
+ const nextElement = elements.find(x => x.startIndex >= index);
2319
+ const indexInElements = nextElement !== undefined ? elements.indexOf(nextElement) : elements.length;
2320
+ elements.splice(indexInElements, 0, ...newElements);
2321
+ }
2322
+ static replaceContent(elements, startIndex, endIndex, length) {
2323
+ RangeElementHelper.removeContent(elements, startIndex, endIndex);
2324
+ RangeElementHelper.insertContent(elements, startIndex, length);
2325
+ }
2326
+ static shiftIndexes(elements, offset) {
2327
+ for (const element of elements) {
2328
+ element.startIndex += offset;
2329
+ element.endIndex += offset;
2330
+ }
2331
+ }
2332
+ static sliceSection(elements, startIndex, endIndex) {
2333
+ return elements.filter(x => x.startIndex >= startIndex && x.endIndex <= endIndex);
2334
+ }
2335
+ }
2336
+
2337
+ class RestoreModel {
2338
+ constructor(fields) {
2339
+ if (fields) {
2340
+ Object.assign(this, fields);
2341
+ }
2342
+ }
2343
+ }
2344
+
2345
+ class ContentsModel {
2346
+ constructor(fields) {
2347
+ if (fields) {
2348
+ Object.assign(this, fields);
2349
+ }
2350
+ }
2351
+ }
2352
+
2353
+ class TableModel {
2354
+ constructor(fields) {
2355
+ if (fields) {
2356
+ if (fields.margins) {
2357
+ fields.margins = new MarginsModel(fields.margins);
2358
+ }
2359
+ Object.assign(this, fields);
2360
+ }
2361
+ }
2362
+ }
2363
+
2364
+ class TabModel {
2365
+ constructor(fields) {
2366
+ if (fields) {
2367
+ Object.assign(this, fields);
2368
+ }
2369
+ }
2370
+ }
2371
+
2372
+ class ContentsOperationsHelper {
2373
+ static GetRestoreFromSlice(contents, startIndex, count) {
2374
+ const text = ContentOperationsHelper.sliceContent(contents.content, startIndex, count);
2375
+ const endIndex = startIndex + count - 1;
2376
+ const formats = FormatHelper.sliceSection(contents.formats, startIndex, endIndex);
2377
+ const paragraphs = IndexedElementHelper.sliceSection(contents.paragraphs, startIndex, endIndex).map(x => new ParagraphModel(x));
2378
+ const images = IndexedElementHelper.sliceSection(contents.images, startIndex, endIndex).map(x => new ImageModel(x));
2379
+ const tables = IndexedElementHelper.sliceSection(contents.tables, startIndex, endIndex).map(x => new TableModel(x));
2380
+ const elements = IndexedElementHelper.sliceSection(contents.elements, startIndex, endIndex).map(x => new ElementModel(x));
2381
+ const comments = RangeElementHelper.sliceSection(contents.comments, startIndex, endIndex);
2382
+ const breaks = IndexedElementHelper.sliceSection(contents.breaks, startIndex, endIndex).map(x => new BreakModel(x));
2383
+ const tabs = IndexedElementHelper.sliceSection(contents.tabs, startIndex, endIndex).map(x => new TabModel(x));
2384
+ const links = LinkHelper.sliceSection(contents.links, startIndex, endIndex).map(x => new LinkModel(x));
2385
+ const pageFormats = PageFormatHelper.sliceSection(contents, startIndex, endIndex).map(x => new PageFormatModel(x));
2386
+ return new RestoreModel({
2387
+ insertIndex: startIndex,
2388
+ text,
2389
+ formats,
2390
+ paragraphs,
2391
+ images,
2392
+ tables,
2393
+ elements,
2394
+ breaks,
2395
+ tabs,
2396
+ links,
2397
+ pageFormats,
2398
+ comments
2399
+ });
2400
+ }
2401
+ static GetRelativeContentSlice(contents, startIndex, count) {
2402
+ const content = ContentOperationsHelper.sliceContent(contents.content, startIndex, count);
2403
+ const endIndex = startIndex + count - 1;
2404
+ const formats = FormatHelper.sliceSection(contents.formats, startIndex, endIndex).map(x => new FormatModel(x));
2405
+ const paragraphs = IndexedElementHelper.sliceSection(contents.paragraphs, startIndex, endIndex).map(x => new ParagraphModel(x));
2406
+ const images = IndexedElementHelper.sliceSection(contents.images, startIndex, endIndex).map(x => new ImageModel(x));
2407
+ const tables = IndexedElementHelper.sliceSection(contents.tables, startIndex, endIndex).map(x => new TableModel(x));
2408
+ const elements = IndexedElementHelper.sliceSection(contents.elements, startIndex, endIndex).map(x => new ElementModel(x));
2409
+ const comments = RangeElementHelper.sliceSection(contents.comments, startIndex, endIndex).map(x => new CommentModel(x));
2410
+ const breaks = IndexedElementHelper.sliceSection(contents.breaks, startIndex, endIndex).map(x => new BreakModel(x));
2411
+ const tabs = IndexedElementHelper.sliceSection(contents.tabs, startIndex, endIndex).map(x => new TabModel(x));
2412
+ const links = LinkHelper.sliceSection(contents.links, startIndex, endIndex).map(x => new LinkModel(x));
2413
+ FormatHelper.shiftIndexes(formats, -startIndex);
2414
+ IndexedElementHelper.shiftIndexes(paragraphs, -startIndex);
2415
+ IndexedElementHelper.shiftIndexes(images, -startIndex);
2416
+ IndexedElementHelper.shiftIndexes(tables, -startIndex);
2417
+ IndexedElementHelper.shiftIndexes(elements, -startIndex);
2418
+ IndexedElementHelper.shiftIndexes(breaks, -startIndex);
2419
+ IndexedElementHelper.shiftIndexes(tabs, -startIndex);
2420
+ RangeElementHelper.shiftIndexes(comments, -startIndex);
2421
+ LinkHelper.shiftIndexes(links, -startIndex);
2422
+ return new ContentsModel({
2423
+ content,
2424
+ formats,
2425
+ paragraphs,
2426
+ images,
2427
+ tables,
2428
+ elements,
2429
+ breaks,
2430
+ tabs,
2431
+ links,
2432
+ comments
2433
+ });
2434
+ }
2435
+ }
2436
+
2437
+ const CONTEXT_MENU_HEIGHT = 210;
2438
+ const CONTEXT_MENU_WIDTH = 320;
2439
+ class ContextMenuComponent {
2440
+ constructor(editorService, overlayService) {
2441
+ this.editorService = editorService;
2442
+ this.overlayService = overlayService;
2443
+ }
2444
+ ngOnDestroy() {
2445
+ this.overlayService.close();
2446
+ }
2447
+ onCopy() {
2448
+ this.editorService.copySelected();
2449
+ this.overlayService.close();
2450
+ }
2451
+ onPaste() {
2452
+ this.editorService.pasteFromClipboard();
2453
+ this.overlayService.close();
2454
+ }
2455
+ onCut() {
2456
+ this.editorService.cutSelected();
2457
+ this.overlayService.close();
2458
+ }
2459
+ onStartNewList() {
2460
+ this.editorService.startNewList();
2461
+ this.overlayService.close();
2462
+ }
2463
+ onContinueNumbering() {
2464
+ this.editorService.continueNumbering();
2465
+ this.overlayService.close();
2466
+ }
2467
+ onSetNumberingValue() {
2468
+ this.overlayService.close(AfterCloseOverlayActions.OpenSetNumberingValue);
2469
+ }
2470
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ContextMenuComponent, deps: [{ token: EditorService }, { token: OverlayService }], target: i0.ɵɵFactoryTarget.Component }); }
2471
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: ContextMenuComponent, isStandalone: true, selector: "app-nod-context-menu", inputs: { hasNumbering: "hasNumbering", hasSelection: "hasSelection", disableContinueNumber: "disableContinueNumber" }, host: { properties: { "style.height.px": "210", "style.width.px": "320" } }, ngImport: i0, template: "<button\n mat-button\n (click)=\"onCopy()\"\n [disabled]=\"!hasSelection\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-copy\" />\n {{ 'NODER.LABEL.COPY' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onPaste()\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-paste\" />\n {{ 'NODER.LABEL.PASTE' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onCut()\"\n [disabled]=\"!hasSelection\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-cut\" />\n {{ 'NODER.LABEL.CUT' | translate }}\n</button>\n<div class=\"separator\"></div>\n<button\n mat-button\n (click)=\"onStartNewList()\"\n [disabled]=\"!hasNumbering\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-restart-numbering\" />\n {{ 'NODER.LABEL.START_NEW_LIST' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onContinueNumbering()\"\n [disabled]=\"!hasNumbering || disableContinueNumber\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-continue-numbering\" />\n {{ 'NODER.LABEL.CONTINUE_NUMBERING' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onSetNumberingValue()\"\n [disabled]=\"!hasNumbering\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-starting-value\" />\n {{ 'NODER.LABEL.SET_NUMBERING_VALUE' | translate }}\n</button>\n", styles: [":host{display:flex;padding:8px 16px;flex-direction:column;align-items:flex-start;gap:4px;border-radius:8px;box-shadow:2px 2px 8px #21212129}.separator{width:288px;height:1px}button{width:100%;justify-content:start;min-height:28px;height:28px}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i6.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2472
+ }
2473
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: ContextMenuComponent, decorators: [{
2474
+ type: Component,
2475
+ args: [{ selector: 'app-nod-context-menu', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatButtonModule, TranslateModule, MatIconModule], host: {
2476
+ '[style.height.px]': `${CONTEXT_MENU_HEIGHT}`,
2477
+ '[style.width.px]': `${CONTEXT_MENU_WIDTH}`
2478
+ }, template: "<button\n mat-button\n (click)=\"onCopy()\"\n [disabled]=\"!hasSelection\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-copy\" />\n {{ 'NODER.LABEL.COPY' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onPaste()\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-paste\" />\n {{ 'NODER.LABEL.PASTE' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onCut()\"\n [disabled]=\"!hasSelection\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-cut\" />\n {{ 'NODER.LABEL.CUT' | translate }}\n</button>\n<div class=\"separator\"></div>\n<button\n mat-button\n (click)=\"onStartNewList()\"\n [disabled]=\"!hasNumbering\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-restart-numbering\" />\n {{ 'NODER.LABEL.START_NEW_LIST' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onContinueNumbering()\"\n [disabled]=\"!hasNumbering || disableContinueNumber\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-continue-numbering\" />\n {{ 'NODER.LABEL.CONTINUE_NUMBERING' | translate }}\n</button>\n<button\n mat-button\n (click)=\"onSetNumberingValue()\"\n [disabled]=\"!hasNumbering\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-starting-value\" />\n {{ 'NODER.LABEL.SET_NUMBERING_VALUE' | translate }}\n</button>\n", styles: [":host{display:flex;padding:8px 16px;flex-direction:column;align-items:flex-start;gap:4px;border-radius:8px;box-shadow:2px 2px 8px #21212129}.separator{width:288px;height:1px}button{width:100%;justify-content:start;min-height:28px;height:28px}\n"] }]
2479
+ }], ctorParameters: () => [{ type: EditorService }, { type: OverlayService }], propDecorators: { hasNumbering: [{
2480
+ type: Input
2481
+ }], hasSelection: [{
2482
+ type: Input
2483
+ }], disableContinueNumber: [{
2484
+ type: Input
2485
+ }] } });
2486
+
2487
+ class CreateEdgesModel {
2488
+ constructor(fields) {
2489
+ if (fields) {
2490
+ Object.assign(this, fields);
2491
+ }
2492
+ }
2493
+ }
2494
+
2495
+ const PARENT_TAG = 'APP-NOD-EDITOR';
2496
+ const TABLE_CELL_TAG = 'APP-NOD-TABLE-CELL';
2497
+ const EDGE_TAG = 'APP-NOD-EDGE';
2498
+ const IMAGE_TAG = 'APP-NOD-IMAGE';
2499
+ const CUSTOM_TAG = 'app-nod-custom-element';
2500
+
2501
+ class CustomElementSearchResult {
2502
+ constructor(init) {
2503
+ Object.assign(this, init);
2504
+ }
2505
+ }
2506
+
2507
+ class DeleteModel {
2508
+ constructor(fields) {
2509
+ if (fields) {
2510
+ Object.assign(this, fields);
2511
+ }
2512
+ }
2513
+ }
2514
+
2515
+ class BaseHandler {
2516
+ constructor() {
2517
+ this.actions = {};
2518
+ }
2519
+ getKeyCombination(event) {
2520
+ let result = event.metaKey ? 'Command-' : '';
2521
+ if (event.ctrlKey) {
2522
+ result = `${result}Ctrl-`;
2523
+ }
2524
+ if (event.altKey) {
2525
+ result = `${result}Alt-`;
2526
+ }
2527
+ if (event.shiftKey) {
2528
+ result = `${result}Shift-`;
2529
+ }
2530
+ return `${result}${event.code}`;
2531
+ }
2532
+ }
2533
+
2534
+ class DocumentHandler extends BaseHandler {
2535
+ constructor(editor) {
2536
+ super();
2537
+ this.documentKeyDown$ = fromEvent(document, 'keydown').subscribe((event) => this.onKeyDown(event));
2538
+ this.contextMenu$ = fromEvent(document, 'contextmenu').subscribe(event => event.preventDefault());
2539
+ this.fillActions(editor);
2540
+ }
2541
+ destroy() {
2542
+ this.documentKeyDown$?.unsubscribe();
2543
+ this.contextMenu$.unsubscribe();
2544
+ }
2545
+ onKeyDown(event) {
2546
+ const keyCombination = this.getKeyCombination(event);
2547
+ if (this.actions[keyCombination]) {
2548
+ this.actions[keyCombination](event);
2549
+ }
2550
+ else {
2551
+ return;
2552
+ }
2553
+ event.preventDefault();
2554
+ }
2555
+ fillActions(editor) {
2556
+ this.actions['Ctrl-KeyP'] = () => editor.onPrint();
2557
+ this.actions['Ctrl-KeyO'] = (event) => editor.onHotKeyDown(event);
2558
+ }
2559
+ }
2560
+
2561
+ class DragAndDrop {
2562
+ constructor(editorContainer) {
2563
+ this.editorContainer = editorContainer;
2564
+ this.onMove$ = new Subject();
2565
+ this.onDrop$ = new Subject();
2566
+ }
2567
+ onStart(session, range) {
2568
+ if (this.isDragging) {
2569
+ return;
2570
+ }
2571
+ this.isDragging = true;
2572
+ this.editorContainer.classList.add('drag-and-drop-progress');
2573
+ this.sourceSession = session;
2574
+ this.sourceRange = range;
2575
+ this.initListeners();
2576
+ }
2577
+ destroyListeners() {
2578
+ this.mouseMove$?.unsubscribe();
2579
+ this.mouseUp$?.unsubscribe();
2580
+ }
2581
+ onEnd() {
2582
+ this.destroyListeners();
2583
+ if (!this.isDragging) {
2584
+ return;
2585
+ }
2586
+ this.isDragging = false;
2587
+ this.editorContainer.classList.remove('drag-and-drop-progress');
2588
+ this.onDrop$.next({ sourceSession: this.sourceSession, sourceRange: this.sourceRange });
2589
+ }
2590
+ initListeners() {
2591
+ this.destroyListeners();
2592
+ this.mouseMove$ = fromEvent(document, 'mousemove')
2593
+ .pipe(throttleTime(20))
2594
+ .subscribe(event => this.onMove$.next(event));
2595
+ this.mouseUp$ = fromEvent(document, 'mouseup')
2596
+ .pipe(take(1))
2597
+ .subscribe(() => this.onEnd());
2598
+ }
2599
+ }
2600
+
2601
+ var EdgeType;
2602
+ (function (EdgeType) {
2603
+ EdgeType[EdgeType["Header"] = 0] = "Header";
2604
+ EdgeType[EdgeType["Footer"] = 1] = "Footer";
2605
+ })(EdgeType || (EdgeType = {}));
2606
+
2607
+ class GrammarPopupComponent {
2608
+ constructor(editorService, overlayService) {
2609
+ this.editorService = editorService;
2610
+ this.overlayService = overlayService;
2611
+ }
2612
+ onSuggestionClick(index) {
2613
+ this.editorService.applyGrammarSuggestion(this.error, index, this.paragraphIndex);
2614
+ this.overlayService.close();
2615
+ }
2616
+ onIgnoreClick() {
2617
+ this.editorService.ignoreGrammarSuggestion(this.error);
2618
+ this.overlayService.close();
2206
2619
  }
2620
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: GrammarPopupComponent, deps: [{ token: EditorService }, { token: OverlayService }], target: i0.ɵɵFactoryTarget.Component }); }
2621
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: GrammarPopupComponent, isStandalone: true, selector: "app-nod-grammar-popup", inputs: { error: "error", paragraphIndex: "paragraphIndex" }, ngImport: i0, template: "<span class=\"message\">{{ error.message }}</span>\n<div class=\"options\">\n @for (suggestion of error.replacements; track i; let i = $index) {\n <span\n class=\"suggestion\"\n (click)=\"onSuggestionClick(i)\">\n {{ suggestion }}\n </span>\n }\n</div>\n<button\n mat-button\n class=\"ignore\"\n (click)=\"onIgnoreClick()\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-ignore\"></mat-icon>\n <span>\n {{ 'NODER.LABEL.IGNORE' | translate }}\n </span>\n</button>\n", styles: [":host{border-radius:8px;display:flex;flex-direction:column;padding:8px;max-width:500px;gap:5px}.message{flex:1;display:flex;align-items:center;justify-content:center;text-align:center;font-size:12px}.options{display:flex;flex-flow:column wrap;justify-content:center;gap:5px;padding:10px 0;border-bottom-width:1px;border-bottom-style:solid}.suggestion{font-weight:600;font-size:14px;cursor:pointer;text-decoration:underline;padding:3px 8px}.ignore{margin-left:auto;font-size:12px;letter-spacing:0;cursor:pointer;height:32px}.ignore mat-icon{margin-right:4px}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i6.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2207
2622
  }
2623
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: GrammarPopupComponent, decorators: [{
2624
+ type: Component,
2625
+ args: [{ selector: 'app-nod-grammar-popup', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatButtonModule, MatIconModule, TranslateModule], standalone: true, template: "<span class=\"message\">{{ error.message }}</span>\n<div class=\"options\">\n @for (suggestion of error.replacements; track i; let i = $index) {\n <span\n class=\"suggestion\"\n (click)=\"onSuggestionClick(i)\">\n {{ suggestion }}\n </span>\n }\n</div>\n<button\n mat-button\n class=\"ignore\"\n (click)=\"onIgnoreClick()\">\n <mat-icon\n fontSet=\"noder-icon\"\n fontIcon=\"icon-ignore\"></mat-icon>\n <span>\n {{ 'NODER.LABEL.IGNORE' | translate }}\n </span>\n</button>\n", styles: [":host{border-radius:8px;display:flex;flex-direction:column;padding:8px;max-width:500px;gap:5px}.message{flex:1;display:flex;align-items:center;justify-content:center;text-align:center;font-size:12px}.options{display:flex;flex-flow:column wrap;justify-content:center;gap:5px;padding:10px 0;border-bottom-width:1px;border-bottom-style:solid}.suggestion{font-weight:600;font-size:14px;cursor:pointer;text-decoration:underline;padding:3px 8px}.ignore{margin-left:auto;font-size:12px;letter-spacing:0;cursor:pointer;height:32px}.ignore mat-icon{margin-right:4px}\n"] }]
2626
+ }], ctorParameters: () => [{ type: EditorService }, { type: OverlayService }], propDecorators: { error: [{
2627
+ type: Input
2628
+ }], paragraphIndex: [{
2629
+ type: Input
2630
+ }] } });
2208
2631
 
2209
- class IndexedElementHelper {
2210
- static sliceSection(elements, startIndex, endIndex) {
2211
- return elements.filter(x => x.insertIndex >= startIndex && x.insertIndex <= endIndex);
2632
+ class ImageDataModel {
2633
+ constructor(fields) {
2634
+ if (fields) {
2635
+ Object.assign(this, fields);
2636
+ }
2212
2637
  }
2213
- static shiftIndexes(elements, offset) {
2214
- for (const element of elements) {
2215
- element.insertIndex += offset;
2638
+ }
2639
+
2640
+ class ImageHelper {
2641
+ static getImageWithAllowedSize(imageData, maxWidth) {
2642
+ if (imageData.width <= maxWidth) {
2643
+ return imageData;
2216
2644
  }
2645
+ const aspectRatio = imageData.width / imageData.height;
2646
+ const height = maxWidth / aspectRatio;
2647
+ return new ImageDataModel({ width: Math.round(maxWidth), height: Math.round(height), content: imageData.content });
2217
2648
  }
2218
2649
  }
2219
2650
 
@@ -2373,6 +2804,17 @@ class InsertBreakModel {
2373
2804
  }
2374
2805
  }
2375
2806
 
2807
+ class InsertContentsModel {
2808
+ constructor(fields) {
2809
+ if (fields) {
2810
+ if (fields.contents) {
2811
+ fields.contents = new ContentsModel(fields.contents);
2812
+ }
2813
+ Object.assign(this, fields);
2814
+ }
2815
+ }
2816
+ }
2817
+
2376
2818
  class InsertElementModel {
2377
2819
  constructor(fields) {
2378
2820
  if (fields) {
@@ -2476,56 +2918,6 @@ class InsertTextModel {
2476
2918
  }
2477
2919
  }
2478
2920
 
2479
- class LinkModel {
2480
- constructor(fields) {
2481
- if (fields) {
2482
- Object.assign(this, fields);
2483
- }
2484
- }
2485
- }
2486
-
2487
- class LinkHelper {
2488
- static sliceSection(links, start, end) {
2489
- return links.map(link => LinkHelper.getPartialLink(link, start, end)).filter(x => x !== null);
2490
- }
2491
- static shiftIndexes(links, offset) {
2492
- for (const link of links) {
2493
- link.startIndex += offset;
2494
- link.endIndex += offset;
2495
- }
2496
- }
2497
- static sliceFormats(links, startIndex, endIndex) {
2498
- const result = [];
2499
- for (const link of links) {
2500
- const absoluteFormats = link.formats.map(x => new FormatModel({ ...x, startIndex: x.startIndex + link.startIndex, endIndex: x.endIndex + link.startIndex }));
2501
- const slicedLinkFormats = FormatHelper.sliceSection(absoluteFormats, startIndex, endIndex);
2502
- result.push(...slicedLinkFormats);
2503
- }
2504
- return result;
2505
- }
2506
- static getPartialLink(link, selectionStart, selectionEnd) {
2507
- if (link.endIndex < selectionStart || link.startIndex > selectionEnd) {
2508
- return null;
2509
- }
2510
- const newStart = Math.max(link.startIndex, selectionStart);
2511
- const newEnd = Math.min(link.endIndex, selectionEnd);
2512
- const formats = link.formats
2513
- .map(format => {
2514
- const formatStart = link.startIndex + format.startIndex;
2515
- const formatEnd = link.startIndex + format.endIndex;
2516
- if (formatEnd < newStart || formatStart > newEnd) {
2517
- return null;
2518
- }
2519
- const newFormatStart = Math.max(formatStart, newStart) - newStart;
2520
- const newFormatEnd = Math.min(formatEnd, newEnd) - newStart;
2521
- const textStyle = new TextStyleModel(format.textStyle);
2522
- return new FormatModel({ startIndex: newFormatStart, endIndex: newFormatEnd, textStyle });
2523
- })
2524
- .filter(x => x !== null);
2525
- return new LinkModel({ ...link, startIndex: newStart, endIndex: newEnd, formats });
2526
- }
2527
- }
2528
-
2529
2921
  var MouseButton;
2530
2922
  (function (MouseButton) {
2531
2923
  MouseButton[MouseButton["Left"] = 0] = "Left";
@@ -2658,14 +3050,6 @@ class RemoveTableRowsModel {
2658
3050
  }
2659
3051
  }
2660
3052
 
2661
- class RestoreModel {
2662
- constructor(fields) {
2663
- if (fields) {
2664
- Object.assign(this, fields);
2665
- }
2666
- }
2667
- }
2668
-
2669
3053
  class ReplaceByRestoreModel {
2670
3054
  constructor(fields) {
2671
3055
  if (fields) {
@@ -2875,6 +3259,12 @@ class OperationHistory {
2875
3259
  pushMoveRange(restore, replace, selection) {
2876
3260
  this.addToHistory(restore, replace, selection, []);
2877
3261
  }
3262
+ pushInsertContents(undo, redo) {
3263
+ this.addToHistory(undo, redo);
3264
+ }
3265
+ pushReplaceByContents(undo, redo) {
3266
+ this.addToHistory(undo, redo);
3267
+ }
2878
3268
  pushReplace(restore, replace) {
2879
3269
  let count = replace.insertText ? replace.insertText.text.length : 1;
2880
3270
  if (replace.insertTable?.insertParagraphBefore) {
@@ -2943,14 +3333,6 @@ class OperationHistory {
2943
3333
  }
2944
3334
  }
2945
3335
 
2946
- class BreakModel {
2947
- constructor(fields) {
2948
- if (fields) {
2949
- Object.assign(this, fields);
2950
- }
2951
- }
2952
- }
2953
-
2954
3336
  class IndexedElementOperationsHelper {
2955
3337
  static removeContent(elements, startIndex, endIndex) {
2956
3338
  const length = endIndex - startIndex + 1;
@@ -2981,165 +3363,43 @@ class IndexedElementOperationsHelper {
2981
3363
  x.insertIndex += length;
2982
3364
  }
2983
3365
  });
2984
- }
2985
- static restore(elements, index, contentLength, newElements) {
2986
- this.insertContent(elements, index, contentLength);
2987
- let indexInElements = elements.findIndex(x => x.insertIndex >= index);
2988
- indexInElements = indexInElements === -1 ? elements.length : indexInElements;
2989
- elements.splice(indexInElements, 0, ...newElements);
2990
- }
2991
- static replaceContent(elements, startIndex, endIndex, length) {
2992
- this.removeContent(elements, startIndex, endIndex);
2993
- this.insertContent(elements, startIndex, length);
2994
- }
2995
- }
2996
-
2997
- class BreakOperationsHelper {
2998
- static insertContent(elements, index, breakType, length) {
2999
- const element = new BreakModel({ insertIndex: index, breakType });
3000
- IndexedElementOperationsHelper.insert(elements, element, length);
3001
- }
3002
- }
3003
-
3004
- class CellModel {
3005
- constructor(fields) {
3006
- if (fields) {
3007
- if (fields.margins) {
3008
- fields.margins = new MarginsModel(fields.margins);
3009
- }
3010
- Object.assign(this, fields);
3011
- }
3012
- }
3013
- }
3014
-
3015
- class ContentOperationsHelper {
3016
- static removeContent(content, startIndex, count) {
3017
- return `${content.slice(0, startIndex)}${content.slice(startIndex + count, content.length)}`;
3018
- }
3019
- static sliceContent(content, startIndex, count) {
3020
- return content.slice(startIndex, startIndex + count);
3021
- }
3022
- static insertContent(content, text, index) {
3023
- const before = content.slice(0, index);
3024
- const after = content.slice(index, content.length);
3025
- return `${before}${text}${after}`;
3026
- }
3027
- static replaceContent(content, startIndex, endIndex, text) {
3028
- const reduced = this.removeContent(content, startIndex, endIndex - startIndex + 1);
3029
- return this.insertContent(reduced, text, startIndex);
3030
- }
3031
- }
3032
-
3033
- class BordersStyleModel {
3034
- constructor(fields) {
3035
- if (fields) {
3036
- Object.assign(this, fields);
3037
- }
3038
- }
3039
- }
3040
-
3041
- class ImageModel {
3042
- constructor(fields) {
3043
- if (fields) {
3044
- if (fields.border) {
3045
- fields.border = new BordersStyleModel(fields.border);
3046
- }
3047
- Object.assign(this, fields);
3048
- }
3049
- }
3050
- }
3051
-
3052
- class PageFormatHelper {
3053
- static sliceSection(content, start, end) {
3054
- if (content instanceof DocxModel) {
3055
- return content.pageFormats.filter(x => x.insertIndex !== 0 && x.insertIndex >= start && x.insertIndex <= end);
3056
- }
3057
- return [];
3058
- }
3059
- static shiftIndexes(pagesFormats, offset) {
3060
- for (const pageFormat of pagesFormats) {
3061
- if (pageFormat.insertIndex === 0) {
3062
- return;
3063
- }
3064
- pageFormat.insertIndex += offset;
3065
- }
3066
- }
3067
- }
3068
-
3069
- class ParagraphModel {
3070
- constructor(fields) {
3071
- if (fields) {
3072
- if (fields.paragraphStyle) {
3073
- fields.paragraphStyle = new ParagraphStyleModel(fields.paragraphStyle);
3074
- }
3075
- Object.assign(this, fields);
3076
- }
3077
- }
3078
- }
3079
-
3080
- class RangeElementHelper {
3081
- static removeContent(elements, startIndex, endIndex) {
3082
- const length = endIndex - startIndex + 1;
3083
- for (let i = elements.length - 1; i >= 0; i--) {
3084
- const element = elements[i];
3085
- if (element.endIndex < startIndex) {
3086
- continue;
3087
- }
3088
- if (element.startIndex < startIndex) {
3089
- if (element.endIndex > endIndex) {
3090
- element.endIndex -= length;
3091
- }
3092
- else {
3093
- element.endIndex = startIndex - 1;
3094
- }
3095
- continue;
3096
- }
3097
- if (element.startIndex >= startIndex && element.startIndex <= endIndex) {
3098
- if (element.endIndex <= endIndex) {
3099
- elements.splice(i, 1);
3100
- continue;
3101
- }
3102
- element.startIndex -= element.startIndex - startIndex;
3103
- element.endIndex -= endIndex - element.startIndex;
3104
- continue;
3105
- }
3106
- element.startIndex -= length;
3107
- element.endIndex -= length;
3108
- }
3109
- }
3110
- static insertContent(elements, index, length) {
3111
- for (const element of elements) {
3112
- if (element.startIndex >= index) {
3113
- element.startIndex += length;
3114
- element.endIndex += length;
3115
- }
3116
- else if (element.endIndex > index) {
3117
- element.endIndex += length;
3118
- }
3366
+ }
3367
+ static insertRelative(elements, insertIndex, insertLength, insertElements) {
3368
+ this.insertContent(elements, insertIndex, insertLength);
3369
+ if (insertElements.length === 0) {
3370
+ return;
3371
+ }
3372
+ for (const element of insertElements) {
3373
+ element.insertIndex += insertIndex;
3374
+ }
3375
+ const targetIndex = elements.findIndex(x => x.insertIndex > insertIndex);
3376
+ if (targetIndex < 0) {
3377
+ elements.push(...insertElements);
3378
+ }
3379
+ else {
3380
+ elements.splice(targetIndex, 0, ...insertElements);
3119
3381
  }
3120
3382
  }
3121
3383
  static restore(elements, index, contentLength, newElements) {
3122
- RangeElementHelper.insertContent(elements, index, contentLength);
3123
- const nextElement = elements.find(x => x.startIndex >= index);
3124
- const indexInElements = nextElement !== undefined ? elements.indexOf(nextElement) : elements.length;
3384
+ this.insertContent(elements, index, contentLength);
3385
+ let indexInElements = elements.findIndex(x => x.insertIndex >= index);
3386
+ indexInElements = indexInElements === -1 ? elements.length : indexInElements;
3125
3387
  elements.splice(indexInElements, 0, ...newElements);
3126
3388
  }
3127
3389
  static replaceContent(elements, startIndex, endIndex, length) {
3128
- RangeElementHelper.removeContent(elements, startIndex, endIndex);
3129
- RangeElementHelper.insertContent(elements, startIndex, length);
3130
- }
3131
- static shiftIndexes(elements, offset) {
3132
- for (const element of elements) {
3133
- element.startIndex += offset;
3134
- element.endIndex += offset;
3135
- }
3390
+ this.removeContent(elements, startIndex, endIndex);
3391
+ this.insertContent(elements, startIndex, length);
3136
3392
  }
3137
- static sliceSection(elements, startIndex, endIndex) {
3138
- return elements.filter(x => x.startIndex >= startIndex && x.endIndex <= endIndex);
3393
+ }
3394
+
3395
+ class BreakOperationsHelper {
3396
+ static insertContent(elements, index, breakType, length) {
3397
+ const element = new BreakModel({ insertIndex: index, breakType });
3398
+ IndexedElementOperationsHelper.insert(elements, element, length);
3139
3399
  }
3140
3400
  }
3141
3401
 
3142
- class TableModel {
3402
+ class CellModel {
3143
3403
  constructor(fields) {
3144
3404
  if (fields) {
3145
3405
  if (fields.margins) {
@@ -3150,45 +3410,6 @@ class TableModel {
3150
3410
  }
3151
3411
  }
3152
3412
 
3153
- class TabModel {
3154
- constructor(fields) {
3155
- if (fields) {
3156
- Object.assign(this, fields);
3157
- }
3158
- }
3159
- }
3160
-
3161
- class ContentsOperationsHelper {
3162
- static GetRestoreFromSlice(contents, startIndex, count) {
3163
- const text = ContentOperationsHelper.sliceContent(contents.content, startIndex, count);
3164
- const endIndex = startIndex + count - 1;
3165
- const formats = FormatHelper.sliceSection(contents.formats, startIndex, endIndex);
3166
- const paragraphs = IndexedElementHelper.sliceSection(contents.paragraphs, startIndex, endIndex).map(x => new ParagraphModel(x));
3167
- const images = IndexedElementHelper.sliceSection(contents.images, startIndex, endIndex).map(x => new ImageModel(x));
3168
- const tables = IndexedElementHelper.sliceSection(contents.tables, startIndex, endIndex).map(x => new TableModel(x));
3169
- const elements = IndexedElementHelper.sliceSection(contents.elements, startIndex, endIndex).map(x => new ElementModel(x));
3170
- const comments = RangeElementHelper.sliceSection(contents.comments, startIndex, endIndex);
3171
- const breaks = IndexedElementHelper.sliceSection(contents.breaks, startIndex, endIndex).map(x => new BreakModel(x));
3172
- const tabs = IndexedElementHelper.sliceSection(contents.tabs, startIndex, endIndex).map(x => new TabModel(x));
3173
- const links = LinkHelper.sliceSection(contents.links, startIndex, endIndex).map(x => new LinkModel(x));
3174
- const pageFormats = PageFormatHelper.sliceSection(contents, startIndex, endIndex).map(x => new PageFormatModel(x));
3175
- return new RestoreModel({
3176
- insertIndex: startIndex,
3177
- text,
3178
- formats,
3179
- paragraphs,
3180
- images,
3181
- tables,
3182
- elements,
3183
- breaks,
3184
- tabs,
3185
- links,
3186
- pageFormats,
3187
- comments
3188
- });
3189
- }
3190
- }
3191
-
3192
3413
  class EdgeModel {
3193
3414
  constructor(fields) {
3194
3415
  if (fields) {
@@ -3252,6 +3473,14 @@ class FormatOperationsHelper {
3252
3473
  }
3253
3474
  });
3254
3475
  }
3476
+ static insertRelative(formats, insertIndex, insertLength, insertFormats) {
3477
+ this.insertContent(formats, insertIndex, insertLength);
3478
+ for (const format of insertFormats) {
3479
+ format.startIndex += insertIndex;
3480
+ format.endIndex += insertIndex;
3481
+ this.apply(formats, format.startIndex, format.endIndex, format.textStyle);
3482
+ }
3483
+ }
3255
3484
  static insertStyledContent(formats, index, textLength, style) {
3256
3485
  this.insertContent(formats, index, textLength);
3257
3486
  this.apply(formats, index, index + textLength - 1, style);
@@ -3354,6 +3583,24 @@ class LinkOperationsHelper {
3354
3583
  }
3355
3584
  }
3356
3585
  }
3586
+ static insertRelative(links, insertIndex, insertLength, insertLinks) {
3587
+ this.insertContent(links, insertIndex, insertLength);
3588
+ if (insertLinks.length === 0) {
3589
+ return;
3590
+ }
3591
+ for (const link of links) {
3592
+ link.startIndex += insertIndex;
3593
+ link.endIndex += insertIndex;
3594
+ }
3595
+ const targetIndex = links.findIndex(x => x.startIndex === insertIndex);
3596
+ if (targetIndex < 0) {
3597
+ links.push(...insertLinks);
3598
+ }
3599
+ else {
3600
+ links.splice(targetIndex, 0, ...insertLinks);
3601
+ }
3602
+ this.merge(links, insertIndex - 1, insertIndex + insertLength);
3603
+ }
3357
3604
  static removeContent(links, startIndex, endIndex) {
3358
3605
  const length = endIndex - startIndex + 1;
3359
3606
  for (let i = links.length - 1; i >= 0; i--) {
@@ -5778,6 +6025,17 @@ class OperationsHelper {
5778
6025
  this.removeComment(document, model.commentId);
5779
6026
  break;
5780
6027
  }
6028
+ case CommandType.InsertContents: {
6029
+ const model = command.insertContents;
6030
+ this.insertContents(contents, model.insertIndex, model.contents);
6031
+ break;
6032
+ }
6033
+ case CommandType.ReplaceByContents: {
6034
+ const model = command.replaceByContents;
6035
+ this.delete(contents, model.startIndex, model.count);
6036
+ this.insertContents(contents, model.startIndex, model.contents);
6037
+ break;
6038
+ }
5781
6039
  }
5782
6040
  });
5783
6041
  }
@@ -6033,6 +6291,22 @@ class OperationsHelper {
6033
6291
  document.comments = document.comments.filter(x => x.commentId !== commentId);
6034
6292
  return comment;
6035
6293
  }
6294
+ static insertContents(contents, insertIndex, insertContents) {
6295
+ const contentLength = insertContents.content.length;
6296
+ contents.content = ContentOperationsHelper.insertContent(contents.content, insertContents.content, insertIndex);
6297
+ IndexedElementOperationsHelper.insertRelative(contents.paragraphs, insertIndex, contentLength, insertContents.paragraphs);
6298
+ IndexedElementOperationsHelper.insertRelative(contents.images, insertIndex, contentLength, insertContents.images);
6299
+ IndexedElementOperationsHelper.insertRelative(contents.tables, insertIndex, contentLength, insertContents.tables);
6300
+ IndexedElementOperationsHelper.insertRelative(contents.elements, insertIndex, contentLength, insertContents.elements);
6301
+ IndexedElementOperationsHelper.insertRelative(contents.breaks, insertIndex, contentLength, insertContents.breaks);
6302
+ IndexedElementOperationsHelper.insertRelative(contents.tabs, insertIndex, contentLength, insertContents.tabs);
6303
+ FormatOperationsHelper.insertRelative(contents.formats, insertIndex, contentLength, insertContents.formats);
6304
+ RangeElementHelper.insertRelative(contents.comments, insertIndex, contentLength, insertContents.comments);
6305
+ LinkOperationsHelper.insertRelative(contents.links, insertIndex, contentLength, insertContents.links);
6306
+ if (contents instanceof DocxModel) {
6307
+ PageFormatOperationsHelper.insertContent(contents, insertIndex, contentLength);
6308
+ }
6309
+ }
6036
6310
  static replace(document, contents, model) {
6037
6311
  this.delete(document, model.delete.startIndex, model.delete.count);
6038
6312
  if (model.insertText) {
@@ -9162,7 +9436,7 @@ class EditSession {
9162
9436
  }
9163
9437
  removeByDocumentIndexes(startIndex, endIndex) {
9164
9438
  const startParagraphPosition = ContentHelper.documentIndexToParagraphIndex(this.displayData.paragraphs, startIndex);
9165
- const endParagraphPosition = ContentHelper.documentIndexToParagraphIndex(this.displayData.paragraphs, endIndex);
9439
+ const endParagraphPosition = ContentHelper.documentIndexToParagraphIndex(this.displayData.paragraphs, endIndex + 1);
9166
9440
  this.remove(new Range(startParagraphPosition, endParagraphPosition));
9167
9441
  }
9168
9442
  insertTextByDocumentIndex(index, text, style) {
@@ -9313,7 +9587,7 @@ class EditSession {
9313
9587
  this.applyToolbarStyles();
9314
9588
  }
9315
9589
  replace(model) {
9316
- this.removeByDocumentIndexes(model.delete.startIndex, model.delete.startIndex + model.delete.count);
9590
+ this.removeByDocumentIndexes(model.delete.startIndex, model.delete.startIndex + model.delete.count - 1);
9317
9591
  let endPoint;
9318
9592
  if (model.insertText) {
9319
9593
  endPoint = this.insertTextByDocumentIndex(model.insertText.insertIndex, model.insertText.text);
@@ -9348,7 +9622,7 @@ class EditSession {
9348
9622
  this.removeNumberings(paragraphIndex, paragraphIndex);
9349
9623
  }
9350
9624
  this.applyParagraphStyle(paragraphIndex, paragraphIndex, model.paragraphStyle);
9351
- this.removeByDocumentIndexes(model.startIndex, model.startIndex + model.count);
9625
+ this.removeByDocumentIndexes(model.startIndex, model.startIndex + model.count - 1);
9352
9626
  }
9353
9627
  restoreWithParagraph(model) {
9354
9628
  this.restore(model.restore);
@@ -9453,6 +9727,23 @@ class EditSession {
9453
9727
  OperationsHelper.applyTableCellsStyles(this.model, model);
9454
9728
  table.instance.updateTable();
9455
9729
  }
9730
+ insertContents(insertIndex, contents) {
9731
+ OperationsHelper.insertContents(this.model, insertIndex, contents);
9732
+ const endIndex = insertIndex + contents.content.length - 1;
9733
+ this.insertComponents(this.model.tables, this.customComponents.tables, NoderTableComponent, insertIndex, endIndex);
9734
+ this.insertComponents(this.model.images, this.customComponents.images, NoderImageComponent, insertIndex, endIndex);
9735
+ this.insertComponents(this.model.tabs, this.customComponents.tabs, NoderTabComponent, insertIndex, endIndex);
9736
+ this.insertElementComponents(this.model.elements, insertIndex, endIndex);
9737
+ const startPosition = ContentHelper.documentIndexToParagraphIndex(this.displayData.paragraphs, insertIndex);
9738
+ const endPosition = this.displayData.insertText(startPosition, contents.content);
9739
+ this.displayData.updateNextLineIndexes(startPosition.row, endPosition.row);
9740
+ this.selection.placeSelection(endPosition, endPosition);
9741
+ this.applyToolbarStyles();
9742
+ }
9743
+ replaceByContents(startIndex, count, contents) {
9744
+ this.removeByDocumentIndexes(startIndex, startIndex + count - 1);
9745
+ this.insertContents(startIndex, contents);
9746
+ }
9456
9747
  removeMoveRange(moveModel) {
9457
9748
  const endIndex = moveModel.sourceStartIndex + moveModel.sourceCount - 1;
9458
9749
  const startPosition = this.displayData.indexToPosition(moveModel.sourceStartIndex, 0);
@@ -9472,10 +9763,10 @@ class EditSession {
9472
9763
  restoreMoveRange(restoreModel, moveModel, _sourceSessionId) {
9473
9764
  const moveIndex = OperationsHelper.restoreMoveRange(this.model, moveModel, restoreModel);
9474
9765
  const endIndex = moveIndex + moveModel.sourceCount;
9475
- this.restoreComponents(this.model.tables, this.customComponents.tables, NoderTableComponent, moveIndex, endIndex);
9476
- this.restoreComponents(this.model.images, this.customComponents.images, NoderImageComponent, moveIndex, endIndex);
9477
- this.restoreComponents(this.model.tabs, this.customComponents.tabs, NoderTabComponent, moveIndex, endIndex);
9478
- this.restoreElementComponents(this.model.elements, moveIndex, endIndex);
9766
+ this.insertComponents(this.model.tables, this.customComponents.tables, NoderTableComponent, moveIndex, endIndex);
9767
+ this.insertComponents(this.model.images, this.customComponents.images, NoderImageComponent, moveIndex, endIndex);
9768
+ this.insertComponents(this.model.tabs, this.customComponents.tabs, NoderTabComponent, moveIndex, endIndex);
9769
+ this.insertElementComponents(this.model.elements, moveIndex, endIndex);
9479
9770
  const startPosition = ContentHelper.documentIndexToParagraphIndex(this.displayData.paragraphs, moveIndex);
9480
9771
  const endPosition = this.displayData.insertText(startPosition, restoreModel.text);
9481
9772
  this.displayData.updateNextLineIndexes(startPosition.row, endPosition.row);
@@ -9491,6 +9782,12 @@ class EditSession {
9491
9782
  const endIndex = this.displayData.positionToIndex(range.end);
9492
9783
  return positionIndex >= startIndex && positionIndex < endIndex;
9493
9784
  }
9785
+ getContentsSlice(start, end) {
9786
+ const startIndex = ContentHelper.paragraphPositionToDocumentIndex(this.displayData.paragraphs, start);
9787
+ const endIndex = ContentHelper.paragraphPositionToDocumentIndex(this.displayData.paragraphs, end) - 1;
9788
+ const count = endIndex - startIndex + 1;
9789
+ return ContentsOperationsHelper.GetRelativeContentSlice(this.model, startIndex, count);
9790
+ }
9494
9791
  createRestoreFromSlice(start, end) {
9495
9792
  const startIndex = ContentHelper.paragraphToDocumentIndex(this.displayData.paragraphs, start.row, start.column);
9496
9793
  const endIndex = ContentHelper.paragraphToDocumentIndex(this.displayData.paragraphs, end.row, end.column) - 1;
@@ -9557,7 +9854,7 @@ class EditSession {
9557
9854
  return [format.textStyle];
9558
9855
  }
9559
9856
  replaceByRestore(model) {
9560
- this.removeByDocumentIndexes(model.delete.startIndex, model.delete.startIndex + model.delete.count);
9857
+ this.removeByDocumentIndexes(model.delete.startIndex, model.delete.startIndex + model.delete.count - 1);
9561
9858
  this.restore(model.restore);
9562
9859
  }
9563
9860
  restore(model) {
@@ -9565,15 +9862,15 @@ class EditSession {
9565
9862
  OperationsHelper.restore(this.model, model);
9566
9863
  const endPoint = this.displayData.insertText(paragraphPosition, model.text);
9567
9864
  const restoreEndIndex = model.insertIndex + model.text.length;
9568
- this.restoreComponents(this.model.tables, this.customComponents.tables, NoderTableComponent, model.insertIndex, restoreEndIndex);
9569
- this.restoreComponents(this.model.images, this.customComponents.images, NoderImageComponent, model.insertIndex, restoreEndIndex);
9570
- this.restoreComponents(this.model.tabs, this.customComponents.tabs, NoderTabComponent, model.insertIndex, restoreEndIndex);
9571
- this.restoreElementComponents(this.model.elements, model.insertIndex, restoreEndIndex);
9865
+ this.insertComponents(this.model.tables, this.customComponents.tables, NoderTableComponent, model.insertIndex, restoreEndIndex);
9866
+ this.insertComponents(this.model.images, this.customComponents.images, NoderImageComponent, model.insertIndex, restoreEndIndex);
9867
+ this.insertComponents(this.model.tabs, this.customComponents.tabs, NoderTabComponent, model.insertIndex, restoreEndIndex);
9868
+ this.insertElementComponents(this.model.elements, model.insertIndex, restoreEndIndex);
9572
9869
  this.displayData.updateNextLineIndexes(paragraphPosition.row, endPoint.row);
9573
9870
  this.selection.placeCursor(endPoint);
9574
9871
  this.applyToolbarStyles();
9575
9872
  }
9576
- restoreComponents(models, components, componentType, restoreIndex, restoreEndIndex) {
9873
+ insertComponents(models, components, componentType, restoreIndex, restoreEndIndex) {
9577
9874
  for (const model of models) {
9578
9875
  if (model.insertIndex < restoreIndex) {
9579
9876
  continue;
@@ -9584,7 +9881,7 @@ class EditSession {
9584
9881
  this.addComponent(components, model, componentType);
9585
9882
  }
9586
9883
  }
9587
- restoreElementComponents(elements, restoreIndex, restoreEndIndex) {
9884
+ insertElementComponents(elements, restoreIndex, restoreEndIndex) {
9588
9885
  for (const model of elements) {
9589
9886
  if (model.insertIndex < restoreIndex) {
9590
9887
  continue;
@@ -9950,7 +10247,6 @@ class CommentHighlightLayer extends HighlightLayer {
9950
10247
  this.commentService = commentService;
9951
10248
  this.className = 'noder-highlight';
9952
10249
  this.selectedCommentClassName = 'noder-selected-highlight';
9953
- this.selectedCommentId = null;
9954
10250
  }
9955
10251
  update(config) {
9956
10252
  const comments = this.session.model.comments;
@@ -9972,7 +10268,7 @@ class CommentHighlightLayer extends HighlightLayer {
9972
10268
  continue;
9973
10269
  }
9974
10270
  if (!screenRange.isEmpty) {
9975
- const className = comment.commentId === this.selectedCommentId ? this.selectedCommentClassName : this.className;
10271
+ const className = comment.commentId === this.commentService.selectedCommentId ? this.selectedCommentClassName : this.className;
9976
10272
  const result = screenRange.isSingleLine
9977
10273
  ? this.drawSingleLineMarker(screenRange, className)
9978
10274
  : this.drawMultiLineMarker(screenRange, className);
@@ -9986,23 +10282,13 @@ class CommentHighlightLayer extends HighlightLayer {
9986
10282
  }
9987
10283
  }
9988
10284
  }
9989
- removeSessionComments() {
9990
- this.commentService.removeCommentsFromRender(this.session.sessionId);
9991
- }
9992
10285
  removeComment(id) {
9993
10286
  this.commentService.removeCommentFromRender(this.session.sessionId, id);
9994
10287
  }
9995
- setSelectedComment(id) {
9996
- if (this.selectedCommentId) {
9997
- this.commentService.setCommentSelected(this.selectedCommentId, false);
9998
- }
9999
- this.selectedCommentId = id;
10000
- if (id) {
10001
- this.commentService.setCommentSelected(id);
10002
- }
10003
- }
10004
10288
  clearSessionComments() {
10005
- this.commentService.removeCommentsFromRender(this.session.sessionId);
10289
+ if (this.session.model.comments.length) {
10290
+ this.commentService.removeCommentsFromRender(this.session.sessionId);
10291
+ }
10006
10292
  }
10007
10293
  requestCommentRender(highlight, id) {
10008
10294
  const element = Array.isArray(highlight) ? highlight[0] : highlight;
@@ -10200,48 +10486,6 @@ class RenderChangesModel {
10200
10486
  }
10201
10487
  }
10202
10488
 
10203
- class EventHelper {
10204
- static get nextFrame() {
10205
- if (!this._nextFrame) {
10206
- const nextFrame = (callback) => {
10207
- setTimeout(callback, 17);
10208
- };
10209
- this._nextFrame =
10210
- window.requestAnimationFrame ||
10211
- window['webkitRequestAnimationFrame'] ||
10212
- window['mozRequestAnimationFrame'] ||
10213
- window['msRequestAnimationFrame'] ||
10214
- window['oRequestAnimationFrame'] ||
10215
- nextFrame;
10216
- }
10217
- return this._nextFrame;
10218
- }
10219
- }
10220
-
10221
- class RenderLoop {
10222
- constructor(onRender) {
10223
- this.changes = new RenderChangesModel();
10224
- this.flush = () => {
10225
- const changes = this.changes;
10226
- if (changes.any) {
10227
- this.changes = new RenderChangesModel();
10228
- onRender(changes);
10229
- }
10230
- if (this.changes.any) {
10231
- this.schedule();
10232
- }
10233
- };
10234
- }
10235
- schedule(changes) {
10236
- if (changes) {
10237
- this.changes.apply(changes);
10238
- }
10239
- if (this.changes) {
10240
- EventHelper.nextFrame(this.flush);
10241
- }
10242
- }
10243
- }
10244
-
10245
10489
  class CustomElementInfo {
10246
10490
  constructor(init) {
10247
10491
  Object.assign(this, init);
@@ -10605,9 +10849,11 @@ class Renderer extends EventEmitting {
10605
10849
  get paragraphsAppeared$() {
10606
10850
  return this.paragraphsAppeared.asObservable();
10607
10851
  }
10608
- constructor(parentContainer, commentsService, session) {
10852
+ constructor(parentContainer, commentsService, session, loop) {
10609
10853
  super();
10610
10854
  this.session = session;
10855
+ this.loop = loop;
10856
+ this.grammarChecksEnabled = false;
10611
10857
  this.layerConfig = {
10612
10858
  width: 1,
10613
10859
  contentRange: new DistanceModel({ start: 0, end: 0 }), // paragraphs
@@ -10637,7 +10883,7 @@ class Renderer extends EventEmitting {
10637
10883
  width: 1
10638
10884
  };
10639
10885
  this.pagesCountChangedHandler = () => {
10640
- this.loop.schedule({ lines: true, selection: true });
10886
+ this.scheduleChanges({ lines: true, selection: true });
10641
10887
  };
10642
10888
  this.container = parentContainer;
10643
10889
  this.container.className += ' noder-editor';
@@ -10649,10 +10895,10 @@ class Renderer extends EventEmitting {
10649
10895
  this.commentsLayer = new CommentHighlightLayer(this.content, 'comments-highlight', this.session, commentsService);
10650
10896
  this.cursorLayer = new CursorLayer(this.content, this.session);
10651
10897
  this.dragAndDropSelectionLayer = new SelectionLayer(this.content, 'drag-and-drop-selection', this.session);
10652
- this.loop = new RenderLoop(changes => this.renderChanges(changes));
10898
+ loop.registerSession(this.session.sessionId, changes => this.renderChanges(changes));
10653
10899
  this.session.displayData.addEventListener('pagesCountChanged', this.pagesCountChangedHandler);
10654
10900
  this.visibilitySubscription = this.visibilitySubject
10655
- .pipe(debounceTime(3000), filter(x => x))
10901
+ .pipe(filter(() => this.grammarChecksEnabled), debounceTime(3000), filter(x => x))
10656
10902
  .subscribe(() => this.paragraphsScrolledIntoView());
10657
10903
  }
10658
10904
  renderChanges(changes, force) {
@@ -10721,7 +10967,7 @@ class Renderer extends EventEmitting {
10721
10967
  if (lastRow < this.layerConfig.contentRange.start || firstRow > this.layerConfig.contentRange.end) {
10722
10968
  return;
10723
10969
  }
10724
- this.loop.schedule({ lines: true });
10970
+ this.scheduleChanges({ lines: true });
10725
10971
  }
10726
10972
  moveTextAreaToCursor() {
10727
10973
  if (!this.textarea) {
@@ -10743,38 +10989,38 @@ class Renderer extends EventEmitting {
10743
10989
  updateSelection(range) {
10744
10990
  if (range.isEmpty && this.selectionLayer.marker) {
10745
10991
  this.selectionLayer.marker = null;
10746
- this.loop.schedule({ selection: true });
10992
+ this.scheduleChanges({ selection: true });
10747
10993
  }
10748
10994
  else if (!range.isEmpty && !this.selectionLayer.marker?.isEqual(range)) {
10749
10995
  this.selectionLayer.marker = range;
10750
- this.loop.schedule({ selection: true });
10996
+ this.scheduleChanges({ selection: true });
10751
10997
  }
10752
10998
  }
10753
10999
  updateSearchHighlights(ranges) {
10754
11000
  if (this.searchHighlightLayer.markers.length !== ranges.length ||
10755
11001
  !this.searchHighlightLayer.markers.every(x => ranges.some(y => x.isEqual(y)))) {
10756
11002
  this.searchHighlightLayer.markers = ranges;
10757
- this.loop.schedule({ search: true });
11003
+ this.scheduleChanges({ search: true });
10758
11004
  }
10759
11005
  }
10760
11006
  updateCustomElementHighlights(ranges) {
10761
11007
  this.searchHighlightLayer.customElementsRanges = ranges;
10762
- this.loop.schedule({ search: true });
11008
+ this.scheduleChanges({ search: true });
10763
11009
  }
10764
11010
  updateActiveSearchHighlight(active) {
10765
11011
  this.searchHighlightLayer.active = active;
10766
- this.loop.schedule({ search: true });
11012
+ this.scheduleChanges({ search: true });
10767
11013
  }
10768
11014
  updateGrammarHighlights(paragraphId, errors) {
10769
11015
  this.grammarHighlightLayer.setErrors(paragraphId, errors);
10770
- this.loop.schedule({ grammar: true });
11016
+ this.scheduleChanges({ grammar: true });
10771
11017
  }
10772
11018
  removeGrammarHighlights(paragraphId) {
10773
11019
  this.grammarHighlightLayer.removeParagraphHighlights(paragraphId);
10774
11020
  }
10775
11021
  clearGrammarHighlights() {
10776
11022
  this.grammarHighlightLayer.clearHighlights();
10777
- this.loop.schedule({ grammar: true });
11023
+ this.scheduleChanges({ grammar: true });
10778
11024
  }
10779
11025
  paragraphsScrolledIntoView() {
10780
11026
  if (!this.layerConfig.visibleRange) {
@@ -10787,11 +11033,11 @@ class Renderer extends EventEmitting {
10787
11033
  updateDragAndDropSelection(range) {
10788
11034
  if (range.isEmpty && this.dragAndDropSelectionLayer.marker) {
10789
11035
  this.dragAndDropSelectionLayer.marker = null;
10790
- this.loop.schedule({ dragAndDrop: true });
11036
+ this.scheduleChanges({ dragAndDrop: true });
10791
11037
  }
10792
11038
  else if (!range.isEmpty && !this.dragAndDropSelectionLayer.marker?.isEqual(range)) {
10793
11039
  this.dragAndDropSelectionLayer.marker = range;
10794
- this.loop.schedule({ dragAndDrop: true });
11040
+ this.scheduleChanges({ dragAndDrop: true });
10795
11041
  }
10796
11042
  }
10797
11043
  clearDragAndDropSelection() {
@@ -10799,7 +11045,7 @@ class Renderer extends EventEmitting {
10799
11045
  return;
10800
11046
  }
10801
11047
  this.dragAndDropSelectionLayer.marker = null;
10802
- this.loop.schedule({ dragAndDrop: true });
11048
+ this.scheduleChanges({ dragAndDrop: true });
10803
11049
  }
10804
11050
  setVisibility(isVisible) {
10805
11051
  if (this.isVisible !== isVisible) {
@@ -10807,23 +11053,23 @@ class Renderer extends EventEmitting {
10807
11053
  if (!isVisible) {
10808
11054
  this.commentsLayer.clearSessionComments();
10809
11055
  }
10810
- this.loop.schedule({ visibilityChanged: true });
11056
+ this.scheduleChanges({ visibilityChanged: true });
10811
11057
  }
10812
11058
  }
10813
11059
  /**
10814
11060
  * Triggers a full update of the text, for all the rows.
10815
11061
  **/
10816
11062
  updateText() {
10817
- this.loop.schedule({ text: true });
11063
+ this.scheduleChanges({ text: true });
10818
11064
  }
10819
11065
  updateTextAndCursor() {
10820
- this.loop.schedule({ text: true, cursor: true });
11066
+ this.scheduleChanges({ text: true, cursor: true });
10821
11067
  }
10822
11068
  updateMarker() {
10823
- this.loop.schedule({ marker: true });
11069
+ this.scheduleChanges({ marker: true });
10824
11070
  }
10825
11071
  updateCursor() {
10826
- this.loop.schedule({ cursor: true });
11072
+ this.scheduleChanges({ cursor: true });
10827
11073
  }
10828
11074
  // tokenDivider - used to measure if token fits (1 - should be fully fit, 2 - half of token, 3 - third part, ...) to be included
10829
11075
  screenToParagraph(x, y, tokenDivider = 1, rect) {
@@ -10880,14 +11126,11 @@ class Renderer extends EventEmitting {
10880
11126
  renderCommentHighlights() {
10881
11127
  this.commentsLayer.update(this.layerConfig);
10882
11128
  }
10883
- setSelectedComment(comment) {
10884
- this.commentsLayer.setSelectedComment(comment);
10885
- }
10886
11129
  removeComment(id) {
10887
11130
  this.commentsLayer.removeComment(id);
10888
11131
  }
10889
11132
  clearComments() {
10890
- this.commentsLayer.removeSessionComments();
11133
+ this.commentsLayer.clearSessionComments();
10891
11134
  }
10892
11135
  setCommentsVisibility(value) {
10893
11136
  if (!value) {
@@ -10895,6 +11138,9 @@ class Renderer extends EventEmitting {
10895
11138
  }
10896
11139
  this.commentsLayer.enabled = value;
10897
11140
  }
11141
+ scheduleChanges(changes) {
11142
+ this.loop.schedule(this.session.sessionId, changes);
11143
+ }
10898
11144
  renderDragAndDropSelection() {
10899
11145
  this.dragAndDropSelectionLayer.update(this.layerConfig);
10900
11146
  }
@@ -10925,6 +11171,65 @@ class Renderer extends EventEmitting {
10925
11171
  }
10926
11172
  }
10927
11173
 
11174
+ class EventHelper {
11175
+ static get nextFrame() {
11176
+ if (!this._nextFrame) {
11177
+ const nextFrame = (callback) => {
11178
+ setTimeout(callback, 17);
11179
+ };
11180
+ this._nextFrame =
11181
+ window.requestAnimationFrame ||
11182
+ window['webkitRequestAnimationFrame'] ||
11183
+ window['mozRequestAnimationFrame'] ||
11184
+ window['msRequestAnimationFrame'] ||
11185
+ window['oRequestAnimationFrame'] ||
11186
+ nextFrame;
11187
+ }
11188
+ return this._nextFrame;
11189
+ }
11190
+ }
11191
+
11192
+ class RenderLoop {
11193
+ constructor() {
11194
+ this.sessionCallbacks = new Map();
11195
+ this.sessionChanges = new Map();
11196
+ this.flush = () => {
11197
+ const sessionsToRender = Array.from(this.sessionChanges.entries());
11198
+ const hasChanges = sessionsToRender.filter(([_, changes]) => changes.any);
11199
+ if (!hasChanges.length) {
11200
+ return;
11201
+ }
11202
+ for (const [sessionId, changes] of hasChanges) {
11203
+ const callback = this.sessionCallbacks.get(sessionId);
11204
+ callback(new RenderChangesModel(changes));
11205
+ this.sessionChanges.set(sessionId, new RenderChangesModel());
11206
+ }
11207
+ const hasMoreChanges = Array.from(this.sessionChanges.values()).some(changes => changes.any);
11208
+ if (hasMoreChanges) {
11209
+ EventHelper.nextFrame(this.flush);
11210
+ }
11211
+ };
11212
+ }
11213
+ registerSession(sessionId, onRender) {
11214
+ this.sessionCallbacks.set(sessionId, onRender);
11215
+ if (!this.sessionChanges.has(sessionId)) {
11216
+ this.sessionChanges.set(sessionId, new RenderChangesModel());
11217
+ }
11218
+ }
11219
+ unregisterSession(sessionId) {
11220
+ this.sessionCallbacks.delete(sessionId);
11221
+ this.sessionChanges.delete(sessionId);
11222
+ }
11223
+ schedule(sessionId, changes) {
11224
+ if (changes) {
11225
+ this.sessionChanges.get(sessionId).apply(changes);
11226
+ }
11227
+ if (this.sessionChanges.get(sessionId).any) {
11228
+ EventHelper.nextFrame(this.flush);
11229
+ }
11230
+ }
11231
+ }
11232
+
10928
11233
  /**
10929
11234
  * Represents a vertical scroll bar.
10930
11235
  * @class ScrollBar
@@ -11046,13 +11351,17 @@ class CommentLayer {
11046
11351
  constructor(parentEl) {
11047
11352
  this.commentPadding = 8;
11048
11353
  this.rendersBySession = new Map();
11354
+ this.enabled = false;
11049
11355
  this.element = document.createElement('div');
11050
11356
  this.element.className = `noder-comments-layer`;
11051
11357
  parentEl.appendChild(this.element);
11052
11358
  }
11359
+ enable() {
11360
+ this.enabled = true;
11361
+ }
11053
11362
  disable() {
11054
- this.rendersBySession.clear();
11055
- this.renderComments();
11363
+ this.enabled = false;
11364
+ this.element.innerHTML = '';
11056
11365
  }
11057
11366
  scrollComments(offsetY) {
11058
11367
  for (const [sessionId, comments] of this.rendersBySession) {
@@ -11065,6 +11374,9 @@ class CommentLayer {
11065
11374
  }
11066
11375
  }
11067
11376
  renderComments() {
11377
+ if (!this.enabled) {
11378
+ return;
11379
+ }
11068
11380
  this.element.innerHTML = '';
11069
11381
  const topOffset = this.element.getBoundingClientRect().top;
11070
11382
  const sortedComments = Array.from(this.rendersBySession.values())
@@ -11256,12 +11568,6 @@ class VirtualRenderer {
11256
11568
  get cursorLayer() {
11257
11569
  return this.renderer.cursorLayer;
11258
11570
  }
11259
- get loop() {
11260
- return this.renderer.loop;
11261
- }
11262
- set loop(val) {
11263
- this.renderer.loop = val;
11264
- }
11265
11571
  get textarea() {
11266
11572
  return this.renderer.textarea;
11267
11573
  }
@@ -11277,10 +11583,12 @@ class VirtualRenderer {
11277
11583
  get paragraphsAppeared$() {
11278
11584
  return this.renderer.paragraphsAppeared.asObservable();
11279
11585
  }
11280
- constructor(parentContainer, mainSession, commentService, scrollBar) {
11586
+ constructor(parentContainer, mainSession, commentService, loop, scrollBar) {
11281
11587
  this.commentService = commentService;
11588
+ this.loop = loop;
11282
11589
  this.scrollBar = scrollBar;
11283
11590
  this.changes = new RenderChangesModel();
11591
+ this.grammarChecksEnabled = false;
11284
11592
  this.size = {
11285
11593
  width: 0,
11286
11594
  height: 0,
@@ -11291,18 +11599,19 @@ class VirtualRenderer {
11291
11599
  this.paragraphsScrolledIntoViewSubject = new Subject();
11292
11600
  this.container = parentContainer;
11293
11601
  this.createScroller();
11294
- this.renderer = new Renderer(parentContainer, commentService, mainSession);
11602
+ this.renderer = new Renderer(parentContainer, commentService, mainSession, loop);
11603
+ loop.registerSession(0, changes => this.renderChanges(changes));
11295
11604
  this.pagesLayer = new PagesLayer(this.renderer.content, mainSession);
11296
11605
  this.edgesLayer = new EdgesLayer(this.renderer.content, mainSession);
11297
11606
  this.commentLayer = new CommentLayer(this.renderer.content);
11298
11607
  this.scrollSubscription = this.scrollBar.scrolled$.subscribe(x => {
11299
11608
  this.commentLayer.scrollComments(x);
11300
- this.loop.schedule({ scroll: true, comments: true });
11609
+ this.scheduleChanges({ scroll: true, comments: true });
11301
11610
  });
11302
- this.createRenderLoop();
11303
11611
  this.paragraphsScrolledIntoViewSubscription = this.paragraphsScrolledIntoViewSubject
11304
- .pipe(debounceTime(3000))
11612
+ .pipe(filter(() => this.grammarChecksEnabled), debounceTime(3000))
11305
11613
  .subscribe(() => this.paragraphsScrolledIntoView());
11614
+ this.scheduleChanges({ full: true });
11306
11615
  }
11307
11616
  renderChanges(changes, force) {
11308
11617
  changes.apply(this.changes);
@@ -11381,7 +11690,7 @@ class VirtualRenderer {
11381
11690
  this.renderChanges(changes, true);
11382
11691
  }
11383
11692
  else {
11384
- this.loop.schedule(changes);
11693
+ this.scheduleChanges(changes);
11385
11694
  }
11386
11695
  this.scrollBar.setScrollTop(0);
11387
11696
  }
@@ -11411,21 +11720,28 @@ class VirtualRenderer {
11411
11720
  this.size.dirty = !width || !height;
11412
11721
  return changes;
11413
11722
  }
11414
- setSelectedComment(commentId) {
11415
- this.renderer.setSelectedComment(commentId);
11723
+ setSelectedComment(id) {
11724
+ const oldId = this.commentService.selectedCommentId;
11725
+ this.commentService.setSelectedComment(id);
11726
+ if (this.commentService.selectedCommentId !== oldId) {
11727
+ this.scheduleChanges({ comments: true });
11728
+ }
11416
11729
  }
11417
11730
  setCommentsVisibility(value) {
11418
11731
  if (value && !this.commentsSubscription) {
11732
+ this.commentLayer.enable();
11419
11733
  this.commentsSubscription = this.commentService.commentRenderRequests$.subscribe(x => {
11420
11734
  this.commentLayer.applyChanges(x);
11421
- this.loop.schedule({ comments: true });
11735
+ setTimeout(() => this.scheduleChanges({ comments: true }));
11422
11736
  });
11423
11737
  }
11424
11738
  else {
11739
+ this.commentLayer.disable();
11425
11740
  this.commentsSubscription?.unsubscribe();
11426
11741
  this.commentsSubscription = null;
11427
11742
  }
11428
11743
  this.renderer.setCommentsVisibility(value);
11744
+ this.scheduleChanges({ comments: true });
11429
11745
  }
11430
11746
  removeComment(id) {
11431
11747
  this.renderer.removeComment(id);
@@ -11492,6 +11808,9 @@ class VirtualRenderer {
11492
11808
  setVisibility(isVisible) {
11493
11809
  this.renderer.setVisibility(isVisible);
11494
11810
  }
11811
+ scheduleChanges(changes) {
11812
+ this.loop.schedule(0, changes);
11813
+ }
11495
11814
  scrollSelectionIntoView(anchor, lead, offset) {
11496
11815
  // first scroll anchor into view then scroll lead into view
11497
11816
  this.scrollCursorIntoView(anchor, offset);
@@ -11511,7 +11830,7 @@ class VirtualRenderer {
11511
11830
  top -= offset * this.container.scrollHeight;
11512
11831
  }
11513
11832
  this.scrollBar.setScrollTop(top);
11514
- this.loop.schedule({ scroll: true });
11833
+ this.scheduleChanges({ scroll: true });
11515
11834
  }
11516
11835
  else if (this.scrollBar.scrollTop + this.container.scrollHeight < top + position.height) {
11517
11836
  if (offset) {
@@ -11519,7 +11838,7 @@ class VirtualRenderer {
11519
11838
  }
11520
11839
  top += position.height - this.container.scrollHeight;
11521
11840
  this.scrollBar.setScrollTop(top);
11522
- this.loop.schedule({ scroll: true });
11841
+ this.scheduleChanges({ scroll: true });
11523
11842
  }
11524
11843
  }
11525
11844
  scrollBy(deltaY) {
@@ -11529,7 +11848,7 @@ class VirtualRenderer {
11529
11848
  const scrollTop = this.scrollBar.scrollTop + deltaY;
11530
11849
  this.scrollBar.setScrollTop(scrollTop);
11531
11850
  this.commentLayer.scrollComments(deltaY);
11532
- this.loop.schedule({ scroll: true, comments: true });
11851
+ this.scheduleChanges({ scroll: true, comments: true });
11533
11852
  }
11534
11853
  // tokenDivider - used to measure if token fits (1 - should be fully fit, 2 - half of token, 3 - third part, ...) to be included
11535
11854
  screenToParagraph(x, y, tokenDivider = 1, rect) {
@@ -11595,11 +11914,6 @@ class VirtualRenderer {
11595
11914
  this.scroller.className = 'noder-scroller';
11596
11915
  this.container.appendChild(this.scroller);
11597
11916
  }
11598
- createRenderLoop() {
11599
- this.loop = new RenderLoop(changes => this.renderChanges(changes));
11600
- this.renderer.loop = this.loop;
11601
- this.loop.schedule({ full: true });
11602
- }
11603
11917
  renderScroll(changes) {
11604
11918
  this.pagesLayer.update(this.layerConfig);
11605
11919
  this.edgesLayer.scrollEdges(this.layerConfig);
@@ -11792,6 +12106,7 @@ class CommentRenderService {
11792
12106
  this.applicationRef = inject(ApplicationRef);
11793
12107
  this.injector = inject(Injector);
11794
12108
  this.commentRenderRequests = new Subject();
12109
+ this.selectedCommentId = null;
11795
12110
  }
11796
12111
  requestCommentsRender(sessionId, renderRequests) {
11797
12112
  const requests = [];
@@ -11825,9 +12140,17 @@ class CommentRenderService {
11825
12140
  removeCommentsFromRender(sessionId) {
11826
12141
  this.commentRenderRequests.next(new RemoveCommentsFromDom(sessionId));
11827
12142
  }
11828
- setCommentSelected(id, selected = true) {
12143
+ setSelectedComment(id) {
12144
+ if (this.selectedCommentId === id) {
12145
+ return;
12146
+ }
12147
+ if (this.selectedCommentId) {
12148
+ const oldComponentRef = this.componentInstances.find(x => x.instance.id === this.selectedCommentId);
12149
+ oldComponentRef?.instance.setSelected(false);
12150
+ }
11829
12151
  const componentRef = this.componentInstances.find(x => x.instance.id === id);
11830
- componentRef?.instance.setSelected(selected);
12152
+ componentRef?.instance.setSelected(true);
12153
+ this.selectedCommentId = id;
11831
12154
  }
11832
12155
  createComponentRef(id) {
11833
12156
  const ref = createComponent(this.componentType, {
@@ -11857,6 +12180,7 @@ class RegulatorService {
11857
12180
  this.grammarEnabled = false;
11858
12181
  this.selectedCommentSessionId = null;
11859
12182
  this.selectedCommentId = null;
12183
+ this.renderLoop = new RenderLoop();
11860
12184
  this.grammarChecker = new GrammarChecker(this.grammarService);
11861
12185
  this.observer = this.initializeIntersectionObserver();
11862
12186
  }
@@ -11885,9 +12209,9 @@ class RegulatorService {
11885
12209
  const displayData = new DisplayData(model, properties, sessionId, model.pageFormats, DocumentInfo.pagesSpace, customComponents, this.customContentService, this.editorService);
11886
12210
  const scrollBar = new ScrollBar(container.nativeElement.parentElement);
11887
12211
  const mainSession = new EditSession(displayData, sessionId, this.customContentService, this.commentRenderService, model, this.selection, properties, this.editorService, customComponents, 'main', scrollBar);
11888
- const virtualRenderer = new VirtualRenderer(container.nativeElement, mainSession, this.commentRenderService, scrollBar);
12212
+ this.mainRenderer = new VirtualRenderer(container.nativeElement, mainSession, this.commentRenderService, this.renderLoop, scrollBar);
11889
12213
  this.editorService.styles = DEFAULT_TOOLBAR_STYLES();
11890
- this.mainSession = new SessionModel(mainSession, virtualRenderer, sessionId, null, new MainSessionSourceModel(), container.nativeElement);
12214
+ this.mainSession = new SessionModel(mainSession, this.mainRenderer, sessionId, null, new MainSessionSourceModel(), container.nativeElement);
11891
12215
  this.sessions.push(this.mainSession);
11892
12216
  this.currentSession = this.mainSession;
11893
12217
  displayData.updateNextLineIndexes(0, displayData.paragraphs.length - 1);
@@ -11903,7 +12227,7 @@ class RegulatorService {
11903
12227
  const session = new EditSession(displayData, sessionId, this.customContentService, this.commentRenderService, component.cell, this.selection, component.generalProperties, this.editorService, customComponents, sessionType);
11904
12228
  displayData.pagesFormat[0].contentWidth =
11905
12229
  displayData.pagesFormat[0].contentWidth === 0 ? 1 : displayData.pagesFormat[0].contentWidth;
11906
- const renderer = new Renderer(component.container.nativeElement, this.commentRenderService, session);
12230
+ const renderer = new Renderer(component.container.nativeElement, this.commentRenderService, session, this.renderLoop);
11907
12231
  const source = new CellSessionSourceModel(component.table, component);
11908
12232
  const newSession = new SessionModel(session, renderer, sessionId, component.parentSessionId, source, nativeElement);
11909
12233
  this.sessions.push(newSession);
@@ -11920,7 +12244,7 @@ class RegulatorService {
11920
12244
  const customComponents = { images: [], tables: [], tabs: [], customElements: [], edges: null };
11921
12245
  const displayData = new DisplayData(component.model, component.generalProperties, sessionId, this.getPageFormats(component.margins, component.width), 0, customComponents, this.customContentService, this.editorService);
11922
12246
  const session = new EditSession(displayData, sessionId, this.customContentService, this.commentRenderService, component.model, this.selection, component.generalProperties, this.editorService, customComponents, 'edge', null, component.type, component.model.pageType);
11923
- const renderer = new Renderer(component.container.nativeElement, this.commentRenderService, session);
12247
+ const renderer = new Renderer(component.container.nativeElement, this.commentRenderService, session, this.renderLoop);
11924
12248
  const source = new EdgeSessionSourceModel(component.model.pageType, component.type);
11925
12249
  const newSession = new SessionModel(session, renderer, sessionId, component.parentSessionId, source, nativeElement);
11926
12250
  this.sessions.push(newSession);
@@ -12080,7 +12404,7 @@ class RegulatorService {
12080
12404
  setCommentsVisibility(value) {
12081
12405
  for (const sessionModel of this.sessions) {
12082
12406
  sessionModel.renderer.setCommentsVisibility(value);
12083
- sessionModel.renderer.loop.schedule({ commentHighlights: true });
12407
+ sessionModel.renderer.scheduleChanges({ commentHighlights: true });
12084
12408
  }
12085
12409
  }
12086
12410
  setSelectedComment(commentId) {
@@ -12089,36 +12413,38 @@ class RegulatorService {
12089
12413
  return;
12090
12414
  }
12091
12415
  const sessionModel = this.getSessionModel(this.selectedCommentSessionId);
12092
- sessionModel.renderer.setSelectedComment(null);
12093
- sessionModel.renderer.loop.schedule({ commentHighlights: true });
12416
+ this.mainRenderer.setSelectedComment(null);
12417
+ sessionModel.renderer.scheduleChanges({ commentHighlights: true });
12094
12418
  return;
12095
12419
  }
12420
+ this.mainRenderer.setSelectedComment(commentId);
12096
12421
  const newSelectedSession = this.sessions.find(x => x.session.model.comments.some(c => c.commentId === commentId));
12097
12422
  if (this.selectedCommentSessionId && this.selectedCommentSessionId !== newSelectedSession.sessionId) {
12098
12423
  const sessionModel = this.getSessionModel(this.selectedCommentSessionId);
12099
- sessionModel.renderer.setSelectedComment(null);
12100
- sessionModel.renderer.loop.schedule({ commentHighlights: true });
12424
+ sessionModel.renderer.scheduleChanges({ commentHighlights: true });
12425
+ newSelectedSession.renderer.scheduleChanges({ commentHighlights: true });
12101
12426
  }
12102
12427
  else {
12103
- newSelectedSession.renderer.setSelectedComment(commentId);
12104
- newSelectedSession.renderer.loop.schedule({ commentHighlights: true });
12428
+ newSelectedSession.renderer.scheduleChanges({ commentHighlights: true });
12105
12429
  }
12106
12430
  this.selectedCommentId = commentId;
12107
12431
  this.selectedCommentSessionId = newSelectedSession.sessionId;
12108
12432
  }
12109
12433
  setSelectedCommentAtCursor() {
12110
12434
  const comment = this.currentSession.session.getCommentAtCursor();
12435
+ this.mainRenderer.setSelectedComment(comment?.commentId);
12111
12436
  if (this.selectedCommentId && this.selectedCommentId !== comment?.commentId) {
12112
12437
  const sessionModel = this.getSessionModel(this.selectedCommentSessionId);
12113
- sessionModel.renderer.setSelectedComment(null);
12114
- sessionModel.renderer.loop.schedule({ commentHighlights: true });
12438
+ sessionModel.renderer.scheduleChanges({ commentHighlights: true });
12115
12439
  }
12116
12440
  if (comment) {
12117
- this.currentSession.renderer.setSelectedComment(comment.commentId);
12118
- this.currentSession.renderer.loop.schedule({ commentHighlights: true });
12441
+ this.currentSession.renderer.scheduleChanges({ commentHighlights: true });
12119
12442
  this.selectedCommentId = comment.commentId;
12120
12443
  this.selectedCommentSessionId = this.currentSession.sessionId;
12444
+ return;
12121
12445
  }
12446
+ this.selectedCommentId = null;
12447
+ this.selectedCommentSessionId = null;
12122
12448
  }
12123
12449
  isWithinEdge(sessionId) {
12124
12450
  return !!this.getEdgeSessionId(sessionId);
@@ -12147,12 +12473,14 @@ class RegulatorService {
12147
12473
  for (const session of this.sessions) {
12148
12474
  this.grammarChecker.registerSession(session);
12149
12475
  session.renderer.paragraphsScrolledIntoView();
12476
+ session.renderer.grammarChecksEnabled = true;
12150
12477
  }
12151
12478
  return;
12152
12479
  }
12153
12480
  for (const session of this.sessions) {
12154
12481
  this.grammarChecker.unregisterSession(session.sessionId);
12155
12482
  session.renderer.clearGrammarHighlights();
12483
+ session.renderer.grammarChecksEnabled = false;
12156
12484
  }
12157
12485
  }
12158
12486
  getEdgeSessionId(sessionId) {
@@ -13763,6 +14091,17 @@ class RemoveWithParagraphModel {
13763
14091
  }
13764
14092
  }
13765
14093
 
14094
+ class ReplaceByContentsModel {
14095
+ constructor(fields) {
14096
+ if (fields) {
14097
+ if (fields.contents) {
14098
+ fields.contents = new ContentsModel(fields.contents);
14099
+ }
14100
+ Object.assign(this, fields);
14101
+ }
14102
+ }
14103
+ }
14104
+
13766
14105
  class ReplaceModel {
13767
14106
  constructor(fields) {
13768
14107
  if (fields) {
@@ -13862,6 +14201,9 @@ class CommandModel {
13862
14201
  if (fields.insertBreak) {
13863
14202
  fields.insertBreak = new InsertBreakModel(fields.insertBreak);
13864
14203
  }
14204
+ if (fields.insertContents) {
14205
+ fields.insertContents = new InsertContentsModel(fields.insertContents);
14206
+ }
13865
14207
  if (fields.insertElement) {
13866
14208
  fields.insertElement = new InsertElementModel(fields.insertElement);
13867
14209
  }
@@ -13919,6 +14261,9 @@ class CommandModel {
13919
14261
  if (fields.replace) {
13920
14262
  fields.replace = new ReplaceModel(fields.replace);
13921
14263
  }
14264
+ if (fields.replaceByContents) {
14265
+ fields.replaceByContents = new ReplaceByContentsModel(fields.replaceByContents);
14266
+ }
13922
14267
  if (fields.replaceByRestore) {
13923
14268
  fields.replaceByRestore = new ReplaceByRestoreModel(fields.replaceByRestore);
13924
14269
  }
@@ -14047,6 +14392,12 @@ class SaveCommandsHelper {
14047
14392
  static getReplaceByRestoreCommand(replaceByRestore, targets) {
14048
14393
  return new CommandModel({ commandType: CommandType.ReplaceByRestore, replaceByRestore, targets });
14049
14394
  }
14395
+ static getInsertContentsCommand(model, targets) {
14396
+ return new CommandModel({ commandType: CommandType.InsertContents, insertContents: model, targets });
14397
+ }
14398
+ static getReplaceByContentsModel(model, targets) {
14399
+ return new CommandModel({ commandType: CommandType.ReplaceByContents, replaceByContents: model, targets });
14400
+ }
14050
14401
  static getMoveRangeCommand(model, targets) {
14051
14402
  return new CommandModel({ commandType: CommandType.MoveRange, moveRange: model, targets });
14052
14403
  }
@@ -14815,10 +15166,6 @@ class TextInput {
14815
15166
  parentElement.insertBefore(this.input, parentElement.firstChild);
14816
15167
  this.isFocused = document.activeElement === this.input;
14817
15168
  }
14818
- getClipboardData(event) {
14819
- const mime = 'text/plain';
14820
- return event.clipboardData.getData(mime);
14821
- }
14822
15169
  getInsertText() {
14823
15170
  const data = this.input.value;
14824
15171
  const selectionStart = this.input.selectionStart;
@@ -14940,12 +15287,13 @@ class Editor {
14940
15287
  this.inputHandler = new InputHandler(this.textInput.input, this);
14941
15288
  this.documentHandler = new DocumentHandler(this);
14942
15289
  this.dragAndDrop = new DragAndDrop(this.container.nativeElement);
15290
+ this.clipboardHandler = new ClipboardHandler(this.clipboard);
14943
15291
  this.initResizeListener();
14944
15292
  this.focus();
14945
15293
  this.session.applyToolbarStyles();
14946
15294
  this.onSetCommentsVisibility(!!this.model.comments.length);
14947
15295
  this.search = new Search(editorService);
14948
- this.subscriptions.push(this.changedEdgeSizeSubscription(), this.changedEdgeSubscription(), this.changedTableSizeSubscription(), this.clipboardDataSubscription(), this.copySelectedSubscription(), this.createCustomComponentSubscription(), this.replaceByCustomComponentSubscription(), this.cutSelectedSubscription(), this.disableSelectionSubscription(), this.endMousePressSubscription(), this.imageLoadedSubscription(), this.insertBreakSubscription(), this.insertImageSubscription(), this.insertLinkSubscription(), this.insertTableColumnsSubscription(), this.insertTableRowsSubscription(), this.insertTableSubscription(), this.updateTableBorderStyleSubscription(), this.updateTableBorderWidthSubscription(), this.updateTableBordersSubscription(), this.selectSpacingSubscription(), this.selectBeforeSubscription(), this.selectAfterSubscription(), this.insertTextSubscription(), this.pasteFromClipboardSubscription(), this.printSubscription(), this.redoSubscription(), this.removeLeftSubscription(), this.removeNumberingsSubscription(), this.removeRightSubscription(), this.removeSelectedSubscription(), this.removeTableColumnsSubscription(), this.removeTableRowsSubscription(), this.removeTableSubscription(), this.rerenderSubscription(), this.resizeTableColumnsSubscription(), ...this.searchOptionSubscriptions(), ...this.replaceSubscription(), this.grammarReplaceSubscription(), this.ignoreGrammarErrorSubscription(), this.toggleGrammarChecksSubscription(), this.selectAllSubscription(), this.setImageStyleSubscription(), this.setNumberingTemplateTypeSubscription(), this.setParagraphStylesSubscription(), this.setTextStylesSubscription(), this.undoSubscription(), this.updateEdgeSubscription(), this.viewOnlyModeSubscription(), this.applyPageFormatSubscription(), this.applyRightMarginPageFormatSubscription(), this.applyLeftMarginPageFormatSubscription(), this.insertPageFormatSubscription(), this.applyDocumentPageFormatSubscription(), this.dragMoveSubscription(), this.dragDropSubscription(), this.applyFirstLinePositionSubscription(), this.applyRightIndentParagraphSubscription(), this.applyLeftIndentParagraphSubscription(), this.applyTabSettingsSubscription(), this.commandCreatedForEdges(), ...this.commentCreationSubscriptions(), this.removeCommentSubscription(), this.rerenderCommentsSubscription(), this.selectCommentSubscription(), this.setComentsVisibilitySubscription(), this.getCommentTextSubscription(), this.replaceCommentTextSubscription(), this.startNewListSubscription(), this.continueNumberingSubscription(), this.setNumberingValueSubscription());
15296
+ this.subscriptions.push(this.changedEdgeSizeSubscription(), this.changedEdgeSubscription(), this.changedTableSizeSubscription(), this.copySelectedSubscription(), this.createCustomComponentSubscription(), this.replaceByCustomComponentSubscription(), this.cutSelectedSubscription(), this.disableSelectionSubscription(), this.endMousePressSubscription(), this.imageLoadedSubscription(), this.insertBreakSubscription(), this.insertImageSubscription(), this.insertLinkSubscription(), this.insertTableColumnsSubscription(), this.insertTableRowsSubscription(), this.insertTableSubscription(), this.updateTableBorderStyleSubscription(), this.updateTableBorderWidthSubscription(), this.updateTableBordersSubscription(), this.selectSpacingSubscription(), this.selectBeforeSubscription(), this.selectAfterSubscription(), this.insertTextSubscription(), this.pasteFromClipboardSubscription(), this.printSubscription(), this.redoSubscription(), this.removeLeftSubscription(), this.removeNumberingsSubscription(), this.removeRightSubscription(), this.removeSelectedSubscription(), this.removeTableColumnsSubscription(), this.removeTableRowsSubscription(), this.removeTableSubscription(), this.rerenderSubscription(), this.resizeTableColumnsSubscription(), ...this.searchOptionSubscriptions(), ...this.replaceSubscription(), this.grammarReplaceSubscription(), this.ignoreGrammarErrorSubscription(), this.toggleGrammarChecksSubscription(), this.selectAllSubscription(), this.setImageStyleSubscription(), this.setNumberingTemplateTypeSubscription(), this.setParagraphStylesSubscription(), this.setTextStylesSubscription(), this.undoSubscription(), this.updateEdgeSubscription(), this.viewOnlyModeSubscription(), this.applyPageFormatSubscription(), this.applyRightMarginPageFormatSubscription(), this.applyLeftMarginPageFormatSubscription(), this.insertPageFormatSubscription(), this.applyDocumentPageFormatSubscription(), this.dragMoveSubscription(), this.dragDropSubscription(), this.applyFirstLinePositionSubscription(), this.applyRightIndentParagraphSubscription(), this.applyLeftIndentParagraphSubscription(), this.applyTabSettingsSubscription(), this.commandCreatedForEdges(), ...this.commentCreationSubscriptions(), this.removeCommentSubscription(), this.rerenderCommentsSubscription(), this.selectCommentSubscription(), this.setComentsVisibilitySubscription(), this.getCommentTextSubscription(), this.replaceCommentTextSubscription(), this.startNewListSubscription(), this.continueNumberingSubscription(), this.setNumberingValueSubscription(), this.insertContentsSubscription());
14949
15297
  }
14950
15298
  destroy() {
14951
15299
  this.subscriptions.forEach(s => s?.unsubscribe());
@@ -15005,9 +15353,6 @@ class Editor {
15005
15353
  const y = rect.top + cursor.pageY + cursor.height;
15006
15354
  this.overlayService.open(component, { textKey }, x, y);
15007
15355
  }
15008
- cut() {
15009
- this.removeSelected();
15010
- }
15011
15356
  insert(text) {
15012
15357
  const sanitizedText = text.replace(this.emojiRegex, ' ');
15013
15358
  if (this.selection.isEmpty) {
@@ -15039,6 +15384,11 @@ class Editor {
15039
15384
  this.onSelectionChange();
15040
15385
  this.onContentChange();
15041
15386
  }
15387
+ insertSlice(sliceData) {
15388
+ const slice = sliceData.data;
15389
+ const revisionId = sliceData.source.revisionId;
15390
+ this.editorService.requestContentsInsertion(slice, revisionId);
15391
+ }
15042
15392
  removeLeft() {
15043
15393
  if (this.selection.isEmpty) {
15044
15394
  this.selection.selectLeft(this.session);
@@ -15481,7 +15831,7 @@ class Editor {
15481
15831
  command = SaveCommandsHelper.getInsertTextCommand(text, insertIndex, this.targets);
15482
15832
  }
15483
15833
  else if (operation instanceof DeleteModel) {
15484
- this.session.removeByDocumentIndexes(operation.startIndex, operation.startIndex + operation.count);
15834
+ this.session.removeByDocumentIndexes(operation.startIndex, operation.startIndex + operation.count - 1);
15485
15835
  command = SaveCommandsHelper.getDeleteCommand(operation.startIndex, operation.count, this.targets);
15486
15836
  }
15487
15837
  else if (operation instanceof InsertStyledTextModel) {
@@ -15676,6 +16026,16 @@ class Editor {
15676
16026
  this.session.applyNewNumberingForParagraphs(operation.levels, operation.insertIndexes);
15677
16027
  command = SaveCommandsHelper.getApplyNewNumberingForParagraphsCommand(operation.insertIndexes, operation.levels, this.targets);
15678
16028
  }
16029
+ else if (operation instanceof InsertContentsModel) {
16030
+ const deepCopy = structuredClone(operation.contents);
16031
+ this.session.insertContents(operation.insertIndex, deepCopy);
16032
+ command = SaveCommandsHelper.getInsertContentsCommand(operation, this.targets);
16033
+ }
16034
+ else if (operation instanceof ReplaceByContentsModel) {
16035
+ const deepCopy = structuredClone(operation.contents);
16036
+ this.session.replaceByContents(operation.startIndex, operation.count, deepCopy);
16037
+ command = SaveCommandsHelper.getReplaceByContentsModel(operation, this.targets);
16038
+ }
15679
16039
  else {
15680
16040
  throw new Error('Undo/redo is not implemented for the Operation');
15681
16041
  }
@@ -15806,6 +16166,22 @@ class Editor {
15806
16166
  this.history.pushMoveRange(undoModel, redoModel, sourceRange);
15807
16167
  this.commandsService.createCommand(SaveCommandsHelper.getMoveRangeCommand(redoModel, []));
15808
16168
  }
16169
+ saveInsertContentsToHistory(redoModel) {
16170
+ const startIndex = redoModel.insertIndex;
16171
+ const undoModel = new DeleteModel({ startIndex, count: redoModel.contents.content.length });
16172
+ this.history.pushInsertContents(undoModel, redoModel);
16173
+ this.commandsService.createCommand(SaveCommandsHelper.getInsertContentsCommand(redoModel, this.targets));
16174
+ }
16175
+ saveReplaceByContentsToHistory(redoModel) {
16176
+ const undoSlice = ContentsOperationsHelper.GetRelativeContentSlice(this.session.model, redoModel.startIndex, redoModel.count);
16177
+ const undoModel = new ReplaceByContentsModel({
16178
+ startIndex: redoModel.startIndex,
16179
+ contents: undoSlice,
16180
+ count: redoModel.contents.content.length
16181
+ });
16182
+ this.history.pushReplaceByContents(undoModel, redoModel);
16183
+ this.commandsService.createCommand(SaveCommandsHelper.getReplaceByContentsModel(redoModel, this.targets));
16184
+ }
15809
16185
  saveReplaceToHistory(range, model) {
15810
16186
  const restoreModel = this.session.createRestoreFromSlice(range.start, range.end);
15811
16187
  this.history.pushReplace(restoreModel, model);
@@ -15949,29 +16325,42 @@ class Editor {
15949
16325
  this.showInsertOverlay(text);
15950
16326
  }
15951
16327
  onCut(event) {
15952
- event.preventDefault();
15953
- const data = this.getSelectedText();
15954
- if (!data) {
16328
+ const text = this.getSelectedText();
16329
+ const slice = this.getSelectedSlice();
16330
+ if (!text && !slice) {
15955
16331
  return;
15956
16332
  }
15957
- this.editorService.setClipboardData(data);
15958
- this.clipboard.copy(data);
15959
- this.cut();
16333
+ this.clipboardHandler.copyEvent(event, text, slice, this.editorService.revisionId);
16334
+ this.removeSelected();
15960
16335
  this.scrollCursorIntoMainView();
16336
+ this.editorService.setClipboardData(text);
15961
16337
  }
15962
16338
  onCopy(event) {
15963
- event.preventDefault();
15964
- const data = this.getSelectedText();
15965
- if (!data) {
16339
+ const text = this.getSelectedText();
16340
+ const slice = this.getSelectedSlice();
16341
+ if (!text && !slice) {
15966
16342
  return;
15967
16343
  }
15968
- this.editorService.setClipboardData(data);
15969
- this.clipboard.copy(data);
16344
+ this.clipboardHandler.copyEvent(event, text, slice, this.editorService.revisionId);
16345
+ this.editorService.setClipboardData(text);
15970
16346
  }
15971
16347
  onPaste(event) {
15972
- event.preventDefault();
15973
- const data = this.textInput.getClipboardData(event);
15974
- this.pasteData(data);
16348
+ const { text, sliceData } = this.clipboardHandler.readEvent(event);
16349
+ if (sliceData) {
16350
+ this.pasteData(text, sliceData);
16351
+ return;
16352
+ }
16353
+ this.clipboardHandler // If slice not found in event should check navigation clipboard for data.
16354
+ .readAsync()
16355
+ .then(asyncData => {
16356
+ if (text === asyncData.text && asyncData.sliceData) {
16357
+ this.pasteData(asyncData.text, asyncData.sliceData);
16358
+ }
16359
+ else if (text) {
16360
+ this.pasteData(text, null);
16361
+ }
16362
+ })
16363
+ .catch(() => { });
15975
16364
  }
15976
16365
  onCreateComment(commentType) {
15977
16366
  const { startIndex, endIndex } = ContentHelper.getSelectedPartDocumentIndexes(this.session.displayData.paragraphs, this.selection.range);
@@ -15990,8 +16379,8 @@ class Editor {
15990
16379
  this.commentCreateRequests = this.commentCreateRequests.filter(x => x.reqId !== reqId);
15991
16380
  commentModel.commentId = commentId;
15992
16381
  sessionModel.session.addComment(commentModel);
15993
- sessionModel.renderer.setSelectedComment(commentModel.commentId);
15994
- sessionModel.renderer.loop.schedule({ commentHighlights: true });
16382
+ this.mainRenderer.setSelectedComment(commentModel.commentId);
16383
+ sessionModel.renderer.scheduleChanges({ commentHighlights: true });
15995
16384
  this.saveAttachCommentToHistory(commentModel);
15996
16385
  }
15997
16386
  onCommentRemoved(id) {
@@ -16000,7 +16389,7 @@ class Editor {
16000
16389
  session.renderer.removeComment(id);
16001
16390
  this.saveRemoveCommentToHistory(comment, session.source.getTarget());
16002
16391
  this.editorService.removeCommentData([id]);
16003
- session.renderer.loop.schedule({ commentHighlights: true });
16392
+ session.renderer.scheduleChanges({ commentHighlights: true });
16004
16393
  }
16005
16394
  onCommentTextReplace(commentId, newText) {
16006
16395
  const { session, comment } = this.regulatorService.getComment(commentId);
@@ -16033,7 +16422,7 @@ class Editor {
16033
16422
  window.removeEventListener('resize', this.rerenderResize);
16034
16423
  }
16035
16424
  rerenderMarker() {
16036
- this.renderer.loop.schedule({ marker: true });
16425
+ this.renderer.scheduleChanges({ marker: true });
16037
16426
  }
16038
16427
  onBlur() {
16039
16428
  if (!this.textInput.isFocused) {
@@ -16279,6 +16668,19 @@ class Editor {
16279
16668
  this.onSelectionChange();
16280
16669
  this.onContentChange();
16281
16670
  }
16671
+ insertContent(insertIndex, contents) {
16672
+ const insertContents = new InsertContentsModel({ insertIndex, contents });
16673
+ this.saveInsertContentsToHistory(insertContents);
16674
+ this.session.insertContents(insertIndex, structuredClone(contents));
16675
+ this.onSelectionChange();
16676
+ }
16677
+ replaceByContents(startIndex, endIndex, contents) {
16678
+ const count = endIndex - startIndex + 1;
16679
+ const replaceByContents = new ReplaceByContentsModel({ startIndex, count, contents });
16680
+ this.saveReplaceByContentsToHistory(replaceByContents);
16681
+ this.session.replaceByContents(startIndex, count, structuredClone(contents));
16682
+ this.onSelectionChange();
16683
+ }
16282
16684
  moveRange(model) {
16283
16685
  this.regulatorService.setTargetedSessionAsCurrent(model.targetTargets);
16284
16686
  const sourceSession = this.regulatorService.getTargetedSession(model.sourceTargets);
@@ -16362,6 +16764,13 @@ class Editor {
16362
16764
  });
16363
16765
  return textInterval;
16364
16766
  }
16767
+ getSelectedSlice() {
16768
+ const selectionRange = this.selection.selectedRange;
16769
+ if (selectionRange.isEmpty) {
16770
+ return null;
16771
+ }
16772
+ return this.session.getContentsSlice(selectionRange.start, selectionRange.end);
16773
+ }
16365
16774
  initMainSession() {
16366
16775
  const pageWidth = this.customPageWidth ?? Math.max(...this.model.pageFormats.map(x => x.pageWidth));
16367
16776
  this.container.nativeElement.style.maxWidth = `${pageWidth}px`;
@@ -16371,7 +16780,7 @@ class Editor {
16371
16780
  this.editorService.paragraphStyle(this.model.paragraphs[0].paragraphStyle);
16372
16781
  this.regulatorService.addMainSession(this.model, scalingRatio, this.container);
16373
16782
  }
16374
- onSelectionChange() {
16783
+ onSelectionChange(isMouseSelection = false) {
16375
16784
  this.session.applyToolbarStyles();
16376
16785
  this.renderer.updateSelection(this.selection.selectedRange);
16377
16786
  if (this.selection.isEmpty) {
@@ -16387,7 +16796,7 @@ class Editor {
16387
16796
  this.editorService.setPageFormat(pageFormat.pageFormatModel);
16388
16797
  this.rerenderMarker();
16389
16798
  this.regulatorService.setSelectedCommentAtCursor();
16390
- if (!this.selection.isEmpty && this.commentsVisible) {
16799
+ if (!this.selection.isEmpty && this.commentsVisible && !isMouseSelection) {
16391
16800
  const paragraphPos = this.session.selection.cursor;
16392
16801
  const cursor = PositionHelper.paragraphToPixel(this.session, paragraphPos.row, paragraphPos.column);
16393
16802
  const mainRect = this.mainRenderer.container.getBoundingClientRect();
@@ -16398,7 +16807,7 @@ class Editor {
16398
16807
  }
16399
16808
  }
16400
16809
  onContentChange() {
16401
- this.renderer.loop.schedule({ commentHighlights: true });
16810
+ this.renderer.scheduleChanges({ commentHighlights: true });
16402
16811
  if (this.search.term) {
16403
16812
  this.find(this.search.term);
16404
16813
  }
@@ -16502,7 +16911,7 @@ class Editor {
16502
16911
  const cursor = this.selection.cursor;
16503
16912
  this.selection.moveSelection(position);
16504
16913
  if (cursor.column !== this.selection.cursor.column || cursor.row !== this.selection.cursor.row) {
16505
- this.onSelectionChange();
16914
+ this.onSelectionChange(true);
16506
16915
  }
16507
16916
  this.scrollCursorIntoMainView();
16508
16917
  }
@@ -16603,7 +17012,7 @@ class Editor {
16603
17012
  viewOnlyModeSubscription() {
16604
17013
  return this.editorService.isViewOnly$.subscribe(() => {
16605
17014
  this.selection?.clearSelection();
16606
- this.renderer.loop.schedule({ grammar: true });
17015
+ this.renderer.scheduleChanges({ grammar: true });
16607
17016
  });
16608
17017
  }
16609
17018
  applyLeftMarginPageFormatSubscription() {
@@ -16846,49 +17255,59 @@ class Editor {
16846
17255
  }
16847
17256
  cutSelectedSubscription() {
16848
17257
  return this.editorService.cutSelected$.subscribe(() => {
16849
- this.onCut(new ClipboardEvent('cut'));
17258
+ const text = this.getSelectedText();
17259
+ const slice = this.getSelectedSlice();
17260
+ if (!text && !slice) {
17261
+ return;
17262
+ }
17263
+ this.clipboardHandler.copyAsync(text, slice, this.editorService.revisionId).catch(() => { });
17264
+ this.removeSelected();
17265
+ this.scrollCursorIntoMainView();
17266
+ this.editorService.setClipboardData(text);
16850
17267
  });
16851
17268
  }
16852
17269
  copySelectedSubscription() {
16853
17270
  return this.editorService.copySelected$.subscribe(() => {
16854
- this.onCopy(new ClipboardEvent('copy'));
17271
+ const text = this.getSelectedText();
17272
+ const slice = this.getSelectedSlice();
17273
+ if (!text && !slice) {
17274
+ return;
17275
+ }
17276
+ this.clipboardHandler.copyAsync(text, slice, this.editorService.revisionId).catch(() => { });
17277
+ this.editorService.setClipboardData(text);
16855
17278
  });
16856
17279
  }
16857
17280
  pasteFromClipboardSubscription() {
16858
- return this.editorService.pasteFromClipboard$.subscribe(() => {
16859
- this.readClipboard()
16860
- .then(data => this.pasteData(data))
16861
- .catch(() => {
16862
- // continue regardless error
16863
- });
17281
+ return this.editorService.pasteFromClipboard$
17282
+ .pipe(switchMap(() => from(this.clipboardHandler.readAsync())))
17283
+ .subscribe(({ text, sliceData }) => {
17284
+ this.pasteData(text, sliceData);
16864
17285
  });
16865
17286
  }
16866
- async readClipboard() {
16867
- const read = await navigator.permissions.query({ name: 'clipboard-read' });
16868
- return new Promise(resolve => {
16869
- if (navigator.clipboard && read.state != 'denied') {
16870
- navigator.clipboard
16871
- .readText()
16872
- .then(data => {
16873
- resolve(data);
16874
- })
16875
- .catch(() => {
16876
- // continue regardless error
16877
- });
17287
+ pasteData(text, sliceData) {
17288
+ if (sliceData) {
17289
+ this.insertSlice(sliceData);
17290
+ }
17291
+ else if (text) {
17292
+ const insertText = text.replace(/\r\n/g, '\n').replace(/\t/g, ' ');
17293
+ this.insert(insertText);
17294
+ this.scrollCursorIntoMainView();
17295
+ }
17296
+ }
17297
+ insertContentsSubscription() {
17298
+ return this.editorService.insertContents$.subscribe(contents => {
17299
+ const start = this.selection.range.start;
17300
+ const startIndex = ContentHelper.paragraphToDocumentIndex(this.session.displayData.paragraphs, start.row, start.column);
17301
+ if (this.selection.isEmpty) {
17302
+ this.insertContent(startIndex, contents);
16878
17303
  }
16879
17304
  else {
16880
- resolve(this.clipboardData);
17305
+ const end = this.selection.range.end;
17306
+ const endIndex = ContentHelper.paragraphToDocumentIndex(this.session.displayData.paragraphs, end.row, end.column) - 1;
17307
+ this.replaceByContents(startIndex, endIndex, contents);
16881
17308
  }
16882
17309
  });
16883
17310
  }
16884
- pasteData(data) {
16885
- if (!data) {
16886
- return;
16887
- }
16888
- const text = data.replace(/\r\n/g, '\n').replace(/\t/g, ' ');
16889
- this.insert(text);
16890
- this.scrollCursorIntoMainView();
16891
- }
16892
17311
  selectAllSubscription() {
16893
17312
  return this.editorService.selectAll$.subscribe(() => {
16894
17313
  this.selection.selectAll(this.session.model);
@@ -16900,11 +17319,6 @@ class Editor {
16900
17319
  this.removeSelected();
16901
17320
  });
16902
17321
  }
16903
- clipboardDataSubscription() {
16904
- return this.editorService.clipboardData$.subscribe(data => {
16905
- this.clipboardData = data;
16906
- });
16907
- }
16908
17322
  commandCreatedForEdges() {
16909
17323
  return this.commandsService.createCommand$
16910
17324
  .pipe(filter(x => !!x.targets.find(y => !!y.edgeData)))
@@ -16931,7 +17345,7 @@ class Editor {
16931
17345
  ];
16932
17346
  }
16933
17347
  rerenderCommentsSubscription() {
16934
- return this.editorService.commentSizeChanged$.subscribe(() => this.mainRenderer.loop.schedule({ comments: true }));
17348
+ return this.editorService.commentSizeChanged$.subscribe(() => this.mainRenderer.scheduleChanges({ comments: true }));
16935
17349
  }
16936
17350
  selectCommentSubscription() {
16937
17351
  return this.editorService.setCommentSelected$.subscribe(x => this.regulatorService.setSelectedComment(x));