@stll/folio-core 0.28.1 → 0.30.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/dist/controller/folioEditor.d.ts +28 -1
- package/dist/controller/folioEditor.js +37 -26
- package/dist/controller/fontReadiness.js +28 -24
- package/dist/controller/hiddenEditorManager.d.ts +2 -7
- package/dist/controller/layoutPipeline.js +33 -3
- package/dist/controller/noteEditorManager.d.ts +3 -6
- package/dist/docx/metafileSvg.d.ts +12 -0
- package/dist/docx/metafileSvg.js +462 -0
- package/dist/docx/paragraphTextBoxEnrichment.js +55 -4
- package/dist/docx/parser.d.ts +2 -2
- package/dist/docx/parser.js +26 -0
- package/dist/docx/runParser.js +2 -1
- package/dist/docx/serializer/runSerializer.js +14 -2
- package/dist/docx/styleParser.js +2 -1
- package/dist/docx/textBoxParser.js +14 -0
- package/dist/docx/vmlImageParser.js +72 -152
- package/dist/docx/vmlPreview.d.ts +31 -0
- package/dist/docx/vmlPreview.js +535 -0
- package/dist/docx/wrapTypes.d.ts +2 -36
- package/dist/docx/wrapTypes.js +1 -39
- package/dist/fonts/fontAlternates.d.ts +8 -0
- package/dist/fonts/fontAlternates.js +16 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +34 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +5 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +136 -120
- package/dist/layout-bridge/dom/noteStoryDom.d.ts +1 -1
- package/dist/layout-bridge/engine/selectionRects.js +3 -1
- package/dist/layout-engine/index.js +65 -32
- package/dist/layout-engine/justifiedLineFit.d.ts +7 -0
- package/dist/layout-engine/justifiedLineFit.js +6 -0
- package/dist/layout-engine/keep-together.js +15 -10
- package/dist/layout-engine/measure/complexScriptFormatting.d.ts +6 -1
- package/dist/layout-engine/measure/complexScriptFormatting.js +11 -2
- package/dist/layout-engine/measure/floatingTablePosition.d.ts +16 -1
- package/dist/layout-engine/measure/floatingTablePosition.js +29 -6
- package/dist/layout-engine/measure/lineBreakProvider.js +67 -8
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
- package/dist/layout-engine/measure/listMarkerWidth.js +23 -10
- package/dist/layout-engine/measure/measureBlocks.d.ts +15 -0
- package/dist/layout-engine/measure/measureBlocks.js +197 -30
- package/dist/layout-engine/measure/measureContainer.js +20 -24
- package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
- package/dist/layout-engine/measure/measureHelpers.js +14 -8
- package/dist/layout-engine/measure/measureParagraph.js +111 -37
- package/dist/layout-engine/measure/measureTypes.d.ts +3 -0
- package/dist/layout-engine/measure/tabCalculator.d.ts +123 -0
- package/dist/layout-engine/measure/tabCalculator.js +144 -0
- package/dist/layout-engine/measure/tableCellFlow.d.ts +21 -1
- package/dist/layout-engine/measure/tableCellFlow.js +45 -8
- package/dist/layout-engine/measure/tableInlinePlacement.d.ts +10 -2
- package/dist/layout-engine/measure/tableInlinePlacement.js +17 -15
- package/dist/layout-engine/paginator.d.ts +26 -2
- package/dist/layout-engine/paginator.js +76 -14
- package/dist/layout-engine/paragraphSpacing.d.ts +3 -1
- package/dist/layout-engine/paragraphSpacing.js +4 -3
- package/dist/layout-engine/renderedBreakReconciliation.d.ts +14 -3
- package/dist/layout-engine/renderedBreakReconciliation.js +45 -14
- package/dist/layout-engine/section-breaks.d.ts +3 -1
- package/dist/layout-engine/section-breaks.js +6 -2
- package/dist/layout-engine/types.d.ts +18 -1
- package/dist/layout-engine/types.js +1 -1
- package/dist/layout-painter/imageLayout.d.ts +1 -1
- package/dist/layout-painter/renderPage.js +6 -1
- package/dist/layout-painter/renderParagraph.js +169 -82
- package/dist/layout-painter/renderTable.d.ts +1 -1
- package/dist/layout-painter/renderTable.js +18 -7
- package/dist/layout-painter/renderTextBox.d.ts +1 -1
- package/dist/layout-painter/renderTextBox.js +6 -1
- package/dist/markdown/renderParagraph.js +7 -2
- package/dist/model.d.ts +3 -3
- package/dist/model.js +2 -2
- package/dist/paged-layout/sectionBlockWidths.d.ts +14 -0
- package/dist/paged-layout/sectionBlockWidths.js +103 -14
- package/dist/prosemirror/attrs/index.js +14 -2
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +8 -0
- package/dist/prosemirror/bookmarkBoundaryAttrs.js +66 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +176 -54
- package/dist/prosemirror/conversion/toProseDoc.js +179 -64
- package/dist/prosemirror/extensions/StarterKit.js +11 -3
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +8 -4
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +9 -5
- package/dist/prosemirror/extensions/features/pasteCleanup.d.ts +10 -23
- package/dist/prosemirror/extensions/features/pasteCleanup.js +77 -22
- package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +9 -5
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +67 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +10 -4
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +77 -59
- package/dist/prosemirror/extensions/nodes/TableExtension.js +2 -0
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +4 -1
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +4 -3
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +6 -2
- package/dist/prosemirror/listMarker.d.ts +58 -0
- package/dist/prosemirror/listMarker.js +185 -0
- package/dist/prosemirror/numberedRefFields.d.ts +24 -0
- package/dist/prosemirror/numberedRefFields.js +276 -0
- package/dist/prosemirror/paraText.js +56 -17
- package/dist/prosemirror/plugins/anonymizationDecorations.js +1 -1
- package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -1
- package/dist/prosemirror/plugins/pmTextScan.js +28 -7
- package/dist/prosemirror/plugins/templateDirectives.js +2 -2
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/nodes.d.ts +17 -1
- package/dist/prosemirror/utils/tabCalculator.d.ts +2 -123
- package/dist/prosemirror/utils/tabCalculator.js +1 -140
- package/dist/prosemirror/validation.js +93 -0
- package/dist/render-dom/RemoteSelectionOverlay.d.ts +4 -4
- package/dist/types/documentEnumValues.d.ts +4 -1
- package/dist/types/documentEnumValues.js +12 -1
- package/dist/types/editor-story.d.ts +8 -0
- package/dist/types/editor-story.js +0 -0
- package/dist/types/remote-selection.d.ts +11 -0
- package/dist/types/remote-selection.js +0 -0
- package/dist/types/wrap.d.ts +36 -0
- package/dist/types/wrap.js +40 -0
- package/dist/utils/fontResolver.d.ts +1 -1
- package/dist/utils/fontResolver.js +42 -2
- package/dist/utils/formatToStyle.js +4 -2
- package/dist/utils/horizontalScale.d.ts +28 -0
- package/dist/utils/horizontalScale.js +42 -0
- package/package.json +2 -2
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
|
|
2
2
|
import { createStyleEngine } from "../../style-engine/styleEngine.js";
|
|
3
|
+
import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
|
|
3
4
|
import { mergeParagraphFormatting, mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
|
|
4
5
|
import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
|
|
5
6
|
import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
|
|
6
7
|
import { emuToPixels } from "../../utils/units.js";
|
|
7
8
|
import { setAutospacingBaseValue } from "../autospacingBase.js";
|
|
8
9
|
import { buildRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
|
|
10
|
+
import { stampNumberedRefFieldBaselines } from "../numberedRefFields.js";
|
|
9
11
|
import { directionFromBidi } from "../paragraphDirection.js";
|
|
10
12
|
import { schema } from "../schema/index.js";
|
|
11
13
|
import { cascadeStyleTextFormatting } from "../styles/styleToggleCascade.js";
|
|
@@ -36,6 +38,56 @@ const createHyperlinkInstanceIndexAllocator = () => {
|
|
|
36
38
|
return () => index++;
|
|
37
39
|
};
|
|
38
40
|
/**
|
|
41
|
+
* Find bookmark pairs across every editable inline wrapper in a document story.
|
|
42
|
+
* Each endpoint is converted at its own structural position, so a range may
|
|
43
|
+
* start outside a hyperlink and end inside it (or the inverse).
|
|
44
|
+
*/
|
|
45
|
+
const collectPairedBookmarkIds = (blocks) => {
|
|
46
|
+
const counts = /* @__PURE__ */ new Map();
|
|
47
|
+
let position = 0;
|
|
48
|
+
const countBoundary = (id, type) => {
|
|
49
|
+
const count = counts.get(id) ?? {
|
|
50
|
+
starts: 0,
|
|
51
|
+
ends: 0
|
|
52
|
+
};
|
|
53
|
+
if (type === "start") {
|
|
54
|
+
count.starts += 1;
|
|
55
|
+
count.firstStart ??= position;
|
|
56
|
+
} else {
|
|
57
|
+
count.ends += 1;
|
|
58
|
+
count.firstEnd ??= position;
|
|
59
|
+
}
|
|
60
|
+
position += 1;
|
|
61
|
+
counts.set(id, count);
|
|
62
|
+
};
|
|
63
|
+
const visitRun = (run) => {
|
|
64
|
+
for (const content of run.content) if (content.type === "shape" && content.shape.textBody) visitBlocks(content.shape.textBody.content);
|
|
65
|
+
};
|
|
66
|
+
const visitHyperlink = (hyperlink) => {
|
|
67
|
+
for (const child of hyperlink.children) if (child.type === "bookmarkStart") countBoundary(child.id, "start");
|
|
68
|
+
else if (child.type === "bookmarkEnd") countBoundary(child.id, "end");
|
|
69
|
+
else visitRun(child);
|
|
70
|
+
};
|
|
71
|
+
const visitParagraphContent = (content) => {
|
|
72
|
+
if (content.type === "bookmarkStart") countBoundary(content.id, "start");
|
|
73
|
+
else if (content.type === "bookmarkEnd") countBoundary(content.id, "end");
|
|
74
|
+
else if (content.type === "run") visitRun(content);
|
|
75
|
+
else if (content.type === "hyperlink") visitHyperlink(content);
|
|
76
|
+
else if (content.type === "simpleField") for (const child of content.content) if (child.type === "hyperlink") visitHyperlink(child);
|
|
77
|
+
else visitRun(child);
|
|
78
|
+
else if (content.type === "complexField") for (const run of [...content.fieldCode ?? [], ...content.fieldResult]) visitRun(run);
|
|
79
|
+
else if (content.type === "inlineSdt") for (const child of content.content) visitParagraphContent(child);
|
|
80
|
+
else if (content.type === "insertion" || content.type === "deletion" || content.type === "moveFrom" || content.type === "moveTo") for (const child of content.content) visitParagraphContent(child);
|
|
81
|
+
};
|
|
82
|
+
const visitBlocks = (nestedBlocks) => {
|
|
83
|
+
for (const block of nestedBlocks) if (block.type === "paragraph") for (const content of block.content) visitParagraphContent(content);
|
|
84
|
+
else if (block.type === "table") for (const row of block.rows) for (const cell of row.cells) visitBlocks(cell.content);
|
|
85
|
+
else visitBlocks(block.content);
|
|
86
|
+
};
|
|
87
|
+
visitBlocks(blocks);
|
|
88
|
+
return new Set([...counts].flatMap(([id, count]) => count.starts === 1 && count.ends === 1 && count.firstStart !== void 0 && count.firstEnd !== void 0 && count.firstStart < count.firstEnd ? [id] : []));
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
39
91
|
* Convert a Document to a ProseMirror document
|
|
40
92
|
*
|
|
41
93
|
* @param document - The Document to convert
|
|
@@ -50,7 +102,8 @@ function toProseDoc(document, options) {
|
|
|
50
102
|
const conversionContext = {
|
|
51
103
|
theme,
|
|
52
104
|
nextTextBoxGroupId,
|
|
53
|
-
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator()
|
|
105
|
+
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator(),
|
|
106
|
+
pairedBookmarkIds: collectPairedBookmarkIds(paragraphs)
|
|
54
107
|
};
|
|
55
108
|
const convertBodyBlocks = (blocks) => {
|
|
56
109
|
const out = [];
|
|
@@ -85,7 +138,7 @@ function toProseDoc(document, options) {
|
|
|
85
138
|
};
|
|
86
139
|
nodes.push(...convertBodyBlocks(paragraphs));
|
|
87
140
|
if (nodes.length === 0) nodes.push(schema.node("paragraph", {}, []));
|
|
88
|
-
const pmDoc = schema.node("doc", null, nodes);
|
|
141
|
+
const pmDoc = stampNumberedRefFieldBaselines(schema.node("doc", null, nodes));
|
|
89
142
|
assertValidProseMirrorDocument(pmDoc, "Document conversion produced an invalid ProseMirror document");
|
|
90
143
|
return pmDoc;
|
|
91
144
|
}
|
|
@@ -126,7 +179,7 @@ function convertBlockSdt(blockSdt, convertBlocks) {
|
|
|
126
179
|
* Resolves style-based text formatting and passes it to runs so that
|
|
127
180
|
* paragraph styles (like Heading1) apply their font size, color, etc.
|
|
128
181
|
*/
|
|
129
|
-
function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
|
|
182
|
+
function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex, pairedBookmarkIds, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
|
|
130
183
|
const attrs = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
|
|
131
184
|
const isTocParagraph = attrs._tableOfContentsLevel !== void 0;
|
|
132
185
|
const inlineNodes = [];
|
|
@@ -209,42 +262,56 @@ function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex,
|
|
|
209
262
|
const emitTrackedChange = (change, markType, moveKind) => {
|
|
210
263
|
emitInlineNodes(convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
|
|
211
264
|
};
|
|
212
|
-
for (const content of paragraph.content)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
...content.rId !== void 0 ? { rId: content.rId } : {}
|
|
232
|
-
});
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
emitInlineNodes(linkNodes);
|
|
236
|
-
} else if (content.type === "simpleField" || content.type === "complexField") emitInlineNode(convertField(content, getInheritedRunFormatting, styleResolver));
|
|
237
|
-
else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, textBoxAnchors));
|
|
238
|
-
else if (content.type === "insertion" || content.type === "moveTo") emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
|
|
239
|
-
else if (content.type === "deletion" || content.type === "moveFrom") emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
|
|
240
|
-
else if (content.type === "mathEquation") emitInlineNode(convertMathEquation(content));
|
|
241
|
-
if (content.type === "bookmarkStart") {
|
|
242
|
-
if (!bookmarksArr) bookmarksArr = [];
|
|
243
|
-
bookmarksArr.push({
|
|
244
|
-
id: content.id,
|
|
245
|
-
name: content.name
|
|
265
|
+
for (const content of paragraph.content) if (content.type === "commentRangeStart") commentIds.add(content.id);
|
|
266
|
+
else if (content.type === "commentRangeEnd") commentIds.delete(content.id);
|
|
267
|
+
else if (content.type === "commentReference") anchorPointComment(inlineNodes, content.id);
|
|
268
|
+
else if (content.type === "run") emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver, textBoxAnchors));
|
|
269
|
+
else if (content.type === "hyperlink") {
|
|
270
|
+
const linkNodes = convertHyperlink(content, {
|
|
271
|
+
getInheritedRunFormatting,
|
|
272
|
+
styleResolver,
|
|
273
|
+
hyperlinkIndex: nextHyperlinkInstanceIndex(),
|
|
274
|
+
textBoxAnchors
|
|
275
|
+
});
|
|
276
|
+
if (linkNodes.length === 0) {
|
|
277
|
+
emptyHyperlinks ??= [];
|
|
278
|
+
emptyHyperlinks.push({
|
|
279
|
+
offset: inlineOffset,
|
|
280
|
+
...content.href !== void 0 ? { href: content.href } : {},
|
|
281
|
+
...content.anchor !== void 0 ? { anchor: content.anchor } : {},
|
|
282
|
+
...content.tooltip !== void 0 ? { tooltip: content.tooltip } : {},
|
|
283
|
+
...content.rId !== void 0 ? { rId: content.rId } : {}
|
|
246
284
|
});
|
|
285
|
+
continue;
|
|
247
286
|
}
|
|
287
|
+
emitInlineNodes(linkNodes);
|
|
288
|
+
} else if (content.type === "simpleField" || content.type === "complexField") emitInlineNode(convertField(content, {
|
|
289
|
+
getInheritedRunFormatting,
|
|
290
|
+
styleResolver,
|
|
291
|
+
nextHyperlinkInstanceIndex,
|
|
292
|
+
textBoxAnchors
|
|
293
|
+
}));
|
|
294
|
+
else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, textBoxAnchors));
|
|
295
|
+
else if (content.type === "insertion" || content.type === "moveTo") emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
|
|
296
|
+
else if (content.type === "deletion" || content.type === "moveFrom") emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
|
|
297
|
+
else if (content.type === "mathEquation") emitInlineNode(convertMathEquation(content));
|
|
298
|
+
else if (content.type === "bookmarkStart" && pairedBookmarkIds.has(content.id)) emitInlineNode(schema.node("bookmarkBoundary", {
|
|
299
|
+
type: "start",
|
|
300
|
+
id: content.id,
|
|
301
|
+
name: content.name,
|
|
302
|
+
colFirst: content.colFirst,
|
|
303
|
+
colLast: content.colLast
|
|
304
|
+
}));
|
|
305
|
+
else if (content.type === "bookmarkEnd" && pairedBookmarkIds.has(content.id)) emitInlineNode(schema.node("bookmarkBoundary", {
|
|
306
|
+
type: "end",
|
|
307
|
+
id: content.id
|
|
308
|
+
}));
|
|
309
|
+
else if (content.type === "bookmarkStart") {
|
|
310
|
+
if (!bookmarksArr) bookmarksArr = [];
|
|
311
|
+
bookmarksArr.push({
|
|
312
|
+
id: content.id,
|
|
313
|
+
name: content.name
|
|
314
|
+
});
|
|
248
315
|
}
|
|
249
316
|
if (bookmarksArr) attrs.bookmarks = bookmarksArr;
|
|
250
317
|
if (emptyHyperlinks) attrs._emptyHyperlinks = emptyHyperlinks;
|
|
@@ -313,7 +380,7 @@ function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, getI
|
|
|
313
380
|
});
|
|
314
381
|
}
|
|
315
382
|
function canCarryTrackedRunMark(node, markType) {
|
|
316
|
-
return node.isText || node.isInline && node.type.allowsMarkType(markType) && (node.type.name === "image" || node.type.name === "shape" || node.type.name === "hardBreak" || node.type.name === "tab" || node.type.name === "symbol" || node.type.name === "textBoxAnchor");
|
|
383
|
+
return node.isText || node.isInline && node.type.allowsMarkType(markType) && (node.type.name === "image" || node.type.name === "shape" || node.type.name === "hardBreak" || node.type.name === "tab" || node.type.name === "symbol" || node.type.name === "bookmarkBoundary" || node.type.name === "textBoxAnchor");
|
|
317
384
|
}
|
|
318
385
|
/**
|
|
319
386
|
* Convert ParagraphFormatting to ProseMirror paragraph attrs
|
|
@@ -736,6 +803,7 @@ function convertTable(table, styleResolver, context) {
|
|
|
736
803
|
const resolvedTableBorders = table.formatting?.borders ?? tableStyle?.tblPr?.borders ?? fallbackTableStyle?.tblPr?.borders;
|
|
737
804
|
const fallbackTableIndent = fallbackTableStyle?.tblPr?.indent;
|
|
738
805
|
const resolvedTableIndent = table.formatting?.indent ?? tableStyle?.tblPr?.indent ?? (fallbackTableIndent?.value === 0 ? void 0 : fallbackTableIndent);
|
|
806
|
+
const resolvedTableJustification = tableStyle?.tblPr?.justification ?? fallbackTableStyle?.tblPr?.justification;
|
|
739
807
|
const resolvedTableBidi = table.formatting?.bidi ?? tableStyle?.tblPr?.bidi ?? fallbackTableStyle?.tblPr?.bidi;
|
|
740
808
|
const tableCellMargins = table.formatting?.cellMargins ?? tableStyle?.tblPr?.cellMargins ?? fallbackTableStyle?.tblPr?.cellMargins;
|
|
741
809
|
let cellMarginsAttr;
|
|
@@ -758,6 +826,7 @@ function convertTable(table, styleResolver, context) {
|
|
|
758
826
|
if (table.formatting?.look) attrs.look = table.formatting.look;
|
|
759
827
|
if (table.formatting?.borders) attrs.borders = table.formatting.borders;
|
|
760
828
|
if (resolvedTableIndent) attrs._resolvedIndent = resolvedTableIndent;
|
|
829
|
+
if (resolvedTableJustification) attrs._resolvedJustification = resolvedTableJustification;
|
|
761
830
|
if (resolvedTableBidi !== void 0) attrs._resolvedBidi = resolvedTableBidi;
|
|
762
831
|
if (table.formatting) attrs._originalFormatting = table.formatting;
|
|
763
832
|
if (table.propertyChanges && table.propertyChanges.length > 0) attrs.tblPrChange = [...table.propertyChanges];
|
|
@@ -797,7 +866,8 @@ function convertTable(table, styleResolver, context) {
|
|
|
797
866
|
})();
|
|
798
867
|
})();
|
|
799
868
|
if (bandingEnabledH && !isFirstRowStyled && !isLastRow) dataRowIndex++;
|
|
800
|
-
|
|
869
|
+
const resolvedRowJustification = tableStyle?.trPr?.justification ?? fallbackTableStyle?.trPr?.justification;
|
|
870
|
+
return convertTableRow(row, styleResolver, context, isFirstRowStyled, columnWidths, totalWidth, conditionalStyles, rowBandStyle, bandingEnabledV, look, resolvedTableBorders, rowIndex, totalRows, totalColumns, rowSpanMap, cellMarginsAttr, resolvedRowJustification);
|
|
801
871
|
});
|
|
802
872
|
return schema.node("table", attrs, rows);
|
|
803
873
|
}
|
|
@@ -814,11 +884,12 @@ function countTableColumns(rows) {
|
|
|
814
884
|
/**
|
|
815
885
|
* Convert a TableRow to a ProseMirror table row node
|
|
816
886
|
*/
|
|
817
|
-
function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths, totalWidth, conditionalStyles, rowBandStyle, bandingEnabledV, tableLook, tableBorders, rowIndex, totalRows, totalColumns, rowSpanMap, defaultCellMargins) {
|
|
887
|
+
function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths, totalWidth, conditionalStyles, rowBandStyle, bandingEnabledV, tableLook, tableBorders, rowIndex, totalRows, totalColumns, rowSpanMap, defaultCellMargins, resolvedJustification) {
|
|
818
888
|
const attrsWithoutStructuralChange = { isHeader: !!row.formatting?.header };
|
|
819
889
|
if (row.formatting?.height?.value !== void 0) attrsWithoutStructuralChange.height = row.formatting.height.value;
|
|
820
890
|
if (row.formatting?.heightRule) attrsWithoutStructuralChange.heightRule = row.formatting.heightRule;
|
|
821
891
|
if (row.formatting?.hidden) attrsWithoutStructuralChange.hidden = true;
|
|
892
|
+
if (resolvedJustification) attrsWithoutStructuralChange._resolvedJustification = resolvedJustification;
|
|
822
893
|
if (row.formatting) attrsWithoutStructuralChange._originalFormatting = row.formatting;
|
|
823
894
|
if (row.propertyChanges && row.propertyChanges.length > 0) attrsWithoutStructuralChange.trPrChange = [...row.propertyChanges];
|
|
824
895
|
let attrs = attrsWithoutStructuralChange;
|
|
@@ -1011,7 +1082,8 @@ function standaloneTableCellToProseMirror(cell, nodeType) {
|
|
|
1011
1082
|
context: {
|
|
1012
1083
|
theme: null,
|
|
1013
1084
|
nextTextBoxGroupId: createTextBoxGroupIdFactory(),
|
|
1014
|
-
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator()
|
|
1085
|
+
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator(),
|
|
1086
|
+
pairedBookmarkIds: collectPairedBookmarkIds(cell.content)
|
|
1015
1087
|
},
|
|
1016
1088
|
isHeader: nodeType === "tableHeader",
|
|
1017
1089
|
gridWidthPercent: void 0,
|
|
@@ -1024,31 +1096,47 @@ function standaloneTableCellToProseMirror(cell, nodeType) {
|
|
|
1024
1096
|
defaultCellMargins: void 0
|
|
1025
1097
|
});
|
|
1026
1098
|
}
|
|
1027
|
-
|
|
1028
|
-
* Convert a SimpleField or ComplexField to a ProseMirror field node.
|
|
1029
|
-
* Preserves run formatting (bold, fontSize, color, etc.) as PM marks.
|
|
1030
|
-
* Accepts a run formatting resolver so fields inherit paragraph-level
|
|
1031
|
-
* formatting the same way regular text runs do.
|
|
1032
|
-
*/
|
|
1033
|
-
function convertField(field, getInheritedRunFormatting, styleResolver) {
|
|
1099
|
+
function convertField(field, { getInheritedRunFormatting, styleResolver, nextHyperlinkInstanceIndex, textBoxAnchors }) {
|
|
1034
1100
|
let displayText = "";
|
|
1035
1101
|
let fieldFormatting;
|
|
1036
|
-
const
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1102
|
+
const inlineNodes = [];
|
|
1103
|
+
const hasStructuredSourceContent = field.type === "simpleField" && field.content.some((content) => content.type === "hyperlink");
|
|
1104
|
+
const appendRun = (run) => {
|
|
1105
|
+
for (const content of run.content) if (content.type === "text") displayText += content.text;
|
|
1106
|
+
fieldFormatting ??= run.formatting;
|
|
1107
|
+
if (!hasStructuredSourceContent) return;
|
|
1108
|
+
inlineNodes.push(...convertRun(run, getInheritedRunFormatting(run.formatting, field.fieldType), styleResolver, textBoxAnchors));
|
|
1109
|
+
};
|
|
1110
|
+
if (field.type === "simpleField") for (const content of field.content) {
|
|
1111
|
+
if (content.type === "run") {
|
|
1112
|
+
appendRun(content);
|
|
1113
|
+
continue;
|
|
1114
|
+
}
|
|
1115
|
+
for (const child of content.children) if (child.type === "run") {
|
|
1116
|
+
for (const runContent of child.content) if (runContent.type === "text") displayText += runContent.text;
|
|
1117
|
+
fieldFormatting ??= child.formatting;
|
|
1118
|
+
}
|
|
1119
|
+
inlineNodes.push(...convertHyperlink(content, {
|
|
1120
|
+
getInheritedRunFormatting: (formatting) => getInheritedRunFormatting(formatting, field.fieldType),
|
|
1121
|
+
styleResolver,
|
|
1122
|
+
hyperlinkIndex: nextHyperlinkInstanceIndex(),
|
|
1123
|
+
textBoxAnchors
|
|
1124
|
+
}));
|
|
1040
1125
|
}
|
|
1126
|
+
else for (const run of field.fieldResult) appendRun(run);
|
|
1041
1127
|
if (!fieldFormatting && field.type === "complexField" && field.fieldResult.length === 0) fieldFormatting = field.formatting;
|
|
1042
1128
|
const inheritedFormatting = getInheritedRunFormatting(fieldFormatting, field.fieldType);
|
|
1043
1129
|
const { marks } = buildRunMarks(fieldFormatting, inheritedFormatting, styleResolver);
|
|
1044
|
-
|
|
1130
|
+
const hasConvertedHyperlinkContent = inlineNodes.some((node) => node.marks.some((mark) => mark.type.name === "hyperlink"));
|
|
1131
|
+
const createStructuredField = hasStructuredSourceContent && hasConvertedHyperlinkContent;
|
|
1132
|
+
return schema.node(createStructuredField ? "structuredField" : "field", {
|
|
1045
1133
|
fieldType: field.fieldType,
|
|
1046
1134
|
instruction: field.instruction,
|
|
1047
1135
|
displayText,
|
|
1048
1136
|
fieldKind: field.type === "simpleField" ? "simple" : "complex",
|
|
1049
1137
|
fldLock: field.fldLock ?? false,
|
|
1050
1138
|
dirty: field.dirty ?? false
|
|
1051
|
-
}, void 0, marks);
|
|
1139
|
+
}, createStructuredField ? inlineNodes : void 0, marks);
|
|
1052
1140
|
}
|
|
1053
1141
|
/**
|
|
1054
1142
|
* Convert a MathEquation to a ProseMirror math node.
|
|
@@ -1078,7 +1166,12 @@ function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, getInheritedRunFormat
|
|
|
1078
1166
|
});
|
|
1079
1167
|
inlineNodes.push(...linkNodes);
|
|
1080
1168
|
} else if (content.type === "simpleField" || content.type === "complexField") {
|
|
1081
|
-
const fieldNode = convertField(content,
|
|
1169
|
+
const fieldNode = convertField(content, {
|
|
1170
|
+
getInheritedRunFormatting,
|
|
1171
|
+
styleResolver,
|
|
1172
|
+
nextHyperlinkInstanceIndex,
|
|
1173
|
+
textBoxAnchors
|
|
1174
|
+
});
|
|
1082
1175
|
if (fieldNode) inlineNodes.push(fieldNode);
|
|
1083
1176
|
} else if (content.type === "inlineSdt") {
|
|
1084
1177
|
const nestedSdt = convertInlineSdt(content, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, textBoxAnchors);
|
|
@@ -1338,11 +1431,30 @@ function convertHyperlink(hyperlink, { getInheritedRunFormatting, styleResolver,
|
|
|
1338
1431
|
rId: hyperlink.rId,
|
|
1339
1432
|
_docxHyperlinkIndex: hyperlinkIndex
|
|
1340
1433
|
});
|
|
1341
|
-
for (const child of hyperlink.children)
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1434
|
+
for (const child of hyperlink.children) {
|
|
1435
|
+
if (child.type === "bookmarkStart") {
|
|
1436
|
+
nodes.push(schema.node("bookmarkBoundary", {
|
|
1437
|
+
type: "start",
|
|
1438
|
+
id: child.id,
|
|
1439
|
+
name: child.name,
|
|
1440
|
+
colFirst: child.colFirst,
|
|
1441
|
+
colLast: child.colLast
|
|
1442
|
+
}, void 0, [linkMark]));
|
|
1443
|
+
continue;
|
|
1444
|
+
}
|
|
1445
|
+
if (child.type === "bookmarkEnd") {
|
|
1446
|
+
nodes.push(schema.node("bookmarkBoundary", {
|
|
1447
|
+
type: "end",
|
|
1448
|
+
id: child.id
|
|
1449
|
+
}, void 0, [linkMark]));
|
|
1450
|
+
continue;
|
|
1451
|
+
}
|
|
1452
|
+
if (child.type === "run") {
|
|
1453
|
+
const inheritedFormatting = getInheritedRunFormatting(child.formatting);
|
|
1454
|
+
const { marks: runMarks, mergedFormatting } = buildRunMarks(child.formatting, inheritedFormatting, styleResolver);
|
|
1455
|
+
const allMarks = [...runMarks, linkMark];
|
|
1456
|
+
for (const content of child.content) nodes.push(...convertRunContent(content, allMarks, mergedFormatting, textBoxAnchors));
|
|
1457
|
+
}
|
|
1346
1458
|
}
|
|
1347
1459
|
return nodes;
|
|
1348
1460
|
}
|
|
@@ -1386,7 +1498,7 @@ function textFormattingToMarks(formatting, options) {
|
|
|
1386
1498
|
if (formatting.smallCaps) marks.push(schema.mark("smallCaps"));
|
|
1387
1499
|
const spacing = typeof formatting.spacing === "number" ? formatting.spacing : null;
|
|
1388
1500
|
const position = typeof formatting.position === "number" ? formatting.position : null;
|
|
1389
|
-
const scale =
|
|
1501
|
+
const scale = normalizeHorizontalScalePercent(formatting.scale) ?? null;
|
|
1390
1502
|
const kerning = typeof formatting.kerning === "number" ? formatting.kerning : null;
|
|
1391
1503
|
if (spacing !== null || position !== null || scale !== null || kerning !== null) marks.push(schema.mark("characterSpacing", {
|
|
1392
1504
|
spacing,
|
|
@@ -1511,7 +1623,7 @@ function convertShape(shape) {
|
|
|
1511
1623
|
}
|
|
1512
1624
|
function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, context, extraRunFormatting, tableParagraphOverlay }) {
|
|
1513
1625
|
const { textBoxes, textBoxAnchors } = extractTextBoxesFromParagraph(block, textBoxGroupId);
|
|
1514
|
-
const pmParagraph = convertParagraph(block, styleResolver, context.nextHyperlinkInstanceIndex, void 0, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
|
|
1626
|
+
const pmParagraph = convertParagraph(block, styleResolver, context.nextHyperlinkInstanceIndex, context.pairedBookmarkIds, void 0, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
|
|
1515
1627
|
const nodes = [];
|
|
1516
1628
|
const isEmptyAfterExtraction = textBoxes.length > 0 && !hasContentBesidesTextBoxAnchors(pmParagraph);
|
|
1517
1629
|
const keepWrapperParagraph = isEmptyAfterExtraction && hasParagraphBoundaryPayload(block, pmParagraph);
|
|
@@ -1657,6 +1769,7 @@ function textBoxFromShape(shape, textBody) {
|
|
|
1657
1769
|
if (textBody.margins) textBox.margins = textBody.margins;
|
|
1658
1770
|
if (textBody.autoFit) textBox.autoFit = textBody.autoFit;
|
|
1659
1771
|
if (textBody.textWrap) textBox.textWrap = textBody.textWrap;
|
|
1772
|
+
if (textBody.anchor) textBox.verticalAlign = textBody.anchor;
|
|
1660
1773
|
return textBox;
|
|
1661
1774
|
}
|
|
1662
1775
|
/**
|
|
@@ -1732,6 +1845,7 @@ function convertTextBox(textBox, styleResolver, options) {
|
|
|
1732
1845
|
height: heightPx,
|
|
1733
1846
|
autoFit: textBox.autoFit,
|
|
1734
1847
|
textWrap: textBox.textWrap,
|
|
1848
|
+
verticalAlign: textBox.verticalAlign,
|
|
1735
1849
|
textBoxId: textBox.id,
|
|
1736
1850
|
fillColor,
|
|
1737
1851
|
outlineWidth,
|
|
@@ -1773,7 +1887,8 @@ function headerFooterToProseDoc(content, options) {
|
|
|
1773
1887
|
const conversionContext = {
|
|
1774
1888
|
theme,
|
|
1775
1889
|
nextTextBoxGroupId,
|
|
1776
|
-
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator()
|
|
1890
|
+
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator(),
|
|
1891
|
+
pairedBookmarkIds: collectPairedBookmarkIds(content)
|
|
1777
1892
|
};
|
|
1778
1893
|
const convertBlocks = (blocks) => {
|
|
1779
1894
|
const out = [];
|
|
@@ -1787,7 +1902,7 @@ function headerFooterToProseDoc(content, options) {
|
|
|
1787
1902
|
};
|
|
1788
1903
|
nodes.push(...convertBlocks(content));
|
|
1789
1904
|
if (nodes.length === 0) nodes.push(schema.node("paragraph", {}, []));
|
|
1790
|
-
const pmDoc = schema.node("doc", null, nodes);
|
|
1905
|
+
const pmDoc = stampNumberedRefFieldBaselines(schema.node("doc", null, nodes));
|
|
1791
1906
|
assertValidProseMirrorDocument(pmDoc, "Header/footer conversion produced an invalid ProseMirror document");
|
|
1792
1907
|
return pmDoc;
|
|
1793
1908
|
}
|
|
@@ -43,7 +43,8 @@ import { EmbossExtension, EmphasisMarkExtension, ImprintExtension, TextOutlineEx
|
|
|
43
43
|
import { DeletionExtension, InsertionExtension, RunPropertyChangeExtension } from "./marks/TrackedChangeExtensions.js";
|
|
44
44
|
import { UnderlineExtension } from "./marks/UnderlineExtension.js";
|
|
45
45
|
import { BlockSdtExtension } from "./nodes/BlockSdtExtension.js";
|
|
46
|
-
import {
|
|
46
|
+
import { BookmarkBoundaryExtension } from "./nodes/BookmarkBoundaryExtension.js";
|
|
47
|
+
import { FieldExtension, StructuredFieldExtension } from "./nodes/FieldExtension.js";
|
|
47
48
|
import { HardBreakExtension } from "./nodes/HardBreakExtension.js";
|
|
48
49
|
import { HorizontalRuleExtension } from "./nodes/HorizontalRuleExtension.js";
|
|
49
50
|
import { ImageExtension } from "./nodes/ImageExtension.js";
|
|
@@ -64,6 +65,11 @@ import { TextBoxExtension } from "./nodes/TextBoxExtension.js";
|
|
|
64
65
|
function createStarterKit(options = {}) {
|
|
65
66
|
const disabled = options.disable ? new Set(options.disable) : /* @__PURE__ */ new Set();
|
|
66
67
|
const extensions = [];
|
|
68
|
+
let internalClipboardToken;
|
|
69
|
+
const getInternalClipboardToken = () => {
|
|
70
|
+
internalClipboardToken ??= globalThis.crypto.randomUUID();
|
|
71
|
+
return internalClipboardToken;
|
|
72
|
+
};
|
|
67
73
|
function add(name, ext) {
|
|
68
74
|
if (!disabled.has(name)) extensions.push(ext);
|
|
69
75
|
}
|
|
@@ -105,12 +111,13 @@ function createStarterKit(options = {}) {
|
|
|
105
111
|
add("insertion", InsertionExtension());
|
|
106
112
|
add("deletion", DeletionExtension());
|
|
107
113
|
add("runPropertyChange", RunPropertyChangeExtension());
|
|
114
|
+
add("bookmarkBoundary", BookmarkBoundaryExtension({ getInternalClipboardToken }));
|
|
108
115
|
add("hardBreak", HardBreakExtension());
|
|
109
116
|
add("tab", TabExtension());
|
|
110
117
|
add("symbol", SymbolExtension());
|
|
111
118
|
add("image", ImageExtension());
|
|
112
119
|
add("textBox", TextBoxExtension());
|
|
113
|
-
add("textBoxAnchor", TextBoxAnchorExtension());
|
|
120
|
+
add("textBoxAnchor", TextBoxAnchorExtension({ getInternalClipboardToken }));
|
|
114
121
|
add("shape", ShapeExtension());
|
|
115
122
|
add("imageDrag", ImageDragExtension());
|
|
116
123
|
add("imagePaste", ImagePasteExtension());
|
|
@@ -120,11 +127,12 @@ function createStarterKit(options = {}) {
|
|
|
120
127
|
add("pageBreak", PageBreakExtension());
|
|
121
128
|
add("renderedPageBreak", RenderedPageBreakExtension());
|
|
122
129
|
add("field", FieldExtension());
|
|
130
|
+
add("field", StructuredFieldExtension({ getInternalClipboardToken }));
|
|
123
131
|
add("sdt", SdtExtension());
|
|
124
132
|
add("blockSdt", BlockSdtExtension());
|
|
125
133
|
add("math", MathExtension());
|
|
126
134
|
if (!disabled.has("table")) extensions.push(...createTableExtensions());
|
|
127
|
-
add("pasteCleanup", PasteCleanupExtension());
|
|
135
|
+
add("pasteCleanup", PasteCleanupExtension({ getInternalClipboardToken }));
|
|
128
136
|
add("pasteStyleInliner", PasteStyleInlinerExtension());
|
|
129
137
|
add("list", ListExtension());
|
|
130
138
|
add("baseKeymap", BaseKeymapExtension());
|
|
@@ -9,12 +9,16 @@ const autoBidiDetectionKey = new PluginKey("autoBidiDetection");
|
|
|
9
9
|
const paragraphDirectionalText = (node) => {
|
|
10
10
|
let text = "";
|
|
11
11
|
node.descendants((child) => {
|
|
12
|
+
if (child.marks.some((mark) => mark.type.name === "deletion")) return false;
|
|
12
13
|
if (child.isText) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const display = child.attrs["displayText"];
|
|
16
|
-
if (typeof display === "string") text += display;
|
|
14
|
+
text += child.text ?? "";
|
|
15
|
+
return false;
|
|
17
16
|
}
|
|
17
|
+
if (child.isLeaf && child.textContent) {
|
|
18
|
+
text += child.textContent;
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
18
22
|
});
|
|
19
23
|
return text;
|
|
20
24
|
};
|
|
@@ -14,6 +14,9 @@ import { Extension } from "../types.js";
|
|
|
14
14
|
* 2. `Mod-Alt-v` — "paste without formatting", inserting clipboard text with
|
|
15
15
|
* the source formatting stripped (see {@link pasteWithoutFormatting}).
|
|
16
16
|
*/
|
|
17
|
-
|
|
17
|
+
type PasteCleanupOptions = {
|
|
18
|
+
getInternalClipboardToken?: () => string;
|
|
19
|
+
};
|
|
20
|
+
declare const PasteCleanupExtension: (options?: Partial<PasteCleanupOptions> | undefined) => Extension;
|
|
18
21
|
//#endregion
|
|
19
22
|
export { PasteCleanupExtension };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { pasteWithoutFormatting } from "../../commands/pastePlainText.js";
|
|
2
2
|
import { createExtension } from "../create.js";
|
|
3
3
|
import { Priority } from "../types.js";
|
|
4
|
-
import { cleanPastedHtml } from "./pasteCleanup.js";
|
|
4
|
+
import { cleanPastedHtml, removeUnpairedBookmarkBoundaries } from "./pasteCleanup.js";
|
|
5
5
|
import { Plugin } from "prosemirror-state";
|
|
6
6
|
//#region src/prosemirror/extensions/features/PasteCleanupExtension.ts
|
|
7
7
|
/**
|
|
@@ -21,11 +21,15 @@ import { Plugin } from "prosemirror-state";
|
|
|
21
21
|
const PasteCleanupExtension = createExtension({
|
|
22
22
|
name: "pasteCleanup",
|
|
23
23
|
priority: Priority.Highest,
|
|
24
|
-
onSchemaReady() {
|
|
24
|
+
onSchemaReady(_context, options) {
|
|
25
25
|
return {
|
|
26
|
-
plugins: [new Plugin({ props: {
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
plugins: [new Plugin({ props: {
|
|
27
|
+
transformPastedHTML(html) {
|
|
28
|
+
const internalClipboardToken = options.getInternalClipboardToken?.();
|
|
29
|
+
return cleanPastedHtml(html, { ...internalClipboardToken ? { internalClipboardToken } : {} });
|
|
30
|
+
},
|
|
31
|
+
transformPasted: removeUnpairedBookmarkBoundaries
|
|
32
|
+
} })],
|
|
29
33
|
keyboardShortcuts: { "Mod-Alt-v": pasteWithoutFormatting }
|
|
30
34
|
};
|
|
31
35
|
}
|
|
@@ -1,31 +1,18 @@
|
|
|
1
|
+
import { Slice } from "prosemirror-model";
|
|
1
2
|
//#region src/prosemirror/extensions/features/pasteCleanup.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Office / web paste cleanup
|
|
4
|
-
*
|
|
5
|
-
* Content pasted from word processors and web pages arrives wrapped in a large
|
|
6
|
-
* amount of producer-specific cruft: conditional comments, XML processing
|
|
7
|
-
* instructions, namespaced markup (`<o:p>`, `<w:sdt>`, smart tags), `mso-*`
|
|
8
|
-
* style declarations, and empty spans. None of it maps to the editor schema,
|
|
9
|
-
* and some of it confuses the browser HTML parser that ProseMirror's clipboard
|
|
10
|
-
* pipeline relies on. Producer class names (`MsoNormal`, ...) are deliberately
|
|
11
|
-
* kept so the downstream style inliner can match `<style>` rules against them.
|
|
12
|
-
*
|
|
13
|
-
* `cleanPastedHtml` normalizes the raw clipboard HTML string into something the
|
|
14
|
-
* schema's `parseDOM` rules can read cleanly. It is a pure string transform so
|
|
15
|
-
* it runs in the editor and in tests without a DOM, and it is deliberately
|
|
16
|
-
* conservative: it strips producer metadata but never rewrites visible text
|
|
17
|
-
* (curly quotes, non-Latin scripts, and whitespace between words are left
|
|
18
|
-
* untouched, since this editor targets an international, typography-sensitive
|
|
19
|
-
* audience).
|
|
20
|
-
*/
|
|
21
3
|
/**
|
|
22
4
|
* Strip Office/web producer cruft from a raw clipboard HTML string.
|
|
23
5
|
*
|
|
24
|
-
* Best-effort and non-throwing: any unexpected failure returns
|
|
25
|
-
*
|
|
6
|
+
* Best-effort and non-throwing: any unexpected failure returns empty markup so
|
|
7
|
+
* reconstruction capabilities and other untrusted attributes fail closed.
|
|
26
8
|
* `<style>` blocks are intentionally left in place for the downstream style
|
|
27
9
|
* inliner, which resolves class-based CSS before the schema parser runs.
|
|
28
10
|
*/
|
|
29
|
-
|
|
11
|
+
type CleanPastedHtmlOptions = {
|
|
12
|
+
internalClipboardToken?: string;
|
|
13
|
+
};
|
|
14
|
+
declare function cleanPastedHtml(html: string, options?: CleanPastedHtmlOptions): string;
|
|
15
|
+
/** Remove incomplete or duplicate bookmark pairs at copied slice edges. */
|
|
16
|
+
declare function removeUnpairedBookmarkBoundaries(slice: Slice): Slice;
|
|
30
17
|
//#endregion
|
|
31
|
-
export { cleanPastedHtml };
|
|
18
|
+
export { cleanPastedHtml, removeUnpairedBookmarkBoundaries };
|