Skip to content

Commit

Permalink
fix: undo error when input #
Browse files Browse the repository at this point in the history
  • Loading branch information
Jocs committed Oct 12, 2024
1 parent a1249a3 commit bfaa00e
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 56 deletions.
4 changes: 2 additions & 2 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
"name": "muya-examples",
"version": "0.0.1",
"description": "Muya vanilla ts demo project",
"author": "jocs <[email protected]>",
"scripts": {
"dev:demo": "vite"
},
"keywords": [],
"author": "jocs <[email protected]>",
"license": "MIT",
"dependencies": {
"@muyajs/core": "workspace:*",
"intl-segmenter-polyfill": "^0.4.4"
}
}
}
19 changes: 9 additions & 10 deletions packages/core/src/editor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ import { registerBlocks } from '../block';

const debug = logger('editor:');

class Editor {
public jsonState: JSONState;
public inlineRenderer: InlineRenderer;
public selection: Selection;
public searchModule: Search;
public clipboard: Clipboard;
public history: History;
public scrollPage: Nullable<ScrollPage> = null;
export class Editor {
jsonState: JSONState;
inlineRenderer: InlineRenderer;
selection: Selection;
searchModule: Search;
clipboard: Clipboard;
history: History;
scrollPage: Nullable<ScrollPage> = null;

private _activeContentBlock: Nullable<Content> = null;

constructor(public muya: Muya) {
Expand Down Expand Up @@ -334,5 +335,3 @@ class Editor {
this.focus();
}
}

export default Editor;
88 changes: 45 additions & 43 deletions packages/core/src/history/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ interface IStack {
redo: IOperation[];
}

type HistoryAction = 'undo' | 'redo';
enum HistoryAction {
UNDO = 'undo',
REDO = 'redo',
}

const DEFAULT_OPTIONS = {
delay: 1000,
Expand All @@ -30,10 +33,10 @@ const DEFAULT_OPTIONS = {
};

class History {
private lastRecorded: number = 0;
private ignoreChange: boolean = false;
private selectionStack: (Nullable<ISelection>)[] = [];
private stack: IStack = {
private _lastRecorded: number = 0;
private _ignoreChange: boolean = false;
private _selectionStack: (Nullable<ISelection>)[] = [];
private _stack: IStack = {
undo: [],
redo: [],
};
Expand All @@ -43,121 +46,120 @@ class History {
}

constructor(public muya: Muya, private options: IOptions = DEFAULT_OPTIONS) {
this.listen();
this._listen();
}

listen() {
private _listen() {
this.muya.eventCenter.on(
'json-change',
({
op,
source,
doc,
prevDoc,
}: {
op: JSONOpList;
source: string;
prevDoc: TState[];
doc: TState[];
}) => {
if (this.ignoreChange)
if (this._ignoreChange)
return;

if (!this.options.userOnly || source === 'user')
this.record(op, doc);
this._record(op, prevDoc);
else
this.transform(op);
},
);
}

change(source: HistoryAction, dest: HistoryAction) {
if (this.stack[source].length === 0)
private _change(source: HistoryAction, dest: HistoryAction) {
if (this._stack[source].length === 0)
return;

const { operation, selection } = this.stack[source].pop()!;
const { operation, selection } = this._stack[source].pop()!;
const inverseOperation = json1.type.invert(operation);

this.stack[dest].push({
this._stack[dest].push({
operation: inverseOperation as JSONOpList,
selection: this.selection.getSelection(),
});

this.lastRecorded = 0;
this.ignoreChange = true;
this._lastRecorded = 0;
this._ignoreChange = true;
this.muya.editor.updateContents(operation, selection, 'user');
this.ignoreChange = false;
this._ignoreChange = false;

this.getLastSelection();
}

clear() {
this.stack = { undo: [], redo: [] };
this._stack = { undo: [], redo: [] };
}

cutoff() {
this.lastRecorded = 0;
this._lastRecorded = 0;
}

getLastSelection() {
this.selectionStack.push(this.selection.getSelection());
this._selectionStack.push(this.selection.getSelection());

if (this.selectionStack.length > 2)
this.selectionStack.shift();
if (this._selectionStack.length > 2)
this._selectionStack.shift();

return this.selectionStack.length === 2 ? this.selectionStack[0] : null;
return this._selectionStack.length === 2 ? this._selectionStack[0] : null;
}

record(op: JSONOpList, doc: TState[]) {
private _record(op: JSONOpList, doc: TState[]) {
if (op.length === 0)
return;

let selection = this.getLastSelection();
this.stack.redo = [];
let undoOperation = json1.type.invert(op);
this._stack.redo = [];
let undoOperation = json1.type.invertWithDoc(op, doc as unknown as Doc);

const timestamp = Date.now();
if (
this.lastRecorded + this.options.delay > timestamp
&& this.stack.undo.length > 0
this._lastRecorded + this.options.delay > timestamp
&& this._stack.undo.length > 0
) {
const { operation: lastOperation, selection: lastSelection }
= this.stack.undo.pop()!;
= this._stack.undo.pop()!;
selection = lastSelection;
undoOperation = json1.type.makeInvertible(
json1.type.compose(undoOperation, lastOperation),
doc as unknown as Doc,
);
undoOperation = json1.type.compose(undoOperation, lastOperation);
}
else {
this.lastRecorded = timestamp;
this._lastRecorded = timestamp;
}

if (!undoOperation || undoOperation.length === 0)
return;

this.stack.undo.push({ operation: undoOperation, selection });
this._stack.undo.push({ operation: undoOperation, selection });

if (this.stack.undo.length > this.options.maxStack)
this.stack.undo.shift();
if (this._stack.undo.length > this.options.maxStack)
this._stack.undo.shift();
}

canRedo() {
return this.stack.redo.length > 0;
return this._stack.redo.length > 0;
}

redo() {
this.change('redo', 'undo');
this._change(HistoryAction.REDO, HistoryAction.UNDO);
}

transform(op: JSONOpList) {
transformStack(this.stack.undo, op);
transformStack(this.stack.redo, op);
transformStack(this._stack.undo, op);
transformStack(this._stack.redo, op);
}

canUndo() {
return this.stack.undo.length > 0;
return this._stack.undo.length > 0;
}

undo() {
this.change('undo', 'redo');
this._change(HistoryAction.UNDO, HistoryAction.REDO);
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/muya.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
CLASS_NAMES,
MUYA_DEFAULT_OPTIONS,
} from './config/index';
import Editor from './editor/index';
import { Editor } from './editor/index';
import EventCenter from './event/index';
import I18n from './i18n/index';
import { Ui } from './ui/ui';
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/state/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,15 @@ class JSONState {
}

dispatch(op: JSONOpList, source = 'user' /* user, api */) {
const prevDoc = this.getState();
this.apply(op);
// TODO: remove doc in future
const doc = this.getState();
debug.log(JSON.stringify(op));
this.muya.eventCenter.emit('json-change', {
op,
source,
prevDoc,
doc,
});
}
Expand All @@ -137,12 +139,14 @@ class JSONState {

requestAnimationFrame(() => {
const op = this._operationCache.reduce(json1.type.compose as any);
const prevDoc = this.getState();
this.apply(op);
// TODO: remove doc in future
const doc = this.getState();
this.muya.eventCenter.emit('json-change', {
op,
source: 'user',
prevDoc,
doc,
});
this._operationCache = [];
Expand Down

0 comments on commit bfaa00e

Please sign in to comment.