RED-6786: faster text editor
This commit is contained in:
parent
4fc7fa40d8
commit
c68e92f726
@ -1,10 +1,10 @@
|
||||
<ngx-monaco-editor
|
||||
(init)="onCodeEditorInit($event)"
|
||||
(ngModelChange)="codeEditorTextChanged($event)"
|
||||
(ngModelChange)="_editorTextChanged$.next($event)"
|
||||
(paste)="onPaste()"
|
||||
*ngIf="!showDiffEditor"
|
||||
[(ngModel)]="value"
|
||||
[options]="editorOptions"
|
||||
(paste)="onPaste()"
|
||||
></ngx-monaco-editor>
|
||||
|
||||
<ngx-monaco-diff-editor
|
||||
@ -14,5 +14,3 @@
|
||||
[options]="editorOptions"
|
||||
[original]="diffEditorText"
|
||||
></ngx-monaco-diff-editor>
|
||||
|
||||
<ng-container *ngIf="_codeEditorTextChangedHandler$ | async"></ng-container>
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
||||
import { List, LoadingService, OnChange } from '@iqser/common-ui';
|
||||
import { EditorThemeService } from '@services/editor-theme.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import { debounceTime, filter, tap } from 'rxjs/operators';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import IStandaloneEditorConstructionOptions = monaco.editor.IStandaloneEditorConstructionOptions;
|
||||
import ICodeEditor = monaco.editor.ICodeEditor;
|
||||
import IDiffEditor = monaco.editor.IDiffEditor;
|
||||
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
|
||||
import ILineChange = monaco.editor.ILineChange;
|
||||
import IEditorMouseEvent = monaco.editor.IEditorMouseEvent;
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { debounceTime, filter, tap } from 'rxjs/operators';
|
||||
|
||||
const MIN_WORD_LENGTH = 2;
|
||||
const lineChangeToDecoration = ({ originalEndLineNumber, originalStartLineNumber }: ILineChange) =>
|
||||
@ -41,28 +42,35 @@ export class EditorComponent implements OnInit, OnChanges {
|
||||
editorOptions: IStandaloneEditorConstructionOptions = {};
|
||||
codeEditor: ICodeEditor;
|
||||
value: string;
|
||||
protected _initialEntriesMap = new Set<string>();
|
||||
|
||||
protected readonly _editorTextChanged$ = new Subject<string>();
|
||||
private _diffEditor: IDiffEditor;
|
||||
private _decorations: string[] = [];
|
||||
private readonly _codeEditorTextChanged$ = new BehaviorSubject<string>('');
|
||||
protected readonly _codeEditorTextChangedHandler$ = this._codeEditorTextChanged$.asObservable().pipe(
|
||||
filter(Boolean),
|
||||
debounceTime(0), // prevent race condition with onPaste event
|
||||
tap(newText => {
|
||||
const newDecorations = this.#getDecorations(newText);
|
||||
this._decorations = this.codeEditor.deltaDecorations(this._decorations, newDecorations);
|
||||
this.diffValue = this.value;
|
||||
this._loadingService.stop();
|
||||
}),
|
||||
);
|
||||
|
||||
constructor(private readonly _loadingService: LoadingService, private readonly _editorThemeService: EditorThemeService) {}
|
||||
constructor(private readonly _loadingService: LoadingService, private readonly _editorThemeService: EditorThemeService) {
|
||||
const textChanged$ = this._editorTextChanged$.pipe(
|
||||
debounceTime(300), // prevent race condition with onPaste event
|
||||
takeUntilDestroyed(),
|
||||
filter(text => text.length > 0),
|
||||
tap(newText => {
|
||||
const newDecorations = this.#getDecorations(newText);
|
||||
this._decorations = this.codeEditor.deltaDecorations(this._decorations, newDecorations);
|
||||
this.diffValue = this.value;
|
||||
this._loadingService.stop();
|
||||
}),
|
||||
);
|
||||
// eslint-disable-next-line rxjs/no-ignored-subscription
|
||||
textChanged$.subscribe();
|
||||
}
|
||||
|
||||
get currentEntries(): string[] {
|
||||
return this.value.split('\n');
|
||||
}
|
||||
|
||||
// TODO: this is called way too often, we need a better option
|
||||
get hasChanges(): boolean {
|
||||
return this.currentEntries.toString() !== this.initialEntries.toString();
|
||||
return this.value.trim() !== this.initialEntries.join('\n');
|
||||
}
|
||||
|
||||
get #currentEntriesCount(): number {
|
||||
@ -73,10 +81,6 @@ export class EditorComponent implements OnInit, OnChanges {
|
||||
this._loadingService.start();
|
||||
}
|
||||
|
||||
codeEditorTextChanged(event) {
|
||||
this._codeEditorTextChanged$.next(event);
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.diffEditorText) {
|
||||
this._diffEditor?.getOriginalEditor().setValue(this.diffEditorText);
|
||||
@ -114,17 +118,23 @@ export class EditorComponent implements OnInit, OnChanges {
|
||||
|
||||
revert() {
|
||||
this.value = this.initialEntries.join('\n');
|
||||
this._initialEntriesMap = new Set<string>(this.initialEntries);
|
||||
this.diffValue = this.value;
|
||||
this._diffEditor?.getModifiedEditor().setValue(this.diffValue);
|
||||
this._editorTextChanged$.next(this.value);
|
||||
}
|
||||
|
||||
#getDecorations(newText: string) {
|
||||
const currentEntries = newText.split('/n');
|
||||
const currentEntries = newText.split('\n');
|
||||
const newDecorations: IModelDeltaDecoration[] = [];
|
||||
|
||||
for (let index = 0; index < currentEntries.length; ++index) {
|
||||
const entry = currentEntries.at(index);
|
||||
if (!this.#isNew(entry)) {
|
||||
for (let index = 0; index < currentEntries.length; index++) {
|
||||
const entry = currentEntries.at(index)?.trim();
|
||||
if (!entry || entry.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this._initialEntriesMap.has(entry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -187,10 +197,6 @@ export class EditorComponent implements OnInit, OnChanges {
|
||||
});
|
||||
}
|
||||
|
||||
#isNew(entry: string): boolean {
|
||||
return this.initialEntries.indexOf(entry) < 0 && entry?.trim().length > 0;
|
||||
}
|
||||
|
||||
#getDecoration(entry: string, line: number): IModelDeltaDecoration {
|
||||
const cssClass = entry.length < MIN_WORD_LENGTH ? 'too-short-marker' : 'changed-row-marker';
|
||||
const range = new monaco.Range(line, 1, line, 1);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user