reamkit 1.16.0 → 1.18.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/esm/core/bidi/segments.js +1 -2
- package/dist/esm/core/converter/project.js +5 -1
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +526 -8
- package/dist/esm/core/drawingml/chart-geometry.d.ts +8 -12
- package/dist/esm/core/drawingml/chart-geometry.js +58 -9
- package/dist/esm/core/drawingml/chart-parser.js +44 -5
- package/dist/esm/core/drawingml/colors.d.ts +1 -1
- package/dist/esm/core/drawingml/colors.js +27 -1
- package/dist/esm/core/drawingml/preset-geometry.js +233 -0
- package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
- package/dist/esm/core/drawingml/shape-render.js +116 -3
- package/dist/esm/core/drawingml/theme-parser.d.ts +10 -0
- package/dist/esm/core/drawingml/theme-parser.js +19 -1
- package/dist/esm/core/font/measure.d.ts +5 -0
- package/dist/esm/core/font/measure.js +21 -1
- package/dist/esm/core/images.d.ts +2 -2
- package/dist/esm/core/images.js +219 -0
- package/dist/esm/core/ir/flow.d.ts +23 -1
- package/dist/esm/core/lzw.d.ts +17 -0
- package/dist/esm/core/lzw.js +83 -0
- package/dist/esm/core/metafile/emf.d.ts +16 -0
- package/dist/esm/core/metafile/emf.js +635 -0
- package/dist/esm/core/metafile/picture.d.ts +106 -0
- package/dist/esm/core/metafile/picture.js +55 -0
- package/dist/esm/core/metafile/wmf.d.ts +9 -0
- package/dist/esm/core/metafile/wmf.js +371 -0
- package/dist/esm/core/numbering/apply.d.ts +5 -3
- package/dist/esm/core/numbering/apply.js +42 -11
- package/dist/esm/core/numbering/index.js +2 -0
- package/dist/esm/core/numbering/state.d.ts +13 -1
- package/dist/esm/core/numbering/state.js +256 -15
- package/dist/esm/core/po-helpers.js +16 -1
- package/dist/esm/core/style-cascade/resolver.js +66 -11
- package/dist/esm/core/style-cascade/table.js +35 -11
- package/dist/esm/core/style-cascade/types.d.ts +42 -1
- package/dist/esm/core/style-cascade/types.js +4 -0
- package/dist/esm/core/tiff.d.ts +20 -0
- package/dist/esm/core/tiff.js +339 -0
- package/dist/esm/core/vector.d.ts +22 -0
- package/dist/esm/excel/print-model.js +4 -2
- package/dist/esm/excel/sheet-to-flow.js +10 -8
- package/dist/esm/excel/worksheet-parser.js +1 -1
- package/dist/esm/html/html-writer.js +20 -5
- package/dist/esm/layout/page-doc.d.ts +107 -4
- package/dist/esm/layout/styled-layout.d.ts +44 -2
- package/dist/esm/layout/styled-layout.js +2330 -283
- package/dist/esm/pdf/shading.js +76 -6
- package/dist/esm/pdf/styled-page-emitter.js +294 -45
- package/dist/esm/pdf/vector-graphics.d.ts +29 -2
- package/dist/esm/pdf/vector-graphics.js +96 -12
- package/dist/esm/pdf-reader/image-decode.js +7 -75
- package/dist/esm/pptx/pptx-reader.js +1 -0
- package/dist/esm/pptx/slide-parser.d.ts +21 -4
- package/dist/esm/pptx/slide-parser.js +86 -23
- package/dist/esm/svg/svg-writer.js +2 -2
- package/dist/esm/word/document-parser.d.ts +96 -7
- package/dist/esm/word/document-parser.js +540 -116
- package/dist/esm/word/docx-reader.js +135 -43
- package/dist/esm/word/docx-writer.js +6 -1
- package/dist/esm/word/drawing-parser.d.ts +58 -5
- package/dist/esm/word/drawing-parser.js +1632 -63
- package/dist/esm/word/index.d.ts +4 -4
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +107 -21
- package/dist/esm/word/paragraph-properties.d.ts +11 -1
- package/dist/esm/word/paragraph-properties.js +219 -10
- package/dist/esm/word/run-properties.js +45 -1
- package/dist/esm/word/settings-parser.d.ts +24 -0
- package/dist/esm/word/settings-parser.js +31 -5
- package/dist/esm/word/shading.d.ts +11 -0
- package/dist/esm/word/shading.js +64 -0
- package/dist/esm/word/styles-parser.js +8 -2
- package/dist/esm/word/table-parser.d.ts +9 -1
- package/dist/esm/word/table-parser.js +182 -30
- package/package.json +1 -1
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import { emuToPt, twipsToPt } from "../core/ir/units.js";
|
|
1
|
+
import { emuToPt, pt, twipsToPt } from "../core/ir/units.js";
|
|
2
2
|
import { poAttr, poAttrLocal, poChildren, poFindByPath, poFindDescendant, poIntAttr, poIs, poIsLocal, poText } from "../core/po-helpers.js";
|
|
3
3
|
import { defaultColorResolver } from "../core/drawingml/colors.js";
|
|
4
|
-
import { expandMcChildren, parseDrawing, parseVmlPicture } from "./drawing-parser.js";
|
|
5
|
-
import { diagramTransform, noDiagramOverrideLoss,
|
|
4
|
+
import { expandMcChildren, parseDrawing, parseVmlPicture, vmlFill } from "./drawing-parser.js";
|
|
5
|
+
import { diagramTransform, noDiagramOverrideLoss, parseDiagramNodes, parseTxBody } from "../pptx/slide-parser.js";
|
|
6
|
+
import { resolveInternalEntities } from "../core/opc/xml-entities.js";
|
|
6
7
|
import { parseOMath } from "./omml-parser.js";
|
|
7
8
|
import { parseRunProperties } from "./run-properties.js";
|
|
8
9
|
import { parseParagraphProperties } from "./paragraph-properties.js";
|
|
9
10
|
import { poElementToFlat } from "./po-to-flat.js";
|
|
10
|
-
import { parseTable } from "./table-parser.js";
|
|
11
|
+
import { parseBorders, parseTable } from "./table-parser.js";
|
|
11
12
|
import { XMLParser } from "fast-xml-parser";
|
|
12
13
|
//#region src/word/document-parser.ts
|
|
13
14
|
var decoder = new TextDecoder("utf-8");
|
|
15
|
+
var drawingTextParser = (txBody, resolveColor) => parseTxBody(txBody, void 0, void 0, resolveColor, void 0);
|
|
14
16
|
var parser = new XMLParser({
|
|
15
17
|
htmlEntities: true,
|
|
16
18
|
ignoreAttributes: false,
|
|
@@ -18,7 +20,8 @@ var parser = new XMLParser({
|
|
|
18
20
|
preserveOrder: true,
|
|
19
21
|
parseAttributeValue: false,
|
|
20
22
|
parseTagValue: false,
|
|
21
|
-
trimValues: false
|
|
23
|
+
trimValues: false,
|
|
24
|
+
maxNestedTags: 1e3
|
|
22
25
|
});
|
|
23
26
|
var RUN_CONTAINER_TAGS = new Set([
|
|
24
27
|
"w:hyperlink",
|
|
@@ -40,19 +43,102 @@ var DEFAULT_PARSE_CONTEXT = { resolveColor: defaultColorResolver };
|
|
|
40
43
|
* @param ctx The document-wide parse context.
|
|
41
44
|
* @returns The body elements; empty when the `w:body` is absent.
|
|
42
45
|
*/
|
|
43
|
-
function parseDocument(documentXml, ctx = DEFAULT_PARSE_CONTEXT) {
|
|
44
|
-
const xml = decoder.decode(documentXml);
|
|
45
|
-
const
|
|
46
|
-
if (
|
|
47
|
-
return parseBodyElements(
|
|
46
|
+
function parseDocument(documentXml, ctx = DEFAULT_PARSE_CONTEXT, blocks) {
|
|
47
|
+
const xml = resolveInternalEntities(decoder.decode(documentXml));
|
|
48
|
+
const children = documentBodyChildren(parser.parse(xml));
|
|
49
|
+
if (children.length === 0) return [];
|
|
50
|
+
return parseBodyElements(children, ctx, blocks);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* §17.2.2 — the `w:document`'s body content. The schema allows one `w:body`
|
|
54
|
+
* and producers have written several: MultipleBodyBug.docx carries three, and
|
|
55
|
+
* reading only the first printed one paragraph of its three. They are read as
|
|
56
|
+
* the one body they stand for, in order.
|
|
57
|
+
*
|
|
58
|
+
* @param tree The parsed `document.xml`.
|
|
59
|
+
* @returns Every body's children, concatenated.
|
|
60
|
+
*/
|
|
61
|
+
function documentBodyChildren(tree) {
|
|
62
|
+
const doc = poFindByPath(tree, ["w:document"]);
|
|
63
|
+
if (!doc) return [];
|
|
64
|
+
const out = [];
|
|
65
|
+
for (const child of poChildren(doc)) if (poIs(child, "w:body")) out.push(...poChildren(child));
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* §17.2.1 `w:background` — the colour the whole page is painted, as a six-digit
|
|
70
|
+
* hex. Read from `@w:color` (Word's own attribute), falling back to the VML
|
|
71
|
+
* `v:background @fillcolor` beside it. `auto` and a gradient-only background
|
|
72
|
+
* (which carries no flat colour of its own) both come back undefined.
|
|
73
|
+
*
|
|
74
|
+
* @param documentXml The raw `document.xml` bytes.
|
|
75
|
+
* @returns The colour, or undefined when the document names none.
|
|
76
|
+
*/
|
|
77
|
+
function parseBackgroundColor(documentXml) {
|
|
78
|
+
const bg = backgroundNode(documentXml);
|
|
79
|
+
if (!bg) return void 0;
|
|
80
|
+
const vml = poChildren(bg).find((c) => poIs(c, "v:background"));
|
|
81
|
+
const hex = (poAttr(bg, "color") ?? (vml ? poAttr(vml, "fillcolor") : void 0))?.replace(/^#/u, "");
|
|
82
|
+
return hex !== void 0 && /^[0-9A-Fa-f]{6}$/u.test(hex) ? hex.toUpperCase() : void 0;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* §17.2.1 — the page background as the FILL it is. `@w:color` is only the flat
|
|
86
|
+
* fallback: the `v:background` beside it carries the gradient or the picture
|
|
87
|
+
* Word actually paints, and both references draw those. fill.docx runs a
|
|
88
|
+
* five-stop radial sweep where we painted its fallback navy, and
|
|
89
|
+
* tdf126533_pageBitmap.docx papers the page with an image.
|
|
90
|
+
*
|
|
91
|
+
* @param documentXml The raw `document.xml` bytes.
|
|
92
|
+
* @param resolveImage Resolver for a picture background's `r:id`.
|
|
93
|
+
* @returns The fill, or undefined when the document names no background.
|
|
94
|
+
*/
|
|
95
|
+
function parseBackgroundFill(documentXml, resolveImage) {
|
|
96
|
+
const bg = backgroundNode(documentXml);
|
|
97
|
+
if (!bg || poAttr(bg, "color") === void 0) return void 0;
|
|
98
|
+
const vml = poChildren(bg).find((c) => poIs(c, "v:background"));
|
|
99
|
+
if (!vml) return void 0;
|
|
100
|
+
const fill = vmlFill(vml, void 0, resolveImage);
|
|
101
|
+
return fill.kind === "gradient" || fill.kind === "picture" ? fill : void 0;
|
|
102
|
+
}
|
|
103
|
+
function backgroundNode(documentXml) {
|
|
104
|
+
const doc = poFindByPath(parser.parse(resolveInternalEntities(decoder.decode(documentXml))), ["w:document"]);
|
|
105
|
+
return doc ? poChildren(doc).find((c) => poIs(c, "w:background")) : void 0;
|
|
106
|
+
}
|
|
107
|
+
/** A fresh {@link BlockCounter}. */
|
|
108
|
+
function newBlockCounter() {
|
|
109
|
+
return {
|
|
110
|
+
index: [],
|
|
111
|
+
next: 0
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Translate a section boundary counted in source blocks into one counted in body
|
|
116
|
+
* elements: the number of elements that came from a block before `blockEnd`.
|
|
117
|
+
*
|
|
118
|
+
* @param blocks The counter filled while parsing the body.
|
|
119
|
+
* @param blockEnd The section's `endIndex`, in source blocks.
|
|
120
|
+
* @returns The matching body-element index.
|
|
121
|
+
*/
|
|
122
|
+
function bodyIndexForBlock(blocks, blockEnd) {
|
|
123
|
+
let n = 0;
|
|
124
|
+
while (n < blocks.index.length && blocks.index[n] < blockEnd) n++;
|
|
125
|
+
return n;
|
|
48
126
|
}
|
|
49
127
|
var HF_TYPES = new Set([
|
|
50
128
|
"default",
|
|
51
129
|
"first",
|
|
52
130
|
"even"
|
|
53
131
|
]);
|
|
54
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* The empty {@link SectionProperties} fallback (no headers/footers). §17.6.13 —
|
|
134
|
+
* on the page a document with no `w:sectPr` of its own is made on, which is the
|
|
135
|
+
* same US Letter a section with no `w:pgSz` gets.
|
|
136
|
+
*/
|
|
55
137
|
var EMPTY_SECTION = {
|
|
138
|
+
pageSize: {
|
|
139
|
+
width: twipsToPt(12240),
|
|
140
|
+
height: twipsToPt(15840)
|
|
141
|
+
},
|
|
56
142
|
headers: [],
|
|
57
143
|
footers: []
|
|
58
144
|
};
|
|
@@ -67,30 +153,38 @@ var EMPTY_SECTION = {
|
|
|
67
153
|
* @returns The sections in document order; empty when the `w:body` is absent.
|
|
68
154
|
*/
|
|
69
155
|
function parseSections(documentXml) {
|
|
70
|
-
const xml = decoder.decode(documentXml);
|
|
71
|
-
const
|
|
72
|
-
if (
|
|
73
|
-
const children = poChildren(body);
|
|
156
|
+
const xml = resolveInternalEntities(decoder.decode(documentXml));
|
|
157
|
+
const children = documentBodyChildren(parser.parse(xml));
|
|
158
|
+
if (children.length === 0) return [];
|
|
74
159
|
const sections = [];
|
|
75
160
|
let bodyIdx = 0;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
161
|
+
let trailing;
|
|
162
|
+
const walk = (nodes) => {
|
|
163
|
+
for (const child of nodes) {
|
|
164
|
+
if (poIs(child, "w:sectPr")) {
|
|
165
|
+
trailing = parseSectPrNode(child);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (poIs(child, "w:p")) {
|
|
169
|
+
const pPrNode = poChildren(child).find((c) => poIs(c, "w:pPr"));
|
|
170
|
+
const sectPrInPPr = pPrNode ? poChildren(pPrNode).find((c) => poIs(c, "w:sectPr")) : void 0;
|
|
171
|
+
bodyIdx++;
|
|
172
|
+
if (sectPrInPPr) sections.push({
|
|
173
|
+
properties: parseSectPrNode(sectPrInPPr),
|
|
174
|
+
endIndex: bodyIdx
|
|
175
|
+
});
|
|
176
|
+
} else if (poIs(child, "w:tbl")) bodyIdx++;
|
|
177
|
+
else if (poIs(child, "w:sdt")) {
|
|
178
|
+
const content = poChildren(child).find((c) => poIs(c, "w:sdtContent"));
|
|
179
|
+
walk(content ? poChildren(content) : []);
|
|
180
|
+
}
|
|
83
181
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
endIndex: bodyIdx
|
|
91
|
-
});
|
|
92
|
-
} else if (poIs(child, "w:tbl")) bodyIdx++;
|
|
93
|
-
}
|
|
182
|
+
};
|
|
183
|
+
walk(children);
|
|
184
|
+
if (trailing) sections.push({
|
|
185
|
+
properties: trailing,
|
|
186
|
+
endIndex: bodyIdx
|
|
187
|
+
});
|
|
94
188
|
if (sections.length === 0 || sections[sections.length - 1].endIndex < bodyIdx) sections.push({
|
|
95
189
|
properties: EMPTY_SECTION,
|
|
96
190
|
endIndex: bodyIdx
|
|
@@ -98,10 +192,18 @@ function parseSections(documentXml) {
|
|
|
98
192
|
return sections;
|
|
99
193
|
}
|
|
100
194
|
function parseSectPrNode(sectPr) {
|
|
101
|
-
let pageSize
|
|
195
|
+
let pageSize = {
|
|
196
|
+
width: twipsToPt(12240),
|
|
197
|
+
height: twipsToPt(15840)
|
|
198
|
+
};
|
|
102
199
|
let margins;
|
|
103
200
|
let titlePg = false;
|
|
201
|
+
let pageNumberStart;
|
|
202
|
+
let lineNumbering;
|
|
104
203
|
let columns;
|
|
204
|
+
let sectionStart;
|
|
205
|
+
let pageBorders;
|
|
206
|
+
let gridLinePitchPt;
|
|
105
207
|
const headers = [];
|
|
106
208
|
const footers = [];
|
|
107
209
|
for (const child of poChildren(sectPr)) if (poIs(child, "w:pgSz")) {
|
|
@@ -120,30 +222,64 @@ function parseSectPrNode(sectPr) {
|
|
|
120
222
|
const left = poIntAttr(child, "left");
|
|
121
223
|
const header = poIntAttr(child, "header");
|
|
122
224
|
const footer = poIntAttr(child, "footer");
|
|
225
|
+
const gutter = poIntAttr(child, "gutter");
|
|
123
226
|
margins = {
|
|
124
227
|
top: twipsToPt(top ?? 1440),
|
|
125
228
|
right: twipsToPt(right ?? 1440),
|
|
126
229
|
bottom: twipsToPt(bottom ?? 1440),
|
|
127
230
|
left: twipsToPt(left ?? 1440),
|
|
128
231
|
...header !== void 0 ? { header: twipsToPt(header) } : {},
|
|
129
|
-
...footer !== void 0 ? { footer: twipsToPt(footer) } : {}
|
|
232
|
+
...footer !== void 0 ? { footer: twipsToPt(footer) } : {},
|
|
233
|
+
...gutter !== void 0 && gutter > 0 ? { gutter: twipsToPt(gutter) } : {}
|
|
130
234
|
};
|
|
131
235
|
} else if (poIs(child, "w:headerReference")) pushHeaderFooter(child, headers);
|
|
132
236
|
else if (poIs(child, "w:footerReference")) pushHeaderFooter(child, footers);
|
|
133
237
|
else if (poIs(child, "w:titlePg")) {
|
|
134
238
|
const val = poAttr(child, "val");
|
|
135
239
|
titlePg = val === void 0 || val === "" || val !== "0" && val !== "false";
|
|
240
|
+
} else if (poIs(child, "w:lnNumType")) {
|
|
241
|
+
const countBy = poIntAttr(child, "countBy") ?? 1;
|
|
242
|
+
const start = poIntAttr(child, "start") ?? 1;
|
|
243
|
+
const distance = poIntAttr(child, "distance");
|
|
244
|
+
const restartRaw = poAttr(child, "restart");
|
|
245
|
+
lineNumbering = {
|
|
246
|
+
countBy: countBy > 0 ? countBy : 1,
|
|
247
|
+
start,
|
|
248
|
+
...distance !== void 0 ? { distancePt: twipsToPt(distance) } : {},
|
|
249
|
+
restart: restartRaw === "newSection" || restartRaw === "continuous" ? restartRaw : "newPage"
|
|
250
|
+
};
|
|
251
|
+
} else if (poIs(child, "w:pgNumType")) {
|
|
252
|
+
const start = poIntAttr(child, "start");
|
|
253
|
+
if (start !== void 0) pageNumberStart = start;
|
|
136
254
|
} else if (poIs(child, "w:cols")) columns = parseColumns(child);
|
|
255
|
+
else if (poIs(child, "w:pgBorders")) {
|
|
256
|
+
const borders = parseBorders(child);
|
|
257
|
+
if (borders) pageBorders = {
|
|
258
|
+
borders,
|
|
259
|
+
offsetFrom: poAttr(child, "offsetFrom") === "page" ? "page" : "text"
|
|
260
|
+
};
|
|
261
|
+
} else if (poIs(child, "w:docGrid")) {
|
|
262
|
+
const type = poAttr(child, "type") ?? "default";
|
|
263
|
+
const pitch = poIntAttr(child, "linePitch");
|
|
264
|
+
if ((type === "lines" || type === "linesAndChars") && pitch !== void 0 && pitch > 0) gridLinePitchPt = twipsToPt(pitch);
|
|
265
|
+
} else if (poIs(child, "w:type")) sectionStart = poAttr(child, "val") === "continuous" ? "continuous" : "nextPage";
|
|
137
266
|
return {
|
|
138
|
-
|
|
267
|
+
pageSize,
|
|
139
268
|
...margins ? { margins } : {},
|
|
140
269
|
headers,
|
|
141
270
|
footers,
|
|
142
271
|
...titlePg ? { titlePg: true } : {},
|
|
143
|
-
...
|
|
272
|
+
...pageNumberStart !== void 0 ? { pageNumberStart } : {},
|
|
273
|
+
...lineNumbering ? { lineNumbering } : {},
|
|
274
|
+
...columns ? { columns } : {},
|
|
275
|
+
...sectionStart ? { sectionStart } : {},
|
|
276
|
+
...pageBorders ? { pageBorders } : {},
|
|
277
|
+
...gridLinePitchPt !== void 0 ? { gridLinePitchPt } : {}
|
|
144
278
|
};
|
|
145
279
|
}
|
|
146
280
|
function parseColumns(cols) {
|
|
281
|
+
const sepRaw = poAttr(cols, "sep");
|
|
282
|
+
const separator = sepRaw !== void 0 && sepRaw !== "0" && sepRaw !== "false";
|
|
147
283
|
const explicit = [];
|
|
148
284
|
for (const col of poChildren(cols)) {
|
|
149
285
|
if (!poIs(col, "w:col")) continue;
|
|
@@ -160,7 +296,8 @@ function parseColumns(cols) {
|
|
|
160
296
|
return {
|
|
161
297
|
count,
|
|
162
298
|
spacePt: twipsToPt(poIntAttr(cols, "space") ?? 720),
|
|
163
|
-
...explicit.length > 0 ? { explicit } : {}
|
|
299
|
+
...explicit.length > 0 ? { explicit } : {},
|
|
300
|
+
...separator ? { separator: true } : {}
|
|
164
301
|
};
|
|
165
302
|
}
|
|
166
303
|
function pushHeaderFooter(node, list) {
|
|
@@ -182,7 +319,7 @@ function pushHeaderFooter(node, list) {
|
|
|
182
319
|
* @returns The body elements; empty when neither root is found.
|
|
183
320
|
*/
|
|
184
321
|
function parseHeaderFooter(xml, ctx = DEFAULT_PARSE_CONTEXT) {
|
|
185
|
-
const root = parser.parse(decoder.decode(xml)).find((n) => poIs(n, "w:hdr") || poIs(n, "w:ftr"));
|
|
322
|
+
const root = parser.parse(resolveInternalEntities(decoder.decode(xml))).find((n) => poIs(n, "w:hdr") || poIs(n, "w:ftr"));
|
|
186
323
|
if (!root) return [];
|
|
187
324
|
return parseBodyElements(poChildren(root), ctx);
|
|
188
325
|
}
|
|
@@ -196,29 +333,57 @@ function parseHeaderFooter(xml, ctx = DEFAULT_PARSE_CONTEXT) {
|
|
|
196
333
|
* @param ctx The document-wide parse context.
|
|
197
334
|
* @returns The parsed body elements.
|
|
198
335
|
*/
|
|
199
|
-
function parseBodyElements(children, ctx = DEFAULT_PARSE_CONTEXT) {
|
|
336
|
+
function parseBodyElements(children, ctx = DEFAULT_PARSE_CONTEXT, blocks, sdtRunProps) {
|
|
200
337
|
const out = [];
|
|
338
|
+
const mark = (n) => {
|
|
339
|
+
if (!blocks) return;
|
|
340
|
+
for (let i = 0; i < n; i++) blocks.index.push(blocks.next);
|
|
341
|
+
};
|
|
201
342
|
let pendingBookmarks;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
343
|
+
let pendingPageBreak = false;
|
|
344
|
+
for (const child of children) {
|
|
345
|
+
if (poIs(child, "w:br")) {
|
|
346
|
+
if (poAttr(child, "type") === "page") pendingPageBreak = true;
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (poIs(child, "w:bookmarkStart")) {
|
|
350
|
+
const bookmarkName = poAttr(child, "name");
|
|
351
|
+
if (bookmarkName !== void 0 && bookmarkName !== "" && bookmarkName !== "_GoBack") (pendingBookmarks ??= []).push(bookmarkName);
|
|
352
|
+
} else if (poIs(child, "w:p")) {
|
|
353
|
+
const drawings = tryExtractDrawingFromParagraph(child, ctx);
|
|
354
|
+
if (drawings) {
|
|
355
|
+
out.push(...drawings);
|
|
356
|
+
mark(drawings.length);
|
|
357
|
+
} else {
|
|
358
|
+
const anchored = [];
|
|
359
|
+
const parsed = parseParagraph(child, ctx, pendingBookmarks, anchored, sdtRunProps);
|
|
360
|
+
const paragraph = pendingPageBreak ? {
|
|
361
|
+
...parsed,
|
|
362
|
+
properties: {
|
|
363
|
+
...parsed.properties,
|
|
364
|
+
pageBreakBefore: true
|
|
365
|
+
}
|
|
366
|
+
} : parsed;
|
|
367
|
+
pendingPageBreak = false;
|
|
368
|
+
out.push(...anchored, {
|
|
369
|
+
kind: "paragraph",
|
|
370
|
+
paragraph
|
|
371
|
+
});
|
|
372
|
+
mark(anchored.length + 1);
|
|
373
|
+
pendingBookmarks = void 0;
|
|
374
|
+
}
|
|
375
|
+
if (blocks) blocks.next++;
|
|
376
|
+
} else if (poIs(child, "w:tbl")) {
|
|
209
377
|
out.push({
|
|
210
|
-
kind: "
|
|
211
|
-
|
|
378
|
+
kind: "table",
|
|
379
|
+
table: parseTable(child, ctx)
|
|
212
380
|
});
|
|
213
|
-
|
|
381
|
+
mark(1);
|
|
382
|
+
if (blocks) blocks.next++;
|
|
383
|
+
} else if (poIs(child, "w:sdt")) {
|
|
384
|
+
const content = poChildren(child).find((c) => poIs(c, "w:sdtContent"));
|
|
385
|
+
if (content) out.push(...parseBodyElements(poChildren(content), ctx, blocks, sdtRunProps));
|
|
214
386
|
}
|
|
215
|
-
} else if (poIs(child, "w:tbl")) out.push({
|
|
216
|
-
kind: "table",
|
|
217
|
-
table: parseTable(child, ctx)
|
|
218
|
-
});
|
|
219
|
-
else if (poIs(child, "w:sdt")) {
|
|
220
|
-
const content = poChildren(child).find((c) => poIs(c, "w:sdtContent"));
|
|
221
|
-
if (content) out.push(...parseBodyElements(poChildren(content), ctx));
|
|
222
387
|
}
|
|
223
388
|
return out;
|
|
224
389
|
}
|
|
@@ -233,12 +398,11 @@ function scanForLoneDrawing(container, acc) {
|
|
|
233
398
|
for (const child of expandMcChildren(poChildren(container))) {
|
|
234
399
|
if (poIs(child, "w:pPr")) continue;
|
|
235
400
|
if (poIs(child, "w:r")) {
|
|
236
|
-
for (const rc of expandMcChildren(poChildren(child))) if (poIs(rc, "w:drawing"))
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if (!acc.vml && poFindDescendant(rc, "v:imagedata") !== void 0) acc.vml = rc;
|
|
401
|
+
for (const rc of expandMcChildren(poChildren(child))) if (poIs(rc, "w:drawing")) acc.drawings.push(rc);
|
|
402
|
+
else if (poIs(rc, "w:pict") || poIs(rc, "w:object")) {
|
|
403
|
+
if (!acc.vml && (poFindDescendant(rc, "v:imagedata") ?? poFindDescendant(rc, "v:textpath")) !== void 0) acc.vml = rc;
|
|
240
404
|
} else if (poIs(rc, "w:t") && poText(rc).length > 0) acc.hasOther = true;
|
|
241
|
-
else if (poIs(rc, "w:tab") || poIs(rc, "w:br") || poIs(rc, "w:noBreakHyphen")) acc.hasOther = true;
|
|
405
|
+
else if (poIs(rc, "w:tab") || poIs(rc, "w:ptab") || poIs(rc, "w:br") || poIs(rc, "w:noBreakHyphen")) acc.hasOther = true;
|
|
242
406
|
continue;
|
|
243
407
|
}
|
|
244
408
|
if (poIs(child, "m:oMath") || poIs(child, "m:oMathPara")) {
|
|
@@ -251,25 +415,57 @@ function scanForLoneDrawing(container, acc) {
|
|
|
251
415
|
}
|
|
252
416
|
}
|
|
253
417
|
function tryExtractDrawingFromParagraph(p, ctx) {
|
|
254
|
-
const scan = {
|
|
418
|
+
const scan = {
|
|
419
|
+
hasOther: false,
|
|
420
|
+
drawings: []
|
|
421
|
+
};
|
|
255
422
|
scanForLoneDrawing(p, scan);
|
|
256
|
-
const {
|
|
257
|
-
if (scan.hasOther ||
|
|
258
|
-
|
|
423
|
+
const { drawings, vml } = scan;
|
|
424
|
+
if (scan.hasOther || drawings.length === 0 && !vml) return null;
|
|
425
|
+
if (!vml && drawings.every((d) => poChildren(d).some((c) => poIs(c, "wp:anchor")))) return null;
|
|
259
426
|
const parseBody = (children) => parseBodyElements(children, ctx);
|
|
260
|
-
const content = fromVml ? parseVmlPicture(vml) : parseDrawing(drawing, ctx.resolveColor, parseBody);
|
|
261
|
-
if (!content) return null;
|
|
262
|
-
if (fromVml && content.kind === "image" && ctx.resolveImage?.(content.imageId) === void 0) return null;
|
|
263
427
|
const pPrNode = poChildren(p).find((c) => poIs(c, "w:pPr"));
|
|
264
|
-
const paragraphProperties = pPrNode ? parseParagraphProperties(poElementToFlat(pPrNode)) : {};
|
|
428
|
+
const paragraphProperties = pPrNode ? parseParagraphProperties(poElementToFlat(pPrNode), ctx.autoSpacingPt) : {};
|
|
429
|
+
if (drawings.length === 0) {
|
|
430
|
+
const content = parseVmlPicture(vml, parseBody);
|
|
431
|
+
if (!content) return null;
|
|
432
|
+
if (content.kind === "image" && ctx.resolveImage?.(content.imageId) === void 0) return null;
|
|
433
|
+
return blocksForDrawing(content, paragraphProperties, ctx);
|
|
434
|
+
}
|
|
435
|
+
const contents = drawings.map((d) => parseDrawing(d, ctx.resolveColor, parseBody, ctx.resolveImage, ctx.resolveChartPart, ctx.themeLineWidths, ctx.themeStyles, drawingTextParser)).filter((c) => c !== null);
|
|
436
|
+
if (contents.length > 1 && contents.some((c) => !c.float)) return null;
|
|
437
|
+
const out = [];
|
|
438
|
+
for (const content of contents) out.push(...blocksForDrawing(content, paragraphProperties, ctx) ?? []);
|
|
439
|
+
return out.length > 0 ? out : null;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* One parsed drawing as the body elements it becomes: a picture, a chart, a
|
|
443
|
+
* shape, or the several shapes a SmartArt diagram draws.
|
|
444
|
+
*
|
|
445
|
+
* @param content The parsed drawing.
|
|
446
|
+
* @param paragraphProperties The owning paragraph's properties, which a block
|
|
447
|
+
* carries for its spacing and alignment.
|
|
448
|
+
* @param ctx The document-wide parse context.
|
|
449
|
+
* @returns The blocks, or `null` when the drawing renders nothing.
|
|
450
|
+
*/
|
|
451
|
+
function blocksForDrawing(content, paragraphProperties, ctx) {
|
|
265
452
|
if (content.kind === "image") {
|
|
266
453
|
const resource = ctx.resolveImage?.(content.imageId);
|
|
267
454
|
return [{
|
|
268
455
|
kind: "image",
|
|
269
456
|
image: {
|
|
270
457
|
...resource ? { resource } : {},
|
|
458
|
+
...content.outline ? { outline: content.outline } : {},
|
|
459
|
+
...content.shadow ? { shadow: content.shadow } : {},
|
|
460
|
+
...content.wash ? { wash: content.wash } : {},
|
|
271
461
|
width: content.width,
|
|
272
462
|
height: content.height,
|
|
463
|
+
...content.crop ? { crop: content.crop } : {},
|
|
464
|
+
...content.rotation60k ? { rotation60k: content.rotation60k } : {},
|
|
465
|
+
...content.flipH ? { flipH: true } : {},
|
|
466
|
+
...content.flipV ? { flipV: true } : {},
|
|
467
|
+
...content.relativeSize ? { relativeSize: content.relativeSize } : {},
|
|
468
|
+
...content.effectExtent ? { effectExtent: content.effectExtent } : {},
|
|
273
469
|
paragraphProperties,
|
|
274
470
|
...content.altText ? { altText: content.altText } : {},
|
|
275
471
|
...content.float ? { float: content.float } : {}
|
|
@@ -288,31 +484,39 @@ function tryExtractDrawingFromParagraph(p, ctx) {
|
|
|
288
484
|
}
|
|
289
485
|
}];
|
|
290
486
|
if (content.kind === "diagram") {
|
|
291
|
-
const
|
|
292
|
-
if (!
|
|
487
|
+
const diagram = ctx.resolveDiagram?.(content.dmRelId);
|
|
488
|
+
if (!diagram) {
|
|
293
489
|
ctx.onLoss?.(noDiagramOverrideLoss());
|
|
294
490
|
return null;
|
|
295
491
|
}
|
|
296
|
-
const
|
|
492
|
+
const frame = {
|
|
297
493
|
x: 0,
|
|
298
494
|
y: 0,
|
|
299
495
|
cx: content.widthEmu,
|
|
300
496
|
cy: content.heightEmu
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
relativeFrom: "column",
|
|
305
|
-
offsetPt: emuToPt(box.x)
|
|
306
|
-
},
|
|
307
|
-
posV: {
|
|
308
|
-
relativeFrom: "paragraph",
|
|
309
|
-
offsetPt: emuToPt(box.y)
|
|
310
|
-
}
|
|
311
|
-
}), ctx.resolveColor, void 0);
|
|
312
|
-
return shapes.length > 0 ? shapes.map((shape) => ({
|
|
497
|
+
};
|
|
498
|
+
const nodes = parseDiagramNodes(diagram.spTree, diagramTransform(diagram.spTree, frame), ctx.resolveColor, void 0, diagram.resolveImage);
|
|
499
|
+
return [{
|
|
313
500
|
kind: "shape",
|
|
314
|
-
shape
|
|
315
|
-
|
|
501
|
+
shape: {
|
|
502
|
+
width: emuToPt(content.widthEmu),
|
|
503
|
+
height: emuToPt(content.heightEmu),
|
|
504
|
+
children: nodes.map(({ box, shape }) => ({
|
|
505
|
+
shape,
|
|
506
|
+
xPt: emuToPt(box.x),
|
|
507
|
+
yPt: emuToPt(box.y)
|
|
508
|
+
})),
|
|
509
|
+
geometry: {
|
|
510
|
+
kind: "preset",
|
|
511
|
+
preset: "rect",
|
|
512
|
+
adjust: /* @__PURE__ */ new Map()
|
|
513
|
+
},
|
|
514
|
+
fill: { kind: "none" },
|
|
515
|
+
paragraphProperties,
|
|
516
|
+
...content.altText ? { altText: content.altText } : {},
|
|
517
|
+
...content.float ? { float: content.float } : {}
|
|
518
|
+
}
|
|
519
|
+
}];
|
|
316
520
|
}
|
|
317
521
|
return [{
|
|
318
522
|
kind: "shape",
|
|
@@ -324,7 +528,7 @@ function tryExtractDrawingFromParagraph(p, ctx) {
|
|
|
324
528
|
}
|
|
325
529
|
}];
|
|
326
530
|
}
|
|
327
|
-
function parseParagraph(p, ctx, extraBookmarks) {
|
|
531
|
+
function parseParagraph(p, ctx, extraBookmarks, anchored, sdtRunProps) {
|
|
328
532
|
const bookmarks = [...extraBookmarks ?? []];
|
|
329
533
|
for (const child of poChildren(p)) {
|
|
330
534
|
if (!poIs(child, "w:bookmarkStart")) continue;
|
|
@@ -332,7 +536,11 @@ function parseParagraph(p, ctx, extraBookmarks) {
|
|
|
332
536
|
if (bookmarkName !== void 0 && bookmarkName !== "" && bookmarkName !== "_GoBack") bookmarks.push(bookmarkName);
|
|
333
537
|
}
|
|
334
538
|
const pPr = poChildren(p).find((c) => poIs(c, "w:pPr"));
|
|
335
|
-
let properties = parseParagraphProperties(pPr ? poElementToFlat(pPr) : void 0);
|
|
539
|
+
let properties = parseParagraphProperties(pPr ? poElementToFlat(pPr) : void 0, ctx.autoSpacingPt);
|
|
540
|
+
if (pPr && poChildren(pPr).some((c) => poIs(c, "w:sectPr"))) properties = {
|
|
541
|
+
...properties,
|
|
542
|
+
sectionBreak: true
|
|
543
|
+
};
|
|
336
544
|
const mathPara = poChildren(p).find((c) => poIs(c, "m:oMathPara"));
|
|
337
545
|
if (mathPara && properties.alignment === void 0) {
|
|
338
546
|
const paraPr = poChildren(mathPara).find((c) => poIs(c, "m:oMathParaPr"));
|
|
@@ -343,19 +551,79 @@ function parseParagraph(p, ctx, extraBookmarks) {
|
|
|
343
551
|
alignment
|
|
344
552
|
};
|
|
345
553
|
}
|
|
554
|
+
const pTabs = collectPositionTabs(p);
|
|
555
|
+
if (pTabs.length > 0) properties = {
|
|
556
|
+
...properties,
|
|
557
|
+
tabs: [...properties.tabs ?? [], ...pTabs]
|
|
558
|
+
};
|
|
346
559
|
const collected = [];
|
|
347
|
-
collectRuns(p, collected, ctx);
|
|
560
|
+
collectRuns(p, collected, ctx, void 0, void 0, anchored, sdtRunProps);
|
|
348
561
|
return {
|
|
349
562
|
properties,
|
|
350
563
|
runs: applyFieldFsm(collected),
|
|
351
564
|
...bookmarks.length > 0 ? { bookmarks } : {}
|
|
352
565
|
};
|
|
353
566
|
}
|
|
567
|
+
/**
|
|
568
|
+
* §17.3.3.15 `w:ptab` — the absolute-position tabs a paragraph holds, as stops.
|
|
569
|
+
*
|
|
570
|
+
* `@w:alignment` says which edge of the text column the tab reaches for; the
|
|
571
|
+
* `left` alignment reaches for no edge at all (it goes to where the text
|
|
572
|
+
* already is) and states no stop. `@w:relativeTo` distinguishes the margin from
|
|
573
|
+
* the paragraph's indent, which for a stop measured from the text margin is the
|
|
574
|
+
* same place.
|
|
575
|
+
*
|
|
576
|
+
* @param p The `w:p` element.
|
|
577
|
+
* @returns One stop per position tab, in document order.
|
|
578
|
+
*/
|
|
579
|
+
function collectPositionTabs(p) {
|
|
580
|
+
const out = [];
|
|
581
|
+
const visit = (node) => {
|
|
582
|
+
for (const child of poChildren(node)) {
|
|
583
|
+
if (poIs(child, "w:ptab")) {
|
|
584
|
+
const alignment = poAttr(child, "alignment");
|
|
585
|
+
if (alignment === "center" || alignment === "right") out.push({
|
|
586
|
+
positionPt: pt(0),
|
|
587
|
+
alignment,
|
|
588
|
+
relativeTo: alignment
|
|
589
|
+
});
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
if (poIs(child, "w:r") || poIs(child, "w:hyperlink") || poIs(child, "w:ins")) visit(child);
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
visit(p);
|
|
596
|
+
return out;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* §17.16.5.44 `MACROBUTTON macroName displayText` — the display text, which is
|
|
600
|
+
* everything after the macro's name and is all a reader ever sees of the field.
|
|
601
|
+
*
|
|
602
|
+
* @param instr The field instruction.
|
|
603
|
+
* @returns The display text, or `undefined` when this is not a MACROBUTTON.
|
|
604
|
+
*/
|
|
605
|
+
function macroButtonText(instr) {
|
|
606
|
+
const shown = /^\s*MACROBUTTON\s+\S+\s(.*)$/su.exec(instr)?.[1]?.replace(/\s+$/u, "");
|
|
607
|
+
return shown !== void 0 && shown !== "" ? shown : void 0;
|
|
608
|
+
}
|
|
354
609
|
function parseFieldInstr(instr) {
|
|
355
|
-
|
|
356
|
-
const kw = /^\s*([A-Za-z]+)/.exec(instr)?.[1]?.toUpperCase();
|
|
610
|
+
const kw = fieldKeyword(instr);
|
|
357
611
|
return kw === "PAGE" ? "PAGE" : kw === "NUMPAGES" ? "NUMPAGES" : void 0;
|
|
358
612
|
}
|
|
613
|
+
function fieldKeyword(instr) {
|
|
614
|
+
if (instr === void 0) return void 0;
|
|
615
|
+
return /^\s*([A-Za-z]+)/.exec(instr)?.[1]?.toUpperCase();
|
|
616
|
+
}
|
|
617
|
+
var CHECKBOX_CLEAR = "☐";
|
|
618
|
+
var CHECKBOX_CHECKED = "☒";
|
|
619
|
+
var SILENT_FIELDS = new Set([
|
|
620
|
+
"SET",
|
|
621
|
+
"ASK",
|
|
622
|
+
"XE",
|
|
623
|
+
"TC",
|
|
624
|
+
"RD",
|
|
625
|
+
"PRIVATE"
|
|
626
|
+
]);
|
|
359
627
|
function synthesizeFieldRun(result, field, href) {
|
|
360
628
|
const first = result[0];
|
|
361
629
|
const linked = href ?? result.find((r) => r.href !== void 0)?.href;
|
|
@@ -385,7 +653,9 @@ function applyFieldFsm(collected) {
|
|
|
385
653
|
phase: "instr",
|
|
386
654
|
instr: "",
|
|
387
655
|
result: [],
|
|
388
|
-
depth: 0
|
|
656
|
+
depth: 0,
|
|
657
|
+
...c.checkBox !== void 0 ? { checkBox: c.checkBox } : {},
|
|
658
|
+
properties: c.run.properties
|
|
389
659
|
};
|
|
390
660
|
continue;
|
|
391
661
|
}
|
|
@@ -403,8 +673,20 @@ function applyFieldFsm(collected) {
|
|
|
403
673
|
continue;
|
|
404
674
|
}
|
|
405
675
|
const field = parseFieldInstr(st.instr);
|
|
406
|
-
if (field) out.push(synthesizeFieldRun(st.result, field));
|
|
407
|
-
else out.push(...st.result);
|
|
676
|
+
if (SILENT_FIELDS.has(fieldKeyword(st.instr) ?? "")) {} else if (field) out.push(synthesizeFieldRun(st.result, field));
|
|
677
|
+
else if (st.result.length > 0) out.push(...st.result);
|
|
678
|
+
else {
|
|
679
|
+
const shown = macroButtonText(st.instr);
|
|
680
|
+
const box = fieldKeyword(st.instr) === "FORMCHECKBOX" && st.checkBox !== void 0 ? st.checkBox ? CHECKBOX_CHECKED : CHECKBOX_CLEAR : void 0;
|
|
681
|
+
if (shown !== void 0) out.push({
|
|
682
|
+
text: shown,
|
|
683
|
+
properties: {}
|
|
684
|
+
});
|
|
685
|
+
else if (box !== void 0) out.push({
|
|
686
|
+
text: box,
|
|
687
|
+
properties: st.properties ?? {}
|
|
688
|
+
});
|
|
689
|
+
}
|
|
408
690
|
st = null;
|
|
409
691
|
continue;
|
|
410
692
|
}
|
|
@@ -417,7 +699,7 @@ function applyFieldFsm(collected) {
|
|
|
417
699
|
if (st) out.push(...st.result);
|
|
418
700
|
return out;
|
|
419
701
|
}
|
|
420
|
-
function collectRuns(container, out, ctx, href, anchor) {
|
|
702
|
+
function collectRuns(container, out, ctx, href, anchor, anchored, sdtRunProps) {
|
|
421
703
|
for (const child of poChildren(container)) {
|
|
422
704
|
if (poIs(child, "w:pPr")) continue;
|
|
423
705
|
if (poIs(child, "w:commentRangeStart")) {
|
|
@@ -431,10 +713,14 @@ function collectRuns(container, out, ctx, href, anchor) {
|
|
|
431
713
|
continue;
|
|
432
714
|
}
|
|
433
715
|
if (poIs(child, "w:r")) {
|
|
434
|
-
const parsed = parseRun(child, ctx);
|
|
716
|
+
const parsed = parseRun(child, ctx, anchored);
|
|
435
717
|
const ranges = ctx.openCommentRanges && ctx.openCommentRanges.size > 0 ? [...ctx.openCommentRanges] : void 0;
|
|
436
|
-
const run = href !== void 0 || anchor !== void 0 || ranges !== void 0 ? {
|
|
718
|
+
const run = href !== void 0 || anchor !== void 0 || ranges !== void 0 || sdtRunProps ? {
|
|
437
719
|
...parsed.run,
|
|
720
|
+
...sdtRunProps ? { properties: {
|
|
721
|
+
...sdtRunProps,
|
|
722
|
+
...parsed.run.properties
|
|
723
|
+
} } : {},
|
|
438
724
|
...href !== void 0 ? { href } : {},
|
|
439
725
|
...anchor !== void 0 ? { anchor } : {},
|
|
440
726
|
...ranges !== void 0 ? { commentRangeRefs: ranges } : {}
|
|
@@ -442,7 +728,8 @@ function collectRuns(container, out, ctx, href, anchor) {
|
|
|
442
728
|
out.push({
|
|
443
729
|
run,
|
|
444
730
|
...parsed.fldChar ? { fldChar: parsed.fldChar } : {},
|
|
445
|
-
...parsed.instrText !== void 0 ? { instrText: parsed.instrText } : {}
|
|
731
|
+
...parsed.instrText !== void 0 ? { instrText: parsed.instrText } : {},
|
|
732
|
+
...parsed.checkBox !== void 0 ? { checkBox: parsed.checkBox } : {}
|
|
446
733
|
});
|
|
447
734
|
continue;
|
|
448
735
|
}
|
|
@@ -467,11 +754,11 @@ function collectRuns(container, out, ctx, href, anchor) {
|
|
|
467
754
|
const field = parseFieldInstr(poAttr(child, "instr"));
|
|
468
755
|
if (field) {
|
|
469
756
|
const inner = [];
|
|
470
|
-
collectRuns(child, inner, ctx, href, anchor);
|
|
757
|
+
collectRuns(child, inner, ctx, href, anchor, anchored, sdtRunProps);
|
|
471
758
|
out.push({ run: synthesizeFieldRun(applyFieldFsm(inner), field, href) });
|
|
472
759
|
continue;
|
|
473
760
|
}
|
|
474
|
-
collectRuns(child, out, ctx, href, anchor);
|
|
761
|
+
collectRuns(child, out, ctx, href, anchor, anchored, sdtRunProps);
|
|
475
762
|
continue;
|
|
476
763
|
}
|
|
477
764
|
if (tag && RUN_CONTAINER_TAGS.has(tag)) {
|
|
@@ -486,18 +773,111 @@ function collectRuns(container, out, ctx, href, anchor) {
|
|
|
486
773
|
if (bookmark !== void 0 && bookmark !== "") childAnchor = bookmark;
|
|
487
774
|
}
|
|
488
775
|
}
|
|
489
|
-
|
|
776
|
+
const childProps = tag === "w:sdt" ? sdtRunProperties(child) ?? sdtRunProps : sdtRunProps;
|
|
777
|
+
collectRuns(child, out, ctx, childHref, childAnchor, anchored, childProps);
|
|
490
778
|
}
|
|
491
779
|
}
|
|
492
780
|
}
|
|
493
|
-
|
|
781
|
+
/**
|
|
782
|
+
* §17.5.2.28 `w:sdt/w:sdtPr/w:rPr` — the run properties a content control
|
|
783
|
+
* lends what it holds, when it states any.
|
|
784
|
+
*
|
|
785
|
+
* @param sdt The `w:sdt` element.
|
|
786
|
+
* @returns The properties, or `undefined` when the control states none.
|
|
787
|
+
*/
|
|
788
|
+
function sdtRunProperties(sdt) {
|
|
789
|
+
const sdtPr = poChildren(sdt).find((c) => poIs(c, "w:sdtPr"));
|
|
790
|
+
const rPr = sdtPr ? poChildren(sdtPr).find((c) => poIs(c, "w:rPr")) : void 0;
|
|
791
|
+
if (!rPr) return void 0;
|
|
792
|
+
const props = parseRunProperties(poElementToFlat(rPr));
|
|
793
|
+
return Object.keys(props).length > 0 ? props : void 0;
|
|
794
|
+
}
|
|
795
|
+
var WINGDINGS_TO_UNICODE = new Map([
|
|
796
|
+
[108, "●"],
|
|
797
|
+
[109, "❍"],
|
|
798
|
+
[110, "■"],
|
|
799
|
+
[113, "❑"],
|
|
800
|
+
[115, "□"],
|
|
801
|
+
[116, "❒"],
|
|
802
|
+
[118, "❖"],
|
|
803
|
+
[167, "▪"],
|
|
804
|
+
[168, "▫"],
|
|
805
|
+
[252, "✔"],
|
|
806
|
+
[253, "✖"],
|
|
807
|
+
[254, "☒"],
|
|
808
|
+
[251, "☑"],
|
|
809
|
+
[224, "⇦"],
|
|
810
|
+
[225, "⇨"],
|
|
811
|
+
[226, "⇧"],
|
|
812
|
+
[227, "⇩"],
|
|
813
|
+
[231, "←"],
|
|
814
|
+
[232, "→"],
|
|
815
|
+
[233, "↑"],
|
|
816
|
+
[234, "↓"],
|
|
817
|
+
[235, "↖"],
|
|
818
|
+
[236, "↗"],
|
|
819
|
+
[237, "↙"],
|
|
820
|
+
[238, "↘"]
|
|
821
|
+
]);
|
|
822
|
+
var SYMBOL_TO_UNICODE = new Map([
|
|
823
|
+
[34, "∀"],
|
|
824
|
+
[36, "∃"],
|
|
825
|
+
[64, "≅"],
|
|
826
|
+
[92, "∴"],
|
|
827
|
+
[97, "α"],
|
|
828
|
+
[98, "β"],
|
|
829
|
+
[99, "χ"],
|
|
830
|
+
[100, "δ"],
|
|
831
|
+
[101, "ε"],
|
|
832
|
+
[102, "φ"],
|
|
833
|
+
[103, "γ"],
|
|
834
|
+
[104, "η"],
|
|
835
|
+
[105, "ι"],
|
|
836
|
+
[107, "κ"],
|
|
837
|
+
[108, "λ"],
|
|
838
|
+
[109, "μ"],
|
|
839
|
+
[110, "ν"],
|
|
840
|
+
[111, "ο"],
|
|
841
|
+
[112, "π"],
|
|
842
|
+
[113, "θ"],
|
|
843
|
+
[114, "ρ"],
|
|
844
|
+
[115, "σ"],
|
|
845
|
+
[116, "τ"],
|
|
846
|
+
[117, "υ"],
|
|
847
|
+
[119, "ω"],
|
|
848
|
+
[120, "ξ"],
|
|
849
|
+
[121, "ψ"],
|
|
850
|
+
[122, "ζ"],
|
|
851
|
+
[165, "∞"],
|
|
852
|
+
[177, "±"],
|
|
853
|
+
[179, "≥"],
|
|
854
|
+
[180, "×"],
|
|
855
|
+
[183, "•"],
|
|
856
|
+
[184, "÷"],
|
|
857
|
+
[185, "≠"],
|
|
858
|
+
[186, "≡"],
|
|
859
|
+
[187, "≈"],
|
|
860
|
+
[214, "√"],
|
|
861
|
+
[229, "∑"]
|
|
862
|
+
]);
|
|
863
|
+
function symbolChar(font, char) {
|
|
864
|
+
const cp = char !== void 0 ? Number.parseInt(char, 16) : NaN;
|
|
865
|
+
if (!Number.isFinite(cp) || cp <= 0) return "";
|
|
866
|
+
const low = cp & 255;
|
|
867
|
+
const mapped = (/wingdings|webdings|zapf/iu.test(font ?? "") ? WINGDINGS_TO_UNICODE : /symbol/iu.test(font ?? "") ? SYMBOL_TO_UNICODE : void 0)?.get(low);
|
|
868
|
+
if (mapped !== void 0) return mapped;
|
|
869
|
+
return String.fromCodePoint(cp);
|
|
870
|
+
}
|
|
871
|
+
function parseRun(r, ctx, anchored) {
|
|
494
872
|
const rPr = poChildren(r).find((c) => poIs(c, "w:rPr"));
|
|
495
873
|
const properties = parseRunProperties(rPr ? poElementToFlat(rPr) : void 0);
|
|
496
874
|
let text = "";
|
|
497
875
|
let pageBreak = false;
|
|
876
|
+
let columnBreak = false;
|
|
498
877
|
let inlineImage;
|
|
499
878
|
let fldChar;
|
|
500
879
|
let instrText;
|
|
880
|
+
let checkBox;
|
|
501
881
|
let footnoteRef;
|
|
502
882
|
let endnoteRef;
|
|
503
883
|
let commentRef;
|
|
@@ -507,6 +887,7 @@ function parseRun(r, ctx) {
|
|
|
507
887
|
if (poIs(child, "w:fldChar")) {
|
|
508
888
|
const t = poAttr(child, "fldCharType");
|
|
509
889
|
if (t === "begin" || t === "separate" || t === "end") fldChar = t;
|
|
890
|
+
if (t === "begin") checkBox = fieldCheckBoxState(child);
|
|
510
891
|
continue;
|
|
511
892
|
}
|
|
512
893
|
if (poIs(child, "w:instrText")) {
|
|
@@ -534,30 +915,51 @@ function parseRun(r, ctx) {
|
|
|
534
915
|
}
|
|
535
916
|
if (poIs(child, "w:t")) text += poText(child);
|
|
536
917
|
else if (poIs(child, "w:tab")) text += " ";
|
|
537
|
-
else if (poIs(child, "w:
|
|
538
|
-
else
|
|
918
|
+
else if (poIs(child, "w:ptab")) text += " ";
|
|
919
|
+
else if (poIs(child, "w:br")) {
|
|
920
|
+
const breakType = poAttr(child, "type");
|
|
921
|
+
if (breakType === "page") pageBreak = true;
|
|
922
|
+
else {
|
|
923
|
+
if (breakType === "column") columnBreak = true;
|
|
924
|
+
text += "\n";
|
|
925
|
+
}
|
|
926
|
+
} else if (poIs(child, "w:sym")) text += symbolChar(poAttr(child, "font"), poAttr(child, "char"));
|
|
539
927
|
else if (poIs(child, "w:noBreakHyphen")) text += "‑";
|
|
540
928
|
else if (poIs(child, "w:softHyphen")) text += "";
|
|
541
929
|
else if (poIs(child, "w:drawing")) {
|
|
542
|
-
const content = parseDrawing(child,
|
|
543
|
-
if (content && content
|
|
930
|
+
const content = parseDrawing(child, ctx.resolveColor, (children) => parseBodyElements(children, ctx), ctx.resolveImage, ctx.resolveChartPart, ctx.themeLineWidths, ctx.themeStyles, drawingTextParser);
|
|
931
|
+
if (content?.float && anchored) anchored.push(...blocksForDrawing(content, {}, ctx) ?? []);
|
|
932
|
+
else if ((content?.kind === "chart" || content?.kind === "shape" || content?.kind === "diagram") && anchored) anchored.push(...blocksForDrawing(content, {}, ctx) ?? []);
|
|
933
|
+
else if (content && content.kind === "image") {
|
|
544
934
|
const resource = ctx.resolveImage?.(content.imageId);
|
|
545
935
|
inlineImage = {
|
|
546
936
|
...resource ? { resource } : {},
|
|
937
|
+
...content.outline ? { outline: content.outline } : {},
|
|
938
|
+
...content.shadow ? { shadow: content.shadow } : {},
|
|
939
|
+
...content.wash ? { wash: content.wash } : {},
|
|
547
940
|
width: content.width,
|
|
548
|
-
height: content.height
|
|
941
|
+
height: content.height,
|
|
942
|
+
...content.crop ? { crop: content.crop } : {},
|
|
943
|
+
...content.rotation60k ? { rotation60k: content.rotation60k } : {},
|
|
944
|
+
...content.flipH ? { flipH: true } : {},
|
|
945
|
+
...content.flipV ? { flipV: true } : {},
|
|
946
|
+
...content.effectExtent ? { effectExtent: content.effectExtent } : {}
|
|
549
947
|
};
|
|
550
948
|
}
|
|
551
949
|
} else if (poIs(child, "w:pict") || poIs(child, "w:object")) {
|
|
552
|
-
const content = parseVmlPicture(child);
|
|
553
|
-
if (content && content
|
|
950
|
+
const content = parseVmlPicture(child, (children) => parseBodyElements(children, ctx));
|
|
951
|
+
if (content?.float && anchored) anchored.push(...blocksForDrawing(content, {}, ctx) ?? []);
|
|
952
|
+
else if (content && content.kind === "image") {
|
|
554
953
|
const resource = ctx.resolveImage?.(content.imageId);
|
|
555
954
|
if (resource) inlineImage = {
|
|
556
955
|
resource,
|
|
956
|
+
...content.outline ? { outline: content.outline } : {},
|
|
957
|
+
...content.shadow ? { shadow: content.shadow } : {},
|
|
958
|
+
...content.wash ? { wash: content.wash } : {},
|
|
557
959
|
width: content.width,
|
|
558
960
|
height: content.height
|
|
559
961
|
};
|
|
560
|
-
}
|
|
962
|
+
} else if (content && anchored) anchored.push(...blocksForDrawing(content, {}, ctx) ?? []);
|
|
561
963
|
}
|
|
562
964
|
}
|
|
563
965
|
return {
|
|
@@ -566,14 +968,36 @@ function parseRun(r, ctx) {
|
|
|
566
968
|
properties,
|
|
567
969
|
...inlineImage ? { inlineImage } : {},
|
|
568
970
|
...pageBreak ? { pageBreak: true } : {},
|
|
971
|
+
...columnBreak ? { columnBreak: true } : {},
|
|
569
972
|
...footnoteRef !== void 0 ? { footnoteRef } : {},
|
|
570
973
|
...endnoteRef !== void 0 ? { endnoteRef } : {},
|
|
571
974
|
...commentRef !== void 0 ? { commentRef } : {},
|
|
572
975
|
...noteNumber ? { noteNumber: true } : {}
|
|
573
976
|
},
|
|
574
977
|
...fldChar ? { fldChar } : {},
|
|
575
|
-
...instrText !== void 0 ? { instrText } : {}
|
|
978
|
+
...instrText !== void 0 ? { instrText } : {},
|
|
979
|
+
...checkBox !== void 0 ? { checkBox } : {}
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* §17.16.32 `w:fldChar/w:ffData/w:checkBox` — whether a form checkbox is
|
|
984
|
+
* ticked: its current `w:checked` if it states one, else the `w:default` it was
|
|
985
|
+
* created with, else clear.
|
|
986
|
+
*
|
|
987
|
+
* @param fldChar The field's `w:fldChar` (only a `begin` carries `w:ffData`).
|
|
988
|
+
* @returns The state, or undefined when this is not a checkbox field.
|
|
989
|
+
*/
|
|
990
|
+
function fieldCheckBoxState(fldChar) {
|
|
991
|
+
const ffData = poChildren(fldChar).find((c) => poIs(c, "w:ffData"));
|
|
992
|
+
const box = ffData ? poChildren(ffData).find((c) => poIs(c, "w:checkBox")) : void 0;
|
|
993
|
+
if (!box) return void 0;
|
|
994
|
+
const flag = (name) => {
|
|
995
|
+
const el = poChildren(box).find((c) => poIs(c, name));
|
|
996
|
+
if (!el) return void 0;
|
|
997
|
+
const val = poAttr(el, "val");
|
|
998
|
+
return val === void 0 || val === "" || val !== "0" && val !== "false";
|
|
576
999
|
};
|
|
1000
|
+
return flag("w:checked") ?? flag("w:default") ?? false;
|
|
577
1001
|
}
|
|
578
1002
|
function elementTag(node) {
|
|
579
1003
|
for (const key of Object.keys(node)) if (key !== ":@" && key !== "#text") return key;
|
|
@@ -590,7 +1014,7 @@ function elementTag(node) {
|
|
|
590
1014
|
* @returns A map from note id to its body content.
|
|
591
1015
|
*/
|
|
592
1016
|
function parseNotes(notesXml, rootTag, noteTag, ctx = DEFAULT_PARSE_CONTEXT) {
|
|
593
|
-
const xml = decoder.decode(notesXml);
|
|
1017
|
+
const xml = resolveInternalEntities(decoder.decode(notesXml));
|
|
594
1018
|
const root = poFindByPath(parser.parse(xml), [rootTag]);
|
|
595
1019
|
const out = /* @__PURE__ */ new Map();
|
|
596
1020
|
if (!root) return out;
|
|
@@ -605,7 +1029,7 @@ function parseNotes(notesXml, rootTag, noteTag, ctx = DEFAULT_PARSE_CONTEXT) {
|
|
|
605
1029
|
return out;
|
|
606
1030
|
}
|
|
607
1031
|
function parseCommentsRaw(commentsXml, ctx) {
|
|
608
|
-
const xml = decoder.decode(commentsXml);
|
|
1032
|
+
const xml = resolveInternalEntities(decoder.decode(commentsXml));
|
|
609
1033
|
const root = poFindByPath(parser.parse(xml), ["w:comments"]);
|
|
610
1034
|
const comments = /* @__PURE__ */ new Map();
|
|
611
1035
|
const paraIds = /* @__PURE__ */ new Map();
|
|
@@ -649,7 +1073,7 @@ function parseCommentsRaw(commentsXml, ctx) {
|
|
|
649
1073
|
* @returns A map from `paraId` to its {@link CommentExtension}.
|
|
650
1074
|
*/
|
|
651
1075
|
function parseCommentsExtended(xml) {
|
|
652
|
-
const tree = parser.parse(decoder.decode(xml));
|
|
1076
|
+
const tree = parser.parse(resolveInternalEntities(decoder.decode(xml)));
|
|
653
1077
|
const out = /* @__PURE__ */ new Map();
|
|
654
1078
|
const root = tree.find((n) => poIsLocal(n, "commentsEx"));
|
|
655
1079
|
if (!root) return out;
|
|
@@ -711,7 +1135,7 @@ function parseCommentThreads(commentsXml, commentsExtendedXml, ctx = DEFAULT_PAR
|
|
|
711
1135
|
* @returns A map from author name to userId.
|
|
712
1136
|
*/
|
|
713
1137
|
function parsePeople(xml) {
|
|
714
|
-
const tree = parser.parse(decoder.decode(xml));
|
|
1138
|
+
const tree = parser.parse(resolveInternalEntities(decoder.decode(xml)));
|
|
715
1139
|
const out = /* @__PURE__ */ new Map();
|
|
716
1140
|
const root = tree.find((n) => poIsLocal(n, "people"));
|
|
717
1141
|
if (!root) return out;
|
|
@@ -751,4 +1175,4 @@ function applyAuthorIds(comments, people) {
|
|
|
751
1175
|
return out;
|
|
752
1176
|
}
|
|
753
1177
|
//#endregion
|
|
754
|
-
export { DEFAULT_PARSE_CONTEXT, EMPTY_SECTION, applyAuthorIds, parseBodyElements, parseCommentThreads, parseCommentsExtended, parseDocument, parseHeaderFooter, parseNotes, parsePeople, parseSections };
|
|
1178
|
+
export { DEFAULT_PARSE_CONTEXT, EMPTY_SECTION, applyAuthorIds, bodyIndexForBlock, newBlockCounter, parseBackgroundColor, parseBackgroundFill, parseBodyElements, parseCommentThreads, parseCommentsExtended, parseDocument, parseHeaderFooter, parseNotes, parsePeople, parseSections, sdtRunProperties };
|