Do not let a table be the end of a note

A table, code block, quote or list as the last element of a
contenteditable element is a dead end: there is no node after it to put
the caret in, and no key that makes one, so the note simply cannot be
continued below it. Every engine behaves this way. The editor now keeps
an empty paragraph after such a block — it serializes to nothing, so it
never reaches the file, which a test pins down.

Tables got the rest of what they were missing while the cause was in
view: Tab walks the cells and a Tab out of the last one adds a row, the
toolbar button adds a row when the cursor is already in a table (a phone
has no Tab key, and it renames itself so it says which it will do), and
Ctrl/Cmd+Enter opens a paragraph after whatever block the cursor is in.
Empty cells are given a break, because a `<td></td>` with nothing in it
cannot be clicked into in Gecko — a blank cell was uneditable.

Driven in Firefox against a page that reproduces the dead end first.
This commit is contained in:
MechaCat02
2026-09-20 13:06:25 +02:00
parent 534b1b0f58
commit c259d97f04
3 changed files with 148 additions and 4 deletions

View File

@@ -220,3 +220,23 @@ test('a task list keeps its state through the DOM the editor builds', () => {
'<li class="task"><input type="checkbox" contenteditable="false" checked>fertig</li></ul>';
assert.equal(markdownFromDom(parseHtml(html)), '- [ ] offen\n- [x] fertig');
});
test('the editor\'s trailing escape line never reaches the file', () => {
// A table at the end of a contenteditable element is a dead end, so the
// editor keeps an empty paragraph after it. It must serialize to nothing,
// or every note with a table would grow a blank line on each save.
const html = markdownToHtml('| a | b |\n| --- | --- |\n| 1 | 2 |') + '<p><br></p>';
assert.equal(markdownFromDom(parseHtml(html)), '| a | b |\n| --- | --- |\n| 1 | 2 |');
});
test('an empty cell stays an empty cell', () => {
// The editor puts a <br> in blank cells so the caret can reach them.
unchanged('| a | b |\n| --- | --- |\n| | 2 |');
assert.match(markdownToHtml('| a |\n| --- |\n| |'), /<td><br><\/td>/);
});
test('a row the editor appended round-trips', () => {
const html = '<table><thead><tr><th>a</th><th>b</th></tr></thead>' +
'<tbody><tr><td>1</td><td>2</td></tr><tr><td><br></td><td><br></td></tr></tbody></table>';
assert.equal(markdownFromDom(parseHtml(html)), '| a | b |\n| --- | --- |\n| 1 | 2 |\n| | |');
});