@stll/folio-core 0.56.0 → 0.58.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 +122 -22
- package/dist/ai-edits/batch-claims.d.ts +3 -1
- package/dist/ai-edits/batch-claims.js +25 -1
- package/dist/ai-edits/table-row-column-mutations.js +17 -3
- package/dist/ai-suggestions/apply.js +20 -1
- package/dist/compare/inline-atoms.js +40 -16
- package/dist/compare/inline-provenance.js +12 -5
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/controller/canonicalClipboard.d.ts +3 -1
- package/dist/controller/canonicalClipboard.js +31 -13
- package/dist/controller/canonicalComments.d.ts +41 -0
- package/dist/controller/canonicalComments.js +152 -0
- package/dist/controller/canonicalComposition.d.ts +17 -4
- package/dist/controller/canonicalComposition.js +125 -20
- package/dist/controller/canonicalInlineProjection.d.ts +6 -1
- package/dist/controller/canonicalInlineProjection.js +86 -3
- package/dist/controller/canonicalInput.d.ts +1 -1
- package/dist/controller/canonicalInput.js +14 -4
- package/dist/controller/canonicalInputTimer.d.ts +10 -1
- package/dist/controller/canonicalInputTimer.js +24 -1
- package/dist/controller/canonicalPublicOperations.d.ts +2 -2
- package/dist/controller/canonicalPublicOperations.js +107 -15
- package/dist/controller/canonicalSelection.d.ts +18 -0
- package/dist/controller/canonicalSelection.js +41 -0
- package/dist/controller/canonicalSession.d.ts +4 -1
- package/dist/controller/canonicalSession.js +106 -36
- package/dist/controller/canonicalStoryEditor.d.ts +3 -1
- package/dist/controller/canonicalStoryEditor.js +21 -1
- package/dist/controller/canonicalStructure.js +8 -3
- package/dist/controller/folioEditor.js +13 -0
- package/dist/controller/headerFooterEditorManager.d.ts +1 -1
- package/dist/controller/headerFooterEditorManager.js +25 -11
- package/dist/controller/hiddenEditorApi.d.ts +13 -2
- package/dist/controller/hiddenEditorApi.js +5 -1
- package/dist/controller/hiddenEditorManager.d.ts +3 -1
- package/dist/controller/hiddenEditorManager.js +167 -14
- package/dist/controller/noteEditorManager.d.ts +1 -1
- package/dist/controller/noteEditorManager.js +28 -13
- package/dist/docx/builtInStyles.js +13 -6
- package/dist/docx/containerChildren.gen.d.ts +3 -1
- package/dist/docx/containerChildren.gen.js +33 -1
- package/dist/docx/fieldParser.js +14 -2
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/hyperlinkParser.js +20 -1
- 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/listRendering.d.ts +18 -0
- package/dist/{prosemirror/conversion/listRenderingDefinition.js → docx/listRendering.js} +17 -3
- package/dist/docx/paragraphParser.js +88 -67
- package/dist/docx/paragraphPropertySource.d.ts +22 -1
- package/dist/docx/paragraphPropertySource.js +107 -1
- package/dist/docx/preservedRunContent.js +2 -1
- package/dist/docx/relsParser.js +26 -2
- package/dist/docx/rezip.js +9 -6
- package/dist/docx/selectiveSave.js +10 -8
- package/dist/docx/serializer/commentSerializer.d.ts +4 -1
- package/dist/docx/serializer/commentSerializer.js +7 -3
- package/dist/docx/serializer/paragraphSerializer.js +207 -94
- package/dist/docx/server/materializeYjsDocx.js +15 -7
- package/dist/docx/server/migrateYjsAttrSchema.js +17 -5
- 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/revisionResolutionInline.js +25 -3
- package/dist/markdown/internals.js +7 -0
- package/dist/markdown/renderParagraph.js +11 -12
- package/dist/markdown/renderRuns.js +3 -13
- package/dist/markdown/types.d.ts +3 -0
- 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 +9 -0
- package/dist/prosemirror/commands/comments.js +60 -35
- 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.d.ts +8 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +150 -30
- package/dist/prosemirror/conversion/toProseDoc.js +128 -40
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +22 -5
- 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 +22 -14
- package/dist/prosemirror/extensions/marks/markUtils.js +8 -7
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +5 -2
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +8 -1
- 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/imagePictureNames.d.ts +12 -0
- package/dist/prosemirror/imagePictureNames.js +20 -0
- 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/paragraphFormattingProvenance.js +1 -0
- package/dist/prosemirror/plugins/documentStyles.d.ts +4 -1
- package/dist/prosemirror/plugins/documentStyles.js +17 -10
- package/dist/prosemirror/plugins/suggestionMode.js +47 -49
- 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 +74 -2
- package/dist/prosemirror/runStyleFormatting.js +20 -1
- package/dist/prosemirror/schema/marks.d.ts +1 -0
- package/dist/prosemirror/schema/nodes.d.ts +3 -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/styles/styleResolver.d.ts +4 -1
- package/dist/prosemirror/styles/styleResolver.js +32 -11
- 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 +18 -18
- package/dist/types/canonicalCapabilities.js +18 -18
- package/dist/types/canonicalComments.d.ts +51 -0
- package/dist/types/canonicalComments.js +0 -0
- package/dist/types/canonicalSections.d.ts +12 -0
- package/dist/types/canonicalSections.js +0 -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 +2 -2
- package/dist/prosemirror/conversion/listRenderingDefinition.d.ts +0 -6
|
@@ -3,7 +3,7 @@ import { anchorTargetAttrs, normalizeUserUrl, sanitizeExternalUrl } from "../../
|
|
|
3
3
|
import { expectHyperlinkMarkAttrs } from "../../attrs/index.js";
|
|
4
4
|
import { withCanonicalCommand } from "../../canonicalCommands.js";
|
|
5
5
|
import { canonicalSelectionRange } from "../../canonicalSelectionRange.js";
|
|
6
|
-
import { removeHyperlinkInRange } from "../../hyperlinkRemoval.js";
|
|
6
|
+
import { assertHyperlinkRemovalRange, removeHyperlinkInRange } from "../../hyperlinkRemoval.js";
|
|
7
7
|
import { getDocumentBuiltInStyles } from "../../plugins/documentStyleState.js";
|
|
8
8
|
import { createMarkExtension } from "../create.js";
|
|
9
9
|
import { isMarkActive } from "./markUtils.js";
|
|
@@ -149,26 +149,34 @@ const HyperlinkExtension = createMarkExtension({
|
|
|
149
149
|
const removalRange = (state) => {
|
|
150
150
|
const { empty, $from } = state.selection;
|
|
151
151
|
const { from, to } = canonicalSelectionRange(state);
|
|
152
|
+
assertHyperlinkRemovalRange({
|
|
153
|
+
doc: state.doc,
|
|
154
|
+
from,
|
|
155
|
+
to
|
|
156
|
+
});
|
|
152
157
|
if (!empty) return {
|
|
153
158
|
from,
|
|
154
159
|
to
|
|
155
160
|
};
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
158
|
-
let
|
|
159
|
-
let
|
|
161
|
+
const linkMark = $from.marks().find((mark) => mark.type === documentHyperlinkType(state));
|
|
162
|
+
if (!linkMark) return void 0;
|
|
163
|
+
let contiguous;
|
|
164
|
+
let selected;
|
|
160
165
|
$from.parent.forEach((node, offset) => {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
start = Math.min(start, nodeStart);
|
|
165
|
-
end = Math.max(end, nodeEnd);
|
|
166
|
+
if (!node.isInline || !node.marks.some((mark) => mark.eq(linkMark))) {
|
|
167
|
+
contiguous = void 0;
|
|
168
|
+
return;
|
|
166
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;
|
|
167
178
|
});
|
|
168
|
-
return
|
|
169
|
-
from: start,
|
|
170
|
-
to: end
|
|
171
|
-
};
|
|
179
|
+
return selected;
|
|
172
180
|
};
|
|
173
181
|
const removeHyperlink = withCanonicalCommand((state, dispatch) => {
|
|
174
182
|
const range = removalRange(state);
|
|
@@ -1,7 +1,7 @@
|
|
|
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
6
|
import { canonicalSelectionRange } from "../../canonicalSelectionRange.js";
|
|
7
7
|
import { runShadingAttrsToShading, shadingToRunShadingAttrs } from "../../conversion/runShadingMark.js";
|
|
@@ -147,14 +147,15 @@ function saveStoredMarksToParagraph(state, tr, marks) {
|
|
|
147
147
|
const paragraph = $from.parent;
|
|
148
148
|
if (paragraph.type.name !== "paragraph") return tr;
|
|
149
149
|
if (paragraph.textContent.length > 0) return tr;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
defaultTextFormatting: null
|
|
153
|
-
});
|
|
154
|
-
const defaultTextFormatting = marksToTextFormatting(marks);
|
|
150
|
+
const attrs = expectParagraphAttrs(paragraph);
|
|
151
|
+
const defaultTextFormatting = marks.length === 0 ? null : marksToTextFormatting(marks);
|
|
155
152
|
return tr.setNodeMarkup($from.before(), void 0, {
|
|
156
153
|
...paragraph.attrs,
|
|
157
|
-
defaultTextFormatting
|
|
154
|
+
defaultTextFormatting,
|
|
155
|
+
_originalFormatting: {
|
|
156
|
+
...attrs._originalFormatting,
|
|
157
|
+
runProperties: defaultTextFormatting ?? void 0
|
|
158
|
+
}
|
|
158
159
|
});
|
|
159
160
|
}
|
|
160
161
|
function dispatchStoredMarks(state, dispatch, marks) {
|
|
@@ -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);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { imageLuminanceFilter } from "../../../utils/imageLuminance.js";
|
|
2
2
|
import { expectImageAttrs } from "../../attrs/index.js";
|
|
3
|
+
import { pictureNamesDomAttrs, pictureNamesFromDom } from "../../imagePictureNames.js";
|
|
3
4
|
import { createNodeExtension } from "../create.js";
|
|
4
5
|
//#region src/prosemirror/extensions/nodes/ImageExtension.ts
|
|
5
6
|
/**
|
|
@@ -17,6 +18,7 @@ const ImageExtension = createNodeExtension({
|
|
|
17
18
|
src: {},
|
|
18
19
|
preview: { default: null },
|
|
19
20
|
docPrName: { default: null },
|
|
21
|
+
pictureNames: { default: null },
|
|
20
22
|
alt: { default: null },
|
|
21
23
|
title: { default: null },
|
|
22
24
|
width: { default: null },
|
|
@@ -73,6 +75,7 @@ const ImageExtension = createNodeExtension({
|
|
|
73
75
|
tag: "img[src]",
|
|
74
76
|
getAttrs(dom) {
|
|
75
77
|
const element = dom;
|
|
78
|
+
const pictureNames = pictureNamesFromDom(element);
|
|
76
79
|
const alt = element.getAttribute("alt");
|
|
77
80
|
const title = element.getAttribute("title");
|
|
78
81
|
const cssFloat = element.dataset["cssFloat"];
|
|
@@ -85,6 +88,8 @@ const ImageExtension = createNodeExtension({
|
|
|
85
88
|
const contrast = contrastRaw === void 0 ? NaN : Number(contrastRaw);
|
|
86
89
|
return {
|
|
87
90
|
src: element.getAttribute("src") || "",
|
|
91
|
+
...element.dataset["docPrName"] === void 0 ? {} : { docPrName: element.dataset["docPrName"] },
|
|
92
|
+
...Object.keys(pictureNames).length > 0 ? { pictureNames } : {},
|
|
88
93
|
...alt ? { alt } : {},
|
|
89
94
|
...title ? { title } : {},
|
|
90
95
|
...element.width ? { width: element.width } : {},
|
|
@@ -107,8 +112,10 @@ const ImageExtension = createNodeExtension({
|
|
|
107
112
|
const attrs = expectImageAttrs(node);
|
|
108
113
|
const domAttrs = {
|
|
109
114
|
src: attrs.src,
|
|
110
|
-
class: "docx-image"
|
|
115
|
+
class: "docx-image",
|
|
116
|
+
...pictureNamesDomAttrs(attrs.pictureNames)
|
|
111
117
|
};
|
|
118
|
+
if (attrs.docPrName != null) domAttrs["data-doc-pr-name"] = attrs.docPrName;
|
|
112
119
|
if (attrs.alt) domAttrs["alt"] = attrs.alt;
|
|
113
120
|
if (attrs.title) domAttrs["title"] = attrs.title;
|
|
114
121
|
if (attrs.rId) domAttrs["data-rid"] = attrs.rId;
|
|
@@ -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 };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
//#region src/prosemirror/imagePictureNames.d.ts
|
|
3
|
+
declare const PICTURE_NAME_DOM_ATTRIBUTES: {
|
|
4
|
+
readonly name: "data-picture-name";
|
|
5
|
+
readonly alt: "data-picture-alt";
|
|
6
|
+
readonly title: "data-picture-title";
|
|
7
|
+
};
|
|
8
|
+
/** Keep picture metadata separate from the containing drawing's accessibility strings. */
|
|
9
|
+
declare const pictureNamesFromDom: (element: HTMLElement) => document_d_exports.NonVisualDrawingNames;
|
|
10
|
+
declare const pictureNamesDomAttrs: (names: document_d_exports.NonVisualDrawingNames | undefined) => Record<string, string>;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { PICTURE_NAME_DOM_ATTRIBUTES, pictureNamesDomAttrs, pictureNamesFromDom };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/prosemirror/imagePictureNames.ts
|
|
2
|
+
const PICTURE_NAME_DOM_ATTRIBUTES = {
|
|
3
|
+
name: "data-picture-name",
|
|
4
|
+
alt: "data-picture-alt",
|
|
5
|
+
title: "data-picture-title"
|
|
6
|
+
};
|
|
7
|
+
/** Keep picture metadata separate from the containing drawing's accessibility strings. */
|
|
8
|
+
const pictureNamesFromDom = (element) => Object.fromEntries(Object.entries(PICTURE_NAME_DOM_ATTRIBUTES).flatMap(([key, attribute]) => {
|
|
9
|
+
const value = element.getAttribute(attribute);
|
|
10
|
+
return value === null ? [] : [[key, value]];
|
|
11
|
+
}));
|
|
12
|
+
const pictureNamesDomAttrs = (names) => {
|
|
13
|
+
const values = new Map(Object.entries(names ?? {}));
|
|
14
|
+
return Object.fromEntries(Object.entries(PICTURE_NAME_DOM_ATTRIBUTES).flatMap(([key, attribute]) => {
|
|
15
|
+
const value = values.get(key);
|
|
16
|
+
return value === void 0 ? [] : [[attribute, value]];
|
|
17
|
+
}));
|
|
18
|
+
};
|
|
19
|
+
//#endregion
|
|
20
|
+
export { PICTURE_NAME_DOM_ATTRIBUTES, pictureNamesDomAttrs, pictureNamesFromDom };
|
|
@@ -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 };
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { readFootnoteRefMarkAttrs } from "./attrs/index.js";
|
|
2
|
+
import { Result, TaggedError, panic } from "better-result";
|
|
3
|
+
import { Fragment, Mark, Slice } from "prosemirror-model";
|
|
4
|
+
import { Plugin } from "prosemirror-state";
|
|
5
|
+
import { isHistoryTransaction } from "prosemirror-history";
|
|
6
|
+
//#region src/prosemirror/noteReferenceOccurrences.ts
|
|
7
|
+
var NoteReferenceEditRefusal = class extends TaggedError("NoteReferenceEditRefusal") {};
|
|
8
|
+
var NoteReferenceReplayDefect = class extends TaggedError("NoteReferenceReplayDefect") {};
|
|
9
|
+
const NOTE_OCCURRENCE_REPLAY_META = "noteReferenceOccurrenceReplay";
|
|
10
|
+
const markNoteReferenceReplay = (transaction) => {
|
|
11
|
+
transaction.setMeta(NOTE_OCCURRENCE_REPLAY_META, true);
|
|
12
|
+
};
|
|
13
|
+
const NOTE_OCCURRENCE_REPORT_META = "noteReferenceOccurrenceReport";
|
|
14
|
+
const noteReferenceTransactionIssue = (transaction) => {
|
|
15
|
+
const issue = transaction.getMeta(NOTE_OCCURRENCE_REPORT_META);
|
|
16
|
+
return issue instanceof NoteReferenceEditRefusal || issue instanceof NoteReferenceReplayDefect ? issue : void 0;
|
|
17
|
+
};
|
|
18
|
+
const mintNoteReferenceOccurrenceId = () => crypto.randomUUID();
|
|
19
|
+
/** Identity establishes boundaries; text only validates the already bounded unit. */
|
|
20
|
+
const readOccurrences = (paragraph) => {
|
|
21
|
+
const referenceType = paragraph.type.schema.marks["footnoteRef"];
|
|
22
|
+
if (!referenceType || !paragraph.rangeHasMark(0, paragraph.content.size, referenceType)) return Result.ok([]);
|
|
23
|
+
const occurrences = [];
|
|
24
|
+
const seen = /* @__PURE__ */ new Set();
|
|
25
|
+
let previous;
|
|
26
|
+
let issue;
|
|
27
|
+
paragraph.forEach((node, from) => {
|
|
28
|
+
if (issue !== void 0) return;
|
|
29
|
+
const reference = node.marks.find((mark) => mark.type.name === "footnoteRef");
|
|
30
|
+
if (!reference) {
|
|
31
|
+
previous = void 0;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const attrs = readFootnoteRefMarkAttrs(reference);
|
|
35
|
+
if (!attrs.ok || !node.isText) {
|
|
36
|
+
issue = "Note references require attributed text occurrences.";
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const id = attrs.value.occurrenceId;
|
|
40
|
+
if (previous?.id === id) {
|
|
41
|
+
if (!Mark.sameSet(previous.node.marks, node.marks)) {
|
|
42
|
+
issue = "A note reference cannot have different formatting or revision owners within one occurrence.";
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
previous.text += node.text ?? "";
|
|
46
|
+
previous.to = from + node.nodeSize;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (seen.has(id)) {
|
|
50
|
+
issue = "A note-reference occurrence must remain contiguous.";
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
seen.add(id);
|
|
54
|
+
previous = {
|
|
55
|
+
id,
|
|
56
|
+
node,
|
|
57
|
+
text: node.text ?? "",
|
|
58
|
+
from,
|
|
59
|
+
to: from + node.nodeSize
|
|
60
|
+
};
|
|
61
|
+
occurrences.push(previous);
|
|
62
|
+
});
|
|
63
|
+
for (const occurrence of occurrences) {
|
|
64
|
+
const reference = occurrence.node.marks.find((mark) => mark.type.name === "footnoteRef");
|
|
65
|
+
if (!reference) return panic("Missing note-reference mark in an occurrence.");
|
|
66
|
+
const attrs = readFootnoteRefMarkAttrs(reference);
|
|
67
|
+
if (!attrs.ok) return panic("Invalid attributed note-reference occurrence.");
|
|
68
|
+
if (occurrence.text !== String(attrs.value.id)) issue ??= "Edit the whole note reference; its rendered label is indivisible.";
|
|
69
|
+
}
|
|
70
|
+
return issue === void 0 ? Result.ok(occurrences) : Result.err(new NoteReferenceEditRefusal({ message: issue }));
|
|
71
|
+
};
|
|
72
|
+
/** Saving asserts the edit-owner invariant and emits each occurrence once. */
|
|
73
|
+
const coalesceNoteReferenceOccurrences = (paragraph) => {
|
|
74
|
+
if (saveOccurrenceValidator?.cachedIds(paragraph)?.length === 0) return paragraph;
|
|
75
|
+
const referenceType = paragraph.type.schema.marks["footnoteRef"];
|
|
76
|
+
if (!referenceType || !paragraph.rangeHasMark(0, paragraph.content.size, referenceType)) return paragraph;
|
|
77
|
+
const result = readOccurrences(paragraph);
|
|
78
|
+
if (result.isErr()) return panic(result.error.message);
|
|
79
|
+
if (result.value.every(({ node, from, to }) => node.nodeSize === to - from)) return paragraph;
|
|
80
|
+
const byStart = new Map(result.value.map((occurrence) => [occurrence.from, occurrence]));
|
|
81
|
+
const nodes = [];
|
|
82
|
+
let through = -1;
|
|
83
|
+
paragraph.forEach((node, from) => {
|
|
84
|
+
if (from < through) return;
|
|
85
|
+
const occurrence = byStart.get(from);
|
|
86
|
+
if (occurrence) {
|
|
87
|
+
nodes.push(node.type.schema.text(occurrence.text, node.marks));
|
|
88
|
+
through = occurrence.to;
|
|
89
|
+
} else nodes.push(node);
|
|
90
|
+
});
|
|
91
|
+
return paragraph.copy(Fragment.fromArray(nodes));
|
|
92
|
+
};
|
|
93
|
+
const createOccurrenceValidator = () => {
|
|
94
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
95
|
+
const validate = (node) => {
|
|
96
|
+
const cached = cache.get(node);
|
|
97
|
+
if (cached) return cached;
|
|
98
|
+
const ids = /* @__PURE__ */ new Set();
|
|
99
|
+
const include = (id) => {
|
|
100
|
+
if (ids.has(id)) return new NoteReferenceEditRefusal({ message: "Separate note references require distinct occurrence identities." });
|
|
101
|
+
ids.add(id);
|
|
102
|
+
};
|
|
103
|
+
if (node.inlineContent) {
|
|
104
|
+
const own = readOccurrences(node);
|
|
105
|
+
if (own.isErr()) return Result.err(own.error);
|
|
106
|
+
for (const occurrence of own.value) {
|
|
107
|
+
const issue = include(occurrence.id);
|
|
108
|
+
if (issue) return Result.err(issue);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (let index = 0; index < node.childCount; index += 1) {
|
|
112
|
+
const child = node.child(index);
|
|
113
|
+
if (child.isLeaf) continue;
|
|
114
|
+
const nested = validate(child);
|
|
115
|
+
if (nested.isErr()) return nested;
|
|
116
|
+
for (const id of nested.value) {
|
|
117
|
+
const issue = include(id);
|
|
118
|
+
if (issue) return Result.err(issue);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const result = Result.ok([...ids]);
|
|
122
|
+
cache.set(node, result);
|
|
123
|
+
return result;
|
|
124
|
+
};
|
|
125
|
+
return {
|
|
126
|
+
validate,
|
|
127
|
+
cachedIds: (node) => {
|
|
128
|
+
const facts = cache.get(node);
|
|
129
|
+
return facts?.isOk() ? facts.value : void 0;
|
|
130
|
+
},
|
|
131
|
+
validateSave: (doc) => {
|
|
132
|
+
const facts = cache.get(doc);
|
|
133
|
+
if (facts?.isOk() && facts.value.length === 0) return facts;
|
|
134
|
+
cache.delete(doc);
|
|
135
|
+
return validate(doc);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
let saveOccurrenceValidator;
|
|
140
|
+
const assertNoteReferenceOccurrences = (doc) => {
|
|
141
|
+
const result = (saveOccurrenceValidator ??= createOccurrenceValidator()).validateSave(doc);
|
|
142
|
+
if (result.isErr()) panic(result.error.message);
|
|
143
|
+
};
|
|
144
|
+
/** Production edit boundary: refuse before committing an unsaveable occurrence. */
|
|
145
|
+
const noteReferenceOccurrencePlugin = () => {
|
|
146
|
+
const { validate } = createOccurrenceValidator();
|
|
147
|
+
return new Plugin({
|
|
148
|
+
filterTransaction(transaction) {
|
|
149
|
+
if (!transaction.docChanged) return true;
|
|
150
|
+
const result = validate(transaction.doc);
|
|
151
|
+
if (result.isOk()) return true;
|
|
152
|
+
const replay = isHistoryTransaction(transaction) || transaction.getMeta(NOTE_OCCURRENCE_REPLAY_META) === true;
|
|
153
|
+
transaction.setMeta(NOTE_OCCURRENCE_REPORT_META, replay ? new NoteReferenceReplayDefect({ message: result.error.message }) : result.error);
|
|
154
|
+
return replay;
|
|
155
|
+
},
|
|
156
|
+
props: { transformPasted(slice) {
|
|
157
|
+
const identities = /* @__PURE__ */ new Map();
|
|
158
|
+
const remint = (fragment) => {
|
|
159
|
+
const nodes = [];
|
|
160
|
+
fragment.forEach((node) => {
|
|
161
|
+
const marks = node.marks.map((mark) => {
|
|
162
|
+
if (mark.type.name !== "footnoteRef") return mark;
|
|
163
|
+
const attrs = readFootnoteRefMarkAttrs(mark);
|
|
164
|
+
if (!attrs.ok) return mark;
|
|
165
|
+
const id = attrs.value.occurrenceId;
|
|
166
|
+
let replacement = identities.get(id);
|
|
167
|
+
if (replacement === void 0) {
|
|
168
|
+
replacement = mintNoteReferenceOccurrenceId();
|
|
169
|
+
identities.set(id, replacement);
|
|
170
|
+
}
|
|
171
|
+
return mark.type.create({
|
|
172
|
+
...mark.attrs,
|
|
173
|
+
occurrenceId: replacement
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
nodes.push(node.copy(remint(node.content)).mark(marks));
|
|
177
|
+
});
|
|
178
|
+
return Fragment.fromArray(nodes);
|
|
179
|
+
};
|
|
180
|
+
return new Slice(remint(slice.content), slice.openStart, slice.openEnd);
|
|
181
|
+
} }
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
//#endregion
|
|
185
|
+
export { NoteReferenceEditRefusal, NoteReferenceReplayDefect, assertNoteReferenceOccurrences, coalesceNoteReferenceOccurrences, markNoteReferenceReplay, mintNoteReferenceOccurrenceId, noteReferenceOccurrencePlugin, noteReferenceTransactionIssue };
|
|
@@ -2,6 +2,7 @@ import { withoutLostCommentThreads } from "../ai-edits/comment-lifecycle.js";
|
|
|
2
2
|
import { visitCommentMarkers } from "../docx/commentAnchorIndex.js";
|
|
3
3
|
import { isSeparatorEndnote, isSeparatorFootnote } from "../docx/footnoteParser.js";
|
|
4
4
|
import { pluginsForHeadlessRevisionResolution } from "../internal/headlessRevisionResolutionGuard.js";
|
|
5
|
+
import { addTrackedDeletionMark } from "./addTrackedDeletionMark.js";
|
|
5
6
|
import { expectFootnoteRefMarkAttrs, expectParagraphAttrs } from "./attrs/index.js";
|
|
6
7
|
import { rejectAIEditRevision } from "./commands/comments.js";
|
|
7
8
|
import { proseDocToBlocks } from "./conversion/fromProseDoc.js";
|
|
@@ -13,6 +14,12 @@ import { schema, singletonManager } from "./schema/index.js";
|
|
|
13
14
|
import { Transform } from "prosemirror-transform";
|
|
14
15
|
import { EditorState } from "prosemirror-state";
|
|
15
16
|
//#region src/prosemirror/noteReferenceReview.ts
|
|
17
|
+
/**
|
|
18
|
+
* A note goes with its reference. Deleting a note's reference while tracking
|
|
19
|
+
* changes deletes the note's text too, so rejecting that deletion must give
|
|
20
|
+
* the note its text back, whichever surface resolves it: the body editor
|
|
21
|
+
* resolves the reference, and this resolves the note's story to match.
|
|
22
|
+
*/
|
|
16
23
|
const noteKey = (kind, id) => `${kind}:${id}`;
|
|
17
24
|
/**
|
|
18
25
|
* The notes a story's text refers to, and whether each reference is pending
|
|
@@ -155,7 +162,13 @@ const deleteNoteWithReference = (transform, reference) => {
|
|
|
155
162
|
kind: "del",
|
|
156
163
|
info: markInfo
|
|
157
164
|
});
|
|
158
|
-
if (node.isInline && !deletion.type.isInSet(node.marks))
|
|
165
|
+
if (node.isInline && !deletion.type.isInSet(node.marks)) addTrackedDeletionMark({
|
|
166
|
+
insertionPolicy: "preserve-pending",
|
|
167
|
+
tr: transform,
|
|
168
|
+
from: position,
|
|
169
|
+
to: position + node.nodeSize,
|
|
170
|
+
mark: deletion
|
|
171
|
+
});
|
|
159
172
|
return !node.isInline;
|
|
160
173
|
});
|
|
161
174
|
return transform;
|
|
@@ -113,6 +113,7 @@ const styleResolvedParagraphFormatting = (resolved) => {
|
|
|
113
113
|
Reflect.set(governed, field, value);
|
|
114
114
|
found = true;
|
|
115
115
|
}
|
|
116
|
+
if (resolved.indentFirstLine !== void 0 && resolved.hangingIndent !== void 0) governed.hangingIndent = resolved.hangingIndent;
|
|
116
117
|
return found ? governed : void 0;
|
|
117
118
|
};
|
|
118
119
|
//#endregion
|
|
@@ -3,6 +3,9 @@ import { StyleResolver } from "../styles/styleResolver.js";
|
|
|
3
3
|
import { documentStylesKey, getDocumentBuiltInStyles, getDocumentStyleDefinitions, getDocumentStyleResolver } from "./documentStyleState.js";
|
|
4
4
|
import { EditorState, Plugin } from "prosemirror-state";
|
|
5
5
|
//#region src/prosemirror/plugins/documentStyles.d.ts
|
|
6
|
+
type DocumentStylesInput = document_d_exports.StyleDefinitions | StyleResolver | null | undefined;
|
|
7
|
+
/** Canonical projections own formatting; expose the resolver without PM repair transactions. */
|
|
8
|
+
declare const createDocumentStyleContextPlugin: (styles: DocumentStylesInput) => Plugin;
|
|
6
9
|
/**
|
|
7
10
|
* Create the plugin holding a StyleResolver for the document's `styles` for
|
|
8
11
|
* the lifetime of the EditorState. The resolver is fixed per document load;
|
|
@@ -14,4 +17,4 @@ declare function createDocumentStylesPlugin(styles: document_d_exports.StyleDefi
|
|
|
14
17
|
/** Reconfigure so ProseMirror replaces the keyed plugin's resolver state. */
|
|
15
18
|
declare const withDocumentStyles: (state: EditorState, styles: document_d_exports.StyleDefinitions | StyleResolver | null | undefined) => EditorState;
|
|
16
19
|
//#endregion
|
|
17
|
-
export { createDocumentStylesPlugin, documentStylesKey, getDocumentBuiltInStyles, getDocumentStyleDefinitions, getDocumentStyleResolver, withDocumentStyles };
|
|
20
|
+
export { createDocumentStyleContextPlugin, createDocumentStylesPlugin, documentStylesKey, getDocumentBuiltInStyles, getDocumentStyleDefinitions, getDocumentStyleResolver, withDocumentStyles };
|