@stll/folio-core 0.55.0 → 0.57.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/ai-edits/apply.js +214 -52
- package/dist/ai-edits/batch-claims.d.ts +3 -1
- package/dist/ai-edits/batch-claims.js +25 -1
- package/dist/ai-edits/headless.js +2 -2
- package/dist/ai-edits/table-row-column-mutations.js +17 -3
- package/dist/ai-edits/types.d.ts +7 -1
- package/dist/ai-suggestions/apply.js +20 -1
- package/dist/compare/compare.js +1 -0
- package/dist/compare/inline-atoms.js +40 -16
- package/dist/compare/inline-provenance.js +12 -5
- package/dist/compare/reproducible-package.d.ts +0 -17
- package/dist/compare/reproducible-package.js +12 -18
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/controller/canonicalClipboard.d.ts +23 -0
- package/dist/controller/canonicalClipboard.js +482 -0
- package/dist/controller/canonicalClipboardResources.d.ts +21 -0
- package/dist/controller/canonicalClipboardResources.js +382 -0
- package/dist/controller/canonicalComments.d.ts +41 -0
- package/dist/controller/canonicalComments.js +152 -0
- package/dist/controller/canonicalComposition.d.ts +24 -3
- package/dist/controller/canonicalComposition.js +208 -48
- package/dist/controller/canonicalInlineProjection.d.ts +118 -0
- package/dist/controller/canonicalInlineProjection.js +476 -0
- package/dist/controller/canonicalInput.d.ts +13 -4
- package/dist/controller/canonicalInput.js +62 -14
- package/dist/controller/canonicalInputTimer.d.ts +16 -0
- package/dist/controller/canonicalInputTimer.js +34 -0
- package/dist/controller/canonicalPublicOperations.d.ts +48 -0
- package/dist/controller/canonicalPublicOperations.js +648 -0
- package/dist/controller/canonicalSelection.d.ts +18 -0
- package/dist/controller/canonicalSelection.js +32 -0
- package/dist/controller/canonicalSession.d.ts +27 -6
- package/dist/controller/canonicalSession.js +298 -116
- package/dist/controller/canonicalStoryEditor.d.ts +7 -3
- package/dist/controller/canonicalStoryEditor.js +27 -2
- package/dist/controller/canonicalStructure.js +57 -4
- package/dist/controller/canonicalTocSelection.d.ts +11 -0
- package/dist/controller/canonicalTocSelection.js +43 -0
- package/dist/controller/folioEditor.d.ts +2 -9
- package/dist/controller/folioEditor.js +18 -4
- package/dist/controller/headerFooterEditorManager.d.ts +2 -1
- package/dist/controller/headerFooterEditorManager.js +26 -11
- package/dist/controller/hiddenEditorApi.d.ts +24 -3
- package/dist/controller/hiddenEditorApi.js +8 -0
- package/dist/controller/hiddenEditorManager.d.ts +5 -1
- package/dist/controller/hiddenEditorManager.js +378 -43
- package/dist/controller/noteEditorManager.d.ts +2 -1
- package/dist/controller/noteEditorManager.js +29 -13
- package/dist/document-operations.d.ts +8 -1
- package/dist/document-operations.js +6 -4
- package/dist/docx/blockPlainText.d.ts +1 -1
- package/dist/docx/blockPlainText.js +11 -3
- package/dist/docx/builtInStyles.js +13 -6
- package/dist/docx/canonicalResourceSave.d.ts +16 -0
- package/dist/docx/canonicalResourceSave.js +27 -0
- package/dist/docx/canonicalSave.d.ts +29 -0
- package/dist/docx/canonicalSave.js +101 -0
- package/dist/docx/canonicalStoryRepack.d.ts +1 -1
- package/dist/docx/canonicalStoryRepack.js +38 -5
- package/dist/docx/containerChildren.gen.d.ts +3 -1
- package/dist/docx/containerChildren.gen.js +33 -1
- package/dist/docx/documentParser.d.ts +1 -13
- package/dist/docx/documentParser.js +1 -47
- package/dist/docx/ensureParaIds.js +10 -4
- package/dist/docx/fieldParser.js +14 -2
- package/dist/docx/footnoteParser.d.ts +1 -11
- package/dist/docx/footnoteParser.js +1 -16
- package/dist/docx/headerFooterParser.d.ts +1 -9
- package/dist/docx/headerFooterParser.js +1 -12
- package/dist/docx/headerFooterVerbatim.d.ts +26 -1
- package/dist/docx/headerFooterVerbatim.js +81 -3
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/hyperlinkParser.js +20 -1
- package/dist/docx/imageParser.d.ts +13 -1
- package/dist/docx/imageParser.js +20 -11
- package/dist/docx/inlineWrapperContent.d.ts +4 -4
- package/dist/docx/inlineWrapperContent.js +4 -4
- package/dist/docx/linkedSdtPreservation.d.ts +10 -0
- package/dist/docx/linkedSdtPreservation.js +37 -0
- package/dist/docx/metadataPrivacy.js +6 -1
- package/dist/docx/packageParts.js +9 -3
- package/dist/docx/paragraphParser.js +88 -67
- package/dist/docx/paragraphPropertySource.d.ts +22 -1
- package/dist/docx/paragraphPropertySource.js +109 -2
- package/dist/docx/parser.js +2 -1
- package/dist/docx/preservedRunContent.js +2 -1
- package/dist/docx/relsParser.js +26 -2
- package/dist/docx/removeHeaderFooterParts.js +17 -6
- package/dist/docx/rezip.d.ts +49 -5
- package/dist/docx/rezip.js +754 -235
- package/dist/docx/saveDiagnostics.d.ts +11 -0
- package/dist/docx/selectiveSave.d.ts +2 -1
- package/dist/docx/selectiveSave.js +42 -11
- package/dist/docx/selectiveXmlPatch.js +7 -5
- package/dist/docx/serializer/commentSerializer.d.ts +4 -1
- package/dist/docx/serializer/commentSerializer.js +7 -3
- package/dist/docx/serializer/documentSerializer.d.ts +9 -2
- package/dist/docx/serializer/documentSerializer.js +29 -10
- package/dist/docx/serializer/paragraphSerializer.js +207 -94
- package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
- package/dist/docx/server/materializeYjsDocx.js +14 -6
- package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
- package/dist/docx/storyBlockReplay.d.ts +21 -1
- package/dist/docx/storyBlockReplay.js +113 -9
- package/dist/docx/storyPlainText.d.ts +20 -0
- package/dist/docx/storyPlainText.js +23 -0
- package/dist/docx/structuralXmlPatch.js +10 -22
- package/dist/docx/styleParser.d.ts +5 -1
- package/dist/docx/styleParser.js +1 -1
- package/dist/docx/tableParser.d.ts +1 -8
- package/dist/docx/tableParser.js +1 -28
- package/dist/docx/textBoxParser.d.ts +1 -5
- package/dist/docx/textBoxParser.js +1 -20
- package/dist/docx/unzip.js +6 -1
- package/dist/i18n/messages/ar.gen.js +4 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
- package/dist/i18n/messages/catalogs.gen.js +68 -0
- package/dist/i18n/messages/cs.gen.js +4 -0
- package/dist/i18n/messages/de.gen.js +4 -0
- package/dist/i18n/messages/en.gen.js +4 -0
- package/dist/i18n/messages/es.gen.js +4 -0
- package/dist/i18n/messages/et.gen.js +4 -0
- package/dist/i18n/messages/fr.gen.js +4 -0
- package/dist/i18n/messages/he.gen.js +4 -0
- package/dist/i18n/messages/hi.gen.js +4 -0
- package/dist/i18n/messages/hu.gen.js +4 -0
- package/dist/i18n/messages/lt.gen.js +4 -0
- package/dist/i18n/messages/lv.gen.js +4 -0
- package/dist/i18n/messages/messages.gen.d.ts +4 -0
- package/dist/i18n/messages/pl.gen.js +4 -0
- package/dist/i18n/messages/pt-BR.gen.js +4 -0
- package/dist/i18n/messages/sk.gen.js +4 -0
- package/dist/i18n/messages/tr.gen.js +4 -0
- package/dist/i18n/messages/zh-CN.gen.js +4 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/acceptedBlockProjection.d.ts +12 -0
- package/dist/internal/acceptedBlockProjection.js +45 -0
- package/dist/internal/revisionResolutionInline.js +25 -3
- package/dist/managers/DocumentLoaderManager.js +2 -1
- package/dist/markdown/escape.d.ts +3 -1
- package/dist/markdown/escape.js +9 -2
- package/dist/markdown/renderBlock.js +5 -120
- package/dist/markdown/renderParagraph.js +4 -2
- package/dist/markdown/renderRuns.d.ts +7 -1
- package/dist/markdown/renderRuns.js +33 -24
- package/dist/panel-layout.d.ts +11 -9
- package/dist/panel-layout.js +13 -9
- package/dist/prosemirror/addTrackedDeletionMark.d.ts +18 -0
- package/dist/prosemirror/addTrackedDeletionMark.js +87 -0
- package/dist/prosemirror/attrs/index.js +5 -0
- package/dist/prosemirror/canonicalCommands.d.ts +28 -4
- package/dist/prosemirror/canonicalCommands.js +11 -4
- package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
- package/dist/prosemirror/canonicalSelectionRange.js +15 -0
- package/dist/prosemirror/clipboardIntent.d.ts +7 -0
- package/dist/prosemirror/clipboardIntent.js +9 -0
- package/dist/prosemirror/commands/comments.js +60 -35
- package/dist/prosemirror/commands/pageBreak.js +2 -2
- package/dist/prosemirror/commands/pastePlainText.js +2 -1
- package/dist/prosemirror/commands/propertyChangeScope.js +3 -6
- package/dist/prosemirror/commands/resolveParagraphProperties.js +22 -13
- package/dist/prosemirror/commentOps.js +15 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +22 -3
- package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
- package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
- package/dist/prosemirror/conversion/toProseDoc.js +124 -22
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +61 -35
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +74 -25
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +11 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +65 -29
- package/dist/prosemirror/extensions/marks/markUtils.js +11 -8
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
- package/dist/prosemirror/fieldRepresentation.d.ts +8 -0
- package/dist/prosemirror/fieldRepresentation.js +18 -0
- package/dist/prosemirror/hyperlinkRemoval.d.ts +13 -1
- package/dist/prosemirror/hyperlinkRemoval.js +28 -9
- package/dist/prosemirror/insertOperations.js +2 -1
- package/dist/prosemirror/listNumbering.js +11 -5
- package/dist/prosemirror/noteReferenceOccurrenceId.d.ts +5 -0
- package/dist/prosemirror/noteReferenceOccurrenceId.js +5 -0
- package/dist/prosemirror/noteReferenceOccurrences.d.ts +21 -0
- package/dist/prosemirror/noteReferenceOccurrences.js +185 -0
- package/dist/prosemirror/noteReferenceReview.js +14 -1
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
- package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
- package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
- package/dist/prosemirror/plugins/documentStyles.js +17 -10
- package/dist/prosemirror/plugins/suggestionMode.js +48 -48
- package/dist/prosemirror/preservedXmlReview.d.ts +6 -0
- package/dist/prosemirror/preservedXmlReview.js +35 -0
- package/dist/prosemirror/runFormattingFromMarks.js +2 -2
- package/dist/prosemirror/runFormattingReconciliation.js +5 -4
- package/dist/prosemirror/runPropertyChangeResolution.d.ts +8 -1
- package/dist/prosemirror/runPropertyChangeResolution.js +24 -2
- package/dist/prosemirror/runStyleFormatting.d.ts +3 -1
- package/dist/prosemirror/runStyleFormatting.js +3 -1
- package/dist/prosemirror/schema/marks.d.ts +1 -0
- package/dist/prosemirror/schema/nodes.d.ts +2 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.js +4 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +15 -15
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +69 -28
- package/dist/prosemirror/textInput.d.ts +5 -1
- package/dist/prosemirror/textInput.js +3 -3
- package/dist/prosemirror/trackedRevisionPath.d.ts +5 -1
- package/dist/prosemirror/trackedRevisionPath.js +39 -1
- package/dist/prosemirror/validation.js +3 -5
- package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
- package/dist/prosemirror/yjsDocumentMetadata.js +37 -8
- package/dist/types/canonicalCapabilities.d.ts +201 -0
- package/dist/types/canonicalCapabilities.js +198 -0
- package/dist/types/canonicalComments.d.ts +51 -0
- package/dist/types/canonicalComments.js +0 -0
- package/dist/types/canonicalSave.d.ts +11 -0
- package/dist/types/canonicalSave.js +0 -0
- package/dist/types/canonicalSections.d.ts +12 -0
- package/dist/types/canonicalSections.js +0 -0
- package/dist/types/docxSerialization.d.ts +14 -0
- package/dist/types/docxSerialization.js +7 -0
- package/dist/utils/headingCollector.js +45 -4
- package/dist/utils/outlineDepth.d.ts +9 -0
- package/dist/utils/outlineDepth.js +9 -0
- package/package.json +4 -4
package/dist/markdown/escape.js
CHANGED
|
@@ -30,8 +30,15 @@ function escapeInline(text) {
|
|
|
30
30
|
* line.
|
|
31
31
|
*/
|
|
32
32
|
function escapeTableCell(text) {
|
|
33
|
-
return text.replace(/\|/gu, "|")
|
|
33
|
+
return inlineBreaksToHtml(text.replace(/\|/gu, "|"));
|
|
34
34
|
}
|
|
35
|
+
/** Single-line Markdown blocks express inline breaks without their two-space syntax. */
|
|
36
|
+
const inlineBreaksToHtml = (text) => text.split(/\r?\n/u).map((line, index, lines) => {
|
|
37
|
+
if (index === lines.length - 1) return line;
|
|
38
|
+
let end = line.length;
|
|
39
|
+
while (end > 0 && line.at(end - 1) === " ") end--;
|
|
40
|
+
return line.slice(0, end);
|
|
41
|
+
}).join("<br>");
|
|
35
42
|
/**
|
|
36
43
|
* Hyperlink URLs in inline form need parens balanced; we URL-encode the
|
|
37
44
|
* problematic characters rather than escape, so the link still resolves.
|
|
@@ -55,4 +62,4 @@ function escapeAltText(text) {
|
|
|
55
62
|
return text.replace(/(?<ch>[\\[\]])/gu, "\\$<ch>").replace(/\r?\n/gu, " ");
|
|
56
63
|
}
|
|
57
64
|
//#endregion
|
|
58
|
-
export { escapeAltText, escapeInline, escapeLinkUrl, escapeTableCell };
|
|
65
|
+
export { escapeAltText, escapeInline, escapeLinkUrl, escapeTableCell, inlineBreaksToHtml };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ALT_CHUNK_READER_DIAGNOSTIC, isAltChunkMarkup } from "../docx/altChunk.js";
|
|
2
2
|
import { OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC, isOpaqueNestedRowMarkup, opaqueRevisionCarrierName } from "../docx/opaqueCarrier.js";
|
|
3
|
-
import {
|
|
3
|
+
import { projectAcceptedBlocks } from "../internal/acceptedBlockProjection.js";
|
|
4
|
+
import { pushWarning } from "./internals.js";
|
|
4
5
|
import { renderParagraphBlock } from "./renderParagraph.js";
|
|
5
6
|
import { renderTable } from "./renderTable.js";
|
|
6
7
|
import { panic } from "better-result";
|
|
@@ -10,130 +11,14 @@ import { panic } from "better-result";
|
|
|
10
11
|
* markdown for each block, suppressing redundant blank lines between list items
|
|
11
12
|
* of the same list. Ported from eigenpal/docx-editor PR #595.
|
|
12
13
|
*/
|
|
13
|
-
/**
|
|
14
|
-
* In `trackedChanges: "clean"` mode every change is accepted, as the editor's
|
|
15
|
-
* accept-all resolves the story (`internal/wholeStoryRevisionResolution.ts`).
|
|
16
|
-
*
|
|
17
|
-
* A paragraph whose mark is pending deletion loses its break on accept and
|
|
18
|
-
* runs on into the paragraph after it, which is the paragraph left: its mark
|
|
19
|
-
* ends the joined text, and a paragraph's properties (style, list) live on its
|
|
20
|
-
* mark. A run of consecutive deletions collapses into that last paragraph.
|
|
21
|
-
*
|
|
22
|
-
* With a table right after it, its words run on into the table's first cell
|
|
23
|
-
* and lead that cell's first paragraph (`prosemirror/tableRunIn.ts`), unless
|
|
24
|
-
* it ends a section, keeps nothing once accepted, or that cell is pending.
|
|
25
|
-
* Otherwise a paragraph that cannot join keeps its place, or goes when it
|
|
26
|
-
* keeps nothing and something follows it.
|
|
27
|
-
*/
|
|
28
|
-
function mergeAcceptedParagraphBreaks(blocks) {
|
|
29
|
-
const reversed = [];
|
|
30
|
-
let survivor = null;
|
|
31
|
-
let tableFollows = false;
|
|
32
|
-
let followed = false;
|
|
33
|
-
const flush = () => {
|
|
34
|
-
if (survivor) reversed.push(survivor);
|
|
35
|
-
survivor = null;
|
|
36
|
-
};
|
|
37
|
-
for (let index = blocks.length - 1; index >= 0; index--) {
|
|
38
|
-
const block = blocks[index];
|
|
39
|
-
if (!block) continue;
|
|
40
|
-
if (block.type !== "paragraph") {
|
|
41
|
-
flush();
|
|
42
|
-
reversed.push(block);
|
|
43
|
-
tableFollows = block.type === "table";
|
|
44
|
-
followed ||= tableFollows;
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
const goes = block.pPrMark?.kind === "del" || block.pPrMark?.kind === "moveFrom";
|
|
48
|
-
if (goes && survivor) {
|
|
49
|
-
survivor = cloneParagraphWithoutPropertySource(survivor, { content: [...block.content, ...survivor.content] });
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
const table = reversed.at(-1);
|
|
53
|
-
if (goes && tableFollows && table?.type === "table") {
|
|
54
|
-
const ranIn = tableWithParagraphRunIn(table, block);
|
|
55
|
-
if (ranIn) {
|
|
56
|
-
reversed[reversed.length - 1] = ranIn;
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
flush();
|
|
61
|
-
tableFollows = false;
|
|
62
|
-
if (goes && holdsNothingOnAccept(block) && followed && index + reversed.length > 0) continue;
|
|
63
|
-
survivor = block;
|
|
64
|
-
followed = true;
|
|
65
|
-
}
|
|
66
|
-
flush();
|
|
67
|
-
return reversed.reverse();
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Whether the cell a paragraph's words would run into is itself pending (its
|
|
71
|
-
* row or the cell, through nested tables' first cells), as
|
|
72
|
-
* `prosemirror/tableRunIn.ts` reads it.
|
|
73
|
-
*/
|
|
74
|
-
const runInCellPending = (table) => {
|
|
75
|
-
const row = table.rows[0];
|
|
76
|
-
const cell = row?.cells[0];
|
|
77
|
-
if (!row || !cell) return false;
|
|
78
|
-
if (row.structuralChange !== void 0 || cell.structuralChange !== void 0) return true;
|
|
79
|
-
const first = cell.content[0];
|
|
80
|
-
return first?.type === "table" && runInCellPending(first);
|
|
81
|
-
};
|
|
82
|
-
/**
|
|
83
|
-
* `table` with `paragraph`'s words leading its first cell's first paragraph,
|
|
84
|
-
* descending into nested tables, or null when the paragraph keeps its place.
|
|
85
|
-
*/
|
|
86
|
-
const tableWithParagraphRunIn = (table, paragraph) => {
|
|
87
|
-
if (paragraph.sectionProperties !== void 0 || holdsNothingOnAccept(paragraph)) return null;
|
|
88
|
-
if (runInCellPending(table)) return null;
|
|
89
|
-
const runIn = (current) => {
|
|
90
|
-
const [row, ...rows] = current.rows;
|
|
91
|
-
const [cell, ...cells] = row?.cells ?? [];
|
|
92
|
-
const [first, ...rest] = cell?.content ?? [];
|
|
93
|
-
if (!row || !cell || !first) return null;
|
|
94
|
-
let led = null;
|
|
95
|
-
if (first.type === "paragraph") led = cloneParagraphWithoutPropertySource(first, { content: [...paragraph.content, ...first.content] });
|
|
96
|
-
else if (first.type === "table") led = runIn(first);
|
|
97
|
-
if (!led) return null;
|
|
98
|
-
return {
|
|
99
|
-
...current,
|
|
100
|
-
rows: [{
|
|
101
|
-
...row,
|
|
102
|
-
cells: [{
|
|
103
|
-
...cell,
|
|
104
|
-
content: [led, ...rest]
|
|
105
|
-
}, ...cells]
|
|
106
|
-
}, ...rows]
|
|
107
|
-
};
|
|
108
|
-
};
|
|
109
|
-
return runIn(table);
|
|
110
|
-
};
|
|
111
|
-
/** Paragraph content that shows nothing: range boundaries and anchors. */
|
|
112
|
-
const ZERO_WIDTH_CONTENT = /* @__PURE__ */ new Set([
|
|
113
|
-
"bookmarkStart",
|
|
114
|
-
"bookmarkEnd",
|
|
115
|
-
"commentRangeStart",
|
|
116
|
-
"commentRangeEnd",
|
|
117
|
-
"commentReference",
|
|
118
|
-
"moveFromRangeStart",
|
|
119
|
-
"moveFromRangeEnd",
|
|
120
|
-
"moveToRangeStart",
|
|
121
|
-
"moveToRangeEnd"
|
|
122
|
-
]);
|
|
123
|
-
/** Whether an item shows nothing once every change is accepted. */
|
|
124
|
-
const showsNothingOnAccept = (item) => {
|
|
125
|
-
if (item.type === "deletion" || item.type === "moveFrom" || ZERO_WIDTH_CONTENT.has(item.type)) return true;
|
|
126
|
-
if (item.type === "insertion" || item.type === "moveTo") return item.content.every(showsNothingOnAccept);
|
|
127
|
-
return item.type === "run" && item.content.every((content) => content.type === "renderedPageBreak");
|
|
128
|
-
};
|
|
129
|
-
/** Whether a paragraph keeps no visible content once every change is accepted. */
|
|
130
|
-
const holdsNothingOnAccept = (paragraph) => paragraph.content.every(showsNothingOnAccept);
|
|
131
14
|
function renderBlocks(ctx, pkg, blocks) {
|
|
132
15
|
const outerListIndentWidths = ctx.listIndentWidths;
|
|
133
16
|
ctx.listIndentWidths = [];
|
|
134
17
|
const out = [];
|
|
135
18
|
let prevWasListItem = false;
|
|
136
|
-
const
|
|
19
|
+
const projection = ctx.opts.trackedChanges === "clean" ? projectAcceptedBlocks(blocks, pkg) : null;
|
|
20
|
+
if (projection?.completeness === "partial") pushWarning(ctx, "Some tracked structural changes could not be resolved.");
|
|
21
|
+
const ordered = projection?.blocks ?? blocks;
|
|
137
22
|
for (const block of ordered) switch (block.type) {
|
|
138
23
|
case "paragraph": {
|
|
139
24
|
const { markdown: md, isListItem } = renderParagraphBlock(ctx, pkg, block);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isQuoteStyle, resolveHeadingLevel } from "../docx/builtInStyles.js";
|
|
2
2
|
import { listLabelAttrsFromRendering } from "../prosemirror/listLabels.js";
|
|
3
|
+
import { inlineBreaksToHtml } from "./escape.js";
|
|
3
4
|
import { renderParagraphInline } from "./renderRuns.js";
|
|
4
5
|
//#region src/markdown/renderParagraph.ts
|
|
5
6
|
/**
|
|
@@ -37,13 +38,14 @@ function renderParagraphBlock(ctx, pkg, para) {
|
|
|
37
38
|
const headingLevel = markdownHeadingLevel(ctx, para);
|
|
38
39
|
if (headingLevel !== void 0) {
|
|
39
40
|
ctx.listIndentWidths = [];
|
|
40
|
-
if (!inline) return {
|
|
41
|
+
if (!inline || !inline.trim() && label === void 0) return {
|
|
41
42
|
markdown: "",
|
|
42
43
|
isListItem: false
|
|
43
44
|
};
|
|
44
45
|
const hashes = "#".repeat(Math.min(MAX_MARKDOWN_HEADING_LEVEL, headingLevel + 1));
|
|
46
|
+
const headingInline = inlineBreaksToHtml(inline);
|
|
45
47
|
return {
|
|
46
|
-
markdown: label ? `${hashes} ${label} ${
|
|
48
|
+
markdown: label ? `${hashes} ${label} ${headingInline}` : `${hashes} ${headingInline}`,
|
|
47
49
|
isListItem: false
|
|
48
50
|
};
|
|
49
51
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
import { RenderContext } from "./types.js";
|
|
3
3
|
//#region src/markdown/renderRuns.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Inline marks we recognize. Order matters: we open from outermost to innermost
|
|
6
|
+
* so the output reads cleanly (`***bold italic***`), not the reverse.
|
|
7
|
+
*/
|
|
8
|
+
type MarkKey = "bold" | "italic" | "code" | "strike";
|
|
9
|
+
declare function applyMarks(text: string, marks: readonly MarkKey[]): string;
|
|
4
10
|
/**
|
|
5
11
|
* The character beside a run's delimiters: `""` at the paragraph's edge,
|
|
6
12
|
* `undefined` when it cannot be told (read as a letter, the strictest case).
|
|
@@ -16,4 +22,4 @@ type RunNeighbors = {
|
|
|
16
22
|
*/
|
|
17
23
|
declare function renderParagraphInline(ctx: RenderContext, pkg: document_d_exports.DocxPackage | undefined, content: readonly document_d_exports.ParagraphContent[], paraId: string | undefined, edges?: RunNeighbors): string;
|
|
18
24
|
//#endregion
|
|
19
|
-
export { renderParagraphInline };
|
|
25
|
+
export { applyMarks, renderParagraphInline };
|
|
@@ -40,22 +40,32 @@ function marksFor(run) {
|
|
|
40
40
|
if (ascii && MONOSPACE_FONTS.has(ascii)) out.push("code");
|
|
41
41
|
return out;
|
|
42
42
|
}
|
|
43
|
+
const splitEdgeWhitespace = (text) => {
|
|
44
|
+
const start = text.length - text.trimStart().length;
|
|
45
|
+
const end = text.trimEnd().length;
|
|
46
|
+
return {
|
|
47
|
+
leading: text.slice(0, start),
|
|
48
|
+
core: text.slice(start, Math.max(start, end)),
|
|
49
|
+
trailing: text.slice(Math.max(start, end))
|
|
50
|
+
};
|
|
51
|
+
};
|
|
43
52
|
function applyMarks(text, marks) {
|
|
44
|
-
|
|
53
|
+
const { leading, core, trailing } = splitEdgeWhitespace(text);
|
|
54
|
+
if (!core || marks.length === 0) return text;
|
|
45
55
|
if (marks.includes("code")) {
|
|
46
|
-
const literal =
|
|
56
|
+
const literal = core.replace(/\\(?<char>[\\`*[\]_<~])/gu, "$<char>");
|
|
47
57
|
let longestRun = 0;
|
|
48
58
|
for (const m of literal.matchAll(/`+/gu)) longestRun = Math.max(longestRun, m[0].length);
|
|
49
59
|
const fence = "`".repeat(longestRun + 1);
|
|
50
60
|
const pad = literal.startsWith("`") || literal.endsWith("`") ? " " : "";
|
|
51
|
-
return `${fence}${pad}${literal}${pad}${fence}`;
|
|
61
|
+
return `${leading}${fence}${pad}${literal}${pad}${fence}${trailing}`;
|
|
52
62
|
}
|
|
53
|
-
let out =
|
|
63
|
+
let out = core;
|
|
54
64
|
for (const m of marks) {
|
|
55
65
|
const d = MARK_DELIMS[m];
|
|
56
66
|
out = `${d}${out}${d}`;
|
|
57
67
|
}
|
|
58
|
-
return out
|
|
68
|
+
return `${leading}${out}${trailing}`;
|
|
59
69
|
}
|
|
60
70
|
const UNKNOWN_NEIGHBORS = {
|
|
61
71
|
before: void 0,
|
|
@@ -250,11 +260,8 @@ function pieceOf(ctx, pkg, run, paraId) {
|
|
|
250
260
|
text: inner,
|
|
251
261
|
marks: new Set(marks)
|
|
252
262
|
};
|
|
253
|
-
const leadLen = inner.length - inner.trimStart().length;
|
|
254
|
-
const trailLen = inner.length - inner.trimEnd().length;
|
|
255
|
-
const core = inner.slice(leadLen, inner.length - trailLen);
|
|
256
263
|
return {
|
|
257
|
-
text:
|
|
264
|
+
text: inner.split("\n").map((line) => applyMarks(line, marks)).join("\n"),
|
|
258
265
|
marks: /* @__PURE__ */ new Set()
|
|
259
266
|
};
|
|
260
267
|
}
|
|
@@ -346,6 +353,8 @@ function renderHyperlink(ctx, pkg, link, paraId) {
|
|
|
346
353
|
after: "]"
|
|
347
354
|
} : UNKNOWN_NEIGHBORS);
|
|
348
355
|
if (!inner) return "";
|
|
356
|
+
const { leading, core, trailing } = splitEdgeWhitespace(inner);
|
|
357
|
+
if (!core) return inner;
|
|
349
358
|
const href = link.href ?? (link.anchor ? `#${link.anchor}` : "");
|
|
350
359
|
if (!href) {
|
|
351
360
|
pushWarning(ctx, "hyperlink missing href and anchor; rendered as plain text");
|
|
@@ -357,9 +366,9 @@ function renderHyperlink(ctx, pkg, link, paraId) {
|
|
|
357
366
|
href,
|
|
358
367
|
refNumber
|
|
359
368
|
});
|
|
360
|
-
return
|
|
369
|
+
return `${leading}[${core}][${refNumber}]${trailing}`;
|
|
361
370
|
}
|
|
362
|
-
return
|
|
371
|
+
return `${leading}[${core}](${escapeLinkUrl(href)})${trailing}`;
|
|
363
372
|
}
|
|
364
373
|
function renderTrackedWrapper(ctx, pkg, wrapper, paraId) {
|
|
365
374
|
const renderChild = (child) => {
|
|
@@ -419,6 +428,16 @@ function renderTrackedWrapper(ctx, pkg, wrapper, paraId) {
|
|
|
419
428
|
default: return wrapMoveTo(ctx, wrapper.info, inner);
|
|
420
429
|
}
|
|
421
430
|
}
|
|
431
|
+
/** Clean revisions have no inline boundary; group their runs with surrounding runs. */
|
|
432
|
+
const cleanRevisionContent = (content) => content.flatMap((item) => {
|
|
433
|
+
switch (item.type) {
|
|
434
|
+
case "insertion":
|
|
435
|
+
case "moveTo": return cleanRevisionContent(item.content);
|
|
436
|
+
case "deletion":
|
|
437
|
+
case "moveFrom": return [];
|
|
438
|
+
default: return [item];
|
|
439
|
+
}
|
|
440
|
+
});
|
|
422
441
|
/**
|
|
423
442
|
* Render the full inline content of a paragraph, tracking comment-range
|
|
424
443
|
* boundaries to apply the configured wrapper.
|
|
@@ -429,7 +448,7 @@ function renderParagraphInline(ctx, pkg, content, paraId, edges = {
|
|
|
429
448
|
}) {
|
|
430
449
|
let out = "";
|
|
431
450
|
const openComments = [];
|
|
432
|
-
const items = content.filter((item) => !SILENT_MARKERS.has(item.type) && !(ctx.opts.comments === "strip" && COMMENT_MARKERS.has(item.type)));
|
|
451
|
+
const items = (ctx.opts.trackedChanges === "clean" ? cleanRevisionContent(content) : content).filter((item) => !SILENT_MARKERS.has(item.type) && !(ctx.opts.comments === "strip" && COMMENT_MARKERS.has(item.type)));
|
|
433
452
|
const around = (index) => {
|
|
434
453
|
const next = items[index + 1];
|
|
435
454
|
return {
|
|
@@ -471,17 +490,7 @@ function renderParagraphInline(ctx, pkg, content, paraId, edges = {
|
|
|
471
490
|
case "simpleField":
|
|
472
491
|
case "complexField": {
|
|
473
492
|
const runs = item.type === "simpleField" ? item.content : item.fieldResult;
|
|
474
|
-
for (const child of runs)
|
|
475
|
-
if (child.type === "run") {
|
|
476
|
-
out += renderRuns(ctx, pkg, [child], paraId);
|
|
477
|
-
continue;
|
|
478
|
-
}
|
|
479
|
-
if (child.type === "hyperlink") {
|
|
480
|
-
out += renderHyperlink(ctx, pkg, child, paraId);
|
|
481
|
-
continue;
|
|
482
|
-
}
|
|
483
|
-
out += child.type === "inlineWrapper" ? renderParagraphInline(ctx, pkg, child.content, paraId, UNKNOWN_NEIGHBORS) : child.text;
|
|
484
|
-
}
|
|
493
|
+
for (const child of runs) out += child.type === "preservedInline" ? child.text : renderParagraphInline(ctx, pkg, [child], paraId, UNKNOWN_NEIGHBORS);
|
|
485
494
|
break;
|
|
486
495
|
}
|
|
487
496
|
case "inlineSdt":
|
|
@@ -557,4 +566,4 @@ function applyCommentWrapping(ctx, slot, current) {
|
|
|
557
566
|
}, inner);
|
|
558
567
|
}
|
|
559
568
|
//#endregion
|
|
560
|
-
export { renderParagraphInline };
|
|
569
|
+
export { applyMarks, renderParagraphInline };
|
package/dist/panel-layout.d.ts
CHANGED
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
*
|
|
6
6
|
* The editor measures the width it has once, and this module decides how
|
|
7
7
|
* each panel is presented. Every track the page shares the row with is
|
|
8
|
-
* counted here, so the page, the outline and the comments cannot overlap
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* counted here, so the page, the outline and the comments cannot overlap.
|
|
9
|
+
* Explicitly opening the outline gives it a clamped track beside the viewport;
|
|
10
|
+
* comments keep their existing column-or-drawer behavior.
|
|
11
11
|
*
|
|
12
12
|
* Space goes to the page first, then the outline rail, then the comments
|
|
13
13
|
* column, then the full outline column:
|
|
14
14
|
*
|
|
15
15
|
* - comments: a column when the page, the comments and the outline rail fit;
|
|
16
16
|
* otherwise a drawer.
|
|
17
|
-
* - outline: a column when it fits beside the page and
|
|
18
|
-
*
|
|
17
|
+
* - outline: a column when it fits beside the page and comments; otherwise a
|
|
18
|
+
* rail of heading ticks when that fits, or a toolbar toggle for the opened track.
|
|
19
19
|
*
|
|
20
20
|
* The tier names the result: `wide` when every panel has its full column,
|
|
21
21
|
* `medium` when the outline is a rail, `narrow` when a panel is a drawer.
|
|
@@ -29,6 +29,8 @@ declare const PANEL_METRICS: {
|
|
|
29
29
|
readonly outlineColumnWidth: 256;
|
|
30
30
|
/** The outline rail in the `medium` tier, border included. */
|
|
31
31
|
readonly outlineRailWidth: 32;
|
|
32
|
+
/** Minimum width and height of a shared panel control. */
|
|
33
|
+
readonly controlMinimumSize: 32;
|
|
32
34
|
/** A comment card column. */
|
|
33
35
|
readonly commentsWidth: 280;
|
|
34
36
|
/** Space between the page edge and the comment cards, and after them. */
|
|
@@ -41,8 +43,8 @@ declare const PANEL_METRICS: {
|
|
|
41
43
|
/** Width the comments take beside the page: gap, cards, gap. */
|
|
42
44
|
declare const COMMENTS_TRACK_WIDTH: number;
|
|
43
45
|
type PanelLayoutTier = "wide" | "medium" | "narrow";
|
|
44
|
-
/** How the outline is shown: a column,
|
|
45
|
-
type OutlinePresentation = "none" | "column" | "rail" | "drawer";
|
|
46
|
+
/** How the outline is shown: a column, tick rail, drawer, or explicitly opened track. */
|
|
47
|
+
type OutlinePresentation = "none" | "column" | "rail" | "drawer" | "expanded";
|
|
46
48
|
/** How the comments are shown: a column beside the page, a drawer, or not at all. */
|
|
47
49
|
type CommentsPresentation = "hidden" | "column" | "drawer";
|
|
48
50
|
type PanelLayoutInput = {
|
|
@@ -50,8 +52,8 @@ type PanelLayoutInput = {
|
|
|
50
52
|
availableWidth: number;
|
|
51
53
|
/** Width of the widest page at the current zoom. */
|
|
52
54
|
pageWidth: number;
|
|
53
|
-
/** Whether the document
|
|
54
|
-
outline: "absent" | "available";
|
|
55
|
+
/** Whether the document outline is absent, available, or explicitly opened. */
|
|
56
|
+
outline: "absent" | "available" | "expanded";
|
|
55
57
|
/** Whether the user (or the auto-open) wants the comments shown. */
|
|
56
58
|
comments: "closed" | "open";
|
|
57
59
|
};
|
package/dist/panel-layout.js
CHANGED
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
*
|
|
6
6
|
* The editor measures the width it has once, and this module decides how
|
|
7
7
|
* each panel is presented. Every track the page shares the row with is
|
|
8
|
-
* counted here, so the page, the outline and the comments cannot overlap
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* counted here, so the page, the outline and the comments cannot overlap.
|
|
9
|
+
* Explicitly opening the outline gives it a clamped track beside the viewport;
|
|
10
|
+
* comments keep their existing column-or-drawer behavior.
|
|
11
11
|
*
|
|
12
12
|
* Space goes to the page first, then the outline rail, then the comments
|
|
13
13
|
* column, then the full outline column:
|
|
14
14
|
*
|
|
15
15
|
* - comments: a column when the page, the comments and the outline rail fit;
|
|
16
16
|
* otherwise a drawer.
|
|
17
|
-
* - outline: a column when it fits beside the page and
|
|
18
|
-
*
|
|
17
|
+
* - outline: a column when it fits beside the page and comments; otherwise a
|
|
18
|
+
* rail of heading ticks when that fits, or a toolbar toggle for the opened track.
|
|
19
19
|
*
|
|
20
20
|
* The tier names the result: `wide` when every panel has its full column,
|
|
21
21
|
* `medium` when the outline is a rail, `narrow` when a panel is a drawer.
|
|
@@ -29,6 +29,8 @@ const PANEL_METRICS = {
|
|
|
29
29
|
outlineColumnWidth: 256,
|
|
30
30
|
/** The outline rail in the `medium` tier, border included. */
|
|
31
31
|
outlineRailWidth: 32,
|
|
32
|
+
/** Minimum width and height of a shared panel control. */
|
|
33
|
+
controlMinimumSize: 32,
|
|
32
34
|
/** A comment card column. */
|
|
33
35
|
commentsWidth: 280,
|
|
34
36
|
/** Space between the page edge and the comment cards, and after them. */
|
|
@@ -49,7 +51,7 @@ const pageTrackWidth = (pageWidth) => pageWidth + 2 * PANEL_METRICS.pageMargin;
|
|
|
49
51
|
const panelLayoutThresholds = ({ pageWidth, outline, comments }) => {
|
|
50
52
|
const page = pageTrackWidth(pageWidth);
|
|
51
53
|
const commentsTrack = comments === "open" ? COMMENTS_TRACK_WIDTH : 0;
|
|
52
|
-
const hasOutline = outline
|
|
54
|
+
const hasOutline = outline !== "absent";
|
|
53
55
|
return {
|
|
54
56
|
wide: page + commentsTrack + (hasOutline ? PANEL_METRICS.outlineColumnWidth : 0),
|
|
55
57
|
medium: page + commentsTrack + (hasOutline ? PANEL_METRICS.outlineRailWidth : 0)
|
|
@@ -62,7 +64,7 @@ const OUTLINE_TRACK_WIDTH = {
|
|
|
62
64
|
drawer: 0
|
|
63
65
|
};
|
|
64
66
|
const tierFor = (outline, comments) => {
|
|
65
|
-
if (outline === "drawer" || comments === "drawer") return "narrow";
|
|
67
|
+
if (outline === "drawer" || outline === "expanded" || comments === "drawer") return "narrow";
|
|
66
68
|
if (outline === "rail") return "medium";
|
|
67
69
|
return "wide";
|
|
68
70
|
};
|
|
@@ -73,11 +75,13 @@ const computePanelLayout = (input) => {
|
|
|
73
75
|
const page = pageTrackWidth(input.pageWidth);
|
|
74
76
|
const comments = (() => {
|
|
75
77
|
if (input.comments === "closed") return "hidden";
|
|
76
|
-
|
|
78
|
+
const requiredWidth = input.outline === "expanded" ? thresholds.wide : thresholds.medium;
|
|
79
|
+
return availableWidth >= requiredWidth ? "column" : "drawer";
|
|
77
80
|
})();
|
|
78
81
|
const commentsGutter = comments === "column" ? COMMENTS_TRACK_WIDTH : 0;
|
|
79
82
|
const outline = (() => {
|
|
80
83
|
if (input.outline === "absent") return "none";
|
|
84
|
+
if (input.outline === "expanded") return "expanded";
|
|
81
85
|
const beside = page + commentsGutter;
|
|
82
86
|
if (availableWidth >= thresholds.wide) return "column";
|
|
83
87
|
if (availableWidth >= beside + PANEL_METRICS.outlineRailWidth) return "rail";
|
|
@@ -87,7 +91,7 @@ const computePanelLayout = (input) => {
|
|
|
87
91
|
tier: tierFor(outline, comments),
|
|
88
92
|
outline,
|
|
89
93
|
comments,
|
|
90
|
-
outlineTrackWidth: OUTLINE_TRACK_WIDTH[outline],
|
|
94
|
+
outlineTrackWidth: outline === "expanded" ? Math.min(PANEL_METRICS.outlineColumnWidth, Math.max(PANEL_METRICS.controlMinimumSize, (availableWidth - commentsGutter) / 2)) : OUTLINE_TRACK_WIDTH[outline],
|
|
91
95
|
commentsGutter,
|
|
92
96
|
thresholds
|
|
93
97
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Mark } from "prosemirror-model";
|
|
2
|
+
import { Transform } from "prosemirror-transform";
|
|
3
|
+
//#region src/prosemirror/addTrackedDeletionMark.d.ts
|
|
4
|
+
type AddTrackedDeletionMarkOptions = {
|
|
5
|
+
tr: Transform;
|
|
6
|
+
from: number;
|
|
7
|
+
to: number;
|
|
8
|
+
mark: Mark;
|
|
9
|
+
insertionPolicy: "preserve-pending" | "retract-own";
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Already deleted runs keep their revision identity and enclosing insertion path.
|
|
13
|
+
* An own insertion containing deleted descendants is marked rather than retracted:
|
|
14
|
+
* removing its carrier would also remove another pending revision.
|
|
15
|
+
*/
|
|
16
|
+
declare const addTrackedDeletionMark: ({ tr, from, to, mark, insertionPolicy }: AddTrackedDeletionMarkOptions) => void;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { addTrackedDeletionMark };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { expectTrackedChangeMarkAttrs } from "./attrs/index.js";
|
|
2
|
+
import { trackedRevisionLayerOf } from "./trackedRevisionPath.js";
|
|
3
|
+
import { canCarryTrackedRunMark } from "./trackedRunInlineAtoms.js";
|
|
4
|
+
import { panic } from "better-result";
|
|
5
|
+
//#region src/prosemirror/addTrackedDeletionMark.ts
|
|
6
|
+
/**
|
|
7
|
+
* Already deleted runs keep their revision identity and enclosing insertion path.
|
|
8
|
+
* An own insertion containing deleted descendants is marked rather than retracted:
|
|
9
|
+
* removing its carrier would also remove another pending revision.
|
|
10
|
+
*/
|
|
11
|
+
const addTrackedDeletionMark = ({ tr, from, to, mark, insertionPolicy }) => {
|
|
12
|
+
if (mark.type.name !== "deletion") panic("A tracked deletion requires a deletion mark");
|
|
13
|
+
const preservedDeletions = [];
|
|
14
|
+
const protectedCarriers = /* @__PURE__ */ new Set();
|
|
15
|
+
tr.doc.nodesBetween(from, to, (node, position) => {
|
|
16
|
+
const existing = node.marks.find(({ type }) => type.name === "deletion");
|
|
17
|
+
if (node.isInline && existing) {
|
|
18
|
+
const start = Math.max(from, position);
|
|
19
|
+
const end = Math.min(to, position + node.nodeSize);
|
|
20
|
+
if (start < end) preservedDeletions.push({
|
|
21
|
+
from: start,
|
|
22
|
+
to: end,
|
|
23
|
+
mark: existing
|
|
24
|
+
});
|
|
25
|
+
const at = tr.doc.resolve(position);
|
|
26
|
+
for (let depth = 1; depth <= at.depth; depth++) {
|
|
27
|
+
const ancestor = at.node(depth);
|
|
28
|
+
if (canCarryTrackedRunMark(ancestor)) protectedCarriers.add(ancestor);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
});
|
|
33
|
+
const mapFrom = tr.mapping.maps.length;
|
|
34
|
+
const ranges = [];
|
|
35
|
+
const descendantDeletions = [];
|
|
36
|
+
const deletionFor = (node) => {
|
|
37
|
+
const insertion = node.marks.find(({ type }) => type.name === "insertion");
|
|
38
|
+
const ancestors = insertion ? expectTrackedChangeMarkAttrs(insertion)._docxRevisionAncestors : null;
|
|
39
|
+
return insertion && ancestors?.length ? mark.type.create({
|
|
40
|
+
...mark.attrs,
|
|
41
|
+
_docxRevisionAncestors: [...ancestors, trackedRevisionLayerOf(insertion, node)]
|
|
42
|
+
}) : mark;
|
|
43
|
+
};
|
|
44
|
+
tr.doc.nodesBetween(from, to, (node, position) => {
|
|
45
|
+
if (!canCarryTrackedRunMark(node)) return true;
|
|
46
|
+
if (node.marks.some(({ type }) => type.name === "deletion")) return false;
|
|
47
|
+
const start = Math.max(from, position);
|
|
48
|
+
const end = Math.min(to, position + node.nodeSize);
|
|
49
|
+
if (start >= end) return false;
|
|
50
|
+
const insertion = node.marks.find(({ type }) => type.name === "insertion");
|
|
51
|
+
const ownInsertion = insertion !== void 0 && insertion.attrs["author"] === mark.attrs["author"];
|
|
52
|
+
const deletion = deletionFor(node);
|
|
53
|
+
const disposition = insertionPolicy === "retract-own" && ownInsertion && !protectedCarriers.has(node) ? "retract" : "mark";
|
|
54
|
+
const previous = ranges.at(-1);
|
|
55
|
+
if (previous?.to === start && previous.disposition === disposition && previous.mark.eq(deletion)) previous.to = end;
|
|
56
|
+
else ranges.push({
|
|
57
|
+
from: start,
|
|
58
|
+
to: end,
|
|
59
|
+
mark: deletion,
|
|
60
|
+
disposition
|
|
61
|
+
});
|
|
62
|
+
if (disposition === "mark") node.descendants((child, offset) => {
|
|
63
|
+
if (child.marks.some(({ type }) => type.name === "deletion")) return false;
|
|
64
|
+
const childDeletion = deletionFor(child);
|
|
65
|
+
if (childDeletion === mark) return true;
|
|
66
|
+
const childStart = Math.max(from, position + 1 + offset);
|
|
67
|
+
const childEnd = Math.min(to, position + 1 + offset + child.nodeSize);
|
|
68
|
+
if (childStart < childEnd) descendantDeletions.push({
|
|
69
|
+
from: childStart,
|
|
70
|
+
to: childEnd,
|
|
71
|
+
mark: childDeletion
|
|
72
|
+
});
|
|
73
|
+
return true;
|
|
74
|
+
});
|
|
75
|
+
return false;
|
|
76
|
+
});
|
|
77
|
+
for (const range of ranges.toReversed()) if (range.disposition === "retract") tr.delete(range.from, range.to);
|
|
78
|
+
else tr.addMark(range.from, range.to, range.mark);
|
|
79
|
+
const mapping = tr.mapping.slice(mapFrom);
|
|
80
|
+
for (const preserved of [...descendantDeletions, ...preservedDeletions]) {
|
|
81
|
+
const start = mapping.map(preserved.from);
|
|
82
|
+
const end = mapping.map(preserved.to);
|
|
83
|
+
if (start < end) tr.addMark(start, end, preserved.mark);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
//#endregion
|
|
87
|
+
export { addTrackedDeletionMark };
|
|
@@ -8,6 +8,7 @@ import { attrsRecord, attrsResult, expectAttrs, expectCachedNodeAttrs, expectNod
|
|
|
8
8
|
import { COUNTER_FORMAT_VALUES, EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FONT_HINT_VALUES, FONT_THEME_VALUES, HIGHLIGHT_COLOR_VALUES, IMAGE_HORIZONTAL_ALIGNMENT_VALUES, IMAGE_HORIZONTAL_RELATIVE_TO_VALUES, IMAGE_VERTICAL_ALIGNMENT_VALUES, IMAGE_VERTICAL_RELATIVE_TO_VALUES, IMAGE_WRAP_TEXT_VALUES, IMAGE_WRAP_TYPE_VALUES, LINE_SPACING_RULE_VALUES, OUTLINE_STYLE_ATTR_VALUES, PARAGRAPH_ALIGNMENT_VALUES, POSITIONAL_TAB_ALIGNMENT_VALUES, POSITIONAL_TAB_LEADER_VALUES, POSITIONAL_TAB_RELATIVE_TO_VALUES, SDT_LOCK_VALUES, SDT_TYPE_VALUES, SHADING_PATTERN_VALUES, TABLE_CELL_VERTICAL_ALIGNMENT_VALUES, TABLE_JUSTIFICATION_VALUES, TABLE_ROW_HEIGHT_RULE_VALUES, TABLE_WIDTH_TYPE_VALUES, TAB_LEADER_VALUES, TAB_STOP_ALIGNMENT_VALUES, TEXT_DIRECTION_VALUES, TEXT_EFFECT_VALUES, UNDERLINE_STYLE_VALUES } from "../../types/documentEnumValues.js";
|
|
9
9
|
import { canonicalJson } from "../../utils/canonicalJson.js";
|
|
10
10
|
import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
|
|
11
|
+
import { isNoteReferenceOccurrenceId } from "../noteReferenceOccurrenceId.js";
|
|
11
12
|
import { paragraphNumberingFromAttrValue } from "../numberingAttr.js";
|
|
12
13
|
import { outlineLevelFromAttrValue } from "../outlineLevelAttr.js";
|
|
13
14
|
import { isParagraphDirection } from "../paragraphDirection.js";
|
|
@@ -953,6 +954,10 @@ const readFootnoteRefMarkAttrs = (mark) => {
|
|
|
953
954
|
const issues = [];
|
|
954
955
|
expectMarkType(mark, "footnoteRef", issues);
|
|
955
956
|
requiredStringOrNumber(attrs, "id", "footnoteRef.attrs.id", issues);
|
|
957
|
+
if (!isNoteReferenceOccurrenceId(attrs["occurrenceId"])) issues.push({
|
|
958
|
+
path: "footnoteRef.attrs.occurrenceId",
|
|
959
|
+
message: "Expected a nonblank occurrence identity."
|
|
960
|
+
});
|
|
956
961
|
optionalOneOf(attrs, "noteType", "footnoteRef.attrs.noteType", issues, NOTE_TYPES);
|
|
957
962
|
optionalOneOf(attrs, "vertAlign", "footnoteRef.attrs.vertAlign", issues, NOTE_REF_VERT_ALIGNS);
|
|
958
963
|
optionalBoolean(attrs, "customMarkFollows", "footnoteRef.attrs.customMarkFollows", issues);
|
|
@@ -4,6 +4,28 @@ import { ParagraphPropsPatch, RunPropsPatch } from "@stll/docx-core/ops";
|
|
|
4
4
|
//#region src/prosemirror/canonicalCommands.d.ts
|
|
5
5
|
/** Command meaning before canonical positions are resolved by the session. */
|
|
6
6
|
type CanonicalCommandIntent = {
|
|
7
|
+
type: "generateTOC";
|
|
8
|
+
at: number;
|
|
9
|
+
title: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: "setHyperlink";
|
|
12
|
+
from: number;
|
|
13
|
+
to: number;
|
|
14
|
+
href: string;
|
|
15
|
+
tooltip?: string;
|
|
16
|
+
} | {
|
|
17
|
+
type: "removeHyperlink";
|
|
18
|
+
from: number;
|
|
19
|
+
to: number;
|
|
20
|
+
hyperlinkStyleId?: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: "insertHyperlink";
|
|
23
|
+
from: number;
|
|
24
|
+
to: number;
|
|
25
|
+
text: string;
|
|
26
|
+
href: string;
|
|
27
|
+
tooltip?: string;
|
|
28
|
+
} | {
|
|
7
29
|
type: "formatRun";
|
|
8
30
|
from: number;
|
|
9
31
|
to: number;
|
|
@@ -36,9 +58,6 @@ type CanonicalCommandDescriptor = (state: EditorState) => readonly CanonicalComm
|
|
|
36
58
|
declare const withCanonicalCommand: (command: Command, descriptor: CanonicalCommandDescriptor) => Command;
|
|
37
59
|
declare const getCanonicalCommandIntents: (command: Command, state: EditorState) => readonly CanonicalCommandIntent[] | undefined;
|
|
38
60
|
declare const canonicalRunFormatting: (state: EditorState, patch: RunPropsPatch) => readonly [{
|
|
39
|
-
readonly type: "formatRun";
|
|
40
|
-
readonly from: number;
|
|
41
|
-
readonly to: number;
|
|
42
61
|
readonly patch: import("@stll/docx-core/ops").FormattingPatch<{
|
|
43
62
|
bold?: boolean | undefined;
|
|
44
63
|
boldCs?: boolean | undefined;
|
|
@@ -91,7 +110,12 @@ declare const canonicalRunFormatting: (state: EditorState, patch: RunPropsPatch)
|
|
|
91
110
|
styleId?: string | undefined;
|
|
92
111
|
preserved?: import("@stll/docx-core/model").PreservedMarkup | undefined;
|
|
93
112
|
}>;
|
|
113
|
+
readonly from: number;
|
|
114
|
+
readonly to: number;
|
|
115
|
+
readonly type: "formatRun";
|
|
94
116
|
}];
|
|
95
117
|
declare const withCanonicalParagraphFormatting: (command: Command, patch: ParagraphPropsPatch | ((paragraph: Node) => ParagraphPropsPatch)) => Command;
|
|
118
|
+
/** Commands that read the selection start apply that same patch across selected paragraphs. */
|
|
119
|
+
declare const withCanonicalStartParagraphFormatting: (command: Command, patch: (paragraph: Node) => ParagraphPropsPatch) => Command;
|
|
96
120
|
//#endregion
|
|
97
|
-
export { CanonicalCommandIntent, canonicalRunFormatting, getCanonicalCommandIntents, withCanonicalCommand, withCanonicalParagraphFormatting };
|
|
121
|
+
export { CanonicalCommandIntent, canonicalRunFormatting, getCanonicalCommandIntents, withCanonicalCommand, withCanonicalParagraphFormatting, withCanonicalStartParagraphFormatting };
|