@stll/folio-core 0.36.0 → 0.37.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/README.md +59 -1
- package/dist/ai-edits/apply.js +545 -296
- package/dist/ai-edits/block-identity.d.ts +4 -1
- package/dist/ai-edits/block-identity.js +4 -1
- package/dist/ai-edits/blockRange.js +14 -14
- package/dist/ai-edits/clean-text.d.ts +40 -1
- package/dist/ai-edits/clean-text.js +52 -2
- package/dist/ai-edits/headless.d.ts +3 -1
- package/dist/ai-edits/headless.js +133 -71
- package/dist/ai-edits/index.d.ts +3 -3
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/read.js +38 -20
- package/dist/ai-edits/snapshot.d.ts +14 -6
- package/dist/ai-edits/snapshot.js +99 -19
- package/dist/ai-edits/table-cell-mutations.js +1 -1
- package/dist/ai-edits/table-row-column-mutations.js +7 -0
- package/dist/ai-edits/table-template.d.ts +11 -1
- package/dist/ai-edits/table-template.js +49 -17
- package/dist/ai-edits/types.d.ts +45 -57
- package/dist/ai-suggestions/conflict.js +1 -4
- package/dist/ai-suggestions/text-positions.d.ts +8 -0
- package/dist/ai-suggestions/text-positions.js +27 -5
- package/dist/compare/__fixtures__/body-sequence.js +3 -4
- package/dist/compare/column-alignment.d.ts +13 -13
- package/dist/compare/column-alignment.js +78 -39
- package/dist/compare/compare.d.ts +4 -3
- package/dist/compare/compare.js +41 -5
- package/dist/compare/content-alignment.d.ts +95 -0
- package/dist/compare/content-alignment.js +1450 -0
- package/dist/compare/content-types.d.ts +100 -0
- package/dist/compare/content-types.js +0 -0
- package/dist/compare/content.d.ts +209 -0
- package/dist/compare/content.js +885 -0
- package/dist/compare/formatting.d.ts +5 -5
- package/dist/compare/formatting.js +6 -4
- package/dist/compare/plan.d.ts +6 -1
- package/dist/compare/plan.js +169 -567
- package/dist/compare/scenario.d.ts +2 -2
- package/dist/compare/types.d.ts +3 -3
- package/dist/compare/verification.d.ts +2 -2
- package/dist/compare/verification.js +25 -8
- package/dist/compat/eigenpal.d.ts +5 -3
- package/dist/compat/eigenpal.js +3 -2
- package/dist/controller/headerFooterEditorManager.js +14 -6
- package/dist/controller/hiddenEditorManager.d.ts +7 -2
- package/dist/controller/hiddenEditorManager.js +15 -6
- package/dist/controller/layoutPipeline.js +5 -3
- package/dist/controller/noteEditorManager.js +12 -7
- package/dist/display-list/build/headerFooterPrimitives.js +1 -0
- package/dist/display-list/build/storyPrimitives.d.ts +5 -2
- package/dist/display-list/build/storyPrimitives.js +60 -3
- package/dist/display-list/build/tablePrimitives.js +30 -0
- package/dist/display-list/primitives.d.ts +1 -1
- package/dist/document-operations.d.ts +6 -4
- package/dist/document-operations.js +77 -12
- package/dist/docx/blockContentParser.js +6 -27
- package/dist/docx/ensureParaIds.js +9 -4
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +4 -1
- package/dist/docx/paragraphParser.js +7 -6
- package/dist/docx/paragraphTraversal.js +30 -34
- package/dist/docx/rezip.d.ts +0 -8
- package/dist/docx/rezip.js +41 -16
- package/dist/docx/runParser.js +4 -2
- package/dist/docx/serializer/paragraphSerializer.js +2 -0
- package/dist/docx/serializer/runSerializer.js +5 -3
- package/dist/docx/serializer/trackedChangeAttributes.d.ts +3 -1
- package/dist/docx/serializer/trackedChangeAttributes.js +11 -1
- package/dist/docx/server/build.d.ts +1 -1
- package/dist/headless-layout.js +5 -4
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -2
- package/dist/internal/headlessRevisionResolution.d.ts +23 -0
- package/dist/internal/headlessRevisionResolution.js +155 -0
- package/dist/internal/headlessRevisionResolutionGuard.d.ts +12 -0
- package/dist/internal/headlessRevisionResolutionGuard.js +28 -0
- package/dist/internal/pageBreakRunDescendantIndex.d.ts +9 -0
- package/dist/internal/pageBreakRunDescendantIndex.js +27 -0
- package/dist/internal/pageBreakRunPartition.d.ts +26 -0
- package/dist/internal/pageBreakRunPartition.js +35 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +15 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +126 -0
- package/dist/internal/sectionEndpointResolution.d.ts +32 -0
- package/dist/internal/sectionEndpointResolution.js +38 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +16 -4
- package/dist/layout-bridge/convert/headerFooterLayout.js +48 -5
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -0
- package/dist/layout-bridge/convert/toFlowBlocks.js +379 -75
- package/dist/layout-bridge/dom/clickToPositionDom.d.ts +8 -1
- package/dist/layout-bridge/dom/clickToPositionDom.js +114 -40
- package/dist/layout-bridge/dom/textStreamDom.d.ts +24 -0
- package/dist/layout-bridge/dom/textStreamDom.js +75 -0
- package/dist/layout-bridge/headerFooterLayout.js +16 -30
- package/dist/layout-engine/index.js +12 -3
- package/dist/layout-engine/measure/tableFragmentBorderGeometry.d.ts +17 -0
- package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +24 -0
- package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
- package/dist/layout-engine/types.d.ts +7 -0
- package/dist/layout-painter/imageLayout.d.ts +1 -1
- package/dist/layout-painter/renderTable.js +20 -0
- package/dist/model.d.ts +1 -1
- package/dist/paged-layout/rangeProjection.js +6 -9
- package/dist/paged-layout/transactionDirtyRange.d.ts +3 -1
- package/dist/paged-layout/transactionDirtyRange.js +23 -1
- package/dist/prosemirror/attrs/index.d.ts +7 -3
- package/dist/prosemirror/attrs/index.js +113 -7
- package/dist/prosemirror/bookmarkBoundaryIntegrity.d.ts +9 -0
- package/dist/prosemirror/bookmarkBoundaryIntegrity.js +22 -0
- package/dist/prosemirror/commands/comments.d.ts +10 -1
- package/dist/prosemirror/commands/comments.js +190 -59
- package/dist/prosemirror/commands/formatPainter.d.ts +45 -10
- package/dist/prosemirror/commands/formatPainter.js +319 -63
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/pageBreak.d.ts +5 -2
- package/dist/prosemirror/commands/pageBreak.js +18 -36
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +7 -5
- package/dist/prosemirror/commands/propertyChangeScope.js +27 -18
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +7 -2
- package/dist/prosemirror/conversion/fromProseDoc.js +809 -209
- package/dist/prosemirror/conversion/runShadingMark.js +2 -2
- package/dist/prosemirror/conversion/toProseDoc.d.ts +26 -1
- package/dist/prosemirror/conversion/toProseDoc.js +416 -283
- package/dist/prosemirror/extensions/StarterKit.js +4 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -8
- package/dist/prosemirror/extensions/features/ListExtension.js +95 -123
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -1
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +27 -1
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +134 -30
- package/dist/prosemirror/extensions/features/pasteCleanup.js +9 -15
- package/dist/prosemirror/extensions/marks/BoldExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/CharacterStyleExtension.d.ts +4 -7
- package/dist/prosemirror/extensions/marks/CharacterStyleExtension.js +5 -11
- package/dist/prosemirror/extensions/marks/FontSizeExtension.js +3 -3
- package/dist/prosemirror/extensions/marks/ItalicExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.d.ts +13 -0
- package/dist/prosemirror/extensions/marks/PageBreakRunOwnerExtension.js +39 -0
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.d.ts +7 -1
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +67 -21
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +8 -1
- package/dist/prosemirror/extensions/marks/markUtils.js +88 -2
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +44 -3
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
- package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +15 -4
- package/dist/prosemirror/extensions/nodes/PageBreakExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/PageBreakExtension.js +6 -0
- package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/PageBreakRunExtension.js +36 -0
- package/dist/prosemirror/findReplaceSelection.js +8 -3
- package/dist/prosemirror/index.d.ts +3 -3
- package/dist/prosemirror/listMarker.d.ts +26 -1
- package/dist/prosemirror/listMarker.js +108 -14
- package/dist/prosemirror/pageBreakRunProjection.d.ts +28 -0
- package/dist/prosemirror/pageBreakRunProjection.js +47 -0
- package/dist/prosemirror/paraText.js +6 -0
- package/dist/prosemirror/paragraphSpacing.d.ts +29 -0
- package/dist/prosemirror/paragraphSpacing.js +125 -0
- package/dist/prosemirror/plugins/documentNumbering.d.ts +8 -0
- package/dist/prosemirror/plugins/documentNumbering.js +18 -0
- package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -2
- package/dist/prosemirror/plugins/pmTextScan.js +14 -4
- package/dist/prosemirror/plugins/suggestionMode.js +8 -10
- package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +16 -0
- package/dist/prosemirror/rebaseParagraphRunFormatting.js +61 -0
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +64 -0
- package/dist/prosemirror/runFormattingInlineCarriers.js +121 -0
- package/dist/prosemirror/runFormattingProvenance.d.ts +12 -0
- package/dist/prosemirror/runFormattingProvenance.js +48 -0
- package/dist/prosemirror/runFormattingReconciliation.d.ts +25 -0
- package/dist/prosemirror/runFormattingReconciliation.js +54 -0
- package/dist/prosemirror/runPropertyChangeResolution.d.ts +18 -0
- package/dist/prosemirror/runPropertyChangeResolution.js +18 -0
- package/dist/prosemirror/runStyleFormatting.d.ts +50 -0
- package/dist/prosemirror/runStyleFormatting.js +105 -0
- package/dist/prosemirror/schema/index.d.ts +3 -3
- package/dist/prosemirror/schema/marks.d.ts +82 -9
- package/dist/prosemirror/schema/marks.js +73 -1
- package/dist/prosemirror/schema/nodes.d.ts +18 -5
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +14 -2
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +44 -23
- package/dist/prosemirror/styles/styleResolver.d.ts +10 -13
- package/dist/prosemirror/styles/styleResolver.js +3 -3
- package/dist/prosemirror/styles/styleToggleCascade.d.ts +8 -1
- package/dist/prosemirror/styles/styleToggleCascade.js +24 -1
- package/dist/prosemirror/tableGridMutation.d.ts +20 -0
- package/dist/prosemirror/tableGridMutation.js +30 -0
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +31 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +39 -0
- package/dist/prosemirror/utils/visualLineNavigation.js +27 -31
- package/dist/prosemirror/validation.js +23 -4
- package/dist/render-dom/HeaderFooterSelectionOverlay.js +20 -20
- package/dist/render-dom/RenderedDomContext.js +17 -34
- package/dist/server.d.ts +4 -4
- package/dist/server.js +2 -2
- package/dist/style-engine/styleEngine.d.ts +1 -1
- package/dist/utils/clipboard.js +1 -1
- package/dist/utils/findReplace.js +38 -21
- package/dist/version-comparison.d.ts +38 -44
- package/dist/version-comparison.js +270 -401
- package/package.json +3 -2
package/dist/ai-edits/apply.js
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import { expectParagraphAttrs,
|
|
2
|
-
import { paragraphPropertiesSnapshot } from "../prosemirror/commands/propertyChangeScope.js";
|
|
1
|
+
import { expectParagraphAttrs, expectRunPropertyChangeMarkAttrs } from "../prosemirror/attrs/index.js";
|
|
2
|
+
import { hasSerializableParagraphPropertyChange, paragraphPropertiesSnapshot } from "../prosemirror/commands/propertyChangeScope.js";
|
|
3
3
|
import { addedBreakCarrierBefore, finalParagraphsOf, paragraphEndsItsContainer } from "../prosemirror/containerFinalParagraph.js";
|
|
4
|
-
import { marksToTextFormatting } from "../prosemirror/conversion/fromProseDoc.js";
|
|
5
4
|
import { requestDeterministicParaIds } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
|
|
6
5
|
import { markStructuralChange } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
|
|
6
|
+
import { CLEARED_LIST_RENDERING_ATTRS } from "../prosemirror/listMarker.js";
|
|
7
7
|
import { directParagraphAlignment } from "../prosemirror/paragraphAlignment.js";
|
|
8
|
+
import { directParagraphSpacing, paragraphSpacingAttrPatch, paragraphSpacingEqual, paragraphSpacingFromFormatting, withDirectParagraphSpacing } from "../prosemirror/paragraphSpacing.js";
|
|
9
|
+
import { getDocumentNumbering } from "../prosemirror/plugins/documentNumbering.js";
|
|
8
10
|
import { getDocumentStyleResolver } from "../prosemirror/plugins/documentStyles.js";
|
|
11
|
+
import { selectRunFormattingCarrierRepresentations } from "../prosemirror/runFormattingInlineCarriers.js";
|
|
12
|
+
import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "../prosemirror/runFormattingReconciliation.js";
|
|
13
|
+
import { paragraphRunStyleContextAt } from "../prosemirror/runStyleFormatting.js";
|
|
14
|
+
import { listLevelAttrPatch } from "../prosemirror/styles/resolvedStyleAttrs.js";
|
|
9
15
|
import { isZeroWidthAnchor } from "../prosemirror/zeroWidthAnchors.js";
|
|
10
16
|
import { getFolioParaIdFromBlockId } from "../types/block-id.js";
|
|
11
17
|
import { stripBlockIdentityAttrs } from "./block-identity.js";
|
|
12
|
-
import { buildCleanBlockText } from "./clean-text.js";
|
|
18
|
+
import { buildCleanBlockText, resolveCleanTextRange } from "./clean-text.js";
|
|
13
19
|
import { hasInlineEmphasis, parseInlineEmphasisRuns, stripInlineEmphasisMarkers } from "./inline-emphasis.js";
|
|
14
|
-
import { hashFolioAIBlockText, isHiddenTableRow, normalizeFolioAIBlockText } from "./snapshot.js";
|
|
20
|
+
import { hashFolioAIBlockStructuralBoundaries, hashFolioAIBlockText, isHiddenTableRow, normalizeFolioAIBlockText } from "./snapshot.js";
|
|
15
21
|
import { mergeTableRectangle, mergeTrackedVerticalTableCells, splitTableRectangle, splitTrackedVerticalTableCell } from "./table-cell-mutations.js";
|
|
16
22
|
import { planTableMutations } from "./table-mutation-plan.js";
|
|
17
23
|
import { applyTableColumnDeletion, applyTableColumnInsertion, applyTableRowDeletion, applyTableRowInsertion, findTableColumnInsertion, findTableRowInsertion, getTableColumnCoordinateKey, markTableRowContent, splitCellParagraphTexts } from "./table-row-column-mutations.js";
|
|
@@ -19,6 +25,7 @@ import { findEnclosingTableCell, findEnclosingTableRow, findOutermostTableBounda
|
|
|
19
25
|
import { tableFromTemplate } from "./table-template.js";
|
|
20
26
|
import { wordDiffSessionFromOptions } from "./word-diff.js";
|
|
21
27
|
import { panic } from "better-result";
|
|
28
|
+
import { Mark } from "prosemirror-model";
|
|
22
29
|
import { TableMap } from "prosemirror-tables";
|
|
23
30
|
import { canJoin, canSplit } from "prosemirror-transform";
|
|
24
31
|
//#region src/ai-edits/apply.ts
|
|
@@ -43,6 +50,36 @@ const coarseWordDiff = (before, after) => {
|
|
|
43
50
|
text: after
|
|
44
51
|
}];
|
|
45
52
|
};
|
|
53
|
+
const commentMarkRanges = (doc, commentType, commentId) => {
|
|
54
|
+
const ranges = [];
|
|
55
|
+
doc.descendants((node, position) => {
|
|
56
|
+
for (const mark of node.marks) if (mark.type === commentType && mark.attrs["commentId"] === commentId) ranges.push({
|
|
57
|
+
from: position,
|
|
58
|
+
to: position + node.nodeSize,
|
|
59
|
+
mark
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
return ranges;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Replace an operation-local comment id only after its edit has succeeded.
|
|
66
|
+
* The provisional mark lives solely in the undispatched transaction, so an
|
|
67
|
+
* operation that refuses or produces no anchor has no external comment side
|
|
68
|
+
* effect and cannot leave an orphan comments.xml entry behind.
|
|
69
|
+
*/
|
|
70
|
+
const commitProvisionalComment = ({ tr, commentType, provisionalId, committedId }) => {
|
|
71
|
+
const ranges = commentMarkRanges(tr.doc, commentType, provisionalId);
|
|
72
|
+
if (ranges.length === 0) panic("A commented operation changed the document without producing a comment anchor");
|
|
73
|
+
if (provisionalId === committedId) return tr;
|
|
74
|
+
for (const { from, to, mark } of ranges) {
|
|
75
|
+
tr = tr.removeMark(from, to, mark);
|
|
76
|
+
tr = tr.addMark(from, to, commentType.create({
|
|
77
|
+
...mark.attrs,
|
|
78
|
+
commentId: committedId
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
return tr;
|
|
82
|
+
};
|
|
46
83
|
/**
|
|
47
84
|
* Operation types applied in `"suggested"` mode. Every produced revision — an
|
|
48
85
|
* inline mark, a whole-node `_suggestedInsert` marker, or a suggested
|
|
@@ -65,21 +102,6 @@ const SUGGESTED_SUPPORTED_OPERATION_TYPES = /* @__PURE__ */ new Set([
|
|
|
65
102
|
"insertTableColumn",
|
|
66
103
|
"deleteTableColumn"
|
|
67
104
|
]);
|
|
68
|
-
/**
|
|
69
|
-
* The attrs that render a list label, cleared together whenever a paragraph
|
|
70
|
-
* stops being a list item. `w:numPr` alone is not enough: the marker attrs the
|
|
71
|
-
* editor caches would keep drawing a label on a paragraph that is no longer in
|
|
72
|
-
* the list. One frozen record rather than a list repeated at each call site,
|
|
73
|
-
* because a list repeated is a list that drifts.
|
|
74
|
-
*/
|
|
75
|
-
const CLEARED_LIST_MARKER_ATTRS = Object.freeze({
|
|
76
|
-
listMarker: null,
|
|
77
|
-
listMarkerHidden: null,
|
|
78
|
-
listLevelNumFmts: null,
|
|
79
|
-
listLevelStarts: null,
|
|
80
|
-
listAbstractNumId: null,
|
|
81
|
-
listStartOverride: null
|
|
82
|
-
});
|
|
83
105
|
const REPLACE_BLOCK_IMPACT = {
|
|
84
106
|
text: {
|
|
85
107
|
changesStyle: false,
|
|
@@ -95,14 +117,35 @@ const REPLACE_BLOCK_IMPACT = {
|
|
|
95
117
|
}
|
|
96
118
|
};
|
|
97
119
|
const isResolvedReplaceBlockOperation = (item) => item.operation.type === "replaceBlock";
|
|
120
|
+
const isResolvedBaseReplaceBlockOperation = (item) => item.operation.type === "replaceBlock";
|
|
121
|
+
const hasRepresentableCommentAnchor = (item, mode) => {
|
|
122
|
+
switch (item.operation.type) {
|
|
123
|
+
case "insertAfterBlock":
|
|
124
|
+
case "insertBeforeBlock": return (item.insertTexts ?? [""]).some((text) => stripInlineEmphasisMarkers(text).length > 0);
|
|
125
|
+
case "insertSignatureTable": return false;
|
|
126
|
+
case "replaceInBlock":
|
|
127
|
+
case "replaceRange": return stripInlineEmphasisMarkers(item.operation.replace).length > 0 || mode !== "direct" && item.from < item.to;
|
|
128
|
+
case "replaceBlock": {
|
|
129
|
+
if (!isResolvedBaseReplaceBlockOperation(item)) panic("Resolved replaceBlock operation lost its impact discriminator");
|
|
130
|
+
const { changesText } = REPLACE_BLOCK_IMPACT[item.replaceBlockImpact];
|
|
131
|
+
if (!changesText) return item.from < item.to;
|
|
132
|
+
return stripInlineEmphasisMarkers(item.operation.text).length > 0 || mode !== "direct" && item.from < item.to;
|
|
133
|
+
}
|
|
134
|
+
case "deleteBlock": return mode !== "direct" && item.from < item.to;
|
|
135
|
+
default: return item.from < item.to;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const writesParagraphPropertyChange = (item) => item.operation.type === "setBlockParagraphProperties" || isResolvedReplaceBlockOperation(item) && REPLACE_BLOCK_IMPACT[item.replaceBlockImpact].changesStyle;
|
|
98
139
|
const resolveReplaceBlockImpact = ({ changesText, changesStyle }) => {
|
|
99
140
|
if (changesText) return changesStyle ? "textAndStyle" : "text";
|
|
100
141
|
if (changesStyle) return "style";
|
|
101
142
|
return panic("Cannot resolve a replaceBlock that changes neither text nor style");
|
|
102
143
|
};
|
|
103
|
-
const paragraphPropertiesPatch = ({ node, properties,
|
|
144
|
+
const paragraphPropertiesPatch = ({ node, properties, resolvedFormattingFromStyle, numbering = null }) => {
|
|
104
145
|
const attrs = expectParagraphAttrs(node);
|
|
105
146
|
const currentDirectAlignment = directParagraphAlignment(attrs);
|
|
147
|
+
const currentDirectSpacing = directParagraphSpacing(attrs);
|
|
148
|
+
const resolvedSpacingFromStyle = paragraphSpacingFromFormatting(resolvedFormattingFromStyle);
|
|
106
149
|
const patch = {};
|
|
107
150
|
let originalFormatting = attrs._originalFormatting === void 0 || attrs._originalFormatting === null ? void 0 : { ...attrs._originalFormatting };
|
|
108
151
|
let originalFormattingChanged = false;
|
|
@@ -110,8 +153,12 @@ const paragraphPropertiesPatch = ({ node, properties, resolvedAlignmentFromStyle
|
|
|
110
153
|
const styleChanged = nextStyleId !== void 0 && (attrs.styleId ?? null) !== nextStyleId;
|
|
111
154
|
if (styleChanged) {
|
|
112
155
|
patch["styleId"] = nextStyleId;
|
|
113
|
-
patch["alignmentFromStyle"] =
|
|
114
|
-
if (properties.alignment === void 0) patch["alignment"] = currentDirectAlignment ??
|
|
156
|
+
patch["alignmentFromStyle"] = resolvedFormattingFromStyle?.alignment;
|
|
157
|
+
if (properties.alignment === void 0) patch["alignment"] = currentDirectAlignment ?? resolvedFormattingFromStyle?.alignment ?? null;
|
|
158
|
+
if (properties.spacing === void 0) Object.assign(patch, paragraphSpacingAttrPatch({
|
|
159
|
+
direct: currentDirectSpacing,
|
|
160
|
+
inherited: resolvedSpacingFromStyle
|
|
161
|
+
}));
|
|
115
162
|
originalFormatting ??= {};
|
|
116
163
|
if (nextStyleId === null) Reflect.deleteProperty(originalFormatting, "styleId");
|
|
117
164
|
else originalFormatting.styleId = nextStyleId;
|
|
@@ -120,29 +167,39 @@ const paragraphPropertiesPatch = ({ node, properties, resolvedAlignmentFromStyle
|
|
|
120
167
|
}
|
|
121
168
|
if (properties.listLevel !== void 0) {
|
|
122
169
|
const numPr = node.attrs["numPr"];
|
|
123
|
-
const current = typeof numPr === "object" && numPr !== null && "ilvl" in numPr ? numPr.ilvl : void 0;
|
|
124
170
|
if (properties.listLevel === null) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
} else if (current !== properties.listLevel) {
|
|
171
|
+
patch["numPr"] = null;
|
|
172
|
+
Object.assign(patch, CLEARED_LIST_RENDERING_ATTRS);
|
|
173
|
+
} else {
|
|
130
174
|
const numId = typeof numPr === "object" && numPr !== null && "numId" in numPr ? numPr.numId : void 0;
|
|
131
|
-
|
|
132
|
-
|
|
175
|
+
if (typeof numId === "number") Object.assign(patch, listLevelAttrPatch(attrs, {
|
|
176
|
+
numId,
|
|
133
177
|
ilvl: properties.listLevel
|
|
134
|
-
};
|
|
178
|
+
}, numbering));
|
|
179
|
+
else {
|
|
180
|
+
patch["numPr"] = { ilvl: properties.listLevel };
|
|
181
|
+
Object.assign(patch, CLEARED_LIST_RENDERING_ATTRS);
|
|
182
|
+
}
|
|
135
183
|
}
|
|
136
184
|
}
|
|
137
185
|
if (properties.alignment !== void 0 && (styleChanged || (currentDirectAlignment ?? null) !== properties.alignment)) {
|
|
138
186
|
originalFormatting ??= {};
|
|
139
187
|
if (properties.alignment === null) Reflect.deleteProperty(originalFormatting, "alignment");
|
|
140
188
|
else originalFormatting.alignment = properties.alignment;
|
|
141
|
-
const alignmentFromStyle = properties.styleId === void 0 ? attrs.alignmentFromStyle :
|
|
189
|
+
const alignmentFromStyle = properties.styleId === void 0 ? attrs.alignmentFromStyle : resolvedFormattingFromStyle?.alignment;
|
|
142
190
|
patch["alignment"] = properties.alignment ?? alignmentFromStyle ?? null;
|
|
143
191
|
originalFormattingChanged = true;
|
|
144
192
|
}
|
|
145
|
-
if (
|
|
193
|
+
if (properties.spacing !== void 0 && (styleChanged || !paragraphSpacingEqual(currentDirectSpacing, properties.spacing))) {
|
|
194
|
+
const directSpacing = properties.spacing ?? void 0;
|
|
195
|
+
originalFormatting = withDirectParagraphSpacing(originalFormatting, directSpacing);
|
|
196
|
+
Object.assign(patch, paragraphSpacingAttrPatch({
|
|
197
|
+
direct: directSpacing,
|
|
198
|
+
inherited: resolvedSpacingFromStyle
|
|
199
|
+
}));
|
|
200
|
+
originalFormattingChanged = true;
|
|
201
|
+
}
|
|
202
|
+
if (originalFormattingChanged) patch["_originalFormatting"] = originalFormatting && Object.keys(originalFormatting).length > 0 ? originalFormatting : null;
|
|
146
203
|
return Object.keys(patch).length > 0 ? patch : null;
|
|
147
204
|
};
|
|
148
205
|
const REVISION_MARK_NAMES = /* @__PURE__ */ new Set(["insertion", "deletion"]);
|
|
@@ -201,7 +258,14 @@ const paragraphPropertiesBeforeBatch = (node, batchRevisionIds) => {
|
|
|
201
258
|
if (!earliestBatchChange) return paragraphPropertiesSnapshot(node);
|
|
202
259
|
return earliestBatchChange.previousFormatting ?? {};
|
|
203
260
|
};
|
|
204
|
-
const
|
|
261
|
+
const resolveFormattingFromStyle = ({ attrs, styleId, styleResolver }) => {
|
|
262
|
+
const resolved = styleResolver?.resolveParagraphStyle(styleId).paragraphFormatting;
|
|
263
|
+
if (resolved !== void 0) return resolved;
|
|
264
|
+
if ((styleId ?? void 0) !== (attrs.styleId ?? void 0)) return;
|
|
265
|
+
const fallback = {};
|
|
266
|
+
if (attrs.alignmentFromStyle !== void 0) fallback.alignment = attrs.alignmentFromStyle;
|
|
267
|
+
return Object.keys(fallback).length > 0 ? fallback : void 0;
|
|
268
|
+
};
|
|
205
269
|
const applyReplaceBlockStyleId = ({ item, tr, styleResolver, revisionInfo }) => {
|
|
206
270
|
if (item.operation.type !== "replaceBlock" || item.operation.styleId === void 0) return {
|
|
207
271
|
tr,
|
|
@@ -214,7 +278,7 @@ const applyReplaceBlockStyleId = ({ item, tr, styleResolver, revisionInfo }) =>
|
|
|
214
278
|
revisionId: null
|
|
215
279
|
};
|
|
216
280
|
const attrs = expectParagraphAttrs(block);
|
|
217
|
-
const
|
|
281
|
+
const resolvedFormattingFromStyle = resolveFormattingFromStyle({
|
|
218
282
|
attrs,
|
|
219
283
|
styleId: item.operation.styleId,
|
|
220
284
|
styleResolver
|
|
@@ -222,7 +286,7 @@ const applyReplaceBlockStyleId = ({ item, tr, styleResolver, revisionInfo }) =>
|
|
|
222
286
|
const patch = paragraphPropertiesPatch({
|
|
223
287
|
node: block,
|
|
224
288
|
properties: { styleId: item.operation.styleId },
|
|
225
|
-
|
|
289
|
+
resolvedFormattingFromStyle
|
|
226
290
|
});
|
|
227
291
|
if (patch === null) return {
|
|
228
292
|
tr,
|
|
@@ -247,141 +311,134 @@ const REPLACEMENT_BACKGROUND_CLEAR_FORMATTING = {
|
|
|
247
311
|
highlight: false,
|
|
248
312
|
runShading: false
|
|
249
313
|
};
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
highlight: "highlight",
|
|
259
|
-
runShading: "runShading"
|
|
260
|
-
};
|
|
261
|
-
const DIRECT_FONT_PROPERTIES = [
|
|
262
|
-
"fontFamily",
|
|
263
|
-
"fontSize",
|
|
264
|
-
"color"
|
|
265
|
-
];
|
|
266
|
-
const formattingMarkName = (property) => {
|
|
267
|
-
if (!Object.hasOwn(INLINE_FORMATTING_MARK_NAMES, property)) return null;
|
|
268
|
-
const name = Reflect.get(INLINE_FORMATTING_MARK_NAMES, property);
|
|
269
|
-
return typeof name === "string" ? name : null;
|
|
270
|
-
};
|
|
271
|
-
const formattingMarkAttrs = (property, value) => {
|
|
272
|
-
switch (property) {
|
|
273
|
-
case "underline": return { style: "single" };
|
|
274
|
-
case "fontFamily": return typeof value === "string" ? {
|
|
275
|
-
ascii: value,
|
|
276
|
-
hAnsi: value
|
|
277
|
-
} : null;
|
|
278
|
-
case "fontSizePt": return typeof value === "number" ? { size: value * 2 } : null;
|
|
279
|
-
case "color": return typeof value === "string" ? { rgb: value.replace(/^#/u, "").toUpperCase() } : null;
|
|
280
|
-
default: return {};
|
|
314
|
+
const includedFormattingProperty = (includedProperties, property) => includedProperties === void 0 || includedProperties.includes(property);
|
|
315
|
+
const patchAuthoredRunFormatting = ({ authoredFormatting, formatting, includedProperties }) => {
|
|
316
|
+
const next = { ...authoredFormatting };
|
|
317
|
+
for (const property of ["bold", "italic"]) {
|
|
318
|
+
const value = formatting[property];
|
|
319
|
+
if (value === void 0 || !includedFormattingProperty(includedProperties, property)) continue;
|
|
320
|
+
if (value === null) Reflect.deleteProperty(next, property);
|
|
321
|
+
else next[property] = value;
|
|
281
322
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
if (!markType) continue;
|
|
289
|
-
if (value !== false && value !== null) {
|
|
290
|
-
const attrs = formattingMarkAttrs(property, value);
|
|
291
|
-
if (attrs) tr.addMark(from, to, markType.create(attrs));
|
|
292
|
-
continue;
|
|
293
|
-
}
|
|
294
|
-
tr.removeMark(from, to, markType);
|
|
323
|
+
if (formatting.underline !== void 0 && includedFormattingProperty(includedProperties, "underline")) if (formatting.underline === null) delete next.underline;
|
|
324
|
+
else next.underline = { style: formatting.underline ? "single" : "none" };
|
|
325
|
+
if (formatting.strike !== void 0 && includedFormattingProperty(includedProperties, "strike")) {
|
|
326
|
+
delete next.doubleStrike;
|
|
327
|
+
if (formatting.strike === null) delete next.strike;
|
|
328
|
+
else next.strike = formatting.strike;
|
|
295
329
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
330
|
+
if (formatting.fontFamily !== void 0 && includedFormattingProperty(includedProperties, "fontFamily")) if (formatting.fontFamily === null) delete next.fontFamily;
|
|
331
|
+
else next.fontFamily = {
|
|
332
|
+
ascii: formatting.fontFamily,
|
|
333
|
+
hAnsi: formatting.fontFamily
|
|
334
|
+
};
|
|
335
|
+
if (formatting.fontSizePt !== void 0 && includedFormattingProperty(includedProperties, "fontSizePt")) if (formatting.fontSizePt === null) delete next.fontSize;
|
|
336
|
+
else next.fontSize = formatting.fontSizePt * 2;
|
|
337
|
+
if (formatting.color !== void 0 && includedFormattingProperty(includedProperties, "color")) if (formatting.color === null) delete next.color;
|
|
338
|
+
else next.color = { rgb: formatting.color.replace(/^#/u, "").toUpperCase() };
|
|
339
|
+
if (formatting.highlight === false && includedFormattingProperty(includedProperties, "highlight")) delete next.highlight;
|
|
340
|
+
if (formatting.runShading === false && includedFormattingProperty(includedProperties, "runShading")) delete next.shading;
|
|
341
|
+
return next;
|
|
342
|
+
};
|
|
343
|
+
const applyInlineFormatting = ({ tr, from, to, formatting, includedProperties, styleResolver }) => {
|
|
344
|
+
const representations = selectRunFormattingCarrierRepresentations({
|
|
345
|
+
doc: tr.doc,
|
|
299
346
|
from,
|
|
300
|
-
to
|
|
301
|
-
formatting,
|
|
302
|
-
...includedProperties ? { includedProperties } : {}
|
|
347
|
+
to
|
|
303
348
|
});
|
|
349
|
+
for (const representation of representations) {
|
|
350
|
+
const styleContext = paragraphRunStyleContextAt({
|
|
351
|
+
doc: tr.doc,
|
|
352
|
+
pos: representation.from,
|
|
353
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
354
|
+
});
|
|
355
|
+
const authoredFormatting = readAuthoredRunFormatting({
|
|
356
|
+
context: styleContext,
|
|
357
|
+
marks: representation.node.marks,
|
|
358
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
359
|
+
});
|
|
360
|
+
const marks = reconcileRunFormattingMarks({
|
|
361
|
+
authoredFormatting: patchAuthoredRunFormatting({
|
|
362
|
+
authoredFormatting,
|
|
363
|
+
formatting,
|
|
364
|
+
...includedProperties !== void 0 ? { includedProperties } : {}
|
|
365
|
+
}),
|
|
366
|
+
context: styleContext,
|
|
367
|
+
node: representation.node,
|
|
368
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
369
|
+
});
|
|
370
|
+
applyMarksToRunFormattingRepresentation({
|
|
371
|
+
tr,
|
|
372
|
+
representation,
|
|
373
|
+
marks
|
|
374
|
+
});
|
|
375
|
+
}
|
|
304
376
|
return tr;
|
|
305
377
|
};
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
formatting.fontFamily
|
|
313
|
-
],
|
|
314
|
-
[
|
|
315
|
-
"fontSize",
|
|
316
|
-
"fontSizePt",
|
|
317
|
-
formatting.fontSizePt
|
|
318
|
-
],
|
|
319
|
-
[
|
|
320
|
-
"color",
|
|
321
|
-
"color",
|
|
322
|
-
formatting.color
|
|
323
|
-
]
|
|
324
|
-
].filter(([, inputProperty, value]) => value !== void 0 && (!includedProperties || includedProperties.includes(inputProperty)));
|
|
325
|
-
const markType = schema.marks["runFormattingOverride"];
|
|
326
|
-
if (!markType || changed.length === 0) return;
|
|
327
|
-
tr.doc.nodesBetween(from, to, (node, pos) => {
|
|
328
|
-
if (!node.isText) return;
|
|
329
|
-
const segmentFrom = Math.max(from, pos);
|
|
330
|
-
const segmentTo = Math.min(to, pos + node.nodeSize);
|
|
331
|
-
const existing = node.marks.find((mark) => mark.type === markType);
|
|
332
|
-
const attrs = existing ? expectRunFormattingOverrideMarkAttrs(existing) : {};
|
|
333
|
-
const directFontProperties = new Set(attrs.directFontProperties);
|
|
334
|
-
for (const [property, , value] of changed) if (value === null) directFontProperties.delete(property);
|
|
335
|
-
else directFontProperties.add(property);
|
|
336
|
-
tr.removeMark(segmentFrom, segmentTo, markType);
|
|
337
|
-
const nextAttrs = {
|
|
338
|
-
...attrs,
|
|
339
|
-
directFontProperties: DIRECT_FONT_PROPERTIES.filter((property) => directFontProperties.has(property))
|
|
340
|
-
};
|
|
341
|
-
if (Object.entries(nextAttrs).some(([key, value]) => key === "directFontProperties" ? Array.isArray(value) && value.length > 0 : value !== null && value !== void 0)) tr.addMark(segmentFrom, segmentTo, markType.create(nextAttrs));
|
|
342
|
-
});
|
|
343
|
-
};
|
|
344
|
-
const directFontPropertyForFormattingProperty = (property) => {
|
|
345
|
-
switch (property) {
|
|
346
|
-
case "fontFamily": return "fontFamily";
|
|
347
|
-
case "fontSizePt": return "fontSize";
|
|
348
|
-
case "color": return "color";
|
|
349
|
-
default: return null;
|
|
378
|
+
const applyMarksToRunFormattingRepresentation = ({ tr, representation, marks }) => {
|
|
379
|
+
const { node, position, from, to } = representation;
|
|
380
|
+
if (Mark.sameSet(node.marks, marks)) return;
|
|
381
|
+
if (!node.isText) {
|
|
382
|
+
tr.setNodeMarkup(position, void 0, node.attrs, marks);
|
|
383
|
+
return;
|
|
350
384
|
}
|
|
385
|
+
for (const current of node.marks) if (!marks.some((candidate) => candidate.eq(current))) tr.removeMark(from, to, current.type);
|
|
386
|
+
for (const next of marks) if (!node.marks.some((candidate) => candidate.eq(next))) tr.addMark(from, to, next);
|
|
351
387
|
};
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
const isDirect = overrideMark ? (expectRunFormattingOverrideMarkAttrs(overrideMark).directFontProperties ?? []).includes(directFontProperty) : false;
|
|
359
|
-
if (value === false || value === null) return isDirect;
|
|
360
|
-
if (!isDirect) return true;
|
|
361
|
-
} else if (value === false || value === null) return mark !== void 0;
|
|
362
|
-
if (property === "underline") return mark?.attrs["style"] !== "single";
|
|
363
|
-
if (property === "fontFamily") return mark?.attrs["ascii"] !== value || mark?.attrs["hAnsi"] !== value;
|
|
364
|
-
if (property === "fontSizePt") return Number(mark?.attrs["size"]) !== Number(value) * 2;
|
|
365
|
-
if (property === "color") {
|
|
366
|
-
const current = mark?.attrs["rgb"];
|
|
367
|
-
return (typeof current === "string" ? current.replace(/^#/u, "").toUpperCase() : null) !== String(value).replace(/^#/u, "").toUpperCase();
|
|
388
|
+
const sameDefinedFormattingValue = (left, right) => {
|
|
389
|
+
if (left === right) return true;
|
|
390
|
+
if (typeof left !== "object" || left === null || typeof right !== "object" || right === null) return false;
|
|
391
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
392
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;
|
|
393
|
+
return left.every((value, index) => sameDefinedFormattingValue(value, right.at(index)));
|
|
368
394
|
}
|
|
369
|
-
|
|
395
|
+
const leftEntries = Object.entries(left).filter(([, value]) => value !== void 0);
|
|
396
|
+
const rightEntries = Object.entries(right).filter(([, value]) => value !== void 0);
|
|
397
|
+
if (leftEntries.length !== rightEntries.length) return false;
|
|
398
|
+
return leftEntries.every(([property, value]) => Object.hasOwn(right, property) && sameDefinedFormattingValue(value, Reflect.get(right, property)));
|
|
370
399
|
};
|
|
371
|
-
const
|
|
400
|
+
const formattingChangesForAuthoredFormatting = (authoredFormatting, formatting) => {
|
|
372
401
|
const changes = [];
|
|
373
|
-
for (const
|
|
402
|
+
for (const property of [
|
|
403
|
+
"bold",
|
|
404
|
+
"italic",
|
|
405
|
+
"underline",
|
|
406
|
+
"strike",
|
|
407
|
+
"fontFamily",
|
|
408
|
+
"fontSizePt",
|
|
409
|
+
"color",
|
|
410
|
+
"highlight",
|
|
411
|
+
"runShading"
|
|
412
|
+
]) {
|
|
413
|
+
if (formatting[property] === void 0) continue;
|
|
414
|
+
const next = patchAuthoredRunFormatting({
|
|
415
|
+
authoredFormatting,
|
|
416
|
+
formatting,
|
|
417
|
+
includedProperties: [property]
|
|
418
|
+
});
|
|
419
|
+
if (!sameDefinedFormattingValue(authoredFormatting, next)) changes.push(property);
|
|
420
|
+
}
|
|
374
421
|
return changes;
|
|
375
422
|
};
|
|
376
|
-
const clearReplacementBackground = ({ tr, schema, from, to, mode,
|
|
377
|
-
if (![schema.marks["highlight"], schema.marks["runShading"]].some((markType) => markType !== void 0 && tr.doc.rangeHasMark(from, to, markType))) return
|
|
378
|
-
|
|
379
|
-
tr,
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
423
|
+
const clearReplacementBackground = ({ tr, schema, from, to, mode, revisionIdSeed, author, date, initials, suggestionId = null, styleResolver }) => {
|
|
424
|
+
if (![schema.marks["highlight"], schema.marks["runShading"]].some((markType) => markType !== void 0 && tr.doc.rangeHasMark(from, to, markType))) return {
|
|
425
|
+
type: "applied",
|
|
426
|
+
transaction: tr,
|
|
427
|
+
revisionIds: [],
|
|
428
|
+
nextRevisionId: revisionIdSeed
|
|
429
|
+
};
|
|
430
|
+
if (mode === "direct") return {
|
|
431
|
+
type: "applied",
|
|
432
|
+
transaction: applyInlineFormatting({
|
|
433
|
+
tr,
|
|
434
|
+
from,
|
|
435
|
+
to,
|
|
436
|
+
formatting: REPLACEMENT_BACKGROUND_CLEAR_FORMATTING,
|
|
437
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
438
|
+
}),
|
|
439
|
+
revisionIds: [],
|
|
440
|
+
nextRevisionId: revisionIdSeed
|
|
441
|
+
};
|
|
385
442
|
return applyTrackedInlineFormatting({
|
|
386
443
|
tr,
|
|
387
444
|
schema,
|
|
@@ -389,26 +446,85 @@ const clearReplacementBackground = ({ tr, schema, from, to, mode, revisionId, au
|
|
|
389
446
|
from,
|
|
390
447
|
to,
|
|
391
448
|
formatting: REPLACEMENT_BACKGROUND_CLEAR_FORMATTING,
|
|
392
|
-
|
|
449
|
+
revisionIdSeed,
|
|
393
450
|
author,
|
|
394
451
|
date,
|
|
395
452
|
initials,
|
|
396
|
-
suggestionId
|
|
453
|
+
suggestionId,
|
|
454
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
397
455
|
});
|
|
398
456
|
};
|
|
399
|
-
const applyTrackedInlineFormatting = ({ tr, schema, doc, from, to, formatting,
|
|
457
|
+
const applyTrackedInlineFormatting = ({ tr, schema, doc, from, to, formatting, revisionIdSeed, author, date, initials, suggestionId = null, styleResolver }) => {
|
|
400
458
|
const propertyChangeType = schema.marks["runPropertyChange"];
|
|
401
|
-
if (!propertyChangeType) return
|
|
459
|
+
if (!propertyChangeType) return {
|
|
460
|
+
type: "applied",
|
|
461
|
+
transaction: tr,
|
|
462
|
+
revisionIds: [],
|
|
463
|
+
nextRevisionId: revisionIdSeed
|
|
464
|
+
};
|
|
402
465
|
const segments = [];
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
466
|
+
let hasPendingRunPropertyChange = false;
|
|
467
|
+
const representations = selectRunFormattingCarrierRepresentations({
|
|
468
|
+
doc,
|
|
469
|
+
from,
|
|
470
|
+
to
|
|
471
|
+
});
|
|
472
|
+
for (const representation of representations) {
|
|
473
|
+
const { node } = representation;
|
|
474
|
+
const styleContext = paragraphRunStyleContextAt({
|
|
475
|
+
doc,
|
|
476
|
+
pos: representation.from,
|
|
477
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
478
|
+
});
|
|
479
|
+
const previousFormatting = readAuthoredRunFormatting({
|
|
480
|
+
context: styleContext,
|
|
481
|
+
marks: node.marks,
|
|
482
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
483
|
+
});
|
|
484
|
+
const includedProperties = formattingChangesForAuthoredFormatting(previousFormatting, formatting);
|
|
485
|
+
if (includedProperties.length === 0) continue;
|
|
410
486
|
const existingMark = node.marks.find((mark) => mark.type === propertyChangeType);
|
|
411
|
-
|
|
487
|
+
if (existingMark && expectRunPropertyChangeMarkAttrs(existingMark).changes.length > 0) {
|
|
488
|
+
hasPendingRunPropertyChange = true;
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const formattingMarks = reconcileRunFormattingMarks({
|
|
492
|
+
authoredFormatting: patchAuthoredRunFormatting({
|
|
493
|
+
authoredFormatting: previousFormatting,
|
|
494
|
+
formatting,
|
|
495
|
+
includedProperties
|
|
496
|
+
}),
|
|
497
|
+
context: styleContext,
|
|
498
|
+
node,
|
|
499
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
500
|
+
});
|
|
501
|
+
segments.push({
|
|
502
|
+
formattingMarks,
|
|
503
|
+
representation,
|
|
504
|
+
includedProperties,
|
|
505
|
+
previousFormatting
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
if (hasPendingRunPropertyChange) return {
|
|
509
|
+
type: "pendingRunPropertyChange",
|
|
510
|
+
transaction: tr,
|
|
511
|
+
revisionIds: [],
|
|
512
|
+
nextRevisionId: revisionIdSeed
|
|
513
|
+
};
|
|
514
|
+
if (segments.length === 0) return {
|
|
515
|
+
type: "applied",
|
|
516
|
+
transaction: tr,
|
|
517
|
+
revisionIds: [],
|
|
518
|
+
nextRevisionId: revisionIdSeed
|
|
519
|
+
};
|
|
520
|
+
const suggestionAttrs = suggestionId === null ? {} : {
|
|
521
|
+
provenance: "suggested",
|
|
522
|
+
suggestionId
|
|
523
|
+
};
|
|
524
|
+
const revisionIds = [];
|
|
525
|
+
for (const segment of segments) {
|
|
526
|
+
const revisionId = revisionIdSeed + revisionIds.length;
|
|
527
|
+
revisionIds.push(revisionId);
|
|
412
528
|
const change = {
|
|
413
529
|
type: "runPropertyChange",
|
|
414
530
|
info: {
|
|
@@ -417,35 +533,24 @@ const applyTrackedInlineFormatting = ({ tr, schema, doc, from, to, formatting, r
|
|
|
417
533
|
date,
|
|
418
534
|
...initials ? { initials } : {}
|
|
419
535
|
},
|
|
420
|
-
...Object.keys(previousFormatting).length > 0 ? { previousFormatting } : {}
|
|
536
|
+
...Object.keys(segment.previousFormatting).length > 0 ? { previousFormatting: segment.previousFormatting } : {}
|
|
421
537
|
};
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
});
|
|
428
|
-
});
|
|
429
|
-
if (segments.length === 0) return tr;
|
|
430
|
-
const suggestionAttrs = suggestionId === null ? {} : {
|
|
431
|
-
provenance: "suggested",
|
|
432
|
-
suggestionId
|
|
433
|
-
};
|
|
434
|
-
for (const segment of segments) {
|
|
435
|
-
applyInlineFormatting({
|
|
538
|
+
const marks = propertyChangeType.create({
|
|
539
|
+
changes: [change],
|
|
540
|
+
...suggestionAttrs
|
|
541
|
+
}).addToSet(segment.formattingMarks);
|
|
542
|
+
applyMarksToRunFormattingRepresentation({
|
|
436
543
|
tr,
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
to: segment.to,
|
|
440
|
-
formatting,
|
|
441
|
-
includedProperties: segment.includedProperties
|
|
544
|
+
representation: segment.representation,
|
|
545
|
+
marks
|
|
442
546
|
});
|
|
443
|
-
tr.addMark(segment.from, segment.to, propertyChangeType.create({
|
|
444
|
-
changes: segment.changes,
|
|
445
|
-
...suggestionAttrs
|
|
446
|
-
}));
|
|
447
547
|
}
|
|
448
|
-
return
|
|
548
|
+
return {
|
|
549
|
+
type: "applied",
|
|
550
|
+
transaction: tr,
|
|
551
|
+
revisionIds,
|
|
552
|
+
nextRevisionId: revisionIdSeed + revisionIds.length
|
|
553
|
+
};
|
|
449
554
|
};
|
|
450
555
|
/**
|
|
451
556
|
* Module-scoped monotonic counter for tracked-change revision ids.
|
|
@@ -686,6 +791,7 @@ const buildEmphasisInlineContent = (schema, text, baseMarks) => {
|
|
|
686
791
|
};
|
|
687
792
|
const isBatchableParagraphInsertion = (item, mode) => {
|
|
688
793
|
if (item.operation.type !== "insertAfterBlock" && item.operation.type !== "insertBeforeBlock") return false;
|
|
794
|
+
if (item.commentText !== void 0) return false;
|
|
689
795
|
const insertTexts = item.insertTexts ?? [""];
|
|
690
796
|
const isEmptyInsert = insertTexts.length === 1 && insertTexts[0]?.length === 0;
|
|
691
797
|
return !(mode === "tracked-changes" && item.operation.pageBreakBefore === true && isEmptyInsert);
|
|
@@ -781,6 +887,7 @@ const withRotatedAddedFinalBreaks = ({ tr, batchRevisionIds, revisionSeed, autho
|
|
|
781
887
|
const liveCurrent = next.doc.nodeAt(current.position);
|
|
782
888
|
if (!liveCurrent || liveCurrent.type.name !== final.type.name) panic("A final-mark rotation lost its paragraph", { position: current.position });
|
|
783
889
|
const existing = expectParagraphAttrs(liveCurrent)._propertyChanges;
|
|
890
|
+
if (hasSerializableParagraphPropertyChange(existing)) panic("A final-mark rotation cannot append a second w:pPrChange", { position: current.position });
|
|
784
891
|
const revisionId = nextRevisionId++;
|
|
785
892
|
next = next.setNodeMarkup(current.position, void 0, {
|
|
786
893
|
...liveCurrent.attrs,
|
|
@@ -810,7 +917,7 @@ const withRotatedAddedFinalBreaks = ({ tr, batchRevisionIds, revisionSeed, autho
|
|
|
810
917
|
synthesizedRevisions
|
|
811
918
|
};
|
|
812
919
|
};
|
|
813
|
-
const buildInsertedParagraphs = ({ item, schema,
|
|
920
|
+
const buildInsertedParagraphs = ({ item, schema, formattingFromStyle, mode, author, date, initials, commentMark, suggestionId, revisionSeed, isPairedMove, numbering }) => {
|
|
814
921
|
const operation = item.operation;
|
|
815
922
|
if (operation.type !== "insertAfterBlock" && operation.type !== "insertBeforeBlock") panic("Only paragraph insertions can build inserted paragraphs", { type: operation.type });
|
|
816
923
|
const insertionType = schema.marks["insertion"];
|
|
@@ -823,7 +930,12 @@ const buildInsertedParagraphs = ({ item, schema, alignmentFromStyle, mode, autho
|
|
|
823
930
|
suggestionId
|
|
824
931
|
} : {}
|
|
825
932
|
};
|
|
826
|
-
const baseAttrs = operation.inheritFormatting === false ? {} :
|
|
933
|
+
const baseAttrs = operation.inheritFormatting === false ? {} : {
|
|
934
|
+
...stripBlockIdentityAttrs(item.blockNode.attrs),
|
|
935
|
+
_propertyChanges: null,
|
|
936
|
+
pPrMark: null,
|
|
937
|
+
_suggestedInsert: null
|
|
938
|
+
};
|
|
827
939
|
const insertTexts = item.insertTexts ?? [""];
|
|
828
940
|
const revisionIds = [];
|
|
829
941
|
const nodes = [];
|
|
@@ -847,33 +959,51 @@ const buildInsertedParagraphs = ({ item, schema, alignmentFromStyle, mode, autho
|
|
|
847
959
|
const content = text.length > 0 ? buildEmphasisInlineContent(schema, text, marks) : null;
|
|
848
960
|
const attrs = isFirstParagraph ? { ...baseAttrs } : {};
|
|
849
961
|
if (isFirstParagraph && operation.pageBreakBefore === true) attrs["pageBreakBefore"] = true;
|
|
850
|
-
|
|
962
|
+
const listLevel = operation.listLevel;
|
|
963
|
+
if (isFirstParagraph && listLevel === null) {
|
|
851
964
|
attrs["numPr"] = null;
|
|
852
|
-
Object.assign(attrs,
|
|
853
|
-
} else if (isFirstParagraph &&
|
|
854
|
-
const anchorNumPr = baseAttrs
|
|
965
|
+
Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
|
|
966
|
+
} else if (isFirstParagraph && typeof listLevel === "number") {
|
|
967
|
+
const anchorNumPr = Reflect.get(baseAttrs, "numPr");
|
|
855
968
|
const numId = typeof anchorNumPr === "object" && anchorNumPr !== null && "numId" in anchorNumPr ? anchorNumPr.numId : void 0;
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
ilvl:
|
|
859
|
-
};
|
|
969
|
+
if (typeof numId === "number") Object.assign(attrs, listLevelAttrPatch(operation.inheritFormatting === false ? {} : expectParagraphAttrs(item.blockNode), {
|
|
970
|
+
numId,
|
|
971
|
+
ilvl: listLevel
|
|
972
|
+
}, numbering));
|
|
973
|
+
else {
|
|
974
|
+
attrs["numPr"] = { ilvl: listLevel };
|
|
975
|
+
Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
|
|
976
|
+
}
|
|
860
977
|
}
|
|
861
978
|
if (isFirstParagraph && operation.styleId !== void 0) {
|
|
862
979
|
attrs["styleId"] = operation.styleId;
|
|
863
|
-
if (operation.inheritFormatting !== false && operation.styleId !== null) Object.assign(attrs,
|
|
980
|
+
if (operation.inheritFormatting !== false && operation.styleId !== null) Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
|
|
864
981
|
}
|
|
865
|
-
if (isFirstParagraph && (operation.styleId !== void 0 || operation.alignment !== void 0)) {
|
|
982
|
+
if (isFirstParagraph && (operation.styleId !== void 0 || operation.alignment !== void 0 || operation.spacing !== void 0)) {
|
|
866
983
|
const inheritedDirectAlignment = operation.inheritFormatting === false ? void 0 : directParagraphAlignment(expectParagraphAttrs(item.blockNode));
|
|
984
|
+
const inheritedDirectSpacing = operation.inheritFormatting === false ? void 0 : directParagraphSpacing(expectParagraphAttrs(item.blockNode));
|
|
867
985
|
const directAlignment = operation.alignment === void 0 ? inheritedDirectAlignment : operation.alignment ?? void 0;
|
|
868
|
-
|
|
869
|
-
attrs["
|
|
986
|
+
const directSpacing = operation.spacing === void 0 ? inheritedDirectSpacing : operation.spacing ?? void 0;
|
|
987
|
+
attrs["alignmentFromStyle"] = formattingFromStyle?.alignment;
|
|
988
|
+
attrs["alignment"] = directAlignment ?? formattingFromStyle?.alignment ?? null;
|
|
870
989
|
const sourceFormatting = attrs["_originalFormatting"];
|
|
871
|
-
|
|
872
|
-
if (operation.styleId !== void 0)
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
990
|
+
let originalFormatting = typeof sourceFormatting === "object" && sourceFormatting !== null ? { ...sourceFormatting } : void 0;
|
|
991
|
+
if (operation.styleId !== void 0) {
|
|
992
|
+
originalFormatting ??= {};
|
|
993
|
+
if (operation.styleId === null) Reflect.deleteProperty(originalFormatting, "styleId");
|
|
994
|
+
else originalFormatting.styleId = operation.styleId;
|
|
995
|
+
}
|
|
996
|
+
if (operation.alignment !== void 0 || inheritedDirectAlignment !== void 0) {
|
|
997
|
+
originalFormatting ??= {};
|
|
998
|
+
if (directAlignment === void 0) Reflect.deleteProperty(originalFormatting, "alignment");
|
|
999
|
+
else originalFormatting.alignment = directAlignment;
|
|
1000
|
+
}
|
|
1001
|
+
if (operation.spacing !== void 0) originalFormatting = withDirectParagraphSpacing(originalFormatting, directSpacing);
|
|
1002
|
+
if (operation.styleId !== void 0 || operation.spacing !== void 0) Object.assign(attrs, paragraphSpacingAttrPatch({
|
|
1003
|
+
direct: directSpacing,
|
|
1004
|
+
inherited: paragraphSpacingFromFormatting(formattingFromStyle)
|
|
1005
|
+
}));
|
|
1006
|
+
attrs["_originalFormatting"] = originalFormatting && Object.keys(originalFormatting).length > 0 ? originalFormatting : null;
|
|
877
1007
|
}
|
|
878
1008
|
if (isSuggested && suggestionId !== null && paragraphRevisionId !== null) attrs["_suggestedInsert"] = {
|
|
879
1009
|
suggestionId,
|
|
@@ -914,13 +1044,37 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
914
1044
|
const insertionType = view.state.schema.marks["insertion"];
|
|
915
1045
|
const deletionType = view.state.schema.marks["deletion"];
|
|
916
1046
|
const commentType = view.state.schema.marks["comment"];
|
|
1047
|
+
const occupiedCommentIds = /* @__PURE__ */ new Set();
|
|
1048
|
+
if (commentType) view.state.doc.descendants((node) => {
|
|
1049
|
+
for (const mark of node.marks) {
|
|
1050
|
+
if (mark.type !== commentType) continue;
|
|
1051
|
+
const commentId = mark.attrs["commentId"];
|
|
1052
|
+
if (typeof commentId === "number") occupiedCommentIds.add(commentId);
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
let provisionalCommentIdCursor = Number.MIN_SAFE_INTEGER;
|
|
1056
|
+
const reserveProvisionalCommentId = () => {
|
|
1057
|
+
while (occupiedCommentIds.has(provisionalCommentIdCursor)) provisionalCommentIdCursor += 1;
|
|
1058
|
+
const id = provisionalCommentIdCursor;
|
|
1059
|
+
provisionalCommentIdCursor += 1;
|
|
1060
|
+
occupiedCommentIds.add(id);
|
|
1061
|
+
return id;
|
|
1062
|
+
};
|
|
1063
|
+
const allocateCommittedCommentId = (text) => {
|
|
1064
|
+
if (createCommentId === void 0) panic("A resolved comment operation lost its comment-id allocator");
|
|
1065
|
+
const id = createCommentId(text);
|
|
1066
|
+
if (!Number.isSafeInteger(id) || occupiedCommentIds.has(id)) panic("A comment-id allocator returned an invalid or duplicate id", { id });
|
|
1067
|
+
occupiedCommentIds.add(id);
|
|
1068
|
+
return id;
|
|
1069
|
+
};
|
|
917
1070
|
const styleResolver = getDocumentStyleResolver(view.state);
|
|
918
|
-
const
|
|
1071
|
+
const numbering = getDocumentNumbering(view.state);
|
|
1072
|
+
const formattingFromStyleForInsertion = (item) => {
|
|
919
1073
|
if (item.operation.type !== "insertAfterBlock" && item.operation.type !== "insertBeforeBlock") return;
|
|
920
1074
|
const anchorAttrs = expectParagraphAttrs(item.blockNode);
|
|
921
1075
|
const inheritedStyleId = item.operation.inheritFormatting === false ? null : anchorAttrs.styleId;
|
|
922
1076
|
const styleId = item.operation.styleId !== void 0 ? item.operation.styleId : inheritedStyleId;
|
|
923
|
-
return
|
|
1077
|
+
return resolveFormattingFromStyle({
|
|
924
1078
|
attrs: anchorAttrs,
|
|
925
1079
|
styleId,
|
|
926
1080
|
styleResolver
|
|
@@ -964,6 +1118,13 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
964
1118
|
});
|
|
965
1119
|
continue;
|
|
966
1120
|
}
|
|
1121
|
+
if (commentText !== void 0 && !hasRepresentableCommentAnchor(resolution.operation, mode)) {
|
|
1122
|
+
skipped.push({
|
|
1123
|
+
id: operation.id,
|
|
1124
|
+
reason: "unsupportedBlock"
|
|
1125
|
+
});
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
967
1128
|
const deletion = resolution.operation.tableRowDeletion;
|
|
968
1129
|
if (deletion) {
|
|
969
1130
|
const rowKey = `${deletion.tablePosition}:${deletion.rowIndex}`;
|
|
@@ -993,11 +1154,10 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
993
1154
|
code: "splitMultilineText",
|
|
994
1155
|
paragraphCount: resolution.operation.insertTexts?.length ?? 1
|
|
995
1156
|
});
|
|
996
|
-
const commentId = commentText !== void 0 ? createCommentId?.(commentText) : void 0;
|
|
997
1157
|
resolved.push({
|
|
998
1158
|
...resolution.operation,
|
|
999
1159
|
originalIndex: index,
|
|
1000
|
-
...
|
|
1160
|
+
...commentText !== void 0 && { commentText }
|
|
1001
1161
|
});
|
|
1002
1162
|
}
|
|
1003
1163
|
const tablePlan = planTableMutations(resolved.map((item) => ({
|
|
@@ -1040,6 +1200,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1040
1200
|
}
|
|
1041
1201
|
let tr = view.state.tr;
|
|
1042
1202
|
const revisionIdReservation = executableResolved.reduce((total, item) => total + estimateRevisionIdReservation(item), 0);
|
|
1203
|
+
const ownsSharedRevisionIdCursor = revisionIdSeed === void 0 && revisionStamp === void 0;
|
|
1043
1204
|
let revisionSeed = revisionIdSeed ?? revisionStamp?.idSeed ?? nextRevisionSeed(revisionIdReservation);
|
|
1044
1205
|
const date = revisionStamp?.date ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1045
1206
|
const insertedColumnCounts = /* @__PURE__ */ new Map();
|
|
@@ -1071,6 +1232,17 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1071
1232
|
for (let executionIndex = 0; executionIndex < executionOrder.length; executionIndex++) {
|
|
1072
1233
|
const item = executionOrder[executionIndex];
|
|
1073
1234
|
if (!item) panic("The operation execution index exceeded the resolved plan", { executionIndex });
|
|
1235
|
+
if (mode === "tracked-changes" && writesParagraphPropertyChange(item)) {
|
|
1236
|
+
const livePosition = tr.mapping.map(item.blockFrom);
|
|
1237
|
+
const liveBlock = tr.doc.nodeAt(livePosition) ?? item.blockNode;
|
|
1238
|
+
if (hasSerializableParagraphPropertyChange(liveBlock.type.name === "paragraph" ? expectParagraphAttrs(liveBlock)._propertyChanges : void 0)) {
|
|
1239
|
+
skipped.push({
|
|
1240
|
+
id: item.operation.id,
|
|
1241
|
+
reason: "pendingParagraphPropertyChange"
|
|
1242
|
+
});
|
|
1243
|
+
continue;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1074
1246
|
if (isBatchableParagraphInsertion(item, mode)) {
|
|
1075
1247
|
const insertionRun = [item];
|
|
1076
1248
|
for (let lookahead = executionIndex + 1; lookahead < executionOrder.length; lookahead++) {
|
|
@@ -1083,25 +1255,24 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1083
1255
|
const runApplied = [];
|
|
1084
1256
|
for (const insertion of insertionRun) {
|
|
1085
1257
|
const insertionSuggestionId = isSuggested ? insertion.operation.suggestionId ?? insertion.operation.id : null;
|
|
1086
|
-
const insertionCommentMark = insertion.commentId !== void 0 && commentType ? commentType.create({ commentId: insertion.commentId }) : null;
|
|
1087
1258
|
const built = buildInsertedParagraphs({
|
|
1088
1259
|
item: insertion,
|
|
1089
1260
|
schema: view.state.schema,
|
|
1090
|
-
|
|
1261
|
+
formattingFromStyle: formattingFromStyleForInsertion(insertion),
|
|
1091
1262
|
mode,
|
|
1092
1263
|
author,
|
|
1093
1264
|
date,
|
|
1094
1265
|
initials,
|
|
1095
|
-
commentMark:
|
|
1266
|
+
commentMark: null,
|
|
1096
1267
|
suggestionId: insertionSuggestionId,
|
|
1097
1268
|
revisionSeed,
|
|
1098
|
-
isPairedMove
|
|
1269
|
+
isPairedMove,
|
|
1270
|
+
numbering
|
|
1099
1271
|
});
|
|
1100
1272
|
revisionSeed = built.nextRevisionId;
|
|
1101
1273
|
nodeGroups.push(built.nodes);
|
|
1102
1274
|
runApplied.push({
|
|
1103
1275
|
id: insertion.operation.id,
|
|
1104
|
-
...insertion.commentId !== void 0 && { commentId: insertion.commentId },
|
|
1105
1276
|
...built.revisionIds[0] !== void 0 && {
|
|
1106
1277
|
revisionId: built.revisionIds[0],
|
|
1107
1278
|
revisionIds: built.revisionIds
|
|
@@ -1117,7 +1288,8 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1117
1288
|
continue;
|
|
1118
1289
|
}
|
|
1119
1290
|
}
|
|
1120
|
-
const
|
|
1291
|
+
const provisionalCommentId = item.commentText !== void 0 ? reserveProvisionalCommentId() : void 0;
|
|
1292
|
+
const commentMark = provisionalCommentId !== void 0 && commentType ? commentType.create({ commentId: provisionalCommentId }) : null;
|
|
1121
1293
|
const stepsBefore = tr.steps.length;
|
|
1122
1294
|
let appliedRevisionIds;
|
|
1123
1295
|
if (isSuggested && !SUGGESTED_SUPPORTED_OPERATION_TYPES.has(item.operation.type)) {
|
|
@@ -1135,8 +1307,9 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1135
1307
|
suggestionId
|
|
1136
1308
|
} : {}
|
|
1137
1309
|
};
|
|
1310
|
+
let operationRevisionSeed = revisionSeed;
|
|
1138
1311
|
const structuralRevision = producesTrackedChanges ? {
|
|
1139
|
-
revisionId:
|
|
1312
|
+
revisionId: operationRevisionSeed,
|
|
1140
1313
|
author,
|
|
1141
1314
|
date,
|
|
1142
1315
|
...trackedRevisionExtras
|
|
@@ -1144,22 +1317,32 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1144
1317
|
switch (item.operation.type) {
|
|
1145
1318
|
case "replaceInBlock":
|
|
1146
1319
|
case "replaceRange": {
|
|
1147
|
-
const revisionIdDelete =
|
|
1148
|
-
const revisionIdInsert =
|
|
1149
|
-
const
|
|
1320
|
+
const revisionIdDelete = operationRevisionSeed;
|
|
1321
|
+
const revisionIdInsert = producesTrackedChanges ? operationRevisionSeed + 1 : operationRevisionSeed;
|
|
1322
|
+
const revisionIdBackgroundSeed = producesTrackedChanges ? operationRevisionSeed + 2 : operationRevisionSeed;
|
|
1150
1323
|
const stepsBeforeBackgroundClear = tr.steps.length;
|
|
1151
|
-
|
|
1324
|
+
const backgroundResult = clearReplacementBackground({
|
|
1152
1325
|
tr,
|
|
1153
1326
|
schema: view.state.schema,
|
|
1154
1327
|
from: item.from,
|
|
1155
1328
|
to: item.to,
|
|
1156
1329
|
mode,
|
|
1157
|
-
|
|
1330
|
+
revisionIdSeed: revisionIdBackgroundSeed,
|
|
1158
1331
|
author,
|
|
1159
1332
|
date,
|
|
1160
1333
|
initials,
|
|
1161
|
-
suggestionId
|
|
1334
|
+
suggestionId,
|
|
1335
|
+
styleResolver
|
|
1162
1336
|
});
|
|
1337
|
+
if (backgroundResult.type === "pendingRunPropertyChange") {
|
|
1338
|
+
skipped.push({
|
|
1339
|
+
id: item.operation.id,
|
|
1340
|
+
reason: backgroundResult.type
|
|
1341
|
+
});
|
|
1342
|
+
continue;
|
|
1343
|
+
}
|
|
1344
|
+
tr = backgroundResult.transaction;
|
|
1345
|
+
operationRevisionSeed = backgroundResult.nextRevisionId;
|
|
1163
1346
|
const clearedBackground = tr.steps.length > stepsBeforeBackgroundClear;
|
|
1164
1347
|
tr = applyTextReplacement({
|
|
1165
1348
|
tr,
|
|
@@ -1177,7 +1360,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1177
1360
|
if (producesTrackedChanges) appliedRevisionIds = [
|
|
1178
1361
|
revisionIdDelete,
|
|
1179
1362
|
revisionIdInsert,
|
|
1180
|
-
...clearedBackground ?
|
|
1363
|
+
...clearedBackground ? backgroundResult.revisionIds : []
|
|
1181
1364
|
];
|
|
1182
1365
|
break;
|
|
1183
1366
|
}
|
|
@@ -1186,44 +1369,52 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1186
1369
|
break;
|
|
1187
1370
|
case "formatRange":
|
|
1188
1371
|
if (producesTrackedChanges) {
|
|
1189
|
-
const
|
|
1190
|
-
tr = applyTrackedInlineFormatting({
|
|
1372
|
+
const formattingResult = applyTrackedInlineFormatting({
|
|
1191
1373
|
tr,
|
|
1192
1374
|
schema: view.state.schema,
|
|
1193
1375
|
doc: tr.doc,
|
|
1194
1376
|
from: item.from,
|
|
1195
1377
|
to: item.to,
|
|
1196
1378
|
formatting: item.operation.formatting,
|
|
1197
|
-
|
|
1379
|
+
revisionIdSeed: operationRevisionSeed,
|
|
1198
1380
|
author,
|
|
1199
1381
|
date,
|
|
1200
1382
|
initials,
|
|
1201
|
-
suggestionId
|
|
1383
|
+
suggestionId,
|
|
1384
|
+
styleResolver
|
|
1202
1385
|
});
|
|
1203
|
-
|
|
1386
|
+
if (formattingResult.type === "pendingRunPropertyChange") {
|
|
1387
|
+
skipped.push({
|
|
1388
|
+
id: item.operation.id,
|
|
1389
|
+
reason: formattingResult.type
|
|
1390
|
+
});
|
|
1391
|
+
continue;
|
|
1392
|
+
}
|
|
1393
|
+
tr = formattingResult.transaction;
|
|
1394
|
+
operationRevisionSeed = formattingResult.nextRevisionId;
|
|
1395
|
+
appliedRevisionIds = [...formattingResult.revisionIds];
|
|
1204
1396
|
break;
|
|
1205
1397
|
}
|
|
1206
1398
|
tr = applyInlineFormatting({
|
|
1207
1399
|
tr,
|
|
1208
|
-
schema: view.state.schema,
|
|
1209
1400
|
from: item.from,
|
|
1210
1401
|
to: item.to,
|
|
1211
|
-
formatting: item.operation.formatting
|
|
1402
|
+
formatting: item.operation.formatting,
|
|
1403
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
1212
1404
|
});
|
|
1213
1405
|
break;
|
|
1214
1406
|
case "replaceBlock": {
|
|
1215
1407
|
if (!isResolvedReplaceBlockOperation(item)) panic("Resolved replaceBlock operation lost its impact discriminator");
|
|
1216
1408
|
const { changesStyle, changesText } = REPLACE_BLOCK_IMPACT[item.replaceBlockImpact];
|
|
1217
|
-
const revisionIdDelete =
|
|
1218
|
-
const revisionIdInsert = changesText ?
|
|
1219
|
-
const
|
|
1220
|
-
if (changesText)
|
|
1221
|
-
const revisionIdParagraph = producesTrackedChanges && changesStyle ? revisionSeed++ : null;
|
|
1409
|
+
const revisionIdDelete = operationRevisionSeed;
|
|
1410
|
+
const revisionIdInsert = changesText ? operationRevisionSeed + 1 : operationRevisionSeed;
|
|
1411
|
+
const revisionIdBackgroundSeed = changesText ? operationRevisionSeed + 2 : operationRevisionSeed;
|
|
1412
|
+
if (producesTrackedChanges && changesText) operationRevisionSeed = revisionIdBackgroundSeed;
|
|
1222
1413
|
if (item.operation.preserveFormatting === false && mode === "direct") {
|
|
1223
1414
|
const replacement = item.operation.text;
|
|
1224
1415
|
const paragraphType = view.state.schema.nodes["paragraph"];
|
|
1225
1416
|
if (paragraphType) {
|
|
1226
|
-
const node = paragraphType.create(null, replacement.length === 0 ? null : buildEmphasisInlineContent(view.state.schema, replacement, []));
|
|
1417
|
+
const node = paragraphType.create(null, replacement.length === 0 ? null : buildEmphasisInlineContent(view.state.schema, replacement, commentMark ? [commentMark] : []));
|
|
1227
1418
|
tr = tr.replaceWith(item.blockFrom, item.blockTo, node);
|
|
1228
1419
|
tr = applyReplaceBlockStyleId({
|
|
1229
1420
|
item,
|
|
@@ -1244,21 +1435,33 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1244
1435
|
break;
|
|
1245
1436
|
}
|
|
1246
1437
|
let clearedBackground = false;
|
|
1438
|
+
let backgroundRevisionIds = [];
|
|
1247
1439
|
if (changesText) {
|
|
1248
1440
|
const stepsBeforeBackgroundClear = tr.steps.length;
|
|
1249
|
-
|
|
1441
|
+
const backgroundResult = clearReplacementBackground({
|
|
1250
1442
|
tr,
|
|
1251
1443
|
schema: view.state.schema,
|
|
1252
1444
|
from: item.from,
|
|
1253
1445
|
to: item.to,
|
|
1254
1446
|
mode,
|
|
1255
|
-
|
|
1447
|
+
revisionIdSeed: revisionIdBackgroundSeed,
|
|
1256
1448
|
author,
|
|
1257
1449
|
date,
|
|
1258
1450
|
initials,
|
|
1259
|
-
suggestionId
|
|
1451
|
+
suggestionId,
|
|
1452
|
+
styleResolver
|
|
1260
1453
|
});
|
|
1454
|
+
if (backgroundResult.type === "pendingRunPropertyChange") {
|
|
1455
|
+
skipped.push({
|
|
1456
|
+
id: item.operation.id,
|
|
1457
|
+
reason: backgroundResult.type
|
|
1458
|
+
});
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
tr = backgroundResult.transaction;
|
|
1462
|
+
operationRevisionSeed = backgroundResult.nextRevisionId;
|
|
1261
1463
|
clearedBackground = tr.steps.length > stepsBeforeBackgroundClear;
|
|
1464
|
+
backgroundRevisionIds = backgroundResult.revisionIds;
|
|
1262
1465
|
tr = applyTextReplacement({
|
|
1263
1466
|
tr,
|
|
1264
1467
|
item,
|
|
@@ -1273,6 +1476,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1273
1476
|
diffText
|
|
1274
1477
|
});
|
|
1275
1478
|
}
|
|
1479
|
+
const revisionIdParagraph = producesTrackedChanges && changesStyle ? operationRevisionSeed++ : null;
|
|
1276
1480
|
const styleResult = applyReplaceBlockStyleId({
|
|
1277
1481
|
item,
|
|
1278
1482
|
tr,
|
|
@@ -1285,9 +1489,10 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1285
1489
|
} } : {}
|
|
1286
1490
|
});
|
|
1287
1491
|
tr = styleResult.tr;
|
|
1492
|
+
if (!changesText && commentMark) tr = tr.addMark(item.from, item.to, commentMark);
|
|
1288
1493
|
if (producesTrackedChanges) appliedRevisionIds = [
|
|
1289
1494
|
...changesText ? [revisionIdDelete, revisionIdInsert] : [],
|
|
1290
|
-
...clearedBackground ?
|
|
1495
|
+
...clearedBackground ? backgroundRevisionIds : [],
|
|
1291
1496
|
...styleResult.revisionId === null ? [] : [styleResult.revisionId]
|
|
1292
1497
|
];
|
|
1293
1498
|
break;
|
|
@@ -1306,17 +1511,18 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1306
1511
|
const built = buildInsertedParagraphs({
|
|
1307
1512
|
item,
|
|
1308
1513
|
schema: view.state.schema,
|
|
1309
|
-
|
|
1514
|
+
formattingFromStyle: formattingFromStyleForInsertion(item),
|
|
1310
1515
|
mode,
|
|
1311
1516
|
author,
|
|
1312
1517
|
date,
|
|
1313
1518
|
initials,
|
|
1314
1519
|
commentMark,
|
|
1315
1520
|
suggestionId,
|
|
1316
|
-
revisionSeed,
|
|
1317
|
-
isPairedMove
|
|
1521
|
+
revisionSeed: operationRevisionSeed,
|
|
1522
|
+
isPairedMove,
|
|
1523
|
+
numbering
|
|
1318
1524
|
});
|
|
1319
|
-
|
|
1525
|
+
operationRevisionSeed = built.nextRevisionId;
|
|
1320
1526
|
if (built.revisionIds.length > 0) appliedRevisionIds = built.revisionIds;
|
|
1321
1527
|
tr = tr.insert(item.from, built.nodes);
|
|
1322
1528
|
break;
|
|
@@ -1342,7 +1548,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1342
1548
|
}
|
|
1343
1549
|
let node = signatureTable;
|
|
1344
1550
|
if (isSuggested && suggestionId !== null) {
|
|
1345
|
-
const revisionId =
|
|
1551
|
+
const revisionId = operationRevisionSeed++;
|
|
1346
1552
|
node = signatureTable.type.create({
|
|
1347
1553
|
...signatureTable.attrs,
|
|
1348
1554
|
_suggestedInsert: {
|
|
@@ -1385,7 +1591,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1385
1591
|
}
|
|
1386
1592
|
tr = result.transaction;
|
|
1387
1593
|
if (result.revisionId !== null) {
|
|
1388
|
-
|
|
1594
|
+
operationRevisionSeed++;
|
|
1389
1595
|
appliedRevisionIds = [result.revisionId];
|
|
1390
1596
|
}
|
|
1391
1597
|
break;
|
|
@@ -1415,7 +1621,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1415
1621
|
}
|
|
1416
1622
|
tr = result.transaction;
|
|
1417
1623
|
if (result.revisionId !== null) {
|
|
1418
|
-
|
|
1624
|
+
operationRevisionSeed++;
|
|
1419
1625
|
appliedRevisionIds = [result.revisionId];
|
|
1420
1626
|
}
|
|
1421
1627
|
const columnKey = getTableColumnCoordinateKey(insertion);
|
|
@@ -1448,7 +1654,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1448
1654
|
}
|
|
1449
1655
|
tr = result.transaction;
|
|
1450
1656
|
if (result.revisionId !== null) {
|
|
1451
|
-
|
|
1657
|
+
operationRevisionSeed++;
|
|
1452
1658
|
appliedRevisionIds = [result.revisionId];
|
|
1453
1659
|
}
|
|
1454
1660
|
break;
|
|
@@ -1464,7 +1670,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1464
1670
|
});
|
|
1465
1671
|
continue;
|
|
1466
1672
|
}
|
|
1467
|
-
const revisionId = mode === "tracked-changes" ?
|
|
1673
|
+
const revisionId = mode === "tracked-changes" ? operationRevisionSeed : null;
|
|
1468
1674
|
const nextTr = revisionId === null ? mergeTableRectangle({
|
|
1469
1675
|
tr,
|
|
1470
1676
|
tablePosition,
|
|
@@ -1488,7 +1694,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1488
1694
|
}
|
|
1489
1695
|
tr = nextTr;
|
|
1490
1696
|
if (revisionId !== null) {
|
|
1491
|
-
|
|
1697
|
+
operationRevisionSeed++;
|
|
1492
1698
|
appliedRevisionIds = [revisionId];
|
|
1493
1699
|
}
|
|
1494
1700
|
break;
|
|
@@ -1504,7 +1710,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1504
1710
|
});
|
|
1505
1711
|
continue;
|
|
1506
1712
|
}
|
|
1507
|
-
const revisionId = mode === "tracked-changes" ?
|
|
1713
|
+
const revisionId = mode === "tracked-changes" ? operationRevisionSeed : null;
|
|
1508
1714
|
const nextTr = revisionId === null ? splitTableRectangle({
|
|
1509
1715
|
tr,
|
|
1510
1716
|
tablePosition,
|
|
@@ -1528,7 +1734,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1528
1734
|
}
|
|
1529
1735
|
tr = nextTr;
|
|
1530
1736
|
if (revisionId !== null) {
|
|
1531
|
-
|
|
1737
|
+
operationRevisionSeed++;
|
|
1532
1738
|
appliedRevisionIds = [revisionId];
|
|
1533
1739
|
}
|
|
1534
1740
|
break;
|
|
@@ -1556,7 +1762,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1556
1762
|
}
|
|
1557
1763
|
tr = result.transaction;
|
|
1558
1764
|
if (result.revisionId !== null) {
|
|
1559
|
-
|
|
1765
|
+
operationRevisionSeed++;
|
|
1560
1766
|
appliedRevisionIds = [result.revisionId];
|
|
1561
1767
|
}
|
|
1562
1768
|
break;
|
|
@@ -1568,7 +1774,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1568
1774
|
break;
|
|
1569
1775
|
}
|
|
1570
1776
|
if (deletionType) {
|
|
1571
|
-
const revisionId =
|
|
1777
|
+
const revisionId = operationRevisionSeed++;
|
|
1572
1778
|
const deletionMark = deletionType.create({
|
|
1573
1779
|
revisionId,
|
|
1574
1780
|
author,
|
|
@@ -1583,7 +1789,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1583
1789
|
appliedRevisionIds = inlineRevisionApplied ? [revisionId] : [];
|
|
1584
1790
|
const markPosition = tr.mapping.map(item.blockFrom);
|
|
1585
1791
|
if (!paragraphEndsItsContainer(tr.doc.resolve(markPosition), item.blockNode.type.name) && tr.doc.nodeAt(markPosition)?.attrs["pPrMark"] == null) {
|
|
1586
|
-
const markRevisionId =
|
|
1792
|
+
const markRevisionId = operationRevisionSeed++;
|
|
1587
1793
|
tr = tr.setNodeAttribute(markPosition, "pPrMark", {
|
|
1588
1794
|
kind: isPairedMove(item.operation.moveId) ? "moveFrom" : "del",
|
|
1589
1795
|
info: {
|
|
@@ -1600,7 +1806,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1600
1806
|
break;
|
|
1601
1807
|
case "insertTable": {
|
|
1602
1808
|
const revision = {
|
|
1603
|
-
revisionId:
|
|
1809
|
+
revisionId: operationRevisionSeed,
|
|
1604
1810
|
author,
|
|
1605
1811
|
date,
|
|
1606
1812
|
...trackedRevisionExtras
|
|
@@ -1622,7 +1828,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1622
1828
|
});
|
|
1623
1829
|
continue;
|
|
1624
1830
|
}
|
|
1625
|
-
if (producesTrackedChanges) appliedRevisionIds = [
|
|
1831
|
+
if (producesTrackedChanges) appliedRevisionIds = [operationRevisionSeed++];
|
|
1626
1832
|
tr = tr.insert(item.from, table);
|
|
1627
1833
|
markStructuralChange(tr);
|
|
1628
1834
|
break;
|
|
@@ -1660,7 +1866,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1660
1866
|
continue;
|
|
1661
1867
|
}
|
|
1662
1868
|
const revision = {
|
|
1663
|
-
revisionId:
|
|
1869
|
+
revisionId: operationRevisionSeed++,
|
|
1664
1870
|
author,
|
|
1665
1871
|
date,
|
|
1666
1872
|
...trackedRevisionExtras
|
|
@@ -1695,7 +1901,11 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1695
1901
|
const blockPosition = tr.mapping.map(item.blockFrom);
|
|
1696
1902
|
const liveBlock = tr.doc.nodeAt(blockPosition) ?? item.blockNode;
|
|
1697
1903
|
const liveAttrs = expectParagraphAttrs(liveBlock);
|
|
1698
|
-
const
|
|
1904
|
+
const resolvedFormattingFromStyle = item.operation.properties.styleId === void 0 ? resolveFormattingFromStyle({
|
|
1905
|
+
attrs: liveAttrs,
|
|
1906
|
+
styleId: liveAttrs.styleId,
|
|
1907
|
+
styleResolver
|
|
1908
|
+
}) : resolveFormattingFromStyle({
|
|
1699
1909
|
attrs: liveAttrs,
|
|
1700
1910
|
styleId: item.operation.properties.styleId,
|
|
1701
1911
|
styleResolver
|
|
@@ -1703,7 +1913,8 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1703
1913
|
const patch = paragraphPropertiesPatch({
|
|
1704
1914
|
node: liveBlock,
|
|
1705
1915
|
properties: item.operation.properties,
|
|
1706
|
-
|
|
1916
|
+
resolvedFormattingFromStyle,
|
|
1917
|
+
numbering
|
|
1707
1918
|
});
|
|
1708
1919
|
if (patch === null) {
|
|
1709
1920
|
skipped.push({
|
|
@@ -1719,7 +1930,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1719
1930
|
});
|
|
1720
1931
|
break;
|
|
1721
1932
|
}
|
|
1722
|
-
const revisionId =
|
|
1933
|
+
const revisionId = operationRevisionSeed++;
|
|
1723
1934
|
const change = {
|
|
1724
1935
|
type: "paragraphPropertyChange",
|
|
1725
1936
|
info: {
|
|
@@ -1745,7 +1956,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1745
1956
|
tr = tr.split(item.from);
|
|
1746
1957
|
break;
|
|
1747
1958
|
}
|
|
1748
|
-
const revisionIdMark =
|
|
1959
|
+
const revisionIdMark = operationRevisionSeed++;
|
|
1749
1960
|
const info = {
|
|
1750
1961
|
id: revisionIdMark,
|
|
1751
1962
|
author,
|
|
@@ -1754,7 +1965,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1754
1965
|
};
|
|
1755
1966
|
appliedRevisionIds = [revisionIdMark];
|
|
1756
1967
|
if (item.to > item.from && deletionType) {
|
|
1757
|
-
const revisionIdSeparator =
|
|
1968
|
+
const revisionIdSeparator = operationRevisionSeed++;
|
|
1758
1969
|
tr = tr.addMark(item.from, item.to, deletionType.create({
|
|
1759
1970
|
revisionId: revisionIdSeparator,
|
|
1760
1971
|
author,
|
|
@@ -1778,10 +1989,10 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1778
1989
|
tr = tr.join(item.blockTo + separator.length);
|
|
1779
1990
|
break;
|
|
1780
1991
|
}
|
|
1781
|
-
const revisionIdMark =
|
|
1992
|
+
const revisionIdMark = operationRevisionSeed++;
|
|
1782
1993
|
appliedRevisionIds = [revisionIdMark];
|
|
1783
1994
|
if (separator.length > 0 && insertionType) {
|
|
1784
|
-
const revisionIdSeparator =
|
|
1995
|
+
const revisionIdSeparator = operationRevisionSeed++;
|
|
1785
1996
|
tr = tr.insertText(separator, insertAt);
|
|
1786
1997
|
tr = tr.addMark(insertAt, insertAt + separator.length, insertionType.create({
|
|
1787
1998
|
revisionId: revisionIdSeparator,
|
|
@@ -1814,9 +2025,24 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1814
2025
|
});
|
|
1815
2026
|
continue;
|
|
1816
2027
|
}
|
|
2028
|
+
let committedCommentId;
|
|
2029
|
+
if (item.commentText !== void 0) {
|
|
2030
|
+
if (commentType === void 0 || provisionalCommentId === void 0 || commentMarkRanges(tr.doc, commentType, provisionalCommentId).length === 0) panic("A commented operation changed the document without producing a comment anchor", {
|
|
2031
|
+
operationId: item.operation.id,
|
|
2032
|
+
operationType: item.operation.type
|
|
2033
|
+
});
|
|
2034
|
+
committedCommentId = allocateCommittedCommentId(item.commentText);
|
|
2035
|
+
tr = commitProvisionalComment({
|
|
2036
|
+
tr,
|
|
2037
|
+
commentType,
|
|
2038
|
+
provisionalId: provisionalCommentId,
|
|
2039
|
+
committedId: committedCommentId
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
2042
|
+
revisionSeed = operationRevisionSeed;
|
|
1817
2043
|
applied.push({
|
|
1818
2044
|
id: item.operation.id,
|
|
1819
|
-
...
|
|
2045
|
+
...committedCommentId !== void 0 && { commentId: committedCommentId },
|
|
1820
2046
|
...appliedRevisionIds !== void 0 && appliedRevisionIds[0] !== void 0 && {
|
|
1821
2047
|
revisionId: appliedRevisionIds[0],
|
|
1822
2048
|
revisionIds: appliedRevisionIds
|
|
@@ -1851,6 +2077,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1851
2077
|
revisionIds: [...receipt.revisionIds, revisionId]
|
|
1852
2078
|
};
|
|
1853
2079
|
}
|
|
2080
|
+
if (ownsSharedRevisionIdCursor) revisionIdCursor = Math.max(revisionIdCursor, revisionSeed);
|
|
1854
2081
|
if (revisionStamp) requestDeterministicParaIds(tr, `${revisionStamp.date}:${String(revisionStamp.idSeed)}`);
|
|
1855
2082
|
view.dispatch(tr);
|
|
1856
2083
|
}
|
|
@@ -2032,7 +2259,8 @@ const resolveStableBlock = ({ snapshot, blockId, liveBlocks, liveBlocksByParaId
|
|
|
2032
2259
|
const cleanBlock = buildCleanBlockText(live.node, live.from);
|
|
2033
2260
|
const currentText = cleanBlock.text;
|
|
2034
2261
|
const currentTextHash = hashFolioAIBlockText(normalizeFolioAIBlockText(currentText));
|
|
2035
|
-
|
|
2262
|
+
const structuralBoundaryHash = hashFolioAIBlockStructuralBoundaries(cleanBlock);
|
|
2263
|
+
if (currentTextHash !== anchor.textHash || structuralBoundaryHash !== anchor.structuralBoundaryHash) return {
|
|
2036
2264
|
type: "skip",
|
|
2037
2265
|
reason: "changedBlock"
|
|
2038
2266
|
};
|
|
@@ -2062,9 +2290,7 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2062
2290
|
};
|
|
2063
2291
|
if (operation.type === "replaceRange" || operation.type === "commentOnRange" || operation.type === "formatRange") {
|
|
2064
2292
|
const { startOffset, endOffset, selectedTextHash } = operation.range;
|
|
2065
|
-
|
|
2066
|
-
const to = cleanBlock.offsets[endOffset];
|
|
2067
|
-
if (from === void 0 || to === void 0) return {
|
|
2293
|
+
if (cleanBlock.offsets[startOffset] === void 0 || cleanBlock.offsets[endOffset] === void 0) return {
|
|
2068
2294
|
type: "skip",
|
|
2069
2295
|
reason: "staleRange"
|
|
2070
2296
|
};
|
|
@@ -2073,6 +2299,15 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2073
2299
|
type: "skip",
|
|
2074
2300
|
reason: "staleRange"
|
|
2075
2301
|
};
|
|
2302
|
+
const range = resolveCleanTextRange({
|
|
2303
|
+
cleanBlock,
|
|
2304
|
+
startOffset,
|
|
2305
|
+
endOffset
|
|
2306
|
+
});
|
|
2307
|
+
if (range === null) return {
|
|
2308
|
+
type: "skip",
|
|
2309
|
+
reason: "unsupportedBlock"
|
|
2310
|
+
};
|
|
2076
2311
|
if (operation.type === "replaceRange" && selectedText === operation.replace) return {
|
|
2077
2312
|
type: "skip",
|
|
2078
2313
|
reason: "noopOperation"
|
|
@@ -2081,8 +2316,8 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2081
2316
|
type: "resolved",
|
|
2082
2317
|
operation: {
|
|
2083
2318
|
operation,
|
|
2084
|
-
from,
|
|
2085
|
-
to,
|
|
2319
|
+
from: range.from,
|
|
2320
|
+
to: range.to,
|
|
2086
2321
|
blockFrom,
|
|
2087
2322
|
blockTo,
|
|
2088
2323
|
blockNode
|
|
@@ -2385,8 +2620,10 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2385
2620
|
};
|
|
2386
2621
|
if (operation.type === "splitBlock") {
|
|
2387
2622
|
const separator = operation.separator ?? "";
|
|
2388
|
-
const
|
|
2389
|
-
const
|
|
2623
|
+
const startOffset = operation.offset;
|
|
2624
|
+
const endOffset = operation.offset + separator.length;
|
|
2625
|
+
const at = cleanBlock.offsets[startOffset];
|
|
2626
|
+
const after = cleanBlock.offsets[endOffset];
|
|
2390
2627
|
if (at === void 0 || after === void 0 || operation.offset === 0 || operation.offset + separator.length >= currentText.length) return {
|
|
2391
2628
|
type: "skip",
|
|
2392
2629
|
reason: "staleRange"
|
|
@@ -2395,7 +2632,12 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2395
2632
|
type: "skip",
|
|
2396
2633
|
reason: "staleRange"
|
|
2397
2634
|
};
|
|
2398
|
-
|
|
2635
|
+
const range = resolveCleanTextRange({
|
|
2636
|
+
cleanBlock,
|
|
2637
|
+
startOffset,
|
|
2638
|
+
endOffset
|
|
2639
|
+
});
|
|
2640
|
+
if (range === null || !canSplit(doc, range.from)) return {
|
|
2399
2641
|
type: "skip",
|
|
2400
2642
|
reason: "unsupportedBlock"
|
|
2401
2643
|
};
|
|
@@ -2403,8 +2645,8 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2403
2645
|
type: "resolved",
|
|
2404
2646
|
operation: {
|
|
2405
2647
|
operation,
|
|
2406
|
-
from:
|
|
2407
|
-
to:
|
|
2648
|
+
from: range.from,
|
|
2649
|
+
to: range.to,
|
|
2408
2650
|
blockFrom,
|
|
2409
2651
|
blockTo,
|
|
2410
2652
|
blockNode
|
|
@@ -2429,7 +2671,12 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2429
2671
|
};
|
|
2430
2672
|
}
|
|
2431
2673
|
if (operation.type === "deleteBlock" || operation.type === "replaceBlock") {
|
|
2674
|
+
const replaceChangesText = operation.type === "replaceBlock" && operation.text !== currentText;
|
|
2432
2675
|
const replaceChangesStyle = operation.type === "replaceBlock" && operation.styleId !== void 0 && operation.styleId !== (expectParagraphAttrs(blockNode).styleId ?? null);
|
|
2676
|
+
if (replaceChangesText && cleanBlock.structuralBoundaries.length > 0) return {
|
|
2677
|
+
type: "skip",
|
|
2678
|
+
reason: "unsupportedBlock"
|
|
2679
|
+
};
|
|
2433
2680
|
const range = getTextRangeFromCleanBlock(cleanBlock);
|
|
2434
2681
|
if (!range) {
|
|
2435
2682
|
const insertionPoint = cleanBlock.offsets.at(0);
|
|
@@ -2451,7 +2698,7 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2451
2698
|
blockTo,
|
|
2452
2699
|
blockNode,
|
|
2453
2700
|
replaceBlockImpact: resolveReplaceBlockImpact({
|
|
2454
|
-
changesText:
|
|
2701
|
+
changesText: replaceChangesText,
|
|
2455
2702
|
changesStyle: replaceChangesStyle
|
|
2456
2703
|
})
|
|
2457
2704
|
}
|
|
@@ -2484,7 +2731,7 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2484
2731
|
blockTo,
|
|
2485
2732
|
blockNode,
|
|
2486
2733
|
replaceBlockImpact: resolveReplaceBlockImpact({
|
|
2487
|
-
changesText:
|
|
2734
|
+
changesText: replaceChangesText,
|
|
2488
2735
|
changesStyle: replaceChangesStyle
|
|
2489
2736
|
})
|
|
2490
2737
|
}
|
|
@@ -2525,7 +2772,7 @@ const resolveTextInCleanBlock = (cleanBlock, find) => {
|
|
|
2525
2772
|
type: "skip",
|
|
2526
2773
|
reason: "emptyOperation"
|
|
2527
2774
|
};
|
|
2528
|
-
const { text
|
|
2775
|
+
const { text } = cleanBlock;
|
|
2529
2776
|
const firstIndex = text.indexOf(find);
|
|
2530
2777
|
if (firstIndex === -1) return {
|
|
2531
2778
|
type: "skip",
|
|
@@ -2535,16 +2782,18 @@ const resolveTextInCleanBlock = (cleanBlock, find) => {
|
|
|
2535
2782
|
type: "skip",
|
|
2536
2783
|
reason: "ambiguousFind"
|
|
2537
2784
|
};
|
|
2538
|
-
const
|
|
2539
|
-
|
|
2540
|
-
|
|
2785
|
+
const range = resolveCleanTextRange({
|
|
2786
|
+
cleanBlock,
|
|
2787
|
+
startOffset: firstIndex,
|
|
2788
|
+
endOffset: firstIndex + find.length
|
|
2789
|
+
});
|
|
2790
|
+
if (range === null) return {
|
|
2541
2791
|
type: "skip",
|
|
2542
2792
|
reason: "unsupportedBlock"
|
|
2543
2793
|
};
|
|
2544
2794
|
return {
|
|
2545
2795
|
type: "resolved",
|
|
2546
|
-
|
|
2547
|
-
to
|
|
2796
|
+
...range
|
|
2548
2797
|
};
|
|
2549
2798
|
};
|
|
2550
2799
|
const getTextRangeFromCleanBlock = (cleanBlock) => {
|