@stll/folio-core 0.54.2 → 0.56.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 +185 -33
- package/dist/ai-edits/headless.js +3 -2
- package/dist/ai-edits/types.d.ts +7 -1
- package/dist/compare/compare.js +1 -0
- package/dist/compare/content-types.d.ts +3 -15
- package/dist/compare/reproducible-package.d.ts +0 -17
- package/dist/compare/reproducible-package.js +12 -18
- package/dist/controller/canonicalClipboard.d.ts +23 -0
- package/dist/controller/canonicalClipboard.js +476 -0
- package/dist/controller/canonicalClipboardResources.d.ts +21 -0
- package/dist/controller/canonicalClipboardResources.js +382 -0
- package/dist/controller/canonicalComposition.d.ts +53 -0
- package/dist/controller/canonicalComposition.js +296 -0
- package/dist/controller/canonicalInlineProjection.d.ts +113 -0
- package/dist/controller/canonicalInlineProjection.js +393 -0
- package/dist/controller/canonicalInput.d.ts +54 -0
- package/dist/controller/canonicalInput.js +377 -0
- package/dist/controller/canonicalInputTimer.d.ts +7 -0
- package/dist/controller/canonicalInputTimer.js +11 -0
- package/dist/controller/canonicalOperations.d.ts +22 -0
- package/dist/controller/canonicalOperations.js +85 -0
- package/dist/controller/canonicalPublicOperations.d.ts +48 -0
- package/dist/controller/canonicalPublicOperations.js +556 -0
- package/dist/controller/canonicalReview.d.ts +12 -0
- package/dist/controller/canonicalReview.js +19 -0
- package/dist/controller/canonicalSession.d.ts +167 -0
- package/dist/controller/canonicalSession.js +1186 -0
- package/dist/controller/canonicalStoryEditor.d.ts +36 -0
- package/dist/controller/canonicalStoryEditor.js +87 -0
- package/dist/controller/canonicalStructure.d.ts +16 -0
- package/dist/controller/canonicalStructure.js +322 -0
- package/dist/controller/canonicalTocSelection.d.ts +11 -0
- package/dist/controller/canonicalTocSelection.js +43 -0
- package/dist/controller/folioEditor.d.ts +3 -10
- package/dist/controller/folioEditor.js +14 -4
- package/dist/controller/headerFooterEditorManager.d.ts +5 -0
- package/dist/controller/headerFooterEditorManager.js +72 -3
- package/dist/controller/hiddenEditorApi.d.ts +45 -0
- package/dist/controller/hiddenEditorApi.js +29 -8
- package/dist/controller/hiddenEditorManager.d.ts +13 -2
- package/dist/controller/hiddenEditorManager.js +639 -31
- package/dist/controller/layoutPipeline.d.ts +1 -1
- package/dist/controller/layoutPipeline.js +2 -0
- package/dist/controller/noteEditorManager.d.ts +5 -0
- package/dist/controller/noteEditorManager.js +114 -15
- package/dist/document-operations.d.ts +8 -1
- package/dist/document-operations.js +6 -4
- package/dist/docx/attributeRemainder.js +1 -0
- package/dist/docx/blockPlainText.d.ts +1 -1
- package/dist/docx/blockPlainText.js +11 -3
- 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/canonicalSessionInput.d.ts +11 -0
- package/dist/docx/canonicalSessionInput.js +27 -0
- package/dist/docx/canonicalStoryRepack.d.ts +10 -0
- package/dist/docx/canonicalStoryRepack.js +74 -0
- package/dist/docx/contentTypeRegistry.d.ts +8 -0
- package/dist/docx/contentTypeRegistry.js +64 -0
- package/dist/docx/documentParser.d.ts +1 -13
- package/dist/docx/documentParser.js +1 -47
- package/dist/docx/ensureParaIds.d.ts +7 -1
- package/dist/docx/ensureParaIds.js +173 -215
- package/dist/docx/foldedListNumberFields.d.ts +85 -0
- package/dist/docx/foldedListNumberFields.js +267 -0
- 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 +39 -1
- package/dist/docx/headerFooterVerbatim.js +173 -2
- package/dist/docx/imageParser.d.ts +13 -1
- package/dist/docx/imageParser.js +20 -11
- package/dist/docx/metadataPrivacy.js +6 -1
- package/dist/docx/noteIds.d.ts +5 -0
- package/dist/docx/noteIds.js +6 -2
- package/dist/docx/noteReferenceMark.d.ts +3 -1
- package/dist/docx/noteReferenceMark.js +15 -14
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +17 -3
- package/dist/docx/packageParts.d.ts +3 -1
- package/dist/docx/packageParts.js +74 -19
- package/dist/docx/paragraphMarkPropertyPresence.d.ts +9 -0
- package/dist/docx/paragraphMarkPropertyPresence.js +21 -0
- package/dist/docx/paragraphParser.js +101 -53
- package/dist/docx/paragraphPropertySource.d.ts +15 -1
- package/dist/docx/paragraphPropertySource.js +77 -22
- package/dist/docx/parser.js +3 -1
- package/dist/docx/removeHeaderFooterParts.js +17 -6
- package/dist/docx/reviewHistoryNamespace.d.ts +4 -0
- package/dist/docx/reviewHistoryNamespace.js +4 -0
- package/dist/docx/reviewResolutionProvenance.d.ts +25 -0
- package/dist/docx/reviewResolutionProvenance.js +153 -0
- package/dist/docx/rezip.d.ts +54 -6
- package/dist/docx/rezip.js +835 -257
- package/dist/docx/runConsolidator.d.ts +2 -58
- package/dist/docx/runConsolidator.js +3 -175
- package/dist/docx/runParser.d.ts +2 -1
- package/dist/docx/runParser.js +156 -116
- package/dist/docx/saveDiagnostics.d.ts +22 -0
- package/dist/docx/saveDiagnostics.js +0 -0
- package/dist/docx/selectiveSave.d.ts +3 -1
- package/dist/docx/selectiveSave.js +36 -4
- package/dist/docx/selectiveXmlPatch.d.ts +16 -8
- package/dist/docx/selectiveXmlPatch.js +81 -7
- package/dist/docx/serializer/documentSerializer.d.ts +9 -2
- package/dist/docx/serializer/documentSerializer.js +29 -10
- package/dist/docx/serializer/headerFooterSerializer.d.ts +5 -1
- package/dist/docx/serializer/headerFooterSerializer.js +19 -11
- package/dist/docx/serializer/noteSerializer.d.ts +2 -2
- package/dist/docx/serializer/noteSerializer.js +24 -8
- package/dist/docx/serializer/paragraphSerializer.js +41 -4
- package/dist/docx/serializer/partNamespaces.js +2 -1
- package/dist/docx/serializer/runSerializer.js +3 -1
- package/dist/docx/server/applyDocxXmlPatchProposal.js +14 -9
- package/dist/docx/settingsHeaderFooterUpdate.d.ts +5 -0
- package/dist/docx/settingsHeaderFooterUpdate.js +90 -0
- package/dist/docx/settingsParser.d.ts +1 -2
- package/dist/docx/settingsParser.js +5 -6
- package/dist/docx/storyBlockReplay.d.ts +31 -0
- package/dist/docx/storyBlockReplay.js +471 -0
- package/dist/docx/storyPlainText.d.ts +20 -0
- package/dist/docx/storyPlainText.js +23 -0
- package/dist/docx/streamingXmlParser.d.ts +22 -1
- package/dist/docx/streamingXmlParser.js +49 -3
- package/dist/docx/structuralXmlPatch.js +18 -23
- 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/docx/verbatimCapture.d.ts +3 -1
- package/dist/docx/verbatimCapture.js +49 -6
- package/dist/i18n/messages/ar.gen.d.ts +5 -0
- package/dist/i18n/messages/ar.gen.js +656 -0
- package/dist/i18n/messages/cs.gen.d.ts +5 -0
- package/dist/i18n/messages/cs.gen.js +656 -0
- package/dist/i18n/messages/de.gen.d.ts +5 -0
- package/dist/i18n/messages/de.gen.js +656 -0
- package/dist/i18n/messages/en.gen.d.ts +5 -0
- package/dist/i18n/messages/en.gen.js +656 -0
- package/dist/i18n/messages/es.gen.d.ts +5 -0
- package/dist/i18n/messages/es.gen.js +656 -0
- package/dist/i18n/messages/et.gen.d.ts +5 -0
- package/dist/i18n/messages/et.gen.js +656 -0
- package/dist/i18n/messages/fr.gen.d.ts +5 -0
- package/dist/i18n/messages/fr.gen.js +656 -0
- package/dist/i18n/messages/he.gen.d.ts +5 -0
- package/dist/i18n/messages/he.gen.js +656 -0
- package/dist/i18n/messages/hi.gen.d.ts +5 -0
- package/dist/i18n/messages/hi.gen.js +656 -0
- package/dist/i18n/messages/hu.gen.d.ts +5 -0
- package/dist/i18n/messages/hu.gen.js +656 -0
- package/dist/i18n/messages/locales.d.ts +5 -0
- package/dist/i18n/messages/locales.js +22 -0
- package/dist/i18n/messages/lt.gen.d.ts +5 -0
- package/dist/i18n/messages/lt.gen.js +656 -0
- package/dist/i18n/messages/lv.gen.d.ts +5 -0
- package/dist/i18n/messages/lv.gen.js +656 -0
- package/dist/i18n/messages/pl.gen.d.ts +5 -0
- package/dist/i18n/messages/pl.gen.js +656 -0
- package/dist/i18n/messages/pt-BR.gen.d.ts +5 -0
- package/dist/i18n/messages/pt-BR.gen.js +656 -0
- package/dist/i18n/messages/sk.gen.d.ts +5 -0
- package/dist/i18n/messages/sk.gen.js +656 -0
- package/dist/i18n/messages/tr.gen.d.ts +5 -0
- package/dist/i18n/messages/tr.gen.js +656 -0
- package/dist/i18n/messages/zh-CN.gen.d.ts +5 -0
- package/dist/i18n/messages/zh-CN.gen.js +656 -0
- package/dist/i18n/messages.d.ts +2 -3
- package/dist/i18n/messages.js +1 -19
- package/dist/internal/acceptedBlockProjection.d.ts +12 -0
- package/dist/internal/acceptedBlockProjection.js +45 -0
- package/dist/internal/noteMarkerAttrs.d.ts +8 -0
- package/dist/internal/noteMarkerAttrs.js +16 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +1 -0
- package/dist/internal/prosemirrorAttrBoundary.d.ts +21 -0
- package/dist/internal/prosemirrorAttrBoundary.js +50 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +3 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +1 -0
- package/dist/layout-bridge/convert/noteReferences.d.ts +1 -3
- package/dist/layout-bridge/convert/noteReferences.js +1 -6
- package/dist/layout-bridge/convert/paragraphRuns.js +2 -4
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +2 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +2 -2
- package/dist/managers/DocumentLoaderManager.d.ts +1 -0
- package/dist/managers/DocumentLoaderManager.js +9 -1
- package/dist/markdown/escape.d.ts +3 -1
- package/dist/markdown/escape.js +9 -2
- package/dist/markdown/renderBlock.js +20 -121
- package/dist/markdown/renderParagraph.js +13 -15
- package/dist/markdown/renderRuns.d.ts +7 -1
- package/dist/markdown/renderRuns.js +35 -15
- package/dist/markdown/renderTable.js +2 -0
- package/dist/markdown/types.d.ts +3 -9
- package/dist/prosemirror/attrs/index.d.ts +2 -12
- package/dist/prosemirror/attrs/index.js +22 -48
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +2 -1
- package/dist/prosemirror/canonicalCommands.d.ts +121 -0
- package/dist/prosemirror/canonicalCommands.js +35 -0
- 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/pageBreak.js +15 -1
- package/dist/prosemirror/commands/pastePlainText.js +2 -1
- package/dist/prosemirror/commentReferenceAttrs.d.ts +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +91 -19
- package/dist/prosemirror/conversion/hyphenTextCarriers.d.ts +8 -0
- package/dist/prosemirror/conversion/hyphenTextCarriers.js +8 -0
- package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +6 -0
- package/dist/prosemirror/conversion/listRenderingDefinition.js +97 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +11 -4
- package/dist/prosemirror/conversion/toProseDoc.js +55 -14
- package/dist/prosemirror/executeEditorCommand.d.ts +11 -0
- package/dist/prosemirror/executeEditorCommand.js +26 -0
- package/dist/prosemirror/extensions/StarterKit.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +88 -48
- package/dist/prosemirror/extensions/features/ListExtension.js +18 -5
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +5 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +13 -1
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +56 -28
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +3 -2
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +2 -0
- package/dist/prosemirror/extensions/marks/markUtils.js +72 -8
- package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/NoteMarkerExtension.js +36 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +4 -2
- package/dist/prosemirror/insertOperations.js +2 -1
- package/dist/prosemirror/listMarker.d.ts +1 -0
- package/dist/prosemirror/listMarker.js +16 -7
- package/dist/prosemirror/listNumbering.js +26 -5
- package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
- package/dist/prosemirror/listRenderingAttrs.js +3 -0
- package/dist/prosemirror/markupViewNotes.js +3 -2
- package/dist/prosemirror/moveRangeBoundaryAttrs.d.ts +2 -1
- package/dist/prosemirror/noteReferenceReview.js +5 -3
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +7 -1
- package/dist/prosemirror/paragraphPropertyCarry.js +8 -3
- package/dist/prosemirror/plugins/suggestionMode.js +57 -7
- package/dist/prosemirror/rangeAnchorAttrs.d.ts +2 -1
- package/dist/prosemirror/runFormattingFromMarks.d.ts +4 -1
- package/dist/prosemirror/runFormattingFromMarks.js +15 -1
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +2 -1
- package/dist/prosemirror/runFormattingInlineCarriers.js +4 -1
- package/dist/prosemirror/schema/marks.d.ts +2 -0
- package/dist/prosemirror/schema/nodes.d.ts +10 -2
- package/dist/prosemirror/textBoxAnchorAttrs.d.ts +2 -1
- package/dist/prosemirror/textInput.js +5 -1
- package/dist/prosemirror/trackedRevisionPath.js +2 -1
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +1 -0
- package/dist/prosemirror/validation.js +4 -0
- package/dist/types/canonicalCapabilities.d.ts +215 -0
- package/dist/types/canonicalCapabilities.js +212 -0
- package/dist/types/canonicalSave.d.ts +11 -0
- package/dist/types/canonicalSave.js +0 -0
- package/dist/types/content.d.ts +2 -2
- package/dist/types/docxSerialization.d.ts +14 -0
- package/dist/types/docxSerialization.js +7 -0
- package/dist/utils/createDocument.js +2 -2
- package/package.json +16 -4
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
import { recordHiddenEditorPhase, recordHiddenEditorStateCreate } from "../layout-engine/layoutInstrumentation.js";
|
|
2
2
|
import { suppressHiddenEditorScrollToSelection } from "../paged-layout/hiddenEditorScroll.js";
|
|
3
3
|
import { isReadOnlyEditKey } from "../paged-layout/readOnlyEditAttempt.js";
|
|
4
|
+
import { getCanonicalCommandIntents } from "../prosemirror/canonicalCommands.js";
|
|
5
|
+
import { registerClipboardIntentHandler } from "../prosemirror/clipboardIntent.js";
|
|
6
|
+
import { pasteWithoutFormatting } from "../prosemirror/commands/pastePlainText.js";
|
|
4
7
|
import { createEmptyDoc, toProseDoc } from "../prosemirror/conversion/toProseDoc.js";
|
|
8
|
+
import { registerEditorCommandOwner } from "../prosemirror/executeEditorCommand.js";
|
|
5
9
|
import { ensureBaseDirectionInState } from "../prosemirror/extensions/features/AutoBidiDetectionExtension.js";
|
|
6
10
|
import { ensureParaIdsInDoc, ensureParaIdsInState } from "../prosemirror/extensions/features/ParaIdAllocatorExtension.js";
|
|
11
|
+
import { createParagraphChangeTrackerPlugin, markPackageChange } from "../prosemirror/extensions/features/ParagraphChangeTrackerExtension.js";
|
|
12
|
+
import { toggleMarkForAllScripts, toggleUnderlineMark } from "../prosemirror/extensions/marks/markUtils.js";
|
|
7
13
|
import { createDocumentNumberingPlugin } from "../prosemirror/plugins/documentNumbering.js";
|
|
8
14
|
import { createDocumentStylesPlugin } from "../prosemirror/plugins/documentStyles.js";
|
|
9
15
|
import { schema } from "../prosemirror/schema/index.js";
|
|
10
16
|
import { createTextInputPlugin } from "../prosemirror/textInput.js";
|
|
11
17
|
import { applyAttrSchemaMigrations, proseDocumentParagraphSourceContract, readYjsAttrSchemaVersion, readYjsParagraphSourceContract, withParagraphSourceContract, writeYjsDocumentMetadata } from "../prosemirror/yjsDocumentMetadata.js";
|
|
18
|
+
import { CANONICAL_GAP, usesCanonicalSession } from "../types/canonicalCapabilities.js";
|
|
19
|
+
import { prepareCanonicalPaste } from "./canonicalClipboard.js";
|
|
20
|
+
import { createCanonicalInputBoundary } from "./canonicalInput.js";
|
|
21
|
+
import { CanonicalPublicOperations } from "./canonicalPublicOperations.js";
|
|
22
|
+
import { createCanonicalSession, publishCanonicalProjection } from "./canonicalSession.js";
|
|
23
|
+
import { prepareCanonicalAutoformat, prepareCanonicalCommands } from "./canonicalStructure.js";
|
|
12
24
|
import { createHiddenEditorApi } from "./hiddenEditorApi.js";
|
|
13
|
-
import { panic } from "better-result";
|
|
14
|
-
import {
|
|
25
|
+
import { Result, TaggedError, panic } from "better-result";
|
|
26
|
+
import { OP_STORIES } from "@stll/docx-core/ops";
|
|
27
|
+
import { EditorState, Plugin } from "prosemirror-state";
|
|
15
28
|
import { EditorView } from "prosemirror-view";
|
|
16
29
|
//#region src/controller/hiddenEditorManager.ts
|
|
17
|
-
|
|
18
|
-
* Hidden-editor view lifecycle manager
|
|
19
|
-
*
|
|
20
|
-
* Framework-agnostic owner of the off-screen ProseMirror EditorView. Holds the
|
|
21
|
-
* view plus the bookkeeping that decides when an incoming document is a truly
|
|
22
|
-
* external change (vs. an internal edit echoed back through props), builds the
|
|
23
|
-
* editor state and `editorProps`, and composes the slice-2a imperative API so
|
|
24
|
-
* the API and the lifecycle share one view owner. The React adapter
|
|
25
|
-
* (`HiddenProseMirror`) keeps the input refs and its effects (which decide
|
|
26
|
-
* *when* to act) and drives this manager through the methods below.
|
|
27
|
-
*/
|
|
30
|
+
var CanonicalSessionRefusalError = class extends TaggedError("CanonicalSessionRefusalError") {};
|
|
28
31
|
const normalizeSeedState = (state) => ensureBaseDirectionInState(ensureParaIdsInState(state));
|
|
29
32
|
const normalizeLocalSeedState = (state) => ensureBaseDirectionInState(state);
|
|
30
33
|
const isObjectRecord = (value) => typeof value === "object" && value !== null;
|
|
@@ -201,6 +204,318 @@ const createHiddenEditorClipboardHandlers = (deps) => ({
|
|
|
201
204
|
});
|
|
202
205
|
const createHiddenEditorManager = (deps) => {
|
|
203
206
|
let view = null;
|
|
207
|
+
let releaseCommandOwner;
|
|
208
|
+
let editorSession = { type: "prosemirror" };
|
|
209
|
+
let modeOverride = null;
|
|
210
|
+
const syncCanonicalMode = () => {
|
|
211
|
+
if (editorSession.type !== "canonical") return;
|
|
212
|
+
editorSession.session.setMode(modeOverride ?? (deps.getEditingMode?.() === "suggesting" ? {
|
|
213
|
+
type: "suggesting",
|
|
214
|
+
author: deps.getSuggestionAuthor?.() ?? "User"
|
|
215
|
+
} : { type: "editing" }));
|
|
216
|
+
};
|
|
217
|
+
const refuse = (reason, gap = CANONICAL_GAP.dispatch) => {
|
|
218
|
+
const message = reason;
|
|
219
|
+
if (deps.onSessionRefusal) deps.onSessionRefusal(message, gap);
|
|
220
|
+
else throw new CanonicalSessionRefusalError({
|
|
221
|
+
gap,
|
|
222
|
+
message
|
|
223
|
+
});
|
|
224
|
+
};
|
|
225
|
+
const seedSession = (document) => {
|
|
226
|
+
if (!usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) {
|
|
227
|
+
editorSession = { type: "prosemirror" };
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
const documentIdentity = deps.getDocumentIdentity();
|
|
231
|
+
if (editorSession.type === "refused" && editorSession.documentIdentity === documentIdentity) return false;
|
|
232
|
+
if (deps.getCollaboration() || !document) {
|
|
233
|
+
const reason = deps.getCollaboration() ? "Canonical sessions do not support collaboration." : "Canonical sessions require a loaded Document.";
|
|
234
|
+
editorSession = {
|
|
235
|
+
type: "refused",
|
|
236
|
+
reason,
|
|
237
|
+
documentIdentity
|
|
238
|
+
};
|
|
239
|
+
refuse(reason, CANONICAL_GAP.collaboration);
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
const result = createCanonicalSession(document, deps.getStyles());
|
|
243
|
+
if (result.isErr()) {
|
|
244
|
+
editorSession = {
|
|
245
|
+
type: "refused",
|
|
246
|
+
reason: result.error.message,
|
|
247
|
+
documentIdentity
|
|
248
|
+
};
|
|
249
|
+
refuse(result.error.message, result.error.gap);
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
editorSession = {
|
|
253
|
+
type: "canonical",
|
|
254
|
+
session: result.value
|
|
255
|
+
};
|
|
256
|
+
modeOverride = null;
|
|
257
|
+
syncCanonicalMode();
|
|
258
|
+
return true;
|
|
259
|
+
};
|
|
260
|
+
const canonicalState = (session) => EditorState.create({
|
|
261
|
+
doc: session.projection.doc,
|
|
262
|
+
plugins: [
|
|
263
|
+
createParagraphChangeTrackerPlugin(),
|
|
264
|
+
createDocumentStylesPlugin(deps.getStyles() ?? session.document.package.styles),
|
|
265
|
+
createDocumentNumberingPlugin(session.document.package.numbering),
|
|
266
|
+
...[...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: {
|
|
267
|
+
...props.transformCopied === void 0 ? {} : { transformCopied: props.transformCopied },
|
|
268
|
+
...props.clipboardTextSerializer === void 0 ? {} : { clipboardTextSerializer: props.clipboardTextSerializer },
|
|
269
|
+
...props.transformPastedHTML === void 0 ? {} : { transformPastedHTML: props.transformPastedHTML },
|
|
270
|
+
...props.transformPasted === void 0 ? {} : { transformPasted: props.transformPasted }
|
|
271
|
+
} })])
|
|
272
|
+
]
|
|
273
|
+
});
|
|
274
|
+
const publishCommit = (commit) => {
|
|
275
|
+
if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return false;
|
|
276
|
+
const session = editorSession.session;
|
|
277
|
+
const result = publishCanonicalProjection({
|
|
278
|
+
state: view.state,
|
|
279
|
+
commit,
|
|
280
|
+
session
|
|
281
|
+
});
|
|
282
|
+
if (result.isErr()) {
|
|
283
|
+
refuse(result.error.message, result.error.gap);
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
const staged = result.value;
|
|
287
|
+
view.updateState(staged.state);
|
|
288
|
+
deps.onTransaction({
|
|
289
|
+
transactions: staged.transactions,
|
|
290
|
+
newState: staged.state,
|
|
291
|
+
docChanged: true
|
|
292
|
+
});
|
|
293
|
+
deps.onSelectionChange(staged.state);
|
|
294
|
+
return true;
|
|
295
|
+
};
|
|
296
|
+
const history = (direction) => {
|
|
297
|
+
if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return false;
|
|
298
|
+
const session = editorSession.session;
|
|
299
|
+
if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
|
|
300
|
+
const prepared = direction === "undo" ? session.prepareUndo(view.state) : session.prepareRedo(view.state);
|
|
301
|
+
if (prepared.isErr()) {
|
|
302
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
return publishCommit(prepared.value);
|
|
306
|
+
};
|
|
307
|
+
const executeCanonicalCommand = (command) => {
|
|
308
|
+
if (!view || editorSession.type !== "canonical") return void 0;
|
|
309
|
+
if (deps.getReadOnly()) return false;
|
|
310
|
+
if (command === pasteWithoutFormatting) return command(view.state, (transaction) => view?.dispatch(transaction), view);
|
|
311
|
+
if (editorSession.session.isComposing) {
|
|
312
|
+
refuse("Composition must finish before formatting.");
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
const intents = getCanonicalCommandIntents(command, view.state);
|
|
316
|
+
if (intents === void 0) return void 0;
|
|
317
|
+
syncCanonicalMode();
|
|
318
|
+
editorSession.session.breakUndoGroup();
|
|
319
|
+
if (intents.length > 0 && intents.every((intent) => intent.type === "formatRun" && intent.from === intent.to)) return command(view.state, (transaction) => {
|
|
320
|
+
if (view !== null) view.dispatch(view.state.tr.setStoredMarks(transaction.storedMarks));
|
|
321
|
+
}, view);
|
|
322
|
+
const prepared = prepareCanonicalCommands(editorSession.session, view.state, intents);
|
|
323
|
+
if (prepared.isErr()) {
|
|
324
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
return publishCommit(prepared.value);
|
|
328
|
+
};
|
|
329
|
+
let clipboardDrag = { type: "idle" };
|
|
330
|
+
let lastInputRule;
|
|
331
|
+
const canonicalStructuralInput = {
|
|
332
|
+
command: (name) => {
|
|
333
|
+
if (!view) return;
|
|
334
|
+
let command = deps.getExtensionManager()?.getCommand(name)?.();
|
|
335
|
+
if (command === void 0) {
|
|
336
|
+
const mark = view.state.schema.marks[{
|
|
337
|
+
toggleBold: "bold",
|
|
338
|
+
toggleItalic: "italic",
|
|
339
|
+
toggleUnderline: "underline"
|
|
340
|
+
}[name]];
|
|
341
|
+
if (mark !== void 0) command = name === "toggleUnderline" ? toggleUnderlineMark(mark) : toggleMarkForAllScripts(mark, name === "toggleBold" ? "bold" : "italic");
|
|
342
|
+
}
|
|
343
|
+
if (command === void 0) {
|
|
344
|
+
refuse("The formatting command is unavailable.", CANONICAL_GAP.commands);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (executeCanonicalCommand(command) === void 0) command(view.state, (transaction) => view?.dispatch(transaction), view);
|
|
348
|
+
},
|
|
349
|
+
structure: (type) => {
|
|
350
|
+
if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return;
|
|
351
|
+
syncCanonicalMode();
|
|
352
|
+
const session = editorSession.session;
|
|
353
|
+
const state = view.state;
|
|
354
|
+
const selection = session.projection.selectionAt(state);
|
|
355
|
+
if (selection.isErr()) {
|
|
356
|
+
refuse(selection.error.message, selection.error.gap);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
let prepared;
|
|
360
|
+
switch (type) {
|
|
361
|
+
case "split":
|
|
362
|
+
prepared = (session.projection.paragraph(selection.value.head.blockId)?.source)?.formatting?.numPr?.kind === "reference" && state.selection.$from.parent.content.size === 0 ? prepareCanonicalCommands(session, state, [{ type: "removeList" }]) : session.prepareSplit(state);
|
|
363
|
+
break;
|
|
364
|
+
case "joinBackward": {
|
|
365
|
+
if (lastInputRule?.session === session && lastInputRule.version === session.version && lastInputRule.caret === state.selection.head) {
|
|
366
|
+
lastInputRule = void 0;
|
|
367
|
+
history("undo");
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const paragraph = session.projection.paragraph(selection.value.head.blockId)?.source;
|
|
371
|
+
if (paragraph?.formatting?.numPr?.kind === "reference") {
|
|
372
|
+
prepared = prepareCanonicalCommands(session, state, [{ type: "removeList" }]);
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
if ((paragraph?.formatting?.indentLeft ?? 0) > 0 || (paragraph?.formatting?.indentFirstLine ?? 0) > 0) {
|
|
376
|
+
prepared = session.prepareIntent(state, {
|
|
377
|
+
type: "formatParagraph",
|
|
378
|
+
at: selection.value.head,
|
|
379
|
+
patch: {
|
|
380
|
+
indentLeft: null,
|
|
381
|
+
indentFirstLine: null,
|
|
382
|
+
hangingIndent: null
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
prepared = session.prepareJoin(state, "backward");
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
case "joinForward":
|
|
391
|
+
prepared = session.prepareJoin(state, "forward");
|
|
392
|
+
break;
|
|
393
|
+
case "indent":
|
|
394
|
+
case "outdent":
|
|
395
|
+
prepared = prepareCanonicalCommands(session, state, [{
|
|
396
|
+
type: "changeListLevel",
|
|
397
|
+
direction: type === "indent" ? "increase" : "decrease"
|
|
398
|
+
}]);
|
|
399
|
+
break;
|
|
400
|
+
case "tab":
|
|
401
|
+
case "lineBreak":
|
|
402
|
+
case "pageBreak": {
|
|
403
|
+
const from = session.projection.addressAt(state.selection.from);
|
|
404
|
+
const to = session.projection.addressAt(state.selection.to);
|
|
405
|
+
if (from.isErr()) {
|
|
406
|
+
refuse(from.error.message, from.error.gap);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (to.isErr()) {
|
|
410
|
+
refuse(to.error.message, to.error.gap);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
prepared = session.prepareIntent(state, {
|
|
414
|
+
type: "insertAtom",
|
|
415
|
+
from: from.value,
|
|
416
|
+
to: to.value,
|
|
417
|
+
atom: type === "tab" ? { type: "tab" } : {
|
|
418
|
+
type: "break",
|
|
419
|
+
breakType: type === "pageBreak" ? "page" : "textWrapping"
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
default: return type;
|
|
425
|
+
}
|
|
426
|
+
if (prepared.isErr()) {
|
|
427
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
publishCommit(prepared.value);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
const canonicalInputLifecycle = {
|
|
434
|
+
breakUndoGroup: () => {
|
|
435
|
+
if (editorSession.type === "canonical") editorSession.session.breakUndoGroup();
|
|
436
|
+
},
|
|
437
|
+
beginComposition: () => {
|
|
438
|
+
if (deps.getReadOnly() || editorSession.type !== "canonical") return false;
|
|
439
|
+
const begun = editorSession.session.beginComposition();
|
|
440
|
+
if (begun.isErr()) {
|
|
441
|
+
refuse(begun.error.message, begun.error.gap);
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
return true;
|
|
445
|
+
},
|
|
446
|
+
endComposition: () => {
|
|
447
|
+
if (editorSession.type === "canonical") editorSession.session.endComposition();
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
const input = createCanonicalInputBoundary({
|
|
451
|
+
pastePlainText: (pmView) => {
|
|
452
|
+
if (deps.getReadOnly()) {
|
|
453
|
+
deps.onReadOnlyEditAttempt();
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
pasteWithoutFormatting(pmView.state, (transaction) => pmView.dispatch(transaction), pmView);
|
|
457
|
+
},
|
|
458
|
+
cut: (pmView, event) => {
|
|
459
|
+
event.preventDefault();
|
|
460
|
+
if (deps.getReadOnly()) {
|
|
461
|
+
deps.onReadOnlyEditAttempt();
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
if (editorSession.type !== "canonical" || pmView.state.selection.empty) return true;
|
|
465
|
+
if (event.clipboardData === null) {
|
|
466
|
+
refuse("The clipboard cannot receive the cut content.");
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
syncCanonicalMode();
|
|
470
|
+
const session = editorSession.session;
|
|
471
|
+
const { from, to } = pmView.state.selection;
|
|
472
|
+
const prepared = session.prepareReplace(pmView.state, {
|
|
473
|
+
from,
|
|
474
|
+
to,
|
|
475
|
+
text: "",
|
|
476
|
+
semantic: "replacement"
|
|
477
|
+
});
|
|
478
|
+
if (prepared.isErr()) {
|
|
479
|
+
refuse(prepared.error.message, prepared.error.gap);
|
|
480
|
+
return true;
|
|
481
|
+
}
|
|
482
|
+
const copied = Result.try({
|
|
483
|
+
try: () => {
|
|
484
|
+
const serialized = pmView.serializeForClipboard(pmView.state.selection.content());
|
|
485
|
+
event.clipboardData?.setData("text/html", serialized.dom.innerHTML);
|
|
486
|
+
event.clipboardData?.setData("text/plain", serialized.text);
|
|
487
|
+
},
|
|
488
|
+
catch: () => new CanonicalSessionRefusalError({
|
|
489
|
+
gap: CANONICAL_GAP.dispatch,
|
|
490
|
+
message: "The clipboard could not receive the cut content."
|
|
491
|
+
})
|
|
492
|
+
});
|
|
493
|
+
if (copied.isErr()) refuse(copied.error.message, copied.error.gap);
|
|
494
|
+
else publishCommit(prepared.value);
|
|
495
|
+
return true;
|
|
496
|
+
},
|
|
497
|
+
...canonicalInputLifecycle,
|
|
498
|
+
...canonicalStructuralInput,
|
|
499
|
+
replace: (intent) => {
|
|
500
|
+
if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return;
|
|
501
|
+
syncCanonicalMode();
|
|
502
|
+
const rule = prepareCanonicalAutoformat(editorSession.session, view.state, intent);
|
|
503
|
+
const prepared = rule ?? editorSession.session.prepareReplace(view.state, intent);
|
|
504
|
+
if (prepared.isErr()) {
|
|
505
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const session = editorSession.session;
|
|
509
|
+
if (publishCommit(prepared.value) && rule !== void 0 && view !== null) lastInputRule = {
|
|
510
|
+
session,
|
|
511
|
+
version: session.version,
|
|
512
|
+
caret: view.state.selection.head
|
|
513
|
+
};
|
|
514
|
+
},
|
|
515
|
+
undo: () => history("undo"),
|
|
516
|
+
redo: () => history("redo"),
|
|
517
|
+
refuse
|
|
518
|
+
});
|
|
204
519
|
let isDestroying = false;
|
|
205
520
|
let requested = false;
|
|
206
521
|
let isInitialized = false;
|
|
@@ -212,31 +527,52 @@ const createHiddenEditorManager = (deps) => {
|
|
|
212
527
|
if (!host) return;
|
|
213
528
|
const collaboration = deps.getCollaboration();
|
|
214
529
|
const collaborationModules = deps.getCollaborationModules();
|
|
215
|
-
if (collaboration && !collaborationModules) return;
|
|
530
|
+
if (collaboration && !collaborationModules && !usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) return;
|
|
216
531
|
const precomputedInitialState = deps.getPrecomputedInitialState();
|
|
217
532
|
const document = deps.getDocument();
|
|
218
533
|
const styles = deps.getStyles();
|
|
219
534
|
const extensionManager = deps.getExtensionManager();
|
|
220
535
|
const externalPlugins = deps.getExternalPlugins();
|
|
536
|
+
input.reset();
|
|
537
|
+
if (!seedSession(document)) return;
|
|
221
538
|
const editorProps = {
|
|
222
|
-
state:
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
539
|
+
state: (() => {
|
|
540
|
+
if (editorSession.type === "canonical") return canonicalState(editorSession.session);
|
|
541
|
+
if (precomputedInitialState && !collaboration) return precomputedInitialState;
|
|
542
|
+
return createHiddenEditorState({
|
|
543
|
+
document,
|
|
544
|
+
styles,
|
|
545
|
+
manager: extensionManager,
|
|
546
|
+
externalPlugins,
|
|
547
|
+
collaboration,
|
|
548
|
+
collaborationModules,
|
|
549
|
+
reason: "mount"
|
|
550
|
+
});
|
|
551
|
+
})(),
|
|
231
552
|
attributes: HIDDEN_EDITOR_ATTRIBUTES,
|
|
232
|
-
editable: () => !deps.getReadOnly(),
|
|
553
|
+
editable: () => !deps.getReadOnly() && editorSession.type !== "refused",
|
|
233
554
|
dispatchTransaction: (transaction) => {
|
|
234
555
|
if (!view || isDestroying) return;
|
|
235
556
|
if (deps.getReadOnly() && transaction.docChanged) {
|
|
236
557
|
deps.onReadOnlyEditAttempt();
|
|
237
558
|
return;
|
|
238
559
|
}
|
|
560
|
+
if (editorSession.type === "refused") return;
|
|
561
|
+
if (editorSession.type === "canonical" && transaction.docChanged) {
|
|
562
|
+
if (input.acceptComposition(view, transaction)) return;
|
|
563
|
+
if (!input.commitNativeProposal(view, transaction)) input.refuseNativeMutation(view);
|
|
564
|
+
view.updateState(view.state);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (editorSession.type === "canonical" && transaction.selectionSet && !input.isComposing) {
|
|
568
|
+
lastInputRule = void 0;
|
|
569
|
+
editorSession.session.breakUndoGroup();
|
|
570
|
+
}
|
|
239
571
|
const applied = view.state.applyTransaction(transaction);
|
|
572
|
+
if (editorSession.type === "canonical" && !applied.state.doc.eq(view.state.doc)) {
|
|
573
|
+
refuse("A plugin attempted an unclassified canonical document mutation.");
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
240
576
|
view.updateState(applied.state);
|
|
241
577
|
const docChanged = applied.transactions.some((appliedTransaction) => appliedTransaction.docChanged);
|
|
242
578
|
const selectionChanged = applied.transactions.some((appliedTransaction) => appliedTransaction.selectionSet || appliedTransaction.docChanged);
|
|
@@ -256,20 +592,107 @@ const createHiddenEditorManager = (deps) => {
|
|
|
256
592
|
event.preventDefault();
|
|
257
593
|
return true;
|
|
258
594
|
}
|
|
595
|
+
if (editorSession.type === "canonical" && input.handleKeyDown(pmView, event)) return true;
|
|
259
596
|
return deps.onKeyDown(pmView, event);
|
|
260
597
|
},
|
|
598
|
+
handleTextInput: (pmView, from, to, text) => editorSession.type === "canonical" ? input.handleTextInput(pmView, from, to, text) : false,
|
|
599
|
+
handlePaste: (pmView, _event, slice) => {
|
|
600
|
+
if (editorSession.type !== "canonical") return false;
|
|
601
|
+
if (deps.getReadOnly()) {
|
|
602
|
+
deps.onReadOnlyEditAttempt();
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
syncCanonicalMode();
|
|
606
|
+
const prepared = prepareCanonicalPaste({
|
|
607
|
+
session: editorSession.session,
|
|
608
|
+
state: pmView.state,
|
|
609
|
+
slice
|
|
610
|
+
});
|
|
611
|
+
if (prepared.isErr()) {
|
|
612
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
613
|
+
} else publishCommit(prepared.value);
|
|
614
|
+
return true;
|
|
615
|
+
},
|
|
616
|
+
handleDrop: (pmView, event, slice, moved) => {
|
|
617
|
+
if (editorSession.type !== "canonical") return false;
|
|
618
|
+
if (deps.getReadOnly()) {
|
|
619
|
+
deps.onReadOnlyEditAttempt();
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
const target = pmView.posAtCoords({
|
|
623
|
+
left: event.clientX,
|
|
624
|
+
top: event.clientY
|
|
625
|
+
})?.pos;
|
|
626
|
+
if (target === void 0) {
|
|
627
|
+
refuse("The drop has no document destination.");
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
const captured = clipboardDrag;
|
|
631
|
+
clipboardDrag = { type: "idle" };
|
|
632
|
+
if (moved && (captured.type !== "dragging" || captured.session !== editorSession.session || captured.version !== editorSession.session.version)) {
|
|
633
|
+
refuse("The dragged content changed or has no captured source.");
|
|
634
|
+
return true;
|
|
635
|
+
}
|
|
636
|
+
const source = captured.type === "dragging" ? {
|
|
637
|
+
from: captured.from,
|
|
638
|
+
to: captured.to
|
|
639
|
+
} : pmView.state.selection;
|
|
640
|
+
if (moved && target >= source.from && target <= source.to) return true;
|
|
641
|
+
syncCanonicalMode();
|
|
642
|
+
const prepared = prepareCanonicalPaste({
|
|
643
|
+
session: editorSession.session,
|
|
644
|
+
state: pmView.state,
|
|
645
|
+
slice,
|
|
646
|
+
...moved ? {
|
|
647
|
+
moveTarget: target,
|
|
648
|
+
moveSource: {
|
|
649
|
+
from: source.from,
|
|
650
|
+
to: source.to
|
|
651
|
+
}
|
|
652
|
+
} : { pasteTarget: target }
|
|
653
|
+
});
|
|
654
|
+
if (prepared.isErr()) {
|
|
655
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
656
|
+
} else publishCommit(prepared.value);
|
|
657
|
+
return true;
|
|
658
|
+
},
|
|
261
659
|
handleScrollToSelection: suppressHiddenEditorScrollToSelection,
|
|
262
660
|
handleDOMEvents: {
|
|
661
|
+
keydown: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.keydown(pmView, event) : false,
|
|
263
662
|
focus: () => false,
|
|
264
|
-
blur: () => false,
|
|
663
|
+
blur: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.blur(pmView) : false,
|
|
265
664
|
...createHiddenEditorClipboardHandlers(deps),
|
|
665
|
+
compositionstart: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.compositionstart(pmView) : false,
|
|
666
|
+
compositionend: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.compositionend(pmView) : false,
|
|
667
|
+
input: (pmView) => editorSession.type === "canonical" ? input.handleDOMEvents.input(pmView) : false,
|
|
668
|
+
paste: (pmView, event) => {
|
|
669
|
+
if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.paste(pmView, event);
|
|
670
|
+
return createHiddenEditorClipboardHandlers(deps).paste(pmView, event);
|
|
671
|
+
},
|
|
672
|
+
cut: (pmView, event) => editorSession.type === "canonical" ? input.handleDOMEvents.cut(pmView, event) : createHiddenEditorClipboardHandlers(deps).cut(pmView, event),
|
|
266
673
|
beforeinput: (_view, event) => {
|
|
674
|
+
if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.beforeinput(_view, event);
|
|
267
675
|
if (!deps.getReadOnly()) return false;
|
|
268
676
|
deps.onReadOnlyEditAttempt();
|
|
269
677
|
event.preventDefault();
|
|
270
678
|
return true;
|
|
271
679
|
},
|
|
680
|
+
dragstart: (pmView) => {
|
|
681
|
+
if (editorSession.type === "canonical") clipboardDrag = {
|
|
682
|
+
type: "dragging",
|
|
683
|
+
session: editorSession.session,
|
|
684
|
+
version: editorSession.session.version,
|
|
685
|
+
from: pmView.state.selection.from,
|
|
686
|
+
to: pmView.state.selection.to
|
|
687
|
+
};
|
|
688
|
+
return false;
|
|
689
|
+
},
|
|
690
|
+
dragend: () => {
|
|
691
|
+
clipboardDrag = { type: "idle" };
|
|
692
|
+
return false;
|
|
693
|
+
},
|
|
272
694
|
drop: (_view, event) => {
|
|
695
|
+
if (editorSession.type === "canonical" && !deps.getReadOnly()) return input.handleDOMEvents.drop(_view, event);
|
|
273
696
|
if (!deps.getReadOnly()) return false;
|
|
274
697
|
deps.onReadOnlyEditAttempt();
|
|
275
698
|
event.preventDefault();
|
|
@@ -279,6 +702,26 @@ const createHiddenEditorManager = (deps) => {
|
|
|
279
702
|
};
|
|
280
703
|
const viewStartedAt = performance.now();
|
|
281
704
|
view = new EditorView(host, editorProps);
|
|
705
|
+
if (editorSession.type === "canonical") registerClipboardIntentHandler(view, (slice, plain) => {
|
|
706
|
+
if (!view || editorSession.type !== "canonical") return false;
|
|
707
|
+
if (deps.getReadOnly()) {
|
|
708
|
+
deps.onReadOnlyEditAttempt();
|
|
709
|
+
return false;
|
|
710
|
+
}
|
|
711
|
+
syncCanonicalMode();
|
|
712
|
+
const prepared = prepareCanonicalPaste({
|
|
713
|
+
session: editorSession.session,
|
|
714
|
+
state: view.state,
|
|
715
|
+
slice,
|
|
716
|
+
plain
|
|
717
|
+
});
|
|
718
|
+
if (prepared.isErr()) {
|
|
719
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
return publishCommit(prepared.value);
|
|
723
|
+
});
|
|
724
|
+
releaseCommandOwner = registerEditorCommandOwner(view, executeCanonicalCommand);
|
|
282
725
|
recordHiddenEditorPhase("mount", "editor-view", performance.now() - viewStartedAt);
|
|
283
726
|
syncHiddenEditorAccessibility(view, deps.getReadOnly());
|
|
284
727
|
isInitialized = true;
|
|
@@ -298,8 +741,11 @@ const createHiddenEditorManager = (deps) => {
|
|
|
298
741
|
if (view && !isDestroying) {
|
|
299
742
|
isDestroying = true;
|
|
300
743
|
deps.onEditorViewDestroy();
|
|
744
|
+
releaseCommandOwner?.();
|
|
745
|
+
releaseCommandOwner = void 0;
|
|
301
746
|
view.destroy();
|
|
302
747
|
view = null;
|
|
748
|
+
input.reset();
|
|
303
749
|
isDestroying = false;
|
|
304
750
|
}
|
|
305
751
|
};
|
|
@@ -307,17 +753,23 @@ const createHiddenEditorManager = (deps) => {
|
|
|
307
753
|
if (!view || isDestroying) return;
|
|
308
754
|
const collaboration = deps.getCollaboration();
|
|
309
755
|
const collaborationModules = deps.getCollaborationModules();
|
|
310
|
-
if (collaboration && !collaborationModules) return;
|
|
756
|
+
if (collaboration && !collaborationModules && !usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) return;
|
|
311
757
|
const document = deps.getDocument();
|
|
312
758
|
const currentDocId = deps.getDocumentIdentity();
|
|
313
759
|
const currentCollaborationFragment = collaboration?.yXmlFragment ?? null;
|
|
314
760
|
const collaborationSourceChanged = currentCollaborationFragment !== lastCollaborationFragment;
|
|
315
|
-
|
|
316
|
-
if (
|
|
761
|
+
const sessionChanged = editorSession.type !== "prosemirror" !== usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting);
|
|
762
|
+
if (collaboration && !collaborationSourceChanged && !sessionChanged) return;
|
|
763
|
+
if (isInitialized && currentDocId === lastDocumentId && !collaborationSourceChanged && !sessionChanged) return;
|
|
764
|
+
input.reset();
|
|
765
|
+
if (!seedSession(document)) {
|
|
766
|
+
destroyView();
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
317
769
|
isInitialized = true;
|
|
318
770
|
lastDocumentId = currentDocId;
|
|
319
771
|
lastCollaborationFragment = currentCollaborationFragment;
|
|
320
|
-
const newState = createHiddenEditorState({
|
|
772
|
+
const newState = editorSession.type === "canonical" ? canonicalState(editorSession.session) : createHiddenEditorState({
|
|
321
773
|
document,
|
|
322
774
|
styles: deps.getStyles(),
|
|
323
775
|
manager: deps.getExtensionManager(),
|
|
@@ -336,6 +788,57 @@ const createHiddenEditorManager = (deps) => {
|
|
|
336
788
|
if (!view) return;
|
|
337
789
|
syncHiddenEditorAccessibility(view, deps.getReadOnly());
|
|
338
790
|
};
|
|
791
|
+
const publishStoryCommit = (storyView, commit) => {
|
|
792
|
+
if (!view || editorSession.type !== "canonical") return false;
|
|
793
|
+
if (deps.getEditingMode?.() === "suggesting") {
|
|
794
|
+
refuse("Suggesting is unavailable in the experimental canonical session.", CANONICAL_GAP.suggesting);
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
const session = editorSession.session;
|
|
798
|
+
const bodyTransaction = view.state.tr;
|
|
799
|
+
if (!bodyTransaction.doc.eq(commit.bodyProjection.doc)) bodyTransaction.replaceWith(0, bodyTransaction.doc.content.size, commit.bodyProjection.doc.content);
|
|
800
|
+
markPackageChange(bodyTransaction);
|
|
801
|
+
bodyTransaction.setMeta("addToHistory", false);
|
|
802
|
+
const bodyStaged = Result.try(() => view?.state.applyTransaction(bodyTransaction));
|
|
803
|
+
if (bodyStaged.isErr() || !bodyStaged.value || !bodyStaged.value.transactions.includes(bodyTransaction) || !bodyStaged.value.state.doc.eq(commit.bodyProjection.doc) || bodyStaged.value.transactions.some((transaction) => transaction !== bodyTransaction && transaction.docChanged)) {
|
|
804
|
+
refuse("A plugin refused or changed the canonical body projection.");
|
|
805
|
+
return false;
|
|
806
|
+
}
|
|
807
|
+
const staged = publishCanonicalProjection({
|
|
808
|
+
state: storyView.state,
|
|
809
|
+
commit,
|
|
810
|
+
session
|
|
811
|
+
});
|
|
812
|
+
if (staged.isErr()) {
|
|
813
|
+
refuse(staged.error.message, staged.error.gap);
|
|
814
|
+
return false;
|
|
815
|
+
}
|
|
816
|
+
storyView.updateState(staged.value.state);
|
|
817
|
+
view.updateState(bodyStaged.value.state);
|
|
818
|
+
deps.onTransaction({
|
|
819
|
+
transactions: staged.value.transactions,
|
|
820
|
+
newState: view.state,
|
|
821
|
+
docChanged: true
|
|
822
|
+
});
|
|
823
|
+
deps.onSelectionChange(view.state);
|
|
824
|
+
return true;
|
|
825
|
+
};
|
|
826
|
+
let publicOperations = null;
|
|
827
|
+
const getPublicOperations = () => {
|
|
828
|
+
if (editorSession.type !== "canonical") return null;
|
|
829
|
+
const session = editorSession.session;
|
|
830
|
+
if (publicOperations?.session === session) return publicOperations.executor;
|
|
831
|
+
const executor = new CanonicalPublicOperations({
|
|
832
|
+
session,
|
|
833
|
+
getState: (story) => story === OP_STORIES.MAIN && !deps.getReadOnly() && !isDestroying ? view?.state ?? null : null,
|
|
834
|
+
publish: publishCommit
|
|
835
|
+
});
|
|
836
|
+
publicOperations = {
|
|
837
|
+
session,
|
|
838
|
+
executor
|
|
839
|
+
};
|
|
840
|
+
return executor;
|
|
841
|
+
};
|
|
339
842
|
return {
|
|
340
843
|
ensureView,
|
|
341
844
|
retryViewCreation,
|
|
@@ -347,7 +850,112 @@ const createHiddenEditorManager = (deps) => {
|
|
|
347
850
|
isInitialized: () => isInitialized,
|
|
348
851
|
api: createHiddenEditorApi({
|
|
349
852
|
getView: () => view,
|
|
350
|
-
getDocumentContext: deps.getDocumentContext,
|
|
853
|
+
getDocumentContext: () => editorSession.type === "refused" ? null : deps.getDocumentContext(),
|
|
854
|
+
isCanonicalSaveCurrent: (version) => editorSession.type === "canonical" && !editorSession.session.isComposing && editorSession.session.version === version,
|
|
855
|
+
captureCanonicalSave: () => editorSession.type === "canonical" ? editorSession.session.captureSaveSnapshot() : null,
|
|
856
|
+
getCanonicalDocument: () => editorSession.type === "canonical" ? editorSession.session.document : null,
|
|
857
|
+
setCanonicalMode: (mode) => {
|
|
858
|
+
if (editorSession.type !== "canonical") return false;
|
|
859
|
+
modeOverride = mode;
|
|
860
|
+
syncCanonicalMode();
|
|
861
|
+
return true;
|
|
862
|
+
},
|
|
863
|
+
resolveCanonicalRevisions: (revisionIds, resolution) => {
|
|
864
|
+
if (!view || deps.getReadOnly() || editorSession.type !== "canonical") return false;
|
|
865
|
+
const prepared = editorSession.session.prepareResolve(view.state, {
|
|
866
|
+
revisionIds,
|
|
867
|
+
resolution
|
|
868
|
+
});
|
|
869
|
+
if (prepared.isErr()) {
|
|
870
|
+
if (prepared.error.reason !== "noChange") refuse(prepared.error.message, prepared.error.gap);
|
|
871
|
+
return false;
|
|
872
|
+
}
|
|
873
|
+
return publishCommit(prepared.value);
|
|
874
|
+
},
|
|
875
|
+
executeCanonicalCommand,
|
|
876
|
+
getCanonicalHistory: () => editorSession.type === "canonical" ? {
|
|
877
|
+
undo: () => history("undo"),
|
|
878
|
+
redo: () => history("redo"),
|
|
879
|
+
canUndo: () => editorSession.type === "canonical" && editorSession.session.canUndo,
|
|
880
|
+
canRedo: () => editorSession.type === "canonical" && editorSession.session.canRedo
|
|
881
|
+
} : null,
|
|
882
|
+
canonicalOperations: {
|
|
883
|
+
applyCanonicalDocumentOperations: (options) => {
|
|
884
|
+
ensureView();
|
|
885
|
+
return getPublicOperations()?.apply(options) ?? null;
|
|
886
|
+
},
|
|
887
|
+
undoCanonicalDocumentOperations: (handle) => getPublicOperations()?.undo(handle) ?? null,
|
|
888
|
+
updateCanonicalInputLifecycle: (action) => {
|
|
889
|
+
if (editorSession.type !== "canonical") return false;
|
|
890
|
+
switch (action) {
|
|
891
|
+
case "beginComposition": return canonicalInputLifecycle.beginComposition();
|
|
892
|
+
case "endComposition":
|
|
893
|
+
canonicalInputLifecycle.endComposition();
|
|
894
|
+
return true;
|
|
895
|
+
case "breakUndoGroup":
|
|
896
|
+
canonicalInputLifecycle.breakUndoGroup();
|
|
897
|
+
return true;
|
|
898
|
+
}
|
|
899
|
+
},
|
|
900
|
+
getCanonicalStorySelection: (story) => {
|
|
901
|
+
if (editorSession.type !== "canonical") return null;
|
|
902
|
+
const session = editorSession.session;
|
|
903
|
+
const selection = session.selection;
|
|
904
|
+
if (!selection) return null;
|
|
905
|
+
const projection = session.projectStory(story);
|
|
906
|
+
if (projection.isErr()) return null;
|
|
907
|
+
const anchor = projection.value.positionAt(selection.anchor);
|
|
908
|
+
const head = projection.value.positionAt(selection.head);
|
|
909
|
+
return anchor.isOk() && head.isOk() ? {
|
|
910
|
+
anchor: anchor.value,
|
|
911
|
+
head: head.value
|
|
912
|
+
} : null;
|
|
913
|
+
},
|
|
914
|
+
applyCanonicalStoryHistory: ({ view: storyView, story, direction }) => {
|
|
915
|
+
if (story === OP_STORIES.MAIN && storyView === view) return history(direction);
|
|
916
|
+
if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
|
|
917
|
+
const session = editorSession.session;
|
|
918
|
+
if (direction === "undo" ? !session.canUndo : !session.canRedo) return false;
|
|
919
|
+
const prepared = direction === "undo" ? session.prepareUndo(storyView.state, story) : session.prepareRedo(storyView.state, story);
|
|
920
|
+
if (prepared.isErr()) {
|
|
921
|
+
refuse(prepared.error.message, prepared.error.gap);
|
|
922
|
+
return false;
|
|
923
|
+
}
|
|
924
|
+
return publishStoryCommit(storyView, prepared.value);
|
|
925
|
+
},
|
|
926
|
+
applyCanonicalOperations: (ops) => {
|
|
927
|
+
ensureView();
|
|
928
|
+
if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
|
|
929
|
+
const prepared = editorSession.session.prepareOperations(view.state, ops);
|
|
930
|
+
if (prepared.isErr()) {
|
|
931
|
+
refuse(prepared.error.message, prepared.error.gap);
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
return publishCommit(prepared.value);
|
|
935
|
+
},
|
|
936
|
+
getCanonicalStoryProjection: (story) => {
|
|
937
|
+
if (usesCanonicalSession(deps.getExperimentalSession?.(), CANONICAL_GAP.authorityRouting)) ensureView();
|
|
938
|
+
if (editorSession.type !== "canonical" || editorSession.session.isComposing) return null;
|
|
939
|
+
const result = editorSession.session.projectStory(story);
|
|
940
|
+
if (result.isErr()) {
|
|
941
|
+
refuse(result.error.message, result.error.gap);
|
|
942
|
+
return null;
|
|
943
|
+
}
|
|
944
|
+
return result.value.doc;
|
|
945
|
+
},
|
|
946
|
+
replaceCanonicalStoryText: ({ view: storyView, story, intent }) => {
|
|
947
|
+
if (!view || editorSession.type !== "canonical" || deps.getReadOnly()) return false;
|
|
948
|
+
const prepared = editorSession.session.prepareReplace(storyView.state, {
|
|
949
|
+
...intent,
|
|
950
|
+
story
|
|
951
|
+
});
|
|
952
|
+
if (prepared.isErr()) {
|
|
953
|
+
refuse(prepared.error.message, prepared.error.gap);
|
|
954
|
+
return false;
|
|
955
|
+
}
|
|
956
|
+
return publishStoryCommit(storyView, prepared.value);
|
|
957
|
+
}
|
|
958
|
+
},
|
|
351
959
|
isDestroying: () => isDestroying,
|
|
352
960
|
ensureView,
|
|
353
961
|
isViewRequested
|
|
@@ -355,4 +963,4 @@ const createHiddenEditorManager = (deps) => {
|
|
|
355
963
|
};
|
|
356
964
|
};
|
|
357
965
|
//#endregion
|
|
358
|
-
export { collectRemoteSelections, createHiddenEditorClipboardHandlers, createHiddenEditorManager, createHiddenEditorState };
|
|
966
|
+
export { CanonicalSessionRefusalError, collectRemoteSelections, createHiddenEditorClipboardHandlers, createHiddenEditorManager, createHiddenEditorState };
|