@stll/folio-core 0.28.0 → 0.29.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/docx/styleParser.js +15 -14
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +1 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +135 -118
- package/dist/layout-engine/footnoteColumnReflow.d.ts +15 -0
- package/dist/layout-engine/footnoteColumnReflow.js +74 -0
- package/dist/layout-engine/index.d.ts +3 -5
- package/dist/layout-engine/index.js +36 -15
- package/dist/layout-engine/measure/cache.d.ts +1 -1
- package/dist/layout-engine/measure/cache.js +11 -2
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +3 -1
- package/dist/layout-engine/measure/listMarkerWidth.js +6 -4
- package/dist/layout-engine/paginator.d.ts +6 -0
- package/dist/layout-engine/paginator.js +30 -11
- package/dist/layout-engine/types.d.ts +11 -6
- package/dist/markdown/renderParagraph.js +7 -2
- package/dist/prosemirror/attrs/index.js +5 -3
- package/dist/prosemirror/bookmarkBoundaryAttrs.d.ts +8 -0
- package/dist/prosemirror/bookmarkBoundaryAttrs.js +66 -0
- package/dist/prosemirror/commands/formatPainter.js +45 -1
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +4 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +224 -91
- package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -1
- package/dist/prosemirror/conversion/toProseDoc.js +325 -94
- package/dist/prosemirror/extensions/StarterKit.js +11 -3
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +8 -4
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.d.ts +4 -1
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +9 -5
- package/dist/prosemirror/extensions/features/pasteCleanup.d.ts +10 -23
- package/dist/prosemirror/extensions/features/pasteCleanup.js +77 -22
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +22 -22
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.d.ts +9 -0
- package/dist/prosemirror/extensions/nodes/BookmarkBoundaryExtension.js +67 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +10 -4
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +77 -59
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +4 -1
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +4 -3
- package/dist/prosemirror/listMarker.d.ts +58 -0
- package/dist/prosemirror/listMarker.js +185 -0
- package/dist/prosemirror/numberedRefFields.d.ts +24 -0
- package/dist/prosemirror/numberedRefFields.js +276 -0
- package/dist/prosemirror/paraText.js +56 -17
- package/dist/prosemirror/plugins/anonymizationDecorations.js +1 -1
- package/dist/prosemirror/plugins/pmTextScan.d.ts +3 -1
- package/dist/prosemirror/plugins/pmTextScan.js +28 -7
- package/dist/prosemirror/plugins/templateDirectives.js +2 -2
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/marks.d.ts +3 -1
- package/dist/prosemirror/schema/nodes.d.ts +13 -1
- package/dist/prosemirror/styles/styleResolver.d.ts +0 -1
- package/dist/prosemirror/styles/styleResolver.js +22 -29
- package/dist/prosemirror/styles/styleToggleCascade.d.ts +37 -0
- package/dist/prosemirror/styles/styleToggleCascade.js +52 -0
- package/dist/prosemirror/validation.js +93 -0
- package/dist/utils/textFormattingMerge.d.ts +9 -1
- package/dist/utils/textFormattingMerge.js +32 -1
- package/package.json +1 -1
|
@@ -4,10 +4,13 @@ import { OUTLINE_STYLE_CSS_ALIASES } from "../../types/documentEnumValues.js";
|
|
|
4
4
|
import { pixelsToEmu } from "../../utils/units.js";
|
|
5
5
|
import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCharacterStyleMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunPropertyChangeMarkAttrs, expectRunShadingMarkAttrs, expectSdtAttrs, expectShapeAttrs, expectStrikeMarkAttrs, expectSymbolAttrs, expectTabAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../attrs/index.js";
|
|
6
6
|
import { autospacingMatchesBase, hasAutospacingBaseSide } from "../autospacingBase.js";
|
|
7
|
+
import { expectBookmarkBoundaryAttrs } from "../bookmarkBoundaryAttrs.js";
|
|
7
8
|
import { applyRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
|
|
9
|
+
import { resolveNumberedRefFields } from "../numberedRefFields.js";
|
|
8
10
|
import { directionToBidi } from "../paragraphDirection.js";
|
|
9
11
|
import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
|
|
10
12
|
import { parseShapeGeometryAdjustments } from "../shapeGeometryAdjustments.js";
|
|
13
|
+
import { cascadeStyleTextFormatting } from "../styles/styleToggleCascade.js";
|
|
11
14
|
import { expectTextBoxAnchorAttrs } from "../textBoxAnchorAttrs.js";
|
|
12
15
|
import { assertValidProseMirrorDocument } from "../validation.js";
|
|
13
16
|
import { runShadingAttrsToShading } from "./runShadingMark.js";
|
|
@@ -197,12 +200,33 @@ function mapSuggestionStrippedNode(node) {
|
|
|
197
200
|
function stripSuggestedProvenance(doc) {
|
|
198
201
|
return mapSuggestionStrippedNode(doc) ?? doc;
|
|
199
202
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
203
|
+
function materializeNumberedRefValues(doc) {
|
|
204
|
+
const results = resolveNumberedRefFields(doc);
|
|
205
|
+
if (results.size === 0) return doc;
|
|
206
|
+
const visit = (node) => {
|
|
207
|
+
if (node.type.name === "field" || node.type.name === "structuredField") {
|
|
208
|
+
const displayText = results.get(node);
|
|
209
|
+
if (displayText !== void 0) return node.type.create({
|
|
210
|
+
...node.attrs,
|
|
211
|
+
displayText
|
|
212
|
+
}, node.content, node.marks);
|
|
213
|
+
return node;
|
|
214
|
+
}
|
|
215
|
+
if (node.childCount === 0) return node;
|
|
216
|
+
const children = [];
|
|
217
|
+
let changed = false;
|
|
218
|
+
node.forEach((child) => {
|
|
219
|
+
const mappedChild = visit(child);
|
|
220
|
+
children.push(mappedChild);
|
|
221
|
+
changed ||= mappedChild !== child;
|
|
222
|
+
});
|
|
223
|
+
return changed ? node.copy(Fragment.fromArray(children)) : node;
|
|
224
|
+
};
|
|
225
|
+
return visit(doc);
|
|
226
|
+
}
|
|
227
|
+
function extractBlocks(inputDoc, refResolution = "resolve") {
|
|
228
|
+
const strippedDoc = stripSuggestedProvenance(inputDoc);
|
|
229
|
+
const pmDoc = refResolution === "resolve" ? materializeNumberedRefValues(strippedDoc) : strippedDoc;
|
|
206
230
|
const blocks = [];
|
|
207
231
|
const textBoxAnchorMarkers = /* @__PURE__ */ new Map();
|
|
208
232
|
const documentCounts = buildDocumentTrackedChangeCounts(pmDoc);
|
|
@@ -270,7 +294,7 @@ function convertPMBlockSdt(node) {
|
|
|
270
294
|
if (attrs.rawEndPropertiesXml) properties.rawEndPropertiesXml = attrs.rawEndPropertiesXml;
|
|
271
295
|
if (attrs.rawSdtChildrenBeforeContent) properties.rawSdtChildrenBeforeContent = attrs.rawSdtChildrenBeforeContent;
|
|
272
296
|
if (attrs.rawSdtChildrenAfterContent) properties.rawSdtChildrenAfterContent = attrs.rawSdtChildrenAfterContent;
|
|
273
|
-
const extracted = extractBlocks(node.type.schema.node("doc", null, node.content));
|
|
297
|
+
const extracted = extractBlocks(node.type.schema.node("doc", null, node.content), "inherit");
|
|
274
298
|
return {
|
|
275
299
|
type: "blockSdt",
|
|
276
300
|
properties,
|
|
@@ -390,6 +414,7 @@ function editTextBoxAnchorInContent(content, marker, replacement) {
|
|
|
390
414
|
}
|
|
391
415
|
let nestedContent;
|
|
392
416
|
if (item?.type === "hyperlink") nestedContent = item.children;
|
|
417
|
+
else if (item?.type === "simpleField") nestedContent = item.content;
|
|
393
418
|
else if (item?.type === "inlineSdt" || item?.type === "insertion" || item?.type === "deletion" || item?.type === "moveFrom" || item?.type === "moveTo") nestedContent = item.content;
|
|
394
419
|
if (!nestedContent) continue;
|
|
395
420
|
const hadContent = nestedContent.length > 0;
|
|
@@ -639,14 +664,31 @@ function paragraphAttrsToFormatting(attrs) {
|
|
|
639
664
|
if (attrs.suppressAutoHyphens != null) f.suppressAutoHyphens = attrs.suppressAutoHyphens;
|
|
640
665
|
return f;
|
|
641
666
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
667
|
+
function createTrackedRunWrapper(type, info, child) {
|
|
668
|
+
if (type === "insertion") return {
|
|
669
|
+
type,
|
|
670
|
+
info,
|
|
671
|
+
content: [child]
|
|
672
|
+
};
|
|
673
|
+
if (type === "deletion") return {
|
|
674
|
+
type,
|
|
675
|
+
info,
|
|
676
|
+
content: [child]
|
|
677
|
+
};
|
|
678
|
+
if (type === "moveFrom") return {
|
|
679
|
+
type,
|
|
680
|
+
info,
|
|
681
|
+
content: [child]
|
|
682
|
+
};
|
|
683
|
+
return {
|
|
684
|
+
type,
|
|
685
|
+
info,
|
|
686
|
+
content: [child]
|
|
687
|
+
};
|
|
688
|
+
}
|
|
648
689
|
function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, textBoxAnchorMarkers, skipLeadingRenderedPageBreak = false) {
|
|
649
690
|
const content = [];
|
|
691
|
+
const inheritedFormatting = paragraph.type.name === "paragraph" ? expectParagraphAttrs(paragraph).defaultTextFormatting ?? void 0 : void 0;
|
|
650
692
|
const sortedEmptyHyperlinks = (emptyHyperlinks ?? []).map((attrs, order) => ({
|
|
651
693
|
attrs,
|
|
652
694
|
order
|
|
@@ -657,6 +699,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
|
|
|
657
699
|
let currentMarksKey = null;
|
|
658
700
|
let currentHyperlink = null;
|
|
659
701
|
let currentHyperlinkKey = null;
|
|
702
|
+
let currentTrackedChange;
|
|
660
703
|
const openedComments = /* @__PURE__ */ new Set();
|
|
661
704
|
const commentLastOffset = /* @__PURE__ */ new Map();
|
|
662
705
|
paragraph.forEach((node, offset) => {
|
|
@@ -685,6 +728,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
|
|
|
685
728
|
for (const commentId of nodeCommentIds) if (!openedComments.has(commentId)) toOpen.push(commentId);
|
|
686
729
|
if (toClose.length === 0 && toOpen.length === 0) return;
|
|
687
730
|
flushCurrentInline();
|
|
731
|
+
currentTrackedChange = void 0;
|
|
688
732
|
for (const commentId of toClose.toSorted((a, b) => a - b)) {
|
|
689
733
|
content.push({
|
|
690
734
|
type: "commentRangeEnd",
|
|
@@ -706,6 +750,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
|
|
|
706
750
|
if (!item || item.attrs.offset > offset) break;
|
|
707
751
|
nextEmptyHyperlink += 1;
|
|
708
752
|
flushCurrentInline();
|
|
753
|
+
currentTrackedChange = void 0;
|
|
709
754
|
content.push(createEmptyHyperlink(item.attrs));
|
|
710
755
|
}
|
|
711
756
|
};
|
|
@@ -720,8 +765,10 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
|
|
|
720
765
|
const noteRefMark = node.marks.find((m) => m.type.name === "footnoteRef");
|
|
721
766
|
const insertionMark = node.marks.find((m) => m.type.name === "insertion");
|
|
722
767
|
const deletionMark = node.marks.find((m) => m.type.name === "deletion");
|
|
768
|
+
if (!insertionMark && !deletionMark) currentTrackedChange = void 0;
|
|
723
769
|
if (node.type.name === "textBoxAnchor") {
|
|
724
770
|
flushCurrentInline();
|
|
771
|
+
currentTrackedChange = void 0;
|
|
725
772
|
if (!textBoxAnchorMarkers) return;
|
|
726
773
|
const { anchorId } = expectTextBoxAnchorAttrs(node);
|
|
727
774
|
const marker = {
|
|
@@ -763,38 +810,52 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
|
|
|
763
810
|
const changeMark = insertionMark ?? deletionMark;
|
|
764
811
|
if (!changeMark) return;
|
|
765
812
|
const changeAttrs = expectTrackedChangeMarkAttrs(changeMark);
|
|
766
|
-
const
|
|
767
|
-
if (!run) return;
|
|
768
|
-
const trackedContent = linkMark ? {
|
|
769
|
-
...createHyperlink(linkMark),
|
|
770
|
-
children: [run]
|
|
771
|
-
} : run;
|
|
813
|
+
const otherMarks = node.marks.filter((m) => m.type.name !== "insertion" && m.type.name !== "deletion");
|
|
772
814
|
const info = {
|
|
773
815
|
id: changeAttrs.revisionId,
|
|
774
816
|
author: changeAttrs.author || "Unknown"
|
|
775
817
|
};
|
|
776
818
|
if (changeAttrs.date) info.date = changeAttrs.date;
|
|
777
819
|
if (changeAttrs.initials) info.initials = changeAttrs.initials;
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
type
|
|
795
|
-
|
|
796
|
-
|
|
820
|
+
let type;
|
|
821
|
+
if (insertionMark) type = changeAttrs.moveKind === "moveTo" ? "moveTo" : "insertion";
|
|
822
|
+
else type = changeAttrs.moveKind === "moveFrom" ? "moveFrom" : "deletion";
|
|
823
|
+
const trackedChangeKey = `${type}:${JSON.stringify(info)}`;
|
|
824
|
+
if (linkMark) {
|
|
825
|
+
const linkKey = getLinkKey(linkMark);
|
|
826
|
+
if (!currentTrackedChange || currentTrackedChange.key !== trackedChangeKey || currentTrackedChange.hyperlinkKey !== linkKey) {
|
|
827
|
+
const hyperlink = createHyperlink(linkMark);
|
|
828
|
+
const wrapper = createTrackedRunWrapper(type, info, hyperlink);
|
|
829
|
+
content.push(wrapper);
|
|
830
|
+
currentTrackedChange = {
|
|
831
|
+
key: trackedChangeKey,
|
|
832
|
+
hyperlink,
|
|
833
|
+
hyperlinkKey: linkKey
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
if (node.type.name === "bookmarkBoundary") {
|
|
837
|
+
addNodeToHyperlink({
|
|
838
|
+
hyperlink: currentTrackedChange.hyperlink,
|
|
839
|
+
inheritedFormatting,
|
|
840
|
+
node
|
|
841
|
+
});
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
const run = createTrackedChangeRun({
|
|
845
|
+
inheritedFormatting,
|
|
846
|
+
marks: otherMarks,
|
|
847
|
+
node
|
|
848
|
+
});
|
|
849
|
+
if (run) currentTrackedChange.hyperlink.children.push(run);
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
currentTrackedChange = void 0;
|
|
853
|
+
const run = createTrackedChangeRun({
|
|
854
|
+
inheritedFormatting,
|
|
855
|
+
marks: otherMarks,
|
|
856
|
+
node
|
|
797
857
|
});
|
|
858
|
+
if (run) content.push(createTrackedRunWrapper(type, info, run));
|
|
798
859
|
return;
|
|
799
860
|
}
|
|
800
861
|
if (noteRefMark && !linkMark) {
|
|
@@ -809,16 +870,38 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
|
|
|
809
870
|
currentHyperlink = createHyperlink(linkMark);
|
|
810
871
|
currentHyperlinkKey = linkKey;
|
|
811
872
|
}
|
|
812
|
-
addNodeToHyperlink(
|
|
873
|
+
addNodeToHyperlink({
|
|
874
|
+
hyperlink: currentHyperlink,
|
|
875
|
+
inheritedFormatting,
|
|
876
|
+
node
|
|
877
|
+
});
|
|
813
878
|
return;
|
|
814
879
|
}
|
|
815
880
|
if (currentHyperlink) flushCurrentInline();
|
|
816
|
-
if (node.
|
|
881
|
+
if (node.type.name === "bookmarkBoundary") {
|
|
882
|
+
flushCurrentInline();
|
|
883
|
+
const attrs = expectBookmarkBoundaryAttrs(node);
|
|
884
|
+
if (attrs.type === "start") content.push({
|
|
885
|
+
type: "bookmarkStart",
|
|
886
|
+
id: attrs.id,
|
|
887
|
+
name: attrs.name,
|
|
888
|
+
...attrs.colFirst !== void 0 ? { colFirst: attrs.colFirst } : {},
|
|
889
|
+
...attrs.colLast !== void 0 ? { colLast: attrs.colLast } : {}
|
|
890
|
+
});
|
|
891
|
+
else content.push({
|
|
892
|
+
type: "bookmarkEnd",
|
|
893
|
+
id: attrs.id
|
|
894
|
+
});
|
|
895
|
+
} else if (node.isText) {
|
|
817
896
|
const marksKey = getMarksKey(node.marks);
|
|
818
897
|
if (currentRun && currentMarksKey === marksKey) appendTextToRun(currentRun, node.text || "");
|
|
819
898
|
else {
|
|
820
899
|
if (currentRun) content.push(currentRun);
|
|
821
|
-
currentRun = createRunFromText(
|
|
900
|
+
currentRun = createRunFromText({
|
|
901
|
+
inheritedFormatting,
|
|
902
|
+
marks: node.marks,
|
|
903
|
+
text: node.text || ""
|
|
904
|
+
});
|
|
822
905
|
currentMarksKey = marksKey;
|
|
823
906
|
}
|
|
824
907
|
} else if (node.type.name === "symbol") {
|
|
@@ -839,9 +922,12 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
|
|
|
839
922
|
} else if (node.type.name === "renderedPageBreak") {
|
|
840
923
|
flushCurrentInline();
|
|
841
924
|
content.push(createRenderedPageBreakRun());
|
|
842
|
-
} else if (node.type.name === "field") {
|
|
925
|
+
} else if (node.type.name === "field" || node.type.name === "structuredField") {
|
|
843
926
|
flushCurrentInline();
|
|
844
|
-
content.push(createFieldFromNode(node,
|
|
927
|
+
content.push(createFieldFromNode(node, {
|
|
928
|
+
marks: node.marks,
|
|
929
|
+
textBoxAnchorMarkers
|
|
930
|
+
}));
|
|
845
931
|
} else if (node.type.name === "sdt") {
|
|
846
932
|
flushCurrentInline();
|
|
847
933
|
content.push(createInlineSdtFromNode(node, textBoxAnchorMarkers));
|
|
@@ -880,11 +966,11 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
|
|
|
880
966
|
});
|
|
881
967
|
return content;
|
|
882
968
|
}
|
|
883
|
-
function createTrackedChangeRun(
|
|
969
|
+
function createTrackedChangeRun({ inheritedFormatting, marks, node }) {
|
|
884
970
|
const noteRefMark = marks.find((mark) => mark.type.name === "footnoteRef");
|
|
885
971
|
if (noteRefMark) return createNoteReferenceRun(noteRefMark, marks);
|
|
886
972
|
if (node.isText) {
|
|
887
|
-
const formatting = marksToTextFormatting(marks);
|
|
973
|
+
const formatting = marksToTextFormatting(marks, { inheritedFormatting });
|
|
888
974
|
const run = {
|
|
889
975
|
type: "run",
|
|
890
976
|
content: node.text ? [{
|
|
@@ -989,10 +1075,22 @@ function createHyperlink(linkMark) {
|
|
|
989
1075
|
if (attrs.rId) hyperlink.rId = attrs.rId;
|
|
990
1076
|
return hyperlink;
|
|
991
1077
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1078
|
+
function addNodeToHyperlink({ hyperlink, inheritedFormatting, node }) {
|
|
1079
|
+
if (node.type.name === "bookmarkBoundary") {
|
|
1080
|
+
const attrs = expectBookmarkBoundaryAttrs(node);
|
|
1081
|
+
if (attrs.type === "start") hyperlink.children.push({
|
|
1082
|
+
type: "bookmarkStart",
|
|
1083
|
+
id: attrs.id,
|
|
1084
|
+
name: attrs.name,
|
|
1085
|
+
...attrs.colFirst !== void 0 ? { colFirst: attrs.colFirst } : {},
|
|
1086
|
+
...attrs.colLast !== void 0 ? { colLast: attrs.colLast } : {}
|
|
1087
|
+
});
|
|
1088
|
+
else hyperlink.children.push({
|
|
1089
|
+
type: "bookmarkEnd",
|
|
1090
|
+
id: attrs.id
|
|
1091
|
+
});
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
996
1094
|
const noteRefMark = node.marks.find((m) => m.type.name === "footnoteRef");
|
|
997
1095
|
if (noteRefMark) {
|
|
998
1096
|
hyperlink.children.push(createNoteReferenceRun(noteRefMark, node.marks));
|
|
@@ -1000,7 +1098,11 @@ function addNodeToHyperlink(hyperlink, node) {
|
|
|
1000
1098
|
}
|
|
1001
1099
|
const nonLinkMarks = node.marks.filter((m) => m.type.name !== "hyperlink");
|
|
1002
1100
|
if (node.isText && node.text) {
|
|
1003
|
-
const run = createRunFromText(
|
|
1101
|
+
const run = createRunFromText({
|
|
1102
|
+
inheritedFormatting,
|
|
1103
|
+
marks: nonLinkMarks,
|
|
1104
|
+
text: node.text
|
|
1105
|
+
});
|
|
1004
1106
|
hyperlink.children.push(run);
|
|
1005
1107
|
return;
|
|
1006
1108
|
}
|
|
@@ -1044,11 +1146,8 @@ function createNoteReferenceRun(noteRefMark, marks) {
|
|
|
1044
1146
|
if (vertAlign) run.formatting = { vertAlign };
|
|
1045
1147
|
return run;
|
|
1046
1148
|
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
*/
|
|
1050
|
-
function createRunFromText(text, marks) {
|
|
1051
|
-
const formatting = getRunFormattingFromMarks(marks);
|
|
1149
|
+
function createRunFromText({ inheritedFormatting, marks, text }) {
|
|
1150
|
+
const formatting = getRunFormattingFromMarks(marks, { inheritedFormatting });
|
|
1052
1151
|
const run = {
|
|
1053
1152
|
type: "run",
|
|
1054
1153
|
content: [{
|
|
@@ -1082,9 +1181,9 @@ function restoreRunPropertyChanges(run, marks) {
|
|
|
1082
1181
|
if (changes.length === 0) return;
|
|
1083
1182
|
run.propertyChanges = [...changes];
|
|
1084
1183
|
}
|
|
1085
|
-
function getRunFormattingFromMarks(marks) {
|
|
1184
|
+
function getRunFormattingFromMarks(marks, options) {
|
|
1086
1185
|
if (!marks || marks.length === 0) return;
|
|
1087
|
-
const formatting = marksToTextFormatting(marks);
|
|
1186
|
+
const formatting = marksToTextFormatting(marks, options);
|
|
1088
1187
|
return Object.keys(formatting).length > 0 ? formatting : void 0;
|
|
1089
1188
|
}
|
|
1090
1189
|
/**
|
|
@@ -1138,13 +1237,10 @@ function createTabRun(node, marks) {
|
|
|
1138
1237
|
if (formatting) run.formatting = formatting;
|
|
1139
1238
|
return run;
|
|
1140
1239
|
}
|
|
1141
|
-
|
|
1142
|
-
* Create a SimpleField or ComplexField from a PM field node
|
|
1143
|
-
*/
|
|
1144
|
-
function createFieldFromNode(node, marks) {
|
|
1240
|
+
function createFieldFromNode(node, { marks, textBoxAnchorMarkers }) {
|
|
1145
1241
|
const attrs = expectFieldAttrs(node);
|
|
1146
1242
|
const formatting = marks && marks.length > 0 ? marksToTextFormatting(marks) : void 0;
|
|
1147
|
-
let displayText = attrs.displayText
|
|
1243
|
+
let displayText = attrs.displayText ?? "";
|
|
1148
1244
|
if (!displayText) switch (attrs.fieldType) {
|
|
1149
1245
|
case "PAGE":
|
|
1150
1246
|
displayText = "1";
|
|
@@ -1164,13 +1260,15 @@ function createFieldFromNode(node, marks) {
|
|
|
1164
1260
|
}],
|
|
1165
1261
|
...formatting && Object.keys(formatting).length > 0 ? { formatting } : {}
|
|
1166
1262
|
};
|
|
1263
|
+
const extractedContent = extractParagraphContent(node, void 0, void 0, textBoxAnchorMarkers).filter((content) => content.type === "run" || content.type === "hyperlink");
|
|
1264
|
+
const fieldContent = extractedContent.length > 0 ? synchronizeFieldDisplayText(extractedContent, displayText, displayRun) : [];
|
|
1167
1265
|
if (attrs.fieldKind === "complex") {
|
|
1168
1266
|
const complex = {
|
|
1169
1267
|
type: "complexField",
|
|
1170
1268
|
instruction: attrs.instruction,
|
|
1171
1269
|
fieldType: attrs.fieldType,
|
|
1172
1270
|
fieldCode: [],
|
|
1173
|
-
fieldResult: [displayRun]
|
|
1271
|
+
fieldResult: fieldContent.length > 0 ? fieldContent.filter((content) => content.type === "run") : [displayRun]
|
|
1174
1272
|
};
|
|
1175
1273
|
if (attrs.fldLock) complex.fldLock = true;
|
|
1176
1274
|
if (attrs.dirty) complex.dirty = true;
|
|
@@ -1180,12 +1278,45 @@ function createFieldFromNode(node, marks) {
|
|
|
1180
1278
|
type: "simpleField",
|
|
1181
1279
|
instruction: attrs.instruction,
|
|
1182
1280
|
fieldType: attrs.fieldType,
|
|
1183
|
-
content: [displayRun]
|
|
1281
|
+
content: fieldContent.length > 0 ? fieldContent : [displayRun]
|
|
1184
1282
|
};
|
|
1185
1283
|
if (attrs.fldLock) simple.fldLock = true;
|
|
1186
1284
|
if (attrs.dirty) simple.dirty = true;
|
|
1187
1285
|
return simple;
|
|
1188
1286
|
}
|
|
1287
|
+
const synchronizeFieldDisplayText = (content, displayText, fallbackRun) => {
|
|
1288
|
+
let currentText = "";
|
|
1289
|
+
const visitRuns = (visit) => {
|
|
1290
|
+
for (const child of content) {
|
|
1291
|
+
if (child.type === "run") {
|
|
1292
|
+
visit(child);
|
|
1293
|
+
continue;
|
|
1294
|
+
}
|
|
1295
|
+
for (const hyperlinkChild of child.children) if (hyperlinkChild.type === "run") visit(hyperlinkChild);
|
|
1296
|
+
}
|
|
1297
|
+
};
|
|
1298
|
+
visitRuns((run) => {
|
|
1299
|
+
for (const runContent of run.content) if (runContent.type === "text") currentText += runContent.text;
|
|
1300
|
+
});
|
|
1301
|
+
if (currentText === displayText) return content;
|
|
1302
|
+
let replacedText = false;
|
|
1303
|
+
visitRuns((run) => {
|
|
1304
|
+
for (const runContent of run.content) {
|
|
1305
|
+
if (runContent.type !== "text") continue;
|
|
1306
|
+
runContent.text = replacedText ? "" : displayText;
|
|
1307
|
+
replacedText = true;
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
if (replacedText) return content;
|
|
1311
|
+
const hyperlink = content.find((child) => child.type === "hyperlink");
|
|
1312
|
+
if (!hyperlink) {
|
|
1313
|
+
content.push(fallbackRun);
|
|
1314
|
+
return content;
|
|
1315
|
+
}
|
|
1316
|
+
const firstEnd = hyperlink.children.findIndex((child) => child.type === "bookmarkEnd");
|
|
1317
|
+
hyperlink.children.splice(firstEnd < 0 ? hyperlink.children.length : firstEnd, 0, fallbackRun);
|
|
1318
|
+
return content;
|
|
1319
|
+
};
|
|
1189
1320
|
/**
|
|
1190
1321
|
* Create a MathEquation from a PM math node
|
|
1191
1322
|
*/
|
|
@@ -1354,11 +1485,9 @@ function createShapeRun(node) {
|
|
|
1354
1485
|
}]
|
|
1355
1486
|
};
|
|
1356
1487
|
}
|
|
1357
|
-
|
|
1358
|
-
* Convert ProseMirror marks to TextFormatting
|
|
1359
|
-
*/
|
|
1360
|
-
function marksToTextFormatting(marks) {
|
|
1488
|
+
function marksToTextFormatting(marks, options) {
|
|
1361
1489
|
const formatting = {};
|
|
1490
|
+
let directOverrideFormatting;
|
|
1362
1491
|
let characterStyleRPr;
|
|
1363
1492
|
let runFormattingOverrideMark;
|
|
1364
1493
|
for (const mark of marks) switch (mark.type.name) {
|
|
@@ -1483,8 +1612,18 @@ function marksToTextFormatting(marks) {
|
|
|
1483
1612
|
}
|
|
1484
1613
|
default: break;
|
|
1485
1614
|
}
|
|
1486
|
-
if (runFormattingOverrideMark)
|
|
1487
|
-
|
|
1615
|
+
if (runFormattingOverrideMark) {
|
|
1616
|
+
const overrideAttrs = expectRunFormattingOverrideMarkAttrs(runFormattingOverrideMark);
|
|
1617
|
+
applyRunFormattingOverrideAttrs(formatting, overrideAttrs);
|
|
1618
|
+
directOverrideFormatting = {};
|
|
1619
|
+
applyRunFormattingOverrideAttrs(directOverrideFormatting, overrideAttrs);
|
|
1620
|
+
}
|
|
1621
|
+
if (characterStyleRPr) return subtractCharacterStyleFormatting({
|
|
1622
|
+
directOverrideFormatting,
|
|
1623
|
+
formatting,
|
|
1624
|
+
inheritedFormatting: options?.inheritedFormatting,
|
|
1625
|
+
styleRPr: characterStyleRPr
|
|
1626
|
+
});
|
|
1488
1627
|
return formatting;
|
|
1489
1628
|
}
|
|
1490
1629
|
/**
|
|
@@ -1509,35 +1648,29 @@ const NEGATABLE_STYLE_KEYS = [
|
|
|
1509
1648
|
["outline", null],
|
|
1510
1649
|
["rtl", null]
|
|
1511
1650
|
];
|
|
1512
|
-
|
|
1513
|
-
* Drop run formatting values that the run's character style already provides
|
|
1514
|
-
* (the `w:rStyle` reference re-imposes them on load), so a styled run
|
|
1515
|
-
* serializes back to a style reference instead of baked direct formatting.
|
|
1516
|
-
*
|
|
1517
|
-
* `styleRPr` is the load-time snapshot from the characterStyle mark, captured
|
|
1518
|
-
* in the same normal form this module produces from marks, so value equality
|
|
1519
|
-
* is a faithful "came from the style and is unchanged" check. Values that
|
|
1520
|
-
* differ (user edits, direct overrides from the source document) stay as
|
|
1521
|
-
* direct formatting, which wins over the style per the OOXML cascade.
|
|
1522
|
-
*
|
|
1523
|
-
* When the user *removes* a boolean property the style supplied (e.g. toggling
|
|
1524
|
-
* off bold on text whose `w:rStyle` is bold), that key is no longer present in
|
|
1525
|
-
* `formatting`, so the subtraction loop above never sees it. Without a counter,
|
|
1526
|
-
* the run keeps the style reference and Word re-applies the removed formatting
|
|
1527
|
-
* on load. The second pass emits an explicit negative override (`false`) for
|
|
1528
|
-
* each negatable boolean the style set to `true` but the run no longer carries.
|
|
1529
|
-
*/
|
|
1530
|
-
function subtractCharacterStyleFormatting(formatting, styleRPr) {
|
|
1651
|
+
function subtractCharacterStyleFormatting({ directOverrideFormatting, formatting, inheritedFormatting, styleRPr }) {
|
|
1531
1652
|
const result = {};
|
|
1653
|
+
const effectiveStyleFormatting = cascadeStyleTextFormatting([{
|
|
1654
|
+
formatting: inheritedFormatting,
|
|
1655
|
+
type: "direct"
|
|
1656
|
+
}, {
|
|
1657
|
+
formatting: styleRPr,
|
|
1658
|
+
type: "style"
|
|
1659
|
+
}]).formatting;
|
|
1532
1660
|
for (const key of Object.keys(formatting)) {
|
|
1533
1661
|
const value = formatting[key];
|
|
1534
1662
|
if (value === void 0) continue;
|
|
1535
|
-
|
|
1663
|
+
if (directOverrideFormatting?.[key] !== void 0) {
|
|
1664
|
+
result[key] = value;
|
|
1665
|
+
continue;
|
|
1666
|
+
}
|
|
1667
|
+
const styleValue = key === "styleId" ? void 0 : effectiveStyleFormatting?.[key];
|
|
1668
|
+
if ((key === "boldCs" || key === "italicCs") && styleValue === false && value === true) continue;
|
|
1536
1669
|
if (styleValue !== void 0 && JSON.stringify(value) === JSON.stringify(styleValue)) continue;
|
|
1537
1670
|
result[key] = value;
|
|
1538
1671
|
}
|
|
1539
1672
|
for (const [key, csKey] of NEGATABLE_STYLE_KEYS) {
|
|
1540
|
-
if (
|
|
1673
|
+
if (effectiveStyleFormatting?.[key] !== true || formatting[key] !== void 0) continue;
|
|
1541
1674
|
result[key] = false;
|
|
1542
1675
|
if (csKey !== null) result[csKey] = false;
|
|
1543
1676
|
}
|
|
@@ -22,7 +22,10 @@ declare function standaloneTableCellToProseMirror(cell: document_d_exports.Table
|
|
|
22
22
|
/**
|
|
23
23
|
* Convert TextFormatting to ProseMirror marks
|
|
24
24
|
*/
|
|
25
|
-
|
|
25
|
+
type TextFormattingToMarksOptions = {
|
|
26
|
+
overrideFormatting: document_d_exports.TextFormatting | undefined;
|
|
27
|
+
};
|
|
28
|
+
declare function textFormattingToMarks(formatting: document_d_exports.TextFormatting | undefined, options?: TextFormattingToMarksOptions): ReturnType<typeof schema.mark>[];
|
|
26
29
|
/**
|
|
27
30
|
* Convert HeaderFooter content (array of Paragraph/Table blocks) to a ProseMirror document.
|
|
28
31
|
* Used for editing headers/footers in their own ProseMirror editor and for
|