docxmlater 1.5.0 → 1.6.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/README.md +61 -13
- package/dist/core/Document.d.ts +20 -1
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +403 -88
- package/dist/core/Document.js.map +1 -1
- package/dist/elements/TableOfContents.d.ts +1 -0
- package/dist/elements/TableOfContents.d.ts.map +1 -1
- package/dist/elements/TableOfContents.js +3 -0
- package/dist/elements/TableOfContents.js.map +1 -1
- package/dist/formatting/Style.d.ts +6 -0
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +13 -0
- package/dist/formatting/Style.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types/styleConfig.d.ts +47 -0
- package/dist/types/styleConfig.d.ts.map +1 -0
- package/dist/types/styleConfig.js +3 -0
- package/dist/types/styleConfig.js.map +1 -0
- package/package.json +1 -1
package/dist/core/Document.js
CHANGED
|
@@ -1132,76 +1132,168 @@ class Document {
|
|
|
1132
1132
|
}
|
|
1133
1133
|
return counts;
|
|
1134
1134
|
}
|
|
1135
|
-
|
|
1135
|
+
static DEFAULT_HEADING1_CONFIG = {
|
|
1136
|
+
run: {
|
|
1137
|
+
font: 'Verdana',
|
|
1138
|
+
size: 18,
|
|
1139
|
+
bold: true,
|
|
1140
|
+
color: '000000',
|
|
1141
|
+
},
|
|
1142
|
+
paragraph: {
|
|
1143
|
+
alignment: 'left',
|
|
1144
|
+
spacing: { before: 0, after: 240, line: 240, lineRule: 'auto' },
|
|
1145
|
+
},
|
|
1146
|
+
};
|
|
1147
|
+
static DEFAULT_HEADING2_CONFIG = {
|
|
1148
|
+
run: {
|
|
1149
|
+
font: 'Verdana',
|
|
1150
|
+
size: 14,
|
|
1151
|
+
bold: true,
|
|
1152
|
+
color: '000000',
|
|
1153
|
+
},
|
|
1154
|
+
paragraph: {
|
|
1155
|
+
alignment: 'left',
|
|
1156
|
+
spacing: { before: 120, after: 120, line: 240, lineRule: 'auto' },
|
|
1157
|
+
},
|
|
1158
|
+
tableOptions: {
|
|
1159
|
+
shading: 'BFBFBF',
|
|
1160
|
+
marginTop: 0,
|
|
1161
|
+
marginBottom: 0,
|
|
1162
|
+
marginLeft: 115,
|
|
1163
|
+
marginRight: 115,
|
|
1164
|
+
tableWidthPercent: 5000,
|
|
1165
|
+
},
|
|
1166
|
+
};
|
|
1167
|
+
static DEFAULT_HEADING3_CONFIG = {
|
|
1168
|
+
run: {
|
|
1169
|
+
font: 'Verdana',
|
|
1170
|
+
size: 12,
|
|
1171
|
+
bold: true,
|
|
1172
|
+
color: '000000',
|
|
1173
|
+
},
|
|
1174
|
+
paragraph: {
|
|
1175
|
+
alignment: 'left',
|
|
1176
|
+
spacing: { before: 60, after: 60, line: 240, lineRule: 'auto' },
|
|
1177
|
+
},
|
|
1178
|
+
};
|
|
1179
|
+
static DEFAULT_NORMAL_CONFIG = {
|
|
1180
|
+
run: {
|
|
1181
|
+
font: 'Verdana',
|
|
1182
|
+
size: 12,
|
|
1183
|
+
color: '000000',
|
|
1184
|
+
},
|
|
1185
|
+
paragraph: {
|
|
1186
|
+
alignment: 'left',
|
|
1187
|
+
spacing: { before: 60, after: 60, line: 240, lineRule: 'auto' },
|
|
1188
|
+
},
|
|
1189
|
+
};
|
|
1190
|
+
static DEFAULT_LIST_PARAGRAPH_CONFIG = {
|
|
1191
|
+
run: {
|
|
1192
|
+
font: 'Verdana',
|
|
1193
|
+
size: 12,
|
|
1194
|
+
color: '000000',
|
|
1195
|
+
},
|
|
1196
|
+
paragraph: {
|
|
1197
|
+
alignment: 'left',
|
|
1198
|
+
spacing: { before: 0, after: 60, line: 240, lineRule: 'auto' },
|
|
1199
|
+
indentation: { left: 360, hanging: 360 },
|
|
1200
|
+
contextualSpacing: true,
|
|
1201
|
+
},
|
|
1202
|
+
};
|
|
1203
|
+
applyCustomFormattingToExistingStyles(options) {
|
|
1136
1204
|
const results = { heading1: false, heading2: false, heading3: false, normal: false, listParagraph: false };
|
|
1137
1205
|
const heading1 = this.stylesManager.getStyle('Heading1');
|
|
1138
1206
|
const heading2 = this.stylesManager.getStyle('Heading2');
|
|
1139
1207
|
const heading3 = this.stylesManager.getStyle('Heading3');
|
|
1140
1208
|
const normal = this.stylesManager.getStyle('Normal');
|
|
1141
1209
|
const listParagraph = this.stylesManager.getStyle('ListParagraph');
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1210
|
+
const h1Config = {
|
|
1211
|
+
run: {
|
|
1212
|
+
...(heading1?.getRunFormatting() || Document.DEFAULT_HEADING1_CONFIG.run),
|
|
1213
|
+
...options?.heading1?.run
|
|
1214
|
+
},
|
|
1215
|
+
paragraph: {
|
|
1216
|
+
...(heading1?.getParagraphFormatting() || Document.DEFAULT_HEADING1_CONFIG.paragraph),
|
|
1217
|
+
...options?.heading1?.paragraph
|
|
1218
|
+
},
|
|
1219
|
+
};
|
|
1220
|
+
const h2Config = {
|
|
1221
|
+
run: {
|
|
1222
|
+
...(heading2?.getRunFormatting() || Document.DEFAULT_HEADING2_CONFIG.run),
|
|
1223
|
+
...options?.heading2?.run
|
|
1224
|
+
},
|
|
1225
|
+
paragraph: {
|
|
1226
|
+
...(heading2?.getParagraphFormatting() || Document.DEFAULT_HEADING2_CONFIG.paragraph),
|
|
1227
|
+
...options?.heading2?.paragraph
|
|
1228
|
+
},
|
|
1229
|
+
tableOptions: {
|
|
1230
|
+
...Document.DEFAULT_HEADING2_CONFIG.tableOptions,
|
|
1231
|
+
...options?.heading2?.tableOptions
|
|
1232
|
+
},
|
|
1233
|
+
};
|
|
1234
|
+
const h3Config = {
|
|
1235
|
+
run: {
|
|
1236
|
+
...(heading3?.getRunFormatting() || Document.DEFAULT_HEADING3_CONFIG.run),
|
|
1237
|
+
...options?.heading3?.run
|
|
1238
|
+
},
|
|
1239
|
+
paragraph: {
|
|
1240
|
+
...(heading3?.getParagraphFormatting() || Document.DEFAULT_HEADING3_CONFIG.paragraph),
|
|
1241
|
+
...options?.heading3?.paragraph
|
|
1242
|
+
},
|
|
1243
|
+
};
|
|
1244
|
+
const normalConfig = {
|
|
1245
|
+
run: {
|
|
1246
|
+
...(normal?.getRunFormatting() || Document.DEFAULT_NORMAL_CONFIG.run),
|
|
1247
|
+
...options?.normal?.run
|
|
1248
|
+
},
|
|
1249
|
+
paragraph: {
|
|
1250
|
+
...(normal?.getParagraphFormatting() || Document.DEFAULT_NORMAL_CONFIG.paragraph),
|
|
1251
|
+
...options?.normal?.paragraph
|
|
1252
|
+
},
|
|
1253
|
+
};
|
|
1254
|
+
const listParaConfig = {
|
|
1255
|
+
run: {
|
|
1256
|
+
...(listParagraph?.getRunFormatting() || Document.DEFAULT_LIST_PARAGRAPH_CONFIG.run),
|
|
1257
|
+
...options?.listParagraph?.run
|
|
1258
|
+
},
|
|
1259
|
+
paragraph: {
|
|
1260
|
+
...(listParagraph?.getParagraphFormatting() || Document.DEFAULT_LIST_PARAGRAPH_CONFIG.paragraph),
|
|
1261
|
+
...options?.listParagraph?.paragraph
|
|
1262
|
+
},
|
|
1263
|
+
};
|
|
1264
|
+
if (heading1 && h1Config.run && h1Config.paragraph) {
|
|
1265
|
+
if (h1Config.run)
|
|
1266
|
+
heading1.setRunFormatting(h1Config.run);
|
|
1267
|
+
if (h1Config.paragraph)
|
|
1268
|
+
heading1.setParagraphFormatting(h1Config.paragraph);
|
|
1153
1269
|
results.heading1 = true;
|
|
1154
1270
|
}
|
|
1155
|
-
if (heading2) {
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
color: '000000'
|
|
1161
|
-
});
|
|
1162
|
-
heading2.setParagraphFormatting({
|
|
1163
|
-
alignment: 'left',
|
|
1164
|
-
spacing: { before: 120, after: 120, line: 240, lineRule: 'auto' }
|
|
1165
|
-
});
|
|
1271
|
+
if (heading2 && h2Config.run && h2Config.paragraph) {
|
|
1272
|
+
if (h2Config.run)
|
|
1273
|
+
heading2.setRunFormatting(h2Config.run);
|
|
1274
|
+
if (h2Config.paragraph)
|
|
1275
|
+
heading2.setParagraphFormatting(h2Config.paragraph);
|
|
1166
1276
|
results.heading2 = true;
|
|
1167
1277
|
}
|
|
1168
|
-
if (heading3) {
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
color: '000000'
|
|
1174
|
-
});
|
|
1175
|
-
heading3.setParagraphFormatting({
|
|
1176
|
-
alignment: 'left',
|
|
1177
|
-
spacing: { before: 60, after: 60, line: 240, lineRule: 'auto' }
|
|
1178
|
-
});
|
|
1278
|
+
if (heading3 && h3Config.run && h3Config.paragraph) {
|
|
1279
|
+
if (h3Config.run)
|
|
1280
|
+
heading3.setRunFormatting(h3Config.run);
|
|
1281
|
+
if (h3Config.paragraph)
|
|
1282
|
+
heading3.setParagraphFormatting(h3Config.paragraph);
|
|
1179
1283
|
results.heading3 = true;
|
|
1180
1284
|
}
|
|
1181
|
-
if (normal) {
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
});
|
|
1187
|
-
normal.setParagraphFormatting({
|
|
1188
|
-
alignment: 'left',
|
|
1189
|
-
spacing: { before: 60, after: 60, line: 240, lineRule: 'auto' }
|
|
1190
|
-
});
|
|
1285
|
+
if (normal && normalConfig.run && normalConfig.paragraph) {
|
|
1286
|
+
if (normalConfig.run)
|
|
1287
|
+
normal.setRunFormatting(normalConfig.run);
|
|
1288
|
+
if (normalConfig.paragraph)
|
|
1289
|
+
normal.setParagraphFormatting(normalConfig.paragraph);
|
|
1191
1290
|
results.normal = true;
|
|
1192
1291
|
}
|
|
1193
|
-
if (listParagraph) {
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
});
|
|
1199
|
-
listParagraph.setParagraphFormatting({
|
|
1200
|
-
alignment: 'left',
|
|
1201
|
-
spacing: { before: 0, after: 60, line: 240, lineRule: 'auto' },
|
|
1202
|
-
indentation: { left: 360, hanging: 360 },
|
|
1203
|
-
contextualSpacing: true
|
|
1204
|
-
});
|
|
1292
|
+
if (listParagraph && listParaConfig.run && listParaConfig.paragraph) {
|
|
1293
|
+
if (listParaConfig.run)
|
|
1294
|
+
listParagraph.setRunFormatting(listParaConfig.run);
|
|
1295
|
+
if (listParaConfig.paragraph)
|
|
1296
|
+
listParagraph.setParagraphFormatting(listParaConfig.paragraph);
|
|
1205
1297
|
results.listParagraph = true;
|
|
1206
1298
|
}
|
|
1207
1299
|
const processedParagraphs = new Set();
|
|
@@ -1240,30 +1332,42 @@ class Document {
|
|
|
1240
1332
|
}
|
|
1241
1333
|
const { inTable, cell } = this.isParagraphInTable(para);
|
|
1242
1334
|
if (inTable && cell) {
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1335
|
+
if (h2Config.tableOptions?.shading) {
|
|
1336
|
+
cell.setShading({ fill: h2Config.tableOptions.shading });
|
|
1337
|
+
}
|
|
1338
|
+
if (h2Config.tableOptions?.marginTop !== undefined || h2Config.tableOptions?.marginBottom !== undefined ||
|
|
1339
|
+
h2Config.tableOptions?.marginLeft !== undefined || h2Config.tableOptions?.marginRight !== undefined) {
|
|
1340
|
+
cell.setMargins({
|
|
1341
|
+
top: h2Config.tableOptions.marginTop ?? 0,
|
|
1342
|
+
bottom: h2Config.tableOptions.marginBottom ?? 0,
|
|
1343
|
+
left: h2Config.tableOptions.marginLeft ?? 115,
|
|
1344
|
+
right: h2Config.tableOptions.marginRight ?? 115,
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
if (h2Config.tableOptions?.tableWidthPercent) {
|
|
1348
|
+
const table = this.getAllTables().find(t => {
|
|
1349
|
+
for (const row of t.getRows()) {
|
|
1350
|
+
for (const c of row.getCells()) {
|
|
1351
|
+
if (c === cell)
|
|
1352
|
+
return true;
|
|
1353
|
+
}
|
|
1250
1354
|
}
|
|
1355
|
+
return false;
|
|
1356
|
+
});
|
|
1357
|
+
if (table) {
|
|
1358
|
+
table.setWidth(h2Config.tableOptions.tableWidthPercent);
|
|
1359
|
+
table.setWidthType('pct');
|
|
1251
1360
|
}
|
|
1252
|
-
return false;
|
|
1253
|
-
});
|
|
1254
|
-
if (table) {
|
|
1255
|
-
table.setWidth(5000);
|
|
1256
|
-
table.setWidthType('pct');
|
|
1257
1361
|
}
|
|
1258
1362
|
}
|
|
1259
1363
|
else {
|
|
1260
1364
|
this.wrapParagraphInTable(para, {
|
|
1261
|
-
shading: 'BFBFBF',
|
|
1262
|
-
marginTop: 0,
|
|
1263
|
-
marginBottom: 0,
|
|
1264
|
-
marginLeft: 115,
|
|
1265
|
-
marginRight: 115,
|
|
1266
|
-
tableWidthPercent: 5000
|
|
1365
|
+
shading: h2Config.tableOptions?.shading ?? 'BFBFBF',
|
|
1366
|
+
marginTop: h2Config.tableOptions?.marginTop ?? 0,
|
|
1367
|
+
marginBottom: h2Config.tableOptions?.marginBottom ?? 0,
|
|
1368
|
+
marginLeft: h2Config.tableOptions?.marginLeft ?? 115,
|
|
1369
|
+
marginRight: h2Config.tableOptions?.marginRight ?? 115,
|
|
1370
|
+
tableWidthPercent: h2Config.tableOptions?.tableWidthPercent ?? 5000,
|
|
1267
1371
|
});
|
|
1268
1372
|
}
|
|
1269
1373
|
processedParagraphs.add(para);
|
|
@@ -1305,23 +1409,234 @@ class Document {
|
|
|
1305
1409
|
processedParagraphs.add(para);
|
|
1306
1410
|
}
|
|
1307
1411
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1412
|
+
return results;
|
|
1413
|
+
}
|
|
1414
|
+
applyStylesFromObjects(...styles) {
|
|
1415
|
+
const options = {};
|
|
1416
|
+
for (const style of styles) {
|
|
1417
|
+
const styleId = style.getStyleId();
|
|
1418
|
+
switch (styleId) {
|
|
1419
|
+
case 'Heading1':
|
|
1420
|
+
options.heading1 = {
|
|
1421
|
+
run: style.getRunFormatting(),
|
|
1422
|
+
paragraph: style.getParagraphFormatting(),
|
|
1423
|
+
};
|
|
1424
|
+
break;
|
|
1425
|
+
case 'Heading2':
|
|
1426
|
+
options.heading2 = {
|
|
1427
|
+
run: style.getRunFormatting(),
|
|
1428
|
+
paragraph: style.getParagraphFormatting(),
|
|
1429
|
+
tableOptions: style.getHeading2TableOptions(),
|
|
1430
|
+
};
|
|
1431
|
+
break;
|
|
1432
|
+
case 'Heading3':
|
|
1433
|
+
options.heading3 = {
|
|
1434
|
+
run: style.getRunFormatting(),
|
|
1435
|
+
paragraph: style.getParagraphFormatting(),
|
|
1436
|
+
};
|
|
1437
|
+
break;
|
|
1438
|
+
case 'Normal':
|
|
1439
|
+
options.normal = {
|
|
1440
|
+
run: style.getRunFormatting(),
|
|
1441
|
+
paragraph: style.getParagraphFormatting(),
|
|
1442
|
+
};
|
|
1443
|
+
break;
|
|
1444
|
+
case 'ListParagraph':
|
|
1445
|
+
options.listParagraph = {
|
|
1446
|
+
run: style.getRunFormatting(),
|
|
1447
|
+
paragraph: style.getParagraphFormatting(),
|
|
1448
|
+
};
|
|
1449
|
+
break;
|
|
1450
|
+
default:
|
|
1451
|
+
break;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
return this.applyCustomFormattingToExistingStyles(options);
|
|
1455
|
+
}
|
|
1456
|
+
parseTOCFieldInstruction(instrText) {
|
|
1457
|
+
const levels = new Set();
|
|
1458
|
+
const outlineMatch = instrText.match(/\\o\s+"(\d+)-(\d+)"/);
|
|
1459
|
+
if (outlineMatch && outlineMatch[1] && outlineMatch[2]) {
|
|
1460
|
+
const start = parseInt(outlineMatch[1], 10);
|
|
1461
|
+
const end = parseInt(outlineMatch[2], 10);
|
|
1462
|
+
for (let i = start; i <= end; i++) {
|
|
1463
|
+
if (i >= 1 && i <= 9) {
|
|
1464
|
+
levels.add(i);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
const styleMatches = instrText.matchAll(/\\t\s+"([^"]+)",(\d+),"/g);
|
|
1469
|
+
for (const match of styleMatches) {
|
|
1470
|
+
const styleName = match[1];
|
|
1471
|
+
const levelStr = match[2];
|
|
1472
|
+
if (!styleName || !levelStr)
|
|
1473
|
+
continue;
|
|
1474
|
+
const level = parseInt(levelStr, 10);
|
|
1475
|
+
const headingMatch = styleName.match(/Heading\s*(\d+)/i);
|
|
1476
|
+
if (headingMatch && headingMatch[1]) {
|
|
1477
|
+
const headingLevel = parseInt(headingMatch[1], 10);
|
|
1478
|
+
if (headingLevel >= 1 && headingLevel <= 9) {
|
|
1479
|
+
levels.add(headingLevel);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
else if (level >= 1 && level <= 9) {
|
|
1483
|
+
levels.add(level);
|
|
1315
1484
|
}
|
|
1316
1485
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
for (const tocElement of tocElements) {
|
|
1320
|
-
const toc = tocElement.getTableOfContents();
|
|
1321
|
-
toc.setShowPageNumbers(false);
|
|
1322
|
-
toc.setHideInWebLayout(true);
|
|
1486
|
+
if (levels.size === 0) {
|
|
1487
|
+
return [1, 2, 3];
|
|
1323
1488
|
}
|
|
1324
|
-
return
|
|
1489
|
+
return Array.from(levels).sort((a, b) => a - b);
|
|
1490
|
+
}
|
|
1491
|
+
findHeadingsForTOC(levels) {
|
|
1492
|
+
const headings = [];
|
|
1493
|
+
const levelSet = new Set(levels);
|
|
1494
|
+
for (const element of this.bodyElements) {
|
|
1495
|
+
if (element instanceof Paragraph_1.Paragraph) {
|
|
1496
|
+
const para = element;
|
|
1497
|
+
const formatting = para.getFormatting();
|
|
1498
|
+
if (formatting.style) {
|
|
1499
|
+
const styleMatch = formatting.style.match(/Heading(\d+)/i);
|
|
1500
|
+
if (styleMatch && styleMatch[1]) {
|
|
1501
|
+
const headingLevel = parseInt(styleMatch[1], 10);
|
|
1502
|
+
if (levelSet.has(headingLevel)) {
|
|
1503
|
+
const text = para.getText().trim();
|
|
1504
|
+
if (text) {
|
|
1505
|
+
const bookmark = this.bookmarkManager.createHeadingBookmark(text);
|
|
1506
|
+
headings.push({
|
|
1507
|
+
level: headingLevel,
|
|
1508
|
+
text: text,
|
|
1509
|
+
bookmark: bookmark.getName()
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
return headings;
|
|
1518
|
+
}
|
|
1519
|
+
generateTOCXML(headings, originalInstrText) {
|
|
1520
|
+
const sdtId = Math.floor(Math.random() * 2000000000) - 1000000000;
|
|
1521
|
+
let tocXml = '<w:sdt>';
|
|
1522
|
+
tocXml += '<w:sdtPr>';
|
|
1523
|
+
tocXml += `<w:id w:val="${sdtId}"/>`;
|
|
1524
|
+
tocXml += '<w:docPartObj>';
|
|
1525
|
+
tocXml += '<w:docPartGallery w:val="Table of Contents"/>';
|
|
1526
|
+
tocXml += '<w:docPartUnique w:val="1"/>';
|
|
1527
|
+
tocXml += '</w:docPartObj>';
|
|
1528
|
+
tocXml += '</w:sdtPr>';
|
|
1529
|
+
tocXml += '<w:sdtContent>';
|
|
1530
|
+
tocXml += '<w:p>';
|
|
1531
|
+
tocXml += '<w:pPr>';
|
|
1532
|
+
tocXml += '<w:spacing w:after="0" w:before="0" w:line="240" w:lineRule="auto"/>';
|
|
1533
|
+
tocXml += '</w:pPr>';
|
|
1534
|
+
tocXml += '<w:r><w:fldChar w:fldCharType="begin"/></w:r>';
|
|
1535
|
+
tocXml += '<w:r>';
|
|
1536
|
+
tocXml += `<w:instrText xml:space="preserve">${this.escapeXml(originalInstrText)}</w:instrText>`;
|
|
1537
|
+
tocXml += '</w:r>';
|
|
1538
|
+
tocXml += '<w:r><w:fldChar w:fldCharType="separate"/></w:r>';
|
|
1539
|
+
if (headings.length > 0 && headings[0]) {
|
|
1540
|
+
tocXml += this.buildTOCEntryXML(headings[0]);
|
|
1541
|
+
}
|
|
1542
|
+
tocXml += '</w:p>';
|
|
1543
|
+
for (let i = 1; i < headings.length; i++) {
|
|
1544
|
+
const heading = headings[i];
|
|
1545
|
+
if (!heading)
|
|
1546
|
+
continue;
|
|
1547
|
+
tocXml += '<w:p>';
|
|
1548
|
+
tocXml += '<w:pPr>';
|
|
1549
|
+
tocXml += '<w:spacing w:after="0" w:before="0" w:line="240" w:lineRule="auto"/>';
|
|
1550
|
+
const indent = (heading.level - 1) * 720;
|
|
1551
|
+
if (indent > 0) {
|
|
1552
|
+
tocXml += `<w:ind w:left="${indent}"/>`;
|
|
1553
|
+
}
|
|
1554
|
+
tocXml += '</w:pPr>';
|
|
1555
|
+
tocXml += this.buildTOCEntryXML(heading);
|
|
1556
|
+
tocXml += '</w:p>';
|
|
1557
|
+
}
|
|
1558
|
+
tocXml += '<w:p>';
|
|
1559
|
+
tocXml += '<w:pPr>';
|
|
1560
|
+
tocXml += '<w:spacing w:after="0" w:before="0" w:line="240" w:lineRule="auto"/>';
|
|
1561
|
+
tocXml += '</w:pPr>';
|
|
1562
|
+
tocXml += '<w:r><w:fldChar w:fldCharType="end"/></w:r>';
|
|
1563
|
+
tocXml += '</w:p>';
|
|
1564
|
+
tocXml += '</w:sdtContent>';
|
|
1565
|
+
tocXml += '</w:sdt>';
|
|
1566
|
+
return tocXml;
|
|
1567
|
+
}
|
|
1568
|
+
buildTOCEntryXML(heading) {
|
|
1569
|
+
const escapedText = this.escapeXml(heading.text);
|
|
1570
|
+
let xml = '';
|
|
1571
|
+
xml += `<w:hyperlink w:anchor="${this.escapeXml(heading.bookmark)}">`;
|
|
1572
|
+
xml += '<w:r>';
|
|
1573
|
+
xml += '<w:rPr>';
|
|
1574
|
+
xml += '<w:rFonts w:ascii="Verdana" w:hAnsi="Verdana" w:cs="Verdana" w:eastAsia="Verdana"/>';
|
|
1575
|
+
xml += '<w:color w:val="0000FF"/>';
|
|
1576
|
+
xml += '<w:sz w:val="24"/>';
|
|
1577
|
+
xml += '<w:szCs w:val="24"/>';
|
|
1578
|
+
xml += '<w:u w:val="single"/>';
|
|
1579
|
+
xml += '</w:rPr>';
|
|
1580
|
+
xml += `<w:t xml:space="preserve">${escapedText}</w:t>`;
|
|
1581
|
+
xml += '</w:r>';
|
|
1582
|
+
xml += '</w:hyperlink>';
|
|
1583
|
+
return xml;
|
|
1584
|
+
}
|
|
1585
|
+
escapeXml(text) {
|
|
1586
|
+
return text
|
|
1587
|
+
.replace(/&/g, '&')
|
|
1588
|
+
.replace(/</g, '<')
|
|
1589
|
+
.replace(/>/g, '>')
|
|
1590
|
+
.replace(/"/g, '"')
|
|
1591
|
+
.replace(/'/g, ''');
|
|
1592
|
+
}
|
|
1593
|
+
async replaceTableOfContents(filePath) {
|
|
1594
|
+
const handler = new ZipHandler_1.ZipHandler();
|
|
1595
|
+
await handler.load(filePath);
|
|
1596
|
+
const docXml = handler.getFileAsString('word/document.xml');
|
|
1597
|
+
if (!docXml) {
|
|
1598
|
+
throw new Error('word/document.xml not found in document');
|
|
1599
|
+
}
|
|
1600
|
+
const tocRegex = /<w:sdt>[\s\S]*?<w:docPartGallery w:val="Table of Contents"[\s\S]*?<\/w:sdt>/g;
|
|
1601
|
+
const tocMatches = Array.from(docXml.matchAll(tocRegex));
|
|
1602
|
+
if (tocMatches.length === 0) {
|
|
1603
|
+
return 0;
|
|
1604
|
+
}
|
|
1605
|
+
let replacedCount = 0;
|
|
1606
|
+
let modifiedXml = docXml;
|
|
1607
|
+
for (const match of tocMatches) {
|
|
1608
|
+
try {
|
|
1609
|
+
const tocXml = match[0];
|
|
1610
|
+
const instrMatch = tocXml.match(/<w:instrText[^>]*>([\s\S]*?)<\/w:instrText>/);
|
|
1611
|
+
if (!instrMatch || !instrMatch[1]) {
|
|
1612
|
+
continue;
|
|
1613
|
+
}
|
|
1614
|
+
let fieldInstruction = instrMatch[1];
|
|
1615
|
+
fieldInstruction = fieldInstruction
|
|
1616
|
+
.replace(/</g, '<')
|
|
1617
|
+
.replace(/>/g, '>')
|
|
1618
|
+
.replace(/"/g, '"')
|
|
1619
|
+
.replace(/'/g, "'")
|
|
1620
|
+
.replace(/&/g, '&');
|
|
1621
|
+
const levels = this.parseTOCFieldInstruction(fieldInstruction);
|
|
1622
|
+
const headings = this.findHeadingsForTOC(levels);
|
|
1623
|
+
if (headings.length === 0) {
|
|
1624
|
+
continue;
|
|
1625
|
+
}
|
|
1626
|
+
const newTocXml = this.generateTOCXML(headings, fieldInstruction);
|
|
1627
|
+
modifiedXml = modifiedXml.replace(tocXml, newTocXml);
|
|
1628
|
+
replacedCount++;
|
|
1629
|
+
}
|
|
1630
|
+
catch (error) {
|
|
1631
|
+
console.error(`Error replacing TOC: ${error}`);
|
|
1632
|
+
continue;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
if (replacedCount > 0) {
|
|
1636
|
+
handler.updateFile('word/document.xml', modifiedXml);
|
|
1637
|
+
await handler.save(filePath);
|
|
1638
|
+
}
|
|
1639
|
+
return replacedCount;
|
|
1325
1640
|
}
|
|
1326
1641
|
getSection() {
|
|
1327
1642
|
return this.section;
|