@portone/docx-editor 0.1.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/CHANGELOG.md +7 -0
- package/CONTRIBUTING.md +63 -0
- package/LICENSE +203 -0
- package/README.md +48 -0
- package/assets/editor.png +0 -0
- package/dist/DocxEditor.d.ts +123 -0
- package/dist/DocxEditor.js +348 -0
- package/dist/core.d.ts +36 -0
- package/dist/core.js +38 -0
- package/dist/docx/comments/constants.d.ts +8 -0
- package/dist/docx/comments/constants.js +20 -0
- package/dist/docx/comments/model.d.ts +37 -0
- package/dist/docx/comments/model.js +104 -0
- package/dist/docx/comments/reading.d.ts +36 -0
- package/dist/docx/comments/reading.js +149 -0
- package/dist/docx/comments/writing.d.ts +11 -0
- package/dist/docx/comments/writing.js +327 -0
- package/dist/docx/comments.d.ts +3 -0
- package/dist/docx/comments.js +4 -0
- package/dist/docx/container.d.ts +12 -0
- package/dist/docx/container.js +130 -0
- package/dist/docx/documentSettings.d.ts +4 -0
- package/dist/docx/documentSettings.js +14 -0
- package/dist/docx/exportDocx.d.ts +15 -0
- package/dist/docx/exportDocx.js +163 -0
- package/dist/docx/exportRefs.d.ts +16 -0
- package/dist/docx/exportRefs.js +10 -0
- package/dist/docx/formatting/direct.d.ts +30 -0
- package/dist/docx/formatting/direct.js +201 -0
- package/dist/docx/formatting/effectiveParagraph.d.ts +15 -0
- package/dist/docx/formatting/effectiveParagraph.js +81 -0
- package/dist/docx/formatting/styles.d.ts +67 -0
- package/dist/docx/formatting/styles.js +165 -0
- package/dist/docx/formatting/tabStops.d.ts +8 -0
- package/dist/docx/formatting/tabStops.js +65 -0
- package/dist/docx/formatting.d.ts +4 -0
- package/dist/docx/formatting.js +4 -0
- package/dist/docx/headersFooters.d.ts +36 -0
- package/dist/docx/headersFooters.js +218 -0
- package/dist/docx/hyperlink.d.ts +75 -0
- package/dist/docx/hyperlink.js +71 -0
- package/dist/docx/importDocx.d.ts +21 -0
- package/dist/docx/importDocx.js +263 -0
- package/dist/docx/importParagraph.d.ts +32 -0
- package/dist/docx/importParagraph.js +308 -0
- package/dist/docx/importTable.d.ts +9 -0
- package/dist/docx/importTable.js +275 -0
- package/dist/docx/media.d.ts +60 -0
- package/dist/docx/media.js +213 -0
- package/dist/docx/notes.d.ts +22 -0
- package/dist/docx/notes.js +71 -0
- package/dist/docx/pageGeometry.d.ts +75 -0
- package/dist/docx/pageGeometry.js +88 -0
- package/dist/docx/paraProps.d.ts +74 -0
- package/dist/docx/paraProps.js +167 -0
- package/dist/docx/propsXml.d.ts +49 -0
- package/dist/docx/propsXml.js +302 -0
- package/dist/docx/relationships.d.ts +42 -0
- package/dist/docx/relationships.js +94 -0
- package/dist/docx/runProps.d.ts +51 -0
- package/dist/docx/runProps.js +207 -0
- package/dist/docx/scan.d.ts +20 -0
- package/dist/docx/scan.js +110 -0
- package/dist/docx/sdt.d.ts +56 -0
- package/dist/docx/sdt.js +104 -0
- package/dist/docx/sdtProps.d.ts +18 -0
- package/dist/docx/sdtProps.js +11 -0
- package/dist/docx/serializeBlock.d.ts +4 -0
- package/dist/docx/serializeBlock.js +30 -0
- package/dist/docx/serializeParagraph.d.ts +15 -0
- package/dist/docx/serializeParagraph.js +208 -0
- package/dist/docx/serializeTable.d.ts +12 -0
- package/dist/docx/serializeTable.js +134 -0
- package/dist/docx/session.d.ts +81 -0
- package/dist/docx/session.js +79 -0
- package/dist/docx/tableFormatting/editing.d.ts +64 -0
- package/dist/docx/tableFormatting/editing.js +318 -0
- package/dist/docx/tableFormatting/reading.d.ts +96 -0
- package/dist/docx/tableFormatting/reading.js +221 -0
- package/dist/docx/tableFormatting.d.ts +2 -0
- package/dist/docx/tableFormatting.js +3 -0
- package/dist/docx/tableTemplate.d.ts +22 -0
- package/dist/docx/tableTemplate.js +111 -0
- package/dist/docx/theme.d.ts +40 -0
- package/dist/docx/theme.js +61 -0
- package/dist/docx/uniqueControls.d.ts +14 -0
- package/dist/docx/uniqueControls.js +62 -0
- package/dist/download.d.ts +57 -0
- package/dist/download.js +44 -0
- package/dist/editor/clipboard/images.d.ts +14 -0
- package/dist/editor/clipboard/images.js +158 -0
- package/dist/editor/clipboard/inlineFormatting.d.ts +21 -0
- package/dist/editor/clipboard/inlineFormatting.js +232 -0
- package/dist/editor/commands/breakCommands.d.ts +8 -0
- package/dist/editor/commands/breakCommands.js +19 -0
- package/dist/editor/commands/canRunCommand.d.ts +6 -0
- package/dist/editor/commands/canRunCommand.js +10 -0
- package/dist/editor/commands/commentCommands.d.ts +3 -0
- package/dist/editor/commands/commentCommands.js +4 -0
- package/dist/editor/commands/comments/editing.d.ts +21 -0
- package/dist/editor/commands/comments/editing.js +305 -0
- package/dist/editor/commands/comments/model.d.ts +31 -0
- package/dist/editor/commands/comments/model.js +0 -0
- package/dist/editor/commands/comments/reading.d.ts +8 -0
- package/dist/editor/commands/comments/reading.js +58 -0
- package/dist/editor/commands/formatting/editing.d.ts +32 -0
- package/dist/editor/commands/formatting/editing.js +138 -0
- package/dist/editor/commands/formatting/reading.d.ts +57 -0
- package/dist/editor/commands/formatting/reading.js +82 -0
- package/dist/editor/commands/formatting/shared.d.ts +32 -0
- package/dist/editor/commands/formatting/shared.js +53 -0
- package/dist/editor/commands/formattingCommands.d.ts +2 -0
- package/dist/editor/commands/formattingCommands.js +3 -0
- package/dist/editor/commands/historyCommands.d.ts +11 -0
- package/dist/editor/commands/historyCommands.js +16 -0
- package/dist/editor/commands/indentCommands.d.ts +15 -0
- package/dist/editor/commands/indentCommands.js +44 -0
- package/dist/editor/commands/index.d.ts +82 -0
- package/dist/editor/commands/index.js +171 -0
- package/dist/editor/commands/linkCommands.d.ts +56 -0
- package/dist/editor/commands/linkCommands.js +146 -0
- package/dist/editor/commands/listCommands.d.ts +58 -0
- package/dist/editor/commands/listCommands.js +140 -0
- package/dist/editor/commands/lockCommands.d.ts +47 -0
- package/dist/editor/commands/lockCommands.js +198 -0
- package/dist/editor/commands/noteQueries.d.ts +12 -0
- package/dist/editor/commands/noteQueries.js +29 -0
- package/dist/editor/commands/paragraphCommands.d.ts +59 -0
- package/dist/editor/commands/paragraphCommands.js +113 -0
- package/dist/editor/commands/spacingCommands.d.ts +23 -0
- package/dist/editor/commands/spacingCommands.js +48 -0
- package/dist/editor/commands/tabCommands.d.ts +5 -0
- package/dist/editor/commands/tabCommands.js +65 -0
- package/dist/editor/createEditor.d.ts +59 -0
- package/dist/editor/createEditor.js +160 -0
- package/dist/editor/documentStyles.d.ts +60 -0
- package/dist/editor/documentStyles.js +80 -0
- package/dist/editor/externalClipboard.d.ts +11 -0
- package/dist/editor/externalClipboard.js +323 -0
- package/dist/editor/imageFiles.d.ts +74 -0
- package/dist/editor/imageFiles.js +173 -0
- package/dist/editor/insertImage.d.ts +31 -0
- package/dist/editor/insertImage.js +35 -0
- package/dist/editor/insertTable.d.ts +18 -0
- package/dist/editor/insertTable.js +44 -0
- package/dist/editor/paragraphEdits.d.ts +42 -0
- package/dist/editor/paragraphEdits.js +59 -0
- package/dist/editor/plainText.d.ts +3 -0
- package/dist/editor/plainText.js +50 -0
- package/dist/editor/plugins/bookmarkProtection.d.ts +3 -0
- package/dist/editor/plugins/bookmarkProtection.js +28 -0
- package/dist/editor/plugins/columnResize.d.ts +27 -0
- package/dist/editor/plugins/columnResize.js +192 -0
- package/dist/editor/plugins/commentDecorations.d.ts +3 -0
- package/dist/editor/plugins/commentDecorations.js +23 -0
- package/dist/editor/plugins/commentReservations.d.ts +5 -0
- package/dist/editor/plugins/commentReservations.js +26 -0
- package/dist/editor/plugins/dropCaret.d.ts +10 -0
- package/dist/editor/plugins/dropCaret.js +11 -0
- package/dist/editor/plugins/imagePaste.d.ts +8 -0
- package/dist/editor/plugins/imagePaste.js +265 -0
- package/dist/editor/plugins/keymap.d.ts +5 -0
- package/dist/editor/plugins/keymap.js +94 -0
- package/dist/editor/plugins/linkPanel.d.ts +23 -0
- package/dist/editor/plugins/linkPanel.js +39 -0
- package/dist/editor/plugins/listInputRules.d.ts +14 -0
- package/dist/editor/plugins/listInputRules.js +36 -0
- package/dist/editor/plugins/lockedContent.d.ts +6 -0
- package/dist/editor/plugins/lockedContent.js +41 -0
- package/dist/editor/plugins/noteProtection.d.ts +3 -0
- package/dist/editor/plugins/noteProtection.js +25 -0
- package/dist/editor/plugins/numberingDecorations.d.ts +42 -0
- package/dist/editor/plugins/numberingDecorations.js +110 -0
- package/dist/editor/plugins/rowResize.d.ts +15 -0
- package/dist/editor/plugins/rowResize.js +196 -0
- package/dist/editor/plugins/styledParagraphs.d.ts +15 -0
- package/dist/editor/plugins/styledParagraphs.js +65 -0
- package/dist/editor/plugins/tabCaret.d.ts +3 -0
- package/dist/editor/plugins/tabCaret.js +126 -0
- package/dist/editor/plugins/tabDecorations.d.ts +11 -0
- package/dist/editor/plugins/tabDecorations.js +87 -0
- package/dist/editor/plugins/tabLayout.d.ts +16 -0
- package/dist/editor/plugins/tabLayout.js +328 -0
- package/dist/editor/plugins/tabPointer.d.ts +7 -0
- package/dist/editor/plugins/tabPointer.js +95 -0
- package/dist/editor/plugins/tableContextMenu.d.ts +21 -0
- package/dist/editor/plugins/tableContextMenu.js +88 -0
- package/dist/editor/plugins/textContextMenu.d.ts +15 -0
- package/dist/editor/plugins/textContextMenu.js +90 -0
- package/dist/editor/views/imageResize.d.ts +53 -0
- package/dist/editor/views/imageResize.js +167 -0
- package/dist/editor/views/runMarkView.d.ts +15 -0
- package/dist/editor/views/runMarkView.js +9 -0
- package/dist/editor/views/tableView.d.ts +24 -0
- package/dist/editor/views/tableView.js +32 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +38 -0
- package/dist/model/format.d.ts +240 -0
- package/dist/model/format.js +305 -0
- package/dist/model/tabStops.d.ts +17 -0
- package/dist/model/tabStops.js +22 -0
- package/dist/numbering/listTemplate.d.ts +29 -0
- package/dist/numbering/listTemplate.js +83 -0
- package/dist/numbering/markers.d.ts +24 -0
- package/dist/numbering/markers.js +93 -0
- package/dist/numbering/parseNumbering.d.ts +65 -0
- package/dist/numbering/parseNumbering.js +116 -0
- package/dist/numbering/writeNumbering.d.ts +13 -0
- package/dist/numbering/writeNumbering.js +49 -0
- package/dist/ooxml/errors.d.ts +39 -0
- package/dist/ooxml/errors.js +21 -0
- package/dist/ooxml/image.d.ts +88 -0
- package/dist/ooxml/image.js +106 -0
- package/dist/ooxml/tabStops.d.ts +3 -0
- package/dist/ooxml/tabStops.js +51 -0
- package/dist/ooxml/units.d.ts +37 -0
- package/dist/ooxml/units.js +116 -0
- package/dist/ooxml/xml.d.ts +36 -0
- package/dist/ooxml/xml.js +89 -0
- package/dist/page/PageGuides.d.ts +16 -0
- package/dist/page/PageGuides.js +114 -0
- package/dist/page/measureBlocks.d.ts +25 -0
- package/dist/page/measureBlocks.js +80 -0
- package/dist/page/pageDecorations.d.ts +36 -0
- package/dist/page/pageDecorations.js +211 -0
- package/dist/page/pageLayout.d.ts +176 -0
- package/dist/page/pageLayout.js +157 -0
- package/dist/page/tableMeasurements.d.ts +10 -0
- package/dist/page/tableMeasurements.js +115 -0
- package/dist/page/usePageLayout.d.ts +57 -0
- package/dist/page/usePageLayout.js +141 -0
- package/dist/schema/docxSchema.d.ts +9 -0
- package/dist/schema/docxSchema.js +863 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +9 -0
- package/dist/schema/locks.d.ts +112 -0
- package/dist/schema/locks.js +211 -0
- package/dist/schema/rendering.d.ts +6 -0
- package/dist/schema/rendering.js +46 -0
- package/dist/styles/classNames.d.ts +214 -0
- package/dist/styles/classNames.js +208 -0
- package/dist/styles/colors.d.ts +11 -0
- package/dist/styles/colors.js +14 -0
- package/dist/styles/fontSizes.d.ts +6 -0
- package/dist/styles/fontSizes.js +20 -0
- package/dist/styles/fontStack.d.ts +55 -0
- package/dist/styles/fontStack.js +262 -0
- package/dist/styles/fonts.d.ts +6 -0
- package/dist/styles/fonts.js +11 -0
- package/dist/styles/inlineStyle.d.ts +67 -0
- package/dist/styles/inlineStyle.js +212 -0
- package/dist/styles/lineSpacings.d.ts +11 -0
- package/dist/styles/lineSpacings.js +10 -0
- package/dist/styles.css +1650 -0
- package/dist/table/cellBorders.d.ts +12 -0
- package/dist/table/cellBorders.js +9 -0
- package/dist/table/cellFormatting.d.ts +57 -0
- package/dist/table/cellFormatting.js +173 -0
- package/dist/table/columns.d.ts +25 -0
- package/dist/table/columns.js +155 -0
- package/dist/table/commands.d.ts +19 -0
- package/dist/table/commands.js +63 -0
- package/dist/table/format.d.ts +35 -0
- package/dist/table/format.js +26 -0
- package/dist/table/gridBorders.d.ts +42 -0
- package/dist/table/gridBorders.js +192 -0
- package/dist/table/index.d.ts +16 -0
- package/dist/table/index.js +52 -0
- package/dist/table/merge.d.ts +36 -0
- package/dist/table/merge.js +125 -0
- package/dist/table/resize.d.ts +55 -0
- package/dist/table/resize.js +66 -0
- package/dist/table/rowResize.d.ts +14 -0
- package/dist/table/rowResize.js +44 -0
- package/dist/table/rows.d.ts +32 -0
- package/dist/table/rows.js +89 -0
- package/dist/table/widths.d.ts +69 -0
- package/dist/table/widths.js +97 -0
- package/dist/ui/AlignMenu.d.ts +15 -0
- package/dist/ui/AlignMenu.js +64 -0
- package/dist/ui/CellStyleGroup.d.ts +15 -0
- package/dist/ui/CellStyleGroup.js +232 -0
- package/dist/ui/ColorPicker.d.ts +13 -0
- package/dist/ui/ColorPicker.js +165 -0
- package/dist/ui/CommentsPanel.d.ts +15 -0
- package/dist/ui/CommentsPanel.js +348 -0
- package/dist/ui/FontFamilySelect.d.ts +14 -0
- package/dist/ui/FontFamilySelect.js +59 -0
- package/dist/ui/FontSizeSelect.d.ts +11 -0
- package/dist/ui/FontSizeSelect.js +49 -0
- package/dist/ui/InsertImageButton.d.ts +9 -0
- package/dist/ui/InsertImageButton.js +47 -0
- package/dist/ui/LinkCard.d.ts +12 -0
- package/dist/ui/LinkCard.js +127 -0
- package/dist/ui/LinkPanel.d.ts +9 -0
- package/dist/ui/LinkPanel.js +121 -0
- package/dist/ui/MenuChoice.d.ts +11 -0
- package/dist/ui/MenuChoice.js +32 -0
- package/dist/ui/NotesPanel.d.ts +6 -0
- package/dist/ui/NotesPanel.js +33 -0
- package/dist/ui/ParagraphStyleSelect.d.ts +11 -0
- package/dist/ui/ParagraphStyleSelect.js +62 -0
- package/dist/ui/Popover.d.ts +22 -0
- package/dist/ui/Popover.js +74 -0
- package/dist/ui/SpacingMenu.d.ts +12 -0
- package/dist/ui/SpacingMenu.js +54 -0
- package/dist/ui/TableMenu.d.ts +12 -0
- package/dist/ui/TableMenu.js +112 -0
- package/dist/ui/TableSizePicker.d.ts +9 -0
- package/dist/ui/TableSizePicker.js +53 -0
- package/dist/ui/TextMenu.d.ts +15 -0
- package/dist/ui/TextMenu.js +194 -0
- package/dist/ui/Toolbar.d.ts +19 -0
- package/dist/ui/Toolbar.js +448 -0
- package/dist/ui/ToolbarButton.d.ts +23 -0
- package/dist/ui/ToolbarButton.js +56 -0
- package/dist/ui/Tooltip.d.ts +19 -0
- package/dist/ui/Tooltip.js +47 -0
- package/dist/ui/ZoomSelect.d.ts +7 -0
- package/dist/ui/ZoomSelect.js +44 -0
- package/dist/ui/comments/CommentComposer.d.ts +17 -0
- package/dist/ui/comments/CommentComposer.js +59 -0
- package/dist/ui/comments/useCommentRailLayout.d.ts +18 -0
- package/dist/ui/comments/useCommentRailLayout.js +183 -0
- package/dist/ui/keyboardWalk.d.ts +22 -0
- package/dist/ui/keyboardWalk.js +70 -0
- package/dist/ui/openAddress.d.ts +11 -0
- package/dist/ui/openAddress.js +16 -0
- package/dist/ui/panelPlacement.d.ts +51 -0
- package/dist/ui/panelPlacement.js +71 -0
- package/dist/ui/presets.d.ts +11 -0
- package/dist/ui/presets.js +0 -0
- package/dist/ui/rovingFocus.d.ts +20 -0
- package/dist/ui/rovingFocus.js +61 -0
- package/dist/ui/runCommand.d.ts +5 -0
- package/dist/ui/runCommand.js +13 -0
- package/dist/ui/useDismiss.d.ts +6 -0
- package/dist/ui/useDismiss.js +31 -0
- package/dist/ui/useFitWidthZoom.d.ts +2 -0
- package/dist/ui/useFitWidthZoom.js +26 -0
- package/dist/ui/useGridKeyboard.d.ts +12 -0
- package/dist/ui/useGridKeyboard.js +90 -0
- package/dist/ui/useMenuKeyboard.d.ts +12 -0
- package/dist/ui/useMenuKeyboard.js +56 -0
- package/dist/ui/zoom.d.ts +4 -0
- package/dist/ui/zoom.js +21 -0
- package/package.json +120 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// src/numbering/parseNumbering.ts
|
|
2
|
+
import { readTabStopDirectives } from "../ooxml/tabStops.js";
|
|
3
|
+
import { childValue, round, wAttr } from "../ooxml/units.js";
|
|
4
|
+
import { childByLocalName, elementChildren, parseXml } from "../ooxml/xml.js";
|
|
5
|
+
var NUMBER_FORMATS = [
|
|
6
|
+
"decimal",
|
|
7
|
+
"bullet",
|
|
8
|
+
"lowerLetter",
|
|
9
|
+
"upperLetter",
|
|
10
|
+
"lowerRoman"
|
|
11
|
+
];
|
|
12
|
+
var EMPTY_NUMBERING = { lists: /* @__PURE__ */ new Map() };
|
|
13
|
+
function toInteger(value) {
|
|
14
|
+
if (value === null) return null;
|
|
15
|
+
const parsed = Number.parseInt(value, 10);
|
|
16
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
17
|
+
}
|
|
18
|
+
function isNumberFormat(value) {
|
|
19
|
+
return NUMBER_FORMATS.some((format) => format === value);
|
|
20
|
+
}
|
|
21
|
+
function indentOf(lvl) {
|
|
22
|
+
const pPr = childByLocalName(lvl, "pPr");
|
|
23
|
+
const ind = pPr ? childByLocalName(pPr, "ind") : null;
|
|
24
|
+
if (!ind) return null;
|
|
25
|
+
const startTwips = toInteger(wAttr(ind, "start") ?? wAttr(ind, "left"));
|
|
26
|
+
const endTwips = toInteger(wAttr(ind, "end") ?? wAttr(ind, "right"));
|
|
27
|
+
const indent = {
|
|
28
|
+
startTwips,
|
|
29
|
+
endTwips,
|
|
30
|
+
hangingTwips: toInteger(wAttr(ind, "hanging")),
|
|
31
|
+
firstLineTwips: toInteger(wAttr(ind, "firstLine"))
|
|
32
|
+
};
|
|
33
|
+
const empty = startTwips === null && endTwips === null && indent.hangingTwips === null && indent.firstLineTwips === null;
|
|
34
|
+
return empty ? null : indent;
|
|
35
|
+
}
|
|
36
|
+
var NO_LEVEL_INDENT = {
|
|
37
|
+
startPt: null,
|
|
38
|
+
endPt: null,
|
|
39
|
+
textIndentPt: null
|
|
40
|
+
};
|
|
41
|
+
function twipsToPt(twips) {
|
|
42
|
+
return twips === null ? null : round(twips / 20);
|
|
43
|
+
}
|
|
44
|
+
function levelIndentPt(indent) {
|
|
45
|
+
if (!indent) return NO_LEVEL_INDENT;
|
|
46
|
+
const hangingPt = twipsToPt(indent.hangingTwips);
|
|
47
|
+
return {
|
|
48
|
+
startPt: twipsToPt(indent.startTwips),
|
|
49
|
+
endPt: twipsToPt(indent.endTwips),
|
|
50
|
+
textIndentPt: hangingPt !== null ? -hangingPt : twipsToPt(indent.firstLineTwips)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function readLevel(lvl) {
|
|
54
|
+
const format = childValue(lvl, "numFmt");
|
|
55
|
+
const pPr = childByLocalName(lvl, "pPr");
|
|
56
|
+
const tabStops = readTabStopDirectives(pPr);
|
|
57
|
+
return {
|
|
58
|
+
format: isNumberFormat(format) ? format : "decimal",
|
|
59
|
+
text: childValue(lvl, "lvlText") ?? "",
|
|
60
|
+
start: toInteger(childValue(lvl, "start")) ?? 1,
|
|
61
|
+
indent: indentOf(lvl),
|
|
62
|
+
...tabStops.length === 0 ? {} : { tabStops }
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function readLevels(parent) {
|
|
66
|
+
const levels = /* @__PURE__ */ new Map();
|
|
67
|
+
for (const child of elementChildren(parent)) {
|
|
68
|
+
if (child.localName !== "lvl") continue;
|
|
69
|
+
const ilvl = toInteger(wAttr(child, "ilvl"));
|
|
70
|
+
if (ilvl !== null) levels.set(ilvl, readLevel(child));
|
|
71
|
+
}
|
|
72
|
+
return levels;
|
|
73
|
+
}
|
|
74
|
+
function readList(num, abstractLevels) {
|
|
75
|
+
const abstractNumId = toInteger(childValue(num, "abstractNumId"));
|
|
76
|
+
if (abstractNumId === null) return null;
|
|
77
|
+
const levels = new Map(abstractLevels.get(abstractNumId) ?? []);
|
|
78
|
+
for (const child of elementChildren(num)) {
|
|
79
|
+
if (child.localName !== "lvlOverride") continue;
|
|
80
|
+
const ilvl = toInteger(wAttr(child, "ilvl"));
|
|
81
|
+
if (ilvl === null) continue;
|
|
82
|
+
const replacement = childByLocalName(child, "lvl");
|
|
83
|
+
const base = replacement ? readLevel(replacement) : levels.get(ilvl);
|
|
84
|
+
if (!base) continue;
|
|
85
|
+
const startOverride = toInteger(childValue(child, "startOverride"));
|
|
86
|
+
levels.set(
|
|
87
|
+
ilvl,
|
|
88
|
+
startOverride === null ? base : { ...base, start: startOverride }
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return { levels };
|
|
92
|
+
}
|
|
93
|
+
function parseNumbering(xml) {
|
|
94
|
+
if (xml === null) return EMPTY_NUMBERING;
|
|
95
|
+
const root = parseXml(xml).documentElement;
|
|
96
|
+
const abstractLevels = /* @__PURE__ */ new Map();
|
|
97
|
+
for (const child of elementChildren(root)) {
|
|
98
|
+
if (child.localName !== "abstractNum") continue;
|
|
99
|
+
const id = toInteger(wAttr(child, "abstractNumId"));
|
|
100
|
+
if (id !== null) abstractLevels.set(id, readLevels(child));
|
|
101
|
+
}
|
|
102
|
+
const lists = /* @__PURE__ */ new Map();
|
|
103
|
+
for (const child of elementChildren(root)) {
|
|
104
|
+
if (child.localName !== "num") continue;
|
|
105
|
+
const numId = toInteger(wAttr(child, "numId"));
|
|
106
|
+
const list = numId === null ? null : readList(child, abstractLevels);
|
|
107
|
+
if (numId !== null && list) lists.set(numId, list);
|
|
108
|
+
}
|
|
109
|
+
return { lists };
|
|
110
|
+
}
|
|
111
|
+
export {
|
|
112
|
+
EMPTY_NUMBERING,
|
|
113
|
+
NO_LEVEL_INDENT,
|
|
114
|
+
levelIndentPt,
|
|
115
|
+
parseNumbering
|
|
116
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splices the definitions of newly started lists into the original numbering.xml.
|
|
3
|
+
*
|
|
4
|
+
* Not one character of the original is altered; new elements are merely slotted in at
|
|
5
|
+
* two places.
|
|
6
|
+
* OOXML requires the definitions (`abstractNum`) to come before the numbers (`num`), so
|
|
7
|
+
* the definitions go in front of the first number and the numbers go at the very end.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* numbering.xml with a standard template definition added for every list number.
|
|
11
|
+
* When there is nothing to add, the original string is returned unchanged.
|
|
12
|
+
*/
|
|
13
|
+
export declare function addListDefinitions(xml: string, numIds: readonly number[]): string;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// src/numbering/writeNumbering.ts
|
|
2
|
+
import { DocxExportError } from "../ooxml/errors.js";
|
|
3
|
+
import { wAttr } from "../ooxml/units.js";
|
|
4
|
+
import { elementChildren, parseXml } from "../ooxml/xml.js";
|
|
5
|
+
import { abstractNumXml, listKindOf, numXml } from "./listTemplate.js";
|
|
6
|
+
function openTagAt(xml, name) {
|
|
7
|
+
const match = new RegExp(`<(?:[A-Za-z_][\\w.-]*:)?${name}[\\s/>]`).exec(xml);
|
|
8
|
+
return match ? match.index : null;
|
|
9
|
+
}
|
|
10
|
+
function closeTagAt(xml, name) {
|
|
11
|
+
const matches = Array.from(
|
|
12
|
+
xml.matchAll(new RegExp(`</(?:[A-Za-z_][\\w.-]*:)?${name}\\s*>`, "g"))
|
|
13
|
+
);
|
|
14
|
+
return matches.at(-1)?.index ?? null;
|
|
15
|
+
}
|
|
16
|
+
function maxAbstractNumId(xml) {
|
|
17
|
+
let max = 0;
|
|
18
|
+
for (const child of elementChildren(parseXml(xml).documentElement)) {
|
|
19
|
+
if (child.localName !== "abstractNum") continue;
|
|
20
|
+
const id = Number.parseInt(wAttr(child, "abstractNumId") ?? "", 10);
|
|
21
|
+
if (Number.isFinite(id)) max = Math.max(max, id);
|
|
22
|
+
}
|
|
23
|
+
return max;
|
|
24
|
+
}
|
|
25
|
+
function addListDefinitions(xml, numIds) {
|
|
26
|
+
if (numIds.length === 0) return xml;
|
|
27
|
+
const rootEnd = closeTagAt(xml, "numbering");
|
|
28
|
+
if (rootEnd === null) {
|
|
29
|
+
throw new DocxExportError(
|
|
30
|
+
"malformed-xml",
|
|
31
|
+
"no closing tag found in numbering.xml"
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
const numsAt = openTagAt(xml, "numIdMacAtCleanup") ?? rootEnd;
|
|
35
|
+
const definitionsAt = openTagAt(xml, "num") ?? numsAt;
|
|
36
|
+
const firstAbstractNumId = maxAbstractNumId(xml) + 1;
|
|
37
|
+
const additions = [...numIds].sort((a, b) => a - b).map((numId, index) => ({
|
|
38
|
+
numId,
|
|
39
|
+
abstractNumId: firstAbstractNumId + index
|
|
40
|
+
}));
|
|
41
|
+
const definitions = additions.map(
|
|
42
|
+
(added) => abstractNumXml(added.abstractNumId, listKindOf(added.numId))
|
|
43
|
+
).join("");
|
|
44
|
+
const nums = additions.map((added) => numXml(added.numId, added.abstractNumId)).join("");
|
|
45
|
+
return xml.slice(0, definitionsAt) + definitions + xml.slice(definitionsAt, numsAt) + nums + xml.slice(numsAt);
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
addListDefinitions
|
|
49
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The error kinds used when opening and exporting a docx.
|
|
3
|
+
*
|
|
4
|
+
* Messages are English one-liners meant for developers. The `code` is the stable,
|
|
5
|
+
* machine-readable part: consumers switch on it to show their own localized text,
|
|
6
|
+
* so a code never changes meaning even when a message is reworded.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Why a document could not be opened.
|
|
10
|
+
*
|
|
11
|
+
* - `not-a-docx`: the bytes are not a readable zip container, its entry names are not a package's, or an entry does not hold what it says it does
|
|
12
|
+
* - `too-large`: the package asks to inflate to more than we open
|
|
13
|
+
* - `missing-part`: the package has no main document part to read
|
|
14
|
+
* - `missing-body`: the main part carries no `w:body`
|
|
15
|
+
* - `malformed-xml`: the XML cannot be parsed, declares a DTD, or its markup is inconsistent
|
|
16
|
+
* - `unsupported-content`: the document holds markup we cannot write back out unchanged
|
|
17
|
+
*/
|
|
18
|
+
export type DocxImportErrorCode = "not-a-docx" | "too-large" | "missing-part" | "missing-body" | "malformed-xml" | "unsupported-content";
|
|
19
|
+
/** Thrown when we hit a document whose content cannot be kept safely. We refuse to open it instead of losing it silently */
|
|
20
|
+
export declare class DocxImportError extends Error {
|
|
21
|
+
readonly code: DocxImportErrorCode;
|
|
22
|
+
constructor(code: DocxImportErrorCode, message: string, options?: ErrorOptions);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Why a document could not be written back out.
|
|
26
|
+
*
|
|
27
|
+
* - `missing-numbering-part`: a new list needs a numbering.xml the document does not have
|
|
28
|
+
* - `missing-content-types`: a new image needs a [Content_Types].xml the package does not have
|
|
29
|
+
* - `unsupported-content`: the document holds a node kind we have no way to serialize
|
|
30
|
+
* - `lost-original`: a node that only carries its original XML has lost it
|
|
31
|
+
* - `malformed-xml`: an original XML fragment cannot be read well enough to rewrite
|
|
32
|
+
* - `invalid-table`: the table grid is inconsistent, e.g. a vertical merge outliving its rows
|
|
33
|
+
*/
|
|
34
|
+
export type DocxExportErrorCode = "missing-numbering-part" | "missing-content-types" | "unsupported-content" | "lost-original" | "malformed-xml" | "invalid-table";
|
|
35
|
+
/** Thrown when an edited document cannot be written back out without losing or corrupting content */
|
|
36
|
+
export declare class DocxExportError extends Error {
|
|
37
|
+
readonly code: DocxExportErrorCode;
|
|
38
|
+
constructor(code: DocxExportErrorCode, message: string, options?: ErrorOptions);
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/ooxml/errors.ts
|
|
2
|
+
var DocxImportError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(code, message, options) {
|
|
5
|
+
super(message, options);
|
|
6
|
+
this.name = "DocxImportError";
|
|
7
|
+
this.code = code;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var DocxExportError = class extends Error {
|
|
11
|
+
code;
|
|
12
|
+
constructor(code, message, options) {
|
|
13
|
+
super(message, options);
|
|
14
|
+
this.name = "DocxExportError";
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
export {
|
|
19
|
+
DocxExportError,
|
|
20
|
+
DocxImportError
|
|
21
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The inline picture: the values an image node carries, and the DrawingML those values
|
|
3
|
+
* are read out of and written back into.
|
|
4
|
+
*
|
|
5
|
+
* Only the one shape a docx uses for a plain inline picture is interpreted: a
|
|
6
|
+
* `w:drawing` holding a `wp:inline` whose graphic is a `pic:pic` with an embedded blip.
|
|
7
|
+
* A floating anchor, a chart or a diagram, a blip linked to a file outside the package,
|
|
8
|
+
* an image kind a browser cannot draw - all of those are left to the preservation path
|
|
9
|
+
* that was already there, so nothing we cannot draw is ever rewritten.
|
|
10
|
+
*
|
|
11
|
+
* An imported image holds on to its whole original `<w:drawing>` XML, so an untouched
|
|
12
|
+
* image goes back out byte for byte. A resize rewrites nothing but the two extents.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* English Metric Units, the unit every DrawingML length is written in.
|
|
16
|
+
* At 96dpi one CSS pixel is 9525 of them.
|
|
17
|
+
*/
|
|
18
|
+
export declare const EMU_PER_PX = 9525;
|
|
19
|
+
export declare function emuToPx(emu: number): number;
|
|
20
|
+
export declare function pxToEmu(px: number): number;
|
|
21
|
+
/**
|
|
22
|
+
* The size a drawing is shown at.
|
|
23
|
+
*
|
|
24
|
+
* It is kept in EMU rather than in pixels because EMU is the document's own unit:
|
|
25
|
+
* reading it and writing it back is exact, so an image nobody resized goes out carrying
|
|
26
|
+
* the very numbers it came in with. Pixels are derived from it for the screen only.
|
|
27
|
+
*/
|
|
28
|
+
export interface ImageExtent {
|
|
29
|
+
cx: number;
|
|
30
|
+
cy: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The image kinds we both draw on screen and write back into a package.
|
|
34
|
+
*
|
|
35
|
+
* A document may embed a tiff or an emf as well; we do not interpret those, because a
|
|
36
|
+
* browser cannot draw them and a broken picture on screen is worse than the preserved
|
|
37
|
+
* placeholder.
|
|
38
|
+
*/
|
|
39
|
+
export declare const IMAGE_MIMES: readonly ["image/png", "image/jpeg", "image/gif", "image/bmp"];
|
|
40
|
+
export type ImageMime = (typeof IMAGE_MIMES)[number];
|
|
41
|
+
export declare function isImageMime(value: unknown): value is ImageMime;
|
|
42
|
+
/** The image bytes as a data URL. null for anything else */
|
|
43
|
+
export declare function toImageSrc(value: unknown): string | null;
|
|
44
|
+
/** The kind a src declares. It has already been checked by `toImageSrc` */
|
|
45
|
+
export declare function imageMimeOf(src: string): ImageMime | null;
|
|
46
|
+
/** The base64 payload of a src. It has already been checked by `toImageSrc` */
|
|
47
|
+
export declare function imageBase64Of(src: string): string;
|
|
48
|
+
export declare function toImageExtent(value: unknown): ImageExtent | null;
|
|
49
|
+
/** What one inline picture states about itself */
|
|
50
|
+
export interface DrawingPicture {
|
|
51
|
+
/** The relationship id the image bytes hang off */
|
|
52
|
+
relId: string;
|
|
53
|
+
extent: ImageExtent;
|
|
54
|
+
/** The alternative text, from `wp:docPr descr`. null when there is none */
|
|
55
|
+
alt: string | null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Reads a `w:drawing` as an inline picture. null for a drawing we do not interpret,
|
|
59
|
+
* which leaves the caller on the preservation path.
|
|
60
|
+
*
|
|
61
|
+
* Children we do not know about (`wp14` extensions, a crop, a rotation) do not stop us,
|
|
62
|
+
* because the original XML is kept whole and goes back out as it came.
|
|
63
|
+
*/
|
|
64
|
+
export declare function readDrawingPicture(drawing: Element): DrawingPicture | null;
|
|
65
|
+
/**
|
|
66
|
+
* The same drawing XML with both extents set to this size.
|
|
67
|
+
*
|
|
68
|
+
* Only those two elements are touched; every other byte of the original stays where it
|
|
69
|
+
* was. Handed the size it was imported with, this gives back the original string
|
|
70
|
+
* unchanged, so nothing has to keep track of whether a resize happened.
|
|
71
|
+
*/
|
|
72
|
+
export declare function withExtent(xml: string, extent: ImageExtent): string;
|
|
73
|
+
/** A picture that was inserted during editing and has no original XML to go back to */
|
|
74
|
+
export interface NewImage {
|
|
75
|
+
relId: string;
|
|
76
|
+
/** The drawing's id within the document. Word shows it in the selection pane */
|
|
77
|
+
docPrId: number;
|
|
78
|
+
extent: ImageExtent;
|
|
79
|
+
alt: string | null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The smallest `w:drawing` Word opens as an inline picture.
|
|
83
|
+
*
|
|
84
|
+
* Every prefix used is declared right where it is used. The document element declares
|
|
85
|
+
* some of them already, but not all producers declare `a` and `pic`, and a duplicate
|
|
86
|
+
* declaration of the same namespace costs nothing.
|
|
87
|
+
*/
|
|
88
|
+
export declare function imageDrawingXml(image: NewImage): string;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// src/ooxml/image.ts
|
|
2
|
+
import { childByLocalName, escapeXml, R_NS } from "./xml.js";
|
|
3
|
+
var EMU_PER_PX = 9525;
|
|
4
|
+
function emuToPx(emu) {
|
|
5
|
+
return emu / EMU_PER_PX;
|
|
6
|
+
}
|
|
7
|
+
function pxToEmu(px) {
|
|
8
|
+
return Math.round(px * EMU_PER_PX);
|
|
9
|
+
}
|
|
10
|
+
var IMAGE_MIMES = [
|
|
11
|
+
"image/png",
|
|
12
|
+
"image/jpeg",
|
|
13
|
+
"image/gif",
|
|
14
|
+
"image/bmp"
|
|
15
|
+
];
|
|
16
|
+
var IMAGE_DATA_URL = new RegExp(
|
|
17
|
+
`^data:(?:${IMAGE_MIMES.join("|")});base64,[A-Za-z0-9+/]+={0,2}$`
|
|
18
|
+
);
|
|
19
|
+
function isImageMime(value) {
|
|
20
|
+
return IMAGE_MIMES.some((mime) => mime === value);
|
|
21
|
+
}
|
|
22
|
+
function toImageSrc(value) {
|
|
23
|
+
return typeof value === "string" && IMAGE_DATA_URL.test(value) ? value : null;
|
|
24
|
+
}
|
|
25
|
+
function imageMimeOf(src) {
|
|
26
|
+
const mime = src.slice("data:".length, src.indexOf(";"));
|
|
27
|
+
return isImageMime(mime) ? mime : null;
|
|
28
|
+
}
|
|
29
|
+
function imageBase64Of(src) {
|
|
30
|
+
return src.slice(src.indexOf(",") + 1);
|
|
31
|
+
}
|
|
32
|
+
function isRecord(value) {
|
|
33
|
+
return typeof value === "object" && value !== null;
|
|
34
|
+
}
|
|
35
|
+
function positiveInt(value) {
|
|
36
|
+
const parsed = typeof value === "string" ? Number.parseInt(value, 10) : value;
|
|
37
|
+
return typeof parsed === "number" && Number.isInteger(parsed) && parsed > 0 ? parsed : null;
|
|
38
|
+
}
|
|
39
|
+
function toImageExtent(value) {
|
|
40
|
+
if (!isRecord(value)) return null;
|
|
41
|
+
const cx = positiveInt(value.cx);
|
|
42
|
+
const cy = positiveInt(value.cy);
|
|
43
|
+
return cx === null || cy === null ? null : { cx, cy };
|
|
44
|
+
}
|
|
45
|
+
var PICTURE_URI = "http://schemas.openxmlformats.org/drawingml/2006/picture";
|
|
46
|
+
function childOf(el, name) {
|
|
47
|
+
return el ? childByLocalName(el, name) : null;
|
|
48
|
+
}
|
|
49
|
+
function relAttr(el, name) {
|
|
50
|
+
return el.getAttributeNS(R_NS, name) ?? el.getAttribute(`r:${name}`);
|
|
51
|
+
}
|
|
52
|
+
function readExtent(el) {
|
|
53
|
+
if (!el) return null;
|
|
54
|
+
return toImageExtent({
|
|
55
|
+
cx: el.getAttribute("cx"),
|
|
56
|
+
cy: el.getAttribute("cy")
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function readDrawingPicture(drawing) {
|
|
60
|
+
const inline = childOf(drawing, "inline");
|
|
61
|
+
if (!inline) return null;
|
|
62
|
+
const extent = readExtent(childOf(inline, "extent"));
|
|
63
|
+
if (!extent) return null;
|
|
64
|
+
const graphicData = childOf(childOf(inline, "graphic"), "graphicData");
|
|
65
|
+
if (!graphicData || graphicData.getAttribute("uri") !== PICTURE_URI) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const blip = childOf(
|
|
69
|
+
childOf(childOf(graphicData, "pic"), "blipFill"),
|
|
70
|
+
"blip"
|
|
71
|
+
);
|
|
72
|
+
if (!blip) return null;
|
|
73
|
+
if (relAttr(blip, "link") !== null) return null;
|
|
74
|
+
const relId = relAttr(blip, "embed");
|
|
75
|
+
if (relId === null) return null;
|
|
76
|
+
const descr = childOf(inline, "docPr")?.getAttribute("descr") ?? null;
|
|
77
|
+
return { relId, extent, alt: descr === "" ? null : descr };
|
|
78
|
+
}
|
|
79
|
+
var EXTENT_TAG = /<([\w.-]+:)?extent\b[^>]*\/>/g;
|
|
80
|
+
var EXT_TAG = /<([\w.-]+:)?ext\b[^>]*\/>/g;
|
|
81
|
+
function withExtent(xml, extent) {
|
|
82
|
+
const size = `cx="${extent.cx}" cy="${extent.cy}"`;
|
|
83
|
+
return xml.replace(EXTENT_TAG, (_match, prefix) => `<${prefix ?? ""}extent ${size}/>`).replace(EXT_TAG, (_match, prefix) => `<${prefix ?? ""}ext ${size}/>`);
|
|
84
|
+
}
|
|
85
|
+
var WP_NS = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
|
|
86
|
+
var A_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
|
|
87
|
+
function imageDrawingXml(image) {
|
|
88
|
+
const size = `cx="${image.extent.cx}" cy="${image.extent.cy}"`;
|
|
89
|
+
const name = `Picture ${image.docPrId}`;
|
|
90
|
+
const descr = image.alt === null ? "" : ` descr="${escapeXml(image.alt)}"`;
|
|
91
|
+
return `<w:drawing><wp:inline xmlns:wp="${WP_NS}" distT="0" distB="0" distL="0" distR="0"><wp:extent ${size}/><wp:effectExtent l="0" t="0" r="0" b="0"/><wp:docPr id="${image.docPrId}" name="${name}"${descr}/><wp:cNvGraphicFramePr><a:graphicFrameLocks xmlns:a="${A_NS}" noChangeAspect="1"/></wp:cNvGraphicFramePr><a:graphic xmlns:a="${A_NS}"><a:graphicData uri="${PICTURE_URI}"><pic:pic xmlns:pic="${PICTURE_URI}"><pic:nvPicPr><pic:cNvPr id="${image.docPrId}" name="${name}"${descr}/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip xmlns:r="${R_NS}" r:embed="${escapeXml(image.relId)}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext ${size}/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing>`;
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
EMU_PER_PX,
|
|
95
|
+
IMAGE_MIMES,
|
|
96
|
+
emuToPx,
|
|
97
|
+
imageBase64Of,
|
|
98
|
+
imageDrawingXml,
|
|
99
|
+
imageMimeOf,
|
|
100
|
+
isImageMime,
|
|
101
|
+
pxToEmu,
|
|
102
|
+
readDrawingPicture,
|
|
103
|
+
toImageExtent,
|
|
104
|
+
toImageSrc,
|
|
105
|
+
withExtent
|
|
106
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/ooxml/tabStops.ts
|
|
2
|
+
import { twipsToPt, wAttr } from "./units.js";
|
|
3
|
+
import { childByLocalName } from "./xml.js";
|
|
4
|
+
var ALIGN_BY_VALUE = {
|
|
5
|
+
left: "start",
|
|
6
|
+
start: "start",
|
|
7
|
+
center: "center",
|
|
8
|
+
right: "end",
|
|
9
|
+
end: "end",
|
|
10
|
+
decimal: "decimal",
|
|
11
|
+
num: "num",
|
|
12
|
+
bar: "bar",
|
|
13
|
+
clear: "clear"
|
|
14
|
+
};
|
|
15
|
+
var LEADERS = /* @__PURE__ */ new Set([
|
|
16
|
+
"none",
|
|
17
|
+
"dot",
|
|
18
|
+
"hyphen",
|
|
19
|
+
"underscore",
|
|
20
|
+
"heavy",
|
|
21
|
+
"middleDot"
|
|
22
|
+
]);
|
|
23
|
+
function tabLeader(value) {
|
|
24
|
+
return value !== null && LEADERS.has(value) ? value : void 0;
|
|
25
|
+
}
|
|
26
|
+
function readTabStopDirectives(pPr) {
|
|
27
|
+
if (!pPr) return [];
|
|
28
|
+
const tabs = childByLocalName(pPr, "tabs");
|
|
29
|
+
if (!tabs) return [];
|
|
30
|
+
const stops = [];
|
|
31
|
+
for (const tab of Array.from(tabs.children)) {
|
|
32
|
+
if (tab.localName !== "tab") continue;
|
|
33
|
+
const positionPt = twipsToPt(wAttr(tab, "pos"));
|
|
34
|
+
const align = ALIGN_BY_VALUE[wAttr(tab, "val") ?? ""];
|
|
35
|
+
if (positionPt === null || align === void 0) continue;
|
|
36
|
+
if (align === "clear") {
|
|
37
|
+
stops.push({ positionPt, align });
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const leader = tabLeader(wAttr(tab, "leader"));
|
|
41
|
+
stops.push({
|
|
42
|
+
positionPt,
|
|
43
|
+
align,
|
|
44
|
+
...leader === void 0 ? {} : { leader }
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return stops;
|
|
48
|
+
}
|
|
49
|
+
export {
|
|
50
|
+
readTabStopDirectives
|
|
51
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type ParagraphAlign } from "../model/format";
|
|
2
|
+
/** The alignment `w:jc` writes down, both for a paragraph and for a table */
|
|
3
|
+
export declare const ALIGN_BY_JC: Record<string, ParagraphAlign>;
|
|
4
|
+
/** A color as the document writes it, six hex digits and no `#`. Null for anything else */
|
|
5
|
+
export declare function normalizeHex(value: string): string | null;
|
|
6
|
+
export declare function wAttr(el: Element, name: string): string | null;
|
|
7
|
+
/** `<w:b/>` means on, `<w:b w:val="0"/>` means off */
|
|
8
|
+
export declare function isOn(parent: Element, name: string): boolean;
|
|
9
|
+
export declare function childValue(parent: Element, name: string): string | null;
|
|
10
|
+
export declare function toNumber(value: string | null): number | null;
|
|
11
|
+
/** Cuts off the messy digits after the decimal point so the same input always yields the same value */
|
|
12
|
+
export declare function round(value: number): number;
|
|
13
|
+
/** twip (1/20 of a point) */
|
|
14
|
+
export declare function twipsToPt(value: string | null): number | null;
|
|
15
|
+
/** half-point (w:sz 20 = 10pt) */
|
|
16
|
+
export declare function halfPointsToPt(value: string | null): number | null;
|
|
17
|
+
/** 1/8 of a point */
|
|
18
|
+
export declare function eighthsToPt(value: string | null): number | null;
|
|
19
|
+
export declare function toHexColor(value: string | null): string | null;
|
|
20
|
+
/**
|
|
21
|
+
* Moves one border side into a CSS value.
|
|
22
|
+
*
|
|
23
|
+
* A side the document has pinned down as "draw no line here" becomes `none`.
|
|
24
|
+
* A kind we do not know, or a side that is not there at all, becomes null, so the caller can pick a default.
|
|
25
|
+
* A side that draws a line but writes down no thickness gets the default one: reading it as "no
|
|
26
|
+
* line" would take away a line the style laid down.
|
|
27
|
+
*/
|
|
28
|
+
export declare function borderCss(el: Element | null): string | null;
|
|
29
|
+
/** One side inside `w:tblBorders` or `w:tcBorders` */
|
|
30
|
+
export declare function borderSide(borders: Element | null, side: string): string | null;
|
|
31
|
+
/**
|
|
32
|
+
* The background color from `w:shd`. For a pattern fill we only look at the color.
|
|
33
|
+
*
|
|
34
|
+
* A shading with no color to fill with (`w:fill="auto"`, or none at all) says to paint nothing, so
|
|
35
|
+
* it reads back as `NO_FILL`. That is what takes a fill a style laid down back off, the way Word does.
|
|
36
|
+
*/
|
|
37
|
+
export declare function shadingOf(parent: Element): string | null;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// src/ooxml/units.ts
|
|
2
|
+
import { NO_FILL } from "../model/format.js";
|
|
3
|
+
import { childByLocalName, W_NS } from "./xml.js";
|
|
4
|
+
var ALIGN_BY_JC = {
|
|
5
|
+
left: "left",
|
|
6
|
+
start: "left",
|
|
7
|
+
center: "center",
|
|
8
|
+
right: "right",
|
|
9
|
+
end: "right",
|
|
10
|
+
both: "justify",
|
|
11
|
+
distribute: "justify"
|
|
12
|
+
};
|
|
13
|
+
function normalizeHex(value) {
|
|
14
|
+
const hex = value.startsWith("#") ? value.slice(1) : value;
|
|
15
|
+
return /^[0-9a-fA-F]{6}$/.test(hex) ? hex.toUpperCase() : null;
|
|
16
|
+
}
|
|
17
|
+
function wAttr(el, name) {
|
|
18
|
+
return el.getAttributeNS(W_NS, name) ?? el.getAttribute(name);
|
|
19
|
+
}
|
|
20
|
+
function isOn(parent, name) {
|
|
21
|
+
const el = childByLocalName(parent, name);
|
|
22
|
+
if (!el) return false;
|
|
23
|
+
const value = wAttr(el, "val");
|
|
24
|
+
return value === null || value === "1" || value === "true" || value === "on";
|
|
25
|
+
}
|
|
26
|
+
function childValue(parent, name) {
|
|
27
|
+
const el = childByLocalName(parent, name);
|
|
28
|
+
return el ? wAttr(el, "val") : null;
|
|
29
|
+
}
|
|
30
|
+
function toNumber(value) {
|
|
31
|
+
if (value === null) return null;
|
|
32
|
+
const parsed = Number.parseFloat(value);
|
|
33
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
34
|
+
}
|
|
35
|
+
function round(value) {
|
|
36
|
+
return Math.round(value * 100) / 100;
|
|
37
|
+
}
|
|
38
|
+
function twipsToPt(value) {
|
|
39
|
+
const twips = toNumber(value);
|
|
40
|
+
return twips === null ? null : round(twips / 20);
|
|
41
|
+
}
|
|
42
|
+
function halfPointsToPt(value) {
|
|
43
|
+
const half = toNumber(value);
|
|
44
|
+
return half === null ? null : round(half / 2);
|
|
45
|
+
}
|
|
46
|
+
function eighthsToPt(value) {
|
|
47
|
+
const eighths = toNumber(value);
|
|
48
|
+
return eighths === null ? null : round(eighths / 8);
|
|
49
|
+
}
|
|
50
|
+
function toHexColor(value) {
|
|
51
|
+
if (value === null || value === "auto") return null;
|
|
52
|
+
return /^[0-9a-fA-F]{6}$/.test(value) ? `#${value}` : null;
|
|
53
|
+
}
|
|
54
|
+
var BORDER_STYLE_BY_VAL = {
|
|
55
|
+
single: "solid",
|
|
56
|
+
thick: "solid",
|
|
57
|
+
double: "double",
|
|
58
|
+
dotted: "dotted",
|
|
59
|
+
dashed: "dashed",
|
|
60
|
+
dotDash: "dashed",
|
|
61
|
+
wave: "solid",
|
|
62
|
+
outset: "solid",
|
|
63
|
+
inset: "solid",
|
|
64
|
+
threeDEmboss: "solid",
|
|
65
|
+
threeDEngrave: "solid",
|
|
66
|
+
triple: "double",
|
|
67
|
+
doubleWave: "double",
|
|
68
|
+
thinThickSmallGap: "double",
|
|
69
|
+
thickThinSmallGap: "double",
|
|
70
|
+
thinThickThinSmallGap: "double",
|
|
71
|
+
thinThickMediumGap: "double",
|
|
72
|
+
thickThinMediumGap: "double",
|
|
73
|
+
thinThickThinMediumGap: "double",
|
|
74
|
+
thinThickLargeGap: "double",
|
|
75
|
+
thickThinLargeGap: "double",
|
|
76
|
+
thinThickThinLargeGap: "double",
|
|
77
|
+
dashSmallGap: "dashed",
|
|
78
|
+
dotDotDash: "dashed",
|
|
79
|
+
dashDotStroked: "dashed"
|
|
80
|
+
};
|
|
81
|
+
var FALLBACK_BORDER_PT = 0.5;
|
|
82
|
+
function borderCss(el) {
|
|
83
|
+
if (!el) return null;
|
|
84
|
+
const val = wAttr(el, "val") ?? "";
|
|
85
|
+
if (val === "nil" || val === "none") return "none";
|
|
86
|
+
const style = BORDER_STYLE_BY_VAL[val];
|
|
87
|
+
if (!style) return null;
|
|
88
|
+
const written = eighthsToPt(wAttr(el, "sz"));
|
|
89
|
+
const widthPt = written === null || written === 0 ? FALLBACK_BORDER_PT : written;
|
|
90
|
+
const color = toHexColor(wAttr(el, "color")) ?? "#000000";
|
|
91
|
+
return `${widthPt}pt ${style} ${color}`;
|
|
92
|
+
}
|
|
93
|
+
function borderSide(borders, side) {
|
|
94
|
+
return borders ? borderCss(childByLocalName(borders, side)) : null;
|
|
95
|
+
}
|
|
96
|
+
function shadingOf(parent) {
|
|
97
|
+
const shd = childByLocalName(parent, "shd");
|
|
98
|
+
if (!shd) return null;
|
|
99
|
+
return toHexColor(wAttr(shd, "fill")) ?? NO_FILL;
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
ALIGN_BY_JC,
|
|
103
|
+
borderCss,
|
|
104
|
+
borderSide,
|
|
105
|
+
childValue,
|
|
106
|
+
eighthsToPt,
|
|
107
|
+
halfPointsToPt,
|
|
108
|
+
isOn,
|
|
109
|
+
normalizeHex,
|
|
110
|
+
round,
|
|
111
|
+
shadingOf,
|
|
112
|
+
toHexColor,
|
|
113
|
+
toNumber,
|
|
114
|
+
twipsToPt,
|
|
115
|
+
wAttr
|
|
116
|
+
};
|