smartrte-react 0.3.5 → 1.0.0-beta.2
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 +14 -0
- package/README.md +106 -14
- package/dist/adapters/domChecklistCommandBridge.js +1 -1
- package/dist/adapters/domCommandBridge.d.ts +2 -2
- package/dist/adapters/domCommandBridge.js +2 -2
- package/dist/adapters/domInlineAtomCommandBridge.d.ts +10 -9
- package/dist/adapters/domInlineAtomCommandBridge.js +154 -50
- package/dist/adapters/domInlineImageCommandBridge.d.ts +7 -7
- package/dist/adapters/domInlineImageCommandBridge.js +6 -72
- package/dist/adapters/domMoveCommandBridge.js +1 -1
- package/dist/adapters/domSelectionBridge.d.ts +3 -3
- package/dist/adapters/domSmartDocument.d.ts +4 -4
- package/dist/adapters/domSmartDocument.js +2 -2
- package/dist/adapters/domTableCommandBridge.d.ts +42 -16
- package/dist/adapters/domTableCommandBridge.js +203 -173
- package/dist/adapters/internalFlags.d.ts +0 -8
- package/dist/adapters/internalFlags.js +0 -24
- package/dist/adapters/legacyListShadowComparator.d.ts +1 -1
- package/dist/adapters/legacyListShadowComparator.js +1 -1
- package/dist/adapters/pdfPrint.d.ts +8 -0
- package/dist/adapters/pdfPrint.js +22 -0
- package/dist/adapters/shadowMode.d.ts +3 -3
- package/dist/adapters/shadowMode.js +1 -1
- package/dist/canonicalEditorRuntime.d.ts +53 -1
- package/dist/canonicalEditorRuntime.js +61 -4
- package/dist/capabilityPresets.d.ts +27 -0
- package/dist/capabilityPresets.js +21 -0
- package/dist/collabTransport.d.ts +66 -0
- package/dist/collabTransport.js +1 -0
- package/dist/commentProvider.d.ts +24 -0
- package/dist/commentProvider.js +1 -0
- package/dist/components/CanonicalAuthorityEditor.d.ts +35 -1
- package/dist/components/CanonicalAuthorityEditor.js +1086 -112
- package/dist/components/ClassicEditorAuthority.d.ts +93 -22
- package/dist/components/ClassicEditorAuthority.js +11 -43
- package/dist/components/ColorPickerPopover.d.ts +39 -0
- package/dist/components/ColorPickerPopover.js +285 -0
- package/dist/components/CommentMarkers.d.ts +25 -0
- package/dist/components/CommentMarkers.js +105 -0
- package/dist/components/CommentThreadPanel.d.ts +26 -0
- package/dist/components/CommentThreadPanel.js +47 -0
- package/dist/components/ContextMenu.d.ts +23 -0
- package/dist/components/ContextMenu.js +141 -0
- package/dist/components/FormulaLibraryPopover.d.ts +16 -0
- package/dist/components/FormulaLibraryPopover.js +107 -0
- package/dist/components/LinkEditorPopover.d.ts +3 -1
- package/dist/components/LinkEditorPopover.js +22 -6
- package/dist/components/MediaManager.d.ts +4 -20
- package/dist/components/MediaManager.js +35 -6
- package/dist/components/MediaOverlay.d.ts +36 -0
- package/dist/components/MediaOverlay.js +163 -0
- package/dist/components/SpecialCharacterPopover.d.ts +18 -0
- package/dist/components/SpecialCharacterPopover.js +99 -0
- package/dist/components/StructuralSuggestionMarkers.d.ts +20 -0
- package/dist/components/StructuralSuggestionMarkers.js +56 -0
- package/dist/components/SuggestionPanel.d.ts +26 -0
- package/dist/components/SuggestionPanel.js +33 -0
- package/dist/components/TableBorderPopover.d.ts +59 -0
- package/dist/components/TableBorderPopover.js +147 -0
- package/dist/components/TableResizeHandles.d.ts +25 -0
- package/dist/components/TableResizeHandles.js +301 -0
- package/dist/components/TableSizePickerPopover.d.ts +16 -0
- package/dist/components/TableSizePickerPopover.js +126 -0
- package/dist/components/ToolbarPrimitives.d.ts +129 -0
- package/dist/components/ToolbarPrimitives.js +146 -0
- package/dist/components/VersionHistoryPanel.d.ts +9 -0
- package/dist/components/VersionHistoryPanel.js +157 -0
- package/dist/formulaLibrary.d.ts +31 -0
- package/dist/formulaLibrary.js +90 -0
- package/dist/index.d.ts +22 -24
- package/dist/index.js +14 -11
- package/dist/mediaManagerAdapter.d.ts +12 -0
- package/dist/mediaManagerAdapter.js +34 -0
- package/dist/mediaProvider.d.ts +21 -1
- package/dist/specialCharacters.d.ts +22 -0
- package/dist/specialCharacters.js +86 -0
- package/dist/standalone/classic-editor-embed.js +19 -12
- package/dist/suggestionProvider.d.ts +17 -0
- package/dist/suggestionProvider.js +1 -0
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +150 -20
- package/dist/versionProvider.d.ts +29 -0
- package/dist/versionProvider.js +1 -0
- package/package.json +28 -14
- package/dist/adapters/canonicalInlineCommandBridge.d.ts +0 -15
- package/dist/adapters/canonicalInlineCommandBridge.js +0 -269
- package/dist/adapters/canonicalListCommandBridge.d.ts +0 -26
- package/dist/adapters/canonicalListCommandBridge.js +0 -430
- package/dist/adapters/coreBold.d.ts +0 -5
- package/dist/adapters/coreBold.js +0 -3
- package/dist/adapters/documentFormats.d.ts +0 -26
- package/dist/adapters/documentFormats.js +0 -49
- package/dist/adapters/docxFormat.d.ts +0 -5
- package/dist/adapters/docxFormat.js +0 -272
- package/dist/adapters/domBlockCommandBridge.d.ts +0 -19
- package/dist/adapters/domBlockCommandBridge.js +0 -79
- package/dist/adapters/inlineMarkCoreExecution.d.ts +0 -9
- package/dist/adapters/inlineMarkCoreExecution.js +0 -25
- package/dist/adapters/pdfFormat.d.ts +0 -23
- package/dist/adapters/pdfFormat.js +0 -204
- package/dist/adapters/portableDocxAtoms.d.ts +0 -4
- package/dist/adapters/portableDocxAtoms.js +0 -58
- package/dist/adapters/styledDocxFormat.d.ts +0 -8
- package/dist/adapters/styledDocxFormat.js +0 -190
- package/dist/builtInFormatDefinitions.d.ts +0 -5
- package/dist/builtInFormatDefinitions.js +0 -82
- package/dist/canonicalAuthorityFlag.d.ts +0 -32
- package/dist/canonicalAuthorityFlag.js +0 -49
- package/dist/canonicalClipboardRuntime.d.ts +0 -15
- package/dist/canonicalClipboardRuntime.js +0 -76
- package/dist/components/ClassicEditor.d.ts +0 -76
- package/dist/components/ClassicEditor.js +0 -6729
- package/dist/editorController.d.ts +0 -78
- package/dist/editorController.js +0 -298
- package/dist/formatFidelity.d.ts +0 -14
- package/dist/formatFidelity.js +0 -107
- package/dist/formatRuntime.d.ts +0 -50
- package/dist/formatRuntime.js +0 -20
- package/dist/pluginRuntime.d.ts +0 -68
- package/dist/pluginRuntime.js +0 -78
- package/dist/standalone/editor.js +0 -1068
- package/dist/test-harness/atomShadowComparator.d.ts +0 -14
- package/dist/test-harness/atomShadowComparator.js +0 -63
- package/dist/test-harness/blockShadowComparator.d.ts +0 -30
- package/dist/test-harness/blockShadowComparator.js +0 -140
- package/dist/test-harness/clipboardShadowComparator.d.ts +0 -12
- package/dist/test-harness/clipboardShadowComparator.js +0 -46
- package/dist/test-harness/inlineShadowComparator.d.ts +0 -32
- package/dist/test-harness/inlineShadowComparator.js +0 -152
- package/dist/test-harness/legacyAtomEngine.d.ts +0 -10
- package/dist/test-harness/legacyAtomEngine.js +0 -15
- package/dist/test-harness/legacyBlockEngine.d.ts +0 -31
- package/dist/test-harness/legacyBlockEngine.js +0 -31
- package/dist/test-harness/legacyClipboardEngine.d.ts +0 -14
- package/dist/test-harness/legacyClipboardEngine.js +0 -67
- package/dist/test-harness/legacyInlineEngine.d.ts +0 -19
- package/dist/test-harness/legacyInlineEngine.js +0 -49
- package/dist/test-harness/legacyTableEngine.d.ts +0 -12
- package/dist/test-harness/legacyTableEngine.js +0 -25
- package/dist/test-harness/tableShadowComparator.d.ts +0 -29
- package/dist/test-harness/tableShadowComparator.js +0 -101
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
import JSZip from "jszip";
|
|
2
|
-
import mammoth from "mammoth";
|
|
3
|
-
import { normalizeSmartDocument } from "smartrte-core";
|
|
4
|
-
import { portableFormulaMarker, portableImageMarker, restorePortableDocxAtoms } from "./portableDocxAtoms.js";
|
|
5
|
-
import { smartDocumentFromHtml } from "./domSmartDocument.js";
|
|
6
|
-
export const DOCX_MEDIA_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
7
|
-
const xmlEscape = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
8
|
-
const colorValue = (value) => {
|
|
9
|
-
const hex = /^#([0-9a-f]{6})$/i.exec(value.trim());
|
|
10
|
-
if (hex)
|
|
11
|
-
return hex[1].toUpperCase();
|
|
12
|
-
const rgb = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i.exec(value.trim());
|
|
13
|
-
return rgb
|
|
14
|
-
? rgb.slice(1, 4).map((part) => Math.max(0, Math.min(255, Number(part))).toString(16).padStart(2, "0")).join("").toUpperCase()
|
|
15
|
-
: "";
|
|
16
|
-
};
|
|
17
|
-
const runProperties = (marks = []) => marks.map((mark) => {
|
|
18
|
-
if (mark.type === "bold")
|
|
19
|
-
return "<w:b/>";
|
|
20
|
-
if (mark.type === "italic")
|
|
21
|
-
return "<w:i/>";
|
|
22
|
-
if (mark.type === "underline")
|
|
23
|
-
return '<w:u w:val="single"/>';
|
|
24
|
-
if (mark.type === "strike")
|
|
25
|
-
return "<w:strike/>";
|
|
26
|
-
if (mark.type === "superscript")
|
|
27
|
-
return '<w:vertAlign w:val="superscript"/>';
|
|
28
|
-
if (mark.type === "subscript")
|
|
29
|
-
return '<w:vertAlign w:val="subscript"/>';
|
|
30
|
-
if (mark.type === "textColor") {
|
|
31
|
-
const color = colorValue(mark.value);
|
|
32
|
-
return color ? `<w:color w:val="${color}"/>` : "";
|
|
33
|
-
}
|
|
34
|
-
if (mark.type === "backgroundColor") {
|
|
35
|
-
const color = colorValue(mark.value);
|
|
36
|
-
return color ? `<w:shd w:val="clear" w:color="auto" w:fill="${color}"/>` : "";
|
|
37
|
-
}
|
|
38
|
-
if (mark.type === "fontSize")
|
|
39
|
-
return `<w:sz w:val="${Math.max(2, Math.round(mark.valuePx * 1.5))}"/>`;
|
|
40
|
-
return "";
|
|
41
|
-
}).join("");
|
|
42
|
-
const textRun = (text, properties = "") => `<w:r>${properties ? `<w:rPr>${properties}</w:rPr>` : ""}<w:t xml:space="preserve">${xmlEscape(text)}</w:t></w:r>`;
|
|
43
|
-
const createSerializationContext = () => ({
|
|
44
|
-
relationships: [],
|
|
45
|
-
hyperlinkIds: new Map(),
|
|
46
|
-
media: [],
|
|
47
|
-
drawingId: 1,
|
|
48
|
-
});
|
|
49
|
-
const hyperlinkRelationshipId = (context, href) => {
|
|
50
|
-
const existing = context.hyperlinkIds.get(href);
|
|
51
|
-
if (existing)
|
|
52
|
-
return existing;
|
|
53
|
-
const id = `rId${context.relationships.length + 2}`;
|
|
54
|
-
context.hyperlinkIds.set(href, id);
|
|
55
|
-
context.relationships.push({ id, target: href, kind: "hyperlink" });
|
|
56
|
-
return id;
|
|
57
|
-
};
|
|
58
|
-
const embeddableImage = (src) => {
|
|
59
|
-
const match = /^data:(image\/(?:png|jpeg|gif));base64,([a-z0-9+/=\s]+)$/i.exec(src);
|
|
60
|
-
if (!match)
|
|
61
|
-
return;
|
|
62
|
-
return {
|
|
63
|
-
mimeType: match[1].toLowerCase(),
|
|
64
|
-
base64: match[2].replace(/\s/g, ""),
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
const imageRun = (node, context) => {
|
|
68
|
-
const image = embeddableImage(node.src);
|
|
69
|
-
if (!image)
|
|
70
|
-
return textRun(portableImageMarker(node.src, node.alt, node.title));
|
|
71
|
-
const extension = image.mimeType === "image/jpeg" ? "jpg" : image.mimeType.split("/")[1];
|
|
72
|
-
const filename = `image${context.media.length + 1}.${extension}`;
|
|
73
|
-
const relationshipId = `rId${context.relationships.length + 2}`;
|
|
74
|
-
const drawingId = context.drawingId++;
|
|
75
|
-
context.media.push({ filename, ...image });
|
|
76
|
-
context.relationships.push({
|
|
77
|
-
id: relationshipId,
|
|
78
|
-
target: `media/${filename}`,
|
|
79
|
-
kind: "image",
|
|
80
|
-
});
|
|
81
|
-
const widthEmu = Math.max(1, Math.round((node.width || 96) * 9525));
|
|
82
|
-
const heightEmu = Math.max(1, Math.round((node.height || 96) * 9525));
|
|
83
|
-
const name = xmlEscape(node.title || node.alt || filename);
|
|
84
|
-
const description = xmlEscape(node.alt || "");
|
|
85
|
-
return `<w:r><w:drawing><wp:inline xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" distT="0" distB="0" distL="0" distR="0"><wp:extent cx="${widthEmu}" cy="${heightEmu}"/><wp:docPr id="${drawingId}" name="${name}" descr="${description}"/><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="0" name="${name}" descr="${description}"/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip r:embed="${relationshipId}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${widthEmu}" cy="${heightEmu}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing></w:r>`;
|
|
86
|
-
};
|
|
87
|
-
const formulaRun = (node) => {
|
|
88
|
-
const source = xmlEscape(node.value);
|
|
89
|
-
const marker = xmlEscape(portableFormulaMarker(node.value, node.displayText));
|
|
90
|
-
return `<m:oMath><m:r><m:t>${source}</m:t></m:r></m:oMath><w:r><w:rPr><w:vanish/></w:rPr><w:t>${marker}</w:t></w:r>`;
|
|
91
|
-
};
|
|
92
|
-
const inlineRun = (node, context) => {
|
|
93
|
-
if (node.type === "formula")
|
|
94
|
-
return formulaRun(node);
|
|
95
|
-
if (node.type === "inlineImage")
|
|
96
|
-
return imageRun(node, context);
|
|
97
|
-
const properties = runProperties(node.marks);
|
|
98
|
-
const runs = node.text.split("\n").map((part, index) => `${index ? "<w:r><w:br/></w:r>" : ""}${part ? textRun(part, properties) : ""}`).join("");
|
|
99
|
-
const link = node.marks?.find((mark) => mark.type === "link");
|
|
100
|
-
if (!link || !runs)
|
|
101
|
-
return runs;
|
|
102
|
-
return `<w:hyperlink r:id="${hyperlinkRelationshipId(context, link.href)}"${link.target === "_blank" ? ' w:history="1"' : ""}>${runs}</w:hyperlink>`;
|
|
103
|
-
};
|
|
104
|
-
const paragraphProperties = (block, extra = "") => [
|
|
105
|
-
block.alignment ? `<w:jc w:val="${xmlEscape(block.alignment)}"/>` : "",
|
|
106
|
-
block.indent ? `<w:ind w:left="${block.indent * 480}"/>` : "",
|
|
107
|
-
extra,
|
|
108
|
-
].join("");
|
|
109
|
-
const paragraphXml = (children, block, context, extraProperties = "") => {
|
|
110
|
-
const properties = paragraphProperties(block, extraProperties);
|
|
111
|
-
const content = children.map((node) => inlineRun(node, context)).join("") || textRun("");
|
|
112
|
-
return `<w:p>${properties ? `<w:pPr>${properties}</w:pPr>` : ""}${content}</w:p>`;
|
|
113
|
-
};
|
|
114
|
-
const tableXml = (block, context) => {
|
|
115
|
-
const grid = [];
|
|
116
|
-
const placements = [];
|
|
117
|
-
block.children.forEach((row, rowIndex) => {
|
|
118
|
-
grid[rowIndex] || (grid[rowIndex] = []);
|
|
119
|
-
let column = 0;
|
|
120
|
-
row.children.forEach((cell) => {
|
|
121
|
-
var _a;
|
|
122
|
-
while (grid[rowIndex][column])
|
|
123
|
-
column += 1;
|
|
124
|
-
const placement = {
|
|
125
|
-
row: rowIndex,
|
|
126
|
-
column,
|
|
127
|
-
rowspan: cell.rowspan || 1,
|
|
128
|
-
colspan: cell.colspan || 1,
|
|
129
|
-
cell,
|
|
130
|
-
};
|
|
131
|
-
placements.push(placement);
|
|
132
|
-
for (let rowOffset = 0; rowOffset < placement.rowspan; rowOffset += 1) {
|
|
133
|
-
grid[_a = rowIndex + rowOffset] || (grid[_a] = []);
|
|
134
|
-
for (let columnOffset = 0; columnOffset < placement.colspan; columnOffset += 1) {
|
|
135
|
-
grid[rowIndex + rowOffset][column + columnOffset] = placement;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
column += placement.colspan;
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
const width = Math.max(1, ...grid.map((row) => row.length));
|
|
142
|
-
const widths = Array.from({ length: width }, (_, index) => block.columnWidths?.[index] || 96);
|
|
143
|
-
const gridXml = `<w:tblGrid>${widths.map((widthPx) => `<w:gridCol w:w="${Math.max(1, Math.round(widthPx * 15))}"/>`).join("")}</w:tblGrid>`;
|
|
144
|
-
const borderNone = '<w:tcBorders><w:top w:val="nil"/><w:left w:val="nil"/><w:bottom w:val="nil"/><w:right w:val="nil"/></w:tcBorders>';
|
|
145
|
-
const rows = block.children.map((row, rowIndex) => {
|
|
146
|
-
const header = grid[rowIndex]?.every((placement) => placement?.cell.type === "tableHeaderCell");
|
|
147
|
-
const rowProperties = [
|
|
148
|
-
header ? "<w:tblHeader/>" : "",
|
|
149
|
-
row.heightPx ? `<w:trHeight w:val="${Math.round(row.heightPx * 15)}" w:hRule="atLeast"/>` : "",
|
|
150
|
-
].join("");
|
|
151
|
-
let cells = "";
|
|
152
|
-
for (let column = 0; column < width;) {
|
|
153
|
-
const placement = grid[rowIndex]?.[column];
|
|
154
|
-
if (!placement || placement.column !== column) {
|
|
155
|
-
column += 1;
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
const continuation = placement.row < rowIndex;
|
|
159
|
-
const shade = colorValue(placement.cell.backgroundColor || "");
|
|
160
|
-
const properties = [
|
|
161
|
-
placement.colspan > 1 ? `<w:gridSpan w:val="${placement.colspan}"/>` : "",
|
|
162
|
-
placement.rowspan > 1
|
|
163
|
-
? continuation ? "<w:vMerge/>" : '<w:vMerge w:val="restart"/>'
|
|
164
|
-
: "",
|
|
165
|
-
shade ? `<w:shd w:val="clear" w:color="auto" w:fill="${shade}"/>` : "",
|
|
166
|
-
placement.cell.border === "none" ? borderNone : "",
|
|
167
|
-
].join("");
|
|
168
|
-
const content = continuation
|
|
169
|
-
? "<w:p/>"
|
|
170
|
-
: placement.cell.children.map((child) => blockXml(child, context)).join("") || "<w:p/>";
|
|
171
|
-
cells += `<w:tc><w:tcPr>${properties}</w:tcPr>${content}</w:tc>`;
|
|
172
|
-
column += placement.colspan;
|
|
173
|
-
}
|
|
174
|
-
return `<w:tr>${rowProperties ? `<w:trPr>${rowProperties}</w:trPr>` : ""}${cells}</w:tr>`;
|
|
175
|
-
}).join("");
|
|
176
|
-
return `<w:tbl><w:tblPr><w:tblW w:w="0" w:type="auto"/><w:tblBorders><w:top w:val="single" w:sz="4" w:color="D1D5DB"/><w:left w:val="single" w:sz="4" w:color="D1D5DB"/><w:bottom w:val="single" w:sz="4" w:color="D1D5DB"/><w:right w:val="single" w:sz="4" w:color="D1D5DB"/><w:insideH w:val="single" w:sz="4" w:color="D1D5DB"/><w:insideV w:val="single" w:sz="4" w:color="D1D5DB"/></w:tblBorders></w:tblPr>${gridXml}${rows}</w:tbl>`;
|
|
177
|
-
};
|
|
178
|
-
const listStyleNumId = {
|
|
179
|
-
disc: 1, circle: 2, square: 3, decimal: 4,
|
|
180
|
-
"decimal-leading-zero": 4,
|
|
181
|
-
"lower-alpha": 5, "upper-alpha": 6, "lower-roman": 7, "upper-roman": 8,
|
|
182
|
-
};
|
|
183
|
-
const blockXml = (block, context, listLevel = 0) => {
|
|
184
|
-
if (block.type === "paragraph")
|
|
185
|
-
return paragraphXml(block.children, block, context);
|
|
186
|
-
if (block.type === "heading") {
|
|
187
|
-
return paragraphXml(block.children, block, context, `<w:pStyle w:val="Heading${block.level}"/>`);
|
|
188
|
-
}
|
|
189
|
-
if (block.type === "codeBlock")
|
|
190
|
-
return paragraphXml([{ type: "text", text: block.text, marks: [{ type: "code" }] }], block, context);
|
|
191
|
-
if (block.type === "blockquote") {
|
|
192
|
-
return block.children.map((child) => {
|
|
193
|
-
if (child.type === "paragraph")
|
|
194
|
-
return paragraphXml(child.children, child, context, '<w:ind w:left="720"/>');
|
|
195
|
-
return blockXml(child, context, listLevel);
|
|
196
|
-
}).join("");
|
|
197
|
-
}
|
|
198
|
-
if (block.type === "list") {
|
|
199
|
-
return block.children.map((item) => item.children.map((child) => {
|
|
200
|
-
if (child.type === "paragraph") {
|
|
201
|
-
return paragraphXml(child.children, child, context, `<w:numPr><w:ilvl w:val="${Math.min(listLevel, 8)}"/><w:numId w:val="${listStyleNumId[block.style]}"/></w:numPr>`);
|
|
202
|
-
}
|
|
203
|
-
return blockXml(child, context, listLevel + 1);
|
|
204
|
-
}).join("")).join("");
|
|
205
|
-
}
|
|
206
|
-
if (block.type === "table")
|
|
207
|
-
return tableXml(block, context);
|
|
208
|
-
if (block.type === "image")
|
|
209
|
-
return paragraphXml([{
|
|
210
|
-
type: "inlineImage",
|
|
211
|
-
src: block.src,
|
|
212
|
-
alt: block.alt,
|
|
213
|
-
title: block.title,
|
|
214
|
-
width: block.width,
|
|
215
|
-
height: block.height,
|
|
216
|
-
}], block, context);
|
|
217
|
-
return paragraphXml([{ type: "text", text: block.title || block.src }], block, context);
|
|
218
|
-
};
|
|
219
|
-
const numberingLevelXml = (level, format, text, font) => `<w:lvl w:ilvl="${level}"><w:start w:val="1"/><w:numFmt w:val="${format}"/><w:lvlText w:val="${text}"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="num" w:pos="${720 + level * 360}"/></w:tabs><w:ind w:left="${720 + level * 360}" w:hanging="360"/></w:pPr>${font ? `<w:rPr><w:rFonts w:ascii="${font}" w:hAnsi="${font}"/></w:rPr>` : ""}</w:lvl>`;
|
|
220
|
-
const numberingXml = () => {
|
|
221
|
-
const definitions = [
|
|
222
|
-
{ id: 1, format: "bullet", text: "•", font: "Symbol" },
|
|
223
|
-
{ id: 2, format: "bullet", text: "○", font: "Arial" },
|
|
224
|
-
{ id: 3, format: "bullet", text: "▪", font: "Arial" },
|
|
225
|
-
{ id: 4, format: "decimal", text: "%1." },
|
|
226
|
-
{ id: 5, format: "lowerLetter", text: "%1." },
|
|
227
|
-
{ id: 6, format: "upperLetter", text: "%1." },
|
|
228
|
-
{ id: 7, format: "lowerRoman", text: "%1." },
|
|
229
|
-
{ id: 8, format: "upperRoman", text: "%1." },
|
|
230
|
-
];
|
|
231
|
-
const abstracts = definitions.map(({ id, format, text, font }) => `<w:abstractNum w:abstractNumId="${id}"><w:multiLevelType w:val="multilevel"/>${Array.from({ length: 9 }, (_, level) => numberingLevelXml(level, format, text.replace("%1", `%${level + 1}`), font)).join("")}</w:abstractNum>`).join("");
|
|
232
|
-
const instances = definitions.map(({ id }) => `<w:num w:numId="${id}"><w:abstractNumId w:val="${id}"/></w:num>`).join("");
|
|
233
|
-
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">${abstracts}${instances}</w:numbering>`;
|
|
234
|
-
};
|
|
235
|
-
const serializeDocxDocument = (document) => {
|
|
236
|
-
const normalized = normalizeSmartDocument(document);
|
|
237
|
-
const context = createSerializationContext();
|
|
238
|
-
const body = normalized.children.map((block) => blockXml(block, context)).join("");
|
|
239
|
-
return {
|
|
240
|
-
documentXml: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"><w:body>${body}<w:sectPr><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:top="720" w:right="720" w:bottom="720" w:left="720"/></w:sectPr></w:body></w:document>`,
|
|
241
|
-
relationships: context.relationships,
|
|
242
|
-
media: context.media,
|
|
243
|
-
};
|
|
244
|
-
};
|
|
245
|
-
export const smartDocumentToDocxXml = (document) => serializeDocxDocument(document).documentXml;
|
|
246
|
-
export const exportDocxDocument = async (document) => {
|
|
247
|
-
const zip = new JSZip();
|
|
248
|
-
const serialized = serializeDocxDocument(document);
|
|
249
|
-
const imageTypes = [...new Set(serialized.media.map(({ filename, mimeType }) => ({
|
|
250
|
-
extension: filename.split(".").pop(),
|
|
251
|
-
mimeType,
|
|
252
|
-
})).map((entry) => JSON.stringify(entry)))].map((entry) => JSON.parse(entry));
|
|
253
|
-
zip.file("[Content_Types].xml", `<?xml version="1.0" encoding="UTF-8"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/>${imageTypes.map(({ extension, mimeType }) => `<Default Extension="${extension}" ContentType="${mimeType}"/>`).join("")}<Override PartName="/word/document.xml" ContentType="${DOCX_MEDIA_TYPE}.main+xml"/><Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/></Types>`);
|
|
254
|
-
zip.folder("_rels")?.file(".rels", `<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/></Relationships>`);
|
|
255
|
-
zip.folder("word")?.file("document.xml", serialized.documentXml);
|
|
256
|
-
zip.folder("word")?.file("numbering.xml", numberingXml());
|
|
257
|
-
serialized.media.forEach(({ filename, base64 }) => {
|
|
258
|
-
zip.folder("word")?.folder("media")?.file(filename, base64, { base64: true });
|
|
259
|
-
});
|
|
260
|
-
const relationships = serialized.relationships.map((relationship) => relationship.kind === "hyperlink"
|
|
261
|
-
? `<Relationship Id="${relationship.id}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="${xmlEscape(relationship.target)}" TargetMode="External"/>`
|
|
262
|
-
: `<Relationship Id="${relationship.id}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="${relationship.target}"/>`).join("");
|
|
263
|
-
zip.folder("word")?.folder("_rels")?.file("document.xml.rels", `<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/>${relationships}</Relationships>`);
|
|
264
|
-
return zip.generateAsync({ type: "blob", mimeType: DOCX_MEDIA_TYPE });
|
|
265
|
-
};
|
|
266
|
-
export const importDocxDocumentWithMammoth = async (arrayBuffer, ownerDocument) => {
|
|
267
|
-
// Mammoth's browser entry reads `arrayBuffer`, while its Node entry reads
|
|
268
|
-
// `buffer`. Supplying both keeps the adapter portable across bundlers/tests.
|
|
269
|
-
const result = await mammoth.convertToHtml({ arrayBuffer, buffer: arrayBuffer });
|
|
270
|
-
const html = restorePortableDocxAtoms(result.value, ownerDocument);
|
|
271
|
-
return normalizeSmartDocument(smartDocumentFromHtml(html, ownerDocument));
|
|
272
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { type SetBlockTypeInput, type TextAlignment } from "smartrte-core";
|
|
2
|
-
export type DomBlockCommand = {
|
|
3
|
-
id: "block-type.set";
|
|
4
|
-
input: Pick<SetBlockTypeInput, "type" | "level">;
|
|
5
|
-
} | {
|
|
6
|
-
id: "alignment.set";
|
|
7
|
-
input: {
|
|
8
|
-
alignment: TextAlignment | null;
|
|
9
|
-
};
|
|
10
|
-
} | {
|
|
11
|
-
id: "blockquote.toggle";
|
|
12
|
-
} | {
|
|
13
|
-
id: "code-block.toggle";
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* Runs a core block command against a contiguous sibling run and replaces only
|
|
17
|
-
* that run. Returns null when the DOM shape needs a more specialized adapter.
|
|
18
|
-
*/
|
|
19
|
-
export declare const executeDomBlockCommand: (blocks: readonly HTMLElement[], command: DomBlockCommand) => HTMLElement[] | null;
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { alignmentPlugin, blockquotePlugin, blockTypePlugin, codeBlockPlugin, createSmartEditor, } from "smartrte-core";
|
|
2
|
-
import { serializeSmartDocument, smartDocumentFromHtml } from "./domSmartDocument.js";
|
|
3
|
-
const pluginFor = (id) => {
|
|
4
|
-
if (id === "block-type.set")
|
|
5
|
-
return blockTypePlugin;
|
|
6
|
-
if (id === "alignment.set")
|
|
7
|
-
return alignmentPlugin;
|
|
8
|
-
if (id === "blockquote.toggle")
|
|
9
|
-
return blockquotePlugin;
|
|
10
|
-
return codeBlockPlugin;
|
|
11
|
-
};
|
|
12
|
-
const isContiguousSiblingRun = (blocks) => {
|
|
13
|
-
if (!blocks.length || !blocks[0].parentElement)
|
|
14
|
-
return false;
|
|
15
|
-
const parent = blocks[0].parentElement;
|
|
16
|
-
if (!blocks.every((block) => block.parentElement === parent))
|
|
17
|
-
return false;
|
|
18
|
-
const siblings = Array.from(parent.children);
|
|
19
|
-
const indexes = blocks.map((block) => siblings.indexOf(block));
|
|
20
|
-
return indexes.every((index, offset) => index >= 0 && (offset === 0 || index === indexes[offset - 1] + 1));
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* Runs a core block command against a contiguous sibling run and replaces only
|
|
24
|
-
* that run. Returns null when the DOM shape needs a more specialized adapter.
|
|
25
|
-
*/
|
|
26
|
-
export const executeDomBlockCommand = (blocks, command) => {
|
|
27
|
-
if (!isContiguousSiblingRun(blocks))
|
|
28
|
-
return null;
|
|
29
|
-
const ownerDocument = blocks[0].ownerDocument;
|
|
30
|
-
const document = smartDocumentFromHtml(blocks.map((block) => block.outerHTML).join(""), ownerDocument);
|
|
31
|
-
if (document.children.length !== blocks.length)
|
|
32
|
-
return null;
|
|
33
|
-
const indexes = document.children.map((_, index) => index);
|
|
34
|
-
const editor = createSmartEditor({
|
|
35
|
-
state: { document, selection: { type: "all" } },
|
|
36
|
-
plugins: [pluginFor(command.id)],
|
|
37
|
-
});
|
|
38
|
-
const input = command.id === "alignment.set"
|
|
39
|
-
? { paths: indexes.map((index) => [index]), alignment: command.input.alignment }
|
|
40
|
-
: command.id === "block-type.set"
|
|
41
|
-
? { parentPath: [], blockIndexes: indexes, ...command.input }
|
|
42
|
-
: { parentPath: [], blockIndexes: indexes };
|
|
43
|
-
if (!editor.execute(command.id, input))
|
|
44
|
-
return null;
|
|
45
|
-
const container = ownerDocument.createElement("div");
|
|
46
|
-
container.innerHTML = serializeSmartDocument(editor.state.document);
|
|
47
|
-
const replacements = Array.from(container.children);
|
|
48
|
-
if (!replacements.length)
|
|
49
|
-
return null;
|
|
50
|
-
if (command.id === "alignment.set" && replacements.length === blocks.length) {
|
|
51
|
-
replacements.forEach((replacement, index) => {
|
|
52
|
-
blocks[index].style.textAlign = replacement.style.textAlign;
|
|
53
|
-
if (!blocks[index].getAttribute("style"))
|
|
54
|
-
blocks[index].removeAttribute("style");
|
|
55
|
-
});
|
|
56
|
-
return [...blocks];
|
|
57
|
-
}
|
|
58
|
-
const parent = blocks[0].parentElement;
|
|
59
|
-
const reference = blocks[0];
|
|
60
|
-
replacements.forEach((replacement, index) => {
|
|
61
|
-
if (replacements.length === blocks.length) {
|
|
62
|
-
const previous = blocks[index];
|
|
63
|
-
const generatedAlignment = replacement.style.textAlign;
|
|
64
|
-
const previousStyle = previous.getAttribute("style");
|
|
65
|
-
const previousClass = previous.getAttribute("class");
|
|
66
|
-
if (previousStyle)
|
|
67
|
-
replacement.setAttribute("style", previousStyle);
|
|
68
|
-
if (generatedAlignment)
|
|
69
|
-
replacement.style.textAlign = generatedAlignment;
|
|
70
|
-
if (!replacement.getAttribute("style"))
|
|
71
|
-
replacement.removeAttribute("style");
|
|
72
|
-
if (previousClass)
|
|
73
|
-
replacement.setAttribute("class", previousClass);
|
|
74
|
-
}
|
|
75
|
-
parent.insertBefore(replacement, reference);
|
|
76
|
-
});
|
|
77
|
-
blocks.forEach((block) => block.remove());
|
|
78
|
-
return replacements;
|
|
79
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type SmartSelection } from "smartrte-core";
|
|
2
|
-
export type CoreInlineMark = "bold" | "italic" | "underline" | "superscript" | "subscript";
|
|
3
|
-
export interface CoreInlineMarkResult {
|
|
4
|
-
html: string;
|
|
5
|
-
selectionBefore: SmartSelection;
|
|
6
|
-
selectionAfter: SmartSelection;
|
|
7
|
-
}
|
|
8
|
-
export declare const isCoreInlineMarkEnabled: (mark: CoreInlineMark) => boolean;
|
|
9
|
-
export declare const getCoreInlineMarkResult: (root: HTMLElement, mark: CoreInlineMark) => CoreInlineMarkResult | null;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { applyTransaction, toggleBold, toggleItalic, toggleSubscript, toggleSuperscript, toggleUnderline, } from "smartrte-core";
|
|
2
|
-
import { selectionFromDom } from "./domSelectionBridge.js";
|
|
3
|
-
import { serializeSmartDocument, smartDocumentFromEditorRoot } from "./domSmartDocument.js";
|
|
4
|
-
import { isCoreInlineMarkFlagEnabled } from "./internalFlags.js";
|
|
5
|
-
const commands = {
|
|
6
|
-
bold: toggleBold,
|
|
7
|
-
italic: toggleItalic,
|
|
8
|
-
underline: toggleUnderline,
|
|
9
|
-
superscript: toggleSuperscript,
|
|
10
|
-
subscript: toggleSubscript,
|
|
11
|
-
};
|
|
12
|
-
export const isCoreInlineMarkEnabled = (mark) => isCoreInlineMarkFlagEnabled(mark);
|
|
13
|
-
export const getCoreInlineMarkResult = (root, mark) => {
|
|
14
|
-
const selection = selectionFromDom(root, window.getSelection());
|
|
15
|
-
if (!selection)
|
|
16
|
-
return null;
|
|
17
|
-
const { document } = smartDocumentFromEditorRoot(root);
|
|
18
|
-
const state = { document, selection };
|
|
19
|
-
const command = commands[mark];
|
|
20
|
-
if (!command.isEnabled(state))
|
|
21
|
-
return null;
|
|
22
|
-
const transaction = command.execute(state);
|
|
23
|
-
const next = applyTransaction(state, transaction);
|
|
24
|
-
return { html: serializeSmartDocument(next.document), selectionBefore: transaction.selectionBefore, selectionAfter: transaction.selectionAfter };
|
|
25
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { SmartDocument } from "smartrte-core";
|
|
2
|
-
export declare const PDF_MEDIA_TYPE = "application/pdf";
|
|
3
|
-
export interface PdfTextItemSnapshot {
|
|
4
|
-
text: string;
|
|
5
|
-
x: number;
|
|
6
|
-
y: number;
|
|
7
|
-
width: number;
|
|
8
|
-
height: number;
|
|
9
|
-
fontFamily?: string;
|
|
10
|
-
}
|
|
11
|
-
export interface PdfPageSnapshot {
|
|
12
|
-
width: number;
|
|
13
|
-
items: readonly PdfTextItemSnapshot[];
|
|
14
|
-
}
|
|
15
|
-
export interface PdfImportResult {
|
|
16
|
-
document: SmartDocument;
|
|
17
|
-
layoutHtml: string;
|
|
18
|
-
pages: number;
|
|
19
|
-
}
|
|
20
|
-
export declare const reconstructPdfPages: (pages: readonly PdfPageSnapshot[], ownerDocument: Document) => PdfImportResult;
|
|
21
|
-
export declare const importPdfDocument: (arrayBuffer: ArrayBuffer, ownerDocument: Document) => Promise<PdfImportResult>;
|
|
22
|
-
export declare const buildPdfPrintDocument: (document: SmartDocument) => string;
|
|
23
|
-
export declare const printSmartDocumentAsPdf: (document: SmartDocument, hostWindow: Window, delayMs?: number) => boolean;
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import { normalizeSmartDocument } from "smartrte-core";
|
|
2
|
-
import { exportTextDocument } from "./documentFormats.js";
|
|
3
|
-
import { smartDocumentFromHtml } from "./domSmartDocument.js";
|
|
4
|
-
export const PDF_MEDIA_TYPE = "application/pdf";
|
|
5
|
-
const escapeHtml = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
6
|
-
const spanFor = (item) => {
|
|
7
|
-
const family = item.fontFamily?.toLowerCase() || "";
|
|
8
|
-
const styles = [
|
|
9
|
-
`font-size:${Math.max(8, Math.round(item.height))}px`,
|
|
10
|
-
family.includes("bold") ? "font-weight:700" : "",
|
|
11
|
-
family.includes("italic") || family.includes("oblique") ? "font-style:italic" : "",
|
|
12
|
-
].filter(Boolean).join(";");
|
|
13
|
-
return `<span style="${styles}">${escapeHtml(item.text)}</span>`;
|
|
14
|
-
};
|
|
15
|
-
const lineContent = (items) => {
|
|
16
|
-
let previousRight;
|
|
17
|
-
let text = "";
|
|
18
|
-
let html = "";
|
|
19
|
-
const starts = [];
|
|
20
|
-
const gaps = [];
|
|
21
|
-
items.forEach((item, index) => {
|
|
22
|
-
const gap = previousRight === undefined ? 0 : item.x - previousRight;
|
|
23
|
-
if (index === 0 || gap > 20)
|
|
24
|
-
starts.push(item.x);
|
|
25
|
-
if (gap > 2) {
|
|
26
|
-
text += " ";
|
|
27
|
-
html += " ";
|
|
28
|
-
if (gap > 20)
|
|
29
|
-
gaps.push(gap);
|
|
30
|
-
}
|
|
31
|
-
text += item.text;
|
|
32
|
-
html += spanFor(item);
|
|
33
|
-
previousRight = item.x + item.width;
|
|
34
|
-
});
|
|
35
|
-
return { text, html, starts, gaps };
|
|
36
|
-
};
|
|
37
|
-
const alignmentForLine = (items, pageWidth) => {
|
|
38
|
-
const first = items[0]?.x || 0;
|
|
39
|
-
const last = items[items.length - 1];
|
|
40
|
-
const right = last ? last.x + last.width : first;
|
|
41
|
-
const center = (first + right) / 2;
|
|
42
|
-
if (Math.abs(center - pageWidth / 2) < pageWidth * 0.12)
|
|
43
|
-
return "center";
|
|
44
|
-
if (first > pageWidth * 0.55)
|
|
45
|
-
return "right";
|
|
46
|
-
return "";
|
|
47
|
-
};
|
|
48
|
-
export const reconstructPdfPages = (pages, ownerDocument) => {
|
|
49
|
-
let layoutHtml = "";
|
|
50
|
-
pages.forEach((page) => {
|
|
51
|
-
const heights = page.items.map((item) => item.height).filter((height) => height > 0).sort((a, b) => a - b);
|
|
52
|
-
const medianHeight = heights[Math.floor(heights.length / 2)] || 12;
|
|
53
|
-
const lines = [];
|
|
54
|
-
page.items.filter((item) => item.text.trim()).forEach((item) => {
|
|
55
|
-
const line = lines.find((candidate) => Math.abs(candidate.y - item.y) < medianHeight * 0.5);
|
|
56
|
-
if (line)
|
|
57
|
-
line.items.push(item);
|
|
58
|
-
else
|
|
59
|
-
lines.push({ y: item.y, items: [item] });
|
|
60
|
-
});
|
|
61
|
-
lines.sort((left, right) => right.y - left.y);
|
|
62
|
-
lines.forEach((line) => line.items.sort((left, right) => left.x - right.x));
|
|
63
|
-
let pageHtml = "";
|
|
64
|
-
let activeList;
|
|
65
|
-
let tableColumns = [];
|
|
66
|
-
let tableRows = [];
|
|
67
|
-
const closeList = () => {
|
|
68
|
-
if (activeList)
|
|
69
|
-
pageHtml += `</${activeList}>`;
|
|
70
|
-
activeList = undefined;
|
|
71
|
-
};
|
|
72
|
-
const closeTable = () => {
|
|
73
|
-
if (tableRows.length) {
|
|
74
|
-
pageHtml += `<table style="border-collapse:collapse;width:100%"><tbody>${tableRows.join("")}</tbody></table>`;
|
|
75
|
-
}
|
|
76
|
-
tableRows = [];
|
|
77
|
-
tableColumns = [];
|
|
78
|
-
};
|
|
79
|
-
lines.forEach((line) => {
|
|
80
|
-
const content = lineContent(line.items);
|
|
81
|
-
const alignsWithTable = tableColumns.length > 0
|
|
82
|
-
&& content.starts.some((x) => tableColumns.some((column) => Math.abs(column - x) < 20));
|
|
83
|
-
const beginsTable = content.starts.length >= 2 && content.gaps.some((gap) => gap > 30);
|
|
84
|
-
if (beginsTable || alignsWithTable) {
|
|
85
|
-
closeList();
|
|
86
|
-
if (!tableColumns.length)
|
|
87
|
-
tableColumns = [...content.starts];
|
|
88
|
-
const cells = new Array(tableColumns.length).fill("");
|
|
89
|
-
line.items.forEach((item) => {
|
|
90
|
-
let column = 0;
|
|
91
|
-
tableColumns.forEach((start, index) => {
|
|
92
|
-
if (item.x >= start - 10)
|
|
93
|
-
column = index;
|
|
94
|
-
});
|
|
95
|
-
cells[column] += `${cells[column] ? " " : ""}${spanFor(item)}`;
|
|
96
|
-
});
|
|
97
|
-
tableRows.push(`<tr>${cells.map((cell) => `<td style="border:1px solid #d1d5db;padding:8px;vertical-align:top">${cell || " "}</td>`).join("")}</tr>`);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
closeTable();
|
|
101
|
-
const bullet = /^[•\-*]\s/.test(content.text);
|
|
102
|
-
const numbered = /^\d+[.)]\s/.test(content.text);
|
|
103
|
-
if (bullet || numbered) {
|
|
104
|
-
const type = bullet ? "ul" : "ol";
|
|
105
|
-
if (activeList !== type) {
|
|
106
|
-
closeList();
|
|
107
|
-
activeList = type;
|
|
108
|
-
pageHtml += `<${type}>`;
|
|
109
|
-
}
|
|
110
|
-
const listItems = line.items.map((item, index) => index === 0
|
|
111
|
-
? { ...item, text: item.text.replace(bullet ? /^[•\-*]\s*/ : /^\d+[.)]\s*/, "") }
|
|
112
|
-
: item);
|
|
113
|
-
pageHtml += `<li>${lineContent(listItems).html.trim()}</li>`;
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
closeList();
|
|
117
|
-
const largest = Math.max(...line.items.map((item) => item.height));
|
|
118
|
-
const heading = largest > medianHeight * 1.2;
|
|
119
|
-
const tag = heading ? (largest > medianHeight * 1.5 ? "h2" : "h3") : "p";
|
|
120
|
-
const alignment = alignmentForLine(line.items, page.width);
|
|
121
|
-
const indent = !alignment && line.items[0]?.x > 40 ? `margin-left:${Math.round(line.items[0].x)}px` : "";
|
|
122
|
-
const style = [alignment ? `text-align:${alignment}` : "", indent].filter(Boolean).join(";");
|
|
123
|
-
pageHtml += `<${tag}${style ? ` style="${style}"` : ""}>${content.html}</${tag}>`;
|
|
124
|
-
});
|
|
125
|
-
closeList();
|
|
126
|
-
closeTable();
|
|
127
|
-
layoutHtml += pageHtml;
|
|
128
|
-
});
|
|
129
|
-
return {
|
|
130
|
-
document: normalizeSmartDocument(smartDocumentFromHtml(layoutHtml, ownerDocument)),
|
|
131
|
-
layoutHtml,
|
|
132
|
-
pages: pages.length,
|
|
133
|
-
};
|
|
134
|
-
};
|
|
135
|
-
export const importPdfDocument = async (arrayBuffer, ownerDocument) => {
|
|
136
|
-
const pdfjsLib = await import("pdfjs-dist");
|
|
137
|
-
if (typeof window !== "undefined") {
|
|
138
|
-
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL("pdfjs-dist/build/pdf.worker.min.mjs", import.meta.url).toString();
|
|
139
|
-
}
|
|
140
|
-
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
|
|
141
|
-
const pages = [];
|
|
142
|
-
for (let index = 1; index <= pdf.numPages; index += 1) {
|
|
143
|
-
const page = await pdf.getPage(index);
|
|
144
|
-
const viewport = page.getViewport({ scale: 1 });
|
|
145
|
-
const content = await page.getTextContent();
|
|
146
|
-
const styles = content.styles;
|
|
147
|
-
pages.push({
|
|
148
|
-
width: viewport.width,
|
|
149
|
-
items: content.items.map((item) => ({
|
|
150
|
-
text: item.str || "",
|
|
151
|
-
x: item.transform[4],
|
|
152
|
-
y: item.transform[5],
|
|
153
|
-
width: item.width || 0,
|
|
154
|
-
height: Math.abs(item.transform[3]) || 0,
|
|
155
|
-
fontFamily: styles[item.fontName]?.fontFamily,
|
|
156
|
-
})),
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
return reconstructPdfPages(pages, ownerDocument);
|
|
160
|
-
};
|
|
161
|
-
export const buildPdfPrintDocument = (document) => {
|
|
162
|
-
const html = exportTextDocument("html", document);
|
|
163
|
-
return `<!doctype html>
|
|
164
|
-
<html lang="en">
|
|
165
|
-
<head>
|
|
166
|
-
<meta charset="utf-8">
|
|
167
|
-
<title>Smart RTE PDF Export</title>
|
|
168
|
-
<style>
|
|
169
|
-
@page { margin: 18mm; }
|
|
170
|
-
html, body { background: #fff; }
|
|
171
|
-
body {
|
|
172
|
-
color: #111;
|
|
173
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
174
|
-
line-height: 1.6;
|
|
175
|
-
padding: 32px;
|
|
176
|
-
}
|
|
177
|
-
table { border-collapse: collapse; width: 100%; margin: 12px 0; break-inside: auto; }
|
|
178
|
-
tr, img, blockquote, pre { break-inside: avoid; }
|
|
179
|
-
td, th { border: 1px solid #d1d5db; padding: 8px; vertical-align: top; }
|
|
180
|
-
img { max-width: 100%; height: auto; }
|
|
181
|
-
blockquote { border-left: 4px solid #d1d5db; padding-left: 12px; color: #374151; }
|
|
182
|
-
pre, code { background: #f3f4f6; }
|
|
183
|
-
pre { padding: 12px; white-space: pre-wrap; }
|
|
184
|
-
@media print { body { padding: 0; } }
|
|
185
|
-
</style>
|
|
186
|
-
</head>
|
|
187
|
-
<body>${html || "<p></p>"}</body>
|
|
188
|
-
</html>`;
|
|
189
|
-
};
|
|
190
|
-
export const printSmartDocumentAsPdf = (document, hostWindow, delayMs = 150) => {
|
|
191
|
-
const printWindow = hostWindow.open("", "_blank", "width=900,height=700");
|
|
192
|
-
if (!printWindow)
|
|
193
|
-
return false;
|
|
194
|
-
printWindow.addEventListener("load", () => {
|
|
195
|
-
printWindow.setTimeout(() => {
|
|
196
|
-
printWindow.focus();
|
|
197
|
-
printWindow.print();
|
|
198
|
-
}, delayMs);
|
|
199
|
-
}, { once: true });
|
|
200
|
-
printWindow.document.open();
|
|
201
|
-
printWindow.document.write(buildPdfPrintDocument(document));
|
|
202
|
-
printWindow.document.close();
|
|
203
|
-
return true;
|
|
204
|
-
};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export declare const portableFormulaMarker: (value: string, displayText?: string) => string;
|
|
2
|
-
export declare const portableImageMarker: (src: string, alt?: string, title?: string) => string;
|
|
3
|
-
/** Restores Smart RTE atom fallback markers retained by DOCX text runs. */
|
|
4
|
-
export declare const restorePortableDocxAtoms: (html: string, ownerDocument: Document) => string;
|