diff --git a/src/muya/lib/contentState/history.js b/src/muya/lib/contentState/history.js index 8c980fb3..406ae1b2 100644 --- a/src/muya/lib/contentState/history.js +++ b/src/muya/lib/contentState/history.js @@ -6,9 +6,11 @@ class History { this.stack = [] this.index = -1 this.contentState = contentState + this.pending = null } undo () { + this.commitPending() if (this.index > 0) { this.index = this.index - 1 @@ -23,6 +25,7 @@ class History { } redo () { + this.pending = null const { index, stack } = this const len = stack.length if (index < len - 1) { @@ -38,6 +41,7 @@ class History { } push (state) { + this.pending = null this.stack.splice(this.index + 1) const copyState = deepCopy(state) this.stack.push(copyState) @@ -48,9 +52,20 @@ class History { this.index = this.index + 1 } + pushPending (state) { + this.pending = state + } + + commitPending () { + if (this.pending) { + this.push(this.pending) + } + } + clearHistory () { this.stack = [] this.index = -1 + this.pending = null } } diff --git a/src/muya/lib/contentState/index.js b/src/muya/lib/contentState/index.js index f93f0733..4efcaae9 100644 --- a/src/muya/lib/contentState/index.js +++ b/src/muya/lib/contentState/index.js @@ -135,16 +135,18 @@ class ContentState { if (!(cursor instanceof Cursor)) { cursor = new Cursor(cursor) } - const handler = () => { + + this.prevCursor = this.currentCursor + this.currentCursor = cursor + + const getHistoryState = () => { const { blocks, renderRange, currentCursor } = this - this.history.push({ + return { blocks, renderRange, cursor: currentCursor - }) + } } - this.prevCursor = this.currentCursor - this.currentCursor = cursor if (!cursor.noHistory) { if ( @@ -154,10 +156,19 @@ class ContentState { this.prevCursor.end.key !== cursor.end.key ) ) { - handler() + // Push history immediately + this.history.push(getHistoryState()) } else { + // WORKAROUND: The current engine doesn't support a smart history and we + // need to store the whole state. Therefore, we push history only when the + // user stops typing. Pushing one pending entry allows us to commit the + // change before an undo action is triggered to partially solve #1321. if (this.historyTimer) clearTimeout(this.historyTimer) - this.historyTimer = setTimeout(handler, 2000) + this.history.pushPending(getHistoryState()) + + this.historyTimer = setTimeout(() => { + this.history.commitPending() + }, 2000) } } }