@apollo-design/docx-preview 0.6.2

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.
@@ -0,0 +1,4096 @@
1
+ /*
2
+ * @license
3
+ * @apollo-design/docx-preview <https://github.com/apollocmh/docx-preview>
4
+ * Released under Apache License 2.0 — Copyright apollocmh
5
+ * Based on docxjs by Volodymyr Baydalka <https://github.com/VolodymyrBaydalka/docxjs>
6
+ */
7
+ import JSZip from "jszip";
8
+ //#region src/common/relationship.ts
9
+ var RelationshipTypes = /* @__PURE__ */ function(RelationshipTypes) {
10
+ RelationshipTypes["OfficeDocument"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
11
+ RelationshipTypes["FontTable"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
12
+ RelationshipTypes["Image"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
13
+ RelationshipTypes["Numbering"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
14
+ RelationshipTypes["Styles"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
15
+ RelationshipTypes["StylesWithEffects"] = "http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects";
16
+ RelationshipTypes["Theme"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
17
+ RelationshipTypes["Settings"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
18
+ RelationshipTypes["WebSettings"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";
19
+ RelationshipTypes["Hyperlink"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
20
+ RelationshipTypes["Footnotes"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
21
+ RelationshipTypes["Endnotes"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes";
22
+ RelationshipTypes["Footer"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer";
23
+ RelationshipTypes["Header"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
24
+ RelationshipTypes["ExtendedProperties"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
25
+ RelationshipTypes["CoreProperties"] = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
26
+ RelationshipTypes["CustomProperties"] = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/custom-properties";
27
+ RelationshipTypes["Comments"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
28
+ RelationshipTypes["CommentsExtended"] = "http://schemas.microsoft.com/office/2011/relationships/commentsExtended";
29
+ RelationshipTypes["AltChunk"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/aFChunk";
30
+ return RelationshipTypes;
31
+ }({});
32
+ function parseRelationships(root, xml) {
33
+ return xml.elements(root).map((e) => ({
34
+ id: xml.attr(e, "Id"),
35
+ type: xml.attr(e, "Type"),
36
+ target: xml.attr(e, "Target"),
37
+ targetMode: xml.attr(e, "TargetMode")
38
+ }));
39
+ }
40
+ //#endregion
41
+ //#region src/utils.ts
42
+ function escapeClassName(className) {
43
+ return className?.replace(/[ .]+/g, "-").replace(/[&]+/g, "and").toLowerCase();
44
+ }
45
+ function encloseFontFamily(fontFamily) {
46
+ return /^[^"'].*\s.*[^"']$/.test(fontFamily) ? `'${fontFamily}'` : fontFamily;
47
+ }
48
+ function splitPath(path) {
49
+ let si = path.lastIndexOf("/") + 1;
50
+ return [si == 0 ? "" : path.substring(0, si), si == 0 ? path : path.substring(si)];
51
+ }
52
+ function resolvePath(path, base) {
53
+ try {
54
+ return new URL(path, "http://docx/" + base).toString().substring(12);
55
+ } catch {
56
+ return `${base}${path}`;
57
+ }
58
+ }
59
+ function keyBy(array, by) {
60
+ return array.reduce((a, x) => {
61
+ a[by(x)] = x;
62
+ return a;
63
+ }, {});
64
+ }
65
+ function blobToBase64(blob) {
66
+ return new Promise((resolve, reject) => {
67
+ const reader = new FileReader();
68
+ reader.onloadend = () => resolve(reader.result);
69
+ reader.onerror = () => reject();
70
+ reader.readAsDataURL(blob);
71
+ });
72
+ }
73
+ function isObject(item) {
74
+ return item && typeof item === "object" && !Array.isArray(item);
75
+ }
76
+ function isString(item) {
77
+ return typeof item === "string" || item instanceof String;
78
+ }
79
+ function mergeDeep(target, ...sources) {
80
+ if (!sources.length) return target;
81
+ const source = sources.shift();
82
+ if (isObject(target) && isObject(source)) for (const key in source) if (isObject(source[key])) mergeDeep(target[key] ?? (target[key] = {}), source[key]);
83
+ else target[key] = source[key];
84
+ return mergeDeep(target, ...sources);
85
+ }
86
+ function asArray(val) {
87
+ return Array.isArray(val) ? val : [val];
88
+ }
89
+ function clamp(val, min, max) {
90
+ return min > val ? min : max < val ? max : val;
91
+ }
92
+ //#endregion
93
+ //#region src/document/common.ts
94
+ var ns$1 = {
95
+ wordml: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
96
+ drawingml: "http://schemas.openxmlformats.org/drawingml/2006/main",
97
+ picture: "http://schemas.openxmlformats.org/drawingml/2006/picture",
98
+ compatibility: "http://schemas.openxmlformats.org/markup-compatibility/2006",
99
+ math: "http://schemas.openxmlformats.org/officeDocument/2006/math"
100
+ };
101
+ var LengthUsage = {
102
+ Dxa: {
103
+ mul: .05,
104
+ unit: "pt"
105
+ },
106
+ Emu: {
107
+ mul: 1 / 12700,
108
+ unit: "pt"
109
+ },
110
+ FontSize: {
111
+ mul: .5,
112
+ unit: "pt"
113
+ },
114
+ Border: {
115
+ mul: .125,
116
+ unit: "pt",
117
+ min: .25,
118
+ max: 12
119
+ },
120
+ Point: {
121
+ mul: 1,
122
+ unit: "pt"
123
+ },
124
+ Percent: {
125
+ mul: .02,
126
+ unit: "%"
127
+ },
128
+ LineHeight: {
129
+ mul: 1 / 240,
130
+ unit: ""
131
+ },
132
+ VmlEmu: {
133
+ mul: 1 / 12700,
134
+ unit: ""
135
+ }
136
+ };
137
+ function convertLength(val, usage = LengthUsage.Dxa) {
138
+ if (val == null || /.+(p[xt]|[%])$/.test(val)) return val;
139
+ var num = parseInt(val) * usage.mul;
140
+ if (usage.min && usage.max) num = clamp(num, usage.min, usage.max);
141
+ return `${num.toFixed(2)}${usage.unit}`;
142
+ }
143
+ function convertBoolean(v, defaultValue = false) {
144
+ switch (v) {
145
+ case "1": return true;
146
+ case "0": return false;
147
+ case "on": return true;
148
+ case "off": return false;
149
+ case "true": return true;
150
+ case "false": return false;
151
+ default: return defaultValue;
152
+ }
153
+ }
154
+ function parseCommonProperty(elem, props, xml) {
155
+ if (elem.namespaceURI != ns$1.wordml) return false;
156
+ switch (elem.localName) {
157
+ case "color":
158
+ props.color = xml.attr(elem, "val");
159
+ break;
160
+ case "sz":
161
+ props.fontSize = xml.lengthAttr(elem, "val", LengthUsage.FontSize);
162
+ break;
163
+ default: return false;
164
+ }
165
+ return true;
166
+ }
167
+ //#endregion
168
+ //#region src/parser/xml-parser.ts
169
+ function parseXmlString(xmlString, trimXmlDeclaration = false) {
170
+ if (trimXmlDeclaration) xmlString = xmlString.replace(/<[?].*[?]>/, "");
171
+ xmlString = removeUTF8BOM(xmlString);
172
+ const result = new DOMParser().parseFromString(xmlString, "application/xml");
173
+ const errorText = hasXmlParserError(result);
174
+ if (errorText) throw new Error(errorText);
175
+ return result;
176
+ }
177
+ function hasXmlParserError(doc) {
178
+ return doc.getElementsByTagName("parsererror")[0]?.textContent;
179
+ }
180
+ function removeUTF8BOM(data) {
181
+ return data.charCodeAt(0) === 65279 ? data.substring(1) : data;
182
+ }
183
+ function serializeXmlString(elem) {
184
+ return new XMLSerializer().serializeToString(elem);
185
+ }
186
+ var XmlParser = class {
187
+ elements(elem, localName = null) {
188
+ const result = [];
189
+ for (let i = 0, l = elem.childNodes.length; i < l; i++) {
190
+ let c = elem.childNodes.item(i);
191
+ if (c.nodeType == Node.ELEMENT_NODE && (localName == null || c.localName == localName)) result.push(c);
192
+ }
193
+ return result;
194
+ }
195
+ element(elem, localName) {
196
+ for (let i = 0, l = elem.childNodes.length; i < l; i++) {
197
+ let c = elem.childNodes.item(i);
198
+ if (c.nodeType == 1 && c.localName == localName) return c;
199
+ }
200
+ return null;
201
+ }
202
+ elementAttr(elem, localName, attrLocalName) {
203
+ var el = this.element(elem, localName);
204
+ return el ? this.attr(el, attrLocalName) : void 0;
205
+ }
206
+ attrs(elem) {
207
+ return Array.from(elem.attributes);
208
+ }
209
+ attr(elem, localName) {
210
+ for (let i = 0, l = elem.attributes.length; i < l; i++) {
211
+ let a = elem.attributes.item(i);
212
+ if (a.localName == localName) return a.value;
213
+ }
214
+ return null;
215
+ }
216
+ intAttr(node, attrName, defaultValue = null) {
217
+ var val = this.attr(node, attrName);
218
+ return val ? parseInt(val) : defaultValue;
219
+ }
220
+ hexAttr(node, attrName, defaultValue = null) {
221
+ var val = this.attr(node, attrName);
222
+ return val ? parseInt(val, 16) : defaultValue;
223
+ }
224
+ floatAttr(node, attrName, defaultValue = null) {
225
+ var val = this.attr(node, attrName);
226
+ return val ? parseFloat(val) : defaultValue;
227
+ }
228
+ boolAttr(node, attrName, defaultValue = null) {
229
+ return convertBoolean(this.attr(node, attrName), defaultValue);
230
+ }
231
+ lengthAttr(node, attrName, usage = LengthUsage.Dxa) {
232
+ return convertLength(this.attr(node, attrName), usage);
233
+ }
234
+ };
235
+ var globalXmlParser = new XmlParser();
236
+ //#endregion
237
+ //#region src/common/part.ts
238
+ var Part = class {
239
+ constructor(_package, path) {
240
+ this._package = _package;
241
+ this.path = path;
242
+ }
243
+ async load() {
244
+ this.rels = await this._package.loadRelationships(this.path);
245
+ const xmlText = await this._package.load(this.path);
246
+ const xmlDoc = this._package.parseXmlDocument(xmlText);
247
+ if (this._package.options.keepOrigin) this._xmlDocument = xmlDoc;
248
+ this.parseXml(xmlDoc.firstElementChild);
249
+ }
250
+ save() {
251
+ this._package.update(this.path, serializeXmlString(this._xmlDocument));
252
+ }
253
+ parseXml(root) {}
254
+ };
255
+ //#endregion
256
+ //#region src/font-table/fonts.ts
257
+ var embedFontTypeMap = {
258
+ embedRegular: "regular",
259
+ embedBold: "bold",
260
+ embedItalic: "italic",
261
+ embedBoldItalic: "boldItalic"
262
+ };
263
+ function parseFonts(root, xml) {
264
+ return xml.elements(root).map((el) => parseFont(el, xml));
265
+ }
266
+ function parseFont(elem, xml) {
267
+ let result = {
268
+ name: xml.attr(elem, "name"),
269
+ embedFontRefs: []
270
+ };
271
+ for (let el of xml.elements(elem)) switch (el.localName) {
272
+ case "family":
273
+ result.family = xml.attr(el, "val");
274
+ break;
275
+ case "altName":
276
+ result.altName = xml.attr(el, "val");
277
+ break;
278
+ case "embedRegular":
279
+ case "embedBold":
280
+ case "embedItalic":
281
+ case "embedBoldItalic": result.embedFontRefs.push(parseEmbedFontRef(el, xml));
282
+ }
283
+ return result;
284
+ }
285
+ function parseEmbedFontRef(elem, xml) {
286
+ return {
287
+ id: xml.attr(elem, "id"),
288
+ key: xml.attr(elem, "fontKey"),
289
+ type: embedFontTypeMap[elem.localName]
290
+ };
291
+ }
292
+ //#endregion
293
+ //#region src/font-table/font-table.ts
294
+ var FontTablePart = class extends Part {
295
+ parseXml(root) {
296
+ this.fonts = parseFonts(root, this._package.xmlParser);
297
+ }
298
+ };
299
+ //#endregion
300
+ //#region src/common/content-types.ts
301
+ function parseContentTypes(root, xml) {
302
+ return xml.elements(root).map((e) => ({
303
+ extension: xml.attr(e, "Extension"),
304
+ partName: xml.attr(e, "PartName"),
305
+ contentType: xml.attr(e, "ContentType")
306
+ }));
307
+ }
308
+ //#endregion
309
+ //#region src/common/open-xml-package.ts
310
+ var OpenXmlPackage = class OpenXmlPackage {
311
+ constructor(_zip, options) {
312
+ this._zip = _zip;
313
+ this.options = options;
314
+ this.xmlParser = new XmlParser();
315
+ }
316
+ get(path) {
317
+ const p = normalizePath(path);
318
+ return this._zip.files[p] ?? this._zip.files[p.replace(/\//g, "\\")];
319
+ }
320
+ update(path, content) {
321
+ this._zip.file(path, content);
322
+ }
323
+ static async load(input, options) {
324
+ const zip = await JSZip.loadAsync(input);
325
+ return new OpenXmlPackage(zip, options);
326
+ }
327
+ save(type = "blob") {
328
+ return this._zip.generateAsync({ type });
329
+ }
330
+ load(path, type = "string") {
331
+ return this.get(path)?.async(type) ?? Promise.resolve(null);
332
+ }
333
+ async loadRelationships(path = null) {
334
+ let relsPath = `_rels/.rels`;
335
+ if (path != null) {
336
+ const [f, fn] = splitPath(path);
337
+ relsPath = `${f}_rels/${fn}.rels`;
338
+ }
339
+ const txt = await this.load(relsPath);
340
+ return txt ? parseRelationships(this.parseXmlDocument(txt).firstElementChild, this.xmlParser) : null;
341
+ }
342
+ async loadContentTypes() {
343
+ const txt = await this.load("[Content_Types].xml");
344
+ return txt ? parseContentTypes(this.parseXmlDocument(txt).firstElementChild, this.xmlParser) : [];
345
+ }
346
+ /** @internal */
347
+ parseXmlDocument(txt) {
348
+ return parseXmlString(txt, this.options.trimXmlDeclaration);
349
+ }
350
+ };
351
+ function normalizePath(path) {
352
+ return path.startsWith("/") ? path.substr(1) : path;
353
+ }
354
+ //#endregion
355
+ //#region src/document/document-part.ts
356
+ var DocumentPart = class extends Part {
357
+ constructor(pkg, path, parser) {
358
+ super(pkg, path);
359
+ this._documentParser = parser;
360
+ }
361
+ parseXml(root) {
362
+ this.body = this._documentParser.parseDocumentFile(root);
363
+ }
364
+ };
365
+ //#endregion
366
+ //#region src/document/border.ts
367
+ function parseBorder(elem, xml) {
368
+ return {
369
+ type: xml.attr(elem, "val"),
370
+ color: xml.attr(elem, "color"),
371
+ size: xml.lengthAttr(elem, "sz", LengthUsage.Border),
372
+ offset: xml.lengthAttr(elem, "space", LengthUsage.Point),
373
+ frame: xml.boolAttr(elem, "frame"),
374
+ shadow: xml.boolAttr(elem, "shadow")
375
+ };
376
+ }
377
+ function parseBorders(elem, xml) {
378
+ var result = {};
379
+ for (let e of xml.elements(elem)) switch (e.localName) {
380
+ case "left":
381
+ result.left = parseBorder(e, xml);
382
+ break;
383
+ case "top":
384
+ result.top = parseBorder(e, xml);
385
+ break;
386
+ case "right":
387
+ result.right = parseBorder(e, xml);
388
+ break;
389
+ case "bottom": result.bottom = parseBorder(e, xml);
390
+ }
391
+ return result;
392
+ }
393
+ //#endregion
394
+ //#region src/document/section.ts
395
+ function parseSectionProperties(elem, xml = globalXmlParser) {
396
+ var section = {};
397
+ for (let e of xml.elements(elem)) switch (e.localName) {
398
+ case "pgSz":
399
+ section.pageSize = {
400
+ width: xml.lengthAttr(e, "w"),
401
+ height: xml.lengthAttr(e, "h"),
402
+ orientation: xml.attr(e, "orient")
403
+ };
404
+ break;
405
+ case "type":
406
+ section.type = xml.attr(e, "val");
407
+ break;
408
+ case "pgMar":
409
+ section.pageMargins = {
410
+ left: xml.lengthAttr(e, "left"),
411
+ right: xml.lengthAttr(e, "right"),
412
+ top: xml.lengthAttr(e, "top"),
413
+ bottom: xml.lengthAttr(e, "bottom"),
414
+ header: xml.lengthAttr(e, "header"),
415
+ footer: xml.lengthAttr(e, "footer"),
416
+ gutter: xml.lengthAttr(e, "gutter")
417
+ };
418
+ break;
419
+ case "cols":
420
+ section.columns = parseColumns(e, xml);
421
+ break;
422
+ case "headerReference":
423
+ (section.headerRefs ?? (section.headerRefs = [])).push(parseFooterHeaderReference(e, xml));
424
+ break;
425
+ case "footerReference":
426
+ (section.footerRefs ?? (section.footerRefs = [])).push(parseFooterHeaderReference(e, xml));
427
+ break;
428
+ case "titlePg":
429
+ section.titlePage = xml.boolAttr(e, "val", true);
430
+ break;
431
+ case "pgBorders":
432
+ section.pageBorders = parseBorders(e, xml);
433
+ break;
434
+ case "pgNumType": section.pageNumber = parsePageNumber(e, xml);
435
+ }
436
+ return section;
437
+ }
438
+ function parseColumns(elem, xml) {
439
+ return {
440
+ numberOfColumns: xml.intAttr(elem, "num"),
441
+ space: xml.lengthAttr(elem, "space"),
442
+ separator: xml.boolAttr(elem, "sep"),
443
+ equalWidth: xml.boolAttr(elem, "equalWidth", true),
444
+ columns: xml.elements(elem, "col").map((e) => ({
445
+ width: xml.lengthAttr(e, "w"),
446
+ space: xml.lengthAttr(e, "space")
447
+ }))
448
+ };
449
+ }
450
+ function parsePageNumber(elem, xml) {
451
+ return {
452
+ chapSep: xml.attr(elem, "chapSep"),
453
+ chapStyle: xml.attr(elem, "chapStyle"),
454
+ format: xml.attr(elem, "fmt"),
455
+ start: xml.intAttr(elem, "start")
456
+ };
457
+ }
458
+ function parseFooterHeaderReference(elem, xml) {
459
+ return {
460
+ id: xml.attr(elem, "id"),
461
+ type: xml.attr(elem, "type")
462
+ };
463
+ }
464
+ //#endregion
465
+ //#region src/document/line-spacing.ts
466
+ function parseLineSpacing(elem, xml) {
467
+ return {
468
+ before: xml.lengthAttr(elem, "before"),
469
+ after: xml.lengthAttr(elem, "after"),
470
+ line: xml.intAttr(elem, "line"),
471
+ lineRule: xml.attr(elem, "lineRule")
472
+ };
473
+ }
474
+ //#endregion
475
+ //#region src/document/run.ts
476
+ function parseRunProperties(elem, xml) {
477
+ let result = {};
478
+ for (let el of xml.elements(elem)) parseRunProperty(el, result, xml);
479
+ return result;
480
+ }
481
+ function parseRunProperty(elem, props, xml) {
482
+ if (parseCommonProperty(elem, props, xml)) return true;
483
+ return false;
484
+ }
485
+ //#endregion
486
+ //#region src/document/paragraph.ts
487
+ function parseParagraphProperties(elem, xml) {
488
+ let result = {};
489
+ for (let el of xml.elements(elem)) parseParagraphProperty(el, result, xml);
490
+ return result;
491
+ }
492
+ function parseParagraphProperty(elem, props, xml) {
493
+ if (elem.namespaceURI != ns$1.wordml) return false;
494
+ if (parseCommonProperty(elem, props, xml)) return true;
495
+ switch (elem.localName) {
496
+ case "tabs":
497
+ props.tabs = parseTabs(elem, xml);
498
+ break;
499
+ case "sectPr":
500
+ props.sectionProps = parseSectionProperties(elem, xml);
501
+ break;
502
+ case "numPr":
503
+ props.numbering = parseNumbering$1(elem, xml);
504
+ break;
505
+ case "spacing":
506
+ props.lineSpacing = parseLineSpacing(elem, xml);
507
+ return false;
508
+ case "textAlignment":
509
+ props.textAlignment = xml.attr(elem, "val");
510
+ return false;
511
+ case "keepLines":
512
+ props.keepLines = xml.boolAttr(elem, "val", true);
513
+ break;
514
+ case "keepNext":
515
+ props.keepNext = xml.boolAttr(elem, "val", true);
516
+ break;
517
+ case "pageBreakBefore":
518
+ props.pageBreakBefore = xml.boolAttr(elem, "val", true);
519
+ break;
520
+ case "outlineLvl":
521
+ props.outlineLevel = xml.intAttr(elem, "val");
522
+ break;
523
+ case "pStyle":
524
+ props.styleName = xml.attr(elem, "val");
525
+ break;
526
+ case "rPr":
527
+ props.runProps = parseRunProperties(elem, xml);
528
+ break;
529
+ default: return false;
530
+ }
531
+ return true;
532
+ }
533
+ function parseTabs(elem, xml) {
534
+ return xml.elements(elem, "tab").map((e) => ({
535
+ position: xml.lengthAttr(e, "pos"),
536
+ leader: xml.attr(e, "leader"),
537
+ style: xml.attr(e, "val")
538
+ }));
539
+ }
540
+ function parseNumbering$1(elem, xml) {
541
+ var result = {};
542
+ for (let e of xml.elements(elem)) switch (e.localName) {
543
+ case "numId":
544
+ result.id = xml.attr(e, "val");
545
+ break;
546
+ case "ilvl": result.level = xml.intAttr(e, "val");
547
+ }
548
+ return result;
549
+ }
550
+ //#endregion
551
+ //#region src/numbering/numbering.ts
552
+ function parseNumberingPart(elem, xml) {
553
+ let result = {
554
+ numberings: [],
555
+ abstractNumberings: [],
556
+ bulletPictures: []
557
+ };
558
+ for (let e of xml.elements(elem)) switch (e.localName) {
559
+ case "num":
560
+ result.numberings.push(parseNumbering(e, xml));
561
+ break;
562
+ case "abstractNum":
563
+ result.abstractNumberings.push(parseAbstractNumbering(e, xml));
564
+ break;
565
+ case "numPicBullet": result.bulletPictures.push(parseNumberingBulletPicture(e, xml));
566
+ }
567
+ return result;
568
+ }
569
+ function parseNumbering(elem, xml) {
570
+ let result = {
571
+ id: xml.attr(elem, "numId"),
572
+ overrides: []
573
+ };
574
+ for (let e of xml.elements(elem)) switch (e.localName) {
575
+ case "abstractNumId":
576
+ result.abstractId = xml.attr(e, "val");
577
+ break;
578
+ case "lvlOverride": result.overrides.push(parseNumberingLevelOverrride(e, xml));
579
+ }
580
+ return result;
581
+ }
582
+ function parseAbstractNumbering(elem, xml) {
583
+ let result = {
584
+ id: xml.attr(elem, "abstractNumId"),
585
+ levels: []
586
+ };
587
+ for (let e of xml.elements(elem)) switch (e.localName) {
588
+ case "name":
589
+ result.name = xml.attr(e, "val");
590
+ break;
591
+ case "multiLevelType":
592
+ result.multiLevelType = xml.attr(e, "val");
593
+ break;
594
+ case "numStyleLink":
595
+ result.numberingStyleLink = xml.attr(e, "val");
596
+ break;
597
+ case "styleLink":
598
+ result.styleLink = xml.attr(e, "val");
599
+ break;
600
+ case "lvl": result.levels.push(parseNumberingLevel(e, xml));
601
+ }
602
+ return result;
603
+ }
604
+ function parseNumberingLevel(elem, xml) {
605
+ let result = { level: xml.intAttr(elem, "ilvl") };
606
+ for (let e of xml.elements(elem)) switch (e.localName) {
607
+ case "start":
608
+ result.start = xml.attr(e, "val");
609
+ break;
610
+ case "lvlRestart":
611
+ result.restart = xml.intAttr(e, "val");
612
+ break;
613
+ case "numFmt":
614
+ result.format = xml.attr(e, "val");
615
+ break;
616
+ case "lvlText":
617
+ result.text = xml.attr(e, "val");
618
+ break;
619
+ case "lvlJc":
620
+ result.justification = xml.attr(e, "val");
621
+ break;
622
+ case "lvlPicBulletId":
623
+ result.bulletPictureId = xml.attr(e, "val");
624
+ break;
625
+ case "pStyle":
626
+ result.paragraphStyle = xml.attr(e, "val");
627
+ break;
628
+ case "pPr":
629
+ result.paragraphProps = parseParagraphProperties(e, xml);
630
+ break;
631
+ case "rPr": result.runProps = parseRunProperties(e, xml);
632
+ }
633
+ return result;
634
+ }
635
+ function parseNumberingLevelOverrride(elem, xml) {
636
+ let result = { level: xml.intAttr(elem, "ilvl") };
637
+ for (let e of xml.elements(elem)) switch (e.localName) {
638
+ case "startOverride":
639
+ result.start = xml.intAttr(e, "val");
640
+ break;
641
+ case "lvl": result.numberingLevel = parseNumberingLevel(e, xml);
642
+ }
643
+ return result;
644
+ }
645
+ function parseNumberingBulletPicture(elem, xml) {
646
+ var pict = xml.element(elem, "pict");
647
+ var shape = pict && xml.element(pict, "shape");
648
+ var imagedata = shape && xml.element(shape, "imagedata");
649
+ return imagedata ? {
650
+ id: xml.attr(elem, "numPicBulletId"),
651
+ referenceId: xml.attr(imagedata, "id"),
652
+ style: xml.attr(shape, "style")
653
+ } : null;
654
+ }
655
+ //#endregion
656
+ //#region src/numbering/numbering-part.ts
657
+ var NumberingPart = class extends Part {
658
+ constructor(pkg, path, parser) {
659
+ super(pkg, path);
660
+ this._documentParser = parser;
661
+ }
662
+ parseXml(root) {
663
+ Object.assign(this, parseNumberingPart(root, this._package.xmlParser));
664
+ this.domNumberings = this._documentParser.parseNumberingFile(root);
665
+ }
666
+ };
667
+ //#endregion
668
+ //#region src/styles/styles-part.ts
669
+ var StylesPart = class extends Part {
670
+ constructor(pkg, path, parser) {
671
+ super(pkg, path);
672
+ this._documentParser = parser;
673
+ }
674
+ parseXml(root) {
675
+ this.styles = this._documentParser.parseStylesFile(root);
676
+ }
677
+ };
678
+ //#endregion
679
+ //#region src/document/dom.ts
680
+ var DomType = /* @__PURE__ */ function(DomType) {
681
+ DomType["Document"] = "document";
682
+ DomType["Paragraph"] = "paragraph";
683
+ DomType["Run"] = "run";
684
+ DomType["Break"] = "break";
685
+ DomType["NoBreakHyphen"] = "noBreakHyphen";
686
+ DomType["Table"] = "table";
687
+ DomType["Row"] = "row";
688
+ DomType["Cell"] = "cell";
689
+ DomType["Hyperlink"] = "hyperlink";
690
+ DomType["SmartTag"] = "smartTag";
691
+ DomType["Drawing"] = "drawing";
692
+ DomType["Image"] = "image";
693
+ DomType["Text"] = "text";
694
+ DomType["Tab"] = "tab";
695
+ DomType["Symbol"] = "symbol";
696
+ DomType["BookmarkStart"] = "bookmarkStart";
697
+ DomType["BookmarkEnd"] = "bookmarkEnd";
698
+ DomType["Footer"] = "footer";
699
+ DomType["Header"] = "header";
700
+ DomType["FootnoteReference"] = "footnoteReference";
701
+ DomType["EndnoteReference"] = "endnoteReference";
702
+ DomType["Footnote"] = "footnote";
703
+ DomType["Endnote"] = "endnote";
704
+ DomType["SimpleField"] = "simpleField";
705
+ DomType["ComplexField"] = "complexField";
706
+ DomType["Instruction"] = "instruction";
707
+ DomType["VmlPicture"] = "vmlPicture";
708
+ DomType["MmlMath"] = "mmlMath";
709
+ DomType["MmlMathParagraph"] = "mmlMathParagraph";
710
+ DomType["MmlFraction"] = "mmlFraction";
711
+ DomType["MmlFunction"] = "mmlFunction";
712
+ DomType["MmlFunctionName"] = "mmlFunctionName";
713
+ DomType["MmlNumerator"] = "mmlNumerator";
714
+ DomType["MmlDenominator"] = "mmlDenominator";
715
+ DomType["MmlRadical"] = "mmlRadical";
716
+ DomType["MmlBase"] = "mmlBase";
717
+ DomType["MmlDegree"] = "mmlDegree";
718
+ DomType["MmlSuperscript"] = "mmlSuperscript";
719
+ DomType["MmlSubscript"] = "mmlSubscript";
720
+ DomType["MmlPreSubSuper"] = "mmlPreSubSuper";
721
+ DomType["MmlSubArgument"] = "mmlSubArgument";
722
+ DomType["MmlSuperArgument"] = "mmlSuperArgument";
723
+ DomType["MmlNary"] = "mmlNary";
724
+ DomType["MmlDelimiter"] = "mmlDelimiter";
725
+ DomType["MmlRun"] = "mmlRun";
726
+ DomType["MmlEquationArray"] = "mmlEquationArray";
727
+ DomType["MmlLimit"] = "mmlLimit";
728
+ DomType["MmlLimitLower"] = "mmlLimitLower";
729
+ DomType["MmlMatrix"] = "mmlMatrix";
730
+ DomType["MmlMatrixRow"] = "mmlMatrixRow";
731
+ DomType["MmlBox"] = "mmlBox";
732
+ DomType["MmlBar"] = "mmlBar";
733
+ DomType["MmlGroupChar"] = "mmlGroupChar";
734
+ DomType["VmlElement"] = "vmlElement";
735
+ DomType["Inserted"] = "inserted";
736
+ DomType["Deleted"] = "deleted";
737
+ DomType["DeletedText"] = "deletedText";
738
+ DomType["Comment"] = "comment";
739
+ DomType["CommentReference"] = "commentReference";
740
+ DomType["CommentRangeStart"] = "commentRangeStart";
741
+ DomType["CommentRangeEnd"] = "commentRangeEnd";
742
+ DomType["AltChunk"] = "altChunk";
743
+ return DomType;
744
+ }({});
745
+ var OpenXmlElementBase = class {
746
+ constructor() {
747
+ this.children = [];
748
+ this.cssStyle = {};
749
+ }
750
+ };
751
+ //#endregion
752
+ //#region src/header-footer/elements.ts
753
+ var WmlHeader = class extends OpenXmlElementBase {
754
+ constructor(..._args) {
755
+ super(..._args);
756
+ this.type = DomType.Header;
757
+ }
758
+ };
759
+ var WmlFooter = class extends OpenXmlElementBase {
760
+ constructor(..._args2) {
761
+ super(..._args2);
762
+ this.type = DomType.Footer;
763
+ }
764
+ };
765
+ //#endregion
766
+ //#region src/header-footer/parts.ts
767
+ var BaseHeaderFooterPart = class extends Part {
768
+ constructor(pkg, path, parser) {
769
+ super(pkg, path);
770
+ this._documentParser = parser;
771
+ }
772
+ parseXml(root) {
773
+ this.rootElement = this.createRootElement();
774
+ this.rootElement.children = this._documentParser.parseBodyElements(root);
775
+ }
776
+ };
777
+ var HeaderPart = class extends BaseHeaderFooterPart {
778
+ createRootElement() {
779
+ return new WmlHeader();
780
+ }
781
+ };
782
+ var FooterPart = class extends BaseHeaderFooterPart {
783
+ createRootElement() {
784
+ return new WmlFooter();
785
+ }
786
+ };
787
+ //#endregion
788
+ //#region src/document-props/extended-props.ts
789
+ function parseExtendedProps(root, xmlParser) {
790
+ const result = {};
791
+ for (let el of xmlParser.elements(root)) switch (el.localName) {
792
+ case "Template":
793
+ result.template = el.textContent;
794
+ break;
795
+ case "Pages":
796
+ result.pages = safeParseToInt(el.textContent);
797
+ break;
798
+ case "Words":
799
+ result.words = safeParseToInt(el.textContent);
800
+ break;
801
+ case "Characters":
802
+ result.characters = safeParseToInt(el.textContent);
803
+ break;
804
+ case "Application":
805
+ result.application = el.textContent;
806
+ break;
807
+ case "Lines":
808
+ result.lines = safeParseToInt(el.textContent);
809
+ break;
810
+ case "Paragraphs":
811
+ result.paragraphs = safeParseToInt(el.textContent);
812
+ break;
813
+ case "Company":
814
+ result.company = el.textContent;
815
+ break;
816
+ case "AppVersion": result.appVersion = el.textContent;
817
+ }
818
+ return result;
819
+ }
820
+ function safeParseToInt(value) {
821
+ if (typeof value === "undefined") return;
822
+ return parseInt(value);
823
+ }
824
+ //#endregion
825
+ //#region src/document-props/extended-props-part.ts
826
+ var ExtendedPropsPart = class extends Part {
827
+ parseXml(root) {
828
+ this.props = parseExtendedProps(root, this._package.xmlParser);
829
+ }
830
+ };
831
+ //#endregion
832
+ //#region src/document-props/core-props.ts
833
+ function parseCoreProps(root, xmlParser) {
834
+ const result = {};
835
+ for (let el of xmlParser.elements(root)) switch (el.localName) {
836
+ case "title":
837
+ result.title = el.textContent;
838
+ break;
839
+ case "description":
840
+ result.description = el.textContent;
841
+ break;
842
+ case "subject":
843
+ result.subject = el.textContent;
844
+ break;
845
+ case "creator":
846
+ result.creator = el.textContent;
847
+ break;
848
+ case "keywords":
849
+ result.keywords = el.textContent;
850
+ break;
851
+ case "language":
852
+ result.language = el.textContent;
853
+ break;
854
+ case "lastModifiedBy":
855
+ result.lastModifiedBy = el.textContent;
856
+ break;
857
+ case "revision": el.textContent && (result.revision = parseInt(el.textContent));
858
+ }
859
+ return result;
860
+ }
861
+ //#endregion
862
+ //#region src/document-props/core-props-part.ts
863
+ var CorePropsPart = class extends Part {
864
+ parseXml(root) {
865
+ this.props = parseCoreProps(root, this._package.xmlParser);
866
+ }
867
+ };
868
+ //#endregion
869
+ //#region src/theme/theme.ts
870
+ var DmlTheme = class {};
871
+ function parseTheme(elem, xml) {
872
+ var result = new DmlTheme();
873
+ var themeElements = xml.element(elem, "themeElements");
874
+ for (let el of xml.elements(themeElements)) switch (el.localName) {
875
+ case "clrScheme":
876
+ result.colorScheme = parseColorScheme(el, xml);
877
+ break;
878
+ case "fontScheme": result.fontScheme = parseFontScheme(el, xml);
879
+ }
880
+ return result;
881
+ }
882
+ function parseColorScheme(elem, xml) {
883
+ var result = {
884
+ name: xml.attr(elem, "name"),
885
+ colors: {}
886
+ };
887
+ for (let el of xml.elements(elem)) {
888
+ var srgbClr = xml.element(el, "srgbClr");
889
+ var sysClr = xml.element(el, "sysClr");
890
+ if (srgbClr) result.colors[el.localName] = xml.attr(srgbClr, "val");
891
+ else if (sysClr) result.colors[el.localName] = xml.attr(sysClr, "lastClr");
892
+ }
893
+ return result;
894
+ }
895
+ function parseFontScheme(elem, xml) {
896
+ var result = { name: xml.attr(elem, "name") };
897
+ for (let el of xml.elements(elem)) switch (el.localName) {
898
+ case "majorFont":
899
+ result.majorFont = parseFontInfo(el, xml);
900
+ break;
901
+ case "minorFont": result.minorFont = parseFontInfo(el, xml);
902
+ }
903
+ return result;
904
+ }
905
+ function parseFontInfo(elem, xml) {
906
+ return {
907
+ latinTypeface: xml.elementAttr(elem, "latin", "typeface"),
908
+ eaTypeface: xml.elementAttr(elem, "ea", "typeface"),
909
+ csTypeface: xml.elementAttr(elem, "cs", "typeface")
910
+ };
911
+ }
912
+ //#endregion
913
+ //#region src/theme/theme-part.ts
914
+ var ThemePart = class extends Part {
915
+ constructor(pkg, path) {
916
+ super(pkg, path);
917
+ }
918
+ parseXml(root) {
919
+ this.theme = parseTheme(root, this._package.xmlParser);
920
+ }
921
+ };
922
+ //#endregion
923
+ //#region src/notes/elements.ts
924
+ var WmlBaseNote = class {};
925
+ var WmlFootnote = class extends WmlBaseNote {
926
+ constructor(..._args) {
927
+ super(..._args);
928
+ this.type = DomType.Footnote;
929
+ }
930
+ };
931
+ var WmlEndnote = class extends WmlBaseNote {
932
+ constructor(..._args2) {
933
+ super(..._args2);
934
+ this.type = DomType.Endnote;
935
+ }
936
+ };
937
+ //#endregion
938
+ //#region src/notes/parts.ts
939
+ var BaseNotePart = class extends Part {
940
+ constructor(pkg, path, parser) {
941
+ super(pkg, path);
942
+ this._documentParser = parser;
943
+ }
944
+ };
945
+ var FootnotesPart = class extends BaseNotePart {
946
+ constructor(pkg, path, parser) {
947
+ super(pkg, path, parser);
948
+ }
949
+ parseXml(root) {
950
+ this.notes = this._documentParser.parseNotes(root, "footnote", WmlFootnote);
951
+ }
952
+ };
953
+ var EndnotesPart = class extends BaseNotePart {
954
+ constructor(pkg, path, parser) {
955
+ super(pkg, path, parser);
956
+ }
957
+ parseXml(root) {
958
+ this.notes = this._documentParser.parseNotes(root, "endnote", WmlEndnote);
959
+ }
960
+ };
961
+ //#endregion
962
+ //#region src/settings/settings.ts
963
+ function parseSettings(elem, xml) {
964
+ var result = {};
965
+ for (let el of xml.elements(elem)) switch (el.localName) {
966
+ case "defaultTabStop":
967
+ result.defaultTabStop = xml.lengthAttr(el, "val");
968
+ break;
969
+ case "footnotePr":
970
+ result.footnoteProps = parseNoteProperties(el, xml);
971
+ break;
972
+ case "endnotePr":
973
+ result.endnoteProps = parseNoteProperties(el, xml);
974
+ break;
975
+ case "autoHyphenation":
976
+ result.autoHyphenation = xml.boolAttr(el, "val");
977
+ break;
978
+ case "compat": for (let c of xml.elements(el)) if (c.localName == "compatSetting" && xml.attr(c, "name") == "compatibilityMode" && (xml.attr(c, "uri") ?? "").includes("schemas.microsoft.com/office/word")) result.compatMode = xml.intAttr(c, "val", null);
979
+ }
980
+ return result;
981
+ }
982
+ function parseNoteProperties(elem, xml) {
983
+ var result = { defaultNoteIds: [] };
984
+ for (let el of xml.elements(elem)) switch (el.localName) {
985
+ case "numFmt":
986
+ result.nummeringFormat = xml.attr(el, "val");
987
+ break;
988
+ case "footnote":
989
+ case "endnote": result.defaultNoteIds.push(xml.attr(el, "id"));
990
+ }
991
+ return result;
992
+ }
993
+ //#endregion
994
+ //#region src/settings/settings-part.ts
995
+ var SettingsPart = class extends Part {
996
+ constructor(pkg, path) {
997
+ super(pkg, path);
998
+ }
999
+ parseXml(root) {
1000
+ this.settings = parseSettings(root, this._package.xmlParser);
1001
+ }
1002
+ };
1003
+ //#endregion
1004
+ //#region src/document-props/custom-props.ts
1005
+ function parseCustomProps(root, xml) {
1006
+ return xml.elements(root, "property").map((e) => {
1007
+ const firstChild = e.firstChild;
1008
+ return {
1009
+ formatId: xml.attr(e, "fmtid"),
1010
+ name: xml.attr(e, "name"),
1011
+ type: firstChild.nodeName,
1012
+ value: firstChild.textContent
1013
+ };
1014
+ });
1015
+ }
1016
+ //#endregion
1017
+ //#region src/document-props/custom-props-part.ts
1018
+ var CustomPropsPart = class extends Part {
1019
+ parseXml(root) {
1020
+ this.props = parseCustomProps(root, this._package.xmlParser);
1021
+ }
1022
+ };
1023
+ //#endregion
1024
+ //#region src/comments/comments-part.ts
1025
+ var CommentsPart = class extends Part {
1026
+ constructor(pkg, path, parser) {
1027
+ super(pkg, path);
1028
+ this._documentParser = parser;
1029
+ }
1030
+ parseXml(root) {
1031
+ this.comments = this._documentParser.parseComments(root);
1032
+ this.commentMap = keyBy(this.comments, (x) => x.id);
1033
+ }
1034
+ };
1035
+ //#endregion
1036
+ //#region src/comments/comments-extended-part.ts
1037
+ var CommentsExtendedPart = class extends Part {
1038
+ constructor(pkg, path) {
1039
+ super(pkg, path);
1040
+ this.comments = [];
1041
+ }
1042
+ parseXml(root) {
1043
+ const xml = this._package.xmlParser;
1044
+ for (let el of xml.elements(root, "commentEx")) this.comments.push({
1045
+ paraId: xml.attr(el, "paraId"),
1046
+ paraIdParent: xml.attr(el, "paraIdParent"),
1047
+ done: xml.boolAttr(el, "done")
1048
+ });
1049
+ this.commentMap = keyBy(this.comments, (x) => x.paraId);
1050
+ }
1051
+ };
1052
+ //#endregion
1053
+ //#region src/word-document.ts
1054
+ var topLevelRels = [
1055
+ {
1056
+ type: RelationshipTypes.OfficeDocument,
1057
+ target: "word/document.xml"
1058
+ },
1059
+ {
1060
+ type: RelationshipTypes.ExtendedProperties,
1061
+ target: "docProps/app.xml"
1062
+ },
1063
+ {
1064
+ type: RelationshipTypes.CoreProperties,
1065
+ target: "docProps/core.xml"
1066
+ },
1067
+ {
1068
+ type: RelationshipTypes.CustomProperties,
1069
+ target: "docProps/custom.xml"
1070
+ }
1071
+ ];
1072
+ var WordDocument = class WordDocument {
1073
+ constructor() {
1074
+ this.parts = [];
1075
+ this.partsMap = {};
1076
+ this.contentTypes = [];
1077
+ }
1078
+ static async load(blob, parser, options) {
1079
+ var d = new WordDocument();
1080
+ d._options = options;
1081
+ d._parser = parser;
1082
+ d._package = await OpenXmlPackage.load(blob, options);
1083
+ d.rels = await d._package.loadRelationships();
1084
+ d.contentTypes = await d._package.loadContentTypes();
1085
+ await Promise.all(topLevelRels.map((rel) => {
1086
+ const r = d.rels.find((x) => x.type === rel.type) ?? rel;
1087
+ return d.loadRelationshipPart(r.target, r.type);
1088
+ }));
1089
+ return d;
1090
+ }
1091
+ save(type = "blob") {
1092
+ return this._package.save(type);
1093
+ }
1094
+ async loadRelationshipPart(path, type) {
1095
+ if (this.partsMap[path]) return this.partsMap[path];
1096
+ if (!this._package.get(path)) return null;
1097
+ let part = null;
1098
+ switch (type) {
1099
+ case RelationshipTypes.OfficeDocument:
1100
+ this.documentPart = part = new DocumentPart(this._package, path, this._parser);
1101
+ break;
1102
+ case RelationshipTypes.FontTable:
1103
+ this.fontTablePart = part = new FontTablePart(this._package, path);
1104
+ break;
1105
+ case RelationshipTypes.Numbering:
1106
+ this.numberingPart = part = new NumberingPart(this._package, path, this._parser);
1107
+ break;
1108
+ case RelationshipTypes.Styles:
1109
+ this.stylesPart = part = new StylesPart(this._package, path, this._parser);
1110
+ break;
1111
+ case RelationshipTypes.Theme:
1112
+ this.themePart = part = new ThemePart(this._package, path);
1113
+ break;
1114
+ case RelationshipTypes.Footnotes:
1115
+ this.footnotesPart = part = new FootnotesPart(this._package, path, this._parser);
1116
+ break;
1117
+ case RelationshipTypes.Endnotes:
1118
+ this.endnotesPart = part = new EndnotesPart(this._package, path, this._parser);
1119
+ break;
1120
+ case RelationshipTypes.Footer:
1121
+ part = new FooterPart(this._package, path, this._parser);
1122
+ break;
1123
+ case RelationshipTypes.Header:
1124
+ part = new HeaderPart(this._package, path, this._parser);
1125
+ break;
1126
+ case RelationshipTypes.CoreProperties:
1127
+ this.corePropsPart = part = new CorePropsPart(this._package, path);
1128
+ break;
1129
+ case RelationshipTypes.ExtendedProperties:
1130
+ this.extendedPropsPart = part = new ExtendedPropsPart(this._package, path);
1131
+ break;
1132
+ case RelationshipTypes.CustomProperties:
1133
+ part = new CustomPropsPart(this._package, path);
1134
+ break;
1135
+ case RelationshipTypes.Settings:
1136
+ this.settingsPart = part = new SettingsPart(this._package, path);
1137
+ break;
1138
+ case RelationshipTypes.Comments:
1139
+ this.commentsPart = part = new CommentsPart(this._package, path, this._parser);
1140
+ break;
1141
+ case RelationshipTypes.CommentsExtended: this.commentsExtendedPart = part = new CommentsExtendedPart(this._package, path);
1142
+ }
1143
+ if (part == null) return Promise.resolve(null);
1144
+ this.partsMap[path] = part;
1145
+ this.parts.push(part);
1146
+ await part.load();
1147
+ if (part.rels?.length > 0) {
1148
+ const [folder] = splitPath(part.path);
1149
+ await Promise.all(part.rels.map((rel) => this.loadRelationshipPart(resolvePath(rel.target, folder), rel.type)));
1150
+ }
1151
+ return part;
1152
+ }
1153
+ async loadDocumentImage(id, part) {
1154
+ const path = this.getPathById(part ?? this.documentPart, id);
1155
+ return path ? this.blobToURL(await this._package.load(path, "blob"), path) : null;
1156
+ }
1157
+ async loadNumberingImage(id) {
1158
+ const path = this.getPathById(this.numberingPart, id);
1159
+ return path ? this.blobToURL(await this._package.load(path, "blob"), path) : null;
1160
+ }
1161
+ async loadFont(id, key) {
1162
+ const path = this.getPathById(this.fontTablePart, id);
1163
+ if (!path) return null;
1164
+ const x = await this._package.load(path, "uint8array");
1165
+ return x ? this.blobToURL(new Blob([deobfuscate(x, key)]), path) : x;
1166
+ }
1167
+ async loadAltChunk(id, part) {
1168
+ const path = this.getPathById(part ?? this.documentPart, id);
1169
+ return path ? this._package.load(path, "string") : Promise.resolve(null);
1170
+ }
1171
+ blobToURL(blob, path) {
1172
+ if (!blob) return null;
1173
+ if (path) {
1174
+ const ct = this.contentTypes.find((x) => x.partName === path || x.extension && path.endsWith(`.${x.extension}`));
1175
+ blob = ct ? new Blob([blob], { type: ct.contentType }) : blob;
1176
+ }
1177
+ if (this._options.useBase64URL) return blobToBase64(blob);
1178
+ return URL.createObjectURL(blob);
1179
+ }
1180
+ findPartByRelId(id, basePart = null) {
1181
+ var rel = (basePart.rels ?? this.rels).find((r) => r.id == id);
1182
+ const folder = basePart ? splitPath(basePart.path)[0] : "";
1183
+ return rel ? this.partsMap[resolvePath(rel.target, folder)] : null;
1184
+ }
1185
+ getPathById(part, id) {
1186
+ const rel = part.rels.find((x) => x.id == id);
1187
+ const [folder] = splitPath(part.path);
1188
+ return rel ? resolvePath(rel.target, folder) : null;
1189
+ }
1190
+ };
1191
+ function deobfuscate(data, guidKey) {
1192
+ const len = 16;
1193
+ const trimmed = guidKey.replace(/{|}|-/g, "");
1194
+ const numbers = new Array(len);
1195
+ for (let i = 0; i < len; i++) numbers[len - i - 1] = parseInt(trimmed.substring(i * 2, i * 2 + 2), 16);
1196
+ for (let i = 0; i < 32; i++) data[i] = data[i] ^ numbers[i % len];
1197
+ return data;
1198
+ }
1199
+ //#endregion
1200
+ //#region src/document/bookmarks.ts
1201
+ function parseBookmarkStart(elem, xml) {
1202
+ return {
1203
+ type: DomType.BookmarkStart,
1204
+ id: xml.attr(elem, "id"),
1205
+ name: xml.attr(elem, "name"),
1206
+ colFirst: xml.intAttr(elem, "colFirst"),
1207
+ colLast: xml.intAttr(elem, "colLast")
1208
+ };
1209
+ }
1210
+ function parseBookmarkEnd(elem, xml) {
1211
+ return {
1212
+ type: DomType.BookmarkEnd,
1213
+ id: xml.attr(elem, "id")
1214
+ };
1215
+ }
1216
+ //#endregion
1217
+ //#region src/vml/vml.ts
1218
+ var VmlElement = class extends OpenXmlElementBase {
1219
+ constructor(..._args) {
1220
+ super(..._args);
1221
+ this.type = DomType.VmlElement;
1222
+ this.attrs = {};
1223
+ }
1224
+ };
1225
+ function parseVmlElement(elem, parser) {
1226
+ var result = new VmlElement();
1227
+ switch (elem.localName) {
1228
+ case "rect":
1229
+ result.tagName = "rect";
1230
+ Object.assign(result.attrs, {
1231
+ width: "100%",
1232
+ height: "100%"
1233
+ });
1234
+ break;
1235
+ case "oval":
1236
+ result.tagName = "ellipse";
1237
+ Object.assign(result.attrs, {
1238
+ cx: "50%",
1239
+ cy: "50%",
1240
+ rx: "50%",
1241
+ ry: "50%"
1242
+ });
1243
+ break;
1244
+ case "line":
1245
+ result.tagName = "line";
1246
+ break;
1247
+ case "shape":
1248
+ result.tagName = "g";
1249
+ break;
1250
+ case "textbox":
1251
+ result.tagName = "foreignObject";
1252
+ Object.assign(result.attrs, {
1253
+ width: "100%",
1254
+ height: "100%"
1255
+ });
1256
+ break;
1257
+ default: return null;
1258
+ }
1259
+ for (const at of globalXmlParser.attrs(elem)) switch (at.localName) {
1260
+ case "style":
1261
+ result.cssStyleText = at.value;
1262
+ break;
1263
+ case "fillcolor":
1264
+ result.attrs.fill = at.value;
1265
+ break;
1266
+ case "from":
1267
+ const [x1, y1] = parsePoint(at.value);
1268
+ Object.assign(result.attrs, {
1269
+ x1,
1270
+ y1
1271
+ });
1272
+ break;
1273
+ case "to":
1274
+ const [x2, y2] = parsePoint(at.value);
1275
+ Object.assign(result.attrs, {
1276
+ x2,
1277
+ y2
1278
+ });
1279
+ }
1280
+ for (const el of globalXmlParser.elements(elem)) switch (el.localName) {
1281
+ case "stroke":
1282
+ Object.assign(result.attrs, parseStroke(el));
1283
+ break;
1284
+ case "fill":
1285
+ Object.assign(result.attrs, parseFill(el));
1286
+ break;
1287
+ case "imagedata":
1288
+ result.tagName = "image";
1289
+ Object.assign(result.attrs, {
1290
+ width: "100%",
1291
+ height: "100%"
1292
+ });
1293
+ result.imageHref = {
1294
+ id: globalXmlParser.attr(el, "id"),
1295
+ title: globalXmlParser.attr(el, "title")
1296
+ };
1297
+ break;
1298
+ case "txbxContent":
1299
+ result.children.push(...parser.parseBodyElements(el));
1300
+ break;
1301
+ default:
1302
+ const child = parseVmlElement(el, parser);
1303
+ child && result.children.push(child);
1304
+ }
1305
+ return result;
1306
+ }
1307
+ function parseStroke(el) {
1308
+ return {
1309
+ "stroke": globalXmlParser.attr(el, "color"),
1310
+ "stroke-width": globalXmlParser.lengthAttr(el, "weight", LengthUsage.Emu) ?? "1px"
1311
+ };
1312
+ }
1313
+ function parseFill(el) {
1314
+ return {};
1315
+ }
1316
+ function parsePoint(val) {
1317
+ return val.split(",");
1318
+ }
1319
+ //#endregion
1320
+ //#region src/comments/elements.ts
1321
+ var WmlComment = class extends OpenXmlElementBase {
1322
+ constructor(..._args) {
1323
+ super(..._args);
1324
+ this.type = DomType.Comment;
1325
+ }
1326
+ };
1327
+ var WmlCommentReference = class extends OpenXmlElementBase {
1328
+ constructor(id) {
1329
+ super();
1330
+ this.id = id;
1331
+ this.type = DomType.CommentReference;
1332
+ }
1333
+ };
1334
+ var WmlCommentRangeStart = class extends OpenXmlElementBase {
1335
+ constructor(id) {
1336
+ super();
1337
+ this.id = id;
1338
+ this.type = DomType.CommentRangeStart;
1339
+ }
1340
+ };
1341
+ var WmlCommentRangeEnd = class extends OpenXmlElementBase {
1342
+ constructor(id) {
1343
+ super();
1344
+ this.id = id;
1345
+ this.type = DomType.CommentRangeEnd;
1346
+ }
1347
+ };
1348
+ //#endregion
1349
+ //#region src/document-parser.ts
1350
+ var autos = {
1351
+ shd: "inherit",
1352
+ color: "black",
1353
+ borderColor: "black",
1354
+ highlight: "transparent"
1355
+ };
1356
+ var supportedNamespaceURIs = [];
1357
+ var mmlTagMap = {
1358
+ "oMath": DomType.MmlMath,
1359
+ "oMathPara": DomType.MmlMathParagraph,
1360
+ "f": DomType.MmlFraction,
1361
+ "func": DomType.MmlFunction,
1362
+ "fName": DomType.MmlFunctionName,
1363
+ "num": DomType.MmlNumerator,
1364
+ "den": DomType.MmlDenominator,
1365
+ "rad": DomType.MmlRadical,
1366
+ "deg": DomType.MmlDegree,
1367
+ "e": DomType.MmlBase,
1368
+ "sSup": DomType.MmlSuperscript,
1369
+ "sSub": DomType.MmlSubscript,
1370
+ "sPre": DomType.MmlPreSubSuper,
1371
+ "sup": DomType.MmlSuperArgument,
1372
+ "sub": DomType.MmlSubArgument,
1373
+ "d": DomType.MmlDelimiter,
1374
+ "nary": DomType.MmlNary,
1375
+ "eqArr": DomType.MmlEquationArray,
1376
+ "lim": DomType.MmlLimit,
1377
+ "limLow": DomType.MmlLimitLower,
1378
+ "m": DomType.MmlMatrix,
1379
+ "mr": DomType.MmlMatrixRow,
1380
+ "box": DomType.MmlBox,
1381
+ "bar": DomType.MmlBar,
1382
+ "groupChr": DomType.MmlGroupChar
1383
+ };
1384
+ var DocumentParser = class {
1385
+ constructor(options) {
1386
+ this.options = {
1387
+ ignoreWidth: false,
1388
+ debug: false,
1389
+ ...options
1390
+ };
1391
+ }
1392
+ parseNotes(xmlDoc, elemName, elemClass) {
1393
+ var result = [];
1394
+ for (let el of globalXmlParser.elements(xmlDoc, elemName)) {
1395
+ const node = new elemClass();
1396
+ node.id = globalXmlParser.attr(el, "id");
1397
+ node.noteType = globalXmlParser.attr(el, "type");
1398
+ node.children = this.parseBodyElements(el);
1399
+ result.push(node);
1400
+ }
1401
+ return result;
1402
+ }
1403
+ parseComments(xmlDoc) {
1404
+ var result = [];
1405
+ for (let el of globalXmlParser.elements(xmlDoc, "comment")) {
1406
+ const item = new WmlComment();
1407
+ item.id = globalXmlParser.attr(el, "id");
1408
+ item.author = globalXmlParser.attr(el, "author");
1409
+ item.initials = globalXmlParser.attr(el, "initials");
1410
+ item.date = globalXmlParser.attr(el, "date");
1411
+ item.children = this.parseBodyElements(el);
1412
+ result.push(item);
1413
+ }
1414
+ return result;
1415
+ }
1416
+ parseDocumentFile(xmlDoc) {
1417
+ var xbody = globalXmlParser.element(xmlDoc, "body");
1418
+ var background = globalXmlParser.element(xmlDoc, "background");
1419
+ var sectPr = globalXmlParser.element(xbody, "sectPr");
1420
+ return {
1421
+ type: DomType.Document,
1422
+ children: this.parseBodyElements(xbody),
1423
+ props: sectPr ? parseSectionProperties(sectPr, globalXmlParser) : {},
1424
+ cssStyle: background ? this.parseBackground(background) : {}
1425
+ };
1426
+ }
1427
+ parseBackground(elem) {
1428
+ var result = {};
1429
+ var color = xmlUtil.colorAttr(elem, "color");
1430
+ if (color) result["background-color"] = color;
1431
+ return result;
1432
+ }
1433
+ parseBodyElements(element) {
1434
+ var children = [];
1435
+ for (const elem of globalXmlParser.elements(element)) switch (elem.localName) {
1436
+ case "p":
1437
+ children.push(this.parseParagraph(elem));
1438
+ break;
1439
+ case "altChunk":
1440
+ children.push(this.parseAltChunk(elem));
1441
+ break;
1442
+ case "tbl":
1443
+ children.push(this.parseTable(elem));
1444
+ break;
1445
+ case "sdt": children.push(...this.parseSdt(elem, (e) => this.parseBodyElements(e)));
1446
+ }
1447
+ return children;
1448
+ }
1449
+ parseStylesFile(xstyles) {
1450
+ var result = [];
1451
+ for (const n of globalXmlParser.elements(xstyles)) switch (n.localName) {
1452
+ case "style":
1453
+ result.push(this.parseStyle(n));
1454
+ break;
1455
+ case "docDefaults": result.push(this.parseDefaultStyles(n));
1456
+ }
1457
+ return result;
1458
+ }
1459
+ parseDefaultStyles(node) {
1460
+ var result = {
1461
+ id: null,
1462
+ name: null,
1463
+ target: null,
1464
+ basedOn: null,
1465
+ styles: []
1466
+ };
1467
+ for (const c of globalXmlParser.elements(node)) switch (c.localName) {
1468
+ case "rPrDefault":
1469
+ var rPr = globalXmlParser.element(c, "rPr");
1470
+ if (rPr) result.styles.push({
1471
+ target: "span",
1472
+ values: this.parseDefaultProperties(rPr, {})
1473
+ });
1474
+ break;
1475
+ case "pPrDefault":
1476
+ var pPr = globalXmlParser.element(c, "pPr");
1477
+ if (pPr) result.styles.push({
1478
+ target: "p",
1479
+ values: this.parseDefaultProperties(pPr, {})
1480
+ });
1481
+ }
1482
+ return result;
1483
+ }
1484
+ parseStyle(node) {
1485
+ var result = {
1486
+ id: globalXmlParser.attr(node, "styleId"),
1487
+ isDefault: globalXmlParser.boolAttr(node, "default"),
1488
+ name: null,
1489
+ target: null,
1490
+ basedOn: null,
1491
+ styles: [],
1492
+ linked: null
1493
+ };
1494
+ switch (globalXmlParser.attr(node, "type")) {
1495
+ case "paragraph":
1496
+ result.target = "p";
1497
+ break;
1498
+ case "table":
1499
+ result.target = "table";
1500
+ break;
1501
+ case "character": result.target = "span";
1502
+ }
1503
+ for (const n of globalXmlParser.elements(node)) switch (n.localName) {
1504
+ case "basedOn":
1505
+ result.basedOn = globalXmlParser.attr(n, "val");
1506
+ break;
1507
+ case "name":
1508
+ result.name = globalXmlParser.attr(n, "val");
1509
+ break;
1510
+ case "link":
1511
+ result.linked = globalXmlParser.attr(n, "val");
1512
+ break;
1513
+ case "next":
1514
+ result.next = globalXmlParser.attr(n, "val");
1515
+ break;
1516
+ case "aliases":
1517
+ result.aliases = globalXmlParser.attr(n, "val").split(",");
1518
+ break;
1519
+ case "pPr":
1520
+ result.styles.push({
1521
+ target: "p",
1522
+ values: this.parseDefaultProperties(n, {})
1523
+ });
1524
+ result.paragraphProps = parseParagraphProperties(n, globalXmlParser);
1525
+ break;
1526
+ case "rPr":
1527
+ result.styles.push({
1528
+ target: "span",
1529
+ values: this.parseDefaultProperties(n, {})
1530
+ });
1531
+ result.runProps = parseRunProperties(n, globalXmlParser);
1532
+ break;
1533
+ case "tblPr":
1534
+ case "tcPr":
1535
+ result.styles.push({
1536
+ target: "td",
1537
+ values: this.parseDefaultProperties(n, {})
1538
+ });
1539
+ break;
1540
+ case "tblStylePr":
1541
+ for (let s of this.parseTableStyle(n)) result.styles.push(s);
1542
+ break;
1543
+ case "rsid":
1544
+ case "qFormat":
1545
+ case "hidden":
1546
+ case "semiHidden":
1547
+ case "unhideWhenUsed":
1548
+ case "autoRedefine":
1549
+ case "uiPriority": break;
1550
+ default: this.options.debug && console.warn(`DOCX: Unknown style element: ${n.localName}`);
1551
+ }
1552
+ return result;
1553
+ }
1554
+ parseTableStyle(node) {
1555
+ var result = [];
1556
+ var type = globalXmlParser.attr(node, "type");
1557
+ var selector = "";
1558
+ var modificator = "";
1559
+ switch (type) {
1560
+ case "firstRow":
1561
+ modificator = ".first-row";
1562
+ selector = "tr.first-row td";
1563
+ break;
1564
+ case "lastRow":
1565
+ modificator = ".last-row";
1566
+ selector = "tr.last-row td";
1567
+ break;
1568
+ case "firstCol":
1569
+ modificator = ".first-col";
1570
+ selector = "td.first-col";
1571
+ break;
1572
+ case "lastCol":
1573
+ modificator = ".last-col";
1574
+ selector = "td.last-col";
1575
+ break;
1576
+ case "band1Vert":
1577
+ modificator = ":not(.no-vband)";
1578
+ selector = "td.odd-col";
1579
+ break;
1580
+ case "band2Vert":
1581
+ modificator = ":not(.no-vband)";
1582
+ selector = "td.even-col";
1583
+ break;
1584
+ case "band1Horz":
1585
+ modificator = ":not(.no-hband)";
1586
+ selector = "tr.odd-row";
1587
+ break;
1588
+ case "band2Horz":
1589
+ modificator = ":not(.no-hband)";
1590
+ selector = "tr.even-row";
1591
+ break;
1592
+ default: return [];
1593
+ }
1594
+ for (const n of globalXmlParser.elements(node)) switch (n.localName) {
1595
+ case "pPr":
1596
+ result.push({
1597
+ target: `${selector} p`,
1598
+ mod: modificator,
1599
+ values: this.parseDefaultProperties(n, {})
1600
+ });
1601
+ break;
1602
+ case "rPr":
1603
+ result.push({
1604
+ target: `${selector} span`,
1605
+ mod: modificator,
1606
+ values: this.parseDefaultProperties(n, {})
1607
+ });
1608
+ break;
1609
+ case "tblPr":
1610
+ case "tcPr": result.push({
1611
+ target: selector,
1612
+ mod: modificator,
1613
+ values: this.parseDefaultProperties(n, {})
1614
+ });
1615
+ }
1616
+ return result;
1617
+ }
1618
+ parseNumberingFile(node) {
1619
+ const levels = [];
1620
+ const nums = [];
1621
+ const bullets = [];
1622
+ for (const n of globalXmlParser.elements(node)) switch (n.localName) {
1623
+ case "abstractNum":
1624
+ levels.push(...this.parseAbstractNumbering(n, bullets));
1625
+ break;
1626
+ case "numPicBullet":
1627
+ bullets.push(this.parseNumberingPicBullet(n));
1628
+ break;
1629
+ case "num": nums.push({
1630
+ numId: globalXmlParser.attr(n, "numId"),
1631
+ abstractNumId: globalXmlParser.elementAttr(n, "abstractNumId", "val")
1632
+ });
1633
+ }
1634
+ return nums.flatMap((x) => levels.filter((lvl) => x.abstractNumId == lvl.id).map((lvl) => ({
1635
+ ...lvl,
1636
+ id: x.numId
1637
+ })));
1638
+ }
1639
+ parseNumberingPicBullet(elem) {
1640
+ var pict = globalXmlParser.element(elem, "pict");
1641
+ var shape = pict && globalXmlParser.element(pict, "shape");
1642
+ var imagedata = shape && globalXmlParser.element(shape, "imagedata");
1643
+ return imagedata ? {
1644
+ id: globalXmlParser.intAttr(elem, "numPicBulletId"),
1645
+ src: globalXmlParser.attr(imagedata, "id"),
1646
+ style: globalXmlParser.attr(shape, "style")
1647
+ } : null;
1648
+ }
1649
+ parseAbstractNumbering(node, bullets) {
1650
+ var result = [];
1651
+ var id = globalXmlParser.attr(node, "abstractNumId");
1652
+ for (const n of globalXmlParser.elements(node)) switch (n.localName) {
1653
+ case "lvl": result.push(this.parseNumberingLevel(id, n, bullets));
1654
+ }
1655
+ return result;
1656
+ }
1657
+ parseNumberingLevel(id, node, bullets) {
1658
+ var result = {
1659
+ id,
1660
+ level: globalXmlParser.intAttr(node, "ilvl"),
1661
+ start: 1,
1662
+ pStyleName: void 0,
1663
+ pStyle: {},
1664
+ rStyle: {},
1665
+ suff: "tab"
1666
+ };
1667
+ for (const n of globalXmlParser.elements(node)) switch (n.localName) {
1668
+ case "start":
1669
+ result.start = globalXmlParser.intAttr(n, "val");
1670
+ break;
1671
+ case "pPr":
1672
+ this.parseDefaultProperties(n, result.pStyle);
1673
+ break;
1674
+ case "rPr":
1675
+ this.parseDefaultProperties(n, result.rStyle);
1676
+ break;
1677
+ case "lvlPicBulletId":
1678
+ var bulletId = globalXmlParser.intAttr(n, "val");
1679
+ result.bullet = bullets.find((x) => x?.id == bulletId);
1680
+ break;
1681
+ case "lvlText":
1682
+ result.levelText = globalXmlParser.attr(n, "val");
1683
+ break;
1684
+ case "pStyle":
1685
+ result.pStyleName = globalXmlParser.attr(n, "val");
1686
+ break;
1687
+ case "numFmt":
1688
+ result.format = globalXmlParser.attr(n, "val");
1689
+ break;
1690
+ case "suff": result.suff = globalXmlParser.attr(n, "val");
1691
+ }
1692
+ return result;
1693
+ }
1694
+ parseSdt(node, parser) {
1695
+ const sdtContent = globalXmlParser.element(node, "sdtContent");
1696
+ return sdtContent ? parser(sdtContent) : [];
1697
+ }
1698
+ parseChange(type, node, parentParser) {
1699
+ return {
1700
+ type,
1701
+ children: parentParser(node)?.children ?? [],
1702
+ id: globalXmlParser.attr(node, "id"),
1703
+ author: globalXmlParser.attr(node, "author"),
1704
+ date: globalXmlParser.attr(node, "date")
1705
+ };
1706
+ }
1707
+ parseAltChunk(node) {
1708
+ return {
1709
+ type: DomType.AltChunk,
1710
+ children: [],
1711
+ id: globalXmlParser.attr(node, "id")
1712
+ };
1713
+ }
1714
+ parseParagraph(node) {
1715
+ var result = {
1716
+ type: DomType.Paragraph,
1717
+ children: []
1718
+ };
1719
+ for (let el of globalXmlParser.elements(node)) switch (el.localName) {
1720
+ case "pPr":
1721
+ this.parseParagraphProperties(el, result);
1722
+ break;
1723
+ case "r":
1724
+ result.children.push(this.parseRun(el, result));
1725
+ break;
1726
+ case "hyperlink":
1727
+ result.children.push(this.parseHyperlink(el, result));
1728
+ break;
1729
+ case "smartTag":
1730
+ result.children.push(this.parseSmartTag(el, result));
1731
+ break;
1732
+ case "bookmarkStart":
1733
+ result.children.push(parseBookmarkStart(el, globalXmlParser));
1734
+ break;
1735
+ case "bookmarkEnd":
1736
+ result.children.push(parseBookmarkEnd(el, globalXmlParser));
1737
+ break;
1738
+ case "commentRangeStart":
1739
+ result.children.push(new WmlCommentRangeStart(globalXmlParser.attr(el, "id")));
1740
+ break;
1741
+ case "commentRangeEnd":
1742
+ result.children.push(new WmlCommentRangeEnd(globalXmlParser.attr(el, "id")));
1743
+ break;
1744
+ case "oMath":
1745
+ case "oMathPara":
1746
+ result.children.push(this.parseMathElement(el));
1747
+ break;
1748
+ case "sdt":
1749
+ result.children.push(...this.parseSdt(el, (e) => this.parseParagraph(e).children));
1750
+ break;
1751
+ case "ins":
1752
+ result.children.push(this.parseChange(DomType.Inserted, el, (e) => this.parseParagraph(e)));
1753
+ break;
1754
+ case "del": result.children.push(this.parseChange(DomType.Deleted, el, (e) => this.parseParagraph(e)));
1755
+ }
1756
+ return result;
1757
+ }
1758
+ parseParagraphProperties(elem, paragraph) {
1759
+ this.parseDefaultProperties(elem, paragraph.cssStyle = {}, null, (c) => {
1760
+ if (parseParagraphProperty(c, paragraph, globalXmlParser)) return true;
1761
+ switch (c.localName) {
1762
+ case "pStyle":
1763
+ paragraph.styleName = globalXmlParser.attr(c, "val");
1764
+ break;
1765
+ case "cnfStyle":
1766
+ paragraph.className = values.classNameOfCnfStyle(c);
1767
+ break;
1768
+ case "framePr":
1769
+ this.parseFrame(c, paragraph);
1770
+ break;
1771
+ case "rPr": break;
1772
+ default: return false;
1773
+ }
1774
+ return true;
1775
+ });
1776
+ }
1777
+ parseFrame(node, paragraph) {
1778
+ if (globalXmlParser.attr(node, "dropCap") == "drop") paragraph.cssStyle["float"] = "left";
1779
+ }
1780
+ parseHyperlink(node, parent) {
1781
+ var result = {
1782
+ type: DomType.Hyperlink,
1783
+ parent,
1784
+ children: []
1785
+ };
1786
+ result.anchor = globalXmlParser.attr(node, "anchor");
1787
+ result.id = globalXmlParser.attr(node, "id");
1788
+ for (const c of globalXmlParser.elements(node)) switch (c.localName) {
1789
+ case "r": result.children.push(this.parseRun(c, result));
1790
+ }
1791
+ return result;
1792
+ }
1793
+ parseSmartTag(node, parent) {
1794
+ var result = {
1795
+ type: DomType.SmartTag,
1796
+ parent,
1797
+ children: []
1798
+ };
1799
+ var uri = globalXmlParser.attr(node, "uri");
1800
+ var element = globalXmlParser.attr(node, "element");
1801
+ if (uri) result.uri = uri;
1802
+ if (element) result.element = element;
1803
+ for (const c of globalXmlParser.elements(node)) switch (c.localName) {
1804
+ case "r":
1805
+ result.children.push(this.parseRun(c, result));
1806
+ break;
1807
+ case "smartTag": result.children.push(this.parseSmartTag(c, result));
1808
+ }
1809
+ return result;
1810
+ }
1811
+ parseRun(node, parent) {
1812
+ var result = {
1813
+ type: DomType.Run,
1814
+ parent,
1815
+ children: []
1816
+ };
1817
+ for (let c of globalXmlParser.elements(node)) {
1818
+ c = this.checkAlternateContent(c);
1819
+ switch (c.localName) {
1820
+ case "t":
1821
+ result.children.push({
1822
+ type: DomType.Text,
1823
+ text: c.textContent
1824
+ });
1825
+ break;
1826
+ case "delText":
1827
+ result.children.push({
1828
+ type: DomType.DeletedText,
1829
+ text: c.textContent
1830
+ });
1831
+ break;
1832
+ case "commentReference":
1833
+ result.children.push(new WmlCommentReference(globalXmlParser.attr(c, "id")));
1834
+ break;
1835
+ case "fldSimple":
1836
+ result.children.push({
1837
+ type: DomType.SimpleField,
1838
+ instruction: globalXmlParser.attr(c, "instr"),
1839
+ lock: globalXmlParser.boolAttr(c, "lock", false),
1840
+ dirty: globalXmlParser.boolAttr(c, "dirty", false)
1841
+ });
1842
+ break;
1843
+ case "instrText":
1844
+ result.fieldRun = true;
1845
+ result.children.push({
1846
+ type: DomType.Instruction,
1847
+ text: c.textContent
1848
+ });
1849
+ break;
1850
+ case "fldChar":
1851
+ result.fieldRun = true;
1852
+ result.children.push({
1853
+ type: DomType.ComplexField,
1854
+ charType: globalXmlParser.attr(c, "fldCharType"),
1855
+ lock: globalXmlParser.boolAttr(c, "lock", false),
1856
+ dirty: globalXmlParser.boolAttr(c, "dirty", false)
1857
+ });
1858
+ break;
1859
+ case "noBreakHyphen":
1860
+ result.children.push({ type: DomType.NoBreakHyphen });
1861
+ break;
1862
+ case "br":
1863
+ result.children.push({
1864
+ type: DomType.Break,
1865
+ break: globalXmlParser.attr(c, "type") || "textWrapping"
1866
+ });
1867
+ break;
1868
+ case "lastRenderedPageBreak":
1869
+ result.children.push({
1870
+ type: DomType.Break,
1871
+ break: "lastRenderedPageBreak"
1872
+ });
1873
+ break;
1874
+ case "sym":
1875
+ result.children.push({
1876
+ type: DomType.Symbol,
1877
+ font: encloseFontFamily(globalXmlParser.attr(c, "font")),
1878
+ char: globalXmlParser.hexAttr(c, "char")
1879
+ });
1880
+ break;
1881
+ case "tab":
1882
+ result.children.push({ type: DomType.Tab });
1883
+ break;
1884
+ case "footnoteReference":
1885
+ result.children.push({
1886
+ type: DomType.FootnoteReference,
1887
+ id: globalXmlParser.attr(c, "id")
1888
+ });
1889
+ break;
1890
+ case "endnoteReference":
1891
+ result.children.push({
1892
+ type: DomType.EndnoteReference,
1893
+ id: globalXmlParser.attr(c, "id")
1894
+ });
1895
+ break;
1896
+ case "drawing":
1897
+ let d = this.parseDrawing(c);
1898
+ if (d) result.children.push(d);
1899
+ break;
1900
+ case "pict":
1901
+ result.children.push(this.parseVmlPicture(c));
1902
+ break;
1903
+ case "rPr": this.parseRunProperties(c, result);
1904
+ }
1905
+ }
1906
+ return result;
1907
+ }
1908
+ parseMathElement(elem) {
1909
+ const propsTag = `${elem.localName}Pr`;
1910
+ const result = {
1911
+ type: mmlTagMap[elem.localName],
1912
+ children: []
1913
+ };
1914
+ for (const el of globalXmlParser.elements(elem)) if (mmlTagMap[el.localName]) result.children.push(this.parseMathElement(el));
1915
+ else if (el.localName == "r") {
1916
+ var run = this.parseRun(el);
1917
+ run.type = DomType.MmlRun;
1918
+ result.children.push(run);
1919
+ } else if (el.localName == propsTag) result.props = this.parseMathProperies(el);
1920
+ return result;
1921
+ }
1922
+ parseMathProperies(elem) {
1923
+ const result = {};
1924
+ for (const el of globalXmlParser.elements(elem)) switch (el.localName) {
1925
+ case "chr":
1926
+ result.char = globalXmlParser.attr(el, "val");
1927
+ break;
1928
+ case "vertJc":
1929
+ result.verticalJustification = globalXmlParser.attr(el, "val");
1930
+ break;
1931
+ case "pos":
1932
+ result.position = globalXmlParser.attr(el, "val");
1933
+ break;
1934
+ case "degHide":
1935
+ result.hideDegree = globalXmlParser.boolAttr(el, "val");
1936
+ break;
1937
+ case "begChr":
1938
+ result.beginChar = globalXmlParser.attr(el, "val");
1939
+ break;
1940
+ case "endChr": result.endChar = globalXmlParser.attr(el, "val");
1941
+ }
1942
+ return result;
1943
+ }
1944
+ parseRunProperties(elem, run) {
1945
+ this.parseDefaultProperties(elem, run.cssStyle = {}, null, (c) => {
1946
+ switch (c.localName) {
1947
+ case "rStyle":
1948
+ run.styleName = globalXmlParser.attr(c, "val");
1949
+ break;
1950
+ case "vertAlign":
1951
+ run.verticalAlign = values.valueOfVertAlign(c, true);
1952
+ break;
1953
+ default: return false;
1954
+ }
1955
+ return true;
1956
+ });
1957
+ }
1958
+ parseVmlPicture(elem) {
1959
+ const result = {
1960
+ type: DomType.VmlPicture,
1961
+ children: []
1962
+ };
1963
+ for (const el of globalXmlParser.elements(elem)) {
1964
+ const child = parseVmlElement(el, this);
1965
+ child && result.children.push(child);
1966
+ }
1967
+ return result;
1968
+ }
1969
+ checkAlternateContent(elem) {
1970
+ if (elem.localName != "AlternateContent") return elem;
1971
+ var choice = globalXmlParser.element(elem, "Choice");
1972
+ if (choice) {
1973
+ var requires = globalXmlParser.attr(choice, "Requires");
1974
+ var namespaceURI = elem.lookupNamespaceURI(requires);
1975
+ if (supportedNamespaceURIs.includes(namespaceURI)) return choice.firstElementChild;
1976
+ }
1977
+ return globalXmlParser.element(elem, "Fallback")?.firstElementChild;
1978
+ }
1979
+ parseDrawing(node) {
1980
+ for (var n of globalXmlParser.elements(node)) switch (n.localName) {
1981
+ case "inline":
1982
+ case "anchor": return this.parseDrawingWrapper(n);
1983
+ }
1984
+ }
1985
+ parseDrawingWrapper(node) {
1986
+ var result = {
1987
+ type: DomType.Drawing,
1988
+ children: [],
1989
+ cssStyle: {}
1990
+ };
1991
+ var isAnchor = node.localName == "anchor";
1992
+ let wrapType = null;
1993
+ let simplePos = globalXmlParser.boolAttr(node, "simplePos");
1994
+ globalXmlParser.boolAttr(node, "behindDoc");
1995
+ let posX = {
1996
+ relative: "page",
1997
+ align: "left",
1998
+ offset: "0"
1999
+ };
2000
+ let posY = {
2001
+ relative: "page",
2002
+ align: "top",
2003
+ offset: "0"
2004
+ };
2005
+ for (var n of globalXmlParser.elements(node)) switch (n.localName) {
2006
+ case "simplePos":
2007
+ if (simplePos) {
2008
+ posX.offset = globalXmlParser.lengthAttr(n, "x", LengthUsage.Emu);
2009
+ posY.offset = globalXmlParser.lengthAttr(n, "y", LengthUsage.Emu);
2010
+ }
2011
+ break;
2012
+ case "extent":
2013
+ result.cssStyle["width"] = globalXmlParser.lengthAttr(n, "cx", LengthUsage.Emu);
2014
+ result.cssStyle["height"] = globalXmlParser.lengthAttr(n, "cy", LengthUsage.Emu);
2015
+ break;
2016
+ case "positionH":
2017
+ case "positionV":
2018
+ if (!simplePos) {
2019
+ let pos = n.localName == "positionH" ? posX : posY;
2020
+ var alignNode = globalXmlParser.element(n, "align");
2021
+ var offsetNode = globalXmlParser.element(n, "posOffset");
2022
+ pos.relative = globalXmlParser.attr(n, "relativeFrom") ?? pos.relative;
2023
+ if (alignNode) pos.align = alignNode.textContent;
2024
+ if (offsetNode) pos.offset = convertLength(offsetNode.textContent, LengthUsage.Emu);
2025
+ }
2026
+ break;
2027
+ case "wrapTopAndBottom":
2028
+ wrapType = "wrapTopAndBottom";
2029
+ break;
2030
+ case "wrapNone":
2031
+ wrapType = "wrapNone";
2032
+ break;
2033
+ case "graphic":
2034
+ var g = this.parseGraphic(n);
2035
+ if (g) result.children.push(g);
2036
+ }
2037
+ if (wrapType == "wrapTopAndBottom") {
2038
+ result.cssStyle["display"] = "block";
2039
+ if (posX.align) {
2040
+ result.cssStyle["text-align"] = posX.align;
2041
+ result.cssStyle["width"] = "100%";
2042
+ }
2043
+ } else if (wrapType == "wrapNone") {
2044
+ result.cssStyle["display"] = "block";
2045
+ result.cssStyle["position"] = "relative";
2046
+ result.cssStyle["width"] = "0px";
2047
+ result.cssStyle["height"] = "0px";
2048
+ if (posX.offset) result.cssStyle["left"] = posX.offset;
2049
+ if (posY.offset) result.cssStyle["top"] = posY.offset;
2050
+ } else if (isAnchor && (posX.align == "left" || posX.align == "right")) result.cssStyle["float"] = posX.align;
2051
+ return result;
2052
+ }
2053
+ parseGraphic(elem) {
2054
+ var graphicData = globalXmlParser.element(elem, "graphicData");
2055
+ for (let n of globalXmlParser.elements(graphicData)) switch (n.localName) {
2056
+ case "pic": return this.parsePicture(n);
2057
+ }
2058
+ return null;
2059
+ }
2060
+ parsePicture(elem) {
2061
+ var result = {
2062
+ type: DomType.Image,
2063
+ src: "",
2064
+ cssStyle: {}
2065
+ };
2066
+ var blipFill = globalXmlParser.element(elem, "blipFill");
2067
+ var blip = globalXmlParser.element(blipFill, "blip");
2068
+ var srcRect = globalXmlParser.element(blipFill, "srcRect");
2069
+ result.src = globalXmlParser.attr(blip, "embed");
2070
+ if (srcRect) result.srcRect = [
2071
+ globalXmlParser.intAttr(srcRect, "l", 0) / 1e5,
2072
+ globalXmlParser.intAttr(srcRect, "t", 0) / 1e5,
2073
+ globalXmlParser.intAttr(srcRect, "r", 0) / 1e5,
2074
+ globalXmlParser.intAttr(srcRect, "b", 0) / 1e5
2075
+ ];
2076
+ var spPr = globalXmlParser.element(elem, "spPr");
2077
+ var xfrm = globalXmlParser.element(spPr, "xfrm");
2078
+ result.cssStyle["position"] = "relative";
2079
+ if (xfrm) {
2080
+ result.rotation = globalXmlParser.intAttr(xfrm, "rot", 0) / 6e4;
2081
+ for (var n of globalXmlParser.elements(xfrm)) switch (n.localName) {
2082
+ case "ext":
2083
+ result.cssStyle["width"] = globalXmlParser.lengthAttr(n, "cx", LengthUsage.Emu);
2084
+ result.cssStyle["height"] = globalXmlParser.lengthAttr(n, "cy", LengthUsage.Emu);
2085
+ break;
2086
+ case "off":
2087
+ result.cssStyle["left"] = globalXmlParser.lengthAttr(n, "x", LengthUsage.Emu);
2088
+ result.cssStyle["top"] = globalXmlParser.lengthAttr(n, "y", LengthUsage.Emu);
2089
+ }
2090
+ }
2091
+ return result;
2092
+ }
2093
+ parseTable(node) {
2094
+ var result = {
2095
+ type: DomType.Table,
2096
+ children: []
2097
+ };
2098
+ for (const c of globalXmlParser.elements(node)) switch (c.localName) {
2099
+ case "tr":
2100
+ result.children.push(this.parseTableRow(c));
2101
+ break;
2102
+ case "tblGrid":
2103
+ result.columns = this.parseTableColumns(c);
2104
+ break;
2105
+ case "tblPr": this.parseTableProperties(c, result);
2106
+ }
2107
+ return result;
2108
+ }
2109
+ parseTableColumns(node) {
2110
+ var result = [];
2111
+ for (const n of globalXmlParser.elements(node)) switch (n.localName) {
2112
+ case "gridCol": result.push({ width: globalXmlParser.lengthAttr(n, "w") });
2113
+ }
2114
+ return result;
2115
+ }
2116
+ parseTableProperties(elem, table) {
2117
+ table.cssStyle = {};
2118
+ table.cellStyle = {};
2119
+ this.parseDefaultProperties(elem, table.cssStyle, table.cellStyle, (c) => {
2120
+ switch (c.localName) {
2121
+ case "tblStyle":
2122
+ table.styleName = globalXmlParser.attr(c, "val");
2123
+ break;
2124
+ case "tblLook":
2125
+ table.className = values.classNameOftblLook(c);
2126
+ break;
2127
+ case "tblpPr":
2128
+ this.parseTablePosition(c, table);
2129
+ break;
2130
+ case "tblStyleColBandSize":
2131
+ table.colBandSize = globalXmlParser.intAttr(c, "val");
2132
+ break;
2133
+ case "tblStyleRowBandSize":
2134
+ table.rowBandSize = globalXmlParser.intAttr(c, "val");
2135
+ break;
2136
+ case "hidden":
2137
+ table.cssStyle["display"] = "none";
2138
+ break;
2139
+ default: return false;
2140
+ }
2141
+ return true;
2142
+ });
2143
+ switch (table.cssStyle["text-align"]) {
2144
+ case "center":
2145
+ delete table.cssStyle["text-align"];
2146
+ table.cssStyle["margin-left"] = "auto";
2147
+ table.cssStyle["margin-right"] = "auto";
2148
+ break;
2149
+ case "right":
2150
+ delete table.cssStyle["text-align"];
2151
+ table.cssStyle["margin-left"] = "auto";
2152
+ }
2153
+ }
2154
+ parseTablePosition(node, table) {
2155
+ var topFromText = globalXmlParser.lengthAttr(node, "topFromText");
2156
+ var bottomFromText = globalXmlParser.lengthAttr(node, "bottomFromText");
2157
+ var rightFromText = globalXmlParser.lengthAttr(node, "rightFromText");
2158
+ var leftFromText = globalXmlParser.lengthAttr(node, "leftFromText");
2159
+ var horzAnchor = globalXmlParser.attr(node, "horzAnchor");
2160
+ var vertAnchor = globalXmlParser.attr(node, "vertAnchor");
2161
+ var tblpXSpec = globalXmlParser.attr(node, "tblpXSpec");
2162
+ if (globalXmlParser.attr(node, "tblpYSpec") == "bottom" && vertAnchor != "text") {
2163
+ table.cssStyle["position"] = "absolute";
2164
+ table.cssStyle["bottom"] = vertAnchor == "page" ? "0px" : "var(--docx-pad-bottom, 0px)";
2165
+ if (tblpXSpec == "right") table.cssStyle["right"] = horzAnchor == "page" ? "0px" : "var(--docx-pad-right, 0px)";
2166
+ else if (tblpXSpec == "center") {
2167
+ table.cssStyle["left"] = "50%";
2168
+ table.cssStyle["transform"] = "translateX(-50%)";
2169
+ } else table.cssStyle["left"] = horzAnchor == "page" ? "0px" : "var(--docx-pad-left, 0px)";
2170
+ return;
2171
+ }
2172
+ table.cssStyle["float"] = "left";
2173
+ table.cssStyle["margin-bottom"] = values.addSize(table.cssStyle["margin-bottom"], bottomFromText);
2174
+ table.cssStyle["margin-left"] = values.addSize(table.cssStyle["margin-left"], leftFromText);
2175
+ table.cssStyle["margin-right"] = values.addSize(table.cssStyle["margin-right"], rightFromText);
2176
+ table.cssStyle["margin-top"] = values.addSize(table.cssStyle["margin-top"], topFromText);
2177
+ }
2178
+ parseTableRow(node) {
2179
+ var result = {
2180
+ type: DomType.Row,
2181
+ children: []
2182
+ };
2183
+ for (const c of globalXmlParser.elements(node)) switch (c.localName) {
2184
+ case "tc":
2185
+ result.children.push(this.parseTableCell(c));
2186
+ break;
2187
+ case "trPr":
2188
+ case "tblPrEx": this.parseTableRowProperties(c, result);
2189
+ }
2190
+ return result;
2191
+ }
2192
+ parseTableRowProperties(elem, row) {
2193
+ row.cssStyle = this.parseDefaultProperties(elem, {}, null, (c) => {
2194
+ switch (c.localName) {
2195
+ case "cnfStyle":
2196
+ row.className = values.classNameOfCnfStyle(c);
2197
+ break;
2198
+ case "tblHeader":
2199
+ row.isHeader = globalXmlParser.boolAttr(c, "val");
2200
+ break;
2201
+ case "gridBefore":
2202
+ row.gridBefore = globalXmlParser.intAttr(c, "val");
2203
+ break;
2204
+ case "gridAfter":
2205
+ row.gridAfter = globalXmlParser.intAttr(c, "val");
2206
+ break;
2207
+ default: return false;
2208
+ }
2209
+ return true;
2210
+ });
2211
+ }
2212
+ parseTableCell(node) {
2213
+ var result = {
2214
+ type: DomType.Cell,
2215
+ children: []
2216
+ };
2217
+ for (const c of globalXmlParser.elements(node)) switch (c.localName) {
2218
+ case "tbl":
2219
+ result.children.push(this.parseTable(c));
2220
+ break;
2221
+ case "p":
2222
+ result.children.push(this.parseParagraph(c));
2223
+ break;
2224
+ case "tcPr": this.parseTableCellProperties(c, result);
2225
+ }
2226
+ return result;
2227
+ }
2228
+ parseTableCellProperties(elem, cell) {
2229
+ cell.cssStyle = this.parseDefaultProperties(elem, {}, null, (c) => {
2230
+ switch (c.localName) {
2231
+ case "gridSpan":
2232
+ cell.span = globalXmlParser.intAttr(c, "val", null);
2233
+ break;
2234
+ case "vMerge":
2235
+ cell.verticalMerge = globalXmlParser.attr(c, "val") ?? "continue";
2236
+ break;
2237
+ case "cnfStyle":
2238
+ cell.className = values.classNameOfCnfStyle(c);
2239
+ break;
2240
+ default: return false;
2241
+ }
2242
+ return true;
2243
+ });
2244
+ this.parseTableCellVerticalText(elem, cell);
2245
+ }
2246
+ parseTableCellVerticalText(elem, cell) {
2247
+ const directionMap = {
2248
+ "btLr": {
2249
+ writingMode: "vertical-rl",
2250
+ transform: "rotate(180deg)"
2251
+ },
2252
+ "lrTb": {
2253
+ writingMode: "vertical-lr",
2254
+ transform: "none"
2255
+ },
2256
+ "tbRl": {
2257
+ writingMode: "vertical-rl",
2258
+ transform: "none"
2259
+ }
2260
+ };
2261
+ for (const c of globalXmlParser.elements(elem)) if (c.localName === "textDirection") {
2262
+ const style = directionMap[globalXmlParser.attr(c, "val")] || { writingMode: "horizontal-tb" };
2263
+ cell.cssStyle["writing-mode"] = style.writingMode;
2264
+ cell.cssStyle["transform"] = style.transform;
2265
+ }
2266
+ }
2267
+ parseDefaultProperties(elem, style = null, childStyle = null, handler = null) {
2268
+ style = style || {};
2269
+ for (const c of globalXmlParser.elements(elem)) {
2270
+ if (handler?.(c)) continue;
2271
+ switch (c.localName) {
2272
+ case "jc":
2273
+ style["text-align"] = values.valueOfJc(c);
2274
+ break;
2275
+ case "textAlignment":
2276
+ style["vertical-align"] = values.valueOfTextAlignment(c);
2277
+ break;
2278
+ case "color":
2279
+ style["color"] = xmlUtil.colorAttr(c, "val", null, autos.color);
2280
+ break;
2281
+ case "sz":
2282
+ style["font-size"] = style["min-height"] = globalXmlParser.lengthAttr(c, "val", LengthUsage.FontSize);
2283
+ break;
2284
+ case "shd":
2285
+ style["background-color"] = xmlUtil.colorAttr(c, "fill", null, autos.shd);
2286
+ break;
2287
+ case "highlight":
2288
+ style["background-color"] = xmlUtil.colorAttr(c, "val", null, autos.highlight);
2289
+ break;
2290
+ case "vertAlign": break;
2291
+ case "position":
2292
+ style.verticalAlign = globalXmlParser.lengthAttr(c, "val", LengthUsage.FontSize);
2293
+ break;
2294
+ case "tcW": if (this.options.ignoreWidth) break;
2295
+ case "tblW":
2296
+ style["width"] = values.valueOfSize(c, "w");
2297
+ break;
2298
+ case "trHeight":
2299
+ this.parseTrHeight(c, style);
2300
+ break;
2301
+ case "strike":
2302
+ style["text-decoration"] = globalXmlParser.boolAttr(c, "val", true) ? "line-through" : "none";
2303
+ break;
2304
+ case "b":
2305
+ style["font-weight"] = globalXmlParser.boolAttr(c, "val", true) ? "bold" : "normal";
2306
+ break;
2307
+ case "i":
2308
+ style["font-style"] = globalXmlParser.boolAttr(c, "val", true) ? "italic" : "normal";
2309
+ break;
2310
+ case "caps":
2311
+ style["text-transform"] = globalXmlParser.boolAttr(c, "val", true) ? "uppercase" : "none";
2312
+ break;
2313
+ case "smallCaps":
2314
+ style["font-variant"] = globalXmlParser.boolAttr(c, "val", true) ? "small-caps" : "none";
2315
+ break;
2316
+ case "u":
2317
+ this.parseUnderline(c, style);
2318
+ break;
2319
+ case "ind":
2320
+ case "tblInd":
2321
+ this.parseIndentation(c, style);
2322
+ break;
2323
+ case "rFonts":
2324
+ this.parseFont(c, style);
2325
+ break;
2326
+ case "tblBorders":
2327
+ this.parseBorderProperties(c, childStyle || style);
2328
+ break;
2329
+ case "tblCellSpacing":
2330
+ style["border-spacing"] = values.valueOfMargin(c);
2331
+ style["border-collapse"] = "separate";
2332
+ break;
2333
+ case "pBdr":
2334
+ this.parseBorderProperties(c, style);
2335
+ break;
2336
+ case "bdr":
2337
+ style["border"] = values.valueOfBorder(c);
2338
+ break;
2339
+ case "tcBorders":
2340
+ this.parseBorderProperties(c, style);
2341
+ break;
2342
+ case "vanish":
2343
+ if (globalXmlParser.boolAttr(c, "val", true)) style["display"] = "none";
2344
+ break;
2345
+ case "kern": break;
2346
+ case "noWrap": break;
2347
+ case "tblCellMar":
2348
+ case "tcMar":
2349
+ this.parseMarginProperties(c, childStyle || style);
2350
+ break;
2351
+ case "tblLayout":
2352
+ style["table-layout"] = values.valueOfTblLayout(c);
2353
+ break;
2354
+ case "vAlign":
2355
+ style["vertical-align"] = values.valueOfTextAlignment(c);
2356
+ break;
2357
+ case "spacing":
2358
+ if (elem.localName == "pPr") this.parseSpacing(c, style);
2359
+ break;
2360
+ case "wordWrap":
2361
+ if (globalXmlParser.boolAttr(c, "val")) style["overflow-wrap"] = "break-word";
2362
+ break;
2363
+ case "suppressAutoHyphens":
2364
+ style["hyphens"] = globalXmlParser.boolAttr(c, "val", true) ? "none" : "auto";
2365
+ break;
2366
+ case "lang":
2367
+ style["$lang"] = globalXmlParser.attr(c, "val");
2368
+ break;
2369
+ case "rtl":
2370
+ case "bidi":
2371
+ if (globalXmlParser.boolAttr(c, "val", true)) style["direction"] = "rtl";
2372
+ break;
2373
+ case "bCs":
2374
+ case "iCs":
2375
+ case "szCs":
2376
+ case "tabs":
2377
+ case "outlineLvl":
2378
+ case "contextualSpacing":
2379
+ case "tblStyleColBandSize":
2380
+ case "tblStyleRowBandSize":
2381
+ case "webHidden":
2382
+ case "pageBreakBefore":
2383
+ case "suppressLineNumbers":
2384
+ case "keepLines":
2385
+ case "keepNext":
2386
+ case "widowControl":
2387
+ case "noProof": break;
2388
+ default: if (this.options.debug) console.warn(`DOCX: Unknown document element: ${elem.localName}.${c.localName}`);
2389
+ }
2390
+ }
2391
+ return style;
2392
+ }
2393
+ parseUnderline(node, style) {
2394
+ var val = globalXmlParser.attr(node, "val");
2395
+ if (val == null) return;
2396
+ switch (val) {
2397
+ case "dash":
2398
+ case "dashDotDotHeavy":
2399
+ case "dashDotHeavy":
2400
+ case "dashedHeavy":
2401
+ case "dashLong":
2402
+ case "dashLongHeavy":
2403
+ case "dotDash":
2404
+ case "dotDotDash":
2405
+ style["text-decoration"] = "underline dashed";
2406
+ break;
2407
+ case "dotted":
2408
+ case "dottedHeavy":
2409
+ style["text-decoration"] = "underline dotted";
2410
+ break;
2411
+ case "double":
2412
+ style["text-decoration"] = "underline double";
2413
+ break;
2414
+ case "single":
2415
+ case "thick":
2416
+ style["text-decoration"] = "underline";
2417
+ break;
2418
+ case "wave":
2419
+ case "wavyDouble":
2420
+ case "wavyHeavy":
2421
+ style["text-decoration"] = "underline wavy";
2422
+ break;
2423
+ case "words":
2424
+ style["text-decoration"] = "underline";
2425
+ break;
2426
+ case "none": style["text-decoration"] = "none";
2427
+ }
2428
+ var col = xmlUtil.colorAttr(node, "color");
2429
+ if (col) style["text-decoration-color"] = col;
2430
+ }
2431
+ parseFont(node, style) {
2432
+ var ascii = globalXmlParser.attr(node, "ascii") ?? globalXmlParser.attr(node, "hAnsi") ?? values.themeValue(node, "asciiTheme") ?? values.themeValue(node, "hAnsiTheme");
2433
+ var eastAsia = globalXmlParser.attr(node, "eastAsia") ?? values.themeValue(node, "eastAsiaTheme");
2434
+ if (ascii) style["--docx-font-ascii"] = encloseFontFamily(ascii);
2435
+ if (eastAsia) style["--docx-font-ea"] = encloseFontFamily(eastAsia);
2436
+ }
2437
+ parseIndentation(node, style) {
2438
+ var firstLine = globalXmlParser.lengthAttr(node, "firstLine");
2439
+ var hanging = globalXmlParser.lengthAttr(node, "hanging");
2440
+ var left = globalXmlParser.lengthAttr(node, "left");
2441
+ var start = globalXmlParser.lengthAttr(node, "start");
2442
+ var right = globalXmlParser.lengthAttr(node, "right");
2443
+ var end = globalXmlParser.lengthAttr(node, "end");
2444
+ if (firstLine) style["text-indent"] = firstLine;
2445
+ if (hanging) style["text-indent"] = `-${hanging}`;
2446
+ if (left || start) style["margin-inline-start"] = left || start;
2447
+ if (right || end) style["margin-inline-end"] = right || end;
2448
+ }
2449
+ parseSpacing(node, style) {
2450
+ var before = globalXmlParser.lengthAttr(node, "before");
2451
+ var after = globalXmlParser.lengthAttr(node, "after");
2452
+ var beforeLines = globalXmlParser.intAttr(node, "beforeLines", null);
2453
+ var afterLines = globalXmlParser.intAttr(node, "afterLines", null);
2454
+ var line = globalXmlParser.intAttr(node, "line", null);
2455
+ var lineRule = globalXmlParser.attr(node, "lineRule");
2456
+ if (before) style["margin-top"] = before;
2457
+ else if (beforeLines != null) style["margin-top"] = `${beforeLines / 100}em`;
2458
+ if (after) style["margin-bottom"] = after;
2459
+ else if (afterLines != null) style["margin-bottom"] = `${afterLines / 100}em`;
2460
+ if (line !== null) switch (lineRule) {
2461
+ case "auto":
2462
+ style["line-height"] = `${(line / 240).toFixed(2)}`;
2463
+ break;
2464
+ case "atLeast":
2465
+ style["line-height"] = `${line / 20}pt`;
2466
+ break;
2467
+ default: style["line-height"] = style["min-height"] = `${line / 20}pt`;
2468
+ }
2469
+ }
2470
+ parseMarginProperties(node, output) {
2471
+ for (const c of globalXmlParser.elements(node)) switch (c.localName) {
2472
+ case "left":
2473
+ output["padding-left"] = values.valueOfMargin(c);
2474
+ break;
2475
+ case "right":
2476
+ output["padding-right"] = values.valueOfMargin(c);
2477
+ break;
2478
+ case "top":
2479
+ output["padding-top"] = values.valueOfMargin(c);
2480
+ break;
2481
+ case "bottom": output["padding-bottom"] = values.valueOfMargin(c);
2482
+ }
2483
+ }
2484
+ parseTrHeight(node, output) {
2485
+ switch (globalXmlParser.attr(node, "hRule")) {
2486
+ case "exact":
2487
+ output["height"] = globalXmlParser.lengthAttr(node, "val");
2488
+ break;
2489
+ default: output["height"] = globalXmlParser.lengthAttr(node, "val");
2490
+ }
2491
+ }
2492
+ parseBorderProperties(node, output) {
2493
+ for (const c of globalXmlParser.elements(node)) switch (c.localName) {
2494
+ case "start":
2495
+ case "left":
2496
+ output["border-left"] = values.valueOfBorder(c);
2497
+ break;
2498
+ case "end":
2499
+ case "right":
2500
+ output["border-right"] = values.valueOfBorder(c);
2501
+ break;
2502
+ case "top":
2503
+ output["border-top"] = values.valueOfBorder(c);
2504
+ break;
2505
+ case "bottom": output["border-bottom"] = values.valueOfBorder(c);
2506
+ }
2507
+ }
2508
+ };
2509
+ var knownColors = [
2510
+ "black",
2511
+ "blue",
2512
+ "cyan",
2513
+ "darkBlue",
2514
+ "darkCyan",
2515
+ "darkGray",
2516
+ "darkGreen",
2517
+ "darkMagenta",
2518
+ "darkRed",
2519
+ "darkYellow",
2520
+ "green",
2521
+ "lightGray",
2522
+ "magenta",
2523
+ "none",
2524
+ "red",
2525
+ "white",
2526
+ "yellow"
2527
+ ];
2528
+ var xmlUtil = class {
2529
+ static colorAttr(node, attrName, defValue = null, autoColor = "black") {
2530
+ var v = globalXmlParser.attr(node, attrName);
2531
+ if (v) {
2532
+ if (v == "auto") return autoColor;
2533
+ else if (knownColors.includes(v)) return v;
2534
+ return `#${v}`;
2535
+ }
2536
+ var themeColor = globalXmlParser.attr(node, "themeColor");
2537
+ return themeColor ? `var(--docx-${themeColor}-color)` : defValue;
2538
+ }
2539
+ };
2540
+ var values = class values {
2541
+ static themeValue(c, attr) {
2542
+ var val = globalXmlParser.attr(c, attr);
2543
+ return val ? `var(--docx-${val}-font)` : null;
2544
+ }
2545
+ static valueOfSize(c, attr) {
2546
+ var type = LengthUsage.Dxa;
2547
+ switch (globalXmlParser.attr(c, "type")) {
2548
+ case "dxa": break;
2549
+ case "pct":
2550
+ type = LengthUsage.Percent;
2551
+ break;
2552
+ case "auto": return "auto";
2553
+ }
2554
+ return globalXmlParser.lengthAttr(c, attr, type);
2555
+ }
2556
+ static valueOfMargin(c) {
2557
+ return globalXmlParser.lengthAttr(c, "w");
2558
+ }
2559
+ static valueOfBorder(c) {
2560
+ var type = values.parseBorderType(globalXmlParser.attr(c, "val"));
2561
+ if (type == "none") return "none";
2562
+ var color = xmlUtil.colorAttr(c, "color");
2563
+ return `${globalXmlParser.lengthAttr(c, "sz", LengthUsage.Border)} ${type} ${color == "auto" ? autos.borderColor : color}`;
2564
+ }
2565
+ static parseBorderType(type) {
2566
+ switch (type) {
2567
+ case "single": return "solid";
2568
+ case "dashDotStroked": return "solid";
2569
+ case "dashed": return "dashed";
2570
+ case "dashSmallGap": return "dashed";
2571
+ case "dotDash": return "dotted";
2572
+ case "dotDotDash": return "dotted";
2573
+ case "dotted": return "dotted";
2574
+ case "double": return "double";
2575
+ case "doubleWave": return "double";
2576
+ case "inset": return "inset";
2577
+ case "nil": return "none";
2578
+ case "none": return "none";
2579
+ case "outset": return "outset";
2580
+ case "thick": return "solid";
2581
+ case "thickThinLargeGap": return "solid";
2582
+ case "thickThinMediumGap": return "solid";
2583
+ case "thickThinSmallGap": return "solid";
2584
+ case "thinThickLargeGap": return "solid";
2585
+ case "thinThickMediumGap": return "solid";
2586
+ case "thinThickSmallGap": return "solid";
2587
+ case "thinThickThinLargeGap": return "solid";
2588
+ case "thinThickThinMediumGap": return "solid";
2589
+ case "thinThickThinSmallGap": return "solid";
2590
+ case "threeDEmboss": return "solid";
2591
+ case "threeDEngrave": return "solid";
2592
+ case "triple": return "double";
2593
+ case "wave": return "solid";
2594
+ }
2595
+ return "solid";
2596
+ }
2597
+ static valueOfTblLayout(c) {
2598
+ return globalXmlParser.attr(c, "val") == "fixed" ? "fixed" : "auto";
2599
+ }
2600
+ static classNameOfCnfStyle(c) {
2601
+ const val = globalXmlParser.attr(c, "val");
2602
+ const classes = [
2603
+ "first-row",
2604
+ "last-row",
2605
+ "first-col",
2606
+ "last-col",
2607
+ "odd-col",
2608
+ "even-col",
2609
+ "odd-row",
2610
+ "even-row",
2611
+ "ne-cell",
2612
+ "nw-cell",
2613
+ "se-cell",
2614
+ "sw-cell"
2615
+ ];
2616
+ if (val) return classes.filter((_, i) => val[i] == "1").join(" ");
2617
+ const attrs = [
2618
+ "firstRow",
2619
+ "lastRow",
2620
+ "firstColumn",
2621
+ "lastColumn",
2622
+ "oddVBand",
2623
+ "evenVBand",
2624
+ "oddHBand",
2625
+ "evenHBand",
2626
+ "firstRowLastColumn",
2627
+ "firstRowFirstColumn",
2628
+ "lastRowLastColumn",
2629
+ "lastRowFirstColumn"
2630
+ ];
2631
+ return classes.filter((_, i) => globalXmlParser.boolAttr(c, attrs[i])).join(" ");
2632
+ }
2633
+ static valueOfJc(c) {
2634
+ var type = globalXmlParser.attr(c, "val");
2635
+ switch (type) {
2636
+ case "start":
2637
+ case "left": return "left";
2638
+ case "center": return "center";
2639
+ case "end":
2640
+ case "right": return "right";
2641
+ case "both": return "justify";
2642
+ }
2643
+ return type;
2644
+ }
2645
+ static valueOfVertAlign(c, asTagName = false) {
2646
+ var type = globalXmlParser.attr(c, "val");
2647
+ switch (type) {
2648
+ case "subscript": return "sub";
2649
+ case "superscript": return asTagName ? "sup" : "super";
2650
+ }
2651
+ return asTagName ? null : type;
2652
+ }
2653
+ static valueOfTextAlignment(c) {
2654
+ var type = globalXmlParser.attr(c, "val");
2655
+ switch (type) {
2656
+ case "auto":
2657
+ case "baseline": return "baseline";
2658
+ case "top": return "top";
2659
+ case "center": return "middle";
2660
+ case "bottom": return "bottom";
2661
+ }
2662
+ return type;
2663
+ }
2664
+ static addSize(a, b) {
2665
+ if (a == null) return b;
2666
+ if (b == null) return a;
2667
+ return `calc(${a} + ${b})`;
2668
+ }
2669
+ static classNameOftblLook(c) {
2670
+ const val = globalXmlParser.hexAttr(c, "val", 0);
2671
+ let className = "";
2672
+ if (globalXmlParser.boolAttr(c, "firstRow") || val & 32) className += " first-row";
2673
+ if (globalXmlParser.boolAttr(c, "lastRow") || val & 64) className += " last-row";
2674
+ if (globalXmlParser.boolAttr(c, "firstColumn") || val & 128) className += " first-col";
2675
+ if (globalXmlParser.boolAttr(c, "lastColumn") || val & 256) className += " last-col";
2676
+ if (globalXmlParser.boolAttr(c, "noHBand") || val & 512) className += " no-hband";
2677
+ if (globalXmlParser.boolAttr(c, "noVBand") || val & 1024) className += " no-vband";
2678
+ return className.trim();
2679
+ }
2680
+ };
2681
+ //#endregion
2682
+ //#region src/javascript.ts
2683
+ var defaultTab = {
2684
+ pos: 0,
2685
+ leader: "none",
2686
+ style: "left"
2687
+ };
2688
+ var maxTabs = 50;
2689
+ function computePixelToPoint(container = document.body) {
2690
+ const temp = document.createElement("div");
2691
+ temp.style.width = "100pt";
2692
+ container.appendChild(temp);
2693
+ const result = 100 / temp.offsetWidth;
2694
+ container.removeChild(temp);
2695
+ return result;
2696
+ }
2697
+ function updateTabStop(elem, tabs, defaultTabSize, pixelToPoint = 72 / 96) {
2698
+ const p = elem.closest("p");
2699
+ const ebb = elem.getBoundingClientRect();
2700
+ const pbb = p.getBoundingClientRect();
2701
+ const pcs = getComputedStyle(p);
2702
+ const tabStops = tabs?.length > 0 ? tabs.map((t) => ({
2703
+ pos: lengthToPoint(t.position),
2704
+ leader: t.leader,
2705
+ style: t.style
2706
+ })).sort((a, b) => a.pos - b.pos) : [defaultTab];
2707
+ const lastTab = tabStops[tabStops.length - 1];
2708
+ const pWidthPt = pbb.width * pixelToPoint;
2709
+ const size = lengthToPoint(defaultTabSize);
2710
+ let pos = lastTab.pos + size;
2711
+ if (pos < pWidthPt) for (; pos < pWidthPt && tabStops.length < maxTabs; pos += size) tabStops.push({
2712
+ ...defaultTab,
2713
+ pos
2714
+ });
2715
+ const marginLeft = parseFloat(pcs.marginLeft);
2716
+ const pOffset = pbb.left + marginLeft;
2717
+ const left = (ebb.left - pOffset) * pixelToPoint;
2718
+ const tab = tabStops.find((t) => t.style != "clear" && t.pos > left);
2719
+ if (tab == null) return;
2720
+ let width = 1;
2721
+ if (tab.style == "right" || tab.style == "center") {
2722
+ const tabStops = Array.from(p.querySelectorAll(`.${elem.className}`));
2723
+ const nextIdx = tabStops.indexOf(elem) + 1;
2724
+ const range = document.createRange();
2725
+ range.setStart(elem, 1);
2726
+ if (nextIdx < tabStops.length) range.setEndBefore(tabStops[nextIdx]);
2727
+ else range.setEndAfter(p);
2728
+ const mul = tab.style == "center" ? .5 : 1;
2729
+ const nextBB = range.getBoundingClientRect();
2730
+ const offset = nextBB.left + mul * nextBB.width - (pbb.left - marginLeft);
2731
+ width = tab.pos - offset * pixelToPoint;
2732
+ } else width = tab.pos - left;
2733
+ elem.innerHTML = "&nbsp;";
2734
+ elem.style.textDecoration = "inherit";
2735
+ elem.style.wordSpacing = `${width.toFixed(0)}pt`;
2736
+ switch (tab.leader) {
2737
+ case "dot":
2738
+ case "middleDot":
2739
+ elem.style.textDecoration = "underline";
2740
+ elem.style.textDecorationStyle = "dotted";
2741
+ break;
2742
+ case "hyphen":
2743
+ case "heavy":
2744
+ case "underscore": elem.style.textDecoration = "underline";
2745
+ }
2746
+ }
2747
+ function lengthToPoint(length) {
2748
+ return parseFloat(length);
2749
+ }
2750
+ //#endregion
2751
+ //#region src/html.ts
2752
+ var ns = /* @__PURE__ */ function(ns) {
2753
+ ns["html"] = "http://www.w3.org/1999/xhtml";
2754
+ ns["svg"] = "http://www.w3.org/2000/svg";
2755
+ ns["mathML"] = "http://www.w3.org/1998/Math/MathML";
2756
+ return ns;
2757
+ }({});
2758
+ function h(elem) {
2759
+ if (isString(elem)) return document.createTextNode(elem);
2760
+ if (elem instanceof Node) return elem;
2761
+ const { ns, tagName, className, style, children, ...props } = elem;
2762
+ if (tagName === "#fragment") return document.createDocumentFragment();
2763
+ if (tagName === "#comment") return document.createComment(children[0]);
2764
+ const result = ns ? document.createElementNS(ns, tagName) : document.createElement(tagName);
2765
+ if (className) result.setAttribute("class", className);
2766
+ if (style) {
2767
+ if (isString(style)) result.setAttribute("style", style);
2768
+ else for (const [key, value] of Object.entries(style)) if (key.startsWith("--")) result.style.setProperty(key, value);
2769
+ else result.style[key] = value;
2770
+ }
2771
+ if (props) {
2772
+ for (const [key, value] of Object.entries(props)) if (value !== void 0) result[key] = value;
2773
+ }
2774
+ if (children) children.forEach((c) => result.appendChild(h(c)));
2775
+ return result;
2776
+ }
2777
+ function cx(...classNames) {
2778
+ return classNames.filter(Boolean).join(" ");
2779
+ }
2780
+ //#endregion
2781
+ //#region src/html-renderer.ts
2782
+ var HtmlRenderer = class {
2783
+ constructor() {
2784
+ this.className = "docx";
2785
+ this.styleMap = {};
2786
+ this.currentPart = null;
2787
+ this.tableVerticalMerges = [];
2788
+ this.currentVerticalMerge = null;
2789
+ this.tableCellPositions = [];
2790
+ this.currentCellPosition = null;
2791
+ this.footnoteMap = {};
2792
+ this.endnoteMap = {};
2793
+ this.currentEndnoteIds = [];
2794
+ this.usedHederFooterParts = [];
2795
+ this.currentTabs = [];
2796
+ this.legacyCompat = false;
2797
+ this.commentMap = {};
2798
+ this.tasks = [];
2799
+ this.postRenderTasks = [];
2800
+ this.h = h;
2801
+ }
2802
+ async render(document, options) {
2803
+ this.document = document;
2804
+ this.options = options;
2805
+ this.className = options.className;
2806
+ this.rootSelector = options.inWrapper ? `.${this.className}-wrapper` : ":root";
2807
+ this.h = options.h ?? h;
2808
+ this.styleMap = null;
2809
+ this.tasks = [];
2810
+ if (this.options.renderComments && globalThis.Highlight) this.commentHighlight = new Highlight();
2811
+ const result = [...this.renderDefaultStyle()];
2812
+ if (document.themePart) result.push(...this.renderTheme(document.themePart));
2813
+ if (document.stylesPart != null) {
2814
+ this.styleMap = this.processStyles(document.stylesPart.styles);
2815
+ result.push(...this.renderStyles(document.stylesPart.styles));
2816
+ }
2817
+ if (document.numberingPart) {
2818
+ this.prodessNumberings(document.numberingPart.domNumberings);
2819
+ result.push(...await this.renderNumbering(document.numberingPart.domNumberings));
2820
+ }
2821
+ if (document.footnotesPart) this.footnoteMap = keyBy(document.footnotesPart.notes, (x) => x.id);
2822
+ if (document.endnotesPart) this.endnoteMap = keyBy(document.endnotesPart.notes, (x) => x.id);
2823
+ if (document.settingsPart) {
2824
+ this.defaultTabSize = document.settingsPart.settings?.defaultTabStop;
2825
+ const compatMode = document.settingsPart.settings?.compatMode;
2826
+ this.legacyCompat = compatMode != null && compatMode <= 11;
2827
+ }
2828
+ if (!options.ignoreFonts && document.fontTablePart) result.push(...await this.renderFontTable(document.fontTablePart));
2829
+ var sectionElements = this.renderSections(document.documentPart.body);
2830
+ if (this.options.inWrapper) result.push(this.renderWrapper(sectionElements));
2831
+ else result.push(...sectionElements);
2832
+ if (this.commentHighlight && options.renderComments) CSS.highlights.set(`${this.className}-comments`, this.commentHighlight);
2833
+ this.postRenderTasks.forEach((t) => t());
2834
+ await Promise.allSettled(this.tasks);
2835
+ this.refreshTabStops();
2836
+ return result;
2837
+ }
2838
+ renderTheme(themePart) {
2839
+ const variables = {};
2840
+ const fontScheme = themePart.theme?.fontScheme;
2841
+ if (fontScheme) {
2842
+ if (fontScheme.majorFont) {
2843
+ variables["--docx-majorHAnsi-font"] = fontScheme.majorFont.latinTypeface;
2844
+ variables["--docx-majorEastAsia-font"] = fontScheme.majorFont.eaTypeface || fontScheme.majorFont.latinTypeface;
2845
+ }
2846
+ if (fontScheme.minorFont) {
2847
+ variables["--docx-minorHAnsi-font"] = fontScheme.minorFont.latinTypeface;
2848
+ variables["--docx-minorEastAsia-font"] = fontScheme.minorFont.eaTypeface || fontScheme.minorFont.latinTypeface;
2849
+ }
2850
+ }
2851
+ const colorScheme = themePart.theme?.colorScheme;
2852
+ if (colorScheme) for (let [k, v] of Object.entries(colorScheme.colors)) variables[`--docx-${k}-color`] = `#${v}`;
2853
+ const cssText = this.styleToString(`.${this.className}`, variables);
2854
+ return [this.h({
2855
+ tagName: "#comment",
2856
+ children: ["docxjs document theme values"]
2857
+ }), this.h({
2858
+ tagName: "style",
2859
+ children: [cssText]
2860
+ })];
2861
+ }
2862
+ async renderFontTable(fontsPart) {
2863
+ const result = [];
2864
+ for (let f of fontsPart.fonts) for (let ref of f.embedFontRefs) try {
2865
+ const fontData = await this.document.loadFont(ref.id, ref.key);
2866
+ const cssValues = {
2867
+ "font-family": encloseFontFamily(f.name),
2868
+ "src": `url(${fontData})`
2869
+ };
2870
+ if (ref.type == "bold" || ref.type == "boldItalic") cssValues["font-weight"] = "bold";
2871
+ if (ref.type == "italic" || ref.type == "boldItalic") cssValues["font-style"] = "italic";
2872
+ result.push(this.h({
2873
+ tagName: "#comment",
2874
+ children: [`docxjs ${f.name} font`]
2875
+ }));
2876
+ result.push(this.h({
2877
+ tagName: "style",
2878
+ children: [this.styleToString(`@font-face`, cssValues)]
2879
+ }));
2880
+ } catch (e) {
2881
+ if (this.options.debug) console.warn(`Can't load font with id ${ref.id} and key ${ref.key}`);
2882
+ }
2883
+ return result;
2884
+ }
2885
+ processStyleName(className) {
2886
+ return className ? `${this.className}_${escapeClassName(className)}` : this.className;
2887
+ }
2888
+ processStyles(styles) {
2889
+ const stylesMap = keyBy(styles.filter((x) => x.id != null), (x) => x.id);
2890
+ this.defaultParagraphStyle = styles.find((s) => s.isDefault && s.target == "p");
2891
+ this.docDefaultsStyle = styles.find((s) => s.id == null);
2892
+ for (const style of styles.filter((x) => x.basedOn)) {
2893
+ var baseStyle = stylesMap[style.basedOn];
2894
+ if (baseStyle) {
2895
+ style.paragraphProps = mergeDeep(style.paragraphProps, baseStyle.paragraphProps);
2896
+ style.runProps = mergeDeep(style.runProps, baseStyle.runProps);
2897
+ for (const baseValues of baseStyle.styles) {
2898
+ const styleValues = style.styles.find((x) => x.target == baseValues.target);
2899
+ if (styleValues) this.copyStyleProperties(baseValues.values, styleValues.values);
2900
+ else style.styles.push({
2901
+ ...baseValues,
2902
+ values: { ...baseValues.values }
2903
+ });
2904
+ }
2905
+ } else if (this.options.debug) console.warn(`Can't find base style ${style.basedOn}`);
2906
+ }
2907
+ for (let style of styles) style.cssName = this.processStyleName(style.id);
2908
+ return stylesMap;
2909
+ }
2910
+ prodessNumberings(numberings) {
2911
+ for (let num of numberings.filter((n) => n.pStyleName)) {
2912
+ const style = this.findStyle(num.pStyleName);
2913
+ if (style?.paragraphProps?.numbering) style.paragraphProps.numbering.level = num.level;
2914
+ }
2915
+ }
2916
+ processElement(element) {
2917
+ if (element.children) for (var e of element.children) {
2918
+ e.parent = element;
2919
+ if (e.type == DomType.Table) this.processTable(e);
2920
+ else this.processElement(e);
2921
+ }
2922
+ }
2923
+ processTable(table) {
2924
+ for (var r of table.children) for (var c of r.children) {
2925
+ c.cssStyle = this.copyStyleProperties(table.cellStyle, c.cssStyle, [
2926
+ "border-left",
2927
+ "border-right",
2928
+ "border-top",
2929
+ "border-bottom",
2930
+ "padding-left",
2931
+ "padding-right",
2932
+ "padding-top",
2933
+ "padding-bottom"
2934
+ ]);
2935
+ this.processElement(c);
2936
+ }
2937
+ }
2938
+ copyStyleProperties(input, output, attrs = null) {
2939
+ if (!input) return output;
2940
+ if (output == null) output = {};
2941
+ if (attrs == null) attrs = Object.getOwnPropertyNames(input);
2942
+ for (var key of attrs) if (input.hasOwnProperty(key) && !output.hasOwnProperty(key)) output[key] = input[key];
2943
+ return output;
2944
+ }
2945
+ createPageElement(className, props, docStyle) {
2946
+ const style = { ...docStyle };
2947
+ if (props) {
2948
+ if (props.pageMargins) {
2949
+ style.paddingLeft = props.pageMargins.left;
2950
+ style.paddingRight = props.pageMargins.right;
2951
+ style.paddingTop = props.pageMargins.top;
2952
+ style.paddingBottom = props.pageMargins.bottom;
2953
+ style["--docx-pad-left"] = props.pageMargins.left;
2954
+ style["--docx-pad-right"] = props.pageMargins.right;
2955
+ style["--docx-pad-top"] = props.pageMargins.top;
2956
+ style["--docx-pad-bottom"] = props.pageMargins.bottom;
2957
+ }
2958
+ if (props.pageSize) {
2959
+ if (!this.options.ignoreWidth) style.width = props.pageSize.width;
2960
+ if (!this.options.ignoreHeight) style.minHeight = props.pageSize.height;
2961
+ }
2962
+ }
2963
+ return this.h({
2964
+ tagName: "section",
2965
+ className,
2966
+ style
2967
+ });
2968
+ }
2969
+ createSectionContent(props) {
2970
+ const style = {};
2971
+ if (props.columns && props.columns.numberOfColumns) {
2972
+ style.columnCount = `${props.columns.numberOfColumns}`;
2973
+ style.columnGap = props.columns.space;
2974
+ if (props.columns.separator) style.columnRule = "1px solid black";
2975
+ }
2976
+ return this.h({
2977
+ tagName: "article",
2978
+ style
2979
+ });
2980
+ }
2981
+ renderSections(document) {
2982
+ const result = [];
2983
+ this.processElement(document);
2984
+ const sections = this.splitBySection(document.children, document.props);
2985
+ const pages = this.groupByPageBreaks(sections);
2986
+ let prevProps = null;
2987
+ for (let i = 0, l = pages.length; i < l; i++) {
2988
+ this.currentFootnoteIds = [];
2989
+ let props = pages[i][0].sectProps;
2990
+ const pageElement = this.createPageElement(this.className, props, document.cssStyle);
2991
+ this.options.renderHeaders && this.renderHeaderFooter(props.headerRefs, props, result.length, prevProps != props, pageElement);
2992
+ for (const sect of pages[i]) {
2993
+ var contentElement = this.createSectionContent(sect.sectProps);
2994
+ this.renderElements(sect.elements, contentElement);
2995
+ pageElement.appendChild(contentElement);
2996
+ props = sect.sectProps;
2997
+ }
2998
+ if (this.options.renderFootnotes) {
2999
+ const notes = this.renderNotes(this.currentFootnoteIds, this.footnoteMap);
3000
+ notes && pageElement.appendChild(notes);
3001
+ }
3002
+ if (this.options.renderEndnotes && i == l - 1) {
3003
+ const notes = this.renderNotes(this.currentEndnoteIds, this.endnoteMap);
3004
+ notes && pageElement.appendChild(notes);
3005
+ }
3006
+ this.options.renderFooters && this.renderHeaderFooter(props.footerRefs, props, result.length, prevProps != props, pageElement);
3007
+ result.push(pageElement);
3008
+ prevProps = props;
3009
+ }
3010
+ this.resolvePageFields(result);
3011
+ return result;
3012
+ }
3013
+ renderHeaderFooter(refs, props, page, firstOfSection, into) {
3014
+ if (!refs) return;
3015
+ var ref = (props.titlePage && firstOfSection ? refs.find((x) => x.type == "first") : null) ?? (page % 2 == 1 ? refs.find((x) => x.type == "even") : null) ?? refs.find((x) => x.type == "default");
3016
+ var part = ref && this.document.findPartByRelId(ref.id, this.document.documentPart);
3017
+ if (part) {
3018
+ this.currentPart = part;
3019
+ if (!this.usedHederFooterParts.includes(part.path)) {
3020
+ this.processElement(part.rootElement);
3021
+ this.usedHederFooterParts.push(part.path);
3022
+ }
3023
+ const [el] = this.renderElements([part.rootElement], into);
3024
+ if (props?.pageMargins) {
3025
+ if (part.rootElement.type === DomType.Header) {
3026
+ el.style.marginTop = `calc(${props.pageMargins.header} - ${props.pageMargins.top})`;
3027
+ el.style.minHeight = `calc(${props.pageMargins.top} - ${props.pageMargins.header})`;
3028
+ } else if (part.rootElement.type === DomType.Footer) {
3029
+ el.style.marginBottom = `calc(${props.pageMargins.footer} - ${props.pageMargins.bottom})`;
3030
+ el.style.minHeight = `calc(${props.pageMargins.bottom} - ${props.pageMargins.footer})`;
3031
+ }
3032
+ }
3033
+ this.currentPart = null;
3034
+ }
3035
+ }
3036
+ isPageBreakElement(elem) {
3037
+ if (elem.type != DomType.Break) return false;
3038
+ if (elem.break == "lastRenderedPageBreak") return !this.options.ignoreLastRenderedPageBreak;
3039
+ return elem.break == "page";
3040
+ }
3041
+ isPageBreakSection(prev, next) {
3042
+ if (!prev) return false;
3043
+ if (!next) return false;
3044
+ return prev.pageSize?.orientation != next.pageSize?.orientation || prev.pageSize?.width != next.pageSize?.width || prev.pageSize?.height != next.pageSize?.height;
3045
+ }
3046
+ splitBySection(elements, defaultProps) {
3047
+ var current = {
3048
+ sectProps: null,
3049
+ elements: [],
3050
+ pageBreak: false
3051
+ };
3052
+ var result = [current];
3053
+ for (let elem of elements) {
3054
+ if (elem.type == DomType.Paragraph) {
3055
+ if (this.findStyle(elem.styleName)?.paragraphProps?.pageBreakBefore) {
3056
+ current.sectProps = sectProps;
3057
+ current.pageBreak = true;
3058
+ current = {
3059
+ sectProps: null,
3060
+ elements: [],
3061
+ pageBreak: false
3062
+ };
3063
+ result.push(current);
3064
+ }
3065
+ }
3066
+ current.elements.push(elem);
3067
+ if (elem.type == DomType.Paragraph) {
3068
+ const p = elem;
3069
+ var sectProps = p.sectionProps;
3070
+ var pBreakIndex = -1;
3071
+ var rBreakIndex = -1;
3072
+ if (this.options.breakPages && p.children) pBreakIndex = p.children.findIndex((r) => {
3073
+ rBreakIndex = r.children?.findIndex(this.isPageBreakElement.bind(this)) ?? -1;
3074
+ return rBreakIndex != -1;
3075
+ });
3076
+ if (sectProps || pBreakIndex != -1) {
3077
+ current.sectProps = sectProps;
3078
+ current.pageBreak = pBreakIndex != -1;
3079
+ current = {
3080
+ sectProps: null,
3081
+ elements: [],
3082
+ pageBreak: false
3083
+ };
3084
+ result.push(current);
3085
+ }
3086
+ if (pBreakIndex != -1) {
3087
+ let breakRun = p.children[pBreakIndex];
3088
+ let splitRun = rBreakIndex < breakRun.children.length - 1;
3089
+ if (pBreakIndex < p.children.length - 1 || splitRun) {
3090
+ var children = elem.children;
3091
+ var newParagraph = {
3092
+ ...elem,
3093
+ children: children.slice(pBreakIndex)
3094
+ };
3095
+ elem.children = children.slice(0, pBreakIndex);
3096
+ current.elements.push(newParagraph);
3097
+ if (splitRun) {
3098
+ let runChildren = breakRun.children;
3099
+ let newRun = {
3100
+ ...breakRun,
3101
+ children: runChildren.slice(0, rBreakIndex)
3102
+ };
3103
+ elem.children.push(newRun);
3104
+ breakRun.children = runChildren.slice(rBreakIndex);
3105
+ }
3106
+ }
3107
+ }
3108
+ }
3109
+ }
3110
+ let currentSectProps = null;
3111
+ for (let i = result.length - 1; i >= 0; i--) if (result[i].sectProps == null) result[i].sectProps = currentSectProps ?? defaultProps;
3112
+ else currentSectProps = result[i].sectProps;
3113
+ return result;
3114
+ }
3115
+ groupByPageBreaks(sections) {
3116
+ let current = [];
3117
+ let prev;
3118
+ const result = [current];
3119
+ for (let s of sections) {
3120
+ current.push(s);
3121
+ if (this.options.ignoreLastRenderedPageBreak || s.pageBreak || this.isPageBreakSection(prev, s.sectProps)) result.push(current = []);
3122
+ prev = s.sectProps;
3123
+ }
3124
+ return result.filter((x) => x.length > 0);
3125
+ }
3126
+ renderWrapper(children) {
3127
+ return this.h({
3128
+ tagName: "div",
3129
+ className: `${this.className}-wrapper`,
3130
+ children
3131
+ });
3132
+ }
3133
+ renderDefaultStyle() {
3134
+ var c = this.className;
3135
+ var wrapperStyle = `
3136
+ .${c}-wrapper { background: gray; padding: 30px; padding-bottom: 0px; display: flex; flex-flow: column; align-items: center; }
3137
+ .${c}-wrapper>section.${c} { background: white; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); margin-bottom: 30px; }`;
3138
+ if (this.options.hideWrapperOnPrint) wrapperStyle = `@media not print { ${wrapperStyle} }`;
3139
+ var styleText = `${wrapperStyle}
3140
+ .${c} { color: black; hyphens: auto; text-underline-position: from-font; }
3141
+ .${c} { --docx-font-ascii: serif; --docx-font-ea: serif; }
3142
+ .${c}, .${c} * { font-family: var(--docx-font-ascii), var(--docx-font-ea); }
3143
+ section.${c} { box-sizing: border-box; display: flex; flex-flow: column nowrap; position: relative; overflow: hidden; }
3144
+ section.${c}>article { margin-bottom: auto; z-index: 1; }
3145
+ section.${c}>footer { z-index: 1; }
3146
+ .${c} table { border-collapse: collapse; }
3147
+ .${c} table td, .${c} table th { vertical-align: top; }
3148
+ .${c} p { margin: 0pt; min-height: 1em; }
3149
+ .${c} span { white-space: pre-wrap; overflow-wrap: break-word; }
3150
+ .${c} a { color: inherit; text-decoration: inherit; }
3151
+ .${c} svg { fill: transparent; }
3152
+ `;
3153
+ if (this.options.renderComments) styleText += `
3154
+ .${c}-comment-ref { cursor: default; }
3155
+ .${c}-comment-popover { display: none; z-index: 1000; padding: 0.5rem; background: white; position: absolute; box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.25); width: 30ch; }
3156
+ .${c}-comment-ref:hover~.${c}-comment-popover { display: block; }
3157
+ .${c}-comment-author,.${c}-comment-date { font-size: 0.875rem; color: #888; }
3158
+ `;
3159
+ return [this.h({
3160
+ tagName: "#comment",
3161
+ children: ["docxjs library predefined styles"]
3162
+ }), this.h({
3163
+ tagName: "style",
3164
+ children: [styleText]
3165
+ })];
3166
+ }
3167
+ async renderNumbering(numberings) {
3168
+ var styleText = "";
3169
+ var resetCounters = [];
3170
+ for (var num of numberings) {
3171
+ var selector = `p.${this.numberingClass(num.id, num.level)}`;
3172
+ var listStyleType = "none";
3173
+ if (num.bullet) {
3174
+ let valiable = `--${this.className}-${num.bullet.src}`.toLowerCase();
3175
+ styleText += this.styleToString(`${selector}:before`, {
3176
+ "content": "' '",
3177
+ "display": "inline-block",
3178
+ "background": `var(${valiable})`
3179
+ }, num.bullet.style);
3180
+ try {
3181
+ const imgData = await this.document.loadNumberingImage(num.bullet.src);
3182
+ styleText += `${this.rootSelector} { ${valiable}: url(${imgData}) }`;
3183
+ } catch (e) {
3184
+ if (this.options.debug) console.warn(`Can't load numbering image with src ${num.bullet.src}`);
3185
+ }
3186
+ } else if (num.levelText) {
3187
+ let counter = this.numberingCounter(num.id, num.level);
3188
+ const counterReset = counter + " " + (num.start - 1);
3189
+ if (num.level > 0) styleText += this.styleToString(`p.${this.numberingClass(num.id, num.level - 1)}`, { "counter-set": counterReset });
3190
+ resetCounters.push(counterReset);
3191
+ styleText += this.styleToString(`${selector}:before`, {
3192
+ "content": this.levelTextToContent(num.levelText, num.suff, num.id, this.numFormatToCssValue(num.format)),
3193
+ "counter-increment": counter,
3194
+ ...num.rStyle
3195
+ });
3196
+ } else listStyleType = this.numFormatToCssValue(num.format);
3197
+ styleText += this.styleToString(selector, {
3198
+ "display": "list-item",
3199
+ "list-style-position": "inside",
3200
+ "list-style-type": listStyleType,
3201
+ ...num.pStyle
3202
+ });
3203
+ }
3204
+ if (resetCounters.length > 0) styleText += this.styleToString(this.rootSelector, { "counter-reset": resetCounters.join(" ") });
3205
+ return [this.h({
3206
+ tagName: "#comment",
3207
+ children: ["docxjs document numbering styles"]
3208
+ }), this.h({
3209
+ tagName: "style",
3210
+ children: [styleText]
3211
+ })];
3212
+ }
3213
+ renderStyles(styles) {
3214
+ var styleText = "";
3215
+ const stylesMap = this.styleMap;
3216
+ const defautStyles = keyBy(styles.filter((s) => s.isDefault), (s) => s.target);
3217
+ for (const style of styles) {
3218
+ var subStyles = style.styles;
3219
+ if (style.linked) {
3220
+ var linkedStyle = style.linked && stylesMap[style.linked];
3221
+ if (linkedStyle) subStyles = subStyles.concat(linkedStyle.styles);
3222
+ else if (this.options.debug) console.warn(`Can't find linked style ${style.linked}`);
3223
+ }
3224
+ for (const subStyle of subStyles) {
3225
+ var selector = `${style.target ?? ""}.${style.cssName}`;
3226
+ if (style.target != subStyle.target) selector += ` ${subStyle.target}`;
3227
+ if (style.id == null && subStyle.target == "span") selector = `.${this.className}`;
3228
+ if (defautStyles[style.target] == style) selector = `.${this.className} ${style.target}, ` + selector;
3229
+ styleText += this.styleToString(selector, subStyle.values);
3230
+ }
3231
+ }
3232
+ return [this.h({
3233
+ tagName: "#comment",
3234
+ children: ["docxjs document styles"]
3235
+ }), this.h({
3236
+ tagName: "style",
3237
+ children: [styleText]
3238
+ })];
3239
+ }
3240
+ renderNotes(noteIds, notesMap) {
3241
+ var notes = noteIds.map((id) => notesMap[id]).filter((x) => x);
3242
+ if (notes.length > 0) return this.h({
3243
+ tagName: "ol",
3244
+ children: this.renderElements(notes)
3245
+ });
3246
+ }
3247
+ renderElement(elem) {
3248
+ switch (elem.type) {
3249
+ case DomType.Paragraph: return this.renderParagraph(elem);
3250
+ case DomType.BookmarkStart: return this.renderBookmarkStart(elem);
3251
+ case DomType.BookmarkEnd: return null;
3252
+ case DomType.Run: return this.renderRun(elem);
3253
+ case DomType.Table: return this.renderTable(elem);
3254
+ case DomType.Row: return this.renderTableRow(elem);
3255
+ case DomType.Cell: return this.renderTableCell(elem);
3256
+ case DomType.Hyperlink: return this.renderHyperlink(elem);
3257
+ case DomType.SmartTag: return this.renderSmartTag(elem);
3258
+ case DomType.Drawing: return this.renderDrawing(elem);
3259
+ case DomType.Image: return this.renderImage(elem);
3260
+ case DomType.Text: return this.renderText(elem);
3261
+ case DomType.Text: return this.renderText(elem);
3262
+ case DomType.DeletedText: return this.renderDeletedText(elem);
3263
+ case DomType.Tab: return this.renderTab(elem);
3264
+ case DomType.Symbol: return this.renderSymbol(elem);
3265
+ case DomType.Break: return this.renderBreak(elem);
3266
+ case DomType.Footer: return this.renderContainer(elem, "footer");
3267
+ case DomType.Header: return this.renderContainer(elem, "header");
3268
+ case DomType.Footnote:
3269
+ case DomType.Endnote: return this.renderContainer(elem, "li");
3270
+ case DomType.FootnoteReference: return this.renderFootnoteReference(elem);
3271
+ case DomType.EndnoteReference: return this.renderEndnoteReference(elem);
3272
+ case DomType.NoBreakHyphen: return this.h({ tagName: "wbr" });
3273
+ case DomType.VmlPicture: return this.renderVmlPicture(elem);
3274
+ case DomType.VmlElement: return this.renderVmlElement(elem);
3275
+ case DomType.MmlMath: return this.renderContainerNS(elem, ns.mathML, "math", { xmlns: ns.mathML });
3276
+ case DomType.MmlMathParagraph: return this.renderContainer(elem, "span");
3277
+ case DomType.MmlFraction: return this.renderContainerNS(elem, ns.mathML, "mfrac");
3278
+ case DomType.MmlBase: return this.renderContainerNS(elem, ns.mathML, elem.parent.type == DomType.MmlMatrixRow ? "mtd" : "mrow");
3279
+ case DomType.MmlNumerator:
3280
+ case DomType.MmlDenominator:
3281
+ case DomType.MmlFunction:
3282
+ case DomType.MmlLimit:
3283
+ case DomType.MmlBox: return this.renderContainerNS(elem, ns.mathML, "mrow");
3284
+ case DomType.MmlGroupChar: return this.renderMmlGroupChar(elem);
3285
+ case DomType.MmlLimitLower: return this.renderContainerNS(elem, ns.mathML, "munder");
3286
+ case DomType.MmlMatrix: return this.renderContainerNS(elem, ns.mathML, "mtable");
3287
+ case DomType.MmlMatrixRow: return this.renderContainerNS(elem, ns.mathML, "mtr");
3288
+ case DomType.MmlRadical: return this.renderMmlRadical(elem);
3289
+ case DomType.MmlSuperscript: return this.renderContainerNS(elem, ns.mathML, "msup");
3290
+ case DomType.MmlSubscript: return this.renderContainerNS(elem, ns.mathML, "msub");
3291
+ case DomType.MmlDegree:
3292
+ case DomType.MmlSuperArgument:
3293
+ case DomType.MmlSubArgument: return this.renderContainerNS(elem, ns.mathML, "mn");
3294
+ case DomType.MmlFunctionName: return this.renderContainerNS(elem, ns.mathML, "ms");
3295
+ case DomType.MmlDelimiter: return this.renderMmlDelimiter(elem);
3296
+ case DomType.MmlRun: return this.renderMmlRun(elem);
3297
+ case DomType.MmlNary: return this.renderMmlNary(elem);
3298
+ case DomType.MmlPreSubSuper: return this.renderMmlPreSubSuper(elem);
3299
+ case DomType.MmlBar: return this.renderMmlBar(elem);
3300
+ case DomType.MmlEquationArray: return this.renderMllList(elem);
3301
+ case DomType.Inserted: return this.renderInserted(elem);
3302
+ case DomType.Deleted: return this.renderDeleted(elem);
3303
+ case DomType.CommentRangeStart: return this.renderCommentRangeStart(elem);
3304
+ case DomType.CommentRangeEnd: return this.renderCommentRangeEnd(elem);
3305
+ case DomType.CommentReference: return this.renderCommentReference(elem);
3306
+ case DomType.AltChunk: return this.renderAltChunk(elem);
3307
+ }
3308
+ return null;
3309
+ }
3310
+ renderElements(elems, into) {
3311
+ if (elems == null) return null;
3312
+ var result = elems.flatMap((e) => this.renderElement(e)).filter((e) => e != null);
3313
+ if (into) result.forEach((c) => into.appendChild(isString(c) ? document.createTextNode(c) : c));
3314
+ return result;
3315
+ }
3316
+ renderContainer(elem, tagName, props) {
3317
+ return this.h({
3318
+ tagName,
3319
+ children: this.renderElements(elem.children),
3320
+ ...props
3321
+ });
3322
+ }
3323
+ renderContainerNS(elem, ns, tagName, props) {
3324
+ return this.h({
3325
+ ns,
3326
+ tagName,
3327
+ children: this.renderElements(elem.children),
3328
+ ...props
3329
+ });
3330
+ }
3331
+ /**
3332
+ * Marks the cached-result runs of PAGE / NUMPAGES complex fields with a
3333
+ * marker class (`docx-field-page` / `docx-field-numpages`), so the actual
3334
+ * numbers can be substituted once page layout is final (see the end of
3335
+ * renderSections and pagination.ts). Field runs themselves are skipped
3336
+ * by renderRun, leaving the cached value as a plain run between the
3337
+ * separate and end markers.
3338
+ */
3339
+ markPageFieldRuns(elem) {
3340
+ let instruction = null;
3341
+ let inResult = false;
3342
+ for (const run of elem.children ?? []) {
3343
+ if (run.type != DomType.Run) continue;
3344
+ for (const sub of run.children ?? []) if (sub.type == DomType.ComplexField) {
3345
+ const charType = sub.charType;
3346
+ if (charType == "begin") {
3347
+ instruction = null;
3348
+ inResult = false;
3349
+ } else if (charType == "separate") inResult = true;
3350
+ else if (charType == "end") {
3351
+ instruction = null;
3352
+ inResult = false;
3353
+ }
3354
+ } else if (sub.type == DomType.Instruction) instruction = sub.text?.trim().split(/\s/)[0]?.toUpperCase();
3355
+ if (inResult && (instruction == "PAGE" || instruction == "NUMPAGES") && !run.fieldRun) run.className = cx(run.className, `${this.className}-field-${instruction.toLowerCase()}`);
3356
+ }
3357
+ }
3358
+ /**
3359
+ * Substitutes final page numbers into PAGE / NUMPAGES field markers
3360
+ * across the given page sections. Numbering is continuous from 1 —
3361
+ * per-section restarts (w:pgNumType) are not modeled yet.
3362
+ */
3363
+ resolvePageFields(pages) {
3364
+ const total = `${pages.length}`;
3365
+ pages.forEach((page, i) => {
3366
+ for (const el of Array.from(page.querySelectorAll(`.${this.className}-field-page`))) el.textContent = `${i + 1}`;
3367
+ for (const el of Array.from(page.querySelectorAll(`.${this.className}-field-numpages`))) el.textContent = total;
3368
+ });
3369
+ }
3370
+ renderParagraph(elem) {
3371
+ this.markPageFieldRuns(elem);
3372
+ var result = this.toHTML(elem, ns.html, "p");
3373
+ const style = this.findStyle(elem.styleName);
3374
+ elem.tabs ?? (elem.tabs = style?.paragraphProps?.tabs);
3375
+ const numbering = elem.numbering ?? style?.paragraphProps?.numbering;
3376
+ if (numbering) result.classList.add(this.numberingClass(numbering.id, numbering.level));
3377
+ if (this.legacyCompat && this.textAlignOf(elem) === "justify" && / {2,}| {2,}| /.test(result.textContent)) result.style.setProperty("text-align-last", "justify");
3378
+ return result;
3379
+ }
3380
+ /** Effective text-align of a paragraph: direct formatting, then its
3381
+ * style, then the default paragraph style, then docDefaults. */
3382
+ textAlignOf(elem) {
3383
+ if (elem.cssStyle?.["text-align"]) return elem.cssStyle["text-align"];
3384
+ const from = (s) => s?.styles?.find((x) => x.target == "p")?.values?.["text-align"];
3385
+ return from(this.findStyle(elem.styleName)) ?? from(this.defaultParagraphStyle) ?? from(this.docDefaultsStyle) ?? null;
3386
+ }
3387
+ renderHyperlink(elem) {
3388
+ const res = this.toH(elem, ns.html, "a");
3389
+ res.href = "";
3390
+ if (elem.id) res.href = this.document.documentPart.rels.find((it) => it.id == elem.id && it.targetMode === "External")?.target ?? res.href;
3391
+ if (elem.anchor) res.href += `#${elem.anchor}`;
3392
+ return this.h(res);
3393
+ }
3394
+ renderSmartTag(elem) {
3395
+ return this.renderContainer(elem, "span");
3396
+ }
3397
+ renderCommentRangeStart(commentStart) {
3398
+ if (!this.options.renderComments) return null;
3399
+ const rng = new Range();
3400
+ this.commentHighlight?.add(rng);
3401
+ const result = this.h({
3402
+ tagName: "#comment",
3403
+ children: [`start of comment #${commentStart.id}`]
3404
+ });
3405
+ this.later(() => rng.setStart(result, 0));
3406
+ this.commentMap[commentStart.id] = rng;
3407
+ return result;
3408
+ }
3409
+ renderCommentRangeEnd(commentEnd) {
3410
+ if (!this.options.renderComments) return null;
3411
+ const rng = this.commentMap[commentEnd.id];
3412
+ const result = this.h({
3413
+ tagName: "#comment",
3414
+ children: [`end of comment #${commentEnd.id}`]
3415
+ });
3416
+ this.later(() => rng?.setEnd(result, 0));
3417
+ return result;
3418
+ }
3419
+ renderCommentReference(commentRef) {
3420
+ if (!this.options.renderComments) return null;
3421
+ var comment = this.document.commentsPart?.commentMap[commentRef.id];
3422
+ if (!comment) return null;
3423
+ const commentRefEl = this.h({
3424
+ tagName: "span",
3425
+ className: `${this.className}-comment-ref`,
3426
+ children: ["💬"]
3427
+ });
3428
+ const commentsContainerEl = this.h({
3429
+ tagName: "div",
3430
+ className: `${this.className}-comment-popover`,
3431
+ children: [
3432
+ this.h({
3433
+ tagName: "div",
3434
+ className: `${this.className}-comment-author`,
3435
+ children: [comment.author]
3436
+ }),
3437
+ this.h({
3438
+ tagName: "div",
3439
+ className: `${this.className}-comment-date`,
3440
+ children: [new Date(comment.date).toLocaleString()]
3441
+ }),
3442
+ ...this.renderElements(comment.children)
3443
+ ]
3444
+ });
3445
+ return this.h({
3446
+ tagName: "#fragment",
3447
+ children: [
3448
+ this.h({
3449
+ tagName: "#comment",
3450
+ children: [`comment #${comment.id} by ${comment.author} on ${comment.date}`]
3451
+ }),
3452
+ commentRefEl,
3453
+ commentsContainerEl
3454
+ ]
3455
+ });
3456
+ }
3457
+ renderAltChunk(elem) {
3458
+ if (!this.options.renderAltChunks) return null;
3459
+ var result = this.h({ tagName: "iframe" });
3460
+ this.tasks.push(this.document.loadAltChunk(elem.id, this.currentPart).then((x) => {
3461
+ result.srcdoc = x;
3462
+ }));
3463
+ return result;
3464
+ }
3465
+ renderDrawing(elem) {
3466
+ var result = this.toHTML(elem, ns.html, "div");
3467
+ result.style.display = "inline-block";
3468
+ result.style.position = "relative";
3469
+ result.style.textIndent = "0px";
3470
+ return result;
3471
+ }
3472
+ renderImage(elem) {
3473
+ let result = this.toHTML(elem, ns.html, "img", []);
3474
+ let transform = elem.cssStyle?.transform;
3475
+ if (elem.srcRect && elem.srcRect.some((x) => x != 0)) {
3476
+ var [left, top, right, bottom] = elem.srcRect;
3477
+ transform = `scale(${1 / (1 - left - right)}, ${1 / (1 - top - bottom)})`;
3478
+ result.style["clip-path"] = `rect(${(100 * top).toFixed(2)}% ${(100 * (1 - right)).toFixed(2)}% ${(100 * (1 - bottom)).toFixed(2)}% ${(100 * left).toFixed(2)}%)`;
3479
+ }
3480
+ if (elem.rotation) transform = `rotate(${elem.rotation}deg) ${transform ?? ""}`;
3481
+ result.style.transform = transform?.trim();
3482
+ if (this.document) this.tasks.push(this.document.loadDocumentImage(elem.src, this.currentPart).then((x) => {
3483
+ result.src = x;
3484
+ }));
3485
+ return result;
3486
+ }
3487
+ renderText(elem) {
3488
+ return this.h(elem.text);
3489
+ }
3490
+ renderDeletedText(elem) {
3491
+ return this.options.renderChanges ? this.renderText(elem) : null;
3492
+ }
3493
+ renderBreak(elem) {
3494
+ return elem.break == "textWrapping" ? this.h({ tagName: "br" }) : null;
3495
+ }
3496
+ renderInserted(elem) {
3497
+ if (this.options.renderChanges) return this.renderChange(elem, "ins");
3498
+ return this.renderElements(elem.children);
3499
+ }
3500
+ renderDeleted(elem) {
3501
+ if (this.options.renderChanges) return this.renderChange(elem, "del");
3502
+ return null;
3503
+ }
3504
+ renderChange(elem, tag) {
3505
+ return this.renderContainer(elem, tag, { dateTime: elem.date });
3506
+ }
3507
+ renderSymbol(elem) {
3508
+ return this.h({
3509
+ tagName: "span",
3510
+ children: [String.fromCharCode(elem.char)],
3511
+ style: { fontFamily: elem.font }
3512
+ });
3513
+ }
3514
+ renderFootnoteReference(elem) {
3515
+ this.currentFootnoteIds.push(elem.id);
3516
+ return this.h({
3517
+ tagName: "sup",
3518
+ children: [`${this.currentFootnoteIds.length}`]
3519
+ });
3520
+ }
3521
+ renderEndnoteReference(elem) {
3522
+ this.currentEndnoteIds.push(elem.id);
3523
+ return this.h({
3524
+ tagName: "sup",
3525
+ children: [`${this.currentEndnoteIds.length}`]
3526
+ });
3527
+ }
3528
+ renderTab(elem) {
3529
+ var tabSpan = this.h({
3530
+ tagName: "span",
3531
+ children: [" "]
3532
+ });
3533
+ if (this.options.experimental) {
3534
+ tabSpan.className = this.tabStopClass();
3535
+ var stops = findParent(elem, DomType.Paragraph)?.tabs;
3536
+ this.currentTabs.push({
3537
+ stops,
3538
+ span: tabSpan
3539
+ });
3540
+ }
3541
+ return tabSpan;
3542
+ }
3543
+ renderBookmarkStart(elem) {
3544
+ return this.h({
3545
+ tagName: "span",
3546
+ id: elem.name
3547
+ });
3548
+ }
3549
+ renderRun(elem) {
3550
+ if (elem.fieldRun) return null;
3551
+ let children = this.renderElements(elem.children);
3552
+ if (elem.verticalAlign) children = [this.h({
3553
+ tagName: elem.verticalAlign,
3554
+ children: this.renderElements(elem.children)
3555
+ })];
3556
+ const result = this.toHTML(elem, ns.html, "span", children);
3557
+ if (elem.id) result.id = elem.id;
3558
+ return result;
3559
+ }
3560
+ renderTable(elem) {
3561
+ this.tableCellPositions.push(this.currentCellPosition);
3562
+ this.tableVerticalMerges.push(this.currentVerticalMerge);
3563
+ this.currentVerticalMerge = {};
3564
+ this.currentCellPosition = {
3565
+ col: 0,
3566
+ row: 0
3567
+ };
3568
+ const children = [];
3569
+ if (elem.columns) children.push(this.renderTableColumns(elem.columns));
3570
+ children.push(...this.renderElements(elem.children));
3571
+ this.currentVerticalMerge = this.tableVerticalMerges.pop();
3572
+ this.currentCellPosition = this.tableCellPositions.pop();
3573
+ return this.toHTML(elem, ns.html, "table", children);
3574
+ }
3575
+ renderTableColumns(columns) {
3576
+ const children = columns.map((x) => this.h({
3577
+ tagName: "col",
3578
+ style: { width: x.width }
3579
+ }));
3580
+ return this.h({
3581
+ tagName: "colgroup",
3582
+ children
3583
+ });
3584
+ }
3585
+ renderTableRow(elem) {
3586
+ this.currentCellPosition.col = 0;
3587
+ const children = [];
3588
+ if (elem.gridBefore) children.push(this.renderTableCellPlaceholder(elem.gridBefore));
3589
+ children.push(...this.renderElements(elem.children));
3590
+ if (elem.gridAfter) children.push(this.renderTableCellPlaceholder(elem.gridAfter));
3591
+ this.currentCellPosition.row++;
3592
+ return this.toHTML(elem, ns.html, "tr", children);
3593
+ }
3594
+ renderTableCellPlaceholder(colSpan) {
3595
+ return this.h({
3596
+ tagName: "td",
3597
+ colSpan,
3598
+ style: { border: "none" }
3599
+ });
3600
+ }
3601
+ renderTableCell(elem) {
3602
+ let result = this.toHTML(elem, ns.html, "td");
3603
+ const key = this.currentCellPosition.col;
3604
+ if (elem.verticalMerge) {
3605
+ if (elem.verticalMerge == "restart") {
3606
+ this.currentVerticalMerge[key] = result;
3607
+ result.rowSpan = 1;
3608
+ } else if (this.currentVerticalMerge[key]) {
3609
+ this.currentVerticalMerge[key].rowSpan += 1;
3610
+ result.style.display = "none";
3611
+ }
3612
+ } else this.currentVerticalMerge[key] = null;
3613
+ if (elem.span) result.colSpan = elem.span;
3614
+ this.currentCellPosition.col += result.colSpan;
3615
+ return result;
3616
+ }
3617
+ renderVmlPicture(elem) {
3618
+ return this.renderContainer(elem, "div");
3619
+ }
3620
+ renderVmlElement(elem) {
3621
+ var container = this.h({
3622
+ ns: ns.svg,
3623
+ tagName: "svg",
3624
+ style: elem.cssStyleText
3625
+ });
3626
+ const result = this.renderVmlChildElement(elem);
3627
+ if (elem.imageHref?.id) this.tasks.push(this.document?.loadDocumentImage(elem.imageHref.id, this.currentPart).then((x) => result.setAttribute("href", x)));
3628
+ container.appendChild(result);
3629
+ requestAnimationFrame(() => {
3630
+ const bb = container.firstElementChild.getBBox();
3631
+ container.setAttribute("width", `${Math.ceil(bb.x + bb.width)}`);
3632
+ container.setAttribute("height", `${Math.ceil(bb.y + bb.height)}`);
3633
+ });
3634
+ return container;
3635
+ }
3636
+ renderVmlChildElement(elem) {
3637
+ const result = this.createSvgElement(elem.tagName);
3638
+ Object.entries(elem.attrs).forEach(([k, v]) => result.setAttribute(k, v));
3639
+ for (let child of elem.children) if (child.type == DomType.VmlElement) result.appendChild(this.renderVmlChildElement(child));
3640
+ else result.appendChild(...asArray(this.renderElement(child)));
3641
+ return result;
3642
+ }
3643
+ renderMmlRadical(elem) {
3644
+ const base = elem.children.find((el) => el.type == DomType.MmlBase);
3645
+ if (elem.props?.hideDegree) return this.createMathMLElement("msqrt", null, this.renderElements([base]));
3646
+ const degree = elem.children.find((el) => el.type == DomType.MmlDegree);
3647
+ return this.createMathMLElement("mroot", null, this.renderElements([base, degree]));
3648
+ }
3649
+ renderMmlDelimiter(elem) {
3650
+ const children = [];
3651
+ children.push(this.createMathMLElement("mo", null, [elem.props.beginChar ?? "("]));
3652
+ children.push(...this.renderElements(elem.children));
3653
+ children.push(this.createMathMLElement("mo", null, [elem.props.endChar ?? ")"]));
3654
+ return this.createMathMLElement("mrow", null, children);
3655
+ }
3656
+ renderMmlNary(elem) {
3657
+ const children = [];
3658
+ const grouped = keyBy(elem.children, (x) => x.type);
3659
+ const sup = grouped[DomType.MmlSuperArgument];
3660
+ const sub = grouped[DomType.MmlSubArgument];
3661
+ const supElem = sup ? this.createMathMLElement("mo", null, asArray(this.renderElement(sup))) : null;
3662
+ const subElem = sub ? this.createMathMLElement("mo", null, asArray(this.renderElement(sub))) : null;
3663
+ const charElem = this.createMathMLElement("mo", null, [elem.props?.char ?? "∫"]);
3664
+ if (supElem || subElem) children.push(this.createMathMLElement("munderover", null, [
3665
+ charElem,
3666
+ subElem,
3667
+ supElem
3668
+ ]));
3669
+ else if (supElem) children.push(this.createMathMLElement("mover", null, [charElem, supElem]));
3670
+ else if (subElem) children.push(this.createMathMLElement("munder", null, [charElem, subElem]));
3671
+ else children.push(charElem);
3672
+ children.push(...this.renderElements(grouped[DomType.MmlBase].children));
3673
+ return this.createMathMLElement("mrow", null, children);
3674
+ }
3675
+ renderMmlPreSubSuper(elem) {
3676
+ const children = [];
3677
+ const grouped = keyBy(elem.children, (x) => x.type);
3678
+ const sup = grouped[DomType.MmlSuperArgument];
3679
+ const sub = grouped[DomType.MmlSubArgument];
3680
+ const supElem = sup ? this.createMathMLElement("mo", null, asArray(this.renderElement(sup))) : null;
3681
+ const subElem = sub ? this.createMathMLElement("mo", null, asArray(this.renderElement(sub))) : null;
3682
+ const stubElem = this.createMathMLElement("mo", null);
3683
+ children.push(this.createMathMLElement("msubsup", null, [
3684
+ stubElem,
3685
+ subElem,
3686
+ supElem
3687
+ ]));
3688
+ children.push(...this.renderElements(grouped[DomType.MmlBase].children));
3689
+ return this.createMathMLElement("mrow", null, children);
3690
+ }
3691
+ renderMmlGroupChar(elem) {
3692
+ const tagName = elem.props.verticalJustification === "bot" ? "mover" : "munder";
3693
+ const result = this.renderContainerNS(elem, ns.mathML, tagName);
3694
+ if (elem.props.char) result.appendChild(this.createMathMLElement("mo", null, [elem.props.char]));
3695
+ return result;
3696
+ }
3697
+ renderMmlBar(elem) {
3698
+ const style = {};
3699
+ switch (elem.props.position) {
3700
+ case "top":
3701
+ style.textDecoration = "overline";
3702
+ break;
3703
+ case "bottom": style.textDecoration = "underline";
3704
+ }
3705
+ return this.renderContainerNS(elem, ns.mathML, "mrow", { style });
3706
+ }
3707
+ renderMmlRun(elem) {
3708
+ return this.toHTML(elem, ns.mathML, "ms");
3709
+ }
3710
+ renderMllList(elem) {
3711
+ const children = this.renderElements(elem.children).map((x) => this.createMathMLElement("mtr", null, [this.createMathMLElement("mtd", null, [x])]));
3712
+ return this.toHTML(elem, ns.mathML, "mtable", children);
3713
+ }
3714
+ toH(elem, ns, tagName, children = null) {
3715
+ const { "$lang": lang, ...style } = elem.cssStyle ?? {};
3716
+ return {
3717
+ ns,
3718
+ tagName,
3719
+ className: cx(elem.className, elem.styleName && this.processStyleName(elem.styleName)),
3720
+ lang,
3721
+ style,
3722
+ children: children ?? this.renderElements(elem.children)
3723
+ };
3724
+ }
3725
+ toHTML(elem, ns, tagName, children = null) {
3726
+ return this.h(this.toH(elem, ns, tagName, children));
3727
+ }
3728
+ findStyle(styleName) {
3729
+ return styleName && this.styleMap?.[styleName];
3730
+ }
3731
+ numberingClass(id, lvl) {
3732
+ return `${this.className}-num-${id}-${lvl}`;
3733
+ }
3734
+ tabStopClass() {
3735
+ return `${this.className}-tab-stop`;
3736
+ }
3737
+ styleToString(selectors, values, cssText = null) {
3738
+ let result = `${selectors} {\r\n`;
3739
+ for (const key in values) {
3740
+ if (key.startsWith("$")) continue;
3741
+ result += ` ${key}: ${values[key]};\r\n`;
3742
+ }
3743
+ if (cssText) result += cssText;
3744
+ return result + "}\r\n";
3745
+ }
3746
+ numberingCounter(id, lvl) {
3747
+ return `${this.className}-num-${id}-${lvl}`;
3748
+ }
3749
+ levelTextToContent(text, suff, id, numformat) {
3750
+ return `"${text.replace(/%\d*/g, (s) => {
3751
+ let lvl = parseInt(s.substring(1), 10) - 1;
3752
+ return `"counter(${this.numberingCounter(id, lvl)}, ${numformat})"`;
3753
+ })}${{
3754
+ "tab": "\\9",
3755
+ "space": "\\a0"
3756
+ }[suff] ?? ""}"`;
3757
+ }
3758
+ numFormatToCssValue(format) {
3759
+ return {
3760
+ none: "none",
3761
+ bullet: "disc",
3762
+ decimal: "decimal",
3763
+ lowerLetter: "lower-alpha",
3764
+ upperLetter: "upper-alpha",
3765
+ lowerRoman: "lower-roman",
3766
+ upperRoman: "upper-roman",
3767
+ decimalZero: "decimal-leading-zero",
3768
+ aiueo: "katakana",
3769
+ aiueoFullWidth: "katakana",
3770
+ chineseCounting: "simp-chinese-informal",
3771
+ chineseCountingThousand: "simp-chinese-informal",
3772
+ chineseLegalSimplified: "simp-chinese-formal",
3773
+ chosung: "hangul-consonant",
3774
+ ideographDigital: "cjk-ideographic",
3775
+ ideographTraditional: "cjk-heavenly-stem",
3776
+ ideographLegalTraditional: "trad-chinese-formal",
3777
+ ideographZodiac: "cjk-earthly-branch",
3778
+ iroha: "katakana-iroha",
3779
+ irohaFullWidth: "katakana-iroha",
3780
+ japaneseCounting: "japanese-informal",
3781
+ japaneseDigitalTenThousand: "cjk-decimal",
3782
+ japaneseLegal: "japanese-formal",
3783
+ thaiNumbers: "thai",
3784
+ koreanCounting: "korean-hangul-formal",
3785
+ koreanDigital: "korean-hangul-formal",
3786
+ koreanDigital2: "korean-hanja-informal",
3787
+ hebrew1: "hebrew",
3788
+ hebrew2: "hebrew",
3789
+ hindiNumbers: "devanagari",
3790
+ ganada: "hangul",
3791
+ taiwaneseCounting: "cjk-ideographic",
3792
+ taiwaneseCountingThousand: "cjk-ideographic",
3793
+ taiwaneseDigital: "cjk-decimal"
3794
+ }[format] ?? format;
3795
+ }
3796
+ refreshTabStops() {
3797
+ if (!this.options.experimental) return;
3798
+ setTimeout(() => {
3799
+ const pixelToPoint = computePixelToPoint();
3800
+ for (let tab of this.currentTabs) updateTabStop(tab.span, tab.stops, this.defaultTabSize, pixelToPoint);
3801
+ }, 500);
3802
+ }
3803
+ createElementNS(ns, tagName, props, children) {
3804
+ return this.h({
3805
+ ns,
3806
+ tagName,
3807
+ children,
3808
+ ...props
3809
+ });
3810
+ }
3811
+ createElement(tagName, props, children) {
3812
+ return this.createElementNS(ns.html, tagName, props, children);
3813
+ }
3814
+ createMathMLElement(tagName, props, children) {
3815
+ return this.createElementNS(ns.mathML, tagName, props, children);
3816
+ }
3817
+ createSvgElement(tagName, props, children) {
3818
+ return this.createElementNS(ns.svg, tagName, props, children);
3819
+ }
3820
+ later(func) {
3821
+ this.postRenderTasks.push(func);
3822
+ }
3823
+ };
3824
+ function findParent(elem, type) {
3825
+ var parent = elem.parent;
3826
+ while (parent != null && parent.type != type) parent = parent.parent;
3827
+ return parent;
3828
+ }
3829
+ //#endregion
3830
+ //#region src/pagination.ts
3831
+ var FIT_EPSILON = 1;
3832
+ var MAX_PAGES_PER_SECTION = 1e3;
3833
+ function paginateWrapper(container, className) {
3834
+ const sections = Array.from(container.querySelectorAll(`section.${className}`));
3835
+ let pageCount = 0;
3836
+ for (const section of sections) pageCount += paginateSection(section, className);
3837
+ if (pageCount > 0) {
3838
+ const style = document.createElement("style");
3839
+ style.textContent = `.${className} .${className}-continuation { text-indent: 0 !important; }.${className} .${className}-continuation::before { content: none !important; }`;
3840
+ container.prepend(style);
3841
+ const pages = container.querySelectorAll(`section.${className}`);
3842
+ const total = `${pages.length}`;
3843
+ pages.forEach((page, i) => {
3844
+ for (const el of Array.from(page.querySelectorAll(`.${className}-field-page`))) el.textContent = `${i + 1}`;
3845
+ for (const el of Array.from(page.querySelectorAll(`.${className}-field-numpages`))) el.textContent = total;
3846
+ });
3847
+ }
3848
+ return pageCount;
3849
+ }
3850
+ function paginateSection(section, className) {
3851
+ const article = section.querySelector(":scope > article");
3852
+ if (!article) return 0;
3853
+ const sectionStyle = getComputedStyle(section);
3854
+ const pageHeight = parseFloat(sectionStyle.minHeight);
3855
+ if (!pageHeight || Number.isNaN(pageHeight)) return 0;
3856
+ const columns = getComputedStyle(article).columnCount;
3857
+ if (columns !== "auto" && columns !== "1") return 0;
3858
+ const contentLimit = pageHeight - parseFloat(sectionStyle.paddingTop) - parseFloat(sectionStyle.paddingBottom);
3859
+ if (!(contentLimit > 0) || article.scrollHeight <= contentLimit + FIT_EPSILON) return 0;
3860
+ const header = section.querySelector(":scope > header");
3861
+ const footer = section.querySelector(":scope > footer");
3862
+ const notes = Array.from(section.querySelectorAll(":scope > ol"));
3863
+ const pages = [section];
3864
+ let currentArticle = article;
3865
+ let lastPage = section;
3866
+ function newPage() {
3867
+ const shell = section.cloneNode(false);
3868
+ if (header) shell.appendChild(header.cloneNode(true));
3869
+ const pageArticle = article.cloneNode(false);
3870
+ shell.appendChild(pageArticle);
3871
+ if (footer) shell.appendChild(footer.cloneNode(true));
3872
+ lastPage.after(shell);
3873
+ lastPage = shell;
3874
+ pages.push(shell);
3875
+ currentArticle = pageArticle;
3876
+ }
3877
+ const fits = () => currentArticle.scrollHeight <= contentLimit + FIT_EPSILON;
3878
+ const bottomLimit = () => currentArticle.getBoundingClientRect().top + contentLimit;
3879
+ const blocks = Array.from(article.children);
3880
+ for (const b of blocks) b.remove();
3881
+ for (let i = 0; i < blocks.length && pages.length < MAX_PAGES_PER_SECTION; i++) {
3882
+ const block = blocks[i];
3883
+ currentArticle.appendChild(block);
3884
+ if (fits()) continue;
3885
+ const tail = splitBlock(block, bottomLimit(), className);
3886
+ if (tail === "allfit") continue;
3887
+ if (tail) {
3888
+ blocks.splice(i + 1, 0, tail);
3889
+ newPage();
3890
+ continue;
3891
+ }
3892
+ if (tail) {
3893
+ blocks.splice(i + 1, 0, tail);
3894
+ newPage();
3895
+ continue;
3896
+ }
3897
+ block.remove();
3898
+ if (currentArticle.childElementCount === 0) {
3899
+ currentArticle.appendChild(block);
3900
+ continue;
3901
+ }
3902
+ newPage();
3903
+ i--;
3904
+ }
3905
+ if (notes.length > 0 && pages.length > 1) {
3906
+ const lastFooter = lastPage.querySelector(":scope > footer");
3907
+ for (const ol of notes) lastPage.insertBefore(ol, lastFooter);
3908
+ }
3909
+ if (pages.length <= 1) return 0;
3910
+ return pages.length;
3911
+ }
3912
+ /**
3913
+ * Splits `block` (already appended to a page and known to overflow) so its
3914
+ * head fits above `bottomLimit` (viewport coordinate). Returns the detached
3915
+ * tail fragment, "allfit" when the block's content doesn't actually
3916
+ * overflow (keep it on the current page), or null when the block can't
3917
+ * usefully be split here.
3918
+ */
3919
+ function splitBlock(block, bottomLimit, className) {
3920
+ if (block.tagName === "TABLE") return splitTable(block, bottomLimit);
3921
+ const pos = findTextSplitOffset(block, bottomLimit);
3922
+ if (pos === "allfit") return "allfit";
3923
+ if (pos === null) return null;
3924
+ const tail = splitAt(block, pos.node, pos.offset);
3925
+ tail.classList.add(`${className}-continuation`);
3926
+ return tail;
3927
+ }
3928
+ function splitTable(table, bottomLimit) {
3929
+ const bodyRows = [];
3930
+ for (const tbody of Array.from(table.tBodies)) bodyRows.push(...Array.from(tbody.rows));
3931
+ if (bodyRows.length < 2) return null;
3932
+ const splitIndex = bodyRows.findIndex((r) => r.getBoundingClientRect().bottom > bottomLimit);
3933
+ if (splitIndex <= 0) return null;
3934
+ const tail = table.cloneNode(false);
3935
+ const colgroup = table.querySelector(":scope > colgroup");
3936
+ if (colgroup) tail.appendChild(colgroup.cloneNode(true));
3937
+ if (table.tHead) tail.appendChild(table.tHead.cloneNode(true));
3938
+ for (let i = splitIndex; i < bodyRows.length; i++) tail.appendChild(bodyRows[i]);
3939
+ return tail;
3940
+ }
3941
+ /**
3942
+ * Finds the latest text position inside `el` that still renders above
3943
+ * `bottomLimit`, by walking text nodes in order and binary-searching each
3944
+ * one with Range rects. Returns:
3945
+ * - { node, offset } — split here;
3946
+ * - "allfit" — every text node fits; the overflow comes from the block's
3947
+ * own box (min-height overshoot), not its content, so it should stay;
3948
+ * - null — even the first character overflows (or there is no text).
3949
+ */
3950
+ function findTextSplitOffset(el, bottomLimit) {
3951
+ const doc = el.ownerDocument;
3952
+ const walker = doc.createTreeWalker(el, NodeFilter.SHOW_TEXT);
3953
+ const range = doc.createRange();
3954
+ let hasFittingContent = false;
3955
+ let sawText = false;
3956
+ for (let node = walker.nextNode(); node; node = walker.nextNode()) {
3957
+ if (node.length === 0) continue;
3958
+ sawText = true;
3959
+ let lo = 0, hi = node.length, fit = 0;
3960
+ while (lo <= hi) {
3961
+ const mid = lo + hi >> 1;
3962
+ range.setStart(node, 0);
3963
+ range.setEnd(node, mid);
3964
+ const rects = range.getClientRects();
3965
+ const last = rects[rects.length - 1];
3966
+ if (last && last.bottom <= bottomLimit) {
3967
+ fit = mid;
3968
+ lo = mid + 1;
3969
+ } else hi = mid - 1;
3970
+ }
3971
+ if (fit === 0) return hasFittingContent ? {
3972
+ node,
3973
+ offset: 0
3974
+ } : null;
3975
+ if (fit < node.length) {
3976
+ let back = fit;
3977
+ const floor = Math.max(0, fit - 30);
3978
+ while (back > floor && !/\s/.test(node.data[back - 1])) back--;
3979
+ return {
3980
+ node,
3981
+ offset: back > floor ? back : fit
3982
+ };
3983
+ }
3984
+ hasFittingContent = true;
3985
+ }
3986
+ return sawText ? "allfit" : null;
3987
+ }
3988
+ /**
3989
+ * Splits `el` at (textNode, offset): `el` keeps everything before the point,
3990
+ * and the returned element (a shallow clone of `el` with cloned inline
3991
+ * ancestors) gets everything from the point on.
3992
+ */
3993
+ function splitAt(el, textNode, offset) {
3994
+ const tail = el.cloneNode(false);
3995
+ moveTail(textNode.splitText(offset), el, tail);
3996
+ return tail;
3997
+ }
3998
+ /** Moves the split point's following content into a parallel clone
3999
+ * hierarchy under `tailRoot`: `node` and its following siblings go into a
4000
+ * clone of their parent, and each ancestor up to `root` contributes a clone
4001
+ * plus its following siblings. The ORIGINAL ancestors stay in the head —
4002
+ * moving them would rip the head's split-span text out (and reverse the
4003
+ * order of the two text halves in the tail). */
4004
+ function moveTail(node, root, tailRoot) {
4005
+ let child = node;
4006
+ let container = tailRoot;
4007
+ while (child.parentNode && child.parentNode !== root) {
4008
+ const parent = child.parentNode;
4009
+ const parentClone = parent.cloneNode(false);
4010
+ container.appendChild(parentClone);
4011
+ parentClone.appendChild(child);
4012
+ while (child.nextSibling) parentClone.appendChild(child.nextSibling);
4013
+ child = parent;
4014
+ container = parentClone;
4015
+ }
4016
+ if (child === node) tailRoot.appendChild(child);
4017
+ while (child.nextSibling) tailRoot.appendChild(child.nextSibling);
4018
+ }
4019
+ //#endregion
4020
+ //#region src/docx-preview.ts
4021
+ var defaultOptions = {
4022
+ ignoreHeight: false,
4023
+ ignoreWidth: false,
4024
+ ignoreFonts: false,
4025
+ breakPages: true,
4026
+ paginate: false,
4027
+ debug: false,
4028
+ experimental: false,
4029
+ className: "docx",
4030
+ inWrapper: true,
4031
+ hideWrapperOnPrint: false,
4032
+ trimXmlDeclaration: true,
4033
+ ignoreLastRenderedPageBreak: true,
4034
+ renderHeaders: true,
4035
+ renderFooters: true,
4036
+ renderFootnotes: true,
4037
+ renderEndnotes: true,
4038
+ useBase64URL: false,
4039
+ renderChanges: false,
4040
+ renderComments: false,
4041
+ renderAltChunks: true,
4042
+ h
4043
+ };
4044
+ function parseAsync(data, userOptions) {
4045
+ const ops = {
4046
+ ...defaultOptions,
4047
+ ...userOptions
4048
+ };
4049
+ return WordDocument.load(data, new DocumentParser(ops), ops);
4050
+ }
4051
+ async function renderDocument(document, userOptions) {
4052
+ const ops = {
4053
+ ...defaultOptions,
4054
+ ...userOptions
4055
+ };
4056
+ return await new HtmlRenderer().render(document, ops);
4057
+ }
4058
+ function renderFontFaces(fonts) {
4059
+ const css = fonts.map((f) => {
4060
+ const props = [`font-family: "${f.name.replace(/["\\\r\n]/g, "")}"`, `src: ${f.src}`];
4061
+ if (f.weight != null) props.push(`font-weight: ${f.weight}`);
4062
+ if (f.style != null) props.push(`font-style: ${f.style}`);
4063
+ return `@font-face { ${props.join("; ")}; }`;
4064
+ }).join("\n");
4065
+ const el = document.createElement("style");
4066
+ el.textContent = css;
4067
+ return el;
4068
+ }
4069
+ async function renderAsync(data, bodyContainer, styleContainer, userOptions) {
4070
+ const doc = await parseAsync(data, userOptions);
4071
+ const nodes = await renderDocument(doc, userOptions);
4072
+ const ops = {
4073
+ ...defaultOptions,
4074
+ ...userOptions
4075
+ };
4076
+ styleContainer ?? (styleContainer = bodyContainer);
4077
+ styleContainer.innerHTML = "";
4078
+ bodyContainer.innerHTML = "";
4079
+ if (ops.fonts?.length) nodes.unshift(renderFontFaces(ops.fonts));
4080
+ for (let n of nodes) (n.nodeName === "STYLE" ? styleContainer : bodyContainer).appendChild(n);
4081
+ const fontSet = typeof document !== "undefined" ? document.fonts : null;
4082
+ if (ops.fonts?.length && fontSet?.load) try {
4083
+ await Promise.all(ops.fonts.map((f) => fontSet.load(`${f.style ?? "normal"} ${f.weight ?? "normal"} 12px "${f.name.replace(/["\\\r\n]/g, "")}"`)));
4084
+ } catch {}
4085
+ if (ops.paginate) {
4086
+ if (fontSet?.ready) try {
4087
+ await fontSet.ready;
4088
+ } catch {}
4089
+ paginateWrapper(bodyContainer, ops.className);
4090
+ }
4091
+ return doc;
4092
+ }
4093
+ //#endregion
4094
+ export { defaultOptions, parseAsync, renderAsync, renderDocument };
4095
+
4096
+ //# sourceMappingURL=docx-preview.mjs.map