@stll/folio-core 0.44.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-edits/__fixtures__/paragraphs.js +2 -2
- package/dist/ai-edits/apply.js +59 -19
- package/dist/ai-edits/headless.js +2 -1
- package/dist/compare/compare.js +2 -5
- package/dist/compare/content-alignment.js +78 -53
- package/dist/compare/inline-atoms.js +34 -20
- package/dist/compare/scenario.js +2 -5
- package/dist/compare/types.d.ts +9 -1
- package/dist/compare/types.js +12 -1
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/content-controls/checkboxDisplay.d.ts +11 -0
- package/dist/content-controls/checkboxDisplay.js +40 -0
- package/dist/content-controls/findContentControls.js +3 -1
- package/dist/content-controls/mutateContentControls.js +21 -4
- package/dist/controller/contentControlWidgetController.d.ts +1 -0
- package/dist/controller/contentControlWidgetController.js +3 -0
- package/dist/controller/hiddenEditorApi.js +3 -1
- package/dist/controller/hiddenEditorManager.d.ts +1 -1
- package/dist/controller/hiddenEditorManager.js +6 -3
- package/dist/display-list/build/buildDisplayList.js +20 -1
- package/dist/display-list/build/imagePrimitives.d.ts +1 -1
- package/dist/display-list/build/imagePrimitives.js +3 -1
- package/dist/display-list/build/paragraphPrimitives.js +21 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +18 -10
- package/dist/display-list/types.d.ts +17 -0
- package/dist/document-operations.js +14 -3
- package/dist/docx/attributeRemainder.d.ts +43 -0
- package/dist/docx/attributeRemainder.js +65 -0
- package/dist/docx/blockContentParser.d.ts +1 -1
- package/dist/docx/blockContentParser.js +87 -63
- package/dist/docx/blockPlainText.d.ts +3 -4
- package/dist/docx/blockPlainText.js +1 -0
- package/dist/docx/bookmarkPlacement.js +2 -0
- package/dist/docx/borderParser.js +5 -5
- package/dist/docx/commentAnchorIndex.d.ts +30 -0
- package/dist/docx/commentAnchorIndex.js +50 -0
- package/dist/docx/commentParser.d.ts +1 -1
- package/dist/docx/commentParser.js +78 -50
- package/dist/docx/commentRangeIntegrity.d.ts +16 -1
- package/dist/docx/commentRangeIntegrity.js +42 -1
- package/dist/docx/commentRangeJoin.d.ts +9 -0
- package/dist/docx/commentRangeJoin.js +33 -0
- package/dist/docx/commentReferenceCompletion.d.ts +9 -0
- package/dist/docx/commentReferenceCompletion.js +47 -0
- package/dist/docx/commentReferenceNormalization.js +1 -0
- package/dist/docx/commentReplyMarkers.js +11 -19
- package/dist/docx/commentThreadKey.d.ts +18 -0
- package/dist/docx/commentThreadKey.js +22 -0
- package/dist/docx/compatibility.js +1 -0
- package/dist/docx/containerChildren.d.ts +111 -0
- package/dist/docx/containerChildren.gen.d.ts +28 -0
- package/dist/docx/containerChildren.gen.js +246 -0
- package/dist/docx/containerChildren.js +103 -0
- package/dist/docx/diagramPreview.js +87 -27
- package/dist/docx/documentParser.d.ts +1 -1
- package/dist/docx/documentParser.js +3 -3
- package/dist/docx/ensureParaIds.js +17 -7
- package/dist/docx/fieldParser.d.ts +1 -1
- package/dist/docx/fieldParser.js +4 -4
- package/dist/docx/fieldState.d.ts +26 -0
- package/dist/docx/fieldState.js +53 -0
- package/dist/docx/footnoteParser.d.ts +1 -1
- package/dist/docx/graphicFrameLocks.d.ts +16 -4
- package/dist/docx/graphicFrameLocks.js +19 -6
- package/dist/docx/groupDrawingParser.js +3 -3
- package/dist/docx/headerFooterParser.js +1 -1
- package/dist/docx/headerFooterReferenceNormalization.js +1 -0
- package/dist/docx/hyperlinkParser.d.ts +27 -8
- package/dist/docx/hyperlinkParser.js +78 -20
- package/dist/docx/imageParser.d.ts +9 -1
- package/dist/docx/imageParser.js +91 -20
- package/dist/docx/imageRawXml.d.ts +14 -1
- package/dist/docx/imageRawXml.js +30 -6
- package/dist/docx/inlineWrapperContent.d.ts +85 -0
- package/dist/docx/inlineWrapperContent.js +84 -0
- package/dist/docx/mathToMathml.js +12 -14
- package/dist/docx/nonVisualDrawingProps.d.ts +34 -0
- package/dist/docx/nonVisualDrawingProps.js +46 -0
- package/dist/docx/normalizeBaseDirection.js +10 -1
- package/dist/docx/paraIdAttribute.d.ts +21 -0
- package/dist/docx/paraIdAttribute.js +64 -0
- package/dist/docx/paragraphParser.d.ts +1 -1
- package/dist/docx/paragraphParser.js +277 -168
- package/dist/docx/paragraphPropertySource.js +5 -1
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +1 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +9 -52
- package/dist/docx/paragraphTraversal.js +7 -4
- package/dist/docx/parseWarningMessage.js +2 -1
- package/dist/docx/parser.js +2 -2
- package/dist/docx/preservedRunContent.d.ts +32 -0
- package/dist/docx/preservedRunContent.js +86 -0
- package/dist/docx/previewBudget.d.ts +64 -0
- package/dist/docx/previewBudget.js +88 -0
- package/dist/docx/renderedPageBreakNormalization.js +2 -4
- package/dist/docx/revisionIdNormalization.js +17 -5
- package/dist/docx/rezip.js +91 -36
- package/dist/docx/runParser.d.ts +1 -1
- package/dist/docx/runParser.js +16 -12
- package/dist/docx/sdtPropertiesPatch.js +24 -18
- package/dist/docx/sectionParser.js +8 -1
- package/dist/docx/sectionReferenceHistory.js +2 -2
- package/dist/docx/selectiveSave.js +6 -6
- package/dist/docx/selectiveXmlPatch.d.ts +46 -2
- package/dist/docx/selectiveXmlPatch.js +86 -39
- package/dist/docx/serializer/blockSdtSerializer.js +38 -26
- package/dist/docx/serializer/borderSerializer.d.ts +1 -1
- package/dist/docx/serializer/borderSerializer.js +15 -14
- package/dist/docx/serializer/commentSerializer.d.ts +41 -16
- package/dist/docx/serializer/commentSerializer.js +87 -92
- package/dist/docx/serializer/documentSerializer.js +8 -11
- package/dist/docx/serializer/fontTableSerializer.js +6 -6
- package/dist/docx/serializer/headerFooterSerializer.js +12 -14
- package/dist/docx/serializer/markupRangeAttributes.js +2 -2
- package/dist/docx/serializer/noteSerializer.js +8 -8
- package/dist/docx/serializer/numberingSerializer.js +7 -6
- package/dist/docx/serializer/paragraphSerializer.js +93 -72
- package/dist/docx/serializer/partNamespaces.js +2 -2
- package/dist/docx/serializer/runSerializer.js +73 -44
- package/dist/docx/serializer/sectionPropertiesSerializer.js +19 -14
- package/dist/docx/serializer/settingsSerializer.js +4 -3
- package/dist/docx/serializer/stylesSerializer.js +6 -6
- package/dist/docx/serializer/tableSerializer.js +28 -17
- package/dist/docx/serializer/textFormattingSerializer.js +29 -28
- package/dist/docx/serializer/themeSerializer.js +6 -6
- package/dist/docx/serializer/trackedChangeAttributes.js +2 -2
- package/dist/docx/serializer/xmlUtils.d.ts +1 -2
- package/dist/docx/serializer/xmlUtils.js +1 -13
- package/dist/docx/server/boundedArchive.d.ts +12 -0
- package/dist/docx/server/boundedArchive.js +20 -1
- package/dist/docx/server/createBilingualDocument.js +3 -1
- package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
- package/dist/docx/server/materializeYjsDocx.js +9 -1
- package/dist/docx/server/migrateYjsAttrSchema.d.ts +55 -0
- package/dist/docx/server/migrateYjsAttrSchema.js +95 -0
- package/dist/docx/server/validateDocxConformance.js +22 -1
- package/dist/docx/shapeParser.js +12 -10
- package/dist/docx/tableParser.d.ts +1 -1
- package/dist/docx/tableParser.js +206 -85
- package/dist/docx/textBoxParser.d.ts +25 -2
- package/dist/docx/textBoxParser.js +59 -4
- package/dist/docx/unzip.d.ts +23 -0
- package/dist/docx/unzip.js +37 -26
- package/dist/docx/verbatimCapture.js +1 -1
- package/dist/docx/vmlImageParser.d.ts +17 -1
- package/dist/docx/vmlImageParser.js +20 -3
- package/dist/docx/vmlPreview.d.ts +1 -3
- package/dist/docx/vmlPreview.js +2 -30
- package/dist/docx/xmlEncoding.d.ts +5 -0
- package/dist/docx/xmlEncoding.js +12 -0
- package/dist/docx/xmlParser.d.ts +26 -2
- package/dist/docx/xmlParser.js +70 -27
- package/dist/docx/xmlResourceLimits.d.ts +89 -9
- package/dist/docx/xmlResourceLimits.js +105 -24
- package/dist/headless-layout.js +10 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +5 -2
- package/dist/internal/paragraphFormattingSerialization.js +3 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +102 -12
- package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
- package/dist/layout-engine/measure/tableCellFloating.js +2 -0
- package/dist/layout-engine/types.d.ts +23 -1
- package/dist/layout-painter/renderImage.d.ts +5 -1
- package/dist/layout-painter/renderImage.js +14 -6
- package/dist/layout-painter/renderPage.d.ts +2 -0
- package/dist/layout-painter/renderPage.js +4 -0
- package/dist/layout-painter/renderParagraph.d.ts +13 -1
- package/dist/layout-painter/renderParagraph.js +26 -6
- package/dist/managers/autoSaveCodec.d.ts +9 -1
- package/dist/managers/autoSaveCodec.js +14 -12
- package/dist/markdown/images.js +1 -4
- package/dist/markdown/renderBlock.js +1 -0
- package/dist/markdown/renderRuns.d.ts +1 -1
- package/dist/markdown/renderRuns.js +28 -5
- package/dist/markdown/renderTable.js +22 -5
- package/dist/markdown/trailers.js +4 -1
- package/dist/pdf/images.js +142 -6
- package/dist/prosemirror/attrs/index.d.ts +14 -3
- package/dist/prosemirror/attrs/index.js +224 -2
- package/dist/prosemirror/authoredTransformAttrs.d.ts +28 -0
- package/dist/prosemirror/authoredTransformAttrs.js +64 -0
- package/dist/prosemirror/commands/contentControls.js +10 -2
- package/dist/prosemirror/commands/image.d.ts +9 -2
- package/dist/prosemirror/commands/image.js +43 -28
- package/dist/prosemirror/commands/pageBreak.js +1 -1
- package/dist/prosemirror/commentReferenceAttrs.d.ts +8 -0
- package/dist/prosemirror/commentReferenceAttrs.js +33 -0
- package/dist/prosemirror/commentReferenceIntegrity.d.ts +47 -0
- package/dist/prosemirror/commentReferenceIntegrity.js +43 -0
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
- package/dist/prosemirror/conversion/fromProseDoc.js +338 -99
- package/dist/prosemirror/conversion/index.d.ts +2 -2
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -9
- package/dist/prosemirror/conversion/toProseDoc.js +551 -327
- package/dist/prosemirror/extensions/StarterKit.js +8 -58
- package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -1
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +45 -27
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -1
- package/dist/prosemirror/extensions/features/ImagePasteExtension.js +5 -3
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -0
- package/dist/prosemirror/extensions/markRegistry.d.ts +41 -0
- package/dist/prosemirror/extensions/markRegistry.js +75 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +2 -3
- package/dist/prosemirror/extensions/marks/InlineWrapperExtension.d.ts +18 -0
- package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +63 -0
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
- package/dist/prosemirror/extensions/marks/markUtils.js +47 -4
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.d.ts +11 -0
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +87 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +9 -7
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +20 -0
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.d.ts +32 -0
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +67 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.d.ts +16 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +60 -0
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +10 -2
- package/dist/prosemirror/extensions/nodes/TableExtension.js +3 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +13 -5
- package/dist/prosemirror/inlineWrapperStack.d.ts +39 -0
- package/dist/prosemirror/inlineWrapperStack.js +75 -0
- package/dist/prosemirror/pageBreakRunProjection.d.ts +17 -7
- package/dist/prosemirror/pageBreakRunProjection.js +19 -9
- package/dist/prosemirror/paragraphFormattingProvenance.d.ts +6 -3
- package/dist/prosemirror/paragraphFormattingProvenance.js +12 -3
- package/dist/prosemirror/replacedAnnotations.d.ts +59 -0
- package/dist/prosemirror/replacedAnnotations.js +165 -0
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +3 -1
- package/dist/prosemirror/runFormattingInlineCarriers.js +5 -1
- package/dist/prosemirror/schema/index.d.ts +3 -3
- package/dist/prosemirror/schema/marks.d.ts +25 -1
- package/dist/prosemirror/schema/nodes.d.ts +139 -3
- package/dist/prosemirror/schema/nodes.js +16 -1
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +2 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +2 -0
- package/dist/prosemirror/validation.js +16 -2
- package/dist/prosemirror/yjsDocumentMetadata.d.ts +73 -0
- package/dist/prosemirror/yjsDocumentMetadata.js +171 -0
- package/dist/prosemirror/zeroWidthAnchors.js +2 -0
- package/dist/render-dom/commentAnchorAttributes.d.ts +37 -0
- package/dist/render-dom/commentAnchorAttributes.js +54 -0
- package/dist/server.d.ts +3 -1
- package/dist/server.js +3 -1
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/base64.d.ts +36 -0
- package/dist/utils/base64.js +40 -0
- package/dist/utils/clipboard.d.ts +9 -1
- package/dist/utils/clipboard.js +29 -2
- package/dist/utils/findReplace.js +1 -1
- package/dist/utils/imageLuminance.d.ts +15 -0
- package/dist/utils/imageLuminance.js +32 -0
- package/dist/utils/mergeDocumentContent.js +7 -17
- package/dist/utils/replaceText.js +1 -0
- package/dist/utils/units.d.ts +10 -1
- package/dist/utils/units.js +12 -1
- package/dist/utils/urlSecurity.d.ts +8 -2
- package/dist/utils/urlSecurity.js +21 -3
- package/package.json +2 -2
- package/dist/docx/blockRangeMarkers.d.ts +0 -36
- package/dist/docx/blockRangeMarkers.js +0 -59
- package/dist/prosemirror/yjsParagraphSourceContract.d.ts +0 -9
- package/dist/prosemirror/yjsParagraphSourceContract.js +0 -26
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { deterministicHexId } from "../../utils/hexId.js";
|
|
2
|
+
import { commentThreadParaId } from "../commentThreadKey.js";
|
|
3
|
+
import { serializeWithPreservedChildren } from "../containerChildren.js";
|
|
2
4
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
3
5
|
import { serializePartElement } from "./partNamespaces.js";
|
|
4
6
|
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
5
|
-
import {
|
|
7
|
+
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
6
8
|
//#region src/docx/serializer/commentSerializer.ts
|
|
7
9
|
/**
|
|
8
10
|
* Comment Serializer
|
|
@@ -26,16 +28,13 @@ function serializeParagraphWithAnnotationRef(paragraph, formatting) {
|
|
|
26
28
|
return xml.replace(/^<w:p(?=[\s>])[^>]*>/u, (openingTag) => `${openingTag}${annotationReference}`);
|
|
27
29
|
}
|
|
28
30
|
function serializeComment(comment) {
|
|
29
|
-
const attrs = [`w:id="${comment.id}"`, `w:author="${
|
|
30
|
-
if (comment.initials !== void 0) attrs.push(`w:initials="${
|
|
31
|
-
if (comment.date) attrs.push(`w:date="${
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} else xml += `<w:p>${serializeAnnotationReference(comment.annotationReferenceFormatting)}</w:p>`;
|
|
37
|
-
xml += "</w:comment>";
|
|
38
|
-
return xml;
|
|
31
|
+
const attrs = [`w:id="${comment.id}"`, `w:author="${escapeXmlAttribute(comment.author)}"`];
|
|
32
|
+
if (comment.initials !== void 0) attrs.push(`w:initials="${escapeXmlAttribute(comment.initials)}"`);
|
|
33
|
+
if (comment.date) attrs.push(`w:date="${escapeXmlAttribute(comment.date)}"`);
|
|
34
|
+
const paragraphs = comment.content.map((paragraph, index) => index === 0 ? serializeParagraphWithAnnotationRef(paragraph, comment.annotationReferenceFormatting) : serializeParagraph(paragraph));
|
|
35
|
+
if (paragraphs.length === 0 && comment.preserved === void 0) paragraphs.push(`<w:p>${serializeAnnotationReference(comment.annotationReferenceFormatting)}</w:p>`);
|
|
36
|
+
const body = serializeWithPreservedChildren(paragraphs, comment.preserved);
|
|
37
|
+
return `<w:comment ${attrs.join(" ")}>${body}</w:comment>`;
|
|
39
38
|
}
|
|
40
39
|
const COMMENTS_BASELINE_PREFIXES = [
|
|
41
40
|
"wpc",
|
|
@@ -61,46 +60,6 @@ const COMMENTS_EXTENDED_BASELINE_PREFIXES = [
|
|
|
61
60
|
];
|
|
62
61
|
const XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
|
63
62
|
/**
|
|
64
|
-
* The order every comment part is written in: top-level comments, then replies.
|
|
65
|
-
*
|
|
66
|
-
* `word/comments.xml` has always been written this way, and the order matters
|
|
67
|
-
* beyond that one part: the save rewrites comments.xml, so the next parse hands
|
|
68
|
-
* the model back in exactly this order. Any other part built by walking the
|
|
69
|
-
* same array — `word/commentsExtended.xml`, and the paraId minting both parts
|
|
70
|
-
* key on — has to walk it in the same order, or the first save writes a part
|
|
71
|
-
* whose order the second save cannot reproduce and saving is not a fixed point.
|
|
72
|
-
*/
|
|
73
|
-
const commentPartOrder = (comments) => {
|
|
74
|
-
const topLevel = [];
|
|
75
|
-
const replies = [];
|
|
76
|
-
for (const comment of comments) {
|
|
77
|
-
const { parentId } = comment;
|
|
78
|
-
(parentId === null || parentId === void 0 ? topLevel : replies).push(comment);
|
|
79
|
-
}
|
|
80
|
-
return [...topLevel, ...replies];
|
|
81
|
-
};
|
|
82
|
-
/**
|
|
83
|
-
* Serialize comments array to comments.xml content. Returns a valid empty
|
|
84
|
-
* `<w:comments/>` document for an empty array so callers can overwrite an
|
|
85
|
-
* existing `word/comments.xml` part when the editor has removed the last
|
|
86
|
-
* comment — leaving the previous file in place would otherwise re-emit
|
|
87
|
-
* the orphaned comment threads on every save.
|
|
88
|
-
*/
|
|
89
|
-
function serializeComments(comments, sourceBindings) {
|
|
90
|
-
const body = commentPartOrder(comments).map((comment) => serializeComment(comment)).join("");
|
|
91
|
-
return XML_DECLARATION + serializePartElement({
|
|
92
|
-
partPath: "word/comments.xml",
|
|
93
|
-
rootName: "w:comments",
|
|
94
|
-
baselinePrefixes: COMMENTS_BASELINE_PREFIXES,
|
|
95
|
-
sourceBindings,
|
|
96
|
-
body
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
/** The `w14:paraId` Word threads a comment by: its LAST paragraph's paraId. */
|
|
100
|
-
function commentThreadParaId(comment) {
|
|
101
|
-
return comment.content?.at(-1)?.paraId;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
63
|
* The ids of comments that need a `commentsExtended.xml` entry: a reply, a
|
|
105
64
|
* reply's parent (the thread root), or any comment carrying a resolved state.
|
|
106
65
|
* A plain top-level comment set yields an empty set, so no part is written.
|
|
@@ -121,29 +80,71 @@ const commentPlainText = (comment) => {
|
|
|
121
80
|
return text;
|
|
122
81
|
};
|
|
123
82
|
/**
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
83
|
+
* Plan both comment parts from the model, in the model's own order.
|
|
84
|
+
*
|
|
85
|
+
* The order is the document's: the order `word/comments.xml` listed the
|
|
86
|
+
* comments in is the order it is written back in, so a save neither reshuffles
|
|
87
|
+
* a reviewer's threads nor hands the next parse a different `comments[]` than
|
|
88
|
+
* the one it read.
|
|
89
|
+
*
|
|
90
|
+
* Planning also mints the `w14:paraId` a thread needs when the model has none —
|
|
91
|
+
* a comment written in the editor has no Word-authored id, and without one the
|
|
92
|
+
* `commentsExtended.xml` link would be dropped. Minting is deterministic
|
|
93
|
+
* (comment id and text derived) so repeated saves mint the same id, and it
|
|
94
|
+
* happens here rather than at each call site because both parts must see it.
|
|
132
95
|
*/
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
|
|
96
|
+
const planCommentParts = (comments) => {
|
|
97
|
+
const byId = /* @__PURE__ */ new Map();
|
|
98
|
+
const order = [];
|
|
99
|
+
for (const comment of comments) {
|
|
100
|
+
if (byId.has(comment.id)) continue;
|
|
101
|
+
byId.set(comment.id, comment);
|
|
102
|
+
order.push(comment.id);
|
|
103
|
+
}
|
|
104
|
+
const planned = [...byId.values()];
|
|
105
|
+
const threadedIds = threadedCommentIds(planned);
|
|
136
106
|
const used = /* @__PURE__ */ new Set();
|
|
137
|
-
for (const comment of
|
|
138
|
-
|
|
139
|
-
|
|
107
|
+
for (const comment of planned) for (const paragraph of comment.content ?? []) if (paragraph.paraId) used.add(paragraph.paraId.toUpperCase());
|
|
108
|
+
const threadParaIdById = /* @__PURE__ */ new Map();
|
|
109
|
+
for (const id of order) {
|
|
110
|
+
const comment = byId.get(id);
|
|
111
|
+
const existing = commentThreadParaId((comment.content ?? []).map(({ paraId }) => paraId));
|
|
112
|
+
if (existing) {
|
|
113
|
+
threadParaIdById.set(id, existing);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
140
116
|
const last = (comment.content ?? []).at(-1);
|
|
141
|
-
if (!
|
|
142
|
-
let
|
|
143
|
-
for (let salt = 1; used.has(
|
|
144
|
-
used.add(
|
|
145
|
-
last.paraId =
|
|
117
|
+
if (!threadedIds.has(id) || !last) continue;
|
|
118
|
+
let minted = deterministicHexId(`comment:${id}:${commentPlainText(comment)}`);
|
|
119
|
+
for (let salt = 1; used.has(minted.toUpperCase()); salt++) minted = deterministicHexId(`comment:${id}:${salt}`);
|
|
120
|
+
used.add(minted.toUpperCase());
|
|
121
|
+
last.paraId = minted;
|
|
122
|
+
threadParaIdById.set(id, minted);
|
|
146
123
|
}
|
|
124
|
+
return {
|
|
125
|
+
order,
|
|
126
|
+
byId,
|
|
127
|
+
threadParaIdById,
|
|
128
|
+
threadedIds
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Serialize a comment plan to comments.xml content. Returns a valid empty
|
|
133
|
+
* `<w:comments/>` document for an empty plan so callers can overwrite an
|
|
134
|
+
* existing `word/comments.xml` part when the editor has removed the last
|
|
135
|
+
* comment — leaving the previous file in place would otherwise re-emit
|
|
136
|
+
* the orphaned comment threads on every save.
|
|
137
|
+
*/
|
|
138
|
+
function serializeComments({ order, byId }, sourceBindings) {
|
|
139
|
+
let body = "";
|
|
140
|
+
for (const id of order) body += serializeComment(byId.get(id));
|
|
141
|
+
return XML_DECLARATION + serializePartElement({
|
|
142
|
+
partPath: "word/comments.xml",
|
|
143
|
+
rootName: "w:comments",
|
|
144
|
+
baselinePrefixes: COMMENTS_BASELINE_PREFIXES,
|
|
145
|
+
sourceBindings,
|
|
146
|
+
body
|
|
147
|
+
});
|
|
147
148
|
}
|
|
148
149
|
/**
|
|
149
150
|
* Build the `commentsExtended.xml` entries for the comments that participate in
|
|
@@ -152,29 +153,23 @@ function ensureThreadedCommentParaIds(comments) {
|
|
|
152
153
|
* leave any existing part untouched — a plain top-level comment set gets no
|
|
153
154
|
* `commentsExtended.xml`, matching how Word omits it.
|
|
154
155
|
*
|
|
155
|
-
* A `w15:commentEx` keys on the comment's
|
|
156
|
-
* `w15:paraIdParent`
|
|
157
|
-
*
|
|
158
|
-
* skip is a last-ditch safety for a malformed model.
|
|
156
|
+
* A `w15:commentEx` keys on the comment's thread paraId; a reply's
|
|
157
|
+
* `w15:paraIdParent` on its parent's. Both come from the plan, so a reply and
|
|
158
|
+
* its parent name each other by `w:id` right up to the attribute.
|
|
159
159
|
*/
|
|
160
|
-
function buildCommentExtendedEntries(
|
|
161
|
-
|
|
162
|
-
if (threaded.size === 0) return null;
|
|
163
|
-
const paraIdByCommentId = /* @__PURE__ */ new Map();
|
|
164
|
-
for (const comment of comments) {
|
|
165
|
-
const paraId = commentThreadParaId(comment);
|
|
166
|
-
if (paraId) paraIdByCommentId.set(comment.id, paraId);
|
|
167
|
-
}
|
|
160
|
+
function buildCommentExtendedEntries({ order, byId, threadParaIdById, threadedIds }) {
|
|
161
|
+
if (threadedIds.size === 0) return null;
|
|
168
162
|
const entries = [];
|
|
169
|
-
for (const
|
|
170
|
-
if (!
|
|
171
|
-
const paraId =
|
|
163
|
+
for (const id of order) {
|
|
164
|
+
if (!threadedIds.has(id)) continue;
|
|
165
|
+
const paraId = threadParaIdById.get(id);
|
|
172
166
|
if (!paraId) continue;
|
|
173
|
-
const
|
|
167
|
+
const { parentId, done } = byId.get(id);
|
|
168
|
+
const parentParaId = parentId !== void 0 ? threadParaIdById.get(parentId) : void 0;
|
|
174
169
|
entries.push({
|
|
175
170
|
paraId,
|
|
176
171
|
...parentParaId !== void 0 ? { paraIdParent: parentParaId } : {},
|
|
177
|
-
done:
|
|
172
|
+
done: done ?? false
|
|
178
173
|
});
|
|
179
174
|
}
|
|
180
175
|
return entries.length > 0 ? entries : null;
|
|
@@ -185,12 +180,12 @@ function buildCommentExtendedEntries(comments) {
|
|
|
185
180
|
* {@link buildCommentExtendedEntries}). This is the part that makes Word render
|
|
186
181
|
* a comment as a REPLY rather than a separate top-level thread.
|
|
187
182
|
*/
|
|
188
|
-
function serializeCommentsExtended(
|
|
189
|
-
const entries = buildCommentExtendedEntries(
|
|
183
|
+
function serializeCommentsExtended(plan) {
|
|
184
|
+
const entries = buildCommentExtendedEntries(plan);
|
|
190
185
|
if (!entries) return null;
|
|
191
186
|
const body = entries.map((entry) => {
|
|
192
|
-
const parentAttr = entry.paraIdParent !== void 0 ? ` w15:paraIdParent="${
|
|
193
|
-
return `<w15:commentEx w15:paraId="${
|
|
187
|
+
const parentAttr = entry.paraIdParent !== void 0 ? ` w15:paraIdParent="${escapeXmlAttribute(entry.paraIdParent)}"` : "";
|
|
188
|
+
return `<w15:commentEx w15:paraId="${escapeXmlAttribute(entry.paraId)}"${parentAttr} w15:done="${entry.done ? "1" : "0"}"/>`;
|
|
194
189
|
}).join("");
|
|
195
190
|
return XML_DECLARATION + serializePartElement({
|
|
196
191
|
partPath: "word/commentsExtended.xml",
|
|
@@ -201,4 +196,4 @@ function serializeCommentsExtended(comments) {
|
|
|
201
196
|
});
|
|
202
197
|
}
|
|
203
198
|
//#endregion
|
|
204
|
-
export {
|
|
199
|
+
export { planCommentParts, serializeComments, serializeCommentsExtended };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { withBlockRangeMarkers } from "../blockRangeMarkers.js";
|
|
2
1
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
3
2
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
4
3
|
import { serializePartElement } from "./partNamespaces.js";
|
|
@@ -37,17 +36,15 @@ const DOCUMENT_BASELINE_PREFIXES = [
|
|
|
37
36
|
"wpg",
|
|
38
37
|
"wps"
|
|
39
38
|
];
|
|
40
|
-
/**
|
|
41
|
-
* Serialize a single block content item (paragraph, table, or block-level SDT).
|
|
42
|
-
*/
|
|
39
|
+
/** Serialize a single block, whether or not folio models what is in it. */
|
|
43
40
|
function serializeBlockContent(block) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
41
|
+
switch (block.type) {
|
|
42
|
+
case "paragraph": return serializeParagraph(block);
|
|
43
|
+
case "table": return serializeTable(block, serializeParagraph);
|
|
44
|
+
case "blockSdt": return serializeBlockSdt(block, serializeBlockContent);
|
|
45
|
+
case "preservedBlock": return block.xml;
|
|
46
|
+
default: return block;
|
|
47
|
+
}
|
|
51
48
|
}
|
|
52
49
|
/**
|
|
53
50
|
* Serialize document body content
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { serializePartElement } from "./partNamespaces.js";
|
|
2
|
-
import {
|
|
2
|
+
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
3
3
|
//#region src/docx/serializer/fontTableSerializer.ts
|
|
4
4
|
const serializeFontTableXml = (fontTable) => "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + serializePartElement({
|
|
5
5
|
partPath: "word/fontTable.xml",
|
|
@@ -10,20 +10,20 @@ const serializeFontTableXml = (fontTable) => "<?xml version=\"1.0\" encoding=\"U
|
|
|
10
10
|
});
|
|
11
11
|
const serializeFont = (font) => {
|
|
12
12
|
const parts = [];
|
|
13
|
-
if (font.altName) parts.push(`<w:altName w:val="${
|
|
14
|
-
if (font.panose1) parts.push(`<w:panose1 w:val="${
|
|
15
|
-
if (font.charset) parts.push(`<w:charset w:val="${
|
|
13
|
+
if (font.altName) parts.push(`<w:altName w:val="${escapeXmlAttribute(font.altName)}"/>`);
|
|
14
|
+
if (font.panose1) parts.push(`<w:panose1 w:val="${escapeXmlAttribute(font.panose1)}"/>`);
|
|
15
|
+
if (font.charset) parts.push(`<w:charset w:val="${escapeXmlAttribute(font.charset)}"/>`);
|
|
16
16
|
if (font.family) parts.push(`<w:family w:val="${font.family}"/>`);
|
|
17
17
|
if (font.pitch) parts.push(`<w:pitch w:val="${font.pitch}"/>`);
|
|
18
18
|
if (font.sig) {
|
|
19
19
|
const attrs = [];
|
|
20
20
|
for (const [key, value] of Object.entries(font.sig)) {
|
|
21
21
|
if (value === void 0) continue;
|
|
22
|
-
attrs.push(`w:${key}="${
|
|
22
|
+
attrs.push(`w:${key}="${escapeXmlAttribute(value)}"`);
|
|
23
23
|
}
|
|
24
24
|
if (attrs.length > 0) parts.push(`<w:sig ${attrs.join(" ")}/>`);
|
|
25
25
|
}
|
|
26
|
-
return `<w:font w:name="${
|
|
26
|
+
return `<w:font w:name="${escapeXmlAttribute(font.name)}">${parts.join("")}</w:font>`;
|
|
27
27
|
};
|
|
28
28
|
//#endregion
|
|
29
29
|
export { serializeFontTableXml };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { withBlockRangeMarkers } from "../blockRangeMarkers.js";
|
|
2
1
|
import { canReplayHeaderFooterVerbatim, getHeaderFooterVerbatimXml } from "../headerFooterVerbatim.js";
|
|
3
2
|
import { isEmptyParagraph } from "../paragraphParser.js";
|
|
4
3
|
import { captureVerbatimXml } from "../verbatimCapture.js";
|
|
@@ -7,7 +6,7 @@ import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
|
7
6
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
8
7
|
import { serializePartElement } from "./partNamespaces.js";
|
|
9
8
|
import { serializeTable } from "./tableSerializer.js";
|
|
10
|
-
import {
|
|
9
|
+
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
11
10
|
//#region src/docx/serializer/headerFooterSerializer.ts
|
|
12
11
|
const HEADER_FOOTER_BASELINE_PREFIXES = [
|
|
13
12
|
"wpc",
|
|
@@ -37,13 +36,13 @@ const HEADER_FOOTER_BASELINE_PREFIXES = [
|
|
|
37
36
|
* header/footer.
|
|
38
37
|
*/
|
|
39
38
|
function serializeBlock(block) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
switch (block.type) {
|
|
40
|
+
case "paragraph": return serializeParagraph(block);
|
|
41
|
+
case "table": return serializeTable(block, serializeParagraph);
|
|
42
|
+
case "blockSdt": return serializeBlockSdt(block, serializeBlock);
|
|
43
|
+
case "preservedBlock": return block.xml;
|
|
44
|
+
default: return block;
|
|
45
|
+
}
|
|
47
46
|
}
|
|
48
47
|
/**
|
|
49
48
|
* Serialize a HeaderFooter object to valid OOXML XML
|
|
@@ -71,7 +70,6 @@ function serializeHeaderFooter(hf, source) {
|
|
|
71
70
|
});
|
|
72
71
|
contentXml = blocksXml.slice(0, watermarkInsertIndex).join("") + (mergesIntoRetainedHost ? "" : watermarkXml) + blocksXml.slice(watermarkInsertIndex).join("");
|
|
73
72
|
} else contentXml = blocksXml.join("");
|
|
74
|
-
if (!contentXml) contentXml = "<w:p><w:pPr/></w:p>";
|
|
75
73
|
return "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" + serializePartElement({
|
|
76
74
|
partPath: source?.path ?? `word/${hf.type}.xml`,
|
|
77
75
|
rootName: rootTag,
|
|
@@ -85,7 +83,7 @@ function serializeRawWatermarkIntoHost({ hostXml, rawWatermarkXml }) {
|
|
|
85
83
|
if (!rawHost || getLocalName(rawHost.name ?? "") !== "p") return rawWatermarkXml;
|
|
86
84
|
const watermarkContent = (rawHost.elements ?? []).filter((child) => child.type === "element" && getLocalName(child.name ?? "") !== "pPr").map((child) => captureVerbatimXml(child)).join("");
|
|
87
85
|
if (!watermarkContent) return rawWatermarkXml;
|
|
88
|
-
const namespaceAttributes = Object.entries(rawHost.attributes ?? {}).filter(([name, value]) => value !== void 0 && (name === "xmlns" || name.startsWith("xmlns:"))).map(([name, value]) => ` ${name}="${
|
|
86
|
+
const namespaceAttributes = Object.entries(rawHost.attributes ?? {}).filter(([name, value]) => value !== void 0 && (name === "xmlns" || name.startsWith("xmlns:"))).map(([name, value]) => ` ${name}="${escapeXmlAttribute(String(value))}"`).join("");
|
|
89
87
|
return hostXml.replace(/^<w:p(?=[\s>])/u, `<w:p${namespaceAttributes}`).replace("</w:p>", `${watermarkContent}</w:p>`);
|
|
90
88
|
}
|
|
91
89
|
function serializeWatermarkParagraph(hf) {
|
|
@@ -101,15 +99,15 @@ function synthesizeTextWatermark(watermark) {
|
|
|
101
99
|
const rotation = watermark.diagonal === false ? 0 : 315;
|
|
102
100
|
const fillcolor = watermark.color && watermark.color !== "auto" ? `#${watermark.color}` : "#C0C0C0";
|
|
103
101
|
const fontFamily = watermark.font ?? "Calibri";
|
|
104
|
-
const text =
|
|
105
|
-
return `<w:p><w:r><w:pict><v:shape id="PowerPlusWaterMarkObject1" type="#_x0000_t136" style="position:absolute;margin-left:0;margin-top:0;width:415pt;height:207pt;rotation:${rotation};z-index:-251658240;mso-position-horizontal:center;mso-position-horizontal-relative:margin;mso-position-vertical:center;mso-position-vertical-relative:margin" fillcolor="${fillcolor}" stroked="f">${watermark.opacity !== void 0 ? `<v:fill opacity="${watermark.opacity}"/>` : ""}<v:textpath style="font-family:"${
|
|
102
|
+
const text = escapeXmlAttribute(watermark.text);
|
|
103
|
+
return `<w:p><w:r><w:pict><v:shape id="PowerPlusWaterMarkObject1" type="#_x0000_t136" style="position:absolute;margin-left:0;margin-top:0;width:415pt;height:207pt;rotation:${rotation};z-index:-251658240;mso-position-horizontal:center;mso-position-horizontal-relative:margin;mso-position-vertical:center;mso-position-vertical-relative:margin" fillcolor="${fillcolor}" stroked="f">${watermark.opacity !== void 0 ? `<v:fill opacity="${watermark.opacity}"/>` : ""}<v:textpath style="font-family:"${escapeXmlAttribute(fontFamily)}";font-size:1pt" string="${text}"/></v:shape></w:pict></w:r></w:p>`;
|
|
106
104
|
}
|
|
107
105
|
const PICTURE_WATERMARK_DEFAULT_WIDTH_PT = 415;
|
|
108
106
|
const PICTURE_WATERMARK_DEFAULT_HEIGHT_PT = 207;
|
|
109
107
|
const PICTURE_WATERMARK_WASHOUT_GAIN = "19661f";
|
|
110
108
|
const PICTURE_WATERMARK_WASHOUT_BLACKLEVEL = "22938f";
|
|
111
109
|
function synthesizePictureWatermark(watermark) {
|
|
112
|
-
const rId =
|
|
110
|
+
const rId = escapeXmlAttribute(watermark.imageRId);
|
|
113
111
|
return `<w:p><w:r><w:pict><v:shape id="WordPictureWatermark1" type="#_x0000_t75" style="position:absolute;margin-left:0;margin-top:0;width:${watermark.scale === void 0 ? watermark.widthPt ?? PICTURE_WATERMARK_DEFAULT_WIDTH_PT : PICTURE_WATERMARK_DEFAULT_WIDTH_PT * watermark.scale}pt;height:${watermark.scale === void 0 ? watermark.heightPt ?? PICTURE_WATERMARK_DEFAULT_HEIGHT_PT : PICTURE_WATERMARK_DEFAULT_HEIGHT_PT * watermark.scale}pt;z-index:-251658240;mso-position-horizontal:center;mso-position-horizontal-relative:margin;mso-position-vertical:center;mso-position-vertical-relative:margin"><v:imagedata r:id="${rId}" o:title=""${watermark.washout === false ? "" : ` gain="${PICTURE_WATERMARK_WASHOUT_GAIN}" blacklevel="${PICTURE_WATERMARK_WASHOUT_BLACKLEVEL}"`}/></v:shape></w:pict></w:r></w:p>`;
|
|
114
112
|
}
|
|
115
113
|
//#endregion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
2
2
|
//#region src/docx/serializer/markupRangeAttributes.ts
|
|
3
|
-
const attribute = (name, value) => `${name}="${
|
|
3
|
+
const attribute = (name, value) => `${name}="${escapeXmlAttribute(String(value))}"`;
|
|
4
4
|
const markupRangeAttributes = (marker) => {
|
|
5
5
|
const attributes = [attribute("w:id", marker.id)];
|
|
6
6
|
if (marker.displacedByCustomXml !== void 0) attributes.push(attribute("w:displacedByCustomXml", marker.displacedByCustomXml));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { withBlockRangeMarkers } from "../blockRangeMarkers.js";
|
|
2
1
|
import { serializeBlockSdt } from "./blockSdtSerializer.js";
|
|
3
2
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
4
3
|
import { serializePartElement } from "./partNamespaces.js";
|
|
@@ -39,13 +38,13 @@ const serializeNotePart = (elementName, body) => "<?xml version=\"1.0\" encoding
|
|
|
39
38
|
* note body.
|
|
40
39
|
*/
|
|
41
40
|
function serializeBlock(block) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
switch (block.type) {
|
|
42
|
+
case "paragraph": return serializeParagraph(block);
|
|
43
|
+
case "table": return serializeTable(block, serializeParagraph);
|
|
44
|
+
case "blockSdt": return serializeBlockSdt(block, serializeBlock);
|
|
45
|
+
case "preservedBlock": return block.xml;
|
|
46
|
+
default: return block;
|
|
47
|
+
}
|
|
49
48
|
}
|
|
50
49
|
/**
|
|
51
50
|
* Serialize a single note element. Footnotes and endnotes share the same
|
|
@@ -63,6 +62,7 @@ function serializeRequiredNoteSeparators(elementName) {
|
|
|
63
62
|
return `<w:${elementName} w:type="separator" w:id="-1">${NOTE_SEPARATOR_BODY}<w:r><w:separator/></w:r></w:p></w:${elementName}><w:${elementName} w:type="continuationSeparator" w:id="0">${NOTE_SEPARATOR_BODY}<w:r><w:continuationSeparator/></w:r></w:p></w:${elementName}>`;
|
|
64
63
|
}
|
|
65
64
|
function insertNoteReferenceMark(xml, elementName) {
|
|
65
|
+
if (xml.includes(`<w:${elementName}Ref`)) return xml;
|
|
66
66
|
const paragraphOpen = /<w:p(?=[\s>])[^>]*>/u.exec(xml);
|
|
67
67
|
if (!paragraphOpen) return `${`<w:p><w:r><w:rPr><w:rStyle w:val="${elementName === "footnote" ? "FootnoteReference" : "EndnoteReference"}"/></w:rPr><w:${elementName}Ref/></w:r></w:p>`}${xml}`;
|
|
68
68
|
const paragraphStart = paragraphOpen.index + paragraphOpen[0].length;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { serializePartElement } from "./partNamespaces.js";
|
|
2
2
|
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
3
|
-
import {
|
|
3
|
+
import { intAttr } from "./xmlUtils.js";
|
|
4
|
+
import { escapeXmlAttribute } from "@stll/docx-core";
|
|
4
5
|
//#region src/docx/serializer/numberingSerializer.ts
|
|
5
6
|
/**
|
|
6
7
|
* Serialize a level's paragraph properties — the modeled subset is indentation
|
|
@@ -36,11 +37,11 @@ function serializeLevelParagraphProps(pPr) {
|
|
|
36
37
|
function serializeLevel(level) {
|
|
37
38
|
const parts = [];
|
|
38
39
|
if (level.start !== void 0) parts.push(`<w:start w:val="${intAttr(level.start)}"/>`);
|
|
39
|
-
parts.push(`<w:numFmt w:val="${
|
|
40
|
+
parts.push(`<w:numFmt w:val="${escapeXmlAttribute(level.numFmt)}"/>`);
|
|
40
41
|
if (level.lvlRestart !== void 0) parts.push(`<w:lvlRestart w:val="${intAttr(level.lvlRestart)}"/>`);
|
|
41
42
|
if (level.isLgl) parts.push("<w:isLgl/>");
|
|
42
43
|
if (level.suffix) parts.push(`<w:suff w:val="${level.suffix}"/>`);
|
|
43
|
-
parts.push(`<w:lvlText w:val="${
|
|
44
|
+
parts.push(`<w:lvlText w:val="${escapeXmlAttribute(level.lvlText)}"/>`);
|
|
44
45
|
if (level.legacy) {
|
|
45
46
|
const legacyAttrs = [`w:legacy="${level.legacy.legacy ? 1 : 0}"`];
|
|
46
47
|
if (level.legacy.legacySpace !== void 0) legacyAttrs.push(`w:legacySpace="${intAttr(level.legacy.legacySpace)}"`);
|
|
@@ -60,9 +61,9 @@ function serializeLevel(level) {
|
|
|
60
61
|
function serializeAbstractNum(abstractNum) {
|
|
61
62
|
const parts = [];
|
|
62
63
|
if (abstractNum.multiLevelType) parts.push(`<w:multiLevelType w:val="${abstractNum.multiLevelType}"/>`);
|
|
63
|
-
if (abstractNum.name !== void 0) parts.push(`<w:name w:val="${
|
|
64
|
-
if (abstractNum.styleLink !== void 0) parts.push(`<w:styleLink w:val="${
|
|
65
|
-
if (abstractNum.numStyleLink !== void 0) parts.push(`<w:numStyleLink w:val="${
|
|
64
|
+
if (abstractNum.name !== void 0) parts.push(`<w:name w:val="${escapeXmlAttribute(abstractNum.name)}"/>`);
|
|
65
|
+
if (abstractNum.styleLink !== void 0) parts.push(`<w:styleLink w:val="${escapeXmlAttribute(abstractNum.styleLink)}"/>`);
|
|
66
|
+
if (abstractNum.numStyleLink !== void 0) parts.push(`<w:numStyleLink w:val="${escapeXmlAttribute(abstractNum.numStyleLink)}"/>`);
|
|
66
67
|
const levels = [...abstractNum.levels].sort((a, b) => a.ilvl - b.ilvl);
|
|
67
68
|
for (const level of levels) parts.push(serializeLevel(level));
|
|
68
69
|
return `<w:abstractNum w:abstractNumId="${intAttr(abstractNum.abstractNumId)}">${parts.join("")}</w:abstractNum>`;
|