@stll/folio-core 0.52.0 → 0.54.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 +1779 -141
- package/dist/ai-edits/batch-claims.d.ts +145 -0
- package/dist/ai-edits/batch-claims.js +275 -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 +91 -7
- package/dist/ai-edits/headless.js +520 -51
- 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 +6 -4
- package/dist/ai-edits/read.js +113 -50
- package/dist/ai-edits/result-validation.d.ts +29 -0
- package/dist/ai-edits/result-validation.js +164 -0
- package/dist/ai-edits/revisionStretches.d.ts +17 -0
- package/dist/ai-edits/revisionStretches.js +80 -0
- package/dist/ai-edits/snapshot.d.ts +36 -3
- package/dist/ai-edits/snapshot.js +180 -25
- package/dist/ai-edits/table-cell-mutations.d.ts +4 -2
- package/dist/ai-edits/table-cell-mutations.js +6 -2
- package/dist/ai-edits/table-geometry.d.ts +1 -1
- package/dist/ai-edits/table-row-column-mutations.d.ts +44 -17
- package/dist/ai-edits/table-row-column-mutations.js +86 -34
- 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.d.ts +5 -1
- package/dist/compare/content-alignment.js +52 -34
- 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/inline-provenance.js +1 -1
- 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 +65 -11
- 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/archiveInflation.d.ts +127 -0
- package/dist/docx/archiveInflation.js +181 -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/metadataPrivacy.js +24 -1
- package/dist/docx/normalizeBaseDirection.js +2 -1
- package/dist/docx/noteReferenceMark.d.ts +15 -0
- package/dist/docx/noteReferenceMark.js +48 -0
- 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 +96 -27
- package/dist/docx/paragraphPropertySource.d.ts +4 -2
- package/dist/docx/paragraphPropertySource.js +10 -2
- package/dist/docx/paragraphTraversal.js +1 -0
- package/dist/docx/parseWarningMessage.js +4 -1
- package/dist/docx/parser.js +175 -22
- package/dist/docx/rezip.js +31 -7
- 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.d.ts +3 -1
- package/dist/docx/selectiveXmlPatch.js +186 -39
- 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/boundedArchive.d.ts +8 -13
- package/dist/docx/server/boundedArchive.js +70 -59
- package/dist/docx/server/createBilingualDocument.js +3 -3
- package/dist/docx/server/extractDocxText.d.ts +8 -2
- package/dist/docx/server/extractDocxText.js +2 -2
- package/dist/docx/server/validateDocxConformance.d.ts +1 -1
- package/dist/docx/server/validateDocxConformance.js +1 -0
- 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 +20 -2
- package/dist/docx/unzip.js +136 -25
- package/dist/docx/wordprocessingPrefixes.d.ts +78 -0
- package/dist/docx/wordprocessingPrefixes.js +286 -0
- package/dist/fonts/embeddedFonts.js +1 -1
- package/dist/i18n/messages/catalogs.gen.d.ts +170 -34
- package/dist/i18n/messages/catalogs.gen.js +187 -51
- package/dist/i18n/messages/messages.gen.d.ts +10 -2
- 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 +600 -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/measureParagraph.js +2 -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/measure/paragraphMeasureShared.d.ts +12 -1
- package/dist/layout-engine/measure/paragraphMeasureShared.js +14 -1
- 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/escape.d.ts +2 -2
- package/dist/markdown/escape.js +4 -5
- 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 +121 -25
- package/dist/markdown/renderParagraph.d.ts +13 -1
- package/dist/markdown/renderParagraph.js +85 -38
- package/dist/markdown/renderRuns.d.ts +10 -1
- package/dist/markdown/renderRuns.js +323 -69
- 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/clearRunColor.d.ts +6 -0
- package/dist/prosemirror/clearRunColor.js +46 -0
- package/dist/prosemirror/commands/comments.d.ts +7 -8
- package/dist/prosemirror/commands/comments.js +281 -212
- package/dist/prosemirror/commands/contentControls.d.ts +1 -1
- package/dist/prosemirror/commands/formatPainter.d.ts +1 -1
- package/dist/prosemirror/commands/formatPainter.js +1 -1
- package/dist/prosemirror/commands/formatting.d.ts +1 -1
- package/dist/prosemirror/commands/hyperlink.js +2 -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/propertyChangeScope.d.ts +3 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +24 -3
- package/dist/prosemirror/commands/resolveAllTableChanges.d.ts +40 -0
- package/dist/prosemirror/commands/resolveAllTableChanges.js +620 -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 +73 -0
- package/dist/prosemirror/commands/sectionBreak.js +2 -1
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +15 -2
- package/dist/prosemirror/commands/tableCellMergeResolution.js +23 -7
- package/dist/prosemirror/containerFinalParagraph.d.ts +11 -5
- package/dist/prosemirror/containerFinalParagraph.js +7 -6
- package/dist/prosemirror/contentControlRevisions.d.ts +1 -1
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
- package/dist/prosemirror/conversion/fromProseDoc.js +177 -605
- package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -11
- package/dist/prosemirror/conversion/toProseDoc.js +70 -154
- package/dist/prosemirror/documentSchema.d.ts +8 -0
- package/dist/prosemirror/documentSchema.js +18 -0
- 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 +5 -1
- package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +116 -63
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +4 -1
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +24 -3
- package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.d.ts +20 -0
- package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +43 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +167 -128
- 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/pastedHeadingStyles.js +1 -1
- package/dist/prosemirror/extensions/features/pastedHtmlLists.d.ts +12 -0
- package/dist/prosemirror/extensions/features/pastedHtmlLists.js +124 -0
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +33 -11
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +8 -4
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +21 -18
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +37 -17
- package/dist/prosemirror/extensions/marks/StrikeExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/SubscriptExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/SuperscriptExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +15 -8
- package/dist/prosemirror/extensions/marks/markUtils.js +25 -10
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +12 -0
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +46 -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/CommentReferenceExtension.js +2 -2
- package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +3 -3
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +50 -15
- package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +5 -3
- 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 +121 -226
- package/dist/prosemirror/extensions/types.d.ts +11 -1
- package/dist/prosemirror/findReplaceSelection.js +1 -1
- package/dist/prosemirror/hyperlinkRemoval.d.ts +9 -0
- package/dist/prosemirror/hyperlinkRemoval.js +129 -0
- package/dist/prosemirror/index.d.ts +5 -3
- package/dist/prosemirror/index.js +5 -3
- 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 +92 -0
- package/dist/prosemirror/listNumbering.js +330 -0
- package/dist/prosemirror/listRendering.d.ts +27 -0
- package/dist/prosemirror/listRendering.js +27 -0
- package/dist/prosemirror/listRenderingAttrs.d.ts +11 -2
- package/dist/prosemirror/listRenderingAttrs.js +8 -1
- package/dist/prosemirror/markupViewNotes.d.ts +8 -0
- package/dist/prosemirror/markupViewNotes.js +49 -0
- package/dist/prosemirror/markupViewProjection.d.ts +97 -0
- package/dist/prosemirror/markupViewProjection.js +88 -0
- package/dist/prosemirror/noteReferenceReview.d.ts +77 -0
- package/dist/prosemirror/noteReferenceReview.js +332 -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 +32 -7
- package/dist/prosemirror/paragraphMarkJoin.d.ts +21 -0
- package/dist/prosemirror/paragraphMarkJoin.js +26 -0
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +64 -0
- package/dist/prosemirror/paragraphPropertyCarry.js +158 -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/documentStyleState.d.ts +26 -0
- package/dist/prosemirror/plugins/documentStyleState.js +32 -0
- package/dist/prosemirror/plugins/documentStyles.d.ts +3 -13
- package/dist/prosemirror/plugins/documentStyles.js +67 -17
- package/dist/prosemirror/plugins/index.d.ts +2 -1
- package/dist/prosemirror/plugins/index.js +2 -1
- package/dist/prosemirror/plugins/paragraphStyleResolution.d.ts +15 -0
- package/dist/prosemirror/plugins/paragraphStyleResolution.js +230 -0
- package/dist/prosemirror/plugins/suggestionMode.d.ts +27 -3
- package/dist/prosemirror/plugins/suggestionMode.js +490 -63
- 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 +23 -3
- package/dist/prosemirror/rebaseParagraphRunFormatting.js +39 -13
- package/dist/prosemirror/rebaseParagraphRuns.d.ts +36 -0
- package/dist/prosemirror/rebaseParagraphRuns.js +99 -0
- 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/runFormattingFromMarks.d.ts +18 -0
- package/dist/prosemirror/runFormattingFromMarks.js +567 -0
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +1 -1
- package/dist/prosemirror/runFormattingReconciliation.js +10 -9
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/index.js +3 -0
- package/dist/prosemirror/schema/nodes.d.ts +44 -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/styles/paragraphStyleCascade.d.ts +59 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.js +145 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +21 -2
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +38 -1
- package/dist/prosemirror/styles/tableStyleRegions.d.ts +31 -0
- package/dist/prosemirror/styles/tableStyleRegions.js +55 -0
- package/dist/prosemirror/tableCellPaste.d.ts +74 -0
- package/dist/prosemirror/tableCellPaste.js +525 -0
- package/dist/prosemirror/tableGridMutation.d.ts +87 -2
- package/dist/prosemirror/tableGridMutation.js +255 -2
- package/dist/prosemirror/tableRunIn.d.ts +51 -0
- package/dist/prosemirror/tableRunIn.js +165 -0
- package/dist/prosemirror/textInput.js +11 -2
- package/dist/prosemirror/trackedRevisionPath.d.ts +17 -0
- package/dist/prosemirror/trackedRevisionPath.js +32 -0
- 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/server.d.ts +2 -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 +6 -5
- package/dist/internal/headlessRevisionResolution.d.ts +0 -23
|
@@ -1,11 +1,25 @@
|
|
|
1
|
+
import { expectParagraphAttrs, expectTrackedChangeMarkAttrs } from "../attrs/index.js";
|
|
2
|
+
import { paragraphPropertiesSnapshot } from "../commands/propertyChangeScope.js";
|
|
3
|
+
import { paragraphEndsItsContainer } from "../containerFinalParagraph.js";
|
|
1
4
|
import { encloseWholeControls } from "../contentControlRevisions.js";
|
|
2
5
|
import { splitBlockClearBorders } from "../extensions/features/BaseKeymapExtension.js";
|
|
6
|
+
import { JOINED_RUNS_RESTYLED_META } from "../extensions/features/JoinedRunStyleExtension.js";
|
|
7
|
+
import { expandNoteReferenceDeletionRange } from "../extensions/marks/noteReferenceDeletion.js";
|
|
8
|
+
import { carryParagraphProperties, paragraphLeftAfter, recordReplacedParagraphProperties } from "../paragraphPropertyCarry.js";
|
|
9
|
+
import { rebaseParagraphRuns } from "../rebaseParagraphRunFormatting.js";
|
|
10
|
+
import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
|
|
11
|
+
import { paragraphRunStyleContext } from "../runStyleFormatting.js";
|
|
12
|
+
import { cellPasteRange, pasteTableCells } from "../tableCellPaste.js";
|
|
3
13
|
import { handleEditorBeforeInput } from "../textInput.js";
|
|
4
14
|
import { canCarryTrackedRunMark } from "../trackedRunInlineAtoms.js";
|
|
15
|
+
import { getDocumentNumbering } from "./documentNumbering.js";
|
|
16
|
+
import { getDocumentStyleResolver } from "./documentStyleState.js";
|
|
5
17
|
import { mintRevisionId, seedRevisionIdsFromDoc } from "./revisionIds.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
18
|
+
import { Slice } from "prosemirror-model";
|
|
19
|
+
import { Mapping, ReplaceStep } from "prosemirror-transform";
|
|
20
|
+
import { AllSelection, Plugin, PluginKey, Selection, TextSelection } from "prosemirror-state";
|
|
8
21
|
import { isHistoryTransaction } from "prosemirror-history";
|
|
22
|
+
import { undoInputRule } from "prosemirror-inputrules";
|
|
9
23
|
//#region src/prosemirror/plugins/suggestionMode.ts
|
|
10
24
|
/**
|
|
11
25
|
* Suggestion Mode Plugin
|
|
@@ -22,6 +36,12 @@ import { isHistoryTransaction } from "prosemirror-history";
|
|
|
22
36
|
const suggestionModeKey = new PluginKey("suggestionMode");
|
|
23
37
|
const SUGGESTION_META = "suggestionModeApplied";
|
|
24
38
|
const SUGGESTION_BYPASS_META = "suggestionModeBypass";
|
|
39
|
+
/**
|
|
40
|
+
* The text a tracked text-input transaction typed. Rules that react to typing
|
|
41
|
+
* (list autoformat) read it, because this plugin claims text input before any
|
|
42
|
+
* input rule sees it.
|
|
43
|
+
*/
|
|
44
|
+
const SUGGESTED_TEXT_INPUT_META = "suggestionModeTextInput";
|
|
25
45
|
function makeMarkAttrs(pluginState) {
|
|
26
46
|
return {
|
|
27
47
|
revisionId: mintRevisionId(),
|
|
@@ -39,6 +59,27 @@ function makeRevisionInfo(state) {
|
|
|
39
59
|
date: attrs.date
|
|
40
60
|
};
|
|
41
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* A removed paragraph mark leaves the paragraph after it once accepted. An
|
|
64
|
+
* edit that reads as the paragraph before it (Backspace or Delete at the
|
|
65
|
+
* break, a deletion running from inside one paragraph into another) gives the
|
|
66
|
+
* paragraph left that paragraph's properties now, under the mark's revision:
|
|
67
|
+
* accepting reads as the edit made directly, rejecting restores its own.
|
|
68
|
+
*/
|
|
69
|
+
function carryIntoParagraphLeft(state, tr, source, survivorPos, info) {
|
|
70
|
+
carryParagraphProperties({
|
|
71
|
+
tr,
|
|
72
|
+
position: survivorPos,
|
|
73
|
+
source,
|
|
74
|
+
styleResolver: getDocumentStyleResolver(state),
|
|
75
|
+
numbering: getDocumentNumbering(state),
|
|
76
|
+
revision: {
|
|
77
|
+
id: info.id,
|
|
78
|
+
author: info.author ?? "",
|
|
79
|
+
date: info.date ?? ""
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
42
83
|
function makeParagraphMarkInfo(pluginState) {
|
|
43
84
|
const attrs = makeMarkAttrs(pluginState);
|
|
44
85
|
return {
|
|
@@ -69,10 +110,11 @@ function findAdjacentRevisionForRange(doc, from, to, markTypeName, author) {
|
|
|
69
110
|
return findAdjacentRevision(doc, from, markTypeName, author) ?? findAdjacentRevision(doc, to, markTypeName, author);
|
|
70
111
|
}
|
|
71
112
|
/**
|
|
72
|
-
* Walk a
|
|
113
|
+
* Walk a selected range and track its text, paragraph breaks, and table rows.
|
|
114
|
+
* Retract the current author's own inserted text.
|
|
73
115
|
* Processes in reverse order to maintain position validity.
|
|
74
116
|
*/
|
|
75
|
-
function markRangeAsDeleted(tr, doc, from, to, insertionType, deletionType, pluginState) {
|
|
117
|
+
function markRangeAsDeleted(tr, doc, from, to, insertionType, deletionType, pluginState, joinState) {
|
|
76
118
|
const ranges = [];
|
|
77
119
|
doc.nodesBetween(from, to, (node, pos) => {
|
|
78
120
|
if (!canCarryTrackedRunMark(node)) return;
|
|
@@ -87,12 +129,44 @@ function markRangeAsDeleted(tr, doc, from, to, insertionType, deletionType, plug
|
|
|
87
129
|
isOwnInsert
|
|
88
130
|
});
|
|
89
131
|
});
|
|
90
|
-
if (ranges.length === 0) return;
|
|
91
132
|
const delAttrs = findAdjacentRevisionForRange(doc, from, to, "deletion", pluginState.author) || makeMarkAttrs(pluginState);
|
|
133
|
+
let removedMark = false;
|
|
134
|
+
doc.nodesBetween(from, to, (node, pos) => {
|
|
135
|
+
if (node.type.name === "tableRow" && pos >= from && pos + node.nodeSize <= to && node.attrs["trIns"] == null && node.attrs["trDel"] == null) tr.setNodeAttribute(pos, "trDel", delAttrs);
|
|
136
|
+
if (node.type.name !== "paragraph") return;
|
|
137
|
+
const boundary = pos + node.nodeSize;
|
|
138
|
+
if (boundary > from && boundary <= to && node.attrs["pPrMark"] == null) {
|
|
139
|
+
tr.setNodeAttribute(pos, "pPrMark", {
|
|
140
|
+
kind: "del",
|
|
141
|
+
info: {
|
|
142
|
+
id: delAttrs.revisionId,
|
|
143
|
+
author: delAttrs.author,
|
|
144
|
+
date: delAttrs.date
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
removedMark = true;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
const $first = doc.resolve(from);
|
|
151
|
+
const $last = doc.resolve(to);
|
|
152
|
+
if (joinState && removedMark && $first.parent.type.name === "paragraph" && $last.parent.type.name === "paragraph" && $first.parent !== $last.parent && from > $first.start()) {
|
|
153
|
+
const lastPos = doc === tr.doc ? $last.before() : tr.mapping.map($last.before());
|
|
154
|
+
const lastMark = tr.doc.nodeAt(lastPos)?.attrs["pPrMark"];
|
|
155
|
+
const survivorPos = lastMark?.kind === "del" || lastMark?.kind === "moveFrom" ? paragraphLeftAfter({
|
|
156
|
+
doc: tr.doc,
|
|
157
|
+
paragraphPos: lastPos
|
|
158
|
+
}) ?? lastPos : lastPos;
|
|
159
|
+
carryIntoParagraphLeft(joinState, tr, $first.parent, survivorPos, {
|
|
160
|
+
id: delAttrs.revisionId,
|
|
161
|
+
author: delAttrs.author,
|
|
162
|
+
date: delAttrs.date
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (ranges.length === 0) return;
|
|
92
166
|
encloseWholeControls({
|
|
93
167
|
tr,
|
|
94
|
-
from
|
|
95
|
-
to
|
|
168
|
+
from,
|
|
169
|
+
to,
|
|
96
170
|
revisionId: delAttrs.revisionId
|
|
97
171
|
});
|
|
98
172
|
for (let i = ranges.length - 1; i >= 0; i--) {
|
|
@@ -101,10 +175,26 @@ function markRangeAsDeleted(tr, doc, from, to, insertionType, deletionType, plug
|
|
|
101
175
|
else tr.addMark(range.from, range.to, deletionType.create(delAttrs));
|
|
102
176
|
}
|
|
103
177
|
}
|
|
178
|
+
/** Preserve clipboard revisions inside the revision that inserted their content. */
|
|
179
|
+
function enclosePastedRunRevisions({ tr, from, to, revision: insertion }) {
|
|
180
|
+
tr.doc.nodesBetween(from, to, (node, pos) => {
|
|
181
|
+
if (!canCarryTrackedRunMark(node)) return;
|
|
182
|
+
const revision = node.marks.find(({ type }) => type.name === "insertion" || type.name === "deletion");
|
|
183
|
+
if (!revision) return;
|
|
184
|
+
const previous = expectTrackedChangeMarkAttrs(revision);
|
|
185
|
+
tr.addMark(Math.max(from, pos), Math.min(to, pos + node.nodeSize), revision.type.create({
|
|
186
|
+
...revision.attrs,
|
|
187
|
+
_docxRevisionAncestors: [{
|
|
188
|
+
type: "insertion",
|
|
189
|
+
...insertion,
|
|
190
|
+
outerWrapperCount: 0
|
|
191
|
+
}, ...previous._docxRevisionAncestors ?? []]
|
|
192
|
+
}));
|
|
193
|
+
});
|
|
194
|
+
}
|
|
104
195
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* left untouched so another author's attribution is not overwritten.
|
|
196
|
+
* Track every inserted run, paragraph break, and table row in `[from, to)`.
|
|
197
|
+
* Content already carrying a revision keeps its attribution.
|
|
108
198
|
*/
|
|
109
199
|
function markRangeAsInserted(tr, doc, from, to, insertionType, deletionType, attrs) {
|
|
110
200
|
doc.nodesBetween(from, to, (node, pos) => {
|
|
@@ -115,6 +205,23 @@ function markRangeAsInserted(tr, doc, from, to, insertionType, deletionType, att
|
|
|
115
205
|
if (start >= end) return;
|
|
116
206
|
tr.addMark(start, end, insertionType.create(attrs));
|
|
117
207
|
});
|
|
208
|
+
const $end = doc.resolve(to);
|
|
209
|
+
const endsBetweenBlocks = !$end.parent.isTextblock && $end.nodeBefore !== null && $end.nodeBefore.type.name !== "paragraph";
|
|
210
|
+
doc.nodesBetween(from, to, (node, pos) => {
|
|
211
|
+
if (node.type.name === "paragraph") {
|
|
212
|
+
const boundary = pos + node.nodeSize;
|
|
213
|
+
const keepsOwnMark = endsBetweenBlocks && boundary - 1 === from;
|
|
214
|
+
if (boundary > from && boundary < to && !keepsOwnMark && node.attrs["pPrMark"] == null) tr.setNodeAttribute(pos, "pPrMark", {
|
|
215
|
+
kind: "ins",
|
|
216
|
+
info: {
|
|
217
|
+
id: attrs.revisionId,
|
|
218
|
+
author: attrs.author,
|
|
219
|
+
date: attrs.date
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (node.type.name === "tableRow" && pos >= from && pos + node.nodeSize <= to && node.attrs["trIns"] == null && node.attrs["trDel"] == null) tr.setNodeAttribute(pos, "trIns", attrs);
|
|
224
|
+
});
|
|
118
225
|
encloseWholeControls({
|
|
119
226
|
tr,
|
|
120
227
|
from,
|
|
@@ -126,32 +233,221 @@ function markRangeAsInserted(tr, doc, from, to, insertionType, deletionType, att
|
|
|
126
233
|
* With track changes on, pasting over a non-empty text selection marks the
|
|
127
234
|
* replaced text as a tracked deletion and the pasted slice as a tracked
|
|
128
235
|
* insertion (so they read as one replacement), matching typing over a
|
|
129
|
-
* selection.
|
|
236
|
+
* selection. Select-all (an `AllSelection`) counts as a text selection over the
|
|
237
|
+
* whole document. Returns false for a collapsed cursor or another selection so the
|
|
130
238
|
* default paste + the `appendTransaction` catch-all marks a plain insertion
|
|
131
239
|
* (eigenpal/docx-editor#784).
|
|
132
240
|
*/
|
|
133
241
|
function handleSuggestionPaste(view, slice, pluginState) {
|
|
134
242
|
const { selection } = view.state;
|
|
135
|
-
|
|
243
|
+
const selectsAll = selection instanceof AllSelection;
|
|
244
|
+
if (!(selection instanceof TextSelection || selectsAll) || selection.empty) return false;
|
|
136
245
|
const insertionType = view.state.schema.marks["insertion"];
|
|
137
246
|
const deletionType = view.state.schema.marks["deletion"];
|
|
138
247
|
if (!insertionType || !deletionType) return false;
|
|
139
|
-
|
|
248
|
+
if (selectsAll && (slice.openStart > 0 || slice.openEnd > 0)) slice = new Slice(view.state.tr.replaceSelection(slice).doc.content, 0, 0);
|
|
249
|
+
const { from, to } = selectsAll ? {
|
|
250
|
+
from: Selection.atStart(view.state.doc).from,
|
|
251
|
+
to: Selection.atEnd(view.state.doc).to
|
|
252
|
+
} : selection;
|
|
140
253
|
const tr = view.state.tr;
|
|
141
254
|
tr.setMeta(SUGGESTION_META, true);
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
const
|
|
255
|
+
const { doc } = view.state;
|
|
256
|
+
const $from = doc.resolve(from);
|
|
257
|
+
const $to = doc.resolve(to);
|
|
258
|
+
const closedBlocks = slice.openStart === 0 && slice.content.firstChild?.isBlock === true;
|
|
259
|
+
const beforeStruck = closedBlocks && $from.parent.isTextblock && $from.parentOffset === 0;
|
|
260
|
+
const wholeBlocks = beforeStruck && $to.parent.isTextblock && $to.parentOffset === $to.parent.content.size;
|
|
261
|
+
const endsContainer = wholeBlocks && paragraphEndsItsContainer(doc.resolve($to.before()), $to.parent.type.name);
|
|
262
|
+
const rotates = endsContainer && slice.content.firstChild?.type === $to.parent.type && slice.content.lastChild?.type === $to.parent.type;
|
|
263
|
+
const tableFirst = endsContainer && !rotates;
|
|
264
|
+
if (!tableFirst) markRangeAsDeleted(tr, doc, from, wholeBlocks && !endsContainer ? $to.after() : to, insertionType, deletionType, pluginState);
|
|
265
|
+
const carryAcross = () => {
|
|
266
|
+
if (selectsAll || $from.parent.type.name !== "paragraph" || $from.parent === $to.parent || from <= $from.start()) return;
|
|
267
|
+
const firstPos = tr.mapping.map($from.before());
|
|
268
|
+
const mark = tr.doc.nodeAt(firstPos)?.attrs["pPrMark"];
|
|
269
|
+
const survivorPos = paragraphLeftAfter({
|
|
270
|
+
doc: tr.doc,
|
|
271
|
+
paragraphPos: firstPos
|
|
272
|
+
});
|
|
273
|
+
if (mark?.kind === "del" && survivorPos !== null) carryIntoParagraphLeft(view.state, tr, $from.parent, survivorPos, mark.info);
|
|
274
|
+
};
|
|
275
|
+
const inlineSlice = slice.content.firstChild?.isInline === true;
|
|
276
|
+
if (inlineSlice) carryAcross();
|
|
277
|
+
let at = tr.mapping.map(to);
|
|
278
|
+
if (rotates) at = tr.mapping.map($to.after());
|
|
279
|
+
else if (tableFirst) at = $from.before();
|
|
280
|
+
else if (beforeStruck) at = tr.mapping.map(from, -1);
|
|
281
|
+
const firstStep = tr.steps.length;
|
|
282
|
+
tr.replaceRange(at, at, slice);
|
|
283
|
+
const placed = tr.steps.slice(firstStep).flatMap((step, offset) => {
|
|
284
|
+
const later = new Mapping(tr.mapping.maps.slice(firstStep + offset + 1));
|
|
285
|
+
const ranges = [];
|
|
286
|
+
step.getMap().forEach((_oldFrom, _oldTo, newFrom, newTo) => {
|
|
287
|
+
ranges.push({
|
|
288
|
+
from: later.map(newFrom, -1),
|
|
289
|
+
to: later.map(newTo, 1)
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
return ranges;
|
|
293
|
+
});
|
|
294
|
+
let insertFrom = placed.length === 0 ? at : Math.min(...placed.map((range) => range.from));
|
|
295
|
+
let insertTo = placed.length === 0 ? at : Math.max(...placed.map((range) => range.to));
|
|
296
|
+
if (tableFirst) {
|
|
297
|
+
const struck = tr.steps.length;
|
|
298
|
+
markRangeAsDeleted(tr, tr.doc, tr.mapping.map(from), tr.mapping.map(to), insertionType, deletionType, pluginState);
|
|
299
|
+
const since = tr.mapping.slice(struck);
|
|
300
|
+
insertFrom = since.map(insertFrom, -1);
|
|
301
|
+
insertTo = since.map(insertTo, -1);
|
|
302
|
+
}
|
|
303
|
+
const insertAttrs = findAdjacentRevision(doc, from, "insertion", pluginState.author) || makeMarkAttrs(pluginState);
|
|
304
|
+
enclosePastedRunRevisions({
|
|
305
|
+
tr,
|
|
306
|
+
from: insertFrom,
|
|
307
|
+
to: insertTo,
|
|
308
|
+
revision: insertAttrs
|
|
309
|
+
});
|
|
149
310
|
markRangeAsInserted(tr, tr.doc, insertFrom, insertTo, insertionType, deletionType, insertAttrs);
|
|
311
|
+
if (!inlineSlice) carryAcross();
|
|
312
|
+
if (!closedBlocks && $to.parent.type.name === "paragraph") {
|
|
313
|
+
const $end = tr.doc.resolve(tr.mapping.map(to));
|
|
314
|
+
if ($end.parent.type.name === "paragraph" && $end.before() !== tr.mapping.map($from.before())) recordReplacedParagraphProperties({
|
|
315
|
+
tr,
|
|
316
|
+
position: $end.before(),
|
|
317
|
+
replaced: $to.parent,
|
|
318
|
+
revision: {
|
|
319
|
+
id: insertAttrs.revisionId,
|
|
320
|
+
author: insertAttrs.author,
|
|
321
|
+
date: insertAttrs.date
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
const firstPasted = slice.content.firstChild;
|
|
326
|
+
if (selectsAll && !closedBlocks && firstPasted?.type.name === "paragraph") {
|
|
327
|
+
const $first = tr.doc.resolve(insertFrom);
|
|
328
|
+
if ($first.parent.type.name === "paragraph") carryParagraphProperties({
|
|
329
|
+
tr,
|
|
330
|
+
position: $first.before(),
|
|
331
|
+
source: firstPasted,
|
|
332
|
+
revision: {
|
|
333
|
+
id: insertAttrs.revisionId,
|
|
334
|
+
author: insertAttrs.author,
|
|
335
|
+
date: insertAttrs.date
|
|
336
|
+
},
|
|
337
|
+
styleResolver: getDocumentStyleResolver(view.state),
|
|
338
|
+
numbering: getDocumentNumbering(view.state)
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
if (rotates) {
|
|
342
|
+
const rotation = tr.steps.length;
|
|
343
|
+
const joined = rotateIntoFinalParagraph(view.state, tr, tr.mapping.map($to.before()), insertAttrs);
|
|
344
|
+
insertFrom = Math.min(tr.mapping.slice(rotation).map(insertFrom, -1), joined);
|
|
345
|
+
insertTo = tr.mapping.slice(rotation).map(insertTo);
|
|
346
|
+
}
|
|
150
347
|
tr.setSelection(TextSelection.near(tr.doc.resolve(insertTo)));
|
|
151
348
|
view.dispatch(tr.scrollIntoView());
|
|
152
349
|
return true;
|
|
153
350
|
}
|
|
154
351
|
/**
|
|
352
|
+
* With track changes on, a paste into a table's cells (a cell selection, or a
|
|
353
|
+
* block of copied cells) replaces each cell's content the way a paste over a
|
|
354
|
+
* text selection does: the old content struck through, the pasted content
|
|
355
|
+
* after it as an insertion. When the pasted content is whole paragraphs, the
|
|
356
|
+
* last one ends the cell, so its paragraph mark is tracked as added too:
|
|
357
|
+
* rejecting then drops it and accepting joins the struck paragraphs into it.
|
|
358
|
+
*/
|
|
359
|
+
function handleSuggestionTableCellPaste(view, slice, pluginState) {
|
|
360
|
+
const insertionType = view.state.schema.marks["insertion"];
|
|
361
|
+
const deletionType = view.state.schema.marks["deletion"];
|
|
362
|
+
if (!insertionType || !deletionType) return false;
|
|
363
|
+
const revision = makeMarkAttrs(pluginState);
|
|
364
|
+
return pasteTableCells(view.state, slice, (tr) => view.dispatch(tr.setMeta(SUGGESTION_META, true)), {
|
|
365
|
+
revision,
|
|
366
|
+
replaceCellContent: (tr, cellPos, content) => {
|
|
367
|
+
const cell = tr.doc.nodeAt(cellPos);
|
|
368
|
+
if (!cell) return;
|
|
369
|
+
const { from, to } = cellPasteRange(cell, cellPos, content);
|
|
370
|
+
const mapFrom = tr.mapping.maps.length;
|
|
371
|
+
markRangeAsDeleted(tr, tr.doc, from, to, insertionType, deletionType, pluginState);
|
|
372
|
+
const insertFrom = tr.mapping.slice(mapFrom).map(to);
|
|
373
|
+
const sizeBefore = tr.doc.content.size;
|
|
374
|
+
tr.replaceRange(insertFrom, insertFrom, content);
|
|
375
|
+
const insertTo = insertFrom + (tr.doc.content.size - sizeBefore);
|
|
376
|
+
enclosePastedRunRevisions({
|
|
377
|
+
tr,
|
|
378
|
+
from: insertFrom,
|
|
379
|
+
to: insertTo,
|
|
380
|
+
revision
|
|
381
|
+
});
|
|
382
|
+
markRangeAsInserted(tr, tr.doc, insertFrom, insertTo, insertionType, deletionType, revision);
|
|
383
|
+
tr.doc.nodesBetween(insertFrom, insertTo, (node, pos) => {
|
|
384
|
+
if (node.type.name === "paragraph" && pos >= insertFrom && pos + node.nodeSize <= insertTo && node.attrs["pPrMark"] == null) tr.setNodeAttribute(pos, "pPrMark", {
|
|
385
|
+
kind: "ins",
|
|
386
|
+
info: {
|
|
387
|
+
id: revision.revisionId,
|
|
388
|
+
author: revision.author,
|
|
389
|
+
date: revision.date
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Pasted paragraphs replaced a container's last paragraph. They were placed
|
|
398
|
+
* after it, and the paragraph was struck but keeps its mark, as a container's
|
|
399
|
+
* last paragraph must. Join the first pasted paragraph onto it, so the struck
|
|
400
|
+
* text and the first paste share one paragraph whose break is the inserted one,
|
|
401
|
+
* and record the replaced paragraph's formatting on the paragraph that now ends
|
|
402
|
+
* the container: accepting leaves only the paste, and rejecting closes every
|
|
403
|
+
* pasted break back into one paragraph that returns to its old formatting.
|
|
404
|
+
* Returns the position of the joined paragraph.
|
|
405
|
+
*/
|
|
406
|
+
function rotateIntoFinalParagraph(state, tr, replacedPos, attrs) {
|
|
407
|
+
const replaced = tr.doc.nodeAt(replacedPos);
|
|
408
|
+
const first = replaced ? tr.doc.nodeAt(replacedPos + replaced.nodeSize) : null;
|
|
409
|
+
if (!replaced || !first) return replacedPos;
|
|
410
|
+
const replacedAttrs = expectParagraphAttrs(replaced);
|
|
411
|
+
const previousFormatting = {
|
|
412
|
+
...paragraphPropertiesSnapshot(replaced),
|
|
413
|
+
numPr: replacedAttrs.numPr ?? null
|
|
414
|
+
};
|
|
415
|
+
const { _sectionProperties: sectionProperties } = replaced.attrs;
|
|
416
|
+
tr.join(replacedPos + replaced.nodeSize);
|
|
417
|
+
tr.setNodeMarkup(replacedPos, void 0, first.attrs);
|
|
418
|
+
const styleResolver = getDocumentStyleResolver(state);
|
|
419
|
+
if (styleResolver && replaced.content.size > 0) rebaseParagraphRuns({
|
|
420
|
+
previousContext: paragraphRunStyleContext(replaced, styleResolver),
|
|
421
|
+
paragraphPosition: replacedPos,
|
|
422
|
+
range: {
|
|
423
|
+
from: 0,
|
|
424
|
+
to: replaced.content.size
|
|
425
|
+
},
|
|
426
|
+
styleResolver,
|
|
427
|
+
tr
|
|
428
|
+
});
|
|
429
|
+
const $joined = tr.doc.resolve(replacedPos);
|
|
430
|
+
const container = $joined.parent;
|
|
431
|
+
let finalPos = replacedPos;
|
|
432
|
+
for (let index = $joined.index(); index < container.childCount - 1; index += 1) finalPos += container.child(index).nodeSize;
|
|
433
|
+
const final = tr.doc.nodeAt(finalPos);
|
|
434
|
+
if (final) tr.setNodeMarkup(finalPos, void 0, {
|
|
435
|
+
...final.attrs,
|
|
436
|
+
pPrMark: null,
|
|
437
|
+
...sectionProperties == null ? {} : { _sectionProperties: sectionProperties },
|
|
438
|
+
_propertyChanges: [{
|
|
439
|
+
type: "paragraphPropertyChange",
|
|
440
|
+
info: {
|
|
441
|
+
id: attrs.revisionId,
|
|
442
|
+
author: attrs.author,
|
|
443
|
+
date: attrs.date
|
|
444
|
+
},
|
|
445
|
+
previousFormatting
|
|
446
|
+
}]
|
|
447
|
+
});
|
|
448
|
+
return replacedPos;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
155
451
|
* Insert text as a tracked insertion, optionally marking replaced selection as deletion.
|
|
156
452
|
*/
|
|
157
453
|
function applySuggestionInsert(view, from, to, text, pluginState) {
|
|
@@ -159,20 +455,79 @@ function applySuggestionInsert(view, from, to, text, pluginState) {
|
|
|
159
455
|
if (!insertionType) return false;
|
|
160
456
|
const tr = view.state.tr;
|
|
161
457
|
tr.setMeta(SUGGESTION_META, true);
|
|
458
|
+
tr.setMeta(SUGGESTED_TEXT_INPUT_META, text);
|
|
459
|
+
const selectsAll = view.state.selection instanceof AllSelection;
|
|
460
|
+
if (selectsAll) {
|
|
461
|
+
from = Math.max(from, Selection.atStart(view.state.doc).from);
|
|
462
|
+
to = Math.min(to, Selection.atEnd(view.state.doc).to);
|
|
463
|
+
}
|
|
464
|
+
const replacedFormatting = selectsAll ? (view.state.doc.resolve(from).nodeAfter?.marks ?? []).filter(({ type }) => RUN_FORMATTING_MARK_NAMES.has(type.name)) : null;
|
|
162
465
|
const insertAttrs = findAdjacentRevision(view.state.doc, from, "insertion", pluginState.author) || makeMarkAttrs(pluginState);
|
|
163
466
|
if (from !== to) {
|
|
164
467
|
const deletionType = view.state.schema.marks["deletion"];
|
|
165
|
-
if (deletionType) markRangeAsDeleted(tr, view.state.doc, from, to, insertionType, deletionType, pluginState);
|
|
468
|
+
if (deletionType) markRangeAsDeleted(tr, view.state.doc, from, to, insertionType, deletionType, pluginState, view.state);
|
|
166
469
|
}
|
|
167
470
|
const insertAt = tr.mapping.map(to);
|
|
168
471
|
tr.insertText(text, insertAt, insertAt);
|
|
169
472
|
const deletionType = view.state.schema.marks["deletion"];
|
|
170
473
|
if (deletionType) tr.removeMark(insertAt, insertAt + text.length, deletionType);
|
|
171
474
|
tr.addMark(insertAt, insertAt + text.length, insertionType.create(insertAttrs));
|
|
475
|
+
if (replacedFormatting) {
|
|
476
|
+
for (const mark of tr.doc.resolve(insertAt).nodeAfter?.marks ?? []) if (RUN_FORMATTING_MARK_NAMES.has(mark.type.name)) tr.removeMark(insertAt, insertAt + text.length, mark.type);
|
|
477
|
+
for (const mark of replacedFormatting) tr.addMark(insertAt, insertAt + text.length, mark);
|
|
478
|
+
}
|
|
479
|
+
separateSplitStretch(tr, insertAt, insertAt + text.length, insertAttrs.revisionId);
|
|
480
|
+
if (view.state.selection instanceof AllSelection) tr.setSelection(TextSelection.create(tr.doc, insertAt + text.length));
|
|
172
481
|
view.dispatch(tr.scrollIntoView());
|
|
173
482
|
return true;
|
|
174
483
|
}
|
|
175
484
|
/**
|
|
485
|
+
* Text typed inside another revision leaves that revision in two stretches.
|
|
486
|
+
* A saved package writes each stretch as a wrapper of its own with its own
|
|
487
|
+
* `w:id`, so the stretch after the typed text gets a fresh id now: the editor
|
|
488
|
+
* lists, resolves and saves the same changes a reopened package does.
|
|
489
|
+
*/
|
|
490
|
+
function separateSplitStretch(tr, from, to, typedId) {
|
|
491
|
+
const $from = tr.doc.resolve(from);
|
|
492
|
+
const $to = tr.doc.resolve(to);
|
|
493
|
+
const before = $from.nodeBefore;
|
|
494
|
+
if (!before || $to.parent !== $from.parent) return;
|
|
495
|
+
const parent = $to.parent;
|
|
496
|
+
const start = $to.start();
|
|
497
|
+
for (const mark of before.marks) {
|
|
498
|
+
if (mark.type.name !== "insertion" && mark.type.name !== "deletion") continue;
|
|
499
|
+
const revisionId = mark.attrs["revisionId"];
|
|
500
|
+
if (revisionId === typedId || typeof revisionId !== "number") continue;
|
|
501
|
+
let end = to;
|
|
502
|
+
let offset = to - start;
|
|
503
|
+
while (offset < parent.content.size) {
|
|
504
|
+
const child = parent.childAfter(offset).node;
|
|
505
|
+
if (!child?.marks.some((candidate) => candidate.eq(mark))) break;
|
|
506
|
+
offset += child.nodeSize;
|
|
507
|
+
end = start + offset;
|
|
508
|
+
}
|
|
509
|
+
if (end === to) continue;
|
|
510
|
+
tr.removeMark(to, end, mark);
|
|
511
|
+
tr.addMark(to, end, mark.type.create({
|
|
512
|
+
...mark.attrs,
|
|
513
|
+
revisionId: mintRevisionId()
|
|
514
|
+
}));
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Remove `from`..`to` of `tr.doc` as a suggestion: text the current author
|
|
519
|
+
* inserted is retracted, anything else is marked deleted. `false` when the
|
|
520
|
+
* editor is not suggesting.
|
|
521
|
+
*/
|
|
522
|
+
function suggestRangeDeletion(state, tr, from, to) {
|
|
523
|
+
const pluginState = suggestionModeKey.getState(state);
|
|
524
|
+
const insertionType = state.schema.marks["insertion"];
|
|
525
|
+
const deletionType = state.schema.marks["deletion"];
|
|
526
|
+
if (!pluginState?.active || !insertionType || !deletionType) return false;
|
|
527
|
+
markRangeAsDeleted(tr, tr.doc, from, to, insertionType, deletionType, pluginState);
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
176
531
|
* Track-changes Enter: split the paragraph and stamp `pPrMark = 'ins'` on the
|
|
177
532
|
* FIRST half of the split (the upper paragraph), per ECMA-376 §17.13.5. The
|
|
178
533
|
* actual splitting reuses `splitBlockClearBorders` so border/style/stored-mark
|
|
@@ -198,6 +553,13 @@ function handleSuggestionEnter(view, pluginState) {
|
|
|
198
553
|
info: makeParagraphMarkInfo(pluginState)
|
|
199
554
|
};
|
|
200
555
|
tr.setNodeAttribute(sourcePos, "pPrMark", markInfo);
|
|
556
|
+
const $caret = tr.selection.$from;
|
|
557
|
+
if ($caret.parent.type.name === "paragraph" && $caret.before() !== sourcePos) recordReplacedParagraphProperties({
|
|
558
|
+
tr,
|
|
559
|
+
position: $caret.before(),
|
|
560
|
+
replaced: $from.parent,
|
|
561
|
+
revision: markInfo.info
|
|
562
|
+
});
|
|
201
563
|
}
|
|
202
564
|
}
|
|
203
565
|
view.dispatch(tr.scrollIntoView());
|
|
@@ -251,9 +613,22 @@ function applyPPrDel(view, targetParagraphPos, pluginState) {
|
|
|
251
613
|
const tr = view.state.tr;
|
|
252
614
|
tr.setMeta(SUGGESTION_META, true);
|
|
253
615
|
const joinPos = targetParagraphPos + targetNode.nodeSize;
|
|
616
|
+
const joined = view.state.doc.nodeAt(joinPos);
|
|
254
617
|
try {
|
|
255
618
|
tr.join(joinPos);
|
|
256
619
|
tr.setNodeAttribute(targetParagraphPos, "pPrMark", null);
|
|
620
|
+
const styleResolver = getDocumentStyleResolver(view.state);
|
|
621
|
+
if (styleResolver && joined?.type === targetNode.type && joined.content.size > 0) rebaseParagraphRuns({
|
|
622
|
+
previousContext: paragraphRunStyleContext(joined, styleResolver),
|
|
623
|
+
paragraphPosition: targetParagraphPos,
|
|
624
|
+
range: {
|
|
625
|
+
from: targetNode.content.size,
|
|
626
|
+
to: targetNode.content.size + joined.content.size
|
|
627
|
+
},
|
|
628
|
+
styleResolver,
|
|
629
|
+
tr
|
|
630
|
+
});
|
|
631
|
+
tr.setMeta(JOINED_RUNS_RESTYLED_META, true);
|
|
257
632
|
view.dispatch(tr.scrollIntoView());
|
|
258
633
|
} catch {
|
|
259
634
|
return true;
|
|
@@ -268,6 +643,10 @@ function applyPPrDel(view, targetParagraphPos, pluginState) {
|
|
|
268
643
|
info: makeParagraphMarkInfo(pluginState)
|
|
269
644
|
};
|
|
270
645
|
tr.setNodeAttribute(targetParagraphPos, "pPrMark", markInfo);
|
|
646
|
+
carryIntoParagraphLeft(view.state, tr, targetNode, paragraphLeftAfter({
|
|
647
|
+
doc: tr.doc,
|
|
648
|
+
paragraphPos: targetParagraphPos
|
|
649
|
+
}) ?? targetParagraphPos + targetNode.nodeSize, markInfo.info);
|
|
271
650
|
view.dispatch(tr.scrollIntoView());
|
|
272
651
|
return true;
|
|
273
652
|
}
|
|
@@ -291,7 +670,11 @@ function handleSuggestionDelete(state, dispatch, direction) {
|
|
|
291
670
|
const tr = state.tr;
|
|
292
671
|
tr.setMeta(SUGGESTION_META, true);
|
|
293
672
|
if (!empty) {
|
|
294
|
-
|
|
673
|
+
const ranges = state.selection.ranges.map(({ $from: rangeFrom, $to: rangeTo }) => expandNoteReferenceDeletionRange(state.doc, rangeFrom.pos, rangeTo.pos) ?? {
|
|
674
|
+
from: rangeFrom.pos,
|
|
675
|
+
to: rangeTo.pos
|
|
676
|
+
}).sort((a, b) => b.from - a.from);
|
|
677
|
+
for (const { from, to } of ranges) markRangeAsDeleted(tr, state.doc, from, to, insertionType, deletionType, pluginState, state);
|
|
295
678
|
const cursorPos = tr.mapping.map($to.pos);
|
|
296
679
|
tr.setSelection(TextSelection.near(tr.doc.resolve(cursorPos)));
|
|
297
680
|
dispatch(tr.scrollIntoView());
|
|
@@ -301,22 +684,27 @@ function handleSuggestionDelete(state, dispatch, direction) {
|
|
|
301
684
|
const deletePos = isBackward ? $from.pos - 1 : $from.pos;
|
|
302
685
|
const deleteEnd = isBackward ? $from.pos : $from.pos + 1;
|
|
303
686
|
if (deletePos < 0 || deleteEnd > state.doc.content.size) return true;
|
|
304
|
-
const
|
|
687
|
+
const noteRange = expandNoteReferenceDeletionRange(state.doc, deletePos, deleteEnd);
|
|
688
|
+
const rangeFrom = noteRange?.from ?? deletePos;
|
|
689
|
+
const rangeTo = noteRange?.to ?? deleteEnd;
|
|
690
|
+
const nodeAfter = state.doc.resolve(rangeFrom).nodeAfter;
|
|
305
691
|
if (!nodeAfter || !canCarryTrackedRunMark(nodeAfter)) return false;
|
|
306
692
|
const hasOwnInsertion = nodeAfter.marks.some((m) => m.type === insertionType && m.attrs["author"] === pluginState.author);
|
|
307
693
|
if (nodeAfter.marks.some((m) => m.type === deletionType)) {
|
|
308
|
-
const newPos = isBackward ?
|
|
694
|
+
const newPos = isBackward ? rangeFrom : rangeTo;
|
|
309
695
|
tr.setSelection(TextSelection.near(tr.doc.resolve(newPos)));
|
|
310
|
-
} else if (hasOwnInsertion) tr.delete(
|
|
696
|
+
} else if (hasOwnInsertion) tr.delete(rangeFrom, rangeTo);
|
|
311
697
|
else {
|
|
312
|
-
const delAttrs = findAdjacentRevisionForRange(state.doc,
|
|
313
|
-
tr.addMark(
|
|
314
|
-
const newPos = isBackward ?
|
|
698
|
+
const delAttrs = findAdjacentRevisionForRange(state.doc, rangeFrom, rangeTo, "deletion", pluginState.author) || makeMarkAttrs(pluginState);
|
|
699
|
+
tr.addMark(rangeFrom, rangeTo, deletionType.create(delAttrs));
|
|
700
|
+
const newPos = isBackward ? rangeFrom : rangeTo;
|
|
315
701
|
tr.setSelection(TextSelection.near(tr.doc.resolve(newPos)));
|
|
316
702
|
}
|
|
317
703
|
dispatch(tr.scrollIntoView());
|
|
318
704
|
return true;
|
|
319
705
|
}
|
|
706
|
+
/** Apply the editor's selected-content deletion path for a host cut action. */
|
|
707
|
+
const deleteSelectionAsSuggestion = (state, dispatch) => state.selection.empty ? false : handleSuggestionDelete(state, dispatch, "forward");
|
|
320
708
|
/**
|
|
321
709
|
* Mark the text committed by an IME composition as a tracked insertion.
|
|
322
710
|
*
|
|
@@ -329,28 +717,66 @@ function handleSuggestionDelete(state, dispatch, direction) {
|
|
|
329
717
|
* committed range safely. `markRangeAsInserted` skips nodes that already carry a
|
|
330
718
|
* tracked-change mark, so this is idempotent. eigenpal/docx-editor#938.
|
|
331
719
|
*/
|
|
332
|
-
function markComposedAsInsertion(view, from, pluginState) {
|
|
720
|
+
function markComposedAsInsertion(view, from, pluginState, replaced) {
|
|
333
721
|
const insertionType = view.state.schema.marks["insertion"];
|
|
334
722
|
const deletionType = view.state.schema.marks["deletion"];
|
|
335
723
|
if (!insertionType || !deletionType) return;
|
|
336
724
|
const to = view.state.selection.to;
|
|
337
|
-
if (to <= from) return;
|
|
725
|
+
if (to <= from && !replaced) return;
|
|
338
726
|
const tr = view.state.tr;
|
|
339
727
|
tr.setMeta(SUGGESTION_META, true);
|
|
340
|
-
|
|
341
|
-
|
|
728
|
+
if (replaced) {
|
|
729
|
+
tr.insert(from, replaced.content);
|
|
730
|
+
markRangeAsDeleted(tr, tr.doc, from, from + replaced.content.size, insertionType, deletionType, pluginState);
|
|
731
|
+
}
|
|
732
|
+
const insertionFrom = tr.mapping.map(from, 1);
|
|
733
|
+
const insertionTo = tr.mapping.map(to, 1);
|
|
734
|
+
if (insertionTo <= insertionFrom) {
|
|
735
|
+
if (tr.steps.length > 0) view.dispatch(tr);
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
const markAttrs = findAdjacentRevisionForRange(tr.doc, insertionFrom, insertionTo, "insertion", pluginState.author) || makeMarkAttrs(pluginState);
|
|
739
|
+
markRangeAsInserted(tr, tr.doc, insertionFrom, insertionTo, insertionType, deletionType, markAttrs);
|
|
342
740
|
if (tr.steps.length === 0) return;
|
|
343
|
-
const caret = tr.mapping.map(to);
|
|
741
|
+
const caret = tr.mapping.map(to, 1);
|
|
344
742
|
tr.setSelection(TextSelection.create(tr.doc, caret));
|
|
345
743
|
view.dispatch(tr);
|
|
346
744
|
}
|
|
347
745
|
/**
|
|
746
|
+
* Paragraphs inserted into one (a paste at the caret) split it: its break ends
|
|
747
|
+
* the last part, which reads as the last inserted paragraph. Rejecting the
|
|
748
|
+
* inserted breaks leaves that part, so it records what the paragraph read as.
|
|
749
|
+
*/
|
|
750
|
+
function recordSplitParagraph(tr, before, step, insertedFrom, insertedTo, attrs) {
|
|
751
|
+
if (!(step instanceof ReplaceStep) || !before) return;
|
|
752
|
+
const $at = before.resolve(step.from);
|
|
753
|
+
if ($at.parent.type.name !== "paragraph" || step.to > $at.after() || before.textBetween(step.from, step.to) !== "") return;
|
|
754
|
+
const split = $at.parent;
|
|
755
|
+
const $first = tr.doc.resolve(insertedFrom);
|
|
756
|
+
const $last = tr.doc.resolve(insertedTo);
|
|
757
|
+
let lastPos = null;
|
|
758
|
+
if ($last.parent.type.name === "paragraph") lastPos = $last.before();
|
|
759
|
+
else if ($last.nodeBefore?.type.name === "paragraph") lastPos = insertedTo - $last.nodeBefore.nodeSize;
|
|
760
|
+
if ($first.parent.type.name !== "paragraph" || lastPos === null || lastPos === $first.before()) return;
|
|
761
|
+
recordReplacedParagraphProperties({
|
|
762
|
+
tr,
|
|
763
|
+
position: lastPos,
|
|
764
|
+
replaced: split,
|
|
765
|
+
revision: {
|
|
766
|
+
id: attrs.revisionId,
|
|
767
|
+
author: attrs.author,
|
|
768
|
+
date: attrs.date
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
348
773
|
* Create the suggestion mode plugin.
|
|
349
774
|
* When active, text edits become tracked changes.
|
|
350
775
|
*/
|
|
351
776
|
function createSuggestionModePlugin(initialActive = false, author = "User") {
|
|
352
777
|
let composing = false;
|
|
353
778
|
let compositionFrom = null;
|
|
779
|
+
let compositionReplaced = null;
|
|
354
780
|
return new Plugin({
|
|
355
781
|
key: suggestionModeKey,
|
|
356
782
|
state: {
|
|
@@ -372,32 +798,32 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
|
|
|
372
798
|
},
|
|
373
799
|
props: {
|
|
374
800
|
handleDOMEvents: {
|
|
801
|
+
cut(view, event) {
|
|
802
|
+
if (!suggestionModeKey.getState(view.state)?.active || view.state.selection.empty) return false;
|
|
803
|
+
const data = event.clipboardData;
|
|
804
|
+
if (!data) return false;
|
|
805
|
+
const { dom, text } = view.serializeForClipboard(view.state.selection.content());
|
|
806
|
+
data.clearData();
|
|
807
|
+
data.setData("text/html", dom.innerHTML);
|
|
808
|
+
data.setData("text/plain", text);
|
|
809
|
+
event.preventDefault();
|
|
810
|
+
return handleSuggestionDelete(view.state, view.dispatch, "forward");
|
|
811
|
+
},
|
|
375
812
|
compositionstart(view) {
|
|
376
|
-
|
|
377
|
-
if (
|
|
813
|
+
if (!suggestionModeKey.getState(view.state)?.active) return false;
|
|
814
|
+
if (composing) return false;
|
|
378
815
|
composing = true;
|
|
379
816
|
const { from, to } = view.state.selection;
|
|
380
|
-
if (from !== to) {
|
|
381
|
-
const insertionType = view.state.schema.marks["insertion"];
|
|
382
|
-
const deletionType = view.state.schema.marks["deletion"];
|
|
383
|
-
if (insertionType && deletionType) {
|
|
384
|
-
const tr = view.state.tr;
|
|
385
|
-
tr.setMeta(SUGGESTION_META, true);
|
|
386
|
-
markRangeAsDeleted(tr, view.state.doc, from, to, insertionType, deletionType, pluginState);
|
|
387
|
-
const caret = tr.mapping.map(to);
|
|
388
|
-
tr.setSelection(TextSelection.create(tr.doc, caret));
|
|
389
|
-
view.dispatch(tr);
|
|
390
|
-
compositionFrom = caret;
|
|
391
|
-
return false;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
817
|
compositionFrom = from;
|
|
818
|
+
compositionReplaced = from === to ? null : view.state.doc.slice(from, to);
|
|
395
819
|
return false;
|
|
396
820
|
},
|
|
397
821
|
compositionend(view) {
|
|
398
822
|
const pluginState = suggestionModeKey.getState(view.state);
|
|
399
823
|
const from = compositionFrom;
|
|
824
|
+
const replaced = compositionReplaced;
|
|
400
825
|
compositionFrom = null;
|
|
826
|
+
compositionReplaced = null;
|
|
401
827
|
if (!pluginState?.active || from == null) {
|
|
402
828
|
composing = false;
|
|
403
829
|
return false;
|
|
@@ -405,7 +831,7 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
|
|
|
405
831
|
queueMicrotask(() => {
|
|
406
832
|
try {
|
|
407
833
|
const current = suggestionModeKey.getState(view.state);
|
|
408
|
-
if (current?.active) markComposedAsInsertion(view, from, current);
|
|
834
|
+
if (current?.active) markComposedAsInsertion(view, from, current, replaced);
|
|
409
835
|
} finally {
|
|
410
836
|
composing = false;
|
|
411
837
|
}
|
|
@@ -420,8 +846,15 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
|
|
|
420
846
|
handleKeyDown(view, event) {
|
|
421
847
|
const pluginState = suggestionModeKey.getState(view.state);
|
|
422
848
|
if (!pluginState?.active) return false;
|
|
423
|
-
if (event.key === "Enter"
|
|
849
|
+
if (event.key === "Enter" && !event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey) {
|
|
850
|
+
const { $from, empty } = view.state.selection;
|
|
851
|
+
if (empty && $from.parent.type.name === "paragraph" && expectParagraphAttrs($from.parent).numPr?.kind === "reference") return false;
|
|
852
|
+
return handleSuggestionEnter(view, pluginState);
|
|
853
|
+
}
|
|
854
|
+
if (event.key === "Backspace" && undoInputRule(view.state, view.dispatch)) return true;
|
|
424
855
|
if (event.key === "Backspace" || event.key === "Delete") {
|
|
856
|
+
const { $from, empty } = view.state.selection;
|
|
857
|
+
if (event.key === "Backspace" && empty && $from.parentOffset === 0 && $from.parent.type.name === "paragraph" && expectParagraphAttrs($from.parent).numPr?.kind === "reference") return false;
|
|
425
858
|
const boundaryTarget = paragraphBoundaryTarget(view.state, event.key === "Backspace" ? "backward" : "forward");
|
|
426
859
|
if (boundaryTarget !== null) return applyPPrDel(view, boundaryTarget, pluginState);
|
|
427
860
|
const direction = event.key === "Backspace" ? "backward" : "forward";
|
|
@@ -438,7 +871,7 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
|
|
|
438
871
|
handlePaste(view, _event, slice) {
|
|
439
872
|
const pluginState = suggestionModeKey.getState(view.state);
|
|
440
873
|
if (!pluginState?.active) return false;
|
|
441
|
-
return handleSuggestionPaste(view, slice, pluginState);
|
|
874
|
+
return handleSuggestionTableCellPaste(view, slice, pluginState) || handleSuggestionPaste(view, slice, pluginState);
|
|
442
875
|
}
|
|
443
876
|
},
|
|
444
877
|
appendTransaction(transactions, _oldState, newState) {
|
|
@@ -461,20 +894,14 @@ function createSuggestionModePlugin(initialActive = false, author = "User") {
|
|
|
461
894
|
const newFrom = following.map(stepFrom, -1);
|
|
462
895
|
const newTo = following.map(stepTo, 1);
|
|
463
896
|
if (newTo > newFrom) {
|
|
464
|
-
|
|
465
|
-
if (!canCarryTrackedRunMark(node)) return;
|
|
466
|
-
if (!node.marks.some((m) => m.type === insertionType || deletionType && m.type === deletionType)) {
|
|
467
|
-
const nodeStart = Math.max(pos, newFrom);
|
|
468
|
-
const nodeEnd = Math.min(pos + node.nodeSize, newTo);
|
|
469
|
-
tr.addMark(nodeStart, nodeEnd, insertionType.create(markAttrs));
|
|
470
|
-
}
|
|
471
|
-
});
|
|
472
|
-
encloseWholeControls({
|
|
897
|
+
if (userTr.getMeta("paste")) enclosePastedRunRevisions({
|
|
473
898
|
tr,
|
|
474
899
|
from: newFrom,
|
|
475
900
|
to: newTo,
|
|
476
|
-
|
|
901
|
+
revision: markAttrs
|
|
477
902
|
});
|
|
903
|
+
if (deletionType) markRangeAsInserted(tr, newState.doc, newFrom, newTo, insertionType, deletionType, markAttrs);
|
|
904
|
+
recordSplitParagraph(tr, userTr.docs[stepIndex], step, newFrom, newTo, markAttrs);
|
|
478
905
|
}
|
|
479
906
|
});
|
|
480
907
|
}
|
|
@@ -509,4 +936,4 @@ function isSuggestionModeActive(state) {
|
|
|
509
936
|
return suggestionModeKey.getState(state)?.active ?? false;
|
|
510
937
|
}
|
|
511
938
|
//#endregion
|
|
512
|
-
export { SUGGESTION_BYPASS_META, SUGGESTION_META, createSuggestionModePlugin, handleSuggestionEnter, handleSuggestionPaste, isSuggestionModeActive, makeRevisionInfo, paragraphBoundaryTarget, setSuggestionMode, suggestionModeKey, toggleSuggestionMode };
|
|
939
|
+
export { SUGGESTED_TEXT_INPUT_META, SUGGESTION_BYPASS_META, SUGGESTION_META, createSuggestionModePlugin, deleteSelectionAsSuggestion, handleSuggestionEnter, handleSuggestionPaste, handleSuggestionTableCellPaste, isSuggestionModeActive, makeRevisionInfo, paragraphBoundaryTarget, setSuggestionMode, suggestRangeDeletion, suggestionModeKey, toggleSuggestionMode };
|