@stll/folio-core 0.44.0 → 0.46.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/__fixtures__/paragraphs.js +2 -2
- package/dist/ai-edits/apply.js +59 -19
- package/dist/ai-edits/headless.js +2 -1
- package/dist/compare/compare.js +2 -5
- package/dist/compare/content-alignment.js +78 -53
- package/dist/compare/inline-atoms.js +34 -20
- package/dist/compare/scenario.js +2 -5
- package/dist/compare/types.d.ts +9 -1
- package/dist/compare/types.js +12 -1
- package/dist/compat/eigenpal.d.ts +2 -1
- package/dist/compat/eigenpal.js +2 -1
- package/dist/content-controls/checkboxDisplay.d.ts +11 -0
- package/dist/content-controls/checkboxDisplay.js +40 -0
- package/dist/content-controls/findContentControls.js +3 -1
- package/dist/content-controls/mutateContentControls.js +21 -4
- package/dist/controller/contentControlWidgetController.d.ts +1 -0
- package/dist/controller/contentControlWidgetController.js +3 -0
- package/dist/controller/hiddenEditorApi.js +3 -1
- package/dist/controller/hiddenEditorManager.d.ts +1 -1
- package/dist/controller/hiddenEditorManager.js +6 -3
- package/dist/display-list/build/buildDisplayList.js +20 -1
- package/dist/display-list/build/imagePrimitives.d.ts +1 -1
- package/dist/display-list/build/imagePrimitives.js +3 -1
- package/dist/display-list/build/paragraphPrimitives.js +21 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +18 -10
- package/dist/display-list/types.d.ts +17 -0
- package/dist/document-operations.js +14 -3
- package/dist/docx/attributeRemainder.d.ts +43 -0
- package/dist/docx/attributeRemainder.js +65 -0
- package/dist/docx/blockContentParser.d.ts +1 -1
- package/dist/docx/blockContentParser.js +87 -63
- package/dist/docx/blockPlainText.d.ts +3 -4
- package/dist/docx/blockPlainText.js +1 -0
- package/dist/docx/bookmarkPlacement.js +2 -0
- package/dist/docx/borderParser.js +5 -5
- package/dist/docx/commentAnchorIndex.d.ts +30 -0
- package/dist/docx/commentAnchorIndex.js +50 -0
- package/dist/docx/commentParser.d.ts +1 -1
- package/dist/docx/commentParser.js +78 -50
- package/dist/docx/commentRangeIntegrity.d.ts +16 -1
- package/dist/docx/commentRangeIntegrity.js +42 -1
- package/dist/docx/commentRangeJoin.d.ts +9 -0
- package/dist/docx/commentRangeJoin.js +33 -0
- package/dist/docx/commentReferenceCompletion.d.ts +9 -0
- package/dist/docx/commentReferenceCompletion.js +47 -0
- package/dist/docx/commentReferenceNormalization.js +1 -0
- package/dist/docx/commentReplyMarkers.js +11 -19
- package/dist/docx/commentThreadKey.d.ts +18 -0
- package/dist/docx/commentThreadKey.js +22 -0
- package/dist/docx/compatibility.js +1 -0
- package/dist/docx/containerChildren.d.ts +111 -0
- package/dist/docx/containerChildren.gen.d.ts +28 -0
- package/dist/docx/containerChildren.gen.js +246 -0
- package/dist/docx/containerChildren.js +103 -0
- package/dist/docx/diagramPreview.js +87 -27
- package/dist/docx/documentParser.d.ts +1 -1
- package/dist/docx/documentParser.js +3 -3
- package/dist/docx/ensureParaIds.js +17 -7
- package/dist/docx/fieldParser.d.ts +1 -1
- package/dist/docx/fieldParser.js +4 -4
- package/dist/docx/fieldState.d.ts +26 -0
- package/dist/docx/fieldState.js +53 -0
- package/dist/docx/footnoteParser.d.ts +1 -1
- package/dist/docx/graphicFrameLocks.d.ts +16 -4
- package/dist/docx/graphicFrameLocks.js +19 -6
- package/dist/docx/groupDrawingParser.js +3 -3
- package/dist/docx/headerFooterParser.js +1 -1
- package/dist/docx/headerFooterReferenceNormalization.js +1 -0
- package/dist/docx/hyperlinkParser.d.ts +27 -8
- package/dist/docx/hyperlinkParser.js +78 -20
- package/dist/docx/imageParser.d.ts +9 -1
- package/dist/docx/imageParser.js +91 -20
- package/dist/docx/imageRawXml.d.ts +14 -1
- package/dist/docx/imageRawXml.js +30 -6
- package/dist/docx/inlineWrapperContent.d.ts +85 -0
- package/dist/docx/inlineWrapperContent.js +84 -0
- package/dist/docx/mathToMathml.js +12 -14
- package/dist/docx/nonVisualDrawingProps.d.ts +34 -0
- package/dist/docx/nonVisualDrawingProps.js +46 -0
- package/dist/docx/normalizeBaseDirection.js +10 -1
- package/dist/docx/paraIdAttribute.d.ts +21 -0
- package/dist/docx/paraIdAttribute.js +64 -0
- package/dist/docx/paragraphParser.d.ts +1 -1
- package/dist/docx/paragraphParser.js +277 -168
- package/dist/docx/paragraphPropertySource.js +5 -1
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +1 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +9 -52
- package/dist/docx/paragraphTraversal.js +7 -4
- package/dist/docx/parseWarningMessage.js +2 -1
- package/dist/docx/parser.js +2 -2
- package/dist/docx/preservedRunContent.d.ts +32 -0
- package/dist/docx/preservedRunContent.js +86 -0
- package/dist/docx/previewBudget.d.ts +64 -0
- package/dist/docx/previewBudget.js +88 -0
- package/dist/docx/renderedPageBreakNormalization.js +2 -4
- package/dist/docx/revisionIdNormalization.js +17 -5
- package/dist/docx/rezip.js +91 -36
- package/dist/docx/runParser.d.ts +1 -1
- package/dist/docx/runParser.js +16 -12
- package/dist/docx/sdtPropertiesPatch.js +24 -18
- package/dist/docx/sectionParser.js +8 -1
- package/dist/docx/sectionReferenceHistory.js +2 -2
- package/dist/docx/selectiveSave.js +6 -6
- package/dist/docx/selectiveXmlPatch.d.ts +46 -2
- package/dist/docx/selectiveXmlPatch.js +86 -39
- package/dist/docx/serializer/blockSdtSerializer.js +38 -26
- package/dist/docx/serializer/borderSerializer.d.ts +1 -1
- package/dist/docx/serializer/borderSerializer.js +15 -14
- package/dist/docx/serializer/commentSerializer.d.ts +41 -16
- package/dist/docx/serializer/commentSerializer.js +87 -92
- package/dist/docx/serializer/documentSerializer.js +8 -11
- package/dist/docx/serializer/fontTableSerializer.js +6 -6
- package/dist/docx/serializer/headerFooterSerializer.js +12 -14
- package/dist/docx/serializer/markupRangeAttributes.js +2 -2
- package/dist/docx/serializer/noteSerializer.js +8 -8
- package/dist/docx/serializer/numberingSerializer.js +7 -6
- package/dist/docx/serializer/paragraphSerializer.js +93 -72
- package/dist/docx/serializer/partNamespaces.js +2 -2
- package/dist/docx/serializer/runSerializer.js +73 -44
- package/dist/docx/serializer/sectionPropertiesSerializer.js +19 -14
- package/dist/docx/serializer/settingsSerializer.js +4 -3
- package/dist/docx/serializer/stylesSerializer.js +6 -6
- package/dist/docx/serializer/tableSerializer.js +28 -17
- package/dist/docx/serializer/textFormattingSerializer.js +29 -28
- package/dist/docx/serializer/themeSerializer.js +6 -6
- package/dist/docx/serializer/trackedChangeAttributes.js +2 -2
- package/dist/docx/serializer/xmlUtils.d.ts +1 -2
- package/dist/docx/serializer/xmlUtils.js +1 -13
- package/dist/docx/server/boundedArchive.d.ts +12 -0
- package/dist/docx/server/boundedArchive.js +20 -1
- package/dist/docx/server/createBilingualDocument.js +3 -1
- package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
- package/dist/docx/server/materializeYjsDocx.js +9 -1
- package/dist/docx/server/migrateYjsAttrSchema.d.ts +55 -0
- package/dist/docx/server/migrateYjsAttrSchema.js +95 -0
- package/dist/docx/server/validateDocxConformance.js +22 -1
- package/dist/docx/shapeParser.js +12 -10
- package/dist/docx/tableParser.d.ts +1 -1
- package/dist/docx/tableParser.js +206 -85
- package/dist/docx/textBoxParser.d.ts +25 -2
- package/dist/docx/textBoxParser.js +59 -4
- package/dist/docx/unzip.d.ts +23 -0
- package/dist/docx/unzip.js +37 -26
- package/dist/docx/verbatimCapture.js +1 -1
- package/dist/docx/vmlImageParser.d.ts +17 -1
- package/dist/docx/vmlImageParser.js +20 -3
- package/dist/docx/vmlPreview.d.ts +1 -3
- package/dist/docx/vmlPreview.js +2 -30
- package/dist/docx/xmlEncoding.d.ts +5 -0
- package/dist/docx/xmlEncoding.js +12 -0
- package/dist/docx/xmlParser.d.ts +26 -2
- package/dist/docx/xmlParser.js +70 -27
- package/dist/docx/xmlResourceLimits.d.ts +89 -9
- package/dist/docx/xmlResourceLimits.js +105 -24
- package/dist/headless-layout.js +10 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +5 -2
- package/dist/internal/paragraphFormattingSerialization.js +3 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +102 -12
- package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
- package/dist/layout-engine/measure/tableCellFloating.js +2 -0
- package/dist/layout-engine/types.d.ts +23 -1
- package/dist/layout-painter/renderImage.d.ts +5 -1
- package/dist/layout-painter/renderImage.js +14 -6
- package/dist/layout-painter/renderPage.d.ts +2 -0
- package/dist/layout-painter/renderPage.js +4 -0
- package/dist/layout-painter/renderParagraph.d.ts +13 -1
- package/dist/layout-painter/renderParagraph.js +26 -6
- package/dist/managers/autoSaveCodec.d.ts +9 -1
- package/dist/managers/autoSaveCodec.js +14 -12
- package/dist/markdown/images.js +1 -4
- package/dist/markdown/renderBlock.js +1 -0
- package/dist/markdown/renderRuns.d.ts +1 -1
- package/dist/markdown/renderRuns.js +28 -5
- package/dist/markdown/renderTable.js +22 -5
- package/dist/markdown/trailers.js +4 -1
- package/dist/pdf/images.js +142 -6
- package/dist/prosemirror/attrs/index.d.ts +14 -3
- package/dist/prosemirror/attrs/index.js +224 -2
- package/dist/prosemirror/authoredTransformAttrs.d.ts +28 -0
- package/dist/prosemirror/authoredTransformAttrs.js +64 -0
- package/dist/prosemirror/commands/contentControls.js +10 -2
- package/dist/prosemirror/commands/image.d.ts +9 -2
- package/dist/prosemirror/commands/image.js +43 -28
- package/dist/prosemirror/commands/pageBreak.js +1 -1
- package/dist/prosemirror/commentReferenceAttrs.d.ts +8 -0
- package/dist/prosemirror/commentReferenceAttrs.js +33 -0
- package/dist/prosemirror/commentReferenceIntegrity.d.ts +47 -0
- package/dist/prosemirror/commentReferenceIntegrity.js +43 -0
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
- package/dist/prosemirror/conversion/fromProseDoc.js +338 -99
- package/dist/prosemirror/conversion/index.d.ts +2 -2
- package/dist/prosemirror/conversion/toProseDoc.d.ts +7 -9
- package/dist/prosemirror/conversion/toProseDoc.js +551 -327
- package/dist/prosemirror/extensions/StarterKit.js +8 -58
- package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -1
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +45 -27
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +3 -1
- package/dist/prosemirror/extensions/features/ImagePasteExtension.js +5 -3
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +1 -0
- package/dist/prosemirror/extensions/markRegistry.d.ts +41 -0
- package/dist/prosemirror/extensions/markRegistry.js +75 -0
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +2 -3
- package/dist/prosemirror/extensions/marks/InlineWrapperExtension.d.ts +18 -0
- package/dist/prosemirror/extensions/marks/InlineWrapperExtension.js +63 -0
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +2 -1
- package/dist/prosemirror/extensions/marks/markUtils.js +47 -4
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.d.ts +11 -0
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +87 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +9 -7
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +20 -0
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.d.ts +32 -0
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +67 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.d.ts +16 -0
- package/dist/prosemirror/extensions/nodes/PreservedXmlExtension.js +60 -0
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +10 -2
- package/dist/prosemirror/extensions/nodes/TableExtension.js +3 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +13 -5
- package/dist/prosemirror/inlineWrapperStack.d.ts +39 -0
- package/dist/prosemirror/inlineWrapperStack.js +75 -0
- package/dist/prosemirror/pageBreakRunProjection.d.ts +17 -7
- package/dist/prosemirror/pageBreakRunProjection.js +19 -9
- package/dist/prosemirror/paragraphFormattingProvenance.d.ts +6 -3
- package/dist/prosemirror/paragraphFormattingProvenance.js +12 -3
- package/dist/prosemirror/replacedAnnotations.d.ts +59 -0
- package/dist/prosemirror/replacedAnnotations.js +165 -0
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +3 -1
- package/dist/prosemirror/runFormattingInlineCarriers.js +5 -1
- package/dist/prosemirror/schema/index.d.ts +3 -3
- package/dist/prosemirror/schema/marks.d.ts +25 -1
- package/dist/prosemirror/schema/nodes.d.ts +139 -3
- package/dist/prosemirror/schema/nodes.js +16 -1
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +2 -0
- package/dist/prosemirror/trackedRunInlineAtoms.js +2 -0
- package/dist/prosemirror/validation.js +16 -2
- package/dist/prosemirror/yjsDocumentMetadata.d.ts +73 -0
- package/dist/prosemirror/yjsDocumentMetadata.js +171 -0
- package/dist/prosemirror/zeroWidthAnchors.js +2 -0
- package/dist/render-dom/commentAnchorAttributes.d.ts +37 -0
- package/dist/render-dom/commentAnchorAttributes.js +54 -0
- package/dist/server.d.ts +3 -1
- package/dist/server.js +3 -1
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/base64.d.ts +36 -0
- package/dist/utils/base64.js +40 -0
- package/dist/utils/clipboard.d.ts +9 -1
- package/dist/utils/clipboard.js +29 -2
- package/dist/utils/findReplace.js +1 -1
- package/dist/utils/imageLuminance.d.ts +15 -0
- package/dist/utils/imageLuminance.js +32 -0
- package/dist/utils/mergeDocumentContent.js +7 -17
- package/dist/utils/replaceText.js +1 -0
- package/dist/utils/units.d.ts +10 -1
- package/dist/utils/units.js +12 -1
- package/dist/utils/urlSecurity.d.ts +8 -2
- package/dist/utils/urlSecurity.js +21 -3
- package/package.json +2 -2
- package/dist/docx/blockRangeMarkers.d.ts +0 -36
- package/dist/docx/blockRangeMarkers.js +0 -59
- package/dist/prosemirror/yjsParagraphSourceContract.d.ts +0 -9
- package/dist/prosemirror/yjsParagraphSourceContract.js +0 -26
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { readCommentReferenceAttrs } from "../../commentReferenceAttrs.js";
|
|
2
|
+
import { planCommentReferenceRepairs } from "../../commentReferenceIntegrity.js";
|
|
3
|
+
import { createNodeExtension } from "../create.js";
|
|
4
|
+
import { Plugin } from "prosemirror-state";
|
|
5
|
+
//#region src/prosemirror/extensions/nodes/CommentReferenceExtension.ts
|
|
6
|
+
/** The node name, for callers asking whether a paragraph holds any content. */
|
|
7
|
+
const COMMENT_REFERENCE_NODE_NAME = "commentReference";
|
|
8
|
+
const surveyCommentReferences = (doc) => {
|
|
9
|
+
const references = [];
|
|
10
|
+
const markEnds = /* @__PURE__ */ new Map();
|
|
11
|
+
doc.descendants((node, position) => {
|
|
12
|
+
if (node.type.name === "commentReference") {
|
|
13
|
+
const attrs = readCommentReferenceAttrs(node);
|
|
14
|
+
references.push({
|
|
15
|
+
commentId: attrs.ok ? attrs.value.commentId : -1,
|
|
16
|
+
position,
|
|
17
|
+
size: node.nodeSize,
|
|
18
|
+
malformed: !attrs.ok
|
|
19
|
+
});
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (!node.isInline) return true;
|
|
23
|
+
for (const mark of node.marks) {
|
|
24
|
+
if (mark.type.name !== "comment") continue;
|
|
25
|
+
const commentId = mark.attrs["commentId"];
|
|
26
|
+
if (typeof commentId !== "number") continue;
|
|
27
|
+
markEnds.set(commentId, Math.max(markEnds.get(commentId) ?? 0, position + node.nodeSize));
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
references,
|
|
33
|
+
markExtents: [...markEnds].map(([commentId, end]) => ({
|
|
34
|
+
commentId,
|
|
35
|
+
end
|
|
36
|
+
}))
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const CommentReferenceExtension = createNodeExtension({
|
|
40
|
+
name: COMMENT_REFERENCE_NODE_NAME,
|
|
41
|
+
schemaNodeName: COMMENT_REFERENCE_NODE_NAME,
|
|
42
|
+
nodeSpec: (options) => ({
|
|
43
|
+
inline: true,
|
|
44
|
+
group: "inline",
|
|
45
|
+
marks: "_",
|
|
46
|
+
atom: true,
|
|
47
|
+
selectable: false,
|
|
48
|
+
attrs: { commentId: {} },
|
|
49
|
+
parseDOM: [{
|
|
50
|
+
tag: "span[data-docx-comment-reference]",
|
|
51
|
+
getAttrs(dom) {
|
|
52
|
+
const raw = dom.getAttribute("data-docx-comment-reference");
|
|
53
|
+
if (raw === null || !/^(?:0|[1-9]\d*)$/.test(raw)) return false;
|
|
54
|
+
const commentId = Number(raw);
|
|
55
|
+
return Number.isSafeInteger(commentId) ? { commentId } : false;
|
|
56
|
+
}
|
|
57
|
+
}],
|
|
58
|
+
toDOM(node) {
|
|
59
|
+
const attrs = readCommentReferenceAttrs(node);
|
|
60
|
+
return ["span", {
|
|
61
|
+
"data-docx-comment-reference": String(attrs.ok ? attrs.value.commentId : ""),
|
|
62
|
+
"aria-hidden": "true",
|
|
63
|
+
contenteditable: "false",
|
|
64
|
+
style: "display: none;",
|
|
65
|
+
...options.getInternalClipboardToken ? { "data-docx-internal-clipboard": options.getInternalClipboardToken() } : {}
|
|
66
|
+
}];
|
|
67
|
+
}
|
|
68
|
+
}),
|
|
69
|
+
onSchemaReady: ({ schema }) => ({ plugins: [new Plugin({ appendTransaction(transactions, _oldState, newState) {
|
|
70
|
+
if (!transactions.some(({ docChanged }) => docChanged)) return null;
|
|
71
|
+
const referenceType = schema.nodes[COMMENT_REFERENCE_NODE_NAME];
|
|
72
|
+
if (!referenceType) return null;
|
|
73
|
+
const repairs = planCommentReferenceRepairs(surveyCommentReferences(newState.doc));
|
|
74
|
+
if (repairs.length === 0) return null;
|
|
75
|
+
const transaction = newState.tr;
|
|
76
|
+
for (const repair of repairs) {
|
|
77
|
+
if (repair.type === "delete") {
|
|
78
|
+
transaction.delete(repair.position, repair.position + repair.size);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
transaction.insert(transaction.mapping.map(repair.position), referenceType.create({ commentId: repair.commentId }));
|
|
82
|
+
}
|
|
83
|
+
return transaction;
|
|
84
|
+
} })] })
|
|
85
|
+
});
|
|
86
|
+
//#endregion
|
|
87
|
+
export { COMMENT_REFERENCE_NODE_NAME, CommentReferenceExtension };
|
|
@@ -8,16 +8,18 @@ const createFieldAttrs = () => ({
|
|
|
8
8
|
displayText: { default: "" },
|
|
9
9
|
_numberedRefBaseline: { default: void 0 },
|
|
10
10
|
fieldKind: { default: "simple" },
|
|
11
|
-
fldLock: { default:
|
|
12
|
-
dirty: { default:
|
|
11
|
+
fldLock: { default: null },
|
|
12
|
+
dirty: { default: null }
|
|
13
13
|
});
|
|
14
|
+
/** A `data-` flag a pasted field carried: absent states nothing. */
|
|
15
|
+
const statedFlag = (value) => value === void 0 ? null : value === "true";
|
|
14
16
|
const readFieldDomAttrs = (dom) => ({
|
|
15
17
|
fieldType: dom.dataset["fieldType"] ?? "UNKNOWN",
|
|
16
18
|
instruction: dom.dataset["instruction"] ?? "",
|
|
17
19
|
displayText: dom.textContent ?? "",
|
|
18
20
|
fieldKind: dom.dataset["fieldKind"] ?? "simple",
|
|
19
|
-
fldLock: dom.dataset["fldLock"]
|
|
20
|
-
dirty: dom.dataset["dirty"]
|
|
21
|
+
fldLock: statedFlag(dom.dataset["fldLock"]),
|
|
22
|
+
dirty: statedFlag(dom.dataset["dirty"])
|
|
21
23
|
});
|
|
22
24
|
const getFieldDomAttrs = (node) => {
|
|
23
25
|
const { fieldType, instruction, fieldKind, fldLock, dirty } = expectFieldAttrs(node);
|
|
@@ -26,8 +28,8 @@ const getFieldDomAttrs = (node) => {
|
|
|
26
28
|
"data-field-type": fieldType,
|
|
27
29
|
"data-instruction": instruction,
|
|
28
30
|
"data-field-kind": fieldKind,
|
|
29
|
-
...fldLock ? { "data-fld-lock":
|
|
30
|
-
...dirty ? { "data-dirty":
|
|
31
|
+
...fldLock === void 0 ? {} : { "data-fld-lock": String(fldLock) },
|
|
32
|
+
...dirty === void 0 ? {} : { "data-dirty": String(dirty) },
|
|
31
33
|
style: "outline: 1px solid var(--doc-field-outline, rgba(200,200,200,0.4)); padding: 0 1px; border-radius: 2px;"
|
|
32
34
|
};
|
|
33
35
|
};
|
|
@@ -74,7 +76,7 @@ const StructuredFieldExtension = createNodeExtension({
|
|
|
74
76
|
nodeSpec: (options) => ({
|
|
75
77
|
inline: true,
|
|
76
78
|
group: "inline",
|
|
77
|
-
content: "(text | bookmarkBoundary | tab | symbol | hardBreak | pageBreakRun | image | shape | renderedPageBreak | textBoxAnchor)+",
|
|
79
|
+
content: "(text | bookmarkBoundary | tab | symbol | hardBreak | pageBreakRun | image | shape | renderedPageBreak | textBoxAnchor | preservedXml)+",
|
|
78
80
|
atom: true,
|
|
79
81
|
selectable: true,
|
|
80
82
|
attrs: createFieldAttrs(),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { imageLuminanceFilter } from "../../../utils/imageLuminance.js";
|
|
1
2
|
import { expectImageAttrs } from "../../attrs/index.js";
|
|
2
3
|
import { createNodeExtension } from "../create.js";
|
|
3
4
|
//#region src/prosemirror/extensions/nodes/ImageExtension.ts
|
|
@@ -24,7 +25,12 @@ const ImageExtension = createNodeExtension({
|
|
|
24
25
|
displayMode: { default: "inline" },
|
|
25
26
|
cssFloat: { default: null },
|
|
26
27
|
transform: { default: null },
|
|
28
|
+
docxRotation: { default: null },
|
|
29
|
+
docxFlipH: { default: null },
|
|
30
|
+
docxFlipV: { default: null },
|
|
27
31
|
opacity: { default: null },
|
|
32
|
+
brightness: { default: null },
|
|
33
|
+
contrast: { default: null },
|
|
28
34
|
distTop: { default: null },
|
|
29
35
|
distBottom: { default: null },
|
|
30
36
|
distLeft: { default: null },
|
|
@@ -39,8 +45,12 @@ const ImageExtension = createNodeExtension({
|
|
|
39
45
|
paddingLeft: { default: null },
|
|
40
46
|
position: { default: null },
|
|
41
47
|
layoutInCell: { default: null },
|
|
48
|
+
decorative: { default: null },
|
|
49
|
+
hidden: { default: null },
|
|
50
|
+
docPrExtensions: { default: null },
|
|
42
51
|
frameLocks: { default: null },
|
|
43
52
|
borderWidth: { default: null },
|
|
53
|
+
_docxAuthoredEmu: { default: null },
|
|
44
54
|
borderColor: { default: null },
|
|
45
55
|
borderStyle: { default: null },
|
|
46
56
|
wrapText: { default: null },
|
|
@@ -62,6 +72,10 @@ const ImageExtension = createNodeExtension({
|
|
|
62
72
|
const borderWidthRaw = element.dataset["borderWidth"];
|
|
63
73
|
const opacityRaw = element.dataset["opacity"];
|
|
64
74
|
const opacityParsed = opacityRaw === void 0 ? NaN : Number(opacityRaw);
|
|
75
|
+
const brightnessRaw = element.dataset["brightness"];
|
|
76
|
+
const brightness = brightnessRaw === void 0 ? NaN : Number(brightnessRaw);
|
|
77
|
+
const contrastRaw = element.dataset["contrast"];
|
|
78
|
+
const contrast = contrastRaw === void 0 ? NaN : Number(contrastRaw);
|
|
65
79
|
return {
|
|
66
80
|
src: element.getAttribute("src") || "",
|
|
67
81
|
...alt ? { alt } : {},
|
|
@@ -74,6 +88,8 @@ const ImageExtension = createNodeExtension({
|
|
|
74
88
|
...cssFloat ? { cssFloat } : {},
|
|
75
89
|
...element.dataset["transform"] ? { transform: element.dataset["transform"] } : {},
|
|
76
90
|
...Number.isFinite(opacityParsed) ? { opacity: opacityParsed } : {},
|
|
91
|
+
...Number.isFinite(brightness) ? { brightness } : {},
|
|
92
|
+
...Number.isFinite(contrast) ? { contrast } : {},
|
|
77
93
|
...borderWidthRaw ? { borderWidth: Number(borderWidthRaw) } : {},
|
|
78
94
|
...element.dataset["borderColor"] ? { borderColor: element.dataset["borderColor"] } : {},
|
|
79
95
|
...element.dataset["borderStyle"] ? { borderStyle: element.dataset["borderStyle"] } : {}
|
|
@@ -94,6 +110,8 @@ const ImageExtension = createNodeExtension({
|
|
|
94
110
|
if (attrs.cssFloat) domAttrs["data-css-float"] = attrs.cssFloat;
|
|
95
111
|
if (attrs.transform) domAttrs["data-transform"] = attrs.transform;
|
|
96
112
|
if (attrs.opacity != null) domAttrs["data-opacity"] = String(attrs.opacity);
|
|
113
|
+
if (attrs.brightness != null) domAttrs["data-brightness"] = String(attrs.brightness);
|
|
114
|
+
if (attrs.contrast != null) domAttrs["data-contrast"] = String(attrs.contrast);
|
|
97
115
|
if (attrs.borderWidth) domAttrs["data-border-width"] = String(attrs.borderWidth);
|
|
98
116
|
if (attrs.borderColor) domAttrs["data-border-color"] = attrs.borderColor;
|
|
99
117
|
if (attrs.borderStyle) domAttrs["data-border-style"] = attrs.borderStyle;
|
|
@@ -130,6 +148,8 @@ const ImageExtension = createNodeExtension({
|
|
|
130
148
|
}
|
|
131
149
|
if (attrs.transform) styles.push(`transform: ${attrs.transform}`);
|
|
132
150
|
if (attrs.opacity != null && attrs.opacity < 1) styles.push(`opacity: ${Math.max(0, attrs.opacity)}`);
|
|
151
|
+
const luminanceFilter = imageLuminanceFilter(attrs);
|
|
152
|
+
if (luminanceFilter !== void 0) styles.push(`filter: ${luminanceFilter}`);
|
|
133
153
|
if (attrs.borderWidth && attrs.borderWidth > 0) {
|
|
134
154
|
const bStyle = attrs.borderStyle || "solid";
|
|
135
155
|
const bColor = attrs.borderColor || "#000000";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { NodeExtension } from "../types.js";
|
|
2
|
+
//#region src/prosemirror/extensions/nodes/PreservedBlockExtension.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* A zero-width block for markup folio keeps opaquely between two blocks.
|
|
5
|
+
*
|
|
6
|
+
* The block-level twin of the `preservedXml` inline atom. A `w:permStart`
|
|
7
|
+
* between two paragraphs, an `m:oMathPara`, a `w:altChunk`, a comment or move
|
|
8
|
+
* range that opens between blocks: the editor has no model for any of it and
|
|
9
|
+
* does not need one, because it only has to not lose it. So the node renders
|
|
10
|
+
* nothing, takes no selection and holds no text.
|
|
11
|
+
*
|
|
12
|
+
* **Position is structure, not an attribute.** The node sits between the same
|
|
13
|
+
* two blocks it sat between in the source, and ProseMirror's own mapping keeps
|
|
14
|
+
* it there: inserting, splitting or deleting a neighbour moves the markup the
|
|
15
|
+
* way a reader would expect, and nothing has to keep an index honest. The
|
|
16
|
+
* alternative — an index into the container recorded on the node — drifts the
|
|
17
|
+
* first time anything around it changes, and a drifting index is how markup
|
|
18
|
+
* ends up in the wrong place rather than merely lost.
|
|
19
|
+
*
|
|
20
|
+
* Deleting a *neighbour* therefore leaves the markup attached to whatever now
|
|
21
|
+
* follows it; only a selection that covers the node itself removes it, which
|
|
22
|
+
* is the same rule the editor applies to every other block.
|
|
23
|
+
*
|
|
24
|
+
* The integrity plugin removes a node that can never write markup back: bad
|
|
25
|
+
* attributes, or an empty payload left by a paste through the DOM. Keeping one
|
|
26
|
+
* would leave a zero-width block in the document that serializes to nothing.
|
|
27
|
+
*/
|
|
28
|
+
/** The node name, for callers asking what a container holds. */
|
|
29
|
+
declare const PRESERVED_BLOCK_NODE_NAME = "preservedBlock";
|
|
30
|
+
declare const PreservedBlockExtension: (options?: Partial<Record<string, unknown>> | undefined) => NodeExtension;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { PRESERVED_BLOCK_NODE_NAME, PreservedBlockExtension };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { expectPreservedBlockAttrs, readPreservedBlockAttrs } from "../../attrs/index.js";
|
|
2
|
+
import { createNodeExtension } from "../create.js";
|
|
3
|
+
import { Plugin } from "prosemirror-state";
|
|
4
|
+
//#region src/prosemirror/extensions/nodes/PreservedBlockExtension.ts
|
|
5
|
+
/** The node name, for callers asking what a container holds. */
|
|
6
|
+
const PRESERVED_BLOCK_NODE_NAME = "preservedBlock";
|
|
7
|
+
/**
|
|
8
|
+
* A node that can never write markup back.
|
|
9
|
+
*
|
|
10
|
+
* Either the attributes do not read at all, or `xml` is empty: a copy that
|
|
11
|
+
* came back from a paste with its payload stripped. Keeping one would put a
|
|
12
|
+
* zero-width block in the document that serializes to nothing, so the plugin
|
|
13
|
+
* removes it rather than letting it ride along.
|
|
14
|
+
*/
|
|
15
|
+
const isUnwritable = (node) => {
|
|
16
|
+
const attrs = readPreservedBlockAttrs(node);
|
|
17
|
+
return !attrs.ok || attrs.value.xml === "";
|
|
18
|
+
};
|
|
19
|
+
const collectUnwritableBlocks = (doc) => {
|
|
20
|
+
const unwritable = [];
|
|
21
|
+
doc.descendants((node, position) => {
|
|
22
|
+
if (node.type.name !== "preservedBlock") return true;
|
|
23
|
+
if (isUnwritable(node)) unwritable.push({
|
|
24
|
+
position,
|
|
25
|
+
node
|
|
26
|
+
});
|
|
27
|
+
return false;
|
|
28
|
+
});
|
|
29
|
+
return unwritable;
|
|
30
|
+
};
|
|
31
|
+
const PreservedBlockExtension = createNodeExtension({
|
|
32
|
+
name: PRESERVED_BLOCK_NODE_NAME,
|
|
33
|
+
schemaNodeName: PRESERVED_BLOCK_NODE_NAME,
|
|
34
|
+
nodeSpec: {
|
|
35
|
+
group: "block",
|
|
36
|
+
atom: true,
|
|
37
|
+
selectable: false,
|
|
38
|
+
attrs: { xml: {} },
|
|
39
|
+
parseDOM: [{
|
|
40
|
+
tag: "div[data-docx-preserved-block]",
|
|
41
|
+
getAttrs(dom) {
|
|
42
|
+
if (!(dom instanceof HTMLElement)) return false;
|
|
43
|
+
const xml = dom.dataset["docxPreservedBlock"];
|
|
44
|
+
return xml === void 0 || xml === "" ? false : { xml };
|
|
45
|
+
}
|
|
46
|
+
}],
|
|
47
|
+
toDOM(node) {
|
|
48
|
+
const { xml } = expectPreservedBlockAttrs(node);
|
|
49
|
+
return ["div", {
|
|
50
|
+
"data-docx-preserved-block": xml,
|
|
51
|
+
"aria-hidden": "true",
|
|
52
|
+
contenteditable: "false",
|
|
53
|
+
style: "display: none;"
|
|
54
|
+
}];
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
onSchemaReady: () => ({ plugins: [new Plugin({ appendTransaction(transactions, _oldState, newState) {
|
|
58
|
+
if (!transactions.some(({ docChanged }) => docChanged)) return null;
|
|
59
|
+
const unwritable = collectUnwritableBlocks(newState.doc);
|
|
60
|
+
if (unwritable.length === 0) return null;
|
|
61
|
+
const transaction = newState.tr;
|
|
62
|
+
for (const { node, position } of unwritable.toSorted((first, second) => second.position - first.position)) transaction.delete(position, position + node.nodeSize);
|
|
63
|
+
return transaction;
|
|
64
|
+
} })] })
|
|
65
|
+
});
|
|
66
|
+
//#endregion
|
|
67
|
+
export { PRESERVED_BLOCK_NODE_NAME, PreservedBlockExtension };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { NodeExtension } from "../types.js";
|
|
2
|
+
//#region src/prosemirror/extensions/nodes/PreservedXmlExtension.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* An opaque inline atom for a run child folio does not model.
|
|
5
|
+
*
|
|
6
|
+
* The editor cannot edit markup it has no model for, and it does not have to:
|
|
7
|
+
* it only has to not lose it. The node carries the captured bytes untouched
|
|
8
|
+
* and shows the visible text the markup puts on the line (`w:ruby` renders its
|
|
9
|
+
* `w:rubyBase` there), so the round trip keeps both the document's text and
|
|
10
|
+
* the document's markup.
|
|
11
|
+
*/
|
|
12
|
+
/** The node name, for callers asking what a paragraph holds. */
|
|
13
|
+
declare const PRESERVED_XML_NODE_NAME = "preservedXml";
|
|
14
|
+
declare const PreservedXmlExtension: (options?: Partial<Record<string, unknown>> | undefined) => NodeExtension;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { PRESERVED_XML_NODE_NAME, PreservedXmlExtension };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { expectPreservedXmlAttrs } from "../../attrs/index.js";
|
|
2
|
+
import { PRESERVED_XML_LEVELS } from "../../schema/nodes.js";
|
|
3
|
+
import { createNodeExtension } from "../create.js";
|
|
4
|
+
//#region src/prosemirror/extensions/nodes/PreservedXmlExtension.ts
|
|
5
|
+
/**
|
|
6
|
+
* An opaque inline atom for a run child folio does not model.
|
|
7
|
+
*
|
|
8
|
+
* The editor cannot edit markup it has no model for, and it does not have to:
|
|
9
|
+
* it only has to not lose it. The node carries the captured bytes untouched
|
|
10
|
+
* and shows the visible text the markup puts on the line (`w:ruby` renders its
|
|
11
|
+
* `w:rubyBase` there), so the round trip keeps both the document's text and
|
|
12
|
+
* the document's markup.
|
|
13
|
+
*/
|
|
14
|
+
/** The node name, for callers asking what a paragraph holds. */
|
|
15
|
+
const PRESERVED_XML_NODE_NAME = "preservedXml";
|
|
16
|
+
const PreservedXmlExtension = createNodeExtension({
|
|
17
|
+
name: PRESERVED_XML_NODE_NAME,
|
|
18
|
+
schemaNodeName: PRESERVED_XML_NODE_NAME,
|
|
19
|
+
nodeSpec: {
|
|
20
|
+
inline: true,
|
|
21
|
+
group: "inline",
|
|
22
|
+
atom: true,
|
|
23
|
+
marks: "_",
|
|
24
|
+
selectable: false,
|
|
25
|
+
attrs: {
|
|
26
|
+
xml: {},
|
|
27
|
+
text: { default: "" },
|
|
28
|
+
level: { default: PRESERVED_XML_LEVELS.run }
|
|
29
|
+
},
|
|
30
|
+
parseDOM: [{
|
|
31
|
+
tag: "span[data-docx-preserved-xml]",
|
|
32
|
+
getAttrs(node) {
|
|
33
|
+
if (!(node instanceof HTMLElement)) return false;
|
|
34
|
+
const xml = node.dataset["docxPreservedXml"];
|
|
35
|
+
if (xml === void 0 || xml === "") return false;
|
|
36
|
+
const level = node.dataset["docxPreservedLevel"] === PRESERVED_XML_LEVELS.inline ? PRESERVED_XML_LEVELS.inline : PRESERVED_XML_LEVELS.run;
|
|
37
|
+
return {
|
|
38
|
+
xml,
|
|
39
|
+
text: node.dataset["docxPreservedText"] ?? "",
|
|
40
|
+
level
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}],
|
|
44
|
+
toDOM(node) {
|
|
45
|
+
const { xml, text, level } = expectPreservedXmlAttrs(node);
|
|
46
|
+
return [
|
|
47
|
+
"span",
|
|
48
|
+
{
|
|
49
|
+
"data-docx-preserved-xml": xml,
|
|
50
|
+
"data-docx-preserved-level": level,
|
|
51
|
+
...text === "" ? {} : { "data-docx-preserved-text": text },
|
|
52
|
+
contenteditable: "false"
|
|
53
|
+
},
|
|
54
|
+
text
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
//#endregion
|
|
60
|
+
export { PRESERVED_XML_NODE_NAME, PreservedXmlExtension };
|
|
@@ -371,22 +371,30 @@ const ShapeExtension = createNodeExtension({
|
|
|
371
371
|
geometryAdjustments: { default: null },
|
|
372
372
|
_docxRunFormatting: { default: null },
|
|
373
373
|
shapeId: { default: null },
|
|
374
|
+
shapeName: { default: null },
|
|
375
|
+
alt: { default: null },
|
|
376
|
+
title: { default: null },
|
|
374
377
|
width: { default: 100 },
|
|
375
378
|
height: { default: 80 },
|
|
379
|
+
_docxAuthoredEmu: { default: null },
|
|
376
380
|
fillColor: { default: null },
|
|
377
381
|
fillColorValue: { default: null },
|
|
378
382
|
fillType: { default: "solid" },
|
|
379
383
|
gradientType: { default: null },
|
|
380
384
|
gradientAngle: { default: null },
|
|
381
385
|
gradientStops: { default: null },
|
|
382
|
-
outlineWidth: { default:
|
|
386
|
+
outlineWidth: { default: null },
|
|
383
387
|
outlineColor: { default: "var(--doc-shape-outline, #000000)" },
|
|
384
388
|
outlineColorValue: { default: null },
|
|
385
|
-
outlineStyle: { default:
|
|
389
|
+
outlineStyle: { default: null },
|
|
386
390
|
outlineCap: { default: null },
|
|
391
|
+
outlineJoin: { default: null },
|
|
387
392
|
outlineHeadEnd: { default: null },
|
|
388
393
|
outlineTailEnd: { default: null },
|
|
389
394
|
transform: { default: null },
|
|
395
|
+
docxRotation: { default: null },
|
|
396
|
+
docxFlipH: { default: null },
|
|
397
|
+
docxFlipV: { default: null },
|
|
390
398
|
displayMode: { default: "inline" },
|
|
391
399
|
cssFloat: { default: null },
|
|
392
400
|
wrapType: { default: "inline" },
|
|
@@ -206,6 +206,7 @@ const tableRowSpec = {
|
|
|
206
206
|
_resolvedJustification: { default: null },
|
|
207
207
|
_originalFormatting: { default: null },
|
|
208
208
|
trPrChange: { default: null },
|
|
209
|
+
_preservedAttributes: { default: null },
|
|
209
210
|
trIns: { default: null },
|
|
210
211
|
trDel: { default: null }
|
|
211
212
|
},
|
|
@@ -308,7 +309,7 @@ function buildCellWidthStyles(attrs) {
|
|
|
308
309
|
return styles;
|
|
309
310
|
}
|
|
310
311
|
const tableCellSpec = {
|
|
311
|
-
content: "(paragraph | table | textBox)+",
|
|
312
|
+
content: "(paragraph | table | textBox | preservedBlock)+",
|
|
312
313
|
tableRole: "cell",
|
|
313
314
|
isolating: true,
|
|
314
315
|
attrs: {
|
|
@@ -366,7 +367,7 @@ const tableCellSpec = {
|
|
|
366
367
|
}
|
|
367
368
|
};
|
|
368
369
|
const tableHeaderSpec = {
|
|
369
|
-
content: "(paragraph | table | textBox)+",
|
|
370
|
+
content: "(paragraph | table | textBox | preservedBlock)+",
|
|
370
371
|
tableRole: "header_cell",
|
|
371
372
|
isolating: true,
|
|
372
373
|
attrs: {
|
|
@@ -77,19 +77,26 @@ const TextBoxExtension = createNodeExtension({
|
|
|
77
77
|
attrs: {
|
|
78
78
|
width: { default: 200 },
|
|
79
79
|
height: { default: null },
|
|
80
|
+
_docxAuthoredEmu: { default: null },
|
|
80
81
|
autoFit: { default: null },
|
|
81
82
|
wordArt: { default: null },
|
|
82
83
|
textWrap: { default: null },
|
|
83
84
|
textBoxId: { default: null },
|
|
85
|
+
textBoxName: { default: null },
|
|
86
|
+
alt: { default: null },
|
|
87
|
+
title: { default: null },
|
|
84
88
|
fillColor: { default: null },
|
|
85
89
|
outlineWidth: { default: null },
|
|
86
90
|
outlineColor: { default: null },
|
|
87
91
|
outlineStyle: { default: null },
|
|
88
92
|
transform: { default: null },
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
docxRotation: { default: null },
|
|
94
|
+
docxFlipH: { default: null },
|
|
95
|
+
docxFlipV: { default: null },
|
|
96
|
+
marginTop: { default: null },
|
|
97
|
+
marginBottom: { default: null },
|
|
98
|
+
marginLeft: { default: null },
|
|
99
|
+
marginRight: { default: null },
|
|
93
100
|
verticalAlign: { default: null },
|
|
94
101
|
displayMode: { default: "inline" },
|
|
95
102
|
cssFloat: { default: null },
|
|
@@ -105,7 +112,8 @@ const TextBoxExtension = createNodeExtension({
|
|
|
105
112
|
_docxAnchorId: { default: null },
|
|
106
113
|
_docxTextBodyContentState: { default: { type: "authored" } },
|
|
107
114
|
_docxTrackedChange: { default: null },
|
|
108
|
-
_docxInlineSdts: { default: null }
|
|
115
|
+
_docxInlineSdts: { default: null },
|
|
116
|
+
_preservedAttributes: { default: null }
|
|
109
117
|
},
|
|
110
118
|
parseDOM: [{
|
|
111
119
|
tag: "div.docx-textbox",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { InlineWrapperLayer } from "./schema/marks.js";
|
|
3
|
+
//#region src/prosemirror/inlineWrapperStack.d.ts
|
|
4
|
+
/** The DOM attribute that carries a serialised stack through copy and paste. */
|
|
5
|
+
declare const INLINE_WRAPPER_STACK_ATTRIBUTE = "data-inline-wrapper";
|
|
6
|
+
/** A layer with its keys in canonical order, absent fields left absent. */
|
|
7
|
+
declare const inlineWrapperLayer: (layer: InlineWrapperLayer) => InlineWrapperLayer;
|
|
8
|
+
/**
|
|
9
|
+
* The model member a layer describes, holding `content`.
|
|
10
|
+
*
|
|
11
|
+
* The inverse of the `WrapperLayer` projection: `toProseDoc` takes the model
|
|
12
|
+
* member apart into a layer and its content, and the save leg puts one back
|
|
13
|
+
* together. Both directions live here so a wrapper kind is spelled once.
|
|
14
|
+
*/
|
|
15
|
+
declare const inlineWrapperMember: (layer: InlineWrapperLayer, content: document_d_exports.InlineWrapper["content"]) => document_d_exports.InlineWrapper;
|
|
16
|
+
/** `layers` in canonical form, or `null` when there is no wrapper to record. */
|
|
17
|
+
declare const inlineWrapperStack: (layers: readonly InlineWrapperLayer[]) => readonly InlineWrapperLayer[] | null;
|
|
18
|
+
declare const serializeInlineWrapperStack: (stack: readonly InlineWrapperLayer[]) => string;
|
|
19
|
+
/**
|
|
20
|
+
* The key two stacks share exactly when they are the same nest of wrappers.
|
|
21
|
+
*
|
|
22
|
+
* The save leg groups adjacent inline leaves by it, so it has to be the
|
|
23
|
+
* factory's canonical spelling rather than whatever order an attrs object
|
|
24
|
+
* happens to carry: two leaves inside one `w:bdo` that keyed differently would
|
|
25
|
+
* be written as two `w:bdo` elements. The empty stack keys as the empty string,
|
|
26
|
+
* which is what "inside no wrapper" compares as.
|
|
27
|
+
*/
|
|
28
|
+
declare const inlineWrapperStackKey: (stack: readonly InlineWrapperLayer[]) => string;
|
|
29
|
+
/**
|
|
30
|
+
* A stack read back from the DOM, or `null` when the markup carries none.
|
|
31
|
+
*
|
|
32
|
+
* Paste from outside the editor is the ordinary case: the attribute is absent,
|
|
33
|
+
* so the pasted leaf carries no wrapper. Markup that states the attribute but
|
|
34
|
+
* not a stack this build validates is read the same way — the text is what
|
|
35
|
+
* matters, and inventing a wrapper around it would change the document.
|
|
36
|
+
*/
|
|
37
|
+
declare const parseInlineWrapperStack: (serialized: string | null | undefined) => readonly InlineWrapperLayer[] | null;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { INLINE_WRAPPER_STACK_ATTRIBUTE, inlineWrapperLayer, inlineWrapperMember, inlineWrapperStack, inlineWrapperStackKey, parseInlineWrapperStack, serializeInlineWrapperStack };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { readInlineWrapperStack } from "./attrs/index.js";
|
|
2
|
+
import { Result, panic } from "better-result";
|
|
3
|
+
//#region src/prosemirror/inlineWrapperStack.ts
|
|
4
|
+
/**
|
|
5
|
+
* The one place an inline-wrapper layer is built, and the codec that carries a
|
|
6
|
+
* stack through the DOM.
|
|
7
|
+
*
|
|
8
|
+
* Two layers describing the same wrapper have to be the same value, because
|
|
9
|
+
* `fromProseDoc` groups inline leaves into runs by `JSON.stringify` over their
|
|
10
|
+
* mark attrs: one wrapper spelled with its keys in two orders would split one
|
|
11
|
+
* run into two. Object key order is insertion order in JavaScript, so the
|
|
12
|
+
* factory fixes it and every construction site goes through the factory —
|
|
13
|
+
* including the one that reads a stack back out of the DOM, where `JSON.parse`
|
|
14
|
+
* preserves whatever order the markup happened to carry.
|
|
15
|
+
*/
|
|
16
|
+
/** The DOM attribute that carries a serialised stack through copy and paste. */
|
|
17
|
+
const INLINE_WRAPPER_STACK_ATTRIBUTE = "data-inline-wrapper";
|
|
18
|
+
/** A layer with its keys in canonical order, absent fields left absent. */
|
|
19
|
+
const inlineWrapperLayer = (layer) => {
|
|
20
|
+
switch (layer.kind) {
|
|
21
|
+
case "bidi": return layer.direction === void 0 ? {
|
|
22
|
+
kind: "bidi",
|
|
23
|
+
control: layer.control
|
|
24
|
+
} : {
|
|
25
|
+
kind: "bidi",
|
|
26
|
+
control: layer.control,
|
|
27
|
+
direction: layer.direction
|
|
28
|
+
};
|
|
29
|
+
default:
|
|
30
|
+
layer.kind;
|
|
31
|
+
panic(`Unsupported inline wrapper layer: ${JSON.stringify(layer)}`);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The model member a layer describes, holding `content`.
|
|
36
|
+
*
|
|
37
|
+
* The inverse of the `WrapperLayer` projection: `toProseDoc` takes the model
|
|
38
|
+
* member apart into a layer and its content, and the save leg puts one back
|
|
39
|
+
* together. Both directions live here so a wrapper kind is spelled once.
|
|
40
|
+
*/
|
|
41
|
+
const inlineWrapperMember = (layer, content) => ({
|
|
42
|
+
...inlineWrapperLayer(layer),
|
|
43
|
+
type: "inlineWrapper",
|
|
44
|
+
content
|
|
45
|
+
});
|
|
46
|
+
/** `layers` in canonical form, or `null` when there is no wrapper to record. */
|
|
47
|
+
const inlineWrapperStack = (layers) => layers.length === 0 ? null : layers.map(inlineWrapperLayer);
|
|
48
|
+
const serializeInlineWrapperStack = (stack) => JSON.stringify(stack);
|
|
49
|
+
/**
|
|
50
|
+
* The key two stacks share exactly when they are the same nest of wrappers.
|
|
51
|
+
*
|
|
52
|
+
* The save leg groups adjacent inline leaves by it, so it has to be the
|
|
53
|
+
* factory's canonical spelling rather than whatever order an attrs object
|
|
54
|
+
* happens to carry: two leaves inside one `w:bdo` that keyed differently would
|
|
55
|
+
* be written as two `w:bdo` elements. The empty stack keys as the empty string,
|
|
56
|
+
* which is what "inside no wrapper" compares as.
|
|
57
|
+
*/
|
|
58
|
+
const inlineWrapperStackKey = (stack) => stack.length === 0 ? "" : serializeInlineWrapperStack(stack.map(inlineWrapperLayer));
|
|
59
|
+
/**
|
|
60
|
+
* A stack read back from the DOM, or `null` when the markup carries none.
|
|
61
|
+
*
|
|
62
|
+
* Paste from outside the editor is the ordinary case: the attribute is absent,
|
|
63
|
+
* so the pasted leaf carries no wrapper. Markup that states the attribute but
|
|
64
|
+
* not a stack this build validates is read the same way — the text is what
|
|
65
|
+
* matters, and inventing a wrapper around it would change the document.
|
|
66
|
+
*/
|
|
67
|
+
const parseInlineWrapperStack = (serialized) => {
|
|
68
|
+
if (!serialized) return null;
|
|
69
|
+
const parsed = Result.try(() => JSON.parse(serialized));
|
|
70
|
+
if (parsed.isErr()) return null;
|
|
71
|
+
const stack = readInlineWrapperStack(parsed.value);
|
|
72
|
+
return stack.ok ? stack.value.map(inlineWrapperLayer) : null;
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
75
|
+
export { INLINE_WRAPPER_STACK_ATTRIBUTE, inlineWrapperLayer, inlineWrapperMember, inlineWrapperStack, inlineWrapperStackKey, parseInlineWrapperStack, serializeInlineWrapperStack };
|
|
@@ -2,17 +2,27 @@ import { document_d_exports } from "../types/document.js";
|
|
|
2
2
|
import { ParagraphAttrs } from "./schema/nodes.js";
|
|
3
3
|
import { Node } from "prosemirror-model";
|
|
4
4
|
//#region src/prosemirror/pageBreakRunProjection.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Paragraph shapes whose explicit page-break run the editor lays out
|
|
7
|
+
* approximately.
|
|
8
|
+
*
|
|
9
|
+
* Layout splits a paragraph into fragments at its breaks, and a paragraph
|
|
10
|
+
* property that describes the paragraph as a whole then applies to each
|
|
11
|
+
* fragment. That is an approximation, not a loss: the run is projected, it is
|
|
12
|
+
* saved, and the document opens. Folio used to refuse these instead, which
|
|
13
|
+
* meant a file Word opens could not be opened, laid out or exported at all.
|
|
14
|
+
*/
|
|
5
15
|
declare const PAGE_BREAK_RUN_PARAGRAPH_PROJECTION_MESSAGES: {
|
|
6
|
-
readonly borders: "A bordered paragraph
|
|
7
|
-
readonly frame: "A framed paragraph
|
|
8
|
-
readonly outline: "An outline paragraph
|
|
9
|
-
readonly textBoxAnchor: "A
|
|
16
|
+
readonly borders: "A bordered paragraph is split at its explicit page-break run, so its border is drawn around each part";
|
|
17
|
+
readonly frame: "A framed paragraph is split at its explicit page-break run, so its frame applies to each part";
|
|
18
|
+
readonly outline: "An outline paragraph is split at its explicit page-break run, so each part carries the outline level";
|
|
19
|
+
readonly textBoxAnchor: "A text-box anchor following an explicit page-break run is hosted by the paragraph's first part";
|
|
10
20
|
};
|
|
11
21
|
type PageBreakRunParagraphProjectionReason = keyof typeof PAGE_BREAK_RUN_PARAGRAPH_PROJECTION_MESSAGES;
|
|
12
22
|
type PageBreakRunParagraphProjectionDisposition = {
|
|
13
|
-
status: "
|
|
23
|
+
status: "exact";
|
|
14
24
|
} | {
|
|
15
|
-
status: "
|
|
25
|
+
status: "approximate";
|
|
16
26
|
reason: PageBreakRunParagraphProjectionReason;
|
|
17
27
|
message: (typeof PAGE_BREAK_RUN_PARAGRAPH_PROJECTION_MESSAGES)[keyof typeof PAGE_BREAK_RUN_PARAGRAPH_PROJECTION_MESSAGES];
|
|
18
28
|
};
|
|
@@ -25,7 +35,7 @@ type PageBreakRunParagraphFeatures = {
|
|
|
25
35
|
* Layout splits such a paragraph into fragments at its breaks, and only the
|
|
26
36
|
* first fragment keeps the paragraph's block id, which is what an anchor
|
|
27
37
|
* resolves its host through. An anchor before the first break is therefore
|
|
28
|
-
*
|
|
38
|
+
* laid out exactly; one after it falls back to the first fragment.
|
|
29
39
|
*/
|
|
30
40
|
textBoxAnchorAfterPageBreak: boolean;
|
|
31
41
|
};
|