@portone/docx-editor 0.3.0 → 0.4.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/CHANGELOG.md +46 -0
- package/dist/DocxEditor.js +1 -0
- package/dist/core.d.ts +1 -1
- package/dist/docx/comments/writing.js +14 -8
- package/dist/docx/exportDocx.js +20 -4
- package/dist/docx/formatting/attrs.d.ts +20 -2
- package/dist/docx/formatting/attrs.js +57 -2
- package/dist/docx/formatting/context.d.ts +10 -2
- package/dist/docx/formatting/context.js +23 -5
- package/dist/docx/formatting/resolve.d.ts +10 -4
- package/dist/docx/formatting/resolve.js +31 -11
- package/dist/docx/formatting/styles.d.ts +25 -2
- package/dist/docx/formatting/styles.js +84 -3
- package/dist/docx/hyperlink.d.ts +14 -4
- package/dist/docx/hyperlink.js +4 -1
- package/dist/docx/importDocx.js +46 -37
- package/dist/docx/importTable.d.ts +2 -2
- package/dist/docx/importTable.js +52 -55
- package/dist/docx/invariants.js +26 -13
- package/dist/docx/newLists.d.ts +30 -0
- package/dist/docx/newLists.js +24 -1
- package/dist/docx/numberingPlanner.d.ts +6 -3
- package/dist/docx/numberingPlanner.js +38 -7
- package/dist/docx/session.d.ts +1 -1
- package/dist/docx/session.js +11 -1
- package/dist/docx/tableFormatting/conditions.d.ts +76 -0
- package/dist/docx/tableFormatting/conditions.js +196 -0
- package/dist/docx/tableFormatting/editing.d.ts +7 -3
- package/dist/docx/tableFormatting/editing.js +4 -5
- package/dist/docx/tableFormatting/reading.d.ts +49 -19
- package/dist/docx/tableFormatting/reading.js +109 -35
- package/dist/docx/tableFormatting.d.ts +1 -0
- package/dist/docx/tableFormatting.js +1 -0
- package/dist/docx/tableTemplate.js +12 -12
- package/dist/editor/commands/formatting/propertyCommands.js +6 -1
- package/dist/editor/commands/listCommands.d.ts +6 -3
- package/dist/editor/commands/listCommands.js +73 -28
- package/dist/editor/commands/paragraphCommands.js +6 -1
- package/dist/editor/createEditor.js +1 -1
- package/dist/editor/editorDocument.d.ts +7 -6
- package/dist/editor/editorDocument.js +18 -6
- package/dist/editor/externalClipboard.d.ts +13 -2
- package/dist/editor/externalClipboard.js +64 -34
- package/dist/editor/paragraphEdits.d.ts +16 -1
- package/dist/editor/paragraphEdits.js +13 -5
- package/dist/editor/paragraphPlacement.d.ts +11 -0
- package/dist/editor/paragraphPlacement.js +18 -0
- package/dist/editor/plugins/imagePaste.js +7 -4
- package/dist/editor/plugins/numberingDecorations.d.ts +10 -4
- package/dist/editor/plugins/numberingDecorations.js +43 -2
- package/dist/editor/plugins/paragraphDisplay.js +9 -3
- package/dist/editor/plugins/tableDisplay.js +19 -5
- package/dist/model/format.d.ts +50 -0
- package/dist/model/format.js +65 -0
- package/dist/numbering/listRegistry.d.ts +37 -0
- package/dist/numbering/listRegistry.js +112 -0
- package/dist/numbering/listTemplate.d.ts +26 -17
- package/dist/numbering/listTemplate.js +66 -20
- package/dist/numbering/markers.d.ts +15 -6
- package/dist/numbering/markers.js +26 -59
- package/dist/numbering/parseNumbering.d.ts +70 -5
- package/dist/numbering/parseNumbering.js +100 -26
- package/dist/numbering/spellers.d.ts +15 -0
- package/dist/numbering/spellers.js +96 -0
- package/dist/numbering/writeNumbering.d.ts +5 -3
- package/dist/numbering/writeNumbering.js +15 -15
- package/dist/ooxml/conformance.d.ts +28 -0
- package/dist/ooxml/conformance.js +20 -0
- package/dist/ooxml/errors.d.ts +5 -5
- package/dist/ooxml/names.d.ts +9 -0
- package/dist/ooxml/names.js +8 -1
- package/dist/ooxml/partSplice.d.ts +1 -1
- package/dist/ooxml/partSplice.js +10 -3
- package/dist/ooxml/xml.d.ts +8 -9
- package/dist/ooxml/xml.js +6 -6
- package/dist/page/PageGuides.d.ts +1 -1
- package/dist/page/PageGuides.js +0 -13
- package/dist/page/pageLayout.d.ts +0 -10
- package/dist/page/pageLayout.js +3 -10
- package/dist/page/usePageLayout.d.ts +0 -7
- package/dist/page/usePageLayout.js +2 -9
- package/dist/schema/attrRoles.js +8 -1
- package/dist/schema/docxSchema.js +32 -3
- package/dist/styles/classNames.d.ts +13 -2
- package/dist/styles/classNames.js +13 -2
- package/dist/styles.css +16 -18
- package/dist/table/cellFormatting.js +1 -2
- package/dist/table/gridBorders.d.ts +11 -15
- package/dist/table/gridBorders.js +32 -18
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/docx/formatting/styles.ts
|
|
2
2
|
import {
|
|
3
|
+
TABLE_STYLE_CONDITIONS,
|
|
3
4
|
toParagraphFormat,
|
|
4
5
|
toRunFormat,
|
|
5
6
|
toTableFormat
|
|
@@ -9,11 +10,16 @@ import { ST_OnOff } from "../../ooxml/simpleTypes.js";
|
|
|
9
10
|
import { childValue, isOn, wAttr } from "../../ooxml/units.js";
|
|
10
11
|
import { childByLocalName, elementChildren } from "../../ooxml/xml.js";
|
|
11
12
|
import {
|
|
13
|
+
layerBandSizes,
|
|
12
14
|
layerCellMargins,
|
|
15
|
+
layerCellStyleFormat,
|
|
13
16
|
layerInsideBorders,
|
|
17
|
+
NO_BAND_SIZES,
|
|
14
18
|
NO_CELL_MARGINS,
|
|
15
19
|
NO_INSIDE_BORDERS,
|
|
20
|
+
readBandSizes,
|
|
16
21
|
readCellMarginsOf,
|
|
22
|
+
readCellStyleFormat,
|
|
17
23
|
readInsideBorders,
|
|
18
24
|
readTableFormat
|
|
19
25
|
} from "../tableFormatting.js";
|
|
@@ -35,23 +41,51 @@ function styleChain(id, sources) {
|
|
|
35
41
|
return chain;
|
|
36
42
|
}
|
|
37
43
|
var EMPTY_STYLE_FORMAT = {
|
|
44
|
+
type: "paragraph",
|
|
38
45
|
paragraph: {},
|
|
39
46
|
run: {},
|
|
40
47
|
table: {},
|
|
41
48
|
tableInside: NO_INSIDE_BORDERS,
|
|
42
|
-
tableCellMargins: NO_CELL_MARGINS
|
|
49
|
+
tableCellMargins: NO_CELL_MARGINS,
|
|
50
|
+
tableBands: NO_BAND_SIZES,
|
|
51
|
+
tableConditions: {}
|
|
43
52
|
};
|
|
53
|
+
function conditionOf(el) {
|
|
54
|
+
const type = wAttr(el, "type");
|
|
55
|
+
return TABLE_STYLE_CONDITIONS.find((known) => known === type) ?? null;
|
|
56
|
+
}
|
|
57
|
+
function readConditionalFormat(el, themeFonts) {
|
|
58
|
+
const tblPr = childByLocalName(el, "tblPr");
|
|
59
|
+
return {
|
|
60
|
+
paragraph: readParagraphFormat(childByLocalName(el, "pPr")) ?? {},
|
|
61
|
+
run: readRunFormat(childByLocalName(el, "rPr"), themeFonts) ?? {},
|
|
62
|
+
table: readTableFormat(tblPr) ?? {},
|
|
63
|
+
cell: readCellStyleFormat(childByLocalName(el, "tcPr"), tblPr)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function readConditions(source, themeFonts) {
|
|
67
|
+
const conditions = {};
|
|
68
|
+
for (const el of source.tblStylePr) {
|
|
69
|
+
const type = conditionOf(el);
|
|
70
|
+
if (type !== null) conditions[type] = readConditionalFormat(el, themeFonts);
|
|
71
|
+
}
|
|
72
|
+
return conditions;
|
|
73
|
+
}
|
|
44
74
|
function readStyleFormat(source, themeFonts) {
|
|
45
75
|
return {
|
|
76
|
+
type: source.type,
|
|
46
77
|
paragraph: readParagraphFormat(source.pPr) ?? {},
|
|
47
78
|
run: readRunFormat(source.rPr, themeFonts) ?? {},
|
|
48
79
|
table: readTableFormat(source.tblPr) ?? {},
|
|
49
80
|
tableInside: readInsideBorders(source.tblPr),
|
|
50
|
-
tableCellMargins: readCellMarginsOf(source.tblPr, "tblCellMar")
|
|
81
|
+
tableCellMargins: readCellMarginsOf(source.tblPr, "tblCellMar"),
|
|
82
|
+
tableBands: readBandSizes(source.tblPr),
|
|
83
|
+
tableConditions: readConditions(source, themeFonts)
|
|
51
84
|
};
|
|
52
85
|
}
|
|
53
86
|
function layerStyleFormat(base, over) {
|
|
54
87
|
return {
|
|
88
|
+
type: over.type,
|
|
55
89
|
paragraph: layerParagraphValues(base.paragraph, over.paragraph),
|
|
56
90
|
run: { ...base.run, ...over.run },
|
|
57
91
|
table: { ...base.table, ...over.table },
|
|
@@ -59,12 +93,45 @@ function layerStyleFormat(base, over) {
|
|
|
59
93
|
tableCellMargins: layerCellMargins(
|
|
60
94
|
base.tableCellMargins,
|
|
61
95
|
over.tableCellMargins
|
|
96
|
+
),
|
|
97
|
+
tableBands: layerBandSizes(base.tableBands, over.tableBands),
|
|
98
|
+
tableConditions: layerConditions(
|
|
99
|
+
base.tableConditions,
|
|
100
|
+
over.tableConditions
|
|
62
101
|
)
|
|
63
102
|
};
|
|
64
103
|
}
|
|
104
|
+
function layerConditionalFormat(base, over) {
|
|
105
|
+
return {
|
|
106
|
+
paragraph: layerParagraphValues(base.paragraph, over.paragraph),
|
|
107
|
+
run: { ...base.run, ...over.run },
|
|
108
|
+
table: { ...base.table, ...over.table },
|
|
109
|
+
cell: layerCellStyleFormat(base.cell, over.cell)
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function layerConditions(base, over) {
|
|
113
|
+
const conditions = {};
|
|
114
|
+
for (const type of TABLE_STYLE_CONDITIONS) {
|
|
115
|
+
const under = base[type];
|
|
116
|
+
const above = over[type];
|
|
117
|
+
const format = under && above ? layerConditionalFormat(under, above) : above ?? under;
|
|
118
|
+
if (format) conditions[type] = format;
|
|
119
|
+
}
|
|
120
|
+
return conditions;
|
|
121
|
+
}
|
|
65
122
|
function foldChain(chain, themeFonts) {
|
|
66
123
|
return chain.map((source) => readStyleFormat(source, themeFonts)).reduce(layerStyleFormat, EMPTY_STYLE_FORMAT);
|
|
67
124
|
}
|
|
125
|
+
var STYLE_TYPES = [
|
|
126
|
+
"paragraph",
|
|
127
|
+
"character",
|
|
128
|
+
"table",
|
|
129
|
+
"numbering"
|
|
130
|
+
];
|
|
131
|
+
function styleTypeOf(el) {
|
|
132
|
+
const type = wAttr(el, "type");
|
|
133
|
+
return STYLE_TYPES.find((known) => known === type) ?? "paragraph";
|
|
134
|
+
}
|
|
68
135
|
function readStyles(styles, themeFonts = NO_THEME_FONTS) {
|
|
69
136
|
const sources = /* @__PURE__ */ new Map();
|
|
70
137
|
for (const el of elementChildren(styles.documentElement)) {
|
|
@@ -72,10 +139,14 @@ function readStyles(styles, themeFonts = NO_THEME_FONTS) {
|
|
|
72
139
|
const id = wAttr(el, "styleId");
|
|
73
140
|
if (id === null || id.length === 0) continue;
|
|
74
141
|
sources.set(id, {
|
|
142
|
+
type: styleTypeOf(el),
|
|
75
143
|
basedOn: childValue(el, "basedOn"),
|
|
76
144
|
pPr: childByLocalName(el, "pPr"),
|
|
77
145
|
rPr: childByLocalName(el, "rPr"),
|
|
78
|
-
tblPr: childByLocalName(el, "tblPr")
|
|
146
|
+
tblPr: childByLocalName(el, "tblPr"),
|
|
147
|
+
tblStylePr: elementChildren(el).filter(
|
|
148
|
+
(child) => child.localName === "tblStylePr"
|
|
149
|
+
)
|
|
79
150
|
});
|
|
80
151
|
}
|
|
81
152
|
const table = /* @__PURE__ */ new Map();
|
|
@@ -84,6 +155,15 @@ function readStyles(styles, themeFonts = NO_THEME_FONTS) {
|
|
|
84
155
|
}
|
|
85
156
|
return table;
|
|
86
157
|
}
|
|
158
|
+
function numberingStyleLinks(styles) {
|
|
159
|
+
const links = /* @__PURE__ */ new Map();
|
|
160
|
+
for (const [id, format] of styles) {
|
|
161
|
+
if (format.type !== "numbering") continue;
|
|
162
|
+
const numId = format.paragraph.numbering?.numId;
|
|
163
|
+
if (numId !== void 0) links.set(id, numId);
|
|
164
|
+
}
|
|
165
|
+
return links;
|
|
166
|
+
}
|
|
87
167
|
function isDefaultStyle(el) {
|
|
88
168
|
return ST_OnOff.parse(wAttr(el, "default")) === true;
|
|
89
169
|
}
|
|
@@ -158,6 +238,7 @@ export {
|
|
|
158
238
|
layerParagraphFormat,
|
|
159
239
|
layerRunFormat,
|
|
160
240
|
layerTableFormat,
|
|
241
|
+
numberingStyleLinks,
|
|
161
242
|
paragraphStyleFormat,
|
|
162
243
|
readParagraphStyles,
|
|
163
244
|
readStyles,
|
package/dist/docx/hyperlink.d.ts
CHANGED
|
@@ -45,9 +45,8 @@ export declare function relIdIn(prefix: string): string | null;
|
|
|
45
45
|
*
|
|
46
46
|
* A tag that already names one has only that value rewritten, so a link nobody retargeted comes
|
|
47
47
|
* out as the very string it went in as. A tag that named none is given the attribute, which the
|
|
48
|
-
* specification has supersede any `w:anchor` beside it
|
|
49
|
-
*
|
|
50
|
-
* already bound to the same namespace changes nothing.
|
|
48
|
+
* specification has supersede any `w:anchor` beside it. The namespace it lives in is the part
|
|
49
|
+
* root's to bind, which `hyperlinkRefs` reports and `docx/exportDocx` sees to.
|
|
51
50
|
*/
|
|
52
51
|
export declare function withRelId(prefix: string, relId: string): string;
|
|
53
52
|
/** Which relationship each address goes out on while the body is being written */
|
|
@@ -62,6 +61,17 @@ export interface LinkRefs {
|
|
|
62
61
|
}
|
|
63
62
|
/** What a serializer called on its own, outside an export, has to work with */
|
|
64
63
|
export declare const NO_LINK_REFS: LinkRefs;
|
|
64
|
+
/**
|
|
65
|
+
* The refs a body is written through, and what the part it went into has to declare afterwards.
|
|
66
|
+
*
|
|
67
|
+
* `withRelId` puts the attribute on exactly the tag that arrived without one, and that is the tag
|
|
68
|
+
* `relIdOf` is handed a null `was` for, so what is recorded here and what is written cannot come
|
|
69
|
+
* apart.
|
|
70
|
+
*/
|
|
71
|
+
export interface LinkWriting extends LinkRefs {
|
|
72
|
+
/** Whether a link went out under an `r:id` its own opening tag did not arrive carrying */
|
|
73
|
+
addedRelId(): boolean;
|
|
74
|
+
}
|
|
65
75
|
/**
|
|
66
76
|
* Hands out the relationship for every address the body points at, adding one where the package
|
|
67
77
|
* has none.
|
|
@@ -72,4 +82,4 @@ export declare const NO_LINK_REFS: LinkRefs;
|
|
|
72
82
|
* relationship a link arrived on is kept wherever it still leads where the link now goes, so
|
|
73
83
|
* retargeting one link in a document leaves every other link's XML alone.
|
|
74
84
|
*/
|
|
75
|
-
export declare function hyperlinkRefs(relationships: RelationshipWriter):
|
|
85
|
+
export declare function hyperlinkRefs(relationships: RelationshipWriter): LinkWriting;
|
package/dist/docx/hyperlink.js
CHANGED
|
@@ -34,7 +34,7 @@ function withRelId(prefix, relId) {
|
|
|
34
34
|
return prefix.replace(REL_ID_VALUE, ` ${REL_ID_ATTR}="${relId}"`);
|
|
35
35
|
}
|
|
36
36
|
const name = "<w:hyperlink";
|
|
37
|
-
return `${name}
|
|
37
|
+
return `${name} ${REL_ID_ATTR}="${relId}"${prefix.slice(name.length)}`;
|
|
38
38
|
}
|
|
39
39
|
var NO_LINK_REFS = { relIdOf: () => void 0 };
|
|
40
40
|
function hyperlinkRefs(relationships) {
|
|
@@ -42,8 +42,11 @@ function hyperlinkRefs(relationships) {
|
|
|
42
42
|
(rel) => rel.type === HYPERLINK_REL_TYPE && rel.external
|
|
43
43
|
);
|
|
44
44
|
const added = /* @__PURE__ */ new Map();
|
|
45
|
+
let attributeAdded = false;
|
|
45
46
|
return {
|
|
47
|
+
addedRelId: () => attributeAdded,
|
|
46
48
|
relIdOf: (href, was) => {
|
|
49
|
+
if (was === null) attributeAdded = true;
|
|
47
50
|
const kept = external.find((rel) => rel.id === was);
|
|
48
51
|
if (kept?.target === href) return was ?? void 0;
|
|
49
52
|
const found = external.find((rel) => rel.target === href);
|
package/dist/docx/importDocx.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// src/docx/importDocx.ts
|
|
2
2
|
import { Fragment } from "prosemirror-model";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
bindsWritingPrefix,
|
|
5
|
+
conformanceOf,
|
|
6
|
+
STRICT_OFFICE_DOCUMENT_REL
|
|
7
|
+
} from "../ooxml/conformance.js";
|
|
4
8
|
import { DocxImportError } from "../ooxml/errors.js";
|
|
5
9
|
import {
|
|
6
10
|
childByLocalName,
|
|
@@ -23,17 +27,16 @@ import { fidelityNotesOf } from "./fidelity.js";
|
|
|
23
27
|
import {
|
|
24
28
|
formattingContextOf,
|
|
25
29
|
NO_DOCUMENT_DEFAULTS,
|
|
26
|
-
paragraphAttrsOf,
|
|
27
30
|
readDocumentDefaults,
|
|
28
31
|
readParagraphStyles,
|
|
29
|
-
|
|
30
|
-
runMarkUnder
|
|
32
|
+
styledParagraph
|
|
31
33
|
} from "./formatting.js";
|
|
32
34
|
import { readHeadersFooters } from "./headersFooters.js";
|
|
33
35
|
import { readLinkTargets } from "./hyperlink.js";
|
|
34
36
|
import { buildParagraph } from "./importParagraph.js";
|
|
35
37
|
import { buildTable } from "./importTable.js";
|
|
36
38
|
import { readImageSources } from "./media.js";
|
|
39
|
+
import { NUMBERING_REL_TYPE } from "./newLists.js";
|
|
37
40
|
import { readNotes } from "./notes.js";
|
|
38
41
|
import { readPart, relatedPartPath } from "./packageParts.js";
|
|
39
42
|
import { readBodyGeometry } from "./pageGeometry.js";
|
|
@@ -48,14 +51,20 @@ import {
|
|
|
48
51
|
import { NO_THEME_FONTS, readThemeFonts } from "./theme.js";
|
|
49
52
|
var OFFICE_DOCUMENT_REL = `${R_NS}/officeDocument`;
|
|
50
53
|
var STYLES_REL = `${R_NS}/styles`;
|
|
51
|
-
var NUMBERING_REL = `${R_NS}/numbering`;
|
|
52
54
|
var THEME_REL = `${R_NS}/theme`;
|
|
53
55
|
var SETTINGS_REL = `${R_NS}/settings`;
|
|
54
56
|
function findMainPartPath(parts) {
|
|
55
|
-
const
|
|
57
|
+
const relationships = readRelationships(parts, "_rels/.rels");
|
|
58
|
+
const target = relationships.find(
|
|
56
59
|
(rel) => rel.type === OFFICE_DOCUMENT_REL
|
|
57
60
|
)?.target;
|
|
58
61
|
if (!target) {
|
|
62
|
+
if (relationships.some((rel) => rel.type === STRICT_OFFICE_DOCUMENT_REL)) {
|
|
63
|
+
throw new DocxImportError(
|
|
64
|
+
"unsupported-conformance",
|
|
65
|
+
"the package relates its main document part as an ECMA-376 Strict one"
|
|
66
|
+
);
|
|
67
|
+
}
|
|
59
68
|
throw new DocxImportError(
|
|
60
69
|
"missing-part",
|
|
61
70
|
"no relationship pointing at the main document part"
|
|
@@ -63,6 +72,26 @@ function findMainPartPath(parts) {
|
|
|
63
72
|
}
|
|
64
73
|
return target.replace(/^\//, "");
|
|
65
74
|
}
|
|
75
|
+
function assertWritableMainPart(root) {
|
|
76
|
+
if (conformanceOf(root) === "strict") {
|
|
77
|
+
throw new DocxImportError(
|
|
78
|
+
"unsupported-conformance",
|
|
79
|
+
"the main document part is written in the ECMA-376 Strict vocabulary"
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
if (conformanceOf(root) !== "transitional" || root.localName !== "document") {
|
|
83
|
+
throw new DocxImportError(
|
|
84
|
+
"unsupported-content",
|
|
85
|
+
"the main part is not a Transitional WordprocessingML document"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (!bindsWritingPrefix(root)) {
|
|
89
|
+
throw new DocxImportError(
|
|
90
|
+
"unsupported-content",
|
|
91
|
+
"the main document part binds WordprocessingML to a prefix other than w"
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
66
95
|
function buildBlock(el, srcId, sources, context) {
|
|
67
96
|
if (el.localName === "bookmarkStart" || el.localName === "bookmarkEnd") {
|
|
68
97
|
return docxSchema.nodes.bookmarkBlock.create({
|
|
@@ -75,43 +104,18 @@ function buildBlock(el, srcId, sources, context) {
|
|
|
75
104
|
if (paragraph) return paragraph;
|
|
76
105
|
}
|
|
77
106
|
if (el.localName === "tbl") {
|
|
78
|
-
const table = buildTable(
|
|
79
|
-
el,
|
|
80
|
-
srcId,
|
|
81
|
-
sources,
|
|
82
|
-
context.styles,
|
|
83
|
-
context.defaultTableStyleId
|
|
84
|
-
);
|
|
107
|
+
const table = buildTable(el, srcId, sources, context);
|
|
85
108
|
if (table) return table;
|
|
86
109
|
}
|
|
87
110
|
return docxSchema.nodes.docxRaw.create({ srcId, name: el.nodeName });
|
|
88
111
|
}
|
|
89
|
-
function styledParagraph(node, context) {
|
|
90
|
-
const pPr = node.attrs.pPr;
|
|
91
|
-
const paragraph = resolveParagraph(
|
|
92
|
-
typeof pPr === "string" ? pPr : null,
|
|
93
|
-
context
|
|
94
|
-
);
|
|
95
|
-
const inline = node.children.map((child) => {
|
|
96
|
-
const mark = runMarkUnder(
|
|
97
|
-
child.marks.find((entry) => entry.type === docxSchema.marks.run) ?? null,
|
|
98
|
-
child.isText,
|
|
99
|
-
paragraph,
|
|
100
|
-
context
|
|
101
|
-
);
|
|
102
|
-
return mark ? child.mark(mark.addToSet(child.marks)) : child;
|
|
103
|
-
});
|
|
104
|
-
return node.type.create(
|
|
105
|
-
{ ...node.attrs, ...paragraphAttrsOf(paragraph) },
|
|
106
|
-
Fragment.fromArray(inline),
|
|
107
|
-
node.marks
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
112
|
function withStyleFormats(node, context) {
|
|
111
113
|
if (node.type === docxSchema.nodes.paragraph) {
|
|
112
114
|
return styledParagraph(node, context);
|
|
113
115
|
}
|
|
114
|
-
if (node.childCount === 0
|
|
116
|
+
if (node.childCount === 0 || node.type === docxSchema.nodes.table) {
|
|
117
|
+
return node;
|
|
118
|
+
}
|
|
115
119
|
const children = node.children.map(
|
|
116
120
|
(child) => withStyleFormats(child, context)
|
|
117
121
|
);
|
|
@@ -158,6 +162,7 @@ function readDocx(input) {
|
|
|
158
162
|
const { text: source, hadBom } = decodeUtf8(mainPart);
|
|
159
163
|
const scanned = scanBody(source);
|
|
160
164
|
const dom = parseXml(source);
|
|
165
|
+
assertWritableMainPart(dom.documentElement);
|
|
161
166
|
const body = childByLocalName(dom.documentElement, "body");
|
|
162
167
|
if (!body) {
|
|
163
168
|
throw new DocxImportError("missing-body", "document has no w:body");
|
|
@@ -178,7 +183,11 @@ function readDocx(input) {
|
|
|
178
183
|
);
|
|
179
184
|
const settingsDom = settingsXml === null ? null : parseXml(settingsXml);
|
|
180
185
|
const defaultTabStopPt = readDefaultTabStop(settingsDom) ?? DEFAULT_TAB_STOP_PT;
|
|
181
|
-
const numberingPartPath = relatedPartPath(
|
|
186
|
+
const numberingPartPath = relatedPartPath(
|
|
187
|
+
parts,
|
|
188
|
+
mainPartPath,
|
|
189
|
+
NUMBERING_REL_TYPE
|
|
190
|
+
);
|
|
182
191
|
const themeXml = readPart(
|
|
183
192
|
parts,
|
|
184
193
|
relatedPartPath(parts, mainPartPath, THEME_REL)
|
|
@@ -187,7 +196,7 @@ function readDocx(input) {
|
|
|
187
196
|
const numberingXml = readPart(parts, numberingPartPath);
|
|
188
197
|
const formatting = formattingContextOf(
|
|
189
198
|
stylesDom,
|
|
190
|
-
|
|
199
|
+
numberingXml,
|
|
191
200
|
themeFonts,
|
|
192
201
|
readCompatSettings(settingsDom)
|
|
193
202
|
);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* values for display. Unsupported grids return null so the caller can preserve their source XML.
|
|
4
4
|
*/
|
|
5
5
|
import type { Node as PMNode } from "prosemirror-model";
|
|
6
|
-
import { type
|
|
6
|
+
import { type FormattingContext } from "./formatting";
|
|
7
7
|
import { type ImportSources } from "./importParagraph";
|
|
8
8
|
/** Moves a `<w:tbl>` into a table node. null if it cannot be modelled */
|
|
9
|
-
export declare function buildTable(el: Element, srcId: string | null, sources?: ImportSources,
|
|
9
|
+
export declare function buildTable(el: Element, srcId: string | null, sources?: ImportSources, context?: FormattingContext): PMNode | null;
|
package/dist/docx/importTable.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
// src/docx/importTable.ts
|
|
2
|
-
import {
|
|
3
|
-
toCellMargins,
|
|
4
|
-
toInsideBorders
|
|
5
|
-
} from "../model/format.js";
|
|
6
2
|
import { childValue, wAttr } from "../ooxml/units.js";
|
|
7
3
|
import {
|
|
8
4
|
attrString,
|
|
@@ -13,7 +9,10 @@ import {
|
|
|
13
9
|
import { docxSchema } from "../schema/index.js";
|
|
14
10
|
import {
|
|
15
11
|
layerTableFormat,
|
|
16
|
-
|
|
12
|
+
NO_FORMATTING,
|
|
13
|
+
styledParagraph,
|
|
14
|
+
tableStyleAttrs,
|
|
15
|
+
tableStyleFor
|
|
17
16
|
} from "./formatting.js";
|
|
18
17
|
import {
|
|
19
18
|
buildParagraph,
|
|
@@ -21,18 +20,22 @@ import {
|
|
|
21
20
|
} from "./importParagraph.js";
|
|
22
21
|
import { readSdtWrapper } from "./sdt.js";
|
|
23
22
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
cellConditionsOf,
|
|
24
|
+
cellDefaultsFor,
|
|
25
|
+
layerBandSizes,
|
|
26
26
|
layerCellMargins,
|
|
27
27
|
layerInsideBorders,
|
|
28
|
+
NO_BAND_SIZES,
|
|
28
29
|
NO_CELL_MARGINS,
|
|
29
30
|
NO_INSIDE_BORDERS,
|
|
31
|
+
readBandSizes,
|
|
30
32
|
readCellFormat,
|
|
31
33
|
readCellMarginsOf,
|
|
32
34
|
readGridCols,
|
|
33
35
|
readInsideBorders,
|
|
34
36
|
readRowFormat,
|
|
35
37
|
readTableFormat,
|
|
38
|
+
readTableLook,
|
|
36
39
|
readTableWidth,
|
|
37
40
|
tblStyleIdOf
|
|
38
41
|
} from "./tableFormatting.js";
|
|
@@ -162,37 +165,31 @@ function gridWidthOf(rows) {
|
|
|
162
165
|
const first = widths[0];
|
|
163
166
|
return widths.every((width) => width === first) ? first : null;
|
|
164
167
|
}
|
|
165
|
-
function buildCellBlock(el, sources) {
|
|
168
|
+
function buildCellBlock(el, sources, context, placement) {
|
|
166
169
|
if (el.localName === "p") {
|
|
167
170
|
const paragraph = buildParagraph(el, null, sources);
|
|
168
|
-
if (paragraph) return paragraph;
|
|
171
|
+
if (paragraph) return styledParagraph(paragraph, context, placement);
|
|
169
172
|
}
|
|
170
173
|
return docxSchema.nodes.rawBlock.create({
|
|
171
174
|
xml: serializeXml(el),
|
|
172
175
|
name: el.nodeName
|
|
173
176
|
});
|
|
174
177
|
}
|
|
175
|
-
function
|
|
176
|
-
return
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
right: draft.col + draft.colspan
|
|
183
|
-
},
|
|
184
|
-
lines
|
|
185
|
-
),
|
|
186
|
-
lines.outer,
|
|
187
|
-
lines.inside
|
|
188
|
-
);
|
|
178
|
+
function cellRect(draft) {
|
|
179
|
+
return {
|
|
180
|
+
top: draft.row,
|
|
181
|
+
bottom: draft.row + draft.rowspan,
|
|
182
|
+
left: draft.col,
|
|
183
|
+
right: draft.col + draft.colspan
|
|
184
|
+
};
|
|
189
185
|
}
|
|
190
|
-
function buildCell(draft,
|
|
186
|
+
function buildCell(draft, table, sources, context) {
|
|
191
187
|
const tcPr = childByLocalName(draft.el, "tcPr");
|
|
188
|
+
const defaults = cellDefaultsFor(cellRect(draft), table.grid, table.sources);
|
|
192
189
|
const blocks = [];
|
|
193
190
|
for (const child of elementChildren(draft.el)) {
|
|
194
191
|
if (child.localName === "tcPr") continue;
|
|
195
|
-
blocks.push(buildCellBlock(child, sources));
|
|
192
|
+
blocks.push(buildCellBlock(child, sources, context, defaults.placement));
|
|
196
193
|
}
|
|
197
194
|
if (blocks.length === 0) return null;
|
|
198
195
|
return docxSchema.nodes.tableCell.create(
|
|
@@ -203,11 +200,7 @@ function buildCell(draft, lines, sources) {
|
|
|
203
200
|
tcAttrs: attrString(draft.el),
|
|
204
201
|
tcPr: tcPr ? serializeXml(tcPr) : null,
|
|
205
202
|
tcW: readTableWidth(tcPr, "tcW"),
|
|
206
|
-
format: readCellFormat(
|
|
207
|
-
tcPr,
|
|
208
|
-
cellBorderDefaultsFor(draft, lines),
|
|
209
|
-
lines.margins
|
|
210
|
-
),
|
|
203
|
+
format: readCellFormat(tcPr, defaults),
|
|
211
204
|
sdtPrefix: draft.control?.prefix ?? null,
|
|
212
205
|
sdtContentsLocked: draft.control?.contentsLocked ?? false,
|
|
213
206
|
sdtDeletionLocked: draft.control?.deletionLocked ?? false
|
|
@@ -215,10 +208,10 @@ function buildCell(draft, lines, sources) {
|
|
|
215
208
|
blocks
|
|
216
209
|
);
|
|
217
210
|
}
|
|
218
|
-
function buildRow(row, drafts,
|
|
211
|
+
function buildRow(row, drafts, table, sources, context) {
|
|
219
212
|
const cells = [];
|
|
220
213
|
for (const draft of drafts) {
|
|
221
|
-
const cell = buildCell(draft,
|
|
214
|
+
const cell = buildCell(draft, table, sources, context);
|
|
222
215
|
if (!cell) return null;
|
|
223
216
|
cells.push(cell);
|
|
224
217
|
}
|
|
@@ -233,11 +226,7 @@ function buildRow(row, drafts, lines, sources) {
|
|
|
233
226
|
cells
|
|
234
227
|
);
|
|
235
228
|
}
|
|
236
|
-
function
|
|
237
|
-
const styleId = tblStyleIdOf(tblPr);
|
|
238
|
-
return (styleId !== null ? styles.get(styleId) : void 0) ?? (defaultTableStyleId !== null ? styles.get(defaultTableStyleId) : void 0);
|
|
239
|
-
}
|
|
240
|
-
function buildTable(el, srcId, sources = NO_IMPORT_SOURCES, styles = NO_STYLES, defaultTableStyleId = null) {
|
|
229
|
+
function buildTable(el, srcId, sources = NO_IMPORT_SOURCES, context = NO_FORMATTING) {
|
|
241
230
|
const parts = readTableParts(el);
|
|
242
231
|
if (!parts) return null;
|
|
243
232
|
const gridCols = readGridCols(parts.tblGrid);
|
|
@@ -246,27 +235,38 @@ function buildTable(el, srcId, sources = NO_IMPORT_SOURCES, styles = NO_STYLES,
|
|
|
246
235
|
if (gridCols.length > 0 && gridCols.length !== width) return null;
|
|
247
236
|
const drafts = resolveVerticalMerges(parts.rows, width);
|
|
248
237
|
if (!drafts) return null;
|
|
249
|
-
const
|
|
238
|
+
const styleId = tblStyleIdOf(parts.tblPr);
|
|
239
|
+
const style = tableStyleFor(styleId, context);
|
|
250
240
|
const tableFormat = layerTableFormat(
|
|
251
241
|
style?.table ?? {},
|
|
252
242
|
readTableFormat(parts.tblPr)
|
|
253
243
|
);
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
244
|
+
const bands = layerBandSizes(
|
|
245
|
+
style?.tableBands ?? NO_BAND_SIZES,
|
|
246
|
+
readBandSizes(parts.tblPr)
|
|
247
|
+
);
|
|
248
|
+
const conditions = cellConditionsOf(style?.tableConditions ?? {});
|
|
249
|
+
const table = {
|
|
250
|
+
grid: { rows: parts.rows.length, cols: width },
|
|
251
|
+
sources: {
|
|
252
|
+
outer: tableFormat,
|
|
253
|
+
inside: layerInsideBorders(
|
|
254
|
+
style?.tableInside ?? NO_INSIDE_BORDERS,
|
|
255
|
+
readInsideBorders(parts.tblPr)
|
|
256
|
+
),
|
|
257
|
+
margins: layerCellMargins(
|
|
258
|
+
style?.tableCellMargins ?? NO_CELL_MARGINS,
|
|
259
|
+
readCellMarginsOf(parts.tblPr, "tblCellMar")
|
|
260
|
+
),
|
|
261
|
+
look: readTableLook(parts.tblPr),
|
|
262
|
+
bands,
|
|
263
|
+
conditions,
|
|
264
|
+
styleId
|
|
265
|
+
}
|
|
266
266
|
};
|
|
267
267
|
const rows = [];
|
|
268
268
|
for (const [index, row] of parts.rows.entries()) {
|
|
269
|
-
const built = buildRow(row, drafts[index],
|
|
269
|
+
const built = buildRow(row, drafts[index], table, sources, context);
|
|
270
270
|
if (!built) return null;
|
|
271
271
|
rows.push(built);
|
|
272
272
|
}
|
|
@@ -278,10 +278,7 @@ function buildTable(el, srcId, sources = NO_IMPORT_SOURCES, styles = NO_STYLES,
|
|
|
278
278
|
tblW: readTableWidth(parts.tblPr, "tblW"),
|
|
279
279
|
gridCols,
|
|
280
280
|
gridChange: parts.gridChange,
|
|
281
|
-
|
|
282
|
-
// The cells need these again whenever an edit derives their display values afresh
|
|
283
|
-
styleInside: toInsideBorders(style?.tableInside),
|
|
284
|
-
styleCellMargins: toCellMargins(style?.tableCellMargins)
|
|
281
|
+
...tableStyleAttrs(parts.tblPr, context)
|
|
285
282
|
},
|
|
286
283
|
rows
|
|
287
284
|
);
|
package/dist/docx/invariants.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/docx/invariants.ts
|
|
2
|
-
import { spanCount } from "../model/format.js";
|
|
2
|
+
import { spanCount, toParagraphFormat } from "../model/format.js";
|
|
3
3
|
import {
|
|
4
4
|
attributeByLocalName,
|
|
5
5
|
parseXml,
|
|
@@ -22,7 +22,7 @@ import { unrecordedAuthors } from "./comments/people.js";
|
|
|
22
22
|
import { currentCommentBodies } from "./comments/writing.js";
|
|
23
23
|
import { identityProblems } from "./identities.js";
|
|
24
24
|
import { insertedImageSrcs } from "./media.js";
|
|
25
|
-
import { newNumIds,
|
|
25
|
+
import { canDefineNewList, newNumIds, startedLists } from "./newLists.js";
|
|
26
26
|
import { CONTENT_TYPES_PATH } from "./packageParts.js";
|
|
27
27
|
import { lostOriginal } from "./serializeBlock.js";
|
|
28
28
|
import {
|
|
@@ -160,17 +160,24 @@ var uniqueIdentities = {
|
|
|
160
160
|
return identityProblems(doc);
|
|
161
161
|
}
|
|
162
162
|
};
|
|
163
|
-
var
|
|
164
|
-
name: "
|
|
163
|
+
var listDefinitions = {
|
|
164
|
+
name: "listDefinitions",
|
|
165
165
|
check(doc, session) {
|
|
166
|
-
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
166
|
+
const undefinedIds = new Set(startedLists(doc, session).unregistered);
|
|
167
|
+
if (undefinedIds.size === 0) return [];
|
|
168
|
+
const problems = [];
|
|
169
|
+
doc.descendants((node, pos) => {
|
|
170
|
+
if (node.type.name !== "paragraph") return true;
|
|
171
|
+
const numId = toParagraphFormat(node.attrs.format)?.numbering?.numId;
|
|
172
|
+
if (numId === void 0 || !undefinedIds.delete(numId)) return false;
|
|
173
|
+
problems.push({
|
|
174
|
+
code: "unsupported-content",
|
|
175
|
+
message: `the list numbered ${numId} has no definition to be written`,
|
|
176
|
+
pos
|
|
177
|
+
});
|
|
178
|
+
return false;
|
|
179
|
+
});
|
|
180
|
+
return problems;
|
|
174
181
|
}
|
|
175
182
|
};
|
|
176
183
|
function addsCommentsPart(doc, session) {
|
|
@@ -198,6 +205,12 @@ var mediaContentTypes = {
|
|
|
198
205
|
message: `cannot add an image to a package that has no ${CONTENT_TYPES_PATH}`
|
|
199
206
|
});
|
|
200
207
|
}
|
|
208
|
+
if (!canDefineNewList(session) && newNumIds(doc, session).length > 0) {
|
|
209
|
+
problems.push({
|
|
210
|
+
code: "missing-content-types",
|
|
211
|
+
message: `cannot add a part to a package that has no ${CONTENT_TYPES_PATH}`
|
|
212
|
+
});
|
|
213
|
+
}
|
|
201
214
|
if (addsCommentsPart(doc, session)) {
|
|
202
215
|
problems.push({
|
|
203
216
|
code: "missing-content-types",
|
|
@@ -230,7 +243,7 @@ var EXPORT_INVARIANTS = [
|
|
|
230
243
|
tableGrids,
|
|
231
244
|
preservedOriginals,
|
|
232
245
|
uniqueIdentities,
|
|
233
|
-
|
|
246
|
+
listDefinitions,
|
|
234
247
|
mediaContentTypes,
|
|
235
248
|
commentPartRoots
|
|
236
249
|
];
|