@stll/folio-core 0.45.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/apply.js +59 -19
- package/dist/ai-edits/headless.js +1 -1
- package/dist/compare/compare.js +2 -5
- 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 +17 -2
- 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 +10 -2
- package/dist/display-list/types.d.ts +17 -0
- 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/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 +54 -37
- 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/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/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/headerFooterParser.js +1 -1
- package/dist/docx/headerFooterReferenceNormalization.js +1 -0
- package/dist/docx/hyperlinkParser.d.ts +27 -8
- package/dist/docx/hyperlinkParser.js +76 -18
- package/dist/docx/imageParser.js +33 -8
- package/dist/docx/inlineWrapperContent.d.ts +85 -0
- package/dist/docx/inlineWrapperContent.js +84 -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 +6 -52
- package/dist/docx/paragraphTraversal.js +7 -4
- package/dist/docx/parseWarningMessage.js +2 -1
- package/dist/docx/preservedRunContent.d.ts +32 -0
- package/dist/docx/preservedRunContent.js +86 -0
- package/dist/docx/renderedPageBreakNormalization.js +2 -4
- package/dist/docx/rezip.js +74 -18
- package/dist/docx/runParser.d.ts +1 -1
- package/dist/docx/runParser.js +16 -12
- package/dist/docx/sectionParser.js +8 -1
- package/dist/docx/selectiveXmlPatch.d.ts +46 -2
- package/dist/docx/selectiveXmlPatch.js +86 -39
- package/dist/docx/serializer/borderSerializer.js +2 -2
- package/dist/docx/serializer/commentSerializer.js +5 -7
- package/dist/docx/serializer/documentSerializer.js +8 -11
- package/dist/docx/serializer/headerFooterSerializer.js +7 -9
- package/dist/docx/serializer/noteSerializer.js +8 -8
- package/dist/docx/serializer/paragraphSerializer.js +76 -56
- package/dist/docx/serializer/runSerializer.js +25 -16
- package/dist/docx/serializer/sectionPropertiesSerializer.js +8 -4
- package/dist/docx/serializer/tableSerializer.js +18 -8
- 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/shapeParser.js +5 -5
- 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 +52 -2
- package/dist/docx/unzip.js +5 -4
- package/dist/docx/vmlImageParser.d.ts +17 -1
- package/dist/docx/vmlImageParser.js +17 -1
- package/dist/docx/xmlEncoding.d.ts +5 -0
- package/dist/docx/xmlEncoding.js +12 -0
- package/dist/docx/xmlParser.d.ts +10 -1
- package/dist/docx/xmlParser.js +14 -1
- 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/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 +10 -3
- 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 +22 -3
- package/dist/managers/autoSaveCodec.d.ts +9 -1
- package/dist/managers/autoSaveCodec.js +12 -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 +155 -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 +42 -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 +269 -70
- package/dist/prosemirror/conversion/index.d.ts +2 -2
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -9
- package/dist/prosemirror/conversion/toProseDoc.js +468 -308
- 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/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 +16 -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 +3 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +3 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +5 -1
- 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/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 +90 -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/clipboard.d.ts +9 -1
- package/dist/utils/clipboard.js +27 -1
- 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/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,3 +1,4 @@
|
|
|
1
|
+
import { patchBreaksCommentRangeBalance } from "./commentRangeIntegrity.js";
|
|
1
2
|
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
2
3
|
import { WORDPROCESSINGML_NAMESPACE_URIS, cloneElement, findAttributeByNamespaceUri, getAttributeByNamespaceUri, getChildElements, getLocalName, getNamespacePrefix, getNamespaceUri, parseXmlDocument } from "./xmlParser.js";
|
|
3
4
|
//#region src/docx/selectiveXmlPatch.ts
|
|
@@ -237,10 +238,27 @@ function buildPatchedNoteXml(originalXml, serializedXml, changedIds) {
|
|
|
237
238
|
return spliceChangedParagraphs(originalXml, serializedXml, changedIds);
|
|
238
239
|
}
|
|
239
240
|
/**
|
|
241
|
+
* Apply `splices` to `xml`, end-to-start so earlier offsets stay valid.
|
|
242
|
+
*
|
|
243
|
+
* Every selective patch is a splice, and every splice goes through here, so
|
|
244
|
+
* the refusal below is a property of the operation rather than a check each
|
|
245
|
+
* site has to remember. A patch rewrites the regions an edit touched and keeps
|
|
246
|
+
* the rest of the part byte-for-byte, so it can write half a comment range:
|
|
247
|
+
* invalid OOXML that anchors the comment to nothing. Answers null when it
|
|
248
|
+
* would, leaving the caller to rewrite a wider region — ultimately the whole
|
|
249
|
+
* part from the model, which is balanced with itself.
|
|
250
|
+
*/
|
|
251
|
+
const spliceXml = (xml, splices) => {
|
|
252
|
+
let result = xml;
|
|
253
|
+
for (const { start, end, newXml } of [...splices].toSorted((a, b) => b.start - a.start)) result = result.slice(0, start) + newXml + result.slice(end);
|
|
254
|
+
return patchBreaksCommentRangeBalance(xml, result) ? null : result;
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
240
257
|
* Replace each changed paragraph in `originalXml` with its re-serialized form
|
|
241
|
-
* extracted from `serializedXml
|
|
242
|
-
*
|
|
243
|
-
*
|
|
258
|
+
* extracted from `serializedXml`. Assumes safety has already been validated.
|
|
259
|
+
* Returns null if an offset or extraction unexpectedly fails, or if
|
|
260
|
+
* {@link spliceXml} refuses the result; the caller then falls back to a full
|
|
261
|
+
* repack, whose parts are all re-serialized from one model.
|
|
244
262
|
*/
|
|
245
263
|
function spliceChangedParagraphs(originalXml, serializedXml, changedIds) {
|
|
246
264
|
const replacements = [];
|
|
@@ -255,10 +273,7 @@ function spliceChangedParagraphs(originalXml, serializedXml, changedIds) {
|
|
|
255
273
|
newXml
|
|
256
274
|
});
|
|
257
275
|
}
|
|
258
|
-
|
|
259
|
-
let result = originalXml;
|
|
260
|
-
for (const { start, end, newXml } of replacements) result = result.slice(0, start) + newXml + result.slice(end);
|
|
261
|
-
return result;
|
|
276
|
+
return spliceXml(originalXml, replacements);
|
|
262
277
|
}
|
|
263
278
|
/**
|
|
264
279
|
* Depth-count the end of the element that opens at `start` (an `<openLiteral…>`
|
|
@@ -424,11 +439,6 @@ const collectChangedNoteParaIds = (baselineXml, currentXml) => {
|
|
|
424
439
|
}
|
|
425
440
|
return changed;
|
|
426
441
|
};
|
|
427
|
-
const replaceRanges = (xml, replacements) => {
|
|
428
|
-
let result = xml;
|
|
429
|
-
for (const { start, end, newXml } of [...replacements].toSorted((a, b) => b.start - a.start)) result = result.slice(0, start) + newXml + result.slice(end);
|
|
430
|
-
return result;
|
|
431
|
-
};
|
|
432
442
|
/**
|
|
433
443
|
* Patch an existing note part from its model serialization.
|
|
434
444
|
*
|
|
@@ -440,56 +450,79 @@ const replaceRanges = (xml, replacements) => {
|
|
|
440
450
|
* notes, and unaffected equal-shape paragraphs remain byte-exact.
|
|
441
451
|
* `replacementXml` also supplies synthesized automatic note-reference marks,
|
|
442
452
|
* which the parsed model intentionally omits.
|
|
453
|
+
*
|
|
454
|
+
* A comment can be anchored on a note's own text, so its range spans that
|
|
455
|
+
* note's paragraphs and an edit inside the span moves a range half from one
|
|
456
|
+
* paragraph to another. Replacing only the dirty paragraph then drops the half
|
|
457
|
+
* it held and leaves the other standing, so {@link spliceXml} refuses the
|
|
458
|
+
* result and the changed notes are rewritten whole instead — model content on
|
|
459
|
+
* both sides of the range, with every other note still byte-exact.
|
|
443
460
|
*/
|
|
444
461
|
function buildPatchedNotePartXml({ originalXml, baselineXml, serializedXml, replacementXml, elementName, changedParaIds }) {
|
|
445
462
|
const currentElements = collectNoteElementSyntax(serializedXml, elementName);
|
|
446
463
|
const originalElements = collectNoteElementSyntax(originalXml, elementName);
|
|
447
464
|
const replacementElements = collectNoteElementSyntax(replacementXml, elementName);
|
|
448
465
|
const replacementXmlnsDeclarations = collectXmlnsFromOpeningTag(replacementXml);
|
|
449
|
-
const
|
|
466
|
+
const paragraphSplices = [];
|
|
467
|
+
/** The same edits at note granularity, should the paragraph splices be refused. */
|
|
468
|
+
const noteSplices = [];
|
|
450
469
|
const serializedParaIds = collectParaIds(serializedXml);
|
|
451
470
|
const effectiveChangedParaIds = changedParaIds ?? collectChangedNoteParaIds(baselineXml, serializedXml);
|
|
452
471
|
const unroutedChangedParaIds = new Set([...effectiveChangedParaIds].filter((paraId) => serializedParaIds.has(paraId)));
|
|
453
472
|
for (const [id, currentSyntaxEntries] of currentElements) {
|
|
454
473
|
const originalSyntaxEntries = originalElements.get(id);
|
|
455
474
|
const replacementSyntaxEntries = replacementElements.get(id);
|
|
456
|
-
if (currentSyntaxEntries.length !== 1 || originalSyntaxEntries?.length !== 1 || replacementSyntaxEntries?.length !== 1) return
|
|
475
|
+
if (currentSyntaxEntries.length !== 1 || originalSyntaxEntries?.length !== 1 || replacementSyntaxEntries?.length !== 1) return {
|
|
476
|
+
type: "refused",
|
|
477
|
+
reason: "unroutable-paragraph"
|
|
478
|
+
};
|
|
457
479
|
const currentSyntax = currentSyntaxEntries[0];
|
|
458
480
|
const originalSyntax = originalSyntaxEntries[0];
|
|
459
481
|
const replacementSyntax = replacementSyntaxEntries[0];
|
|
460
|
-
if (!currentSyntax || !originalSyntax || !replacementSyntax) return
|
|
482
|
+
if (!currentSyntax || !originalSyntax || !replacementSyntax) return {
|
|
483
|
+
type: "refused",
|
|
484
|
+
reason: "unroutable-paragraph"
|
|
485
|
+
};
|
|
461
486
|
const currentNote = extractNoteElement(serializedXml, currentSyntax, id);
|
|
462
487
|
const originalOffsets = findNoteElement(originalXml, originalSyntax, id);
|
|
463
488
|
const replacementNote = extractNoteElement(replacementXml, replacementSyntax, id);
|
|
464
|
-
if (!currentNote || !originalOffsets || !replacementNote) return
|
|
489
|
+
if (!currentNote || !originalOffsets || !replacementNote) return {
|
|
490
|
+
type: "refused",
|
|
491
|
+
reason: "unroutable-paragraph"
|
|
492
|
+
};
|
|
465
493
|
const originalNote = originalXml.slice(originalOffsets.start, originalOffsets.end);
|
|
466
494
|
const currentParagraphs = paragraphRanges(currentNote, currentSyntax.elementPrefix);
|
|
467
495
|
const originalParagraphs = paragraphRanges(originalNote, originalSyntax.elementPrefix);
|
|
468
496
|
const replacementParagraphs = paragraphRanges(replacementNote, replacementSyntax.elementPrefix);
|
|
469
497
|
const noteChangedParaIds = [...collectParaIds(currentNote).keys()].filter((paraId) => unroutedChangedParaIds.has(paraId));
|
|
470
498
|
if (noteChangedParaIds.length === 0) continue;
|
|
499
|
+
const wholeNoteSplice = {
|
|
500
|
+
start: originalOffsets.start,
|
|
501
|
+
end: originalOffsets.end,
|
|
502
|
+
newXml: rewriteWordprocessingPrefixes(replacementNote, {
|
|
503
|
+
source: replacementSyntax,
|
|
504
|
+
target: originalSyntax,
|
|
505
|
+
sourceXmlnsDeclarations: replacementXmlnsDeclarations
|
|
506
|
+
})
|
|
507
|
+
};
|
|
508
|
+
noteSplices.push(wholeNoteSplice);
|
|
471
509
|
if (currentParagraphs.length !== originalParagraphs.length || currentParagraphs.length !== replacementParagraphs.length) {
|
|
472
510
|
for (const paraId of noteChangedParaIds) unroutedChangedParaIds.delete(paraId);
|
|
473
|
-
|
|
474
|
-
start: originalOffsets.start,
|
|
475
|
-
end: originalOffsets.end,
|
|
476
|
-
newXml: rewriteWordprocessingPrefixes(replacementNote, {
|
|
477
|
-
source: replacementSyntax,
|
|
478
|
-
target: originalSyntax,
|
|
479
|
-
sourceXmlnsDeclarations: replacementXmlnsDeclarations
|
|
480
|
-
})
|
|
481
|
-
});
|
|
511
|
+
paragraphSplices.push(wholeNoteSplice);
|
|
482
512
|
continue;
|
|
483
513
|
}
|
|
484
514
|
for (let index = 0; index < currentParagraphs.length; index++) {
|
|
485
515
|
const currentRange = currentParagraphs[index];
|
|
486
516
|
const originalRange = originalParagraphs[index];
|
|
487
517
|
const replacementRange = replacementParagraphs[index];
|
|
488
|
-
if (!currentRange || !originalRange || !replacementRange) return
|
|
518
|
+
if (!currentRange || !originalRange || !replacementRange) return {
|
|
519
|
+
type: "refused",
|
|
520
|
+
reason: "unroutable-paragraph"
|
|
521
|
+
};
|
|
489
522
|
const routedIds = [...collectParaIds(currentNote.slice(currentRange.start, currentRange.end)).keys()].filter((paraId) => unroutedChangedParaIds.has(paraId));
|
|
490
523
|
if (routedIds.length === 0) continue;
|
|
491
524
|
for (const paraId of routedIds) unroutedChangedParaIds.delete(paraId);
|
|
492
|
-
|
|
525
|
+
paragraphSplices.push({
|
|
493
526
|
start: originalOffsets.start + originalRange.start,
|
|
494
527
|
end: originalOffsets.start + originalRange.end,
|
|
495
528
|
newXml: rewriteWordprocessingPrefixes(replacementNote.slice(replacementRange.start, replacementRange.end), {
|
|
@@ -500,8 +533,23 @@ function buildPatchedNotePartXml({ originalXml, baselineXml, serializedXml, repl
|
|
|
500
533
|
});
|
|
501
534
|
}
|
|
502
535
|
}
|
|
503
|
-
if (unroutedChangedParaIds.size > 0) return
|
|
504
|
-
|
|
536
|
+
if (unroutedChangedParaIds.size > 0) return {
|
|
537
|
+
type: "refused",
|
|
538
|
+
reason: "unroutable-paragraph"
|
|
539
|
+
};
|
|
540
|
+
const patched = spliceXml(originalXml, paragraphSplices);
|
|
541
|
+
if (patched !== null) return {
|
|
542
|
+
type: "patched",
|
|
543
|
+
xml: patched
|
|
544
|
+
};
|
|
545
|
+
const wholeNotes = spliceXml(originalXml, noteSplices);
|
|
546
|
+
return wholeNotes === null ? {
|
|
547
|
+
type: "refused",
|
|
548
|
+
reason: "comment-range-balance"
|
|
549
|
+
} : {
|
|
550
|
+
type: "patched",
|
|
551
|
+
xml: wholeNotes
|
|
552
|
+
};
|
|
505
553
|
}
|
|
506
554
|
/**
|
|
507
555
|
* The full range of the first `<openLiteral …>…</closeTag>` element, or null.
|
|
@@ -695,17 +743,19 @@ function restoreLevelNumFmts(originalDefXml, currentDefXml) {
|
|
|
695
743
|
...collectXmlnsFromOpeningTag(origLevel)
|
|
696
744
|
});
|
|
697
745
|
else replacement = reconstructCustomNumFmt(currentWidth);
|
|
698
|
-
const restoredLevel = curLevel
|
|
746
|
+
const restoredLevel = spliceXml(curLevel, [{
|
|
747
|
+
start: synthetic.index,
|
|
748
|
+
end: synthetic.index + synthetic[0].length,
|
|
749
|
+
newXml: replacement
|
|
750
|
+
}]);
|
|
751
|
+
if (restoredLevel === null) continue;
|
|
699
752
|
replacements.push({
|
|
700
753
|
start: curOffsets.start,
|
|
701
754
|
end: curOffsets.end,
|
|
702
755
|
newXml: restoredLevel
|
|
703
756
|
});
|
|
704
757
|
}
|
|
705
|
-
|
|
706
|
-
let result = currentDefXml;
|
|
707
|
-
for (const { start, end, newXml } of replacements) result = result.slice(0, start) + newXml + result.slice(end);
|
|
708
|
-
return result;
|
|
758
|
+
return spliceXml(currentDefXml, replacements) ?? currentDefXml;
|
|
709
759
|
}
|
|
710
760
|
/**
|
|
711
761
|
* Build a patched `word/numbering.xml` by splicing the changed `w:abstractNum` /
|
|
@@ -733,10 +783,7 @@ function buildPatchedNumberingXml(originalXml, currentXml, changed) {
|
|
|
733
783
|
return true;
|
|
734
784
|
};
|
|
735
785
|
if (!collect("abstractNum", changed.abstractNums) || !collect("num", changed.nums)) return null;
|
|
736
|
-
|
|
737
|
-
let result = originalXml;
|
|
738
|
-
for (const { start, end, newXml } of replacements) result = result.slice(0, start) + newXml + result.slice(end);
|
|
739
|
-
return result;
|
|
786
|
+
return spliceXml(originalXml, replacements);
|
|
740
787
|
}
|
|
741
788
|
/**
|
|
742
789
|
* Numbering definitions present in `currentXml` (the model's serialization)
|
|
@@ -872,4 +919,4 @@ function escapeRegExp(str) {
|
|
|
872
919
|
return str.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
873
920
|
}
|
|
874
921
|
//#endregion
|
|
875
|
-
export { appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNotePartXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNoteParaIds, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, patchNumberingDefinitions, validatePatchSafety };
|
|
922
|
+
export { appendNumberingDefs, buildParagraphOffsetIndex, buildPatchedDocumentXml, buildPatchedNotePartXml, buildPatchedNoteXml, buildPatchedNumberingXml, collectAddedNumberingDefs, collectChangedNoteParaIds, collectChangedNumberingDefs, collectParaIds, countParagraphElements, extractParagraphXml, findParagraphOffsets, isXmlNameBoundary, patchNumberingDefinitions, spliceXml, validatePatchSafety };
|
|
@@ -34,8 +34,8 @@ function serializeBorder(input, elementName) {
|
|
|
34
34
|
if (themeTint) attrs.push(`w:themeTint="${escapeXmlAttribute(themeTint)}"`);
|
|
35
35
|
if (themeShade) attrs.push(`w:themeShade="${escapeXmlAttribute(themeShade)}"`);
|
|
36
36
|
}
|
|
37
|
-
if (shadow) attrs.push(
|
|
38
|
-
if (frame) attrs.push(
|
|
37
|
+
if (shadow !== void 0) attrs.push(`w:shadow="${shadow ? "1" : "0"}"`);
|
|
38
|
+
if (frame !== void 0) attrs.push(`w:frame="${frame ? "1" : "0"}"`);
|
|
39
39
|
if (artRelationshipId) attrs.push(`r:id="${escapeXmlAttribute(artRelationshipId)}"`);
|
|
40
40
|
if (topLeftArtRelationshipId) attrs.push(`r:topLeft="${escapeXmlAttribute(topLeftArtRelationshipId)}"`);
|
|
41
41
|
if (topRightArtRelationshipId) attrs.push(`r:topRight="${escapeXmlAttribute(topRightArtRelationshipId)}"`);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { deterministicHexId } from "../../utils/hexId.js";
|
|
2
2
|
import { commentThreadParaId } from "../commentThreadKey.js";
|
|
3
|
+
import { serializeWithPreservedChildren } from "../containerChildren.js";
|
|
3
4
|
import { serializeParagraph } from "./paragraphSerializer.js";
|
|
4
5
|
import { serializePartElement } from "./partNamespaces.js";
|
|
5
6
|
import { serializeTextFormatting } from "./textFormattingSerializer.js";
|
|
@@ -30,13 +31,10 @@ function serializeComment(comment) {
|
|
|
30
31
|
const attrs = [`w:id="${comment.id}"`, `w:author="${escapeXmlAttribute(comment.author)}"`];
|
|
31
32
|
if (comment.initials !== void 0) attrs.push(`w:initials="${escapeXmlAttribute(comment.initials)}"`);
|
|
32
33
|
if (comment.date) attrs.push(`w:date="${escapeXmlAttribute(comment.date)}"`);
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
} else xml += `<w:p>${serializeAnnotationReference(comment.annotationReferenceFormatting)}</w:p>`;
|
|
38
|
-
xml += "</w:comment>";
|
|
39
|
-
return xml;
|
|
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>`;
|
|
40
38
|
}
|
|
41
39
|
const COMMENTS_BASELINE_PREFIXES = [
|
|
42
40
|
"wpc",
|
|
@@ -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,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";
|
|
@@ -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,
|
|
@@ -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,4 +1,6 @@
|
|
|
1
1
|
import { modelParagraphFormattingEmission } from "../../internal/paragraphFormattingSerialization.js";
|
|
2
|
+
import { serializePreservedAttributes } from "../attributeRemainder.js";
|
|
3
|
+
import { fieldStateAttributes } from "../fieldState.js";
|
|
2
4
|
import { getParagraphPropertySource, paragraphPropertySourceMatchesEmission } from "../paragraphPropertySource.js";
|
|
3
5
|
import { reconcileRawSdtPr } from "../sdtPropertiesPatch.js";
|
|
4
6
|
import { DATE_UTC_ATTRIBUTE } from "../trackedChangeInfo.js";
|
|
@@ -344,13 +346,14 @@ function hyperlinkAttributes(hyperlink) {
|
|
|
344
346
|
/** One `w:hyperlink` child, with the caller deciding how a run is written. */
|
|
345
347
|
function serializeHyperlinkChild(child, serializeChildRun) {
|
|
346
348
|
if (child.type === "run") return serializeChildRun(child);
|
|
347
|
-
|
|
349
|
+
if (child.type === "bookmarkStart") return serializeBookmarkStart(child);
|
|
350
|
+
return child.type === "bookmarkEnd" ? serializeBookmarkEnd(child) : child.xml;
|
|
348
351
|
}
|
|
349
352
|
/**
|
|
350
353
|
* Serialize a hyperlink (w:hyperlink)
|
|
351
354
|
*/
|
|
352
|
-
function serializeHyperlink(hyperlink) {
|
|
353
|
-
const childrenXml = hyperlink.children.map((child) => serializeHyperlinkChild(child,
|
|
355
|
+
function serializeHyperlink(hyperlink, disposition = "kept") {
|
|
356
|
+
const childrenXml = hyperlink.children.map((child) => serializeHyperlinkChild(child, (run) => serializeInlineRun(run, disposition))).join("");
|
|
354
357
|
return `<w:hyperlink${hyperlinkAttributes(hyperlink)}>${childrenXml}</w:hyperlink>`;
|
|
355
358
|
}
|
|
356
359
|
/**
|
|
@@ -367,10 +370,11 @@ function serializeBookmarkEnd(bookmark) {
|
|
|
367
370
|
}
|
|
368
371
|
/** Serialize a simple field without changing its authored OOXML field form. */
|
|
369
372
|
function serializeSimpleField(field) {
|
|
370
|
-
const attrs = [`w:instr="${escapeXmlAttribute(field.instruction)}"
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
373
|
+
const attrs = [`w:instr="${escapeXmlAttribute(field.instruction)}"`, ...fieldStateAttributes(field)];
|
|
374
|
+
const contentXml = field.content.map((item) => {
|
|
375
|
+
if (item.type === "run") return serializeRun(item);
|
|
376
|
+
return item.type === "hyperlink" ? serializeHyperlink(item) : item.xml;
|
|
377
|
+
}).join("");
|
|
374
378
|
return `<w:fldSimple ${attrs.join(" ")}>${contentXml}</w:fldSimple>`;
|
|
375
379
|
}
|
|
376
380
|
/**
|
|
@@ -382,9 +386,7 @@ function serializeComplexField(field) {
|
|
|
382
386
|
const parts = [];
|
|
383
387
|
const structuralFormatting = field.formatting ?? field.fieldResult[0]?.formatting;
|
|
384
388
|
const rPrXml = structuralFormatting ? serializeTextFormatting(structuralFormatting) : "";
|
|
385
|
-
const beginAttrs = ["w:fldCharType=\"begin\""];
|
|
386
|
-
if (field.fldLock) beginAttrs.push("w:fldLock=\"true\"");
|
|
387
|
-
if (field.dirty) beginAttrs.push("w:dirty=\"true\"");
|
|
389
|
+
const beginAttrs = ["w:fldCharType=\"begin\"", ...fieldStateAttributes(field)];
|
|
388
390
|
parts.push(`<w:r>${rPrXml}<w:fldChar ${beginAttrs.join(" ")}/></w:r>`);
|
|
389
391
|
if (field.fieldCode.length > 0) parts.push(...field.fieldCode.map((run) => serializeRun(run)));
|
|
390
392
|
else if (field.instruction.length > 0) {
|
|
@@ -455,20 +457,22 @@ function synthesizeInlineSdtPr(props) {
|
|
|
455
457
|
* the properties block was re-synthesized from the modeled projection alone,
|
|
456
458
|
* silently dropping every unmodeled feature (and `w:sdtEndPr`) on save.
|
|
457
459
|
*/
|
|
458
|
-
function serializeInlineSdt(sdt) {
|
|
460
|
+
function serializeInlineSdt(sdt, disposition = "kept") {
|
|
459
461
|
const props = sdt.properties;
|
|
460
462
|
const contentXml = sdt.content.map((item) => {
|
|
461
463
|
switch (item.type) {
|
|
462
|
-
case "run": return
|
|
463
|
-
case "hyperlink": return serializeHyperlink(item);
|
|
464
|
+
case "run": return serializeInlineRun(item, disposition);
|
|
465
|
+
case "hyperlink": return serializeHyperlink(item, disposition);
|
|
464
466
|
case "simpleField": return serializeSimpleField(item);
|
|
465
467
|
case "complexField": return serializeComplexField(item);
|
|
466
|
-
case "inlineSdt": return serializeInlineSdt(item);
|
|
468
|
+
case "inlineSdt": return serializeInlineSdt(item, disposition);
|
|
469
|
+
case "inlineWrapper": return serializeParagraphContent(item, disposition);
|
|
467
470
|
case "insertion": return serializeTrackedChange("ins", item);
|
|
468
471
|
case "deletion": return serializeTrackedChange("del", item);
|
|
469
472
|
case "moveFrom": return serializeTrackedChange("moveFrom", item);
|
|
470
473
|
case "moveTo": return serializeTrackedChange("moveTo", item);
|
|
471
474
|
case "mathEquation": return item.ommlXml || "";
|
|
475
|
+
case "preservedInline": return item.xml;
|
|
472
476
|
default: return item;
|
|
473
477
|
}
|
|
474
478
|
}).join("");
|
|
@@ -489,6 +493,22 @@ function serializeMoveRangeStart(tag, marker) {
|
|
|
489
493
|
function rewriteRunTextAsDeleted(xml) {
|
|
490
494
|
return xml.replace(/<w:t\b/gu, "<w:delText").replace(/<\/w:t>/gu, "</w:delText>").replace(/<w:instrText\b/gu, "<w:delInstrText").replace(/<\/w:instrText>/gu, "</w:delInstrText>");
|
|
491
495
|
}
|
|
496
|
+
function serializeDeletedRun(run) {
|
|
497
|
+
const xml = serializeRun(run);
|
|
498
|
+
if (!run.content.some((c) => c.type === "drawing" || c.type === "shape")) return rewriteRunTextAsDeleted(xml);
|
|
499
|
+
if (!run.content.some((c) => c.type !== "drawing" && c.type !== "shape")) return xml;
|
|
500
|
+
return run.content.map((content) => {
|
|
501
|
+
const contentXml = serializeRun({
|
|
502
|
+
...run,
|
|
503
|
+
content: [content]
|
|
504
|
+
});
|
|
505
|
+
if (content.type === "drawing" || content.type === "shape") return contentXml;
|
|
506
|
+
return rewriteRunTextAsDeleted(contentXml);
|
|
507
|
+
}).join("");
|
|
508
|
+
}
|
|
509
|
+
function serializeInlineRun(run, disposition) {
|
|
510
|
+
return disposition === "removed" ? serializeDeletedRun(run) : serializeRun(run);
|
|
511
|
+
}
|
|
492
512
|
function trackedChangeTag(change) {
|
|
493
513
|
switch (change.type) {
|
|
494
514
|
case "insertion": return "ins";
|
|
@@ -499,29 +519,28 @@ function trackedChangeTag(change) {
|
|
|
499
519
|
}
|
|
500
520
|
function serializeTrackedChange(tag, change) {
|
|
501
521
|
const attrs = serializeTrackedChangeAttributes(change.info);
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
if (!run.content.some((c) => c.type === "drawing" || c.type === "shape")) return rewriteRunTextAsDeleted(xml);
|
|
505
|
-
if (!run.content.some((c) => c.type !== "drawing" && c.type !== "shape")) return xml;
|
|
506
|
-
return run.content.map((content) => {
|
|
507
|
-
const contentXml = serializeRun({
|
|
508
|
-
...run,
|
|
509
|
-
content: [content]
|
|
510
|
-
});
|
|
511
|
-
if (content.type === "drawing" || content.type === "shape") return contentXml;
|
|
512
|
-
return rewriteRunTextAsDeleted(contentXml);
|
|
513
|
-
}).join("");
|
|
514
|
-
};
|
|
515
|
-
const serializeContentRun = (run) => tag === "del" || tag === "moveFrom" ? serializeDeletedRun(run) : serializeRun(run);
|
|
522
|
+
const disposition = tag === "del" || tag === "moveFrom" ? "removed" : "kept";
|
|
523
|
+
const serializeContentRun = (run) => serializeInlineRun(run, disposition);
|
|
516
524
|
const serializeWrappedItem = (item) => {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
525
|
+
switch (item.type) {
|
|
526
|
+
case "run": return serializeContentRun(item);
|
|
527
|
+
case "simpleField":
|
|
528
|
+
case "complexField": {
|
|
529
|
+
const xml = item.type === "simpleField" ? serializeSimpleField(item) : serializeComplexField(item);
|
|
530
|
+
return disposition === "removed" ? rewriteRunTextAsDeleted(xml) : xml;
|
|
531
|
+
}
|
|
532
|
+
case "mathEquation": return item.ommlXml;
|
|
533
|
+
case "insertion":
|
|
534
|
+
case "deletion":
|
|
535
|
+
case "moveFrom":
|
|
536
|
+
case "moveTo": return serializeTrackedChange(trackedChangeTag(item), item);
|
|
537
|
+
case "bookmarkStart": return serializeBookmarkStart(item);
|
|
538
|
+
case "bookmarkEnd": return serializeBookmarkEnd(item);
|
|
539
|
+
case "preservedInline": return item.xml;
|
|
540
|
+
case "inlineWrapper":
|
|
541
|
+
case "inlineSdt": return serializeParagraphContent(item, disposition);
|
|
542
|
+
default: return item;
|
|
521
543
|
}
|
|
522
|
-
if (item.type === "mathEquation") return item.ommlXml;
|
|
523
|
-
if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") return serializeTrackedChange(trackedChangeTag(item), item);
|
|
524
|
-
return item.type === "bookmarkStart" ? serializeBookmarkStart(item) : serializeBookmarkEnd(item);
|
|
525
544
|
};
|
|
526
545
|
const open = `<w:${tag} ${attrs}>`;
|
|
527
546
|
const close = `</w:${tag}>`;
|
|
@@ -554,27 +573,22 @@ function serializeCommentReferenceRun(id) {
|
|
|
554
573
|
/**
|
|
555
574
|
* Serialize a single paragraph content item.
|
|
556
575
|
*
|
|
557
|
-
* `
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
* editor (fromProseDoc) path emits range markers with no reference node, so the
|
|
562
|
-
* synthetic run is still written when the id is absent from the set.
|
|
576
|
+
* A `commentRangeEnd` writes an end and nothing else. Where the comment's
|
|
577
|
+
* reference run goes is authored data the model carries as its own item, and
|
|
578
|
+
* `completeCommentReferences` fills it in for a model that arrived without
|
|
579
|
+
* one; a guess made here from one paragraph cannot see the rest of the story.
|
|
563
580
|
*/
|
|
564
|
-
function serializeParagraphContent(content,
|
|
581
|
+
function serializeParagraphContent(content, disposition = "kept") {
|
|
565
582
|
switch (content.type) {
|
|
566
|
-
case "run": return
|
|
567
|
-
case "hyperlink": return serializeHyperlink(content);
|
|
583
|
+
case "run": return serializeInlineRun(content, disposition);
|
|
584
|
+
case "hyperlink": return serializeHyperlink(content, disposition);
|
|
568
585
|
case "bookmarkStart": return serializeBookmarkStart(content);
|
|
569
586
|
case "bookmarkEnd": return serializeBookmarkEnd(content);
|
|
570
587
|
case "simpleField": return serializeSimpleField(content);
|
|
571
588
|
case "complexField": return serializeComplexField(content);
|
|
572
|
-
case "inlineSdt": return serializeInlineSdt(content);
|
|
589
|
+
case "inlineSdt": return serializeInlineSdt(content, disposition);
|
|
573
590
|
case "commentRangeStart": return `<w:commentRangeStart ${markupRangeAttributes(content).join(" ")}/>`;
|
|
574
|
-
case "commentRangeEnd": {
|
|
575
|
-
const end = `<w:commentRangeEnd ${markupRangeAttributes(content).join(" ")}/>`;
|
|
576
|
-
return explicitCommentReferenceIds.has(content.id) ? end : `${end}${serializeCommentReferenceRun(content.id)}`;
|
|
577
|
-
}
|
|
591
|
+
case "commentRangeEnd": return `<w:commentRangeEnd ${markupRangeAttributes(content).join(" ")}/>`;
|
|
578
592
|
case "commentReference": return serializeCommentReferenceRun(content.id);
|
|
579
593
|
case "insertion": return serializeTrackedChange("ins", content);
|
|
580
594
|
case "deletion": return serializeTrackedChange("del", content);
|
|
@@ -584,11 +598,18 @@ function serializeParagraphContent(content, explicitCommentReferenceIds) {
|
|
|
584
598
|
case "moveFromRangeEnd": return `<w:moveFromRangeEnd ${markupRangeAttributes(content).join(" ")}/>`;
|
|
585
599
|
case "moveToRangeStart": return serializeMoveRangeStart("moveToRangeStart", content);
|
|
586
600
|
case "moveToRangeEnd": return `<w:moveToRangeEnd ${markupRangeAttributes(content).join(" ")}/>`;
|
|
587
|
-
case "
|
|
588
|
-
const
|
|
589
|
-
|
|
601
|
+
case "inlineWrapper": {
|
|
602
|
+
const inner = content.content.map((child) => serializeParagraphContent(child, disposition)).join("");
|
|
603
|
+
switch (content.kind) {
|
|
604
|
+
case "bidi": {
|
|
605
|
+
const tag = content.control === "override" ? "bdo" : "dir";
|
|
606
|
+
return `<w:${tag}${content.direction === void 0 ? "" : ` w:val="${escapeXmlAttribute(content.direction)}"`}>${inner}</w:${tag}>`;
|
|
607
|
+
}
|
|
608
|
+
default: return content.kind;
|
|
609
|
+
}
|
|
590
610
|
}
|
|
591
611
|
case "mathEquation": return content.ommlXml || "";
|
|
612
|
+
case "preservedInline": return content.xml;
|
|
592
613
|
default: return "";
|
|
593
614
|
}
|
|
594
615
|
}
|
|
@@ -604,18 +625,17 @@ function serializeParagraph(paragraph) {
|
|
|
604
625
|
if (paragraph.paraId) attrs.push(`w14:paraId="${escapeXmlAttribute(paragraph.paraId)}"`);
|
|
605
626
|
if (paragraph.textId) attrs.push(`w14:textId="${escapeXmlAttribute(paragraph.textId)}"`);
|
|
606
627
|
if (paragraph.reviewCarrier) attrs.push(`folio:reviewCarrier="${paragraph.reviewCarrier}"`);
|
|
607
|
-
const
|
|
628
|
+
const written = serializePreservedAttributes(attrs, paragraph.preservedAttributes);
|
|
629
|
+
const attrsStr = written.length > 0 ? ` ${written.join(" ")}` : "";
|
|
608
630
|
parts.push(serializeParagraphFormattingWithOptions(paragraph.formatting, {
|
|
609
631
|
propertyChanges: paragraph.propertyChanges,
|
|
610
632
|
paragraphMarkChange: paragraph.pPrMark,
|
|
611
633
|
propertySource: getParagraphPropertySource(paragraph),
|
|
612
634
|
sectionProperties: paragraph.sectionProperties
|
|
613
635
|
}));
|
|
614
|
-
const explicitCommentReferenceIds = /* @__PURE__ */ new Set();
|
|
615
|
-
for (const content of paragraph.content) if (content.type === "commentReference") explicitCommentReferenceIds.add(content.id);
|
|
616
636
|
let pendingRenderedPageBreak = paragraph.renderedPageBreakBefore === true;
|
|
617
637
|
for (const content of paragraph.content) {
|
|
618
|
-
let contentXml = serializeParagraphContent(content
|
|
638
|
+
let contentXml = serializeParagraphContent(content);
|
|
619
639
|
if (contentXml) {
|
|
620
640
|
if (pendingRenderedPageBreak) {
|
|
621
641
|
const next = injectRenderedPageBreakIntoFirstRun(contentXml);
|