From 23ab02626f5ea7c56a5340d07dfa7ede48f79a1d Mon Sep 17 00:00:00 2001 From: Justin Weiss Date: Fri, 29 Dec 2017 10:57:21 -0800 Subject: [PATCH] Properly invert `merge_node` operations (#1477) --- packages/slate/src/operations/invert.js | 29 +++++++++++- .../history/undo/move-node-affecting-path.js | 36 ++++++++++++++ .../history/undo/move-node-before-itself.js | 47 +++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 packages/slate/test/history/undo/move-node-affecting-path.js create mode 100644 packages/slate/test/history/undo/move-node-before-itself.js diff --git a/packages/slate/src/operations/invert.js b/packages/slate/src/operations/invert.js index 22913616a..ddbc6cd1b 100644 --- a/packages/slate/src/operations/invert.js +++ b/packages/slate/src/operations/invert.js @@ -48,7 +48,34 @@ function invertOperation(op) { if (type == 'move_node') { const { newPath, path } = op - const inverse = op.set('path', newPath).set('newPath', path) + let inversePath = newPath + let inverseNewPath = path + + const pathLast = path.length - 1 + const newPathLast = newPath.length - 1 + + // If the node's old position was a left sibling of an ancestor of + // its new position, we need to adjust part of the path by -1. + if (path.length < inversePath.length && + path.slice(0, pathLast).every((e, i) => e == inversePath[i]) && + path[pathLast] < inversePath[pathLast]) { + inversePath = inversePath.slice(0, pathLast) + .concat([inversePath[pathLast] - 1]) + .concat(inversePath.slice(pathLast + 1, inversePath.length)) + } + + // If the node's new position is an ancestor of the old position, + // or a left sibling of an ancestor of its old position, we need + // to adjust part of the path by 1. + if (newPath.length < inverseNewPath.length && + newPath.slice(0, newPathLast).every((e, i) => e == inverseNewPath[i]) && + newPath[newPathLast] <= inverseNewPath[newPathLast]) { + inverseNewPath = inverseNewPath.slice(0, newPathLast) + .concat([inverseNewPath[newPathLast] + 1]) + .concat(inverseNewPath.slice(newPathLast + 1, inverseNewPath.length)) + } + + const inverse = op.set('path', inversePath).set('newPath', inverseNewPath) return inverse } diff --git a/packages/slate/test/history/undo/move-node-affecting-path.js b/packages/slate/test/history/undo/move-node-affecting-path.js new file mode 100644 index 000000000..44abdfdf9 --- /dev/null +++ b/packages/slate/test/history/undo/move-node-affecting-path.js @@ -0,0 +1,36 @@ +/** @jsx h */ + +import h from '../../helpers/h' + +export default function (value) { + return value + .change() + .moveNodeByKey('c', 'd', 1) + .value + .change() + .undo() + .value +} + +export const input = ( + + + + one + + + two + + + + three + + + + four + + + +) + +export const output = input diff --git a/packages/slate/test/history/undo/move-node-before-itself.js b/packages/slate/test/history/undo/move-node-before-itself.js new file mode 100644 index 000000000..8d6c64ef6 --- /dev/null +++ b/packages/slate/test/history/undo/move-node-before-itself.js @@ -0,0 +1,47 @@ +/** @jsx h */ + +import h from '../../helpers/h' + +export default function (value) { + return value + .change() + .moveNodeByKey('h', 'a', 0) + .value + .change() + .undo() + .value +} + +export const input = ( + + + + one + + + + two + + + + three + + + four + + + five + + + + + six + + + seven + + + +) + +export const output = input