@stll/folio-core 0.33.1 → 0.34.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.d.ts +15 -0
- package/dist/ai-edits/apply.js +271 -48
- package/dist/ai-edits/headless.d.ts +47 -3
- package/dist/ai-edits/headless.js +53 -3
- package/dist/ai-edits/index.d.ts +1 -1
- package/dist/ai-edits/snapshot.d.ts +19 -1
- package/dist/ai-edits/snapshot.js +49 -5
- package/dist/ai-edits/table-geometry.d.ts +56 -0
- package/dist/ai-edits/table-geometry.js +217 -0
- package/dist/ai-edits/table-row-column-mutations.d.ts +34 -16
- package/dist/ai-edits/table-row-column-mutations.js +12 -4
- package/dist/ai-edits/table-template.d.ts +60 -0
- package/dist/ai-edits/table-template.js +176 -0
- package/dist/ai-edits/types.d.ts +13 -6
- package/dist/compare/__fixtures__/body-sequence.d.ts +61 -2
- package/dist/compare/__fixtures__/body-sequence.js +94 -6
- package/dist/compare/compare.d.ts +14 -7
- package/dist/compare/compare.js +136 -38
- package/dist/compare/formatting.d.ts +1 -1
- package/dist/compare/formatting.js +38 -9
- package/dist/compare/plan.d.ts +31 -1
- package/dist/compare/plan.js +233 -66
- package/dist/compare/types.d.ts +9 -7
- package/dist/compare/types.js +7 -5
- package/dist/compare/verification.d.ts +31 -12
- package/dist/compare/verification.js +106 -18
- package/dist/compat/eigenpal.d.ts +4 -4
- package/dist/compat/eigenpal.js +2 -2
- package/dist/controller/headerFooterEditorManager.js +11 -9
- package/dist/controller/layoutPipeline.js +24 -3
- package/dist/display-list/build/watermarkPrimitives.js +15 -3
- package/dist/display-list/primitives.d.ts +1 -1
- package/dist/document-operations.d.ts +10 -1
- package/dist/document-operations.js +33 -5
- package/dist/docx/appVersionNormalization.d.ts +49 -0
- package/dist/docx/appVersionNormalization.js +74 -0
- package/dist/docx/blockContentParser.js +3 -2
- package/dist/docx/drawingUtils.js +4 -3
- package/dist/docx/headerFooterParser.js +8 -14
- package/dist/docx/paragraphParser.js +48 -2
- package/dist/docx/rezip.d.ts +10 -4
- package/dist/docx/rezip.js +54 -18
- package/dist/docx/runParser.js +9 -8
- package/dist/docx/sdtProperties.js +4 -3
- package/dist/docx/selectiveSave.js +7 -6
- package/dist/docx/serializer/commentSerializer.d.ts +1 -1
- package/dist/docx/serializer/commentSerializer.js +43 -19
- package/dist/docx/serializer/documentSerializer.d.ts +3 -1
- package/dist/docx/serializer/documentSerializer.js +42 -78
- package/dist/docx/serializer/fontTableSerializer.js +8 -5
- package/dist/docx/serializer/headerFooterSerializer.d.ts +4 -1
- package/dist/docx/serializer/headerFooterSerializer.js +55 -31
- package/dist/docx/serializer/noteSerializer.js +34 -30
- package/dist/docx/serializer/numberingSerializer.js +8 -4
- package/dist/docx/serializer/paragraphSerializer.d.ts +1 -1
- package/dist/docx/serializer/paragraphSerializer.js +22 -12
- package/dist/docx/serializer/partNamespaces.d.ts +78 -0
- package/dist/docx/serializer/partNamespaces.js +324 -0
- package/dist/docx/serializer/runSerializer.js +1 -1
- package/dist/docx/serializer/settingsSerializer.js +8 -2
- package/dist/docx/serializer/stylesSerializer.js +8 -5
- package/dist/docx/serializer/tableSerializer.js +83 -18
- package/dist/docx/serializer/themeSerializer.js +10 -2
- package/dist/docx/server/build.d.ts +1 -1
- package/dist/docx/settingsParser.js +3 -0
- package/dist/docx/strictValueEncodings.gen.d.ts +15 -0
- package/dist/docx/strictValueEncodings.gen.js +275 -0
- package/dist/docx/tableParser.d.ts +0 -6
- package/dist/docx/tableParser.js +52 -7
- package/dist/docx/transitionalSpelling.d.ts +23 -0
- package/dist/docx/transitionalSpelling.js +36 -0
- package/dist/docx/universalMeasure.d.ts +20 -0
- package/dist/docx/universalMeasure.js +32 -0
- package/dist/docx/verbatimCapture.d.ts +20 -0
- package/dist/docx/verbatimCapture.js +131 -0
- package/dist/docx/vmlImageParser.js +4 -3
- package/dist/docx/watermarkParser.d.ts +2 -4
- package/dist/docx/watermarkParser.js +8 -9
- package/dist/docx/xmlParser.d.ts +23 -2
- package/dist/docx/xmlParser.js +43 -11
- package/dist/headless-layout.js +14 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +2 -2
- package/dist/layout-bridge/convert/footnoteLayout.js +23 -10
- package/dist/layout-bridge/convert/headerFooterLayout.js +13 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +96 -13
- package/dist/layout-engine/index.js +11 -4
- package/dist/layout-engine/justifiedLineFit.d.ts +4 -4
- package/dist/layout-engine/justifiedLineFit.js +4 -4
- package/dist/layout-engine/measure/lineBreakProvider.js +1 -0
- package/dist/layout-engine/measure/measureBlocks.js +1 -1
- package/dist/layout-engine/measure/measureParagraph.js +29 -29
- package/dist/layout-painter/renderPage.js +6 -1
- package/dist/layout-painter/renderParagraph.js +18 -8
- package/dist/layout-painter/renderWatermark.js +11 -4
- package/dist/model.d.ts +3 -3
- package/dist/model.js +2 -2
- package/dist/prosemirror/attrs/index.js +11 -0
- package/dist/prosemirror/commands/comments.js +24 -3
- package/dist/prosemirror/containerFinalParagraph.d.ts +47 -0
- package/dist/prosemirror/containerFinalParagraph.js +92 -0
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +8 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +47 -9
- package/dist/prosemirror/conversion/toProseDoc.js +61 -14
- package/dist/prosemirror/extensions/core/DocExtension.js +7 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
- package/dist/prosemirror/extensions/marks/RunFormattingOverrideExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +5 -0
- package/dist/prosemirror/schema/marks.d.ts +3 -9
- package/dist/prosemirror/schema/nodes.d.ts +22 -0
- package/dist/server.d.ts +1 -1
- package/dist/types/block-id.d.ts +12 -1
- package/dist/types/block-id.js +17 -1
- package/dist/utils/canonicalJson.d.ts +14 -0
- package/dist/utils/canonicalJson.js +19 -0
- package/dist/utils/fontResolver.js +51 -0
- package/dist/utils/formatToStyle.d.ts +1 -1
- package/dist/utils/formatToStyle.js +41 -1
- package/dist/watermark/index.js +7 -0
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { expectParagraphAttrs, expectRunPropertyChangeMarkAttrs } from "../attrs/index.js";
|
|
2
|
+
import { paragraphEndsItsContainer } from "../containerFinalParagraph.js";
|
|
2
3
|
import { textFormattingToMarks } from "../conversion/toProseDoc.js";
|
|
3
4
|
import { markStructuralChange } from "../extensions/features/ParagraphChangeTrackerExtension.js";
|
|
4
5
|
import { getFolioNodeRevisionCarriers } from "../revisionCarriers.js";
|
|
@@ -61,6 +62,7 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
61
62
|
const keepType = mode === "accept" ? insertionType : deletionType;
|
|
62
63
|
const removeType = mode === "accept" ? deletionType : insertionType;
|
|
63
64
|
const revisionSet = revisionIds === void 0 ? null : new Set(revisionIds);
|
|
65
|
+
const removeKeptMarksInBulk = revisionSet === null && keepType !== void 0;
|
|
64
66
|
const matchesRevision = (mark) => revisionSet === null || typeof mark.attrs["revisionId"] === "number" && revisionSet.has(mark.attrs["revisionId"]);
|
|
65
67
|
if (dispatch) {
|
|
66
68
|
const tr = state.tr;
|
|
@@ -138,10 +140,29 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
138
140
|
from: rangeFrom,
|
|
139
141
|
to: rangeTo
|
|
140
142
|
});
|
|
141
|
-
|
|
143
|
+
if (!removeKeptMarksInBulk) {
|
|
144
|
+
for (const mark of node.marks) if (keepType && mark.type === keepType && matchesRevision(mark)) tr.removeMark(rangeFrom, rangeTo, mark);
|
|
145
|
+
}
|
|
142
146
|
return true;
|
|
143
147
|
});
|
|
144
|
-
|
|
148
|
+
if (removeKeptMarksInBulk) tr.removeMark(from, to, keepType);
|
|
149
|
+
let rangesToDelete = deleteRanges;
|
|
150
|
+
if (revisionSet === null) {
|
|
151
|
+
const coalescedDeleteRanges = [];
|
|
152
|
+
for (const range of deleteRanges) {
|
|
153
|
+
const previous = coalescedDeleteRanges.at(-1);
|
|
154
|
+
if (previous && range.from <= previous.to) {
|
|
155
|
+
previous.to = Math.max(previous.to, range.to);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
coalescedDeleteRanges.push({
|
|
159
|
+
from: range.from,
|
|
160
|
+
to: range.to
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
rangesToDelete = coalescedDeleteRanges;
|
|
164
|
+
}
|
|
165
|
+
for (const range of rangesToDelete.toReversed()) tr.delete(range.from, range.to);
|
|
145
166
|
pPrMarkOps.sort((a, b) => b.paragraphPos - a.paragraphPos);
|
|
146
167
|
for (const op of pPrMarkOps) {
|
|
147
168
|
const mappedPos = tr.mapping.map(op.paragraphPos);
|
|
@@ -157,7 +178,7 @@ function resolveChange(from, to, mode, revisionIds) {
|
|
|
157
178
|
const resolved = tr.doc.resolve(mappedPos);
|
|
158
179
|
const previous = resolved.nodeBefore;
|
|
159
180
|
const sectionCanMoveBack = !carriesSection(paragraph) || previous?.type.name === paragraph.type.name && !carriesSection(previous);
|
|
160
|
-
const endsItsContainer = resolved
|
|
181
|
+
const endsItsContainer = paragraphEndsItsContainer(resolved, paragraph.type.name);
|
|
161
182
|
const canGo = op.markWasAdded || !endsItsContainer;
|
|
162
183
|
if (sectionCanMoveBack && holdsNoContent(paragraph) && canGo && resolved.parent.childCount > 1) {
|
|
163
184
|
if (carriesSection(paragraph) && previous) tr.setNodeMarkup(mappedPos - previous.nodeSize, void 0, {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Node, ResolvedPos } from "prosemirror-model";
|
|
2
|
+
//#region src/prosemirror/containerFinalParagraph.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Whether the paragraph starting at `at` is the one its container ENDS with,
|
|
5
|
+
* which is the one place a paragraph mark cannot carry a revision.
|
|
6
|
+
*
|
|
7
|
+
* A deleted mark asks a reader to join the paragraph it ends with the one
|
|
8
|
+
* after it, and an inserted mark says that break was added, so rejecting it
|
|
9
|
+
* closes the paragraph back over the next one. A body, a table cell, a header
|
|
10
|
+
* or footer, a note and a text box each end with a paragraph that nothing
|
|
11
|
+
* follows, so neither direction can be resolved there: a consumer is left with
|
|
12
|
+
* a revision it can only ignore, and the redline no longer resolves to the two
|
|
13
|
+
* documents it was written from.
|
|
14
|
+
*
|
|
15
|
+
* A paragraph before a TABLE is not one of those: the table is a following
|
|
16
|
+
* sibling, so the paragraph does not end anything and carries its own mark
|
|
17
|
+
* like any other.
|
|
18
|
+
*/
|
|
19
|
+
declare const paragraphEndsItsContainer: (at: ResolvedPos, paragraphTypeName: string) => boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Every paragraph a container ENDS with in `doc`, with its position.
|
|
22
|
+
*
|
|
23
|
+
* One walk for the whole document: asking the question of each paragraph in
|
|
24
|
+
* turn costs a scan of its siblings each time, which is quadratic in a body
|
|
25
|
+
* whose paragraphs a batch has just filled.
|
|
26
|
+
*/
|
|
27
|
+
declare const finalParagraphsOf: (doc: Node, paragraphTypeName: string) => {
|
|
28
|
+
position: number;
|
|
29
|
+
node: Node;
|
|
30
|
+
}[];
|
|
31
|
+
/**
|
|
32
|
+
* The paragraph an added break can rotate BACK onto from the one at `at`: the
|
|
33
|
+
* paragraph the run of inserted ones was appended after.
|
|
34
|
+
*
|
|
35
|
+
* The walk crosses the inserted paragraphs — their own marks stay where they
|
|
36
|
+
* are, and only which paragraph is left markless changes — and stops at the
|
|
37
|
+
* first one whose mark is free. `null` when there is none: a table in between,
|
|
38
|
+
* which no mark joins across; a paragraph whose mark says something else,
|
|
39
|
+
* which the rotation must not overwrite; or a container whose every paragraph
|
|
40
|
+
* is new.
|
|
41
|
+
*/
|
|
42
|
+
declare const addedBreakCarrierBefore: (at: ResolvedPos, paragraphTypeName: string) => {
|
|
43
|
+
position: number;
|
|
44
|
+
node: Node;
|
|
45
|
+
} | null;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { addedBreakCarrierBefore, finalParagraphsOf, paragraphEndsItsContainer };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
//#region src/prosemirror/containerFinalParagraph.ts
|
|
2
|
+
/**
|
|
3
|
+
* A node the FILE holds as a child of the container it appears in.
|
|
4
|
+
*
|
|
5
|
+
* The editor keeps a text box as a block-level sibling of the paragraph that
|
|
6
|
+
* anchors it; the file hangs it off that paragraph's own run, so it is not a
|
|
7
|
+
* child of the container at all. A paragraph and a table are children in both.
|
|
8
|
+
*/
|
|
9
|
+
const isAContainerChild = (node, paragraphTypeName) => node.type.name === paragraphTypeName || node.type.spec["tableRole"] === "table";
|
|
10
|
+
/** Whether every child from `fromIndex` on is one the file does not hold here. */
|
|
11
|
+
const nothingFollowsIn = (parent, fromIndex, paragraphTypeName) => {
|
|
12
|
+
for (let index = fromIndex; index < parent.childCount; index++) if (isAContainerChild(parent.child(index), paragraphTypeName)) return false;
|
|
13
|
+
return true;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Whether the paragraph starting at `at` is the one its container ENDS with,
|
|
17
|
+
* which is the one place a paragraph mark cannot carry a revision.
|
|
18
|
+
*
|
|
19
|
+
* A deleted mark asks a reader to join the paragraph it ends with the one
|
|
20
|
+
* after it, and an inserted mark says that break was added, so rejecting it
|
|
21
|
+
* closes the paragraph back over the next one. A body, a table cell, a header
|
|
22
|
+
* or footer, a note and a text box each end with a paragraph that nothing
|
|
23
|
+
* follows, so neither direction can be resolved there: a consumer is left with
|
|
24
|
+
* a revision it can only ignore, and the redline no longer resolves to the two
|
|
25
|
+
* documents it was written from.
|
|
26
|
+
*
|
|
27
|
+
* A paragraph before a TABLE is not one of those: the table is a following
|
|
28
|
+
* sibling, so the paragraph does not end anything and carries its own mark
|
|
29
|
+
* like any other.
|
|
30
|
+
*/
|
|
31
|
+
const paragraphEndsItsContainer = (at, paragraphTypeName) => nothingFollowsIn(at.parent, at.index() + 1, paragraphTypeName);
|
|
32
|
+
/**
|
|
33
|
+
* Every paragraph a container ENDS with in `doc`, with its position.
|
|
34
|
+
*
|
|
35
|
+
* One walk for the whole document: asking the question of each paragraph in
|
|
36
|
+
* turn costs a scan of its siblings each time, which is quadratic in a body
|
|
37
|
+
* whose paragraphs a batch has just filled.
|
|
38
|
+
*/
|
|
39
|
+
const finalParagraphsOf = (doc, paragraphTypeName) => {
|
|
40
|
+
const found = [];
|
|
41
|
+
const collect = (node, contentStart) => {
|
|
42
|
+
let last = null;
|
|
43
|
+
node.forEach((child, offset) => {
|
|
44
|
+
const position = contentStart + offset;
|
|
45
|
+
if (child.type.name === paragraphTypeName) last = {
|
|
46
|
+
position,
|
|
47
|
+
node: child
|
|
48
|
+
};
|
|
49
|
+
else if (isAContainerChild(child, paragraphTypeName)) last = null;
|
|
50
|
+
if (!child.isTextblock && child.childCount > 0) collect(child, position + 1);
|
|
51
|
+
});
|
|
52
|
+
if (last !== null) found.push(last);
|
|
53
|
+
};
|
|
54
|
+
collect(doc, 0);
|
|
55
|
+
return found;
|
|
56
|
+
};
|
|
57
|
+
/** A paragraph's mark, when it says the break was ADDED. */
|
|
58
|
+
const marksAnAddedBreak = (node) => {
|
|
59
|
+
const mark = node.attrs["pPrMark"];
|
|
60
|
+
if (typeof mark !== "object" || mark === null || !("kind" in mark)) return false;
|
|
61
|
+
return mark.kind === "ins" || mark.kind === "moveTo";
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* The paragraph an added break can rotate BACK onto from the one at `at`: the
|
|
65
|
+
* paragraph the run of inserted ones was appended after.
|
|
66
|
+
*
|
|
67
|
+
* The walk crosses the inserted paragraphs — their own marks stay where they
|
|
68
|
+
* are, and only which paragraph is left markless changes — and stops at the
|
|
69
|
+
* first one whose mark is free. `null` when there is none: a table in between,
|
|
70
|
+
* which no mark joins across; a paragraph whose mark says something else,
|
|
71
|
+
* which the rotation must not overwrite; or a container whose every paragraph
|
|
72
|
+
* is new.
|
|
73
|
+
*/
|
|
74
|
+
const addedBreakCarrierBefore = (at, paragraphTypeName) => {
|
|
75
|
+
let position = at.pos;
|
|
76
|
+
for (let index = at.index() - 1; index >= 0; index--) {
|
|
77
|
+
const sibling = at.parent.child(index);
|
|
78
|
+
position -= sibling.nodeSize;
|
|
79
|
+
if (sibling.type.name !== paragraphTypeName) {
|
|
80
|
+
if (isAContainerChild(sibling, paragraphTypeName)) return null;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (sibling.attrs["pPrMark"] == null) return {
|
|
84
|
+
position,
|
|
85
|
+
node: sibling
|
|
86
|
+
};
|
|
87
|
+
if (!marksAnAddedBreak(sibling)) return null;
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
};
|
|
91
|
+
//#endregion
|
|
92
|
+
export { addedBreakCarrierBefore, finalParagraphsOf, paragraphEndsItsContainer };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
import { TableAttrs, TableCellAttrs, TableRowAttrs } from "../schema/nodes.js";
|
|
2
3
|
import { Mark, Node } from "prosemirror-model";
|
|
3
4
|
//#region src/prosemirror/conversion/fromProseDoc.d.ts
|
|
4
5
|
/**
|
|
@@ -12,7 +13,13 @@ type MarksToTextFormattingOptions = {
|
|
|
12
13
|
inheritedFormatting: document_d_exports.TextFormatting | undefined;
|
|
13
14
|
};
|
|
14
15
|
declare function marksToTextFormatting(marks: readonly Mark[], options?: MarksToTextFormattingOptions): document_d_exports.TextFormatting;
|
|
16
|
+
declare function tableAttrsToFormatting(attrs: TableAttrs): document_d_exports.TableFormatting | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Convert ProseMirror table row attrs to TableRowFormatting
|
|
19
|
+
*/
|
|
20
|
+
declare function tableRowAttrsToFormatting(attrs: TableRowAttrs): document_d_exports.TableRowFormatting | undefined;
|
|
15
21
|
declare const standaloneTableCellFromProseMirror: (node: Node) => document_d_exports.TableCell;
|
|
22
|
+
declare function tableCellAttrsToFormatting(attrs: TableCellAttrs): document_d_exports.TableCellFormatting | undefined;
|
|
16
23
|
/**
|
|
17
24
|
* Update a Document with content from a ProseMirror document
|
|
18
25
|
* Preserves all non-content parts of the original document
|
|
@@ -27,4 +34,4 @@ declare function updateDocumentContent(originalDocument: document_d_exports.Docu
|
|
|
27
34
|
*/
|
|
28
35
|
declare function proseDocToBlocks(pmDoc: Node): document_d_exports.BlockContent[];
|
|
29
36
|
//#endregion
|
|
30
|
-
export { fromProseDoc, marksToTextFormatting, proseDocToBlocks, standaloneTableCellFromProseMirror, updateDocumentContent };
|
|
37
|
+
export { fromProseDoc, marksToTextFormatting, proseDocToBlocks, standaloneTableCellFromProseMirror, tableAttrsToFormatting, tableCellAttrsToFormatting, tableRowAttrsToFormatting, updateDocumentContent };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { numPrEqual } from "../../docx/numberingParser.js";
|
|
2
2
|
import { ShapeOutlineStyleSchema, narrowEnum } from "../../docx/parserEnums.js";
|
|
3
3
|
import { OUTLINE_STYLE_CSS_ALIASES, normalizeShapeTextAnchor } from "../../types/documentEnumValues.js";
|
|
4
|
+
import { canonicalJson } from "../../utils/canonicalJson.js";
|
|
4
5
|
import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
|
|
5
6
|
import { pixelsToEmu } from "../../utils/units.js";
|
|
6
7
|
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";
|
|
@@ -688,9 +689,9 @@ function createTrackedRunWrapper(type, info, child) {
|
|
|
688
689
|
content
|
|
689
690
|
};
|
|
690
691
|
}
|
|
691
|
-
function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, textBoxAnchorMarkers, skipLeadingRenderedPageBreak = false) {
|
|
692
|
+
function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, textBoxAnchorMarkers, skipLeadingRenderedPageBreak = false, inheritedFormattingOverride) {
|
|
692
693
|
const content = [];
|
|
693
|
-
const inheritedFormatting = paragraph.type.name === "paragraph" ? expectParagraphAttrs(paragraph).defaultTextFormatting ?? void 0 : void 0;
|
|
694
|
+
const inheritedFormatting = inheritedFormattingOverride ?? (paragraph.type.name === "paragraph" ? expectParagraphAttrs(paragraph).defaultTextFormatting ?? void 0 : void 0);
|
|
694
695
|
const sortedEmptyHyperlinks = (emptyHyperlinks ?? []).map((attrs, order) => ({
|
|
695
696
|
attrs,
|
|
696
697
|
order
|
|
@@ -965,7 +966,7 @@ function extractParagraphContent(paragraph, _documentCounts, emptyHyperlinks, te
|
|
|
965
966
|
}));
|
|
966
967
|
} else if (node.type.name === "sdt") {
|
|
967
968
|
flushCurrentInline();
|
|
968
|
-
content.push(createInlineSdtFromNode(node, textBoxAnchorMarkers));
|
|
969
|
+
content.push(createInlineSdtFromNode(node, textBoxAnchorMarkers, inheritedFormatting));
|
|
969
970
|
} else if (node.type.name === "math") {
|
|
970
971
|
flushCurrentInline();
|
|
971
972
|
content.push(createMathFromNode(node));
|
|
@@ -1368,11 +1369,11 @@ function createMathFromNode(node) {
|
|
|
1368
1369
|
/**
|
|
1369
1370
|
* Create an InlineSdt from a PM sdt node
|
|
1370
1371
|
*/
|
|
1371
|
-
function createInlineSdtFromNode(node, textBoxAnchorMarkers) {
|
|
1372
|
+
function createInlineSdtFromNode(node, textBoxAnchorMarkers, inheritedFormatting) {
|
|
1372
1373
|
return {
|
|
1373
1374
|
type: "inlineSdt",
|
|
1374
1375
|
properties: sdtPropertiesFromAttrs(expectSdtAttrs(node)),
|
|
1375
|
-
content: extractParagraphContent(node, void 0, void 0, textBoxAnchorMarkers).filter((c) => c.type === "run" || c.type === "hyperlink" || c.type === "simpleField" || c.type === "complexField" || c.type === "inlineSdt" || c.type === "insertion" || c.type === "deletion" || c.type === "moveFrom" || c.type === "moveTo" || c.type === "mathEquation")
|
|
1376
|
+
content: extractParagraphContent(node, void 0, void 0, textBoxAnchorMarkers, false, inheritedFormatting).filter((c) => c.type === "run" || c.type === "hyperlink" || c.type === "simpleField" || c.type === "complexField" || c.type === "inlineSdt" || c.type === "insertion" || c.type === "deletion" || c.type === "moveFrom" || c.type === "moveTo" || c.type === "mathEquation")
|
|
1376
1377
|
};
|
|
1377
1378
|
}
|
|
1378
1379
|
/**
|
|
@@ -1523,6 +1524,7 @@ function createShapeRun(node) {
|
|
|
1523
1524
|
function marksToTextFormatting(marks, options) {
|
|
1524
1525
|
const formatting = {};
|
|
1525
1526
|
let directOverrideFormatting;
|
|
1527
|
+
let directFontProperties;
|
|
1526
1528
|
let characterStyleRPr;
|
|
1527
1529
|
let runFormattingOverrideMark;
|
|
1528
1530
|
for (const mark of marks) switch (mark.type.name) {
|
|
@@ -1650,9 +1652,14 @@ function marksToTextFormatting(marks, options) {
|
|
|
1650
1652
|
}
|
|
1651
1653
|
if (runFormattingOverrideMark) {
|
|
1652
1654
|
const overrideAttrs = expectRunFormattingOverrideMarkAttrs(runFormattingOverrideMark);
|
|
1655
|
+
directFontProperties = overrideAttrs.directFontProperties;
|
|
1653
1656
|
applyRunFormattingOverrideAttrs(formatting, overrideAttrs);
|
|
1654
1657
|
directOverrideFormatting = {};
|
|
1655
1658
|
applyRunFormattingOverrideAttrs(directOverrideFormatting, overrideAttrs);
|
|
1659
|
+
for (const property of directFontProperties ?? []) {
|
|
1660
|
+
const value = formatting[property];
|
|
1661
|
+
if (value !== void 0) Reflect.set(directOverrideFormatting, property, value);
|
|
1662
|
+
}
|
|
1656
1663
|
}
|
|
1657
1664
|
if (characterStyleRPr) return subtractCharacterStyleFormatting({
|
|
1658
1665
|
directOverrideFormatting,
|
|
@@ -1660,8 +1667,29 @@ function marksToTextFormatting(marks, options) {
|
|
|
1660
1667
|
inheritedFormatting: options?.inheritedFormatting,
|
|
1661
1668
|
styleRPr: characterStyleRPr
|
|
1662
1669
|
});
|
|
1670
|
+
for (const property of [
|
|
1671
|
+
"fontFamily",
|
|
1672
|
+
"fontSize",
|
|
1673
|
+
"color"
|
|
1674
|
+
]) {
|
|
1675
|
+
if (directFontProperties?.includes(property)) continue;
|
|
1676
|
+
const value = formatting[property];
|
|
1677
|
+
const inheritedValue = options?.inheritedFormatting?.[property];
|
|
1678
|
+
const matchesInherited = property === "fontFamily" ? sameFontFamily(formatting.fontFamily, options?.inheritedFormatting?.fontFamily) : JSON.stringify(value) === JSON.stringify(inheritedValue);
|
|
1679
|
+
if (inheritedValue !== void 0 && matchesInherited) Reflect.deleteProperty(formatting, property);
|
|
1680
|
+
}
|
|
1663
1681
|
return formatting;
|
|
1664
1682
|
}
|
|
1683
|
+
const sameFontFamily = (left, right) => [
|
|
1684
|
+
"ascii",
|
|
1685
|
+
"hAnsi",
|
|
1686
|
+
"eastAsia",
|
|
1687
|
+
"hint",
|
|
1688
|
+
"asciiTheme",
|
|
1689
|
+
"hAnsiTheme",
|
|
1690
|
+
"eastAsiaTheme",
|
|
1691
|
+
"csTheme"
|
|
1692
|
+
].every((property) => left?.[property] === right?.[property]) && (left?.cs ?? left?.ascii) === (right?.cs ?? right?.ascii);
|
|
1665
1693
|
/**
|
|
1666
1694
|
* Negatable boolean run-property keys whose serializer emits an explicit
|
|
1667
1695
|
* `w:val="0"` override when the value is `false` (see `serializeTextFormatting`
|
|
@@ -1801,6 +1829,16 @@ function buildCellMarginsFromAttrs(m) {
|
|
|
1801
1829
|
/**
|
|
1802
1830
|
* Convert ProseMirror table attrs to TableFormatting
|
|
1803
1831
|
*/
|
|
1832
|
+
/**
|
|
1833
|
+
* Whether a live attr still holds what the style cascade resolved to.
|
|
1834
|
+
*
|
|
1835
|
+
* `toProseDoc` seeds an attr with the EFFECTIVE value — a border a table
|
|
1836
|
+
* style supplied, a margin a table declared — because that is what the editor
|
|
1837
|
+
* renders with. A save must write only what the node itself states, or the
|
|
1838
|
+
* inherited value becomes a direct override that outranks the style it came
|
|
1839
|
+
* from on reload. The resolved companion is what tells the two apart.
|
|
1840
|
+
*/
|
|
1841
|
+
const sameResolvedValue = (live, resolved) => resolved !== void 0 && resolved !== null && canonicalJson(live) === canonicalJson(resolved);
|
|
1804
1842
|
function tableAttrsToFormatting(attrs) {
|
|
1805
1843
|
if (attrs._originalFormatting) {
|
|
1806
1844
|
const orig = attrs._originalFormatting;
|
|
@@ -1824,7 +1862,7 @@ function tableAttrsToFormatting(attrs) {
|
|
|
1824
1862
|
type: tableWidthType ?? "dxa"
|
|
1825
1863
|
};
|
|
1826
1864
|
else delete result.width;
|
|
1827
|
-
if (attrs.cellMargins) result.cellMargins = buildCellMarginsFromAttrs(attrs.cellMargins);
|
|
1865
|
+
if (attrs.cellMargins && !sameResolvedValue(attrs.cellMargins, attrs._resolvedCellMargins)) result.cellMargins = buildCellMarginsFromAttrs(attrs.cellMargins);
|
|
1828
1866
|
return result;
|
|
1829
1867
|
}
|
|
1830
1868
|
const tableWidth = attrs.width;
|
|
@@ -2022,8 +2060,8 @@ function tableCellAttrsToFormatting(attrs) {
|
|
|
2022
2060
|
if (attrs.verticalAlign !== (orig.verticalAlign ?? void 0)) if (attrs.verticalAlign) result.verticalAlign = attrs.verticalAlign;
|
|
2023
2061
|
else delete result.verticalAlign;
|
|
2024
2062
|
if (backgroundChanged) result.shading = cellShadingFromAttrs(attrs);
|
|
2025
|
-
if (attrs.borders) result.borders = attrs.borders;
|
|
2026
|
-
if (attrs.margins) result.margins = buildCellMarginsFromAttrs(attrs.margins);
|
|
2063
|
+
if (attrs.borders && !sameResolvedValue(attrs.borders, attrs._resolvedBorders)) result.borders = attrs.borders;
|
|
2064
|
+
if (attrs.margins && !sameResolvedValue(attrs.margins, attrs._resolvedMargins)) result.margins = buildCellMarginsFromAttrs(attrs.margins);
|
|
2027
2065
|
if (attrs.textDirection !== (orig.textDirection ?? void 0)) if (attrs.textDirection) result.textDirection = attrs.textDirection;
|
|
2028
2066
|
else delete result.textDirection;
|
|
2029
2067
|
return result;
|
|
@@ -2154,4 +2192,4 @@ function proseDocToBlocks(pmDoc) {
|
|
|
2154
2192
|
return extractBlocks(pmDoc);
|
|
2155
2193
|
}
|
|
2156
2194
|
//#endregion
|
|
2157
|
-
export { fromProseDoc, marksToTextFormatting, proseDocToBlocks, standaloneTableCellFromProseMirror, updateDocumentContent };
|
|
2195
|
+
export { fromProseDoc, marksToTextFormatting, proseDocToBlocks, standaloneTableCellFromProseMirror, tableAttrsToFormatting, tableCellAttrsToFormatting, tableRowAttrsToFormatting, updateDocumentContent };
|
|
@@ -18,6 +18,7 @@ import { shadingToRunShadingAttrs } from "./runShadingMark.js";
|
|
|
18
18
|
import { sdtAttrsFromProperties } from "./sdtAttrs.js";
|
|
19
19
|
import { panic } from "better-result";
|
|
20
20
|
//#region src/prosemirror/conversion/toProseDoc.ts
|
|
21
|
+
const DETACHED_WATERMARK_HOST = Symbol.for("stll.detachedWatermarkHost");
|
|
21
22
|
/**
|
|
22
23
|
* Build a `nextTextBoxGroupId()` generator salted with a random per-load
|
|
23
24
|
* nonce, so minted text-box anchor ids (`<salt>:<group>:<index>`) are unique
|
|
@@ -139,7 +140,12 @@ function toProseDoc(document, options) {
|
|
|
139
140
|
};
|
|
140
141
|
nodes.push(...convertBodyBlocks(paragraphs));
|
|
141
142
|
if (nodes.length === 0) nodes.push(schema.node("paragraph", {}, []));
|
|
142
|
-
const
|
|
143
|
+
const finalSectionStart = document.package.document.sections?.at(-1)?.properties.sectionStart ?? null;
|
|
144
|
+
const adjustLineHeightInTable = document.package.settings?.adjustLineHeightInTable === true;
|
|
145
|
+
const pmDoc = stampNumberedRefFieldBaselines(schema.node("doc", {
|
|
146
|
+
_finalSectionStart: finalSectionStart,
|
|
147
|
+
_adjustLineHeightInTable: adjustLineHeightInTable
|
|
148
|
+
}, nodes));
|
|
143
149
|
assertValidProseMirrorDocument(pmDoc, "Document conversion produced an invalid ProseMirror document");
|
|
144
150
|
return pmDoc;
|
|
145
151
|
}
|
|
@@ -210,6 +216,7 @@ function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex,
|
|
|
210
216
|
const paragraphRunFormatting = resolveRunFormattingWithoutDefaults(paragraph.formatting?.runProperties, styleResolver);
|
|
211
217
|
let inheritableParagraphRunFormatting;
|
|
212
218
|
if (paragraphRunFormatting && !isTocParagraph) inheritableParagraphRunFormatting = stripParagraphMarkFormattingForBodyRuns(paragraphRunFormatting);
|
|
219
|
+
const ordinaryStyleFormatting = paragraph.formatting?.styleId === void 0 ? mergeTextFormatting(styleRunFormatting, extraRunFormatting) : mergeTextFormatting(extraRunFormatting, styleRunFormatting);
|
|
213
220
|
const orderedToggleFormatting = cascadeStyleTextFormatting([
|
|
214
221
|
{
|
|
215
222
|
formatting: styleResolver?.getDocDefaults()?.rPr,
|
|
@@ -223,7 +230,7 @@ function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex,
|
|
|
223
230
|
formatting: paragraphStyleRunFormatting,
|
|
224
231
|
type: "style"
|
|
225
232
|
}
|
|
226
|
-
], { ordinaryFormatting:
|
|
233
|
+
], { ordinaryFormatting: ordinaryStyleFormatting });
|
|
227
234
|
let baseRunFormatting = orderedToggleFormatting.formatting;
|
|
228
235
|
if (paragraphStyleFontFamily) baseRunFormatting = mergeTextFormatting(baseRunFormatting, { fontFamily: paragraphStyleFontFamily });
|
|
229
236
|
const paragraphMarkPrecedesStyle = paragraph.formatting?.styleId !== void 0;
|
|
@@ -850,7 +857,10 @@ function convertTable(table, styleResolver, context) {
|
|
|
850
857
|
if (table.formatting?.justification) attrs.justification = table.formatting.justification;
|
|
851
858
|
if (columnWidths) attrs.columnWidths = columnWidths;
|
|
852
859
|
if (table.formatting?.floating) attrs.floating = table.formatting.floating;
|
|
853
|
-
if (cellMarginsAttr)
|
|
860
|
+
if (cellMarginsAttr) {
|
|
861
|
+
attrs.cellMargins = cellMarginsAttr;
|
|
862
|
+
attrs._resolvedCellMargins = cellMarginsAttr;
|
|
863
|
+
}
|
|
854
864
|
if (table.formatting?.look) attrs.look = table.formatting.look;
|
|
855
865
|
if (table.formatting?.borders) attrs.borders = table.formatting.borders;
|
|
856
866
|
if (resolvedTableIndent) attrs._resolvedIndent = resolvedTableIndent;
|
|
@@ -997,10 +1007,10 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
|
|
|
997
1007
|
let cellConditionalStyle = conditionalStyles?.wholeTable;
|
|
998
1008
|
cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, effectiveRowBandStyle);
|
|
999
1009
|
cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, vertBandStyle);
|
|
1000
|
-
if (cellIsFirstRow && (tableLook?.firstRow || rowCnf?.firstRow || cellCnf?.firstRow)) cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, conditionalStyles?.firstRow);
|
|
1001
|
-
if (cellIsLastRow && (tableLook?.lastRow || rowCnf?.lastRow || cellCnf?.lastRow)) cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, conditionalStyles?.lastRow);
|
|
1002
1010
|
if (cellIsFirstCol && (tableLook?.firstColumn || rowCnf?.firstColumn || cellCnf?.firstColumn)) cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, conditionalStyles?.firstCol);
|
|
1003
1011
|
if (cellIsLastCol && (tableLook?.lastColumn || rowCnf?.lastColumn || cellCnf?.lastColumn)) cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, conditionalStyles?.lastCol);
|
|
1012
|
+
if (cellIsFirstRow && (tableLook?.firstRow || rowCnf?.firstRow || cellCnf?.firstRow)) cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, conditionalStyles?.firstRow);
|
|
1013
|
+
if (cellIsLastRow && (tableLook?.lastRow || rowCnf?.lastRow || cellCnf?.lastRow)) cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, conditionalStyles?.lastRow);
|
|
1004
1014
|
if (cellIsFirstRow && cellIsFirstCol && (tableLook?.firstRow || rowCnf?.firstRow || cellCnf?.firstRow) && (tableLook?.firstColumn || rowCnf?.firstColumn || cellCnf?.firstColumn)) cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, conditionalStyles?.nwCell);
|
|
1005
1015
|
if (cellIsFirstRow && cellIsLastCol && (tableLook?.firstRow || rowCnf?.firstRow || cellCnf?.firstRow) && (tableLook?.lastColumn || rowCnf?.lastColumn || cellCnf?.lastColumn)) cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, conditionalStyles?.neCell);
|
|
1006
1016
|
if (cellIsLastRow && cellIsFirstCol && (tableLook?.lastRow || rowCnf?.lastRow || cellCnf?.lastRow) && (tableLook?.firstColumn || rowCnf?.firstColumn || cellCnf?.firstColumn)) cellConditionalStyle = mergeConditionalStyles(cellConditionalStyle, conditionalStyles?.swCell);
|
|
@@ -1059,8 +1069,14 @@ function convertTableCell({ cell, styleResolver, context, isHeader, gridWidthPer
|
|
|
1059
1069
|
if (formatting?.noWrap !== void 0) attrs.noWrap = formatting.noWrap;
|
|
1060
1070
|
const hideMark = formatting?.hideMark ?? conditionalStyle?.tcPr?.hideMark;
|
|
1061
1071
|
if (hideMark !== void 0) attrs.hideMark = hideMark;
|
|
1062
|
-
if (effectiveFormatting.borders)
|
|
1063
|
-
|
|
1072
|
+
if (effectiveFormatting.borders) {
|
|
1073
|
+
attrs.borders = effectiveFormatting.borders;
|
|
1074
|
+
attrs._resolvedBorders = effectiveFormatting.borders;
|
|
1075
|
+
}
|
|
1076
|
+
if (effectiveFormatting.margins) {
|
|
1077
|
+
attrs.margins = effectiveFormatting.margins;
|
|
1078
|
+
attrs._resolvedMargins = effectiveFormatting.margins;
|
|
1079
|
+
}
|
|
1064
1080
|
if (formatting) attrs._originalFormatting = formatting;
|
|
1065
1081
|
if (cell.propertyChanges && cell.propertyChanges.length > 0) attrs.tcPrChange = [...cell.propertyChanges];
|
|
1066
1082
|
if (cell.structuralChange?.type === "tableCellInsertion") attrs.cellMarker = {
|
|
@@ -1256,6 +1272,7 @@ function buildRunMarks(runFormatting, inherited, styleResolver) {
|
|
|
1256
1272
|
hasCharacterStyle: styleId !== void 0,
|
|
1257
1273
|
paragraphMarkOverrides: inherited.paragraphMarkOverrides
|
|
1258
1274
|
}) });
|
|
1275
|
+
addDirectFontProvenance(marks, runFormatting);
|
|
1259
1276
|
if (styleId) {
|
|
1260
1277
|
const styleRPr = characterStyleFormatting ? marksToTextFormatting(textFormattingToMarks(characterStyleFormatting)) : void 0;
|
|
1261
1278
|
marks.push(schema.mark("characterStyle", {
|
|
@@ -1268,6 +1285,24 @@ function buildRunMarks(runFormatting, inherited, styleResolver) {
|
|
|
1268
1285
|
mergedFormatting
|
|
1269
1286
|
};
|
|
1270
1287
|
}
|
|
1288
|
+
const addDirectFontProvenance = (marks, directFormatting) => {
|
|
1289
|
+
const directFontProperties = [];
|
|
1290
|
+
if (directFormatting?.fontFamily !== void 0) directFontProperties.push("fontFamily");
|
|
1291
|
+
if (directFormatting?.fontSize !== void 0) directFontProperties.push("fontSize");
|
|
1292
|
+
if (directFormatting?.color !== void 0) directFontProperties.push("color");
|
|
1293
|
+
if (!directFormatting || !Object.keys(directFormatting).some((property) => property !== "styleId")) return;
|
|
1294
|
+
const index = marks.findIndex(({ type }) => type.name === "runFormattingOverride");
|
|
1295
|
+
const existing = index >= 0 ? marks.at(index) : void 0;
|
|
1296
|
+
const override = schema.mark("runFormattingOverride", {
|
|
1297
|
+
...existing?.attrs,
|
|
1298
|
+
...directFontProperties.length > 0 && { directFontProperties }
|
|
1299
|
+
});
|
|
1300
|
+
if (index >= 0) {
|
|
1301
|
+
marks[index] = override;
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
marks.push(override);
|
|
1305
|
+
};
|
|
1271
1306
|
const ORDINARY_STYLE_TOGGLE_KEYS = [
|
|
1272
1307
|
"bold",
|
|
1273
1308
|
"italic",
|
|
@@ -1649,12 +1684,12 @@ function convertShape(shape) {
|
|
|
1649
1684
|
position
|
|
1650
1685
|
});
|
|
1651
1686
|
}
|
|
1652
|
-
function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, context, extraRunFormatting, tableParagraphOverlay }) {
|
|
1687
|
+
function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, context, extraRunFormatting, preserveEmptyWrapper, tableParagraphOverlay }) {
|
|
1653
1688
|
const { textBoxes, textBoxAnchors } = extractTextBoxesFromParagraph(block, textBoxGroupId);
|
|
1654
1689
|
const pmParagraph = convertParagraph(block, styleResolver, context.nextHyperlinkInstanceIndex, context.pairedBookmarkIds, void 0, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
|
|
1655
1690
|
const nodes = [];
|
|
1656
1691
|
const isEmptyAfterExtraction = textBoxes.length > 0 && !hasContentBesidesTextBoxAnchors(pmParagraph);
|
|
1657
|
-
const keepWrapperParagraph = isEmptyAfterExtraction && hasParagraphBoundaryPayload(block, pmParagraph);
|
|
1692
|
+
const keepWrapperParagraph = isEmptyAfterExtraction && (preserveEmptyWrapper === true || hasParagraphBoundaryPayload(block, pmParagraph));
|
|
1658
1693
|
if (!isEmptyAfterExtraction || keepWrapperParagraph) nodes.push(pmParagraph);
|
|
1659
1694
|
for (const { textBox, anchorId, trackedChange, inlineSdts } of textBoxes) nodes.push(convertTextBox(textBox, styleResolver, {
|
|
1660
1695
|
placement: isEmptyAfterExtraction && !keepWrapperParagraph ? "standalone" : "inlineWithPrevious",
|
|
@@ -1920,11 +1955,23 @@ function headerFooterToProseDoc(content, options) {
|
|
|
1920
1955
|
};
|
|
1921
1956
|
const convertBlocks = (blocks) => {
|
|
1922
1957
|
const out = [];
|
|
1923
|
-
for (const block of blocks) if (block.type === "paragraph")
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1958
|
+
for (const block of blocks) if (block.type === "paragraph") {
|
|
1959
|
+
const isDetachedWatermarkHost = Reflect.get(block, DETACHED_WATERMARK_HOST) === true;
|
|
1960
|
+
const paragraphNodes = convertParagraphWithTextBoxes(block, styleResolver, {
|
|
1961
|
+
textBoxGroupId: nextTextBoxGroupId(),
|
|
1962
|
+
context: conversionContext,
|
|
1963
|
+
preserveEmptyWrapper: isDetachedWatermarkHost
|
|
1964
|
+
});
|
|
1965
|
+
if (isDetachedWatermarkHost) {
|
|
1966
|
+
const paragraphNodeIndex = paragraphNodes.findIndex(({ type }) => type.name === "paragraph");
|
|
1967
|
+
const paragraphNode = paragraphNodes[paragraphNodeIndex];
|
|
1968
|
+
if (paragraphNode) paragraphNodes[paragraphNodeIndex] = paragraphNode.type.create({
|
|
1969
|
+
...paragraphNode.attrs,
|
|
1970
|
+
_detachedWatermarkHost: true
|
|
1971
|
+
}, paragraphNode.content, paragraphNode.marks);
|
|
1972
|
+
}
|
|
1973
|
+
out.push(...paragraphNodes);
|
|
1974
|
+
} else if (block.type === "table") out.push(convertTable(block, styleResolver, conversionContext));
|
|
1928
1975
|
else out.push(convertBlockSdt(block, convertBlocks));
|
|
1929
1976
|
return out;
|
|
1930
1977
|
};
|
|
@@ -6,7 +6,13 @@ import { createNodeExtension } from "../create.js";
|
|
|
6
6
|
const DocExtension = createNodeExtension({
|
|
7
7
|
name: "doc",
|
|
8
8
|
schemaNodeName: "doc",
|
|
9
|
-
nodeSpec: {
|
|
9
|
+
nodeSpec: {
|
|
10
|
+
attrs: {
|
|
11
|
+
_finalSectionStart: { default: null },
|
|
12
|
+
_adjustLineHeightInTable: { default: false }
|
|
13
|
+
},
|
|
14
|
+
content: "(paragraph | horizontalRule | pageBreak | table | textBox | blockSdt)+"
|
|
15
|
+
}
|
|
10
16
|
});
|
|
11
17
|
//#endregion
|
|
12
18
|
export { DocExtension };
|
|
@@ -223,6 +223,7 @@ const paragraphNodeSpec = {
|
|
|
223
223
|
pageBreakBefore: { default: null },
|
|
224
224
|
renderedPageBreakBefore: { default: null },
|
|
225
225
|
_pageBreakCarrier: { default: null },
|
|
226
|
+
_detachedWatermarkHost: { default: null },
|
|
226
227
|
_trailingPageBreak: { default: null },
|
|
227
228
|
keepNext: { default: null },
|
|
228
229
|
keepLines: { default: null },
|
|
@@ -50,6 +50,7 @@ const RunFormattingOverrideExtension = createMarkExtension({
|
|
|
50
50
|
schemaMarkName: "runFormattingOverride",
|
|
51
51
|
markSpec: {
|
|
52
52
|
attrs: {
|
|
53
|
+
directFontProperties: { default: null },
|
|
53
54
|
bold: { default: null },
|
|
54
55
|
italic: { default: null },
|
|
55
56
|
underline: { default: null },
|
|
@@ -151,6 +151,7 @@ const tableSpec = {
|
|
|
151
151
|
columnWidths: { default: null },
|
|
152
152
|
floating: { default: null },
|
|
153
153
|
cellMargins: { default: null },
|
|
154
|
+
_resolvedCellMargins: { default: null },
|
|
154
155
|
look: { default: null },
|
|
155
156
|
borders: { default: null },
|
|
156
157
|
_resolvedIndent: { default: null },
|
|
@@ -319,7 +320,9 @@ const tableCellSpec = {
|
|
|
319
320
|
backgroundColor: { default: null },
|
|
320
321
|
_resolvedBackgroundColor: { default: null },
|
|
321
322
|
borders: { default: null },
|
|
323
|
+
_resolvedBorders: { default: null },
|
|
322
324
|
margins: { default: null },
|
|
325
|
+
_resolvedMargins: { default: null },
|
|
323
326
|
textDirection: { default: null },
|
|
324
327
|
noWrap: { default: false },
|
|
325
328
|
hideMark: { default: false },
|
|
@@ -375,7 +378,9 @@ const tableHeaderSpec = {
|
|
|
375
378
|
backgroundColor: { default: null },
|
|
376
379
|
_resolvedBackgroundColor: { default: null },
|
|
377
380
|
borders: { default: null },
|
|
381
|
+
_resolvedBorders: { default: null },
|
|
378
382
|
margins: { default: null },
|
|
383
|
+
_resolvedMargins: { default: null },
|
|
379
384
|
textDirection: { default: null },
|
|
380
385
|
noWrap: { default: false },
|
|
381
386
|
hideMark: { default: false },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { document_d_exports } from "../../types/document.js";
|
|
2
1
|
import { ShadingProperties } from "../../types/colors.js";
|
|
2
|
+
import { document_d_exports } from "../../types/document.js";
|
|
3
3
|
//#region src/prosemirror/schema/marks.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Text color mark attributes
|
|
@@ -121,17 +121,11 @@ type RunPropertyChangeMarkAttrs = {
|
|
|
121
121
|
provenance: TrackedChangeProvenance;
|
|
122
122
|
suggestionId?: string;
|
|
123
123
|
};
|
|
124
|
-
type RunFormattingOverrideAttrs =
|
|
124
|
+
type RunFormattingOverrideAttrs = Partial<Record<"bold" | "boldCs" | "cs" | "italic" | "italicCs" | "strike" | "allCaps" | "smallCaps" | "hidden" | "emboss" | "imprint" | "shadow" | "outline", boolean>> & {
|
|
125
|
+
directFontProperties?: readonly ("fontFamily" | "fontSize" | "color")[];
|
|
125
126
|
doubleStrike?: false;
|
|
126
127
|
rtl?: false;
|
|
127
|
-
/** Independent complex-script weight (`w:bCs`). */
|
|
128
|
-
boldCs?: boolean;
|
|
129
|
-
/** Force complex-script formatting for the full run (`w:cs`). */
|
|
130
|
-
cs?: boolean;
|
|
131
|
-
/** Independent complex-script size in half-points (`w:szCs`). */
|
|
132
128
|
fontSizeCs?: number;
|
|
133
|
-
/** Independent complex-script slant (`w:iCs`). */
|
|
134
|
-
italicCs?: boolean;
|
|
135
129
|
underline?: "none";
|
|
136
130
|
};
|
|
137
131
|
/**
|
|
@@ -569,6 +569,13 @@ type TableAttrs = {
|
|
|
569
569
|
look?: document_d_exports.TableLook;
|
|
570
570
|
/** Table-level borders (w:tblBorders) — full BorderSpec per side */
|
|
571
571
|
borders?: document_d_exports.TableBorders;
|
|
572
|
+
/**
|
|
573
|
+
* Effective default cell margins after the table-style cascade. PM-only;
|
|
574
|
+
* never serialized. What `cellMargins` resolves to when the table declares
|
|
575
|
+
* none of its own, so a save can tell a value a style supplied from one the
|
|
576
|
+
* table states — and stop writing the style's into the table's `w:tblPr`.
|
|
577
|
+
*/
|
|
578
|
+
_resolvedCellMargins?: TableAttrs["cellMargins"];
|
|
572
579
|
/** Effective table indent after style resolution. PM-only; never serialized. */
|
|
573
580
|
_resolvedIndent?: NonNullable<document_d_exports.TableFormatting["indent"]>;
|
|
574
581
|
/** Style-derived table justification fallback. PM-only; never serialized. */
|
|
@@ -677,6 +684,14 @@ type TableCellAttrs = {
|
|
|
677
684
|
hideMark?: boolean;
|
|
678
685
|
/** Cell borders — full BorderSpec per side (style, color, size) */
|
|
679
686
|
borders?: document_d_exports.TableCellBorders;
|
|
687
|
+
/**
|
|
688
|
+
* Effective borders after the table and table-style cascade. PM-only; never
|
|
689
|
+
* serialized. The companion to `borders` that `_resolvedBackgroundColor` is
|
|
690
|
+
* to `backgroundColor`: what the cell renders with when it declares none of
|
|
691
|
+
* its own, so a save can tell a border a style supplied from one the cell
|
|
692
|
+
* states.
|
|
693
|
+
*/
|
|
694
|
+
_resolvedBorders?: document_d_exports.TableCellBorders;
|
|
680
695
|
/** Cell margins/padding in twips per side */
|
|
681
696
|
margins?: {
|
|
682
697
|
top?: number;
|
|
@@ -684,6 +699,13 @@ type TableCellAttrs = {
|
|
|
684
699
|
left?: number;
|
|
685
700
|
right?: number;
|
|
686
701
|
};
|
|
702
|
+
/** Effective margins after the cascade. PM-only; never serialized. */
|
|
703
|
+
_resolvedMargins?: {
|
|
704
|
+
top?: number;
|
|
705
|
+
bottom?: number;
|
|
706
|
+
left?: number;
|
|
707
|
+
right?: number;
|
|
708
|
+
};
|
|
687
709
|
/** Original cell formatting from DOCX for lossless round-trip serialization */
|
|
688
710
|
_originalFormatting?: document_d_exports.TableCellFormatting;
|
|
689
711
|
/** Tracked cell property changes (w:tcPrChange) for round-trip + accept/reject */
|