@stll/folio-core 0.55.0 → 0.57.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/dist/ai-edits/apply.js +214 -52
- package/dist/ai-edits/batch-claims.d.ts +3 -1
- package/dist/ai-edits/batch-claims.js +25 -1
- package/dist/ai-edits/headless.js +2 -2
- package/dist/ai-edits/table-row-column-mutations.js +17 -3
- package/dist/ai-edits/types.d.ts +7 -1
- package/dist/ai-suggestions/apply.js +20 -1
- package/dist/compare/compare.js +1 -0
- package/dist/compare/inline-atoms.js +40 -16
- package/dist/compare/inline-provenance.js +12 -5
- package/dist/compare/reproducible-package.d.ts +0 -17
- package/dist/compare/reproducible-package.js +12 -18
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/controller/canonicalClipboard.d.ts +23 -0
- package/dist/controller/canonicalClipboard.js +482 -0
- package/dist/controller/canonicalClipboardResources.d.ts +21 -0
- package/dist/controller/canonicalClipboardResources.js +382 -0
- package/dist/controller/canonicalComments.d.ts +41 -0
- package/dist/controller/canonicalComments.js +152 -0
- package/dist/controller/canonicalComposition.d.ts +24 -3
- package/dist/controller/canonicalComposition.js +208 -48
- package/dist/controller/canonicalInlineProjection.d.ts +118 -0
- package/dist/controller/canonicalInlineProjection.js +476 -0
- package/dist/controller/canonicalInput.d.ts +13 -4
- package/dist/controller/canonicalInput.js +62 -14
- package/dist/controller/canonicalInputTimer.d.ts +16 -0
- package/dist/controller/canonicalInputTimer.js +34 -0
- package/dist/controller/canonicalPublicOperations.d.ts +48 -0
- package/dist/controller/canonicalPublicOperations.js +648 -0
- package/dist/controller/canonicalSelection.d.ts +18 -0
- package/dist/controller/canonicalSelection.js +32 -0
- package/dist/controller/canonicalSession.d.ts +27 -6
- package/dist/controller/canonicalSession.js +298 -116
- package/dist/controller/canonicalStoryEditor.d.ts +7 -3
- package/dist/controller/canonicalStoryEditor.js +27 -2
- package/dist/controller/canonicalStructure.js +57 -4
- package/dist/controller/canonicalTocSelection.d.ts +11 -0
- package/dist/controller/canonicalTocSelection.js +43 -0
- package/dist/controller/folioEditor.d.ts +2 -9
- package/dist/controller/folioEditor.js +18 -4
- package/dist/controller/headerFooterEditorManager.d.ts +2 -1
- package/dist/controller/headerFooterEditorManager.js +26 -11
- package/dist/controller/hiddenEditorApi.d.ts +24 -3
- package/dist/controller/hiddenEditorApi.js +8 -0
- package/dist/controller/hiddenEditorManager.d.ts +5 -1
- package/dist/controller/hiddenEditorManager.js +378 -43
- package/dist/controller/noteEditorManager.d.ts +2 -1
- package/dist/controller/noteEditorManager.js +29 -13
- package/dist/document-operations.d.ts +8 -1
- package/dist/document-operations.js +6 -4
- package/dist/docx/blockPlainText.d.ts +1 -1
- package/dist/docx/blockPlainText.js +11 -3
- package/dist/docx/builtInStyles.js +13 -6
- package/dist/docx/canonicalResourceSave.d.ts +16 -0
- package/dist/docx/canonicalResourceSave.js +27 -0
- package/dist/docx/canonicalSave.d.ts +29 -0
- package/dist/docx/canonicalSave.js +101 -0
- package/dist/docx/canonicalStoryRepack.d.ts +1 -1
- package/dist/docx/canonicalStoryRepack.js +38 -5
- package/dist/docx/containerChildren.gen.d.ts +3 -1
- package/dist/docx/containerChildren.gen.js +33 -1
- package/dist/docx/documentParser.d.ts +1 -13
- package/dist/docx/documentParser.js +1 -47
- package/dist/docx/ensureParaIds.js +10 -4
- package/dist/docx/fieldParser.js +14 -2
- package/dist/docx/footnoteParser.d.ts +1 -11
- package/dist/docx/footnoteParser.js +1 -16
- package/dist/docx/headerFooterParser.d.ts +1 -9
- package/dist/docx/headerFooterParser.js +1 -12
- package/dist/docx/headerFooterVerbatim.d.ts +26 -1
- package/dist/docx/headerFooterVerbatim.js +81 -3
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/hyperlinkParser.js +20 -1
- package/dist/docx/imageParser.d.ts +13 -1
- package/dist/docx/imageParser.js +20 -11
- package/dist/docx/inlineWrapperContent.d.ts +4 -4
- package/dist/docx/inlineWrapperContent.js +4 -4
- package/dist/docx/linkedSdtPreservation.d.ts +10 -0
- package/dist/docx/linkedSdtPreservation.js +37 -0
- package/dist/docx/metadataPrivacy.js +6 -1
- package/dist/docx/packageParts.js +9 -3
- package/dist/docx/paragraphParser.js +88 -67
- package/dist/docx/paragraphPropertySource.d.ts +22 -1
- package/dist/docx/paragraphPropertySource.js +109 -2
- package/dist/docx/parser.js +2 -1
- package/dist/docx/preservedRunContent.js +2 -1
- package/dist/docx/relsParser.js +26 -2
- package/dist/docx/removeHeaderFooterParts.js +17 -6
- package/dist/docx/rezip.d.ts +49 -5
- package/dist/docx/rezip.js +754 -235
- package/dist/docx/saveDiagnostics.d.ts +11 -0
- package/dist/docx/selectiveSave.d.ts +2 -1
- package/dist/docx/selectiveSave.js +42 -11
- package/dist/docx/selectiveXmlPatch.js +7 -5
- package/dist/docx/serializer/commentSerializer.d.ts +4 -1
- package/dist/docx/serializer/commentSerializer.js +7 -3
- package/dist/docx/serializer/documentSerializer.d.ts +9 -2
- package/dist/docx/serializer/documentSerializer.js +29 -10
- package/dist/docx/serializer/paragraphSerializer.js +207 -94
- package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
- package/dist/docx/server/materializeYjsDocx.js +14 -6
- package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
- package/dist/docx/storyBlockReplay.d.ts +21 -1
- package/dist/docx/storyBlockReplay.js +113 -9
- package/dist/docx/storyPlainText.d.ts +20 -0
- package/dist/docx/storyPlainText.js +23 -0
- package/dist/docx/structuralXmlPatch.js +10 -22
- package/dist/docx/styleParser.d.ts +5 -1
- package/dist/docx/styleParser.js +1 -1
- package/dist/docx/tableParser.d.ts +1 -8
- package/dist/docx/tableParser.js +1 -28
- package/dist/docx/textBoxParser.d.ts +1 -5
- package/dist/docx/textBoxParser.js +1 -20
- package/dist/docx/unzip.js +6 -1
- package/dist/i18n/messages/ar.gen.js +4 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +68 -0
- package/dist/i18n/messages/catalogs.gen.js +68 -0
- package/dist/i18n/messages/cs.gen.js +4 -0
- package/dist/i18n/messages/de.gen.js +4 -0
- package/dist/i18n/messages/en.gen.js +4 -0
- package/dist/i18n/messages/es.gen.js +4 -0
- package/dist/i18n/messages/et.gen.js +4 -0
- package/dist/i18n/messages/fr.gen.js +4 -0
- package/dist/i18n/messages/he.gen.js +4 -0
- package/dist/i18n/messages/hi.gen.js +4 -0
- package/dist/i18n/messages/hu.gen.js +4 -0
- package/dist/i18n/messages/lt.gen.js +4 -0
- package/dist/i18n/messages/lv.gen.js +4 -0
- package/dist/i18n/messages/messages.gen.d.ts +4 -0
- package/dist/i18n/messages/pl.gen.js +4 -0
- package/dist/i18n/messages/pt-BR.gen.js +4 -0
- package/dist/i18n/messages/sk.gen.js +4 -0
- package/dist/i18n/messages/tr.gen.js +4 -0
- package/dist/i18n/messages/zh-CN.gen.js +4 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/acceptedBlockProjection.d.ts +12 -0
- package/dist/internal/acceptedBlockProjection.js +45 -0
- package/dist/internal/revisionResolutionInline.js +25 -3
- package/dist/managers/DocumentLoaderManager.js +2 -1
- package/dist/markdown/escape.d.ts +3 -1
- package/dist/markdown/escape.js +9 -2
- package/dist/markdown/renderBlock.js +5 -120
- package/dist/markdown/renderParagraph.js +4 -2
- package/dist/markdown/renderRuns.d.ts +7 -1
- package/dist/markdown/renderRuns.js +33 -24
- package/dist/panel-layout.d.ts +11 -9
- package/dist/panel-layout.js +13 -9
- package/dist/prosemirror/addTrackedDeletionMark.d.ts +18 -0
- package/dist/prosemirror/addTrackedDeletionMark.js +87 -0
- package/dist/prosemirror/attrs/index.js +5 -0
- package/dist/prosemirror/canonicalCommands.d.ts +28 -4
- package/dist/prosemirror/canonicalCommands.js +11 -4
- package/dist/prosemirror/canonicalSelectionRange.d.ts +9 -0
- package/dist/prosemirror/canonicalSelectionRange.js +15 -0
- package/dist/prosemirror/clipboardIntent.d.ts +7 -0
- package/dist/prosemirror/clipboardIntent.js +9 -0
- package/dist/prosemirror/commands/comments.js +60 -35
- package/dist/prosemirror/commands/pageBreak.js +2 -2
- package/dist/prosemirror/commands/pastePlainText.js +2 -1
- package/dist/prosemirror/commands/propertyChangeScope.js +3 -6
- package/dist/prosemirror/commands/resolveParagraphProperties.js +22 -13
- package/dist/prosemirror/commentOps.js +15 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +22 -3
- package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
- package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -1
- package/dist/prosemirror/conversion/toProseDoc.js +124 -22
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +61 -35
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +74 -25
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +11 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +65 -29
- package/dist/prosemirror/extensions/marks/markUtils.js +11 -8
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
- package/dist/prosemirror/fieldRepresentation.d.ts +8 -0
- package/dist/prosemirror/fieldRepresentation.js +18 -0
- package/dist/prosemirror/hyperlinkRemoval.d.ts +13 -1
- package/dist/prosemirror/hyperlinkRemoval.js +28 -9
- package/dist/prosemirror/insertOperations.js +2 -1
- package/dist/prosemirror/listNumbering.js +11 -5
- package/dist/prosemirror/noteReferenceOccurrenceId.d.ts +5 -0
- package/dist/prosemirror/noteReferenceOccurrenceId.js +5 -0
- package/dist/prosemirror/noteReferenceOccurrences.d.ts +21 -0
- package/dist/prosemirror/noteReferenceOccurrences.js +185 -0
- package/dist/prosemirror/noteReferenceReview.js +14 -1
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
- package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
- package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
- package/dist/prosemirror/plugins/documentStyles.js +17 -10
- package/dist/prosemirror/plugins/suggestionMode.js +48 -48
- package/dist/prosemirror/preservedXmlReview.d.ts +6 -0
- package/dist/prosemirror/preservedXmlReview.js +35 -0
- package/dist/prosemirror/runFormattingFromMarks.js +2 -2
- package/dist/prosemirror/runFormattingReconciliation.js +5 -4
- package/dist/prosemirror/runPropertyChangeResolution.d.ts +8 -1
- package/dist/prosemirror/runPropertyChangeResolution.js +24 -2
- package/dist/prosemirror/runStyleFormatting.d.ts +3 -1
- package/dist/prosemirror/runStyleFormatting.js +3 -1
- package/dist/prosemirror/schema/marks.d.ts +1 -0
- package/dist/prosemirror/schema/nodes.d.ts +2 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.js +4 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +15 -15
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +69 -28
- package/dist/prosemirror/textInput.d.ts +5 -1
- package/dist/prosemirror/textInput.js +3 -3
- package/dist/prosemirror/trackedRevisionPath.d.ts +5 -1
- package/dist/prosemirror/trackedRevisionPath.js +39 -1
- package/dist/prosemirror/validation.js +3 -5
- package/dist/prosemirror/yjsDocumentMetadata.d.ts +9 -3
- package/dist/prosemirror/yjsDocumentMetadata.js +37 -8
- package/dist/types/canonicalCapabilities.d.ts +201 -0
- package/dist/types/canonicalCapabilities.js +198 -0
- package/dist/types/canonicalComments.d.ts +51 -0
- package/dist/types/canonicalComments.js +0 -0
- package/dist/types/canonicalSave.d.ts +11 -0
- package/dist/types/canonicalSave.js +0 -0
- package/dist/types/canonicalSections.d.ts +12 -0
- package/dist/types/canonicalSections.js +0 -0
- package/dist/types/docxSerialization.d.ts +14 -0
- package/dist/types/docxSerialization.js +7 -0
- package/dist/utils/headingCollector.js +45 -4
- package/dist/utils/outlineDepth.d.ts +9 -0
- package/dist/utils/outlineDepth.js +9 -0
- package/package.json +4 -4
|
@@ -2,24 +2,34 @@ import { recordHiddenEditorPhase, recordHiddenEditorStateCreate } from "../layou
|
|
|
2
2
|
import { suppressHiddenEditorScrollToSelection } from "../paged-layout/hiddenEditorScroll.js";
|
|
3
3
|
import { isReadOnlyEditKey } from "../paged-layout/readOnlyEditAttempt.js";
|
|
4
4
|
import { getCanonicalCommandIntents } from "../prosemirror/canonicalCommands.js";
|
|
5
|
+
import { registerClipboardIntentHandler } from "../prosemirror/clipboardIntent.js";
|
|
6
|
+
import { pasteWithoutFormatting } from "../prosemirror/commands/pastePlainText.js";
|
|
5
7
|
import { createEmptyDoc, toProseDoc } from "../prosemirror/conversion/toProseDoc.js";
|
|
6
8
|
import { registerEditorCommandOwner } from "../prosemirror/executeEditorCommand.js";
|
|
7
9
|
import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
|
|
8
10
|
import { ensureParaIdsInDoc, ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
|
|
9
11
|
import { createParagraphChangeTrackerPlugin, markPackageChange } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
|
|
10
12
|
import { toggleMarkForAllScripts, toggleUnderlineMark } from "../prosemirror/extensions/marks/markUtils.js";
|
|
13
|
+
import { HyperlinkRemovalRefusal } from "../prosemirror/hyperlinkRemoval.js";
|
|
14
|
+
import { markNoteReferenceReplay, noteReferenceTransactionIssue } from "../prosemirror/noteReferenceOccurrences.js";
|
|
11
15
|
import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
|
|
12
|
-
import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
16
|
+
import { createDocumentStyleContextPlugin, createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
13
17
|
import { schema } from "../prosemirror/schema/index.js";
|
|
14
18
|
import { createTextInputPlugin } from "../prosemirror/textInput.js";
|
|
15
19
|
import { applyAttrSchemaMigrations, proseDocumentParagraphSourceContract, readYjsAttrSchemaVersion, readYjsParagraphSourceContract, withParagraphSourceContract, writeYjsDocumentMetadata } from "../prosemirror/yjsDocumentMetadata.js";
|
|
20
|
+
import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
|
|
21
|
+
import { prepareCanonicalPaste } from "./canonicalClipboard.js";
|
|
22
|
+
import { canonicalCommentBody, compileCanonicalComments } from "./canonicalComments.js";
|
|
16
23
|
import { createCanonicalInputBoundary } from "./canonicalInput.js";
|
|
24
|
+
import { createCanonicalSectionPropertiesOperation } from "./canonicalOperations.js";
|
|
25
|
+
import { CanonicalPublicOperations } from "./canonicalPublicOperations.js";
|
|
26
|
+
import { restoreCanonicalSelection } from "./canonicalSelection.js";
|
|
17
27
|
import { createCanonicalSession, publishCanonicalProjection } from "./canonicalSession.js";
|
|
18
28
|
import { prepareCanonicalAutoformat, prepareCanonicalCommands } from "./canonicalStructure.js";
|
|
19
29
|
import { createHiddenEditorApi } from "./hiddenEditorApi.js";
|
|
20
30
|
import { Result, TaggedError, panic } from "better-result";
|
|
21
|
-
import { OP_STORIES } from "@stll/docx-core/ops";
|
|
22
|
-
import { EditorState } from "prosemirror-state";
|
|
31
|
+
import { OP_STORIES, freshCommentId } from "@stll/docx-core/ops";
|
|
32
|
+
import { EditorState, Plugin } from "prosemirror-state";
|
|
23
33
|
import { EditorView } from "prosemirror-view";
|
|
24
34
|
//#region src/controller/hiddenEditorManager.ts
|
|
25
35
|
var CanonicalSessionRefusalError = class extends TaggedError("CanonicalSessionRefusalError") {};
|
|
@@ -201,6 +211,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
201
211
|
let view = null;
|
|
202
212
|
let releaseCommandOwner;
|
|
203
213
|
let editorSession = { type: "prosemirror" };
|
|
214
|
+
let canonicalSessionEpoch = 0;
|
|
204
215
|
let modeOverride = null;
|
|
205
216
|
const syncCanonicalMode = () => {
|
|
206
217
|
if (editorSession.type !== "canonical") return;
|
|
@@ -209,12 +220,16 @@ const createHiddenEditorManager = (deps) => {
|
|
|
209
220
|
author: deps.getSuggestionAuthor?.() ?? "User"
|
|
210
221
|
} : { type: "editing" }));
|
|
211
222
|
};
|
|
212
|
-
const refuse = (reason) => {
|
|
213
|
-
|
|
214
|
-
|
|
223
|
+
const refuse = (reason, gap = CANONICAL_GAP.dispatch) => {
|
|
224
|
+
const message = reason;
|
|
225
|
+
if (deps.onSessionRefusal) deps.onSessionRefusal(message, gap);
|
|
226
|
+
else throw new CanonicalSessionRefusalError({
|
|
227
|
+
gap,
|
|
228
|
+
message
|
|
229
|
+
});
|
|
215
230
|
};
|
|
216
231
|
const seedSession = (document) => {
|
|
217
|
-
if (deps.getExperimentalSession?.()
|
|
232
|
+
if (!usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
|
|
218
233
|
editorSession = { type: "prosemirror" };
|
|
219
234
|
return true;
|
|
220
235
|
}
|
|
@@ -227,7 +242,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
227
242
|
reason,
|
|
228
243
|
documentIdentity
|
|
229
244
|
};
|
|
230
|
-
refuse(reason);
|
|
245
|
+
refuse(reason, CANONICAL_GAP.collaboration);
|
|
231
246
|
return false;
|
|
232
247
|
}
|
|
233
248
|
const result = createCanonicalSession(document, deps.getStyles());
|
|
@@ -237,13 +252,14 @@ const createHiddenEditorManager = (deps) => {
|
|
|
237
252
|
reason: result.error.message,
|
|
238
253
|
documentIdentity
|
|
239
254
|
};
|
|
240
|
-
refuse(result.error.message);
|
|
255
|
+
refuse(result.error.message, result.error.gap);
|
|
241
256
|
return false;
|
|
242
257
|
}
|
|
243
258
|
editorSession = {
|
|
244
259
|
type: "canonical",
|
|
245
260
|
session: result.value
|
|
246
261
|
};
|
|
262
|
+
canonicalSessionEpoch += 1;
|
|
247
263
|
modeOverride = null;
|
|
248
264
|
syncCanonicalMode();
|
|
249
265
|
return true;
|
|
@@ -252,11 +268,17 @@ const createHiddenEditorManager = (deps) => {
|
|
|
252
268
|
doc: session.projection.doc,
|
|
253
269
|
plugins: [
|
|
254
270
|
createParagraphChangeTrackerPlugin(),
|
|
255
|
-
|
|
256
|
-
createDocumentNumberingPlugin(session.document.package.numbering)
|
|
271
|
+
createDocumentStyleContextPlugin(deps.getStyles() ?? session.document.package.styles),
|
|
272
|
+
createDocumentNumberingPlugin(session.document.package.numbering),
|
|
273
|
+
...[...deps.getExtensionManager()?.getPlugins() ?? [], ...deps.getExternalPlugins()].flatMap(({ props }) => props.transformPastedHTML === void 0 && props.transformPasted === void 0 && props.transformCopied === void 0 && props.clipboardTextSerializer === void 0 ? [] : [new Plugin({ props: {
|
|
274
|
+
...props.transformCopied === void 0 ? {} : { transformCopied: props.transformCopied },
|
|
275
|
+
...props.clipboardTextSerializer === void 0 ? {} : { clipboardTextSerializer: props.clipboardTextSerializer },
|
|
276
|
+
...props.transformPastedHTML === void 0 ? {} : { transformPastedHTML: props.transformPastedHTML },
|
|
277
|
+
...props.transformPasted === void 0 ? {} : { transformPasted: props.transformPasted }
|
|
278
|
+
} })])
|
|
257
279
|
]
|
|
258
280
|
});
|
|
259
|
-
const publishCommit = (commit) => {
|
|
281
|
+
const publishCommit = (commit, reportRefusal = refuse) => {
|
|
260
282
|
if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return false;
|
|
261
283
|
const session = editorSession.session;
|
|
262
284
|
const result = publishCanonicalProjection({
|
|
@@ -265,7 +287,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
265
287
|
session
|
|
266
288
|
});
|
|
267
289
|
if (result.isErr()) {
|
|
268
|
-
|
|
290
|
+
reportRefusal(result.error.message, result.error.gap);
|
|
269
291
|
return false;
|
|
270
292
|
}
|
|
271
293
|
const staged = result.value;
|
|
@@ -284,7 +306,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
284
306
|
if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
|
|
285
307
|
const prepared = direction === "undo" ? session.prepareUndo(view.state) : session.prepareRedo(view.state);
|
|
286
308
|
if (prepared.isErr()) {
|
|
287
|
-
if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
|
|
309
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
288
310
|
return false;
|
|
289
311
|
}
|
|
290
312
|
return publishCommit(prepared.value);
|
|
@@ -292,11 +314,26 @@ const createHiddenEditorManager = (deps) => {
|
|
|
292
314
|
const executeCanonicalCommand = (command) => {
|
|
293
315
|
if (!view || editorSession.type !== "canonical") return void 0;
|
|
294
316
|
if (deps.getReadOnly()) return false;
|
|
317
|
+
if (command === pasteWithoutFormatting) return command(view.state, (transaction) => view?.dispatch(transaction), view);
|
|
295
318
|
if (editorSession.session.isComposing) {
|
|
296
319
|
refuse("Composition must finish before formatting.");
|
|
297
320
|
return false;
|
|
298
321
|
}
|
|
299
|
-
const
|
|
322
|
+
const commandState = view.state;
|
|
323
|
+
const described = Result.try({
|
|
324
|
+
try: () => getCanonicalCommandIntents(command, commandState),
|
|
325
|
+
catch: (error) => error
|
|
326
|
+
});
|
|
327
|
+
if (described.isErr()) {
|
|
328
|
+
if (!(described.error instanceof HyperlinkRemovalRefusal)) throw described.error;
|
|
329
|
+
const refusal = new CanonicalSessionRefusalError({
|
|
330
|
+
gap: CANONICAL_GAP.commands,
|
|
331
|
+
message: described.error.message
|
|
332
|
+
});
|
|
333
|
+
refuse(refusal.message, refusal.gap);
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
const intents = described.value;
|
|
300
337
|
if (intents === void 0) return void 0;
|
|
301
338
|
syncCanonicalMode();
|
|
302
339
|
editorSession.session.breakUndoGroup();
|
|
@@ -305,11 +342,12 @@ const createHiddenEditorManager = (deps) => {
|
|
|
305
342
|
}, view);
|
|
306
343
|
const prepared = prepareCanonicalCommands(editorSession.session, view.state, intents);
|
|
307
344
|
if (prepared.isErr()) {
|
|
308
|
-
if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
|
|
345
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
309
346
|
return false;
|
|
310
347
|
}
|
|
311
348
|
return publishCommit(prepared.value);
|
|
312
349
|
};
|
|
350
|
+
let clipboardDrag = { type: "idle" };
|
|
313
351
|
let lastInputRule;
|
|
314
352
|
const canonicalStructuralInput = {
|
|
315
353
|
command: (name) => {
|
|
@@ -324,7 +362,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
324
362
|
if (mark !== void 0) command = name === "toggleUnderline" ? toggleUnderlineMark(mark) : toggleMarkForAllScripts(mark, name === "toggleBold" ? "bold" : "italic");
|
|
325
363
|
}
|
|
326
364
|
if (command === void 0) {
|
|
327
|
-
refuse("The formatting command is unavailable.");
|
|
365
|
+
refuse("The formatting command is unavailable.", CANONICAL_GAP.commands);
|
|
328
366
|
return;
|
|
329
367
|
}
|
|
330
368
|
if (executeCanonicalCommand(command) === void 0) command(view.state, (transaction) => view?.dispatch(transaction), view);
|
|
@@ -336,7 +374,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
336
374
|
const state = view.state;
|
|
337
375
|
const selection = session.projection.selectionAt(state);
|
|
338
376
|
if (selection.isErr()) {
|
|
339
|
-
refuse(selection.error.message);
|
|
377
|
+
refuse(selection.error.message, selection.error.gap);
|
|
340
378
|
return;
|
|
341
379
|
}
|
|
342
380
|
let prepared;
|
|
@@ -386,11 +424,11 @@ const createHiddenEditorManager = (deps) => {
|
|
|
386
424
|
const from = session.projection.addressAt(state.selection.from);
|
|
387
425
|
const to = session.projection.addressAt(state.selection.to);
|
|
388
426
|
if (from.isErr()) {
|
|
389
|
-
refuse(from.error.message);
|
|
427
|
+
refuse(from.error.message, from.error.gap);
|
|
390
428
|
return;
|
|
391
429
|
}
|
|
392
430
|
if (to.isErr()) {
|
|
393
|
-
refuse(to.error.message);
|
|
431
|
+
refuse(to.error.message, to.error.gap);
|
|
394
432
|
return;
|
|
395
433
|
}
|
|
396
434
|
prepared = session.prepareIntent(state, {
|
|
@@ -407,7 +445,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
407
445
|
default: return type;
|
|
408
446
|
}
|
|
409
447
|
if (prepared.isErr()) {
|
|
410
|
-
if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
|
|
448
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
411
449
|
return;
|
|
412
450
|
}
|
|
413
451
|
publishCommit(prepared.value);
|
|
@@ -421,7 +459,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
421
459
|
if (deps.getReadOnly() || editorSession.type !== "canonical") return false;
|
|
422
460
|
const begun = editorSession.session.beginComposition();
|
|
423
461
|
if (begun.isErr()) {
|
|
424
|
-
refuse(begun.error.message);
|
|
462
|
+
refuse(begun.error.message, begun.error.gap);
|
|
425
463
|
return false;
|
|
426
464
|
}
|
|
427
465
|
return true;
|
|
@@ -431,6 +469,52 @@ const createHiddenEditorManager = (deps) => {
|
|
|
431
469
|
}
|
|
432
470
|
};
|
|
433
471
|
const input = createCanonicalInputBoundary({
|
|
472
|
+
pastePlainText: (pmView) => {
|
|
473
|
+
if (deps.getReadOnly()) {
|
|
474
|
+
deps.onReadOnlyEditAttempt();
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
pasteWithoutFormatting(pmView.state, (transaction) => pmView.dispatch(transaction), pmView);
|
|
478
|
+
},
|
|
479
|
+
cut: (pmView, event) => {
|
|
480
|
+
event.preventDefault();
|
|
481
|
+
if (deps.getReadOnly()) {
|
|
482
|
+
deps.onReadOnlyEditAttempt();
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
485
|
+
if (editorSession.type !== "canonical" || pmView.state.selection.empty) return true;
|
|
486
|
+
if (event.clipboardData === null) {
|
|
487
|
+
refuse("The clipboard cannot receive the cut content.");
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
syncCanonicalMode();
|
|
491
|
+
const session = editorSession.session;
|
|
492
|
+
const { from, to } = pmView.state.selection;
|
|
493
|
+
const prepared = session.prepareReplace(pmView.state, {
|
|
494
|
+
from,
|
|
495
|
+
to,
|
|
496
|
+
text: "",
|
|
497
|
+
semantic: "replacement"
|
|
498
|
+
});
|
|
499
|
+
if (prepared.isErr()) {
|
|
500
|
+
refuse(prepared.error.message, prepared.error.gap);
|
|
501
|
+
return true;
|
|
502
|
+
}
|
|
503
|
+
const copied = Result.try({
|
|
504
|
+
try: () => {
|
|
505
|
+
const serialized = pmView.serializeForClipboard(pmView.state.selection.content());
|
|
506
|
+
event.clipboardData?.setData("text/html", serialized.dom.innerHTML);
|
|
507
|
+
event.clipboardData?.setData("text/plain", serialized.text);
|
|
508
|
+
},
|
|
509
|
+
catch: () => new CanonicalSessionRefusalError({
|
|
510
|
+
gap: CANONICAL_GAP.dispatch,
|
|
511
|
+
message: "The clipboard could not receive the cut content."
|
|
512
|
+
})
|
|
513
|
+
});
|
|
514
|
+
if (copied.isErr()) refuse(copied.error.message, copied.error.gap);
|
|
515
|
+
else publishCommit(prepared.value);
|
|
516
|
+
return true;
|
|
517
|
+
},
|
|
434
518
|
...canonicalInputLifecycle,
|
|
435
519
|
...canonicalStructuralInput,
|
|
436
520
|
replace: (intent) => {
|
|
@@ -439,7 +523,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
439
523
|
const rule = prepareCanonicalAutoformat(editorSession.session, view.state, intent);
|
|
440
524
|
const prepared = rule ?? editorSession.session.prepareReplace(view.state, intent);
|
|
441
525
|
if (prepared.isErr()) {
|
|
442
|
-
if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
|
|
526
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
443
527
|
return;
|
|
444
528
|
}
|
|
445
529
|
const session = editorSession.session;
|
|
@@ -464,14 +548,14 @@ const createHiddenEditorManager = (deps) => {
|
|
|
464
548
|
if (!host) return;
|
|
465
549
|
const collaboration = deps.getCollaboration();
|
|
466
550
|
const collaborationModules = deps.getCollaborationModules();
|
|
467
|
-
if (collaboration && !collaborationModules && deps.getExperimentalSession?.()
|
|
551
|
+
if (collaboration && !collaborationModules && !usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) return;
|
|
468
552
|
const precomputedInitialState = deps.getPrecomputedInitialState();
|
|
469
553
|
const document = deps.getDocument();
|
|
470
554
|
const styles = deps.getStyles();
|
|
471
555
|
const extensionManager = deps.getExtensionManager();
|
|
472
556
|
const externalPlugins = deps.getExternalPlugins();
|
|
473
|
-
if (!seedSession(document)) return;
|
|
474
557
|
input.reset();
|
|
558
|
+
if (!seedSession(document)) return;
|
|
475
559
|
const editorProps = {
|
|
476
560
|
state: (() => {
|
|
477
561
|
if (editorSession.type === "canonical") return canonicalState(editorSession.session);
|
|
@@ -505,7 +589,11 @@ const createHiddenEditorManager = (deps) => {
|
|
|
505
589
|
lastInputRule = void 0;
|
|
506
590
|
editorSession.session.breakUndoGroup();
|
|
507
591
|
}
|
|
592
|
+
const modules = deps.getCollaborationModules();
|
|
593
|
+
if (modules && transaction.getMeta(modules.yProseMirror.ySyncPluginKey) !== void 0) markNoteReferenceReplay(transaction);
|
|
508
594
|
const applied = view.state.applyTransaction(transaction);
|
|
595
|
+
const noteIssue = noteReferenceTransactionIssue(transaction);
|
|
596
|
+
if (noteIssue) deps.onSessionRefusal?.(noteIssue.message, CANONICAL_GAP.dispatch, noteIssue);
|
|
509
597
|
if (editorSession.type === "canonical" && !applied.state.doc.eq(view.state.doc)) {
|
|
510
598
|
refuse("A plugin attempted an unclassified canonical document mutation.");
|
|
511
599
|
return;
|
|
@@ -533,16 +621,79 @@ const createHiddenEditorManager = (deps) => {
|
|
|
533
621
|
return deps.onKeyDown(pmView, event);
|
|
534
622
|
},
|
|
535
623
|
handleTextInput: (pmView, from, to, text) => editorSession.type === "canonical" ? input.handleTextInput(pmView, from, to, text) : false,
|
|
624
|
+
handlePaste: (pmView, _event, slice) => {
|
|
625
|
+
if (editorSession.type !== "canonical") return false;
|
|
626
|
+
if (deps.getReadOnly()) {
|
|
627
|
+
deps.onReadOnlyEditAttempt();
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
syncCanonicalMode();
|
|
631
|
+
const prepared = prepareCanonicalPaste({
|
|
632
|
+
session: editorSession.session,
|
|
633
|
+
state: pmView.state,
|
|
634
|
+
slice
|
|
635
|
+
});
|
|
636
|
+
if (prepared.isErr()) {
|
|
637
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
638
|
+
} else publishCommit(prepared.value);
|
|
639
|
+
return true;
|
|
640
|
+
},
|
|
641
|
+
handleDrop: (pmView, event, slice, moved) => {
|
|
642
|
+
if (editorSession.type !== "canonical") return false;
|
|
643
|
+
if (deps.getReadOnly()) {
|
|
644
|
+
deps.onReadOnlyEditAttempt();
|
|
645
|
+
return true;
|
|
646
|
+
}
|
|
647
|
+
const target = pmView.posAtCoords({
|
|
648
|
+
left: event.clientX,
|
|
649
|
+
top: event.clientY
|
|
650
|
+
})?.pos;
|
|
651
|
+
if (target === void 0) {
|
|
652
|
+
refuse("The drop has no document destination.");
|
|
653
|
+
return true;
|
|
654
|
+
}
|
|
655
|
+
const captured = clipboardDrag;
|
|
656
|
+
clipboardDrag = { type: "idle" };
|
|
657
|
+
if (moved && (captured.type !== "dragging" || captured.session !== editorSession.session || captured.version !== editorSession.session.version)) {
|
|
658
|
+
refuse("The dragged content changed or has no captured source.");
|
|
659
|
+
return true;
|
|
660
|
+
}
|
|
661
|
+
const source = captured.type === "dragging" ? {
|
|
662
|
+
from: captured.from,
|
|
663
|
+
to: captured.to
|
|
664
|
+
} : pmView.state.selection;
|
|
665
|
+
if (moved && target >= source.from && target <= source.to) return true;
|
|
666
|
+
syncCanonicalMode();
|
|
667
|
+
const prepared = prepareCanonicalPaste({
|
|
668
|
+
session: editorSession.session,
|
|
669
|
+
state: pmView.state,
|
|
670
|
+
slice,
|
|
671
|
+
...moved ? {
|
|
672
|
+
moveTarget: target,
|
|
673
|
+
moveSource: {
|
|
674
|
+
from: source.from,
|
|
675
|
+
to: source.to
|
|
676
|
+
}
|
|
677
|
+
} : { pasteTarget: target }
|
|
678
|
+
});
|
|
679
|
+
if (prepared.isErr()) {
|
|
680
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
681
|
+
} else publishCommit(prepared.value);
|
|
682
|
+
return true;
|
|
683
|
+
},
|
|
536
684
|
handleScrollToSelection: suppressHiddenEditorScrollToSelection,
|
|
537
685
|
handleDOMEvents: {
|
|
686
|
+
keydown: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.keydown(pmView, event) : false,
|
|
538
687
|
focus: () => false,
|
|
539
688
|
blur: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.blur(pmView) : false,
|
|
540
689
|
...createHiddenEditorClipboardHandlers(deps),
|
|
541
|
-
mousedown: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.mousedown(pmView) : false,
|
|
542
690
|
compositionstart: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.compositionstart(pmView) : false,
|
|
543
691
|
compositionend: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.compositionend(pmView) : false,
|
|
544
692
|
input: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.input(pmView) : false,
|
|
545
|
-
paste: (pmView, event) =>
|
|
693
|
+
paste: (pmView, event) => {
|
|
694
|
+
if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.paste(pmView, event);
|
|
695
|
+
return createHiddenEditorClipboardHandlers(deps).paste(pmView, event);
|
|
696
|
+
},
|
|
546
697
|
cut: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.cut(pmView, event) : createHiddenEditorClipboardHandlers(deps).cut(pmView, event),
|
|
547
698
|
beforeinput: (_view, event) => {
|
|
548
699
|
if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.beforeinput(_view, event);
|
|
@@ -551,8 +702,22 @@ const createHiddenEditorManager = (deps) => {
|
|
|
551
702
|
event.preventDefault();
|
|
552
703
|
return true;
|
|
553
704
|
},
|
|
705
|
+
dragstart: (pmView) => {
|
|
706
|
+
if (editorSession.type === "canonical") clipboardDrag = {
|
|
707
|
+
type: "dragging",
|
|
708
|
+
session: editorSession.session,
|
|
709
|
+
version: editorSession.session.version,
|
|
710
|
+
from: pmView.state.selection.from,
|
|
711
|
+
to: pmView.state.selection.to
|
|
712
|
+
};
|
|
713
|
+
return false;
|
|
714
|
+
},
|
|
715
|
+
dragend: () => {
|
|
716
|
+
clipboardDrag = { type: "idle" };
|
|
717
|
+
return false;
|
|
718
|
+
},
|
|
554
719
|
drop: (_view, event) => {
|
|
555
|
-
if (editorSession.type === "canonical") return input.handleDOMEvents.drop(_view, event);
|
|
720
|
+
if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.drop(_view, event);
|
|
556
721
|
if (!deps.getReadOnly()) return false;
|
|
557
722
|
deps.onReadOnlyEditAttempt();
|
|
558
723
|
event.preventDefault();
|
|
@@ -562,6 +727,25 @@ const createHiddenEditorManager = (deps) => {
|
|
|
562
727
|
};
|
|
563
728
|
const viewStartedAt = performance.now();
|
|
564
729
|
view = new EditorView(host, editorProps);
|
|
730
|
+
if (editorSession.type === "canonical") registerClipboardIntentHandler(view, (slice, plain) => {
|
|
731
|
+
if (!view || editorSession.type !== "canonical") return false;
|
|
732
|
+
if (deps.getReadOnly()) {
|
|
733
|
+
deps.onReadOnlyEditAttempt();
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
syncCanonicalMode();
|
|
737
|
+
const prepared = prepareCanonicalPaste({
|
|
738
|
+
session: editorSession.session,
|
|
739
|
+
state: view.state,
|
|
740
|
+
slice,
|
|
741
|
+
plain
|
|
742
|
+
});
|
|
743
|
+
if (prepared.isErr()) {
|
|
744
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
return publishCommit(prepared.value);
|
|
748
|
+
});
|
|
565
749
|
releaseCommandOwner = registerEditorCommandOwner(view, executeCanonicalCommand);
|
|
566
750
|
recordHiddenEditorPhase("mount", "editor-view", performance.now() - viewStartedAt);
|
|
567
751
|
syncHiddenEditorAccessibility(view, deps.getReadOnly());
|
|
@@ -592,21 +776,22 @@ const createHiddenEditorManager = (deps) => {
|
|
|
592
776
|
};
|
|
593
777
|
const syncExternalDocument = () => {
|
|
594
778
|
if (!view || isDestroying) return;
|
|
779
|
+
const canonicalRequested = usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
|
|
595
780
|
const collaboration = deps.getCollaboration();
|
|
596
781
|
const collaborationModules = deps.getCollaborationModules();
|
|
597
|
-
if (collaboration && !collaborationModules &&
|
|
782
|
+
if (collaboration && !collaborationModules && !canonicalRequested) return;
|
|
598
783
|
const document = deps.getDocument();
|
|
599
784
|
const currentDocId = deps.getDocumentIdentity();
|
|
600
785
|
const currentCollaborationFragment = collaboration?.yXmlFragment ?? null;
|
|
601
786
|
const collaborationSourceChanged = currentCollaborationFragment !== lastCollaborationFragment;
|
|
602
|
-
const sessionChanged = editorSession.type !== "prosemirror" !==
|
|
787
|
+
const sessionChanged = editorSession.type !== "prosemirror" !== canonicalRequested;
|
|
603
788
|
if (collaboration && !collaborationSourceChanged && !sessionChanged) return;
|
|
604
789
|
if (isInitialized && currentDocId === lastDocumentId && !collaborationSourceChanged && !sessionChanged) return;
|
|
790
|
+
input.reset();
|
|
605
791
|
if (!seedSession(document)) {
|
|
606
792
|
destroyView();
|
|
607
793
|
return;
|
|
608
794
|
}
|
|
609
|
-
input.reset();
|
|
610
795
|
isInitialized = true;
|
|
611
796
|
lastDocumentId = currentDocId;
|
|
612
797
|
lastCollaborationFragment = currentCollaborationFragment;
|
|
@@ -631,13 +816,20 @@ const createHiddenEditorManager = (deps) => {
|
|
|
631
816
|
};
|
|
632
817
|
const publishStoryCommit = (storyView, commit) => {
|
|
633
818
|
if (!view || editorSession.type !== "canonical") return false;
|
|
634
|
-
if (deps.getEditingMode?.() === "suggesting") {
|
|
635
|
-
refuse("Suggesting is unavailable in the experimental canonical session.");
|
|
636
|
-
return false;
|
|
637
|
-
}
|
|
638
819
|
const session = editorSession.session;
|
|
639
820
|
const bodyTransaction = view.state.tr;
|
|
640
821
|
if (!bodyTransaction.doc.eq(commit.bodyProjection.doc)) bodyTransaction.replaceWith(0, bodyTransaction.doc.content.size, commit.bodyProjection.doc.content);
|
|
822
|
+
if (commit.selection.anchor.story === OP_STORIES.MAIN && commit.selection.head.story === OP_STORIES.MAIN) {
|
|
823
|
+
if (!restoreCanonicalSelection({
|
|
824
|
+
transaction: bodyTransaction,
|
|
825
|
+
projection: commit.bodyProjection,
|
|
826
|
+
selection: commit.selection,
|
|
827
|
+
unavailable: { type: "refuse" }
|
|
828
|
+
})) {
|
|
829
|
+
refuse("The canonical body history selection is unavailable.");
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
641
833
|
markPackageChange(bodyTransaction);
|
|
642
834
|
bodyTransaction.setMeta("addToHistory", false);
|
|
643
835
|
const bodyStaged = Result.try(() => view?.state.applyTransaction(bodyTransaction));
|
|
@@ -651,7 +843,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
651
843
|
session
|
|
652
844
|
});
|
|
653
845
|
if (staged.isErr()) {
|
|
654
|
-
refuse(staged.error.message);
|
|
846
|
+
refuse(staged.error.message, staged.error.gap);
|
|
655
847
|
return false;
|
|
656
848
|
}
|
|
657
849
|
storyView.updateState(staged.value.state);
|
|
@@ -664,6 +856,23 @@ const createHiddenEditorManager = (deps) => {
|
|
|
664
856
|
deps.onSelectionChange(view.state);
|
|
665
857
|
return true;
|
|
666
858
|
};
|
|
859
|
+
let publicOperations = null;
|
|
860
|
+
const getPublicOperations = () => {
|
|
861
|
+
if (editorSession.type !== "canonical") return null;
|
|
862
|
+
const session = editorSession.session;
|
|
863
|
+
if (publicOperations?.session === session) return publicOperations.executor;
|
|
864
|
+
const executor = new CanonicalPublicOperations({
|
|
865
|
+
session,
|
|
866
|
+
getState: (story) => story === OP_STORIES.MAIN && !deps.getReadOnly() && !isDestroying ? view?.state ?? null : null,
|
|
867
|
+
publish: publishCommit
|
|
868
|
+
});
|
|
869
|
+
publicOperations = {
|
|
870
|
+
session,
|
|
871
|
+
executor
|
|
872
|
+
};
|
|
873
|
+
return executor;
|
|
874
|
+
};
|
|
875
|
+
const isCanonicalModelSessionRequested = () => usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
|
|
667
876
|
return {
|
|
668
877
|
ensureView,
|
|
669
878
|
retryViewCreation,
|
|
@@ -676,6 +885,10 @@ const createHiddenEditorManager = (deps) => {
|
|
|
676
885
|
api: createHiddenEditorApi({
|
|
677
886
|
getView: () => view,
|
|
678
887
|
getDocumentContext: () => editorSession.type === "refused" ? null : deps.getDocumentContext(),
|
|
888
|
+
getCanonicalComments: () => editorSession.type === "canonical" ? editorSession.session.getCommittedComments() : null,
|
|
889
|
+
getCanonicalCommittedVersion: () => editorSession.type === "canonical" ? `${canonicalSessionEpoch}:${editorSession.session.version}` : null,
|
|
890
|
+
isCanonicalSaveCurrent: (version) => editorSession.type === "canonical" && !editorSession.session.isComposing && editorSession.session.version === version,
|
|
891
|
+
captureCanonicalSave: () => editorSession.type === "canonical" ? editorSession.session.captureSaveSnapshot() : null,
|
|
679
892
|
getCanonicalDocument: () => editorSession.type === "canonical" ? editorSession.session.document : null,
|
|
680
893
|
setCanonicalMode: (mode) => {
|
|
681
894
|
if (editorSession.type !== "canonical") return false;
|
|
@@ -690,7 +903,7 @@ const createHiddenEditorManager = (deps) => {
|
|
|
690
903
|
resolution
|
|
691
904
|
});
|
|
692
905
|
if (prepared.isErr()) {
|
|
693
|
-
if (prepared.error.reason !== "noChange") refuse(prepared.error.message);
|
|
906
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
694
907
|
return false;
|
|
695
908
|
}
|
|
696
909
|
return publishCommit(prepared.value);
|
|
@@ -703,6 +916,125 @@ const createHiddenEditorManager = (deps) => {
|
|
|
703
916
|
canRedo: () => editorSession.type === "canonical" && editorSession.session.canRedo
|
|
704
917
|
} : null,
|
|
705
918
|
canonicalOperations: {
|
|
919
|
+
applyCanonicalSectionProperties: (patch) => {
|
|
920
|
+
ensureView();
|
|
921
|
+
const fail = (message) => {
|
|
922
|
+
refuse(message, CANONICAL_GAP.sectionProperties);
|
|
923
|
+
return {
|
|
924
|
+
status: "refused",
|
|
925
|
+
gap: CANONICAL_GAP.sectionProperties,
|
|
926
|
+
message
|
|
927
|
+
};
|
|
928
|
+
};
|
|
929
|
+
if (editorSession.type === "refused") return fail(editorSession.reason);
|
|
930
|
+
if (editorSession.type !== "canonical") {
|
|
931
|
+
if (isCanonicalModelSessionRequested()) return fail("The canonical document is not ready for section changes.");
|
|
932
|
+
return null;
|
|
933
|
+
}
|
|
934
|
+
if (!view || deps.getReadOnly() || isDestroying) return fail("The document is not editable.");
|
|
935
|
+
const session = editorSession.session;
|
|
936
|
+
if (session.isComposing) return fail("Section properties cannot change during composition.");
|
|
937
|
+
const prepared = session.prepareOperations(view.state, [createCanonicalSectionPropertiesOperation(session.document, patch)]);
|
|
938
|
+
if (prepared.isErr()) return fail(prepared.error.message);
|
|
939
|
+
let failureMessage = "The section projection could not publish.";
|
|
940
|
+
if (!publishCommit(prepared.value, (message) => {
|
|
941
|
+
failureMessage = message;
|
|
942
|
+
})) return fail(failureMessage);
|
|
943
|
+
return {
|
|
944
|
+
status: "applied",
|
|
945
|
+
version: session.version
|
|
946
|
+
};
|
|
947
|
+
},
|
|
948
|
+
applyCanonicalComment: (request) => {
|
|
949
|
+
ensureView();
|
|
950
|
+
const fail = (message, retry = "never") => {
|
|
951
|
+
if (retry === "never") refuse(message, CANONICAL_GAP.comments);
|
|
952
|
+
return {
|
|
953
|
+
status: "refused",
|
|
954
|
+
gap: CANONICAL_GAP.comments,
|
|
955
|
+
message,
|
|
956
|
+
retry
|
|
957
|
+
};
|
|
958
|
+
};
|
|
959
|
+
if (editorSession.type === "refused") return fail(editorSession.reason);
|
|
960
|
+
if (editorSession.type !== "canonical") {
|
|
961
|
+
if (isCanonicalModelSessionRequested()) return fail("The canonical document is not ready for comment changes.");
|
|
962
|
+
return null;
|
|
963
|
+
}
|
|
964
|
+
if (!view || deps.getReadOnly()) return fail("The document is not editable.");
|
|
965
|
+
const session = editorSession.session;
|
|
966
|
+
if (session.isComposing) return fail("Comments cannot change during composition.", "afterComposition");
|
|
967
|
+
let command;
|
|
968
|
+
if (request.type === "create") {
|
|
969
|
+
const id = freshCommentId(session.document);
|
|
970
|
+
if (id.isErr()) return fail(id.error.message);
|
|
971
|
+
let anchor;
|
|
972
|
+
switch (request.anchor.kind) {
|
|
973
|
+
case "selection": {
|
|
974
|
+
const projection = session.projectStory(request.anchor.story);
|
|
975
|
+
if (projection.isErr()) return fail(projection.error.message);
|
|
976
|
+
const from = projection.value.addressAt(request.anchor.from);
|
|
977
|
+
const to = projection.value.addressAt(request.anchor.to);
|
|
978
|
+
if (from.isErr()) return fail(from.error.message);
|
|
979
|
+
if (to.isErr()) return fail(to.error.message);
|
|
980
|
+
anchor = request.anchor.from === request.anchor.to ? {
|
|
981
|
+
kind: "point",
|
|
982
|
+
at: from.value
|
|
983
|
+
} : {
|
|
984
|
+
kind: "range",
|
|
985
|
+
from: from.value,
|
|
986
|
+
to: to.value
|
|
987
|
+
};
|
|
988
|
+
break;
|
|
989
|
+
}
|
|
990
|
+
case "reply":
|
|
991
|
+
anchor = {
|
|
992
|
+
kind: "reply",
|
|
993
|
+
parentId: request.anchor.parentId
|
|
994
|
+
};
|
|
995
|
+
break;
|
|
996
|
+
case "revision":
|
|
997
|
+
anchor = {
|
|
998
|
+
kind: "revision",
|
|
999
|
+
story: request.anchor.story,
|
|
1000
|
+
revisionId: request.anchor.revisionId
|
|
1001
|
+
};
|
|
1002
|
+
break;
|
|
1003
|
+
default: return request.anchor;
|
|
1004
|
+
}
|
|
1005
|
+
command = {
|
|
1006
|
+
type: "create",
|
|
1007
|
+
anchor,
|
|
1008
|
+
comment: {
|
|
1009
|
+
id: id.value,
|
|
1010
|
+
author: request.author,
|
|
1011
|
+
done: false,
|
|
1012
|
+
date: request.date ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1013
|
+
content: canonicalCommentBody(session.document, request.text)
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
} else command = request;
|
|
1017
|
+
const compiled = compileCanonicalComments({
|
|
1018
|
+
document: session.document,
|
|
1019
|
+
command
|
|
1020
|
+
});
|
|
1021
|
+
if (compiled.isErr()) return fail(compiled.error.message);
|
|
1022
|
+
if (compiled.value.ops.length > 0) {
|
|
1023
|
+
const prepared = session.prepareOperations(view.state, compiled.value.ops);
|
|
1024
|
+
if (prepared.isErr()) return fail(prepared.error.message);
|
|
1025
|
+
if (!publishCommit(prepared.value)) return fail("The comment projection could not publish.");
|
|
1026
|
+
}
|
|
1027
|
+
return {
|
|
1028
|
+
status: "applied",
|
|
1029
|
+
comments: session.getCommittedComments(),
|
|
1030
|
+
...compiled.value.commentId === void 0 ? {} : { commentId: compiled.value.commentId }
|
|
1031
|
+
};
|
|
1032
|
+
},
|
|
1033
|
+
applyCanonicalDocumentOperations: (options) => {
|
|
1034
|
+
ensureView();
|
|
1035
|
+
return getPublicOperations()?.apply(options) ?? null;
|
|
1036
|
+
},
|
|
1037
|
+
undoCanonicalDocumentOperations: (handle) => getPublicOperations()?.undo(handle) ?? null,
|
|
706
1038
|
updateCanonicalInputLifecycle: (action) => {
|
|
707
1039
|
if (editorSession.type !== "canonical") return false;
|
|
708
1040
|
switch (action) {
|
|
@@ -732,11 +1064,12 @@ const createHiddenEditorManager = (deps) => {
|
|
|
732
1064
|
applyCanonicalStoryHistory: ({ view: storyView, story, direction }) => {
|
|
733
1065
|
if (story === OP_STORIES.MAIN && storyView === view) return history(direction);
|
|
734
1066
|
if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
|
|
1067
|
+
syncCanonicalMode();
|
|
735
1068
|
const session = editorSession.session;
|
|
736
1069
|
if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
|
|
737
1070
|
const prepared = direction === "undo" ? session.prepareUndo(storyView.state, story) : session.prepareRedo(storyView.state, story);
|
|
738
1071
|
if (prepared.isErr()) {
|
|
739
|
-
refuse(prepared.error.message);
|
|
1072
|
+
refuse(prepared.error.message, prepared.error.gap);
|
|
740
1073
|
return false;
|
|
741
1074
|
}
|
|
742
1075
|
return publishStoryCommit(storyView, prepared.value);
|
|
@@ -746,29 +1079,30 @@ const createHiddenEditorManager = (deps) => {
|
|
|
746
1079
|
if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
|
|
747
1080
|
const prepared = editorSession.session.prepareOperations(view.state, ops);
|
|
748
1081
|
if (prepared.isErr()) {
|
|
749
|
-
refuse(prepared.error.message);
|
|
1082
|
+
refuse(prepared.error.message, prepared.error.gap);
|
|
750
1083
|
return false;
|
|
751
1084
|
}
|
|
752
1085
|
return publishCommit(prepared.value);
|
|
753
1086
|
},
|
|
754
1087
|
getCanonicalStoryProjection: (story) => {
|
|
755
|
-
if (deps.getExperimentalSession?.()
|
|
1088
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) ensureView();
|
|
756
1089
|
if (editorSession.type !== "canonical" || editorSession.session.isComposing) return null;
|
|
757
1090
|
const result = editorSession.session.projectStory(story);
|
|
758
1091
|
if (result.isErr()) {
|
|
759
|
-
refuse(result.error.message);
|
|
1092
|
+
refuse(result.error.message, result.error.gap);
|
|
760
1093
|
return null;
|
|
761
1094
|
}
|
|
762
1095
|
return result.value.doc;
|
|
763
1096
|
},
|
|
764
1097
|
replaceCanonicalStoryText: ({ view: storyView, story, intent }) => {
|
|
765
1098
|
if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
|
|
1099
|
+
syncCanonicalMode();
|
|
766
1100
|
const prepared = editorSession.session.prepareReplace(storyView.state, {
|
|
767
1101
|
...intent,
|
|
768
1102
|
story
|
|
769
1103
|
});
|
|
770
1104
|
if (prepared.isErr()) {
|
|
771
|
-
refuse(prepared.error.message);
|
|
1105
|
+
refuse(prepared.error.message, prepared.error.gap);
|
|
772
1106
|
return false;
|
|
773
1107
|
}
|
|
774
1108
|
return publishStoryCommit(storyView, prepared.value);
|
|
@@ -777,7 +1111,8 @@ const createHiddenEditorManager = (deps) => {
|
|
|
777
1111
|
isDestroying: () => isDestroying,
|
|
778
1112
|
ensureView,
|
|
779
1113
|
isViewRequested
|
|
780
|
-
})
|
|
1114
|
+
}),
|
|
1115
|
+
isCanonicalComposing: () => editorSession.type === "canonical" && editorSession.session.isComposing
|
|
781
1116
|
};
|
|
782
1117
|
};
|
|
783
1118
|
//#endregion
|