Skip to content

Commit ab3dfd1

Browse files
committed
Generalize textblock merging in joinBackward to handle wrapped single textblocks
FIX: Make `joinBackward` capable of joining textblocks wrapped in parent nodes when the parent nodes themselves can't be joined (for example two list items which allow only a single paragraph). See https://discuss.prosemirror.net/t/joinbackward-behavior/3296
1 parent ed66020 commit ab3dfd1

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

src/commands.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,11 @@ export function joinBackward(state, dispatch, view) {
6161
return false
6262
}
6363

64-
function textblockAt(node, side) {
65-
for (; node; node = (side == "start" ? node.firstChild : node.lastChild))
64+
function textblockAt(node, side, only) {
65+
for (; node; node = (side == "start" ? node.firstChild : node.lastChild)) {
6666
if (node.isTextblock) return true
67+
if (only && node.childCount != 1) return false
68+
}
6769
return false
6870
}
6971

@@ -405,19 +407,21 @@ function deleteBarrier(state, $cut, dispatch) {
405407
return true
406408
}
407409

408-
if (canDelAfter && after.isTextblock && textblockAt(before, "end")) {
410+
if (canDelAfter && textblockAt(after, "start", true) && textblockAt(before, "end")) {
409411
let at = before, wrap = []
410412
for (;;) {
411413
wrap.push(at)
412414
if (at.isTextblock) break
413415
at = at.lastChild
414416
}
415-
if (at.canReplace(at.childCount, at.childCount, after.content)) {
417+
let afterText = after, afterDepth = 1
418+
for (; !afterText.isTextblock; afterText = afterText.firstChild) afterDepth++
419+
if (at.canReplace(at.childCount, at.childCount, afterText.content)) {
416420
if (dispatch) {
417421
let end = Fragment.empty
418422
for (let i = wrap.length - 1; i >= 0; i--) end = Fragment.from(wrap[i].copy(end))
419423
let tr = state.tr.step(new ReplaceAroundStep($cut.pos - wrap.length, $cut.pos + after.nodeSize,
420-
$cut.pos + 1, $cut.pos + after.nodeSize - 1,
424+
$cut.pos + afterDepth, $cut.pos + after.nodeSize - afterDepth,
421425
new Slice(end, wrap.length, 0), 0, true))
422426
dispatch(tr.scrollIntoView())
423427
}

test/test-commands.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,24 @@ describe("joinBackward", () => {
7575

7676
it("does nothing at start of doc", () =>
7777
apply(doc(p("<a>foo")), joinBackward, null))
78+
79+
it("can join single-textblock-child nodes", () => {
80+
let s = new Schema({
81+
nodes: {
82+
text: {inline: true},
83+
doc: {content: "block+"},
84+
block: {content: "para"},
85+
para: {content: "text*"}
86+
}
87+
})
88+
let doc = s.node("doc", null, [
89+
s.node("block", null, [s.node("para", null, [s.text("a")])]),
90+
s.node("block", null, [s.node("para", null, [s.text("b")])])
91+
])
92+
let state = EditorState.create({doc, selection: TextSelection.near(doc.resolve(7))})
93+
ist(joinBackward(state, tr => state = state.apply(tr)))
94+
ist(state.doc.toString(), "doc(block(para(\"ab\")))")
95+
})
7896
})
7997

8098
describe("selectNodeBackward", () => {

0 commit comments

Comments
 (0)