From 29fa60ccf9fd537352de088fdf362e7df25fa076 Mon Sep 17 00:00:00 2001 From: Kevin Jahns Date: Thu, 29 Feb 2024 14:46:43 +0100 Subject: [PATCH] [Undo] add UndoManager.currStackItem --- package.json | 3 +- src/utils/UndoManager.js | 22 +++++---------- tests/undo-redo.tests.js | 61 +++++++++------------------------------- 3 files changed, 23 insertions(+), 63 deletions(-) diff --git a/package.json b/package.json index d0133c49..16544493 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,10 @@ "url": "https://github.com/sponsors/dmonad" }, "scripts": { + "clean": "rm -rf dist docs", "test": "npm run dist && node ./dist/tests.cjs --repetition-time 50", "test-extensive": "npm run lint && npm run dist && node ./dist/tests.cjs --production --repetition-time 10000", - "dist": "rm -rf dist && rollup -c && tsc", + "dist": "npm run clean && rollup -c && tsc", "watch": "rollup -wc", "lint": "markdownlint README.md && standard && tsc", "docs": "rm -rf docs; jsdoc --configure ./.jsdoc.json --verbose --readme ./README.md --package ./package.json || true", diff --git a/src/utils/UndoManager.js b/src/utils/UndoManager.js index c0dca63d..16ccb7ae 100644 --- a/src/utils/UndoManager.js +++ b/src/utils/UndoManager.js @@ -52,11 +52,6 @@ const clearUndoManagerStackItem = (tr, um, stackItem) => { * @return {StackItem?} */ const popStackItem = (undoManager, stack, eventType) => { - /** - * Whether a change happened - * @type {StackItem?} - */ - let result = null /** * Keep a reference to the transaction so we can fire the event with the changedParentTypes * @type {any} @@ -65,7 +60,7 @@ const popStackItem = (undoManager, stack, eventType) => { const doc = undoManager.doc const scope = undoManager.scope transact(doc, transaction => { - while (stack.length > 0 && result === null) { + while (stack.length > 0 && undoManager.currStackItem === null) { const store = doc.store const stackItem = /** @type {StackItem} */ (stack.pop()) /** @@ -113,7 +108,7 @@ const popStackItem = (undoManager, stack, eventType) => { performedChange = true } } - result = performedChange ? stackItem : null + undoManager.currStackItem = performedChange ? stackItem : null } transaction.changed.forEach((subProps, type) => { // destroy search marker if necessary @@ -123,11 +118,12 @@ const popStackItem = (undoManager, stack, eventType) => { }) _tr = transaction }, undoManager) - if (result != null) { + if (undoManager.currStackItem != null) { const changedParentTypes = _tr.changedParentTypes - undoManager.emit('stack-item-popped', [{ stackItem: result, type: eventType, changedParentTypes }, undoManager]) + undoManager.emit('stack-item-popped', [{ stackItem: undoManager.currStackItem, type: eventType, changedParentTypes }, undoManager]) + undoManager.currStackItem = null } - return result + return undoManager.currStackItem } /** @@ -196,7 +192,7 @@ export class UndoManager extends Observable { * * @type {StackItem|null} */ - this.doingStackItem = null + this.currStackItem = null this.lastChange = 0 this.ignoreRemoteMapChanges = ignoreRemoteMapChanges this.captureTimeout = captureTimeout @@ -337,12 +333,10 @@ export class UndoManager extends Observable { */ undo () { this.undoing = true - this.doingStackItem = array.last(this.undoStack) ?? null let res try { res = popStackItem(this, this.undoStack, 'undo') } finally { - this.doingStackItem = null this.undoing = false } return res @@ -355,12 +349,10 @@ export class UndoManager extends Observable { */ redo () { this.redoing = true - this.doingStackItem = array.last(this.redoStack) ?? null let res try { res = popStackItem(this, this.redoStack, 'redo') } finally { - this.doingStackItem = null this.redoing = false } return res diff --git a/tests/undo-redo.tests.js b/tests/undo-redo.tests.js index 82c98129..2fb2ff2e 100644 --- a/tests/undo-redo.tests.js +++ b/tests/undo-redo.tests.js @@ -719,62 +719,29 @@ export const testUndoDeleteInMap = (tc) => { /** * It should expose the StackItem being processed if undoing * - * @param {t.TestCase} tc - */ -export const testUndoDoingStackItem = async (tc) => { - const doc = new Y.Doc() - const text = doc.getText('text') - const undoManager = new Y.UndoManager([text]) - - undoManager.on('stack-item-added', /** @param {any} event */ event => { - event.stackItem.meta.set('str', '42') - }) - - const meta = new Promise((resolve) => { - setTimeout(() => resolve('ABORTED'), 50) - text.observe((event) => { - const /** @type {Y.UndoManager} */ origin = event.transaction.origin - if (origin === undoManager && origin.undoing) { - resolve(origin.doingStackItem?.meta.get('str')) - } - }) - }) - - text.insert(0, 'abc') - undoManager.undo() - - t.compare(await meta, '42') - t.compare(undoManager.doingStackItem, null) -} - -/** - * It should expose the StackItem being processed if redoing - * - * @param {t.TestCase} tc + * @param {t.TestCase} _tc */ -export const testRedoDoingStackItem = async (tc) => { +export const testUndoDoingStackItem = async (_tc) => { const doc = new Y.Doc() const text = doc.getText('text') const undoManager = new Y.UndoManager([text]) - undoManager.on('stack-item-added', /** @param {any} event */ event => { event.stackItem.meta.set('str', '42') }) - - const meta = new Promise(resolve => { - setTimeout(() => resolve('ABORTED'), 50) - text.observe((event) => { - const /** @type {Y.UndoManager} */ origin = event.transaction.origin - if (origin === undoManager && origin.redoing) { - resolve(origin.doingStackItem?.meta.get('str')) - } - }) + let metaUndo = /** @type {any} */ (null) + let metaRedo = /** @type {any} */ (null) + text.observe((event) => { + const /** @type {Y.UndoManager} */ origin = event.transaction.origin + if (origin === undoManager && origin.undoing) { + metaUndo = origin.currStackItem?.meta.get('str') + } else if (origin === undoManager && origin.redoing) { + metaRedo = origin.currStackItem?.meta.get('str') + } }) - text.insert(0, 'abc') undoManager.undo() undoManager.redo() - - t.compare(await meta, '42') - t.compare(undoManager.doingStackItem, null) + t.compare(metaUndo, '42', 'currStackItem is accessible while undoing') + t.compare(metaRedo, '42', 'currStackItem is accessible while redoing') + t.compare(undoManager.currStackItem, null, 'currStackItem is null after observe/transaction') }