fix: sibling nested lists of different formats stop sharing one w:lvl
A DOCX numbering level keeps the first format it saw, so a second nested list under the same parent with another number format or bullet char silently rendered as the first one's (an attr-less nested list under an upper-roman parent came back lower-alpha). The kind-mismatch fork now covers format and bullet char too, and copies the shallower levels so the importer's cycle walk still sees the ancestry.
This commit is contained in:
1 parent
a7fe334900
commit
5258feb146
1 file changed
+24
-8
+24
-8
@@ -238,9 +238,29 @@ class Numbering {
|
||||
return reference;
|
||||
}
|
||||
|
||||
levelKindAt(reference: string, depth: number): 'ordered' | 'bullet' | null {
|
||||
const l = this.map.get(reference)!.find((lv) => lv.level === depth);
|
||||
return l ? (l.format === LevelFormat.BULLET ? 'bullet' : 'ordered') : null;
|
||||
// A level keeps the first format it saw, so a sibling nested list of another kind,
|
||||
// number format or bullet char forks its own reference (the ODT side mints its own
|
||||
// list style). The fork copies the shallower levels so the importer's cycle walk
|
||||
// (listBaseCycle) still sees the ancestry.
|
||||
forkFor(reference: string, depth: number, node: TiptapNode, cycle: OrderedCycle): string {
|
||||
const levels = this.map.get(reference)!;
|
||||
const l = levels.find((lv) => lv.level === depth);
|
||||
if (!l) return reference;
|
||||
let format: string, text: string;
|
||||
if (node.type === 'orderedList') {
|
||||
const attr = node.attrs?.listStyleType as string | null | undefined;
|
||||
const def = effectiveOrderedDefAt(attr === 'multilevel' ? 'decimal' : attr, cycle);
|
||||
format = ORDERED_FORMAT[def.numFormat] ?? LevelFormat.DECIMAL;
|
||||
text = `%${depth + 1}${def.numSuffix}`;
|
||||
if (this.mlRefs.has(reference) && !attr) return reference; // chain member inherits
|
||||
} else {
|
||||
format = LevelFormat.BULLET;
|
||||
text = bulletCharOf(node, depth);
|
||||
}
|
||||
if (l.format === format && l.text === text) return reference;
|
||||
const fork = this.newReference();
|
||||
this.map.get(fork)!.push(...levels.filter((lv) => lv.level < depth));
|
||||
return fork;
|
||||
}
|
||||
|
||||
ensureLevel(reference: string, depth: number, node: TiptapNode, extraIndentCm: number, cycle: OrderedCycle): void {
|
||||
@@ -1480,11 +1500,7 @@ function listToParagraphs(
|
||||
let numberedFirst = false;
|
||||
for (const child of item.content ?? []) {
|
||||
if (child.type === 'bulletList' || child.type === 'orderedList') {
|
||||
// A level keeps the first kind it saw, so a sibling nested list of the other
|
||||
// kind forks its own reference (as the ODT side mints its own list style).
|
||||
const seen = num.levelKindAt(reference, depth + 1);
|
||||
const ref = seen && seen !== (child.type === 'orderedList' ? 'ordered' : 'bullet')
|
||||
? num.newReference() : reference;
|
||||
const ref = num.forkFor(reference, depth + 1, child, cChild);
|
||||
listToParagraphs(child, depth + 1, ref, indentCm, num, out, cChild);
|
||||
} else if (child.type === 'paragraph' || child.type === 'heading') {
|
||||
if (!numberedFirst) {
|
||||
|
||||
Reference in new issue
Block a user