@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
|
@@ -3,6 +3,7 @@ import { matchInlineProvenance } from "../compare/inline-provenance.js";
|
|
|
3
3
|
import { stageSectionBoundaryProperties } from "../compare/section-boundary-properties.js";
|
|
4
4
|
import { importReferencedStyleDefinitions } from "../compare/style-resources.js";
|
|
5
5
|
import { applyFolioDocumentOperations } from "../document-operations.js";
|
|
6
|
+
import { applyReplyThreadMarkers } from "../docx/commentReplyMarkers.js";
|
|
6
7
|
import { rebindDrawingImageRelationship } from "../docx/drawingRelationships.js";
|
|
7
8
|
import { getEndnoteText, getFootnoteText, isSeparatorEndnote, isSeparatorFootnote } from "../docx/footnoteParser.js";
|
|
8
9
|
import { getHeaderFooterText } from "../docx/headerFooterParser.js";
|
|
@@ -16,22 +17,30 @@ import { attemptSelectiveSave } from "../docx/selectiveSave.js";
|
|
|
16
17
|
import { pluginsForHeadlessRevisionResolution } from "../internal/headlessRevisionResolutionGuard.js";
|
|
17
18
|
import { withTrackedSectionEndpointRemoval } from "../internal/sectionEndpointResolution.js";
|
|
18
19
|
import { captureSectionReferenceInventory, resolvedSectionReferenceLosses, withSectionReferenceResolution } from "../internal/sectionReferenceResolution.js";
|
|
19
|
-
import { expectCharacterStyleMarkAttrs } from "../prosemirror/attrs/index.js";
|
|
20
|
-
import { acceptAIEditRevision, rejectAIEditRevision, resolveAllChangesInHeadlessState } from "../prosemirror/commands/comments.js";
|
|
20
|
+
import { expectCharacterStyleMarkAttrs, expectFootnoteRefMarkAttrs } from "../prosemirror/attrs/index.js";
|
|
21
|
+
import { acceptAIEditRevision, acceptSuggestion, getSuggestions, rejectAIEditRevision, rejectAllSuggestions, rejectSuggestion, resolveAllChangesInHeadlessState, suggestionIdOfRevision } from "../prosemirror/commands/comments.js";
|
|
21
22
|
import { sectionRejectProperties } from "../prosemirror/commands/propertyChangeScope.js";
|
|
22
23
|
import { proseDocToBlocks, updateDocumentContent } from "../prosemirror/conversion/fromProseDoc.js";
|
|
23
24
|
import { footnoteToProseDoc, headerFooterToProseDoc, toProseDoc } from "../prosemirror/conversion/toProseDoc.js";
|
|
24
25
|
import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
|
|
25
26
|
import { getChangedParagraphIds, getTrackedSectionEndpointRemoval, hasStructuralChanges, hasUntrackedChanges } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
|
|
27
|
+
import { completeNumberingForDoc } from "../prosemirror/listInstanceReferences.js";
|
|
26
28
|
import "../prosemirror/listMarker.js";
|
|
29
|
+
import { deleteNoteWithReference, noteDeletionRevisions, noteKeysReferencedIn, noteReferenceStates, noteReferencesRestored, referenceDeletions, referencedNotes } from "../prosemirror/noteReferenceReview.js";
|
|
27
30
|
import { createDocumentNumberingPlugin, withDocumentNumbering } from "../prosemirror/plugins/documentNumbering.js";
|
|
28
|
-
import {
|
|
31
|
+
import { getDocumentStyleResolver } from "../prosemirror/plugins/documentStyleState.js";
|
|
32
|
+
import { createDocumentStylesPlugin, withDocumentStyles } from "../prosemirror/plugins/documentStyles.js";
|
|
29
33
|
import { schema, singletonManager } from "../prosemirror/schema/index.js";
|
|
34
|
+
import { sectionPropertiesOf } from "../prosemirror/sectionCarrier.js";
|
|
35
|
+
import { storyListNumbering } from "../prosemirror/storyListNumbering.js";
|
|
30
36
|
import { canonicalJson } from "../utils/canonicalJson.js";
|
|
31
37
|
import { deterministicHexId } from "../utils/hexId.js";
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
38
|
+
import { buildAnnotatedBlockTextWithNoteReferences } from "./clean-text.js";
|
|
39
|
+
import { anchoredCommentIdsInBlocks, anchoredCommentIdsInProseDoc, withoutLostCommentThreads } from "./comment-lifecycle.js";
|
|
40
|
+
import { noteReferenceEditsAllowed } from "./note-references.js";
|
|
41
|
+
import { FolioPendingSuggestionRegistry, createPendingSuggestionSourceSnapshot, withoutPendingSuggestionCommentMarks } from "./pending-suggestions.js";
|
|
42
|
+
import { getCommentAnchorsFromDoc, getTrackedChangeGroupIdsFromDoc, getTrackedChangeStatsFromDoc, getTrackedChangesFromDoc, getTrackedChangesFromSnapshot } from "./read.js";
|
|
43
|
+
import { collectNoteReferenceLabels, createFolioAIEditSnapshotWithStyleResolver, detachFolioAIEditSnapshotExternalHyperlinks, folioStoryTables, isFolioAIContentBlock, normalizeFolioAIBlockText, sourceDocumentOf } from "./snapshot.js";
|
|
35
44
|
import { matchTableGeometry } from "./table-geometry.js";
|
|
36
45
|
import { tableTemplateCanCrossPackageLosslessly } from "./table-template.js";
|
|
37
46
|
import { TaggedError, panic } from "better-result";
|
|
@@ -248,6 +257,37 @@ const comparisonAccessByReviewer = /* @__PURE__ */ new WeakMap();
|
|
|
248
257
|
const MAIN_STORY = Object.freeze({ type: "main" });
|
|
249
258
|
const headerFooterStoryKey = ({ type, relationshipId }) => `${type}:${relationshipId}`;
|
|
250
259
|
const noteStoryKey = ({ type, noteId }) => `${type}:${noteId}`;
|
|
260
|
+
/** The note story a {@link noteStoryKey} key names. */
|
|
261
|
+
const noteStoryHandleOf = (key) => {
|
|
262
|
+
const [type, noteId] = key.split(":");
|
|
263
|
+
return (type === "footnote" || type === "endnote") && noteId !== void 0 ? {
|
|
264
|
+
type,
|
|
265
|
+
noteId: Number(noteId)
|
|
266
|
+
} : null;
|
|
267
|
+
};
|
|
268
|
+
/** The notes a story's text refers to, keyed as {@link noteStoryKey} keys them. */
|
|
269
|
+
const referencedNoteKeys = (doc) => {
|
|
270
|
+
const keys = /* @__PURE__ */ new Set();
|
|
271
|
+
doc.descendants((node) => {
|
|
272
|
+
if (!node.isText) return true;
|
|
273
|
+
for (const mark of node.marks) {
|
|
274
|
+
if (mark.type.name !== "footnoteRef") continue;
|
|
275
|
+
const { id, noteType } = expectFootnoteRefMarkAttrs(mark);
|
|
276
|
+
keys.add(`${noteType === "endnote" ? "endnote" : "footnote"}:${String(id)}`);
|
|
277
|
+
}
|
|
278
|
+
return false;
|
|
279
|
+
});
|
|
280
|
+
return keys;
|
|
281
|
+
};
|
|
282
|
+
/**
|
|
283
|
+
* A part's roles as a reader label: `first`, or, in a document with several
|
|
284
|
+
* sections, `first (sections 1, 3), default (section 2)`.
|
|
285
|
+
*/
|
|
286
|
+
const describePlacements = (placements, sectionCount) => {
|
|
287
|
+
const sectionsByRole = /* @__PURE__ */ new Map();
|
|
288
|
+
for (const { type, section } of placements) sectionsByRole.set(type, [...sectionsByRole.get(type) ?? [], section]);
|
|
289
|
+
return [...sectionsByRole].map(([type, sections]) => sectionCount > 1 ? `${type} (${sections.length > 1 ? "sections" : "section"} ${sections.join(", ")})` : type).join(", ");
|
|
290
|
+
};
|
|
251
291
|
const secondaryStoryKey = (story) => story.type === "header" || story.type === "footer" ? headerFooterStoryKey(story) : noteStoryKey(story);
|
|
252
292
|
const editableStoryKey = (story) => story.type === "main" ? "main" : secondaryStoryKey(story);
|
|
253
293
|
const isFolioReviewedView = (value) => FOLIO_REVIEWED_VIEWS.some((view) => view === value);
|
|
@@ -256,6 +296,18 @@ const resolveReviewedState = (state, view) => {
|
|
|
256
296
|
if (view === "current-markup") return state;
|
|
257
297
|
return resolveAllChangesInHeadlessState(state, view === "original" ? "reject" : "accept");
|
|
258
298
|
};
|
|
299
|
+
/**
|
|
300
|
+
* Reject suggestions before resolving all ordinary revisions. A suggested
|
|
301
|
+
* whole-paragraph or table insert is flagged on the node; its flag must stay
|
|
302
|
+
* intact until that suggestion is explicitly accepted or rejected.
|
|
303
|
+
*/
|
|
304
|
+
const rejectSuggestions = (state) => {
|
|
305
|
+
let settled = state;
|
|
306
|
+
rejectAllSuggestions()(state, (transaction) => {
|
|
307
|
+
settled = state.apply(transaction);
|
|
308
|
+
});
|
|
309
|
+
return settled;
|
|
310
|
+
};
|
|
259
311
|
const createHeadlessPlugins = (styles, numbering) => [
|
|
260
312
|
...pluginsForHeadlessRevisionResolution(singletonManager.getPlugins()),
|
|
261
313
|
createDocumentStylesPlugin(styles),
|
|
@@ -266,7 +318,9 @@ const formatStorySnapshotForLLM = (snapshot, annotated) => {
|
|
|
266
318
|
const blocks = snapshot.blocks.filter(isFolioAIContentBlock);
|
|
267
319
|
if (!annotated) return blocks.map(formatBlockForLLM).join("\n");
|
|
268
320
|
const nodeByStart = /* @__PURE__ */ new Map();
|
|
269
|
-
sourceDocumentOf(snapshot)
|
|
321
|
+
const sourceDocument = sourceDocumentOf(snapshot);
|
|
322
|
+
const noteReferences = collectNoteReferenceLabels(sourceDocument);
|
|
323
|
+
sourceDocument.descendants((node, pos) => {
|
|
270
324
|
if (!node.isTextblock) return true;
|
|
271
325
|
nodeByStart.set(pos, node);
|
|
272
326
|
return false;
|
|
@@ -276,18 +330,22 @@ const formatStorySnapshotForLLM = (snapshot, annotated) => {
|
|
|
276
330
|
return blocks.map((block) => {
|
|
277
331
|
const from = startById.get(block.id);
|
|
278
332
|
const node = from === void 0 ? void 0 : nodeByStart.get(from);
|
|
279
|
-
const text = node ?
|
|
333
|
+
const text = node ? buildAnnotatedBlockTextWithNoteReferences(node, noteReferences) : block.text;
|
|
280
334
|
return formatBlockLine(block, text);
|
|
281
335
|
}).join("\n");
|
|
282
336
|
};
|
|
283
337
|
/**
|
|
284
338
|
* One LLM-ready line for a block: `[<blockId>] text`, with an `(h<level>)` tag
|
|
285
|
-
* for headings
|
|
286
|
-
* block id straight back into an
|
|
339
|
+
* for headings, then the number a numbered heading shows, and the list marker
|
|
340
|
+
* for list items, so a model can copy the block id straight back into an
|
|
341
|
+
* operation and match the numbers the document shows.
|
|
287
342
|
*/
|
|
288
343
|
const formatBlockLine = (block, text) => {
|
|
289
344
|
const label = `[${block.id}]`;
|
|
290
|
-
if (block.kind === "heading")
|
|
345
|
+
if (block.kind === "heading") {
|
|
346
|
+
const number = block.displayLabel !== void 0 && block.displayLabel !== block.styleId ? `${block.displayLabel} ` : "";
|
|
347
|
+
return `${label} (h${headingLevel(block)}) ${number}${text}`;
|
|
348
|
+
}
|
|
291
349
|
if (block.kind === "listItem") return `${label} ${block.displayLabel ?? "•"} ${text}`;
|
|
292
350
|
return `${label} ${text}`;
|
|
293
351
|
};
|
|
@@ -332,6 +390,8 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
332
390
|
state;
|
|
333
391
|
secondaryStoryStates = /* @__PURE__ */ new Map();
|
|
334
392
|
removedHeaderFooterStories = /* @__PURE__ */ new Map();
|
|
393
|
+
/** Notes whose reference a resolution removed: a note exists only through its reference. */
|
|
394
|
+
removedNoteStories = /* @__PURE__ */ new Map();
|
|
335
395
|
sectionReferenceRemovals = [];
|
|
336
396
|
importedStyles;
|
|
337
397
|
importedMedia = /* @__PURE__ */ new Map();
|
|
@@ -340,7 +400,10 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
340
400
|
resolvedStoryExpectations = /* @__PURE__ */ new Map();
|
|
341
401
|
createdComments = [];
|
|
342
402
|
usedCommentIds;
|
|
403
|
+
/** Comments the body anchored when it was loaded, read as the editor projects it. */
|
|
404
|
+
loadedMainCommentIds;
|
|
343
405
|
documentOperationUndoEntries = [];
|
|
406
|
+
pendingSuggestions = new FolioPendingSuggestionRegistry();
|
|
344
407
|
/**
|
|
345
408
|
* Resolved-state overrides recorded by {@link resolveComment}, keyed by
|
|
346
409
|
* comment id. Applied on read ({@link getComments}) and on write
|
|
@@ -356,6 +419,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
356
419
|
this.state = args.state;
|
|
357
420
|
this.author = args.author;
|
|
358
421
|
this.usedCommentIds = new Set((args.baseDocument.package.document.comments ?? []).map(({ id }) => id));
|
|
422
|
+
this.loadedMainCommentIds = anchoredCommentIdsInProseDoc(args.state.doc);
|
|
359
423
|
comparisonAccessByReviewer.set(this, Object.freeze({
|
|
360
424
|
stageTerminalTableReviewCarrier: (target) => this.stageTerminalTableReviewCarrier(target),
|
|
361
425
|
stageTargetStyles: (source, snapshots, importedHeaderFooterSnapshots) => this.stageTargetStyles(source, snapshots, importedHeaderFooterSnapshots),
|
|
@@ -609,6 +673,51 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
609
673
|
snapshot() {
|
|
610
674
|
return createStateSnapshot(this.state);
|
|
611
675
|
}
|
|
676
|
+
/** Export staged AI operations for storage by the host, outside the DOCX. */
|
|
677
|
+
exportPendingSuggestions() {
|
|
678
|
+
const active = new Set(getSuggestions(this.state).map(({ suggestionId }) => suggestionId));
|
|
679
|
+
for (const entry of this.secondaryStoryStates.values()) for (const { suggestionId } of getSuggestions(entry.state)) active.add(suggestionId);
|
|
680
|
+
return this.pendingSuggestions.exportPendingSuggestions({
|
|
681
|
+
activeSuggestionIds: active,
|
|
682
|
+
snapshotForStory: (story, commentIds) => {
|
|
683
|
+
const state = this.getEditableStoryState(story);
|
|
684
|
+
return state ? createPendingSuggestionSourceSnapshot(state, commentIds) : null;
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
/** Validate saved proposals against this document before restaging them. */
|
|
689
|
+
loadPendingSuggestions(records) {
|
|
690
|
+
return this.pendingSuggestions.loadPendingSuggestions({
|
|
691
|
+
records,
|
|
692
|
+
snapshotForStory: (story) => this.snapshotStory(story),
|
|
693
|
+
sourceSnapshotForStory: (story, commentIds) => {
|
|
694
|
+
const state = this.getEditableStoryState(story);
|
|
695
|
+
return state ? createPendingSuggestionSourceSnapshot(state, commentIds) : null;
|
|
696
|
+
},
|
|
697
|
+
apply: (record, snapshot) => {
|
|
698
|
+
const result = this.applyDocumentOperationsInternal({
|
|
699
|
+
story: record.story,
|
|
700
|
+
batch: {
|
|
701
|
+
version: 1,
|
|
702
|
+
operations: [record.operation],
|
|
703
|
+
mode: "suggested"
|
|
704
|
+
},
|
|
705
|
+
snapshot,
|
|
706
|
+
author: record.author,
|
|
707
|
+
createUndoEntry: false
|
|
708
|
+
});
|
|
709
|
+
return {
|
|
710
|
+
applied: result.applied,
|
|
711
|
+
skipped: result.skipped
|
|
712
|
+
};
|
|
713
|
+
},
|
|
714
|
+
activeSuggestionIds: () => {
|
|
715
|
+
const active = new Set(getSuggestions(this.state).map(({ suggestionId }) => suggestionId));
|
|
716
|
+
for (const entry of this.secondaryStoryStates.values()) for (const { suggestionId } of getSuggestions(entry.state)) active.add(suggestionId);
|
|
717
|
+
return active;
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
}
|
|
612
721
|
/**
|
|
613
722
|
* The package's numbering, flattened to what a reader sees: one entry per
|
|
614
723
|
* numbering instance and level, with the format and level text that produce
|
|
@@ -621,7 +730,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
621
730
|
* packages can be compared entry by entry.
|
|
622
731
|
*/
|
|
623
732
|
readNumberingDefinitions() {
|
|
624
|
-
return numberingLevelsOf(this.baseDocument.package.numbering).toSorted((left, right) => left.numId - right.numId || left.level - right.level);
|
|
733
|
+
return numberingLevelsOf(completeNumberingForDoc(this.baseDocument.package.numbering, this.state.doc)).toSorted((left, right) => left.numId - right.numId || left.level - right.level);
|
|
625
734
|
}
|
|
626
735
|
/** Return parsed package metadata without exposing the mutable document model. */
|
|
627
736
|
getDocumentProperties() {
|
|
@@ -810,7 +919,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
810
919
|
});
|
|
811
920
|
}
|
|
812
921
|
/** Apply a versioned operation batch to one editable document story. */
|
|
813
|
-
applyDocumentOperationsToStory({ story, batch, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground }) {
|
|
922
|
+
applyDocumentOperationsToStory({ story, batch, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedStyles }) {
|
|
814
923
|
return this.applyDocumentOperationsInternal({
|
|
815
924
|
story,
|
|
816
925
|
batch,
|
|
@@ -819,11 +928,19 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
819
928
|
...wordDiff !== void 0 && { wordDiff },
|
|
820
929
|
...tableTemplates !== void 0 && { tableTemplates },
|
|
821
930
|
...replacementBackground !== void 0 && { replacementBackground },
|
|
931
|
+
...undefinedStyles !== void 0 && { undefinedStyles },
|
|
822
932
|
createUndoEntry: true
|
|
823
933
|
});
|
|
824
934
|
}
|
|
825
|
-
|
|
935
|
+
/** Apply a batch; the notes whose references it deletes or removes follow them. */
|
|
936
|
+
applyDocumentOperationsInternal(options) {
|
|
937
|
+
if (noteReferenceEditsAllowed()) return this.applyDocumentOperationsToStoryState(options);
|
|
938
|
+
return this.withNotesFollowingReferences(() => this.applyDocumentOperationsToStoryState(options));
|
|
939
|
+
}
|
|
940
|
+
applyDocumentOperationsToStoryState({ story, batch, author, snapshot, revisionStamp, wordDiff, tableTemplates, replacementBackground, undefinedStyles, createUndoEntry }) {
|
|
826
941
|
const beforeState = this.requireEditableStoryState(story);
|
|
942
|
+
const operationAuthor = author ?? this.author;
|
|
943
|
+
const sourceSnapshot = snapshot ?? createStateSnapshot(beforeState);
|
|
827
944
|
const createdCommentsLengthBefore = this.createdComments.length;
|
|
828
945
|
const view = {
|
|
829
946
|
state: beforeState,
|
|
@@ -833,19 +950,20 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
833
950
|
};
|
|
834
951
|
const result = applyFolioDocumentOperations({
|
|
835
952
|
view,
|
|
836
|
-
snapshot:
|
|
953
|
+
snapshot: sourceSnapshot,
|
|
837
954
|
batch,
|
|
838
955
|
story: story.type === "main" ? "main" : story,
|
|
839
|
-
author:
|
|
956
|
+
author: operationAuthor,
|
|
840
957
|
...revisionStamp !== void 0 && { revisionStamp },
|
|
841
958
|
...wordDiff !== void 0 && { wordDiff },
|
|
842
959
|
...tableTemplates !== void 0 && { tableTemplates },
|
|
843
960
|
...replacementBackground !== void 0 && { replacementBackground },
|
|
961
|
+
...undefinedStyles !== void 0 && { undefinedStyles },
|
|
844
962
|
createCommentId: (text) => {
|
|
845
963
|
const comment = createReviewerComment({
|
|
846
964
|
id: this.nextCommentId(),
|
|
847
965
|
text,
|
|
848
|
-
author:
|
|
966
|
+
author: operationAuthor,
|
|
849
967
|
date: revisionStamp?.date
|
|
850
968
|
});
|
|
851
969
|
this.createdComments.push(comment);
|
|
@@ -856,7 +974,23 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
856
974
|
id: `headless-${String(undoHandleCursor++)}`
|
|
857
975
|
}) }
|
|
858
976
|
});
|
|
977
|
+
const appliedCommentIds = new Set(result.applied.flatMap(({ commentId }) => commentId === void 0 ? [] : [commentId]));
|
|
978
|
+
const createdByBatch = this.createdComments.splice(createdCommentsLengthBefore);
|
|
979
|
+
this.createdComments.push(...createdByBatch.filter((comment) => appliedCommentIds.has(comment.id)));
|
|
859
980
|
this.setEditableStoryState(story, view.state);
|
|
981
|
+
if (batch.mode === "suggested") {
|
|
982
|
+
const activeSuggestionIds = new Set(getSuggestions(beforeState).map(({ suggestionId }) => suggestionId));
|
|
983
|
+
for (const { suggestionId } of getSuggestions(this.state)) activeSuggestionIds.add(suggestionId);
|
|
984
|
+
for (const entry of this.secondaryStoryStates.values()) for (const { suggestionId } of getSuggestions(entry.state)) activeSuggestionIds.add(suggestionId);
|
|
985
|
+
this.pendingSuggestions.recordApplied({
|
|
986
|
+
snapshot: sourceSnapshot,
|
|
987
|
+
story,
|
|
988
|
+
operations: batch.operations,
|
|
989
|
+
applied: result.applied,
|
|
990
|
+
author: operationAuthor,
|
|
991
|
+
activeSuggestionIds
|
|
992
|
+
});
|
|
993
|
+
}
|
|
860
994
|
if (result.undoHandle !== null) this.documentOperationUndoEntries.push({
|
|
861
995
|
undoHandle: result.undoHandle,
|
|
862
996
|
story,
|
|
@@ -891,7 +1025,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
891
1025
|
undoHandle,
|
|
892
1026
|
reason: "documentChanged"
|
|
893
1027
|
};
|
|
894
|
-
this.setEditableStoryState(entry.story, entry.beforeState);
|
|
1028
|
+
this.withNotesFollowingReferences(() => this.setEditableStoryState(entry.story, entry.beforeState));
|
|
895
1029
|
this.createdComments.length = entry.createdCommentsLengthBefore;
|
|
896
1030
|
this.documentOperationUndoEntries.pop();
|
|
897
1031
|
return {
|
|
@@ -926,10 +1060,15 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
926
1060
|
* one per non-empty part: `[header default] …`, `[footer default] …`,
|
|
927
1061
|
* `[footnote #N] …`, `[endnote #N] …`. Lines reflect in-memory edits. Empty
|
|
928
1062
|
* parts and separator notes are omitted.
|
|
1063
|
+
*
|
|
1064
|
+
* A header or footer is labelled with the role its section references give
|
|
1065
|
+
* it (`default`, `first`, `even`); in a document with several sections, also
|
|
1066
|
+
* with the sections that show it: `[header first (sections 1, 3)] …`.
|
|
929
1067
|
*/
|
|
930
1068
|
getNotesAsText() {
|
|
931
1069
|
const pkg = this.baseDocument.package;
|
|
932
1070
|
const lines = [];
|
|
1071
|
+
const placements = this.headerFooterPlacements();
|
|
933
1072
|
const pushHeaderFooter = (map, label) => {
|
|
934
1073
|
if (!map) return;
|
|
935
1074
|
for (const [relationshipId, hf] of map) {
|
|
@@ -938,7 +1077,10 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
938
1077
|
relationshipId
|
|
939
1078
|
};
|
|
940
1079
|
const text = this.getHeaderFooterStoryText(handle, hf);
|
|
941
|
-
if (text.length > 0)
|
|
1080
|
+
if (text.length > 0) {
|
|
1081
|
+
const roles = placements.byPart.get(`${label}:${relationshipId}`);
|
|
1082
|
+
lines.push(`[${label} ${roles ? describePlacements(roles, placements.sectionCount) : hf.hdrFtrType}] ${text}`);
|
|
1083
|
+
}
|
|
942
1084
|
}
|
|
943
1085
|
};
|
|
944
1086
|
pushHeaderFooter(pkg.headers, "header");
|
|
@@ -990,7 +1132,10 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
990
1132
|
type: "endnote",
|
|
991
1133
|
noteId: endnote.id
|
|
992
1134
|
});
|
|
993
|
-
return handles.filter((handle) =>
|
|
1135
|
+
return handles.filter((handle) => {
|
|
1136
|
+
if (handle.type === "header" || handle.type === "footer") return !this.removedHeaderFooterStories.has(headerFooterStoryKey(handle));
|
|
1137
|
+
return handle.type !== "footnote" && handle.type !== "endnote" || !this.removedNoteStories.has(noteStoryKey(handle));
|
|
1138
|
+
});
|
|
994
1139
|
}
|
|
995
1140
|
/** Discover every readable document story through a typed, serializable handle. */
|
|
996
1141
|
listStories() {
|
|
@@ -1031,7 +1176,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1031
1176
|
* (nested tracked changes, hyperlinks) is out of scope.
|
|
1032
1177
|
*/
|
|
1033
1178
|
getComments(filter) {
|
|
1034
|
-
const definitions = this.withResolvedOverrides([...this.baseDocument.package.document.comments ?? [], ...this.createdComments]);
|
|
1179
|
+
const definitions = this.withResolvedOverrides(this.keptCommentThreads([...this.baseDocument.package.document.comments ?? [], ...this.createdComments], this.state, this.secondaryStoryStates.values()));
|
|
1035
1180
|
if (definitions.length === 0) return [];
|
|
1036
1181
|
const anchors = this.commentAnchors();
|
|
1037
1182
|
const repliesByParent = /* @__PURE__ */ new Map();
|
|
@@ -1054,6 +1199,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1054
1199
|
text: commentPlainText(comment),
|
|
1055
1200
|
anchoredText: anchor?.text ?? "",
|
|
1056
1201
|
blockId: anchor?.blockId ?? null,
|
|
1202
|
+
story: anchor?.story ?? null,
|
|
1057
1203
|
replies: (repliesByParent.get(comment.id) ?? []).map((reply) => ({
|
|
1058
1204
|
id: reply.id,
|
|
1059
1205
|
author: reply.author,
|
|
@@ -1071,7 +1217,8 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1071
1217
|
* {@link getComments} or its id; the reply threads under that comment's root
|
|
1072
1218
|
* (Word threads are flat). On {@link toBuffer} the reply is written as a real
|
|
1073
1219
|
* Word reply — linked via `commentsExtended.xml` and given its own
|
|
1074
|
-
* `commentRange` markers + reference anchored on the parent's range.
|
|
1220
|
+
* `commentRange` markers + reference anchored on the parent's range. The
|
|
1221
|
+
* live document carries the same anchor. Returns
|
|
1075
1222
|
* the created reply, or `null` when the target comment is absent.
|
|
1076
1223
|
*/
|
|
1077
1224
|
replyTo(target, input) {
|
|
@@ -1085,6 +1232,10 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1085
1232
|
if (!reply) return null;
|
|
1086
1233
|
this.createdComments.push(reply);
|
|
1087
1234
|
this.usedCommentIds.add(reply.id);
|
|
1235
|
+
this.anchorReplyInEditor({
|
|
1236
|
+
parentId: reply.parentId ?? parentId,
|
|
1237
|
+
replyId: reply.id
|
|
1238
|
+
});
|
|
1088
1239
|
return {
|
|
1089
1240
|
id: reply.id,
|
|
1090
1241
|
author: reply.author,
|
|
@@ -1092,6 +1243,31 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1092
1243
|
text: input.text
|
|
1093
1244
|
};
|
|
1094
1245
|
}
|
|
1246
|
+
anchorReplyInEditor({ parentId, replyId }) {
|
|
1247
|
+
for (const story of this.listStoryHandlesInternal()) {
|
|
1248
|
+
const state = this.getEditableStoryState(story);
|
|
1249
|
+
if (!state) continue;
|
|
1250
|
+
const commentMark = state.schema.marks["comment"];
|
|
1251
|
+
const referenceNode = state.schema.nodes["commentReference"];
|
|
1252
|
+
if (!commentMark || !referenceNode) continue;
|
|
1253
|
+
let from = null;
|
|
1254
|
+
let to = 0;
|
|
1255
|
+
let referenceAt = null;
|
|
1256
|
+
state.doc.descendants((node, pos) => {
|
|
1257
|
+
if (node.type === referenceNode && node.attrs["commentId"] === parentId) referenceAt ??= pos + node.nodeSize;
|
|
1258
|
+
if (node.isInline && node.marks.some((mark) => mark.type === commentMark && mark.attrs["commentId"] === parentId)) {
|
|
1259
|
+
from ??= pos;
|
|
1260
|
+
to = pos + node.nodeSize;
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1263
|
+
if (referenceAt === null || from === null || from >= to) continue;
|
|
1264
|
+
let transaction = state.tr;
|
|
1265
|
+
transaction = transaction.addMark(from, to, commentMark.create({ commentId: replyId }));
|
|
1266
|
+
transaction = transaction.insert(referenceAt, referenceNode.create({ commentId: replyId }));
|
|
1267
|
+
this.setEditableStoryState(story, state.apply(transaction));
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1095
1271
|
/**
|
|
1096
1272
|
* Mark a comment thread resolved, or reopen a previously resolved one. Pass
|
|
1097
1273
|
* the id from {@link getComments} / {@link FolioReviewComment.id}. Applies
|
|
@@ -1111,6 +1287,39 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1111
1287
|
this.resolvedOverrides.set(target.id, resolved);
|
|
1112
1288
|
return true;
|
|
1113
1289
|
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Where each header and footer part is shown, as the live section
|
|
1292
|
+
* references state it: its role (`w:type`) and the 1-based section, in
|
|
1293
|
+
* section order. A part's own `hdrFtrType` holds one role, and one part can
|
|
1294
|
+
* serve several sections, in different roles.
|
|
1295
|
+
*/
|
|
1296
|
+
headerFooterPlacements() {
|
|
1297
|
+
const records = [];
|
|
1298
|
+
this.state.doc.descendants((node) => {
|
|
1299
|
+
if (node.type.name !== "paragraph") return true;
|
|
1300
|
+
const record = sectionPropertiesOf(node);
|
|
1301
|
+
if (record && !records.includes(record)) records.push(record);
|
|
1302
|
+
return false;
|
|
1303
|
+
});
|
|
1304
|
+
const final = this.currentFinalSectionProperties();
|
|
1305
|
+
if (final) records.push(final);
|
|
1306
|
+
const byPart = /* @__PURE__ */ new Map();
|
|
1307
|
+
for (const [index, record] of records.entries()) {
|
|
1308
|
+
const place = (part, type, rId) => {
|
|
1309
|
+
const key = `${part}:${rId}`;
|
|
1310
|
+
byPart.set(key, [...byPart.get(key) ?? [], {
|
|
1311
|
+
type,
|
|
1312
|
+
section: index + 1
|
|
1313
|
+
}]);
|
|
1314
|
+
};
|
|
1315
|
+
for (const { type, rId } of record.headerReferences ?? []) place("header", type, rId);
|
|
1316
|
+
for (const { type, rId } of record.footerReferences ?? []) place("footer", type, rId);
|
|
1317
|
+
}
|
|
1318
|
+
return {
|
|
1319
|
+
byPart,
|
|
1320
|
+
sectionCount: records.length
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1114
1323
|
currentFinalSectionProperties() {
|
|
1115
1324
|
return this.finalSectionPropertiesOverride ?? this.baseDocument.package.document.finalSectionProperties;
|
|
1116
1325
|
}
|
|
@@ -1199,11 +1408,15 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1199
1408
|
* revision is no longer present (already resolved, or never existed).
|
|
1200
1409
|
*/
|
|
1201
1410
|
acceptChange(target) {
|
|
1202
|
-
return this.resolveWithSectionReferenceHistory(() => this.acceptChangeInternal(target));
|
|
1411
|
+
return this.resolveWithSectionReferenceHistory(() => this.withNotesFollowingReferences(() => this.acceptChangeInternal(target)));
|
|
1203
1412
|
}
|
|
1204
1413
|
acceptChangeInternal(target) {
|
|
1205
1414
|
const id = revisionIdOf(target);
|
|
1206
|
-
const
|
|
1415
|
+
const ids = getTrackedChangeGroupIdsFromDoc(this.state.doc, id);
|
|
1416
|
+
const suggestionId = suggestionIdOfRevision(this.state, id);
|
|
1417
|
+
if (suggestionId !== null) this.runCommand(acceptSuggestion(suggestionId, { author: this.author }));
|
|
1418
|
+
let bodyChanged = false;
|
|
1419
|
+
for (const memberId of ids) bodyChanged = this.runCommand(acceptAIEditRevision(memberId)) || bodyChanged;
|
|
1207
1420
|
const sectionChanged = this.resolveFinalSectionProperties("accept", id) > 0;
|
|
1208
1421
|
return bodyChanged || sectionChanged;
|
|
1209
1422
|
}
|
|
@@ -1212,17 +1425,46 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1212
1425
|
* deletion's text is restored. See {@link acceptChange} for targeting.
|
|
1213
1426
|
*/
|
|
1214
1427
|
rejectChange(target) {
|
|
1215
|
-
return this.resolveWithSectionReferenceHistory(() => this.rejectChangeInternal(target));
|
|
1428
|
+
return this.resolveWithSectionReferenceHistory(() => this.withNotesFollowingReferences(() => this.rejectChangeInternal(target)));
|
|
1216
1429
|
}
|
|
1217
1430
|
rejectChangeInternal(target) {
|
|
1218
1431
|
const id = revisionIdOf(target);
|
|
1219
|
-
const
|
|
1432
|
+
const ids = getTrackedChangeGroupIdsFromDoc(this.state.doc, id);
|
|
1433
|
+
const suggestionId = suggestionIdOfRevision(this.state, id);
|
|
1434
|
+
if (suggestionId !== null && this.runCommand(rejectSuggestion(suggestionId))) return true;
|
|
1435
|
+
let bodyChanged = false;
|
|
1436
|
+
for (const memberId of ids) bodyChanged = this.runCommand(rejectAIEditRevision(memberId)) || bodyChanged;
|
|
1220
1437
|
const sectionChanged = this.resolveFinalSectionProperties("reject", id) > 0;
|
|
1221
1438
|
return bodyChanged || sectionChanged;
|
|
1222
1439
|
}
|
|
1440
|
+
/** Convert one pending suggestion into an ordinary tracked change. */
|
|
1441
|
+
acceptSuggestion(suggestionId, options) {
|
|
1442
|
+
return this.resolveWithSectionReferenceHistory(() => {
|
|
1443
|
+
let accepted = false;
|
|
1444
|
+
for (const handle of this.listStoryHandlesInternal()) {
|
|
1445
|
+
const state = this.getEditableStoryState(handle);
|
|
1446
|
+
if (!state || !getSuggestions(state).some((entry) => entry.suggestionId === suggestionId)) continue;
|
|
1447
|
+
accepted = this.runStoryCommand(acceptSuggestion(suggestionId, { author: options?.author ?? this.author }), handle) || accepted;
|
|
1448
|
+
}
|
|
1449
|
+
return accepted;
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
/** Remove one pending suggestion without applying it. */
|
|
1453
|
+
rejectSuggestion(suggestionId) {
|
|
1454
|
+
return this.resolveWithSectionReferenceHistory(() => {
|
|
1455
|
+
let rejected = false;
|
|
1456
|
+
for (const handle of this.listStoryHandlesInternal()) {
|
|
1457
|
+
const state = this.getEditableStoryState(handle);
|
|
1458
|
+
if (!state || !getSuggestions(state).some((entry) => entry.suggestionId === suggestionId)) continue;
|
|
1459
|
+
rejected = this.runStoryCommand(rejectSuggestion(suggestionId), handle) || rejected;
|
|
1460
|
+
}
|
|
1461
|
+
return rejected;
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1223
1464
|
/**
|
|
1224
|
-
* Accept every tracked change in the package.
|
|
1225
|
-
*
|
|
1465
|
+
* Accept every ordinary tracked change in the package. Pending suggestions
|
|
1466
|
+
* remain staged until {@link acceptSuggestion} is called. Returns the number
|
|
1467
|
+
* of ordinary changes present before the sweep.
|
|
1226
1468
|
*
|
|
1227
1469
|
* Every story, not just the body: a revision in a header or a footnote is
|
|
1228
1470
|
* one a reviewer meant to resolve, and leaving it behind means an accepted
|
|
@@ -1270,18 +1512,161 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1270
1512
|
return propertyChanges?.length ?? 0;
|
|
1271
1513
|
}
|
|
1272
1514
|
resolveEveryStory(mode) {
|
|
1515
|
+
return this.withNotesFollowingReferences(() => this.resolveEveryStoryOnce(mode));
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Change the body the way a note follows its reference: a note whose
|
|
1519
|
+
* reference goes, goes too, as a note no text refers to does; a note whose
|
|
1520
|
+
* reference an edit deletes as a tracked change has its text deleted with
|
|
1521
|
+
* it; a note whose reference's deletion is rejected gets back the text that
|
|
1522
|
+
* deletion took.
|
|
1523
|
+
*/
|
|
1524
|
+
withNotesFollowingReferences(change) {
|
|
1525
|
+
const before = this.state.doc;
|
|
1526
|
+
const result = change();
|
|
1527
|
+
const after = this.state.doc;
|
|
1528
|
+
const referencedAfter = referencedNoteKeys(after);
|
|
1529
|
+
for (const key of referencedAfter) this.removedNoteStories.delete(key);
|
|
1530
|
+
const unreferenced = new Set([...referencedNoteKeys(before)].filter((key) => !referencedAfter.has(key)));
|
|
1531
|
+
const referencedElsewhere = unreferenced.size > 0 ? this.noteKeysReferencedOutsideBody(unreferenced) : /* @__PURE__ */ new Set();
|
|
1532
|
+
for (const key of unreferenced) {
|
|
1533
|
+
if (referencedElsewhere.has(key)) continue;
|
|
1534
|
+
const handle = noteStoryHandleOf(key);
|
|
1535
|
+
if (handle) this.removedNoteStories.set(noteStoryKey(handle), handle);
|
|
1536
|
+
}
|
|
1537
|
+
const rejectedDeletions = referenceDeletions(before);
|
|
1538
|
+
for (const key of noteReferencesRestored(before, after)) {
|
|
1539
|
+
const handle = noteStoryHandleOf(key);
|
|
1540
|
+
const state = handle ? this.getEditableStoryState(handle) : null;
|
|
1541
|
+
const reference = rejectedDeletions.get(key);
|
|
1542
|
+
const revisions = state && reference ? noteDeletionRevisions(state.doc, reference) : [];
|
|
1543
|
+
if (handle && revisions.length > 0) this.runStoryCommand(rejectAIEditRevision(revisions), handle);
|
|
1544
|
+
}
|
|
1545
|
+
this.deleteNotesWithTheirReferences(before, after);
|
|
1546
|
+
return result;
|
|
1547
|
+
}
|
|
1548
|
+
/** Delete the text of each note whose reference went from live to a tracked deletion. */
|
|
1549
|
+
deleteNotesWithTheirReferences(before, after) {
|
|
1550
|
+
const was = noteReferenceStates(before);
|
|
1551
|
+
const deletions = referenceDeletions(after);
|
|
1552
|
+
for (const [key, state] of noteReferenceStates(after)) {
|
|
1553
|
+
if (state !== "deleted" || was.get(key) !== "live") continue;
|
|
1554
|
+
const reference = deletions.get(key);
|
|
1555
|
+
if (!reference || reference.attrs["provenance"] === "suggested" || reference.attrs["moveKind"] != null) continue;
|
|
1556
|
+
const handle = noteStoryHandleOf(key);
|
|
1557
|
+
if (!handle || this.removedNoteStories.has(noteStoryKey(handle))) continue;
|
|
1558
|
+
this.runStoryCommand((storyState, dispatch) => {
|
|
1559
|
+
const transaction = deleteNoteWithReference(storyState.tr, reference);
|
|
1560
|
+
if (!transaction.docChanged) return false;
|
|
1561
|
+
dispatch?.(transaction);
|
|
1562
|
+
return true;
|
|
1563
|
+
}, handle);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
/**
|
|
1567
|
+
* The notes a story other than the body refers to (a header, a footer, a
|
|
1568
|
+
* comment, another note), leaving out references inside the `skipped` notes.
|
|
1569
|
+
*/
|
|
1570
|
+
noteKeysReferencedOutsideBody(skipped) {
|
|
1571
|
+
const keys = new Set(noteKeysReferencedIn(this.baseDocument.package.document.comments ?? []));
|
|
1572
|
+
for (const handle of this.listStoryHandlesInternal()) {
|
|
1573
|
+
if (handle.type === "main") continue;
|
|
1574
|
+
let source;
|
|
1575
|
+
if (handle.type === "footnote" || handle.type === "endnote") {
|
|
1576
|
+
if (skipped.has(noteStoryKey(handle))) continue;
|
|
1577
|
+
source = this.getNoteStory(handle);
|
|
1578
|
+
} else source = this.getHeaderFooterStory(handle);
|
|
1579
|
+
const state = this.secondaryStoryStates.get(secondaryStoryKey(handle))?.state;
|
|
1580
|
+
const found = state ? referencedNoteKeys(state.doc) : noteKeysReferencedIn(source?.content ?? []);
|
|
1581
|
+
for (const key of found) keys.add(key);
|
|
1582
|
+
}
|
|
1583
|
+
return keys;
|
|
1584
|
+
}
|
|
1585
|
+
resolveEveryStoryOnce(mode) {
|
|
1273
1586
|
let count = 0;
|
|
1274
|
-
|
|
1587
|
+
const resolvedStories = [];
|
|
1588
|
+
const refreshes = [];
|
|
1589
|
+
for (const handle of this.listStoryHandlesInternal()) {
|
|
1275
1590
|
const state = this.getEditableStoryState(handle);
|
|
1276
1591
|
if (!state) continue;
|
|
1277
|
-
|
|
1278
|
-
|
|
1592
|
+
const ordinaryCount = getTrackedChangesFromDoc(state.doc).filter(({ id }) => mode === "reject" || suggestionIdOfRevision(state, id) === null).length;
|
|
1593
|
+
count += ordinaryCount;
|
|
1594
|
+
const withSuggestions = mode === "accept" && ordinaryCount > 0 && getSuggestions(state).length > 0 ? this.acceptOrdinaryChangesWithSuggestions(state, handle) : null;
|
|
1595
|
+
if (withSuggestions) refreshes.push(withSuggestions.refresh);
|
|
1596
|
+
let resolvedState = state;
|
|
1597
|
+
if (mode === "reject") resolvedState = resolveAllChangesInHeadlessState(rejectSuggestions(state), mode);
|
|
1598
|
+
else if (ordinaryCount > 0) resolvedState = withSuggestions?.state ?? resolveAllChangesInHeadlessState(state, mode);
|
|
1599
|
+
resolvedStories.push({
|
|
1600
|
+
handle,
|
|
1601
|
+
state: resolvedState
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
for (const { handle, state } of resolvedStories) this.setEditableStoryState(handle, state);
|
|
1605
|
+
if (refreshes.length > 0) {
|
|
1606
|
+
const activeSuggestionIds = new Set(getSuggestions(this.state).map(({ suggestionId }) => suggestionId));
|
|
1607
|
+
for (const entry of this.secondaryStoryStates.values()) for (const { suggestionId } of getSuggestions(entry.state)) activeSuggestionIds.add(suggestionId);
|
|
1608
|
+
for (const refresh of refreshes) refresh(activeSuggestionIds);
|
|
1279
1609
|
}
|
|
1280
1610
|
return count;
|
|
1281
1611
|
}
|
|
1612
|
+
acceptOrdinaryChangesWithSuggestions(state, story) {
|
|
1613
|
+
const originalSuggestions = getSuggestions(state);
|
|
1614
|
+
const records = this.exportPendingSuggestions().filter((record) => editableStoryKey(record.story) === editableStoryKey(story));
|
|
1615
|
+
const recordedIds = new Set(records.map(({ suggestionId }) => suggestionId));
|
|
1616
|
+
if (originalSuggestions.some(({ suggestionId }) => !recordedIds.has(suggestionId))) panic("A pending suggestion has no operation to restage after bulk acceptance");
|
|
1617
|
+
let clean = rejectSuggestions(state);
|
|
1618
|
+
const restagedCommentIds = new Set(records.flatMap(({ commentId }) => commentId === void 0 ? [] : [commentId]));
|
|
1619
|
+
clean = withoutPendingSuggestionCommentMarks(clean, restagedCommentIds);
|
|
1620
|
+
let resolved = resolveAllChangesInHeadlessState(clean, "accept");
|
|
1621
|
+
const restaged = [];
|
|
1622
|
+
for (const record of records) {
|
|
1623
|
+
const snapshot = createStateSnapshot(resolved);
|
|
1624
|
+
const view = {
|
|
1625
|
+
state: resolved,
|
|
1626
|
+
dispatch: (transaction) => {
|
|
1627
|
+
view.state = view.state.apply(transaction);
|
|
1628
|
+
}
|
|
1629
|
+
};
|
|
1630
|
+
const applied = applyFolioDocumentOperations({
|
|
1631
|
+
view,
|
|
1632
|
+
snapshot,
|
|
1633
|
+
batch: {
|
|
1634
|
+
version: 1,
|
|
1635
|
+
mode: "suggested",
|
|
1636
|
+
operations: [record.operation]
|
|
1637
|
+
},
|
|
1638
|
+
story: story.type === "main" ? "main" : story,
|
|
1639
|
+
author: record.author,
|
|
1640
|
+
createCommentId: () => {
|
|
1641
|
+
if (record.commentId === void 0) panic("A staged comment suggestion has no comment id", { suggestionId: record.suggestionId });
|
|
1642
|
+
return record.commentId;
|
|
1643
|
+
}
|
|
1644
|
+
}).applied.find(({ id }) => id === record.operation.id);
|
|
1645
|
+
if (!applied) continue;
|
|
1646
|
+
restaged.push({
|
|
1647
|
+
snapshot,
|
|
1648
|
+
operation: record.operation,
|
|
1649
|
+
applied,
|
|
1650
|
+
author: record.author
|
|
1651
|
+
});
|
|
1652
|
+
resolved = view.state;
|
|
1653
|
+
}
|
|
1654
|
+
const restagedIds = new Set(getSuggestions(resolved).map(({ suggestionId }) => suggestionId));
|
|
1655
|
+
if (restaged.some(({ applied }) => !restagedIds.has(applied.suggestionId ?? applied.id))) panic("Bulk acceptance lost a pending suggestion");
|
|
1656
|
+
return {
|
|
1657
|
+
state: resolved,
|
|
1658
|
+
refresh: (activeSuggestionIds) => this.pendingSuggestions.replaceRestagedStory({
|
|
1659
|
+
story,
|
|
1660
|
+
restaged,
|
|
1661
|
+
activeSuggestionIds
|
|
1662
|
+
})
|
|
1663
|
+
};
|
|
1664
|
+
}
|
|
1282
1665
|
/** The current document model with edits merged back in. */
|
|
1283
1666
|
toDocument() {
|
|
1284
|
-
|
|
1667
|
+
const document = this.documentFromStateSnapshot(this.captureReviewerState());
|
|
1668
|
+
applyReplyThreadMarkers(document);
|
|
1669
|
+
return document;
|
|
1285
1670
|
}
|
|
1286
1671
|
captureReviewerState() {
|
|
1287
1672
|
const secondaryStoryStates = [];
|
|
@@ -1296,6 +1681,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1296
1681
|
secondaryStoryStates,
|
|
1297
1682
|
sectionReferenceRemovals: [...this.sectionReferenceRemovals],
|
|
1298
1683
|
removedHeaderFooterStories: [...this.removedHeaderFooterStories.values()],
|
|
1684
|
+
removedNoteStories: [...this.removedNoteStories.values()],
|
|
1299
1685
|
importedStyles: this.importedStyles,
|
|
1300
1686
|
importedMedia: new Map(this.importedMedia),
|
|
1301
1687
|
importedHeaders: new Map(this.importedHeaders),
|
|
@@ -1326,13 +1712,30 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1326
1712
|
document.package.footers.delete(handle.relationshipId);
|
|
1327
1713
|
}
|
|
1328
1714
|
this.mergeEditedSecondaryStories(document, snapshot.secondaryStoryStates);
|
|
1329
|
-
if (snapshot.
|
|
1715
|
+
if (snapshot.removedNoteStories.length > 0) {
|
|
1716
|
+
const candidates = new Set(snapshot.removedNoteStories.map(noteStoryKey));
|
|
1717
|
+
const referenced = referencedNotes(document, candidates);
|
|
1718
|
+
const removed = new Set([...candidates].filter((key) => !referenced.has(key)));
|
|
1719
|
+
const { footnotes, endnotes } = document.package;
|
|
1720
|
+
if (footnotes) document.package.footnotes = footnotes.filter((note) => !removed.has(noteStoryKey({
|
|
1721
|
+
type: "footnote",
|
|
1722
|
+
noteId: note.id
|
|
1723
|
+
})));
|
|
1724
|
+
if (endnotes) document.package.endnotes = endnotes.filter((note) => !removed.has(noteStoryKey({
|
|
1725
|
+
type: "endnote",
|
|
1726
|
+
noteId: note.id
|
|
1727
|
+
})));
|
|
1728
|
+
}
|
|
1729
|
+
const definitions = [...document.package.document.comments ?? [], ...snapshot.createdComments];
|
|
1730
|
+
const kept = this.keptCommentThreads(definitions, snapshot.mainState, snapshot.secondaryStoryStates);
|
|
1731
|
+
if (kept.length !== definitions.length || snapshot.createdComments.length > 0 || snapshot.resolvedOverrides.size > 0) document.package.document.comments = this.withResolvedOverrides(kept, snapshot.resolvedOverrides);
|
|
1330
1732
|
return document;
|
|
1331
1733
|
}
|
|
1332
1734
|
captureSaveSnapshot() {
|
|
1333
1735
|
const snapshot = this.captureReviewerState();
|
|
1736
|
+
const pendingCommentIds = new Set(this.exportPendingSuggestions().flatMap(({ commentId }) => commentId === void 0 ? [] : [commentId]));
|
|
1334
1737
|
const changedParaIds = new Set(getChangedParagraphIds(snapshot.mainState));
|
|
1335
|
-
let structuralChange = hasStructuralChanges(snapshot.mainState) || snapshot.finalSectionPropertiesOverride !== void 0 || snapshot.importedStyles !== void 0 || snapshot.importedHeaders.size > 0 || snapshot.importedFooters.size > 0;
|
|
1738
|
+
let structuralChange = hasStructuralChanges(snapshot.mainState) || snapshot.finalSectionPropertiesOverride !== void 0 || snapshot.importedStyles !== void 0 || snapshot.importedHeaders.size > 0 || snapshot.importedFooters.size > 0 || snapshot.removedNoteStories.length > 0;
|
|
1336
1739
|
let untrackedChanges = hasUntrackedChanges(snapshot.mainState);
|
|
1337
1740
|
const changedNoteParaIds = /* @__PURE__ */ new Set();
|
|
1338
1741
|
for (const entry of snapshot.secondaryStoryStates) {
|
|
@@ -1357,7 +1760,15 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1357
1760
|
reason: "untrackedChange"
|
|
1358
1761
|
};
|
|
1359
1762
|
return {
|
|
1360
|
-
document: this.documentFromStateSnapshot(
|
|
1763
|
+
document: this.documentFromStateSnapshot({
|
|
1764
|
+
...snapshot,
|
|
1765
|
+
mainState: withoutPendingSuggestionCommentMarks(rejectSuggestions(snapshot.mainState), pendingCommentIds),
|
|
1766
|
+
secondaryStoryStates: snapshot.secondaryStoryStates.map((entry) => ({
|
|
1767
|
+
...entry,
|
|
1768
|
+
state: withoutPendingSuggestionCommentMarks(rejectSuggestions(entry.state), pendingCommentIds)
|
|
1769
|
+
})),
|
|
1770
|
+
createdComments: snapshot.createdComments.filter(({ id }) => !pendingCommentIds.has(id))
|
|
1771
|
+
}),
|
|
1361
1772
|
path,
|
|
1362
1773
|
changedNoteParaIds,
|
|
1363
1774
|
sectionReferenceRemovals: snapshot.sectionReferenceRemovals,
|
|
@@ -1469,16 +1880,11 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1469
1880
|
const key = secondaryStoryKey(story);
|
|
1470
1881
|
const existing = this.secondaryStoryStates.get(key);
|
|
1471
1882
|
if (existing) return existing.state;
|
|
1472
|
-
const
|
|
1473
|
-
if (!
|
|
1474
|
-
const conversionOptions = {
|
|
1475
|
-
...this.baseDocument.package.styles !== void 0 && { styles: this.baseDocument.package.styles },
|
|
1476
|
-
...this.baseDocument.package.theme !== void 0 && { theme: this.baseDocument.package.theme }
|
|
1477
|
-
};
|
|
1478
|
-
const storyDoc = story.type === "header" || story.type === "footer" ? headerFooterToProseDoc(source.content, conversionOptions) : footnoteToProseDoc(source.content, conversionOptions);
|
|
1883
|
+
const doc = this.secondaryStoryDoc(story);
|
|
1884
|
+
if (!doc) return null;
|
|
1479
1885
|
const state = ensureBaseDirectionInState(EditorState.create({
|
|
1480
1886
|
schema,
|
|
1481
|
-
doc
|
|
1887
|
+
doc,
|
|
1482
1888
|
plugins: createHeadlessPlugins(this.baseDocument.package.styles, this.baseDocument.package.numbering)
|
|
1483
1889
|
}));
|
|
1484
1890
|
this.secondaryStoryStates.set(key, {
|
|
@@ -1488,6 +1894,25 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1488
1894
|
});
|
|
1489
1895
|
return state;
|
|
1490
1896
|
}
|
|
1897
|
+
/**
|
|
1898
|
+
* A secondary story as its editable state holds it: the loaded state's
|
|
1899
|
+
* document once an operation has loaded it, otherwise the conversion loading
|
|
1900
|
+
* performs — with the same deterministic block ids — without retaining a
|
|
1901
|
+
* state for a story nothing edits.
|
|
1902
|
+
*/
|
|
1903
|
+
readSecondaryStoryDoc(story) {
|
|
1904
|
+
return this.secondaryStoryStates.get(secondaryStoryKey(story))?.state.doc ?? this.secondaryStoryDoc(story);
|
|
1905
|
+
}
|
|
1906
|
+
secondaryStoryDoc(story) {
|
|
1907
|
+
const source = story.type === "header" || story.type === "footer" ? this.getHeaderFooterStory(story) : this.getNoteStory(story);
|
|
1908
|
+
if (!source) return null;
|
|
1909
|
+
const conversionOptions = {
|
|
1910
|
+
...this.baseDocument.package.styles !== void 0 && { styles: this.baseDocument.package.styles },
|
|
1911
|
+
...this.baseDocument.package.theme !== void 0 && { theme: this.baseDocument.package.theme }
|
|
1912
|
+
};
|
|
1913
|
+
const storyDoc = story.type === "header" || story.type === "footer" ? headerFooterToProseDoc(source.content, conversionOptions) : footnoteToProseDoc(source.content, conversionOptions);
|
|
1914
|
+
return ensureDeterministicParaIdsInDoc(storyDoc);
|
|
1915
|
+
}
|
|
1491
1916
|
requireEditableStoryState(story) {
|
|
1492
1917
|
const state = this.getEditableStoryState(story);
|
|
1493
1918
|
if (state) return state;
|
|
@@ -1650,12 +2075,14 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1650
2075
|
let endnotes;
|
|
1651
2076
|
for (const entry of secondaryStoryStates) {
|
|
1652
2077
|
if (entry.state === entry.initialState) continue;
|
|
2078
|
+
const lists = storyListNumbering(entry.state, document.package.numbering);
|
|
2079
|
+
if (lists.numbering) document.package.numbering = lists.numbering;
|
|
1653
2080
|
if (entry.handle.type === "header" || entry.handle.type === "footer") {
|
|
1654
2081
|
const source = entry.handle.type === "header" ? document.package.headers?.get(entry.handle.relationshipId) : document.package.footers?.get(entry.handle.relationshipId);
|
|
1655
2082
|
if (!source) continue;
|
|
1656
2083
|
const edited = {
|
|
1657
2084
|
...source,
|
|
1658
|
-
content: proseDocToBlocks(
|
|
2085
|
+
content: proseDocToBlocks(lists.doc, source.content, document.package.styles)
|
|
1659
2086
|
};
|
|
1660
2087
|
if (entry.handle.type === "header") {
|
|
1661
2088
|
headers ??= new Map(document.package.headers);
|
|
@@ -1672,7 +2099,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1672
2099
|
if (!source) continue;
|
|
1673
2100
|
const edited = {
|
|
1674
2101
|
...source,
|
|
1675
|
-
content: proseDocToBlocks(
|
|
2102
|
+
content: proseDocToBlocks(lists.doc, source.content, document.package.styles)
|
|
1676
2103
|
};
|
|
1677
2104
|
footnotes ??= [...document.package.footnotes ?? []];
|
|
1678
2105
|
const index = footnotes.findIndex((note) => note.id === noteId);
|
|
@@ -1684,7 +2111,7 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1684
2111
|
if (!source) continue;
|
|
1685
2112
|
const edited = {
|
|
1686
2113
|
...source,
|
|
1687
|
-
content: proseDocToBlocks(
|
|
2114
|
+
content: proseDocToBlocks(lists.doc, source.content, document.package.styles)
|
|
1688
2115
|
};
|
|
1689
2116
|
endnotes ??= [...document.package.endnotes ?? []];
|
|
1690
2117
|
const index = endnotes.findIndex((note) => note.id === noteId);
|
|
@@ -1706,13 +2133,55 @@ var FolioDocxReviewer = class FolioDocxReviewer {
|
|
|
1706
2133
|
};
|
|
1707
2134
|
});
|
|
1708
2135
|
}
|
|
1709
|
-
/**
|
|
2136
|
+
/**
|
|
2137
|
+
* `comments` without the threads an edit left anchored nowhere: anchored in
|
|
2138
|
+
* a story when it was loaded (or created anchored by this reviewer), and
|
|
2139
|
+
* anchored in no story now. See `comment-lifecycle.ts`.
|
|
2140
|
+
*/
|
|
2141
|
+
keptCommentThreads(comments, mainState, secondaryStoryStates) {
|
|
2142
|
+
const anchoredBefore = new Set(this.loadedMainCommentIds);
|
|
2143
|
+
for (const { id } of this.createdComments) anchoredBefore.add(id);
|
|
2144
|
+
const anchoredNow = anchoredCommentIdsInProseDoc(mainState.doc);
|
|
2145
|
+
const loaded = /* @__PURE__ */ new Map();
|
|
2146
|
+
for (const entry of secondaryStoryStates) loaded.set(secondaryStoryKey(entry.handle), entry);
|
|
2147
|
+
const addAll = (target, ids) => {
|
|
2148
|
+
for (const id of ids) target.add(id);
|
|
2149
|
+
};
|
|
2150
|
+
for (const handle of this.listStoryHandlesInternal()) {
|
|
2151
|
+
if (handle.type === "main") continue;
|
|
2152
|
+
const entry = loaded.get(secondaryStoryKey(handle));
|
|
2153
|
+
if (entry) {
|
|
2154
|
+
addAll(anchoredBefore, anchoredCommentIdsInProseDoc(entry.initialState.doc));
|
|
2155
|
+
addAll(anchoredNow, anchoredCommentIdsInProseDoc(entry.state.doc));
|
|
2156
|
+
continue;
|
|
2157
|
+
}
|
|
2158
|
+
addAll(anchoredNow, anchoredCommentIdsInBlocks((handle.type === "header" || handle.type === "footer" ? this.getHeaderFooterStory(handle) : this.getNoteStory(handle))?.content ?? []));
|
|
2159
|
+
}
|
|
2160
|
+
for (const handle of this.removedNoteStories.values()) {
|
|
2161
|
+
const entry = loaded.get(secondaryStoryKey(handle));
|
|
2162
|
+
addAll(anchoredBefore, entry ? anchoredCommentIdsInProseDoc(entry.initialState.doc) : anchoredCommentIdsInBlocks(this.getNoteStory(handle)?.content ?? []));
|
|
2163
|
+
}
|
|
2164
|
+
return withoutLostCommentThreads(comments, {
|
|
2165
|
+
anchoredBefore,
|
|
2166
|
+
anchoredNow
|
|
2167
|
+
});
|
|
2168
|
+
}
|
|
2169
|
+
/**
|
|
2170
|
+
* Map each anchored comment id to its anchored text, its containing block id
|
|
2171
|
+
* and the story holding it. A comment can be anchored in any story, so every
|
|
2172
|
+
* story is read, not only the body.
|
|
2173
|
+
*/
|
|
1710
2174
|
commentAnchors() {
|
|
1711
2175
|
const anchors = /* @__PURE__ */ new Map();
|
|
1712
|
-
for (const
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
2176
|
+
for (const story of this.listStoryHandlesInternal()) {
|
|
2177
|
+
const doc = story.type === "main" ? this.state.doc : this.readSecondaryStoryDoc(story);
|
|
2178
|
+
if (!doc) continue;
|
|
2179
|
+
for (const anchor of getCommentAnchorsFromDoc(doc)) if (!anchors.has(anchor.commentId)) anchors.set(anchor.commentId, {
|
|
2180
|
+
text: anchor.quote,
|
|
2181
|
+
blockId: anchor.blockId,
|
|
2182
|
+
story
|
|
2183
|
+
});
|
|
2184
|
+
}
|
|
1716
2185
|
return anchors;
|
|
1717
2186
|
}
|
|
1718
2187
|
/** Allocate outside every parsed or newly-created comment and reply id. */
|