@stll/folio-core 0.35.1 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -1
- package/dist/ai-edits/apply.js +878 -377
- 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 +141 -73
- 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 +105 -20
- 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 +62 -61
- package/dist/ai-edits/word-diff.d.ts +18 -3
- package/dist/ai-edits/word-diff.js +556 -67
- 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 +48 -21
- 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 +171 -566
- package/dist/compare/scenario.d.ts +2 -2
- package/dist/compare/types.d.ts +3 -3
- package/dist/compare/verification.d.ts +8 -9
- package/dist/compare/verification.js +72 -50
- package/dist/compat/eigenpal.d.ts +5 -3
- package/dist/compat/eigenpal.js +3 -2
- package/dist/controller/headerFooterEditorManager.js +18 -10
- package/dist/controller/hiddenEditorApi.js +1 -1
- 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 -4
- package/dist/document-operations.js +104 -12
- package/dist/docx/blockContentParser.js +6 -27
- package/dist/docx/commentParser.js +2 -4
- package/dist/docx/commentRangeIntegrity.js +2 -4
- package/dist/docx/documentClone.d.ts +2 -0
- package/dist/docx/documentClone.js +2 -0
- package/dist/docx/ensureParaIds.js +9 -4
- package/dist/docx/headerFooterParser.js +2 -4
- package/dist/docx/normalizeBaseDirection.js +5 -7
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +4 -1
- package/dist/docx/paragraphParser.js +34 -35
- package/dist/docx/paragraphPropertySource.d.ts +49 -0
- package/dist/docx/paragraphPropertySource.js +113 -0
- 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/runConsolidator.js +2 -4
- package/dist/docx/runParser.js +6 -17
- package/dist/docx/sectionParser.js +1 -15
- package/dist/docx/serializer/paragraphSerializer.js +289 -30
- package/dist/docx/serializer/runSerializer.js +6 -12
- package/dist/docx/serializer/sectionPropertiesSerializer.js +2 -10
- package/dist/docx/serializer/tableSerializer.js +4 -23
- package/dist/docx/serializer/trackedChangeAttributes.d.ts +11 -0
- package/dist/docx/serializer/trackedChangeAttributes.js +31 -0
- package/dist/docx/server/build.d.ts +1 -1
- package/dist/docx/server/createBilingualDocument.js +8 -10
- package/dist/docx/server/evaluateDocxXmlPatchProposal.js +22 -13
- package/dist/docx/server/validateDocxConformance.js +17 -13
- package/dist/docx/tableParser.js +1 -37
- package/dist/docx/trackedChangeInfo.d.ts +11 -0
- package/dist/docx/trackedChangeInfo.js +38 -0
- package/dist/docx/verbatimCapture.d.ts +20 -9
- package/dist/docx/verbatimCapture.js +208 -8
- package/dist/docx/xmlParser.d.ts +3 -1
- package/dist/docx/xmlParser.js +6 -1
- package/dist/docx/xmlSafety.d.ts +1 -1
- package/dist/docx/xmlSafety.js +157 -0
- package/dist/headless-layout.js +5 -4
- package/dist/index.d.ts +5 -3
- package/dist/index.js +3 -2
- package/dist/internal/headlessRevisionResolution.d.ts +23 -0
- package/dist/internal/headlessRevisionResolution.js +155 -0
- package/dist/internal/headlessRevisionResolutionGuard.d.ts +12 -0
- package/dist/internal/headlessRevisionResolutionGuard.js +28 -0
- package/dist/internal/pageBreakRunDescendantIndex.d.ts +9 -0
- package/dist/internal/pageBreakRunDescendantIndex.js +27 -0
- package/dist/internal/pageBreakRunPartition.d.ts +26 -0
- package/dist/internal/pageBreakRunPartition.js +35 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.d.ts +15 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +126 -0
- package/dist/internal/sectionEndpointResolution.d.ts +32 -0
- package/dist/internal/sectionEndpointResolution.js +38 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +16 -4
- package/dist/layout-bridge/convert/headerFooterLayout.js +52 -9
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -0
- package/dist/layout-bridge/convert/toFlowBlocks.js +391 -82
- 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/markdown/renderBlock.js +7 -10
- 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 +128 -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 +551 -87
- 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 +27 -3
- package/dist/prosemirror/commands/propertyChangeScope.js +85 -14
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +8 -5
- package/dist/prosemirror/conversion/fromProseDoc.js +935 -223
- package/dist/prosemirror/conversion/runShadingMark.js +2 -2
- package/dist/prosemirror/conversion/toProseDoc.d.ts +26 -1
- package/dist/prosemirror/conversion/toProseDoc.js +439 -291
- package/dist/prosemirror/extensions/StarterKit.js +4 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +54 -6
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -1
- package/dist/prosemirror/extensions/features/ListExtension.js +95 -123
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +19 -6
- 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/TrackedChangeExtensions.js +2 -0
- 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/paragraphAlignment.d.ts +12 -0
- package/dist/prosemirror/paragraphAlignment.js +13 -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 +9 -11
- 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 +84 -9
- package/dist/prosemirror/schema/marks.js +73 -1
- package/dist/prosemirror/schema/nodes.d.ts +30 -6
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +14 -2
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +45 -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/redline.js +4 -1
- 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/utils/mergeDocumentContent.js +3 -3
- package/dist/utils/replaceText.js +2 -1
- package/dist/version-comparison.d.ts +38 -44
- package/dist/version-comparison.js +270 -399
- package/dist/watermark/index.js +2 -4
- package/package.json +8 -2
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
import { appendHeadlessInlineResolution } from "../../internal/headlessRevisionResolution.js";
|
|
2
|
+
import { stateAllowsHeadlessRevisionResolution } from "../../internal/headlessRevisionResolutionGuard.js";
|
|
1
3
|
import { expectParagraphAttrs, expectRunPropertyChangeMarkAttrs } from "../attrs/index.js";
|
|
2
|
-
import { paragraphEndsItsContainer } from "../containerFinalParagraph.js";
|
|
3
|
-
import {
|
|
4
|
-
import { markStructuralChange } from "../extensions/features/ParagraphChangeTrackerExtension.js";
|
|
4
|
+
import { addedBreakCarrierBefore, finalParagraphsOf, paragraphEndsItsContainer } from "../containerFinalParagraph.js";
|
|
5
|
+
import { resolveParagraphDefaultTextFormatting } from "../conversion/toProseDoc.js";
|
|
6
|
+
import { markChangedParagraphRanges, markStructuralChange, markTrackedSectionEndpointRemoval } from "../extensions/features/ParagraphChangeTrackerExtension.js";
|
|
7
|
+
import { getDocumentStyleResolver } from "../plugins/documentStyles.js";
|
|
8
|
+
import { setParagraphAttrsWithRebasedRunFormatting } from "../rebaseParagraphRunFormatting.js";
|
|
5
9
|
import { getFolioNodeRevisionCarriers } from "../revisionCarriers.js";
|
|
6
10
|
import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
|
|
11
|
+
import { reconstructRejectedRunFormattingMarks } from "../runPropertyChangeResolution.js";
|
|
12
|
+
import { paragraphRunStyleContextAt } from "../runStyleFormatting.js";
|
|
7
13
|
import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
|
|
14
|
+
import { reconcileTableGridAfterColumnRemoval } from "../tableGridMutation.js";
|
|
8
15
|
import { holdsNoContent } from "../zeroWidthAnchors.js";
|
|
9
|
-
import { paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, sectionRejectProperties, tableCellRejectAttrPatch, tableRejectAttrPatch, tableRowRejectAttrPatch } from "./propertyChangeScope.js";
|
|
16
|
+
import { hasSerializableParagraphPropertyChange, paragraphPropertiesSnapshot, paragraphRejectAttrPatch, paragraphRejectOriginalFormatting, removeParagraphPropertyChanges, sectionRejectProperties, tableCellRejectAttrPatch, tableRejectAttrPatch, tableRowRejectAttrPatch } from "./propertyChangeScope.js";
|
|
10
17
|
import { hasMatchingCollapsedTableCellMerge, resolveCollapsedTableCellMerge, resolveVisibleTableCellMerge } from "./tableCellMergeResolution.js";
|
|
11
18
|
import { TableMap, removeRow } from "prosemirror-tables";
|
|
12
19
|
import { PARAGRAPH_MARK_CHANGE_KINDS } from "@stll/docx-core/model";
|
|
@@ -43,6 +50,7 @@ function removeCommentMark(commentId) {
|
|
|
43
50
|
return true;
|
|
44
51
|
};
|
|
45
52
|
}
|
|
53
|
+
const BULK_INLINE_RESOLUTION_THRESHOLD = 256;
|
|
46
54
|
/**
|
|
47
55
|
* Resolve a tracked change: accept or reject.
|
|
48
56
|
* - Accept: keep insertions (remove mark), delete deletions (remove text)
|
|
@@ -55,14 +63,16 @@ function removeCommentMark(commentId) {
|
|
|
55
63
|
* the operation matches every revision mark or property-change entry in the
|
|
56
64
|
* range (the bulk accept-all/reject-all path).
|
|
57
65
|
*/
|
|
58
|
-
function resolveChange(from, to, mode, revisionIds) {
|
|
66
|
+
function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
|
|
59
67
|
return (state, dispatch) => {
|
|
60
68
|
const insertionType = state.schema.marks["insertion"];
|
|
61
69
|
const deletionType = state.schema.marks["deletion"];
|
|
70
|
+
const styleResolver = getDocumentStyleResolver(state);
|
|
62
71
|
const keepType = mode === "accept" ? insertionType : deletionType;
|
|
63
72
|
const removeType = mode === "accept" ? deletionType : insertionType;
|
|
64
73
|
const revisionSet = revisionIds === void 0 ? null : new Set(revisionIds);
|
|
65
74
|
const removeKeptMarksInBulk = revisionSet === null && keepType !== void 0;
|
|
75
|
+
const canBulkInlineResolution = execution === "headless-bulk-inline" && revisionSet === null && from === 0 && to === state.doc.content.size && stateAllowsHeadlessRevisionResolution(state);
|
|
66
76
|
const matchesRevision = (mark) => revisionSet === null || typeof mark.attrs["revisionId"] === "number" && revisionSet.has(mark.attrs["revisionId"]);
|
|
67
77
|
if (dispatch) {
|
|
68
78
|
const tr = state.tr;
|
|
@@ -70,6 +80,10 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
70
80
|
const pPrMarkOps = [];
|
|
71
81
|
const tableRowStructuralOps = [];
|
|
72
82
|
const tableCellStructuralOps = [];
|
|
83
|
+
const deferredRunPropertyChanges = [];
|
|
84
|
+
let bulkInlineCarrierCount = 0;
|
|
85
|
+
let removedSectionEndpointCount = 0;
|
|
86
|
+
const removedSectionReferences = [];
|
|
73
87
|
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
74
88
|
if (node.type.name === "paragraph") {
|
|
75
89
|
const op = collectPPrMarkOp(node, pos, from, to, mode, revisionSet);
|
|
@@ -78,16 +92,26 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
78
92
|
let nextAttrs = null;
|
|
79
93
|
const propertyChanges = expectParagraphAttrs(node)._propertyChanges;
|
|
80
94
|
if (Array.isArray(propertyChanges) && propertyChanges.length > 0 && boundaryCovered) {
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
83
|
-
const
|
|
95
|
+
const matchesPropertyChange = (change) => revisionSet === null || revisionSet.has(change.info.id);
|
|
96
|
+
if (propertyChanges.some(matchesPropertyChange)) {
|
|
97
|
+
const rejection = mode === "reject" ? removeParagraphPropertyChanges(propertyChanges, matchesPropertyChange) : null;
|
|
98
|
+
let remaining;
|
|
99
|
+
if (rejection === null) remaining = propertyChanges.filter((change) => !matchesPropertyChange(change));
|
|
100
|
+
else if (rejection.type === "unchanged") remaining = propertyChanges;
|
|
101
|
+
else remaining = rejection.remaining;
|
|
84
102
|
nextAttrs = {
|
|
85
103
|
...node.attrs,
|
|
86
104
|
_propertyChanges: remaining.length > 0 ? remaining : null
|
|
87
105
|
};
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
106
|
+
if (rejection?.type === "restore-previous") {
|
|
107
|
+
const inheritedAlignment = expectParagraphAttrs(node).alignmentFromStyle;
|
|
108
|
+
let previousFormattingFromStyle;
|
|
109
|
+
if (styleResolver) previousFormattingFromStyle = styleResolver.resolveParagraphStyle(rejection.previousFormatting?.styleId).paragraphFormatting;
|
|
110
|
+
else if (inheritedAlignment !== void 0) previousFormattingFromStyle = { alignment: inheritedAlignment };
|
|
111
|
+
Object.assign(nextAttrs, paragraphRejectAttrPatch(rejection.previousFormatting, previousFormattingFromStyle));
|
|
112
|
+
const restoredFormatting = paragraphRejectOriginalFormatting(rejection.previousFormatting, node.attrs["_originalFormatting"]);
|
|
113
|
+
nextAttrs["_originalFormatting"] = restoredFormatting;
|
|
114
|
+
if (styleResolver) nextAttrs["defaultTextFormatting"] = resolveParagraphDefaultTextFormatting(rejection.previousFormatting?.styleId, restoredFormatting ?? void 0, styleResolver) ?? null;
|
|
91
115
|
}
|
|
92
116
|
}
|
|
93
117
|
}
|
|
@@ -106,7 +130,13 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
106
130
|
nextAttrs["sectionBreakType"] = sectionBreakTypeFromSectionStart(restored.sectionStart);
|
|
107
131
|
}
|
|
108
132
|
}
|
|
109
|
-
if (nextAttrs)
|
|
133
|
+
if (nextAttrs) if (nextAttrs["styleId"] !== node.attrs["styleId"] && styleResolver) setParagraphAttrsWithRebasedRunFormatting({
|
|
134
|
+
nextAttrs,
|
|
135
|
+
paragraphPosition: pos,
|
|
136
|
+
styleResolver,
|
|
137
|
+
tr
|
|
138
|
+
});
|
|
139
|
+
else tr.setNodeMarkup(pos, void 0, nextAttrs);
|
|
110
140
|
return true;
|
|
111
141
|
}
|
|
112
142
|
if (node.type.name === "tableRow" && rangeCoversNode(from, to, pos, node)) {
|
|
@@ -118,7 +148,10 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
118
148
|
if (tableChangeAttrName !== void 0) {
|
|
119
149
|
if (rangeCoversNode(from, to, pos, node)) {
|
|
120
150
|
const nextAttrs = resolveTablePropertyChangeAttrs(node, tableChangeAttrName, mode, revisionSet);
|
|
121
|
-
if (nextAttrs)
|
|
151
|
+
if (nextAttrs) {
|
|
152
|
+
tr.setNodeMarkup(pos, void 0, nextAttrs);
|
|
153
|
+
markStructuralChange(tr);
|
|
154
|
+
}
|
|
122
155
|
}
|
|
123
156
|
return true;
|
|
124
157
|
}
|
|
@@ -127,6 +160,27 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
127
160
|
const rangeFrom = Math.max(from, pos);
|
|
128
161
|
const rangeTo = Math.min(to, nodeEnd);
|
|
129
162
|
const runPropertyChangeMark = node.marks.find((mark) => mark.type.name === "runPropertyChange");
|
|
163
|
+
const resolvesRunPropertyChange = runPropertyChangeMark !== void 0 && expectRunPropertyChangeMarkAttrs(runPropertyChangeMark).changes.length > 0;
|
|
164
|
+
const removesNode = removeType !== void 0 && node.marks.some((mark) => mark.type === removeType && matchesRevision(mark));
|
|
165
|
+
const removesKeptMark = keepType !== void 0 && node.marks.some((mark) => mark.type === keepType && matchesRevision(mark));
|
|
166
|
+
if (canBulkInlineResolution) {
|
|
167
|
+
if (resolvesRunPropertyChange) deferredRunPropertyChanges.push({
|
|
168
|
+
tr,
|
|
169
|
+
node,
|
|
170
|
+
from: rangeFrom,
|
|
171
|
+
to: rangeTo,
|
|
172
|
+
mark: runPropertyChangeMark,
|
|
173
|
+
mode,
|
|
174
|
+
revisionSet,
|
|
175
|
+
styleResolver
|
|
176
|
+
});
|
|
177
|
+
if (removesNode) deleteRanges.push({
|
|
178
|
+
from: rangeFrom,
|
|
179
|
+
to: rangeTo
|
|
180
|
+
});
|
|
181
|
+
if (resolvesRunPropertyChange || removesNode || removesKeptMark) bulkInlineCarrierCount++;
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
130
184
|
if (runPropertyChangeMark) resolveRunPropertyChange({
|
|
131
185
|
tr,
|
|
132
186
|
node,
|
|
@@ -134,9 +188,10 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
134
188
|
to: rangeTo,
|
|
135
189
|
mark: runPropertyChangeMark,
|
|
136
190
|
mode,
|
|
137
|
-
revisionSet
|
|
191
|
+
revisionSet,
|
|
192
|
+
styleResolver
|
|
138
193
|
});
|
|
139
|
-
if (
|
|
194
|
+
if (removesNode) deleteRanges.push({
|
|
140
195
|
from: rangeFrom,
|
|
141
196
|
to: rangeTo
|
|
142
197
|
});
|
|
@@ -145,24 +200,35 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
145
200
|
}
|
|
146
201
|
return true;
|
|
147
202
|
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
203
|
+
let bulkInlineChangeTracking = null;
|
|
204
|
+
if (canBulkInlineResolution && bulkInlineCarrierCount >= BULK_INLINE_RESOLUTION_THRESHOLD) bulkInlineChangeTracking = appendHeadlessInlineResolution({
|
|
205
|
+
tr,
|
|
206
|
+
mode,
|
|
207
|
+
keepType,
|
|
208
|
+
removeType,
|
|
209
|
+
styleResolver
|
|
210
|
+
});
|
|
211
|
+
else {
|
|
212
|
+
for (const deferred of deferredRunPropertyChanges) resolveRunPropertyChange(deferred);
|
|
213
|
+
if (removeKeptMarksInBulk) tr.removeMark(from, to, keepType);
|
|
214
|
+
let rangesToDelete = deleteRanges;
|
|
215
|
+
if (revisionSet === null) {
|
|
216
|
+
const coalescedDeleteRanges = [];
|
|
217
|
+
for (const range of deleteRanges) {
|
|
218
|
+
const previous = coalescedDeleteRanges.at(-1);
|
|
219
|
+
if (previous && range.from <= previous.to) {
|
|
220
|
+
previous.to = Math.max(previous.to, range.to);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
coalescedDeleteRanges.push({
|
|
224
|
+
from: range.from,
|
|
225
|
+
to: range.to
|
|
226
|
+
});
|
|
157
227
|
}
|
|
158
|
-
coalescedDeleteRanges
|
|
159
|
-
from: range.from,
|
|
160
|
-
to: range.to
|
|
161
|
-
});
|
|
228
|
+
rangesToDelete = coalescedDeleteRanges;
|
|
162
229
|
}
|
|
163
|
-
rangesToDelete
|
|
230
|
+
for (const range of rangesToDelete.toReversed()) tr.delete(range.from, range.to);
|
|
164
231
|
}
|
|
165
|
-
for (const range of rangesToDelete.toReversed()) tr.delete(range.from, range.to);
|
|
166
232
|
pPrMarkOps.sort((a, b) => b.paragraphPos - a.paragraphPos);
|
|
167
233
|
for (const op of pPrMarkOps) {
|
|
168
234
|
const mappedPos = tr.mapping.map(op.paragraphPos);
|
|
@@ -174,35 +240,34 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
174
240
|
}
|
|
175
241
|
const joinPos = mappedPos + paragraph.nodeSize;
|
|
176
242
|
const nextNode = joinPos < tr.doc.content.size ? tr.doc.nodeAt(joinPos) : null;
|
|
177
|
-
if (!(nextNode?.type.name === paragraph.type.name
|
|
243
|
+
if (!(nextNode?.type.name === paragraph.type.name)) {
|
|
178
244
|
const resolved = tr.doc.resolve(mappedPos);
|
|
179
|
-
const previous = resolved.nodeBefore;
|
|
180
|
-
const sectionCanMoveBack = !carriesSection(paragraph) || previous?.type.name === paragraph.type.name && !carriesSection(previous);
|
|
181
245
|
const endsItsContainer = paragraphEndsItsContainer(resolved, paragraph.type.name);
|
|
182
246
|
const canGo = op.markWasAdded || !endsItsContainer;
|
|
183
|
-
if (
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
});
|
|
247
|
+
if (holdsNoContent(paragraph) && canGo && resolved.parent.childCount > 1) {
|
|
248
|
+
if (ownsSectionEndpoint(paragraph)) {
|
|
249
|
+
removedSectionEndpointCount++;
|
|
250
|
+
removedSectionReferences.push(...sectionReferencesOf(paragraph));
|
|
251
|
+
}
|
|
189
252
|
tr.delete(mappedPos, mappedPos + paragraph.nodeSize);
|
|
190
253
|
continue;
|
|
191
254
|
}
|
|
192
255
|
tr.setNodeAttribute(mappedPos, "pPrMark", null);
|
|
193
256
|
continue;
|
|
194
257
|
}
|
|
195
|
-
const formattingOwner = holdsNoContent(paragraph) ? nextNode : paragraph;
|
|
196
|
-
const sectionOwner = carriesSection(paragraph) ? paragraph : nextNode;
|
|
197
258
|
const joinedAttrs = {
|
|
198
|
-
...
|
|
259
|
+
...(holdsNoContent(paragraph) ? nextNode : paragraph).attrs,
|
|
199
260
|
pPrMark: nextNode.attrs["pPrMark"],
|
|
200
|
-
sectionBreakType:
|
|
201
|
-
_sectionProperties:
|
|
261
|
+
sectionBreakType: nextNode.attrs["sectionBreakType"],
|
|
262
|
+
_sectionProperties: nextNode.attrs["_sectionProperties"]
|
|
202
263
|
};
|
|
203
264
|
try {
|
|
204
265
|
tr.join(joinPos);
|
|
205
266
|
tr.setNodeMarkup(mappedPos, void 0, joinedAttrs);
|
|
267
|
+
if (ownsSectionEndpoint(paragraph)) {
|
|
268
|
+
removedSectionEndpointCount++;
|
|
269
|
+
removedSectionReferences.push(...sectionReferencesOf(paragraph));
|
|
270
|
+
}
|
|
206
271
|
} catch {}
|
|
207
272
|
}
|
|
208
273
|
tableRowStructuralOps.sort((left, right) => right.rowPos - left.rowPos);
|
|
@@ -252,12 +317,18 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
252
317
|
}
|
|
253
318
|
if (failedTableCellMergeResolution) return false;
|
|
254
319
|
if (resolvedTableCellStructure) markStructuralChange(tr);
|
|
320
|
+
if (bulkInlineChangeTracking) markChangedParagraphRanges(tr, bulkInlineChangeTracking);
|
|
321
|
+
if (removedSectionEndpointCount > 0) markTrackedSectionEndpointRemoval(tr, {
|
|
322
|
+
sourceDoc: state.doc,
|
|
323
|
+
removedEndpointCount: removedSectionEndpointCount,
|
|
324
|
+
removedReferences: removedSectionReferences
|
|
325
|
+
});
|
|
255
326
|
if (tr.steps.length > 0) dispatch(tr);
|
|
256
327
|
}
|
|
257
328
|
return true;
|
|
258
329
|
};
|
|
259
330
|
}
|
|
260
|
-
const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet }) => {
|
|
331
|
+
const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet, styleResolver }) => {
|
|
261
332
|
const { changes } = expectRunPropertyChangeMarkAttrs(mark);
|
|
262
333
|
const matches = changes.filter((change) => revisionSet === null || revisionSet.has(change.info.id));
|
|
263
334
|
if (matches.length === 0) return;
|
|
@@ -266,15 +337,18 @@ const resolveRunPropertyChange = ({ tr, node, from, to, mark, mode, revisionSet
|
|
|
266
337
|
if (remaining.length > 0) tr.addMark(from, to, mark.type.create({ changes: remaining }));
|
|
267
338
|
if (mode === "accept") return;
|
|
268
339
|
const previousFormatting = matches.at(0)?.previousFormatting;
|
|
340
|
+
const styleContext = paragraphRunStyleContextAt({
|
|
341
|
+
doc: tr.doc,
|
|
342
|
+
pos: from,
|
|
343
|
+
styleResolver
|
|
344
|
+
});
|
|
269
345
|
for (const currentMark of node.marks) if (RUN_FORMATTING_MARK_NAMES.has(currentMark.type.name)) tr.removeMark(from, to, currentMark.type);
|
|
270
|
-
for (const previousMark of
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}));
|
|
277
|
-
}
|
|
346
|
+
for (const previousMark of reconstructRejectedRunFormattingMarks({
|
|
347
|
+
node,
|
|
348
|
+
paragraphContext: styleContext,
|
|
349
|
+
previousFormatting,
|
|
350
|
+
styleResolver
|
|
351
|
+
})) tr.addMark(from, to, previousMark);
|
|
278
352
|
};
|
|
279
353
|
function collectTableRowStructuralOp(node, rowPos, mode, revisionSet) {
|
|
280
354
|
for (const attrName of ["trIns", "trDel"]) {
|
|
@@ -369,11 +443,33 @@ function deleteTableCellAt(tr, cellPos) {
|
|
|
369
443
|
const resolved = tr.doc.resolve(cellPos);
|
|
370
444
|
const row = resolved.parent;
|
|
371
445
|
if (row.type.spec["tableRole"] !== "row") return;
|
|
446
|
+
const tableDepth = resolved.depth - 1;
|
|
447
|
+
const table = resolved.node(tableDepth);
|
|
448
|
+
if (table.type.spec["tableRole"] !== "table") return;
|
|
449
|
+
const tablePosition = resolved.before(tableDepth);
|
|
450
|
+
const cellOffset = cellPos - resolved.start(tableDepth);
|
|
451
|
+
const removedColumn = TableMap.get(table).findCell(cellOffset).left;
|
|
372
452
|
if (row.childCount > 1) {
|
|
373
453
|
tr.delete(cellPos, cellPos + cell.nodeSize);
|
|
454
|
+
reconcileTableGridAfterColumnRemoval({
|
|
455
|
+
tr,
|
|
456
|
+
tablePosition,
|
|
457
|
+
previousTable: table,
|
|
458
|
+
removedColumn
|
|
459
|
+
});
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (table.childCount === 1) {
|
|
463
|
+
deleteTableRowAt(tr, resolved.start() - 1);
|
|
374
464
|
return;
|
|
375
465
|
}
|
|
376
466
|
deleteTableRowAt(tr, resolved.start() - 1);
|
|
467
|
+
reconcileTableGridAfterColumnRemoval({
|
|
468
|
+
tr,
|
|
469
|
+
tablePosition,
|
|
470
|
+
previousTable: table,
|
|
471
|
+
removedColumn
|
|
472
|
+
});
|
|
377
473
|
}
|
|
378
474
|
function deleteTableRowAt(tr, rowPos) {
|
|
379
475
|
const resolved = tr.doc.resolve(rowPos);
|
|
@@ -480,15 +576,24 @@ function isPPrMarkAttr(value) {
|
|
|
480
576
|
* the two ends belong together, not because they resolve differently.
|
|
481
577
|
*/
|
|
482
578
|
const paragraphMarkWasAdded = (kind) => kind === "ins" || kind === "moveTo";
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
579
|
+
const ownsSectionEndpoint = (paragraph) => {
|
|
580
|
+
const attrs = expectParagraphAttrs(paragraph);
|
|
581
|
+
return attrs._sectionProperties !== void 0 || attrs.sectionBreakType !== void 0;
|
|
582
|
+
};
|
|
583
|
+
const sectionReferencesOf = (paragraph) => {
|
|
584
|
+
const sectionProperties = expectParagraphAttrs(paragraph)._sectionProperties;
|
|
585
|
+
if (!sectionProperties) return [];
|
|
586
|
+
return [...(sectionProperties.headerReferences ?? []).map(({ type, rId }) => ({
|
|
587
|
+
part: "header",
|
|
588
|
+
type,
|
|
589
|
+
relationshipId: rId
|
|
590
|
+
})), ...(sectionProperties.footerReferences ?? []).map(({ type, rId }) => ({
|
|
591
|
+
part: "footer",
|
|
592
|
+
type,
|
|
593
|
+
relationshipId: rId
|
|
594
|
+
}))];
|
|
595
|
+
};
|
|
596
|
+
const isAddedPPrMarkAttr = (value) => isPPrMarkAttr(value) && (value.kind === "ins" || value.kind === "moveTo");
|
|
492
597
|
function readRevisionInfo(info) {
|
|
493
598
|
const revision = {};
|
|
494
599
|
if (typeof info?.author === "string") revision.author = info.author;
|
|
@@ -566,6 +671,20 @@ function rejectAllChanges() {
|
|
|
566
671
|
return (state, dispatch) => rejectChange(0, state.doc.content.size)(state, dispatch);
|
|
567
672
|
}
|
|
568
673
|
/**
|
|
674
|
+
* Resolve a complete state synchronously for a headless reader or writer.
|
|
675
|
+
*
|
|
676
|
+
* @internal The replacement transaction is consumed here and never exposed:
|
|
677
|
+
* it is deliberately not an editor command and must not be transported or
|
|
678
|
+
* mapped through concurrent edits.
|
|
679
|
+
*/
|
|
680
|
+
function resolveAllChangesInHeadlessState(state, mode) {
|
|
681
|
+
let resolvedState = state;
|
|
682
|
+
resolveChange(0, state.doc.content.size, mode, void 0, "headless-bulk-inline")(state, (transaction) => {
|
|
683
|
+
resolvedState = state.apply(transaction);
|
|
684
|
+
});
|
|
685
|
+
return resolvedState;
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
569
688
|
* Find the document range covered by all revision carriers with any of the
|
|
570
689
|
* given ids. Returns null when none are present (already accepted/rejected, or
|
|
571
690
|
* never existed). A replace operation typically passes two ids; standalone
|
|
@@ -682,6 +801,13 @@ const readSuggestedMarker = (marker) => {
|
|
|
682
801
|
revisionId
|
|
683
802
|
};
|
|
684
803
|
};
|
|
804
|
+
const readSuggestedParagraphPropertyChange = (change) => {
|
|
805
|
+
if (change.info.provenance !== "suggested" || typeof change.info.suggestionId !== "string") return null;
|
|
806
|
+
return {
|
|
807
|
+
suggestionId: change.info.suggestionId,
|
|
808
|
+
revisionId: change.info.id
|
|
809
|
+
};
|
|
810
|
+
};
|
|
685
811
|
const readStructuralSuggestion = (node) => {
|
|
686
812
|
const attrs = node.attrs;
|
|
687
813
|
const name = node.type.name;
|
|
@@ -754,6 +880,20 @@ const collectSuggestions = (state) => {
|
|
|
754
880
|
entry.kinds.add(structural.kind);
|
|
755
881
|
entry.revisionIds.add(structural.revisionId);
|
|
756
882
|
}
|
|
883
|
+
if (node.type.name === "paragraph") {
|
|
884
|
+
const propertyChanges = expectParagraphAttrs(node)._propertyChanges;
|
|
885
|
+
if (Array.isArray(propertyChanges)) for (const change of propertyChanges) {
|
|
886
|
+
const suggested = readSuggestedParagraphPropertyChange(change);
|
|
887
|
+
if (!suggested) continue;
|
|
888
|
+
const entry = entryFor(suggested.suggestionId);
|
|
889
|
+
entry.segments.push({
|
|
890
|
+
from: pos,
|
|
891
|
+
to: pos + node.nodeSize
|
|
892
|
+
});
|
|
893
|
+
entry.kinds.add("formatting");
|
|
894
|
+
entry.revisionIds.add(suggested.revisionId);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
757
897
|
if (!node.isInline) return;
|
|
758
898
|
for (const mark of node.marks) {
|
|
759
899
|
if (!isSuggestionMark(mark)) continue;
|
|
@@ -848,6 +988,22 @@ const normalizeAcceptDate = (date) => {
|
|
|
848
988
|
const parsed = new Date(date);
|
|
849
989
|
return Number.isNaN(parsed.getTime()) ? (/* @__PURE__ */ new Date()).toISOString() : parsed.toISOString();
|
|
850
990
|
};
|
|
991
|
+
const acceptedParagraphMark = (node, author, date) => {
|
|
992
|
+
if (node.type.name !== "paragraph") return null;
|
|
993
|
+
const marker = node.attrs["_suggestedInsert"];
|
|
994
|
+
if (typeof marker !== "object" || marker === null || !("revisionId" in marker)) return null;
|
|
995
|
+
if (typeof marker.revisionId !== "number") return null;
|
|
996
|
+
const initials = "initials" in marker ? marker.initials : void 0;
|
|
997
|
+
return {
|
|
998
|
+
kind: "ins",
|
|
999
|
+
info: {
|
|
1000
|
+
id: marker.revisionId,
|
|
1001
|
+
author,
|
|
1002
|
+
date,
|
|
1003
|
+
...typeof initials === "string" ? { initials } : {}
|
|
1004
|
+
}
|
|
1005
|
+
};
|
|
1006
|
+
};
|
|
851
1007
|
/**
|
|
852
1008
|
* The node-attr patch that converts a suggested block/table revision into a
|
|
853
1009
|
* normal (`"user"`) one authored by the accepting user. Returns `null` when the
|
|
@@ -868,23 +1024,15 @@ const convertStructuralSuggestionAttrs = (node, author, date) => {
|
|
|
868
1024
|
const name = node.type.name;
|
|
869
1025
|
const insertMarker = attrs["_suggestedInsert"];
|
|
870
1026
|
if ((name === "paragraph" || name === "table") && typeof insertMarker === "object" && insertMarker !== null) {
|
|
871
|
-
const marker = insertMarker;
|
|
872
1027
|
if (name === "table") return {
|
|
873
1028
|
...attrs,
|
|
874
1029
|
_suggestedInsert: null
|
|
875
1030
|
};
|
|
876
|
-
|
|
1031
|
+
const paragraphMark = acceptedParagraphMark(node, author, date);
|
|
1032
|
+
if (paragraphMark) return {
|
|
877
1033
|
...attrs,
|
|
878
1034
|
_suggestedInsert: null,
|
|
879
|
-
pPrMark:
|
|
880
|
-
kind: "ins",
|
|
881
|
-
info: {
|
|
882
|
-
id: marker.revisionId,
|
|
883
|
-
author,
|
|
884
|
-
date,
|
|
885
|
-
...typeof marker.initials === "string" ? { initials: marker.initials } : {}
|
|
886
|
-
}
|
|
887
|
-
}
|
|
1035
|
+
pPrMark: attrs["pPrMark"] ?? paragraphMark
|
|
888
1036
|
};
|
|
889
1037
|
}
|
|
890
1038
|
if (node.type.name === "tableRow") {
|
|
@@ -909,6 +1057,266 @@ const convertStructuralSuggestionAttrs = (node, author, date) => {
|
|
|
909
1057
|
}
|
|
910
1058
|
return null;
|
|
911
1059
|
};
|
|
1060
|
+
const reauthorParagraphPropertySuggestions = ({ node, matchesSuggestion, author, date }) => {
|
|
1061
|
+
if (node.type.name !== "paragraph") return null;
|
|
1062
|
+
const propertyChanges = expectParagraphAttrs(node)._propertyChanges;
|
|
1063
|
+
if (!Array.isArray(propertyChanges)) return null;
|
|
1064
|
+
let changed = false;
|
|
1065
|
+
const next = propertyChanges.map((change) => {
|
|
1066
|
+
const suggested = readSuggestedParagraphPropertyChange(change);
|
|
1067
|
+
if (!suggested || !matchesSuggestion(suggested.suggestionId)) return change;
|
|
1068
|
+
changed = true;
|
|
1069
|
+
return Object.assign({}, change, { info: {
|
|
1070
|
+
...change.info,
|
|
1071
|
+
author,
|
|
1072
|
+
date,
|
|
1073
|
+
provenance: "user",
|
|
1074
|
+
suggestionId: null
|
|
1075
|
+
} });
|
|
1076
|
+
});
|
|
1077
|
+
return changed ? next : null;
|
|
1078
|
+
};
|
|
1079
|
+
const canReauthorParagraphPropertySuggestions = (doc, matchesSuggestion) => {
|
|
1080
|
+
let valid = true;
|
|
1081
|
+
doc.descendants((node) => {
|
|
1082
|
+
if (!valid || node.type.name !== "paragraph") return;
|
|
1083
|
+
const propertyChanges = expectParagraphAttrs(node)._propertyChanges;
|
|
1084
|
+
if (!Array.isArray(propertyChanges)) return;
|
|
1085
|
+
let serializableCount = 0;
|
|
1086
|
+
for (const change of propertyChanges) {
|
|
1087
|
+
const suggested = readSuggestedParagraphPropertyChange(change);
|
|
1088
|
+
if (!suggested || matchesSuggestion(suggested.suggestionId)) serializableCount++;
|
|
1089
|
+
}
|
|
1090
|
+
if (serializableCount > 1) {
|
|
1091
|
+
valid = false;
|
|
1092
|
+
return false;
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
return valid;
|
|
1096
|
+
};
|
|
1097
|
+
const appendRotatedParagraphPropertyChange = ({ tr, currentPosition, previous, mark, fallbackAuthor }) => {
|
|
1098
|
+
const current = tr.doc.nodeAt(currentPosition);
|
|
1099
|
+
if (!current || current.type.name !== "paragraph") return false;
|
|
1100
|
+
const author = typeof mark.info.author === "string" ? mark.info.author : fallbackAuthor;
|
|
1101
|
+
if (author === void 0) return false;
|
|
1102
|
+
const existing = expectParagraphAttrs(current)._propertyChanges;
|
|
1103
|
+
if (hasSerializableParagraphPropertyChange(existing)) return false;
|
|
1104
|
+
tr.setNodeMarkup(currentPosition, void 0, {
|
|
1105
|
+
...current.attrs,
|
|
1106
|
+
_propertyChanges: [...Array.isArray(existing) ? existing : [], {
|
|
1107
|
+
type: "paragraphPropertyChange",
|
|
1108
|
+
info: {
|
|
1109
|
+
id: mark.info.id,
|
|
1110
|
+
author,
|
|
1111
|
+
...typeof mark.info.date === "string" ? { date: mark.info.date } : {},
|
|
1112
|
+
...typeof mark.info.initials === "string" ? { initials: mark.info.initials } : {}
|
|
1113
|
+
},
|
|
1114
|
+
previousFormatting: paragraphPropertiesSnapshot(previous)
|
|
1115
|
+
}]
|
|
1116
|
+
});
|
|
1117
|
+
return true;
|
|
1118
|
+
};
|
|
1119
|
+
/**
|
|
1120
|
+
* Shift a final run of inserted paragraph marks one paragraph to the left.
|
|
1121
|
+
* The container-final paragraph stays markless, while every inserted
|
|
1122
|
+
* paragraph keeps a same-revision property snapshot that makes targeted
|
|
1123
|
+
* rejection restore the paragraph whose mark now carries its break.
|
|
1124
|
+
*/
|
|
1125
|
+
const rotateAddedFinalParagraphBreaks = ({ tr, shouldRotate, fallbackAuthor }) => {
|
|
1126
|
+
const paragraphTypeName = tr.doc.type.schema.nodes["paragraph"]?.name ?? "paragraph";
|
|
1127
|
+
const finals = finalParagraphsOf(tr.doc, paragraphTypeName).filter(({ node, position }) => shouldRotate(node, position));
|
|
1128
|
+
for (const { position: finalPosition } of finals) {
|
|
1129
|
+
const final = tr.doc.nodeAt(finalPosition);
|
|
1130
|
+
const finalMark = final?.attrs["pPrMark"];
|
|
1131
|
+
if (!final || !isAddedPPrMarkAttr(finalMark)) continue;
|
|
1132
|
+
tr.setNodeAttribute(finalPosition, "pPrMark", null);
|
|
1133
|
+
if (!shiftAddedParagraphBreakBefore({
|
|
1134
|
+
tr,
|
|
1135
|
+
paragraphPosition: finalPosition,
|
|
1136
|
+
mark: finalMark,
|
|
1137
|
+
...fallbackAuthor !== void 0 && { fallbackAuthor }
|
|
1138
|
+
})) return false;
|
|
1139
|
+
}
|
|
1140
|
+
return true;
|
|
1141
|
+
};
|
|
1142
|
+
const rebaseRotatedParagraphPropertyChange = ({ tr, currentPosition, previous, revisionId }) => {
|
|
1143
|
+
const current = tr.doc.nodeAt(currentPosition);
|
|
1144
|
+
if (!current || current.type.name !== "paragraph") return false;
|
|
1145
|
+
const existing = expectParagraphAttrs(current)._propertyChanges;
|
|
1146
|
+
if (!Array.isArray(existing)) return false;
|
|
1147
|
+
if (existing.filter(({ info }) => info.id === revisionId).length !== 1) return false;
|
|
1148
|
+
tr.setNodeMarkup(currentPosition, void 0, {
|
|
1149
|
+
...current.attrs,
|
|
1150
|
+
_propertyChanges: existing.map((change) => change.info.id === revisionId ? Object.assign({}, change, { previousFormatting: paragraphPropertiesSnapshot(previous) }) : change)
|
|
1151
|
+
});
|
|
1152
|
+
return true;
|
|
1153
|
+
};
|
|
1154
|
+
/**
|
|
1155
|
+
* Rebase every property change in one rotated paragraph-break chain to the
|
|
1156
|
+
* formatting of its original, leftmost carrier. A later targeted suggestion
|
|
1157
|
+
* may extend an already-rotated chain, so normalizing only the newly shifted
|
|
1158
|
+
* prefix would leave the serialized history dependent on acceptance order.
|
|
1159
|
+
*/
|
|
1160
|
+
const rebaseAddedParagraphBreakChain = ({ tr, carrierPosition, previous }) => {
|
|
1161
|
+
const carrier = tr.doc.nodeAt(carrierPosition);
|
|
1162
|
+
if (!carrier || carrier.type.name !== "paragraph") return false;
|
|
1163
|
+
const resolved = tr.doc.resolve(carrierPosition);
|
|
1164
|
+
let current = carrier;
|
|
1165
|
+
let nextPosition = carrierPosition + carrier.nodeSize;
|
|
1166
|
+
for (let index = resolved.index() + 1; index < resolved.parent.childCount; index++) {
|
|
1167
|
+
const currentMark = current.attrs["pPrMark"];
|
|
1168
|
+
if (!isAddedPPrMarkAttr(currentMark)) return true;
|
|
1169
|
+
const sibling = resolved.parent.child(index);
|
|
1170
|
+
if (sibling.type.name !== carrier.type.name) {
|
|
1171
|
+
if (sibling.type.spec["tableRole"] === "table") return false;
|
|
1172
|
+
nextPosition += sibling.nodeSize;
|
|
1173
|
+
continue;
|
|
1174
|
+
}
|
|
1175
|
+
if (!rebaseRotatedParagraphPropertyChange({
|
|
1176
|
+
tr,
|
|
1177
|
+
currentPosition: nextPosition,
|
|
1178
|
+
previous,
|
|
1179
|
+
revisionId: currentMark.info.id
|
|
1180
|
+
})) return false;
|
|
1181
|
+
const next = tr.doc.nodeAt(nextPosition);
|
|
1182
|
+
if (!next || next.type.name !== carrier.type.name) return false;
|
|
1183
|
+
current = next;
|
|
1184
|
+
nextPosition += sibling.nodeSize;
|
|
1185
|
+
}
|
|
1186
|
+
return !isAddedPPrMarkAttr(current.attrs["pPrMark"]);
|
|
1187
|
+
};
|
|
1188
|
+
/**
|
|
1189
|
+
* Insert an added paragraph break immediately before `paragraphPosition`.
|
|
1190
|
+
* Existing added marks shift left as one chain until the first free carrier;
|
|
1191
|
+
* each shifted mark keeps a property snapshot on the paragraph to its right.
|
|
1192
|
+
*/
|
|
1193
|
+
const shiftAddedParagraphBreakBefore = ({ tr, paragraphPosition, mark, fallbackAuthor, firstPropertyChange = { type: "append" } }) => {
|
|
1194
|
+
const paragraph = tr.doc.nodeAt(paragraphPosition);
|
|
1195
|
+
if (!paragraph || paragraph.type.name !== "paragraph") return false;
|
|
1196
|
+
const resolved = tr.doc.resolve(paragraphPosition);
|
|
1197
|
+
const carrier = addedBreakCarrierBefore(resolved, paragraph.type.name);
|
|
1198
|
+
if (!carrier) return false;
|
|
1199
|
+
const path = [{
|
|
1200
|
+
node: paragraph,
|
|
1201
|
+
position: paragraphPosition
|
|
1202
|
+
}];
|
|
1203
|
+
let position = paragraphPosition;
|
|
1204
|
+
for (let index = resolved.index() - 1; index >= 0; index--) {
|
|
1205
|
+
const sibling = resolved.parent.child(index);
|
|
1206
|
+
position -= sibling.nodeSize;
|
|
1207
|
+
if (sibling.type.name !== paragraph.type.name) {
|
|
1208
|
+
if (sibling.type.spec["tableRole"] === "table") break;
|
|
1209
|
+
continue;
|
|
1210
|
+
}
|
|
1211
|
+
path.push({
|
|
1212
|
+
node: sibling,
|
|
1213
|
+
position
|
|
1214
|
+
});
|
|
1215
|
+
if (position === carrier.position) break;
|
|
1216
|
+
}
|
|
1217
|
+
if (path.at(-1)?.position !== carrier.position) return false;
|
|
1218
|
+
const propertyChangeBaseline = carrier.node;
|
|
1219
|
+
let carriedMark = mark;
|
|
1220
|
+
for (let index = 1; index < path.length; index++) {
|
|
1221
|
+
const current = path[index - 1];
|
|
1222
|
+
const previous = path[index];
|
|
1223
|
+
if (!current || !previous) return false;
|
|
1224
|
+
const displacedMark = previous.node.attrs["pPrMark"];
|
|
1225
|
+
tr.setNodeAttribute(previous.position, "pPrMark", carriedMark);
|
|
1226
|
+
if (!(index === 1 && firstPropertyChange.type === "rebase" ? rebaseRotatedParagraphPropertyChange({
|
|
1227
|
+
tr,
|
|
1228
|
+
currentPosition: current.position,
|
|
1229
|
+
previous: propertyChangeBaseline,
|
|
1230
|
+
revisionId: firstPropertyChange.revisionId
|
|
1231
|
+
}) : appendRotatedParagraphPropertyChange({
|
|
1232
|
+
tr,
|
|
1233
|
+
currentPosition: current.position,
|
|
1234
|
+
previous: propertyChangeBaseline,
|
|
1235
|
+
mark: carriedMark,
|
|
1236
|
+
...fallbackAuthor !== void 0 && { fallbackAuthor }
|
|
1237
|
+
}))) return false;
|
|
1238
|
+
if (displacedMark == null) return rebaseAddedParagraphBreakChain({
|
|
1239
|
+
tr,
|
|
1240
|
+
carrierPosition: carrier.position,
|
|
1241
|
+
previous: propertyChangeBaseline
|
|
1242
|
+
});
|
|
1243
|
+
if (!isAddedPPrMarkAttr(displacedMark)) return false;
|
|
1244
|
+
carriedMark = displacedMark;
|
|
1245
|
+
}
|
|
1246
|
+
return false;
|
|
1247
|
+
};
|
|
1248
|
+
/**
|
|
1249
|
+
* Place an accepted paragraph's break when a following accepted insertion has
|
|
1250
|
+
* already rotated its own break onto that paragraph.
|
|
1251
|
+
*/
|
|
1252
|
+
const placeAcceptedParagraphBreakBefore = ({ tr, paragraphPosition, mark, fallbackAuthor }) => {
|
|
1253
|
+
const paragraph = tr.doc.nodeAt(paragraphPosition);
|
|
1254
|
+
const displaced = paragraph?.attrs["pPrMark"];
|
|
1255
|
+
if (!paragraph || paragraph.type.name !== "paragraph" || !isPPrMarkAttr(displaced) || !paragraphMarkWasAdded(displaced.kind)) return false;
|
|
1256
|
+
return shiftAddedParagraphBreakBefore({
|
|
1257
|
+
tr,
|
|
1258
|
+
paragraphPosition,
|
|
1259
|
+
mark,
|
|
1260
|
+
fallbackAuthor
|
|
1261
|
+
});
|
|
1262
|
+
};
|
|
1263
|
+
/**
|
|
1264
|
+
* Remember non-final added breaks before suggested nodes are removed. If one
|
|
1265
|
+
* becomes final because of those removals, it must rotate with its own
|
|
1266
|
+
* revision rather than remain as an unresolvable final mark.
|
|
1267
|
+
*/
|
|
1268
|
+
const collectAddedBreakRotationCandidates = (doc) => {
|
|
1269
|
+
const paragraphTypeName = doc.type.schema.nodes["paragraph"]?.name ?? "paragraph";
|
|
1270
|
+
const finalPositions = new Set(finalParagraphsOf(doc, paragraphTypeName).map(({ position }) => position));
|
|
1271
|
+
const candidates = [];
|
|
1272
|
+
doc.descendants((node, position) => {
|
|
1273
|
+
if (node.type.name !== paragraphTypeName || finalPositions.has(position)) return;
|
|
1274
|
+
const mark = node.attrs["pPrMark"];
|
|
1275
|
+
if (isPPrMarkAttr(mark) && paragraphMarkWasAdded(mark.kind)) candidates.push({
|
|
1276
|
+
position,
|
|
1277
|
+
revisionId: mark.info.id
|
|
1278
|
+
});
|
|
1279
|
+
});
|
|
1280
|
+
return candidates;
|
|
1281
|
+
};
|
|
1282
|
+
const mappedRotationCandidatePredicate = ({ candidates, tr }) => {
|
|
1283
|
+
const revisionIdsByPosition = /* @__PURE__ */ new Map();
|
|
1284
|
+
for (const candidate of candidates) {
|
|
1285
|
+
const mapped = tr.mapping.mapResult(candidate.position, 1);
|
|
1286
|
+
if (mapped.deleted) continue;
|
|
1287
|
+
const mappedPosition = mapped.pos;
|
|
1288
|
+
const revisionIds = revisionIdsByPosition.get(mappedPosition) ?? /* @__PURE__ */ new Set();
|
|
1289
|
+
revisionIds.add(candidate.revisionId);
|
|
1290
|
+
revisionIdsByPosition.set(mappedPosition, revisionIds);
|
|
1291
|
+
}
|
|
1292
|
+
return (node, position) => {
|
|
1293
|
+
const mark = node.attrs["pPrMark"];
|
|
1294
|
+
return isPPrMarkAttr(mark) && paragraphMarkWasAdded(mark.kind) && revisionIdsByPosition.get(position)?.has(mark.info.id) === true;
|
|
1295
|
+
};
|
|
1296
|
+
};
|
|
1297
|
+
/**
|
|
1298
|
+
* Remove suggested nodes without deleting a following accepted insertion's
|
|
1299
|
+
* paragraph break that has rotated onto one of them.
|
|
1300
|
+
*/
|
|
1301
|
+
const removeSuggestedInsertNodes = ({ tr, positions, resolvedRevisionIds }) => {
|
|
1302
|
+
for (const position of positions.toSorted((left, right) => right - left)) {
|
|
1303
|
+
const node = tr.doc.nodeAt(position);
|
|
1304
|
+
if (!node) continue;
|
|
1305
|
+
const mark = node.attrs["pPrMark"];
|
|
1306
|
+
const followingBreak = node.type.name === "paragraph" && isAddedPPrMarkAttr(mark) && !resolvedRevisionIds.has(mark.info.id) ? mark : null;
|
|
1307
|
+
tr.delete(position, position + node.nodeSize);
|
|
1308
|
+
if (followingBreak && !shiftAddedParagraphBreakBefore({
|
|
1309
|
+
tr,
|
|
1310
|
+
paragraphPosition: position,
|
|
1311
|
+
mark: followingBreak,
|
|
1312
|
+
firstPropertyChange: {
|
|
1313
|
+
type: "rebase",
|
|
1314
|
+
revisionId: followingBreak.info.id
|
|
1315
|
+
}
|
|
1316
|
+
})) return false;
|
|
1317
|
+
}
|
|
1318
|
+
return true;
|
|
1319
|
+
};
|
|
912
1320
|
/**
|
|
913
1321
|
* Convert suggested marks AND block/table node revisions to normal (`"user"`)
|
|
914
1322
|
* tracked changes. `matchesSuggestion(id)` selects which suggestion to convert
|
|
@@ -916,21 +1324,43 @@ const convertStructuralSuggestionAttrs = (node, author, date) => {
|
|
|
916
1324
|
*/
|
|
917
1325
|
const acceptSuggestions = (matchesSuggestion, options) => {
|
|
918
1326
|
return (state, dispatch) => {
|
|
1327
|
+
if (!canReauthorParagraphPropertySuggestions(state.doc, matchesSuggestion)) return false;
|
|
919
1328
|
const insertionType = state.schema.marks["insertion"];
|
|
920
1329
|
const deletionType = state.schema.marks["deletion"];
|
|
921
1330
|
const runPropertyChangeType = state.schema.marks["runPropertyChange"];
|
|
922
1331
|
const date = normalizeAcceptDate(options.date);
|
|
923
1332
|
const tr = state.tr;
|
|
1333
|
+
const acceptedParagraphBreaks = [];
|
|
924
1334
|
let changed = false;
|
|
925
1335
|
state.doc.descendants((node, pos) => {
|
|
926
1336
|
const structural = readStructuralSuggestion(node);
|
|
1337
|
+
let nextAttrs = null;
|
|
927
1338
|
if (structural && matchesSuggestion(structural.suggestionId)) {
|
|
928
|
-
|
|
929
|
-
if (
|
|
930
|
-
|
|
931
|
-
|
|
1339
|
+
nextAttrs = convertStructuralSuggestionAttrs(node, options.author, date);
|
|
1340
|
+
if (structural.kind === "insertBlock") {
|
|
1341
|
+
const mark = acceptedParagraphMark(node, options.author, date);
|
|
1342
|
+
if (!mark) return;
|
|
1343
|
+
acceptedParagraphBreaks.push({
|
|
1344
|
+
position: pos,
|
|
1345
|
+
mark,
|
|
1346
|
+
hadBreak: node.attrs["pPrMark"] != null
|
|
1347
|
+
});
|
|
932
1348
|
}
|
|
933
1349
|
}
|
|
1350
|
+
const propertyChanges = reauthorParagraphPropertySuggestions({
|
|
1351
|
+
node,
|
|
1352
|
+
matchesSuggestion,
|
|
1353
|
+
author: options.author,
|
|
1354
|
+
date
|
|
1355
|
+
});
|
|
1356
|
+
if (propertyChanges) nextAttrs = {
|
|
1357
|
+
...nextAttrs ?? node.attrs,
|
|
1358
|
+
_propertyChanges: propertyChanges
|
|
1359
|
+
};
|
|
1360
|
+
if (nextAttrs) {
|
|
1361
|
+
tr.setNodeMarkup(pos, void 0, nextAttrs);
|
|
1362
|
+
changed = true;
|
|
1363
|
+
}
|
|
934
1364
|
if (!node.isInline) return;
|
|
935
1365
|
const from = pos;
|
|
936
1366
|
const to = pos + node.nodeSize;
|
|
@@ -964,6 +1394,18 @@ const acceptSuggestions = (matchesSuggestion, options) => {
|
|
|
964
1394
|
}));
|
|
965
1395
|
}
|
|
966
1396
|
});
|
|
1397
|
+
for (const accepted of acceptedParagraphBreaks) if (accepted.hadBreak && !placeAcceptedParagraphBreakBefore({
|
|
1398
|
+
tr,
|
|
1399
|
+
paragraphPosition: accepted.position,
|
|
1400
|
+
mark: accepted.mark,
|
|
1401
|
+
fallbackAuthor: options.author
|
|
1402
|
+
})) return false;
|
|
1403
|
+
const directlyMarkedParagraphPositions = new Set(acceptedParagraphBreaks.filter(({ hadBreak }) => !hadBreak).map(({ position }) => position));
|
|
1404
|
+
if (directlyMarkedParagraphPositions.size > 0 && !rotateAddedFinalParagraphBreaks({
|
|
1405
|
+
tr,
|
|
1406
|
+
shouldRotate: (_node, position) => directlyMarkedParagraphPositions.has(position),
|
|
1407
|
+
fallbackAuthor: options.author
|
|
1408
|
+
})) return false;
|
|
967
1409
|
if (!changed) return false;
|
|
968
1410
|
if (dispatch) dispatch(tr);
|
|
969
1411
|
return true;
|
|
@@ -1001,6 +1443,7 @@ function rejectSuggestion(suggestionId) {
|
|
|
1001
1443
|
return (state, dispatch) => {
|
|
1002
1444
|
const entry = collectSuggestions(state).get(suggestionId);
|
|
1003
1445
|
if (!entry) return false;
|
|
1446
|
+
const rotationCandidates = entry.kinds.has("insertBlock") || entry.kinds.has("insertTable") ? collectAddedBreakRotationCandidates(state.doc) : [];
|
|
1004
1447
|
let tr = null;
|
|
1005
1448
|
if (entry.revisionIds.size > 0) {
|
|
1006
1449
|
const ranges = mergeSegments(entry.segments);
|
|
@@ -1015,10 +1458,18 @@ function rejectSuggestion(suggestionId) {
|
|
|
1015
1458
|
const structural = readStructuralSuggestion(node);
|
|
1016
1459
|
if (structural?.isNodeInsert && structural.suggestionId === suggestionId) positions.push(pos);
|
|
1017
1460
|
});
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1461
|
+
if (!removeSuggestedInsertNodes({
|
|
1462
|
+
tr: workingTr,
|
|
1463
|
+
positions,
|
|
1464
|
+
resolvedRevisionIds: entry.revisionIds
|
|
1465
|
+
})) return false;
|
|
1466
|
+
if (positions.length > 0 && rotationCandidates.length > 0 && !rotateAddedFinalParagraphBreaks({
|
|
1467
|
+
tr: workingTr,
|
|
1468
|
+
shouldRotate: mappedRotationCandidatePredicate({
|
|
1469
|
+
candidates: rotationCandidates,
|
|
1470
|
+
tr: workingTr
|
|
1471
|
+
})
|
|
1472
|
+
})) return false;
|
|
1022
1473
|
if (workingTr.steps.length === 0) return false;
|
|
1023
1474
|
if (dispatch) dispatch(workingTr);
|
|
1024
1475
|
return true;
|
|
@@ -1030,7 +1481,12 @@ function rejectAllSuggestions() {
|
|
|
1030
1481
|
const bySuggestion = collectSuggestions(state);
|
|
1031
1482
|
if (bySuggestion.size === 0) return false;
|
|
1032
1483
|
const revisionIds = /* @__PURE__ */ new Set();
|
|
1033
|
-
|
|
1484
|
+
let removesWholeNode = false;
|
|
1485
|
+
for (const entry of bySuggestion.values()) {
|
|
1486
|
+
removesWholeNode ||= entry.kinds.has("insertBlock") || entry.kinds.has("insertTable");
|
|
1487
|
+
for (const id of entry.revisionIds) revisionIds.add(id);
|
|
1488
|
+
}
|
|
1489
|
+
const rotationCandidates = removesWholeNode ? collectAddedBreakRotationCandidates(state.doc) : [];
|
|
1034
1490
|
let tr = null;
|
|
1035
1491
|
if (revisionIds.size > 0) resolveChange(0, state.doc.content.size, "reject", [...revisionIds])(state, (resolved) => {
|
|
1036
1492
|
tr = resolved;
|
|
@@ -1040,10 +1496,18 @@ function rejectAllSuggestions() {
|
|
|
1040
1496
|
workingTr.doc.descendants((node, pos) => {
|
|
1041
1497
|
if (readStructuralSuggestion(node)?.isNodeInsert) positions.push(pos);
|
|
1042
1498
|
});
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1499
|
+
if (!removeSuggestedInsertNodes({
|
|
1500
|
+
tr: workingTr,
|
|
1501
|
+
positions,
|
|
1502
|
+
resolvedRevisionIds: revisionIds
|
|
1503
|
+
})) return false;
|
|
1504
|
+
if (positions.length > 0 && rotationCandidates.length > 0 && !rotateAddedFinalParagraphBreaks({
|
|
1505
|
+
tr: workingTr,
|
|
1506
|
+
shouldRotate: mappedRotationCandidatePredicate({
|
|
1507
|
+
candidates: rotationCandidates,
|
|
1508
|
+
tr: workingTr
|
|
1509
|
+
})
|
|
1510
|
+
})) return false;
|
|
1047
1511
|
if (workingTr.steps.length === 0) return false;
|
|
1048
1512
|
if (dispatch) dispatch(workingTr);
|
|
1049
1513
|
return true;
|
|
@@ -1214,4 +1678,4 @@ function findPreviousChange(state, startPos) {
|
|
|
1214
1678
|
return result.value;
|
|
1215
1679
|
}
|
|
1216
1680
|
//#endregion
|
|
1217
|
-
export { acceptAIEditRevision, acceptAllChanges, acceptAllSuggestions, acceptChange, acceptSuggestion, addCommentMark, findAIEditRevisionRange, findChangeAtPosition, findNextChange, findParagraphBoundaryChangeAtPosition, findPreviousChange, findSuggestionRange, getSuggestions, rejectAIEditRevision, rejectAllChanges, rejectAllSuggestions, rejectChange, rejectSuggestion, removeCommentMark };
|
|
1681
|
+
export { acceptAIEditRevision, acceptAllChanges, acceptAllSuggestions, acceptChange, acceptSuggestion, addCommentMark, findAIEditRevisionRange, findChangeAtPosition, findNextChange, findParagraphBoundaryChangeAtPosition, findPreviousChange, findSuggestionRange, getSuggestions, rejectAIEditRevision, rejectAllChanges, rejectAllSuggestions, rejectChange, rejectSuggestion, removeCommentMark, resolveAllChangesInHeadlessState };
|