@shadow-garden/bapbong-docx 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +304 -77
- package/dist/index.js +304 -77
- package/dist/lib/docx.d.ts.map +1 -1
- package/dist/lib/export.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -351,11 +351,16 @@ function propsToMarks(p, ctx) {
|
|
|
351
351
|
if (p.italic) marks.push(ctx.schema.marks["em"].create());
|
|
352
352
|
if (p.underline) marks.push(ctx.schema.marks["underline"].create());
|
|
353
353
|
if (p.strike) marks.push(ctx.schema.marks["strike"].create());
|
|
354
|
-
if (p.color)
|
|
355
|
-
|
|
356
|
-
if (p.
|
|
357
|
-
|
|
358
|
-
if (p.
|
|
354
|
+
if (p.color)
|
|
355
|
+
marks.push(ctx.schema.marks["textColor"].create({ color: p.color }));
|
|
356
|
+
if (p.sizePt !== void 0)
|
|
357
|
+
marks.push(ctx.schema.marks["fontSize"].create({ size: p.sizePt }));
|
|
358
|
+
if (p.fontFamily)
|
|
359
|
+
marks.push(ctx.schema.marks["fontFamily"].create({ family: p.fontFamily }));
|
|
360
|
+
if (p.highlight)
|
|
361
|
+
marks.push(ctx.schema.marks["highlight"].create({ color: p.highlight }));
|
|
362
|
+
if (p.vertAlign)
|
|
363
|
+
marks.push(ctx.schema.marks["vertAlign"].create({ value: p.vertAlign }));
|
|
359
364
|
return marks;
|
|
360
365
|
}
|
|
361
366
|
var SYMBOL_MAP = {
|
|
@@ -375,7 +380,9 @@ function symbolChar(code) {
|
|
|
375
380
|
return Number.isNaN(n) ? "" : String.fromCodePoint(n >= 61440 ? n - 61440 + 32 : n);
|
|
376
381
|
}
|
|
377
382
|
function hasPageBreak(run) {
|
|
378
|
-
return run.children.some(
|
|
383
|
+
return run.children.some(
|
|
384
|
+
(n) => n.name === "w:br" && attrOf(n, "w:type") === "page"
|
|
385
|
+
);
|
|
379
386
|
}
|
|
380
387
|
function effectiveChildren(nodes) {
|
|
381
388
|
const out = [];
|
|
@@ -424,8 +431,12 @@ function runInlineNodes(run, marks, ctx) {
|
|
|
424
431
|
if (id && ctx.notes.bodies[kind].has(id)) {
|
|
425
432
|
flush();
|
|
426
433
|
const num = ctx.notes.ref(kind, id);
|
|
427
|
-
const refMarks = [
|
|
428
|
-
|
|
434
|
+
const refMarks = [
|
|
435
|
+
...marks,
|
|
436
|
+
ctx.schema.marks["vertAlign"].create({ value: "super" })
|
|
437
|
+
];
|
|
438
|
+
if (kind === "footnote")
|
|
439
|
+
refMarks.push(ctx.schema.marks["footnote"].create({ num }));
|
|
429
440
|
out.push(ctx.schema.text(String(num), refMarks));
|
|
430
441
|
}
|
|
431
442
|
} else if (node.name === "w:br" && attrOf(node, "w:type") !== "page") {
|
|
@@ -449,9 +460,11 @@ function parseAnchorFloat(drawing) {
|
|
|
449
460
|
const posH = child(anchor, "wp:positionH");
|
|
450
461
|
if (posH) {
|
|
451
462
|
const align = child(posH, "wp:align")?.text.trim();
|
|
452
|
-
if (align === "left" || align === "right" || align === "center")
|
|
463
|
+
if (align === "left" || align === "right" || align === "center")
|
|
464
|
+
float["hAlign"] = align;
|
|
453
465
|
const off = emuToPxZero(child(posH, "wp:posOffset")?.text);
|
|
454
|
-
if (off !== void 0 && float["hAlign"] === void 0)
|
|
466
|
+
if (off !== void 0 && float["hAlign"] === void 0)
|
|
467
|
+
float["hOffset"] = off;
|
|
455
468
|
const rel = attrOf(posH, "relativeFrom");
|
|
456
469
|
float["hRel"] = rel === "page" ? "page" : "margin";
|
|
457
470
|
}
|
|
@@ -628,7 +641,9 @@ function parseShape(run, ctx) {
|
|
|
628
641
|
function parseTextbox(wsp, ctx) {
|
|
629
642
|
const content = child(child(wsp, "wps:txbx"), "w:txbxContent");
|
|
630
643
|
if (!content) return null;
|
|
631
|
-
const paragraphs = children(content, "w:p").map(
|
|
644
|
+
const paragraphs = children(content, "w:p").map(
|
|
645
|
+
(p) => parseParagraph(p, ctx).toJSON()
|
|
646
|
+
);
|
|
632
647
|
if (paragraphs.length === 0) return null;
|
|
633
648
|
const bodyPr = child(wsp, "wps:bodyPr");
|
|
634
649
|
const ins = (name) => emuToPxZero(attrOf(bodyPr, name));
|
|
@@ -723,7 +738,10 @@ function flattenOmml(node) {
|
|
|
723
738
|
function parseParagraph(p, ctx) {
|
|
724
739
|
const pPr = child(p, "w:pPr");
|
|
725
740
|
const pStyleId = attrOf(child(pPr, "w:pStyle"), "w:val");
|
|
726
|
-
const paraBase = mergeRunProps(
|
|
741
|
+
const paraBase = mergeRunProps(
|
|
742
|
+
ctx.styles.docDefaults,
|
|
743
|
+
ctx.styles.resolveStyle(pStyleId)
|
|
744
|
+
);
|
|
727
745
|
const pPrChain = [
|
|
728
746
|
ctx.styles.docDefaultsPPr,
|
|
729
747
|
...ctx.styles.resolveStylePPr(pStyleId),
|
|
@@ -756,9 +774,12 @@ function parseParagraph(p, ctx) {
|
|
|
756
774
|
} else if (fldType === "end") {
|
|
757
775
|
const kind = fieldKind(field.instr);
|
|
758
776
|
if (kind) {
|
|
759
|
-
inline.push(
|
|
777
|
+
inline.push(
|
|
778
|
+
pageFieldNode(kind, field.resultRuns[0], paraBase, ctx)
|
|
779
|
+
);
|
|
760
780
|
} else {
|
|
761
|
-
for (const r of field.resultRuns)
|
|
781
|
+
for (const r of field.resultRuns)
|
|
782
|
+
inline.push(...runToInline(r, paraBase, ctx, null));
|
|
762
783
|
}
|
|
763
784
|
field = null;
|
|
764
785
|
} else if (field.phase === "instr") {
|
|
@@ -775,7 +796,8 @@ function parseParagraph(p, ctx) {
|
|
|
775
796
|
if (kind) {
|
|
776
797
|
inline.push(pageFieldNode(kind, resultRuns[0], paraBase, ctx));
|
|
777
798
|
} else {
|
|
778
|
-
for (const r of resultRuns)
|
|
799
|
+
for (const r of resultRuns)
|
|
800
|
+
inline.push(...runToInline(r, paraBase, ctx, null));
|
|
779
801
|
}
|
|
780
802
|
} else if (node.name === "w:hyperlink") {
|
|
781
803
|
const rel = attrOf(node, "r:id") ? ctx.rels.get(attrOf(node, "r:id")) : void 0;
|
|
@@ -788,7 +810,9 @@ function parseParagraph(p, ctx) {
|
|
|
788
810
|
const text = flattenOmml(node);
|
|
789
811
|
if (text.length > 0) {
|
|
790
812
|
const first = findDescendant(node, "m:r");
|
|
791
|
-
inline.push(
|
|
813
|
+
inline.push(
|
|
814
|
+
ctx.schema.text(text, runMarks(first, paraBase, ctx, null))
|
|
815
|
+
);
|
|
792
816
|
}
|
|
793
817
|
} else if (node.name === "w:commentRangeStart") {
|
|
794
818
|
const id = Number(attrOf(node, "w:id"));
|
|
@@ -805,6 +829,9 @@ function parseParagraph(p, ctx) {
|
|
|
805
829
|
if (list) attrs.list = list;
|
|
806
830
|
if (align) attrs.align = align;
|
|
807
831
|
if (heading) attrs.heading = heading;
|
|
832
|
+
else if (pStyleId && /^(title|subtitle)$/i.test(pStyleId)) {
|
|
833
|
+
attrs.styleId = pStyleId.toLowerCase() === "title" ? "Title" : "Subtitle";
|
|
834
|
+
}
|
|
808
835
|
if (indent) attrs.indent = indent;
|
|
809
836
|
if (spacing) attrs.spacing = spacing;
|
|
810
837
|
if (tabs) attrs.tabs = tabs;
|
|
@@ -917,7 +944,9 @@ function parseList(pPr) {
|
|
|
917
944
|
return { numId, level: Number.isNaN(ilvl) ? 0 : ilvl };
|
|
918
945
|
}
|
|
919
946
|
function emptyCell(ctx) {
|
|
920
|
-
return ctx.schema.nodes["table_cell"].create(null, [
|
|
947
|
+
return ctx.schema.nodes["table_cell"].create(null, [
|
|
948
|
+
ctx.schema.nodes["paragraph"].create()
|
|
949
|
+
]);
|
|
921
950
|
}
|
|
922
951
|
function parseCellMargins(tbl) {
|
|
923
952
|
const mar = child(child(tbl, "w:tblPr"), "w:tblCellMar");
|
|
@@ -970,7 +999,14 @@ function parseBordersEl(bordersEl, sides) {
|
|
|
970
999
|
}
|
|
971
1000
|
return Object.keys(out).length > 0 ? out : null;
|
|
972
1001
|
}
|
|
973
|
-
var TABLE_SIDES = [
|
|
1002
|
+
var TABLE_SIDES = [
|
|
1003
|
+
"top",
|
|
1004
|
+
"bottom",
|
|
1005
|
+
"left",
|
|
1006
|
+
"right",
|
|
1007
|
+
"insideH",
|
|
1008
|
+
"insideV"
|
|
1009
|
+
];
|
|
974
1010
|
var CELL_SIDES = ["top", "bottom", "left", "right"];
|
|
975
1011
|
function parseTableBorders(tbl, ctx) {
|
|
976
1012
|
const tblPr = child(tbl, "w:tblPr");
|
|
@@ -997,8 +1033,18 @@ function parseTable(tbl, ctx) {
|
|
|
997
1033
|
const vAlign = vAlignVal === "center" || vAlignVal === "bottom" ? vAlignVal : null;
|
|
998
1034
|
const borders2 = parseBordersEl(child(tcPr, "w:tcBorders"), CELL_SIDES);
|
|
999
1035
|
const content = parseBlocks(tc, ctx);
|
|
1000
|
-
if (content.length === 0)
|
|
1001
|
-
|
|
1036
|
+
if (content.length === 0)
|
|
1037
|
+
content.push(ctx.schema.nodes["paragraph"].create());
|
|
1038
|
+
cells.push({
|
|
1039
|
+
startCol: col,
|
|
1040
|
+
colspan,
|
|
1041
|
+
vMerge,
|
|
1042
|
+
colwidth: widths.length ? widths : null,
|
|
1043
|
+
background,
|
|
1044
|
+
vAlign,
|
|
1045
|
+
borders: borders2,
|
|
1046
|
+
content
|
|
1047
|
+
});
|
|
1002
1048
|
col += colspan;
|
|
1003
1049
|
}
|
|
1004
1050
|
return cells;
|
|
@@ -1009,12 +1055,17 @@ function parseTable(tbl, ctx) {
|
|
|
1009
1055
|
const header = hdr ? attrOf(hdr, "w:val") !== "false" && attrOf(hdr, "w:val") !== "0" : false;
|
|
1010
1056
|
const trH = child(trPr, "w:trHeight");
|
|
1011
1057
|
const hv = attrOf(trH, "w:val");
|
|
1012
|
-
const height = hv !== void 0 ? {
|
|
1058
|
+
const height = hv !== void 0 ? {
|
|
1059
|
+
value: twipsToPx(Number(hv)),
|
|
1060
|
+
exact: attrOf(trH, "w:hRule") === "exact"
|
|
1061
|
+
} : null;
|
|
1013
1062
|
const cs = child(trPr, "w:cantSplit");
|
|
1014
1063
|
const cantSplit = cs ? attrOf(cs, "w:val") !== "false" && attrOf(cs, "w:val") !== "0" : false;
|
|
1015
1064
|
return { header, height, cantSplit };
|
|
1016
1065
|
});
|
|
1017
|
-
const colIndex = logicalRows.map(
|
|
1066
|
+
const colIndex = logicalRows.map(
|
|
1067
|
+
(cells) => new Map(cells.map((c) => [c.startCol, c]))
|
|
1068
|
+
);
|
|
1018
1069
|
const rows = logicalRows.map((cells, r) => {
|
|
1019
1070
|
const emitted = [];
|
|
1020
1071
|
for (const cell of cells) {
|
|
@@ -1055,7 +1106,8 @@ function parseTable(tbl, ctx) {
|
|
|
1055
1106
|
const attrs = {};
|
|
1056
1107
|
if (cellPadding) attrs["cellPadding"] = cellPadding;
|
|
1057
1108
|
if (borders) attrs["borders"] = borders;
|
|
1058
|
-
if (jc === "center" || jc === "right" || jc === "end")
|
|
1109
|
+
if (jc === "center" || jc === "right" || jc === "end")
|
|
1110
|
+
attrs["align"] = jc === "end" ? "right" : jc;
|
|
1059
1111
|
return ctx.schema.nodes["table"].create(
|
|
1060
1112
|
Object.keys(attrs).length > 0 ? attrs : null,
|
|
1061
1113
|
rows.length > 0 ? rows : [ctx.schema.nodes["table_row"].create(null, [emptyCell(ctx)])]
|
|
@@ -1121,18 +1173,27 @@ async function readPartRels(zip, partPath) {
|
|
|
1121
1173
|
return xml ? parseXml(xml) : void 0;
|
|
1122
1174
|
}
|
|
1123
1175
|
async function buildNotesRegistry(zip) {
|
|
1124
|
-
const bodies = {
|
|
1176
|
+
const bodies = {
|
|
1177
|
+
footnote: /* @__PURE__ */ new Map(),
|
|
1178
|
+
endnote: /* @__PURE__ */ new Map()
|
|
1179
|
+
};
|
|
1125
1180
|
const load = async (path, root, tag, into) => {
|
|
1126
1181
|
const xml = await readPart(zip, path);
|
|
1127
1182
|
if (!xml) return;
|
|
1128
1183
|
for (const note of children(child(parseXml(xml), root), tag)) {
|
|
1129
1184
|
const id = attrOf(note, "w:id");
|
|
1130
1185
|
const type = attrOf(note, "w:type");
|
|
1131
|
-
if (id === void 0 || Number(id) < 1 || type && type !== "normal")
|
|
1186
|
+
if (id === void 0 || Number(id) < 1 || type && type !== "normal")
|
|
1187
|
+
continue;
|
|
1132
1188
|
into.set(id, note);
|
|
1133
1189
|
}
|
|
1134
1190
|
};
|
|
1135
|
-
await load(
|
|
1191
|
+
await load(
|
|
1192
|
+
"word/footnotes.xml",
|
|
1193
|
+
"w:footnotes",
|
|
1194
|
+
"w:footnote",
|
|
1195
|
+
bodies.footnote
|
|
1196
|
+
);
|
|
1136
1197
|
await load("word/endnotes.xml", "w:endnotes", "w:endnote", bodies.endnote);
|
|
1137
1198
|
const reg = {
|
|
1138
1199
|
bodies,
|
|
@@ -1167,7 +1228,10 @@ async function buildCommentsRegistry(zip) {
|
|
|
1167
1228
|
const ext = /* @__PURE__ */ new Map();
|
|
1168
1229
|
const extXml = await readPart(zip, "word/commentsExtended.xml");
|
|
1169
1230
|
if (extXml) {
|
|
1170
|
-
for (const ex of children(
|
|
1231
|
+
for (const ex of children(
|
|
1232
|
+
child(parseXml(extXml), "w15:commentsEx"),
|
|
1233
|
+
"w15:commentEx"
|
|
1234
|
+
)) {
|
|
1171
1235
|
const paraId2 = attrOf(ex, "w15:paraId");
|
|
1172
1236
|
if (!paraId2) continue;
|
|
1173
1237
|
const done = attrOf(ex, "w15:done");
|
|
@@ -1187,14 +1251,24 @@ function buildCommentsList(ctx) {
|
|
|
1187
1251
|
const out = [];
|
|
1188
1252
|
for (const id of ctx.comments.used) {
|
|
1189
1253
|
const def = ctx.comments.defs.get(id);
|
|
1190
|
-
if (def)
|
|
1254
|
+
if (def)
|
|
1255
|
+
out.push({
|
|
1256
|
+
id,
|
|
1257
|
+
author: def.author,
|
|
1258
|
+
date: def.date,
|
|
1259
|
+
text: collectText(def.body).trim()
|
|
1260
|
+
});
|
|
1191
1261
|
}
|
|
1192
1262
|
return out;
|
|
1193
1263
|
}
|
|
1194
1264
|
function commentBodyJSON(comment) {
|
|
1195
1265
|
const paras = children(comment, "w:p").map((p) => {
|
|
1196
1266
|
const text = collectText(p);
|
|
1197
|
-
return commentSchema.node(
|
|
1267
|
+
return commentSchema.node(
|
|
1268
|
+
"paragraph",
|
|
1269
|
+
null,
|
|
1270
|
+
text ? [commentSchema.text(text)] : []
|
|
1271
|
+
);
|
|
1198
1272
|
});
|
|
1199
1273
|
return commentSchema.node("doc", null, paras.length ? paras : [commentSchema.node("paragraph")]).toJSON();
|
|
1200
1274
|
}
|
|
@@ -1214,12 +1288,18 @@ function buildCommentNodes(ctx) {
|
|
|
1214
1288
|
if (usedSet.has(cur)) return true;
|
|
1215
1289
|
return false;
|
|
1216
1290
|
};
|
|
1217
|
-
const ids = [
|
|
1291
|
+
const ids = [
|
|
1292
|
+
...used.filter((id) => defs.has(id)),
|
|
1293
|
+
...[...defs.keys()].filter((id) => !usedSet.has(id))
|
|
1294
|
+
];
|
|
1218
1295
|
const out = [];
|
|
1219
1296
|
for (const id of ids) {
|
|
1220
1297
|
const def = defs.get(id);
|
|
1221
1298
|
if (!def || !referenced(id)) continue;
|
|
1222
|
-
const user = {
|
|
1299
|
+
const user = {
|
|
1300
|
+
id: def.author || "unknown",
|
|
1301
|
+
name: def.author || "Unknown"
|
|
1302
|
+
};
|
|
1223
1303
|
out.push({
|
|
1224
1304
|
id,
|
|
1225
1305
|
parentId: parentOf.get(id) ?? null,
|
|
@@ -1233,7 +1313,9 @@ function buildCommentNodes(ctx) {
|
|
|
1233
1313
|
}
|
|
1234
1314
|
function noteBlocks(note, num, ctx) {
|
|
1235
1315
|
const blocks = parseBlocks(note, ctx);
|
|
1236
|
-
const marker = ctx.schema.text(`${num}. `, [
|
|
1316
|
+
const marker = ctx.schema.text(`${num}. `, [
|
|
1317
|
+
ctx.schema.marks["vertAlign"].create({ value: "super" })
|
|
1318
|
+
]);
|
|
1237
1319
|
const first = blocks[0];
|
|
1238
1320
|
if (first && first.type.name === "paragraph") {
|
|
1239
1321
|
const kids = [marker];
|
|
@@ -1283,7 +1365,10 @@ async function extractMedia(zip) {
|
|
|
1283
1365
|
if (!path.startsWith("word/media/")) continue;
|
|
1284
1366
|
const entry = zip.file(path);
|
|
1285
1367
|
if (!entry || entry.dir) continue;
|
|
1286
|
-
media.set(
|
|
1368
|
+
media.set(
|
|
1369
|
+
path,
|
|
1370
|
+
`data:${mimeOf(path)};base64,${await entry.async("base64")}`
|
|
1371
|
+
);
|
|
1287
1372
|
}
|
|
1288
1373
|
return media;
|
|
1289
1374
|
}
|
|
@@ -1293,11 +1378,16 @@ async function importDocx(input, opts) {
|
|
|
1293
1378
|
if (rawDocumentXml === void 0) {
|
|
1294
1379
|
throw new Error("bapbong-docx: word/document.xml not found in archive");
|
|
1295
1380
|
}
|
|
1296
|
-
const
|
|
1381
|
+
const stylesXml2 = await readPart(zip, "word/styles.xml");
|
|
1297
1382
|
const numberingXml = await readPart(zip, "word/numbering.xml");
|
|
1298
1383
|
const themeXml = await readPart(zip, "word/theme/theme1.xml");
|
|
1299
|
-
const resolveTheme = buildThemeResolver(
|
|
1300
|
-
|
|
1384
|
+
const resolveTheme = buildThemeResolver(
|
|
1385
|
+
themeXml ? parseXml(themeXml) : void 0
|
|
1386
|
+
);
|
|
1387
|
+
const styles = buildStyleRegistry(
|
|
1388
|
+
stylesXml2 ? parseXml(stylesXml2) : void 0,
|
|
1389
|
+
resolveTheme
|
|
1390
|
+
);
|
|
1301
1391
|
const numberingRoot = numberingXml ? parseXml(numberingXml) : void 0;
|
|
1302
1392
|
const media = await extractMedia(zip);
|
|
1303
1393
|
const notes = await buildNotesRegistry(zip);
|
|
@@ -1346,7 +1436,11 @@ async function importDocx(input, opts) {
|
|
|
1346
1436
|
if (!xml) continue;
|
|
1347
1437
|
const partCtx = makeCtx(buildRels(await readPartRels(zip, partPath)));
|
|
1348
1438
|
const el = child(parseXml(xml), root);
|
|
1349
|
-
store[type] = storyDoc(
|
|
1439
|
+
store[type] = storyDoc(
|
|
1440
|
+
partCtx,
|
|
1441
|
+
el ? parseBlocks(el, partCtx) : [],
|
|
1442
|
+
ctx.numbering.defs
|
|
1443
|
+
);
|
|
1350
1444
|
}
|
|
1351
1445
|
};
|
|
1352
1446
|
await collect("w:headerReference", headers, "w:hdr");
|
|
@@ -1423,7 +1517,10 @@ var pxToEmu = (px) => Math.round(px * 9525);
|
|
|
1423
1517
|
var commentIdsOf = (node) => node.marks.find((m) => m.type.name === "comment")?.attrs["ids"] ?? [];
|
|
1424
1518
|
var isInlineLeaf = (node) => node.isText || node.type.name === "image" || node.type.name === "hard_break";
|
|
1425
1519
|
function esc(s) {
|
|
1426
|
-
return s.replace(
|
|
1520
|
+
return s.replace(
|
|
1521
|
+
/[&<>"]/g,
|
|
1522
|
+
(c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]
|
|
1523
|
+
);
|
|
1427
1524
|
}
|
|
1428
1525
|
var MIME_EXT = {
|
|
1429
1526
|
"image/png": "png",
|
|
@@ -1446,9 +1543,15 @@ function runProps(marks) {
|
|
|
1446
1543
|
const size = byName.get("fontSize")?.attrs["size"];
|
|
1447
1544
|
if (size != null) out.push(`<w:sz w:val="${Math.round(size * 2)}"/>`);
|
|
1448
1545
|
const hl = byName.get("highlight")?.attrs["color"];
|
|
1449
|
-
if (hl)
|
|
1546
|
+
if (hl)
|
|
1547
|
+
out.push(
|
|
1548
|
+
`<w:shd w:val="clear" w:color="auto" w:fill="${hl.replace(/^#/, "")}"/>`
|
|
1549
|
+
);
|
|
1450
1550
|
const va = byName.get("vertAlign")?.attrs["value"];
|
|
1451
|
-
if (va)
|
|
1551
|
+
if (va)
|
|
1552
|
+
out.push(
|
|
1553
|
+
`<w:vertAlign w:val="${va === "sub" ? "subscript" : "superscript"}"/>`
|
|
1554
|
+
);
|
|
1452
1555
|
return out.length ? `<w:rPr>${out.join("")}</w:rPr>` : "";
|
|
1453
1556
|
}
|
|
1454
1557
|
function anchorXml(float, cx, cy, n, graphic) {
|
|
@@ -1490,7 +1593,9 @@ function imageXml(node, ctx) {
|
|
|
1490
1593
|
const n = ctx.nextId++;
|
|
1491
1594
|
const rid = `rId${n}`;
|
|
1492
1595
|
ctx.media.push({ path: `word/media/image${n}.${ext}`, base64: m[2] });
|
|
1493
|
-
ctx.rels.push(
|
|
1596
|
+
ctx.rels.push(
|
|
1597
|
+
`<Relationship Id="${rid}" Type="${R_NS}/image" Target="media/image${n}.${ext}"/>`
|
|
1598
|
+
);
|
|
1494
1599
|
const cx = pxToEmu(node.attrs["width"] ?? 96);
|
|
1495
1600
|
const cy = pxToEmu(node.attrs["height"] ?? 96);
|
|
1496
1601
|
return `<w:r><w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0"><wp:extent cx="${cx}" cy="${cy}"/><wp:docPr id="${n}" name="Picture ${n}"/><a:graphic><a:graphicData uri="${PIC_NS}"><pic:pic><pic:nvPicPr><pic:cNvPr id="${n}" name="image${n}.${ext}"/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip r:embed="${rid}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm${rotAttr(node)}><a:off x="0" y="0"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing></w:r>`;
|
|
@@ -1500,7 +1605,8 @@ function inlineXml(node, ctx) {
|
|
|
1500
1605
|
if (node.type.name === "image") return imageXml(node, ctx);
|
|
1501
1606
|
if (node.isText) {
|
|
1502
1607
|
const fn = node.marks.find((m) => m.type.name === "footnote");
|
|
1503
|
-
if (fn)
|
|
1608
|
+
if (fn)
|
|
1609
|
+
return `<w:r>${runProps(node.marks)}<w:footnoteReference w:id="${fn.attrs["num"]}"/></w:r>`;
|
|
1504
1610
|
return `<w:r>${runProps(node.marks)}<w:t xml:space="preserve">${esc(node.text ?? "")}</w:t></w:r>`;
|
|
1505
1611
|
}
|
|
1506
1612
|
return "";
|
|
@@ -1510,9 +1616,12 @@ function inlineUnit(node, ctx) {
|
|
|
1510
1616
|
const inner = inlineXml(node, ctx);
|
|
1511
1617
|
const href = linkHref(node);
|
|
1512
1618
|
if (!href || !inner) return inner;
|
|
1513
|
-
if (href.startsWith("#"))
|
|
1619
|
+
if (href.startsWith("#"))
|
|
1620
|
+
return `<w:hyperlink w:anchor="${esc(href.slice(1))}">${inner}</w:hyperlink>`;
|
|
1514
1621
|
const n = ctx.nextId++;
|
|
1515
|
-
ctx.rels.push(
|
|
1622
|
+
ctx.rels.push(
|
|
1623
|
+
`<Relationship Id="rId${n}" Type="${R_NS}/hyperlink" Target="${esc(href)}" TargetMode="External"/>`
|
|
1624
|
+
);
|
|
1516
1625
|
return `<w:hyperlink r:id="rId${n}">${inner}</w:hyperlink>`;
|
|
1517
1626
|
}
|
|
1518
1627
|
function inlineContent(node, ctx) {
|
|
@@ -1546,10 +1655,16 @@ function paraProps(node) {
|
|
|
1546
1655
|
const a = node.attrs;
|
|
1547
1656
|
const out = [];
|
|
1548
1657
|
const heading = a["heading"];
|
|
1658
|
+
const styleId = a["styleId"];
|
|
1549
1659
|
if (heading) out.push(`<w:pStyle w:val="Heading${heading}"/>`);
|
|
1660
|
+
else if (styleId === "Title" || styleId === "Subtitle")
|
|
1661
|
+
out.push(`<w:pStyle w:val="${styleId}"/>`);
|
|
1550
1662
|
if (a["pageBreakBefore"]) out.push("<w:pageBreakBefore/>");
|
|
1551
1663
|
const list = a["list"];
|
|
1552
|
-
if (list)
|
|
1664
|
+
if (list)
|
|
1665
|
+
out.push(
|
|
1666
|
+
`<w:numPr><w:ilvl w:val="${list.level}"/><w:numId w:val="${esc(list.numId)}"/></w:numPr>`
|
|
1667
|
+
);
|
|
1553
1668
|
const sp = a["spacing"];
|
|
1554
1669
|
if (sp) {
|
|
1555
1670
|
const at = [];
|
|
@@ -1557,7 +1672,9 @@ function paraProps(node) {
|
|
|
1557
1672
|
if (sp.after != null) at.push(`w:after="${pxToTwips(sp.after)}"`);
|
|
1558
1673
|
if (sp.line != null) {
|
|
1559
1674
|
const auto = sp.lineRule === "auto" || sp.lineRule == null;
|
|
1560
|
-
at.push(
|
|
1675
|
+
at.push(
|
|
1676
|
+
`w:line="${auto ? Math.round(sp.line * 240) : pxToTwips(sp.line)}"`
|
|
1677
|
+
);
|
|
1561
1678
|
at.push(`w:lineRule="${sp.lineRule ?? "auto"}"`);
|
|
1562
1679
|
}
|
|
1563
1680
|
if (at.length) out.push(`<w:spacing ${at.join(" ")}/>`);
|
|
@@ -1568,11 +1685,13 @@ function paraProps(node) {
|
|
|
1568
1685
|
if (ind.left != null) at.push(`w:left="${pxToTwips(ind.left)}"`);
|
|
1569
1686
|
if (ind.right != null) at.push(`w:right="${pxToTwips(ind.right)}"`);
|
|
1570
1687
|
if (ind.hanging != null) at.push(`w:hanging="${pxToTwips(ind.hanging)}"`);
|
|
1571
|
-
else if (ind.firstLine != null)
|
|
1688
|
+
else if (ind.firstLine != null)
|
|
1689
|
+
at.push(`w:firstLine="${pxToTwips(ind.firstLine)}"`);
|
|
1572
1690
|
if (at.length) out.push(`<w:ind ${at.join(" ")}/>`);
|
|
1573
1691
|
}
|
|
1574
1692
|
const align = a["align"];
|
|
1575
|
-
if (align)
|
|
1693
|
+
if (align)
|
|
1694
|
+
out.push(`<w:jc w:val="${align === "justify" ? "both" : align}"/>`);
|
|
1576
1695
|
return out.join("");
|
|
1577
1696
|
}
|
|
1578
1697
|
function paragraphXml(node, ctx, sectPr = "") {
|
|
@@ -1580,7 +1699,14 @@ function paragraphXml(node, ctx, sectPr = "") {
|
|
|
1580
1699
|
const pPr = props ? `<w:pPr>${props}</w:pPr>` : "";
|
|
1581
1700
|
return `<w:p>${pPr}${inlineContent(node, ctx)}</w:p>`;
|
|
1582
1701
|
}
|
|
1583
|
-
var TABLE_SIDES2 = [
|
|
1702
|
+
var TABLE_SIDES2 = [
|
|
1703
|
+
"top",
|
|
1704
|
+
"bottom",
|
|
1705
|
+
"left",
|
|
1706
|
+
"right",
|
|
1707
|
+
"insideH",
|
|
1708
|
+
"insideV"
|
|
1709
|
+
];
|
|
1584
1710
|
var CELL_SIDES2 = ["top", "bottom", "left", "right"];
|
|
1585
1711
|
var BORDER_STYLE_OUT = {
|
|
1586
1712
|
solid: "single",
|
|
@@ -1602,12 +1728,19 @@ function cellXml(cell, ctx) {
|
|
|
1602
1728
|
const a = cell.attrs;
|
|
1603
1729
|
const pr = [];
|
|
1604
1730
|
const colwidth = a["colwidth"];
|
|
1605
|
-
if (colwidth?.length)
|
|
1606
|
-
|
|
1731
|
+
if (colwidth?.length)
|
|
1732
|
+
pr.push(
|
|
1733
|
+
`<w:tcW w:w="${pxToTwips(colwidth.reduce((x, y) => x + y, 0))}" w:type="dxa"/>`
|
|
1734
|
+
);
|
|
1735
|
+
if (a["colspan"] > 1)
|
|
1736
|
+
pr.push(`<w:gridSpan w:val="${a["colspan"]}"/>`);
|
|
1607
1737
|
const borders = a["borders"];
|
|
1608
1738
|
if (borders) pr.push(bordersXml("w:tcBorders", borders, CELL_SIDES2));
|
|
1609
1739
|
const bg = a["background"];
|
|
1610
|
-
if (bg)
|
|
1740
|
+
if (bg)
|
|
1741
|
+
pr.push(
|
|
1742
|
+
`<w:shd w:val="clear" w:color="auto" w:fill="${bg.replace(/^#/, "")}"/>`
|
|
1743
|
+
);
|
|
1611
1744
|
const vAlign = a["vAlign"];
|
|
1612
1745
|
if (vAlign) pr.push(`<w:vAlign w:val="${vAlign}"/>`);
|
|
1613
1746
|
let content = "";
|
|
@@ -1620,7 +1753,10 @@ function rowXml(row, ctx) {
|
|
|
1620
1753
|
if (row.attrs["header"]) pr.push("<w:tblHeader/>");
|
|
1621
1754
|
if (row.attrs["cantSplit"]) pr.push("<w:cantSplit/>");
|
|
1622
1755
|
const h = row.attrs["height"];
|
|
1623
|
-
if (h)
|
|
1756
|
+
if (h)
|
|
1757
|
+
pr.push(
|
|
1758
|
+
`<w:trHeight w:val="${pxToTwips(h.value)}" w:hRule="${h.exact ? "exact" : "atLeast"}"/>`
|
|
1759
|
+
);
|
|
1624
1760
|
const trPr = pr.length ? `<w:trPr>${pr.join("")}</w:trPr>` : "";
|
|
1625
1761
|
let cells = "";
|
|
1626
1762
|
row.forEach((c) => cells += cellXml(c, ctx));
|
|
@@ -1639,7 +1775,9 @@ function tableXml(node, ctx) {
|
|
|
1639
1775
|
}
|
|
1640
1776
|
const firstRow = node.firstChild;
|
|
1641
1777
|
const grid = [];
|
|
1642
|
-
firstRow?.forEach(
|
|
1778
|
+
firstRow?.forEach(
|
|
1779
|
+
(c) => c.attrs["colwidth"]?.forEach((w) => grid.push(w))
|
|
1780
|
+
);
|
|
1643
1781
|
const gridXml = grid.length ? `<w:tblGrid>${grid.map((w) => `<w:gridCol w:w="${pxToTwips(w)}"/>`).join("")}</w:tblGrid>` : "";
|
|
1644
1782
|
let rows = "";
|
|
1645
1783
|
node.forEach((r) => rows += rowXml(r, ctx));
|
|
@@ -1674,10 +1812,14 @@ function commentBodyXml(body, firstParaId) {
|
|
|
1674
1812
|
doc.forEach((p, _o, i) => {
|
|
1675
1813
|
let runs = "";
|
|
1676
1814
|
p.forEach((inline) => {
|
|
1677
|
-
if (inline.isText)
|
|
1678
|
-
|
|
1815
|
+
if (inline.isText)
|
|
1816
|
+
runs += `<w:r><w:t xml:space="preserve">${esc(inline.text ?? "")}</w:t></w:r>`;
|
|
1817
|
+
else if (inline.type.name === "mention")
|
|
1818
|
+
runs += `<w:r><w:t xml:space="preserve">@${esc(String(inline.attrs["label"] ?? ""))}</w:t></w:r>`;
|
|
1679
1819
|
});
|
|
1680
|
-
ps.push(
|
|
1820
|
+
ps.push(
|
|
1821
|
+
`<w:p${i === 0 ? ` w14:paraId="${firstParaId}"` : ""}>${runs}</w:p>`
|
|
1822
|
+
);
|
|
1681
1823
|
});
|
|
1682
1824
|
return ps.join("") || `<w:p w14:paraId="${firstParaId}"/>`;
|
|
1683
1825
|
}
|
|
@@ -1699,16 +1841,65 @@ function commentsExtendedXml(comments) {
|
|
|
1699
1841
|
}
|
|
1700
1842
|
var ROOT_RELS = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1701
1843
|
<Relationships xmlns="${PR_NS}"><Relationship Id="rId1" Type="${R_NS}/officeDocument" Target="word/document.xml"/></Relationships>`;
|
|
1844
|
+
var STYLE_DEFS = (() => {
|
|
1845
|
+
const heading = (level, halfPt) => `<w:style w:type="paragraph" w:styleId="Heading${level}"><w:name w:val="heading ${level}"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:qFormat/><w:pPr><w:keepNext/><w:spacing w:before="240" w:after="120"/><w:outlineLvl w:val="${level - 1}"/></w:pPr><w:rPr><w:b/><w:sz w:val="${halfPt}"/><w:szCs w:val="${halfPt}"/></w:rPr></w:style>`;
|
|
1846
|
+
return {
|
|
1847
|
+
Heading1: heading(1, 48),
|
|
1848
|
+
Heading2: heading(2, 36),
|
|
1849
|
+
Heading3: heading(3, 28),
|
|
1850
|
+
Heading4: heading(4, 24),
|
|
1851
|
+
Heading5: heading(5, 22),
|
|
1852
|
+
Heading6: heading(6, 22),
|
|
1853
|
+
Title: `<w:style w:type="paragraph" w:styleId="Title"><w:name w:val="Title"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:qFormat/><w:pPr><w:spacing w:after="80"/></w:pPr><w:rPr><w:sz w:val="56"/><w:szCs w:val="56"/></w:rPr></w:style>`,
|
|
1854
|
+
Subtitle: `<w:style w:type="paragraph" w:styleId="Subtitle"><w:name w:val="Subtitle"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:qFormat/><w:rPr><w:i/><w:sz w:val="28"/><w:szCs w:val="28"/></w:rPr></w:style>`
|
|
1855
|
+
};
|
|
1856
|
+
})();
|
|
1857
|
+
function usedStyleIds(doc) {
|
|
1858
|
+
const used = /* @__PURE__ */ new Set();
|
|
1859
|
+
doc.descendants((n) => {
|
|
1860
|
+
if (n.type.name !== "paragraph") return;
|
|
1861
|
+
const heading = n.attrs["heading"];
|
|
1862
|
+
const styleId = n.attrs["styleId"];
|
|
1863
|
+
if (heading) used.add(`Heading${heading}`);
|
|
1864
|
+
else if (styleId && STYLE_DEFS[styleId]) used.add(styleId);
|
|
1865
|
+
});
|
|
1866
|
+
return used;
|
|
1867
|
+
}
|
|
1868
|
+
function stylesXml(used) {
|
|
1869
|
+
const defs = [...used].map((id) => STYLE_DEFS[id]).join("");
|
|
1870
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1871
|
+
<w:styles xmlns:w="${W_NS}"><w:docDefaults><w:rPrDefault><w:rPr><w:sz w:val="22"/><w:szCs w:val="22"/></w:rPr></w:rPrDefault><w:pPrDefault/></w:docDefaults><w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style>` + defs + `</w:styles>`;
|
|
1872
|
+
}
|
|
1873
|
+
function mergeStyles(xml, used) {
|
|
1874
|
+
const missing = [...used].filter((id) => !xml.includes(`w:styleId="${id}"`));
|
|
1875
|
+
if (!missing.length) return xml;
|
|
1876
|
+
return xml.replace(
|
|
1877
|
+
"</w:styles>",
|
|
1878
|
+
`${missing.map((id) => STYLE_DEFS[id]).join("")}</w:styles>`
|
|
1879
|
+
);
|
|
1880
|
+
}
|
|
1702
1881
|
function contentTypes(exts, hasComments) {
|
|
1703
1882
|
const parts = [
|
|
1704
1883
|
'<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>',
|
|
1705
1884
|
'<Default Extension="xml" ContentType="application/xml"/>'
|
|
1706
1885
|
];
|
|
1707
|
-
for (const ext of exts)
|
|
1708
|
-
|
|
1886
|
+
for (const ext of exts)
|
|
1887
|
+
parts.push(
|
|
1888
|
+
`<Default Extension="${ext}" ContentType="image/${ext === "jpg" ? "jpeg" : ext}"/>`
|
|
1889
|
+
);
|
|
1890
|
+
parts.push(
|
|
1891
|
+
'<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>'
|
|
1892
|
+
);
|
|
1893
|
+
parts.push(
|
|
1894
|
+
'<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>'
|
|
1895
|
+
);
|
|
1709
1896
|
if (hasComments) {
|
|
1710
|
-
parts.push(
|
|
1711
|
-
|
|
1897
|
+
parts.push(
|
|
1898
|
+
'<Override PartName="/word/comments.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"/>'
|
|
1899
|
+
);
|
|
1900
|
+
parts.push(
|
|
1901
|
+
'<Override PartName="/word/commentsExtended.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml"/>'
|
|
1902
|
+
);
|
|
1712
1903
|
}
|
|
1713
1904
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1714
1905
|
<Types xmlns="${CT_NS}">${parts.join("")}</Types>`;
|
|
@@ -1716,17 +1907,30 @@ function contentTypes(exts, hasComments) {
|
|
|
1716
1907
|
function mergeContentTypes(xml, exts, hasComments) {
|
|
1717
1908
|
let out = xml;
|
|
1718
1909
|
const add = (frag, key) => {
|
|
1719
|
-
if (!out.includes(`"${key}"`))
|
|
1910
|
+
if (!out.includes(`"${key}"`))
|
|
1911
|
+
out = out.replace("</Types>", `${frag}</Types>`);
|
|
1720
1912
|
};
|
|
1721
|
-
for (const ext of exts)
|
|
1913
|
+
for (const ext of exts)
|
|
1914
|
+
add(
|
|
1915
|
+
`<Default Extension="${ext}" ContentType="image/${ext === "jpg" ? "jpeg" : ext}"/>`,
|
|
1916
|
+
ext
|
|
1917
|
+
);
|
|
1722
1918
|
if (hasComments) {
|
|
1723
|
-
add(
|
|
1724
|
-
|
|
1919
|
+
add(
|
|
1920
|
+
'<Override PartName="/word/comments.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"/>',
|
|
1921
|
+
"/word/comments.xml"
|
|
1922
|
+
);
|
|
1923
|
+
add(
|
|
1924
|
+
'<Override PartName="/word/commentsExtended.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml"/>',
|
|
1925
|
+
"/word/commentsExtended.xml"
|
|
1926
|
+
);
|
|
1725
1927
|
}
|
|
1726
1928
|
return out;
|
|
1727
1929
|
}
|
|
1728
1930
|
function extractBodySectPr(xml) {
|
|
1729
|
-
const all = xml.match(
|
|
1931
|
+
const all = xml.match(
|
|
1932
|
+
/<w:sectPr\b[^>]*>[\s\S]*?<\/w:sectPr>|<w:sectPr\b[^>]*\/>/g
|
|
1933
|
+
);
|
|
1730
1934
|
return all ? all[all.length - 1] : "";
|
|
1731
1935
|
}
|
|
1732
1936
|
function mergeRels(xml, newRels) {
|
|
@@ -1735,7 +1939,10 @@ function mergeRels(xml, newRels) {
|
|
|
1735
1939
|
/<Relationship\b[^>]*Target="comments(?:Extended)?\.xml"[^>]*\/>/g,
|
|
1736
1940
|
""
|
|
1737
1941
|
);
|
|
1738
|
-
return base.replace(
|
|
1942
|
+
return base.replace(
|
|
1943
|
+
"</Relationships>",
|
|
1944
|
+
`${newRels.join("")}</Relationships>`
|
|
1945
|
+
);
|
|
1739
1946
|
}
|
|
1740
1947
|
async function exportDocx(doc, opts) {
|
|
1741
1948
|
const comments = doc.attrs["comments"] ?? [];
|
|
@@ -1744,7 +1951,8 @@ async function exportDocx(doc, opts) {
|
|
|
1744
1951
|
let idx = 0;
|
|
1745
1952
|
doc.descendants((n) => {
|
|
1746
1953
|
if (!isInlineLeaf(n)) return;
|
|
1747
|
-
for (const id of commentIdsOf(n))
|
|
1954
|
+
for (const id of commentIdsOf(n))
|
|
1955
|
+
if (knownComments.has(id)) lastRun.set(id, idx);
|
|
1748
1956
|
idx++;
|
|
1749
1957
|
});
|
|
1750
1958
|
const ctx = {
|
|
@@ -1759,13 +1967,20 @@ async function exportDocx(doc, opts) {
|
|
|
1759
1967
|
};
|
|
1760
1968
|
const boundaries = sectionBoundaries(doc);
|
|
1761
1969
|
let body = "";
|
|
1762
|
-
doc.forEach(
|
|
1970
|
+
doc.forEach(
|
|
1971
|
+
(block, _offset, i) => body += blockXml(block, ctx, boundaries.get(i))
|
|
1972
|
+
);
|
|
1763
1973
|
const hasComments = comments.length > 0;
|
|
1764
1974
|
if (hasComments) {
|
|
1765
|
-
ctx.rels.push(
|
|
1766
|
-
|
|
1975
|
+
ctx.rels.push(
|
|
1976
|
+
`<Relationship Id="rIdComments" Type="${R_NS}/comments" Target="comments.xml"/>`
|
|
1977
|
+
);
|
|
1978
|
+
ctx.rels.push(
|
|
1979
|
+
`<Relationship Id="rIdCommentsExt" Type="${R_NS}/commentsExtended" Target="commentsExtended.xml"/>`
|
|
1980
|
+
);
|
|
1767
1981
|
}
|
|
1768
1982
|
const zip = new JSZip2();
|
|
1983
|
+
const styleIds = usedStyleIds(doc);
|
|
1769
1984
|
let sectPr = "";
|
|
1770
1985
|
if (opts?.carry) {
|
|
1771
1986
|
const carry = opts.carry;
|
|
@@ -1773,18 +1988,29 @@ async function exportDocx(doc, opts) {
|
|
|
1773
1988
|
if (!f.dir) zip.file(path, await f.async("uint8array"));
|
|
1774
1989
|
}
|
|
1775
1990
|
const ct = await carry.file("[Content_Types].xml")?.async("string");
|
|
1776
|
-
zip.file(
|
|
1991
|
+
zip.file(
|
|
1992
|
+
"[Content_Types].xml",
|
|
1993
|
+
ct ? mergeContentTypes(ct, ctx.exts, hasComments) : contentTypes(ctx.exts, hasComments)
|
|
1994
|
+
);
|
|
1995
|
+
const carriedStyles = await carry.file("word/styles.xml")?.async("string");
|
|
1996
|
+
if (carriedStyles)
|
|
1997
|
+
zip.file("word/styles.xml", mergeStyles(carriedStyles, styleIds));
|
|
1777
1998
|
const rels = await carry.file("word/_rels/document.xml.rels")?.async("string");
|
|
1778
1999
|
zip.file("word/_rels/document.xml.rels", mergeRels(rels, ctx.rels));
|
|
1779
2000
|
const origDoc = await carry.file("word/document.xml")?.async("string");
|
|
1780
2001
|
if (origDoc) sectPr = extractBodySectPr(origDoc);
|
|
1781
2002
|
} else {
|
|
2003
|
+
ctx.rels.push(
|
|
2004
|
+
`<Relationship Id="rIdStyles" Type="${R_NS}/styles" Target="styles.xml"/>`
|
|
2005
|
+
);
|
|
2006
|
+
zip.file("word/styles.xml", stylesXml(styleIds));
|
|
1782
2007
|
zip.file("[Content_Types].xml", contentTypes(ctx.exts, hasComments));
|
|
1783
2008
|
zip.file("_rels/.rels", ROOT_RELS);
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
2009
|
+
zip.file(
|
|
2010
|
+
"word/_rels/document.xml.rels",
|
|
2011
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
2012
|
+
<Relationships xmlns="${PR_NS}">${ctx.rels.join("")}</Relationships>`
|
|
2013
|
+
);
|
|
1788
2014
|
}
|
|
1789
2015
|
const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
1790
2016
|
<w:document xmlns:w="${W_NS}" xmlns:r="${R_NS}" xmlns:wp="${WP_NS}" xmlns:a="${A_NS}" xmlns:pic="${PIC_NS}" xmlns:wps="${WPS_NS}"><w:body>${body}${sectPr}</w:body></w:document>`;
|
|
@@ -1793,7 +2019,8 @@ async function exportDocx(doc, opts) {
|
|
|
1793
2019
|
zip.file("word/comments.xml", commentsXml(comments));
|
|
1794
2020
|
zip.file("word/commentsExtended.xml", commentsExtendedXml(comments));
|
|
1795
2021
|
}
|
|
1796
|
-
for (const { path, base64 } of ctx.media)
|
|
2022
|
+
for (const { path, base64 } of ctx.media)
|
|
2023
|
+
zip.file(path, base64, { base64: true });
|
|
1797
2024
|
return zip.generateAsync({ type: "uint8array" });
|
|
1798
2025
|
}
|
|
1799
2026
|
export {
|