@stll/folio-core 0.7.0 → 0.9.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/README.md +39 -0
- package/dist/ai-edits/apply.js +18 -4
- package/dist/ai-edits/blockRange.d.ts +13 -2
- package/dist/ai-edits/blockRange.js +23 -2
- package/dist/ai-edits/headless.d.ts +31 -4
- package/dist/ai-edits/headless.js +148 -35
- package/dist/ai-edits/index.d.ts +6 -4
- package/dist/ai-edits/index.js +4 -1
- package/dist/ai-edits/scoped-reading.d.ts +9 -0
- package/dist/ai-edits/scoped-reading.js +60 -0
- package/dist/ai-edits/snapshot.js +53 -7
- package/dist/ai-edits/types.d.ts +46 -3
- package/dist/compat/eigenpal.d.ts +8 -3
- package/dist/compat/eigenpal.js +7 -2
- package/dist/controller/fontReadiness.d.ts +29 -0
- package/dist/controller/fontReadiness.js +139 -0
- package/dist/controller/latestRequestGate.d.ts +13 -0
- package/dist/controller/latestRequestGate.js +16 -0
- package/dist/controller/layoutPipeline.js +88 -10
- package/dist/document-operations.d.ts +10 -3
- package/dist/document-operations.js +29 -14
- package/dist/docx/blockContentParser.js +53 -10
- package/dist/docx/commentParser.js +1 -1
- package/dist/docx/compatibility.d.ts +30 -2
- package/dist/docx/compatibility.js +118 -39
- package/dist/docx/conformance.d.ts +6 -0
- package/dist/docx/conformance.js +18 -0
- package/dist/docx/encryption/agileDecryption.js +1 -1
- package/dist/docx/encryption/encryptionInfo.js +1 -1
- package/dist/docx/encryption/openEncryptedDocx.js +1 -1
- package/dist/docx/ensureParaIds.d.ts +29 -0
- package/dist/docx/ensureParaIds.js +423 -0
- package/dist/docx/fontTableParser.d.ts +6 -0
- package/dist/docx/fontTableParser.js +72 -0
- package/dist/docx/groupDrawingParser.js +7 -2
- package/dist/docx/headerFooterParser.js +1 -1
- package/dist/docx/normalizeBaseDirection.js +1 -1
- package/dist/docx/numberingParser.js +2 -0
- package/dist/docx/paragraphParser.js +21 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +141 -2
- package/dist/docx/parser.d.ts +1 -1
- package/dist/docx/parser.js +14 -9
- package/dist/docx/rezip.js +70 -5
- package/dist/docx/runConsolidator.js +4 -0
- package/dist/docx/runParser.js +19 -1
- package/dist/docx/selectiveSave.js +3 -3
- package/dist/docx/selectiveXmlPatch.d.ts +10 -1
- package/dist/docx/selectiveXmlPatch.js +1 -1
- package/dist/docx/serializer/fontTableSerializer.d.ts +6 -0
- package/dist/docx/serializer/fontTableSerializer.js +26 -0
- package/dist/docx/serializer/headerFooterSerializer.js +1 -1
- package/dist/docx/serializer/paragraphSerializer.js +8 -0
- package/dist/docx/serializer/runSerializer.js +14 -2
- package/dist/docx/serializer/settingsSerializer.d.ts +6 -0
- package/dist/docx/serializer/settingsSerializer.js +16 -0
- package/dist/docx/serializer/stylesSerializer.d.ts +6 -0
- package/dist/docx/serializer/stylesSerializer.js +56 -0
- package/dist/docx/serializer/tableSerializer.js +29 -26
- package/dist/docx/serializer/themeSerializer.d.ts +6 -0
- package/dist/docx/serializer/themeSerializer.js +36 -0
- package/dist/docx/settingsParser.js +46 -0
- package/dist/docx/styleParser.js +26 -1
- package/dist/docx/tableParser.js +19 -1
- package/dist/docx/textBoxParser.js +6 -1
- package/dist/docx/vmlImageParser.js +146 -1
- package/dist/i18n/messages/catalogs.gen.d.ts +5916 -5916
- package/dist/i18n/messages/catalogs.gen.js +5910 -5910
- package/dist/index.d.ts +8 -3
- package/dist/index.js +7 -2
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +3 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +3 -1
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +3 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +22 -3
- package/dist/layout-bridge/convert/paragraphFrames.d.ts +7 -0
- package/dist/layout-bridge/convert/paragraphFrames.js +136 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +14 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +93 -17
- package/dist/layout-bridge/engine/hitTest.js +2 -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 +2 -1
- package/dist/layout-engine/headerFooterRefs.d.ts +7 -0
- package/dist/layout-engine/headerFooterRefs.js +40 -0
- package/dist/layout-engine/index.d.ts +3 -2
- package/dist/layout-engine/index.js +68 -106
- package/dist/layout-engine/measure/cache.js +11 -3
- package/dist/layout-engine/measure/font-metrics.worker.js +1 -0
- package/dist/layout-engine/measure/index.d.ts +2 -1
- package/dist/layout-engine/measure/index.js +2 -1
- package/dist/layout-engine/measure/lineBreakProvider.d.ts +33 -0
- package/dist/layout-engine/measure/lineBreakProvider.js +252 -0
- package/dist/layout-engine/measure/lineBreaks.d.ts +7 -2
- package/dist/layout-engine/measure/lineBreaks.js +11 -18
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +4 -1
- package/dist/layout-engine/measure/listMarkerWidth.js +33 -8
- package/dist/layout-engine/measure/measureBlocks.d.ts +4 -2
- package/dist/layout-engine/measure/measureBlocks.js +138 -86
- package/dist/layout-engine/measure/measureContainer.js +32 -9
- package/dist/layout-engine/measure/measureHelpers.js +5 -2
- package/dist/layout-engine/measure/measureParagraph.js +346 -74
- package/dist/layout-engine/measure/measureTypes.d.ts +2 -1
- package/dist/layout-engine/measure/measureWorker.d.ts +2 -2
- package/dist/layout-engine/measure/measureWorker.js +8 -19
- package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +3 -14
- package/dist/layout-engine/measure/tableCellFloating.d.ts +10 -3
- package/dist/layout-engine/measure/tableCellFloating.js +37 -29
- package/dist/layout-engine/measure/tableCellFlow.d.ts +27 -0
- package/dist/layout-engine/measure/tableCellFlow.js +73 -0
- package/dist/layout-engine/measure/tableCellGrid.d.ts +15 -0
- package/dist/layout-engine/measure/tableCellGrid.js +62 -0
- package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +18 -0
- package/dist/layout-engine/measure/textBoxParagraphLayout.js +32 -0
- package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +18 -0
- package/dist/layout-engine/measure/textMeasurementPolicy.js +24 -0
- package/dist/layout-engine/paginator.d.ts +2 -1
- package/dist/layout-engine/paginator.js +7 -6
- package/dist/layout-engine/paragraphFrame.d.ts +22 -0
- package/dist/layout-engine/paragraphFrame.js +17 -0
- package/dist/layout-engine/paragraphSequence.d.ts +7 -0
- package/dist/layout-engine/paragraphSequence.js +25 -0
- package/dist/layout-engine/paragraphSpacing.d.ts +17 -0
- package/dist/layout-engine/paragraphSpacing.js +30 -0
- package/dist/layout-engine/renderedBreakReconciliation.d.ts +63 -0
- package/dist/layout-engine/renderedBreakReconciliation.js +86 -0
- package/dist/layout-engine/tableRowBreak.d.ts +5 -2
- package/dist/layout-engine/tableRowBreak.js +62 -29
- package/dist/layout-engine/types.d.ts +54 -12
- package/dist/layout-engine/types.js +15 -2
- package/dist/layout-painter/anchoredImagePosition.d.ts +23 -0
- package/dist/layout-painter/anchoredImagePosition.js +95 -0
- package/dist/layout-painter/borderStroke.d.ts +23 -0
- package/dist/layout-painter/borderStroke.js +39 -0
- package/dist/layout-painter/renderImage.d.ts +5 -4
- package/dist/layout-painter/renderImage.js +18 -4
- package/dist/layout-painter/renderPage.d.ts +2 -27
- package/dist/layout-painter/renderPage.js +15 -101
- package/dist/layout-painter/renderParagraph.js +45 -26
- package/dist/layout-painter/renderTable.d.ts +2 -0
- package/dist/layout-painter/renderTable.js +257 -47
- package/dist/layout-painter/renderTextBox.js +17 -7
- package/dist/managers/DocumentLoaderManager.d.ts +1 -1
- package/dist/managers/DocumentLoaderManager.js +2 -2
- package/dist/paged-layout/sectionBlockWidths.d.ts +3 -0
- package/dist/paged-layout/sectionBlockWidths.js +9 -0
- package/dist/paged-layout/sectionGeometry.js +1 -1
- package/dist/prosemirror/attrs/index.d.ts +4 -2
- package/dist/prosemirror/attrs/index.js +32 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +1 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +35 -18
- package/dist/prosemirror/conversion/toProseDoc.js +73 -37
- package/dist/prosemirror/extensions/StarterKit.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +8 -2
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +1 -1
- package/dist/prosemirror/extensions/features/ListExtension.js +2 -0
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +68 -16
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +1 -0
- package/dist/prosemirror/extensions/marks/HighlightExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/LanguageExtension.d.ts +7 -0
- package/dist/prosemirror/extensions/marks/LanguageExtension.js +30 -0
- package/dist/prosemirror/extensions/marks/RunShadingExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +1 -1
- package/dist/prosemirror/extensions/marks/markUtils.js +12 -0
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +2 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +4 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +2 -1
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +7 -0
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/marks.d.ts +6 -1
- package/dist/prosemirror/schema/nodes.d.ts +16 -12
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +2 -0
- package/dist/prosemirror/utils/tabCalculator.d.ts +3 -1
- package/dist/prosemirror/utils/tabCalculator.js +12 -10
- package/dist/prosemirror/validation.js +4 -1
- package/dist/redline.js +13 -3
- package/dist/server.d.ts +9 -4
- package/dist/server.js +7 -2
- package/dist/style-sets/extract.d.ts +35 -0
- package/dist/style-sets/extract.js +123 -0
- package/dist/style-sets/stellaStyle.d.ts +13 -0
- package/dist/style-sets/stellaStyle.js +516 -0
- package/dist/style-sets/types.d.ts +31 -0
- package/dist/style-sets/types.js +5 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/utils/createDocument.d.ts +12 -2
- package/dist/utils/createDocument.js +55 -36
- package/dist/utils/fontResolver.js +6 -6
- package/dist/utils/formatToStyle.js +1 -1
- package/dist/utils/hexId.d.ts +8 -1
- package/dist/utils/hexId.js +11 -3
- package/dist/utils/paragraphFormattingMerge.d.ts +14 -3
- package/dist/utils/paragraphFormattingMerge.js +14 -4
- package/package.json +5 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { escapeXml } from "./xmlUtils.js";
|
|
2
|
+
import { serializeTextFormatting } from "./runSerializer.js";
|
|
3
|
+
import { serializeParagraphFormatting } from "./paragraphSerializer.js";
|
|
4
|
+
import { serializeTableCellFormatting, serializeTableFormatting, serializeTableRowFormatting } from "./tableSerializer.js";
|
|
5
|
+
//#region src/docx/serializer/stylesSerializer.ts
|
|
6
|
+
const W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
|
7
|
+
const serializeStylesXml = (definitions) => {
|
|
8
|
+
const docDefaults = serializeDocumentDefaults(definitions);
|
|
9
|
+
const latentStyles = serializeLatentStyles(definitions);
|
|
10
|
+
const styles = definitions.styles.map(serializeStyle).join("");
|
|
11
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<w:styles xmlns:w="${W_NS}">${docDefaults}${latentStyles}${styles}</w:styles>`;
|
|
12
|
+
};
|
|
13
|
+
const serializeDocumentDefaults = (definitions) => {
|
|
14
|
+
return `<w:docDefaults><w:rPrDefault>${serializeTextFormatting(definitions.docDefaults?.rPr) || "<w:rPr/>"}</w:rPrDefault><w:pPrDefault>${serializeParagraphFormatting(definitions.docDefaults?.pPr) || "<w:pPr/>"}</w:pPrDefault></w:docDefaults>`;
|
|
15
|
+
};
|
|
16
|
+
const serializeLatentStyles = (definitions) => {
|
|
17
|
+
const latent = definitions.latentStyles;
|
|
18
|
+
if (!latent) return "";
|
|
19
|
+
const attrs = [];
|
|
20
|
+
pushBooleanAttr(attrs, "w:defLockedState", latent.defLockedState);
|
|
21
|
+
if (latent.defUIPriority !== void 0) attrs.push(`w:defUIPriority="${latent.defUIPriority}"`);
|
|
22
|
+
pushBooleanAttr(attrs, "w:defSemiHidden", latent.defSemiHidden);
|
|
23
|
+
pushBooleanAttr(attrs, "w:defUnhideWhenUsed", latent.defUnhideWhenUsed);
|
|
24
|
+
pushBooleanAttr(attrs, "w:defQFormat", latent.defQFormat);
|
|
25
|
+
return `<w:latentStyles${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""}/>`;
|
|
26
|
+
};
|
|
27
|
+
const serializeStyle = (style) => {
|
|
28
|
+
const attrs = [`w:type="${style.type}"`, `w:styleId="${escapeXml(style.styleId)}"`];
|
|
29
|
+
if (style.default) attrs.push("w:default=\"1\"");
|
|
30
|
+
const parts = [`<w:name w:val="${escapeXml(style.name ?? style.styleId)}"/>`];
|
|
31
|
+
if (style.basedOn) parts.push(`<w:basedOn w:val="${escapeXml(style.basedOn)}"/>`);
|
|
32
|
+
if (style.next) parts.push(`<w:next w:val="${escapeXml(style.next)}"/>`);
|
|
33
|
+
if (style.link) parts.push(`<w:link w:val="${escapeXml(style.link)}"/>`);
|
|
34
|
+
if (style.uiPriority !== void 0) parts.push(`<w:uiPriority w:val="${style.uiPriority}"/>`);
|
|
35
|
+
pushBooleanElement(parts, "hidden", style.hidden);
|
|
36
|
+
pushBooleanElement(parts, "semiHidden", style.semiHidden);
|
|
37
|
+
pushBooleanElement(parts, "unhideWhenUsed", style.unhideWhenUsed);
|
|
38
|
+
pushBooleanElement(parts, "qFormat", style.qFormat);
|
|
39
|
+
pushBooleanElement(parts, "personal", style.personal);
|
|
40
|
+
parts.push(serializeParagraphFormatting(style.pPr));
|
|
41
|
+
parts.push(serializeTextFormatting(style.rPr));
|
|
42
|
+
parts.push(serializeTableFormatting(style.tblPr));
|
|
43
|
+
parts.push(serializeTableRowFormatting(style.trPr));
|
|
44
|
+
parts.push(serializeTableCellFormatting(style.tcPr));
|
|
45
|
+
for (const conditional of style.tblStylePr ?? []) parts.push(`<w:tblStylePr w:type="${conditional.type}">${serializeParagraphFormatting(conditional.pPr)}${serializeTextFormatting(conditional.rPr)}${serializeTableFormatting(conditional.tblPr)}${serializeTableRowFormatting(conditional.trPr)}${serializeTableCellFormatting(conditional.tcPr)}</w:tblStylePr>`);
|
|
46
|
+
return `<w:style ${attrs.join(" ")}>${parts.join("")}</w:style>`;
|
|
47
|
+
};
|
|
48
|
+
const pushBooleanElement = (parts, name, value) => {
|
|
49
|
+
if (value === true) parts.push(`<w:${name}/>`);
|
|
50
|
+
else if (value === false) parts.push(`<w:${name} w:val="0"/>`);
|
|
51
|
+
};
|
|
52
|
+
const pushBooleanAttr = (attrs, name, value) => {
|
|
53
|
+
if (value !== void 0) attrs.push(`${name}="${value ? 1 : 0}"`);
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
export { serializeStylesXml };
|
|
@@ -30,36 +30,35 @@ function serializeMeasurement(measurement, elementName) {
|
|
|
30
30
|
/**
|
|
31
31
|
* Serialize table borders (w:tblBorders or w:tcBorders)
|
|
32
32
|
*/
|
|
33
|
+
function serializeTableBorderParts(borders) {
|
|
34
|
+
const parts = [];
|
|
35
|
+
const appendBorder = (border, name) => {
|
|
36
|
+
const xml = serializeBorder(border, name);
|
|
37
|
+
if (xml) parts.push(xml);
|
|
38
|
+
};
|
|
39
|
+
appendBorder(borders.top, "top");
|
|
40
|
+
appendBorder(borders.left, "left");
|
|
41
|
+
appendBorder(borders.bottom, "bottom");
|
|
42
|
+
appendBorder(borders.right, "right");
|
|
43
|
+
appendBorder(borders.insideH, "insideH");
|
|
44
|
+
appendBorder(borders.insideV, "insideV");
|
|
45
|
+
return parts;
|
|
46
|
+
}
|
|
33
47
|
function serializeTableBorders(borders, elementName) {
|
|
34
48
|
if (!borders) return "";
|
|
35
|
-
const parts =
|
|
36
|
-
if (borders.top) {
|
|
37
|
-
const topXml = serializeBorder(borders.top, "top");
|
|
38
|
-
if (topXml) parts.push(topXml);
|
|
39
|
-
}
|
|
40
|
-
if (borders.left) {
|
|
41
|
-
const leftXml = serializeBorder(borders.left, "left");
|
|
42
|
-
if (leftXml) parts.push(leftXml);
|
|
43
|
-
}
|
|
44
|
-
if (borders.bottom) {
|
|
45
|
-
const bottomXml = serializeBorder(borders.bottom, "bottom");
|
|
46
|
-
if (bottomXml) parts.push(bottomXml);
|
|
47
|
-
}
|
|
48
|
-
if (borders.right) {
|
|
49
|
-
const rightXml = serializeBorder(borders.right, "right");
|
|
50
|
-
if (rightXml) parts.push(rightXml);
|
|
51
|
-
}
|
|
52
|
-
if (borders.insideH) {
|
|
53
|
-
const insideHXml = serializeBorder(borders.insideH, "insideH");
|
|
54
|
-
if (insideHXml) parts.push(insideHXml);
|
|
55
|
-
}
|
|
56
|
-
if (borders.insideV) {
|
|
57
|
-
const insideVXml = serializeBorder(borders.insideV, "insideV");
|
|
58
|
-
if (insideVXml) parts.push(insideVXml);
|
|
59
|
-
}
|
|
49
|
+
const parts = serializeTableBorderParts(borders);
|
|
60
50
|
if (parts.length === 0) return "";
|
|
61
51
|
return `<w:${elementName}>${parts.join("")}</w:${elementName}>`;
|
|
62
52
|
}
|
|
53
|
+
function serializeTableCellBorders(borders) {
|
|
54
|
+
if (!borders) return "";
|
|
55
|
+
const parts = serializeTableBorderParts(borders);
|
|
56
|
+
const topLeftToBottomRight = serializeBorder(borders.topLeftToBottomRight, "tl2br");
|
|
57
|
+
if (topLeftToBottomRight) parts.push(topLeftToBottomRight);
|
|
58
|
+
const topRightToBottomLeft = serializeBorder(borders.topRightToBottomLeft, "tr2bl");
|
|
59
|
+
if (topRightToBottomLeft) parts.push(topRightToBottomLeft);
|
|
60
|
+
return parts.length > 0 ? `<w:tcBorders>${parts.join("")}</w:tcBorders>` : "";
|
|
61
|
+
}
|
|
63
62
|
/**
|
|
64
63
|
* Serialize cell margins (w:tblCellMar or w:tcMar)
|
|
65
64
|
*/
|
|
@@ -172,6 +171,10 @@ function serializeTablePropertyChange(change) {
|
|
|
172
171
|
function serializeTableRowFormatting(formatting, propertyChanges, structuralChange) {
|
|
173
172
|
const parts = [];
|
|
174
173
|
if (formatting) {
|
|
174
|
+
if (formatting.gridBefore) parts.push(`<w:gridBefore w:val="${intAttr(formatting.gridBefore)}"/>`);
|
|
175
|
+
if (formatting.widthBefore) parts.push(`<w:wBefore w:w="${intAttr(formatting.widthBefore.value)}" w:type="${formatting.widthBefore.type}"/>`);
|
|
176
|
+
if (formatting.gridAfter) parts.push(`<w:gridAfter w:val="${intAttr(formatting.gridAfter)}"/>`);
|
|
177
|
+
if (formatting.widthAfter) parts.push(`<w:wAfter w:w="${intAttr(formatting.widthAfter.value)}" w:type="${formatting.widthAfter.type}"/>`);
|
|
175
178
|
if (formatting.cantSplit) parts.push("<w:cantSplit/>");
|
|
176
179
|
if (formatting.header) parts.push("<w:tblHeader/>");
|
|
177
180
|
if (formatting.height) {
|
|
@@ -234,7 +237,7 @@ function serializeTableCellFormatting(formatting, propertyChanges, structuralCha
|
|
|
234
237
|
if (formatting.gridSpan && formatting.gridSpan > 1) parts.push(`<w:gridSpan w:val="${intAttr(formatting.gridSpan)}"/>`);
|
|
235
238
|
if (formatting.vMerge) if (formatting.vMerge === "restart") parts.push("<w:vMerge w:val=\"restart\"/>");
|
|
236
239
|
else parts.push("<w:vMerge/>");
|
|
237
|
-
const bordersXml =
|
|
240
|
+
const bordersXml = serializeTableCellBorders(formatting.borders);
|
|
238
241
|
if (bordersXml) parts.push(bordersXml);
|
|
239
242
|
const shadingXml = serializeShading(formatting.shading);
|
|
240
243
|
if (shadingXml) parts.push(shadingXml);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { escapeXml } from "./xmlUtils.js";
|
|
2
|
+
//#region src/docx/serializer/themeSerializer.ts
|
|
3
|
+
const A_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
|
|
4
|
+
const serializeThemeXml = (theme) => {
|
|
5
|
+
const name = escapeXml(theme.name ?? "Folio Theme");
|
|
6
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<a:theme xmlns:a="${A_NS}" name="${name}"><a:themeElements>${serializeColorScheme(theme.colorScheme)}${serializeFontScheme(theme)}${serializeFormatScheme(theme)}</a:themeElements></a:theme>`;
|
|
7
|
+
};
|
|
8
|
+
const serializeColorScheme = (colors) => {
|
|
9
|
+
const values = {
|
|
10
|
+
dk1: colors?.dk1 ?? "000000",
|
|
11
|
+
lt1: colors?.lt1 ?? "FFFFFF",
|
|
12
|
+
dk2: colors?.dk2 ?? "44546A",
|
|
13
|
+
lt2: colors?.lt2 ?? "E7E6E6",
|
|
14
|
+
accent1: colors?.accent1 ?? "4472C4",
|
|
15
|
+
accent2: colors?.accent2 ?? "ED7D31",
|
|
16
|
+
accent3: colors?.accent3 ?? "A5A5A5",
|
|
17
|
+
accent4: colors?.accent4 ?? "FFC000",
|
|
18
|
+
accent5: colors?.accent5 ?? "5B9BD5",
|
|
19
|
+
accent6: colors?.accent6 ?? "70AD47",
|
|
20
|
+
hlink: colors?.hlink ?? "0563C1",
|
|
21
|
+
folHlink: colors?.folHlink ?? "954F72"
|
|
22
|
+
};
|
|
23
|
+
return `<a:clrScheme name="Folio">${Object.entries(values).map(([slot, value]) => `<a:${slot}><a:srgbClr val="${escapeXml(value)}"/></a:${slot}>`).join("")}</a:clrScheme>`;
|
|
24
|
+
};
|
|
25
|
+
const serializeFontScheme = (theme) => {
|
|
26
|
+
return `<a:fontScheme name="Folio">${serializeThemeFont(theme.fontScheme?.majorFont, "majorFont", "Arial")}${serializeThemeFont(theme.fontScheme?.minorFont, "minorFont", "Arial")}</a:fontScheme>`;
|
|
27
|
+
};
|
|
28
|
+
const serializeThemeFont = (font, element, fallback) => {
|
|
29
|
+
const scriptFonts = Object.entries(font?.fonts ?? {}).map(([script, typeface]) => `<a:font script="${escapeXml(script)}" typeface="${escapeXml(typeface)}"/>`).join("");
|
|
30
|
+
return `<a:${element}><a:latin typeface="${escapeXml(font?.latin ?? fallback)}"/><a:ea typeface="${escapeXml(font?.ea ?? "")}"/><a:cs typeface="${escapeXml(font?.cs ?? "")}"/>${scriptFonts}</a:${element}>`;
|
|
31
|
+
};
|
|
32
|
+
const serializeFormatScheme = (theme) => {
|
|
33
|
+
return `<a:fmtScheme name="${escapeXml(theme.formatScheme?.name ?? "Folio")}"><a:fillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:fillStyleLst><a:lnStyleLst><a:ln w="6350" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:bgFillStyleLst></a:fmtScheme>`;
|
|
34
|
+
};
|
|
35
|
+
//#endregion
|
|
36
|
+
export { serializeThemeXml };
|
|
@@ -8,6 +8,8 @@ const DEFAULT_TAB_STOP_TWIPS = 720;
|
|
|
8
8
|
* we substitute the OOXML default instead.
|
|
9
9
|
*/
|
|
10
10
|
const MAX_TAB_STOP_TWIPS = 31680;
|
|
11
|
+
const MAX_HYPHENATION_ZONE_TWIPS = 31680;
|
|
12
|
+
const MAX_CONSECUTIVE_HYPHEN_LIMIT = 255;
|
|
11
13
|
function parseSettings(xml) {
|
|
12
14
|
const root = xml ? parseXmlDocument(xml) : null;
|
|
13
15
|
const settings = { defaultTabStop: parseDefaultTabStop(root) };
|
|
@@ -22,8 +24,52 @@ function parseSettings(xml) {
|
|
|
22
24
|
...eastAsiaLang ? { eastAsia: eastAsiaLang } : {},
|
|
23
25
|
...bidiLang ? { bidi: bidiLang } : {}
|
|
24
26
|
};
|
|
27
|
+
const autoHyphenation = parseOnOffSetting(root, "autoHyphenation");
|
|
28
|
+
if (autoHyphenation !== void 0) settings.autoHyphenation = autoHyphenation;
|
|
29
|
+
const doNotHyphenateCaps = parseOnOffSetting(root, "doNotHyphenateCaps");
|
|
30
|
+
if (doNotHyphenateCaps !== void 0) settings.doNotHyphenateCaps = doNotHyphenateCaps;
|
|
31
|
+
const consecutiveHyphenLimit = parseIntegerSetting(root, "consecutiveHyphenLimit", MAX_CONSECUTIVE_HYPHEN_LIMIT);
|
|
32
|
+
if (consecutiveHyphenLimit !== void 0) settings.consecutiveHyphenLimit = consecutiveHyphenLimit;
|
|
33
|
+
const hyphenationZoneTwips = parseIntegerSetting(root, "hyphenationZone", MAX_HYPHENATION_ZONE_TWIPS);
|
|
34
|
+
if (hyphenationZoneTwips !== void 0) settings.hyphenationZoneTwips = hyphenationZoneTwips;
|
|
35
|
+
const noLineBreaksBefore = parseKinsokuOverride(root, "noLineBreaksBefore");
|
|
36
|
+
const noLineBreaksAfter = parseKinsokuOverride(root, "noLineBreaksAfter");
|
|
37
|
+
const compat = root ? findChild(root, "w", "compat") : null;
|
|
38
|
+
const splitPageBreakAndParagraphMark = compat ? findChild(compat, "w", "splitPgBreakAndParaMark") : null;
|
|
39
|
+
if (splitPageBreakAndParagraphMark && parseBooleanElement(splitPageBreakAndParagraphMark)) settings.splitPageBreakAndParagraphMark = true;
|
|
40
|
+
const applyBreakingRules = compat ? findChild(compat, "w", "applyBreakingRules") : null;
|
|
41
|
+
const useLegacyEthiopicAmharicRules = applyBreakingRules !== null && parseBooleanElement(applyBreakingRules);
|
|
42
|
+
if (noLineBreaksBefore || noLineBreaksAfter || useLegacyEthiopicAmharicRules) settings.lineBreakRules = {
|
|
43
|
+
...noLineBreaksBefore ? { noLineBreaksBefore } : {},
|
|
44
|
+
...noLineBreaksAfter ? { noLineBreaksAfter } : {},
|
|
45
|
+
...useLegacyEthiopicAmharicRules ? { useLegacyEthiopicAmharicRules: true } : {}
|
|
46
|
+
};
|
|
25
47
|
return settings;
|
|
26
48
|
}
|
|
49
|
+
function parseOnOffSetting(root, name) {
|
|
50
|
+
if (!root) return;
|
|
51
|
+
const element = findChild(root, "w", name);
|
|
52
|
+
return element ? parseBooleanElement(element) : void 0;
|
|
53
|
+
}
|
|
54
|
+
function parseIntegerSetting(root, name, maximum) {
|
|
55
|
+
if (!root) return;
|
|
56
|
+
const element = findChild(root, "w", name);
|
|
57
|
+
const raw = element ? getAttribute(element, "w", "val") : null;
|
|
58
|
+
if (raw === null || !/^\d+$/u.test(raw)) return;
|
|
59
|
+
const parsed = Number.parseInt(raw, 10);
|
|
60
|
+
return Number.isSafeInteger(parsed) && parsed <= maximum ? parsed : void 0;
|
|
61
|
+
}
|
|
62
|
+
function parseKinsokuOverride(root, name) {
|
|
63
|
+
if (!root) return;
|
|
64
|
+
const element = findChild(root, "w", name);
|
|
65
|
+
const characters = element ? getAttribute(element, "w", "val") : null;
|
|
66
|
+
if (!characters) return;
|
|
67
|
+
const language = getAttribute(element, "w", "lang") || void 0;
|
|
68
|
+
return {
|
|
69
|
+
characters,
|
|
70
|
+
...language ? { language } : {}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
27
73
|
function parseDefaultTabStop(root) {
|
|
28
74
|
if (!root) return 720;
|
|
29
75
|
const el = findChild(root, "w", "defaultTabStop");
|
package/dist/docx/styleParser.js
CHANGED
|
@@ -110,6 +110,17 @@ function parseRunProperties(rPr, theme) {
|
|
|
110
110
|
}
|
|
111
111
|
formatting.fontFamily = fontFamily;
|
|
112
112
|
}
|
|
113
|
+
const lang = findChild(rPr, "w", "lang");
|
|
114
|
+
if (lang) {
|
|
115
|
+
const val = getAttribute(lang, "w", "val") || void 0;
|
|
116
|
+
const eastAsia = getAttribute(lang, "w", "eastAsia") || void 0;
|
|
117
|
+
const bidi = getAttribute(lang, "w", "bidi") || void 0;
|
|
118
|
+
if (val || eastAsia || bidi) formatting.language = {
|
|
119
|
+
...val ? { val } : {},
|
|
120
|
+
...eastAsia ? { eastAsia } : {},
|
|
121
|
+
...bidi ? { bidi } : {}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
113
124
|
const spacing = findChild(rPr, "w", "spacing");
|
|
114
125
|
if (spacing) {
|
|
115
126
|
const val = parseNumericAttribute(spacing, "w", "val");
|
|
@@ -348,6 +359,10 @@ function parseParagraphProperties(pPr, theme) {
|
|
|
348
359
|
if (suppressLineNumbers) formatting.suppressLineNumbers = parseBooleanElement(suppressLineNumbers);
|
|
349
360
|
const suppressAutoHyphens = findChild(pPr, "w", "suppressAutoHyphens");
|
|
350
361
|
if (suppressAutoHyphens) formatting.suppressAutoHyphens = parseBooleanElement(suppressAutoHyphens);
|
|
362
|
+
const kinsoku = findChild(pPr, "w", "kinsoku");
|
|
363
|
+
if (kinsoku) formatting.kinsoku = parseBooleanElement(kinsoku);
|
|
364
|
+
const overflowPunct = findChild(pPr, "w", "overflowPunct");
|
|
365
|
+
if (overflowPunct) formatting.overflowPunctuation = parseBooleanElement(overflowPunct);
|
|
351
366
|
const rPr = findChild(pPr, "w", "rPr");
|
|
352
367
|
if (rPr) {
|
|
353
368
|
const runProps = parseRunProperties(rPr, theme);
|
|
@@ -388,6 +403,16 @@ function parseTableBorders(tblBorders) {
|
|
|
388
403
|
if (insideV) borders.insideV = insideV;
|
|
389
404
|
return Object.keys(borders).length > 0 ? borders : void 0;
|
|
390
405
|
}
|
|
406
|
+
/** Parse cell-only diagonal borders in addition to the shared table sides. */
|
|
407
|
+
function parseTableCellBorders(tcBorders) {
|
|
408
|
+
if (!tcBorders) return;
|
|
409
|
+
const borders = { ...parseTableBorders(tcBorders) };
|
|
410
|
+
const topLeftToBottomRight = parseBorderSpec(findChild(tcBorders, "w", "tl2br"));
|
|
411
|
+
if (topLeftToBottomRight) borders.topLeftToBottomRight = topLeftToBottomRight;
|
|
412
|
+
const topRightToBottomLeft = parseBorderSpec(findChild(tcBorders, "w", "tr2bl"));
|
|
413
|
+
if (topRightToBottomLeft) borders.topRightToBottomLeft = topRightToBottomLeft;
|
|
414
|
+
return Object.keys(borders).length > 0 ? borders : void 0;
|
|
415
|
+
}
|
|
391
416
|
/**
|
|
392
417
|
* Parse cell margins
|
|
393
418
|
*/
|
|
@@ -535,7 +560,7 @@ function parseTableCellProperties(tcPr, _theme) {
|
|
|
535
560
|
}
|
|
536
561
|
const tcBorders = findChild(tcPr, "w", "tcBorders");
|
|
537
562
|
if (tcBorders) {
|
|
538
|
-
const bordersResult =
|
|
563
|
+
const bordersResult = parseTableCellBorders(tcBorders);
|
|
539
564
|
if (bordersResult) formatting.borders = bordersResult;
|
|
540
565
|
}
|
|
541
566
|
const tcMar = findChild(tcPr, "w", "tcMar");
|
package/dist/docx/tableParser.js
CHANGED
|
@@ -105,6 +105,16 @@ function parseTableBorders(bordersElement) {
|
|
|
105
105
|
if (Object.keys(borders).length === 0) return;
|
|
106
106
|
return borders;
|
|
107
107
|
}
|
|
108
|
+
/** Parse cell-only diagonal borders in addition to the shared table sides. */
|
|
109
|
+
function parseTableCellBorders(bordersElement) {
|
|
110
|
+
if (!bordersElement) return;
|
|
111
|
+
const borders = { ...parseTableBorders(bordersElement) };
|
|
112
|
+
const topLeftToBottomRight = parseBorderSpec(findChild(bordersElement, "w", "tl2br"));
|
|
113
|
+
if (topLeftToBottomRight) borders.topLeftToBottomRight = topLeftToBottomRight;
|
|
114
|
+
const topRightToBottomLeft = parseBorderSpec(findChild(bordersElement, "w", "tr2bl"));
|
|
115
|
+
if (topRightToBottomLeft) borders.topRightToBottomLeft = topRightToBottomLeft;
|
|
116
|
+
return Object.keys(borders).length > 0 ? borders : void 0;
|
|
117
|
+
}
|
|
108
118
|
/**
|
|
109
119
|
* Parse cell margins (w:tblCellMar or w:tcMar)
|
|
110
120
|
*
|
|
@@ -353,6 +363,14 @@ function parseTableCellStructuralChange(tcPrElement) {
|
|
|
353
363
|
function parseTableRowProperties(trPrElement) {
|
|
354
364
|
if (!trPrElement) return;
|
|
355
365
|
const formatting = {};
|
|
366
|
+
const gridBefore = parseNumericAttribute(findChild(trPrElement, "w", "gridBefore"), "w", "val");
|
|
367
|
+
if (gridBefore !== void 0 && gridBefore > 0) formatting.gridBefore = gridBefore;
|
|
368
|
+
const widthBefore = parseTableMeasurement(findChild(trPrElement, "w", "wBefore"));
|
|
369
|
+
if (widthBefore) formatting.widthBefore = widthBefore;
|
|
370
|
+
const gridAfter = parseNumericAttribute(findChild(trPrElement, "w", "gridAfter"), "w", "val");
|
|
371
|
+
if (gridAfter !== void 0 && gridAfter > 0) formatting.gridAfter = gridAfter;
|
|
372
|
+
const widthAfter = parseTableMeasurement(findChild(trPrElement, "w", "wAfter"));
|
|
373
|
+
if (widthAfter) formatting.widthAfter = widthAfter;
|
|
356
374
|
const heightElement = findChild(trPrElement, "w", "trHeight");
|
|
357
375
|
if (heightElement) {
|
|
358
376
|
const heightVal = parseNumericAttribute(heightElement, "w", "val");
|
|
@@ -438,7 +456,7 @@ function parseTableCellProperties(tcPrElement) {
|
|
|
438
456
|
const formatting = {};
|
|
439
457
|
const width = parseWidth(findChild(tcPrElement, "w", "tcW"));
|
|
440
458
|
if (width) formatting.width = width;
|
|
441
|
-
const borders =
|
|
459
|
+
const borders = parseTableCellBorders(findChild(tcPrElement, "w", "tcBorders"));
|
|
442
460
|
if (borders) formatting.borders = borders;
|
|
443
461
|
const margins = parseCellMargins(findChild(tcPrElement, "w", "tcMar"));
|
|
444
462
|
if (margins) formatting.margins = margins;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { findByFullName, findChildrenByLocalName, getAttribute, getChildElements, parseNumericAttribute } from "./xmlParser.js";
|
|
1
|
+
import { findByFullName, findChildByLocalName, findChildrenByLocalName, getAttribute, getChildElements, parseNumericAttribute } from "./xmlParser.js";
|
|
2
2
|
import { emuToPixels } from "../utils/units.js";
|
|
3
3
|
import { parseAnchorPosition, parseAnchorWrap, parseFill, parseOutline, resolveColorValueToHex } from "./drawingUtils.js";
|
|
4
4
|
//#region src/docx/textBoxParser.ts
|
|
@@ -11,6 +11,9 @@ const DEFAULT_MARGIN_EMU = 91440;
|
|
|
11
11
|
function parseBodyProperties(bodyPr) {
|
|
12
12
|
if (!bodyPr) return {};
|
|
13
13
|
const result = {};
|
|
14
|
+
if (findChildByLocalName(bodyPr, "spAutoFit")) result.autoFit = "shape";
|
|
15
|
+
else if (findChildByLocalName(bodyPr, "normAutofit")) result.autoFit = "normal";
|
|
16
|
+
else if (findChildByLocalName(bodyPr, "noAutofit")) result.autoFit = "none";
|
|
14
17
|
const lIns = parseNumericAttribute(bodyPr, null, "lIns");
|
|
15
18
|
const rIns = parseNumericAttribute(bodyPr, null, "rIns");
|
|
16
19
|
const tIns = parseNumericAttribute(bodyPr, null, "tIns");
|
|
@@ -121,6 +124,7 @@ function parseTextBox(drawingEl) {
|
|
|
121
124
|
if (fill) textBox.fill = fill;
|
|
122
125
|
if (outline) textBox.outline = outline;
|
|
123
126
|
if (bodyProps.margins) textBox.margins = bodyProps.margins;
|
|
127
|
+
if (bodyProps.autoFit) textBox.autoFit = bodyProps.autoFit;
|
|
124
128
|
if (isAnchor) {
|
|
125
129
|
const position = parseAnchorPosition(container);
|
|
126
130
|
if (position) textBox.position = position;
|
|
@@ -162,6 +166,7 @@ function parseTextBoxFromShape(wsp, size, position, wrap) {
|
|
|
162
166
|
if (fill) textBox.fill = fill;
|
|
163
167
|
if (outline) textBox.outline = outline;
|
|
164
168
|
if (bodyProps.margins) textBox.margins = bodyProps.margins;
|
|
169
|
+
if (bodyProps.autoFit) textBox.autoFit = bodyProps.autoFit;
|
|
165
170
|
if (position) textBox.position = position;
|
|
166
171
|
if (wrap) textBox.wrap = wrap;
|
|
167
172
|
return textBox;
|
|
@@ -1,8 +1,30 @@
|
|
|
1
|
-
import { cloneWithXmlnsDeclarations, elementToXml, findAllDeep, findChild, getAttribute } from "./xmlParser.js";
|
|
1
|
+
import { cloneWithXmlnsDeclarations, elementToXml, findAllDeep, findChild, getAttribute, getChildElements, getLocalName } from "./xmlParser.js";
|
|
2
2
|
import { pixelsToEmu } from "../utils/units.js";
|
|
3
3
|
import { resolveImageData } from "./imageParser.js";
|
|
4
4
|
import { isWatermarkShape } from "./watermarkParser.js";
|
|
5
5
|
//#region src/docx/vmlImageParser.ts
|
|
6
|
+
const MAX_VML_PREVIEW_SHAPES = 256;
|
|
7
|
+
const MAX_VML_PREVIEW_DIMENSION_PX = 2e4;
|
|
8
|
+
const MAX_VML_SVG_CHARACTERS = 1e6;
|
|
9
|
+
const SAFE_VML_COLORS = /* @__PURE__ */ new Set([
|
|
10
|
+
"black",
|
|
11
|
+
"white",
|
|
12
|
+
"red",
|
|
13
|
+
"green",
|
|
14
|
+
"blue",
|
|
15
|
+
"yellow",
|
|
16
|
+
"gray",
|
|
17
|
+
"grey",
|
|
18
|
+
"silver",
|
|
19
|
+
"maroon",
|
|
20
|
+
"purple",
|
|
21
|
+
"fuchsia",
|
|
22
|
+
"lime",
|
|
23
|
+
"olive",
|
|
24
|
+
"navy",
|
|
25
|
+
"teal",
|
|
26
|
+
"aqua"
|
|
27
|
+
]);
|
|
6
28
|
/**
|
|
7
29
|
* Convert a CSS length (pt/in/px/cm/mm/pc, default px) to pixels. Units are
|
|
8
30
|
* matched case-insensitively (`2IN`, `2Pt` are valid VML). The numeric part
|
|
@@ -40,6 +62,116 @@ function parseStyleAttr(style) {
|
|
|
40
62
|
}
|
|
41
63
|
return out;
|
|
42
64
|
}
|
|
65
|
+
const finiteNumber = (raw) => {
|
|
66
|
+
if (!raw || !/^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(raw.trim())) return;
|
|
67
|
+
const value = Number.parseFloat(raw);
|
|
68
|
+
return Number.isFinite(value) ? value : void 0;
|
|
69
|
+
};
|
|
70
|
+
const coordinatePair = (raw) => {
|
|
71
|
+
const [firstRaw, secondRaw, extra] = raw?.split(",").map((part) => part.trim()) ?? [];
|
|
72
|
+
if (extra !== void 0) return;
|
|
73
|
+
const first = finiteNumber(firstRaw);
|
|
74
|
+
const second = finiteNumber(secondRaw);
|
|
75
|
+
return first === void 0 || second === void 0 ? void 0 : {
|
|
76
|
+
first,
|
|
77
|
+
second
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
const safeColor = (raw, fallback) => {
|
|
81
|
+
const normalized = raw?.trim().toLowerCase();
|
|
82
|
+
if (!normalized) return fallback;
|
|
83
|
+
if (SAFE_VML_COLORS.has(normalized)) return normalized;
|
|
84
|
+
if (/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/u.test(normalized)) return normalized;
|
|
85
|
+
return /^[0-9a-f]{6}$/u.test(normalized) ? `#${normalized}` : fallback;
|
|
86
|
+
};
|
|
87
|
+
const validPreviewDimension = (value) => value !== void 0 && value > 0 && value <= MAX_VML_PREVIEW_DIMENSION_PX;
|
|
88
|
+
const svgDataUrl = (svg) => svg.length <= MAX_VML_SVG_CHARACTERS ? `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}` : void 0;
|
|
89
|
+
const vmlShapeSvg = (shape, width, height, x = 0, y = 0) => {
|
|
90
|
+
const fill = safeColor(getAttribute(shape, null, "fillcolor"), "white");
|
|
91
|
+
const stroke = getAttribute(shape, null, "stroked")?.toLowerCase() !== "f" ? safeColor(getAttribute(shape, null, "strokecolor"), "black") : "none";
|
|
92
|
+
const localName = getLocalName(shape.name ?? "");
|
|
93
|
+
if (localName === "oval") return `<ellipse cx="${x + width / 2}" cy="${y + height / 2}" rx="${width / 2}" ry="${height / 2}" fill="${fill}" stroke="${stroke}"/>`;
|
|
94
|
+
return `<rect x="${x}" y="${y}" width="${width}" height="${height}" rx="${localName === "roundrect" ? Math.min(width, height) * .1 : 0}" fill="${fill}" stroke="${stroke}"/>`;
|
|
95
|
+
};
|
|
96
|
+
const previewImage = (pictElement, svg, widthPx, heightPx, style, rootXmlns) => {
|
|
97
|
+
const src = svgDataUrl(svg);
|
|
98
|
+
if (!src) return null;
|
|
99
|
+
const leftPx = cssLengthToPx(style["margin-left"] ?? style["left"]) ?? 0;
|
|
100
|
+
const topPx = cssLengthToPx(style["margin-top"] ?? style["top"]) ?? 0;
|
|
101
|
+
const horizontalRelative = style["mso-position-horizontal-relative"] === "page";
|
|
102
|
+
const verticalRelative = style["mso-position-vertical-relative"] === "page";
|
|
103
|
+
const zIndex = finiteNumber(style["z-index"]);
|
|
104
|
+
return {
|
|
105
|
+
type: "drawing",
|
|
106
|
+
image: {
|
|
107
|
+
type: "image",
|
|
108
|
+
rId: "",
|
|
109
|
+
src,
|
|
110
|
+
mimeType: "image/svg+xml",
|
|
111
|
+
filename: "vml-shape-preview.svg",
|
|
112
|
+
size: {
|
|
113
|
+
width: pixelsToEmu(widthPx),
|
|
114
|
+
height: pixelsToEmu(heightPx)
|
|
115
|
+
},
|
|
116
|
+
wrap: { type: zIndex !== void 0 && zIndex >= 0 ? "inFront" : "behind" },
|
|
117
|
+
position: {
|
|
118
|
+
horizontal: {
|
|
119
|
+
relativeTo: horizontalRelative ? "page" : "character",
|
|
120
|
+
posOffset: pixelsToEmu(leftPx)
|
|
121
|
+
},
|
|
122
|
+
vertical: {
|
|
123
|
+
relativeTo: verticalRelative ? "page" : "paragraph",
|
|
124
|
+
posOffset: pixelsToEmu(topPx)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
rawXml: elementToXml(cloneWithXmlnsDeclarations(pictElement, rootXmlns))
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
const parseStandaloneShapePreview = (pictElement, shape, rootXmlns) => {
|
|
132
|
+
const style = parseStyleAttr(getAttribute(shape, null, "style"));
|
|
133
|
+
const widthPx = cssLengthToPx(style["width"]);
|
|
134
|
+
const heightPx = cssLengthToPx(style["height"]);
|
|
135
|
+
if (!validPreviewDimension(widthPx) || !validPreviewDimension(heightPx)) return null;
|
|
136
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${widthPx} ${heightPx}" width="${widthPx}" height="${heightPx}">${vmlShapeSvg(shape, widthPx, heightPx)}</svg>`;
|
|
137
|
+
return previewImage(pictElement, svg, widthPx, heightPx, style, rootXmlns);
|
|
138
|
+
};
|
|
139
|
+
const parseGroupPreview = (pictElement, group, rootXmlns) => {
|
|
140
|
+
const style = parseStyleAttr(getAttribute(group, null, "style"));
|
|
141
|
+
const widthPx = cssLengthToPx(style["width"]);
|
|
142
|
+
const heightPx = cssLengthToPx(style["height"]);
|
|
143
|
+
if (!validPreviewDimension(widthPx) || !validPreviewDimension(heightPx)) return null;
|
|
144
|
+
const origin = coordinatePair(getAttribute(group, null, "coordorigin")) ?? {
|
|
145
|
+
first: 0,
|
|
146
|
+
second: 0
|
|
147
|
+
};
|
|
148
|
+
const size = coordinatePair(getAttribute(group, null, "coordsize")) ?? {
|
|
149
|
+
first: widthPx,
|
|
150
|
+
second: heightPx
|
|
151
|
+
};
|
|
152
|
+
if (size.first <= 0 || size.second <= 0) return null;
|
|
153
|
+
const content = getChildElements(group).slice(0, MAX_VML_PREVIEW_SHAPES).map((child) => {
|
|
154
|
+
const localName = getLocalName(child.name ?? "");
|
|
155
|
+
if (localName === "line") {
|
|
156
|
+
const from = coordinatePair(getAttribute(child, null, "from"));
|
|
157
|
+
const to = coordinatePair(getAttribute(child, null, "to"));
|
|
158
|
+
if (!from || !to) return "";
|
|
159
|
+
const stroke = safeColor(getAttribute(child, null, "strokecolor"), "black");
|
|
160
|
+
return `<line x1="${from.first}" y1="${from.second}" x2="${to.first}" y2="${to.second}" stroke="${stroke}"/>`;
|
|
161
|
+
}
|
|
162
|
+
if (localName !== "rect" && localName !== "roundrect" && localName !== "oval") return "";
|
|
163
|
+
const childStyle = parseStyleAttr(getAttribute(child, null, "style"));
|
|
164
|
+
const x = finiteNumber(childStyle["left"]);
|
|
165
|
+
const y = finiteNumber(childStyle["top"]);
|
|
166
|
+
const width = finiteNumber(childStyle["width"]);
|
|
167
|
+
const height = finiteNumber(childStyle["height"]);
|
|
168
|
+
if (x === void 0 || y === void 0 || width === void 0 || height === void 0) return "";
|
|
169
|
+
return vmlShapeSvg(child, width, height, x, y);
|
|
170
|
+
}).join("");
|
|
171
|
+
if (!content) return null;
|
|
172
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${origin.first} ${origin.second} ${size.first} ${size.second}" width="${widthPx}" height="${heightPx}">${content}</svg>`;
|
|
173
|
+
return previewImage(pictElement, svg, widthPx, heightPx, style, rootXmlns);
|
|
174
|
+
};
|
|
43
175
|
/**
|
|
44
176
|
* Read the relationship id off a `v:imagedata` element. Word writes `r:id`;
|
|
45
177
|
* some legacy / third-party generators use `r:embed` or the office-namespace
|
|
@@ -74,6 +206,7 @@ function parseVmlImageContent(pictElement, rels, media, rootXmlns = {}) {
|
|
|
74
206
|
const shapeStyle = parseStyleAttr(getAttribute(shape, null, "style"));
|
|
75
207
|
const widthPx = cssLengthToPx(shapeStyle["width"]);
|
|
76
208
|
const heightPx = cssLengthToPx(shapeStyle["height"]);
|
|
209
|
+
if (getLocalName(pictElement.name ?? "") === "object" && (widthPx !== void 0 && !validPreviewDimension(widthPx) || heightPx !== void 0 && !validPreviewDimension(heightPx))) continue;
|
|
77
210
|
const image = {
|
|
78
211
|
type: "image",
|
|
79
212
|
rId,
|
|
@@ -94,6 +227,18 @@ function parseVmlImageContent(pictElement, rels, media, rootXmlns = {}) {
|
|
|
94
227
|
rawXml: elementToXml(cloneWithXmlnsDeclarations(pictElement, rootXmlns))
|
|
95
228
|
};
|
|
96
229
|
}
|
|
230
|
+
for (const child of getChildElements(pictElement)) {
|
|
231
|
+
const localName = getLocalName(child.name ?? "");
|
|
232
|
+
if (localName === "group") {
|
|
233
|
+
const preview = parseGroupPreview(pictElement, child, rootXmlns);
|
|
234
|
+
if (preview) return preview;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (localName === "rect" || localName === "roundrect" || localName === "oval") {
|
|
238
|
+
const preview = parseStandaloneShapePreview(pictElement, child, rootXmlns);
|
|
239
|
+
if (preview) return preview;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
97
242
|
return null;
|
|
98
243
|
}
|
|
99
244
|
//#endregion
|