From 17a014deacffcd93570ebd4f4c08a562de4c5c92 Mon Sep 17 00:00:00 2001 From: Nicolas Gaborit Date: Mon, 13 Feb 2017 23:27:59 +0100 Subject: [PATCH] Fix deleteAtRange with nested blocks (#594) * Add failing test for backspace in a nested block * Fix deleteAtRange * Move to test to delete-at-range * Use and improve getHighestOnlyChildParent --- src/models/node.js | 19 +++++++---- src/transforms/at-range.js | 3 +- .../double-nested-block/index.js | 7 ++++ .../double-nested-block/input.yaml | 32 +++++++++++++++++++ .../double-nested-block/output.yaml | 13 ++++++++ 5 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 test/transforms/fixtures/at-range/delete-at-range/double-nested-block/index.js create mode 100644 test/transforms/fixtures/at-range/delete-at-range/double-nested-block/input.yaml create mode 100644 test/transforms/fixtures/at-range/delete-at-range/double-nested-block/output.yaml diff --git a/src/models/node.js b/src/models/node.js index ddebb8719..2b4e66e35 100644 --- a/src/models/node.js +++ b/src/models/node.js @@ -658,15 +658,20 @@ const Node = { */ getHighestOnlyChildParent(key) { - let child = this.assertDescendant(key) - let match = null - let parent + const ancestors = this.getAncestors(key) - while (parent = this.getParent(child)) { - if (parent == null || parent.nodes.size > 1) return match - match = parent - child = parent + if (!ancestors) { + key = Normalize.key(key) + throw new Error(`Could not find a descendant node with key "${key}".`) } + + return ancestors + // Skip this node + .skipLast() + // Take parents until there are more than one child + .reverse().takeUntil(p => p.nodes.size > 1) + // Pick the highest + .last() }, /** diff --git a/src/transforms/at-range.js b/src/transforms/at-range.js index f5816fe82..6f6aee1ab 100644 --- a/src/transforms/at-range.js +++ b/src/transforms/at-range.js @@ -111,7 +111,8 @@ export function deleteAtRange(transform, range, options = {}) { transform.moveNodeByKey(child.key, newKey, newIndex, OPTS) }) - const lonely = document.getFurthest(endBlock.key, p => p.nodes.size == 1) || endBlock + // Remove parents of endBlock as long as they have a single child + const lonely = document.getHighestOnlyChildParent(endBlock.key) || endBlock transform.removeNodeByKey(lonely.key, OPTS) } diff --git a/test/transforms/fixtures/at-range/delete-at-range/double-nested-block/index.js b/test/transforms/fixtures/at-range/delete-at-range/double-nested-block/index.js new file mode 100644 index 000000000..69d0e28e5 --- /dev/null +++ b/test/transforms/fixtures/at-range/delete-at-range/double-nested-block/index.js @@ -0,0 +1,7 @@ + +export default function (state) { + return state + .transform() + .deleteAtRange(state.selection) + .apply() +} diff --git a/test/transforms/fixtures/at-range/delete-at-range/double-nested-block/input.yaml b/test/transforms/fixtures/at-range/delete-at-range/double-nested-block/input.yaml new file mode 100644 index 000000000..1bc26659b --- /dev/null +++ b/test/transforms/fixtures/at-range/delete-at-range/double-nested-block/input.yaml @@ -0,0 +1,32 @@ + +document: + key: a + nodes: + - key: b + kind: block + type: list + nodes: + - key: c + kind: block + type: item + nodes: + - key: d + kind: block + type: line + nodes: + - key: e + kind: text + text: "Text" + - key: f + kind: block + type: line + nodes: + - key: g + kind: text + text: "" +selection: + anchorKey: e + anchorOffset: 4 + focusKey: g + focusOffset: 0 + isFocused: true diff --git a/test/transforms/fixtures/at-range/delete-at-range/double-nested-block/output.yaml b/test/transforms/fixtures/at-range/delete-at-range/double-nested-block/output.yaml new file mode 100644 index 000000000..71a6d4138 --- /dev/null +++ b/test/transforms/fixtures/at-range/delete-at-range/double-nested-block/output.yaml @@ -0,0 +1,13 @@ + +nodes: +- kind: block + type: list + nodes: + - kind: block + type: item + nodes: + - kind: block + type: line + nodes: + - kind: text + text: "Text"