@stll/folio-core 0.11.0 → 0.13.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.d.ts +2 -1
- package/dist/ai-edits/apply.js +693 -63
- package/dist/ai-edits/block-identity.d.ts +4 -0
- package/dist/ai-edits/block-identity.js +9 -0
- package/dist/ai-edits/blockRange.d.ts +28 -1
- package/dist/ai-edits/blockRange.js +68 -2
- package/dist/ai-edits/clean-text.js +2 -1
- package/dist/ai-edits/headless.d.ts +4 -4
- package/dist/ai-edits/headless.js +9 -9
- package/dist/ai-edits/index.d.ts +2 -2
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/read.d.ts +7 -7
- package/dist/ai-edits/read.js +110 -3
- package/dist/ai-edits/snapshot.js +21 -3
- package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
- package/dist/ai-edits/table-cell-mutations.js +238 -0
- package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
- package/dist/ai-edits/table-mutation-plan.js +90 -0
- package/dist/ai-edits/table-row-column-mutations.d.ts +108 -0
- package/dist/ai-edits/table-row-column-mutations.js +300 -0
- package/dist/ai-edits/table-targets.d.ts +32 -0
- package/dist/ai-edits/table-targets.js +70 -0
- package/dist/ai-edits/types.d.ts +62 -1
- package/dist/ai-edits/word-diff.js +21 -0
- package/dist/compat/eigenpal.d.ts +3 -3
- package/dist/compat/eigenpal.js +3 -3
- package/dist/content-controls/mutateContentControls.js +1 -1
- package/dist/controller/activeEditorStory.d.ts +36 -0
- package/dist/controller/activeEditorStory.js +30 -0
- package/dist/controller/contentControlWidgetController.d.ts +55 -0
- package/dist/controller/contentControlWidgetController.js +141 -0
- package/dist/controller/fontReadiness.js +2 -0
- package/dist/controller/headerFooterEditorManager.js +2 -2
- package/dist/controller/hiddenEditorApi.js +2 -2
- package/dist/controller/hiddenEditorManager.d.ts +12 -1
- package/dist/controller/hiddenEditorManager.js +44 -12
- package/dist/controller/layoutPipeline.d.ts +2 -0
- package/dist/controller/layoutPipeline.js +17 -2
- package/dist/controller/noteEditorManager.d.ts +36 -0
- package/dist/controller/noteEditorManager.js +210 -0
- package/dist/document-operations.d.ts +43 -11
- package/dist/document-operations.js +186 -18
- package/dist/docx/blockContentParser.js +21 -7
- package/dist/docx/commentParser.js +6 -1
- package/dist/docx/commentRangeIntegrity.d.ts +6 -0
- package/dist/docx/commentRangeIntegrity.js +186 -0
- package/dist/docx/conformance.js +62 -1
- package/dist/docx/documentGrid.d.ts +8 -0
- package/dist/docx/documentGrid.js +8 -0
- package/dist/docx/drawingUtils.js +1 -1
- package/dist/docx/encryption/agileDecryption.js +12 -2
- package/dist/docx/encryption/compoundFile.js +6 -1
- package/dist/docx/encryption/encryptionInfo.d.ts +9 -1
- package/dist/docx/encryption/encryptionInfo.js +18 -2
- package/dist/docx/encryption/openEncryptedDocx.js +1 -1
- package/dist/docx/ensureParaIds.js +8 -7
- package/dist/docx/fieldParser.js +1 -1
- package/dist/docx/groupDrawingParser.js +10 -5
- package/dist/docx/hyperlinkParser.js +1 -1
- package/dist/docx/imageParser.js +10 -6
- package/dist/docx/metadataPrivacy.js +17 -3
- package/dist/docx/notePropertiesParser.js +1 -1
- package/dist/docx/numberingParser.js +1 -1
- package/dist/docx/paragraphParser.js +70 -61
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
- package/dist/docx/paragraphTraversal.js +1 -1
- package/dist/docx/parser.js +3 -3
- package/dist/docx/rezip.js +20 -9
- package/dist/docx/runParser.js +17 -6
- package/dist/docx/sdtProperties.js +1 -1
- package/dist/docx/sectionParser.js +18 -5
- package/dist/docx/selectiveSave.js +5 -1
- package/dist/docx/selectiveXmlPatch.d.ts +22 -1
- package/dist/docx/selectiveXmlPatch.js +61 -1
- package/dist/docx/serializer/blockSdtSerializer.js +3 -2
- package/dist/docx/serializer/commentSerializer.js +5 -6
- package/dist/docx/serializer/documentSerializer.js +2 -2
- package/dist/docx/serializer/headerFooterSerializer.js +2 -2
- package/dist/docx/serializer/noteSerializer.js +2 -2
- package/dist/docx/serializer/paragraphSerializer.js +23 -15
- package/dist/docx/serializer/runSerializer.js +25 -21
- package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -1
- package/dist/docx/serializer/stylesSerializer.js +1 -1
- package/dist/docx/serializer/tableSerializer.d.ts +5 -4
- package/dist/docx/serializer/tableSerializer.js +26 -20
- package/dist/docx/serializer/xmlUtils.d.ts +13 -1
- package/dist/docx/serializer/xmlUtils.js +27 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
- package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
- package/dist/docx/server/boundedArchive.d.ts +14 -3
- package/dist/docx/server/boundedArchive.js +56 -11
- package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
- package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
- package/dist/docx/server/extractDocxText.js +55 -8
- package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
- package/dist/docx/server/inspectDocxPackage.js +217 -0
- package/dist/docx/server/validateDocxConformance.d.ts +41 -0
- package/dist/docx/server/validateDocxConformance.js +336 -0
- package/dist/docx/settingsParser.js +26 -3
- package/dist/docx/shapeParser.js +1 -1
- package/dist/docx/styleParser.js +4 -2
- package/dist/docx/tableParser.d.ts +8 -1
- package/dist/docx/tableParser.js +31 -10
- package/dist/docx/textBoxParser.d.ts +3 -3
- package/dist/docx/textBoxParser.js +16 -12
- package/dist/docx/unzip.js +1 -0
- package/dist/docx/vmlImageParser.js +11 -3
- package/dist/docx/xmlParser.js +11 -1
- package/dist/docx/xmlSafety.d.ts +5 -0
- package/dist/docx/xmlSafety.js +9 -0
- package/dist/fields/resolveFieldValues.js +1 -3
- package/dist/fonts/embeddedFonts.d.ts +33 -5
- package/dist/fonts/embeddedFonts.js +37 -8
- package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
- package/dist/i18n/messages/catalogs.gen.js +17 -0
- package/dist/i18n/messages/messages.gen.d.ts +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
- package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +151 -20
- package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
- package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
- package/dist/layout-bridge/engine/clickToPosition.js +2 -2
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +58 -30
- package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
- package/dist/layout-engine/justificationCompatibility.js +8 -0
- package/dist/layout-engine/keep-together.js +11 -1
- package/dist/layout-engine/measure/cache.js +23 -5
- package/dist/layout-engine/measure/effectiveLineBreakPolicy.js +8 -2
- package/dist/layout-engine/measure/lineBreakProvider.d.ts +2 -2
- package/dist/layout-engine/measure/lineBreakProvider.js +56 -37
- package/dist/layout-engine/measure/measureBlocks.js +15 -4
- package/dist/layout-engine/measure/measureContainer.js +1 -1
- package/dist/layout-engine/measure/measureHelpers.d.ts +11 -2
- package/dist/layout-engine/measure/measureHelpers.js +15 -4
- package/dist/layout-engine/measure/measureParagraph.js +85 -25
- package/dist/layout-engine/measure/measureProvider.js +4 -3
- package/dist/layout-engine/measure/tableCellFlow.js +5 -2
- package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
- package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
- package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
- package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
- package/dist/layout-engine/paginator.js +5 -1
- package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
- package/dist/layout-engine/paragraphSpacing.js +107 -13
- package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
- package/dist/layout-engine/types.d.ts +48 -15
- package/dist/layout-painter/registry/modules/textBox.js +5 -1
- package/dist/layout-painter/renderImage.d.ts +12 -1
- package/dist/layout-painter/renderImage.js +21 -4
- package/dist/layout-painter/renderPage.d.ts +5 -2
- package/dist/layout-painter/renderPage.js +59 -14
- package/dist/layout-painter/renderParagraph.js +55 -15
- package/dist/layout-painter/renderTable.d.ts +5 -1
- package/dist/layout-painter/renderTable.js +7 -3
- package/dist/layout-painter/renderTextBox.d.ts +2 -1
- package/dist/layout-painter/renderTextBox.js +25 -14
- package/dist/layout-painter/renderWatermark.d.ts +1 -1
- package/dist/layout-painter/renderWatermark.js +2 -1
- package/dist/managers/DocumentLoaderManager.js +1 -1
- package/dist/markdown/fromMarkdown.js +1 -1
- package/dist/model.js +1 -1
- package/dist/prosemirror/attrs/index.d.ts +4 -2
- package/dist/prosemirror/attrs/index.js +175 -18
- package/dist/prosemirror/commands/comments.d.ts +79 -4
- package/dist/prosemirror/commands/comments.js +622 -13
- package/dist/prosemirror/commands/contentControls.js +1 -1
- package/dist/prosemirror/commands/hyperlink.js +15 -1
- package/dist/prosemirror/commands/image.js +7 -1
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/pageBreak.js +1 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
- package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
- package/dist/prosemirror/commentIdAllocator.js +13 -3
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +404 -62
- package/dist/prosemirror/conversion/index.js +1 -1
- package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
- package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
- package/dist/prosemirror/conversion/toProseDoc.js +364 -103
- package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
- package/dist/prosemirror/extensions/StarterKit.js +6 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +6 -2
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
- package/dist/prosemirror/extensions/features/ImagePasteExtension.js +10 -2
- package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
- package/dist/prosemirror/extensions/features/pasteCleanup.js +15 -2
- package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +30 -4
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +70 -11
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +14 -6
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
- package/dist/prosemirror/index.d.ts +1 -1
- package/dist/prosemirror/index.js +1 -1
- package/dist/prosemirror/plugins/contentControlWidgets.d.ts +36 -10
- package/dist/prosemirror/plugins/contentControlWidgets.js +128 -94
- package/dist/prosemirror/plugins/revisionIds.d.ts +23 -0
- package/dist/prosemirror/plugins/revisionIds.js +57 -0
- package/dist/prosemirror/plugins/selectionTracker.js +1 -0
- package/dist/prosemirror/plugins/suggestionMode.js +5 -4
- package/dist/prosemirror/runFormattingMarkNames.d.ts +14 -0
- package/dist/prosemirror/runFormattingMarkNames.js +40 -0
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/marks.d.ts +30 -3
- package/dist/prosemirror/schema/marks.js +15 -0
- package/dist/prosemirror/schema/nodes.d.ts +111 -6
- package/dist/prosemirror/selectionState.js +1 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
- package/dist/prosemirror/tableCellMergeRevision.js +22 -0
- package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
- package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
- package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
- package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
- package/dist/prosemirror/validation.js +9 -1
- package/dist/render-dom/RemoteSelectionOverlay.js +2 -2
- package/dist/server.d.ts +7 -3
- package/dist/server.js +7 -3
- package/dist/utils/clipboard.d.ts +10 -1
- package/dist/utils/clipboard.js +33 -6
- package/dist/utils/colorResolver.d.ts +8 -1
- package/dist/utils/colorResolver.js +35 -5
- package/dist/utils/fontFamilyMerge.js +9 -11
- package/dist/utils/fontLoader.js +3 -2
- package/dist/utils/fontResolver.d.ts +2 -1
- package/dist/utils/fontResolver.js +31 -7
- package/dist/utils/fontWeights.d.ts +1 -1
- package/dist/utils/fontWeights.js +1 -1
- package/dist/utils/hexId.d.ts +11 -1
- package/dist/utils/hexId.js +11 -1
- package/dist/utils/paragraphFormattingMerge.js +1 -0
- package/dist/utils/sanitizeImageSrc.d.ts +21 -0
- package/dist/utils/sanitizeImageSrc.js +30 -0
- package/dist/utils/stripXmlDeclarations.d.ts +11 -0
- package/dist/utils/stripXmlDeclarations.js +35 -0
- package/dist/version-comparison.d.ts +22 -2
- package/dist/version-comparison.js +41 -12
- package/dist/watermark/index.d.ts +11 -1
- package/dist/watermark/index.js +22 -1
- package/package.json +3 -2
|
@@ -71,7 +71,8 @@ declare const getDefaultPageFontFamily: () => string;
|
|
|
71
71
|
* A single footnote item ready for rendering at page bottom.
|
|
72
72
|
*/
|
|
73
73
|
type FootnoteRenderItem = {
|
|
74
|
-
/** Display number (e.g. "1", "2") */
|
|
74
|
+
/** Stable story id used by editable-note surfaces. */noteId?: number; /** Display number (e.g. "1", "2") */
|
|
75
|
+
displayNumber: string; /** Plain text content */
|
|
75
76
|
text?: string; /** Pre-measured structured footnote content. */
|
|
76
77
|
content?: Pick<FootnoteContent, "blocks" | "measures" | "height">;
|
|
77
78
|
};
|
|
@@ -87,7 +88,9 @@ type RenderPageOptions = {
|
|
|
87
88
|
pageClassName?: string; /** Show page borders (for debugging) */
|
|
88
89
|
showBorders?: boolean; /** Background color for pages */
|
|
89
90
|
backgroundColor?: string; /** Drop shadow on pages */
|
|
90
|
-
showShadow?: boolean; /**
|
|
91
|
+
showShadow?: boolean; /** Show the effective body-content boundary for each page. */
|
|
92
|
+
showMarginGuides?: boolean; /** CSS color used for margin guides. */
|
|
93
|
+
marginGuideColor?: string; /** Header content to render (used for all pages, or pages 2+ when titlePg is set). */
|
|
91
94
|
headerContent?: HeaderFooterContent; /** Footer content to render (used for all pages, or pages 2+ when titlePg is set). */
|
|
92
95
|
footerContent?: HeaderFooterContent; /** Header content by part relationship id, used for section-scoped rendering. */
|
|
93
96
|
headerContentByRId?: ReadonlyMap<string, HeaderFooterContent>; /** Footer content by part relationship id, used for section-scoped rendering. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { eighthsToPixels, pointsToPixels } from "../utils/units.js";
|
|
2
2
|
import { resolveFontFamily } from "../utils/fontResolver.js";
|
|
3
3
|
import { borderToStyle } from "../utils/formatToStyle.js";
|
|
4
|
+
import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
4
5
|
import { floatingTextBoxReservesBand, floatingTextBoxWrapsText, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun } from "../layout-engine/types.js";
|
|
5
6
|
import { rectsToFloatingZones } from "../layout-engine/measure/floatingZones.js";
|
|
6
7
|
import { measureParagraph } from "../layout-engine/measure/measureParagraph.js";
|
|
@@ -10,7 +11,7 @@ import { renderFragment } from "./renderFragment.js";
|
|
|
10
11
|
import { applyImageVisualAttrs, hasImageVisualAttrs, renderImageFragment } from "./renderImage.js";
|
|
11
12
|
import { renderParagraphFragment } from "./renderParagraph.js";
|
|
12
13
|
import { renderTextBoxFragment } from "./renderTextBox.js";
|
|
13
|
-
import { renderTableFragment } from "./renderTable.js";
|
|
14
|
+
import { renderNestedTable, renderTableFragment } from "./renderTable.js";
|
|
14
15
|
import { renderWatermarkLayer } from "./renderWatermark.js";
|
|
15
16
|
import { panic } from "better-result";
|
|
16
17
|
//#region src/layout-painter/renderPage.ts
|
|
@@ -35,6 +36,7 @@ const PAGE_CLASS_NAMES = {
|
|
|
35
36
|
footer: "layout-page-footer"
|
|
36
37
|
};
|
|
37
38
|
const HEADER_FOOTER_RULE_CLIP_MARGIN = pointsToPixels(1.5);
|
|
39
|
+
const DEFAULT_MARGIN_GUIDE_COLOR = "#c0c0c0";
|
|
38
40
|
const getDefaultPageFontFamily = () => resolveFontFamily("Calibri").cssFallback;
|
|
39
41
|
/**
|
|
40
42
|
* Apply page styles to an element
|
|
@@ -127,6 +129,26 @@ function renderPageBorderOverlay(page, options, doc) {
|
|
|
127
129
|
applyPageBorderSide(overlay, pb.right, "Right", options.theme);
|
|
128
130
|
return overlay;
|
|
129
131
|
}
|
|
132
|
+
function renderPageMarginGuideOverlay(page, options, doc) {
|
|
133
|
+
if (options.showMarginGuides !== true) return null;
|
|
134
|
+
const overlay = doc.createElement("div");
|
|
135
|
+
overlay.className = "layout-page-margin-guide";
|
|
136
|
+
overlay.style.position = "absolute";
|
|
137
|
+
overlay.style.top = `${page.margins.top}px`;
|
|
138
|
+
overlay.style.right = `${page.margins.right}px`;
|
|
139
|
+
overlay.style.bottom = `${page.margins.bottom}px`;
|
|
140
|
+
overlay.style.left = `${page.margins.left}px`;
|
|
141
|
+
overlay.style.boxSizing = "border-box";
|
|
142
|
+
overlay.style.border = `1px dashed ${options.marginGuideColor ?? DEFAULT_MARGIN_GUIDE_COLOR}`;
|
|
143
|
+
overlay.style.pointerEvents = "none";
|
|
144
|
+
overlay.style.zIndex = "19";
|
|
145
|
+
return overlay;
|
|
146
|
+
}
|
|
147
|
+
function syncPageMarginGuideOverlay(pageEl, page, options, doc) {
|
|
148
|
+
for (const stale of Array.from(pageEl.querySelectorAll(":scope > .layout-page-margin-guide"))) stale.remove();
|
|
149
|
+
const overlay = renderPageMarginGuideOverlay(page, options, doc);
|
|
150
|
+
if (overlay) pageEl.append(overlay);
|
|
151
|
+
}
|
|
130
152
|
/**
|
|
131
153
|
* Refresh the page-border overlay on an existing page shell so incremental
|
|
132
154
|
* rerenders pick up changes to size, margins, page number, or pageBorders
|
|
@@ -359,7 +381,7 @@ function renderFloatingImagesLayer(floatingImages, doc, layerMode = "front") {
|
|
|
359
381
|
if (floatImg.pmStart !== void 0) container.dataset["pmStart"] = String(floatImg.pmStart);
|
|
360
382
|
if (floatImg.pmEnd !== void 0) container.dataset["pmEnd"] = String(floatImg.pmEnd);
|
|
361
383
|
const img = doc.createElement("img");
|
|
362
|
-
img
|
|
384
|
+
applySanitizedImageSrc(img, floatImg.src);
|
|
363
385
|
img.style.width = `${floatImg.width}px`;
|
|
364
386
|
img.style.height = `${floatImg.height}px`;
|
|
365
387
|
img.style.display = "block";
|
|
@@ -470,7 +492,10 @@ function renderHeaderFooterContent(content, context, options, layout) {
|
|
|
470
492
|
height: measure.height,
|
|
471
493
|
...block.pmStart !== void 0 ? { pmStart: block.pmStart } : {},
|
|
472
494
|
...block.pmEnd !== void 0 ? { pmEnd: block.pmEnd } : {}
|
|
473
|
-
}, block, measure, hfContext, {
|
|
495
|
+
}, block, measure, hfContext, {
|
|
496
|
+
document: doc,
|
|
497
|
+
renderTable: renderNestedTable
|
|
498
|
+
});
|
|
474
499
|
const textBoxTop = block.position ? resolveHeaderFooterFloatTop({
|
|
475
500
|
height: measure.height,
|
|
476
501
|
paragraphY: cursorY,
|
|
@@ -485,7 +510,7 @@ function renderHeaderFooterContent(content, context, options, layout) {
|
|
|
485
510
|
}
|
|
486
511
|
for (const floatImg of floatingImages) {
|
|
487
512
|
const img = doc.createElement("img");
|
|
488
|
-
img
|
|
513
|
+
applySanitizedImageSrc(img, floatImg.src);
|
|
489
514
|
img.width = floatImg.width;
|
|
490
515
|
img.height = floatImg.height;
|
|
491
516
|
if (floatImg.alt) img.alt = floatImg.alt;
|
|
@@ -546,6 +571,10 @@ function renderFootnoteArea(footnotes, contentWidth, doc, context) {
|
|
|
546
571
|
container.append(separator);
|
|
547
572
|
for (const fn of footnotes) {
|
|
548
573
|
const fnEl = doc.createElement("div");
|
|
574
|
+
if (fn.noteId !== void 0) {
|
|
575
|
+
fnEl.dataset["noteKind"] = "footnote";
|
|
576
|
+
fnEl.dataset["noteId"] = String(fn.noteId);
|
|
577
|
+
}
|
|
549
578
|
fnEl.style.marginBottom = `0px`;
|
|
550
579
|
fnEl.style.color = "var(--doc-canvas-text, #000)";
|
|
551
580
|
if (fn.content) {
|
|
@@ -642,7 +671,10 @@ function renderFootnoteBlock(block, measure, contentWidth, y, context, doc) {
|
|
|
642
671
|
y,
|
|
643
672
|
width: measure.width,
|
|
644
673
|
height: measure.height
|
|
645
|
-
}, renderBlock, measure, context, {
|
|
674
|
+
}, renderBlock, measure, context, {
|
|
675
|
+
document: doc,
|
|
676
|
+
renderTable: renderNestedTable
|
|
677
|
+
});
|
|
646
678
|
positionFootnoteBlock(element, y, measure.width, measure.height);
|
|
647
679
|
return element;
|
|
648
680
|
}
|
|
@@ -651,13 +683,7 @@ function renderFootnoteBlock(block, measure, contentWidth, y, context, doc) {
|
|
|
651
683
|
function stripFootnotePmAnchors(block) {
|
|
652
684
|
switch (block.kind) {
|
|
653
685
|
case "paragraph": return stripFootnoteParagraphPmAnchors(block);
|
|
654
|
-
case "table":
|
|
655
|
-
const { pmStart: _pmStart, pmEnd: _pmEnd, ...table } = block;
|
|
656
|
-
return {
|
|
657
|
-
...table,
|
|
658
|
-
rows: table.rows.map(stripFootnoteTableRowPmAnchors)
|
|
659
|
-
};
|
|
660
|
-
}
|
|
686
|
+
case "table": return stripFootnoteTablePmAnchors(block);
|
|
661
687
|
case "image": {
|
|
662
688
|
const { pmStart: _pmStart, pmEnd: _pmEnd, ...image } = block;
|
|
663
689
|
return image;
|
|
@@ -666,7 +692,7 @@ function stripFootnotePmAnchors(block) {
|
|
|
666
692
|
const { pmStart: _pmStart, pmEnd: _pmEnd, ...textBox } = block;
|
|
667
693
|
return {
|
|
668
694
|
...textBox,
|
|
669
|
-
content: textBox.content.map(stripFootnoteParagraphPmAnchors)
|
|
695
|
+
content: textBox.content.map((contentBlock) => contentBlock.kind === "table" ? stripFootnoteTablePmAnchors(contentBlock) : stripFootnoteParagraphPmAnchors(contentBlock))
|
|
670
696
|
};
|
|
671
697
|
}
|
|
672
698
|
case "pageBreak":
|
|
@@ -678,6 +704,13 @@ function stripFootnotePmAnchors(block) {
|
|
|
678
704
|
default: return block;
|
|
679
705
|
}
|
|
680
706
|
}
|
|
707
|
+
function stripFootnoteTablePmAnchors(block) {
|
|
708
|
+
const { pmStart: _pmStart, pmEnd: _pmEnd, ...table } = block;
|
|
709
|
+
return {
|
|
710
|
+
...table,
|
|
711
|
+
rows: table.rows.map(stripFootnoteTableRowPmAnchors)
|
|
712
|
+
};
|
|
713
|
+
}
|
|
681
714
|
function stripFootnoteTableRowPmAnchors(row) {
|
|
682
715
|
return {
|
|
683
716
|
...row,
|
|
@@ -931,7 +964,10 @@ function renderPage(page, context, options = {}) {
|
|
|
931
964
|
fragmentEl = renderImageFragment(fragment, blockData.block, blockData.measure, fragmentContext, { document: doc });
|
|
932
965
|
prevParagraphBorders = void 0;
|
|
933
966
|
} else if (fragment.kind === "textBox" && blockData?.block.kind === "textBox" && blockData.measure.kind === "textBox") {
|
|
934
|
-
fragmentEl = renderTextBoxFragment(fragment, blockData.block, blockData.measure, fragmentContext, {
|
|
967
|
+
fragmentEl = renderTextBoxFragment(fragment, blockData.block, blockData.measure, fragmentContext, {
|
|
968
|
+
document: doc,
|
|
969
|
+
renderTable: renderNestedTable
|
|
970
|
+
});
|
|
935
971
|
prevParagraphBorders = void 0;
|
|
936
972
|
} else {
|
|
937
973
|
fragmentEl = renderFragment(fragment, fragmentContext, { document: doc });
|
|
@@ -1074,6 +1110,8 @@ function renderPage(page, context, options = {}) {
|
|
|
1074
1110
|
moveBehindHeaderFooterElementsToPage(footerEl, pageEl, footerNaturalTop, page.margins.left);
|
|
1075
1111
|
}
|
|
1076
1112
|
if (pageBorderEl && options.pageBorders?.zOrder !== "back") pageEl.append(pageBorderEl);
|
|
1113
|
+
const marginGuideEl = renderPageMarginGuideOverlay(page, options, doc);
|
|
1114
|
+
if (marginGuideEl) pageEl.append(marginGuideEl);
|
|
1077
1115
|
return pageEl;
|
|
1078
1116
|
}
|
|
1079
1117
|
function moveBehindHeaderFooterElementsToPage(slotEl, pageEl, contentTop, contentLeft) {
|
|
@@ -1265,6 +1303,7 @@ function collectContentFingerprint(block, parts) {
|
|
|
1265
1303
|
}
|
|
1266
1304
|
function runContentKey(run) {
|
|
1267
1305
|
if (run.kind === "lineBreak") return "lb";
|
|
1306
|
+
if (run.kind === "renderedPageBreak") return "rpb";
|
|
1268
1307
|
if (run.kind === "image") return `img:${run.src}|${run.width}x${run.height}${run.transform ? `|tr:${run.transform}` : ""}`;
|
|
1269
1308
|
const parts = [run.kind];
|
|
1270
1309
|
if (run.kind === "text") {
|
|
@@ -1324,6 +1363,7 @@ function computeOptionsHash(options) {
|
|
|
1324
1363
|
if (options.titlePg) parts.push("titlePg");
|
|
1325
1364
|
if (options.theme) parts.push(`thm:${options.theme.name ?? "default"}`);
|
|
1326
1365
|
if (options.pageBorders) parts.push(`pb:${JSON.stringify(options.pageBorders)}`);
|
|
1366
|
+
if (options.showMarginGuides === true) parts.push(`mg:${options.marginGuideColor ?? DEFAULT_MARGIN_GUIDE_COLOR}`);
|
|
1327
1367
|
if (options.headerDistance !== void 0) parts.push(`hd:${options.headerDistance}`);
|
|
1328
1368
|
if (options.footerDistance !== void 0) parts.push(`fd:${options.footerDistance}`);
|
|
1329
1369
|
if (options.watermark) parts.push(`wm:${JSON.stringify(options.watermark)}`);
|
|
@@ -1412,6 +1452,7 @@ function renderPages(pages, container, options = {}) {
|
|
|
1412
1452
|
prev.renderFingerprint = null;
|
|
1413
1453
|
applyPageStyles(prev.element, page.size.w, page.size.h, options);
|
|
1414
1454
|
syncPageBorderOverlay(prev.element, page, options, options.document ?? document);
|
|
1455
|
+
syncPageMarginGuideOverlay(prev.element, page, options, options.document ?? document);
|
|
1415
1456
|
prev.element.dataset["pageNumber"] = String(page.number);
|
|
1416
1457
|
continue;
|
|
1417
1458
|
}
|
|
@@ -1424,6 +1465,7 @@ function renderPages(pages, container, options = {}) {
|
|
|
1424
1465
|
populatePageShell(shell, prevDataMap, totalPages, options);
|
|
1425
1466
|
applyPageStyles(shell, page.size.w, page.size.h, options);
|
|
1426
1467
|
syncPageBorderOverlay(shell, page, options, options.document ?? document);
|
|
1468
|
+
syncPageMarginGuideOverlay(shell, page, options, options.document ?? document);
|
|
1427
1469
|
shell.dataset["pageNumber"] = String(page.number);
|
|
1428
1470
|
continue;
|
|
1429
1471
|
}
|
|
@@ -1433,6 +1475,7 @@ function renderPages(pages, container, options = {}) {
|
|
|
1433
1475
|
prev.renderFingerprint = newRenderFp;
|
|
1434
1476
|
applyPageStyles(shell, page.size.w, page.size.h, options);
|
|
1435
1477
|
syncPageBorderOverlay(shell, page, options, options.document ?? document);
|
|
1478
|
+
syncPageMarginGuideOverlay(shell, page, options, options.document ?? document);
|
|
1436
1479
|
shell.dataset["pageNumber"] = String(page.number);
|
|
1437
1480
|
}
|
|
1438
1481
|
if (pages.length > prevShells.length) {
|
|
@@ -1445,6 +1488,7 @@ function renderPages(pages, container, options = {}) {
|
|
|
1445
1488
|
pageEl.dataset["pageIndex"] = String(i);
|
|
1446
1489
|
applyPageStyles(pageEl, page.size.w, page.size.h, options);
|
|
1447
1490
|
syncPageBorderOverlay(pageEl, page, options, doc);
|
|
1491
|
+
syncPageMarginGuideOverlay(pageEl, page, options, doc);
|
|
1448
1492
|
container.append(pageEl);
|
|
1449
1493
|
prevShells.push({
|
|
1450
1494
|
element: pageEl,
|
|
@@ -1505,6 +1549,7 @@ function renderPages(pages, container, options = {}) {
|
|
|
1505
1549
|
pageEl.dataset["pageIndex"] = String(i);
|
|
1506
1550
|
applyPageStyles(pageEl, page.size.w, page.size.h, options);
|
|
1507
1551
|
syncPageBorderOverlay(pageEl, page, options, doc);
|
|
1552
|
+
syncPageMarginGuideOverlay(pageEl, page, options, doc);
|
|
1508
1553
|
}
|
|
1509
1554
|
container.insertBefore(pageEl, overlayBefore);
|
|
1510
1555
|
pageShells.push(pageEl);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { parseXmlDocument } from "../docx/xmlParser.js";
|
|
2
2
|
import { resolveFontFamily } from "../utils/fontResolver.js";
|
|
3
3
|
import { detectBaseDirection } from "../utils/baseDirection.js";
|
|
4
|
+
import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
4
5
|
import { AUTHOR_COLORS, getAuthorColorIdx } from "../utils/authorColors.js";
|
|
6
|
+
import { FONT_KERNING_MODE, countCompressibleSpaces, getFontKerningMode, getRunFontKerningMode, toPaintedText } from "../layout-engine/measure/textMeasurementPolicy.js";
|
|
5
7
|
import "../utils/fontWeights.js";
|
|
6
|
-
import { FONT_KERNING_MODE, countCompressibleSpaces, getFontKerningMode, getRunFontKerningMode } from "../layout-engine/measure/textMeasurementPolicy.js";
|
|
7
8
|
import "../layout-engine/measure/measureHelpers.js";
|
|
8
9
|
import { calculateTabWidth } from "../prosemirror/utils/tabCalculator.js";
|
|
9
10
|
import { inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox } from "../utils/rotationBoundingBox.js";
|
|
@@ -12,7 +13,7 @@ import { isFloatingImageRun } from "../layout-engine/types.js";
|
|
|
12
13
|
import { getListMarkerInlineWidth, getListMarkerVisualOffset } from "../layout-engine/measure/listMarkerWidth.js";
|
|
13
14
|
import { resolveImageLineAlign } from "./renderUtils.js";
|
|
14
15
|
import { applySdtDataAttrs } from "./sdtBoundary.js";
|
|
15
|
-
import { applyImageVisualAttrs, hasImageVisualAttrs, wrapImageWithCrop } from "./renderImage.js";
|
|
16
|
+
import { applyImageBorder, applyImageVisualAttrs, hasImageCrop, hasImageVisualAttrs, wrapImageWithCrop } from "./renderImage.js";
|
|
16
17
|
import { ommlToMathml } from "../docx/mathToMathml.js";
|
|
17
18
|
import { evaluateFieldInstruction } from "../fields/evaluateField.js";
|
|
18
19
|
import { borderStrokeToCss, resolveParagraphBorderHorizontalOutsets } from "./borderStroke.js";
|
|
@@ -75,6 +76,9 @@ function isMathRun(run) {
|
|
|
75
76
|
const AUTOMATIC_TEXT_COLOR_VALUES = /* @__PURE__ */ new Set(["auto", "windowtext"]);
|
|
76
77
|
const DEFAULT_BLACK_TEXT_COLOR_VALUES = /* @__PURE__ */ new Set(["000000", "000"]);
|
|
77
78
|
const DOCX_SUPERSCRIPT_SCALE = .75;
|
|
79
|
+
const SUGGESTION_COLOR_CSS = "var(--suggestion-color, #6d3bd6)";
|
|
80
|
+
const SUGGESTION_TINT_CSS = "var(--suggestion-bg, color-mix(in oklch, #6d3bd6 12%, transparent))";
|
|
81
|
+
const SUGGESTION_TINT_LAYER_CSS = `linear-gradient(${SUGGESTION_TINT_CSS}, ${SUGGESTION_TINT_CSS})`;
|
|
78
82
|
function normalizeTextColorValue(color) {
|
|
79
83
|
return color.trim().toLowerCase().replace(/^#/u, "");
|
|
80
84
|
}
|
|
@@ -113,7 +117,7 @@ function getRaisedRunFontSize(run) {
|
|
|
113
117
|
function applyRunStyles(element, run) {
|
|
114
118
|
if (run.fontFamily) element.style.fontFamily = resolveFontFamily(run.fontFamily).cssFallback;
|
|
115
119
|
if (run.fontSize) element.style.fontSize = `${fontSizePtToPx(run.fontSize)}px`;
|
|
116
|
-
if (run.bold) element.style.fontWeight = "
|
|
120
|
+
if (run.bold) element.style.fontWeight = "700";
|
|
117
121
|
if (run.italic) element.style.fontStyle = "italic";
|
|
118
122
|
let hasExplicitTextColor = false;
|
|
119
123
|
const textColor = getRenderableTextColor(run);
|
|
@@ -192,13 +196,21 @@ function applyRunStyles(element, run) {
|
|
|
192
196
|
if (run.isInsertion) {
|
|
193
197
|
const authorIdx = getAuthorColorIdx(run.changeAuthor ?? "");
|
|
194
198
|
const authorColor = AUTHOR_COLORS[authorIdx];
|
|
195
|
-
|
|
199
|
+
const strokeColor = run.isSuggestion ? SUGGESTION_COLOR_CSS : authorColor;
|
|
200
|
+
element.style.color = strokeColor;
|
|
196
201
|
if (!decorations.includes("underline")) decorations.push("underline");
|
|
197
|
-
element.style.textDecorationColor =
|
|
202
|
+
element.style.textDecorationColor = strokeColor;
|
|
198
203
|
element.classList.add("docx-insertion");
|
|
199
204
|
element.dataset["tcAuthorIdx"] = String(authorIdx);
|
|
205
|
+
if (run.isSuggestion) {
|
|
206
|
+
element.classList.add("docx-insertion--suggested");
|
|
207
|
+
element.style.textDecorationStyle = "dotted";
|
|
208
|
+
element.style.backgroundImage = SUGGESTION_TINT_LAYER_CSS;
|
|
209
|
+
element.dataset["provenance"] = "suggested";
|
|
210
|
+
if (run.suggestionId) element.dataset["suggestionId"] = run.suggestionId;
|
|
211
|
+
}
|
|
200
212
|
const insertionParts = [run.changeAuthor, run.changeDate ? new Date(run.changeDate).toLocaleDateString() : ""].filter(Boolean);
|
|
201
|
-
if (insertionParts.length > 0) element.title =
|
|
213
|
+
if (insertionParts.length > 0) element.title = `${run.isSuggestion ? "Suggested" : "Inserted"}: ${insertionParts.join(", ")}`;
|
|
202
214
|
if (run.changeAuthor) element.dataset["changeAuthor"] = run.changeAuthor;
|
|
203
215
|
if (run.changeDate) element.dataset["changeDate"] = run.changeDate;
|
|
204
216
|
if (run.changeRevisionId !== void 0) element.dataset["revisionId"] = String(run.changeRevisionId);
|
|
@@ -206,13 +218,21 @@ function applyRunStyles(element, run) {
|
|
|
206
218
|
if (run.isDeletion) {
|
|
207
219
|
const authorIdx = getAuthorColorIdx(run.changeAuthor ?? "");
|
|
208
220
|
const authorColor = AUTHOR_COLORS[authorIdx];
|
|
209
|
-
|
|
221
|
+
const strokeColor = run.isSuggestion ? SUGGESTION_COLOR_CSS : authorColor;
|
|
222
|
+
element.style.color = strokeColor;
|
|
210
223
|
if (!decorations.includes("line-through")) decorations.push("line-through");
|
|
211
|
-
element.style.textDecorationColor =
|
|
224
|
+
element.style.textDecorationColor = strokeColor;
|
|
212
225
|
element.classList.add("docx-deletion");
|
|
213
226
|
element.dataset["tcAuthorIdx"] = String(authorIdx);
|
|
227
|
+
if (run.isSuggestion) {
|
|
228
|
+
element.classList.add("docx-deletion--suggested");
|
|
229
|
+
element.style.textDecorationStyle = "dotted";
|
|
230
|
+
element.style.backgroundImage = SUGGESTION_TINT_LAYER_CSS;
|
|
231
|
+
element.dataset["provenance"] = "suggested";
|
|
232
|
+
if (run.suggestionId) element.dataset["suggestionId"] = run.suggestionId;
|
|
233
|
+
}
|
|
214
234
|
const deletionParts = [run.changeAuthor, run.changeDate ? new Date(run.changeDate).toLocaleDateString() : ""].filter(Boolean);
|
|
215
|
-
if (deletionParts.length > 0) element.title =
|
|
235
|
+
if (deletionParts.length > 0) element.title = `${run.isSuggestion ? "Suggested deletion" : "Deleted"}: ${deletionParts.join(", ")}`;
|
|
216
236
|
if (run.changeAuthor) element.dataset["changeAuthor"] = run.changeAuthor;
|
|
217
237
|
if (run.changeDate) element.dataset["changeDate"] = run.changeDate;
|
|
218
238
|
if (run.changeRevisionId !== void 0) element.dataset["revisionId"] = String(run.changeRevisionId);
|
|
@@ -246,12 +266,20 @@ function applyPmPositions(element, pmStart, pmEnd) {
|
|
|
246
266
|
function renderTextRun(run, doc) {
|
|
247
267
|
const span = doc.createElement("span");
|
|
248
268
|
span.className = `${PARAGRAPH_CLASS_NAMES.run} ${PARAGRAPH_CLASS_NAMES.text}`;
|
|
269
|
+
if (run.footnoteRefId !== void 0) {
|
|
270
|
+
span.dataset["noteKind"] = "footnote";
|
|
271
|
+
span.dataset["noteId"] = String(run.footnoteRefId);
|
|
272
|
+
} else if (run.endnoteRefId !== void 0) {
|
|
273
|
+
span.dataset["noteKind"] = "endnote";
|
|
274
|
+
span.dataset["noteId"] = String(run.endnoteRefId);
|
|
275
|
+
}
|
|
249
276
|
if (run.templatePreview) {
|
|
250
277
|
span.classList.add("folio-template-preview-run");
|
|
251
278
|
if (run.templatePreview === "highlighted") span.classList.add("folio-template-preview-run--highlighted");
|
|
252
279
|
}
|
|
253
280
|
applyRunStyles(span, run);
|
|
254
281
|
applyPmPositions(span, run.pmStart, run.pmEnd);
|
|
282
|
+
const paintedText = toPaintedText(run.text);
|
|
255
283
|
if (run.hyperlink) {
|
|
256
284
|
const anchor = doc.createElement("a");
|
|
257
285
|
anchor.href = run.hyperlink.href;
|
|
@@ -260,7 +288,7 @@ function renderTextRun(run, doc) {
|
|
|
260
288
|
anchor.rel = "noopener noreferrer";
|
|
261
289
|
}
|
|
262
290
|
if (run.hyperlink.tooltip) anchor.title = run.hyperlink.tooltip;
|
|
263
|
-
anchor.textContent =
|
|
291
|
+
anchor.textContent = paintedText;
|
|
264
292
|
if (!run.hyperlink.noDefaultStyle) {
|
|
265
293
|
const hyperlinkColor = getHyperlinkTextColor(run, span.style.color);
|
|
266
294
|
anchor.style.color = hyperlinkColor;
|
|
@@ -270,7 +298,7 @@ function renderTextRun(run, doc) {
|
|
|
270
298
|
span.style.setProperty("--doc-run-color", hyperlinkColor);
|
|
271
299
|
}
|
|
272
300
|
span.append(anchor);
|
|
273
|
-
} else span.textContent =
|
|
301
|
+
} else span.textContent = paintedText;
|
|
274
302
|
applyWhitespaceUnderline(span, run);
|
|
275
303
|
return span;
|
|
276
304
|
}
|
|
@@ -360,7 +388,7 @@ function getLeaderChar(leader) {
|
|
|
360
388
|
function renderInlineImageRun(run, doc) {
|
|
361
389
|
const img = doc.createElement("img");
|
|
362
390
|
img.className = `${PARAGRAPH_CLASS_NAMES.run} ${PARAGRAPH_CLASS_NAMES.image}`;
|
|
363
|
-
img
|
|
391
|
+
applySanitizedImageSrc(img, run.src);
|
|
364
392
|
img.width = run.width;
|
|
365
393
|
img.height = run.height;
|
|
366
394
|
img.style.width = `${run.width}px`;
|
|
@@ -370,6 +398,7 @@ function renderInlineImageRun(run, doc) {
|
|
|
370
398
|
img.style.transform = run.transform;
|
|
371
399
|
img.style.transformOrigin = "center center";
|
|
372
400
|
}
|
|
401
|
+
if (!hasImageCrop(run)) applyImageBorder(img, run);
|
|
373
402
|
const rotation = parseRotationDegrees(run.transform);
|
|
374
403
|
if (rotation !== 0) {
|
|
375
404
|
const bbox = rotatedBoundingBox(run.width, run.height, rotation);
|
|
@@ -399,6 +428,7 @@ function renderInlineImageRun(run, doc) {
|
|
|
399
428
|
wrapper.style.verticalAlign = "middle";
|
|
400
429
|
if (run.distTop) wrapper.style.marginTop = `${run.distTop}px`;
|
|
401
430
|
if (run.distBottom) wrapper.style.marginBottom = `${run.distBottom}px`;
|
|
431
|
+
if (hasImageCrop(run)) applyImageBorder(wrapper, run);
|
|
402
432
|
applyPmPositions(wrapper, run.pmStart, run.pmEnd);
|
|
403
433
|
return wrapper;
|
|
404
434
|
}
|
|
@@ -426,7 +456,7 @@ function renderBlockImage(run, doc) {
|
|
|
426
456
|
container.style.marginTop = `${run.distTop ?? 6}px`;
|
|
427
457
|
container.style.marginBottom = `${run.distBottom ?? 6}px`;
|
|
428
458
|
const img = doc.createElement("img");
|
|
429
|
-
img
|
|
459
|
+
applySanitizedImageSrc(img, run.src);
|
|
430
460
|
img.width = run.width;
|
|
431
461
|
img.height = run.height;
|
|
432
462
|
if (run.alt) img.alt = run.alt;
|
|
@@ -434,6 +464,7 @@ function renderBlockImage(run, doc) {
|
|
|
434
464
|
img.style.transform = run.transform;
|
|
435
465
|
img.style.transformOrigin = "center center";
|
|
436
466
|
}
|
|
467
|
+
if (!hasImageCrop(run)) applyImageBorder(img, run);
|
|
437
468
|
const rotation = parseRotationDegrees(run.transform);
|
|
438
469
|
if (rotation !== 0) {
|
|
439
470
|
const bbox = rotatedBoundingBox(run.width, run.height, rotation);
|
|
@@ -455,6 +486,7 @@ function renderBlockImage(run, doc) {
|
|
|
455
486
|
widthPx: run.width,
|
|
456
487
|
heightPx: run.height
|
|
457
488
|
});
|
|
489
|
+
if (hasImageCrop(run)) applyImageBorder(wrapper, run);
|
|
458
490
|
applyPmPositions(container, run.pmStart, run.pmEnd);
|
|
459
491
|
container.append(wrapper);
|
|
460
492
|
return container;
|
|
@@ -642,6 +674,14 @@ function renderRun(run, doc, context) {
|
|
|
642
674
|
if (isLineBreakRun(run)) return renderLineBreakRun(run, doc);
|
|
643
675
|
if (isFieldRun(run) && context) return renderFieldRun(run, doc, context);
|
|
644
676
|
if (isMathRun(run)) return renderMathRun(run, doc);
|
|
677
|
+
if (run.kind === "renderedPageBreak") {
|
|
678
|
+
const span = doc.createElement("span");
|
|
679
|
+
span.className = PARAGRAPH_CLASS_NAMES.run;
|
|
680
|
+
span.style.display = "none";
|
|
681
|
+
span.dataset["docxRenderedPageBreak"] = "true";
|
|
682
|
+
applyPmPositions(span, run.pmStart, run.pmEnd);
|
|
683
|
+
return span;
|
|
684
|
+
}
|
|
645
685
|
const span = doc.createElement("span");
|
|
646
686
|
span.className = PARAGRAPH_CLASS_NAMES.run;
|
|
647
687
|
return span;
|
|
@@ -913,7 +953,7 @@ function createTextMeasurer(doc) {
|
|
|
913
953
|
const fontPrefixParts = [];
|
|
914
954
|
if (style.italic) fontPrefixParts.push("italic");
|
|
915
955
|
if (style.smallCaps) fontPrefixParts.push("small-caps");
|
|
916
|
-
if (style.bold) fontPrefixParts.push("
|
|
956
|
+
if (style.bold) fontPrefixParts.push("700");
|
|
917
957
|
fontPrefixParts.push(`${fontSizePx}px`);
|
|
918
958
|
const fontPrefix = fontPrefixParts.join(" ");
|
|
919
959
|
if (style.eastAsiaFontFamily && !style.letterSpacing && hasCjk(text)) {
|
|
@@ -1391,7 +1431,7 @@ function renderListMarker(marker, inlineWidth, visualOffset, doc, fontFamily, fo
|
|
|
1391
1431
|
span.style.display = "inline-block";
|
|
1392
1432
|
if (fontFamily) span.style.fontFamily = resolveFontFamily(fontFamily).cssFallback;
|
|
1393
1433
|
if (fontSize) span.style.fontSize = `${fontSize * 96 / 72}px`;
|
|
1394
|
-
if (bold !== void 0) span.style.fontWeight = bold ? "
|
|
1434
|
+
if (bold !== void 0) span.style.fontWeight = bold ? "700" : "normal";
|
|
1395
1435
|
span.style.textAlign = "left";
|
|
1396
1436
|
span.style.textAlignLast = "left";
|
|
1397
1437
|
span.style.boxSizing = "border-box";
|
|
@@ -23,6 +23,10 @@ type RenderTableFragmentOptions = {
|
|
|
23
23
|
document?: Document;
|
|
24
24
|
pageGeometry?: PageGeometry;
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Render a nested table (within a cell)
|
|
28
|
+
*/
|
|
29
|
+
declare function renderNestedTable(block: TableBlock, measure: TableMeasure, context: RenderContext, doc: Document): HTMLElement;
|
|
26
30
|
/**
|
|
27
31
|
* Render a table fragment to DOM
|
|
28
32
|
*
|
|
@@ -35,4 +39,4 @@ type RenderTableFragmentOptions = {
|
|
|
35
39
|
*/
|
|
36
40
|
declare function renderTableFragment(fragment: TableFragment, block: TableBlock, measure: TableMeasure, context: RenderContext, options?: RenderTableFragmentOptions): HTMLElement;
|
|
37
41
|
//#endregion
|
|
38
|
-
export { RenderTableFragmentOptions, TABLE_CLASS_NAMES, renderTableFragment };
|
|
42
|
+
export { RenderTableFragmentOptions, TABLE_CLASS_NAMES, renderNestedTable, renderTableFragment };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { emuToPixels } from "../utils/units.js";
|
|
2
|
+
import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
2
3
|
import { getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, tableColumnsArePinned } from "../layout-engine/types.js";
|
|
3
4
|
import { measureParagraph } from "../layout-engine/measure/measureParagraph.js";
|
|
4
5
|
import { resolveAnchoredImagePosition } from "./anchoredImagePosition.js";
|
|
@@ -70,7 +71,7 @@ function renderCellContent({ cell, cellMeasure, context, doc, contentWidthOverri
|
|
|
70
71
|
if (img.pmStart !== void 0) imgContainer.dataset["pmStart"] = String(img.pmStart);
|
|
71
72
|
if (img.pmEnd !== void 0) imgContainer.dataset["pmEnd"] = String(img.pmEnd);
|
|
72
73
|
const imgEl = doc.createElement("img");
|
|
73
|
-
imgEl
|
|
74
|
+
applySanitizedImageSrc(imgEl, img.src);
|
|
74
75
|
imgEl.style.width = `${img.width}px`;
|
|
75
76
|
imgEl.style.height = `${img.height}px`;
|
|
76
77
|
imgEl.style.display = "block";
|
|
@@ -156,7 +157,10 @@ function renderCellContent({ cell, cellMeasure, context, doc, contentWidthOverri
|
|
|
156
157
|
}, textBoxBlock, textBoxMeasure, {
|
|
157
158
|
...context,
|
|
158
159
|
insideTableCell: true
|
|
159
|
-
}, {
|
|
160
|
+
}, {
|
|
161
|
+
document: doc,
|
|
162
|
+
renderTable: renderNestedTable
|
|
163
|
+
});
|
|
160
164
|
if (isFloatingTextBoxBlock(textBoxBlock)) {
|
|
161
165
|
floatingTextBoxesLayer ??= createCellFloatingTextBoxesLayer(doc);
|
|
162
166
|
textBoxEl.style.left = `${resolveCellTextBoxX(textBoxBlock, contentWidth)}px`;
|
|
@@ -737,4 +741,4 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
737
741
|
return tableEl;
|
|
738
742
|
}
|
|
739
743
|
//#endregion
|
|
740
|
-
export { TABLE_CLASS_NAMES, renderTableFragment };
|
|
744
|
+
export { TABLE_CLASS_NAMES, renderNestedTable, renderTableFragment };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TextBoxBlock, TextBoxFragment, TextBoxMeasure } from "../layout-engine/types.js";
|
|
1
|
+
import { TableBlock, TableMeasure, TextBoxBlock, TextBoxFragment, TextBoxMeasure } from "../layout-engine/types.js";
|
|
2
2
|
import { RenderContext } from "./renderUtils.js";
|
|
3
3
|
|
|
4
4
|
//#region src/layout-painter/renderTextBox.d.ts
|
|
@@ -13,6 +13,7 @@ declare const TEXTBOX_CLASS_NAMES: {
|
|
|
13
13
|
*/
|
|
14
14
|
type RenderTextBoxFragmentOptions = {
|
|
15
15
|
document?: Document;
|
|
16
|
+
renderTable?: (block: TableBlock, measure: TableMeasure, context: RenderContext, document: Document) => HTMLElement;
|
|
16
17
|
};
|
|
17
18
|
/**
|
|
18
19
|
* Render a text box fragment to DOM
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_TEXTBOX_MARGINS } from "../layout-engine/types.js";
|
|
2
2
|
import { renderParagraphFragment } from "./renderParagraph.js";
|
|
3
|
-
import {
|
|
3
|
+
import { layoutTextBoxContent } from "../layout-engine/measure/textBoxParagraphLayout.js";
|
|
4
|
+
import { panic } from "better-result";
|
|
4
5
|
//#region src/layout-painter/renderTextBox.ts
|
|
5
6
|
/**
|
|
6
7
|
* Text Box Renderer
|
|
@@ -9,7 +10,7 @@ import { layoutTextBoxParagraphs } from "../layout-engine/measure/textBoxParagra
|
|
|
9
10
|
* - Background fill color
|
|
10
11
|
* - Border/outline
|
|
11
12
|
* - Internal padding (margins)
|
|
12
|
-
* -
|
|
13
|
+
* - Block content inside the box (using pre-measured data)
|
|
13
14
|
*/
|
|
14
15
|
/**
|
|
15
16
|
* CSS class names for text box elements
|
|
@@ -39,27 +40,37 @@ function renderTextBoxFragment(fragment, block, measure, context, options = {})
|
|
|
39
40
|
if (fragment.pmStart !== void 0) containerEl.dataset["pmStart"] = String(fragment.pmStart);
|
|
40
41
|
if (fragment.pmEnd !== void 0) containerEl.dataset["pmEnd"] = String(fragment.pmEnd);
|
|
41
42
|
const innerWidth = fragment.width - margins.left - margins.right;
|
|
42
|
-
const
|
|
43
|
+
const contentLayout = layoutTextBoxContent(block.content, measure.innerMeasures);
|
|
43
44
|
for (let i = 0; i < block.content.length; i++) {
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const placement =
|
|
47
|
-
if (!
|
|
45
|
+
const contentBlock = block.content[i];
|
|
46
|
+
const contentMeasure = measure.innerMeasures[i];
|
|
47
|
+
const placement = contentLayout.placements[i];
|
|
48
|
+
if (!contentBlock || !contentMeasure || !placement) continue;
|
|
49
|
+
if (contentBlock.kind === "table" && contentMeasure.kind === "table") {
|
|
50
|
+
if (!options.renderTable) panic("renderTextBoxFragment: a nested table renderer is required for table content");
|
|
51
|
+
const tableEl = options.renderTable(contentBlock, contentMeasure, context, doc);
|
|
52
|
+
tableEl.style.marginTop = `${placement.leadingSpacing}px`;
|
|
53
|
+
containerEl.append(tableEl);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (contentBlock.kind !== "paragraph" || contentMeasure.kind !== "paragraph") continue;
|
|
48
57
|
const paraFragment = {
|
|
49
58
|
kind: "paragraph",
|
|
50
|
-
blockId:
|
|
59
|
+
blockId: contentBlock.id,
|
|
51
60
|
x: 0,
|
|
52
61
|
y: 0,
|
|
53
62
|
width: innerWidth,
|
|
54
63
|
height: placement.contentHeight,
|
|
55
|
-
...
|
|
56
|
-
...
|
|
64
|
+
...contentBlock.pmStart !== void 0 ? { pmStart: contentBlock.pmStart } : {},
|
|
65
|
+
...contentBlock.pmEnd !== void 0 ? { pmEnd: contentBlock.pmEnd } : {},
|
|
57
66
|
fromLine: 0,
|
|
58
|
-
toLine:
|
|
67
|
+
toLine: contentMeasure.lines.length
|
|
59
68
|
};
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
const
|
|
69
|
+
const previousBlock = block.content[i - 1];
|
|
70
|
+
const nextBlock = block.content[i + 1];
|
|
71
|
+
const prevBorders = previousBlock?.kind === "paragraph" ? previousBlock.attrs?.borders : void 0;
|
|
72
|
+
const nextBorders = nextBlock?.kind === "paragraph" ? nextBlock.attrs?.borders : void 0;
|
|
73
|
+
const paraEl = renderParagraphFragment(paraFragment, contentBlock, contentMeasure, context, {
|
|
63
74
|
document: doc,
|
|
64
75
|
...prevBorders !== void 0 ? { prevBorders } : {},
|
|
65
76
|
...nextBorders !== void 0 ? { nextBorders } : {}
|
|
@@ -3,7 +3,7 @@ import { Page } from "../layout-engine/types.js";
|
|
|
3
3
|
|
|
4
4
|
//#region src/layout-painter/renderWatermark.d.ts
|
|
5
5
|
type RenderWatermarkOptions = {
|
|
6
|
-
/** Resolved image src for picture watermarks (data
|
|
6
|
+
/** Resolved image src for picture watermarks (`data:` / `blob:` only). */imageSrc?: string;
|
|
7
7
|
};
|
|
8
8
|
/**
|
|
9
9
|
* Build the watermark overlay element for a page. Returns `null` when
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveFontFamily } from "../utils/fontResolver.js";
|
|
2
|
+
import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
2
3
|
//#region src/layout-painter/renderWatermark.ts
|
|
3
4
|
const WATERMARK_CLASS = "layout-page-watermark";
|
|
4
5
|
/**
|
|
@@ -47,7 +48,7 @@ function renderTextWatermark(watermark, doc) {
|
|
|
47
48
|
}
|
|
48
49
|
function renderPictureWatermark(watermark, imageSrc, doc) {
|
|
49
50
|
const img = doc.createElement("img");
|
|
50
|
-
img
|
|
51
|
+
applySanitizedImageSrc(img, imageSrc);
|
|
51
52
|
img.alt = "";
|
|
52
53
|
img.setAttribute("aria-hidden", "true");
|
|
53
54
|
const scalePct = (watermark.scale ?? 1) * 100;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { resetAuthorColors } from "../utils/authorColors.js";
|
|
1
2
|
import { loadFontsWithMapping } from "../utils/fontLoader.js";
|
|
2
3
|
import { parseDocx } from "../docx/parser.js";
|
|
3
4
|
import { inspectDocxCompatibility } from "../docx/compatibility.js";
|
|
4
|
-
import { resetAuthorColors } from "../utils/authorColors.js";
|
|
5
5
|
import { recordDocumentLoadPhase } from "../layout-engine/layoutInstrumentation.js";
|
|
6
6
|
//#region src/managers/DocumentLoaderManager.ts
|
|
7
7
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createEmptyDocument } from "../utils/createDocument.js";
|
|
2
1
|
import { sanitizeExternalUrl } from "../utils/urlSecurity.js";
|
|
2
|
+
import { createEmptyDocument } from "../utils/createDocument.js";
|
|
3
3
|
import { marked } from "marked";
|
|
4
4
|
//#region src/markdown/fromMarkdown.ts
|
|
5
5
|
/**
|
package/dist/model.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
|
|
2
1
|
import { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, PARAGRAPH_ALIGNMENT_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES } from "./types/documentEnumValues.js";
|
|
2
|
+
import { deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId } from "./types/block-id.js";
|
|
3
3
|
import { types_exports } from "./layout-engine/types.js";
|
|
4
4
|
export { BORDER_STYLE_VALUES, CONDITIONAL_STYLE_TYPE_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FLOATING_TABLE_X_SPEC_VALUES, FLOATING_TABLE_Y_SPEC_VALUES, FONT_THEME_VALUES, FRAME_WRAP_VALUES, FRAME_X_ALIGN_VALUES, FRAME_Y_ALIGN_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LEVEL_SUFFIX_VALUES, LINE_SPACING_RULE_VALUES, types_exports as Layout, NUMBER_FORMAT_VALUES, OUTLINE_STYLE_ATTR_VALUES, OUTLINE_STYLE_CSS_ALIASES, OUTLINE_STYLE_CSS_ALIAS_VALUES, PARAGRAPH_ALIGNMENT_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, SHAPE_OUTLINE_STYLE_VALUES, SHAPE_TYPE_VALUES, STYLE_TYPE_VALUES, TABLE_CELL_TEXT_DIRECTION_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_EFFECT_VALUES, THEME_COLOR_SLOT_VALUES, UNDERLINE_STYLE_VALUES, deriveBlockId, getFolioParaIdFromBlockId, getSequentialFolioBlockIdIndex, isFolioBlockId, isSequentialFolioBlockId };
|