fix: a page break survives beside other paragraph formatting

applyPageBreaks required its sentinel directly after the opening tag, but a
custom paragraph's serialized text starts with the FSZ/STY/PBX payloads, so
the break was silently dropped. It also minted PB# names, colliding with
applyParagraphBoxes' PB# — the importer then resolved both paragraphs to one
definition, painting the break paragraph with a stranger's box props. Now the
sentinel matches anywhere in the block and the pass mints PBK# instead.
This commit is contained in:
Steffen Becker committed 2026-08-16 07:29:06 +02:00
1 parent 6397594d35
commit 7a8c552342
1 file changed
+9 -4
+9 -4
View File
@@ -1581,7 +1581,9 @@ function applyPageBreaks(odtBytes: Uint8Array): Uint8Array {
const breakStyleFor = (source: string): string => {
const existing = nameBySource.get(source);
if (existing) return existing;
const name = `PB${++counter}`;
// PBK, not PB: applyParagraphBoxes mints PB names, and a duplicate style:name
// makes the importer resolve both paragraphs to whichever definition it finds.
const name = `PBK${++counter}`;
nameBySource.set(source, name);
const def = source ? findAutoStyle(content, source) : null;
minted.push(def
@@ -1591,15 +1593,18 @@ function applyPageBreaks(odtBytes: Uint8Array): Uint8Array {
return name;
};
// The sentinel sits anywhere in the block: a custom paragraph's serialized text
// starts with the FSZ/STY/PBX payloads (their passes run later), then the PGB.
content = content.replace(
new RegExp(`<text:(p|h)\\b([^>]*)>${PGB}`, 'g'),
(_m, tag: string, attrs: string) => {
new RegExp(`<text:(p|h)\\b([^>]*)>([\\s\\S]*?)</text:\\1>`, 'g'),
(m, tag: string, attrs: string, inner: string) => {
if (!inner.includes(PGB)) return m;
const sm = /text:style-name="([^"]*)"/.exec(attrs);
const name = breakStyleFor(sm ? sm[1] : '');
const newAttrs = sm
? attrs.replace(/text:style-name="[^"]*"/, `text:style-name="${name}"`)
: ` text:style-name="${name}"${attrs}`;
return `<text:${tag}${newAttrs}>`;
return `<text:${tag}${newAttrs}>${inner.split(PGB).join('')}</text:${tag}>`;
},
);
// Drop any sentinels not consumed above (defensive — never legitimate text).