@stll/folio-core 0.49.0 → 0.50.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/headless.d.ts +37 -1
- package/dist/ai-edits/headless.js +47 -16
- package/dist/display-list/dom/renderDisplayListToDom.d.ts +10 -1
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -7
- package/dist/display-list/html/renderDisplayListToHtml.d.ts +21 -0
- package/dist/display-list/html/renderDisplayListToHtml.js +126 -0
- package/dist/display-list/selectDisplayPages.d.ts +6 -0
- package/dist/display-list/selectDisplayPages.js +44 -0
- package/dist/export-pdf.d.ts +35 -2
- package/dist/export-pdf.js +51 -20
- package/dist/fonts/fontsourceFaces.d.ts +47 -0
- package/dist/fonts/fontsourceFaces.js +230 -0
- package/dist/layout-bridge/convert/flowBlockPostprocessing.d.ts +8 -0
- package/dist/layout-bridge/convert/flowBlockPostprocessing.js +106 -0
- package/dist/layout-bridge/convert/flowBorders.d.ts +17 -0
- package/dist/layout-bridge/convert/flowBorders.js +31 -0
- package/dist/layout-bridge/convert/flowConversionShared.d.ts +111 -0
- package/dist/layout-bridge/convert/flowConversionShared.js +23 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +2 -1
- package/dist/layout-bridge/convert/footnoteLayout.js +2 -1
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +2 -1
- package/dist/layout-bridge/convert/imageConversion.d.ts +33 -0
- package/dist/layout-bridge/convert/imageConversion.js +118 -0
- package/dist/layout-bridge/convert/listMarkers.d.ts +28 -0
- package/dist/layout-bridge/convert/listMarkers.js +98 -0
- package/dist/layout-bridge/convert/noteReferences.d.ts +14 -0
- package/dist/layout-bridge/convert/noteReferences.js +29 -0
- package/dist/layout-bridge/convert/pageBreakSplitting.d.ts +16 -0
- package/dist/layout-bridge/convert/pageBreakSplitting.js +140 -0
- package/dist/layout-bridge/convert/paragraphAttrs.d.ts +20 -0
- package/dist/layout-bridge/convert/paragraphAttrs.js +234 -0
- package/dist/layout-bridge/convert/paragraphConversion.d.ts +12 -0
- package/dist/layout-bridge/convert/paragraphConversion.js +112 -0
- package/dist/layout-bridge/convert/paragraphRuns.d.ts +15 -0
- package/dist/layout-bridge/convert/paragraphRuns.js +281 -0
- package/dist/layout-bridge/convert/runFormattingMerge.d.ts +19 -0
- package/dist/layout-bridge/convert/runFormattingMerge.js +167 -0
- package/dist/layout-bridge/convert/runMarkFormatting.d.ts +11 -0
- package/dist/layout-bridge/convert/runMarkFormatting.js +291 -0
- package/dist/layout-bridge/convert/sectionBoundaries.d.ts +35 -0
- package/dist/layout-bridge/convert/sectionBoundaries.js +114 -0
- package/dist/layout-bridge/convert/tableConversion.d.ts +12 -0
- package/dist/layout-bridge/convert/tableConversion.js +303 -0
- package/dist/layout-bridge/convert/textBoxFill.d.ts +20 -0
- package/dist/layout-bridge/convert/textBoxFill.js +42 -0
- package/dist/layout-bridge/convert/textFormattingConversion.d.ts +22 -0
- package/dist/layout-bridge/convert/textFormattingConversion.js +120 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +5 -113
- package/dist/layout-bridge/convert/toFlowBlocks.js +11 -2082
- package/dist/layout-bridge/engine/hitTest.js +1 -1
- package/dist/layout-bridge/engine/measuring/index.d.ts +2 -1
- package/dist/layout-bridge/engine/measuring/index.js +2 -1
- package/dist/layout-bridge/engine/selectionRects.js +1 -1
- package/dist/layout-engine/imageLayout.d.ts +9 -0
- package/dist/layout-engine/imageLayout.js +48 -0
- package/dist/layout-engine/index.d.ts +3 -18
- package/dist/layout-engine/index.js +12 -937
- package/dist/layout-engine/layoutFlowShared.d.ts +6 -0
- package/dist/layout-engine/layoutFlowShared.js +8 -0
- package/dist/layout-engine/measure/crossRunWords.d.ts +45 -0
- package/dist/layout-engine/measure/crossRunWords.js +172 -0
- package/dist/layout-engine/measure/floatingLineClearance.d.ts +24 -0
- package/dist/layout-engine/measure/floatingLineClearance.js +44 -0
- package/dist/layout-engine/measure/inlineObjectMetrics.d.ts +6 -0
- package/dist/layout-engine/measure/inlineObjectMetrics.js +52 -0
- package/dist/layout-engine/measure/justification.d.ts +32 -0
- package/dist/layout-engine/measure/justification.js +83 -0
- package/dist/layout-engine/measure/lineFitting.d.ts +48 -0
- package/dist/layout-engine/measure/lineFitting.js +145 -0
- package/dist/layout-engine/measure/lineTypography.d.ts +44 -0
- package/dist/layout-engine/measure/lineTypography.js +124 -0
- package/dist/layout-engine/measure/measureBlocks.js +2 -1
- package/dist/layout-engine/measure/measureParagraph.d.ts +1 -20
- package/dist/layout-engine/measure/measureParagraph.js +32 -734
- package/dist/layout-engine/measure/paragraphMeasureShared.d.ts +109 -0
- package/dist/layout-engine/measure/paragraphMeasureShared.js +82 -0
- package/dist/layout-engine/measure/paragraphTabs.d.ts +18 -0
- package/dist/layout-engine/measure/paragraphTabs.js +78 -0
- package/dist/layout-engine/paragraphLayout.d.ts +23 -0
- package/dist/layout-engine/paragraphLayout.js +204 -0
- package/dist/layout-engine/sectionLayout.d.ts +45 -0
- package/dist/layout-engine/sectionLayout.js +216 -0
- package/dist/layout-engine/tableLayout.d.ts +17 -0
- package/dist/layout-engine/tableLayout.js +369 -0
- package/dist/layout-engine/textBoxLayout.d.ts +15 -0
- package/dist/layout-engine/textBoxLayout.js +137 -0
- package/dist/layout-painter/renderPage.js +1 -0
- package/dist/paged-layout/sectionBlockWidths.d.ts +2 -1
- package/dist/paged-layout/sectionBlockWidths.js +1 -1
- package/dist/server.d.ts +3 -2
- package/package.json +2 -2
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { bulletMarkerFontName, convertBulletToUnicode } from "../../docx/bulletMarkers.js";
|
|
2
|
+
import { getFontAlternate } from "../../fonts/fontAlternates.js";
|
|
3
|
+
import { autospacingMatchesBase } from "../../prosemirror/autospacingBase.js";
|
|
4
|
+
import { advanceVisibleListMarker } from "../../prosemirror/listMarker.js";
|
|
5
|
+
import { directionIsRtl, directionToBidi } from "../../prosemirror/paragraphDirection.js";
|
|
6
|
+
import { mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
|
|
7
|
+
import { AUTO_PARAGRAPH_SPACING_PX } from "../../utils/units.js";
|
|
8
|
+
import { convertBorderSpecToLayout } from "./flowBorders.js";
|
|
9
|
+
import { twipsToPixels } from "./flowConversionShared.js";
|
|
10
|
+
import { applyDeletedListMarkerAttrs, applyMarkerAllCaps, isAddedNumberingChange, isChangedNumberingChange, isRemovedNumberingChange, toListMarkerRevision } from "./listMarkers.js";
|
|
11
|
+
import { listMarkerFormattingFor, resolveWesternThemeFont } from "./textFormattingConversion.js";
|
|
12
|
+
import { paragraphNumberingLevel, paragraphNumberingReferenceId } from "@stll/docx-core/model";
|
|
13
|
+
//#region src/layout-bridge/convert/paragraphAttrs.ts
|
|
14
|
+
/**
|
|
15
|
+
* Converts ProseMirror paragraph attributes to layout ParagraphAttrs:
|
|
16
|
+
* alignment, spacing, indentation, borders, tab stops, and list markers.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Every `ST_Jc` member, and the flow alignment that paints it.
|
|
20
|
+
*
|
|
21
|
+
* `start` and `end` stay unresolved here: they name an edge of the writing
|
|
22
|
+
* direction, not a side of the page, so which of `left` and `right` paints
|
|
23
|
+
* them depends on the paragraph's direction. `numTab` has no flow alignment at
|
|
24
|
+
* all — it aligns the paragraph to the list number's tab stop, which the flow
|
|
25
|
+
* engine does not model — so it falls back to the start edge, which is where a
|
|
26
|
+
* numbered paragraph without one sits.
|
|
27
|
+
*/
|
|
28
|
+
const FLOW_ALIGNMENT_BY_PARAGRAPH_ALIGNMENT = {
|
|
29
|
+
start: "start",
|
|
30
|
+
end: "end",
|
|
31
|
+
numTab: "start",
|
|
32
|
+
left: "left",
|
|
33
|
+
center: "center",
|
|
34
|
+
right: "right",
|
|
35
|
+
both: "justify",
|
|
36
|
+
distribute: "justify",
|
|
37
|
+
mediumKashida: "justify",
|
|
38
|
+
highKashida: "justify",
|
|
39
|
+
lowKashida: "justify",
|
|
40
|
+
thaiDistribute: "justify"
|
|
41
|
+
};
|
|
42
|
+
/** Resolve a logical alignment against the direction the paragraph runs in. */
|
|
43
|
+
const resolveFlowAlignment = (alignment, rightToLeft) => {
|
|
44
|
+
const flow = FLOW_ALIGNMENT_BY_PARAGRAPH_ALIGNMENT[alignment];
|
|
45
|
+
switch (flow) {
|
|
46
|
+
case "start": return rightToLeft ? "right" : "left";
|
|
47
|
+
case "end": return rightToLeft ? "left" : "right";
|
|
48
|
+
default: return flow;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
function convertParagraphAttrs(pmAttrs, { theme, fontAlternates, listCounterStreams, defaultTabStopTwips, paragraphMarkFormatting }) {
|
|
52
|
+
const attrs = {};
|
|
53
|
+
if (pmAttrs.alignment) attrs.alignment = resolveFlowAlignment(pmAttrs.alignment, directionIsRtl(pmAttrs.direction));
|
|
54
|
+
if (pmAttrs.outlineLevel !== void 0) attrs.outlineLevel = pmAttrs.outlineLevel;
|
|
55
|
+
const spaceBefore = pmAttrs.spaceBefore;
|
|
56
|
+
const spaceAfter = pmAttrs.spaceAfter;
|
|
57
|
+
const lineSpacing = pmAttrs.lineSpacing;
|
|
58
|
+
if (typeof pmAttrs.snapToGrid === "boolean") attrs.snapToGrid = pmAttrs.snapToGrid;
|
|
59
|
+
const autoBefore = autospacingMatchesBase(pmAttrs._autospacingBase, "before", spaceBefore);
|
|
60
|
+
const autoAfter = autospacingMatchesBase(pmAttrs._autospacingBase, "after", spaceAfter);
|
|
61
|
+
if (autoBefore || autoAfter || typeof spaceBefore === "number" || typeof spaceAfter === "number" || typeof lineSpacing === "number") {
|
|
62
|
+
attrs.spacing = {};
|
|
63
|
+
if (autoBefore) attrs.spacing.before = AUTO_PARAGRAPH_SPACING_PX;
|
|
64
|
+
else if (typeof spaceBefore === "number") attrs.spacing.before = twipsToPixels(spaceBefore);
|
|
65
|
+
if (autoAfter) attrs.spacing.after = AUTO_PARAGRAPH_SPACING_PX;
|
|
66
|
+
else if (typeof spaceAfter === "number") attrs.spacing.after = twipsToPixels(spaceAfter);
|
|
67
|
+
if (autoBefore || autoAfter) attrs.automaticSpacing = {
|
|
68
|
+
...autoBefore ? { before: true } : {},
|
|
69
|
+
...autoAfter ? { after: true } : {}
|
|
70
|
+
};
|
|
71
|
+
const pmSpacingExplicit = pmAttrs.spacingExplicit;
|
|
72
|
+
const spacingFromDocDefaults = pmAttrs.spacingFromDocDefaults;
|
|
73
|
+
const spacingFromImplicitDefaultStyle = pmAttrs.spacingFromImplicitDefaultStyle;
|
|
74
|
+
const explicit = {};
|
|
75
|
+
if (autoBefore || pmSpacingExplicit?.before || spacingFromDocDefaults?.before || spacingFromImplicitDefaultStyle?.before) explicit.before = true;
|
|
76
|
+
if (autoAfter || pmSpacingExplicit?.after || spacingFromDocDefaults?.after || spacingFromImplicitDefaultStyle?.after) explicit.after = true;
|
|
77
|
+
if (explicit.before !== void 0 || explicit.after !== void 0) attrs.spacingExplicit = explicit;
|
|
78
|
+
if (typeof lineSpacing === "number") if (pmAttrs.lineSpacingRule === "exact" || pmAttrs.lineSpacingRule === "atLeast") {
|
|
79
|
+
attrs.spacing.line = twipsToPixels(lineSpacing);
|
|
80
|
+
attrs.spacing.lineUnit = "px";
|
|
81
|
+
attrs.spacing.lineRule = pmAttrs.lineSpacingRule;
|
|
82
|
+
} else {
|
|
83
|
+
attrs.spacing.line = lineSpacing / 240;
|
|
84
|
+
attrs.spacing.lineUnit = "multiplier";
|
|
85
|
+
attrs.spacing.lineRule = "auto";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
let indentLeft = typeof pmAttrs.indentLeft === "number" ? pmAttrs.indentLeft : void 0;
|
|
89
|
+
let indentFirstLine = typeof pmAttrs.indentFirstLine === "number" ? pmAttrs.indentFirstLine : void 0;
|
|
90
|
+
let hangingIndent = pmAttrs.hangingIndent;
|
|
91
|
+
if (paragraphNumberingReferenceId(pmAttrs.numPr) !== void 0 && indentLeft === void 0 && indentFirstLine === void 0) {
|
|
92
|
+
indentLeft = ((paragraphNumberingLevel(pmAttrs.numPr) ?? 0) + 1) * 720;
|
|
93
|
+
if (indentFirstLine === void 0) {
|
|
94
|
+
indentFirstLine = -360;
|
|
95
|
+
hangingIndent = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (indentLeft !== void 0 || typeof pmAttrs.indentRight === "number" || indentFirstLine !== void 0) {
|
|
99
|
+
attrs.indent = {};
|
|
100
|
+
if (indentLeft !== void 0) attrs.indent.left = twipsToPixels(indentLeft);
|
|
101
|
+
if (typeof pmAttrs.indentRight === "number") attrs.indent.right = twipsToPixels(pmAttrs.indentRight);
|
|
102
|
+
if (indentFirstLine !== void 0) if (hangingIndent) attrs.indent.hanging = Math.abs(twipsToPixels(indentFirstLine));
|
|
103
|
+
else attrs.indent.firstLine = twipsToPixels(indentFirstLine);
|
|
104
|
+
}
|
|
105
|
+
if (pmAttrs.styleId) attrs.styleId = pmAttrs.styleId;
|
|
106
|
+
if (pmAttrs.borders) {
|
|
107
|
+
const borders = pmAttrs.borders;
|
|
108
|
+
attrs.borders = {};
|
|
109
|
+
const convertBorder = (border) => border ? convertBorderSpecToLayout(border, theme) : void 0;
|
|
110
|
+
const topBorder = borders.top ? convertBorder(borders.top) : void 0;
|
|
111
|
+
if (topBorder) attrs.borders.top = topBorder;
|
|
112
|
+
const bottomBorder = borders.bottom ? convertBorder(borders.bottom) : void 0;
|
|
113
|
+
if (bottomBorder) attrs.borders.bottom = bottomBorder;
|
|
114
|
+
const leftBorder = borders.left ? convertBorder(borders.left) : void 0;
|
|
115
|
+
if (leftBorder) attrs.borders.left = leftBorder;
|
|
116
|
+
const rightBorder = borders.right ? convertBorder(borders.right) : void 0;
|
|
117
|
+
if (rightBorder) attrs.borders.right = rightBorder;
|
|
118
|
+
const betweenBorder = borders.between ? convertBorder(borders.between) : void 0;
|
|
119
|
+
if (betweenBorder) attrs.borders.between = betweenBorder;
|
|
120
|
+
const barBorder = borders.bar ? convertBorder(borders.bar) : void 0;
|
|
121
|
+
if (barBorder) attrs.borders.bar = barBorder;
|
|
122
|
+
if (!attrs.borders.top && !attrs.borders.bottom && !attrs.borders.left && !attrs.borders.right && !attrs.borders.between && !attrs.borders.bar) delete attrs.borders;
|
|
123
|
+
}
|
|
124
|
+
const shadingRgb = pmAttrs.shading?.fill?.rgb?.toUpperCase();
|
|
125
|
+
if (shadingRgb && shadingRgb !== "FFFFFF" && shadingRgb !== "FFFFFE") attrs.shading = `#${pmAttrs.shading?.fill?.rgb}`;
|
|
126
|
+
const tabs = mergeParagraphTabStops(pmAttrs.listLevelTabs ?? void 0, pmAttrs.tabs ?? void 0);
|
|
127
|
+
if (tabs && tabs.length > 0) {
|
|
128
|
+
const rightToLeft = directionIsRtl(pmAttrs.direction);
|
|
129
|
+
attrs.tabs = tabs.map((tab) => {
|
|
130
|
+
const tabStop = {
|
|
131
|
+
val: resolveTabAlignment(tab.alignment, rightToLeft),
|
|
132
|
+
pos: tab.position
|
|
133
|
+
};
|
|
134
|
+
if (tab.leader) tabStop.leader = tab.leader;
|
|
135
|
+
return tabStop;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (pmAttrs.pageBreakBefore) attrs.pageBreakBefore = true;
|
|
139
|
+
if (pmAttrs.kinsoku !== void 0 && pmAttrs.kinsoku !== null) attrs.kinsoku = pmAttrs.kinsoku;
|
|
140
|
+
if (pmAttrs.overflowPunctuation !== void 0 && pmAttrs.overflowPunctuation !== null) attrs.overflowPunctuation = pmAttrs.overflowPunctuation;
|
|
141
|
+
if (pmAttrs.suppressAutoHyphens !== void 0 && pmAttrs.suppressAutoHyphens !== null) attrs.suppressAutoHyphens = pmAttrs.suppressAutoHyphens;
|
|
142
|
+
if (pmAttrs.renderedPageBreakBefore) attrs.renderedPageBreakBefore = true;
|
|
143
|
+
if (pmAttrs.keepNext) attrs.keepNext = true;
|
|
144
|
+
if (pmAttrs.keepLines) attrs.keepLines = true;
|
|
145
|
+
if (pmAttrs.widowControl === false) attrs.widowControl = false;
|
|
146
|
+
if (pmAttrs.contextualSpacing) attrs.contextualSpacing = true;
|
|
147
|
+
if (pmAttrs.runInWithNext) attrs.runInWithNext = true;
|
|
148
|
+
const bidi = directionToBidi(pmAttrs.direction);
|
|
149
|
+
if (bidi !== void 0) attrs.bidi = bidi;
|
|
150
|
+
if (pmAttrs.styleId) attrs.styleId = pmAttrs.styleId;
|
|
151
|
+
const propertyChanges = pmAttrs._propertyChanges ?? [];
|
|
152
|
+
let changedNumberingChange;
|
|
153
|
+
if (pmAttrs.numPr) {
|
|
154
|
+
attrs.numPr = pmAttrs.numPr;
|
|
155
|
+
if (pmAttrs.pPrMark?.kind === "del") attrs.listMarkerRevision = toListMarkerRevision("del", pmAttrs.pPrMark.info);
|
|
156
|
+
else if (pmAttrs.pPrMark?.kind === "ins") attrs.listMarkerRevision = toListMarkerRevision("ins", pmAttrs.pPrMark.info);
|
|
157
|
+
else {
|
|
158
|
+
const numberingAddedChange = propertyChanges.find(isAddedNumberingChange);
|
|
159
|
+
const currentNumPr = pmAttrs.numPr;
|
|
160
|
+
changedNumberingChange = propertyChanges.find((change) => isChangedNumberingChange(currentNumPr, change));
|
|
161
|
+
const numberingInsertionChange = numberingAddedChange ?? changedNumberingChange;
|
|
162
|
+
if (numberingInsertionChange) attrs.listMarkerRevision = toListMarkerRevision("ins", numberingInsertionChange.info);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const resolvedMarker = applyMarkerAllCaps(advanceVisibleListMarker(pmAttrs, listCounterStreams).marker, pmAttrs.listMarkerAllCaps);
|
|
166
|
+
if (resolvedMarker !== null) attrs.listMarker = resolvedMarker;
|
|
167
|
+
else if (pmAttrs.listMarker) attrs.listMarker = pmAttrs.listIsBullet ? convertBulletToUnicode(pmAttrs.listMarker, bulletMarkerFontName(pmAttrs.listMarkerFormatting)) : pmAttrs.listMarker;
|
|
168
|
+
if (pmAttrs.listIsBullet !== void 0) attrs.listIsBullet = pmAttrs.listIsBullet;
|
|
169
|
+
if (pmAttrs.listMarkerHidden) attrs.listMarkerHidden = true;
|
|
170
|
+
if (attrs.listMarker !== void 0 || pmAttrs.listMarkerFormatting) {
|
|
171
|
+
const listMarkerFormatting = listMarkerFormattingFor(pmAttrs.listMarkerFormatting, paragraphMarkFormatting(), theme, fontAlternates);
|
|
172
|
+
if (listMarkerFormatting) attrs.listMarkerFormatting = listMarkerFormatting;
|
|
173
|
+
}
|
|
174
|
+
if (pmAttrs.listMarkerAlignment) attrs.listMarkerAlignment = pmAttrs.listMarkerAlignment;
|
|
175
|
+
if (pmAttrs.listMarkerSuffix) attrs.listMarkerSuffix = pmAttrs.listMarkerSuffix;
|
|
176
|
+
if (pmAttrs.listMarkerSecondSlotOffsetTwips !== void 0) attrs.listMarkerSecondSlotOffsetTwips = pmAttrs.listMarkerSecondSlotOffsetTwips;
|
|
177
|
+
if (!pmAttrs.numPr) {
|
|
178
|
+
const numberingRemovedChange = propertyChanges.find(isRemovedNumberingChange);
|
|
179
|
+
if (numberingRemovedChange) {
|
|
180
|
+
applyDeletedListMarkerAttrs(attrs, numberingRemovedChange, void 0, theme, fontAlternates, paragraphMarkFormatting);
|
|
181
|
+
if (resolvedMarker !== null) {
|
|
182
|
+
attrs.listMarker = resolvedMarker;
|
|
183
|
+
attrs.listMarkerRevision = toListMarkerRevision("del", numberingRemovedChange.info);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (defaultTabStopTwips !== void 0) attrs.defaultTabStopTwips = defaultTabStopTwips;
|
|
188
|
+
const dtf = pmAttrs.defaultTextFormatting;
|
|
189
|
+
if (dtf) {
|
|
190
|
+
if (dtf.fontSize !== void 0) attrs.defaultFontSize = dtf.fontSize / 2;
|
|
191
|
+
if (attrs.listMarker !== void 0 && !attrs.listMarkerHidden && (attrs.bidi === true || dtf.rtl === true || dtf.cs === true) && dtf.fontSizeCs !== void 0 && (dtf.fontSize === void 0 || dtf.fontSizeCs > dtf.fontSize)) attrs.listParagraphMarkFontSize = dtf.fontSizeCs / 2;
|
|
192
|
+
if (dtf.fontFamily) {
|
|
193
|
+
const resolvedFamily = resolveWesternThemeFont(dtf.fontFamily, theme);
|
|
194
|
+
if (resolvedFamily) {
|
|
195
|
+
attrs.defaultFontFamily = resolvedFamily;
|
|
196
|
+
const alternate = getFontAlternate(resolvedFamily, fontAlternates);
|
|
197
|
+
if (alternate) attrs.defaultAlternateFontFamily = alternate;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return attrs;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Every `ST_TabJc` member, and the layout engine's name for it.
|
|
205
|
+
*
|
|
206
|
+
* The engine's `start` and `end` are its names for the left and right edges of
|
|
207
|
+
* the line, not direction-aware ones, so `w:tab w:val="left"` maps to `start`
|
|
208
|
+
* unconditionally. `ST_TabJc`'s own `start` and `end` *are* direction-aware
|
|
209
|
+
* and stay unresolved here, under names the engine has no member for.
|
|
210
|
+
* `num`, the tab a numbered paragraph's text hangs from, has no engine
|
|
211
|
+
* alignment of its own and falls back to the line's start edge.
|
|
212
|
+
*/
|
|
213
|
+
const TAB_ALIGNMENT_BY_TAB_STOP_ALIGNMENT = {
|
|
214
|
+
start: "logicalStart",
|
|
215
|
+
end: "logicalEnd",
|
|
216
|
+
num: "logicalStart",
|
|
217
|
+
left: "start",
|
|
218
|
+
right: "end",
|
|
219
|
+
center: "center",
|
|
220
|
+
decimal: "decimal",
|
|
221
|
+
bar: "bar",
|
|
222
|
+
clear: "clear"
|
|
223
|
+
};
|
|
224
|
+
/** Resolve a logical tab alignment against the direction the paragraph runs in. */
|
|
225
|
+
const resolveTabAlignment = (alignment, rightToLeft) => {
|
|
226
|
+
const mapped = TAB_ALIGNMENT_BY_TAB_STOP_ALIGNMENT[alignment];
|
|
227
|
+
switch (mapped) {
|
|
228
|
+
case "logicalStart": return rightToLeft ? "end" : "start";
|
|
229
|
+
case "logicalEnd": return rightToLeft ? "start" : "end";
|
|
230
|
+
default: return mapped;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
//#endregion
|
|
234
|
+
export { convertParagraphAttrs };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ParagraphAttrs } from "../../prosemirror/schema/nodes.js";
|
|
2
|
+
import { ParagraphAttrs as ParagraphAttrs$1, ParagraphBlock } from "../../layout-engine/types.js";
|
|
3
|
+
import { FlowConversionOptions } from "./flowConversionShared.js";
|
|
4
|
+
import { PageBreakRunProjection } from "./paragraphRuns.js";
|
|
5
|
+
import { Node } from "prosemirror-model";
|
|
6
|
+
//#region src/layout-bridge/convert/paragraphConversion.d.ts
|
|
7
|
+
declare function hasVisibleParagraphPayload(attrs: ParagraphAttrs$1): boolean;
|
|
8
|
+
/** Whether any `w:pBdr` side draws a rule (`none`/`nil` sides draw nothing). */
|
|
9
|
+
declare function drawsParagraphBorder(borders: ParagraphAttrs["borders"]): boolean;
|
|
10
|
+
declare function convertParagraph(node: Node, startPos: number, options: FlowConversionOptions, pageBreaks?: PageBreakRunProjection[]): ParagraphBlock;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { convertParagraph, drawsParagraphBorder, hasVisibleParagraphPayload };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { getFontAlternate } from "../../fonts/fontAlternates.js";
|
|
2
|
+
import { setParagraphFrame } from "../../layout-engine/paragraphFrame.js";
|
|
3
|
+
import { expectParagraphAttrs } from "../../prosemirror/attrs/index.js";
|
|
4
|
+
import { expectTextBoxAnchorAttrs } from "../../prosemirror/textBoxAnchorAttrs.js";
|
|
5
|
+
import { nextBlockId, twipsToPixels } from "./flowConversionShared.js";
|
|
6
|
+
import { convertParagraphAttrs } from "./paragraphAttrs.js";
|
|
7
|
+
import { resolveParagraphMarkFormatting, resolveParagraphMarkOwnFormatting } from "./paragraphMarkFormatting.js";
|
|
8
|
+
import { paragraphToRuns } from "./paragraphRuns.js";
|
|
9
|
+
import { resolveWesternThemeFont } from "./textFormattingConversion.js";
|
|
10
|
+
import { panic } from "better-result";
|
|
11
|
+
import { statesNoBorder } from "@stll/docx-core/model";
|
|
12
|
+
//#region src/layout-bridge/convert/paragraphConversion.ts
|
|
13
|
+
const DETACHED_WATERMARK_HOST_ATTR = "_detachedWatermarkHost";
|
|
14
|
+
const expectDetachedWatermarkHostAttr = (attrs) => {
|
|
15
|
+
const value = Reflect.get(attrs, DETACHED_WATERMARK_HOST_ATTR);
|
|
16
|
+
if (value === null || value === void 0) return false;
|
|
17
|
+
if (typeof value !== "boolean") panic("Invalid ProseMirror detached watermark host attrs:\nparagraph.attrs._detachedWatermarkHost: Expected a boolean.");
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Convert a paragraph node to a ParagraphBlock.
|
|
22
|
+
*/
|
|
23
|
+
function hasOnlyVisuallyEmptyTextRuns(runs) {
|
|
24
|
+
return runs.length > 0 && runs.every((run) => run.kind === "text" && run.text.replace(/\u00a0/gu, " ").trim().length === 0);
|
|
25
|
+
}
|
|
26
|
+
function hasOnlyHiddenTextRuns(runs) {
|
|
27
|
+
return runs.length > 0 && runs.every((run) => run.kind === "text" && run.hidden === true);
|
|
28
|
+
}
|
|
29
|
+
function hasVisibleParagraphPayload(attrs) {
|
|
30
|
+
return attrs.listMarker !== void 0 && !attrs.listMarkerHidden || attrs.borders?.top !== void 0 || attrs.borders?.bottom !== void 0 || attrs.borders?.left !== void 0 || attrs.borders?.right !== void 0 || attrs.borders?.between !== void 0 || attrs.borders?.bar !== void 0 || attrs.shading !== void 0;
|
|
31
|
+
}
|
|
32
|
+
/** Whether any `w:pBdr` side draws a rule (`none`/`nil` sides draw nothing). */
|
|
33
|
+
function drawsParagraphBorder(borders) {
|
|
34
|
+
if (!borders) return false;
|
|
35
|
+
return [
|
|
36
|
+
borders.top,
|
|
37
|
+
borders.bottom,
|
|
38
|
+
borders.left,
|
|
39
|
+
borders.right,
|
|
40
|
+
borders.between,
|
|
41
|
+
borders.bar
|
|
42
|
+
].some((border) => border?.style !== void 0 && !statesNoBorder(border.style));
|
|
43
|
+
}
|
|
44
|
+
function convertParagraph(node, startPos, options, pageBreaks) {
|
|
45
|
+
const pmAttrs = expectParagraphAttrs(node);
|
|
46
|
+
const runs = paragraphToRuns(node, startPos, options, pageBreaks);
|
|
47
|
+
const attrs = convertParagraphAttrs(pmAttrs, {
|
|
48
|
+
theme: options.theme,
|
|
49
|
+
fontAlternates: options.fontAlternates,
|
|
50
|
+
listCounterStreams: options.listCounterStreams,
|
|
51
|
+
defaultTabStopTwips: options.defaultTabStopTwips,
|
|
52
|
+
paragraphMarkFormatting: () => resolveParagraphMarkFormatting(pmAttrs, options.styleResolver)
|
|
53
|
+
});
|
|
54
|
+
if (options.numberingTabIgnoresIndent && attrs.listMarker !== void 0) attrs.listNumberingTabIgnoresIndent = true;
|
|
55
|
+
if (options.defaultFont !== void 0) attrs.defaultFontFamily ??= options.defaultFont;
|
|
56
|
+
if (options.defaultSize !== void 0) attrs.defaultFontSize ??= options.defaultSize;
|
|
57
|
+
if (options.lineBreakRules) attrs.lineBreakRules = options.lineBreakRules;
|
|
58
|
+
if (options.justificationCompatibility) attrs.justificationCompatibility = options.justificationCompatibility;
|
|
59
|
+
if (options.automaticHyphenation) attrs.automaticHyphenation = options.automaticHyphenation;
|
|
60
|
+
const defaultTextFormatting = pmAttrs.defaultTextFormatting;
|
|
61
|
+
if (runs.length === 0 || hasOnlyVisuallyEmptyTextRuns(runs)) {
|
|
62
|
+
if (pmAttrs._originalFormatting && Object.entries(pmAttrs._originalFormatting).some(([key, value]) => key !== "runProperties" && value !== void 0 && value !== null)) attrs.hasDirectParagraphFormatting = true;
|
|
63
|
+
const directParagraphMarkFormatting = pmAttrs._originalFormatting?.runProperties;
|
|
64
|
+
if (directParagraphMarkFormatting && Object.values(directParagraphMarkFormatting).some((value) => value !== void 0 && value !== null)) attrs.hasDirectParagraphMarkFormatting = true;
|
|
65
|
+
const paragraphMarkFormatting = resolveParagraphMarkOwnFormatting(directParagraphMarkFormatting, options.styleResolver);
|
|
66
|
+
if (paragraphMarkFormatting?.fontSize !== void 0) attrs.defaultFontSize = paragraphMarkFormatting.fontSize / 2;
|
|
67
|
+
const paragraphMarkFontFamily = paragraphMarkFormatting?.fontFamily ? resolveWesternThemeFont(paragraphMarkFormatting.fontFamily, options.theme) : void 0;
|
|
68
|
+
if (paragraphMarkFontFamily) {
|
|
69
|
+
attrs.defaultFontFamily = paragraphMarkFontFamily;
|
|
70
|
+
const alternate = getFontAlternate(paragraphMarkFontFamily, options.fontAlternates);
|
|
71
|
+
if (alternate) attrs.defaultAlternateFontFamily = alternate;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const isFullyHiddenParagraph = defaultTextFormatting?.hidden === true && (runs.length === 0 || hasOnlyHiddenTextRuns(runs));
|
|
75
|
+
if (isFullyHiddenParagraph && attrs.listMarker !== void 0) attrs.listMarkerHidden = true;
|
|
76
|
+
if (isFullyHiddenParagraph) attrs.suppressEmptyParagraphHeight = true;
|
|
77
|
+
if (runs.length === 0 && expectDetachedWatermarkHostAttr(node.attrs)) attrs.suppressEmptyParagraphHeight = false;
|
|
78
|
+
if (runs.length === 0 && pmAttrs._pageBreakCarrier === true && !hasVisibleParagraphPayload(attrs)) attrs.suppressEmptyParagraphHeight = true;
|
|
79
|
+
const bookmarkNames = pmAttrs.bookmarks?.map((b) => b.name);
|
|
80
|
+
const block = {
|
|
81
|
+
kind: "paragraph",
|
|
82
|
+
id: nextBlockId(),
|
|
83
|
+
runs,
|
|
84
|
+
attrs,
|
|
85
|
+
...pmAttrs.paraId ? { paraId: pmAttrs.paraId } : {},
|
|
86
|
+
...bookmarkNames && bookmarkNames.length > 0 ? { bookmarks: bookmarkNames } : {},
|
|
87
|
+
pmStart: startPos,
|
|
88
|
+
pmEnd: startPos + node.nodeSize
|
|
89
|
+
};
|
|
90
|
+
const frame = pmAttrs._originalFormatting?.frame;
|
|
91
|
+
if (frame !== void 0 && frame.dropCap !== "drop" && frame.dropCap !== "margin") setParagraphFrame(block, {
|
|
92
|
+
...frame.width !== void 0 ? { width: twipsToPixels(frame.width) } : {},
|
|
93
|
+
...frame.height !== void 0 ? { height: twipsToPixels(frame.height) } : {},
|
|
94
|
+
...frame.hSpace !== void 0 ? { hSpace: twipsToPixels(frame.hSpace) } : {},
|
|
95
|
+
...frame.vSpace !== void 0 ? { vSpace: twipsToPixels(frame.vSpace) } : {},
|
|
96
|
+
...frame.hAnchor !== void 0 ? { hAnchor: frame.hAnchor } : {},
|
|
97
|
+
...frame.vAnchor !== void 0 ? { vAnchor: frame.vAnchor } : {},
|
|
98
|
+
...frame.x !== void 0 ? { x: twipsToPixels(frame.x) } : {},
|
|
99
|
+
...frame.y !== void 0 ? { y: twipsToPixels(frame.y) } : {},
|
|
100
|
+
...frame.xAlign !== void 0 ? { xAlign: frame.xAlign } : {},
|
|
101
|
+
...frame.yAlign !== void 0 ? { yAlign: frame.yAlign } : {},
|
|
102
|
+
...frame.wrap !== void 0 ? { wrap: frame.wrap } : {}
|
|
103
|
+
});
|
|
104
|
+
node.descendants((child) => {
|
|
105
|
+
if (child.type.name !== "textBoxAnchor") return true;
|
|
106
|
+
options.textBoxAnchorBlockIds.set(expectTextBoxAnchorAttrs(child).anchorId, block.id);
|
|
107
|
+
return false;
|
|
108
|
+
});
|
|
109
|
+
return block;
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
export { convertParagraph, drawsParagraphBorder, hasVisibleParagraphPayload };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Run, RunFormatting } from "../../layout-engine/types.js";
|
|
2
|
+
import { FlowConversionOptions } from "./flowConversionShared.js";
|
|
3
|
+
import { Node } from "prosemirror-model";
|
|
4
|
+
//#region src/layout-bridge/convert/paragraphRuns.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Convert a paragraph node to runs.
|
|
7
|
+
*/
|
|
8
|
+
type PageBreakRunProjection = {
|
|
9
|
+
pmStart: number;
|
|
10
|
+
pmEnd: number;
|
|
11
|
+
trackedChange?: Pick<RunFormatting, "isInsertion" | "changeAuthor" | "changeDate" | "changeRevisionId" | "isSuggestion" | "suggestionId">;
|
|
12
|
+
};
|
|
13
|
+
declare function paragraphToRuns(node: Node, startPos: number, _options: FlowConversionOptions, pageBreaks?: PageBreakRunProjection[]): Run[];
|
|
14
|
+
//#endregion
|
|
15
|
+
export { PageBreakRunProjection, paragraphToRuns };
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { getFontAlternate } from "../../fonts/fontAlternates.js";
|
|
2
|
+
import { expectFieldAttrs, expectImageAttrs, expectMathAttrs, expectParagraphAttrs, expectPreservedXmlAttrs, expectSymbolAttrs } from "../../prosemirror/attrs/index.js";
|
|
3
|
+
import { decodeOoxmlSymbolCharacter } from "../../utils/ooxmlSymbol.js";
|
|
4
|
+
import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
|
|
5
|
+
import { buildImageRun, constrainImageToPage, hasPaintableImageSource, hasRelationshipBackedImageBox } from "./imageConversion.js";
|
|
6
|
+
import { isNoteReferenceMarkXml } from "./noteReferences.js";
|
|
7
|
+
import { applyCharacterStyleToggleFormatting, markDefaultBlackTextColorSource, mergeRunFormatting } from "./runFormattingMerge.js";
|
|
8
|
+
import { extractRunFormatting } from "./runMarkFormatting.js";
|
|
9
|
+
import { paragraphRunDefaults } from "./textFormattingConversion.js";
|
|
10
|
+
//#region src/layout-bridge/convert/paragraphRuns.ts
|
|
11
|
+
/**
|
|
12
|
+
* In TOC paragraphs, strip the resolved Hyperlink character-style colour and
|
|
13
|
+
* underline so the painter's link fallback doesn't fire. The PM doc keeps the
|
|
14
|
+
* original marks so copy/paste out of a TOC still carries the Hyperlink
|
|
15
|
+
* styling like Word does. Applies to both text and field runs — a TOC entry's
|
|
16
|
+
* page number is a PAGEREF field inside the entry's hyperlink.
|
|
17
|
+
*
|
|
18
|
+
* Mutates `formatting` in place; cheaper than re-cloning per run.
|
|
19
|
+
*/
|
|
20
|
+
function stripTocHyperlinkStyle(formatting) {
|
|
21
|
+
if (!formatting.hyperlink) return;
|
|
22
|
+
formatting.hyperlink.noDefaultStyle = true;
|
|
23
|
+
delete formatting.color;
|
|
24
|
+
delete formatting.underline;
|
|
25
|
+
}
|
|
26
|
+
const isTrackedRunMark = ({ type }) => type.name === "insertion" || type.name === "deletion";
|
|
27
|
+
/**
|
|
28
|
+
* Inline wrappers own marks that apply to every projected descendant. A
|
|
29
|
+
* descendant's mark of the same type is more specific, and any descendant
|
|
30
|
+
* revision replaces (rather than combines with) an inherited revision.
|
|
31
|
+
*/
|
|
32
|
+
const mergeProjectedInlineMarks = (inheritedMarks, ownMarks) => {
|
|
33
|
+
if (inheritedMarks.length === 0) return ownMarks;
|
|
34
|
+
const ownMarkTypes = new Set(ownMarks.map(({ type }) => type));
|
|
35
|
+
const hasOwnTrackedMark = ownMarks.some(isTrackedRunMark);
|
|
36
|
+
return [...inheritedMarks.filter((mark) => !ownMarkTypes.has(mark.type) && !(hasOwnTrackedMark && isTrackedRunMark(mark))), ...ownMarks];
|
|
37
|
+
};
|
|
38
|
+
function paragraphToRuns(node, startPos, _options, pageBreaks) {
|
|
39
|
+
const runs = [];
|
|
40
|
+
const offset = startPos + 1;
|
|
41
|
+
const theme = _options.theme;
|
|
42
|
+
const fontAlternates = _options.fontAlternates;
|
|
43
|
+
const pmAttrs = expectParagraphAttrs(node);
|
|
44
|
+
const paraDefaults = paragraphRunDefaults(pmAttrs, theme, fontAlternates);
|
|
45
|
+
const paragraphStyleId = pmAttrs.styleId;
|
|
46
|
+
const inTocParagraph = pmAttrs._tableOfContentsLevel !== void 0 || tableOfContentsStyleLevel({ styleId: paragraphStyleId }) !== void 0;
|
|
47
|
+
let leadingRenderedPageBreakPending = pmAttrs.renderedPageBreakBefore === true;
|
|
48
|
+
function pushRunsForChild(child, childPos, inheritedMarks = []) {
|
|
49
|
+
if (child.type.name === "bookmarkBoundary") return;
|
|
50
|
+
if (child.type.name === "renderedPageBreak") {
|
|
51
|
+
if (leadingRenderedPageBreakPending) {
|
|
52
|
+
leadingRenderedPageBreakPending = false;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
runs.push({
|
|
56
|
+
kind: "renderedPageBreak",
|
|
57
|
+
pmStart: childPos,
|
|
58
|
+
pmEnd: childPos + child.nodeSize
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const effectiveMarks = mergeProjectedInlineMarks(inheritedMarks, child.marks);
|
|
63
|
+
if (child.type.name === "pageBreakRun") {
|
|
64
|
+
const trackedChange = extractRunFormatting(effectiveMarks, theme, fontAlternates);
|
|
65
|
+
if (trackedChange.isDeletion) {
|
|
66
|
+
runs.push({
|
|
67
|
+
kind: "text",
|
|
68
|
+
text: "",
|
|
69
|
+
isDeletion: true,
|
|
70
|
+
...trackedChange.changeAuthor !== void 0 ? { changeAuthor: trackedChange.changeAuthor } : {},
|
|
71
|
+
...trackedChange.changeDate !== void 0 ? { changeDate: trackedChange.changeDate } : {},
|
|
72
|
+
...trackedChange.changeRevisionId !== void 0 ? { changeRevisionId: trackedChange.changeRevisionId } : {},
|
|
73
|
+
...trackedChange.isSuggestion === true ? { isSuggestion: true } : {},
|
|
74
|
+
...trackedChange.suggestionId !== void 0 ? { suggestionId: trackedChange.suggestionId } : {},
|
|
75
|
+
pmStart: childPos,
|
|
76
|
+
pmEnd: childPos + child.nodeSize
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
pageBreaks?.push({
|
|
81
|
+
pmStart: childPos,
|
|
82
|
+
pmEnd: childPos + child.nodeSize,
|
|
83
|
+
...trackedChange.isInsertion ? { trackedChange: {
|
|
84
|
+
isInsertion: true,
|
|
85
|
+
...trackedChange.changeAuthor !== void 0 ? { changeAuthor: trackedChange.changeAuthor } : {},
|
|
86
|
+
...trackedChange.changeDate !== void 0 ? { changeDate: trackedChange.changeDate } : {},
|
|
87
|
+
...trackedChange.changeRevisionId !== void 0 ? { changeRevisionId: trackedChange.changeRevisionId } : {},
|
|
88
|
+
...trackedChange.isSuggestion === true ? { isSuggestion: true } : {},
|
|
89
|
+
...trackedChange.suggestionId !== void 0 ? { suggestionId: trackedChange.suggestionId } : {}
|
|
90
|
+
} } : {}
|
|
91
|
+
});
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (child.type.name !== "sdt") leadingRenderedPageBreakPending = false;
|
|
95
|
+
if (child.isText && child.text) {
|
|
96
|
+
const formatting = extractRunFormatting(effectiveMarks, theme, fontAlternates);
|
|
97
|
+
applyCharacterStyleToggleFormatting({
|
|
98
|
+
formatting,
|
|
99
|
+
marks: effectiveMarks,
|
|
100
|
+
paragraphFormatting: pmAttrs.defaultTextFormatting,
|
|
101
|
+
styleResolver: _options.styleResolver
|
|
102
|
+
});
|
|
103
|
+
if (inTocParagraph) stripTocHyperlinkStyle(formatting);
|
|
104
|
+
const run = {
|
|
105
|
+
kind: "text",
|
|
106
|
+
text: child.text,
|
|
107
|
+
...mergeRunFormatting(paraDefaults, formatting),
|
|
108
|
+
pmStart: childPos,
|
|
109
|
+
pmEnd: childPos + child.nodeSize
|
|
110
|
+
};
|
|
111
|
+
runs.push(run);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (child.type.name === "symbol") {
|
|
115
|
+
const attrs = expectSymbolAttrs(child);
|
|
116
|
+
const text = decodeOoxmlSymbolCharacter(attrs.char);
|
|
117
|
+
if (text === null) return;
|
|
118
|
+
const formatting = extractRunFormatting(effectiveMarks, theme, fontAlternates);
|
|
119
|
+
applyCharacterStyleToggleFormatting({
|
|
120
|
+
formatting,
|
|
121
|
+
marks: effectiveMarks,
|
|
122
|
+
paragraphFormatting: pmAttrs.defaultTextFormatting,
|
|
123
|
+
styleResolver: _options.styleResolver
|
|
124
|
+
});
|
|
125
|
+
if (inTocParagraph) stripTocHyperlinkStyle(formatting);
|
|
126
|
+
const alternateFontFamily = getFontAlternate(attrs.font, fontAlternates);
|
|
127
|
+
formatting.fontFamily = attrs.font;
|
|
128
|
+
if (alternateFontFamily) formatting.alternateFontFamily = alternateFontFamily;
|
|
129
|
+
runs.push({
|
|
130
|
+
kind: "text",
|
|
131
|
+
text,
|
|
132
|
+
...mergeRunFormatting(paraDefaults, formatting),
|
|
133
|
+
pmStart: childPos,
|
|
134
|
+
pmEnd: childPos + child.nodeSize
|
|
135
|
+
});
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (child.type.name === "preservedXml") {
|
|
139
|
+
const { xml, text: capturedText } = expectPreservedXmlAttrs(child);
|
|
140
|
+
const text = capturedText === "" && _options.noteReferenceMarkText !== void 0 && isNoteReferenceMarkXml(xml) ? _options.noteReferenceMarkText : capturedText;
|
|
141
|
+
if (text === "") return;
|
|
142
|
+
const formatting = extractRunFormatting(effectiveMarks, theme, fontAlternates);
|
|
143
|
+
applyCharacterStyleToggleFormatting({
|
|
144
|
+
formatting,
|
|
145
|
+
marks: effectiveMarks,
|
|
146
|
+
paragraphFormatting: pmAttrs.defaultTextFormatting,
|
|
147
|
+
styleResolver: _options.styleResolver
|
|
148
|
+
});
|
|
149
|
+
runs.push({
|
|
150
|
+
kind: "text",
|
|
151
|
+
text,
|
|
152
|
+
...mergeRunFormatting(paraDefaults, formatting),
|
|
153
|
+
pmStart: childPos,
|
|
154
|
+
pmEnd: childPos + child.nodeSize
|
|
155
|
+
});
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (child.type.name === "hardBreak") {
|
|
159
|
+
runs.push({
|
|
160
|
+
kind: "lineBreak",
|
|
161
|
+
pmStart: childPos,
|
|
162
|
+
pmEnd: childPos + child.nodeSize
|
|
163
|
+
});
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (child.type.name === "tab") {
|
|
167
|
+
const formatting = extractRunFormatting(effectiveMarks, theme, fontAlternates);
|
|
168
|
+
applyCharacterStyleToggleFormatting({
|
|
169
|
+
formatting,
|
|
170
|
+
marks: effectiveMarks,
|
|
171
|
+
paragraphFormatting: pmAttrs.defaultTextFormatting,
|
|
172
|
+
styleResolver: _options.styleResolver
|
|
173
|
+
});
|
|
174
|
+
const run = {
|
|
175
|
+
kind: "tab",
|
|
176
|
+
...mergeRunFormatting(paraDefaults, formatting),
|
|
177
|
+
pmStart: childPos,
|
|
178
|
+
pmEnd: childPos + child.nodeSize
|
|
179
|
+
};
|
|
180
|
+
runs.push(run);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (child.type.name === "image") {
|
|
184
|
+
const attrs = expectImageAttrs(child);
|
|
185
|
+
if (!hasPaintableImageSource(attrs) && !hasRelationshipBackedImageBox(attrs)) return;
|
|
186
|
+
const constrained = constrainImageToPage(attrs.width ?? 100, attrs.height ?? 100, _options.pageContentHeight);
|
|
187
|
+
const trackedFmt = extractRunFormatting(effectiveMarks, theme, fontAlternates);
|
|
188
|
+
const run = buildImageRun(attrs, constrained, childPos, childPos + child.nodeSize, trackedFmt, _options.forceAnchorLayoutInCell);
|
|
189
|
+
runs.push(run);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (child.type.name === "structuredField") {
|
|
193
|
+
let containsPageBreak = false;
|
|
194
|
+
child.descendants((descendant) => {
|
|
195
|
+
if (descendant.type.name === "pageBreakRun") {
|
|
196
|
+
containsPageBreak = true;
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
return true;
|
|
200
|
+
});
|
|
201
|
+
if (containsPageBreak) {
|
|
202
|
+
const fieldContentStart = childPos + 1;
|
|
203
|
+
child.forEach((fieldChild, fieldChildOffset) => {
|
|
204
|
+
pushRunsForChild(fieldChild, fieldContentStart + fieldChildOffset, effectiveMarks);
|
|
205
|
+
});
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (child.type.name === "field" || child.type.name === "structuredField") {
|
|
210
|
+
const attrs = expectFieldAttrs(child);
|
|
211
|
+
const ft = attrs.fieldType;
|
|
212
|
+
let mappedType = "OTHER";
|
|
213
|
+
if (ft === "PAGE") mappedType = "PAGE";
|
|
214
|
+
else if (ft === "NUMPAGES") mappedType = "NUMPAGES";
|
|
215
|
+
else if (ft === "DATE") mappedType = "DATE";
|
|
216
|
+
else if (ft === "TIME") mappedType = "TIME";
|
|
217
|
+
const extractedFieldFormatting = extractRunFormatting(effectiveMarks, theme, fontAlternates);
|
|
218
|
+
applyCharacterStyleToggleFormatting({
|
|
219
|
+
formatting: extractedFieldFormatting,
|
|
220
|
+
marks: effectiveMarks,
|
|
221
|
+
paragraphFormatting: pmAttrs.defaultTextFormatting,
|
|
222
|
+
styleResolver: _options.styleResolver
|
|
223
|
+
});
|
|
224
|
+
if (inTocParagraph) stripTocHyperlinkStyle(extractedFieldFormatting);
|
|
225
|
+
const fieldFormatting = markDefaultBlackTextColorSource(extractedFieldFormatting, paraDefaults);
|
|
226
|
+
const run = {
|
|
227
|
+
kind: "field",
|
|
228
|
+
fieldType: mappedType,
|
|
229
|
+
instruction: attrs.instruction,
|
|
230
|
+
fallback: _options.numberedRefResults?.get(child) ?? attrs.displayText ?? "",
|
|
231
|
+
...attrs.fldLock ? { fldLock: true } : {},
|
|
232
|
+
pmStart: childPos,
|
|
233
|
+
pmEnd: childPos + child.nodeSize,
|
|
234
|
+
...fieldFormatting
|
|
235
|
+
};
|
|
236
|
+
runs.push(run);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (child.type.name === "math") {
|
|
240
|
+
const attrs = expectMathAttrs(child);
|
|
241
|
+
const plainText = attrs.plainText || "[equation]";
|
|
242
|
+
runs.push({
|
|
243
|
+
kind: "math",
|
|
244
|
+
display: attrs.display ?? "inline",
|
|
245
|
+
ommlXml: attrs.ommlXml,
|
|
246
|
+
plainText,
|
|
247
|
+
italic: true,
|
|
248
|
+
fontFamily: "Cambria Math",
|
|
249
|
+
pmStart: childPos,
|
|
250
|
+
pmEnd: childPos + child.nodeSize
|
|
251
|
+
});
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (child.type.name === "sdt") {
|
|
255
|
+
const sdtInnerOffset = childPos + 1;
|
|
256
|
+
child.forEach((sdtChild, sdtChildOffset) => {
|
|
257
|
+
pushRunsForChild(sdtChild, sdtInnerOffset + sdtChildOffset, effectiveMarks);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
node.forEach((child, childOffset) => {
|
|
262
|
+
pushRunsForChild(child, offset + childOffset);
|
|
263
|
+
});
|
|
264
|
+
const { defaultFont, defaultSize } = _options;
|
|
265
|
+
if (defaultFont !== void 0 || defaultSize !== void 0) for (const run of runs) switch (run.kind) {
|
|
266
|
+
case "text":
|
|
267
|
+
case "tab":
|
|
268
|
+
case "renderedPageBreak":
|
|
269
|
+
case "field":
|
|
270
|
+
case "math":
|
|
271
|
+
if (defaultFont !== void 0) run.fontFamily ??= defaultFont;
|
|
272
|
+
if (defaultSize !== void 0) run.fontSize ??= defaultSize;
|
|
273
|
+
break;
|
|
274
|
+
case "image":
|
|
275
|
+
case "lineBreak": break;
|
|
276
|
+
default:
|
|
277
|
+
}
|
|
278
|
+
return runs;
|
|
279
|
+
}
|
|
280
|
+
//#endregion
|
|
281
|
+
export { paragraphToRuns };
|