@stll/folio-core 0.56.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 +45 -14
- package/dist/ai-edits/batch-claims.d.ts +3 -1
- package/dist/ai-edits/batch-claims.js +25 -1
- package/dist/ai-edits/table-row-column-mutations.js +17 -3
- package/dist/ai-suggestions/apply.js +20 -1
- package/dist/compare/inline-atoms.js +40 -16
- package/dist/compare/inline-provenance.js +12 -5
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/controller/canonicalClipboard.js +7 -1
- package/dist/controller/canonicalComments.d.ts +41 -0
- package/dist/controller/canonicalComments.js +152 -0
- package/dist/controller/canonicalComposition.d.ts +4 -0
- package/dist/controller/canonicalComposition.js +43 -11
- package/dist/controller/canonicalInlineProjection.d.ts +6 -1
- package/dist/controller/canonicalInlineProjection.js +86 -3
- package/dist/controller/canonicalInput.js +10 -1
- package/dist/controller/canonicalInputTimer.d.ts +10 -1
- package/dist/controller/canonicalInputTimer.js +24 -1
- package/dist/controller/canonicalPublicOperations.d.ts +2 -2
- package/dist/controller/canonicalPublicOperations.js +107 -15
- package/dist/controller/canonicalSelection.d.ts +18 -0
- package/dist/controller/canonicalSelection.js +32 -0
- package/dist/controller/canonicalSession.d.ts +3 -0
- package/dist/controller/canonicalSession.js +58 -24
- package/dist/controller/canonicalStoryEditor.d.ts +2 -0
- package/dist/controller/canonicalStoryEditor.js +20 -0
- package/dist/controller/folioEditor.js +13 -0
- package/dist/controller/headerFooterEditorManager.d.ts +1 -1
- package/dist/controller/headerFooterEditorManager.js +25 -11
- package/dist/controller/hiddenEditorApi.d.ts +13 -2
- package/dist/controller/hiddenEditorApi.js +4 -0
- package/dist/controller/hiddenEditorManager.d.ts +3 -1
- package/dist/controller/hiddenEditorManager.js +166 -13
- package/dist/controller/noteEditorManager.d.ts +1 -1
- package/dist/controller/noteEditorManager.js +28 -13
- package/dist/docx/builtInStyles.js +13 -6
- package/dist/docx/containerChildren.gen.d.ts +3 -1
- package/dist/docx/containerChildren.gen.js +33 -1
- package/dist/docx/fieldParser.js +14 -2
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/hyperlinkParser.js +20 -1
- 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/paragraphParser.js +88 -67
- package/dist/docx/paragraphPropertySource.d.ts +22 -1
- package/dist/docx/paragraphPropertySource.js +107 -1
- package/dist/docx/preservedRunContent.js +2 -1
- package/dist/docx/relsParser.js +26 -2
- package/dist/docx/rezip.js +9 -6
- package/dist/docx/selectiveSave.js +10 -8
- package/dist/docx/serializer/commentSerializer.d.ts +4 -1
- package/dist/docx/serializer/commentSerializer.js +7 -3
- package/dist/docx/serializer/paragraphSerializer.js +207 -94
- package/dist/docx/server/materializeYjsDocx.js +14 -6
- package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
- 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/revisionResolutionInline.js +25 -3
- package/dist/markdown/renderRuns.js +1 -11
- 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/commands/comments.js +60 -35
- 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/toProseDoc.js +119 -18
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +22 -5
- 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 +22 -14
- package/dist/prosemirror/extensions/marks/markUtils.js +8 -7
- 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/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/plugins/documentStyles.d.ts +4 -1
- package/dist/prosemirror/plugins/documentStyles.js +17 -10
- package/dist/prosemirror/plugins/suggestionMode.js +47 -49
- 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 +6 -20
- package/dist/types/canonicalCapabilities.js +6 -20
- package/dist/types/canonicalComments.d.ts +51 -0
- package/dist/types/canonicalComments.js +0 -0
- package/dist/types/canonicalSections.d.ts +12 -0
- package/dist/types/canonicalSections.js +0 -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 +2 -2
|
@@ -3,9 +3,11 @@ import { expectFieldAttrs, expectRunPropertyChangeMarkAttrs, expectTrackedChange
|
|
|
3
3
|
import { resolutionRemovesControl, withoutResolvedEnclosures } from "../prosemirror/contentControlRevisions.js";
|
|
4
4
|
import { resolveEmptyFieldResultRuns } from "../prosemirror/emptyFieldResultRuns.js";
|
|
5
5
|
import "../prosemirror/extensions/nodes/SdtExtension.js";
|
|
6
|
+
import { canonicalFieldNode } from "../prosemirror/fieldRepresentation.js";
|
|
7
|
+
import { resolvedPreservedXmlAttrs } from "../prosemirror/preservedXmlReview.js";
|
|
6
8
|
import { continuedRunMarks } from "../prosemirror/rejoinRunCarriers.js";
|
|
7
9
|
import { RUN_FORMATTING_MARK_NAMES } from "../prosemirror/runFormattingMarkNames.js";
|
|
8
|
-
import { reconstructRejectedRunFormattingMarks } from "../prosemirror/runPropertyChangeResolution.js";
|
|
10
|
+
import { reconstructRejectedRunFormattingMarks, restoreHistoricalRunFormatting } from "../prosemirror/runPropertyChangeResolution.js";
|
|
9
11
|
import { paragraphRunStyleContext } from "../prosemirror/runStyleFormatting.js";
|
|
10
12
|
import { recordNodeResolution } from "./revisionResolutionEdits.js";
|
|
11
13
|
import { panic } from "better-result";
|
|
@@ -35,6 +37,11 @@ const rebuildNode = (source, attrs, content, marks = source.marks) => recreatePr
|
|
|
35
37
|
const resolveInlineNode = ({ node, context, paragraphScope }) => {
|
|
36
38
|
let marks = node.marks;
|
|
37
39
|
let attrs = node.attrs;
|
|
40
|
+
if (context.mode === "reject" && node.marks.some((mark) => mark.type === context.keepType && expectTrackedChangeMarkAttrs(mark)._historicalFormatting)) marks = restoreHistoricalRunFormatting({
|
|
41
|
+
node,
|
|
42
|
+
paragraphContext: resolveParagraphRunStyleScope(paragraphScope, context.styleResolver),
|
|
43
|
+
styleResolver: context.styleResolver
|
|
44
|
+
});
|
|
38
45
|
const runPropertyChangeMark = marks.find((mark) => mark.type.name === "runPropertyChange");
|
|
39
46
|
if (runPropertyChangeMark) {
|
|
40
47
|
const { changes } = expectRunPropertyChangeMarkAttrs(runPropertyChangeMark);
|
|
@@ -64,6 +71,7 @@ const resolveInlineNode = ({ node, context, paragraphScope }) => {
|
|
|
64
71
|
}
|
|
65
72
|
if (node.marks.some((mark) => (mark.type.name === "insertion" || mark.type.name === "deletion") && expectTrackedChangeMarkAttrs(mark)._docxRevisionAncestors?.some((layer) => context.mode === "accept" ? layer.type === "deletion" || layer.type === "moveFrom" : layer.type === "insertion" || layer.type === "moveTo")) || context.removeType && node.marks.some((mark) => mark.type === context.removeType)) return null;
|
|
66
73
|
if (context.keepType) marks = marks.filter((mark) => mark.type !== context.keepType);
|
|
74
|
+
if (attrs === node.attrs) attrs = resolvedPreservedXmlAttrs(node, marks);
|
|
67
75
|
if (attrs !== node.attrs) return rebuildNode(node, attrs, node.content, marks);
|
|
68
76
|
return marksEqual(marks, node.marks) ? node : node.mark(marks);
|
|
69
77
|
};
|
|
@@ -172,7 +180,7 @@ const resolveInlineContent = ({ node, position, context, inheritedParagraphScope
|
|
|
172
180
|
context
|
|
173
181
|
});
|
|
174
182
|
let resolvedContent = Fragment.fromArray(children);
|
|
175
|
-
if (!resolvedNode.type.validContent(resolvedContent)) {
|
|
183
|
+
if (!resolvedNode.type.validContent(resolvedContent) && !(resolvedNode.type.name === "structuredField" && resolvedContent.size === 0)) {
|
|
176
184
|
const fitted = resolvedNode.type.createAndFill(resolvedNode.attrs, resolvedContent, resolvedNode.marks);
|
|
177
185
|
if (!fitted || !resolvedNode.type.validContent(fitted.content)) {
|
|
178
186
|
if (!resolvedNode.isInline) return panic(`Revision inline resolution invalidated ${resolvedNode.type.name} content`);
|
|
@@ -195,7 +203,21 @@ const resolveInlineContent = ({ node, position, context, inheritedParagraphScope
|
|
|
195
203
|
from: position,
|
|
196
204
|
to: position + resolvedNode.nodeSize
|
|
197
205
|
});
|
|
198
|
-
|
|
206
|
+
const rebuilt = rebuildNode(node, resolvedAttrs, resolvedContent, resolvedNode.marks);
|
|
207
|
+
const canonical = canonicalFieldNode(rebuilt);
|
|
208
|
+
if (canonical !== rebuilt && canonical.type === rebuilt.type) recordNodeResolution({
|
|
209
|
+
before: rebuilt,
|
|
210
|
+
after: canonical,
|
|
211
|
+
position,
|
|
212
|
+
steps: context.steps
|
|
213
|
+
});
|
|
214
|
+
else if (canonical !== rebuilt) context.replacementRanges.splice(replacementRangeStart, context.replacementRanges.length - replacementRangeStart, {
|
|
215
|
+
from: position,
|
|
216
|
+
to: position + node.nodeSize,
|
|
217
|
+
newSize: canonical.nodeSize,
|
|
218
|
+
slice: new Slice(Fragment.from(canonical), 0, 0)
|
|
219
|
+
});
|
|
220
|
+
return canonical;
|
|
199
221
|
};
|
|
200
222
|
const coalesceReplacementRanges = (replacementRanges) => {
|
|
201
223
|
const coalesced = [];
|
|
@@ -490,17 +490,7 @@ function renderParagraphInline(ctx, pkg, content, paraId, edges = {
|
|
|
490
490
|
case "simpleField":
|
|
491
491
|
case "complexField": {
|
|
492
492
|
const runs = item.type === "simpleField" ? item.content : item.fieldResult;
|
|
493
|
-
for (const child of runs)
|
|
494
|
-
if (child.type === "run") {
|
|
495
|
-
out += renderRuns(ctx, pkg, [child], paraId);
|
|
496
|
-
continue;
|
|
497
|
-
}
|
|
498
|
-
if (child.type === "hyperlink") {
|
|
499
|
-
out += renderHyperlink(ctx, pkg, child, paraId);
|
|
500
|
-
continue;
|
|
501
|
-
}
|
|
502
|
-
out += child.type === "inlineWrapper" ? renderParagraphInline(ctx, pkg, child.content, paraId, UNKNOWN_NEIGHBORS) : child.text;
|
|
503
|
-
}
|
|
493
|
+
for (const child of runs) out += child.type === "preservedInline" ? child.text : renderParagraphInline(ctx, pkg, [child], paraId, UNKNOWN_NEIGHBORS);
|
|
504
494
|
break;
|
|
505
495
|
}
|
|
506
496
|
case "inlineSdt":
|
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);
|
|
@@ -10,20 +10,23 @@ import { resolveEmptyFieldResultRuns } from "../emptyFieldResultRuns.js";
|
|
|
10
10
|
import { JOINED_RUNS_RESTYLED_META } from "../extensions/features/JoinedRunStyleExtension.js";
|
|
11
11
|
import { markChangedParagraphRanges, markStructuralChange, markTrackedSectionEndpointRemoval } from "../extensions/features/ParagraphChangeTrackerExtension.js";
|
|
12
12
|
import "../extensions/nodes/SdtExtension.js";
|
|
13
|
+
import { canonicalFieldNode } from "../fieldRepresentation.js";
|
|
13
14
|
import { resolveStateStory } from "../markupViewProjection.js";
|
|
14
15
|
import { joinAtParagraphMark } from "../paragraphMarkJoin.js";
|
|
15
16
|
import { getDocumentNumbering } from "../plugins/documentNumbering.js";
|
|
16
17
|
import { getDocumentStyleResolver } from "../plugins/documentStyleState.js";
|
|
18
|
+
import { resolvedPreservedXmlAttrs } from "../preservedXmlReview.js";
|
|
17
19
|
import { rebaseParagraphRuns, setParagraphAttrsWithRebasedRunFormatting } from "../rebaseParagraphRunFormatting.js";
|
|
18
20
|
import { rejoinRunsAt } from "../rejoinRunCarriers.js";
|
|
19
21
|
import { getFolioNodeRevisionCarriers, nodePropertyRevisionSites } from "../revisionCarriers.js";
|
|
20
22
|
import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
|
|
21
|
-
import { reconstructRejectedRunFormattingMarks } from "../runPropertyChangeResolution.js";
|
|
23
|
+
import { reconstructRejectedRunFormattingMarks, restoreHistoricalRunFormatting } from "../runPropertyChangeResolution.js";
|
|
22
24
|
import { paragraphRunStyleContext, paragraphRunStyleContextAt } from "../runStyleFormatting.js";
|
|
23
25
|
import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
|
|
24
26
|
import { isTableCellRetainedInReviewView } from "../tableCellRevisionVisibility.js";
|
|
25
27
|
import { markRowEmptiedInBatch, reconcileTableGridAfterColumnRemoval, removeRowsWithoutCellsAfterBatch, removeTableRow } from "../tableGridMutation.js";
|
|
26
28
|
import { runInCellPending, runParagraphIntoTable } from "../tableRunIn.js";
|
|
29
|
+
import { retainedTrackedRevisionMark, trackedRevisionPathOf } from "../trackedRevisionPath.js";
|
|
27
30
|
import { holdsNoContent } from "../zeroWidthAnchors.js";
|
|
28
31
|
import { inlineBookmarksForParagraphJoin } from "./paragraphBookmarkJoin.js";
|
|
29
32
|
import { hasSerializableParagraphPropertyChange, paragraphPropertiesSnapshot } from "./propertyChangeScope.js";
|
|
@@ -32,10 +35,16 @@ import { resolveParagraphChangeAttrs } from "./resolveParagraphProperties.js";
|
|
|
32
35
|
import { hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge } from "./tableCellMergeResolution.js";
|
|
33
36
|
import { panic } from "better-result";
|
|
34
37
|
import { PARAGRAPH_MARK_CHANGE_KINDS, REVIEW_CARRIERS } from "@stll/docx-core/model";
|
|
38
|
+
import { Fragment } from "prosemirror-model";
|
|
35
39
|
import { TableMap } from "prosemirror-tables";
|
|
36
40
|
import { Mapping } from "prosemirror-transform";
|
|
37
41
|
//#region src/prosemirror/commands/comments.ts
|
|
38
42
|
/**
|
|
43
|
+
* Comment and Track Changes Commands
|
|
44
|
+
*
|
|
45
|
+
* PM commands for adding/removing comments and accepting/rejecting tracked changes.
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
39
48
|
* Add a comment mark to the current selection.
|
|
40
49
|
*/
|
|
41
50
|
function addCommentMark(commentId) {
|
|
@@ -67,21 +76,6 @@ function removeCommentMark(commentId) {
|
|
|
67
76
|
return true;
|
|
68
77
|
};
|
|
69
78
|
}
|
|
70
|
-
const revisionLayerOf = (mark) => {
|
|
71
|
-
const attrs = expectTrackedChangeMarkAttrs(mark);
|
|
72
|
-
let type;
|
|
73
|
-
if (mark.type.name === "insertion") type = attrs.moveKind === "moveTo" ? "moveTo" : "insertion";
|
|
74
|
-
else type = attrs.moveKind === "moveFrom" ? "moveFrom" : "deletion";
|
|
75
|
-
return {
|
|
76
|
-
type,
|
|
77
|
-
revisionId: attrs.revisionId,
|
|
78
|
-
author: attrs.author,
|
|
79
|
-
...attrs.date ? { date: attrs.date } : {},
|
|
80
|
-
...attrs.utcDate ? { utcDate: attrs.utcDate } : {},
|
|
81
|
-
...attrs.initials ? { initials: attrs.initials } : {},
|
|
82
|
-
outerWrapperCount: attrs._docxOuterWrapperCount ?? 0
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
79
|
const revisionLayerRemovesContent = (layer, mode) => mode === "accept" ? layer.type === "deletion" || layer.type === "moveFrom" : layer.type === "insertion" || layer.type === "moveTo";
|
|
86
80
|
/**
|
|
87
81
|
* Resolve a tracked change: accept or reject.
|
|
@@ -189,6 +183,19 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
189
183
|
const runPropertyChangeMark = node.marks.find((mark) => mark.type.name === "runPropertyChange");
|
|
190
184
|
const removesNode = removeType !== void 0 && node.marks.some((mark) => mark.type === removeType && matchesRevision(mark));
|
|
191
185
|
if (removesNode || runPropertyChangeMark !== void 0 || node.marks.some((mark) => (mark.type === insertionType || mark.type === deletionType) && matchesRevision(mark))) resolvedBoundaries.push(rangeFrom, rangeTo);
|
|
186
|
+
if (mode === "reject" && node.marks.find((mark) => mark.type === keepType && matchesRevision(mark) && expectTrackedChangeMarkAttrs(mark)._historicalFormatting && !expectTrackedChangeMarkAttrs(mark)._docxRevisionAncestors?.some((layer) => (layer.type === "deletion" || layer.type === "moveFrom") && revisionSet !== null && !revisionSet.has(layer.revisionId))) && !removesNode) {
|
|
187
|
+
const nextMarks = restoreHistoricalRunFormatting({
|
|
188
|
+
node,
|
|
189
|
+
paragraphContext: paragraphRunStyleContextAt({
|
|
190
|
+
doc: tr.doc,
|
|
191
|
+
pos: rangeFrom,
|
|
192
|
+
styleResolver
|
|
193
|
+
}),
|
|
194
|
+
styleResolver
|
|
195
|
+
});
|
|
196
|
+
for (const mark of node.marks) if (RUN_FORMATTING_MARK_NAMES.has(mark.type.name)) tr.removeMark(rangeFrom, rangeTo, mark);
|
|
197
|
+
for (const mark of nextMarks) if (RUN_FORMATTING_MARK_NAMES.has(mark.type.name)) tr.addMark(rangeFrom, rangeTo, mark);
|
|
198
|
+
}
|
|
192
199
|
if (runPropertyChangeMark) resolveRunPropertyChange({
|
|
193
200
|
tr,
|
|
194
201
|
node,
|
|
@@ -201,7 +208,7 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
201
208
|
});
|
|
202
209
|
const nestedMark = node.marks.find((mark) => (mark.type === insertionType || mark.type === deletionType) && (expectTrackedChangeMarkAttrs(mark)._docxRevisionAncestors?.length ?? 0) > 0);
|
|
203
210
|
if (nestedMark) {
|
|
204
|
-
const path =
|
|
211
|
+
const path = trackedRevisionPathOf(nestedMark);
|
|
205
212
|
const selected = (layer) => revisionSet === null || revisionSet.has(layer.revisionId);
|
|
206
213
|
if (path.some(selected)) if (path.some((layer) => selected(layer) && revisionLayerRemovesContent(layer, mode))) deleteRanges.push({
|
|
207
214
|
from: rangeFrom,
|
|
@@ -209,23 +216,13 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
209
216
|
});
|
|
210
217
|
else {
|
|
211
218
|
tr.removeMark(rangeFrom, rangeTo, nestedMark);
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
author: active.author,
|
|
220
|
-
date: active.date ?? null,
|
|
221
|
-
utcDate: active.utcDate ?? null,
|
|
222
|
-
initials: active.initials ?? null,
|
|
223
|
-
moveKind: active.type === "moveTo" || active.type === "moveFrom" ? active.type : null,
|
|
224
|
-
_historicalFormatting: active.type === "deletion" || active.type === "moveFrom" ? true : null,
|
|
225
|
-
_docxOuterWrapperCount: active.outerWrapperCount,
|
|
226
|
-
_docxRevisionAncestors: remaining.length > 1 ? remaining.slice(0, -1) : null
|
|
227
|
-
}));
|
|
228
|
-
}
|
|
219
|
+
const retained = retainedTrackedRevisionMark(nestedMark, (layer) => !selected(layer));
|
|
220
|
+
if (retained) tr.addMark(rangeFrom, rangeTo, retained);
|
|
221
|
+
}
|
|
222
|
+
const current = tr.doc.nodeAt(pos);
|
|
223
|
+
if (current) {
|
|
224
|
+
const attrs = resolvedPreservedXmlAttrs(node, current.marks);
|
|
225
|
+
if (attrs !== node.attrs) tr.setNodeMarkup(pos, void 0, attrs);
|
|
229
226
|
}
|
|
230
227
|
return true;
|
|
231
228
|
}
|
|
@@ -233,6 +230,10 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
233
230
|
from: rangeFrom,
|
|
234
231
|
to: rangeTo
|
|
235
232
|
});
|
|
233
|
+
if (!removesNode && keepType && node.marks.some((mark) => mark.type === keepType && matchesRevision(mark))) {
|
|
234
|
+
const attrs = resolvedPreservedXmlAttrs(node, node.marks.filter((mark) => !(mark.type === keepType && matchesRevision(mark))));
|
|
235
|
+
if (attrs !== node.attrs) tr.setNodeMarkup(pos, void 0, attrs);
|
|
236
|
+
}
|
|
236
237
|
if (!removeKeptMarksInBulk) {
|
|
237
238
|
for (const mark of node.marks) if (keepType && mark.type === keepType && matchesRevision(mark)) tr.removeMark(rangeFrom, rangeTo, mark);
|
|
238
239
|
}
|
|
@@ -255,7 +256,17 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
255
256
|
}
|
|
256
257
|
rangesToDelete = coalescedDeleteRanges;
|
|
257
258
|
}
|
|
258
|
-
for (const range of rangesToDelete.toReversed())
|
|
259
|
+
for (const range of rangesToDelete.toReversed()) {
|
|
260
|
+
const start = tr.doc.resolve(range.from);
|
|
261
|
+
const field = start.parent;
|
|
262
|
+
if (field.type.name === "structuredField" && start.parentOffset === 0 && range.to === start.end()) {
|
|
263
|
+
const position = start.before();
|
|
264
|
+
const empty = canonicalFieldNode(field.copy(Fragment.empty));
|
|
265
|
+
tr.replaceWith(position, position + field.nodeSize, empty);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
tr.delete(range.from, range.to);
|
|
269
|
+
}
|
|
259
270
|
if (deleteTextBoxesAnchoredAt(tr, droppedTextBoxAnchorIds(state.doc, tr.doc))) markStructuralChange(tr);
|
|
260
271
|
tableRowStructuralOps.sort((left, right) => right.rowPos - left.rowPos);
|
|
261
272
|
let resolvedTableRowStructure = false;
|
|
@@ -418,6 +429,20 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
418
429
|
boundaries: resolvedBoundaries.map((position) => tr.mapping.map(position)).filter((position) => !seams.has(position)),
|
|
419
430
|
styleResolver
|
|
420
431
|
});
|
|
432
|
+
const resolvedFields = [];
|
|
433
|
+
tr.doc.descendants((node, position) => {
|
|
434
|
+
const canonical = canonicalFieldNode(node);
|
|
435
|
+
if (canonical !== node) resolvedFields.push({
|
|
436
|
+
node: canonical,
|
|
437
|
+
position
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
for (const { node, position } of resolvedFields.toReversed()) {
|
|
441
|
+
const field = tr.doc.nodeAt(position);
|
|
442
|
+
if (!field) continue;
|
|
443
|
+
if (field.type === node.type) tr.setNodeMarkup(position, void 0, node.attrs, node.marks);
|
|
444
|
+
else tr.replaceWith(position, position + field.nodeSize, node);
|
|
445
|
+
}
|
|
421
446
|
if (tr.steps.length > 0) dispatch(tr);
|
|
422
447
|
}
|
|
423
448
|
return true;
|
|
@@ -4,6 +4,7 @@ import { readParagraphNumberingAttr } from "../numberingAttr.js";
|
|
|
4
4
|
import { directParagraphAlignment } from "../paragraphAlignment.js";
|
|
5
5
|
import { directionFromBidi } from "../paragraphDirection.js";
|
|
6
6
|
import { PARAGRAPH_FORMATTING_WRITE_BACK, STYLE_RESOLVED_PARAGRAPH_FIELDS } from "../paragraphFormattingProvenance.js";
|
|
7
|
+
import { directParagraphIndentation } from "../paragraphIndentation.js";
|
|
7
8
|
import { directParagraphSpacing, paragraphSpacingAttrPatch, paragraphSpacingFromFormatting } from "../paragraphSpacing.js";
|
|
8
9
|
import { sameFormattingValue } from "../runFormattingFromMarks.js";
|
|
9
10
|
//#region src/prosemirror/commands/propertyChangeScope.ts
|
|
@@ -127,18 +128,14 @@ const paragraphPropertiesSnapshot = (node) => {
|
|
|
127
128
|
const attrs = expectParagraphAttrs(node);
|
|
128
129
|
const snapshot = {};
|
|
129
130
|
for (const key of PPR_CHANGE_SCOPED_ATTR_KEYS) {
|
|
130
|
-
if (key === "alignment" || PPR_SPACING_ATTR_KEYS.has(key) || key === "numPr" && isStyleSourcedParagraphNumbering(attrs.numPr, attrs.numPrFromStyle)) continue;
|
|
131
|
+
if (key === "alignment" || key === "indentLeft" || key === "indentRight" || key === "indentFirstLine" || key === "hangingIndent" || PPR_SPACING_ATTR_KEYS.has(key) || key === "numPr" && isStyleSourcedParagraphNumbering(attrs.numPr, attrs.numPrFromStyle)) continue;
|
|
131
132
|
if (styleSuppliedParagraphValue(attrs, key)) continue;
|
|
132
|
-
if (key === "hangingIndent" && styleSuppliedParagraphValue(attrs, "indentFirstLine")) continue;
|
|
133
|
-
if (styleSuppliedParagraphValue(attrs, key)) continue;
|
|
134
|
-
if (key === "hangingIndent" && styleSuppliedParagraphValue(attrs, "indentFirstLine")) continue;
|
|
135
133
|
const value = attrs[key];
|
|
136
|
-
if (key === "hangingIndent" && value === false && attrs._originalFormatting?.hangingIndent === void 0) continue;
|
|
137
134
|
if (value !== null && value !== void 0) snapshot[key] = value;
|
|
138
135
|
}
|
|
139
136
|
const directAlignment = directParagraphAlignment(attrs);
|
|
140
137
|
if (directAlignment !== void 0) snapshot["alignment"] = directAlignment;
|
|
141
|
-
Object.assign(snapshot, directParagraphSpacing(attrs));
|
|
138
|
+
Object.assign(snapshot, directParagraphSpacing(attrs), directParagraphIndentation(attrs));
|
|
142
139
|
return snapshot;
|
|
143
140
|
};
|
|
144
141
|
/**
|
|
@@ -2,8 +2,9 @@ import { resolveParagraphNumbering } from "../../docx/numberingReference.js";
|
|
|
2
2
|
import { expectParagraphAttrs } from "../attrs/index.js";
|
|
3
3
|
import { rejectedListRenderingPatch } from "../listRendering.js";
|
|
4
4
|
import { paragraphNumberingAttr } from "../numberingAttr.js";
|
|
5
|
-
import {
|
|
5
|
+
import { paragraphIndentationFromFormatting } from "../paragraphIndentation.js";
|
|
6
6
|
import { resolveParagraphDefaultTextFormatting } from "../styles/paragraphStyleCascade.js";
|
|
7
|
+
import { listIndentationProvenancePatch } from "../styles/resolvedStyleAttrs.js";
|
|
7
8
|
import { paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, removeParagraphPropertyChanges, sectionRejectProperties } from "./propertyChangeScope.js";
|
|
8
9
|
//#region src/prosemirror/commands/resolveParagraphProperties.ts
|
|
9
10
|
/** Resolve paragraph and section property records before resolving their inline content. */
|
|
@@ -27,24 +28,32 @@ const resolveParagraphChangeAttrs = ({ node, boundaryCovered, mode, revisionSet,
|
|
|
27
28
|
const inheritedAlignment = currentAttrs.alignmentFromStyle;
|
|
28
29
|
const restoredStyleId = rejection.previousFormatting?.styleId ?? void 0;
|
|
29
30
|
const sameStyle = restoredStyleId === (currentAttrs.styleId ?? void 0);
|
|
30
|
-
let previousFormattingFromStyle;
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
previousFormattingFromStyle = styleResolver.resolveParagraphStyle(restoredStyleId).paragraphFormatting;
|
|
34
|
-
if (!sameStyle) {
|
|
35
|
-
resolvedFromStyle = styleResolvedParagraphFormatting(previousFormattingFromStyle);
|
|
36
|
-
nextAttrs["_resolvedFormatting"] = resolvedFromStyle;
|
|
37
|
-
}
|
|
38
|
-
} else if (inheritedAlignment !== void 0) previousFormattingFromStyle = { alignment: inheritedAlignment };
|
|
39
|
-
const inheritedFormatting = previousFormattingFromStyle === void 0 && resolvedFromStyle === void 0 ? void 0 : {
|
|
31
|
+
let previousFormattingFromStyle = sameStyle ? currentAttrs._styleResolvedFormatting : void 0;
|
|
32
|
+
if (styleResolver) previousFormattingFromStyle = styleResolver.resolveParagraphStyle(restoredStyleId).paragraphFormatting;
|
|
33
|
+
else if (inheritedAlignment !== void 0) previousFormattingFromStyle = {
|
|
40
34
|
...previousFormattingFromStyle,
|
|
41
|
-
|
|
35
|
+
alignment: inheritedAlignment
|
|
42
36
|
};
|
|
43
37
|
let styleNumbering = previousFormattingFromStyle?.numPr;
|
|
44
38
|
if (!styleResolver && sameStyle) styleNumbering = currentAttrs.numPrFromStyle ?? void 0;
|
|
45
39
|
const inheritedNumbering = styleNumbering == null ? null : paragraphNumberingAttr(resolveParagraphNumbering(styleNumbering));
|
|
46
40
|
const recordedNumbering = rejection.previousFormatting?.numPr;
|
|
47
41
|
const restoredNumbering = recordedNumbering ?? inheritedNumbering;
|
|
42
|
+
const restoredFormatting = paragraphRejectOriginalFormatting(rejection.previousFormatting, node.attrs["_originalFormatting"]);
|
|
43
|
+
const indentation = listIndentationProvenancePatch({
|
|
44
|
+
direct: paragraphIndentationFromFormatting(restoredFormatting ?? void 0),
|
|
45
|
+
styleFormatting: previousFormattingFromStyle,
|
|
46
|
+
numberingSource: recordedNumbering == null ? "style" : "paragraph",
|
|
47
|
+
numPr: restoredNumbering?.kind === "reference" ? {
|
|
48
|
+
numId: restoredNumbering.numId,
|
|
49
|
+
ilvl: restoredNumbering.ilvl ?? 0
|
|
50
|
+
} : void 0,
|
|
51
|
+
numbering
|
|
52
|
+
});
|
|
53
|
+
const inheritedFormatting = {
|
|
54
|
+
...previousFormattingFromStyle,
|
|
55
|
+
...indentation._resolvedFormatting
|
|
56
|
+
};
|
|
48
57
|
Object.assign(nextAttrs, paragraphRejectAttrPatch(rejection.previousFormatting, inheritedFormatting), rejectedListRenderingPatch({
|
|
49
58
|
current: expectParagraphAttrs(node),
|
|
50
59
|
previousFormatting: rejection.previousFormatting,
|
|
@@ -54,7 +63,7 @@ const resolveParagraphChangeAttrs = ({ node, boundaryCovered, mode, revisionSet,
|
|
|
54
63
|
numPr: restoredNumbering,
|
|
55
64
|
numPrFromStyle: recordedNumbering == null ? inheritedNumbering : null
|
|
56
65
|
});
|
|
57
|
-
|
|
66
|
+
Object.assign(nextAttrs, indentation);
|
|
58
67
|
nextAttrs["_originalFormatting"] = restoredFormatting;
|
|
59
68
|
if (styleResolver) nextAttrs["defaultTextFormatting"] = resolveParagraphDefaultTextFormatting(rejection.previousFormatting?.styleId, restoredFormatting ?? void 0, styleResolver) ?? null;
|
|
60
69
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
import { addTrackedDeletionMark } from "./addTrackedDeletionMark.js";
|
|
1
2
|
import { findTextInPmParagraph } from "./paraText.js";
|
|
2
3
|
import { findParagraphByParaId } from "./utils/findParagraphByParaId.js";
|
|
3
4
|
//#region src/prosemirror/commentOps.ts
|
|
5
|
+
/**
|
|
6
|
+
* Comment + tracked-change (proposeChange) PM transaction builders shared by
|
|
7
|
+
* the React and Vue adapters. They locate the target range, apply the mark(s),
|
|
8
|
+
* dispatch, and return a result. ID allocation lives in `commentIdAllocator.ts`
|
|
9
|
+
* and is injected. Adapter-specific state mutation, event emission, and sidebar
|
|
10
|
+
* UI stay in each adapter.
|
|
11
|
+
*/
|
|
4
12
|
/** Build a Comment object with a freshly-allocated ID. */
|
|
5
13
|
function createComment(allocator, text, authorName, parentId) {
|
|
6
14
|
return {
|
|
@@ -95,7 +103,13 @@ function applyProposedChange(view, options, allocator) {
|
|
|
95
103
|
date
|
|
96
104
|
});
|
|
97
105
|
let tr = view.state.tr;
|
|
98
|
-
if (!isInsertion)
|
|
106
|
+
if (!isInsertion) addTrackedDeletionMark({
|
|
107
|
+
insertionPolicy: "preserve-pending",
|
|
108
|
+
tr,
|
|
109
|
+
from: textFrom,
|
|
110
|
+
to: textTo,
|
|
111
|
+
mark: deletionMark
|
|
112
|
+
});
|
|
99
113
|
if (!isDeletion) tr = tr.insert(textTo, schema.text(options.replaceWith, [insertionMark]));
|
|
100
114
|
view.dispatch(tr);
|
|
101
115
|
return true;
|