diff --git a/src/structs/Item.js b/src/structs/Item.js index 0b39a246..704dcd32 100644 --- a/src/structs/Item.js +++ b/src/structs/Item.js @@ -211,11 +211,6 @@ export const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemo while (left !== null && left.redone !== null) { left = getItemCleanStart(transaction, left.redone) } - // check wether we were allowed to follow right (indicating that originally this op was replaced by another item) - if (left === null || /** @type {AbstractType} */ (left.parent)._item !== parentItem) { - // invalid parent; should never happen - return null - } if (left && left.right !== null) { // It is not possible to redo this item because it conflicts with a // change from another client diff --git a/tests/undo-redo.tests.js b/tests/undo-redo.tests.js index b5bbeba8..3b3794f0 100644 --- a/tests/undo-redo.tests.js +++ b/tests/undo-redo.tests.js @@ -602,3 +602,32 @@ export const testBehaviorOfIgnoreremotemapchangesProperty = tc => { t.assert(map1.get('x') === 2) t.assert(map2.get('x') === 2) } + +/** + * Special deletion case. + * + * @see https://github.com/yjs/yjs/issues/447 + * @param {t.TestCase} tc + */ +export const testSpecialDeletionCase = tc => { + const origin = 'undoable' + const doc = new Y.Doc() + const fragment = doc.getXmlFragment() + const undoManager = new Y.UndoManager(fragment, { trackedOrigins: new Set([origin]) }) + doc.transact(() => { + const e = new Y.XmlElement('test') + e.setAttribute('a', '1') + e.setAttribute('b', '2') + fragment.insert(0, [e]) + }) + t.compareStrings(fragment.toString(), '') + doc.transact(() => { + // change attribute "b" and delete test-node + const e = fragment.get(0) + e.setAttribute('b', '3') + fragment.delete(0) + }, origin) + t.compareStrings(fragment.toString(), '') + undoManager.undo() + t.compareStrings(fragment.toString(), '') +}