@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,4 +1,6 @@
|
|
|
1
|
+
import { rangedCommentIds } from "../../docx/commentAnchorIndex.js";
|
|
1
2
|
import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
|
|
3
|
+
import { isInlineSdtContent, isTrackedChangeWrapperChild } from "../../docx/inlineWrapperContent.js";
|
|
2
4
|
import { isNumberingReference } from "../../docx/numberingReference.js";
|
|
3
5
|
import { PROSE_PARAGRAPH_SOURCE_CONTRACT_ATTR, createProseParagraphWithPropertySource, getDocumentParagraphPropertySourceContract, recreateProseNodeWithParagraphPropertySource, transportTableCellsWithParagraphPropertySources } from "../../docx/paragraphPropertySource.js";
|
|
4
6
|
import { isBaselineVertAlign } from "../../docx/runParser.js";
|
|
@@ -11,8 +13,11 @@ import { mergeParagraphFormatting, mergeParagraphTabStops } from "../../utils/pa
|
|
|
11
13
|
import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
|
|
12
14
|
import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
|
|
13
15
|
import { emuToPixels, emuToStrokePixels } from "../../utils/units.js";
|
|
16
|
+
import { expectInlineWrapperMarkAttrs } from "../attrs/index.js";
|
|
17
|
+
import { authoredTransformAttrs } from "../authoredTransformAttrs.js";
|
|
14
18
|
import { setAutospacingBaseValue } from "../autospacingBase.js";
|
|
15
19
|
import { textFormattingToMarks } from "../extensions/marks/markUtils.js";
|
|
20
|
+
import { inlineWrapperLayer } from "../inlineWrapperStack.js";
|
|
16
21
|
import { listRenderingAttrPatch } from "../listRenderingAttrs.js";
|
|
17
22
|
import { stampNumberedRefFieldBaselines } from "../numberedRefFields.js";
|
|
18
23
|
import { pageBreakRunParagraphProjectionDispositionForFeatures } from "../pageBreakRunProjection.js";
|
|
@@ -21,17 +26,23 @@ import { styleResolvedParagraphFormatting } from "../paragraphFormattingProvenan
|
|
|
21
26
|
import { lineSpacingProvenanceFromSpacing } from "../paragraphSpacing.js";
|
|
22
27
|
import { getParagraphMarkSuppressionOverrides, hasDirectRunFormatting, resolveParagraphBodyRunFormatting, stripParagraphMarkFormattingForBodyRuns, stripParagraphMarkOnlyFormatting, suppressParagraphMarkFormatting } from "../runStyleFormatting.js";
|
|
23
28
|
import { schema } from "../schema/index.js";
|
|
29
|
+
import { PRESERVED_XML_LEVELS } from "../schema/nodes.js";
|
|
24
30
|
import { cascadeStyleTextFormatting } from "../styles/styleToggleCascade.js";
|
|
25
31
|
import { canCarryTrackedRunMark, trackedRunInlineAtomDisposition } from "../trackedRunInlineAtoms.js";
|
|
26
32
|
import { assertValidProseMirrorDocument } from "../validation.js";
|
|
27
33
|
import { resolveEffectiveTableCellFormatting } from "./effectiveTableCellFormatting.js";
|
|
28
34
|
import { sdtAttrsFromProperties } from "./sdtAttrs.js";
|
|
29
|
-
import {
|
|
30
|
-
import { DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
|
|
35
|
+
import { panic } from "better-result";
|
|
36
|
+
import { DRAWING_RAW_XML_MODES, PARSE_WARNING_CODES } from "@stll/docx-core/model";
|
|
31
37
|
//#region src/prosemirror/conversion/toProseDoc.ts
|
|
32
|
-
/** DOCX content that cannot be preserved by the editable ProseMirror model. */
|
|
33
|
-
var UnsupportedDocxToProseMirrorConversionError = class extends TaggedError("UnsupportedDocxToProseMirrorConversionError") {};
|
|
34
38
|
const DETACHED_WATERMARK_HOST = Symbol.for("stll.detachedWatermarkHost");
|
|
39
|
+
const noPageBreakProjectionWarning = () => {};
|
|
40
|
+
const pageBreakProjectionWarn = (warn) => warn === void 0 ? noPageBreakProjectionWarning : (detail) => {
|
|
41
|
+
warn({
|
|
42
|
+
code: PARSE_WARNING_CODES.pageBreakProjectionApproximated,
|
|
43
|
+
detail
|
|
44
|
+
});
|
|
45
|
+
};
|
|
35
46
|
/**
|
|
36
47
|
* Build a `nextTextBoxGroupId()` generator salted with a random per-load
|
|
37
48
|
* nonce, so minted text-box anchor ids (`<salt>:<group>:<index>`) are unique
|
|
@@ -89,6 +100,7 @@ const collectPairedBookmarkIds = (blocks) => {
|
|
|
89
100
|
case "run":
|
|
90
101
|
visitRun(child);
|
|
91
102
|
break;
|
|
103
|
+
case "preservedInline": break;
|
|
92
104
|
default: panic(`Unsupported hyperlink child: ${JSON.stringify(child)}`);
|
|
93
105
|
}
|
|
94
106
|
};
|
|
@@ -108,7 +120,7 @@ const collectPairedBookmarkIds = (blocks) => {
|
|
|
108
120
|
return;
|
|
109
121
|
case "simpleField":
|
|
110
122
|
for (const child of content.content) if (child.type === "hyperlink") visitHyperlink(child);
|
|
111
|
-
else visitRun(child);
|
|
123
|
+
else if (child.type === "run") visitRun(child);
|
|
112
124
|
return;
|
|
113
125
|
case "complexField":
|
|
114
126
|
for (const run of [...content.fieldCode ?? [], ...content.fieldResult]) visitRun(run);
|
|
@@ -118,7 +130,7 @@ const collectPairedBookmarkIds = (blocks) => {
|
|
|
118
130
|
case "deletion":
|
|
119
131
|
case "moveFrom":
|
|
120
132
|
case "moveTo":
|
|
121
|
-
case "
|
|
133
|
+
case "inlineWrapper":
|
|
122
134
|
for (const child of content.content) visitParagraphContent(child);
|
|
123
135
|
return;
|
|
124
136
|
case "commentRangeStart":
|
|
@@ -128,7 +140,8 @@ const collectPairedBookmarkIds = (blocks) => {
|
|
|
128
140
|
case "moveFromRangeEnd":
|
|
129
141
|
case "moveToRangeStart":
|
|
130
142
|
case "moveToRangeEnd":
|
|
131
|
-
case "mathEquation":
|
|
143
|
+
case "mathEquation":
|
|
144
|
+
case "preservedInline": return;
|
|
132
145
|
default: panic(`Unsupported paragraph content: ${JSON.stringify(content)}`);
|
|
133
146
|
}
|
|
134
147
|
};
|
|
@@ -143,6 +156,7 @@ const collectPairedBookmarkIds = (blocks) => {
|
|
|
143
156
|
case "blockSdt":
|
|
144
157
|
visitBlocks(block.content);
|
|
145
158
|
break;
|
|
159
|
+
case "preservedBlock": break;
|
|
146
160
|
default: panic(`Unsupported block content: ${JSON.stringify(block)}`);
|
|
147
161
|
}
|
|
148
162
|
};
|
|
@@ -166,7 +180,10 @@ function toProseDoc(document, options) {
|
|
|
166
180
|
nextTextBoxGroupId,
|
|
167
181
|
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator(),
|
|
168
182
|
pairedBookmarkIds: collectPairedBookmarkIds(paragraphs),
|
|
169
|
-
pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(paragraphs)
|
|
183
|
+
pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(paragraphs),
|
|
184
|
+
storyRangedCommentIds: rangedCommentIds(paragraphs),
|
|
185
|
+
openCommentIds: /* @__PURE__ */ new Set(),
|
|
186
|
+
warnPageBreakProjection: pageBreakProjectionWarn(options?.warn)
|
|
170
187
|
};
|
|
171
188
|
const convertBodyBlocks = (blocks) => {
|
|
172
189
|
const out = [];
|
|
@@ -183,6 +200,9 @@ function toProseDoc(document, options) {
|
|
|
183
200
|
case "blockSdt":
|
|
184
201
|
out.push(convertBlockSdt(block, convertBodyBlocks));
|
|
185
202
|
break;
|
|
203
|
+
case "preservedBlock":
|
|
204
|
+
out.push(convertPreservedBlock(block));
|
|
205
|
+
break;
|
|
186
206
|
default: panic(`Unsupported block content: ${JSON.stringify(block)}`);
|
|
187
207
|
}
|
|
188
208
|
return out;
|
|
@@ -200,6 +220,30 @@ function toProseDoc(document, options) {
|
|
|
200
220
|
return pmDoc;
|
|
201
221
|
}
|
|
202
222
|
/**
|
|
223
|
+
* Carry a block folio does not model into the editor as a zero-width node.
|
|
224
|
+
*
|
|
225
|
+
* The node's place in the document is the whole of its position, so it needs
|
|
226
|
+
* no index and nothing has to keep one honest as the blocks around it change.
|
|
227
|
+
*/
|
|
228
|
+
function convertPreservedBlock(block) {
|
|
229
|
+
return schema.node("preservedBlock", { xml: block.xml });
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Carry an inline child folio does not model into the editor as an opaque atom.
|
|
233
|
+
*
|
|
234
|
+
* The same atom the run level uses, tagged with the level it came from: the
|
|
235
|
+
* markup is a paragraph child and the save path must not put it back inside a
|
|
236
|
+
* `w:r`. It carries whatever marks surround it, so a capture inside a
|
|
237
|
+
* `w:ins` keeps the insertion and is accepted or rejected with it.
|
|
238
|
+
*/
|
|
239
|
+
function preservedInlineNode(content) {
|
|
240
|
+
return schema.node("preservedXml", {
|
|
241
|
+
xml: content.xml,
|
|
242
|
+
text: content.text,
|
|
243
|
+
level: PRESERVED_XML_LEVELS.inline
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
203
247
|
* Convert a `BlockSdt` model node into a `blockSdt` PM node, recursively
|
|
204
248
|
* converting its children with the caller-supplied block converter. Pass
|
|
205
249
|
* `rawPropertiesXml` / `rawEndPropertiesXml` through as attrs so the
|
|
@@ -236,26 +280,27 @@ function convertBlockSdt(blockSdt, convertBlocks) {
|
|
|
236
280
|
* Resolves style-based text formatting and passes it to runs so that
|
|
237
281
|
* paragraph styles (like Heading1) apply their font size, color, etc.
|
|
238
282
|
*/
|
|
239
|
-
function convertParagraph(paragraph, styleResolver, context,
|
|
240
|
-
const { nextHyperlinkInstanceIndex, pairedBookmarkIds, pageBreakRunSourceDescendants } = context;
|
|
283
|
+
function convertParagraph(paragraph, styleResolver, context, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
|
|
284
|
+
const { nextHyperlinkInstanceIndex, pairedBookmarkIds, pageBreakRunSourceDescendants, storyRangedCommentIds, openCommentIds } = context;
|
|
241
285
|
let pageBreakRunOwnerId = 0;
|
|
242
286
|
const nextPageBreakRunOwnerId = () => pageBreakRunOwnerId++;
|
|
243
287
|
const { attrs, effectiveFrame } = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
|
|
244
|
-
|
|
288
|
+
reportParagraphPageBreakProjection({
|
|
245
289
|
paragraph,
|
|
246
290
|
attrs,
|
|
247
291
|
effectiveFrame,
|
|
248
|
-
sourceDescendants: pageBreakRunSourceDescendants
|
|
292
|
+
sourceDescendants: pageBreakRunSourceDescendants,
|
|
293
|
+
warn: context.warnPageBreakProjection
|
|
249
294
|
});
|
|
250
295
|
const isTocParagraph = attrs._tableOfContentsLevel !== void 0;
|
|
251
296
|
const inlineNodes = [];
|
|
252
297
|
let inlineOffset = 0;
|
|
253
298
|
let bookmarksArr;
|
|
254
299
|
let emptyHyperlinks;
|
|
255
|
-
|
|
300
|
+
let wrapperStack = [];
|
|
256
301
|
const emitInlineNodes = (nodes) => {
|
|
257
302
|
if (nodes.length === 0) return;
|
|
258
|
-
const markedNodes = applyCommentMarks(nodes,
|
|
303
|
+
const markedNodes = applyCommentMarks(withInlineWrapperMark(nodes, wrapperStack), openCommentIds);
|
|
259
304
|
inlineNodes.push(...markedNodes);
|
|
260
305
|
for (const node of markedNodes) inlineOffset += node.nodeSize;
|
|
261
306
|
};
|
|
@@ -321,97 +366,104 @@ function convertParagraph(paragraph, styleResolver, context, activeCommentIds, e
|
|
|
321
366
|
};
|
|
322
367
|
};
|
|
323
368
|
const emitTrackedChange = (change, markType, moveKind) => {
|
|
324
|
-
emitInlineNodes(convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
|
|
369
|
+
emitInlineNodes(convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors, wrapperStack));
|
|
325
370
|
};
|
|
326
|
-
for (const content of
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
emptyHyperlinks.push({
|
|
350
|
-
offset: inlineOffset,
|
|
351
|
-
...content.href !== void 0 ? { href: content.href } : {},
|
|
352
|
-
...content.anchor !== void 0 ? { anchor: content.anchor } : {},
|
|
353
|
-
...content.tooltip !== void 0 ? { tooltip: content.tooltip } : {},
|
|
354
|
-
...content.rId !== void 0 ? { rId: content.rId } : {}
|
|
371
|
+
for (const { content, stack } of withInlineWrapperStacks(paragraph.content)) {
|
|
372
|
+
wrapperStack = stack;
|
|
373
|
+
switch (content.type) {
|
|
374
|
+
case "commentRangeStart":
|
|
375
|
+
openCommentIds.add(content.id);
|
|
376
|
+
break;
|
|
377
|
+
case "commentRangeEnd":
|
|
378
|
+
openCommentIds.delete(content.id);
|
|
379
|
+
break;
|
|
380
|
+
case "commentReference":
|
|
381
|
+
if (!storyRangedCommentIds.has(content.id)) anchorPointComment(inlineNodes, content.id);
|
|
382
|
+
emitInlineNode(schema.node("commentReference", { commentId: content.id }));
|
|
383
|
+
break;
|
|
384
|
+
case "run":
|
|
385
|
+
emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
|
|
386
|
+
break;
|
|
387
|
+
case "hyperlink": {
|
|
388
|
+
const linkNodes = convertHyperlink(content, {
|
|
389
|
+
getInheritedRunFormatting,
|
|
390
|
+
styleResolver,
|
|
391
|
+
hyperlinkIndex: nextHyperlinkInstanceIndex(),
|
|
392
|
+
textBoxAnchors,
|
|
393
|
+
nextPageBreakRunOwnerId
|
|
355
394
|
});
|
|
395
|
+
if (linkNodes.length === 0) {
|
|
396
|
+
emptyHyperlinks ??= [];
|
|
397
|
+
emptyHyperlinks.push({
|
|
398
|
+
offset: inlineOffset,
|
|
399
|
+
...content.href !== void 0 ? { href: content.href } : {},
|
|
400
|
+
...content.anchor !== void 0 ? { anchor: content.anchor } : {},
|
|
401
|
+
...content.tooltip !== void 0 ? { tooltip: content.tooltip } : {},
|
|
402
|
+
...content.rId !== void 0 ? { rId: content.rId } : {}
|
|
403
|
+
});
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
emitInlineNodes(linkNodes);
|
|
356
407
|
break;
|
|
357
408
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
409
|
+
case "simpleField":
|
|
410
|
+
case "complexField":
|
|
411
|
+
emitInlineNode(convertField(content, {
|
|
412
|
+
getInheritedRunFormatting,
|
|
413
|
+
styleResolver,
|
|
414
|
+
nextHyperlinkInstanceIndex,
|
|
415
|
+
nextPageBreakRunOwnerId,
|
|
416
|
+
textBoxAnchors
|
|
417
|
+
}));
|
|
418
|
+
break;
|
|
419
|
+
case "inlineSdt":
|
|
420
|
+
emitInlineNode(convertInlineSdt(content, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors, stack));
|
|
421
|
+
break;
|
|
422
|
+
case "insertion":
|
|
423
|
+
case "moveTo":
|
|
424
|
+
emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
|
|
425
|
+
break;
|
|
426
|
+
case "deletion":
|
|
427
|
+
case "moveFrom":
|
|
428
|
+
emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
|
|
429
|
+
break;
|
|
430
|
+
case "mathEquation":
|
|
431
|
+
emitInlineNode(convertMathEquation(content));
|
|
432
|
+
break;
|
|
433
|
+
case "bookmarkStart":
|
|
434
|
+
if (pairedBookmarkIds.has(content.id)) {
|
|
435
|
+
emitInlineNode(schema.node("bookmarkBoundary", {
|
|
436
|
+
type: "start",
|
|
437
|
+
id: content.id,
|
|
438
|
+
name: content.name,
|
|
439
|
+
colFirst: content.colFirst,
|
|
440
|
+
colLast: content.colLast,
|
|
441
|
+
displacedByCustomXml: content.displacedByCustomXml
|
|
442
|
+
}));
|
|
443
|
+
break;
|
|
444
|
+
}
|
|
445
|
+
if (!bookmarksArr) bookmarksArr = [];
|
|
446
|
+
bookmarksArr.push({
|
|
447
|
+
id: content.id,
|
|
448
|
+
name: content.name
|
|
449
|
+
});
|
|
450
|
+
break;
|
|
451
|
+
case "bookmarkEnd":
|
|
452
|
+
if (pairedBookmarkIds.has(content.id)) emitInlineNode(schema.node("bookmarkBoundary", {
|
|
453
|
+
type: "end",
|
|
389
454
|
id: content.id,
|
|
390
|
-
name: content.name,
|
|
391
|
-
colFirst: content.colFirst,
|
|
392
|
-
colLast: content.colLast,
|
|
393
455
|
displacedByCustomXml: content.displacedByCustomXml
|
|
394
456
|
}));
|
|
395
457
|
break;
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
type: "end",
|
|
406
|
-
id: content.id,
|
|
407
|
-
displacedByCustomXml: content.displacedByCustomXml
|
|
408
|
-
}));
|
|
409
|
-
break;
|
|
410
|
-
case "moveFromRangeStart":
|
|
411
|
-
case "moveFromRangeEnd":
|
|
412
|
-
case "moveToRangeStart":
|
|
413
|
-
case "moveToRangeEnd": break;
|
|
414
|
-
default: panic(`Unsupported paragraph content: ${JSON.stringify(content)}`);
|
|
458
|
+
case "moveFromRangeStart":
|
|
459
|
+
case "moveFromRangeEnd":
|
|
460
|
+
case "moveToRangeStart":
|
|
461
|
+
case "moveToRangeEnd": break;
|
|
462
|
+
case "preservedInline":
|
|
463
|
+
emitInlineNode(preservedInlineNode(content));
|
|
464
|
+
break;
|
|
465
|
+
default: panic(`Unsupported paragraph content: ${JSON.stringify(content)}`);
|
|
466
|
+
}
|
|
415
467
|
}
|
|
416
468
|
if (bookmarksArr) attrs.bookmarks = bookmarksArr;
|
|
417
469
|
if (emptyHyperlinks) attrs._emptyHyperlinks = emptyHyperlinks;
|
|
@@ -449,48 +501,57 @@ function anchorPointComment(nodes, commentId) {
|
|
|
449
501
|
* Convert tracked change (insertion or deletion) content to PM nodes with
|
|
450
502
|
* an insertion/deletion mark applied.
|
|
451
503
|
*/
|
|
452
|
-
function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, moveKind = null, textBoxAnchors) {
|
|
504
|
+
function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, moveKind = null, textBoxAnchors, wrappedBy = []) {
|
|
453
505
|
const nodes = [];
|
|
454
|
-
for (const
|
|
455
|
-
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
506
|
+
for (const { content: item, stack } of withInlineWrapperStacks(change.content)) {
|
|
507
|
+
if (!isTrackedChangeWrapperChild(item)) continue;
|
|
508
|
+
const itemNodes = [];
|
|
509
|
+
if (item.type === "run") itemNodes.push(...convertRun(item, getInheritedRunFormatting(item.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
|
|
510
|
+
else if (item.type === "hyperlink") {
|
|
511
|
+
const currentHyperlinkIndex = nextHyperlinkInstanceIndex();
|
|
512
|
+
itemNodes.push(...convertHyperlink(item, {
|
|
513
|
+
getInheritedRunFormatting,
|
|
514
|
+
styleResolver,
|
|
515
|
+
hyperlinkIndex: currentHyperlinkIndex,
|
|
516
|
+
textBoxAnchors,
|
|
517
|
+
nextPageBreakRunOwnerId
|
|
518
|
+
}));
|
|
519
|
+
} else if (item.type === "simpleField" || item.type === "complexField") {
|
|
520
|
+
const fieldNode = convertField(item, {
|
|
521
|
+
getInheritedRunFormatting,
|
|
522
|
+
styleResolver,
|
|
523
|
+
nextHyperlinkInstanceIndex,
|
|
524
|
+
nextPageBreakRunOwnerId,
|
|
525
|
+
textBoxAnchors
|
|
526
|
+
});
|
|
527
|
+
if (fieldNode) itemNodes.push(fieldNode);
|
|
528
|
+
} else if (item.type === "mathEquation") {
|
|
529
|
+
const mathNode = convertMathEquation(item);
|
|
530
|
+
if (mathNode) itemNodes.push(mathNode);
|
|
531
|
+
} else if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
|
|
532
|
+
const nestedMarkType = item.type === "insertion" || item.type === "moveTo" ? "insertion" : "deletion";
|
|
533
|
+
const nestedMoveKind = item.type === "moveFrom" || item.type === "moveTo" ? item.type : null;
|
|
534
|
+
itemNodes.push(...convertTrackedChange(item, nestedMarkType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, nestedMoveKind, textBoxAnchors));
|
|
535
|
+
} else if (item.type === "inlineSdt") {
|
|
536
|
+
const sdtNode = convertInlineSdt(item, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors, [...wrappedBy, ...stack]);
|
|
537
|
+
if (sdtNode) itemNodes.push(sdtNode);
|
|
538
|
+
} else if (item.type === "bookmarkStart") itemNodes.push(schema.node("bookmarkBoundary", {
|
|
539
|
+
type: "start",
|
|
540
|
+
id: item.id,
|
|
541
|
+
name: item.name,
|
|
542
|
+
colFirst: item.colFirst,
|
|
543
|
+
colLast: item.colLast,
|
|
544
|
+
displacedByCustomXml: item.displacedByCustomXml
|
|
463
545
|
}));
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
} else if (item.type === "mathEquation") {
|
|
474
|
-
const mathNode = convertMathEquation(item);
|
|
475
|
-
if (mathNode) nodes.push(mathNode);
|
|
476
|
-
} else if (item.type === "insertion" || item.type === "deletion" || item.type === "moveFrom" || item.type === "moveTo") {
|
|
477
|
-
const nestedMarkType = item.type === "insertion" || item.type === "moveTo" ? "insertion" : "deletion";
|
|
478
|
-
const nestedMoveKind = item.type === "moveFrom" || item.type === "moveTo" ? item.type : null;
|
|
479
|
-
nodes.push(...convertTrackedChange(item, nestedMarkType, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, nestedMoveKind, textBoxAnchors));
|
|
480
|
-
} else if (item.type === "bookmarkStart") nodes.push(schema.node("bookmarkBoundary", {
|
|
481
|
-
type: "start",
|
|
482
|
-
id: item.id,
|
|
483
|
-
name: item.name,
|
|
484
|
-
colFirst: item.colFirst,
|
|
485
|
-
colLast: item.colLast,
|
|
486
|
-
displacedByCustomXml: item.displacedByCustomXml
|
|
487
|
-
}));
|
|
488
|
-
else if (item.type === "bookmarkEnd") nodes.push(schema.node("bookmarkBoundary", {
|
|
489
|
-
type: "end",
|
|
490
|
-
id: item.id,
|
|
491
|
-
displacedByCustomXml: item.displacedByCustomXml
|
|
492
|
-
}));
|
|
493
|
-
else panic(`Unsupported tracked-run content: ${JSON.stringify(item)}`);
|
|
546
|
+
else if (item.type === "bookmarkEnd") itemNodes.push(schema.node("bookmarkBoundary", {
|
|
547
|
+
type: "end",
|
|
548
|
+
id: item.id,
|
|
549
|
+
displacedByCustomXml: item.displacedByCustomXml
|
|
550
|
+
}));
|
|
551
|
+
else if (item.type === "preservedInline") itemNodes.push(preservedInlineNode(item));
|
|
552
|
+
else panic(`Unsupported tracked-run content: ${JSON.stringify(item)}`);
|
|
553
|
+
nodes.push(...withInlineWrapperMark(itemNodes, stack));
|
|
554
|
+
}
|
|
494
555
|
const mark = schema.marks[markType].create({
|
|
495
556
|
revisionId: change.info.id,
|
|
496
557
|
author: change.info.author,
|
|
@@ -525,6 +586,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
|
|
|
525
586
|
if (paragraph.listRendering) Object.assign(attrs, listRenderingAttrPatch(paragraph.listRendering));
|
|
526
587
|
if (formatting) attrs._originalFormatting = formatting;
|
|
527
588
|
if (paragraph.propertyChanges && paragraph.propertyChanges.length > 0) attrs._propertyChanges = [...paragraph.propertyChanges];
|
|
589
|
+
if (paragraph.preservedAttributes && paragraph.preservedAttributes.length > 0) attrs._preservedAttributes = paragraph.preservedAttributes;
|
|
528
590
|
if (paragraph.pPrMark) attrs.pPrMark = paragraph.pPrMark;
|
|
529
591
|
const set = (key, val) => {
|
|
530
592
|
if (val !== void 0) attrs[key] = val;
|
|
@@ -850,6 +912,7 @@ function tableCellHasMeaningfulContent(cell) {
|
|
|
850
912
|
return cell.content.some(blockHasMeaningfulContent);
|
|
851
913
|
}
|
|
852
914
|
function blockHasMeaningfulContent(block) {
|
|
915
|
+
if (block.type === "preservedBlock") return true;
|
|
853
916
|
if (block.type === "table") return block.rows.some((row) => row.cells.some((cell) => tableCellHasMeaningfulContent(cell)));
|
|
854
917
|
return block.content.some(paragraphContentHasMeaningfulContent);
|
|
855
918
|
}
|
|
@@ -861,12 +924,11 @@ function paragraphContentHasMeaningfulContent(content) {
|
|
|
861
924
|
}
|
|
862
925
|
function convertTable(table, styleResolver, context) {
|
|
863
926
|
for (const row of table.rows) for (const cell of row.cells) {
|
|
864
|
-
if (isCellMergeContinuation(cell) && context.pageBreakRunSourceDescendants.containsPageBreakRun(cell.content))
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
assertSourceContainerHasNoPageBreakRun(cell.content, "table-cell", context.pageBreakRunSourceDescendants);
|
|
927
|
+
if (isCellMergeContinuation(cell) && context.pageBreakRunSourceDescendants.containsPageBreakRun(cell.content)) {
|
|
928
|
+
context.warnPageBreakProjection("A page break inside a vertically merged table cell paginates with the merged row");
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
reportSourceContainerPageBreakRun(cell.content, "table-cell", context.pageBreakRunSourceDescendants, context.warnPageBreakProjection);
|
|
870
932
|
}
|
|
871
933
|
const rowSpanMap = calculateRowSpans(table);
|
|
872
934
|
const columnWidths = table.columnWidths;
|
|
@@ -972,6 +1034,7 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
|
|
|
972
1034
|
if (resolvedJustification) attrsWithoutStructuralChange._resolvedJustification = resolvedJustification;
|
|
973
1035
|
if (row.formatting) attrsWithoutStructuralChange._originalFormatting = row.formatting;
|
|
974
1036
|
if (row.propertyChanges && row.propertyChanges.length > 0) attrsWithoutStructuralChange.trPrChange = [...row.propertyChanges];
|
|
1037
|
+
if (row.preservedAttributes && row.preservedAttributes.length > 0) attrsWithoutStructuralChange._preservedAttributes = row.preservedAttributes;
|
|
975
1038
|
let attrs = attrsWithoutStructuralChange;
|
|
976
1039
|
const rowStructuralChange = row.structuralChange;
|
|
977
1040
|
if (rowStructuralChange) {
|
|
@@ -1168,13 +1231,23 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
|
|
|
1168
1231
|
if (preserveVMergeRestart) attrs._preserveVMergeRestart = true;
|
|
1169
1232
|
if (vMergeContinuationCells && vMergeContinuationCells.length > 0) attrs._docxVMergeContinuationCells = transportTableCellsWithParagraphPropertySources(vMergeContinuationCells);
|
|
1170
1233
|
const contentNodes = [];
|
|
1171
|
-
for (const content of cell.content)
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1234
|
+
for (const content of cell.content) switch (content.type) {
|
|
1235
|
+
case "paragraph":
|
|
1236
|
+
contentNodes.push(...convertParagraphWithTextBoxes(content, styleResolver, {
|
|
1237
|
+
textBoxGroupId: context.nextTextBoxGroupId(),
|
|
1238
|
+
context,
|
|
1239
|
+
...conditionalStyle?.rPr !== void 0 ? { extraRunFormatting: conditionalStyle.rPr } : {},
|
|
1240
|
+
...conditionalStyle?.pPr !== void 0 ? { tableParagraphOverlay: conditionalStyle.pPr } : {}
|
|
1241
|
+
}));
|
|
1242
|
+
break;
|
|
1243
|
+
case "table":
|
|
1244
|
+
contentNodes.push(convertTable(content, styleResolver, context));
|
|
1245
|
+
break;
|
|
1246
|
+
case "preservedBlock":
|
|
1247
|
+
contentNodes.push(convertPreservedBlock(content));
|
|
1248
|
+
break;
|
|
1249
|
+
default: panic(`Unsupported table cell content: ${JSON.stringify(content)}`);
|
|
1250
|
+
}
|
|
1178
1251
|
if (contentNodes.length === 0) contentNodes.push(schema.node("paragraph", {}, []));
|
|
1179
1252
|
const nodeType = isHeader ? "tableHeader" : "tableCell";
|
|
1180
1253
|
return schema.node(nodeType, attrs, contentNodes);
|
|
@@ -1183,7 +1256,7 @@ function standaloneTableCellToProseMirror(cell, nodeType) {
|
|
|
1183
1256
|
const nextTextBoxGroupId = createTextBoxGroupIdFactory();
|
|
1184
1257
|
const nextHyperlinkInstanceIndex = createHyperlinkInstanceIndexAllocator();
|
|
1185
1258
|
const pageBreakRunSourceDescendants = buildPageBreakRunSourceDescendantIndex(cell.content);
|
|
1186
|
-
|
|
1259
|
+
reportSourceContainerPageBreakRun(cell.content, "table-cell", pageBreakRunSourceDescendants, noPageBreakProjectionWarning);
|
|
1187
1260
|
return convertTableCell({
|
|
1188
1261
|
cell,
|
|
1189
1262
|
styleResolver: null,
|
|
@@ -1192,7 +1265,10 @@ function standaloneTableCellToProseMirror(cell, nodeType) {
|
|
|
1192
1265
|
nextTextBoxGroupId,
|
|
1193
1266
|
nextHyperlinkInstanceIndex,
|
|
1194
1267
|
pairedBookmarkIds: collectPairedBookmarkIds(cell.content),
|
|
1195
|
-
pageBreakRunSourceDescendants
|
|
1268
|
+
pageBreakRunSourceDescendants,
|
|
1269
|
+
storyRangedCommentIds: rangedCommentIds(cell.content),
|
|
1270
|
+
openCommentIds: /* @__PURE__ */ new Set(),
|
|
1271
|
+
warnPageBreakProjection: noPageBreakProjectionWarning
|
|
1196
1272
|
},
|
|
1197
1273
|
isHeader: nodeType === "tableHeader",
|
|
1198
1274
|
gridWidthPercent: void 0,
|
|
@@ -1210,15 +1286,7 @@ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyp
|
|
|
1210
1286
|
let fieldFormatting;
|
|
1211
1287
|
let fieldPropertyChanges;
|
|
1212
1288
|
const inlineNodes = [];
|
|
1213
|
-
const
|
|
1214
|
-
if (field.type === "complexField" && field.fieldCode.some(runHasPageBreak)) throw new UnsupportedDocxToProseMirrorConversionError({
|
|
1215
|
-
message: "A complex-field instruction containing an explicit page break cannot be represented in the editor model",
|
|
1216
|
-
owner: "complex-field-instruction",
|
|
1217
|
-
contentType: "break"
|
|
1218
|
-
});
|
|
1219
|
-
const hasPageBreakContent = field.type === "simpleField" ? field.content.some((content) => content.type === "run" ? runHasPageBreak(content) : content.children.some((child) => child.type === "run" && runHasPageBreak(child))) : field.fieldResult.some(runHasPageBreak);
|
|
1220
|
-
if (hasPageBreakContent) assertPageBreakFieldResultIsRepresentable(field);
|
|
1221
|
-
const hasStructuredSourceContent = hasPageBreakContent || field.type === "simpleField" && field.content.some((content) => content.type === "hyperlink");
|
|
1289
|
+
const hasStructuredSourceContent = fieldResultHasPageBreakContent(field) || field.type === "simpleField" && field.content.some((content) => content.type === "hyperlink" || content.type === "preservedInline");
|
|
1222
1290
|
const appendRun = (run) => {
|
|
1223
1291
|
for (const content of run.content) if (content.type === "text") displayText += content.text;
|
|
1224
1292
|
fieldFormatting ??= run.formatting;
|
|
@@ -1231,6 +1299,10 @@ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyp
|
|
|
1231
1299
|
appendRun(content);
|
|
1232
1300
|
continue;
|
|
1233
1301
|
}
|
|
1302
|
+
if (content.type === "preservedInline") {
|
|
1303
|
+
inlineNodes.push(preservedInlineNode(content));
|
|
1304
|
+
continue;
|
|
1305
|
+
}
|
|
1234
1306
|
for (const child of content.children) if (child.type === "run") {
|
|
1235
1307
|
for (const runContent of child.content) if (runContent.type === "text") displayText += runContent.text;
|
|
1236
1308
|
fieldFormatting ??= child.formatting;
|
|
@@ -1249,36 +1321,64 @@ function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyp
|
|
|
1249
1321
|
const inheritedFormatting = getInheritedRunFormatting(fieldFormatting, field.fieldType);
|
|
1250
1322
|
const { marks } = buildRunMarks(fieldFormatting, inheritedFormatting, styleResolver);
|
|
1251
1323
|
const hasConvertedHyperlinkContent = inlineNodes.some((node) => node.marks.some((mark) => mark.type.name === "hyperlink"));
|
|
1252
|
-
const
|
|
1324
|
+
const hasConvertedPageBreakContent = inlineNodes.some((node) => node.type.name === "pageBreakRun");
|
|
1325
|
+
const hasConvertedPreservedContent = inlineNodes.some((node) => node.type.name === "preservedXml");
|
|
1326
|
+
const createStructuredField = hasConvertedPageBreakContent || hasConvertedPreservedContent || hasStructuredSourceContent && hasConvertedHyperlinkContent;
|
|
1253
1327
|
if (!createStructuredField && fieldPropertyChanges && fieldPropertyChanges.length > 0) marks.push(schema.mark("runPropertyChange", { changes: [...fieldPropertyChanges] }));
|
|
1254
1328
|
return schema.node(createStructuredField ? "structuredField" : "field", {
|
|
1255
1329
|
fieldType: field.fieldType,
|
|
1256
1330
|
instruction: field.instruction,
|
|
1257
1331
|
displayText,
|
|
1258
1332
|
fieldKind: field.type === "simpleField" ? "simple" : "complex",
|
|
1259
|
-
fldLock: field.fldLock ??
|
|
1260
|
-
dirty: field.dirty ??
|
|
1333
|
+
fldLock: field.fldLock ?? null,
|
|
1334
|
+
dirty: field.dirty ?? null
|
|
1261
1335
|
}, createStructuredField ? inlineNodes : void 0, marks);
|
|
1262
1336
|
}
|
|
1263
1337
|
/**
|
|
1264
|
-
*
|
|
1338
|
+
* Lift the transparent wrappers out of an inline content list, remembering for
|
|
1339
|
+
* each item which wrappers it sat inside.
|
|
1340
|
+
*
|
|
1341
|
+
* The tree becomes one sequence because every inline loop below narrows by a
|
|
1342
|
+
* chain of `else if` rather than by exhaustion, and a wrapper left in it would
|
|
1343
|
+
* reach whichever branch happens to be last. What the wrapper said is not lost
|
|
1344
|
+
* with the tree: it rides the `inlineWrapper` mark on the leaves it held, and
|
|
1345
|
+
* ProseMirror maintains that range across edits instead of an index.
|
|
1346
|
+
*
|
|
1347
|
+
* It is applied to the content of whatever holds the wrapper, never around it:
|
|
1348
|
+
* a wrapper inside a revision or a content control is lifted inside that
|
|
1349
|
+
* wrapper, so its runs keep the revision mark or the control they were
|
|
1350
|
+
* authored under.
|
|
1265
1351
|
*/
|
|
1352
|
+
const withInlineWrapperStacks = (content, stack = []) => content.flatMap((item) => item.type === "inlineWrapper" ? withInlineWrapperStacks(item.content, [...stack, inlineWrapperLayer(item)]) : [{
|
|
1353
|
+
content: item,
|
|
1354
|
+
stack
|
|
1355
|
+
}]);
|
|
1266
1356
|
/**
|
|
1267
|
-
*
|
|
1357
|
+
* `nodes` with `stack` recorded outside whatever wrapper they already carry.
|
|
1268
1358
|
*
|
|
1269
|
-
*
|
|
1270
|
-
*
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
* only its direction, which the survival census records as an
|
|
1275
|
-
* editor-projection loss until the mark that carries it exists.
|
|
1359
|
+
* A revision converts its own content first, so a node that arrives here
|
|
1360
|
+
* already marked sat inside the item this stack wraps: the two stacks
|
|
1361
|
+
* concatenate, outermost first. Concatenating is what the schema forces — the
|
|
1362
|
+
* mark excludes itself, so a second one replaces the first, and the inner
|
|
1363
|
+
* wrapper would be the one lost.
|
|
1276
1364
|
*
|
|
1277
|
-
*
|
|
1278
|
-
*
|
|
1279
|
-
*
|
|
1365
|
+
* A node that holds its own leaves, a content control, is marked here as the
|
|
1366
|
+
* one node it is; its leaves were marked with the whole enclosing stack when
|
|
1367
|
+
* it was built, because the painter reads the wrapper off the leaf.
|
|
1368
|
+
*/
|
|
1369
|
+
const withInlineWrapperMark = (nodes, stack) => {
|
|
1370
|
+
const markType = schema.marks["inlineWrapper"];
|
|
1371
|
+
if (stack.length === 0 || !markType) return nodes;
|
|
1372
|
+
return nodes.map((node) => {
|
|
1373
|
+
if (!node.isText && (!node.isInline || !node.type.allowsMarkType(markType))) return node;
|
|
1374
|
+
const inner = node.marks.find((mark) => mark.type === markType);
|
|
1375
|
+
const layers = inner === void 0 ? stack : [...stack, ...expectInlineWrapperMarkAttrs(inner).stack];
|
|
1376
|
+
return node.mark(markType.create({ stack: layers }).addToSet(node.marks));
|
|
1377
|
+
});
|
|
1378
|
+
};
|
|
1379
|
+
/**
|
|
1380
|
+
* Convert a MathEquation to a ProseMirror math node.
|
|
1280
1381
|
*/
|
|
1281
|
-
const withoutBidiWrappers = (content) => content.flatMap((item) => item.type === "bidiWrapper" ? withoutBidiWrappers(item.content) : [item]);
|
|
1282
1382
|
function convertMathEquation(math) {
|
|
1283
1383
|
return schema.node("math", {
|
|
1284
1384
|
display: math.display,
|
|
@@ -1288,54 +1388,66 @@ function convertMathEquation(math) {
|
|
|
1288
1388
|
}
|
|
1289
1389
|
/**
|
|
1290
1390
|
* Convert an InlineSdt to a ProseMirror sdt node with inline content.
|
|
1391
|
+
*
|
|
1392
|
+
* `wrappedBy` is the stack the control itself sits inside. The control holds
|
|
1393
|
+
* its own leaves, so nothing outside can mark them afterwards: the caller's
|
|
1394
|
+
* stack has to reach them here, under the wrappers written inside the control.
|
|
1291
1395
|
*/
|
|
1292
|
-
function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors) {
|
|
1396
|
+
function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors, wrappedBy = []) {
|
|
1293
1397
|
const props = sdt.properties;
|
|
1294
1398
|
const inlineNodes = [];
|
|
1295
|
-
for (const content of sdt.content
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1399
|
+
for (const { content, stack } of withInlineWrapperStacks(sdt.content, wrappedBy)) {
|
|
1400
|
+
if (!isInlineSdtContent(content)) continue;
|
|
1401
|
+
const itemNodes = [];
|
|
1402
|
+
switch (content.type) {
|
|
1403
|
+
case "run":
|
|
1404
|
+
itemNodes.push(...convertRun(content, getInheritedRunFormatting(content.formatting), nextPageBreakRunOwnerId, styleResolver, textBoxAnchors));
|
|
1405
|
+
break;
|
|
1406
|
+
case "hyperlink": {
|
|
1407
|
+
const currentHyperlinkIndex = nextHyperlinkInstanceIndex();
|
|
1408
|
+
itemNodes.push(...convertHyperlink(content, {
|
|
1409
|
+
getInheritedRunFormatting,
|
|
1410
|
+
styleResolver,
|
|
1411
|
+
hyperlinkIndex: currentHyperlinkIndex,
|
|
1412
|
+
textBoxAnchors,
|
|
1413
|
+
nextPageBreakRunOwnerId
|
|
1414
|
+
}));
|
|
1415
|
+
break;
|
|
1416
|
+
}
|
|
1417
|
+
case "simpleField":
|
|
1418
|
+
case "complexField": {
|
|
1419
|
+
const fieldNode = convertField(content, {
|
|
1420
|
+
getInheritedRunFormatting,
|
|
1421
|
+
styleResolver,
|
|
1422
|
+
nextHyperlinkInstanceIndex,
|
|
1423
|
+
nextPageBreakRunOwnerId,
|
|
1424
|
+
textBoxAnchors
|
|
1425
|
+
});
|
|
1426
|
+
if (fieldNode) itemNodes.push(fieldNode);
|
|
1427
|
+
break;
|
|
1428
|
+
}
|
|
1429
|
+
case "inlineSdt": {
|
|
1430
|
+
const nestedSdt = convertInlineSdt(content, nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, textBoxAnchors, stack);
|
|
1431
|
+
if (nestedSdt) itemNodes.push(nestedSdt);
|
|
1432
|
+
break;
|
|
1433
|
+
}
|
|
1434
|
+
case "insertion":
|
|
1435
|
+
case "deletion":
|
|
1436
|
+
case "moveTo":
|
|
1437
|
+
case "moveFrom":
|
|
1438
|
+
itemNodes.push(...convertTrackedChange(content, content.type === "insertion" || content.type === "moveTo" ? "insertion" : "deletion", nextHyperlinkInstanceIndex, nextPageBreakRunOwnerId, getInheritedRunFormatting, styleResolver, content.type === "moveTo" || content.type === "moveFrom" ? content.type : null, textBoxAnchors));
|
|
1439
|
+
break;
|
|
1440
|
+
case "mathEquation": {
|
|
1441
|
+
const mathNode = convertMathEquation(content);
|
|
1442
|
+
if (mathNode) itemNodes.push(mathNode);
|
|
1443
|
+
break;
|
|
1444
|
+
}
|
|
1445
|
+
case "preservedInline":
|
|
1446
|
+
itemNodes.push(preservedInlineNode(content));
|
|
1447
|
+
break;
|
|
1448
|
+
default: panic(`Unsupported inline SDT content: ${JSON.stringify(content)}`);
|
|
1337
1449
|
}
|
|
1338
|
-
|
|
1450
|
+
inlineNodes.push(...withInlineWrapperMark(itemNodes, stack));
|
|
1339
1451
|
}
|
|
1340
1452
|
return schema.node("sdt", sdtAttrsFromProperties(props), inlineNodes.length > 0 ? inlineNodes : void 0);
|
|
1341
1453
|
}
|
|
@@ -1346,7 +1458,6 @@ function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, nextPageBreakRunOwner
|
|
|
1346
1458
|
* @param resolvedStyleFormatting - Paragraph formatting and its explicit style-toggle state
|
|
1347
1459
|
*/
|
|
1348
1460
|
function convertRun(run, resolvedStyleFormatting, nextPageBreakRunOwnerId, styleResolver, textBoxAnchors) {
|
|
1349
|
-
assertPageBreakSourceRunIsRepresentable(run);
|
|
1350
1461
|
const nodes = [];
|
|
1351
1462
|
const { marks, mergedFormatting } = buildRunMarks(run.formatting, resolvedStyleFormatting, styleResolver);
|
|
1352
1463
|
if (run.propertyChanges && run.propertyChanges.length > 0) marks.push(schema.mark("runPropertyChange", { changes: [...run.propertyChanges] }));
|
|
@@ -1357,28 +1468,35 @@ function convertRun(run, resolvedStyleFormatting, nextPageBreakRunOwnerId, style
|
|
|
1357
1468
|
}
|
|
1358
1469
|
return nodes;
|
|
1359
1470
|
}
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1471
|
+
const runHasPageBreakContent = (run) => run.content.some((content) => content.type === "break" && content.breakType === "page");
|
|
1472
|
+
/**
|
|
1473
|
+
* Whether a field's result holds an explicit page break.
|
|
1474
|
+
*
|
|
1475
|
+
* `convertField` re-cuts the whole result into a structured field when it
|
|
1476
|
+
* does, so this answers both who gets re-cut and who gets reported. One
|
|
1477
|
+
* predicate for the two, because a reporter that disagreed with the converter
|
|
1478
|
+
* would name a loss nobody suffered.
|
|
1479
|
+
*/
|
|
1480
|
+
const fieldResultHasPageBreakContent = (field) => field.type === "simpleField" ? field.content.some((content) => {
|
|
1481
|
+
switch (content.type) {
|
|
1482
|
+
case "run": return runHasPageBreakContent(content);
|
|
1483
|
+
case "hyperlink": return content.children.some((child) => child.type === "run" && runHasPageBreakContent(child));
|
|
1484
|
+
case "preservedInline": return false;
|
|
1485
|
+
default: panic(`Unsupported simple-field content: ${JSON.stringify(content)}`);
|
|
1486
|
+
}
|
|
1487
|
+
}) : field.fieldResult.some(runHasPageBreakContent);
|
|
1488
|
+
function reportPageBreakSourceRunContent(run, warn) {
|
|
1489
|
+
if (!runHasPageBreakContent(run)) return;
|
|
1490
|
+
reportRunContentBesidePageBreak(run, "page-break-bearing-run", warn);
|
|
1363
1491
|
}
|
|
1364
1492
|
const PAGE_BREAK_CONTAINER_DESCRIPTIONS = {
|
|
1365
|
-
"table-cell": "
|
|
1366
|
-
"text-box": "A text box
|
|
1367
|
-
};
|
|
1368
|
-
const PAGE_BREAK_PARAGRAPH_OWNERS = {
|
|
1369
|
-
borders: "paragraph-borders",
|
|
1370
|
-
frame: "paragraph-frame",
|
|
1371
|
-
outline: "paragraph-outline",
|
|
1372
|
-
textBoxAnchor: "paragraph-text-box-anchor"
|
|
1493
|
+
"table-cell": "An interior page break in a table cell does not paginate the cell; its row moves as a unit",
|
|
1494
|
+
"text-box": "A page break inside a text box does not paginate the text box"
|
|
1373
1495
|
};
|
|
1374
|
-
function
|
|
1496
|
+
function reportSourceContainerPageBreakRun(content, owner, sourceDescendants, warn) {
|
|
1375
1497
|
if (!sourceDescendants.containsPageBreakRun(content)) return;
|
|
1376
1498
|
if (owner === "table-cell" && hasSingleLeadingTableCellPageBreak(content, sourceDescendants)) return;
|
|
1377
|
-
|
|
1378
|
-
message: `${PAGE_BREAK_CONTAINER_DESCRIPTIONS[owner]} cannot be represented in the editor model`,
|
|
1379
|
-
owner,
|
|
1380
|
-
contentType: "break"
|
|
1381
|
-
});
|
|
1499
|
+
warn(PAGE_BREAK_CONTAINER_DESCRIPTIONS[owner]);
|
|
1382
1500
|
}
|
|
1383
1501
|
/**
|
|
1384
1502
|
* A page break opening a cell advances the whole row during pagination.
|
|
@@ -1419,7 +1537,7 @@ const scanLeadingPageBreakContent = (content, scan) => {
|
|
|
1419
1537
|
case "moveFrom":
|
|
1420
1538
|
case "moveTo":
|
|
1421
1539
|
case "inlineSdt":
|
|
1422
|
-
case "
|
|
1540
|
+
case "inlineWrapper":
|
|
1423
1541
|
for (const child of content.content) scanLeadingPageBreakContent(child, scan);
|
|
1424
1542
|
return;
|
|
1425
1543
|
case "simpleField":
|
|
@@ -1438,6 +1556,7 @@ const scanLeadingPageBreakContent = (content, scan) => {
|
|
|
1438
1556
|
case "moveToRangeEnd": return;
|
|
1439
1557
|
case "commentReference":
|
|
1440
1558
|
case "mathEquation":
|
|
1559
|
+
case "preservedInline":
|
|
1441
1560
|
if (scan.pageBreaks === 0) scan.contentBeforeBreak = true;
|
|
1442
1561
|
return;
|
|
1443
1562
|
default: return content;
|
|
@@ -1456,64 +1575,103 @@ const hasSingleLeadingParagraphPageBreak = (paragraph) => {
|
|
|
1456
1575
|
const scan = scanParagraphPageBreaks(paragraph);
|
|
1457
1576
|
return !scan.contentBeforeBreak && scan.pageBreaks === 1;
|
|
1458
1577
|
};
|
|
1459
|
-
function
|
|
1578
|
+
function reportParagraphPageBreakProjection({ paragraph, attrs, effectiveFrame, sourceDescendants, warn }) {
|
|
1460
1579
|
const sourceFeatures = sourceDescendants.paragraphFeatures(paragraph);
|
|
1461
1580
|
if (!sourceFeatures.hasPageBreakRun) return;
|
|
1581
|
+
reportParagraphPageBreakRunContent(paragraph, warn);
|
|
1462
1582
|
const disposition = pageBreakRunParagraphProjectionDispositionForFeatures({
|
|
1463
1583
|
attrs,
|
|
1464
1584
|
effectiveFrame,
|
|
1465
1585
|
textBoxAnchorAfterPageBreak: sourceFeatures.hasTextBoxShape && !sourceFeatures.pageBreakSharesTextBoxShape && scanParagraphPageBreaks(paragraph).textBoxShapeAfterBreak
|
|
1466
1586
|
});
|
|
1467
|
-
if (disposition.status === "
|
|
1587
|
+
if (disposition.status === "exact") return;
|
|
1468
1588
|
if (disposition.reason !== "textBoxAnchor" && hasSingleLeadingParagraphPageBreak(paragraph)) return;
|
|
1469
|
-
|
|
1470
|
-
message: disposition.message,
|
|
1471
|
-
owner: PAGE_BREAK_PARAGRAPH_OWNERS[disposition.reason],
|
|
1472
|
-
contentType: "break"
|
|
1473
|
-
});
|
|
1589
|
+
warn(disposition.message);
|
|
1474
1590
|
}
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1591
|
+
/**
|
|
1592
|
+
* Report every run-level loss a paragraph's page breaks bring with them.
|
|
1593
|
+
*
|
|
1594
|
+
* One walk of the paragraph rather than a check at each `convertRun` and
|
|
1595
|
+
* `convertField`: the reporter is a conversion-wide fact, and a per-call-site
|
|
1596
|
+
* check would have to be threaded through every nested converter to reach it.
|
|
1597
|
+
*/
|
|
1598
|
+
function reportParagraphPageBreakRunContent(paragraph, warn) {
|
|
1599
|
+
const visitField = (field) => {
|
|
1600
|
+
if (field.type === "complexField") {
|
|
1601
|
+
if (field.fieldCode.some(runHasPageBreakContent)) warn("A complex-field instruction holds an explicit page break");
|
|
1602
|
+
if (!fieldResultHasPageBreakContent(field)) return;
|
|
1603
|
+
for (const run of field.fieldResult) reportRunContentBesidePageBreak(run, "field-result", warn);
|
|
1604
|
+
return;
|
|
1484
1605
|
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1606
|
+
if (!fieldResultHasPageBreakContent(field)) return;
|
|
1607
|
+
for (const content of field.content) {
|
|
1608
|
+
if (content.type === "run") {
|
|
1609
|
+
reportRunContentBesidePageBreak(content, "field-result", warn);
|
|
1610
|
+
continue;
|
|
1611
|
+
}
|
|
1612
|
+
if (content.type !== "hyperlink") continue;
|
|
1613
|
+
for (const child of content.children) if (child.type === "run") reportRunContentBesidePageBreak(child, "field-result", warn);
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
const visitContent = (content) => {
|
|
1617
|
+
switch (content.type) {
|
|
1618
|
+
case "run":
|
|
1619
|
+
reportPageBreakSourceRunContent(content, warn);
|
|
1620
|
+
return;
|
|
1621
|
+
case "hyperlink":
|
|
1622
|
+
for (const child of content.children) if (child.type === "run") reportPageBreakSourceRunContent(child, warn);
|
|
1623
|
+
return;
|
|
1624
|
+
case "simpleField":
|
|
1625
|
+
case "complexField":
|
|
1626
|
+
visitField(content);
|
|
1627
|
+
return;
|
|
1628
|
+
case "insertion":
|
|
1629
|
+
case "deletion":
|
|
1630
|
+
case "moveFrom":
|
|
1631
|
+
case "moveTo":
|
|
1632
|
+
case "inlineSdt":
|
|
1633
|
+
case "inlineWrapper":
|
|
1634
|
+
for (const child of content.content) visitContent(child);
|
|
1635
|
+
return;
|
|
1636
|
+
default: return;
|
|
1637
|
+
}
|
|
1638
|
+
};
|
|
1639
|
+
for (const content of paragraph.content) visitContent(content);
|
|
1487
1640
|
}
|
|
1488
1641
|
const PAGE_BREAK_OWNER_DESCRIPTIONS = {
|
|
1489
1642
|
"field-result": "A field result with an explicit page break",
|
|
1490
1643
|
"page-break-bearing-run": "A page-break-bearing run"
|
|
1491
1644
|
};
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1645
|
+
/**
|
|
1646
|
+
* Record what a page-break-bearing run loses when the editor re-cuts it.
|
|
1647
|
+
*
|
|
1648
|
+
* The run is split into one node per inline atom and rebuilt from the
|
|
1649
|
+
* `pageBreakRunOwner` mark, and the kinds below have no node of their own:
|
|
1650
|
+
* a hyphen returns as its character, a field character or instruction leaves
|
|
1651
|
+
* no trace, and a text-box shape is hoisted to its own block. Every one of
|
|
1652
|
+
* those losses is what the same run suffers with no page break in it, so
|
|
1653
|
+
* refusing the document here declined to open a file folio otherwise reads.
|
|
1654
|
+
*/
|
|
1655
|
+
function reportRunContentBesidePageBreak(run, owner, warn) {
|
|
1501
1656
|
for (const content of run.content) switch (content.type) {
|
|
1502
1657
|
case "break":
|
|
1503
1658
|
case "drawing":
|
|
1504
1659
|
case "endnoteRef":
|
|
1505
1660
|
case "footnoteRef":
|
|
1661
|
+
case "preservedXml":
|
|
1506
1662
|
case "renderedPageBreak":
|
|
1507
1663
|
case "symbol":
|
|
1508
1664
|
case "tab":
|
|
1509
1665
|
case "text": continue;
|
|
1510
1666
|
case "shape":
|
|
1511
|
-
if (content.shape.textBody)
|
|
1667
|
+
if (content.shape.textBody) warn(`${PAGE_BREAK_OWNER_DESCRIPTIONS[owner]} also holds a text-box shape`);
|
|
1512
1668
|
continue;
|
|
1513
1669
|
case "fieldChar":
|
|
1514
1670
|
case "instrText":
|
|
1515
1671
|
case "noBreakHyphen":
|
|
1516
|
-
case "softHyphen":
|
|
1672
|
+
case "softHyphen":
|
|
1673
|
+
warn(`${PAGE_BREAK_OWNER_DESCRIPTIONS[owner]} also holds ${content.type}`);
|
|
1674
|
+
continue;
|
|
1517
1675
|
default: panic(`Unsupported page-break-bearing run content: ${JSON.stringify(content)}`);
|
|
1518
1676
|
}
|
|
1519
1677
|
}
|
|
@@ -1761,6 +1919,11 @@ function convertRunContent(content, marks, formatting, textBoxAnchors, authoredF
|
|
|
1761
1919
|
}
|
|
1762
1920
|
case "fieldChar":
|
|
1763
1921
|
case "instrText": return [];
|
|
1922
|
+
case "preservedXml": return [schema.node("preservedXml", {
|
|
1923
|
+
xml: content.xml,
|
|
1924
|
+
text: content.text,
|
|
1925
|
+
level: PRESERVED_XML_LEVELS.run
|
|
1926
|
+
}).mark(marks)];
|
|
1764
1927
|
case "noBreakHyphen": return [schema.text("‑", marks)];
|
|
1765
1928
|
case "softHyphen": return [schema.text("", marks)];
|
|
1766
1929
|
case "symbol": return [schema.node("symbol", {
|
|
@@ -1808,14 +1971,7 @@ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint, runForma
|
|
|
1808
1971
|
else if (wrapType === "behind" || wrapType === "inFront") displayMode = "float";
|
|
1809
1972
|
else if (cssFloat !== "none") displayMode = "float";
|
|
1810
1973
|
else displayMode = "block";
|
|
1811
|
-
|
|
1812
|
-
if (image.transform) {
|
|
1813
|
-
const transforms = [];
|
|
1814
|
-
if (image.transform.rotation) transforms.push(`rotate(${image.transform.rotation}deg)`);
|
|
1815
|
-
if (image.transform.flipH) transforms.push("scaleX(-1)");
|
|
1816
|
-
if (image.transform.flipV) transforms.push("scaleY(-1)");
|
|
1817
|
-
if (transforms.length > 0) transform = transforms.join(" ");
|
|
1818
|
-
}
|
|
1974
|
+
const transformAttrs = authoredTransformAttrs(image.transform);
|
|
1819
1975
|
const distTop = image.wrap.distT != null ? emuToPixels(image.wrap.distT) : void 0;
|
|
1820
1976
|
const distBottom = image.wrap.distB != null ? emuToPixels(image.wrap.distB) : void 0;
|
|
1821
1977
|
const distLeft = image.wrap.distL != null ? emuToPixels(image.wrap.distL) : void 0;
|
|
@@ -1867,8 +2023,10 @@ function convertImage({ image, rawXml, rawXmlMode, rawImageFingerprint, runForma
|
|
|
1867
2023
|
wrapType,
|
|
1868
2024
|
displayMode,
|
|
1869
2025
|
cssFloat,
|
|
1870
|
-
|
|
2026
|
+
...transformAttrs,
|
|
1871
2027
|
opacity: image.opacity,
|
|
2028
|
+
brightness: image.effects?.brightness,
|
|
2029
|
+
contrast: image.effects?.contrast,
|
|
1872
2030
|
distTop,
|
|
1873
2031
|
distBottom,
|
|
1874
2032
|
distLeft,
|
|
@@ -1935,8 +2093,11 @@ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver,
|
|
|
1935
2093
|
}, void 0, [linkMark]));
|
|
1936
2094
|
continue;
|
|
1937
2095
|
}
|
|
2096
|
+
if (child.type === "preservedInline") {
|
|
2097
|
+
nodes.push(preservedInlineNode(child).mark([linkMark]));
|
|
2098
|
+
continue;
|
|
2099
|
+
}
|
|
1938
2100
|
if (child.type === "run") {
|
|
1939
|
-
assertPageBreakSourceRunIsRepresentable(child);
|
|
1940
2101
|
const inheritedFormatting = getInheritedRunFormatting(child.formatting);
|
|
1941
2102
|
const { marks: runMarks, mergedFormatting } = buildRunMarks(child.formatting, inheritedFormatting, styleResolver);
|
|
1942
2103
|
if (child.propertyChanges && child.propertyChanges.length > 0) runMarks.push(schema.mark("runPropertyChange", { changes: [...child.propertyChanges] }));
|
|
@@ -1997,14 +2158,7 @@ function convertShape(shape, runFormatting) {
|
|
|
1997
2158
|
outlineHeadEnd = shape.outline.headEnd;
|
|
1998
2159
|
outlineTailEnd = shape.outline.tailEnd;
|
|
1999
2160
|
} else outlineWidth = 0;
|
|
2000
|
-
|
|
2001
|
-
if (shape.transform) {
|
|
2002
|
-
const transforms = [];
|
|
2003
|
-
if (shape.transform.rotation) transforms.push(`rotate(${shape.transform.rotation}deg)`);
|
|
2004
|
-
if (shape.transform.flipH) transforms.push("scaleX(-1)");
|
|
2005
|
-
if (shape.transform.flipV) transforms.push("scaleY(-1)");
|
|
2006
|
-
if (transforms.length > 0) transform = transforms.join(" ");
|
|
2007
|
-
}
|
|
2161
|
+
const transformAttrs = authoredTransformAttrs(shape.transform);
|
|
2008
2162
|
const wrapType = shape.wrap?.type ?? "inline";
|
|
2009
2163
|
const displayMode = wrapType === "inline" ? "inline" : "float";
|
|
2010
2164
|
let cssFloat = "none";
|
|
@@ -2053,7 +2207,7 @@ function convertShape(shape, runFormatting) {
|
|
|
2053
2207
|
outlineJoin,
|
|
2054
2208
|
outlineHeadEnd,
|
|
2055
2209
|
outlineTailEnd,
|
|
2056
|
-
|
|
2210
|
+
...transformAttrs,
|
|
2057
2211
|
displayMode,
|
|
2058
2212
|
cssFloat,
|
|
2059
2213
|
wrapType,
|
|
@@ -2067,18 +2221,20 @@ function convertShape(shape, runFormatting) {
|
|
|
2067
2221
|
}
|
|
2068
2222
|
function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, context, extraRunFormatting, preserveEmptyWrapper, tableParagraphOverlay }) {
|
|
2069
2223
|
const { textBoxes, textBoxAnchors } = extractTextBoxesFromParagraph(block, textBoxGroupId);
|
|
2070
|
-
const pmParagraph = convertParagraph(block, styleResolver, context,
|
|
2224
|
+
const pmParagraph = convertParagraph(block, styleResolver, context, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
|
|
2071
2225
|
const nodes = [];
|
|
2072
2226
|
const isEmptyAfterExtraction = textBoxes.length > 0 && !hasContentBesidesTextBoxAnchors(pmParagraph);
|
|
2073
2227
|
const keepWrapperParagraph = isEmptyAfterExtraction && (preserveEmptyWrapper === true || hasParagraphBoundaryPayload(block, pmParagraph));
|
|
2074
2228
|
if (!isEmptyAfterExtraction || keepWrapperParagraph) nodes.push(pmParagraph);
|
|
2075
|
-
|
|
2076
|
-
|
|
2229
|
+
const standalone = isEmptyAfterExtraction && !keepWrapperParagraph;
|
|
2230
|
+
for (const [index, { textBox, anchorId, trackedChange, inlineSdts }] of textBoxes.entries()) nodes.push(convertTextBox(textBox, styleResolver, {
|
|
2231
|
+
placement: standalone ? "standalone" : "inlineWithPrevious",
|
|
2077
2232
|
groupId: textBoxGroupId,
|
|
2078
2233
|
anchorId,
|
|
2079
2234
|
context,
|
|
2080
2235
|
trackedChange,
|
|
2081
|
-
inlineSdts
|
|
2236
|
+
inlineSdts,
|
|
2237
|
+
...standalone && index === 0 && block.preservedAttributes ? { hostPreservedAttributes: block.preservedAttributes } : {}
|
|
2082
2238
|
}));
|
|
2083
2239
|
return nodes;
|
|
2084
2240
|
}
|
|
@@ -2225,7 +2381,7 @@ function textBoxFromShape(shape, textBody) {
|
|
|
2225
2381
|
* Convert a TextBox to a ProseMirror textBox node
|
|
2226
2382
|
*/
|
|
2227
2383
|
function convertTextBox(textBox, styleResolver, options) {
|
|
2228
|
-
|
|
2384
|
+
reportSourceContainerPageBreakRun(textBox.content, "text-box", options.context.pageBreakRunSourceDescendants, options.context.warnPageBreakProjection);
|
|
2229
2385
|
const textBoxSize = textBox.size;
|
|
2230
2386
|
const widthPx = textBoxSize?.width ? emuToPixels(textBoxSize.width) : 200;
|
|
2231
2387
|
const heightPx = textBoxSize?.height ? emuToPixels(textBoxSize.height) : void 0;
|
|
@@ -2239,28 +2395,25 @@ function convertTextBox(textBox, styleResolver, options) {
|
|
|
2239
2395
|
if (textBox.outline.color?.rgb) outlineColor = `#${textBox.outline.color.rgb}`;
|
|
2240
2396
|
outlineStyle = textBox.outline.style || "solid";
|
|
2241
2397
|
}
|
|
2242
|
-
|
|
2243
|
-
if (textBox.transform) {
|
|
2244
|
-
const transforms = [];
|
|
2245
|
-
if (textBox.transform.rotation) transforms.push(`rotate(${textBox.transform.rotation}deg)`);
|
|
2246
|
-
if (textBox.transform.flipH) transforms.push("scaleX(-1)");
|
|
2247
|
-
if (textBox.transform.flipV) transforms.push("scaleY(-1)");
|
|
2248
|
-
if (transforms.length > 0) transform = transforms.join(" ");
|
|
2249
|
-
}
|
|
2398
|
+
const transformAttrs = authoredTransformAttrs(textBox.transform);
|
|
2250
2399
|
const marginTop = textBox.margins?.top !== void 0 ? emuToPixels(textBox.margins.top) : void 0;
|
|
2251
2400
|
const marginBottom = textBox.margins?.bottom !== void 0 ? emuToPixels(textBox.margins.bottom) : void 0;
|
|
2252
2401
|
const marginLeft = textBox.margins?.left !== void 0 ? emuToPixels(textBox.margins.left) : void 0;
|
|
2253
2402
|
const marginRight = textBox.margins?.right !== void 0 ? emuToPixels(textBox.margins.right) : void 0;
|
|
2403
|
+
const textBoxContext = {
|
|
2404
|
+
...options.context,
|
|
2405
|
+
openCommentIds: /* @__PURE__ */ new Set()
|
|
2406
|
+
};
|
|
2254
2407
|
const contentNodes = [];
|
|
2255
2408
|
for (const block of textBox.content) {
|
|
2256
2409
|
if (block.type === "paragraph") {
|
|
2257
2410
|
contentNodes.push(...convertParagraphWithTextBoxes(block, styleResolver, {
|
|
2258
|
-
textBoxGroupId:
|
|
2259
|
-
context:
|
|
2411
|
+
textBoxGroupId: textBoxContext.nextTextBoxGroupId(),
|
|
2412
|
+
context: textBoxContext
|
|
2260
2413
|
}));
|
|
2261
2414
|
continue;
|
|
2262
2415
|
}
|
|
2263
|
-
contentNodes.push(convertTable(block, styleResolver,
|
|
2416
|
+
contentNodes.push(convertTable(block, styleResolver, textBoxContext));
|
|
2264
2417
|
}
|
|
2265
2418
|
if (contentNodes.length === 0) contentNodes.push(schema.node("paragraph", {}, []));
|
|
2266
2419
|
const wrapType = textBox.wrap?.type;
|
|
@@ -2323,7 +2476,7 @@ function convertTextBox(textBox, styleResolver, options) {
|
|
|
2323
2476
|
outlineWidth,
|
|
2324
2477
|
outlineColor,
|
|
2325
2478
|
outlineStyle,
|
|
2326
|
-
|
|
2479
|
+
...transformAttrs,
|
|
2327
2480
|
marginTop,
|
|
2328
2481
|
marginBottom,
|
|
2329
2482
|
marginLeft,
|
|
@@ -2342,7 +2495,8 @@ function convertTextBox(textBox, styleResolver, options) {
|
|
|
2342
2495
|
_docxAnchorId: options.anchorId,
|
|
2343
2496
|
_docxTextBodyContentState: textBox.content.length === 0 ? { type: "source-empty" } : { type: "authored" },
|
|
2344
2497
|
_docxTrackedChange: options.trackedChange,
|
|
2345
|
-
_docxInlineSdts: options.inlineSdts.length > 0 ? options.inlineSdts : void 0
|
|
2498
|
+
_docxInlineSdts: options.inlineSdts.length > 0 ? options.inlineSdts : void 0,
|
|
2499
|
+
_preservedAttributes: options.hostPreservedAttributes
|
|
2346
2500
|
}, contentNodes);
|
|
2347
2501
|
}
|
|
2348
2502
|
/**
|
|
@@ -2363,7 +2517,10 @@ function headerFooterToProseDoc(content, options) {
|
|
|
2363
2517
|
nextTextBoxGroupId,
|
|
2364
2518
|
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator(),
|
|
2365
2519
|
pairedBookmarkIds: collectPairedBookmarkIds(content),
|
|
2366
|
-
pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(content)
|
|
2520
|
+
pageBreakRunSourceDescendants: buildPageBreakRunSourceDescendantIndex(content),
|
|
2521
|
+
storyRangedCommentIds: rangedCommentIds(content),
|
|
2522
|
+
openCommentIds: /* @__PURE__ */ new Set(),
|
|
2523
|
+
warnPageBreakProjection: pageBreakProjectionWarn(options?.warn)
|
|
2367
2524
|
};
|
|
2368
2525
|
const convertBlocks = (blocks) => {
|
|
2369
2526
|
const out = [];
|
|
@@ -2392,6 +2549,9 @@ function headerFooterToProseDoc(content, options) {
|
|
|
2392
2549
|
case "blockSdt":
|
|
2393
2550
|
out.push(convertBlockSdt(block, convertBlocks));
|
|
2394
2551
|
break;
|
|
2552
|
+
case "preservedBlock":
|
|
2553
|
+
out.push(convertPreservedBlock(block));
|
|
2554
|
+
break;
|
|
2395
2555
|
default: panic(`Unsupported block content: ${JSON.stringify(block)}`);
|
|
2396
2556
|
}
|
|
2397
2557
|
return out;
|
|
@@ -2412,4 +2572,4 @@ function createEmptyDoc() {
|
|
|
2412
2572
|
return schema.node("doc", null, [schema.node("paragraph", {}, [])]);
|
|
2413
2573
|
}
|
|
2414
2574
|
//#endregion
|
|
2415
|
-
export {
|
|
2575
|
+
export { createEmptyDoc, footnoteToProseDoc, headerFooterToProseDoc, resolveParagraphDefaultTextFormatting, standaloneTableCellToProseMirror, toProseDoc };
|