diff --git a/src/transforms/apply-operation.js b/src/transforms/apply-operation.js index b639c74d5..7971bae3a 100644 --- a/src/transforms/apply-operation.js +++ b/src/transforms/apply-operation.js @@ -187,19 +187,42 @@ function moveNode(state, operation) { const { path, newPath, newIndex } = operation let { document } = state const node = document.assertPath(path) + const index = path.pop() + const parentDepth = path.length // Remove the node from its current parent let parent = document.getParent(node.key) - const isParent = document == parent - const index = parent.nodes.indexOf(node) parent = parent.removeNode(index) - document = isParent ? parent : document.updateDescendant(parent) + document = parent.kind === 'document' ? parent : document.updateDescendant(parent) + + // Check if `parent` is an anchestor of `target` + const isAncestor = path.every((x, i) => x === newPath[i]) + + let target + + // If `parent` ia an ancestor of `target` and they have the same depth, + // then `parent` and `target` are the same node. + if (isAncestor && parentDepth === newPath.length) { + target = parent + } + + // Else if `parent` is an ancestor of `target` and `node` index is less than + // the index of the `target` ancestor with the same depth of `node`, + // then removing `node` changes the path to `target`. + // So we have to adjust `newPath` before picking `target`. + else if (isAncestor && index < newPath[parentDepth]) { + newPath[parentDepth]-- + target = document.assertPath(newPath) + } + + // Else pick `target` + else { + target = document.assertPath(newPath) + } // Insert the new node to its new parent - let target = document.assertPath(newPath) - const isTarget = document == target target = target.insertNode(newIndex, node) - document = isTarget ? target : document.updateDescendant(target) + document = target.kind === 'document' ? target : document.updateDescendant(target) state = state.set('document', document) return state diff --git a/test/transforms/fixtures/by-key/move-node-by-key/to-sibling/index.js b/test/transforms/fixtures/by-key/move-node-by-key/to-sibling/index.js new file mode 100644 index 000000000..ea457489a --- /dev/null +++ b/test/transforms/fixtures/by-key/move-node-by-key/to-sibling/index.js @@ -0,0 +1,11 @@ + +export default function (state) { + const { document, selection } = state + const first = document.getBlocks().first() + const container = document.nodes.last() + + return state + .transform() + .moveNodeByKey(first.key, container.key, 1) + .apply() +} diff --git a/test/transforms/fixtures/by-key/move-node-by-key/to-sibling/input.yaml b/test/transforms/fixtures/by-key/move-node-by-key/to-sibling/input.yaml new file mode 100644 index 000000000..7ac5a10c6 --- /dev/null +++ b/test/transforms/fixtures/by-key/move-node-by-key/to-sibling/input.yaml @@ -0,0 +1,15 @@ + +nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: one + - kind: block + type: container + nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: two diff --git a/test/transforms/fixtures/by-key/move-node-by-key/to-sibling/output.yaml b/test/transforms/fixtures/by-key/move-node-by-key/to-sibling/output.yaml new file mode 100644 index 000000000..7188f6966 --- /dev/null +++ b/test/transforms/fixtures/by-key/move-node-by-key/to-sibling/output.yaml @@ -0,0 +1,15 @@ + +nodes: + - kind: block + type: container + nodes: + - kind: block + type: paragraph + nodes: + - kind: text + text: two + - kind: block + type: paragraph + nodes: + - kind: text + text: one