Skip to content

Commit cfcad60

Browse files
committed
Fix bug in reading contenteditable text from DOM
Which often caused strangeness around empty lines Issue codemirror#4307
1 parent aab2357 commit cfcad60

File tree

2 files changed

+39
-12
lines changed

2 files changed

+39
-12
lines changed

src/input/ContentEditableInput.js

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -375,34 +375,40 @@ function badPos(pos, bad) { if (bad) pos.bad = true; return pos }
375375
function domTextBetween(cm, from, to, fromLine, toLine) {
376376
let text = "", closing = false, lineSep = cm.doc.lineSeparator()
377377
function recognizeMarker(id) { return marker => marker.id == id }
378+
function close() {
379+
if (closing) {
380+
text += lineSep
381+
closing = false
382+
}
383+
}
384+
function addText(str) {
385+
if (str) {
386+
close()
387+
text += str
388+
}
389+
}
378390
function walk(node) {
379391
if (node.nodeType == 1) {
380392
let cmText = node.getAttribute("cm-text")
381393
if (cmText != null) {
382-
if (cmText == "") text += node.textContent.replace(/\u200b/g, "")
383-
else text += cmText
394+
addText(cmText || node.textContent.replace(/\u200b/g, ""))
384395
return
385396
}
386397
let markerID = node.getAttribute("cm-marker"), range
387398
if (markerID) {
388399
let found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID))
389400
if (found.length && (range = found[0].find()))
390-
text += getBetween(cm.doc, range.from, range.to).join(lineSep)
401+
addText(getBetween(cm.doc, range.from, range.to).join(lineSep))
391402
return
392403
}
393404
if (node.getAttribute("contenteditable") == "false") return
405+
let isBlock = /^(pre|div|p)$/i.test(node.nodeName)
406+
if (isBlock) close()
394407
for (let i = 0; i < node.childNodes.length; i++)
395408
walk(node.childNodes[i])
396-
if (/^(pre|div|p)$/i.test(node.nodeName))
397-
closing = true
409+
if (isBlock) closing = true
398410
} else if (node.nodeType == 3) {
399-
let val = node.nodeValue
400-
if (!val) return
401-
if (closing) {
402-
text += lineSep
403-
closing = false
404-
}
405-
text += val
411+
addText(node.nodeValue)
406412
}
407413
}
408414
for (;;) {

test/contenteditable_test.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,25 @@
8686
cm.display.input.updateFromDOM()
8787
eq(byClassName(cm.getInputField(), "inserted").length, 0)
8888
}, {inputStyle: "contenteditable", value: "foo"})
89+
90+
testCM("type_on_empty_line", function(cm) {
91+
cm.setSelection(Pos(1, 0))
92+
findTextNode(cm, "\u200b").nodeValue += "hello"
93+
cm.display.input.updateFromDOM()
94+
eq(cm.getValue(), "foo\nhello\nbar")
95+
}, {inputStyle: "contenteditable", value: "foo\n\nbar"})
96+
97+
testCM("type_after_empty_line", function(cm) {
98+
cm.setSelection(Pos(2, 0))
99+
findTextNode(cm, "bar").nodeValue = "hellobar"
100+
cm.display.input.updateFromDOM()
101+
eq(cm.getValue(), "foo\n\nhellobar")
102+
}, {inputStyle: "contenteditable", value: "foo\n\nbar"})
103+
104+
testCM("type_before_empty_line", function(cm) {
105+
cm.setSelection(Pos(0, 3))
106+
findTextNode(cm, "foo").nodeValue = "foohello"
107+
cm.display.input.updateFromDOM()
108+
eq(cm.getValue(), "foohello\n\nbar")
109+
}, {inputStyle: "contenteditable", value: "foo\n\nbar"})
89110
})();

0 commit comments

Comments
 (0)