@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
|
@@ -1,54 +1,92 @@
|
|
|
1
1
|
import { splitsSurrogatePair } from "../ai-edits/character-boundaries.js";
|
|
2
|
+
import { CANONICAL_GAP } from "../types/canonicalCapabilities.js";
|
|
3
|
+
import { setCanonicalInputTimer } from "./canonicalInputTimer.js";
|
|
2
4
|
import { CanonicalSessionError } from "./canonicalSession.js";
|
|
3
5
|
import { Result } from "better-result";
|
|
6
|
+
import { EditorState, TextSelection } from "prosemirror-state";
|
|
4
7
|
//#region src/controller/canonicalComposition.ts
|
|
5
|
-
const COMPOSITION_FLUSH_DELAY_MS = 25;
|
|
6
8
|
/** Native IME owns the provisional view; the captured canonical projection stays unchanged. */
|
|
7
9
|
const createCanonicalComposition = (options) => {
|
|
8
10
|
let state = { type: "committed" };
|
|
9
11
|
let authorizedNativeState = null;
|
|
12
|
+
let completed = { type: "idle" };
|
|
10
13
|
let timer;
|
|
11
14
|
const clearTimer = () => {
|
|
12
15
|
if (timer !== void 0) clearTimeout(timer);
|
|
13
16
|
timer = void 0;
|
|
14
17
|
};
|
|
18
|
+
const selectedText = (baseline, proposed) => {
|
|
19
|
+
const { from, to } = baseline.selection;
|
|
20
|
+
const size = proposed.doc.content.size - baseline.doc.content.size + to - from;
|
|
21
|
+
if (size < 0 || from + size > proposed.doc.content.size) return null;
|
|
22
|
+
const text = proposed.doc.textBetween(from, from + size, "", "");
|
|
23
|
+
return text.length === size ? text : null;
|
|
24
|
+
};
|
|
25
|
+
const selectedReplacement = (baseline, proposed) => {
|
|
26
|
+
const { from, to } = baseline.selection;
|
|
27
|
+
const text = selectedText(baseline, proposed);
|
|
28
|
+
if (text === null || !baseline.tr.insertText(text, from, to).doc.eq(proposed.doc)) return null;
|
|
29
|
+
return {
|
|
30
|
+
from,
|
|
31
|
+
to,
|
|
32
|
+
text,
|
|
33
|
+
semantic: "composition"
|
|
34
|
+
};
|
|
35
|
+
};
|
|
15
36
|
const replacement = (baseline, proposed) => {
|
|
16
37
|
const { $from, $to } = baseline.selection;
|
|
17
38
|
if (!$from.parent.isTextblock || !$to.parent.isTextblock) return null;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (text.length !== insertedSize) return null;
|
|
25
|
-
if (!baseline.tr.insertText(text, from, to).doc.eq(proposed.doc)) return null;
|
|
26
|
-
return {
|
|
27
|
-
from,
|
|
28
|
-
to,
|
|
29
|
-
text,
|
|
39
|
+
const selected = selectedReplacement(baseline, proposed);
|
|
40
|
+
if (selected) {
|
|
41
|
+
if ($from.sameParent($to) && selected.text === baseline.doc.textBetween(selected.from, selected.to, "", "")) return {
|
|
42
|
+
from: selected.from,
|
|
43
|
+
to: selected.from,
|
|
44
|
+
text: "",
|
|
30
45
|
semantic: "composition"
|
|
31
46
|
};
|
|
47
|
+
return selected;
|
|
32
48
|
}
|
|
49
|
+
if (!$from.sameParent($to)) return null;
|
|
33
50
|
const start = $from.start();
|
|
34
51
|
const next = proposed.doc.nodeAt(start - 1);
|
|
35
|
-
if (!next || next.type !== $from.parent.type
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
if (!next || next.type !== $from.parent.type) return null;
|
|
53
|
+
const previous = $from.parent.content;
|
|
54
|
+
const changedFrom = previous.findDiffStart(next.content);
|
|
55
|
+
if (changedFrom === null) {
|
|
56
|
+
if (!baseline.doc.eq(proposed.doc)) return null;
|
|
57
|
+
return {
|
|
58
|
+
from: baseline.selection.from,
|
|
59
|
+
to: baseline.selection.from,
|
|
60
|
+
text: "",
|
|
61
|
+
semantic: "composition"
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const changedEnd = previous.findDiffEnd(next.content);
|
|
65
|
+
if (changedEnd === null) return null;
|
|
66
|
+
let from = changedFrom;
|
|
67
|
+
let oldEnd = changedEnd.a;
|
|
68
|
+
let newEnd = changedEnd.b;
|
|
69
|
+
const overlap = from - Math.min(oldEnd, newEnd);
|
|
70
|
+
if (overlap > 0) {
|
|
71
|
+
oldEnd += overlap;
|
|
72
|
+
newEnd += overlap;
|
|
73
|
+
}
|
|
74
|
+
const before = previous.textBetween(0, previous.size, "", "");
|
|
75
|
+
const after = next.content.textBetween(0, next.content.size, "", "");
|
|
76
|
+
while (from < oldEnd && from < newEnd && before[from] === after[from]) from++;
|
|
43
77
|
while (oldEnd > from && newEnd > from && before[oldEnd - 1] === after[newEnd - 1]) {
|
|
44
78
|
oldEnd--;
|
|
45
79
|
newEnd--;
|
|
46
80
|
}
|
|
81
|
+
while (splitsSurrogatePair(before, from) || splitsSurrogatePair(after, from)) from--;
|
|
47
82
|
while (splitsSurrogatePair(before, oldEnd) || splitsSurrogatePair(after, newEnd)) {
|
|
48
83
|
oldEnd++;
|
|
49
84
|
newEnd++;
|
|
50
85
|
}
|
|
51
|
-
const
|
|
86
|
+
const removed = previous.cut(from, oldEnd);
|
|
87
|
+
const inserted = next.content.cut(from, newEnd);
|
|
88
|
+
const text = inserted.textBetween(0, inserted.size, "", "");
|
|
89
|
+
if (removed.textBetween(0, removed.size, "", "").length !== removed.size || text.length !== inserted.size) return null;
|
|
52
90
|
if (!baseline.tr.insertText(text, start + from, start + oldEnd).doc.eq(proposed.doc)) return null;
|
|
53
91
|
return {
|
|
54
92
|
from: start + from,
|
|
@@ -57,26 +95,62 @@ const createCanonicalComposition = (options) => {
|
|
|
57
95
|
semantic: "composition"
|
|
58
96
|
};
|
|
59
97
|
};
|
|
98
|
+
const applyNative = (view, transaction) => Result.try({
|
|
99
|
+
try: () => view.state.applyTransaction(transaction),
|
|
100
|
+
catch: (cause) => new CanonicalSessionError({
|
|
101
|
+
gap: CANONICAL_GAP.dispatch,
|
|
102
|
+
reason: "refused",
|
|
103
|
+
message: `Composition projection failed: ${String(cause)}`
|
|
104
|
+
})
|
|
105
|
+
});
|
|
60
106
|
const finish = (view, commit) => {
|
|
61
107
|
clearTimer();
|
|
62
108
|
authorizedNativeState = null;
|
|
63
109
|
const pending = state;
|
|
64
|
-
if (pending.type === "committed") return;
|
|
110
|
+
if (pending.type === "committed") return { type: "idle" };
|
|
65
111
|
const input = commit && pending.type === "provisional" ? replacement(pending.baseline, view.state) : null;
|
|
112
|
+
const committedText = selectedText(pending.baseline, view.state);
|
|
113
|
+
const proposed = view.state;
|
|
114
|
+
const from = pending.baseline.selection.from;
|
|
115
|
+
completed = { type: "idle" };
|
|
66
116
|
state = { type: "committed" };
|
|
67
|
-
if (!view.isDestroyed)
|
|
117
|
+
if (!view.isDestroyed) {
|
|
118
|
+
if (view.composing) view.dom.dispatchEvent(new Event("compositionend", { bubbles: true }));
|
|
119
|
+
view.updateState(pending.baseline);
|
|
120
|
+
}
|
|
68
121
|
options.end();
|
|
69
|
-
if (!commit || view.isDestroyed
|
|
70
|
-
if (
|
|
122
|
+
if (!commit || view.isDestroyed) return { type: "cancelled" };
|
|
123
|
+
if (pending.type === "refused") return {
|
|
124
|
+
type: "refused",
|
|
125
|
+
text: pending.text
|
|
126
|
+
};
|
|
71
127
|
if (!input) {
|
|
72
128
|
options.refuse("Composition changed unsupported content; the canonical document was restored.");
|
|
73
|
-
return
|
|
129
|
+
return {
|
|
130
|
+
type: "refused",
|
|
131
|
+
text: committedText
|
|
132
|
+
};
|
|
74
133
|
}
|
|
75
|
-
options.replace(input);
|
|
134
|
+
if (input.from !== input.to || input.text !== "") options.replace(input);
|
|
135
|
+
if (committedText !== null && !view.isDestroyed && view.state.doc.textContent === proposed.doc.textContent && from + committedText.length <= view.state.doc.content.size && view.state.doc.textBetween(from, from + committedText.length, "", "") === committedText) completed = {
|
|
136
|
+
type: "completed",
|
|
137
|
+
receipt: {
|
|
138
|
+
view,
|
|
139
|
+
state: view.state,
|
|
140
|
+
from,
|
|
141
|
+
to: from + committedText.length,
|
|
142
|
+
text: committedText,
|
|
143
|
+
marks: pending.baseline.storedMarks ?? pending.baseline.selection.$from.marksAcross(pending.baseline.selection.$to)
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
return {
|
|
147
|
+
type: "committed",
|
|
148
|
+
text: committedText
|
|
149
|
+
};
|
|
76
150
|
};
|
|
77
151
|
const schedule = (view) => {
|
|
78
152
|
clearTimer();
|
|
79
|
-
timer =
|
|
153
|
+
timer = setCanonicalInputTimer(() => finish(view, true), 25);
|
|
80
154
|
};
|
|
81
155
|
return {
|
|
82
156
|
get status() {
|
|
@@ -85,24 +159,72 @@ const createCanonicalComposition = (options) => {
|
|
|
85
159
|
get active() {
|
|
86
160
|
return state.type !== "committed";
|
|
87
161
|
},
|
|
162
|
+
matchesCancellationRange: (view, range) => {
|
|
163
|
+
if (state.type === "committed" || state.view !== view) return false;
|
|
164
|
+
const text = selectedText(state.baseline, view.state);
|
|
165
|
+
if (text === null || text.length === 0) return false;
|
|
166
|
+
const from = state.baseline.selection.from;
|
|
167
|
+
if (range.from !== from || range.to !== from + text.length) return false;
|
|
168
|
+
const selection = view.dom.ownerDocument.getSelection();
|
|
169
|
+
if (!selection || selection.rangeCount !== 1) return false;
|
|
170
|
+
const selected = selection.getRangeAt(0);
|
|
171
|
+
if (!view.dom.contains(selected.startContainer) || !view.dom.contains(selected.endContainer)) return false;
|
|
172
|
+
return view.posAtDOM(selected.startContainer, selected.startOffset) === range.from && view.posAtDOM(selected.endContainer, selected.endOffset) === range.to;
|
|
173
|
+
},
|
|
88
174
|
start: (view) => {
|
|
89
175
|
if (state.type !== "committed") return;
|
|
90
176
|
if (!options.begin()) return;
|
|
91
177
|
state = {
|
|
92
178
|
type: "provisional",
|
|
93
179
|
baseline: view.state,
|
|
180
|
+
view,
|
|
94
181
|
phase: "active"
|
|
95
182
|
};
|
|
96
183
|
},
|
|
97
184
|
ended: (view) => {
|
|
98
185
|
if (state.type === "committed") return;
|
|
99
|
-
state
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
186
|
+
switch (state.type) {
|
|
187
|
+
case "provisional":
|
|
188
|
+
state = {
|
|
189
|
+
type: "provisional",
|
|
190
|
+
baseline: state.baseline,
|
|
191
|
+
view: state.view,
|
|
192
|
+
phase: "ended"
|
|
193
|
+
};
|
|
194
|
+
break;
|
|
195
|
+
case "refused":
|
|
196
|
+
state = {
|
|
197
|
+
type: "refused",
|
|
198
|
+
baseline: state.baseline,
|
|
199
|
+
view: state.view,
|
|
200
|
+
phase: "ended",
|
|
201
|
+
text: state.text
|
|
202
|
+
};
|
|
203
|
+
break;
|
|
204
|
+
default:
|
|
205
|
+
}
|
|
104
206
|
schedule(view);
|
|
105
207
|
},
|
|
208
|
+
forgetCompleted: () => {
|
|
209
|
+
completed = { type: "idle" };
|
|
210
|
+
},
|
|
211
|
+
get pendingFinal() {
|
|
212
|
+
return completed.type === "authorized";
|
|
213
|
+
},
|
|
214
|
+
authorizeLateFinal: (view, text) => {
|
|
215
|
+
if (completed.type === "idle") return false;
|
|
216
|
+
const { receipt } = completed;
|
|
217
|
+
if (view.isDestroyed || receipt.view !== view || receipt.state !== view.state || text === null) {
|
|
218
|
+
completed = { type: "idle" };
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
completed = {
|
|
222
|
+
type: "authorized",
|
|
223
|
+
receipt,
|
|
224
|
+
text
|
|
225
|
+
};
|
|
226
|
+
return true;
|
|
227
|
+
},
|
|
106
228
|
authorizeNative: (view) => {
|
|
107
229
|
authorizedNativeState = view.state;
|
|
108
230
|
},
|
|
@@ -116,13 +238,53 @@ const createCanonicalComposition = (options) => {
|
|
|
116
238
|
recover: (view) => finish(view, true),
|
|
117
239
|
cancel: (view) => finish(view, false),
|
|
118
240
|
reset: () => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
241
|
+
completed = { type: "idle" };
|
|
242
|
+
if (state.type !== "committed") finish(state.view, false);
|
|
243
|
+
else {
|
|
244
|
+
clearTimer();
|
|
245
|
+
authorizedNativeState = null;
|
|
246
|
+
}
|
|
123
247
|
},
|
|
124
248
|
accept: (view, transaction) => {
|
|
125
|
-
if (state.type === "committed")
|
|
249
|
+
if (state.type === "committed") {
|
|
250
|
+
const final = completed;
|
|
251
|
+
if (final.type !== "authorized" || final.receipt.view !== view) return false;
|
|
252
|
+
completed = { type: "idle" };
|
|
253
|
+
if (view.isDestroyed || final.receipt.state !== view.state) return false;
|
|
254
|
+
const applied = applyNative(view, transaction);
|
|
255
|
+
const baseline = EditorState.create({
|
|
256
|
+
schema: final.receipt.state.schema,
|
|
257
|
+
doc: final.receipt.state.doc,
|
|
258
|
+
selection: TextSelection.create(final.receipt.state.doc, final.receipt.from, final.receipt.to),
|
|
259
|
+
storedMarks: final.receipt.marks
|
|
260
|
+
});
|
|
261
|
+
const input = applied.isOk() ? replacement(baseline, applied.value.state) : null;
|
|
262
|
+
if (applied.isErr() || !input || input.from < final.receipt.from || input.to > final.receipt.to || selectedText(baseline, applied.value.state) !== final.text) {
|
|
263
|
+
view.updateState(final.receipt.state);
|
|
264
|
+
options.refuse(applied.isErr() ? applied.error.message : "Final composition changed unsupported content; the canonical document was restored.");
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
if (final.receipt.text !== final.text) options.replace({
|
|
268
|
+
from: final.receipt.from,
|
|
269
|
+
to: final.receipt.to,
|
|
270
|
+
text: final.text,
|
|
271
|
+
semantic: "composition",
|
|
272
|
+
compositionPhase: "correction"
|
|
273
|
+
});
|
|
274
|
+
if (!view.isDestroyed) view.updateState(view.state);
|
|
275
|
+
if (!view.isDestroyed && view.state.doc.textContent === applied.value.state.doc.textContent && final.receipt.from + final.text.length <= view.state.doc.content.size && view.state.doc.textBetween(final.receipt.from, final.receipt.from + final.text.length, "", "") === final.text) completed = {
|
|
276
|
+
type: "completed",
|
|
277
|
+
receipt: {
|
|
278
|
+
view,
|
|
279
|
+
state: view.state,
|
|
280
|
+
from: final.receipt.from,
|
|
281
|
+
to: final.receipt.from + final.text.length,
|
|
282
|
+
text: final.text,
|
|
283
|
+
marks: final.receipt.marks
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
126
288
|
if (state.type === "refused") {
|
|
127
289
|
view.updateState(state.baseline);
|
|
128
290
|
return true;
|
|
@@ -132,19 +294,15 @@ const createCanonicalComposition = (options) => {
|
|
|
132
294
|
return true;
|
|
133
295
|
}
|
|
134
296
|
authorizedNativeState = null;
|
|
135
|
-
const applied =
|
|
136
|
-
try: () => view.state.applyTransaction(transaction),
|
|
137
|
-
catch: (cause) => new CanonicalSessionError({
|
|
138
|
-
reason: "refused",
|
|
139
|
-
message: `Composition projection failed: ${String(cause)}`
|
|
140
|
-
})
|
|
141
|
-
});
|
|
297
|
+
const applied = applyNative(view, transaction);
|
|
142
298
|
if (applied.isErr()) {
|
|
143
299
|
view.updateState(state.baseline);
|
|
144
300
|
state = {
|
|
145
301
|
type: "refused",
|
|
146
302
|
baseline: state.baseline,
|
|
147
|
-
|
|
303
|
+
view: state.view,
|
|
304
|
+
phase: state.phase,
|
|
305
|
+
text: selectedText(state.baseline, transaction)
|
|
148
306
|
};
|
|
149
307
|
options.refuse(applied.error.message);
|
|
150
308
|
return true;
|
|
@@ -154,7 +312,9 @@ const createCanonicalComposition = (options) => {
|
|
|
154
312
|
state = {
|
|
155
313
|
type: "refused",
|
|
156
314
|
baseline: state.baseline,
|
|
157
|
-
|
|
315
|
+
view: state.view,
|
|
316
|
+
phase: state.phase,
|
|
317
|
+
text: selectedText(state.baseline, applied.value.state)
|
|
158
318
|
};
|
|
159
319
|
options.refuse("Composition changed unsupported content; the canonical document was restored.");
|
|
160
320
|
return true;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { Node } from "prosemirror-model";
|
|
3
|
+
import { Result } from "better-result";
|
|
4
|
+
//#region src/controller/canonicalInlineProjection.d.ts
|
|
5
|
+
declare const CANONICAL_SOURCE_INLINE_POLICIES: {
|
|
6
|
+
readonly run: "container";
|
|
7
|
+
readonly hyperlink: "container";
|
|
8
|
+
readonly insertion: "container";
|
|
9
|
+
readonly deletion: "container";
|
|
10
|
+
readonly moveFrom: "container";
|
|
11
|
+
readonly moveTo: "container";
|
|
12
|
+
readonly inlineWrapper: "container";
|
|
13
|
+
readonly inlineSdt: "control";
|
|
14
|
+
readonly simpleField: "leaf";
|
|
15
|
+
readonly complexField: "leaf";
|
|
16
|
+
readonly mathEquation: "leaf";
|
|
17
|
+
readonly preservedInline: "leaf";
|
|
18
|
+
readonly bookmarkStart: "leaf";
|
|
19
|
+
readonly bookmarkEnd: "leaf";
|
|
20
|
+
readonly commentRangeStart: "leaf";
|
|
21
|
+
readonly commentRangeEnd: "leaf";
|
|
22
|
+
readonly commentReference: "leaf";
|
|
23
|
+
readonly moveFromRangeStart: "leaf";
|
|
24
|
+
readonly moveFromRangeEnd: "leaf";
|
|
25
|
+
readonly moveToRangeStart: "leaf";
|
|
26
|
+
readonly moveToRangeEnd: "leaf";
|
|
27
|
+
readonly text: "text";
|
|
28
|
+
readonly tab: "leaf";
|
|
29
|
+
readonly break: "leaf";
|
|
30
|
+
readonly symbol: "leaf";
|
|
31
|
+
readonly footnoteRef: "leaf";
|
|
32
|
+
readonly endnoteRef: "leaf";
|
|
33
|
+
readonly noteMarker: "leaf";
|
|
34
|
+
readonly fieldChar: "rawField";
|
|
35
|
+
readonly instrText: "rawField";
|
|
36
|
+
readonly softHyphen: "leaf";
|
|
37
|
+
readonly noBreakHyphen: "leaf";
|
|
38
|
+
readonly renderedPageBreak: "layout";
|
|
39
|
+
readonly preservedXml: "leaf";
|
|
40
|
+
readonly drawing: "leaf";
|
|
41
|
+
readonly shape: "leaf";
|
|
42
|
+
};
|
|
43
|
+
declare const CANONICAL_NATIVE_INLINE_POLICIES: {
|
|
44
|
+
readonly text: "text";
|
|
45
|
+
readonly bookmarkBoundary: "markers";
|
|
46
|
+
readonly moveRangeBoundary: "markers";
|
|
47
|
+
readonly rangeAnchor: "markers";
|
|
48
|
+
readonly noteMarker: "noteMarker";
|
|
49
|
+
readonly preservedXml: "capture";
|
|
50
|
+
readonly field: "unit";
|
|
51
|
+
readonly structuredField: "unit";
|
|
52
|
+
readonly hardBreak: "unit";
|
|
53
|
+
readonly image: "unit";
|
|
54
|
+
readonly math: "unit";
|
|
55
|
+
readonly pageBreakRun: "unit";
|
|
56
|
+
readonly shape: "unit";
|
|
57
|
+
readonly symbol: "unit";
|
|
58
|
+
readonly tab: "unit";
|
|
59
|
+
readonly textBoxAnchor: "unit";
|
|
60
|
+
readonly commentReference: "unit";
|
|
61
|
+
readonly renderedPageBreak: "refused";
|
|
62
|
+
readonly sdt: "refused";
|
|
63
|
+
};
|
|
64
|
+
declare const InlineProjectionError_base: import("better-result").TaggedErrorClass<"InlineProjectionError">;
|
|
65
|
+
declare class InlineProjectionError extends InlineProjectionError_base<{
|
|
66
|
+
message: string;
|
|
67
|
+
}> {}
|
|
68
|
+
/** Every source variant makes a decision before conversion can discard its positions. */
|
|
69
|
+
declare const canonicalInlineSourceIssue: (items: readonly (document_d_exports.ParagraphContent | document_d_exports.RunContent)[], context?: "paragraph" | "fieldPayload") => string | null;
|
|
70
|
+
type NativeCell = {
|
|
71
|
+
type: "text";
|
|
72
|
+
text: string;
|
|
73
|
+
from: number;
|
|
74
|
+
to: number;
|
|
75
|
+
node: Node;
|
|
76
|
+
} | {
|
|
77
|
+
type: "unit";
|
|
78
|
+
from: number;
|
|
79
|
+
to: number;
|
|
80
|
+
node: Node;
|
|
81
|
+
} | {
|
|
82
|
+
type: "markedUnit";
|
|
83
|
+
sourceType: document_d_exports.NoteReferenceContent["type"];
|
|
84
|
+
label: string;
|
|
85
|
+
from: number;
|
|
86
|
+
to: number;
|
|
87
|
+
node: Node;
|
|
88
|
+
} | {
|
|
89
|
+
type: "zeroWidth";
|
|
90
|
+
sources: readonly (document_d_exports.ParagraphContent | document_d_exports.RunContent)[];
|
|
91
|
+
from: number;
|
|
92
|
+
to: number;
|
|
93
|
+
node: Node;
|
|
94
|
+
};
|
|
95
|
+
/** Native positions and deletion geometry read the same inline-cell classification. */
|
|
96
|
+
declare const canonicalNativeCells: (paragraph: Node) => Result<NativeCell[], InlineProjectionError>;
|
|
97
|
+
type CanonicalInlineGap = {
|
|
98
|
+
position: number;
|
|
99
|
+
zeroWidthBefore: number;
|
|
100
|
+
};
|
|
101
|
+
type InlineProjection = {
|
|
102
|
+
text: string;
|
|
103
|
+
boundaries: CanonicalInlineGap[][];
|
|
104
|
+
};
|
|
105
|
+
type CanonicalInlineProjectionArgs = {
|
|
106
|
+
source: document_d_exports.Paragraph;
|
|
107
|
+
paragraph: Node;
|
|
108
|
+
pairedBookmarkIds: ReadonlySet<number>;
|
|
109
|
+
commentContext?: {
|
|
110
|
+
rangedIds: ReadonlySet<number>;
|
|
111
|
+
pointIds: ReadonlySet<number>;
|
|
112
|
+
openIds: ReadonlySet<number>;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
/** Bind rendered gaps to the operation owner's source leaf ordinals, including collapsed pairs. */
|
|
116
|
+
declare const projectCanonicalInline: ({ source, paragraph, pairedBookmarkIds, commentContext }: CanonicalInlineProjectionArgs) => Result<InlineProjection, InlineProjectionError>;
|
|
117
|
+
//#endregion
|
|
118
|
+
export { CANONICAL_NATIVE_INLINE_POLICIES, CANONICAL_SOURCE_INLINE_POLICIES, CanonicalInlineGap, canonicalInlineSourceIssue, canonicalNativeCells, projectCanonicalInline };
|