@stll/folio-core 0.52.0 → 0.53.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 +23 -0
- package/dist/ai-edits/apply.d.ts +26 -1
- package/dist/ai-edits/apply.js +1519 -105
- package/dist/ai-edits/batch-claims.d.ts +130 -0
- package/dist/ai-edits/batch-claims.js +244 -0
- package/dist/ai-edits/blockRange.js +9 -3
- package/dist/ai-edits/character-boundaries.d.ts +43 -0
- package/dist/ai-edits/character-boundaries.js +95 -0
- package/dist/ai-edits/clean-text.d.ts +33 -3
- package/dist/ai-edits/clean-text.js +52 -6
- package/dist/ai-edits/comment-lifecycle.d.ts +18 -0
- package/dist/ai-edits/comment-lifecycle.js +52 -0
- package/dist/ai-edits/headless.d.ts +71 -7
- package/dist/ai-edits/headless.js +381 -41
- package/dist/ai-edits/index.d.ts +2 -1
- package/dist/ai-edits/index.js +2 -1
- package/dist/ai-edits/minimal-replacement.d.ts +21 -6
- package/dist/ai-edits/minimal-replacement.js +134 -15
- package/dist/ai-edits/newListNumbering.d.ts +23 -0
- package/dist/ai-edits/newListNumbering.js +94 -0
- package/dist/ai-edits/note-references.d.ts +96 -0
- package/dist/ai-edits/note-references.js +139 -0
- package/dist/ai-edits/pending-suggestions.d.ts +79 -0
- package/dist/ai-edits/pending-suggestions.js +306 -0
- package/dist/ai-edits/read.d.ts +1 -1
- package/dist/ai-edits/read.js +56 -43
- package/dist/ai-edits/result-validation.d.ts +29 -0
- package/dist/ai-edits/result-validation.js +164 -0
- package/dist/ai-edits/snapshot.d.ts +36 -3
- package/dist/ai-edits/snapshot.js +177 -23
- package/dist/ai-edits/table-cell-mutations.d.ts +1 -1
- package/dist/ai-edits/table-cell-mutations.js +4 -1
- package/dist/ai-edits/table-geometry.d.ts +1 -1
- package/dist/ai-edits/table-row-column-mutations.d.ts +38 -16
- package/dist/ai-edits/table-row-column-mutations.js +61 -26
- package/dist/ai-edits/types.d.ts +155 -16
- package/dist/compare/compare.d.ts +1 -1
- package/dist/compare/compare.js +65 -16
- package/dist/compare/content-alignment.js +13 -2
- package/dist/compare/content-types.d.ts +7 -0
- package/dist/compare/content.d.ts +4 -1
- package/dist/compare/content.js +6 -1
- package/dist/compare/formatting.js +2 -1
- package/dist/compare/inline-atoms.d.ts +21 -4
- package/dist/compare/inline-atoms.js +138 -16
- package/dist/compare/plan.js +10 -5
- package/dist/compare/scenario.js +14 -3
- package/dist/compare/section-boundary-properties.js +1 -1
- package/dist/compare/types.d.ts +4 -2
- package/dist/compare/types.js +2 -1
- package/dist/compare/verification.d.ts +1 -1
- package/dist/compare/verification.js +15 -3
- package/dist/controller/committedLayoutDiff.d.ts +25 -0
- package/dist/controller/committedLayoutDiff.js +71 -0
- package/dist/controller/contentControlWidgetController.d.ts +1 -1
- package/dist/controller/folioEditor.d.ts +1 -1
- package/dist/controller/fontReadiness.d.ts +70 -3
- package/dist/controller/fontReadiness.js +100 -10
- package/dist/controller/headerFooterEditorManager.js +6 -1
- package/dist/controller/layoutPipeline.d.ts +12 -10
- package/dist/controller/layoutPipeline.js +62 -9
- package/dist/controller/layoutRunOptions.d.ts +24 -0
- package/dist/controller/layoutRunOptions.js +17 -0
- package/dist/controller/layoutScheduler.d.ts +19 -14
- package/dist/controller/layoutScheduler.js +15 -12
- package/dist/controller/layoutSession.d.ts +26 -2
- package/dist/controller/layoutSession.js +1 -1
- package/dist/controller/noteEditorManager.js +8 -3
- package/dist/document-operations.d.ts +11 -2
- package/dist/document-operations.js +230 -21
- package/dist/docx/altChunk.d.ts +8 -0
- package/dist/docx/altChunk.js +17 -0
- package/dist/docx/attributeRemainder.d.ts +1 -1
- package/dist/docx/blockContentParser.d.ts +64 -1
- package/dist/docx/blockContentParser.js +17 -4
- package/dist/docx/blockCustomXmlShell.d.ts +7 -0
- package/dist/docx/blockCustomXmlShell.js +14 -0
- package/dist/docx/blockPlainText.js +7 -0
- package/dist/docx/commentAnchorIndex.js +1 -1
- package/dist/docx/commentRangeIntegrity.js +8 -3
- package/dist/docx/commentReferenceNormalization.js +1 -1
- package/dist/docx/commentReplyMarkers.js +20 -1
- package/dist/docx/compatibility.d.ts +1 -1
- package/dist/docx/compatibility.js +34 -13
- package/dist/docx/containerChildren.gen.d.ts +1 -1
- package/dist/docx/containerChildren.gen.js +1 -0
- package/dist/docx/documentParser.js +12 -12
- package/dist/docx/drawingIdNormalization.d.ts +3 -1
- package/dist/docx/drawingIdNormalization.js +6 -1
- package/dist/docx/ensureParaIds.js +119 -97
- package/dist/docx/footnoteParser.js +8 -4
- package/dist/docx/headerFooterParser.js +3 -3
- package/dist/docx/headerFooterReferenceNormalization.d.ts +20 -1
- package/dist/docx/headerFooterReferenceNormalization.js +52 -27
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/index.d.ts +1 -1
- package/dist/docx/listNumberingInstances.d.ts +59 -0
- package/dist/docx/listNumberingInstances.js +249 -0
- package/dist/docx/normalizeBaseDirection.js +2 -1
- package/dist/docx/opaqueCarrier.d.ts +7 -0
- package/dist/docx/opaqueCarrier.js +38 -0
- package/dist/docx/packageParts.js +4 -1
- package/dist/docx/paragraphParser.js +91 -24
- package/dist/docx/paragraphPropertySource.d.ts +4 -2
- package/dist/docx/paragraphPropertySource.js +7 -1
- package/dist/docx/paragraphTraversal.js +1 -0
- package/dist/docx/parseWarningMessage.js +4 -1
- package/dist/docx/parser.js +173 -20
- package/dist/docx/rezip.js +27 -5
- package/dist/docx/sdtProperties.js +1 -1
- package/dist/docx/sdtPropertiesPatch.js +3 -0
- package/dist/docx/selectiveSave.js +16 -9
- package/dist/docx/selectiveXmlPatch.js +106 -37
- package/dist/docx/serializer/blockCustomXmlSerializer.d.ts +5 -0
- package/dist/docx/serializer/blockCustomXmlSerializer.js +4 -0
- package/dist/docx/serializer/documentSerializer.js +2 -0
- package/dist/docx/serializer/headerFooterSerializer.js +2 -0
- package/dist/docx/serializer/noteSerializer.js +3 -1
- package/dist/docx/serializer/paragraphSerializer.js +33 -9
- package/dist/docx/serializer/tableSerializer.js +25 -38
- package/dist/docx/server/createBilingualDocument.js +3 -3
- package/dist/docx/tableParser.d.ts +157 -1
- package/dist/docx/tableParser.js +89 -10
- package/dist/docx/textBoxParser.js +1 -1
- package/dist/docx/unzip.d.ts +2 -1
- package/dist/docx/unzip.js +1 -1
- package/dist/docx/wordprocessingPrefixes.d.ts +78 -0
- package/dist/docx/wordprocessingPrefixes.js +286 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +136 -0
- package/dist/i18n/messages/catalogs.gen.js +153 -17
- package/dist/i18n/messages/messages.gen.d.ts +8 -0
- package/dist/internal/compare/inline-presentation.d.ts +2 -1
- package/dist/internal/compare/inline-presentation.js +11 -10
- package/dist/internal/headlessRevisionResolutionGuard.d.ts +2 -8
- package/dist/internal/headlessRevisionResolutionGuard.js +2 -11
- package/dist/internal/indexedPositionMap.d.ts +11 -0
- package/dist/internal/indexedPositionMap.js +42 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
- package/dist/internal/revisionResolutionEdits.d.ts +13 -0
- package/dist/internal/revisionResolutionEdits.js +19 -0
- package/dist/internal/revisionResolutionInline.d.ts +24 -0
- package/dist/internal/{headlessRevisionResolution.js → revisionResolutionInline.js} +61 -43
- package/dist/internal/revisionResolutionStep.d.ts +34 -0
- package/dist/internal/revisionResolutionStep.js +282 -0
- package/dist/internal/revisionResolutionTracking.d.ts +11 -0
- package/dist/internal/revisionResolutionTracking.js +124 -0
- package/dist/internal/wholeStoryRevisionResolution.d.ts +56 -0
- package/dist/internal/wholeStoryRevisionResolution.js +530 -0
- package/dist/layout-bridge/convert/markupViewFlow.d.ts +20 -0
- package/dist/layout-bridge/convert/markupViewFlow.js +123 -0
- package/dist/layout-bridge/convert/tableConversion.js +1 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +10 -1
- package/dist/layout-engine/layoutInstrumentation.d.ts +9 -1
- package/dist/layout-engine/layoutInstrumentation.js +4 -1
- package/dist/layout-engine/measure/cache.d.ts +18 -1
- package/dist/layout-engine/measure/cache.js +31 -1
- package/dist/layout-engine/measure/font-metrics.worker.js +3 -7
- package/dist/layout-engine/measure/measureContainer.js +7 -47
- package/dist/layout-engine/measure/measureHelpers.d.ts +6 -1
- package/dist/layout-engine/measure/measureHelpers.js +22 -2
- package/dist/layout-engine/measure/measureWorker.js +2 -3
- package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +6 -7
- package/dist/layout-engine/measure/measureWorkerProtocol.js +1 -2
- package/dist/layout-engine/types.d.ts +6 -0
- package/dist/layout-painter/renderPage.js +1 -0
- package/dist/layout-painter/renderParagraph.js +1 -1
- package/dist/managers/ContextMenuManager.js +5 -2
- package/dist/managers/types.d.ts +3 -0
- package/dist/markdown/fromMarkdown.js +2 -1
- package/dist/markdown/internals.d.ts +11 -1
- package/dist/markdown/internals.js +24 -3
- package/dist/markdown/renderBlock.js +39 -9
- package/dist/markdown/renderParagraph.d.ts +13 -1
- package/dist/markdown/renderParagraph.js +85 -38
- package/dist/markdown/renderRuns.js +3 -10
- package/dist/markdown/renderTable.js +24 -12
- package/dist/markdown/trailers.js +2 -2
- package/dist/markdown/types.d.ts +29 -7
- package/dist/paged-layout/incrementalMeasure.d.ts +1 -2
- package/dist/paged-layout/incrementalMeasure.js +1 -9
- package/dist/paged-layout/transactionDirtyRange.d.ts +1 -3
- package/dist/paged-layout/transactionDirtyRange.js +29 -41
- package/dist/panel-layout.d.ts +83 -0
- package/dist/panel-layout.js +96 -0
- package/dist/prosemirror/anchoredTextBoxes.d.ts +37 -0
- package/dist/prosemirror/anchoredTextBoxes.js +156 -0
- package/dist/prosemirror/attrs/index.d.ts +6 -2
- package/dist/prosemirror/attrs/index.js +172 -1
- package/dist/prosemirror/commands/comments.d.ts +7 -8
- package/dist/prosemirror/commands/comments.js +241 -207
- package/dist/prosemirror/commands/contentControls.d.ts +1 -1
- package/dist/prosemirror/commands/formatPainter.d.ts +1 -1
- package/dist/prosemirror/commands/formatting.d.ts +1 -1
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/paragraph.d.ts +7 -1
- package/dist/prosemirror/commands/paragraph.js +9 -1
- package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +13 -0
- package/dist/prosemirror/commands/paragraphBookmarkJoin.js +22 -0
- package/dist/prosemirror/commands/pastePlainText.d.ts +1 -1
- package/dist/prosemirror/commands/resolveAllTableChanges.d.ts +40 -0
- package/dist/prosemirror/commands/resolveAllTableChanges.js +615 -0
- package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.d.ts +15 -0
- package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.js +46 -0
- package/dist/prosemirror/commands/resolveParagraphProperties.d.ts +16 -0
- package/dist/prosemirror/commands/resolveParagraphProperties.js +59 -0
- package/dist/prosemirror/commands/sectionBreak.js +2 -1
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +8 -2
- package/dist/prosemirror/commands/tableCellMergeResolution.js +1 -1
- package/dist/prosemirror/contentControlRevisions.d.ts +1 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +181 -31
- package/dist/prosemirror/conversion/toProseDoc.js +39 -4
- package/dist/prosemirror/emptyFieldResultRuns.d.ts +18 -0
- package/dist/prosemirror/emptyFieldResultRuns.js +33 -0
- package/dist/prosemirror/extensions/ExtensionManager.d.ts +1 -1
- package/dist/prosemirror/extensions/ExtensionManager.js +3 -1
- package/dist/prosemirror/extensions/StarterKit.js +3 -1
- package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -0
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +3 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +161 -123
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +19 -2
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +33 -20
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +31 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +270 -99
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +3 -2
- package/dist/prosemirror/extensions/features/pasteCleanup.js +2 -1
- package/dist/prosemirror/extensions/features/pastedHtmlLists.d.ts +12 -0
- package/dist/prosemirror/extensions/features/pastedHtmlLists.js +126 -0
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +21 -5
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +21 -18
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +37 -17
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +7 -2
- package/dist/prosemirror/extensions/marks/markUtils.js +8 -2
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +10 -0
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +35 -0
- package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.js +52 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +3 -3
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +50 -15
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +4 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +19 -18
- package/dist/prosemirror/extensions/types.d.ts +4 -1
- package/dist/prosemirror/findReplaceSelection.js +1 -1
- package/dist/prosemirror/index.d.ts +3 -2
- package/dist/prosemirror/index.js +3 -2
- package/dist/prosemirror/indexedNodeLookup.d.ts +17 -0
- package/dist/prosemirror/indexedNodeLookup.js +103 -0
- package/dist/prosemirror/listAutoformatMarkers.d.ts +19 -0
- package/dist/prosemirror/listAutoformatMarkers.js +98 -0
- package/dist/prosemirror/listInstanceReferences.d.ts +12 -0
- package/dist/prosemirror/listInstanceReferences.js +72 -0
- package/dist/prosemirror/listLabels.d.ts +24 -0
- package/dist/prosemirror/listLabels.js +111 -0
- package/dist/prosemirror/listNumbering.d.ts +110 -0
- package/dist/prosemirror/listNumbering.js +345 -0
- package/dist/prosemirror/listRenderingAttrs.d.ts +11 -2
- package/dist/prosemirror/listRenderingAttrs.js +8 -1
- package/dist/prosemirror/markupViewProjection.d.ts +95 -0
- package/dist/prosemirror/markupViewProjection.js +83 -0
- package/dist/prosemirror/numberingAttr.d.ts +9 -1
- package/dist/prosemirror/numberingAttr.js +9 -1
- package/dist/prosemirror/outlineLevelAttr.js +1 -1
- package/dist/prosemirror/paragraphIndentation.d.ts +10 -1
- package/dist/prosemirror/paragraphIndentation.js +29 -7
- package/dist/prosemirror/paragraphMarkJoin.d.ts +19 -0
- package/dist/prosemirror/paragraphMarkJoin.js +24 -0
- package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +1 -1
- package/dist/prosemirror/plugins/documentNumbering.d.ts +27 -1
- package/dist/prosemirror/plugins/documentNumbering.js +97 -11
- package/dist/prosemirror/plugins/documentStyles.d.ts +10 -1
- package/dist/prosemirror/plugins/documentStyles.js +14 -1
- package/dist/prosemirror/plugins/suggestionMode.d.ts +16 -2
- package/dist/prosemirror/plugins/suggestionMode.js +116 -52
- package/dist/prosemirror/plugins/templateDirectives.d.ts +1 -1
- package/dist/prosemirror/plugins/transactionInvariants.d.ts +32 -0
- package/dist/prosemirror/plugins/transactionInvariants.js +86 -0
- package/dist/prosemirror/positionSweep.d.ts +24 -0
- package/dist/prosemirror/positionSweep.js +222 -0
- package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +1 -1
- package/dist/prosemirror/rejoinRunCarriers.d.ts +1 -1
- package/dist/prosemirror/replacedAnnotations.d.ts +33 -1
- package/dist/prosemirror/replacedAnnotations.js +170 -1
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +1 -1
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/index.js +3 -0
- package/dist/prosemirror/schema/nodes.d.ts +42 -11
- package/dist/prosemirror/sectionMarkEdits.d.ts +20 -0
- package/dist/prosemirror/sectionMarkEdits.js +59 -0
- package/dist/prosemirror/storyListNumbering.d.ts +17 -0
- package/dist/prosemirror/storyListNumbering.js +102 -0
- package/dist/prosemirror/tableGridMutation.d.ts +48 -2
- package/dist/prosemirror/tableGridMutation.js +106 -1
- package/dist/prosemirror/validation.js +5 -1
- package/dist/redline.js +93 -9
- package/dist/render-dom/BodySelectionOverlay.d.ts +4 -1
- package/dist/render-dom/BodySelectionOverlay.js +3 -2
- package/dist/utils/findReplace.js +2 -2
- package/dist/utils/mergeDocumentContent.js +1 -1
- package/dist/utils/noteReferenceLabels.d.ts +36 -0
- package/dist/utils/noteReferenceLabels.js +32 -0
- package/dist/utils/replaceText.js +1 -1
- package/dist/version-comparison.d.ts +1 -0
- package/dist/version-comparison.js +1 -0
- package/package.json +3 -2
- package/dist/internal/headlessRevisionResolution.d.ts +0 -23
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import { withTrackedSectionEndpointRemoval } from "../../../internal/sectionEndpointResolution.js";
|
|
1
2
|
import { canonicalJson } from "../../../utils/canonicalJson.js";
|
|
3
|
+
import { enclosingParagraphIndexed, nodeAtIndexed, nodesBetweenIndexed } from "../../indexedNodeLookup.js";
|
|
4
|
+
import { sweepPositions } from "../../positionSweep.js";
|
|
2
5
|
import { sectionPropertiesOf } from "../../sectionCarrier.js";
|
|
6
|
+
import { sectionMarkEditsOf } from "../../sectionMarkEdits.js";
|
|
3
7
|
import { createExtension } from "../create.js";
|
|
4
8
|
import { AddMarkStep, AddNodeMarkStep, AttrStep, RemoveMarkStep, RemoveNodeMarkStep } from "prosemirror-transform";
|
|
5
9
|
import { Plugin, PluginKey } from "prosemirror-state";
|
|
10
|
+
import { isHistoryTransaction } from "prosemirror-history";
|
|
6
11
|
//#region src/prosemirror/extensions/features/ParagraphChangeTrackerExtension.ts
|
|
7
12
|
const paragraphChangeTrackerKey = new PluginKey("paragraphChangeTracker");
|
|
8
13
|
const CLEAR_META = "clear";
|
|
@@ -10,14 +15,16 @@ const IGNORE_META = "ignore";
|
|
|
10
15
|
const STRUCTURAL_META = "structural";
|
|
11
16
|
const CHANGED_PARAGRAPH_RANGES_META = "folioChangedParagraphRanges";
|
|
12
17
|
const SECTION_ENDPOINT_REMOVAL_META = "folioSectionEndpointRemoval";
|
|
18
|
+
const SECTION_EDIT_META = "folioSectionEdit";
|
|
13
19
|
const isChangedParagraphRangesMeta = (value) => typeof value === "object" && value !== null && "type" in value && value.type === "changed-paragraph-ranges";
|
|
14
20
|
const isRemovedSectionReference = (value) => typeof value === "object" && value !== null && "part" in value && (value.part === "header" || value.part === "footer") && "type" in value && (value.type === "default" || value.type === "first" || value.type === "even") && "relationshipId" in value && typeof value.relationshipId === "string";
|
|
15
21
|
const isTrackedSectionEndpointRemoval = (value) => typeof value === "object" && value !== null && "type" in value && value.type === "tracked-section-endpoint-removal" && "sourceParagraphEndpointCount" in value && typeof value.sourceParagraphEndpointCount === "number" && Number.isSafeInteger(value.sourceParagraphEndpointCount) && "expectedParagraphEndpointCount" in value && typeof value.expectedParagraphEndpointCount === "number" && Number.isSafeInteger(value.expectedParagraphEndpointCount) && value.sourceParagraphEndpointCount > value.expectedParagraphEndpointCount && value.expectedParagraphEndpointCount >= 0 && "sourceEndpointFingerprint" in value && typeof value.sourceEndpointFingerprint === "string" && "expectedEndpointFingerprint" in value && typeof value.expectedEndpointFingerprint === "string" && "removedReferences" in value && Array.isArray(value.removedReferences) && value.removedReferences.every(isRemovedSectionReference);
|
|
16
22
|
const isTrackedSectionEndpointRemovalMeta = (value) => typeof value === "object" && value !== null && "type" in value && value.type === "tracked-section-endpoint-removal-meta" && "authorization" in value && isTrackedSectionEndpointRemoval(value.authorization);
|
|
23
|
+
const isSectionEditMeta = (value) => typeof value === "object" && value !== null && "type" in value && value.type === "section-edit-meta" && "authorization" in value && (value.authorization === null || isTrackedSectionEndpointRemoval(value.authorization)) && "expectedEndpointFingerprint" in value && typeof value.expectedEndpointFingerprint === "string";
|
|
17
24
|
/** Count the structural values the tracker compares for every transaction. */
|
|
18
25
|
function countDocumentStructure(doc) {
|
|
19
26
|
let paragraphs = 0;
|
|
20
|
-
|
|
27
|
+
const sectionRecords = /* @__PURE__ */ new Set();
|
|
21
28
|
const blockRecords = [];
|
|
22
29
|
const endpointRecords = [];
|
|
23
30
|
const visit = (parent, parentPath) => {
|
|
@@ -36,7 +43,7 @@ function countDocumentStructure(doc) {
|
|
|
36
43
|
paragraphs++;
|
|
37
44
|
const sectionProperties = sectionPropertiesOf(node);
|
|
38
45
|
if (sectionProperties !== null) {
|
|
39
|
-
|
|
46
|
+
sectionRecords.add(sectionProperties);
|
|
40
47
|
endpointRecords.push({
|
|
41
48
|
path: parentPath.length === 0 ? `${index}` : `${parentPath}.${index}`,
|
|
42
49
|
paraId: node.attrs["paraId"] ?? null,
|
|
@@ -51,11 +58,21 @@ function countDocumentStructure(doc) {
|
|
|
51
58
|
visit(doc, "");
|
|
52
59
|
return {
|
|
53
60
|
blockStructureFingerprint: JSON.stringify(blockRecords),
|
|
61
|
+
sectionRecords,
|
|
54
62
|
paragraphs,
|
|
55
|
-
sectionEndpoints,
|
|
63
|
+
sectionEndpoints: sectionRecords.size,
|
|
56
64
|
sectionEndpointFingerprint: canonicalJson(endpointRecords)
|
|
57
65
|
};
|
|
58
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Whether a transaction left every section record in place, by identity: the
|
|
69
|
+
* same sections, however their paragraphs moved around them. An edit before a
|
|
70
|
+
* section break (a paragraph inserted, a split, a paraId allocated) moves the
|
|
71
|
+
* endpoint without changing which sections the package states, so a removal
|
|
72
|
+
* authorized earlier still describes the saved section count exactly. A record
|
|
73
|
+
* edited, added or dropped is a new transition the authorization never saw.
|
|
74
|
+
*/
|
|
75
|
+
const holdsTheSameSections = (previous, next) => previous.sectionRecords.size === next.sectionRecords.size && [...next.sectionRecords].every((record) => previous.sectionRecords.has(record));
|
|
59
76
|
const isUsableParaId = (value) => typeof value === "string" && value.length > 0 && value !== "00000000";
|
|
60
77
|
/**
|
|
61
78
|
* Collect paraIds of all paragraphs that overlap with the given range
|
|
@@ -64,7 +81,8 @@ function collectAffectedParaIds(doc, from, to) {
|
|
|
64
81
|
const ids = /* @__PURE__ */ new Set();
|
|
65
82
|
const positions = /* @__PURE__ */ new Set();
|
|
66
83
|
let hasUntracked = false;
|
|
67
|
-
|
|
84
|
+
const start = Math.max(0, Math.min(from, doc.content.size));
|
|
85
|
+
nodesBetweenIndexed(doc, start, Math.max(start, Math.min(to, doc.content.size)), (node, pos) => {
|
|
68
86
|
if (node.type.name === "paragraph") {
|
|
69
87
|
positions.add(pos);
|
|
70
88
|
const paraId = node.attrs["paraId"];
|
|
@@ -88,17 +106,14 @@ function collectAffectedParaIdsFromMarkLikeStep(doc, from, to) {
|
|
|
88
106
|
const hi = Math.max(from, to);
|
|
89
107
|
const primary = collectAffectedParaIds(doc, lo, hi > lo ? hi : lo + 1);
|
|
90
108
|
if (primary.ids.size > 0 || primary.hasUntracked) return primary;
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
hasUntracked: !isUsableParaId(paraId)
|
|
100
|
-
};
|
|
101
|
-
}
|
|
109
|
+
const paragraph = enclosingParagraphIndexed(doc, lo);
|
|
110
|
+
if (paragraph) {
|
|
111
|
+
const paraId = paragraph.node.attrs["paraId"];
|
|
112
|
+
return {
|
|
113
|
+
ids: new Set(isUsableParaId(paraId) ? [paraId] : []),
|
|
114
|
+
positions: /* @__PURE__ */ new Set([paragraph.pos]),
|
|
115
|
+
hasUntracked: !isUsableParaId(paraId)
|
|
116
|
+
};
|
|
102
117
|
}
|
|
103
118
|
return {
|
|
104
119
|
ids: /* @__PURE__ */ new Set(),
|
|
@@ -106,25 +121,78 @@ function collectAffectedParaIdsFromMarkLikeStep(doc, from, to) {
|
|
|
106
121
|
hasUntracked: false
|
|
107
122
|
};
|
|
108
123
|
}
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Map edited paragraphs' interiors so markup replacement retains their
|
|
126
|
+
* ownership: each position's paragraph in `tr.doc`, or null once deleted. The
|
|
127
|
+
* positions go through the transaction together (see `sweepPositions`).
|
|
128
|
+
*/
|
|
129
|
+
const mapParagraphPositions = (tr, positions) => sweepPositions([tr.mapping], positions.map((position) => ({
|
|
130
|
+
pos: position + 1,
|
|
131
|
+
assoc: 1,
|
|
132
|
+
from: 0
|
|
133
|
+
}))).map((mapped) => mapped.deletedAcross ? null : enclosingParagraphIndexed(tr.doc, mapped.pos)?.pos ?? null);
|
|
117
134
|
const mapAffectedParagraphPositions = (tr, positions) => {
|
|
118
135
|
const mappedPositions = /* @__PURE__ */ new Set();
|
|
119
|
-
for (const
|
|
120
|
-
const mapped = mapParagraphPosition(tr, position);
|
|
121
|
-
if (mapped !== null) mappedPositions.add(mapped);
|
|
122
|
-
}
|
|
136
|
+
for (const mapped of mapParagraphPositions(tr, [...positions])) if (mapped !== null) mappedPositions.add(mapped);
|
|
123
137
|
return mappedPositions;
|
|
124
138
|
};
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Every position the step loop reads, each entering the sweep at the step
|
|
141
|
+
* after the one that produced it: the transaction is mapped once rather than
|
|
142
|
+
* sliced and walked again for every step.
|
|
143
|
+
*/
|
|
144
|
+
const mapStepTouches = (tr, batches) => {
|
|
145
|
+
const queries = [];
|
|
146
|
+
const touches = [];
|
|
147
|
+
const addRange = (kind, from, to, at) => {
|
|
148
|
+
touches.push({
|
|
149
|
+
kind,
|
|
150
|
+
query: queries.length
|
|
151
|
+
});
|
|
152
|
+
queries.push({
|
|
153
|
+
pos: from,
|
|
154
|
+
assoc: 1,
|
|
155
|
+
from: at
|
|
156
|
+
}, {
|
|
157
|
+
pos: to,
|
|
158
|
+
assoc: -1,
|
|
159
|
+
from: at
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
const replacedStepMaps = /* @__PURE__ */ new Set();
|
|
163
|
+
for (const batch of batches) {
|
|
164
|
+
if (batch.replacesStepMapAt !== void 0) replacedStepMaps.add(batch.replacesStepMapAt);
|
|
165
|
+
for (const range of batch.ranges) addRange("mark-range", range.from, range.to, batch.mappingFrom);
|
|
166
|
+
}
|
|
167
|
+
for (let stepIndex = 0; stepIndex < tr.steps.length; stepIndex++) {
|
|
168
|
+
if (replacedStepMaps.has(stepIndex)) continue;
|
|
169
|
+
const step = tr.steps[stepIndex];
|
|
170
|
+
const at = stepIndex + 1;
|
|
171
|
+
if (step instanceof AddMarkStep || step instanceof RemoveMarkStep) {
|
|
172
|
+
addRange("mark-range", step.from, step.to, at);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (step instanceof AddNodeMarkStep || step instanceof RemoveNodeMarkStep || step instanceof AttrStep) {
|
|
176
|
+
touches.push({
|
|
177
|
+
kind: "node",
|
|
178
|
+
query: queries.length
|
|
179
|
+
});
|
|
180
|
+
queries.push({
|
|
181
|
+
pos: step.pos,
|
|
182
|
+
assoc: 1,
|
|
183
|
+
from: at
|
|
184
|
+
});
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
step.getMap().forEach((_oldStart, _oldEnd, newStart, newEnd) => {
|
|
188
|
+
addRange("replaced-range", newStart, newEnd, at);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
touches,
|
|
193
|
+
mapped: sweepPositions([tr.mapping], queries)
|
|
194
|
+
};
|
|
195
|
+
};
|
|
128
196
|
function createParagraphChangeTrackerPlugin() {
|
|
129
197
|
return new Plugin({
|
|
130
198
|
key: paragraphChangeTrackerKey,
|
|
@@ -141,6 +209,7 @@ function createParagraphChangeTrackerPlugin() {
|
|
|
141
209
|
paragraphCount: counts.paragraphs,
|
|
142
210
|
sectionEndpointCount: counts.sectionEndpoints,
|
|
143
211
|
sectionEndpointFingerprint: counts.sectionEndpointFingerprint,
|
|
212
|
+
sectionRecords: counts.sectionRecords,
|
|
144
213
|
sectionEndpointRemoval: null
|
|
145
214
|
};
|
|
146
215
|
},
|
|
@@ -148,6 +217,7 @@ function createParagraphChangeTrackerPlugin() {
|
|
|
148
217
|
const meta = tr.getMeta(paragraphChangeTrackerKey);
|
|
149
218
|
const changedParagraphRangesMeta = tr.getMeta(CHANGED_PARAGRAPH_RANGES_META);
|
|
150
219
|
const sectionEndpointRemovalMeta = tr.getMeta(SECTION_ENDPOINT_REMOVAL_META);
|
|
220
|
+
const sectionEditMeta = tr.getMeta(SECTION_EDIT_META);
|
|
151
221
|
if (meta === CLEAR_META) {
|
|
152
222
|
const counts = countDocumentStructure(tr.doc);
|
|
153
223
|
return {
|
|
@@ -160,6 +230,7 @@ function createParagraphChangeTrackerPlugin() {
|
|
|
160
230
|
paragraphCount: counts.paragraphs,
|
|
161
231
|
sectionEndpointCount: counts.sectionEndpoints,
|
|
162
232
|
sectionEndpointFingerprint: counts.sectionEndpointFingerprint,
|
|
233
|
+
sectionRecords: counts.sectionRecords,
|
|
163
234
|
sectionEndpointRemoval: null
|
|
164
235
|
};
|
|
165
236
|
}
|
|
@@ -170,7 +241,7 @@ function createParagraphChangeTrackerPlugin() {
|
|
|
170
241
|
const changedParaIds = /* @__PURE__ */ new Set();
|
|
171
242
|
let unresolvedChanges = prevState.hasUntrackedSourceChanges;
|
|
172
243
|
for (const position of affectedParagraphPositions) {
|
|
173
|
-
const paraId = tr.doc
|
|
244
|
+
const paraId = nodeAtIndexed(tr.doc, position)?.attrs["paraId"];
|
|
174
245
|
if (isUsableParaId(paraId)) changedParaIds.add(paraId);
|
|
175
246
|
else unresolvedChanges = true;
|
|
176
247
|
}
|
|
@@ -182,25 +253,32 @@ function createParagraphChangeTrackerPlugin() {
|
|
|
182
253
|
blockStructureFingerprint: counts.blockStructureFingerprint,
|
|
183
254
|
paragraphCount: counts.paragraphs,
|
|
184
255
|
sectionEndpointCount: counts.sectionEndpoints,
|
|
185
|
-
sectionEndpointRemoval: counts
|
|
186
|
-
sectionEndpointFingerprint: counts.sectionEndpointFingerprint
|
|
256
|
+
sectionEndpointRemoval: holdsTheSameSections(prevState, counts) ? prevState.sectionEndpointRemoval : null,
|
|
257
|
+
sectionEndpointFingerprint: counts.sectionEndpointFingerprint,
|
|
258
|
+
sectionRecords: counts.sectionRecords
|
|
187
259
|
};
|
|
188
260
|
}
|
|
189
|
-
if (!tr.docChanged) return prevState
|
|
261
|
+
if (!tr.docChanged) return isSectionEditMeta(sectionEditMeta) && sectionEditMeta.expectedEndpointFingerprint === prevState.sectionEndpointFingerprint ? {
|
|
262
|
+
...prevState,
|
|
263
|
+
sectionEndpointRemoval: sectionEditMeta.authorization
|
|
264
|
+
} : prevState;
|
|
190
265
|
const counts = countDocumentStructure(tr.doc);
|
|
191
266
|
const newCount = counts.paragraphs;
|
|
192
267
|
let sectionEndpointRemoval = prevState.sectionEndpointRemoval;
|
|
193
|
-
if (counts.sectionEndpointFingerprint !== prevState.sectionEndpointFingerprint)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
268
|
+
if (counts.sectionEndpointFingerprint !== prevState.sectionEndpointFingerprint) {
|
|
269
|
+
if (isTrackedSectionEndpointRemovalMeta(sectionEndpointRemovalMeta) && sectionEndpointRemovalMeta.authorization.sourceEndpointFingerprint === prevState.sectionEndpointFingerprint && sectionEndpointRemovalMeta.authorization.expectedEndpointFingerprint === counts.sectionEndpointFingerprint && sectionEndpointRemovalMeta.authorization.sourceParagraphEndpointCount === prevState.sectionEndpointCount && sectionEndpointRemovalMeta.authorization.expectedParagraphEndpointCount === counts.sectionEndpoints && counts.sectionEndpoints < prevState.sectionEndpointCount) {
|
|
270
|
+
const authorization = sectionEndpointRemovalMeta.authorization;
|
|
271
|
+
sectionEndpointRemoval = {
|
|
272
|
+
type: "tracked-section-endpoint-removal",
|
|
273
|
+
sourceParagraphEndpointCount: prevState.sectionEndpointRemoval?.expectedParagraphEndpointCount === authorization.sourceParagraphEndpointCount ? prevState.sectionEndpointRemoval.sourceParagraphEndpointCount : authorization.sourceParagraphEndpointCount,
|
|
274
|
+
expectedParagraphEndpointCount: authorization.expectedParagraphEndpointCount,
|
|
275
|
+
sourceEndpointFingerprint: prevState.sectionEndpointRemoval?.expectedParagraphEndpointCount === authorization.sourceParagraphEndpointCount ? prevState.sectionEndpointRemoval.sourceEndpointFingerprint : authorization.sourceEndpointFingerprint,
|
|
276
|
+
expectedEndpointFingerprint: authorization.expectedEndpointFingerprint,
|
|
277
|
+
removedReferences: [...prevState.sectionEndpointRemoval?.expectedParagraphEndpointCount === authorization.sourceParagraphEndpointCount ? prevState.sectionEndpointRemoval.removedReferences : [], ...authorization.removedReferences]
|
|
278
|
+
};
|
|
279
|
+
} else if (!holdsTheSameSections(prevState, counts)) sectionEndpointRemoval = null;
|
|
280
|
+
}
|
|
281
|
+
if (isSectionEditMeta(sectionEditMeta) && sectionEditMeta.expectedEndpointFingerprint === counts.sectionEndpointFingerprint) sectionEndpointRemoval = sectionEditMeta.authorization;
|
|
204
282
|
const newState = {
|
|
205
283
|
affectedParagraphPositions: mapAffectedParagraphPositions(tr, prevState.affectedParagraphPositions),
|
|
206
284
|
hasUntrackedSourceChanges: prevState.hasUntrackedSourceChanges,
|
|
@@ -211,71 +289,129 @@ function createParagraphChangeTrackerPlugin() {
|
|
|
211
289
|
paragraphCount: newCount,
|
|
212
290
|
sectionEndpointCount: counts.sectionEndpoints,
|
|
213
291
|
sectionEndpointFingerprint: counts.sectionEndpointFingerprint,
|
|
292
|
+
sectionRecords: counts.sectionRecords,
|
|
214
293
|
sectionEndpointRemoval
|
|
215
294
|
};
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
for (const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (prevState.blockStructureFingerprint !== counts.blockStructureFingerprint) newState.structuralChange = true;
|
|
229
|
-
for (let stepIndex = 0; stepIndex < tr.steps.length; stepIndex++) {
|
|
230
|
-
const step = tr.steps[stepIndex];
|
|
231
|
-
const remap = tr.mapping.slice(stepIndex + 1);
|
|
232
|
-
if (step instanceof AddMarkStep || step instanceof RemoveMarkStep) {
|
|
233
|
-
const from = mapStepPosition(remap, step.from, 1);
|
|
234
|
-
const to = mapStepPosition(remap, step.to, -1);
|
|
235
|
-
if (to <= from) continue;
|
|
236
|
-
const { ids, positions, hasUntracked } = collectAffectedParaIdsFromMarkLikeStep(tr.doc, from, to);
|
|
237
|
-
for (const position of positions) newState.affectedParagraphPositions.add(position);
|
|
238
|
-
for (const id of ids) newState.changedParaIds.add(id);
|
|
239
|
-
if (hasUntracked) newState.hasUntrackedChanges = true;
|
|
295
|
+
const recordAffected = ({ ids, positions, hasUntracked }) => {
|
|
296
|
+
for (const position of positions) newState.affectedParagraphPositions.add(position);
|
|
297
|
+
for (const id of ids) newState.changedParaIds.add(id);
|
|
298
|
+
if (hasUntracked) newState.hasUntrackedChanges = true;
|
|
299
|
+
};
|
|
300
|
+
const { touches, mapped } = mapStepTouches(tr, isChangedParagraphRangesMeta(changedParagraphRangesMeta) ? changedParagraphRangesMeta.batches : []);
|
|
301
|
+
for (const touch of touches) {
|
|
302
|
+
const from = mapped[touch.query].pos;
|
|
303
|
+
if (touch.kind === "node") {
|
|
304
|
+
if (mapped[touch.query].deletedAcross) continue;
|
|
305
|
+
const node = nodeAtIndexed(tr.doc, from);
|
|
306
|
+
if (node) recordAffected(collectAffectedParaIds(tr.doc, from, from + node.nodeSize));
|
|
240
307
|
continue;
|
|
241
308
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (!node) continue;
|
|
246
|
-
const end = pos + node.nodeSize;
|
|
247
|
-
const { ids, positions, hasUntracked } = collectAffectedParaIds(tr.doc, pos, end);
|
|
248
|
-
for (const position of positions) newState.affectedParagraphPositions.add(position);
|
|
249
|
-
for (const id of ids) newState.changedParaIds.add(id);
|
|
250
|
-
if (hasUntracked) newState.hasUntrackedChanges = true;
|
|
309
|
+
const to = mapped[touch.query + 1].pos;
|
|
310
|
+
if (touch.kind === "mark-range") {
|
|
311
|
+
if (to > from) recordAffected(collectAffectedParaIdsFromMarkLikeStep(tr.doc, from, to));
|
|
251
312
|
continue;
|
|
252
313
|
}
|
|
253
|
-
|
|
254
|
-
const from = mapStepPosition(remap, newStart, 1);
|
|
255
|
-
const to = mapStepPosition(remap, newEnd, -1);
|
|
256
|
-
if (to < from) return;
|
|
257
|
-
const { ids, positions, hasUntracked } = collectAffectedParaIds(tr.doc, from, to);
|
|
258
|
-
for (const position of positions) newState.affectedParagraphPositions.add(position);
|
|
259
|
-
for (const id of ids) newState.changedParaIds.add(id);
|
|
260
|
-
if (hasUntracked) newState.hasUntrackedChanges = true;
|
|
261
|
-
});
|
|
314
|
+
if (to >= from) recordAffected(collectAffectedParaIds(tr.doc, from, to));
|
|
262
315
|
}
|
|
263
|
-
if (
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
if (
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
316
|
+
if (prevState.blockStructureFingerprint !== counts.blockStructureFingerprint) newState.structuralChange = true;
|
|
317
|
+
if (newState.hasUntrackedChanges || prevState.blockStructureFingerprint !== counts.blockStructureFingerprint) {
|
|
318
|
+
const unidentified = [];
|
|
319
|
+
tr.before.descendants((node, position) => {
|
|
320
|
+
if (node.type.name !== "paragraph") return true;
|
|
321
|
+
if (!isUsableParaId(node.attrs["paraId"])) unidentified.push(position);
|
|
322
|
+
return false;
|
|
323
|
+
});
|
|
324
|
+
for (const survivor of mapParagraphPositions(tr, unidentified)) if (survivor === null || newState.affectedParagraphPositions.has(survivor)) {
|
|
325
|
+
newState.hasUntrackedSourceChanges = true;
|
|
326
|
+
newState.hasUntrackedChanges = true;
|
|
271
327
|
}
|
|
272
|
-
|
|
273
|
-
});
|
|
328
|
+
}
|
|
274
329
|
return newState;
|
|
275
330
|
}
|
|
276
|
-
}
|
|
331
|
+
},
|
|
332
|
+
appendTransaction: (transactions, oldState, newState) => sectionEditTransaction(transactions, oldState, newState)
|
|
277
333
|
});
|
|
278
334
|
}
|
|
335
|
+
const referencesOf = (records) => {
|
|
336
|
+
const references = [];
|
|
337
|
+
for (const record of records) {
|
|
338
|
+
for (const { type, rId } of record.headerReferences ?? []) references.push({
|
|
339
|
+
part: "header",
|
|
340
|
+
type,
|
|
341
|
+
relationshipId: rId
|
|
342
|
+
});
|
|
343
|
+
for (const { type, rId } of record.footerReferences ?? []) references.push({
|
|
344
|
+
part: "footer",
|
|
345
|
+
type,
|
|
346
|
+
relationshipId: rId
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
return references;
|
|
350
|
+
};
|
|
351
|
+
/** `references` without one occurrence of each of `restored`. */
|
|
352
|
+
const withoutReferences = (references, restored) => {
|
|
353
|
+
const remaining = [...references];
|
|
354
|
+
for (const reference of restored) {
|
|
355
|
+
const index = remaining.findIndex((candidate) => candidate.part === reference.part && candidate.type === reference.type && candidate.relationshipId === reference.relationshipId);
|
|
356
|
+
if (index !== -1) remaining.splice(index, 1);
|
|
357
|
+
}
|
|
358
|
+
return remaining;
|
|
359
|
+
};
|
|
360
|
+
/**
|
|
361
|
+
* Carry section breaks through an ordinary edit, and record the ones it
|
|
362
|
+
* deleted.
|
|
363
|
+
*
|
|
364
|
+
* Deleting the mark of a section-ending paragraph (Backspace or Delete across
|
|
365
|
+
* it, a selection, a cut or a paste over it, a join) deletes the break, and
|
|
366
|
+
* the section's content joins the following section: the same outcome as
|
|
367
|
+
* deleting the paragraph as a block, or accepting its tracked deletion. The
|
|
368
|
+
* appended transaction moves each joined paragraph's record to the one its
|
|
369
|
+
* surviving mark carries (see `sectionMarkEditsOf`) and states the removal
|
|
370
|
+
* the save is to accept.
|
|
371
|
+
*
|
|
372
|
+
* Only a record whose mark a replacement deleted counts as removed on
|
|
373
|
+
* purpose. A record that goes any other way (an attribute cleared, a record
|
|
374
|
+
* swapped for another) leaves the edit unauthorized, and the save refuses the
|
|
375
|
+
* smaller package as it always did. Records coming back (an undo) take their
|
|
376
|
+
* removal back out of the authorization.
|
|
377
|
+
*/
|
|
378
|
+
const sectionEditTransaction = (transactions, oldState, newState) => {
|
|
379
|
+
if (!transactions.some((transaction) => transaction.docChanged && transaction.getMeta(paragraphChangeTrackerKey) !== IGNORE_META) || transactions.some((transaction) => transaction.getMeta(SECTION_EDIT_META) !== void 0 || transaction.getMeta(SECTION_ENDPOINT_REMOVAL_META) !== void 0 || transaction.getMeta(paragraphChangeTrackerKey) === CLEAR_META)) return null;
|
|
380
|
+
const base = paragraphChangeTrackerKey.getState(oldState);
|
|
381
|
+
if (!base) return null;
|
|
382
|
+
if (base.sectionRecords.size === 0) return null;
|
|
383
|
+
const edits = sectionMarkEditsOf(transactions, newState.doc);
|
|
384
|
+
const tr = newState.tr;
|
|
385
|
+
const restoring = transactions.some((transaction) => isHistoryTransaction(transaction));
|
|
386
|
+
for (const { position, record } of restoring ? [] : edits.carriers) {
|
|
387
|
+
const paragraph = tr.doc.nodeAt(position);
|
|
388
|
+
if (paragraph?.type.name === "paragraph" && sectionPropertiesOf(paragraph) !== record) tr.setNodeAttribute(position, "_sectionProperties", record);
|
|
389
|
+
}
|
|
390
|
+
const after = countDocumentStructure(tr.doc);
|
|
391
|
+
if (holdsTheSameSections(base, after)) return tr.docChanged ? tr.setMeta(SECTION_EDIT_META, {
|
|
392
|
+
type: "section-edit-meta",
|
|
393
|
+
authorization: base.sectionEndpointRemoval,
|
|
394
|
+
expectedEndpointFingerprint: after.sectionEndpointFingerprint
|
|
395
|
+
}) : null;
|
|
396
|
+
const removed = [...base.sectionRecords].filter((record) => !after.sectionRecords.has(record));
|
|
397
|
+
const added = [...after.sectionRecords].filter((record) => !base.sectionRecords.has(record));
|
|
398
|
+
if (removed.some((record) => !edits.deletedMarks.has(record))) return tr.docChanged ? tr : null;
|
|
399
|
+
const prior = base.sectionEndpointRemoval;
|
|
400
|
+
const sourceParagraphEndpointCount = prior?.sourceParagraphEndpointCount ?? base.sectionEndpointCount;
|
|
401
|
+
const authorization = after.sectionEndpoints < sourceParagraphEndpointCount ? {
|
|
402
|
+
type: "tracked-section-endpoint-removal",
|
|
403
|
+
sourceParagraphEndpointCount,
|
|
404
|
+
expectedParagraphEndpointCount: after.sectionEndpoints,
|
|
405
|
+
sourceEndpointFingerprint: prior?.sourceEndpointFingerprint ?? base.sectionEndpointFingerprint,
|
|
406
|
+
expectedEndpointFingerprint: after.sectionEndpointFingerprint,
|
|
407
|
+
removedReferences: withoutReferences([...prior?.removedReferences ?? [], ...referencesOf(removed)], referencesOf(added))
|
|
408
|
+
} : null;
|
|
409
|
+
return tr.setMeta(SECTION_EDIT_META, {
|
|
410
|
+
type: "section-edit-meta",
|
|
411
|
+
authorization,
|
|
412
|
+
expectedEndpointFingerprint: after.sectionEndpointFingerprint
|
|
413
|
+
});
|
|
414
|
+
};
|
|
279
415
|
/**
|
|
280
416
|
* Get the change tracker state from an EditorState
|
|
281
417
|
*/
|
|
@@ -304,6 +440,24 @@ function hasUntrackedChanges(state) {
|
|
|
304
440
|
function getTrackedSectionEndpointRemoval(state) {
|
|
305
441
|
return getChangeTrackerState(state)?.sectionEndpointRemoval ?? null;
|
|
306
442
|
}
|
|
443
|
+
/**
|
|
444
|
+
* Run an editor save's full repack with the section removals the editor's own
|
|
445
|
+
* edits made.
|
|
446
|
+
*
|
|
447
|
+
* A save refuses a package with fewer sections than its source unless it is
|
|
448
|
+
* told which removals were meant: deleting the paragraph that ends a section,
|
|
449
|
+
* or accepting its tracked deletion, removes that section on purpose. The
|
|
450
|
+
* tracker records exactly those removals; without them the repack throws and
|
|
451
|
+
* the edit cannot be saved.
|
|
452
|
+
*/
|
|
453
|
+
const repackWithEditorSectionRemovals = ({ state, document, repack }) => {
|
|
454
|
+
const resolution = getTrackedSectionEndpointRemoval(state);
|
|
455
|
+
return resolution === null ? repack() : withTrackedSectionEndpointRemoval({
|
|
456
|
+
document,
|
|
457
|
+
resolution,
|
|
458
|
+
repack
|
|
459
|
+
});
|
|
460
|
+
};
|
|
307
461
|
/** Record only a complete, internally consistent endpoint-removal transition. */
|
|
308
462
|
function markTrackedSectionEndpointRemoval(tr, { sourceDoc, removedEndpointCount, removedReferences }) {
|
|
309
463
|
const sourceStructure = countDocumentStructure(sourceDoc);
|
|
@@ -324,6 +478,23 @@ function markTrackedSectionEndpointRemoval(tr, { sourceDoc, removedEndpointCount
|
|
|
324
478
|
});
|
|
325
479
|
}
|
|
326
480
|
/**
|
|
481
|
+
* Record that `tr` removed section breaks on purpose: a command whose job is
|
|
482
|
+
* to remove the break (not to delete its paragraph mark, which the tracker
|
|
483
|
+
* reads for itself). Only a plain removal is recorded; a transaction that also
|
|
484
|
+
* adds or replaces a record is left as it is.
|
|
485
|
+
*/
|
|
486
|
+
function markSectionBreakRemoval(tr, sourceDoc) {
|
|
487
|
+
const before = countDocumentStructure(sourceDoc).sectionRecords;
|
|
488
|
+
const after = countDocumentStructure(tr.doc).sectionRecords;
|
|
489
|
+
const removed = [...before].filter((record) => !after.has(record));
|
|
490
|
+
if (removed.length === 0 || [...after].some((record) => !before.has(record))) return tr;
|
|
491
|
+
return markTrackedSectionEndpointRemoval(tr, {
|
|
492
|
+
sourceDoc,
|
|
493
|
+
removedEndpointCount: removed.length,
|
|
494
|
+
removedReferences: referencesOf(removed)
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
327
498
|
* Create a transaction that clears the change tracker
|
|
328
499
|
*/
|
|
329
500
|
function clearTrackedChanges(state) {
|
|
@@ -352,4 +523,4 @@ const ParagraphChangeTrackerExtension = createExtension({
|
|
|
352
523
|
}
|
|
353
524
|
});
|
|
354
525
|
//#endregion
|
|
355
|
-
export { ParagraphChangeTrackerExtension, clearTrackedChanges, getChangeTrackerState, getChangedParagraphIds, getTrackedSectionEndpointRemoval, hasStructuralChanges, hasUntrackedChanges, ignoreTrackedChanges, markChangedParagraphRanges, markStructuralChange, markTrackedSectionEndpointRemoval, paragraphChangeTrackerKey };
|
|
526
|
+
export { ParagraphChangeTrackerExtension, clearTrackedChanges, getChangeTrackerState, getChangedParagraphIds, getTrackedSectionEndpointRemoval, hasStructuralChanges, hasUntrackedChanges, ignoreTrackedChanges, markChangedParagraphRanges, markSectionBreakRemoval, markStructuralChange, markTrackedSectionEndpointRemoval, paragraphChangeTrackerKey, repackWithEditorSectionRemovals };
|
|
@@ -3,6 +3,7 @@ import { createExtension } from "../create.js";
|
|
|
3
3
|
import { Priority } from "../types.js";
|
|
4
4
|
import { cleanPastedHtml, removeUnpairedBookmarkBoundaries, removeUnpairedMoveRangeBoundaries } from "./pasteCleanup.js";
|
|
5
5
|
import { retargetPastedHeadingStyles } from "./pastedHeadingStyles.js";
|
|
6
|
+
import { flattenPastedHtmlLists, numberPastedHtmlLists } from "./pastedHtmlLists.js";
|
|
6
7
|
import { Plugin } from "prosemirror-state";
|
|
7
8
|
//#region src/prosemirror/extensions/features/PasteCleanupExtension.ts
|
|
8
9
|
/**
|
|
@@ -30,9 +31,9 @@ const PasteCleanupExtension = createExtension({
|
|
|
30
31
|
plugins: [new Plugin({ props: {
|
|
31
32
|
transformPastedHTML(html) {
|
|
32
33
|
const internalClipboardToken = options.getInternalClipboardToken?.();
|
|
33
|
-
return cleanPastedHtml(html, { ...internalClipboardToken ? { internalClipboardToken } : {} });
|
|
34
|
+
return flattenPastedHtmlLists(cleanPastedHtml(html, { ...internalClipboardToken ? { internalClipboardToken } : {} }));
|
|
34
35
|
},
|
|
35
|
-
transformPasted: (slice, view) => retargetPastedHeadingStyles(removeUnpairedMoveRangeBoundaries(removeUnpairedBookmarkBoundaries(slice)), view)
|
|
36
|
+
transformPasted: (slice, view) => numberPastedHtmlLists(retargetPastedHeadingStyles(removeUnpairedMoveRangeBoundaries(removeUnpairedBookmarkBoundaries(slice)), view), view)
|
|
36
37
|
} })],
|
|
37
38
|
keyboardShortcuts: { "Mod-Alt-v": pasteWithoutFormatting }
|
|
38
39
|
};
|
|
@@ -128,6 +128,7 @@ const BOOKMARK_BOUNDARY_ATTR = /\s+data-docx-bookmark-(?:boundary|id|name|col-fi
|
|
|
128
128
|
const RANGE_ANCHOR_ATTR = /\s+data-docx-range-anchor(?:="[^"]*"|='[^']*'|=[^\s>]+)?/gi;
|
|
129
129
|
const MOVE_RANGE_BOUNDARY_ATTR = /\s+data-docx-move-range-boundary(?:="[^"]*"|='[^']*'|=[^\s>]+)?/gi;
|
|
130
130
|
const STRUCTURED_FIELD_ATTR = /\s+data-field-structured(?:="[^"]*"|='[^']*'|=[^\s>]+)?/gi;
|
|
131
|
+
const FIELD_CODE_ATTR = /\s+data-field-code(?:="[^"]*"|'[^']*'|=[^\s>]+)?/gi;
|
|
131
132
|
/**
|
|
132
133
|
* Treat reconstruction attributes as internal only when the HTML carries the
|
|
133
134
|
* unguessable capability created with this editor schema. `data-pm-slice`
|
|
@@ -153,7 +154,7 @@ function stripForeignRangeCarriers(html, internal) {
|
|
|
153
154
|
}
|
|
154
155
|
function stripForeignStructuredFields(html, internal) {
|
|
155
156
|
if (internal) return html;
|
|
156
|
-
return html.replace(STRUCTURED_FIELD_ATTR, "");
|
|
157
|
+
return html.replace(STRUCTURED_FIELD_ATTR, "").replace(FIELD_CODE_ATTR, "");
|
|
157
158
|
}
|
|
158
159
|
/**
|
|
159
160
|
* Remove empty spans left behind after stripping `mso-*` styles. Only truly
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Slice } from "prosemirror-model";
|
|
2
|
+
import { EditorView } from "prosemirror-view";
|
|
3
|
+
//#region src/prosemirror/extensions/features/pastedHtmlLists.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Flatten only list containers. Other HTML remains in place for the normal
|
|
6
|
+
* clipboard parser, including tables and inline formatting inside list items.
|
|
7
|
+
*/
|
|
8
|
+
declare const flattenPastedHtmlLists: (html: string) => string;
|
|
9
|
+
/** Resolve clipboard-only list hints against fresh document numbering ids. */
|
|
10
|
+
declare const numberPastedHtmlLists: (slice: Slice, view: EditorView) => Slice;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { flattenPastedHtmlLists, numberPastedHtmlLists };
|