@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,323 @@
|
|
|
1
|
+
// src/editor/externalClipboard.ts
|
|
2
|
+
import { Fragment, Slice } from "prosemirror-model";
|
|
3
|
+
import { Plugin } from "prosemirror-state";
|
|
4
|
+
import { effectiveParagraphFormat, styleIdOf } from "../docx/formatting.js";
|
|
5
|
+
import { withParagraphStyle } from "../docx/paraProps.js";
|
|
6
|
+
import { MAX_ILVL, nextNumId } from "../numbering/listTemplate.js";
|
|
7
|
+
import { docxSchema } from "../schema/index.js";
|
|
8
|
+
import { editorClassNames } from "../styles/classNames.js";
|
|
9
|
+
import { PASTED_IMAGE_ATTRIBUTE } from "./clipboard/images.js";
|
|
10
|
+
import {
|
|
11
|
+
appendInline,
|
|
12
|
+
contextFor,
|
|
13
|
+
marksFor,
|
|
14
|
+
withInlineStyle
|
|
15
|
+
} from "./clipboard/inlineFormatting.js";
|
|
16
|
+
import { listRefOf } from "./commands/listCommands.js";
|
|
17
|
+
import {
|
|
18
|
+
defaultParagraphStyleId,
|
|
19
|
+
documentParagraphFormatting,
|
|
20
|
+
documentParagraphStyles,
|
|
21
|
+
documentStyles
|
|
22
|
+
} from "./documentStyles.js";
|
|
23
|
+
import { insertPlainText } from "./plainText.js";
|
|
24
|
+
import { moveCaretToDrop } from "./plugins/dropCaret.js";
|
|
25
|
+
import {
|
|
26
|
+
canStartNewList,
|
|
27
|
+
documentNumbering
|
|
28
|
+
} from "./plugins/numberingDecorations.js";
|
|
29
|
+
var BLOCK_TAGS = /* @__PURE__ */ new Set([
|
|
30
|
+
"ADDRESS",
|
|
31
|
+
"ARTICLE",
|
|
32
|
+
"ASIDE",
|
|
33
|
+
"BLOCKQUOTE",
|
|
34
|
+
"DIV",
|
|
35
|
+
"H1",
|
|
36
|
+
"H2",
|
|
37
|
+
"H3",
|
|
38
|
+
"H4",
|
|
39
|
+
"H5",
|
|
40
|
+
"H6",
|
|
41
|
+
"LI",
|
|
42
|
+
"P",
|
|
43
|
+
"PRE",
|
|
44
|
+
"SECTION"
|
|
45
|
+
]);
|
|
46
|
+
var HEADING_LEVELS = {
|
|
47
|
+
H1: 1,
|
|
48
|
+
H2: 2,
|
|
49
|
+
H3: 3,
|
|
50
|
+
H4: 4,
|
|
51
|
+
H5: 5,
|
|
52
|
+
H6: 6
|
|
53
|
+
};
|
|
54
|
+
var HEADING_FALLBACKS = {
|
|
55
|
+
1: { bold: true, fontSizePt: 24 },
|
|
56
|
+
2: { bold: true, fontSizePt: 18 },
|
|
57
|
+
3: { bold: true, fontSizePt: 14 },
|
|
58
|
+
4: { bold: true, fontSizePt: 12 },
|
|
59
|
+
5: { bold: true, fontSizePt: 10 },
|
|
60
|
+
6: { bold: true, fontSizePt: 8 }
|
|
61
|
+
};
|
|
62
|
+
function normalizedStyleName(value) {
|
|
63
|
+
return value.toLowerCase().replace(/[\s_-]+/g, "");
|
|
64
|
+
}
|
|
65
|
+
function copiedStyleId(element) {
|
|
66
|
+
return element.classList.contains(editorClassNames.paragraph) ? styleIdOf(element.getAttribute("data-ppr")) : null;
|
|
67
|
+
}
|
|
68
|
+
function headingLevel(element, sourceStyleId) {
|
|
69
|
+
const direct = HEADING_LEVELS[element.tagName];
|
|
70
|
+
if (direct !== void 0) return direct;
|
|
71
|
+
const match = /^heading([1-6])$/.exec(
|
|
72
|
+
normalizedStyleName(sourceStyleId ?? "")
|
|
73
|
+
);
|
|
74
|
+
return match ? Number.parseInt(match[1] ?? "", 10) : null;
|
|
75
|
+
}
|
|
76
|
+
function destinationStyleId(state, sourceStyleId, level) {
|
|
77
|
+
const styles = documentParagraphStyles(state);
|
|
78
|
+
if (sourceStyleId && styles.some((style) => style.id === sourceStyleId)) {
|
|
79
|
+
return sourceStyleId;
|
|
80
|
+
}
|
|
81
|
+
if (level === null) return null;
|
|
82
|
+
const wanted = `heading${level}`;
|
|
83
|
+
return styles.find(
|
|
84
|
+
(style) => normalizedStyleName(style.id) === wanted || normalizedStyleName(style.name) === wanted
|
|
85
|
+
)?.id ?? null;
|
|
86
|
+
}
|
|
87
|
+
function blockContext(state, parent, element, preserveParagraphStyle) {
|
|
88
|
+
const editorParagraph = element.classList.contains(
|
|
89
|
+
editorClassNames.paragraph
|
|
90
|
+
);
|
|
91
|
+
const sourceStyleId = copiedStyleId(element);
|
|
92
|
+
const level = headingLevel(element, sourceStyleId);
|
|
93
|
+
if (!preserveParagraphStyle && editorParagraph) {
|
|
94
|
+
return {
|
|
95
|
+
inline: contextFor(parent, element),
|
|
96
|
+
paragraph: null
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const styleId = destinationStyleId(state, sourceStyleId, level);
|
|
100
|
+
const paragraph = styleId === null ? null : withParagraphStyle(
|
|
101
|
+
null,
|
|
102
|
+
styleId,
|
|
103
|
+
documentStyles(state),
|
|
104
|
+
defaultParagraphStyleId(state)
|
|
105
|
+
);
|
|
106
|
+
const usesDestinationStyle = editorParagraph && (sourceStyleId === null || paragraph !== null);
|
|
107
|
+
let inline = parent;
|
|
108
|
+
if (paragraph === null && level !== null) {
|
|
109
|
+
inline = withInlineStyle(inline, HEADING_FALLBACKS[level] ?? {});
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
inline: contextFor(inline, element, !usesDestinationStyle),
|
|
113
|
+
paragraph
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function listParagraphAttrs(state, list) {
|
|
117
|
+
if (!list || list.numId === null) return null;
|
|
118
|
+
const ilvl = Math.min(MAX_ILVL, list.level);
|
|
119
|
+
const pPr = `<w:pPr><w:numPr><w:ilvl w:val="${ilvl}"/><w:numId w:val="${list.numId}"/></w:numPr></w:pPr>`;
|
|
120
|
+
return {
|
|
121
|
+
pPr,
|
|
122
|
+
format: effectiveParagraphFormat(pPr, documentParagraphFormatting(state))
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function paragraphAttrs(state, list, paragraph) {
|
|
126
|
+
const listed = listParagraphAttrs(state, list);
|
|
127
|
+
if (listed) return listed;
|
|
128
|
+
return paragraph ? {
|
|
129
|
+
pPr: paragraph.pPr,
|
|
130
|
+
format: effectiveParagraphFormat(
|
|
131
|
+
paragraph.pPr,
|
|
132
|
+
documentParagraphFormatting(state)
|
|
133
|
+
),
|
|
134
|
+
styleRun: paragraph.styleRun
|
|
135
|
+
} : null;
|
|
136
|
+
}
|
|
137
|
+
function usedNumIds(state) {
|
|
138
|
+
const used = new Set(documentNumbering(state).lists.keys());
|
|
139
|
+
state.doc.descendants((node) => {
|
|
140
|
+
if (node.type !== docxSchema.nodes.paragraph) return true;
|
|
141
|
+
const ref = listRefOf(node);
|
|
142
|
+
if (ref) used.add(ref.numId);
|
|
143
|
+
return false;
|
|
144
|
+
});
|
|
145
|
+
return used;
|
|
146
|
+
}
|
|
147
|
+
var HtmlReader = class {
|
|
148
|
+
constructor(state, preserveParagraphStyles, images) {
|
|
149
|
+
this.state = state;
|
|
150
|
+
this.preserveParagraphStyles = preserveParagraphStyles;
|
|
151
|
+
this.images = images;
|
|
152
|
+
this.used = usedNumIds(state);
|
|
153
|
+
this.canCreateLists = canStartNewList(state);
|
|
154
|
+
}
|
|
155
|
+
state;
|
|
156
|
+
preserveParagraphStyles;
|
|
157
|
+
images;
|
|
158
|
+
blocks = [];
|
|
159
|
+
used;
|
|
160
|
+
canCreateLists;
|
|
161
|
+
read(root) {
|
|
162
|
+
this.readFlow(root, { style: {}, href: null, preserveWhitespace: false });
|
|
163
|
+
return this.blocks;
|
|
164
|
+
}
|
|
165
|
+
appendInline(target, node, context) {
|
|
166
|
+
appendInline(target, node, context, (content, element, inline) => {
|
|
167
|
+
if (element.tagName !== "IMG") return false;
|
|
168
|
+
const token = element.getAttribute(PASTED_IMAGE_ATTRIBUTE);
|
|
169
|
+
const image = token === null ? void 0 : this.images.get(token);
|
|
170
|
+
if (!image) return true;
|
|
171
|
+
content.push(
|
|
172
|
+
docxSchema.nodes.image.create(
|
|
173
|
+
{
|
|
174
|
+
...image,
|
|
175
|
+
// The source drawing may point at a relationship in another package.
|
|
176
|
+
xml: null
|
|
177
|
+
},
|
|
178
|
+
null,
|
|
179
|
+
marksFor(inline)
|
|
180
|
+
)
|
|
181
|
+
);
|
|
182
|
+
return true;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
addParagraph(content, list = null, paragraph = null) {
|
|
186
|
+
if (list && list.numId === null) {
|
|
187
|
+
const marker = list.kind === "bullet" ? "\u2022 " : "1. ";
|
|
188
|
+
content.unshift(docxSchema.text(marker));
|
|
189
|
+
}
|
|
190
|
+
this.blocks.push(
|
|
191
|
+
docxSchema.nodes.paragraph.create(
|
|
192
|
+
paragraphAttrs(this.state, list, paragraph),
|
|
193
|
+
content
|
|
194
|
+
)
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
readFlow(parent, context, paragraph = null) {
|
|
198
|
+
let inline = [];
|
|
199
|
+
const flush = () => {
|
|
200
|
+
if (inline.length === 0) return;
|
|
201
|
+
this.addParagraph(inline, null, paragraph);
|
|
202
|
+
inline = [];
|
|
203
|
+
};
|
|
204
|
+
for (const child of parent.childNodes) {
|
|
205
|
+
const element = child.nodeType === child.ELEMENT_NODE ? child : null;
|
|
206
|
+
if (element?.tagName === "UL" || element?.tagName === "OL") {
|
|
207
|
+
flush();
|
|
208
|
+
this.readList(element, context, 0, null);
|
|
209
|
+
} else if (element && BLOCK_TAGS.has(element.tagName)) {
|
|
210
|
+
flush();
|
|
211
|
+
const before = this.blocks.length;
|
|
212
|
+
const block = blockContext(
|
|
213
|
+
this.state,
|
|
214
|
+
context,
|
|
215
|
+
element,
|
|
216
|
+
this.preserveParagraphStyles
|
|
217
|
+
);
|
|
218
|
+
this.readFlow(element, block.inline, block.paragraph);
|
|
219
|
+
if (this.blocks.length === before) {
|
|
220
|
+
this.addParagraph([], null, block.paragraph);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
this.appendInline(inline, child, context);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
flush();
|
|
227
|
+
}
|
|
228
|
+
takeNumId(kind) {
|
|
229
|
+
if (!this.canCreateLists) return null;
|
|
230
|
+
const id = nextNumId(this.used, kind);
|
|
231
|
+
this.used.add(id);
|
|
232
|
+
return id;
|
|
233
|
+
}
|
|
234
|
+
readList(list, context, level, inherited) {
|
|
235
|
+
const kind = list.tagName === "UL" ? "bullet" : "numbered";
|
|
236
|
+
const listContext = {
|
|
237
|
+
kind,
|
|
238
|
+
numId: inherited?.kind === kind ? inherited.numId : this.takeNumId(kind),
|
|
239
|
+
level
|
|
240
|
+
};
|
|
241
|
+
const items = Array.from(list.children).filter(
|
|
242
|
+
(child) => child.tagName === "LI"
|
|
243
|
+
);
|
|
244
|
+
for (const item of items) {
|
|
245
|
+
const itemContext = contextFor(context, item);
|
|
246
|
+
const content = [];
|
|
247
|
+
for (const child of item.childNodes) {
|
|
248
|
+
const nested = child.nodeType === child.ELEMENT_NODE ? child : null;
|
|
249
|
+
if (nested?.tagName === "UL" || nested?.tagName === "OL") continue;
|
|
250
|
+
this.appendInline(content, child, itemContext);
|
|
251
|
+
}
|
|
252
|
+
this.addParagraph(content, listContext);
|
|
253
|
+
for (const nested of Array.from(item.children)) {
|
|
254
|
+
if (nested.tagName === "UL" || nested.tagName === "OL") {
|
|
255
|
+
this.readList(
|
|
256
|
+
nested,
|
|
257
|
+
itemContext,
|
|
258
|
+
level + 1,
|
|
259
|
+
listContext
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
function sliceDepth(root) {
|
|
267
|
+
const marker = root.querySelector("[data-pm-slice]");
|
|
268
|
+
const openStart = Number.parseInt(
|
|
269
|
+
marker?.getAttribute("data-pm-slice")?.split(/\s+/, 1)[0] ?? "",
|
|
270
|
+
10
|
|
271
|
+
);
|
|
272
|
+
if (Number.isFinite(openStart)) return openStart === 0 ? 0 : 1;
|
|
273
|
+
const blocks = [...BLOCK_TAGS, "OL", "UL"].map((tag) => tag.toLowerCase());
|
|
274
|
+
return root.querySelector(blocks.join(",")) ? 0 : 1;
|
|
275
|
+
}
|
|
276
|
+
function richHtmlSlice(state, document, source, images = /* @__PURE__ */ new Map()) {
|
|
277
|
+
if (source.trim() === "") return null;
|
|
278
|
+
const template = document.createElement("template");
|
|
279
|
+
template.innerHTML = source;
|
|
280
|
+
const open = sliceDepth(template.content);
|
|
281
|
+
const blocks = new HtmlReader(state, open === 0, images).read(
|
|
282
|
+
template.content
|
|
283
|
+
);
|
|
284
|
+
return blocks.length === 0 ? null : new Slice(Fragment.fromArray([...blocks]), open, open);
|
|
285
|
+
}
|
|
286
|
+
function insertRichHtml(view, source) {
|
|
287
|
+
const slice = richHtmlSlice(view.state, view.dom.ownerDocument, source);
|
|
288
|
+
if (slice === null) return false;
|
|
289
|
+
view.dispatch(view.state.tr.replaceSelection(slice).scrollIntoView());
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
function insertClipboardData(view, data) {
|
|
293
|
+
if (insertRichHtml(view, data.html ?? "")) return;
|
|
294
|
+
insertPlainText(view, data.text ?? "");
|
|
295
|
+
}
|
|
296
|
+
function externalClipboard() {
|
|
297
|
+
return new Plugin({
|
|
298
|
+
props: {
|
|
299
|
+
handlePaste(view, event) {
|
|
300
|
+
insertClipboardData(view, {
|
|
301
|
+
html: event.clipboardData?.getData("text/html"),
|
|
302
|
+
text: event.clipboardData?.getData("text/plain")
|
|
303
|
+
});
|
|
304
|
+
return true;
|
|
305
|
+
},
|
|
306
|
+
handleDrop(view, event) {
|
|
307
|
+
if (view.dragging) return false;
|
|
308
|
+
const text = event.dataTransfer?.getData("text/plain") ?? "";
|
|
309
|
+
if (text) {
|
|
310
|
+
moveCaretToDrop(view, event);
|
|
311
|
+
insertPlainText(view, text);
|
|
312
|
+
}
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
export {
|
|
319
|
+
externalClipboard,
|
|
320
|
+
insertClipboardData,
|
|
321
|
+
insertRichHtml,
|
|
322
|
+
richHtmlSlice
|
|
323
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image files coming in from outside: from the picker the toolbar opens, from a paste, and
|
|
3
|
+
* from a drop.
|
|
4
|
+
*
|
|
5
|
+
* All three take one path. The file is read as a data URL, the decoded image states its
|
|
6
|
+
* natural pixel size, and that size - shrunk to the width of a line of body text when the
|
|
7
|
+
* image is wider than the page - becomes the size the drawing records.
|
|
8
|
+
* Only the kinds `docx/image` can write back are taken; a file of any other kind is left
|
|
9
|
+
* where it was, for whoever else wants the event.
|
|
10
|
+
*/
|
|
11
|
+
import { Plugin } from "prosemirror-state";
|
|
12
|
+
import type { EditorView } from "prosemirror-view";
|
|
13
|
+
import { type ImageExtent } from "../ooxml/image";
|
|
14
|
+
import { type ImageToInsert } from "./insertImage";
|
|
15
|
+
/** What a file picker is told to accept: the kinds we can both draw and write back */
|
|
16
|
+
export declare const IMAGE_FILE_ACCEPT: string;
|
|
17
|
+
/** Anything holding a list of files: a clipboard, a drag, a file input */
|
|
18
|
+
interface FileCarrier {
|
|
19
|
+
readonly files: ArrayLike<File> | null;
|
|
20
|
+
}
|
|
21
|
+
/** The image files a clipboard, a drag or an input is carrying, in the order they came */
|
|
22
|
+
export declare function imageFilesIn(carrier: FileCarrier | null | undefined): File[];
|
|
23
|
+
/**
|
|
24
|
+
* The size an image is first shown at.
|
|
25
|
+
*
|
|
26
|
+
* Its own pixel size, shrunk to the supplied width and height caps. A photo straight off a
|
|
27
|
+
* camera would otherwise come in several times wider than the paper. An image that already
|
|
28
|
+
* fits is never grown.
|
|
29
|
+
* Null for a size we cannot show, so nothing goes in that would draw as an empty box.
|
|
30
|
+
*
|
|
31
|
+
* The width is the open document's own (`documentBodyWidthPx`). A caller with no document to
|
|
32
|
+
* ask gets the A4 body width, which is the width every document used to be fitted to.
|
|
33
|
+
*/
|
|
34
|
+
export declare function fittedExtent(width: number, height: number, maxWidthPx?: number, maxHeightPx?: number): ImageExtent | null;
|
|
35
|
+
export declare function boundedImageSrc(source: unknown): string | null;
|
|
36
|
+
export declare function imageSourceByteLength(source: string): number;
|
|
37
|
+
/**
|
|
38
|
+
* Reads one file into the values an image node needs.
|
|
39
|
+
* Null for a file that is not an image kind we can carry, or one the browser could not
|
|
40
|
+
* decode.
|
|
41
|
+
*
|
|
42
|
+
* `maxWidthPx` is the width an image wider than the page is shrunk to, which the caller
|
|
43
|
+
* reads off the document it is inserting into.
|
|
44
|
+
*/
|
|
45
|
+
export declare function readImageFile(file: File, maxWidthPx?: number): Promise<ImageToInsert | null>;
|
|
46
|
+
export interface ImageReadOptions {
|
|
47
|
+
maxWidthPx?: number;
|
|
48
|
+
maxHeightPx?: number;
|
|
49
|
+
preferredExtent?: ImageExtent | null;
|
|
50
|
+
alt?: string | null;
|
|
51
|
+
signal?: AbortSignal;
|
|
52
|
+
}
|
|
53
|
+
export declare function readImageSource(source: string, { maxWidthPx, maxHeightPx, preferredExtent, alt, signal, }?: ImageReadOptions): Promise<ImageToInsert | null>;
|
|
54
|
+
export declare function readImageBlob(source: Blob, options?: ImageReadOptions): Promise<ImageToInsert | null>;
|
|
55
|
+
/**
|
|
56
|
+
* Puts the files into the document one after another, each at the position the one before
|
|
57
|
+
* it left the caret. A file that could not be read is skipped.
|
|
58
|
+
*
|
|
59
|
+
* Each image is fitted to one line of body text on the document's own paper, read once up
|
|
60
|
+
* front: the paper is fixed for as long as the document is open.
|
|
61
|
+
* Reading a file is asynchronous, so the editor may be gone by the time the bytes are
|
|
62
|
+
* there; a torn down view is left alone.
|
|
63
|
+
*/
|
|
64
|
+
export declare function insertImageFiles(view: EditorView, files: readonly File[]): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* The plugin that takes image files pasted or dropped onto the paper.
|
|
67
|
+
*
|
|
68
|
+
* It has to sit ahead of the plain-text plugin, which answers for every paste and drop
|
|
69
|
+
* whether or not it has anything to insert (see the plugin order in `createEditor.ts`).
|
|
70
|
+
* An event carrying no image file is passed on untouched, so text keeps coming in exactly
|
|
71
|
+
* as it did.
|
|
72
|
+
*/
|
|
73
|
+
export declare function imageFiles(): Plugin;
|
|
74
|
+
export {};
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// src/editor/imageFiles.ts
|
|
2
|
+
import { Plugin } from "prosemirror-state";
|
|
3
|
+
import { MAX_IMAGE_BYTES } from "../docx/media.js";
|
|
4
|
+
import { A4_BODY_WIDTH } from "../docx/pageGeometry.js";
|
|
5
|
+
import {
|
|
6
|
+
emuToPx,
|
|
7
|
+
IMAGE_MIMES,
|
|
8
|
+
imageBase64Of,
|
|
9
|
+
isImageMime,
|
|
10
|
+
pxToEmu,
|
|
11
|
+
toImageSrc
|
|
12
|
+
} from "../ooxml/image.js";
|
|
13
|
+
import { documentBodyWidthPx } from "./documentStyles.js";
|
|
14
|
+
import { insertImage } from "./insertImage.js";
|
|
15
|
+
import { moveCaretToDrop } from "./plugins/dropCaret.js";
|
|
16
|
+
var IMAGE_FILE_ACCEPT = IMAGE_MIMES.join(",");
|
|
17
|
+
function imageFilesIn(carrier) {
|
|
18
|
+
const files = carrier?.files;
|
|
19
|
+
return files ? Array.from(files).filter((file) => isImageMime(file.type)) : [];
|
|
20
|
+
}
|
|
21
|
+
function fittedExtent(width, height, maxWidthPx = A4_BODY_WIDTH.px, maxHeightPx = Number.POSITIVE_INFINITY) {
|
|
22
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || !(width > 0) || !(height > 0) || !(maxWidthPx > 0) || !(maxHeightPx > 0)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const scale = Math.min(1, maxWidthPx / width, maxHeightPx / height);
|
|
26
|
+
const extent = {
|
|
27
|
+
cx: pxToEmu(width * scale),
|
|
28
|
+
cy: pxToEmu(height * scale)
|
|
29
|
+
};
|
|
30
|
+
return Number.isSafeInteger(extent.cx) && Number.isSafeInteger(extent.cy) && extent.cx > 0 && extent.cy > 0 ? extent : null;
|
|
31
|
+
}
|
|
32
|
+
function readDataUrl(file) {
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
const reader = new FileReader();
|
|
35
|
+
reader.addEventListener(
|
|
36
|
+
"load",
|
|
37
|
+
() => resolve(typeof reader.result === "string" ? reader.result : null)
|
|
38
|
+
);
|
|
39
|
+
reader.addEventListener("error", () => resolve(null));
|
|
40
|
+
reader.readAsDataURL(file);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function imageByteLength(src) {
|
|
44
|
+
const base64 = imageBase64Of(src);
|
|
45
|
+
const padding = base64.endsWith("==") ? 2 : base64.endsWith("=") ? 1 : 0;
|
|
46
|
+
return Math.floor(base64.length * 3 / 4) - padding;
|
|
47
|
+
}
|
|
48
|
+
function imageMimeFromBytes(binary) {
|
|
49
|
+
const byte = (index) => binary.charCodeAt(index);
|
|
50
|
+
if (byte(0) === 137 && binary.slice(1, 4) === "PNG" && [13, 10, 26, 10].every((value, index) => byte(index + 4) === value)) {
|
|
51
|
+
return "image/png";
|
|
52
|
+
}
|
|
53
|
+
if (byte(0) === 255 && byte(1) === 216 && byte(2) === 255) {
|
|
54
|
+
return "image/jpeg";
|
|
55
|
+
}
|
|
56
|
+
if (binary.startsWith("GIF87a") || binary.startsWith("GIF89a")) {
|
|
57
|
+
return "image/gif";
|
|
58
|
+
}
|
|
59
|
+
return binary.startsWith("BM") ? "image/bmp" : null;
|
|
60
|
+
}
|
|
61
|
+
function boundedImageSrc(source) {
|
|
62
|
+
const src = toImageSrc(source);
|
|
63
|
+
if (src === null || imageByteLength(src) > MAX_IMAGE_BYTES) return null;
|
|
64
|
+
try {
|
|
65
|
+
const base64 = imageBase64Of(src);
|
|
66
|
+
const mime = imageMimeFromBytes(atob(base64));
|
|
67
|
+
return mime === null ? null : `data:${mime};base64,${base64}`;
|
|
68
|
+
} catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function imageSourceByteLength(source) {
|
|
73
|
+
return imageByteLength(source);
|
|
74
|
+
}
|
|
75
|
+
function naturalSize(src, signal) {
|
|
76
|
+
return new Promise((resolve) => {
|
|
77
|
+
const image = new Image();
|
|
78
|
+
let settled = false;
|
|
79
|
+
const finish = (value) => {
|
|
80
|
+
if (settled) return;
|
|
81
|
+
settled = true;
|
|
82
|
+
signal?.removeEventListener("abort", onAbort);
|
|
83
|
+
image.removeEventListener("load", onLoad);
|
|
84
|
+
image.removeEventListener("error", onError);
|
|
85
|
+
resolve(value);
|
|
86
|
+
};
|
|
87
|
+
const onLoad = () => finish({ width: image.naturalWidth, height: image.naturalHeight });
|
|
88
|
+
const onError = () => finish(null);
|
|
89
|
+
const onAbort = () => {
|
|
90
|
+
finish(null);
|
|
91
|
+
image.src = "";
|
|
92
|
+
};
|
|
93
|
+
image.addEventListener("load", onLoad);
|
|
94
|
+
image.addEventListener("error", onError);
|
|
95
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
96
|
+
if (signal?.aborted) {
|
|
97
|
+
finish(null);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
image.src = src;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async function readImageFile(file, maxWidthPx) {
|
|
104
|
+
if (!isImageMime(file.type) || file.size > MAX_IMAGE_BYTES) return null;
|
|
105
|
+
const source = await readDataUrl(file);
|
|
106
|
+
return source === null ? null : readImageSource(source, { maxWidthPx, alt: null });
|
|
107
|
+
}
|
|
108
|
+
async function readImageSource(source, {
|
|
109
|
+
maxWidthPx,
|
|
110
|
+
maxHeightPx,
|
|
111
|
+
preferredExtent = null,
|
|
112
|
+
alt = null,
|
|
113
|
+
signal
|
|
114
|
+
} = {}) {
|
|
115
|
+
const src = boundedImageSrc(source);
|
|
116
|
+
if (src === null) return null;
|
|
117
|
+
const natural = await naturalSize(src, signal);
|
|
118
|
+
const preferred = preferredExtent && {
|
|
119
|
+
width: emuToPx(preferredExtent.cx),
|
|
120
|
+
height: emuToPx(preferredExtent.cy)
|
|
121
|
+
};
|
|
122
|
+
const size = preferred ?? natural;
|
|
123
|
+
const extent = natural && size && fittedExtent(size.width, size.height, maxWidthPx, maxHeightPx);
|
|
124
|
+
return extent === null ? null : { src, extent, alt };
|
|
125
|
+
}
|
|
126
|
+
async function readImageBlob(source, options = {}) {
|
|
127
|
+
if (!isImageMime(source.type) || source.size > MAX_IMAGE_BYTES) return null;
|
|
128
|
+
const dataUrl = await readDataUrl(source);
|
|
129
|
+
return dataUrl === null ? null : readImageSource(dataUrl, options);
|
|
130
|
+
}
|
|
131
|
+
async function insertImageFiles(view, files) {
|
|
132
|
+
const maxWidthPx = documentBodyWidthPx(view.state);
|
|
133
|
+
for (const file of files) {
|
|
134
|
+
const image = await readImageFile(file, maxWidthPx);
|
|
135
|
+
if (!image || view.isDestroyed) continue;
|
|
136
|
+
insertImage(image)(view.state, (tr) => view.dispatch(tr), view);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function imageFiles() {
|
|
140
|
+
return new Plugin({
|
|
141
|
+
props: {
|
|
142
|
+
handlePaste(view, event) {
|
|
143
|
+
const files = imageFilesIn(event.clipboardData);
|
|
144
|
+
if (files.length === 0) return false;
|
|
145
|
+
void insertImageFiles(view, files);
|
|
146
|
+
return true;
|
|
147
|
+
},
|
|
148
|
+
/**
|
|
149
|
+
* A drag that started inside the editor carries no file, so a picture being moved
|
|
150
|
+
* within the document never reaches this and stays ProseMirror's own move.
|
|
151
|
+
*/
|
|
152
|
+
handleDrop(view, event) {
|
|
153
|
+
const files = imageFilesIn(event.dataTransfer);
|
|
154
|
+
if (files.length === 0) return false;
|
|
155
|
+
moveCaretToDrop(view, event);
|
|
156
|
+
void insertImageFiles(view, files);
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
export {
|
|
163
|
+
IMAGE_FILE_ACCEPT,
|
|
164
|
+
boundedImageSrc,
|
|
165
|
+
fittedExtent,
|
|
166
|
+
imageFiles,
|
|
167
|
+
imageFilesIn,
|
|
168
|
+
imageSourceByteLength,
|
|
169
|
+
insertImageFiles,
|
|
170
|
+
readImageBlob,
|
|
171
|
+
readImageFile,
|
|
172
|
+
readImageSource
|
|
173
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The command that puts an image into the document.
|
|
3
|
+
*
|
|
4
|
+
* What it takes is what an image node carries: the bytes as a data URL and the size the
|
|
5
|
+
* drawing records, in EMU. Working out that size from the image itself takes a decoded
|
|
6
|
+
* image, which only a browser can give, so it happens where the file is read
|
|
7
|
+
* (`editor/imageFiles.ts`) and never in here.
|
|
8
|
+
*
|
|
9
|
+
* The node is created without original XML, and that is what marks it as inserted: the
|
|
10
|
+
* export writes a media part for its bytes and builds a drawing around them.
|
|
11
|
+
*/
|
|
12
|
+
import type { Command, EditorState } from "prosemirror-state";
|
|
13
|
+
import { type ImageExtent } from "../ooxml/image";
|
|
14
|
+
/** What has to be known about an image before it can go into a document */
|
|
15
|
+
export interface ImageToInsert {
|
|
16
|
+
/** The image bytes as a data URL */
|
|
17
|
+
src: string;
|
|
18
|
+
/** The size to show it at, in EMU */
|
|
19
|
+
extent: ImageExtent;
|
|
20
|
+
/** The alternative text. Nothing when there is none */
|
|
21
|
+
alt?: string | null;
|
|
22
|
+
}
|
|
23
|
+
/** Whether an image can be inserted at the current position. Used to enable and disable the toolbar button */
|
|
24
|
+
export declare function canInsertImage(state: EditorState): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Puts the image where the selection is, in place of whatever was selected.
|
|
27
|
+
*
|
|
28
|
+
* It goes in carrying the formatting of the text around it, so the run it ends up in is
|
|
29
|
+
* the one it was inserted into - the same as a picture pasted in Word.
|
|
30
|
+
*/
|
|
31
|
+
export declare function insertImage(image: ImageToInsert): Command;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// src/editor/insertImage.ts
|
|
2
|
+
import { insertPoint } from "prosemirror-transform";
|
|
3
|
+
import { toImageExtent, toImageSrc } from "../ooxml/image.js";
|
|
4
|
+
import { docxSchema } from "../schema/index.js";
|
|
5
|
+
import { replacementShut } from "../schema/locks.js";
|
|
6
|
+
function insertPosition(state) {
|
|
7
|
+
if (replacementShut(state.selection, state.doc)) return null;
|
|
8
|
+
return insertPoint(state.doc, state.selection.from, docxSchema.nodes.image);
|
|
9
|
+
}
|
|
10
|
+
function canInsertImage(state) {
|
|
11
|
+
return insertPosition(state) !== null;
|
|
12
|
+
}
|
|
13
|
+
function insertImage(image) {
|
|
14
|
+
return (state, dispatch) => {
|
|
15
|
+
const src = toImageSrc(image.src);
|
|
16
|
+
const extent = toImageExtent(image.extent);
|
|
17
|
+
if (src === null || extent === null || insertPosition(state) === null) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (dispatch) {
|
|
21
|
+
const node = docxSchema.nodes.image.create({
|
|
22
|
+
src,
|
|
23
|
+
extent,
|
|
24
|
+
alt: image.alt ?? null,
|
|
25
|
+
xml: null
|
|
26
|
+
});
|
|
27
|
+
dispatch(state.tr.replaceSelectionWith(node).scrollIntoView());
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
canInsertImage,
|
|
34
|
+
insertImage
|
|
35
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A table only goes between body blocks, never inside another table. A table inside a cell is not
|
|
3
|
+
* made editable even when a document is opened (nested tables are only preserved), so one created
|
|
4
|
+
* here would become an untouchable blob once the document is saved and reopened.
|
|
5
|
+
*/
|
|
6
|
+
import { type Command, type EditorState } from "prosemirror-state";
|
|
7
|
+
/** Whether a table can be inserted at the current position. Used to enable and disable the toolbar button */
|
|
8
|
+
export declare function canInsertTable(state: EditorState): boolean;
|
|
9
|
+
/** How many rows and columns the new table has */
|
|
10
|
+
export interface TableSize {
|
|
11
|
+
rows: number;
|
|
12
|
+
columns: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Inserts a table of empty cells and moves the caret into the first cell.
|
|
16
|
+
* The table is as wide as one line of body text on the paper the open document names
|
|
17
|
+
*/
|
|
18
|
+
export declare function insertTable({ rows, columns }: TableSize): Command;
|