@stll/folio-core 0.36.0 → 0.37.1
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 +689 -367
- 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 +60 -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 +201 -569
- 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 +8 -6
- package/dist/document-operations.js +121 -26
- 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 +176 -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 +167 -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,40 @@ 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) => {
|
|
139
|
+
if (item.operation.type === "setBlockParagraphProperties") return true;
|
|
140
|
+
if (item.operation.type === "splitBlock") return item.operation.firstParagraphProperties !== void 0 || item.operation.secondParagraphProperties !== void 0;
|
|
141
|
+
if (item.operation.type === "mergeBlockWithNext") return item.operation.mergedParagraphProperties !== void 0;
|
|
142
|
+
return isResolvedReplaceBlockOperation(item) && REPLACE_BLOCK_IMPACT[item.replaceBlockImpact].changesStyle;
|
|
143
|
+
};
|
|
98
144
|
const resolveReplaceBlockImpact = ({ changesText, changesStyle }) => {
|
|
99
145
|
if (changesText) return changesStyle ? "textAndStyle" : "text";
|
|
100
146
|
if (changesStyle) return "style";
|
|
101
147
|
return panic("Cannot resolve a replaceBlock that changes neither text nor style");
|
|
102
148
|
};
|
|
103
|
-
const paragraphPropertiesPatch = ({ node, properties,
|
|
149
|
+
const paragraphPropertiesPatch = ({ node, properties, resolvedFormattingFromStyle, numbering = null }) => {
|
|
104
150
|
const attrs = expectParagraphAttrs(node);
|
|
105
151
|
const currentDirectAlignment = directParagraphAlignment(attrs);
|
|
152
|
+
const currentDirectSpacing = directParagraphSpacing(attrs);
|
|
153
|
+
const resolvedSpacingFromStyle = paragraphSpacingFromFormatting(resolvedFormattingFromStyle);
|
|
106
154
|
const patch = {};
|
|
107
155
|
let originalFormatting = attrs._originalFormatting === void 0 || attrs._originalFormatting === null ? void 0 : { ...attrs._originalFormatting };
|
|
108
156
|
let originalFormattingChanged = false;
|
|
@@ -110,8 +158,12 @@ const paragraphPropertiesPatch = ({ node, properties, resolvedAlignmentFromStyle
|
|
|
110
158
|
const styleChanged = nextStyleId !== void 0 && (attrs.styleId ?? null) !== nextStyleId;
|
|
111
159
|
if (styleChanged) {
|
|
112
160
|
patch["styleId"] = nextStyleId;
|
|
113
|
-
patch["alignmentFromStyle"] =
|
|
114
|
-
if (properties.alignment === void 0) patch["alignment"] = currentDirectAlignment ??
|
|
161
|
+
patch["alignmentFromStyle"] = resolvedFormattingFromStyle?.alignment;
|
|
162
|
+
if (properties.alignment === void 0) patch["alignment"] = currentDirectAlignment ?? resolvedFormattingFromStyle?.alignment ?? null;
|
|
163
|
+
if (properties.spacing === void 0) Object.assign(patch, paragraphSpacingAttrPatch({
|
|
164
|
+
direct: currentDirectSpacing,
|
|
165
|
+
inherited: resolvedSpacingFromStyle
|
|
166
|
+
}));
|
|
115
167
|
originalFormatting ??= {};
|
|
116
168
|
if (nextStyleId === null) Reflect.deleteProperty(originalFormatting, "styleId");
|
|
117
169
|
else originalFormatting.styleId = nextStyleId;
|
|
@@ -120,29 +172,39 @@ const paragraphPropertiesPatch = ({ node, properties, resolvedAlignmentFromStyle
|
|
|
120
172
|
}
|
|
121
173
|
if (properties.listLevel !== void 0) {
|
|
122
174
|
const numPr = node.attrs["numPr"];
|
|
123
|
-
const current = typeof numPr === "object" && numPr !== null && "ilvl" in numPr ? numPr.ilvl : void 0;
|
|
124
175
|
if (properties.listLevel === null) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
} else if (current !== properties.listLevel) {
|
|
176
|
+
patch["numPr"] = null;
|
|
177
|
+
Object.assign(patch, CLEARED_LIST_RENDERING_ATTRS);
|
|
178
|
+
} else {
|
|
130
179
|
const numId = typeof numPr === "object" && numPr !== null && "numId" in numPr ? numPr.numId : void 0;
|
|
131
|
-
|
|
132
|
-
|
|
180
|
+
if (typeof numId === "number") Object.assign(patch, listLevelAttrPatch(attrs, {
|
|
181
|
+
numId,
|
|
133
182
|
ilvl: properties.listLevel
|
|
134
|
-
};
|
|
183
|
+
}, numbering));
|
|
184
|
+
else {
|
|
185
|
+
patch["numPr"] = { ilvl: properties.listLevel };
|
|
186
|
+
Object.assign(patch, CLEARED_LIST_RENDERING_ATTRS);
|
|
187
|
+
}
|
|
135
188
|
}
|
|
136
189
|
}
|
|
137
190
|
if (properties.alignment !== void 0 && (styleChanged || (currentDirectAlignment ?? null) !== properties.alignment)) {
|
|
138
191
|
originalFormatting ??= {};
|
|
139
192
|
if (properties.alignment === null) Reflect.deleteProperty(originalFormatting, "alignment");
|
|
140
193
|
else originalFormatting.alignment = properties.alignment;
|
|
141
|
-
const alignmentFromStyle = properties.styleId === void 0 ? attrs.alignmentFromStyle :
|
|
194
|
+
const alignmentFromStyle = properties.styleId === void 0 ? attrs.alignmentFromStyle : resolvedFormattingFromStyle?.alignment;
|
|
142
195
|
patch["alignment"] = properties.alignment ?? alignmentFromStyle ?? null;
|
|
143
196
|
originalFormattingChanged = true;
|
|
144
197
|
}
|
|
145
|
-
if (
|
|
198
|
+
if (properties.spacing !== void 0 && (styleChanged || !paragraphSpacingEqual(currentDirectSpacing, properties.spacing))) {
|
|
199
|
+
const directSpacing = properties.spacing ?? void 0;
|
|
200
|
+
originalFormatting = withDirectParagraphSpacing(originalFormatting, directSpacing);
|
|
201
|
+
Object.assign(patch, paragraphSpacingAttrPatch({
|
|
202
|
+
direct: directSpacing,
|
|
203
|
+
inherited: resolvedSpacingFromStyle
|
|
204
|
+
}));
|
|
205
|
+
originalFormattingChanged = true;
|
|
206
|
+
}
|
|
207
|
+
if (originalFormattingChanged) patch["_originalFormatting"] = originalFormatting && Object.keys(originalFormatting).length > 0 ? originalFormatting : null;
|
|
146
208
|
return Object.keys(patch).length > 0 ? patch : null;
|
|
147
209
|
};
|
|
148
210
|
const REVISION_MARK_NAMES = /* @__PURE__ */ new Set(["insertion", "deletion"]);
|
|
@@ -201,7 +263,58 @@ const paragraphPropertiesBeforeBatch = (node, batchRevisionIds) => {
|
|
|
201
263
|
if (!earliestBatchChange) return paragraphPropertiesSnapshot(node);
|
|
202
264
|
return earliestBatchChange.previousFormatting ?? {};
|
|
203
265
|
};
|
|
204
|
-
const
|
|
266
|
+
const resolveFormattingFromStyle = ({ attrs, styleId, styleResolver }) => {
|
|
267
|
+
const resolved = styleResolver?.resolveParagraphStyle(styleId).paragraphFormatting;
|
|
268
|
+
if (resolved !== void 0) return resolved;
|
|
269
|
+
if ((styleId ?? void 0) !== (attrs.styleId ?? void 0)) return;
|
|
270
|
+
const fallback = {};
|
|
271
|
+
if (attrs.alignmentFromStyle !== void 0) fallback.alignment = attrs.alignmentFromStyle;
|
|
272
|
+
return Object.keys(fallback).length > 0 ? fallback : void 0;
|
|
273
|
+
};
|
|
274
|
+
/**
|
|
275
|
+
* Apply one paragraph-property patch to a live node. A tracked patch stores
|
|
276
|
+
* the complete previous pPr: a partial snapshot cannot distinguish a property
|
|
277
|
+
* the change left alone from one it explicitly cleared when rejecting it.
|
|
278
|
+
*/
|
|
279
|
+
const applyBlockParagraphProperties = ({ tr, position, node, properties, styleResolver, numbering = null, revisionInfo }) => {
|
|
280
|
+
const attrs = expectParagraphAttrs(node);
|
|
281
|
+
const resolvedFormattingFromStyle = properties.styleId === void 0 ? resolveFormattingFromStyle({
|
|
282
|
+
attrs,
|
|
283
|
+
styleId: attrs.styleId,
|
|
284
|
+
styleResolver
|
|
285
|
+
}) : resolveFormattingFromStyle({
|
|
286
|
+
attrs,
|
|
287
|
+
styleId: properties.styleId,
|
|
288
|
+
styleResolver
|
|
289
|
+
});
|
|
290
|
+
const patch = paragraphPropertiesPatch({
|
|
291
|
+
node,
|
|
292
|
+
properties,
|
|
293
|
+
resolvedFormattingFromStyle,
|
|
294
|
+
numbering
|
|
295
|
+
});
|
|
296
|
+
if (patch === null) return {
|
|
297
|
+
tr,
|
|
298
|
+
changed: false,
|
|
299
|
+
revisionId: null
|
|
300
|
+
};
|
|
301
|
+
const changeInfo = revisionInfo?.();
|
|
302
|
+
const change = changeInfo ? {
|
|
303
|
+
type: "paragraphPropertyChange",
|
|
304
|
+
info: changeInfo,
|
|
305
|
+
previousFormatting: paragraphPropertiesSnapshot(node)
|
|
306
|
+
} : null;
|
|
307
|
+
const existing = attrs._propertyChanges;
|
|
308
|
+
return {
|
|
309
|
+
tr: tr.setNodeMarkup(position, void 0, {
|
|
310
|
+
...node.attrs,
|
|
311
|
+
...patch,
|
|
312
|
+
...change ? { _propertyChanges: [...Array.isArray(existing) ? existing : [], change] } : {}
|
|
313
|
+
}),
|
|
314
|
+
changed: true,
|
|
315
|
+
revisionId: change?.info.id ?? null
|
|
316
|
+
};
|
|
317
|
+
};
|
|
205
318
|
const applyReplaceBlockStyleId = ({ item, tr, styleResolver, revisionInfo }) => {
|
|
206
319
|
if (item.operation.type !== "replaceBlock" || item.operation.styleId === void 0) return {
|
|
207
320
|
tr,
|
|
@@ -214,7 +327,7 @@ const applyReplaceBlockStyleId = ({ item, tr, styleResolver, revisionInfo }) =>
|
|
|
214
327
|
revisionId: null
|
|
215
328
|
};
|
|
216
329
|
const attrs = expectParagraphAttrs(block);
|
|
217
|
-
const
|
|
330
|
+
const resolvedFormattingFromStyle = resolveFormattingFromStyle({
|
|
218
331
|
attrs,
|
|
219
332
|
styleId: item.operation.styleId,
|
|
220
333
|
styleResolver
|
|
@@ -222,7 +335,7 @@ const applyReplaceBlockStyleId = ({ item, tr, styleResolver, revisionInfo }) =>
|
|
|
222
335
|
const patch = paragraphPropertiesPatch({
|
|
223
336
|
node: block,
|
|
224
337
|
properties: { styleId: item.operation.styleId },
|
|
225
|
-
|
|
338
|
+
resolvedFormattingFromStyle
|
|
226
339
|
});
|
|
227
340
|
if (patch === null) return {
|
|
228
341
|
tr,
|
|
@@ -247,141 +360,134 @@ const REPLACEMENT_BACKGROUND_CLEAR_FORMATTING = {
|
|
|
247
360
|
highlight: false,
|
|
248
361
|
runShading: false
|
|
249
362
|
};
|
|
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 {};
|
|
363
|
+
const includedFormattingProperty = (includedProperties, property) => includedProperties === void 0 || includedProperties.includes(property);
|
|
364
|
+
const patchAuthoredRunFormatting = ({ authoredFormatting, formatting, includedProperties }) => {
|
|
365
|
+
const next = { ...authoredFormatting };
|
|
366
|
+
for (const property of ["bold", "italic"]) {
|
|
367
|
+
const value = formatting[property];
|
|
368
|
+
if (value === void 0 || !includedFormattingProperty(includedProperties, property)) continue;
|
|
369
|
+
if (value === null) Reflect.deleteProperty(next, property);
|
|
370
|
+
else next[property] = value;
|
|
281
371
|
}
|
|
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);
|
|
372
|
+
if (formatting.underline !== void 0 && includedFormattingProperty(includedProperties, "underline")) if (formatting.underline === null) delete next.underline;
|
|
373
|
+
else next.underline = { style: formatting.underline ? "single" : "none" };
|
|
374
|
+
if (formatting.strike !== void 0 && includedFormattingProperty(includedProperties, "strike")) {
|
|
375
|
+
delete next.doubleStrike;
|
|
376
|
+
if (formatting.strike === null) delete next.strike;
|
|
377
|
+
else next.strike = formatting.strike;
|
|
295
378
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
379
|
+
if (formatting.fontFamily !== void 0 && includedFormattingProperty(includedProperties, "fontFamily")) if (formatting.fontFamily === null) delete next.fontFamily;
|
|
380
|
+
else next.fontFamily = {
|
|
381
|
+
ascii: formatting.fontFamily,
|
|
382
|
+
hAnsi: formatting.fontFamily
|
|
383
|
+
};
|
|
384
|
+
if (formatting.fontSizePt !== void 0 && includedFormattingProperty(includedProperties, "fontSizePt")) if (formatting.fontSizePt === null) delete next.fontSize;
|
|
385
|
+
else next.fontSize = formatting.fontSizePt * 2;
|
|
386
|
+
if (formatting.color !== void 0 && includedFormattingProperty(includedProperties, "color")) if (formatting.color === null) delete next.color;
|
|
387
|
+
else next.color = { rgb: formatting.color.replace(/^#/u, "").toUpperCase() };
|
|
388
|
+
if (formatting.highlight === false && includedFormattingProperty(includedProperties, "highlight")) delete next.highlight;
|
|
389
|
+
if (formatting.runShading === false && includedFormattingProperty(includedProperties, "runShading")) delete next.shading;
|
|
390
|
+
return next;
|
|
391
|
+
};
|
|
392
|
+
const applyInlineFormatting = ({ tr, from, to, formatting, includedProperties, styleResolver }) => {
|
|
393
|
+
const representations = selectRunFormattingCarrierRepresentations({
|
|
394
|
+
doc: tr.doc,
|
|
299
395
|
from,
|
|
300
|
-
to
|
|
301
|
-
formatting,
|
|
302
|
-
...includedProperties ? { includedProperties } : {}
|
|
396
|
+
to
|
|
303
397
|
});
|
|
398
|
+
for (const representation of representations) {
|
|
399
|
+
const styleContext = paragraphRunStyleContextAt({
|
|
400
|
+
doc: tr.doc,
|
|
401
|
+
pos: representation.from,
|
|
402
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
403
|
+
});
|
|
404
|
+
const authoredFormatting = readAuthoredRunFormatting({
|
|
405
|
+
context: styleContext,
|
|
406
|
+
marks: representation.node.marks,
|
|
407
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
408
|
+
});
|
|
409
|
+
const marks = reconcileRunFormattingMarks({
|
|
410
|
+
authoredFormatting: patchAuthoredRunFormatting({
|
|
411
|
+
authoredFormatting,
|
|
412
|
+
formatting,
|
|
413
|
+
...includedProperties !== void 0 ? { includedProperties } : {}
|
|
414
|
+
}),
|
|
415
|
+
context: styleContext,
|
|
416
|
+
node: representation.node,
|
|
417
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
418
|
+
});
|
|
419
|
+
applyMarksToRunFormattingRepresentation({
|
|
420
|
+
tr,
|
|
421
|
+
representation,
|
|
422
|
+
marks
|
|
423
|
+
});
|
|
424
|
+
}
|
|
304
425
|
return tr;
|
|
305
426
|
};
|
|
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;
|
|
427
|
+
const applyMarksToRunFormattingRepresentation = ({ tr, representation, marks }) => {
|
|
428
|
+
const { node, position, from, to } = representation;
|
|
429
|
+
if (Mark.sameSet(node.marks, marks)) return;
|
|
430
|
+
if (!node.isText) {
|
|
431
|
+
tr.setNodeMarkup(position, void 0, node.attrs, marks);
|
|
432
|
+
return;
|
|
350
433
|
}
|
|
434
|
+
for (const current of node.marks) if (!marks.some((candidate) => candidate.eq(current))) tr.removeMark(from, to, current.type);
|
|
435
|
+
for (const next of marks) if (!node.marks.some((candidate) => candidate.eq(next))) tr.addMark(from, to, next);
|
|
351
436
|
};
|
|
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();
|
|
437
|
+
const sameDefinedFormattingValue = (left, right) => {
|
|
438
|
+
if (left === right) return true;
|
|
439
|
+
if (typeof left !== "object" || left === null || typeof right !== "object" || right === null) return false;
|
|
440
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
441
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) return false;
|
|
442
|
+
return left.every((value, index) => sameDefinedFormattingValue(value, right.at(index)));
|
|
368
443
|
}
|
|
369
|
-
|
|
444
|
+
const leftEntries = Object.entries(left).filter(([, value]) => value !== void 0);
|
|
445
|
+
const rightEntries = Object.entries(right).filter(([, value]) => value !== void 0);
|
|
446
|
+
if (leftEntries.length !== rightEntries.length) return false;
|
|
447
|
+
return leftEntries.every(([property, value]) => Object.hasOwn(right, property) && sameDefinedFormattingValue(value, Reflect.get(right, property)));
|
|
370
448
|
};
|
|
371
|
-
const
|
|
449
|
+
const formattingChangesForAuthoredFormatting = (authoredFormatting, formatting) => {
|
|
372
450
|
const changes = [];
|
|
373
|
-
for (const
|
|
451
|
+
for (const property of [
|
|
452
|
+
"bold",
|
|
453
|
+
"italic",
|
|
454
|
+
"underline",
|
|
455
|
+
"strike",
|
|
456
|
+
"fontFamily",
|
|
457
|
+
"fontSizePt",
|
|
458
|
+
"color",
|
|
459
|
+
"highlight",
|
|
460
|
+
"runShading"
|
|
461
|
+
]) {
|
|
462
|
+
if (formatting[property] === void 0) continue;
|
|
463
|
+
const next = patchAuthoredRunFormatting({
|
|
464
|
+
authoredFormatting,
|
|
465
|
+
formatting,
|
|
466
|
+
includedProperties: [property]
|
|
467
|
+
});
|
|
468
|
+
if (!sameDefinedFormattingValue(authoredFormatting, next)) changes.push(property);
|
|
469
|
+
}
|
|
374
470
|
return changes;
|
|
375
471
|
};
|
|
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
|
-
|
|
472
|
+
const clearReplacementBackground = ({ tr, schema, from, to, mode, revisionIdSeed, author, date, initials, suggestionId = null, styleResolver }) => {
|
|
473
|
+
if (![schema.marks["highlight"], schema.marks["runShading"]].some((markType) => markType !== void 0 && tr.doc.rangeHasMark(from, to, markType))) return {
|
|
474
|
+
type: "applied",
|
|
475
|
+
transaction: tr,
|
|
476
|
+
revisionIds: [],
|
|
477
|
+
nextRevisionId: revisionIdSeed
|
|
478
|
+
};
|
|
479
|
+
if (mode === "direct") return {
|
|
480
|
+
type: "applied",
|
|
481
|
+
transaction: applyInlineFormatting({
|
|
482
|
+
tr,
|
|
483
|
+
from,
|
|
484
|
+
to,
|
|
485
|
+
formatting: REPLACEMENT_BACKGROUND_CLEAR_FORMATTING,
|
|
486
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
487
|
+
}),
|
|
488
|
+
revisionIds: [],
|
|
489
|
+
nextRevisionId: revisionIdSeed
|
|
490
|
+
};
|
|
385
491
|
return applyTrackedInlineFormatting({
|
|
386
492
|
tr,
|
|
387
493
|
schema,
|
|
@@ -389,26 +495,85 @@ const clearReplacementBackground = ({ tr, schema, from, to, mode, revisionId, au
|
|
|
389
495
|
from,
|
|
390
496
|
to,
|
|
391
497
|
formatting: REPLACEMENT_BACKGROUND_CLEAR_FORMATTING,
|
|
392
|
-
|
|
498
|
+
revisionIdSeed,
|
|
393
499
|
author,
|
|
394
500
|
date,
|
|
395
501
|
initials,
|
|
396
|
-
suggestionId
|
|
502
|
+
suggestionId,
|
|
503
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
397
504
|
});
|
|
398
505
|
};
|
|
399
|
-
const applyTrackedInlineFormatting = ({ tr, schema, doc, from, to, formatting,
|
|
506
|
+
const applyTrackedInlineFormatting = ({ tr, schema, doc, from, to, formatting, revisionIdSeed, author, date, initials, suggestionId = null, styleResolver }) => {
|
|
400
507
|
const propertyChangeType = schema.marks["runPropertyChange"];
|
|
401
|
-
if (!propertyChangeType) return
|
|
508
|
+
if (!propertyChangeType) return {
|
|
509
|
+
type: "applied",
|
|
510
|
+
transaction: tr,
|
|
511
|
+
revisionIds: [],
|
|
512
|
+
nextRevisionId: revisionIdSeed
|
|
513
|
+
};
|
|
402
514
|
const segments = [];
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
515
|
+
let hasPendingRunPropertyChange = false;
|
|
516
|
+
const representations = selectRunFormattingCarrierRepresentations({
|
|
517
|
+
doc,
|
|
518
|
+
from,
|
|
519
|
+
to
|
|
520
|
+
});
|
|
521
|
+
for (const representation of representations) {
|
|
522
|
+
const { node } = representation;
|
|
523
|
+
const styleContext = paragraphRunStyleContextAt({
|
|
524
|
+
doc,
|
|
525
|
+
pos: representation.from,
|
|
526
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
527
|
+
});
|
|
528
|
+
const previousFormatting = readAuthoredRunFormatting({
|
|
529
|
+
context: styleContext,
|
|
530
|
+
marks: node.marks,
|
|
531
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
532
|
+
});
|
|
533
|
+
const includedProperties = formattingChangesForAuthoredFormatting(previousFormatting, formatting);
|
|
534
|
+
if (includedProperties.length === 0) continue;
|
|
410
535
|
const existingMark = node.marks.find((mark) => mark.type === propertyChangeType);
|
|
411
|
-
|
|
536
|
+
if (existingMark && expectRunPropertyChangeMarkAttrs(existingMark).changes.length > 0) {
|
|
537
|
+
hasPendingRunPropertyChange = true;
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
const formattingMarks = reconcileRunFormattingMarks({
|
|
541
|
+
authoredFormatting: patchAuthoredRunFormatting({
|
|
542
|
+
authoredFormatting: previousFormatting,
|
|
543
|
+
formatting,
|
|
544
|
+
includedProperties
|
|
545
|
+
}),
|
|
546
|
+
context: styleContext,
|
|
547
|
+
node,
|
|
548
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
549
|
+
});
|
|
550
|
+
segments.push({
|
|
551
|
+
formattingMarks,
|
|
552
|
+
representation,
|
|
553
|
+
includedProperties,
|
|
554
|
+
previousFormatting
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
if (hasPendingRunPropertyChange) return {
|
|
558
|
+
type: "pendingRunPropertyChange",
|
|
559
|
+
transaction: tr,
|
|
560
|
+
revisionIds: [],
|
|
561
|
+
nextRevisionId: revisionIdSeed
|
|
562
|
+
};
|
|
563
|
+
if (segments.length === 0) return {
|
|
564
|
+
type: "applied",
|
|
565
|
+
transaction: tr,
|
|
566
|
+
revisionIds: [],
|
|
567
|
+
nextRevisionId: revisionIdSeed
|
|
568
|
+
};
|
|
569
|
+
const suggestionAttrs = suggestionId === null ? {} : {
|
|
570
|
+
provenance: "suggested",
|
|
571
|
+
suggestionId
|
|
572
|
+
};
|
|
573
|
+
const revisionIds = [];
|
|
574
|
+
for (const segment of segments) {
|
|
575
|
+
const revisionId = revisionIdSeed + revisionIds.length;
|
|
576
|
+
revisionIds.push(revisionId);
|
|
412
577
|
const change = {
|
|
413
578
|
type: "runPropertyChange",
|
|
414
579
|
info: {
|
|
@@ -417,35 +582,24 @@ const applyTrackedInlineFormatting = ({ tr, schema, doc, from, to, formatting, r
|
|
|
417
582
|
date,
|
|
418
583
|
...initials ? { initials } : {}
|
|
419
584
|
},
|
|
420
|
-
...Object.keys(previousFormatting).length > 0 ? { previousFormatting } : {}
|
|
585
|
+
...Object.keys(segment.previousFormatting).length > 0 ? { previousFormatting: segment.previousFormatting } : {}
|
|
421
586
|
};
|
|
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({
|
|
587
|
+
const marks = propertyChangeType.create({
|
|
588
|
+
changes: [change],
|
|
589
|
+
...suggestionAttrs
|
|
590
|
+
}).addToSet(segment.formattingMarks);
|
|
591
|
+
applyMarksToRunFormattingRepresentation({
|
|
436
592
|
tr,
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
to: segment.to,
|
|
440
|
-
formatting,
|
|
441
|
-
includedProperties: segment.includedProperties
|
|
593
|
+
representation: segment.representation,
|
|
594
|
+
marks
|
|
442
595
|
});
|
|
443
|
-
tr.addMark(segment.from, segment.to, propertyChangeType.create({
|
|
444
|
-
changes: segment.changes,
|
|
445
|
-
...suggestionAttrs
|
|
446
|
-
}));
|
|
447
596
|
}
|
|
448
|
-
return
|
|
597
|
+
return {
|
|
598
|
+
type: "applied",
|
|
599
|
+
transaction: tr,
|
|
600
|
+
revisionIds,
|
|
601
|
+
nextRevisionId: revisionIdSeed + revisionIds.length
|
|
602
|
+
};
|
|
449
603
|
};
|
|
450
604
|
/**
|
|
451
605
|
* Module-scoped monotonic counter for tracked-change revision ids.
|
|
@@ -686,6 +840,7 @@ const buildEmphasisInlineContent = (schema, text, baseMarks) => {
|
|
|
686
840
|
};
|
|
687
841
|
const isBatchableParagraphInsertion = (item, mode) => {
|
|
688
842
|
if (item.operation.type !== "insertAfterBlock" && item.operation.type !== "insertBeforeBlock") return false;
|
|
843
|
+
if (item.commentText !== void 0) return false;
|
|
689
844
|
const insertTexts = item.insertTexts ?? [""];
|
|
690
845
|
const isEmptyInsert = insertTexts.length === 1 && insertTexts[0]?.length === 0;
|
|
691
846
|
return !(mode === "tracked-changes" && item.operation.pageBreakBefore === true && isEmptyInsert);
|
|
@@ -781,6 +936,7 @@ const withRotatedAddedFinalBreaks = ({ tr, batchRevisionIds, revisionSeed, autho
|
|
|
781
936
|
const liveCurrent = next.doc.nodeAt(current.position);
|
|
782
937
|
if (!liveCurrent || liveCurrent.type.name !== final.type.name) panic("A final-mark rotation lost its paragraph", { position: current.position });
|
|
783
938
|
const existing = expectParagraphAttrs(liveCurrent)._propertyChanges;
|
|
939
|
+
if (hasSerializableParagraphPropertyChange(existing)) panic("A final-mark rotation cannot append a second w:pPrChange", { position: current.position });
|
|
784
940
|
const revisionId = nextRevisionId++;
|
|
785
941
|
next = next.setNodeMarkup(current.position, void 0, {
|
|
786
942
|
...liveCurrent.attrs,
|
|
@@ -810,7 +966,7 @@ const withRotatedAddedFinalBreaks = ({ tr, batchRevisionIds, revisionSeed, autho
|
|
|
810
966
|
synthesizedRevisions
|
|
811
967
|
};
|
|
812
968
|
};
|
|
813
|
-
const buildInsertedParagraphs = ({ item, schema,
|
|
969
|
+
const buildInsertedParagraphs = ({ item, schema, formattingFromStyle, mode, author, date, initials, commentMark, suggestionId, revisionSeed, isPairedMove, numbering }) => {
|
|
814
970
|
const operation = item.operation;
|
|
815
971
|
if (operation.type !== "insertAfterBlock" && operation.type !== "insertBeforeBlock") panic("Only paragraph insertions can build inserted paragraphs", { type: operation.type });
|
|
816
972
|
const insertionType = schema.marks["insertion"];
|
|
@@ -823,7 +979,12 @@ const buildInsertedParagraphs = ({ item, schema, alignmentFromStyle, mode, autho
|
|
|
823
979
|
suggestionId
|
|
824
980
|
} : {}
|
|
825
981
|
};
|
|
826
|
-
const baseAttrs = operation.inheritFormatting === false ? {} :
|
|
982
|
+
const baseAttrs = operation.inheritFormatting === false ? {} : {
|
|
983
|
+
...stripBlockIdentityAttrs(item.blockNode.attrs),
|
|
984
|
+
_propertyChanges: null,
|
|
985
|
+
pPrMark: null,
|
|
986
|
+
_suggestedInsert: null
|
|
987
|
+
};
|
|
827
988
|
const insertTexts = item.insertTexts ?? [""];
|
|
828
989
|
const revisionIds = [];
|
|
829
990
|
const nodes = [];
|
|
@@ -847,33 +1008,51 @@ const buildInsertedParagraphs = ({ item, schema, alignmentFromStyle, mode, autho
|
|
|
847
1008
|
const content = text.length > 0 ? buildEmphasisInlineContent(schema, text, marks) : null;
|
|
848
1009
|
const attrs = isFirstParagraph ? { ...baseAttrs } : {};
|
|
849
1010
|
if (isFirstParagraph && operation.pageBreakBefore === true) attrs["pageBreakBefore"] = true;
|
|
850
|
-
|
|
1011
|
+
const listLevel = operation.listLevel;
|
|
1012
|
+
if (isFirstParagraph && listLevel === null) {
|
|
851
1013
|
attrs["numPr"] = null;
|
|
852
|
-
Object.assign(attrs,
|
|
853
|
-
} else if (isFirstParagraph &&
|
|
854
|
-
const anchorNumPr = baseAttrs
|
|
1014
|
+
Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
|
|
1015
|
+
} else if (isFirstParagraph && typeof listLevel === "number") {
|
|
1016
|
+
const anchorNumPr = Reflect.get(baseAttrs, "numPr");
|
|
855
1017
|
const numId = typeof anchorNumPr === "object" && anchorNumPr !== null && "numId" in anchorNumPr ? anchorNumPr.numId : void 0;
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
ilvl:
|
|
859
|
-
};
|
|
1018
|
+
if (typeof numId === "number") Object.assign(attrs, listLevelAttrPatch(operation.inheritFormatting === false ? {} : expectParagraphAttrs(item.blockNode), {
|
|
1019
|
+
numId,
|
|
1020
|
+
ilvl: listLevel
|
|
1021
|
+
}, numbering));
|
|
1022
|
+
else {
|
|
1023
|
+
attrs["numPr"] = { ilvl: listLevel };
|
|
1024
|
+
Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
|
|
1025
|
+
}
|
|
860
1026
|
}
|
|
861
1027
|
if (isFirstParagraph && operation.styleId !== void 0) {
|
|
862
1028
|
attrs["styleId"] = operation.styleId;
|
|
863
|
-
if (operation.inheritFormatting !== false && operation.styleId !== null) Object.assign(attrs,
|
|
1029
|
+
if (operation.inheritFormatting !== false && operation.styleId !== null) Object.assign(attrs, CLEARED_LIST_RENDERING_ATTRS);
|
|
864
1030
|
}
|
|
865
|
-
if (isFirstParagraph && (operation.styleId !== void 0 || operation.alignment !== void 0)) {
|
|
1031
|
+
if (isFirstParagraph && (operation.styleId !== void 0 || operation.alignment !== void 0 || operation.spacing !== void 0)) {
|
|
866
1032
|
const inheritedDirectAlignment = operation.inheritFormatting === false ? void 0 : directParagraphAlignment(expectParagraphAttrs(item.blockNode));
|
|
1033
|
+
const inheritedDirectSpacing = operation.inheritFormatting === false ? void 0 : directParagraphSpacing(expectParagraphAttrs(item.blockNode));
|
|
867
1034
|
const directAlignment = operation.alignment === void 0 ? inheritedDirectAlignment : operation.alignment ?? void 0;
|
|
868
|
-
|
|
869
|
-
attrs["
|
|
1035
|
+
const directSpacing = operation.spacing === void 0 ? inheritedDirectSpacing : operation.spacing ?? void 0;
|
|
1036
|
+
attrs["alignmentFromStyle"] = formattingFromStyle?.alignment;
|
|
1037
|
+
attrs["alignment"] = directAlignment ?? formattingFromStyle?.alignment ?? null;
|
|
870
1038
|
const sourceFormatting = attrs["_originalFormatting"];
|
|
871
|
-
|
|
872
|
-
if (operation.styleId !== void 0)
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
1039
|
+
let originalFormatting = typeof sourceFormatting === "object" && sourceFormatting !== null ? { ...sourceFormatting } : void 0;
|
|
1040
|
+
if (operation.styleId !== void 0) {
|
|
1041
|
+
originalFormatting ??= {};
|
|
1042
|
+
if (operation.styleId === null) Reflect.deleteProperty(originalFormatting, "styleId");
|
|
1043
|
+
else originalFormatting.styleId = operation.styleId;
|
|
1044
|
+
}
|
|
1045
|
+
if (operation.alignment !== void 0 || inheritedDirectAlignment !== void 0) {
|
|
1046
|
+
originalFormatting ??= {};
|
|
1047
|
+
if (directAlignment === void 0) Reflect.deleteProperty(originalFormatting, "alignment");
|
|
1048
|
+
else originalFormatting.alignment = directAlignment;
|
|
1049
|
+
}
|
|
1050
|
+
if (operation.spacing !== void 0) originalFormatting = withDirectParagraphSpacing(originalFormatting, directSpacing);
|
|
1051
|
+
if (operation.styleId !== void 0 || operation.spacing !== void 0) Object.assign(attrs, paragraphSpacingAttrPatch({
|
|
1052
|
+
direct: directSpacing,
|
|
1053
|
+
inherited: paragraphSpacingFromFormatting(formattingFromStyle)
|
|
1054
|
+
}));
|
|
1055
|
+
attrs["_originalFormatting"] = originalFormatting && Object.keys(originalFormatting).length > 0 ? originalFormatting : null;
|
|
877
1056
|
}
|
|
878
1057
|
if (isSuggested && suggestionId !== null && paragraphRevisionId !== null) attrs["_suggestedInsert"] = {
|
|
879
1058
|
suggestionId,
|
|
@@ -914,13 +1093,37 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
914
1093
|
const insertionType = view.state.schema.marks["insertion"];
|
|
915
1094
|
const deletionType = view.state.schema.marks["deletion"];
|
|
916
1095
|
const commentType = view.state.schema.marks["comment"];
|
|
1096
|
+
const occupiedCommentIds = /* @__PURE__ */ new Set();
|
|
1097
|
+
if (commentType) view.state.doc.descendants((node) => {
|
|
1098
|
+
for (const mark of node.marks) {
|
|
1099
|
+
if (mark.type !== commentType) continue;
|
|
1100
|
+
const commentId = mark.attrs["commentId"];
|
|
1101
|
+
if (typeof commentId === "number") occupiedCommentIds.add(commentId);
|
|
1102
|
+
}
|
|
1103
|
+
});
|
|
1104
|
+
let provisionalCommentIdCursor = Number.MIN_SAFE_INTEGER;
|
|
1105
|
+
const reserveProvisionalCommentId = () => {
|
|
1106
|
+
while (occupiedCommentIds.has(provisionalCommentIdCursor)) provisionalCommentIdCursor += 1;
|
|
1107
|
+
const id = provisionalCommentIdCursor;
|
|
1108
|
+
provisionalCommentIdCursor += 1;
|
|
1109
|
+
occupiedCommentIds.add(id);
|
|
1110
|
+
return id;
|
|
1111
|
+
};
|
|
1112
|
+
const allocateCommittedCommentId = (text) => {
|
|
1113
|
+
if (createCommentId === void 0) panic("A resolved comment operation lost its comment-id allocator");
|
|
1114
|
+
const id = createCommentId(text);
|
|
1115
|
+
if (!Number.isSafeInteger(id) || occupiedCommentIds.has(id)) panic("A comment-id allocator returned an invalid or duplicate id", { id });
|
|
1116
|
+
occupiedCommentIds.add(id);
|
|
1117
|
+
return id;
|
|
1118
|
+
};
|
|
917
1119
|
const styleResolver = getDocumentStyleResolver(view.state);
|
|
918
|
-
const
|
|
1120
|
+
const numbering = getDocumentNumbering(view.state);
|
|
1121
|
+
const formattingFromStyleForInsertion = (item) => {
|
|
919
1122
|
if (item.operation.type !== "insertAfterBlock" && item.operation.type !== "insertBeforeBlock") return;
|
|
920
1123
|
const anchorAttrs = expectParagraphAttrs(item.blockNode);
|
|
921
1124
|
const inheritedStyleId = item.operation.inheritFormatting === false ? null : anchorAttrs.styleId;
|
|
922
1125
|
const styleId = item.operation.styleId !== void 0 ? item.operation.styleId : inheritedStyleId;
|
|
923
|
-
return
|
|
1126
|
+
return resolveFormattingFromStyle({
|
|
924
1127
|
attrs: anchorAttrs,
|
|
925
1128
|
styleId,
|
|
926
1129
|
styleResolver
|
|
@@ -964,6 +1167,13 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
964
1167
|
});
|
|
965
1168
|
continue;
|
|
966
1169
|
}
|
|
1170
|
+
if (commentText !== void 0 && !hasRepresentableCommentAnchor(resolution.operation, mode)) {
|
|
1171
|
+
skipped.push({
|
|
1172
|
+
id: operation.id,
|
|
1173
|
+
reason: "unsupportedBlock"
|
|
1174
|
+
});
|
|
1175
|
+
continue;
|
|
1176
|
+
}
|
|
967
1177
|
const deletion = resolution.operation.tableRowDeletion;
|
|
968
1178
|
if (deletion) {
|
|
969
1179
|
const rowKey = `${deletion.tablePosition}:${deletion.rowIndex}`;
|
|
@@ -993,11 +1203,10 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
993
1203
|
code: "splitMultilineText",
|
|
994
1204
|
paragraphCount: resolution.operation.insertTexts?.length ?? 1
|
|
995
1205
|
});
|
|
996
|
-
const commentId = commentText !== void 0 ? createCommentId?.(commentText) : void 0;
|
|
997
1206
|
resolved.push({
|
|
998
1207
|
...resolution.operation,
|
|
999
1208
|
originalIndex: index,
|
|
1000
|
-
...
|
|
1209
|
+
...commentText !== void 0 && { commentText }
|
|
1001
1210
|
});
|
|
1002
1211
|
}
|
|
1003
1212
|
const tablePlan = planTableMutations(resolved.map((item) => ({
|
|
@@ -1040,6 +1249,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1040
1249
|
}
|
|
1041
1250
|
let tr = view.state.tr;
|
|
1042
1251
|
const revisionIdReservation = executableResolved.reduce((total, item) => total + estimateRevisionIdReservation(item), 0);
|
|
1252
|
+
const ownsSharedRevisionIdCursor = revisionIdSeed === void 0 && revisionStamp === void 0;
|
|
1043
1253
|
let revisionSeed = revisionIdSeed ?? revisionStamp?.idSeed ?? nextRevisionSeed(revisionIdReservation);
|
|
1044
1254
|
const date = revisionStamp?.date ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1045
1255
|
const insertedColumnCounts = /* @__PURE__ */ new Map();
|
|
@@ -1071,6 +1281,17 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1071
1281
|
for (let executionIndex = 0; executionIndex < executionOrder.length; executionIndex++) {
|
|
1072
1282
|
const item = executionOrder[executionIndex];
|
|
1073
1283
|
if (!item) panic("The operation execution index exceeded the resolved plan", { executionIndex });
|
|
1284
|
+
if (mode === "tracked-changes" && writesParagraphPropertyChange(item)) {
|
|
1285
|
+
const livePosition = tr.mapping.map(item.blockFrom);
|
|
1286
|
+
const liveBlock = tr.doc.nodeAt(livePosition) ?? item.blockNode;
|
|
1287
|
+
if (hasSerializableParagraphPropertyChange(liveBlock.type.name === "paragraph" ? expectParagraphAttrs(liveBlock)._propertyChanges : void 0)) {
|
|
1288
|
+
skipped.push({
|
|
1289
|
+
id: item.operation.id,
|
|
1290
|
+
reason: "pendingParagraphPropertyChange"
|
|
1291
|
+
});
|
|
1292
|
+
continue;
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1074
1295
|
if (isBatchableParagraphInsertion(item, mode)) {
|
|
1075
1296
|
const insertionRun = [item];
|
|
1076
1297
|
for (let lookahead = executionIndex + 1; lookahead < executionOrder.length; lookahead++) {
|
|
@@ -1083,25 +1304,24 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1083
1304
|
const runApplied = [];
|
|
1084
1305
|
for (const insertion of insertionRun) {
|
|
1085
1306
|
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
1307
|
const built = buildInsertedParagraphs({
|
|
1088
1308
|
item: insertion,
|
|
1089
1309
|
schema: view.state.schema,
|
|
1090
|
-
|
|
1310
|
+
formattingFromStyle: formattingFromStyleForInsertion(insertion),
|
|
1091
1311
|
mode,
|
|
1092
1312
|
author,
|
|
1093
1313
|
date,
|
|
1094
1314
|
initials,
|
|
1095
|
-
commentMark:
|
|
1315
|
+
commentMark: null,
|
|
1096
1316
|
suggestionId: insertionSuggestionId,
|
|
1097
1317
|
revisionSeed,
|
|
1098
|
-
isPairedMove
|
|
1318
|
+
isPairedMove,
|
|
1319
|
+
numbering
|
|
1099
1320
|
});
|
|
1100
1321
|
revisionSeed = built.nextRevisionId;
|
|
1101
1322
|
nodeGroups.push(built.nodes);
|
|
1102
1323
|
runApplied.push({
|
|
1103
1324
|
id: insertion.operation.id,
|
|
1104
|
-
...insertion.commentId !== void 0 && { commentId: insertion.commentId },
|
|
1105
1325
|
...built.revisionIds[0] !== void 0 && {
|
|
1106
1326
|
revisionId: built.revisionIds[0],
|
|
1107
1327
|
revisionIds: built.revisionIds
|
|
@@ -1117,9 +1337,10 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1117
1337
|
continue;
|
|
1118
1338
|
}
|
|
1119
1339
|
}
|
|
1120
|
-
const
|
|
1340
|
+
const provisionalCommentId = item.commentText !== void 0 ? reserveProvisionalCommentId() : void 0;
|
|
1341
|
+
const commentMark = provisionalCommentId !== void 0 && commentType ? commentType.create({ commentId: provisionalCommentId }) : null;
|
|
1121
1342
|
const stepsBefore = tr.steps.length;
|
|
1122
|
-
let appliedRevisionIds;
|
|
1343
|
+
let appliedRevisionIds = [];
|
|
1123
1344
|
if (isSuggested && !SUGGESTED_SUPPORTED_OPERATION_TYPES.has(item.operation.type)) {
|
|
1124
1345
|
skipped.push({
|
|
1125
1346
|
id: item.operation.id,
|
|
@@ -1135,8 +1356,9 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1135
1356
|
suggestionId
|
|
1136
1357
|
} : {}
|
|
1137
1358
|
};
|
|
1359
|
+
let operationRevisionSeed = revisionSeed;
|
|
1138
1360
|
const structuralRevision = producesTrackedChanges ? {
|
|
1139
|
-
revisionId:
|
|
1361
|
+
revisionId: operationRevisionSeed,
|
|
1140
1362
|
author,
|
|
1141
1363
|
date,
|
|
1142
1364
|
...trackedRevisionExtras
|
|
@@ -1144,22 +1366,32 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1144
1366
|
switch (item.operation.type) {
|
|
1145
1367
|
case "replaceInBlock":
|
|
1146
1368
|
case "replaceRange": {
|
|
1147
|
-
const revisionIdDelete =
|
|
1148
|
-
const revisionIdInsert =
|
|
1149
|
-
const
|
|
1369
|
+
const revisionIdDelete = operationRevisionSeed;
|
|
1370
|
+
const revisionIdInsert = producesTrackedChanges ? operationRevisionSeed + 1 : operationRevisionSeed;
|
|
1371
|
+
const revisionIdBackgroundSeed = producesTrackedChanges ? operationRevisionSeed + 2 : operationRevisionSeed;
|
|
1150
1372
|
const stepsBeforeBackgroundClear = tr.steps.length;
|
|
1151
|
-
|
|
1373
|
+
const backgroundResult = clearReplacementBackground({
|
|
1152
1374
|
tr,
|
|
1153
1375
|
schema: view.state.schema,
|
|
1154
1376
|
from: item.from,
|
|
1155
1377
|
to: item.to,
|
|
1156
1378
|
mode,
|
|
1157
|
-
|
|
1379
|
+
revisionIdSeed: revisionIdBackgroundSeed,
|
|
1158
1380
|
author,
|
|
1159
1381
|
date,
|
|
1160
1382
|
initials,
|
|
1161
|
-
suggestionId
|
|
1383
|
+
suggestionId,
|
|
1384
|
+
styleResolver
|
|
1162
1385
|
});
|
|
1386
|
+
if (backgroundResult.type === "pendingRunPropertyChange") {
|
|
1387
|
+
skipped.push({
|
|
1388
|
+
id: item.operation.id,
|
|
1389
|
+
reason: backgroundResult.type
|
|
1390
|
+
});
|
|
1391
|
+
continue;
|
|
1392
|
+
}
|
|
1393
|
+
tr = backgroundResult.transaction;
|
|
1394
|
+
operationRevisionSeed = backgroundResult.nextRevisionId;
|
|
1163
1395
|
const clearedBackground = tr.steps.length > stepsBeforeBackgroundClear;
|
|
1164
1396
|
tr = applyTextReplacement({
|
|
1165
1397
|
tr,
|
|
@@ -1177,7 +1409,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1177
1409
|
if (producesTrackedChanges) appliedRevisionIds = [
|
|
1178
1410
|
revisionIdDelete,
|
|
1179
1411
|
revisionIdInsert,
|
|
1180
|
-
...clearedBackground ?
|
|
1412
|
+
...clearedBackground ? backgroundResult.revisionIds : []
|
|
1181
1413
|
];
|
|
1182
1414
|
break;
|
|
1183
1415
|
}
|
|
@@ -1186,44 +1418,52 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1186
1418
|
break;
|
|
1187
1419
|
case "formatRange":
|
|
1188
1420
|
if (producesTrackedChanges) {
|
|
1189
|
-
const
|
|
1190
|
-
tr = applyTrackedInlineFormatting({
|
|
1421
|
+
const formattingResult = applyTrackedInlineFormatting({
|
|
1191
1422
|
tr,
|
|
1192
1423
|
schema: view.state.schema,
|
|
1193
1424
|
doc: tr.doc,
|
|
1194
1425
|
from: item.from,
|
|
1195
1426
|
to: item.to,
|
|
1196
1427
|
formatting: item.operation.formatting,
|
|
1197
|
-
|
|
1428
|
+
revisionIdSeed: operationRevisionSeed,
|
|
1198
1429
|
author,
|
|
1199
1430
|
date,
|
|
1200
1431
|
initials,
|
|
1201
|
-
suggestionId
|
|
1432
|
+
suggestionId,
|
|
1433
|
+
styleResolver
|
|
1202
1434
|
});
|
|
1203
|
-
|
|
1435
|
+
if (formattingResult.type === "pendingRunPropertyChange") {
|
|
1436
|
+
skipped.push({
|
|
1437
|
+
id: item.operation.id,
|
|
1438
|
+
reason: formattingResult.type
|
|
1439
|
+
});
|
|
1440
|
+
continue;
|
|
1441
|
+
}
|
|
1442
|
+
tr = formattingResult.transaction;
|
|
1443
|
+
operationRevisionSeed = formattingResult.nextRevisionId;
|
|
1444
|
+
appliedRevisionIds = [...formattingResult.revisionIds];
|
|
1204
1445
|
break;
|
|
1205
1446
|
}
|
|
1206
1447
|
tr = applyInlineFormatting({
|
|
1207
1448
|
tr,
|
|
1208
|
-
schema: view.state.schema,
|
|
1209
1449
|
from: item.from,
|
|
1210
1450
|
to: item.to,
|
|
1211
|
-
formatting: item.operation.formatting
|
|
1451
|
+
formatting: item.operation.formatting,
|
|
1452
|
+
...styleResolver !== void 0 ? { styleResolver } : {}
|
|
1212
1453
|
});
|
|
1213
1454
|
break;
|
|
1214
1455
|
case "replaceBlock": {
|
|
1215
1456
|
if (!isResolvedReplaceBlockOperation(item)) panic("Resolved replaceBlock operation lost its impact discriminator");
|
|
1216
1457
|
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;
|
|
1458
|
+
const revisionIdDelete = operationRevisionSeed;
|
|
1459
|
+
const revisionIdInsert = changesText ? operationRevisionSeed + 1 : operationRevisionSeed;
|
|
1460
|
+
const revisionIdBackgroundSeed = changesText ? operationRevisionSeed + 2 : operationRevisionSeed;
|
|
1461
|
+
if (producesTrackedChanges && changesText) operationRevisionSeed = revisionIdBackgroundSeed;
|
|
1222
1462
|
if (item.operation.preserveFormatting === false && mode === "direct") {
|
|
1223
1463
|
const replacement = item.operation.text;
|
|
1224
1464
|
const paragraphType = view.state.schema.nodes["paragraph"];
|
|
1225
1465
|
if (paragraphType) {
|
|
1226
|
-
const node = paragraphType.create(null, replacement.length === 0 ? null : buildEmphasisInlineContent(view.state.schema, replacement, []));
|
|
1466
|
+
const node = paragraphType.create(null, replacement.length === 0 ? null : buildEmphasisInlineContent(view.state.schema, replacement, commentMark ? [commentMark] : []));
|
|
1227
1467
|
tr = tr.replaceWith(item.blockFrom, item.blockTo, node);
|
|
1228
1468
|
tr = applyReplaceBlockStyleId({
|
|
1229
1469
|
item,
|
|
@@ -1244,21 +1484,33 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1244
1484
|
break;
|
|
1245
1485
|
}
|
|
1246
1486
|
let clearedBackground = false;
|
|
1487
|
+
let backgroundRevisionIds = [];
|
|
1247
1488
|
if (changesText) {
|
|
1248
1489
|
const stepsBeforeBackgroundClear = tr.steps.length;
|
|
1249
|
-
|
|
1490
|
+
const backgroundResult = clearReplacementBackground({
|
|
1250
1491
|
tr,
|
|
1251
1492
|
schema: view.state.schema,
|
|
1252
1493
|
from: item.from,
|
|
1253
1494
|
to: item.to,
|
|
1254
1495
|
mode,
|
|
1255
|
-
|
|
1496
|
+
revisionIdSeed: revisionIdBackgroundSeed,
|
|
1256
1497
|
author,
|
|
1257
1498
|
date,
|
|
1258
1499
|
initials,
|
|
1259
|
-
suggestionId
|
|
1500
|
+
suggestionId,
|
|
1501
|
+
styleResolver
|
|
1260
1502
|
});
|
|
1503
|
+
if (backgroundResult.type === "pendingRunPropertyChange") {
|
|
1504
|
+
skipped.push({
|
|
1505
|
+
id: item.operation.id,
|
|
1506
|
+
reason: backgroundResult.type
|
|
1507
|
+
});
|
|
1508
|
+
continue;
|
|
1509
|
+
}
|
|
1510
|
+
tr = backgroundResult.transaction;
|
|
1511
|
+
operationRevisionSeed = backgroundResult.nextRevisionId;
|
|
1261
1512
|
clearedBackground = tr.steps.length > stepsBeforeBackgroundClear;
|
|
1513
|
+
backgroundRevisionIds = backgroundResult.revisionIds;
|
|
1262
1514
|
tr = applyTextReplacement({
|
|
1263
1515
|
tr,
|
|
1264
1516
|
item,
|
|
@@ -1273,6 +1525,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1273
1525
|
diffText
|
|
1274
1526
|
});
|
|
1275
1527
|
}
|
|
1528
|
+
const revisionIdParagraph = producesTrackedChanges && changesStyle ? operationRevisionSeed++ : null;
|
|
1276
1529
|
const styleResult = applyReplaceBlockStyleId({
|
|
1277
1530
|
item,
|
|
1278
1531
|
tr,
|
|
@@ -1285,9 +1538,10 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1285
1538
|
} } : {}
|
|
1286
1539
|
});
|
|
1287
1540
|
tr = styleResult.tr;
|
|
1541
|
+
if (!changesText && commentMark) tr = tr.addMark(item.from, item.to, commentMark);
|
|
1288
1542
|
if (producesTrackedChanges) appliedRevisionIds = [
|
|
1289
1543
|
...changesText ? [revisionIdDelete, revisionIdInsert] : [],
|
|
1290
|
-
...clearedBackground ?
|
|
1544
|
+
...clearedBackground ? backgroundRevisionIds : [],
|
|
1291
1545
|
...styleResult.revisionId === null ? [] : [styleResult.revisionId]
|
|
1292
1546
|
];
|
|
1293
1547
|
break;
|
|
@@ -1306,17 +1560,18 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1306
1560
|
const built = buildInsertedParagraphs({
|
|
1307
1561
|
item,
|
|
1308
1562
|
schema: view.state.schema,
|
|
1309
|
-
|
|
1563
|
+
formattingFromStyle: formattingFromStyleForInsertion(item),
|
|
1310
1564
|
mode,
|
|
1311
1565
|
author,
|
|
1312
1566
|
date,
|
|
1313
1567
|
initials,
|
|
1314
1568
|
commentMark,
|
|
1315
1569
|
suggestionId,
|
|
1316
|
-
revisionSeed,
|
|
1317
|
-
isPairedMove
|
|
1570
|
+
revisionSeed: operationRevisionSeed,
|
|
1571
|
+
isPairedMove,
|
|
1572
|
+
numbering
|
|
1318
1573
|
});
|
|
1319
|
-
|
|
1574
|
+
operationRevisionSeed = built.nextRevisionId;
|
|
1320
1575
|
if (built.revisionIds.length > 0) appliedRevisionIds = built.revisionIds;
|
|
1321
1576
|
tr = tr.insert(item.from, built.nodes);
|
|
1322
1577
|
break;
|
|
@@ -1342,7 +1597,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1342
1597
|
}
|
|
1343
1598
|
let node = signatureTable;
|
|
1344
1599
|
if (isSuggested && suggestionId !== null) {
|
|
1345
|
-
const revisionId =
|
|
1600
|
+
const revisionId = operationRevisionSeed++;
|
|
1346
1601
|
node = signatureTable.type.create({
|
|
1347
1602
|
...signatureTable.attrs,
|
|
1348
1603
|
_suggestedInsert: {
|
|
@@ -1385,7 +1640,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1385
1640
|
}
|
|
1386
1641
|
tr = result.transaction;
|
|
1387
1642
|
if (result.revisionId !== null) {
|
|
1388
|
-
|
|
1643
|
+
operationRevisionSeed++;
|
|
1389
1644
|
appliedRevisionIds = [result.revisionId];
|
|
1390
1645
|
}
|
|
1391
1646
|
break;
|
|
@@ -1415,7 +1670,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1415
1670
|
}
|
|
1416
1671
|
tr = result.transaction;
|
|
1417
1672
|
if (result.revisionId !== null) {
|
|
1418
|
-
|
|
1673
|
+
operationRevisionSeed++;
|
|
1419
1674
|
appliedRevisionIds = [result.revisionId];
|
|
1420
1675
|
}
|
|
1421
1676
|
const columnKey = getTableColumnCoordinateKey(insertion);
|
|
@@ -1448,7 +1703,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1448
1703
|
}
|
|
1449
1704
|
tr = result.transaction;
|
|
1450
1705
|
if (result.revisionId !== null) {
|
|
1451
|
-
|
|
1706
|
+
operationRevisionSeed++;
|
|
1452
1707
|
appliedRevisionIds = [result.revisionId];
|
|
1453
1708
|
}
|
|
1454
1709
|
break;
|
|
@@ -1464,7 +1719,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1464
1719
|
});
|
|
1465
1720
|
continue;
|
|
1466
1721
|
}
|
|
1467
|
-
const revisionId = mode === "tracked-changes" ?
|
|
1722
|
+
const revisionId = mode === "tracked-changes" ? operationRevisionSeed : null;
|
|
1468
1723
|
const nextTr = revisionId === null ? mergeTableRectangle({
|
|
1469
1724
|
tr,
|
|
1470
1725
|
tablePosition,
|
|
@@ -1488,7 +1743,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1488
1743
|
}
|
|
1489
1744
|
tr = nextTr;
|
|
1490
1745
|
if (revisionId !== null) {
|
|
1491
|
-
|
|
1746
|
+
operationRevisionSeed++;
|
|
1492
1747
|
appliedRevisionIds = [revisionId];
|
|
1493
1748
|
}
|
|
1494
1749
|
break;
|
|
@@ -1504,7 +1759,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1504
1759
|
});
|
|
1505
1760
|
continue;
|
|
1506
1761
|
}
|
|
1507
|
-
const revisionId = mode === "tracked-changes" ?
|
|
1762
|
+
const revisionId = mode === "tracked-changes" ? operationRevisionSeed : null;
|
|
1508
1763
|
const nextTr = revisionId === null ? splitTableRectangle({
|
|
1509
1764
|
tr,
|
|
1510
1765
|
tablePosition,
|
|
@@ -1528,7 +1783,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1528
1783
|
}
|
|
1529
1784
|
tr = nextTr;
|
|
1530
1785
|
if (revisionId !== null) {
|
|
1531
|
-
|
|
1786
|
+
operationRevisionSeed++;
|
|
1532
1787
|
appliedRevisionIds = [revisionId];
|
|
1533
1788
|
}
|
|
1534
1789
|
break;
|
|
@@ -1556,7 +1811,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1556
1811
|
}
|
|
1557
1812
|
tr = result.transaction;
|
|
1558
1813
|
if (result.revisionId !== null) {
|
|
1559
|
-
|
|
1814
|
+
operationRevisionSeed++;
|
|
1560
1815
|
appliedRevisionIds = [result.revisionId];
|
|
1561
1816
|
}
|
|
1562
1817
|
break;
|
|
@@ -1568,7 +1823,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1568
1823
|
break;
|
|
1569
1824
|
}
|
|
1570
1825
|
if (deletionType) {
|
|
1571
|
-
const revisionId =
|
|
1826
|
+
const revisionId = operationRevisionSeed++;
|
|
1572
1827
|
const deletionMark = deletionType.create({
|
|
1573
1828
|
revisionId,
|
|
1574
1829
|
author,
|
|
@@ -1583,7 +1838,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1583
1838
|
appliedRevisionIds = inlineRevisionApplied ? [revisionId] : [];
|
|
1584
1839
|
const markPosition = tr.mapping.map(item.blockFrom);
|
|
1585
1840
|
if (!paragraphEndsItsContainer(tr.doc.resolve(markPosition), item.blockNode.type.name) && tr.doc.nodeAt(markPosition)?.attrs["pPrMark"] == null) {
|
|
1586
|
-
const markRevisionId =
|
|
1841
|
+
const markRevisionId = operationRevisionSeed++;
|
|
1587
1842
|
tr = tr.setNodeAttribute(markPosition, "pPrMark", {
|
|
1588
1843
|
kind: isPairedMove(item.operation.moveId) ? "moveFrom" : "del",
|
|
1589
1844
|
info: {
|
|
@@ -1600,7 +1855,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1600
1855
|
break;
|
|
1601
1856
|
case "insertTable": {
|
|
1602
1857
|
const revision = {
|
|
1603
|
-
revisionId:
|
|
1858
|
+
revisionId: operationRevisionSeed,
|
|
1604
1859
|
author,
|
|
1605
1860
|
date,
|
|
1606
1861
|
...trackedRevisionExtras
|
|
@@ -1622,7 +1877,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1622
1877
|
});
|
|
1623
1878
|
continue;
|
|
1624
1879
|
}
|
|
1625
|
-
if (producesTrackedChanges) appliedRevisionIds = [
|
|
1880
|
+
if (producesTrackedChanges) appliedRevisionIds = [operationRevisionSeed++];
|
|
1626
1881
|
tr = tr.insert(item.from, table);
|
|
1627
1882
|
markStructuralChange(tr);
|
|
1628
1883
|
break;
|
|
@@ -1660,7 +1915,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1660
1915
|
continue;
|
|
1661
1916
|
}
|
|
1662
1917
|
const revision = {
|
|
1663
|
-
revisionId:
|
|
1918
|
+
revisionId: operationRevisionSeed++,
|
|
1664
1919
|
author,
|
|
1665
1920
|
date,
|
|
1666
1921
|
...trackedRevisionExtras
|
|
@@ -1694,80 +1949,89 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1694
1949
|
case "setBlockParagraphProperties": {
|
|
1695
1950
|
const blockPosition = tr.mapping.map(item.blockFrom);
|
|
1696
1951
|
const liveBlock = tr.doc.nodeAt(blockPosition) ?? item.blockNode;
|
|
1697
|
-
const
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
styleId: item.operation.properties.styleId,
|
|
1701
|
-
styleResolver
|
|
1702
|
-
});
|
|
1703
|
-
const patch = paragraphPropertiesPatch({
|
|
1952
|
+
const appliedProperties = applyBlockParagraphProperties({
|
|
1953
|
+
tr,
|
|
1954
|
+
position: blockPosition,
|
|
1704
1955
|
node: liveBlock,
|
|
1705
1956
|
properties: item.operation.properties,
|
|
1706
|
-
|
|
1957
|
+
styleResolver,
|
|
1958
|
+
numbering,
|
|
1959
|
+
...mode === "direct" ? {} : { revisionInfo: () => ({
|
|
1960
|
+
id: operationRevisionSeed++,
|
|
1961
|
+
author,
|
|
1962
|
+
date,
|
|
1963
|
+
...trackedRevisionExtras
|
|
1964
|
+
}) }
|
|
1707
1965
|
});
|
|
1708
|
-
if (
|
|
1966
|
+
if (!appliedProperties.changed) {
|
|
1709
1967
|
skipped.push({
|
|
1710
1968
|
id: item.operation.id,
|
|
1711
1969
|
reason: "noopOperation"
|
|
1712
1970
|
});
|
|
1713
1971
|
continue;
|
|
1714
1972
|
}
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
...liveBlock.attrs,
|
|
1718
|
-
...patch
|
|
1719
|
-
});
|
|
1720
|
-
break;
|
|
1721
|
-
}
|
|
1722
|
-
const revisionId = revisionSeed++;
|
|
1723
|
-
const change = {
|
|
1724
|
-
type: "paragraphPropertyChange",
|
|
1725
|
-
info: {
|
|
1726
|
-
id: revisionId,
|
|
1727
|
-
author,
|
|
1728
|
-
date,
|
|
1729
|
-
...trackedRevisionExtras
|
|
1730
|
-
},
|
|
1731
|
-
previousFormatting: paragraphPropertiesSnapshot(liveBlock)
|
|
1732
|
-
};
|
|
1733
|
-
const existing = expectParagraphAttrs(liveBlock)._propertyChanges;
|
|
1734
|
-
tr = tr.setNodeMarkup(blockPosition, void 0, {
|
|
1735
|
-
...liveBlock.attrs,
|
|
1736
|
-
...patch,
|
|
1737
|
-
_propertyChanges: [...Array.isArray(existing) ? existing : [], change]
|
|
1738
|
-
});
|
|
1739
|
-
appliedRevisionIds = [revisionId];
|
|
1973
|
+
tr = appliedProperties.tr;
|
|
1974
|
+
if (appliedProperties.revisionId !== null) appliedRevisionIds = [appliedProperties.revisionId];
|
|
1740
1975
|
break;
|
|
1741
1976
|
}
|
|
1742
1977
|
case "splitBlock": {
|
|
1743
1978
|
if (mode === "direct") {
|
|
1744
1979
|
if (item.to > item.from) tr = tr.delete(item.from, item.to);
|
|
1745
1980
|
tr = tr.split(item.from);
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
id: revisionIdMark,
|
|
1751
|
-
author,
|
|
1752
|
-
date,
|
|
1753
|
-
...trackedRevisionExtras
|
|
1754
|
-
};
|
|
1755
|
-
appliedRevisionIds = [revisionIdMark];
|
|
1756
|
-
if (item.to > item.from && deletionType) {
|
|
1757
|
-
const revisionIdSeparator = revisionSeed++;
|
|
1758
|
-
tr = tr.addMark(item.from, item.to, deletionType.create({
|
|
1759
|
-
revisionId: revisionIdSeparator,
|
|
1981
|
+
} else {
|
|
1982
|
+
const revisionIdMark = operationRevisionSeed++;
|
|
1983
|
+
const info = {
|
|
1984
|
+
id: revisionIdMark,
|
|
1760
1985
|
author,
|
|
1761
1986
|
date,
|
|
1762
1987
|
...trackedRevisionExtras
|
|
1763
|
-
}
|
|
1764
|
-
appliedRevisionIds = [revisionIdMark
|
|
1988
|
+
};
|
|
1989
|
+
appliedRevisionIds = [revisionIdMark];
|
|
1990
|
+
if (item.to > item.from && deletionType) {
|
|
1991
|
+
const revisionIdSeparator = operationRevisionSeed++;
|
|
1992
|
+
tr = tr.addMark(item.from, item.to, deletionType.create({
|
|
1993
|
+
revisionId: revisionIdSeparator,
|
|
1994
|
+
author,
|
|
1995
|
+
date,
|
|
1996
|
+
...trackedRevisionExtras
|
|
1997
|
+
}));
|
|
1998
|
+
appliedRevisionIds.push(revisionIdSeparator);
|
|
1999
|
+
}
|
|
2000
|
+
tr = tr.split(item.from);
|
|
2001
|
+
tr = tr.setNodeAttribute(item.blockFrom, "pPrMark", {
|
|
2002
|
+
kind: "ins",
|
|
2003
|
+
info
|
|
2004
|
+
});
|
|
1765
2005
|
}
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
2006
|
+
const allocateSplitParagraphPropertyRevisionInfo = () => ({
|
|
2007
|
+
id: operationRevisionSeed++,
|
|
2008
|
+
author,
|
|
2009
|
+
date,
|
|
2010
|
+
...trackedRevisionExtras
|
|
1770
2011
|
});
|
|
2012
|
+
const paragraphPropertyTargets = [{
|
|
2013
|
+
position: item.blockFrom,
|
|
2014
|
+
properties: item.operation.firstParagraphProperties
|
|
2015
|
+
}, {
|
|
2016
|
+
position: item.from + 1,
|
|
2017
|
+
properties: item.operation.secondParagraphProperties
|
|
2018
|
+
}];
|
|
2019
|
+
for (const { position, properties } of paragraphPropertyTargets) {
|
|
2020
|
+
if (!properties) continue;
|
|
2021
|
+
const paragraph = tr.doc.nodeAt(position);
|
|
2022
|
+
if (!paragraph) panic("A resolved split did not produce two paragraphs");
|
|
2023
|
+
const appliedProperties = applyBlockParagraphProperties({
|
|
2024
|
+
tr,
|
|
2025
|
+
position,
|
|
2026
|
+
node: paragraph,
|
|
2027
|
+
properties,
|
|
2028
|
+
styleResolver,
|
|
2029
|
+
numbering,
|
|
2030
|
+
...mode === "direct" ? {} : { revisionInfo: allocateSplitParagraphPropertyRevisionInfo }
|
|
2031
|
+
});
|
|
2032
|
+
tr = appliedProperties.tr;
|
|
2033
|
+
if (appliedProperties.revisionId !== null) appliedRevisionIds.push(appliedProperties.revisionId);
|
|
2034
|
+
}
|
|
1771
2035
|
break;
|
|
1772
2036
|
}
|
|
1773
2037
|
case "mergeBlockWithNext": {
|
|
@@ -1776,30 +2040,50 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1776
2040
|
if (mode === "direct") {
|
|
1777
2041
|
if (separator.length > 0) tr = tr.insertText(separator, insertAt);
|
|
1778
2042
|
tr = tr.join(item.blockTo + separator.length);
|
|
1779
|
-
|
|
2043
|
+
} else {
|
|
2044
|
+
const revisionIdMark = operationRevisionSeed++;
|
|
2045
|
+
appliedRevisionIds = [revisionIdMark];
|
|
2046
|
+
if (separator.length > 0 && insertionType) {
|
|
2047
|
+
const revisionIdSeparator = operationRevisionSeed++;
|
|
2048
|
+
tr = tr.insertText(separator, insertAt);
|
|
2049
|
+
tr = tr.addMark(insertAt, insertAt + separator.length, insertionType.create({
|
|
2050
|
+
revisionId: revisionIdSeparator,
|
|
2051
|
+
author,
|
|
2052
|
+
date,
|
|
2053
|
+
...trackedRevisionExtras
|
|
2054
|
+
}));
|
|
2055
|
+
appliedRevisionIds.push(revisionIdSeparator);
|
|
2056
|
+
}
|
|
2057
|
+
tr = tr.setNodeAttribute(item.blockFrom, "pPrMark", {
|
|
2058
|
+
kind: "del",
|
|
2059
|
+
info: {
|
|
2060
|
+
id: revisionIdMark,
|
|
2061
|
+
author,
|
|
2062
|
+
date,
|
|
2063
|
+
...trackedRevisionExtras
|
|
2064
|
+
}
|
|
2065
|
+
});
|
|
1780
2066
|
}
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
const
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
2067
|
+
if (item.operation.mergedParagraphProperties) {
|
|
2068
|
+
const mergedParagraph = tr.doc.nodeAt(item.blockFrom);
|
|
2069
|
+
if (!mergedParagraph) panic("A resolved merge did not produce a paragraph");
|
|
2070
|
+
const appliedProperties = applyBlockParagraphProperties({
|
|
2071
|
+
tr,
|
|
2072
|
+
position: item.blockFrom,
|
|
2073
|
+
node: mergedParagraph,
|
|
2074
|
+
properties: item.operation.mergedParagraphProperties,
|
|
2075
|
+
styleResolver,
|
|
2076
|
+
numbering,
|
|
2077
|
+
...mode === "direct" ? {} : { revisionInfo: () => ({
|
|
2078
|
+
id: operationRevisionSeed++,
|
|
2079
|
+
author,
|
|
2080
|
+
date,
|
|
2081
|
+
...trackedRevisionExtras
|
|
2082
|
+
}) }
|
|
2083
|
+
});
|
|
2084
|
+
tr = appliedProperties.tr;
|
|
2085
|
+
if (appliedProperties.revisionId !== null) appliedRevisionIds.push(appliedProperties.revisionId);
|
|
1793
2086
|
}
|
|
1794
|
-
tr = tr.setNodeAttribute(item.blockFrom, "pPrMark", {
|
|
1795
|
-
kind: "del",
|
|
1796
|
-
info: {
|
|
1797
|
-
id: revisionIdMark,
|
|
1798
|
-
author,
|
|
1799
|
-
date,
|
|
1800
|
-
...trackedRevisionExtras
|
|
1801
|
-
}
|
|
1802
|
-
});
|
|
1803
2087
|
break;
|
|
1804
2088
|
}
|
|
1805
2089
|
case "commentOnBlock":
|
|
@@ -1814,10 +2098,25 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1814
2098
|
});
|
|
1815
2099
|
continue;
|
|
1816
2100
|
}
|
|
2101
|
+
let committedCommentId;
|
|
2102
|
+
if (item.commentText !== void 0) {
|
|
2103
|
+
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", {
|
|
2104
|
+
operationId: item.operation.id,
|
|
2105
|
+
operationType: item.operation.type
|
|
2106
|
+
});
|
|
2107
|
+
committedCommentId = allocateCommittedCommentId(item.commentText);
|
|
2108
|
+
tr = commitProvisionalComment({
|
|
2109
|
+
tr,
|
|
2110
|
+
commentType,
|
|
2111
|
+
provisionalId: provisionalCommentId,
|
|
2112
|
+
committedId: committedCommentId
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2115
|
+
revisionSeed = operationRevisionSeed;
|
|
1817
2116
|
applied.push({
|
|
1818
2117
|
id: item.operation.id,
|
|
1819
|
-
...
|
|
1820
|
-
...appliedRevisionIds
|
|
2118
|
+
...committedCommentId !== void 0 && { commentId: committedCommentId },
|
|
2119
|
+
...appliedRevisionIds[0] !== void 0 && {
|
|
1821
2120
|
revisionId: appliedRevisionIds[0],
|
|
1822
2121
|
revisionIds: appliedRevisionIds
|
|
1823
2122
|
},
|
|
@@ -1851,6 +2150,7 @@ const applyFolioAIEditOperationsInternal = ({ view, snapshot, operations, mode =
|
|
|
1851
2150
|
revisionIds: [...receipt.revisionIds, revisionId]
|
|
1852
2151
|
};
|
|
1853
2152
|
}
|
|
2153
|
+
if (ownsSharedRevisionIdCursor) revisionIdCursor = Math.max(revisionIdCursor, revisionSeed);
|
|
1854
2154
|
if (revisionStamp) requestDeterministicParaIds(tr, `${revisionStamp.date}:${String(revisionStamp.idSeed)}`);
|
|
1855
2155
|
view.dispatch(tr);
|
|
1856
2156
|
}
|
|
@@ -2032,7 +2332,8 @@ const resolveStableBlock = ({ snapshot, blockId, liveBlocks, liveBlocksByParaId
|
|
|
2032
2332
|
const cleanBlock = buildCleanBlockText(live.node, live.from);
|
|
2033
2333
|
const currentText = cleanBlock.text;
|
|
2034
2334
|
const currentTextHash = hashFolioAIBlockText(normalizeFolioAIBlockText(currentText));
|
|
2035
|
-
|
|
2335
|
+
const structuralBoundaryHash = hashFolioAIBlockStructuralBoundaries(cleanBlock);
|
|
2336
|
+
if (currentTextHash !== anchor.textHash || structuralBoundaryHash !== anchor.structuralBoundaryHash) return {
|
|
2036
2337
|
type: "skip",
|
|
2037
2338
|
reason: "changedBlock"
|
|
2038
2339
|
};
|
|
@@ -2062,9 +2363,7 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2062
2363
|
};
|
|
2063
2364
|
if (operation.type === "replaceRange" || operation.type === "commentOnRange" || operation.type === "formatRange") {
|
|
2064
2365
|
const { startOffset, endOffset, selectedTextHash } = operation.range;
|
|
2065
|
-
|
|
2066
|
-
const to = cleanBlock.offsets[endOffset];
|
|
2067
|
-
if (from === void 0 || to === void 0) return {
|
|
2366
|
+
if (cleanBlock.offsets[startOffset] === void 0 || cleanBlock.offsets[endOffset] === void 0) return {
|
|
2068
2367
|
type: "skip",
|
|
2069
2368
|
reason: "staleRange"
|
|
2070
2369
|
};
|
|
@@ -2073,6 +2372,15 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2073
2372
|
type: "skip",
|
|
2074
2373
|
reason: "staleRange"
|
|
2075
2374
|
};
|
|
2375
|
+
const range = resolveCleanTextRange({
|
|
2376
|
+
cleanBlock,
|
|
2377
|
+
startOffset,
|
|
2378
|
+
endOffset
|
|
2379
|
+
});
|
|
2380
|
+
if (range === null) return {
|
|
2381
|
+
type: "skip",
|
|
2382
|
+
reason: "unsupportedBlock"
|
|
2383
|
+
};
|
|
2076
2384
|
if (operation.type === "replaceRange" && selectedText === operation.replace) return {
|
|
2077
2385
|
type: "skip",
|
|
2078
2386
|
reason: "noopOperation"
|
|
@@ -2081,8 +2389,8 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2081
2389
|
type: "resolved",
|
|
2082
2390
|
operation: {
|
|
2083
2391
|
operation,
|
|
2084
|
-
from,
|
|
2085
|
-
to,
|
|
2392
|
+
from: range.from,
|
|
2393
|
+
to: range.to,
|
|
2086
2394
|
blockFrom,
|
|
2087
2395
|
blockTo,
|
|
2088
2396
|
blockNode
|
|
@@ -2385,8 +2693,10 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2385
2693
|
};
|
|
2386
2694
|
if (operation.type === "splitBlock") {
|
|
2387
2695
|
const separator = operation.separator ?? "";
|
|
2388
|
-
const
|
|
2389
|
-
const
|
|
2696
|
+
const startOffset = operation.offset;
|
|
2697
|
+
const endOffset = operation.offset + separator.length;
|
|
2698
|
+
const at = cleanBlock.offsets[startOffset];
|
|
2699
|
+
const after = cleanBlock.offsets[endOffset];
|
|
2390
2700
|
if (at === void 0 || after === void 0 || operation.offset === 0 || operation.offset + separator.length >= currentText.length) return {
|
|
2391
2701
|
type: "skip",
|
|
2392
2702
|
reason: "staleRange"
|
|
@@ -2395,7 +2705,12 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2395
2705
|
type: "skip",
|
|
2396
2706
|
reason: "staleRange"
|
|
2397
2707
|
};
|
|
2398
|
-
|
|
2708
|
+
const range = resolveCleanTextRange({
|
|
2709
|
+
cleanBlock,
|
|
2710
|
+
startOffset,
|
|
2711
|
+
endOffset
|
|
2712
|
+
});
|
|
2713
|
+
if (range === null || !canSplit(doc, range.from)) return {
|
|
2399
2714
|
type: "skip",
|
|
2400
2715
|
reason: "unsupportedBlock"
|
|
2401
2716
|
};
|
|
@@ -2403,8 +2718,8 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2403
2718
|
type: "resolved",
|
|
2404
2719
|
operation: {
|
|
2405
2720
|
operation,
|
|
2406
|
-
from:
|
|
2407
|
-
to:
|
|
2721
|
+
from: range.from,
|
|
2722
|
+
to: range.to,
|
|
2408
2723
|
blockFrom,
|
|
2409
2724
|
blockTo,
|
|
2410
2725
|
blockNode
|
|
@@ -2429,7 +2744,12 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2429
2744
|
};
|
|
2430
2745
|
}
|
|
2431
2746
|
if (operation.type === "deleteBlock" || operation.type === "replaceBlock") {
|
|
2747
|
+
const replaceChangesText = operation.type === "replaceBlock" && operation.text !== currentText;
|
|
2432
2748
|
const replaceChangesStyle = operation.type === "replaceBlock" && operation.styleId !== void 0 && operation.styleId !== (expectParagraphAttrs(blockNode).styleId ?? null);
|
|
2749
|
+
if (replaceChangesText && cleanBlock.structuralBoundaries.length > 0) return {
|
|
2750
|
+
type: "skip",
|
|
2751
|
+
reason: "unsupportedBlock"
|
|
2752
|
+
};
|
|
2433
2753
|
const range = getTextRangeFromCleanBlock(cleanBlock);
|
|
2434
2754
|
if (!range) {
|
|
2435
2755
|
const insertionPoint = cleanBlock.offsets.at(0);
|
|
@@ -2451,7 +2771,7 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2451
2771
|
blockTo,
|
|
2452
2772
|
blockNode,
|
|
2453
2773
|
replaceBlockImpact: resolveReplaceBlockImpact({
|
|
2454
|
-
changesText:
|
|
2774
|
+
changesText: replaceChangesText,
|
|
2455
2775
|
changesStyle: replaceChangesStyle
|
|
2456
2776
|
})
|
|
2457
2777
|
}
|
|
@@ -2484,7 +2804,7 @@ const resolveOperation = ({ snapshot, operation, liveBlocks, liveBlocksByParaId,
|
|
|
2484
2804
|
blockTo,
|
|
2485
2805
|
blockNode,
|
|
2486
2806
|
replaceBlockImpact: resolveReplaceBlockImpact({
|
|
2487
|
-
changesText:
|
|
2807
|
+
changesText: replaceChangesText,
|
|
2488
2808
|
changesStyle: replaceChangesStyle
|
|
2489
2809
|
})
|
|
2490
2810
|
}
|
|
@@ -2525,7 +2845,7 @@ const resolveTextInCleanBlock = (cleanBlock, find) => {
|
|
|
2525
2845
|
type: "skip",
|
|
2526
2846
|
reason: "emptyOperation"
|
|
2527
2847
|
};
|
|
2528
|
-
const { text
|
|
2848
|
+
const { text } = cleanBlock;
|
|
2529
2849
|
const firstIndex = text.indexOf(find);
|
|
2530
2850
|
if (firstIndex === -1) return {
|
|
2531
2851
|
type: "skip",
|
|
@@ -2535,16 +2855,18 @@ const resolveTextInCleanBlock = (cleanBlock, find) => {
|
|
|
2535
2855
|
type: "skip",
|
|
2536
2856
|
reason: "ambiguousFind"
|
|
2537
2857
|
};
|
|
2538
|
-
const
|
|
2539
|
-
|
|
2540
|
-
|
|
2858
|
+
const range = resolveCleanTextRange({
|
|
2859
|
+
cleanBlock,
|
|
2860
|
+
startOffset: firstIndex,
|
|
2861
|
+
endOffset: firstIndex + find.length
|
|
2862
|
+
});
|
|
2863
|
+
if (range === null) return {
|
|
2541
2864
|
type: "skip",
|
|
2542
2865
|
reason: "unsupportedBlock"
|
|
2543
2866
|
};
|
|
2544
2867
|
return {
|
|
2545
2868
|
type: "resolved",
|
|
2546
|
-
|
|
2547
|
-
to
|
|
2869
|
+
...range
|
|
2548
2870
|
};
|
|
2549
2871
|
};
|
|
2550
2872
|
const getTextRangeFromCleanBlock = (cleanBlock) => {
|