@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,4 +1,5 @@
|
|
|
1
1
|
import { expectFootnoteRefMarkAttrs } from "../../attrs/index.js";
|
|
2
|
+
import { mintNoteReferenceOccurrenceId, noteReferenceOccurrencePlugin } from "../../noteReferenceOccurrences.js";
|
|
2
3
|
import { suggestRangeDeletion, suggestionModeKey } from "../../plugins/suggestionMode.js";
|
|
3
4
|
import { createMarkExtension } from "../create.js";
|
|
4
5
|
import { expandNoteReferenceDeletionRange, noteReferenceRanges } from "./noteReferenceDeletion.js";
|
|
@@ -9,7 +10,9 @@ import { panic } from "better-result";
|
|
|
9
10
|
*
|
|
10
11
|
* Provides footnoteRef mark + insert/delete commands for footnotes and endnotes.
|
|
11
12
|
*/
|
|
13
|
+
const NOTE_REFERENCE_PARSE_PRIORITY = 60;
|
|
12
14
|
const noteRefAttrsFromDom = (dom, noteType, vertAlign) => ({
|
|
15
|
+
occurrenceId: dom.dataset["noteOccurrence"] ?? mintNoteReferenceOccurrenceId(),
|
|
13
16
|
id: dom.dataset["id"] ?? "",
|
|
14
17
|
noteType: dom.dataset["noteType"] ?? noteType,
|
|
15
18
|
...vertAlign ? { vertAlign } : {}
|
|
@@ -21,6 +24,7 @@ const FootnoteRefExtension = createMarkExtension({
|
|
|
21
24
|
inclusive: false,
|
|
22
25
|
attrs: {
|
|
23
26
|
id: {},
|
|
27
|
+
occurrenceId: {},
|
|
24
28
|
noteType: { default: "footnote" },
|
|
25
29
|
vertAlign: { default: null },
|
|
26
30
|
customMarkFollows: { default: null }
|
|
@@ -28,18 +32,22 @@ const FootnoteRefExtension = createMarkExtension({
|
|
|
28
32
|
parseDOM: [
|
|
29
33
|
{
|
|
30
34
|
tag: "sup.docx-footnote-ref",
|
|
35
|
+
priority: NOTE_REFERENCE_PARSE_PRIORITY,
|
|
31
36
|
getAttrs: (dom) => noteRefAttrsFromDom(dom, "footnote", "superscript")
|
|
32
37
|
},
|
|
33
38
|
{
|
|
34
39
|
tag: "sup.docx-endnote-ref",
|
|
40
|
+
priority: NOTE_REFERENCE_PARSE_PRIORITY,
|
|
35
41
|
getAttrs: (dom) => noteRefAttrsFromDom(dom, "endnote", "superscript")
|
|
36
42
|
},
|
|
37
43
|
{
|
|
38
44
|
tag: "span.docx-footnote-ref",
|
|
45
|
+
priority: NOTE_REFERENCE_PARSE_PRIORITY,
|
|
39
46
|
getAttrs: (dom) => noteRefAttrsFromDom(dom, "footnote", "baseline")
|
|
40
47
|
},
|
|
41
48
|
{
|
|
42
49
|
tag: "span.docx-endnote-ref",
|
|
50
|
+
priority: NOTE_REFERENCE_PARSE_PRIORITY,
|
|
43
51
|
getAttrs: (dom) => noteRefAttrsFromDom(dom, "endnote", "baseline")
|
|
44
52
|
}
|
|
45
53
|
],
|
|
@@ -53,6 +61,7 @@ const FootnoteRefExtension = createMarkExtension({
|
|
|
53
61
|
{
|
|
54
62
|
class: `docx-${noteType}-ref ${isSuperscript ? "docx-note-ref-superscript" : "docx-note-ref-baseline"}`,
|
|
55
63
|
"data-id": id,
|
|
64
|
+
"data-note-occurrence": attrs.occurrenceId,
|
|
56
65
|
"data-note-type": noteType
|
|
57
66
|
},
|
|
58
67
|
0
|
|
@@ -76,6 +85,7 @@ const FootnoteRefExtension = createMarkExtension({
|
|
|
76
85
|
if (!footnoteRefType) panic("Missing mark type: footnoteRef");
|
|
77
86
|
const mark = footnoteRefType.create({
|
|
78
87
|
id: String(id),
|
|
88
|
+
occurrenceId: mintNoteReferenceOccurrenceId(),
|
|
79
89
|
noteType,
|
|
80
90
|
vertAlign: "superscript"
|
|
81
91
|
});
|
|
@@ -100,6 +110,7 @@ const FootnoteRefExtension = createMarkExtension({
|
|
|
100
110
|
return true;
|
|
101
111
|
};
|
|
102
112
|
return {
|
|
113
|
+
plugins: [noteReferenceOccurrencePlugin()],
|
|
103
114
|
keyboardShortcuts: {
|
|
104
115
|
Backspace: deleteWholeNoteReference("backward"),
|
|
105
116
|
Delete: deleteWholeNoteReference("forward")
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { BUILT_IN_STYLE_NAME } from "../../../docx/builtInStyles.js";
|
|
1
2
|
import { anchorTargetAttrs, normalizeUserUrl, sanitizeExternalUrl } from "../../../utils/urlSecurity.js";
|
|
2
3
|
import { expectHyperlinkMarkAttrs } from "../../attrs/index.js";
|
|
3
|
-
import {
|
|
4
|
+
import { withCanonicalCommand } from "../../canonicalCommands.js";
|
|
5
|
+
import { canonicalSelectionRange } from "../../canonicalSelectionRange.js";
|
|
6
|
+
import { assertHyperlinkRemovalRange, removeHyperlinkInRange } from "../../hyperlinkRemoval.js";
|
|
7
|
+
import { getDocumentBuiltInStyles } from "../../plugins/documentStyleState.js";
|
|
4
8
|
import { createMarkExtension } from "../create.js";
|
|
5
9
|
import { isMarkActive } from "./markUtils.js";
|
|
6
10
|
import { panic } from "better-result";
|
|
@@ -121,7 +125,7 @@ const HyperlinkExtension = createMarkExtension({
|
|
|
121
125
|
onSchemaReady(ctx) {
|
|
122
126
|
if (!ctx.schema.marks["hyperlink"]) panic("Missing mark type: hyperlink");
|
|
123
127
|
const documentHyperlinkType = (state) => state.schema.marks["hyperlink"] ?? panic("Missing mark type: hyperlink");
|
|
124
|
-
const setHyperlink = (href, tooltip) => (state, dispatch) => {
|
|
128
|
+
const setHyperlink = (href, tooltip) => withCanonicalCommand((state, dispatch) => {
|
|
125
129
|
const hlType = documentHyperlinkType(state);
|
|
126
130
|
const { from, to, empty } = state.selection;
|
|
127
131
|
if (empty) return false;
|
|
@@ -136,34 +140,60 @@ const HyperlinkExtension = createMarkExtension({
|
|
|
136
140
|
dispatch(tr.scrollIntoView());
|
|
137
141
|
}
|
|
138
142
|
return true;
|
|
143
|
+
}, (state) => state.selection.empty ? [] : [{
|
|
144
|
+
type: "setHyperlink",
|
|
145
|
+
...canonicalSelectionRange(state),
|
|
146
|
+
href: normalizeHyperlinkInput(href),
|
|
147
|
+
...tooltip ? { tooltip } : {}
|
|
148
|
+
}]);
|
|
149
|
+
const removalRange = (state) => {
|
|
150
|
+
const { empty, $from } = state.selection;
|
|
151
|
+
const { from, to } = canonicalSelectionRange(state);
|
|
152
|
+
assertHyperlinkRemovalRange({
|
|
153
|
+
doc: state.doc,
|
|
154
|
+
from,
|
|
155
|
+
to
|
|
156
|
+
});
|
|
157
|
+
if (!empty) return {
|
|
158
|
+
from,
|
|
159
|
+
to
|
|
160
|
+
};
|
|
161
|
+
const linkMark = $from.marks().find((mark) => mark.type === documentHyperlinkType(state));
|
|
162
|
+
if (!linkMark) return void 0;
|
|
163
|
+
let contiguous;
|
|
164
|
+
let selected;
|
|
165
|
+
$from.parent.forEach((node, offset) => {
|
|
166
|
+
if (!node.isInline || !node.marks.some((mark) => mark.eq(linkMark))) {
|
|
167
|
+
contiguous = void 0;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const start = $from.start() + offset;
|
|
171
|
+
const end = start + node.nodeSize;
|
|
172
|
+
if (contiguous?.to === start) contiguous.to = end;
|
|
173
|
+
else contiguous = {
|
|
174
|
+
from: start,
|
|
175
|
+
to: end
|
|
176
|
+
};
|
|
177
|
+
if (start <= from && from <= end) selected = contiguous;
|
|
178
|
+
});
|
|
179
|
+
return selected;
|
|
139
180
|
};
|
|
140
|
-
const removeHyperlink = (state, dispatch) => {
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
if (
|
|
144
|
-
const $pos = state.selection.$from;
|
|
145
|
-
if (!$pos.marks().find((m) => m.type === hlType)) return false;
|
|
146
|
-
let start = $pos.pos;
|
|
147
|
-
let end = $pos.pos;
|
|
148
|
-
$pos.parent.forEach((node, offset) => {
|
|
149
|
-
if (node.isText) {
|
|
150
|
-
const nodeStart = $pos.start() + offset;
|
|
151
|
-
const nodeEnd = nodeStart + node.nodeSize;
|
|
152
|
-
if (nodeStart <= $pos.pos && $pos.pos <= nodeEnd) {
|
|
153
|
-
if (node.marks.some((m) => m.type === hlType)) {
|
|
154
|
-
start = Math.min(start, nodeStart);
|
|
155
|
-
end = Math.max(end, nodeEnd);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
if (dispatch) dispatch(removeHyperlinkInRange(state, state.tr, start, end).scrollIntoView());
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
if (dispatch) dispatch(removeHyperlinkInRange(state, state.tr, from, to).scrollIntoView());
|
|
181
|
+
const removeHyperlink = withCanonicalCommand((state, dispatch) => {
|
|
182
|
+
const range = removalRange(state);
|
|
183
|
+
if (!range) return false;
|
|
184
|
+
if (dispatch) dispatch(removeHyperlinkInRange(state, state.tr, range.from, range.to).scrollIntoView());
|
|
164
185
|
return true;
|
|
165
|
-
}
|
|
166
|
-
|
|
186
|
+
}, (state) => {
|
|
187
|
+
const range = removalRange(state);
|
|
188
|
+
if (!range) return [];
|
|
189
|
+
const hyperlinkStyleId = getDocumentBuiltInStyles(state).styleIdForBuiltInName(BUILT_IN_STYLE_NAME.hyperlink);
|
|
190
|
+
return [{
|
|
191
|
+
type: "removeHyperlink",
|
|
192
|
+
...range,
|
|
193
|
+
...hyperlinkStyleId === void 0 ? {} : { hyperlinkStyleId }
|
|
194
|
+
}];
|
|
195
|
+
});
|
|
196
|
+
const insertHyperlink = (text, href, tooltip) => withCanonicalCommand((state, dispatch) => {
|
|
167
197
|
const hlType = documentHyperlinkType(state);
|
|
168
198
|
if (dispatch) {
|
|
169
199
|
const mark = hlType.create({
|
|
@@ -174,7 +204,13 @@ const HyperlinkExtension = createMarkExtension({
|
|
|
174
204
|
dispatch(state.tr.replaceSelectionWith(textNode, false).scrollIntoView());
|
|
175
205
|
}
|
|
176
206
|
return true;
|
|
177
|
-
}
|
|
207
|
+
}, (state) => [{
|
|
208
|
+
type: "insertHyperlink",
|
|
209
|
+
...canonicalSelectionRange(state),
|
|
210
|
+
text,
|
|
211
|
+
href: normalizeHyperlinkInput(href),
|
|
212
|
+
...tooltip ? { tooltip } : {}
|
|
213
|
+
}]);
|
|
178
214
|
return { commands: {
|
|
179
215
|
setHyperlink,
|
|
180
216
|
removeHyperlink: () => removeHyperlink,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { FONT_THEME_VALUES } from "../../../types/documentEnumValues.js";
|
|
2
2
|
import { mergeFontFamily } from "../../../utils/fontFamilyMerge.js";
|
|
3
3
|
import { normalizeHorizontalScalePercent } from "../../../utils/horizontalScale.js";
|
|
4
|
-
import { expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectEmphasisMarkAttrs, expectFontFamilyMarkAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectStrikeMarkAttrs, expectTextEffectMarkAttrs } from "../../attrs/index.js";
|
|
4
|
+
import { expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectEmphasisMarkAttrs, expectFontFamilyMarkAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectStrikeMarkAttrs, expectTextEffectMarkAttrs } from "../../attrs/index.js";
|
|
5
5
|
import { canonicalRunFormatting, withCanonicalCommand } from "../../canonicalCommands.js";
|
|
6
|
+
import { canonicalSelectionRange } from "../../canonicalSelectionRange.js";
|
|
6
7
|
import { runShadingAttrsToShading, shadingToRunShadingAttrs } from "../../conversion/runShadingMark.js";
|
|
7
8
|
import { documentMarkType } from "../../documentSchema.js";
|
|
8
9
|
import { selectRunFormattingCarrierRepresentations } from "../../runFormattingInlineCarriers.js";
|
|
@@ -146,14 +147,15 @@ function saveStoredMarksToParagraph(state, tr, marks) {
|
|
|
146
147
|
const paragraph = $from.parent;
|
|
147
148
|
if (paragraph.type.name !== "paragraph") return tr;
|
|
148
149
|
if (paragraph.textContent.length > 0) return tr;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
defaultTextFormatting: null
|
|
152
|
-
});
|
|
153
|
-
const defaultTextFormatting = marksToTextFormatting(marks);
|
|
150
|
+
const attrs = expectParagraphAttrs(paragraph);
|
|
151
|
+
const defaultTextFormatting = marks.length === 0 ? null : marksToTextFormatting(marks);
|
|
154
152
|
return tr.setNodeMarkup($from.before(), void 0, {
|
|
155
153
|
...paragraph.attrs,
|
|
156
|
-
defaultTextFormatting
|
|
154
|
+
defaultTextFormatting,
|
|
155
|
+
_originalFormatting: {
|
|
156
|
+
...attrs._originalFormatting,
|
|
157
|
+
runProperties: defaultTextFormatting ?? void 0
|
|
158
|
+
}
|
|
157
159
|
});
|
|
158
160
|
}
|
|
159
161
|
function dispatchStoredMarks(state, dispatch, marks) {
|
|
@@ -188,7 +190,8 @@ function createMarkWithMergedAttrs(markType, currentMark, nextAttrs) {
|
|
|
188
190
|
}
|
|
189
191
|
const canonicalSetMarkFormatting = ({ state, type, attrs }) => {
|
|
190
192
|
const markType = documentMarkType(state, type);
|
|
191
|
-
const {
|
|
193
|
+
const { empty } = state.selection;
|
|
194
|
+
const { from, to } = canonicalSelectionRange(state);
|
|
192
195
|
if (empty) return canonicalRunFormatting(state, marksToTextFormatting([createMarkWithMergedAttrs(markType, markType.isInSet(state.storedMarks ?? state.selection.$from.marks()), attrs)]));
|
|
193
196
|
return selectRunFormattingCarrierRepresentations({
|
|
194
197
|
doc: state.doc,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { expectFootnoteRefMarkAttrs } from "../../attrs/index.js";
|
|
1
2
|
//#region src/prosemirror/extensions/marks/noteReferenceDeletion.ts
|
|
2
3
|
/** Keep the text carrying one OOXML note reference together during deletion. */
|
|
3
4
|
const expandNoteReferenceDeletionRange = (doc, from, to) => {
|
|
@@ -7,6 +8,8 @@ const expandNoteReferenceDeletionRange = (doc, from, to) => {
|
|
|
7
8
|
doc.nodesBetween(from, to, (node, pos) => {
|
|
8
9
|
const reference = node.marks.find((mark) => mark.type.name === "footnoteRef");
|
|
9
10
|
if (!node.isText || !reference) return;
|
|
11
|
+
const { occurrenceId } = expectFootnoteRefMarkAttrs(reference);
|
|
12
|
+
const sameOccurrence = (sibling) => sibling.isText && sibling.marks.some((mark) => mark.type.name === "footnoteRef" && expectFootnoteRefMarkAttrs(mark).occurrenceId === occurrenceId);
|
|
10
13
|
intersectsReference = true;
|
|
11
14
|
const $pos = doc.resolve(pos);
|
|
12
15
|
const parent = $pos.parent;
|
|
@@ -15,12 +18,12 @@ const expandNoteReferenceDeletionRange = (doc, from, to) => {
|
|
|
15
18
|
let referenceTo = pos + node.nodeSize;
|
|
16
19
|
for (let left = index - 1; left >= 0; left--) {
|
|
17
20
|
const sibling = parent.child(left);
|
|
18
|
-
if (!sibling
|
|
21
|
+
if (!sameOccurrence(sibling)) break;
|
|
19
22
|
referenceFrom -= sibling.nodeSize;
|
|
20
23
|
}
|
|
21
24
|
for (let right = index + 1; right < parent.childCount; right++) {
|
|
22
25
|
const sibling = parent.child(right);
|
|
23
|
-
if (!sibling
|
|
26
|
+
if (!sameOccurrence(sibling)) break;
|
|
24
27
|
referenceTo += sibling.nodeSize;
|
|
25
28
|
}
|
|
26
29
|
expandedFrom = Math.min(expandedFrom, referenceFrom);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Node } from "prosemirror-model";
|
|
2
|
+
//#region src/prosemirror/fieldRepresentation.d.ts
|
|
3
|
+
/** Current children alone decide whether a field needs editable structural content. */
|
|
4
|
+
declare const fieldRequiresStructuredContent: (children: readonly Node[]) => boolean;
|
|
5
|
+
/** Resolution returns text-only fields to the same atom representation as initial conversion. */
|
|
6
|
+
declare const canonicalFieldNode: (node: Node) => Node;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { canonicalFieldNode, fieldRequiresStructuredContent };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "./extensions/marks/InlineWrapperExtension.js";
|
|
2
|
+
//#region src/prosemirror/fieldRepresentation.ts
|
|
3
|
+
/** Current children alone decide whether a field needs editable structural content. */
|
|
4
|
+
const fieldRequiresStructuredContent = (children) => children.some((child) => !child.isText || child.marks.some((mark) => mark.type.name === "hyperlink" || mark.type.name === "inlineWrapper" || mark.type.name === "insertion" || mark.type.name === "deletion"));
|
|
5
|
+
/** Resolution returns text-only fields to the same atom representation as initial conversion. */
|
|
6
|
+
const canonicalFieldNode = (node) => {
|
|
7
|
+
if (node.type.name !== "structuredField") return node;
|
|
8
|
+
const attrs = {
|
|
9
|
+
...node.attrs,
|
|
10
|
+
displayText: node.textContent
|
|
11
|
+
};
|
|
12
|
+
if (fieldRequiresStructuredContent(node.content.content)) return node.attrs["displayText"] === node.textContent ? node : node.type.create(attrs, node.content, node.marks);
|
|
13
|
+
let marks = node.marks;
|
|
14
|
+
for (const mark of node.firstChild?.marks ?? []) marks = mark.addToSet(marks);
|
|
15
|
+
return node.type.schema.node("field", attrs, void 0, marks);
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { canonicalFieldNode, fieldRequiresStructuredContent };
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
+
import { Node } from "prosemirror-model";
|
|
1
2
|
import { EditorState, Transaction } from "prosemirror-state";
|
|
2
3
|
//#region src/prosemirror/hyperlinkRemoval.d.ts
|
|
4
|
+
declare const HyperlinkRemovalRefusal_base: import("better-result").TaggedErrorClass<"HyperlinkRemovalRefusal">;
|
|
5
|
+
declare class HyperlinkRemovalRefusal extends HyperlinkRemovalRefusal_base<{
|
|
6
|
+
message: string;
|
|
7
|
+
}> {}
|
|
8
|
+
type HyperlinkRemovalRangeOptions = {
|
|
9
|
+
doc: Node;
|
|
10
|
+
from: number;
|
|
11
|
+
to: number;
|
|
12
|
+
};
|
|
13
|
+
/** Canonical inline elements have no addressable interior gaps. */
|
|
14
|
+
declare const assertHyperlinkRemovalRange: ({ doc, from, to }: HyperlinkRemovalRangeOptions) => void;
|
|
3
15
|
/**
|
|
4
16
|
* Remove the hyperlinks from [`from`, `to`) of `tr.doc`: directly, or, with
|
|
5
17
|
* suggestions on, as a tracked replacement of the linked text by plain text.
|
|
6
18
|
*/
|
|
7
19
|
declare const removeHyperlinkInRange: (state: EditorState, tr: Transaction, from: number, to: number) => Transaction;
|
|
8
20
|
//#endregion
|
|
9
|
-
export { removeHyperlinkInRange };
|
|
21
|
+
export { HyperlinkRemovalRefusal, assertHyperlinkRemovalRange, removeHyperlinkInRange };
|
|
@@ -3,19 +3,33 @@ import { getDocumentBuiltInStyles, getDocumentStyleResolver } from "./plugins/do
|
|
|
3
3
|
import { isSuggestionModeActive, makeRevisionInfo, suggestRangeDeletion } from "./plugins/suggestionMode.js";
|
|
4
4
|
import { readAuthoredRunFormatting, reconcileRunFormattingMarks } from "./runFormattingReconciliation.js";
|
|
5
5
|
import { paragraphRunStyleContextAt } from "./runStyleFormatting.js";
|
|
6
|
+
import { TaggedError } from "better-result";
|
|
6
7
|
//#region src/prosemirror/hyperlinkRemoval.ts
|
|
7
|
-
|
|
8
|
+
var HyperlinkRemovalRefusal = class extends TaggedError("HyperlinkRemovalRefusal") {};
|
|
9
|
+
const partialInlineRefusal = () => new HyperlinkRemovalRefusal({ message: "Hyperlink removal cannot split an indivisible inline element." });
|
|
10
|
+
/** Canonical inline elements have no addressable interior gaps. */
|
|
11
|
+
const assertHyperlinkRemovalRange = ({ doc, from, to }) => {
|
|
12
|
+
for (const position of [from, to]) {
|
|
13
|
+
const resolved = doc.resolve(position);
|
|
14
|
+
for (let depth = 1; depth <= resolved.depth; depth += 1) {
|
|
15
|
+
const node = resolved.node(depth);
|
|
16
|
+
if (node.isInline && node.marks.some(({ type }) => type.name === "hyperlink")) throw partialInlineRefusal();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/** Contiguous stretches of linked, not yet deleted, inline content in [`from`, `to`) of `doc`. */
|
|
8
21
|
const linkedRanges = (doc, from, to) => {
|
|
9
22
|
const ranges = [];
|
|
10
23
|
doc.nodesBetween(from, to, (node, position) => {
|
|
11
|
-
if (!node.
|
|
24
|
+
if (!node.isInline || !node.marks.some(({ type }) => type.name === "hyperlink") || node.marks.some(({ type }) => type.name === "deletion")) return true;
|
|
12
25
|
const start = Math.max(position, from);
|
|
13
26
|
const end = Math.min(position + node.nodeSize, to);
|
|
14
27
|
if (start >= end) return true;
|
|
28
|
+
if (!node.isText && (start !== position || end !== position + node.nodeSize)) throw partialInlineRefusal();
|
|
15
29
|
const piece = {
|
|
16
30
|
from: start,
|
|
17
31
|
to: end,
|
|
18
|
-
node: node.cut(start - position, end - position)
|
|
32
|
+
node: node.isText ? node.cut(start - position, end - position) : node
|
|
19
33
|
};
|
|
20
34
|
const last = ranges.at(-1);
|
|
21
35
|
if (last && last.to === start) {
|
|
@@ -26,7 +40,7 @@ const linkedRanges = (doc, from, to) => {
|
|
|
26
40
|
to: end,
|
|
27
41
|
pieces: [piece]
|
|
28
42
|
});
|
|
29
|
-
return
|
|
43
|
+
return false;
|
|
30
44
|
});
|
|
31
45
|
return ranges;
|
|
32
46
|
};
|
|
@@ -60,8 +74,8 @@ const withoutHyperlinkStyle = (state, doc, piece) => {
|
|
|
60
74
|
previousFormatting
|
|
61
75
|
};
|
|
62
76
|
};
|
|
63
|
-
/** Replace the marks of the
|
|
64
|
-
const
|
|
77
|
+
/** Replace the marks of the inline content at [`from`, `to`) of `tr.doc` with `marks`. */
|
|
78
|
+
const setInlineMarks = (tr, from, to, current, marks) => {
|
|
65
79
|
for (const mark of current) if (!mark.isInSet(marks)) tr.removeMark(from, to, mark);
|
|
66
80
|
for (const mark of marks) if (!mark.isInSet(current)) tr.addMark(from, to, mark);
|
|
67
81
|
};
|
|
@@ -70,6 +84,11 @@ const setTextMarks = (tr, from, to, current, marks) => {
|
|
|
70
84
|
* suggestions on, as a tracked replacement of the linked text by plain text.
|
|
71
85
|
*/
|
|
72
86
|
const removeHyperlinkInRange = (state, tr, from, to) => {
|
|
87
|
+
assertHyperlinkRemovalRange({
|
|
88
|
+
doc: tr.doc,
|
|
89
|
+
from,
|
|
90
|
+
to
|
|
91
|
+
});
|
|
73
92
|
const { schema } = state;
|
|
74
93
|
const hyperlinkType = schema.marks["hyperlink"];
|
|
75
94
|
if (!hyperlinkType) return tr;
|
|
@@ -108,7 +127,7 @@ const removeHyperlinkInRange = (state, tr, from, to) => {
|
|
|
108
127
|
...withoutHyperlinkStyle(state, tr.doc, piece)
|
|
109
128
|
}));
|
|
110
129
|
if (!insertion || !deletionType) {
|
|
111
|
-
for (const { piece, marks } of unlinked)
|
|
130
|
+
for (const { piece, marks } of unlinked) setInlineMarks(tr, piece.from, piece.to, piece.node.marks, marks.filter(({ type }) => type !== hyperlinkType));
|
|
112
131
|
continue;
|
|
113
132
|
}
|
|
114
133
|
const plain = unlinked.map(({ piece, marks, previousFormatting }) => {
|
|
@@ -119,11 +138,11 @@ const removeHyperlinkInRange = (state, tr, from, to) => {
|
|
|
119
138
|
tr.insert(range.to, plain);
|
|
120
139
|
for (const { piece, marks, previousFormatting } of unlinked.toReversed()) {
|
|
121
140
|
const change = previousFormatting && !hasPendingPropertyChange(piece.node.marks) ? propertyChange(previousFormatting) : null;
|
|
122
|
-
|
|
141
|
+
setInlineMarks(tr, piece.from, piece.to, piece.node.marks, change ? change.addToSet(marks) : marks);
|
|
123
142
|
}
|
|
124
143
|
suggestRangeDeletion(state, tr, range.from, range.to);
|
|
125
144
|
}
|
|
126
145
|
return tr;
|
|
127
146
|
};
|
|
128
147
|
//#endregion
|
|
129
|
-
export { removeHyperlinkInRange };
|
|
148
|
+
export { HyperlinkRemovalRefusal, assertHyperlinkRemovalRange, removeHyperlinkInRange };
|
|
@@ -2,6 +2,7 @@ import { insertImageFromFile } from "./commands/image.js";
|
|
|
2
2
|
import { insertPageBreak } from "./commands/pageBreak.js";
|
|
3
3
|
import { generateTableOfContents } from "./commands/paragraph.js";
|
|
4
4
|
import { insertTable } from "./commands/table.js";
|
|
5
|
+
import { executeEditorCommand } from "./executeEditorCommand.js";
|
|
5
6
|
//#region src/prosemirror/insertOperations.ts
|
|
6
7
|
/** Insert a `rows × columns` table at the current selection. */
|
|
7
8
|
function insertTableInView(view, rows, columns) {
|
|
@@ -18,7 +19,7 @@ function insertPageBreakInView(view) {
|
|
|
18
19
|
* {@link GenerateTableOfContentsOptions}.
|
|
19
20
|
*/
|
|
20
21
|
function insertTableOfContentsInView(view, options) {
|
|
21
|
-
return
|
|
22
|
+
return executeEditorCommand(view, generateTableOfContents(options));
|
|
22
23
|
}
|
|
23
24
|
//#endregion
|
|
24
25
|
export { insertImageFromFile, insertPageBreakInView, insertTableInView, insertTableOfContentsInView };
|
|
@@ -10,7 +10,7 @@ import { directParagraphIndentation } from "./paragraphIndentation.js";
|
|
|
10
10
|
import { getDocumentNumbering } from "./plugins/documentNumbering.js";
|
|
11
11
|
import { getDocumentStyleResolver } from "./plugins/documentStyleState.js";
|
|
12
12
|
import { SUGGESTION_META, makeRevisionInfo } from "./plugins/suggestionMode.js";
|
|
13
|
-
import { listAttrsFromNumbering,
|
|
13
|
+
import { listAttrsFromNumbering, listIndentationProvenancePatch } from "./styles/resolvedStyleAttrs.js";
|
|
14
14
|
//#region src/prosemirror/listNumbering.ts
|
|
15
15
|
/**
|
|
16
16
|
* Which numbering instance a list command puts a paragraph in, and the
|
|
@@ -199,10 +199,16 @@ const listItemAttrs = (attrs, { numId, ilvl }, numbering) => ({
|
|
|
199
199
|
numId,
|
|
200
200
|
ilvl
|
|
201
201
|
}, numbering),
|
|
202
|
-
...
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
202
|
+
...listIndentationProvenancePatch({
|
|
203
|
+
direct: directParagraphIndentation(attrs),
|
|
204
|
+
styleFormatting: attrs._styleResolvedFormatting,
|
|
205
|
+
numberingSource: "paragraph",
|
|
206
|
+
numPr: {
|
|
207
|
+
numId,
|
|
208
|
+
ilvl
|
|
209
|
+
},
|
|
210
|
+
numbering
|
|
211
|
+
}),
|
|
206
212
|
listImplicitChildLevelAdvances: attrs["listImplicitChildLevelAdvances"] ?? null,
|
|
207
213
|
listFoldedMarkerSuffix: attrs["listFoldedMarkerSuffix"] ?? void 0,
|
|
208
214
|
listMarkerSecondSlotOffsetTwips: attrs["listMarkerSecondSlotOffsetTwips"] ?? null
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
//#region src/prosemirror/noteReferenceOccurrenceId.ts
|
|
2
|
+
/** Occurrence identities are opaque, nonblank attribution tokens. */
|
|
3
|
+
const isNoteReferenceOccurrenceId = (value) => typeof value === "string" && value.trim().length > 0;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { isNoteReferenceOccurrenceId };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Node } from "prosemirror-model";
|
|
2
|
+
import { Plugin, Transaction } from "prosemirror-state";
|
|
3
|
+
//#region src/prosemirror/noteReferenceOccurrences.d.ts
|
|
4
|
+
declare const NoteReferenceEditRefusal_base: import("better-result").TaggedErrorClass<"NoteReferenceEditRefusal">;
|
|
5
|
+
declare class NoteReferenceEditRefusal extends NoteReferenceEditRefusal_base<{
|
|
6
|
+
message: string;
|
|
7
|
+
}> {}
|
|
8
|
+
declare const NoteReferenceReplayDefect_base: import("better-result").TaggedErrorClass<"NoteReferenceReplayDefect">;
|
|
9
|
+
declare class NoteReferenceReplayDefect extends NoteReferenceReplayDefect_base<{
|
|
10
|
+
message: string;
|
|
11
|
+
}> {}
|
|
12
|
+
declare const markNoteReferenceReplay: (transaction: Transaction) => void;
|
|
13
|
+
declare const noteReferenceTransactionIssue: (transaction: Transaction) => NoteReferenceEditRefusal | NoteReferenceReplayDefect | undefined;
|
|
14
|
+
declare const mintNoteReferenceOccurrenceId: () => string;
|
|
15
|
+
/** Saving asserts the edit-owner invariant and emits each occurrence once. */
|
|
16
|
+
declare const coalesceNoteReferenceOccurrences: (paragraph: Node) => Node;
|
|
17
|
+
declare const assertNoteReferenceOccurrences: (doc: Node) => void;
|
|
18
|
+
/** Production edit boundary: refuse before committing an unsaveable occurrence. */
|
|
19
|
+
declare const noteReferenceOccurrencePlugin: () => Plugin<any>;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { NoteReferenceEditRefusal, NoteReferenceReplayDefect, assertNoteReferenceOccurrences, coalesceNoteReferenceOccurrences, markNoteReferenceReplay, mintNoteReferenceOccurrenceId, noteReferenceOccurrencePlugin, noteReferenceTransactionIssue };
|