diff --git a/src/lib/editor/extensions/tableOfContents.ts b/src/lib/editor/extensions/tableOfContents.ts index 8e6c794..046aa79 100644 --- a/src/lib/editor/extensions/tableOfContents.ts +++ b/src/lib/editor/extensions/tableOfContents.ts @@ -156,7 +156,11 @@ class TocView { const out: HeadingRef[] = []; this.editor.state.doc.descendants((node, pos) => { if (node.type.name === 'heading') { - const text = node.textContent.trim(); + // A hard break inside the heading is a line of the entry too — a book's + // "Chapter 1" / title pair is two lines in LibreOffice's own index. + let raw = ''; + node.forEach((child) => { raw += child.type.name === 'hardBreak' ? '\n' : child.textContent; }); + const text = raw.trim(); const level = Math.min(MAX_HEADING_LEVEL, (node.attrs.level as number) ?? 1); if (text && level <= max) out.push({ text, level, pos }); } @@ -246,7 +250,10 @@ class TocView { if (levelStyle) row.dataset.style = levelStyle; const text = document.createElement('span'); text.className = 'toc-text'; - text.textContent = e.text; + e.text.split('\n').forEach((part, li) => { + if (li) text.appendChild(document.createElement('br')); + text.appendChild(document.createTextNode(part)); + }); const leader = document.createElement('span'); leader.className = 'toc-leader'; // Real fill characters, as a word processor draws them: they scale with the font diff --git a/src/lib/export/odt.ts b/src/lib/export/odt.ts index e6f1f51..8a00299 100644 --- a/src/lib/export/odt.ts +++ b/src/lib/export/odt.ts @@ -3268,7 +3268,7 @@ function tocXml(toc: TocExport, index: number): string { `` : '') + toc.entries - .map(e => `${escapeXml(e.text)}${e.page}`) + .map(e => `${escapeXml(e.text).replace(/\n/g, '')}${e.page}`) .join('') + ``; return `${source}${body}`; diff --git a/src/styles/editor.css b/src/styles/editor.css index 8597464..062f211 100644 --- a/src/styles/editor.css +++ b/src/styles/editor.css @@ -225,7 +225,9 @@ } .paper .tiptap .toc-entry { display: flex; - align-items: baseline; + /* The last one: an entry whose heading carries a hard break is several lines, and the + leader and page number belong beside the last of them. */ + align-items: last baseline; cursor: pointer; } .paper .tiptap .toc-entry:hover .toc-text {