@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,165 @@
|
|
|
1
|
+
// src/docx/formatting/styles.ts
|
|
2
|
+
import {
|
|
3
|
+
toParagraphFormat,
|
|
4
|
+
toRunFormat,
|
|
5
|
+
toTableFormat
|
|
6
|
+
} from "../../model/format.js";
|
|
7
|
+
import { childValue, isOn, wAttr } from "../../ooxml/units.js";
|
|
8
|
+
import { childByLocalName, elementChildren } from "../../ooxml/xml.js";
|
|
9
|
+
import { parsePropsXml } from "../propsXml.js";
|
|
10
|
+
import {
|
|
11
|
+
layerCellMargins,
|
|
12
|
+
layerInsideBorders,
|
|
13
|
+
NO_CELL_MARGINS,
|
|
14
|
+
NO_INSIDE_BORDERS,
|
|
15
|
+
readCellMarginsOf,
|
|
16
|
+
readInsideBorders,
|
|
17
|
+
readTableFormat
|
|
18
|
+
} from "../tableFormatting.js";
|
|
19
|
+
import { NO_THEME_FONTS } from "../theme.js";
|
|
20
|
+
import { readParagraphFormat, readRunFormat } from "./direct.js";
|
|
21
|
+
import { layerParagraphValues } from "./tabStops.js";
|
|
22
|
+
var NO_STYLES = /* @__PURE__ */ new Map();
|
|
23
|
+
function styleChain(id, sources) {
|
|
24
|
+
const chain = [];
|
|
25
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26
|
+
let current = id;
|
|
27
|
+
while (current !== null && !seen.has(current)) {
|
|
28
|
+
seen.add(current);
|
|
29
|
+
const source = sources.get(current);
|
|
30
|
+
if (!source) break;
|
|
31
|
+
chain.unshift(source);
|
|
32
|
+
current = source.basedOn;
|
|
33
|
+
}
|
|
34
|
+
return chain;
|
|
35
|
+
}
|
|
36
|
+
var EMPTY_STYLE_FORMAT = {
|
|
37
|
+
paragraph: {},
|
|
38
|
+
run: {},
|
|
39
|
+
table: {},
|
|
40
|
+
tableInside: NO_INSIDE_BORDERS,
|
|
41
|
+
tableCellMargins: NO_CELL_MARGINS
|
|
42
|
+
};
|
|
43
|
+
function readStyleFormat(source, themeFonts) {
|
|
44
|
+
return {
|
|
45
|
+
paragraph: readParagraphFormat(source.pPr) ?? {},
|
|
46
|
+
run: readRunFormat(source.rPr, themeFonts) ?? {},
|
|
47
|
+
table: readTableFormat(source.tblPr) ?? {},
|
|
48
|
+
tableInside: readInsideBorders(source.tblPr),
|
|
49
|
+
tableCellMargins: readCellMarginsOf(source.tblPr, "tblCellMar")
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function layerStyleFormat(base, over) {
|
|
53
|
+
return {
|
|
54
|
+
paragraph: layerParagraphValues(base.paragraph, over.paragraph),
|
|
55
|
+
run: { ...base.run, ...over.run },
|
|
56
|
+
table: { ...base.table, ...over.table },
|
|
57
|
+
tableInside: layerInsideBorders(base.tableInside, over.tableInside),
|
|
58
|
+
tableCellMargins: layerCellMargins(
|
|
59
|
+
base.tableCellMargins,
|
|
60
|
+
over.tableCellMargins
|
|
61
|
+
)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function foldChain(chain, themeFonts) {
|
|
65
|
+
return chain.map((source) => readStyleFormat(source, themeFonts)).reduce(layerStyleFormat, EMPTY_STYLE_FORMAT);
|
|
66
|
+
}
|
|
67
|
+
function readStyles(styles, themeFonts = NO_THEME_FONTS) {
|
|
68
|
+
const sources = /* @__PURE__ */ new Map();
|
|
69
|
+
for (const el of elementChildren(styles.documentElement)) {
|
|
70
|
+
if (el.localName !== "style") continue;
|
|
71
|
+
const id = wAttr(el, "styleId");
|
|
72
|
+
if (id === null || id.length === 0) continue;
|
|
73
|
+
sources.set(id, {
|
|
74
|
+
basedOn: childValue(el, "basedOn"),
|
|
75
|
+
pPr: childByLocalName(el, "pPr"),
|
|
76
|
+
rPr: childByLocalName(el, "rPr"),
|
|
77
|
+
tblPr: childByLocalName(el, "tblPr")
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const table = /* @__PURE__ */ new Map();
|
|
81
|
+
for (const id of sources.keys()) {
|
|
82
|
+
table.set(id, foldChain(styleChain(id, sources), themeFonts));
|
|
83
|
+
}
|
|
84
|
+
return table;
|
|
85
|
+
}
|
|
86
|
+
function isDefaultStyle(el) {
|
|
87
|
+
const value = wAttr(el, "default");
|
|
88
|
+
return value === "1" || value === "true";
|
|
89
|
+
}
|
|
90
|
+
function defaultStyleIdOf(styles, type) {
|
|
91
|
+
let found = null;
|
|
92
|
+
for (const el of elementChildren(styles.documentElement)) {
|
|
93
|
+
if (el.localName !== "style" || wAttr(el, "type") !== type) continue;
|
|
94
|
+
if (!isDefaultStyle(el)) continue;
|
|
95
|
+
const id = wAttr(el, "styleId");
|
|
96
|
+
if (id !== null && id.length > 0) found = id;
|
|
97
|
+
}
|
|
98
|
+
return found;
|
|
99
|
+
}
|
|
100
|
+
function defaultTableStyleIdOf(styles) {
|
|
101
|
+
return defaultStyleIdOf(styles, "table");
|
|
102
|
+
}
|
|
103
|
+
function defaultParagraphStyleIdOf(styles) {
|
|
104
|
+
return defaultStyleIdOf(styles, "paragraph");
|
|
105
|
+
}
|
|
106
|
+
function readParagraphStyles(styles) {
|
|
107
|
+
const defaultId = defaultParagraphStyleIdOf(styles);
|
|
108
|
+
const options = [];
|
|
109
|
+
for (const el of elementChildren(styles.documentElement)) {
|
|
110
|
+
if (el.localName !== "style" || wAttr(el, "type") !== "paragraph") continue;
|
|
111
|
+
const id = wAttr(el, "styleId");
|
|
112
|
+
if (id === null || id.length === 0) continue;
|
|
113
|
+
const name = childValue(el, "name");
|
|
114
|
+
options.push({
|
|
115
|
+
id,
|
|
116
|
+
name: name === null || name.length === 0 ? id : name,
|
|
117
|
+
isDefault: id === defaultId,
|
|
118
|
+
primary: isOn(el, "qFormat"),
|
|
119
|
+
hidden: isOn(el, "semiHidden") || isOn(el, "hidden")
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return options;
|
|
123
|
+
}
|
|
124
|
+
var styleIdsByPPr = /* @__PURE__ */ new Map();
|
|
125
|
+
var STYLE_ID_CACHE_LIMIT = 2e3;
|
|
126
|
+
function styleIdOf(pPr) {
|
|
127
|
+
if (typeof pPr !== "string" || !pPr.includes("pStyle")) return null;
|
|
128
|
+
const known = styleIdsByPPr.get(pPr);
|
|
129
|
+
if (known !== void 0) return known;
|
|
130
|
+
const el = parsePropsXml(pPr);
|
|
131
|
+
const id = el ? childValue(el, "pStyle") : null;
|
|
132
|
+
if (styleIdsByPPr.size >= STYLE_ID_CACHE_LIMIT) styleIdsByPPr.clear();
|
|
133
|
+
styleIdsByPPr.set(pPr, id);
|
|
134
|
+
return id;
|
|
135
|
+
}
|
|
136
|
+
function paragraphStyleFormat(pPr, styles, defaultStyleId = null) {
|
|
137
|
+
const id = styleIdOf(pPr) ?? defaultStyleId;
|
|
138
|
+
return id === null ? void 0 : styles.get(id);
|
|
139
|
+
}
|
|
140
|
+
function layered(style, direct) {
|
|
141
|
+
if (direct === null && Object.keys(style).length === 0) return null;
|
|
142
|
+
return { ...style, ...direct };
|
|
143
|
+
}
|
|
144
|
+
function layerParagraphFormat(style, direct) {
|
|
145
|
+
if (direct === null && Object.keys(style).length === 0) return null;
|
|
146
|
+
return toParagraphFormat(layerParagraphValues(style, direct ?? {}));
|
|
147
|
+
}
|
|
148
|
+
function layerRunFormat(style, direct) {
|
|
149
|
+
return toRunFormat(layered(style, direct));
|
|
150
|
+
}
|
|
151
|
+
function layerTableFormat(style, direct) {
|
|
152
|
+
return toTableFormat(layered(style, direct));
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
NO_STYLES,
|
|
156
|
+
defaultParagraphStyleIdOf,
|
|
157
|
+
defaultTableStyleIdOf,
|
|
158
|
+
layerParagraphFormat,
|
|
159
|
+
layerRunFormat,
|
|
160
|
+
layerTableFormat,
|
|
161
|
+
paragraphStyleFormat,
|
|
162
|
+
readParagraphStyles,
|
|
163
|
+
readStyles,
|
|
164
|
+
styleIdOf
|
|
165
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ParagraphFormat } from "../../model/format";
|
|
2
|
+
import { type TabStopDirective } from "../../model/tabStops";
|
|
3
|
+
export type ParagraphFormatLayer = Omit<ParagraphFormat, "numbering" | "tabStops"> & {
|
|
4
|
+
numbering?: ParagraphFormat["numbering"] | null;
|
|
5
|
+
tabStops?: readonly TabStopDirective[];
|
|
6
|
+
};
|
|
7
|
+
export declare function toParagraphFormatLayer(value: unknown): ParagraphFormatLayer | null;
|
|
8
|
+
export declare function layerParagraphValues(base: ParagraphFormatLayer, over: ParagraphFormatLayer): ParagraphFormatLayer;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// src/docx/formatting/tabStops.ts
|
|
2
|
+
import { toParagraphFormat } from "../../model/format.js";
|
|
3
|
+
import {
|
|
4
|
+
layerTabStopDirectives
|
|
5
|
+
} from "../../model/tabStops.js";
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
var ALIGNMENTS = /* @__PURE__ */ new Set([
|
|
10
|
+
"start",
|
|
11
|
+
"center",
|
|
12
|
+
"end",
|
|
13
|
+
"decimal",
|
|
14
|
+
"num",
|
|
15
|
+
"bar",
|
|
16
|
+
"clear"
|
|
17
|
+
]);
|
|
18
|
+
var LEADERS = /* @__PURE__ */ new Set([
|
|
19
|
+
"none",
|
|
20
|
+
"dot",
|
|
21
|
+
"hyphen",
|
|
22
|
+
"underscore",
|
|
23
|
+
"heavy",
|
|
24
|
+
"middleDot"
|
|
25
|
+
]);
|
|
26
|
+
function toTabStopDirective(value) {
|
|
27
|
+
if (!isRecord(value) || typeof value.positionPt !== "number" || !Number.isFinite(value.positionPt) || typeof value.align !== "string" || !ALIGNMENTS.has(value.align)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (value.align === "clear") {
|
|
31
|
+
return { positionPt: value.positionPt, align: "clear" };
|
|
32
|
+
}
|
|
33
|
+
const align = value.align;
|
|
34
|
+
const leader = typeof value.leader === "string" && LEADERS.has(value.leader) ? value.leader : void 0;
|
|
35
|
+
return {
|
|
36
|
+
positionPt: value.positionPt,
|
|
37
|
+
align,
|
|
38
|
+
...leader === void 0 ? {} : { leader }
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function toParagraphFormatLayer(value) {
|
|
42
|
+
if (!isRecord(value)) return null;
|
|
43
|
+
const format = toParagraphFormat(value) ?? {};
|
|
44
|
+
if (!Array.isArray(value.tabStops)) return format;
|
|
45
|
+
const tabStops = value.tabStops.flatMap((entry) => {
|
|
46
|
+
const stop = toTabStopDirective(entry);
|
|
47
|
+
return stop === null ? [] : [stop];
|
|
48
|
+
});
|
|
49
|
+
if (tabStops.length > 0) format.tabStops = tabStops;
|
|
50
|
+
return format;
|
|
51
|
+
}
|
|
52
|
+
function layerParagraphValues(base, over) {
|
|
53
|
+
const result = { ...base, ...over };
|
|
54
|
+
const tabStops = layerTabStopDirectives(
|
|
55
|
+
base.tabStops ?? [],
|
|
56
|
+
over.tabStops ?? []
|
|
57
|
+
);
|
|
58
|
+
if (tabStops.length > 0) result.tabStops = tabStops;
|
|
59
|
+
else delete result.tabStops;
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
layerParagraphValues,
|
|
64
|
+
toParagraphFormatLayer
|
|
65
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Reads the first section's header and footer stories for the page preview. */
|
|
2
|
+
import type { ParagraphAlign } from "../model/format";
|
|
3
|
+
export type HeaderFooterVariant = "default" | "first" | "even";
|
|
4
|
+
export type PageField = "PAGE" | "NUMPAGES";
|
|
5
|
+
export type HeaderFooterSegment = {
|
|
6
|
+
kind: "text";
|
|
7
|
+
value: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "field";
|
|
10
|
+
field: PageField;
|
|
11
|
+
};
|
|
12
|
+
/** A display-only projection. The original part remains untouched in the package. */
|
|
13
|
+
export interface HeaderFooterContent {
|
|
14
|
+
segments: readonly HeaderFooterSegment[];
|
|
15
|
+
align: ParagraphAlign | null;
|
|
16
|
+
}
|
|
17
|
+
export interface HeaderFooterVariants {
|
|
18
|
+
default: HeaderFooterContent | null;
|
|
19
|
+
first: HeaderFooterContent | null;
|
|
20
|
+
even: HeaderFooterContent | null;
|
|
21
|
+
}
|
|
22
|
+
export interface HeadersFooters {
|
|
23
|
+
headers: HeaderFooterVariants;
|
|
24
|
+
footers: HeaderFooterVariants;
|
|
25
|
+
firstPageDifferent: boolean;
|
|
26
|
+
evenAndOdd: boolean;
|
|
27
|
+
pageNumberStart: number;
|
|
28
|
+
}
|
|
29
|
+
export declare const NO_HEADERS_FOOTERS: HeadersFooters;
|
|
30
|
+
/** Reads the first section's display stories and section-level selection switches. */
|
|
31
|
+
export declare function readHeadersFooters(parts: Map<string, Uint8Array>, mainPartPath: string, body: Element): HeadersFooters;
|
|
32
|
+
export declare function displayPageNumber(headersFooters: HeadersFooters, page: number): number;
|
|
33
|
+
/** Resolves the section variant and evaluates PAGE and NUMPAGES for one visual page. */
|
|
34
|
+
export declare function headerFooterText(variants: HeaderFooterVariants, headersFooters: HeadersFooters, page: number, totalPages: number): string | null;
|
|
35
|
+
/** Resolves the direct alignment of the first paragraph in the selected story. */
|
|
36
|
+
export declare function headerFooterAlign(variants: HeaderFooterVariants, headersFooters: HeadersFooters, page: number): ParagraphAlign | null;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// src/docx/headersFooters.ts
|
|
2
|
+
import { ALIGN_BY_JC } from "../ooxml/units.js";
|
|
3
|
+
import {
|
|
4
|
+
decodeUtf8,
|
|
5
|
+
elementChildren,
|
|
6
|
+
parseXml,
|
|
7
|
+
R_NS,
|
|
8
|
+
W_NS
|
|
9
|
+
} from "../ooxml/xml.js";
|
|
10
|
+
import { readRelationships, relsPathOf, resolveTarget } from "./relationships.js";
|
|
11
|
+
var EMPTY_VARIANTS = {
|
|
12
|
+
default: null,
|
|
13
|
+
first: null,
|
|
14
|
+
even: null
|
|
15
|
+
};
|
|
16
|
+
var NO_HEADERS_FOOTERS = {
|
|
17
|
+
headers: EMPTY_VARIANTS,
|
|
18
|
+
footers: EMPTY_VARIANTS,
|
|
19
|
+
firstPageDifferent: false,
|
|
20
|
+
evenAndOdd: false,
|
|
21
|
+
pageNumberStart: 1
|
|
22
|
+
};
|
|
23
|
+
function attribute(el, localName) {
|
|
24
|
+
return Array.from(el.attributes).find((entry) => entry.localName === localName)?.value ?? null;
|
|
25
|
+
}
|
|
26
|
+
function isOn(el) {
|
|
27
|
+
if (!el) return false;
|
|
28
|
+
const value = attribute(el, "val")?.toLowerCase();
|
|
29
|
+
return value !== "0" && value !== "false" && value !== "off";
|
|
30
|
+
}
|
|
31
|
+
function firstSectPrIn(root) {
|
|
32
|
+
const namespaced = root.getElementsByTagNameNS(W_NS, "sectPr").item(0);
|
|
33
|
+
if (namespaced) return namespaced;
|
|
34
|
+
for (const el of root.getElementsByTagName("*")) {
|
|
35
|
+
if (el.localName === "sectPr") return el;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
function pageField(instruction) {
|
|
40
|
+
const name = instruction.trim().split(/\s+/, 1)[0]?.toUpperCase();
|
|
41
|
+
return name === "PAGE" || name === "NUMPAGES" ? name : null;
|
|
42
|
+
}
|
|
43
|
+
function paragraphSegments(paragraph) {
|
|
44
|
+
const segments = [];
|
|
45
|
+
const fields = [];
|
|
46
|
+
const suppressed = () => fields.some((field) => !field.separated || field.field !== null);
|
|
47
|
+
const text = (value) => {
|
|
48
|
+
if (!value || suppressed()) return;
|
|
49
|
+
const previous = segments.at(-1);
|
|
50
|
+
if (previous?.kind === "text") previous.value += value;
|
|
51
|
+
else segments.push({ kind: "text", value });
|
|
52
|
+
};
|
|
53
|
+
const dynamic = (field) => {
|
|
54
|
+
if (!suppressed()) segments.push({ kind: "field", field });
|
|
55
|
+
};
|
|
56
|
+
const visit = (el) => {
|
|
57
|
+
if (el.namespaceURI === W_NS && (el.localName === "drawing" || el.localName === "pict" || el.localName === "object" || el.localName === "tbl" || el.localName === "txbxContent")) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (el.namespaceURI === W_NS && el.localName === "fldSimple") {
|
|
61
|
+
const field = pageField(attribute(el, "instr") ?? "");
|
|
62
|
+
if (field) dynamic(field);
|
|
63
|
+
else for (const child of elementChildren(el)) visit(child);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (el.namespaceURI === W_NS && el.localName === "fldChar") {
|
|
67
|
+
const kind = attribute(el, "fldCharType");
|
|
68
|
+
if (kind === "begin") {
|
|
69
|
+
fields.push({ instruction: "", separated: false, field: null });
|
|
70
|
+
} else if (kind === "separate") {
|
|
71
|
+
const active = fields.at(-1);
|
|
72
|
+
if (active) {
|
|
73
|
+
active.field = pageField(active.instruction);
|
|
74
|
+
active.separated = true;
|
|
75
|
+
if (active.field) {
|
|
76
|
+
const outerSuppresses = fields.slice(0, -1).some((field) => !field.separated || field.field !== null);
|
|
77
|
+
if (!outerSuppresses) {
|
|
78
|
+
segments.push({ kind: "field", field: active.field });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} else if (kind === "end") {
|
|
83
|
+
const active = fields.pop();
|
|
84
|
+
if (active && !active.separated) {
|
|
85
|
+
const field = pageField(active.instruction);
|
|
86
|
+
if (field) dynamic(field);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (el.namespaceURI === W_NS && el.localName === "instrText") {
|
|
92
|
+
const active = fields.at(-1);
|
|
93
|
+
if (active && !active.separated)
|
|
94
|
+
active.instruction += el.textContent ?? "";
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (el.namespaceURI === W_NS && el.localName === "t") {
|
|
98
|
+
text(el.textContent ?? "");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (el.namespaceURI === W_NS && el.localName === "tab") {
|
|
102
|
+
text(" ");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (el.namespaceURI === W_NS && (el.localName === "br" || el.localName === "cr")) {
|
|
106
|
+
text("\n");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
for (const child of elementChildren(el)) visit(child);
|
|
110
|
+
};
|
|
111
|
+
for (const child of elementChildren(paragraph)) visit(child);
|
|
112
|
+
return segments;
|
|
113
|
+
}
|
|
114
|
+
function readContent(bytes) {
|
|
115
|
+
const root = parseXml(decodeUtf8(bytes).text).documentElement;
|
|
116
|
+
const paragraphs = elementChildren(root).filter(
|
|
117
|
+
(child) => child.namespaceURI === W_NS && child.localName === "p"
|
|
118
|
+
);
|
|
119
|
+
const segments = [];
|
|
120
|
+
paragraphs.forEach((paragraph, index) => {
|
|
121
|
+
if (index > 0) segments.push({ kind: "text", value: "\n" });
|
|
122
|
+
segments.push(...paragraphSegments(paragraph));
|
|
123
|
+
});
|
|
124
|
+
const pPr = paragraphs[0] ? elementChildren(paragraphs[0]).find(
|
|
125
|
+
(child) => child.namespaceURI === W_NS && child.localName === "pPr"
|
|
126
|
+
) : void 0;
|
|
127
|
+
const jc = pPr ? elementChildren(pPr).find(
|
|
128
|
+
(child) => child.namespaceURI === W_NS && child.localName === "jc"
|
|
129
|
+
) : void 0;
|
|
130
|
+
return {
|
|
131
|
+
segments,
|
|
132
|
+
align: jc ? ALIGN_BY_JC[attribute(jc, "val") ?? ""] ?? null : null
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function settingsEvenAndOdd(parts, mainPartPath) {
|
|
136
|
+
const relationship = readRelationships(parts, relsPathOf(mainPartPath)).find(
|
|
137
|
+
(entry) => entry.type === `${R_NS}/settings` && !entry.external
|
|
138
|
+
);
|
|
139
|
+
if (!relationship) return false;
|
|
140
|
+
const bytes = parts.get(resolveTarget(mainPartPath, relationship.target));
|
|
141
|
+
if (!bytes) return false;
|
|
142
|
+
const root = parseXml(decodeUtf8(bytes).text).documentElement;
|
|
143
|
+
const setting = root.getElementsByTagNameNS(W_NS, "evenAndOddHeaders").item(0);
|
|
144
|
+
return isOn(setting);
|
|
145
|
+
}
|
|
146
|
+
function readVariants(parts, mainPartPath, sectPr, kind) {
|
|
147
|
+
const relationships = new Map(
|
|
148
|
+
readRelationships(parts, relsPathOf(mainPartPath)).map((entry) => [
|
|
149
|
+
entry.id,
|
|
150
|
+
entry
|
|
151
|
+
])
|
|
152
|
+
);
|
|
153
|
+
const variants = { ...EMPTY_VARIANTS };
|
|
154
|
+
for (const reference of elementChildren(sectPr)) {
|
|
155
|
+
if (reference.localName !== `${kind}Reference`) continue;
|
|
156
|
+
const type = attribute(reference, "type") ?? "default";
|
|
157
|
+
if (type !== "default" && type !== "first" && type !== "even") continue;
|
|
158
|
+
const id = reference.getAttributeNS(R_NS, "id") ?? attribute(reference, "id");
|
|
159
|
+
if (!id) continue;
|
|
160
|
+
const relationship = relationships.get(id);
|
|
161
|
+
if (!relationship || relationship.external || relationship.type !== `${R_NS}/${kind}`) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const bytes = parts.get(resolveTarget(mainPartPath, relationship.target));
|
|
165
|
+
if (bytes) variants[type] = readContent(bytes);
|
|
166
|
+
}
|
|
167
|
+
return variants;
|
|
168
|
+
}
|
|
169
|
+
function pageNumberStart(sectPr) {
|
|
170
|
+
const pgNumType = elementChildren(sectPr).find(
|
|
171
|
+
(child) => child.localName === "pgNumType"
|
|
172
|
+
);
|
|
173
|
+
const declared = pgNumType ? attribute(pgNumType, "start") : null;
|
|
174
|
+
if (declared === null) return 1;
|
|
175
|
+
const start = Number(declared);
|
|
176
|
+
return Number.isSafeInteger(start) && start >= 0 ? start : 1;
|
|
177
|
+
}
|
|
178
|
+
function readHeadersFooters(parts, mainPartPath, body) {
|
|
179
|
+
const sectPr = firstSectPrIn(body);
|
|
180
|
+
if (!sectPr) return NO_HEADERS_FOOTERS;
|
|
181
|
+
return {
|
|
182
|
+
headers: readVariants(parts, mainPartPath, sectPr, "header"),
|
|
183
|
+
footers: readVariants(parts, mainPartPath, sectPr, "footer"),
|
|
184
|
+
firstPageDifferent: isOn(
|
|
185
|
+
elementChildren(sectPr).find((child) => child.localName === "titlePg") ?? null
|
|
186
|
+
),
|
|
187
|
+
evenAndOdd: settingsEvenAndOdd(parts, mainPartPath),
|
|
188
|
+
pageNumberStart: pageNumberStart(sectPr)
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function displayPageNumber(headersFooters, page) {
|
|
192
|
+
return headersFooters.pageNumberStart + page - 1;
|
|
193
|
+
}
|
|
194
|
+
function contentForPage(variants, headersFooters, page) {
|
|
195
|
+
if (page === 1 && headersFooters.firstPageDifferent) return variants.first;
|
|
196
|
+
if (headersFooters.evenAndOdd && displayPageNumber(headersFooters, page) % 2 === 0) {
|
|
197
|
+
return variants.even;
|
|
198
|
+
}
|
|
199
|
+
return variants.default;
|
|
200
|
+
}
|
|
201
|
+
function headerFooterText(variants, headersFooters, page, totalPages) {
|
|
202
|
+
const content = contentForPage(variants, headersFooters, page);
|
|
203
|
+
if (!content) return null;
|
|
204
|
+
return content.segments.map((segment) => {
|
|
205
|
+
if (segment.kind === "text") return segment.value;
|
|
206
|
+
return segment.field === "PAGE" ? `${displayPageNumber(headersFooters, page)}` : `${totalPages}`;
|
|
207
|
+
}).join("");
|
|
208
|
+
}
|
|
209
|
+
function headerFooterAlign(variants, headersFooters, page) {
|
|
210
|
+
return contentForPage(variants, headersFooters, page)?.align ?? null;
|
|
211
|
+
}
|
|
212
|
+
export {
|
|
213
|
+
NO_HEADERS_FOOTERS,
|
|
214
|
+
displayPageNumber,
|
|
215
|
+
headerFooterAlign,
|
|
216
|
+
headerFooterText,
|
|
217
|
+
readHeadersFooters
|
|
218
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hyperlinks (`w:hyperlink`, §17.16.22): the wrapper a document brought in, and the relationship a
|
|
3
|
+
* link's address lives on. `spec/notes/hyperlinks.md` has what the specification settles.
|
|
4
|
+
*
|
|
5
|
+
* A link names its target one of two ways. `r:id` points at a relationship whose target is the
|
|
6
|
+
* address, so the address of an external link is never in the body at all; `w:anchor` names a
|
|
7
|
+
* bookmark, which this editor does not model and therefore never reads.
|
|
8
|
+
*
|
|
9
|
+
* The wrapper travels as the verbatim opening tag, the way a content control's does (`docx/sdt`),
|
|
10
|
+
* so `w:tooltip`, `w:history`, `w:docLocation` and anything else we never read go back out
|
|
11
|
+
* untouched.
|
|
12
|
+
*/
|
|
13
|
+
import { type RelationshipWriter } from "./relationships";
|
|
14
|
+
export interface HyperlinkWrapper {
|
|
15
|
+
/** The `<w:hyperlink>` opening tag as it came */
|
|
16
|
+
prefix: string;
|
|
17
|
+
/** The relationship its address lives on. null for a link that names a bookmark alone */
|
|
18
|
+
relId: string | null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Takes a `w:hyperlink` apart into the wrapper to put back on export. null for a shape we do not
|
|
22
|
+
* write ourselves, which leaves whatever held the link preserved as its own fragment.
|
|
23
|
+
*
|
|
24
|
+
* The `w:` prefix on the tag is one we write, and `r:id` is an attribute a retargeted link has
|
|
25
|
+
* rewritten by name, so a document that binds either namespace to another prefix is left alone
|
|
26
|
+
* rather than written back under ours.
|
|
27
|
+
*/
|
|
28
|
+
export declare function readHyperlinkWrapper(el: Element): HyperlinkWrapper | null;
|
|
29
|
+
/** The address of every external link the body can point at, keyed by relationship id */
|
|
30
|
+
export type LinkTargets = ReadonlyMap<string, string>;
|
|
31
|
+
export declare const NO_LINK_TARGETS: LinkTargets;
|
|
32
|
+
/**
|
|
33
|
+
* Every address the body has a hyperlink relationship to.
|
|
34
|
+
*
|
|
35
|
+
* A relationship of another type, or one whose target is a part inside the package rather than an
|
|
36
|
+
* address outside it, is left out: the link that points at it keeps its wrapper and offers no
|
|
37
|
+
* address, the same as a link naming a bookmark.
|
|
38
|
+
*/
|
|
39
|
+
export declare function readLinkTargets(parts: Map<string, Uint8Array>, mainPartPath: string): LinkTargets;
|
|
40
|
+
/** The relationship id this opening tag names, null when it names none */
|
|
41
|
+
export declare function relIdIn(prefix: string): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* The same opening tag pointing at this relationship. `<w:hyperlink>` on its own is what a link
|
|
44
|
+
* made in the editor starts from.
|
|
45
|
+
*
|
|
46
|
+
* A tag that already names one has only that value rewritten, so a link nobody retargeted comes
|
|
47
|
+
* out as the very string it went in as. A tag that named none is given the attribute, which the
|
|
48
|
+
* specification has supersede any `w:anchor` beside it, along with the namespace it lives in: the
|
|
49
|
+
* body we write into is not always one that declares it, and declaring it again where it is
|
|
50
|
+
* already bound to the same namespace changes nothing.
|
|
51
|
+
*/
|
|
52
|
+
export declare function withRelId(prefix: string, relId: string): string;
|
|
53
|
+
/** Which relationship each address goes out on while the body is being written */
|
|
54
|
+
export interface LinkRefs {
|
|
55
|
+
/**
|
|
56
|
+
* The relationship the link at this address points at. `was` is the id the link came in on,
|
|
57
|
+
* which is kept where it still leads to that same address.
|
|
58
|
+
* undefined where there is no relationships part to add to, which is a serializer running
|
|
59
|
+
* outside an export.
|
|
60
|
+
*/
|
|
61
|
+
relIdOf(href: string, was: string | null): string | undefined;
|
|
62
|
+
}
|
|
63
|
+
/** What a serializer called on its own, outside an export, has to work with */
|
|
64
|
+
export declare const NO_LINK_REFS: LinkRefs;
|
|
65
|
+
/**
|
|
66
|
+
* Hands out the relationship for every address the body points at, adding one where the package
|
|
67
|
+
* has none.
|
|
68
|
+
*
|
|
69
|
+
* Nothing is planned ahead: an address is asked for as its link is written, and the relationships
|
|
70
|
+
* part is built once the body is (`docx/exportDocx`).
|
|
71
|
+
* An address already in the package is pointed at again rather than written twice, and the
|
|
72
|
+
* relationship a link arrived on is kept wherever it still leads where the link now goes, so
|
|
73
|
+
* retargeting one link in a document leaves every other link's XML alone.
|
|
74
|
+
*/
|
|
75
|
+
export declare function hyperlinkRefs(relationships: RelationshipWriter): LinkRefs;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// src/docx/hyperlink.ts
|
|
2
|
+
import { attrString, R_NS } from "../ooxml/xml.js";
|
|
3
|
+
import {
|
|
4
|
+
readRelationships,
|
|
5
|
+
relsPathOf
|
|
6
|
+
} from "./relationships.js";
|
|
7
|
+
var HYPERLINK_REL_TYPE = `${R_NS}/hyperlink`;
|
|
8
|
+
var REL_ID_ATTR = "r:id";
|
|
9
|
+
var REL_ID_VALUE = /\sr:id="([^"]*)"/;
|
|
10
|
+
function readHyperlinkWrapper(el) {
|
|
11
|
+
if (el.nodeName !== "w:hyperlink") return null;
|
|
12
|
+
const relId = el.getAttributeNS(R_NS, "id");
|
|
13
|
+
if (relId !== null && !el.hasAttribute(REL_ID_ATTR)) return null;
|
|
14
|
+
const attrs = attrString(el);
|
|
15
|
+
return {
|
|
16
|
+
prefix: attrs ? `<w:hyperlink ${attrs}>` : "<w:hyperlink>",
|
|
17
|
+
relId
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
var NO_LINK_TARGETS = /* @__PURE__ */ new Map();
|
|
21
|
+
function readLinkTargets(parts, mainPartPath) {
|
|
22
|
+
const targets = /* @__PURE__ */ new Map();
|
|
23
|
+
for (const rel of readRelationships(parts, relsPathOf(mainPartPath))) {
|
|
24
|
+
if (rel.type !== HYPERLINK_REL_TYPE || !rel.external) continue;
|
|
25
|
+
targets.set(rel.id, rel.target);
|
|
26
|
+
}
|
|
27
|
+
return targets;
|
|
28
|
+
}
|
|
29
|
+
function relIdIn(prefix) {
|
|
30
|
+
return REL_ID_VALUE.exec(prefix)?.[1] ?? null;
|
|
31
|
+
}
|
|
32
|
+
function withRelId(prefix, relId) {
|
|
33
|
+
if (REL_ID_VALUE.test(prefix)) {
|
|
34
|
+
return prefix.replace(REL_ID_VALUE, ` ${REL_ID_ATTR}="${relId}"`);
|
|
35
|
+
}
|
|
36
|
+
const name = "<w:hyperlink";
|
|
37
|
+
return `${name} xmlns:r="${R_NS}" ${REL_ID_ATTR}="${relId}"${prefix.slice(name.length)}`;
|
|
38
|
+
}
|
|
39
|
+
var NO_LINK_REFS = { relIdOf: () => void 0 };
|
|
40
|
+
function hyperlinkRefs(relationships) {
|
|
41
|
+
const external = relationships.opened.filter(
|
|
42
|
+
(rel) => rel.type === HYPERLINK_REL_TYPE && rel.external
|
|
43
|
+
);
|
|
44
|
+
const added = /* @__PURE__ */ new Map();
|
|
45
|
+
return {
|
|
46
|
+
relIdOf: (href, was) => {
|
|
47
|
+
const kept = external.find((rel) => rel.id === was);
|
|
48
|
+
if (kept?.target === href) return was ?? void 0;
|
|
49
|
+
const found = external.find((rel) => rel.target === href);
|
|
50
|
+
if (found) return found.id;
|
|
51
|
+
const already = added.get(href);
|
|
52
|
+
if (already !== void 0) return already;
|
|
53
|
+
const id = relationships.add({
|
|
54
|
+
type: HYPERLINK_REL_TYPE,
|
|
55
|
+
target: href,
|
|
56
|
+
external: true
|
|
57
|
+
});
|
|
58
|
+
added.set(href, id);
|
|
59
|
+
return id;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
NO_LINK_REFS,
|
|
65
|
+
NO_LINK_TARGETS,
|
|
66
|
+
hyperlinkRefs,
|
|
67
|
+
readHyperlinkWrapper,
|
|
68
|
+
readLinkTargets,
|
|
69
|
+
relIdIn,
|
|
70
|
+
withRelId
|
|
71
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads docx bytes and builds the document to edit plus the store holding the original.
|
|
3
|
+
*
|
|
4
|
+
* This module knows nothing about the screen. All it knows is the file and the document model.
|
|
5
|
+
*/
|
|
6
|
+
import { type Node as PMNode } from "prosemirror-model";
|
|
7
|
+
import { SessionStore } from "./session";
|
|
8
|
+
/** A docx file as bytes, however it arrived (file input, fetch, filesystem) */
|
|
9
|
+
export type DocxBytes = ArrayBuffer | Uint8Array;
|
|
10
|
+
/**
|
|
11
|
+
* A docx file however a consumer holds it: the bytes, or the `File`/`Blob` a file
|
|
12
|
+
* input or a fetch hands over.
|
|
13
|
+
*
|
|
14
|
+
* Reading a `Blob` is asynchronous, so only the React component takes one; the
|
|
15
|
+
* engine on `./core` stays synchronous and bytes-only.
|
|
16
|
+
*/
|
|
17
|
+
export type DocxSource = DocxBytes | Blob;
|
|
18
|
+
export declare function importDocx(input: DocxBytes): {
|
|
19
|
+
doc: PMNode;
|
|
20
|
+
session: SessionStore;
|
|
21
|
+
};
|