@a3s-lab/office 0.29.0 → 0.31.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.
Files changed (61) hide show
  1. package/README.md +117 -3
  2. package/dist/{0~7043.js → 0~4808.js} +347 -2
  3. package/dist/0~5050.js +10 -1
  4. package/dist/{0~5093.js → 0~7240.js} +465 -55
  5. package/dist/0~document-editor.js +1694 -187
  6. package/dist/0~spreadsheet-editor.js +183 -34
  7. package/dist/0~work-docx-export.js +507 -31
  8. package/dist/0~work-docx-import.js +41 -7
  9. package/dist/0~work-office-diagnostics.js +146 -5
  10. package/dist/1544.js +13 -1
  11. package/dist/4104.js +29 -6
  12. package/dist/4121.js +2340 -1
  13. package/dist/6282.js +1072 -1148
  14. package/dist/internal/features/work/editors/document-command-catalog.d.ts +45 -0
  15. package/dist/internal/features/work/editors/document-dom-selection.d.ts +7 -0
  16. package/dist/internal/features/work/editors/document-editor-support.d.ts +1 -0
  17. package/dist/internal/features/work/editors/document-font-dialog-model.d.ts +5 -2
  18. package/dist/internal/features/work/editors/document-font-dialog-run-shading-model.d.ts +23 -0
  19. package/dist/internal/features/work/editors/document-font-dialog-run-shading-section.d.ts +8 -0
  20. package/dist/internal/features/work/editors/document-index-dialog.d.ts +10 -0
  21. package/dist/internal/features/work/editors/document-index-entry-dialog.d.ts +10 -0
  22. package/dist/internal/features/work/editors/document-page-chrome-ribbon.d.ts +2 -1
  23. package/dist/internal/features/work/editors/document-proofing-dialog-model.d.ts +22 -0
  24. package/dist/internal/features/work/editors/document-proofing-dialog.d.ts +7 -0
  25. package/dist/internal/features/work/editors/document-references-ribbon.d.ts +19 -0
  26. package/dist/internal/features/work/editors/document-table-of-contents-dialog.d.ts +10 -0
  27. package/dist/internal/features/work/editors/document-toolbar.d.ts +6 -1
  28. package/dist/internal/features/work/editors/spreadsheet-data-validation.d.ts +7 -1
  29. package/dist/internal/features/work/editors/use-document-insert-commands.d.ts +5 -0
  30. package/dist/internal/features/work/work-document-character-formatting.d.ts +8 -0
  31. package/dist/internal/features/work/work-document-format-changes.d.ts +6 -0
  32. package/dist/internal/features/work/work-document-highlight.d.ts +9 -0
  33. package/dist/internal/features/work/work-document-index-fields.d.ts +19 -0
  34. package/dist/internal/features/work/work-document-index-nodes.d.ts +32 -0
  35. package/dist/internal/features/work/work-document-index.d.ts +63 -0
  36. package/dist/internal/features/work/work-document-outline.d.ts +1 -0
  37. package/dist/internal/features/work/work-document-paragraph-shading.d.ts +6 -0
  38. package/dist/internal/features/work/work-document-proofing.d.ts +19 -0
  39. package/dist/internal/features/work/work-document-run-shading.d.ts +12 -0
  40. package/dist/internal/features/work/work-document-table-of-contents-node.d.ts +18 -0
  41. package/dist/internal/features/work/work-document-table-of-contents.d.ts +51 -0
  42. package/dist/internal/features/work/work-document-word-line-metrics.d.ts +3 -0
  43. package/dist/internal/features/work/work-docx-field-instructions.d.ts +1 -1
  44. package/dist/internal/features/work/work-docx-import.d.ts +5 -1
  45. package/dist/internal/features/work/work-docx-index-export.d.ts +14 -0
  46. package/dist/internal/features/work/work-docx-index-import.d.ts +23 -0
  47. package/dist/internal/features/work/work-docx-proofing-diagnostics.d.ts +3 -0
  48. package/dist/internal/features/work/work-docx-proofing.d.ts +38 -0
  49. package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +7 -0
  50. package/dist/internal/features/work/work-docx-run-shading-diagnostics.d.ts +3 -0
  51. package/dist/internal/features/work/work-docx-run-shading-export.d.ts +17 -0
  52. package/dist/internal/features/work/work-docx-run-shading.d.ts +20 -0
  53. package/dist/internal/features/work/work-docx-table-of-contents-export.d.ts +11 -0
  54. package/dist/internal/features/work/work-docx-table-of-contents-import.d.ts +15 -0
  55. package/dist/internal/features/work/work-spreadsheet-data-validation.d.ts +7 -0
  56. package/dist/internal/features/work/work-types.d.ts +9 -0
  57. package/dist/internal/kernel/office-kernel-protocol.d.ts +1 -0
  58. package/dist/office-kernel.wasm +0 -0
  59. package/dist/styles.css +607 -4
  60. package/docs/latest/en/browser-editor-architecture.md +64 -1
  61. package/package.json +15 -2
package/dist/4121.js CHANGED
@@ -1,4 +1,73 @@
1
1
  import jszip from "jszip";
2
+ import { Extension } from "@tiptap/core";
3
+ import { isHistoryTransaction } from "@tiptap/pm/history";
4
+ import { Plugin } from "@tiptap/pm/state";
5
+ import { Mapping } from "@tiptap/pm/transform";
6
+ const DOCUMENT_INTEGRITY_BOOKMARK = 1;
7
+ const DOCUMENT_INTEGRITY_FIELD = 2;
8
+ const DOCUMENT_INTEGRITY_IMAGE = 4;
9
+ const DOCUMENT_INTEGRITY_NOTE = 8;
10
+ const DOCUMENT_INTEGRITY_PARAGRAPH_IDENTITY = 16;
11
+ const DOCUMENT_INTEGRITY_TABLE_ROW_IDENTITY = 32;
12
+ const featureCache = new WeakMap();
13
+ function documentHasIntegrityFeature(document, feature) {
14
+ return (documentIntegrityFeatures(document, true) & feature) !== 0;
15
+ }
16
+ function primeDocumentIntegrityFeatures(document) {
17
+ document.forEach(primeDocumentIntegrityNode);
18
+ }
19
+ function primeDocumentIntegrityNode(node) {
20
+ if ('documentChunk' === node.type.name) {
21
+ const features = nonNegativeInteger(node.attrs.integrityFeatures);
22
+ if (null !== features) featureCache.set(node, features);
23
+ if (true !== node.attrs.windowContainer) return;
24
+ }
25
+ node.forEach(primeDocumentIntegrityNode);
26
+ }
27
+ function documentIntegrityFeatures(node, cacheNode) {
28
+ if (cacheNode) {
29
+ const cached = featureCache.get(node);
30
+ if (void 0 !== cached) return cached;
31
+ }
32
+ let features = nodeIntegrityFeatures(node);
33
+ node.forEach((child)=>{
34
+ features |= documentIntegrityFeatures(child, 'documentChunk' === child.type.name);
35
+ });
36
+ if (cacheNode) featureCache.set(node, features);
37
+ return features;
38
+ }
39
+ function nodeIntegrityFeatures(node) {
40
+ let features = 0;
41
+ switch(node.type.name){
42
+ case 'documentBookmarkBoundary':
43
+ features |= DOCUMENT_INTEGRITY_BOOKMARK;
44
+ break;
45
+ case 'documentCrossReference':
46
+ if ('bookmark' === node.attrs.targetType) features |= DOCUMENT_INTEGRITY_BOOKMARK;
47
+ break;
48
+ case 'documentField':
49
+ features |= DOCUMENT_INTEGRITY_FIELD;
50
+ break;
51
+ case 'image':
52
+ features |= DOCUMENT_INTEGRITY_IMAGE;
53
+ break;
54
+ case 'documentNote':
55
+ case 'documentNoteReference':
56
+ features |= DOCUMENT_INTEGRITY_NOTE;
57
+ break;
58
+ }
59
+ if (node.isText && node.marks.some((mark)=>'link' === mark.type.name && 'string' == typeof mark.attrs.href && mark.attrs.href.startsWith('#'))) features |= DOCUMENT_INTEGRITY_BOOKMARK;
60
+ if (identityComponent(node.attrs.paragraphId) || identityComponent(node.attrs.textId)) features |= DOCUMENT_INTEGRITY_PARAGRAPH_IDENTITY;
61
+ if (identityComponent(node.attrs.rowId) || identityComponent(node.attrs.rowTextId)) features |= DOCUMENT_INTEGRITY_TABLE_ROW_IDENTITY;
62
+ return features;
63
+ }
64
+ function identityComponent(value) {
65
+ return 'string' == typeof value && value.trim().length > 0;
66
+ }
67
+ function nonNegativeInteger(value) {
68
+ const number = Number(value);
69
+ return Number.isSafeInteger(number) && number >= 0 ? number : null;
70
+ }
2
71
  function normalizeCssColor(source) {
3
72
  const value = source?.trim().toLowerCase();
4
73
  if (!value) return null;
@@ -971,6 +1040,1779 @@ function cssBorderStyle(style) {
971
1040
  function work_document_run_border_formatPixels(value) {
972
1041
  return Number(value.toFixed(3)).toString();
973
1042
  }
1043
+ const work_document_paragraph_shading_DOCUMENT_PARAGRAPH_SHADING_PATTERNS = new Set([
1044
+ 'nil',
1045
+ 'clear',
1046
+ 'solid',
1047
+ 'horzStripe',
1048
+ 'vertStripe',
1049
+ 'reverseDiagStripe',
1050
+ 'diagStripe',
1051
+ 'horzCross',
1052
+ 'diagCross',
1053
+ 'thinHorzStripe',
1054
+ 'thinVertStripe',
1055
+ 'thinReverseDiagStripe',
1056
+ 'thinDiagStripe',
1057
+ 'thinHorzCross',
1058
+ 'thinDiagCross',
1059
+ 'pct5',
1060
+ 'pct10',
1061
+ 'pct12',
1062
+ 'pct15',
1063
+ 'pct20',
1064
+ 'pct25',
1065
+ 'pct30',
1066
+ 'pct35',
1067
+ 'pct37',
1068
+ 'pct40',
1069
+ 'pct45',
1070
+ 'pct50',
1071
+ 'pct55',
1072
+ 'pct60',
1073
+ 'pct62',
1074
+ 'pct65',
1075
+ 'pct70',
1076
+ 'pct75',
1077
+ 'pct80',
1078
+ 'pct85',
1079
+ 'pct87',
1080
+ 'pct90',
1081
+ 'pct95'
1082
+ ]);
1083
+ function normalizeDocumentParagraphShading(source) {
1084
+ if (!source || 'object' != typeof source) return null;
1085
+ const value = source;
1086
+ const pattern = value.pattern;
1087
+ if ('string' != typeof pattern || !work_document_paragraph_shading_DOCUMENT_PARAGRAPH_SHADING_PATTERNS.has(pattern)) return null;
1088
+ const color = normalizeShadingColor(value.color);
1089
+ const fill = normalizeShadingColor(value.fill);
1090
+ if (void 0 !== value.color && !color || void 0 !== value.fill && !fill) return null;
1091
+ return {
1092
+ pattern: pattern,
1093
+ ...color ? {
1094
+ color
1095
+ } : {},
1096
+ ...fill ? {
1097
+ fill
1098
+ } : {}
1099
+ };
1100
+ }
1101
+ function parseDocumentParagraphShading(source) {
1102
+ if ('string' != typeof source) return normalizeDocumentParagraphShading(source);
1103
+ if (!source.trim()) return null;
1104
+ try {
1105
+ return normalizeDocumentParagraphShading(JSON.parse(source));
1106
+ } catch {
1107
+ return null;
1108
+ }
1109
+ }
1110
+ function serializeDocumentParagraphShading(source) {
1111
+ const shading = normalizeDocumentParagraphShading(source);
1112
+ if (!shading) return;
1113
+ return JSON.stringify({
1114
+ pattern: shading.pattern,
1115
+ ...shading.color ? {
1116
+ color: serializedShadingColor(shading.color)
1117
+ } : {},
1118
+ ...shading.fill ? {
1119
+ fill: serializedShadingColor(shading.fill)
1120
+ } : {}
1121
+ });
1122
+ }
1123
+ function parseDocumentParagraphShadingElement(element) {
1124
+ const semantic = parseDocumentParagraphShading(element.dataset.officeParagraphShading);
1125
+ const background = normalizeCssColor(element.style.backgroundColor);
1126
+ if (semantic) {
1127
+ const presentation = documentParagraphShadingPresentation(semantic);
1128
+ const expected = normalizeCssColor(presentation.backgroundColor);
1129
+ if (background && expected && background !== expected) {
1130
+ if ('transparent' === background) return {
1131
+ pattern: 'nil'
1132
+ };
1133
+ if (paragraphShadingBackgroundUsesForeground(semantic)) return {
1134
+ ...semantic,
1135
+ color: {
1136
+ value: background
1137
+ }
1138
+ };
1139
+ return {
1140
+ ...semantic,
1141
+ fill: {
1142
+ value: background
1143
+ }
1144
+ };
1145
+ }
1146
+ return semantic;
1147
+ }
1148
+ return background && 'transparent' !== background ? {
1149
+ pattern: 'clear',
1150
+ fill: {
1151
+ value: background
1152
+ }
1153
+ } : null;
1154
+ }
1155
+ function documentParagraphShadingDomAttributes(source) {
1156
+ const shading = normalizeDocumentParagraphShading(source);
1157
+ const serialized = serializeDocumentParagraphShading(shading);
1158
+ if (!shading || !serialized) return {};
1159
+ const presentation = documentParagraphShadingPresentation(shading);
1160
+ const styles = [
1161
+ `background-color: ${presentation.backgroundColor}`,
1162
+ presentation.backgroundImage ? `background-image: ${presentation.backgroundImage}` : '',
1163
+ presentation.backgroundSize ? `background-size: ${presentation.backgroundSize}` : ''
1164
+ ].filter(Boolean);
1165
+ return {
1166
+ 'data-office-paragraph-shading': serialized,
1167
+ style: styles.join('; ')
1168
+ };
1169
+ }
1170
+ function normalizeShadingColor(source) {
1171
+ if (!source || 'object' != typeof source) return null;
1172
+ const value = source;
1173
+ const theme = parseDocxThemeReference('string' == typeof value.theme ? value.theme : value.theme ? JSON.stringify(value.theme) : void 0);
1174
+ const direct = 'auto' === value.value ? 'auto' : 'string' == typeof value.value ? normalizeCssColor(value.value) : null;
1175
+ const resolved = direct ?? theme?.resolved ?? null;
1176
+ if (!resolved || 'transparent' === resolved) return null;
1177
+ if (theme && resolved !== theme.resolved) return null;
1178
+ return {
1179
+ value: resolved,
1180
+ ...theme ? {
1181
+ theme
1182
+ } : {}
1183
+ };
1184
+ }
1185
+ function serializedShadingColor(color) {
1186
+ const theme = serializeDocxThemeReference(color.theme ?? null);
1187
+ return {
1188
+ value: color.value,
1189
+ ...theme ? {
1190
+ theme: JSON.parse(theme)
1191
+ } : {}
1192
+ };
1193
+ }
1194
+ function documentParagraphShadingPresentation(shading) {
1195
+ if ('nil' === shading.pattern) return {
1196
+ backgroundColor: 'transparent'
1197
+ };
1198
+ const foreground = shadingColor(shading.color, '#000000');
1199
+ const background = shadingColor(shading.fill, 'transparent');
1200
+ if ('clear' === shading.pattern) return {
1201
+ backgroundColor: background
1202
+ };
1203
+ if ('solid' === shading.pattern) return {
1204
+ backgroundColor: foreground
1205
+ };
1206
+ const percentage = shadingPercentage(shading.pattern);
1207
+ if (null !== percentage) {
1208
+ const inverted = percentage > 50;
1209
+ const dotColor = inverted ? background : foreground;
1210
+ const baseColor = inverted ? foreground : background;
1211
+ const density = Math.min(50, inverted ? 100 - percentage : percentage);
1212
+ const spacing = Math.max(2, Math.round(9 - density / 7));
1213
+ return {
1214
+ backgroundColor: baseColor,
1215
+ backgroundImage: `radial-gradient(circle, ${dotColor} 0 1px, transparent 1.2px)`,
1216
+ backgroundSize: `${spacing}px ${spacing}px`
1217
+ };
1218
+ }
1219
+ const thin = shading.pattern.startsWith('thin');
1220
+ const width = thin ? 1 : 2;
1221
+ const period = thin ? 7 : 6;
1222
+ const stripe = (angle)=>`repeating-linear-gradient(${angle}deg, ${foreground} 0 ${width}px, transparent ${width}px ${period}px)`;
1223
+ const angles = shadingPatternAngles(shading.pattern);
1224
+ return {
1225
+ backgroundColor: background,
1226
+ backgroundImage: angles.map(stripe).join(', ')
1227
+ };
1228
+ }
1229
+ function shadingColor(color, fallback) {
1230
+ return color && 'auto' !== color.value ? color.value : fallback;
1231
+ }
1232
+ function shadingPercentage(pattern) {
1233
+ const match = /^pct(\d+)$/.exec(pattern);
1234
+ return match?.[1] ? Number(match[1]) : null;
1235
+ }
1236
+ function paragraphShadingBackgroundUsesForeground(shading) {
1237
+ if ('solid' === shading.pattern) return true;
1238
+ const percentage = shadingPercentage(shading.pattern);
1239
+ return null !== percentage && percentage > 50;
1240
+ }
1241
+ function shadingPatternAngles(pattern) {
1242
+ if (pattern.includes('HorzCross')) return [
1243
+ 0,
1244
+ 90
1245
+ ];
1246
+ if (pattern.includes('DiagCross')) return [
1247
+ 45,
1248
+ -45
1249
+ ];
1250
+ if (pattern.includes('VertStripe')) return [
1251
+ 90
1252
+ ];
1253
+ if (pattern.includes('ReverseDiagStripe')) return [
1254
+ -45
1255
+ ];
1256
+ if (pattern.includes('DiagStripe')) return [
1257
+ 45
1258
+ ];
1259
+ return [
1260
+ 0
1261
+ ];
1262
+ }
1263
+ const DOCUMENT_HIGHLIGHT_ATTRIBUTE = 'data-office-highlight';
1264
+ const DOCUMENT_HIGHLIGHT_VALUES = new Set([
1265
+ 'black',
1266
+ 'blue',
1267
+ 'cyan',
1268
+ 'darkBlue',
1269
+ 'darkCyan',
1270
+ 'darkGray',
1271
+ 'darkGreen',
1272
+ 'darkMagenta',
1273
+ 'darkRed',
1274
+ 'darkYellow',
1275
+ 'green',
1276
+ 'lightGray',
1277
+ 'magenta',
1278
+ 'none',
1279
+ 'red',
1280
+ 'white',
1281
+ 'yellow'
1282
+ ]);
1283
+ const HIGHLIGHT_COLORS = {
1284
+ black: '#000000',
1285
+ blue: '#0000ff',
1286
+ cyan: '#00ffff',
1287
+ darkBlue: '#000080',
1288
+ darkCyan: '#008080',
1289
+ darkGray: '#808080',
1290
+ darkGreen: '#008000',
1291
+ darkMagenta: '#800080',
1292
+ darkRed: '#800000',
1293
+ darkYellow: '#808000',
1294
+ green: '#00ff00',
1295
+ lightGray: '#c0c0c0',
1296
+ magenta: '#ff00ff',
1297
+ none: 'transparent',
1298
+ red: '#ff0000',
1299
+ white: '#ffffff',
1300
+ yellow: '#ffff00'
1301
+ };
1302
+ function normalizeDocumentHighlight(source) {
1303
+ return 'string' == typeof source && DOCUMENT_HIGHLIGHT_VALUES.has(source) ? source : null;
1304
+ }
1305
+ function documentHighlightFromDocxValue(source) {
1306
+ if ('string' != typeof source) return null;
1307
+ const normalized = source.trim().toLowerCase();
1308
+ for (const value of DOCUMENT_HIGHLIGHT_VALUES)if (value.toLowerCase() === normalized) return value;
1309
+ return null;
1310
+ }
1311
+ function documentHighlightCssColor(source) {
1312
+ const value = normalizeDocumentHighlight(source);
1313
+ return value ? HIGHLIGHT_COLORS[value] : null;
1314
+ }
1315
+ function documentHighlightForCssColor(source) {
1316
+ const color = normalizeCssColor('string' == typeof source ? source : null);
1317
+ if (!color) return null;
1318
+ for (const [value, candidate] of Object.entries(HIGHLIGHT_COLORS))if (candidate === color) return value;
1319
+ return null;
1320
+ }
1321
+ function documentHighlightFromElement(element) {
1322
+ return normalizeDocumentHighlight(element.getAttribute(DOCUMENT_HIGHLIGHT_ATTRIBUTE)) ?? documentHighlightForCssColor(element.style.backgroundColor);
1323
+ }
1324
+ function documentHighlightDomAttributes(source) {
1325
+ const value = normalizeDocumentHighlight(source);
1326
+ const color = documentHighlightCssColor(value);
1327
+ return value && color ? {
1328
+ [DOCUMENT_HIGHLIGHT_ATTRIBUTE]: value,
1329
+ style: `background-color: ${color}`
1330
+ } : {};
1331
+ }
1332
+ const DOCUMENT_RUN_SHADING_ATTRIBUTE = 'data-office-run-shading';
1333
+ const MAX_SERIALIZED_RUN_SHADING_BYTES = 4096;
1334
+ const RUN_SHADING_KEYS = new Set([
1335
+ 'pattern',
1336
+ 'color',
1337
+ 'fill'
1338
+ ]);
1339
+ const RUN_SHADING_COLOR_KEYS = new Set([
1340
+ 'value',
1341
+ 'theme'
1342
+ ]);
1343
+ const THEME_REFERENCE_KEYS = new Set([
1344
+ 'theme',
1345
+ 'resolved',
1346
+ 'tint',
1347
+ 'shade'
1348
+ ]);
1349
+ function normalizeDocumentRunShading(source) {
1350
+ if (!isRecordWithKeys(source, RUN_SHADING_KEYS)) return null;
1351
+ for (const name of [
1352
+ 'color',
1353
+ 'fill'
1354
+ ]){
1355
+ const color = source[name];
1356
+ if (void 0 !== color) {
1357
+ if (!isRecordWithKeys(color, RUN_SHADING_COLOR_KEYS)) return null;
1358
+ if (void 0 !== color.theme && !isRecordWithKeys(color.theme, THEME_REFERENCE_KEYS)) return null;
1359
+ }
1360
+ }
1361
+ return normalizeDocumentParagraphShading(source);
1362
+ }
1363
+ function parseDocumentRunShading(source) {
1364
+ if ('string' != typeof source) return normalizeDocumentRunShading(source);
1365
+ if (!source.trim() || source.length > MAX_SERIALIZED_RUN_SHADING_BYTES) return null;
1366
+ try {
1367
+ return normalizeDocumentRunShading(JSON.parse(source));
1368
+ } catch {
1369
+ return null;
1370
+ }
1371
+ }
1372
+ function serializeDocumentRunShading(source) {
1373
+ const shading = normalizeDocumentRunShading(source);
1374
+ const serialized = shading ? serializeDocumentParagraphShading(shading) : void 0;
1375
+ return serialized && serialized.length <= MAX_SERIALIZED_RUN_SHADING_BYTES ? serialized : void 0;
1376
+ }
1377
+ function parseDocumentRunShadingElement(element) {
1378
+ const semantic = parseDocumentRunShading(element.getAttribute(DOCUMENT_RUN_SHADING_ATTRIBUTE));
1379
+ if (!semantic) return null;
1380
+ if (element.hasAttribute(DOCUMENT_HIGHLIGHT_ATTRIBUTE)) return semantic;
1381
+ const background = normalizeCssColor(element.style.backgroundColor);
1382
+ const expected = normalizeCssColor(documentParagraphShadingPresentation(semantic).backgroundColor);
1383
+ if (!background || !expected || background === expected) return semantic;
1384
+ if ('transparent' === background) return {
1385
+ pattern: 'nil'
1386
+ };
1387
+ return paragraphShadingBackgroundUsesForeground(semantic) ? {
1388
+ ...semantic,
1389
+ color: {
1390
+ value: background
1391
+ }
1392
+ } : {
1393
+ ...semantic,
1394
+ fill: {
1395
+ value: background
1396
+ }
1397
+ };
1398
+ }
1399
+ function documentRunShadingDomAttributes(source) {
1400
+ const shading = normalizeDocumentRunShading(source);
1401
+ const serialized = serializeDocumentRunShading(shading);
1402
+ if (!shading || !serialized) return {};
1403
+ const paragraphAttributes = documentParagraphShadingDomAttributes(shading);
1404
+ const style = [
1405
+ paragraphAttributes.style,
1406
+ 'box-decoration-break: clone',
1407
+ '-webkit-box-decoration-break: clone'
1408
+ ].filter(Boolean).join('; ');
1409
+ return {
1410
+ [DOCUMENT_RUN_SHADING_ATTRIBUTE]: serialized,
1411
+ style
1412
+ };
1413
+ }
1414
+ function isRecordWithKeys(source, allowed) {
1415
+ return 'object' == typeof source && null !== source && !Array.isArray(source) && Object.keys(source).every((key)=>allowed.has(key));
1416
+ }
1417
+ const DOCUMENT_SCRIPT_FONTS_ATTRIBUTE = "data-office-script-fonts";
1418
+ const DOCUMENT_SCRIPT_FONT_SLOT_ATTRIBUTE = "data-office-script-font-slot";
1419
+ const MAX_FONT_NAME_LENGTH = 127;
1420
+ const MAX_SERIALIZED_SCRIPT_FONTS_LENGTH = 4096;
1421
+ const SCRIPT_FONT_KEYS = new Set([
1422
+ 'ascii',
1423
+ 'highAnsi',
1424
+ 'eastAsia',
1425
+ 'complexScript',
1426
+ 'hint'
1427
+ ]);
1428
+ const SCRIPT_FONT_FACE_KEYS = new Set([
1429
+ 'name',
1430
+ 'theme',
1431
+ 'resolved'
1432
+ ]);
1433
+ const SCRIPT_FONT_HINTS = new Set([
1434
+ 'default',
1435
+ 'eastAsia',
1436
+ 'cs'
1437
+ ]);
1438
+ const THEME_FONTS = new Set([
1439
+ 'majorEastAsia',
1440
+ 'majorBidi',
1441
+ 'majorAscii',
1442
+ 'majorHAnsi',
1443
+ 'minorEastAsia',
1444
+ 'minorBidi',
1445
+ 'minorAscii',
1446
+ 'minorHAnsi'
1447
+ ]);
1448
+ const SLOT_FALLBACK_ORDER = {
1449
+ ascii: [
1450
+ 'ascii',
1451
+ 'highAnsi',
1452
+ 'eastAsia',
1453
+ 'complexScript'
1454
+ ],
1455
+ highAnsi: [
1456
+ 'highAnsi',
1457
+ 'ascii',
1458
+ 'eastAsia',
1459
+ 'complexScript'
1460
+ ],
1461
+ eastAsia: [
1462
+ 'eastAsia',
1463
+ 'highAnsi',
1464
+ 'ascii',
1465
+ 'complexScript'
1466
+ ],
1467
+ complexScript: [
1468
+ 'complexScript',
1469
+ 'highAnsi',
1470
+ 'ascii',
1471
+ 'eastAsia'
1472
+ ]
1473
+ };
1474
+ const NEUTRAL_SCRIPT_CHARACTER = /^[\p{Cc}\p{Cf}\p{M}\p{N}\p{P}\p{S}\p{Z}]$/u;
1475
+ function normalizeDocumentScriptFonts(source) {
1476
+ if (!work_document_script_fonts_isRecordWithKeys(source, SCRIPT_FONT_KEYS)) return null;
1477
+ const normalized = {};
1478
+ for (const slot of scriptFontSlots){
1479
+ if (void 0 === source[slot]) continue;
1480
+ const face = normalizeDocumentScriptFontFace(source[slot]);
1481
+ if (!face) return null;
1482
+ normalized[slot] = face;
1483
+ }
1484
+ if (void 0 !== source.hint) {
1485
+ const hint = normalizeDocumentScriptFontHint(source.hint);
1486
+ if (!hint) return null;
1487
+ normalized.hint = hint;
1488
+ }
1489
+ return Object.keys(normalized).length ? normalized : null;
1490
+ }
1491
+ function serializeDocumentScriptFonts(source) {
1492
+ const fonts = normalizeDocumentScriptFonts(source);
1493
+ return fonts ? JSON.stringify(fonts) : null;
1494
+ }
1495
+ function parseDocumentScriptFonts(source) {
1496
+ if (!source || source.length > MAX_SERIALIZED_SCRIPT_FONTS_LENGTH) return null;
1497
+ try {
1498
+ return normalizeDocumentScriptFonts(JSON.parse(source));
1499
+ } catch {
1500
+ return null;
1501
+ }
1502
+ }
1503
+ function documentScriptFontsFromElement(element) {
1504
+ return parseDocumentScriptFonts(element.getAttribute(DOCUMENT_SCRIPT_FONTS_ATTRIBUTE));
1505
+ }
1506
+ function documentScriptFontSlotFromElement(element) {
1507
+ return normalizeDocumentScriptFontSlot(element.getAttribute(DOCUMENT_SCRIPT_FONT_SLOT_ATTRIBUTE));
1508
+ }
1509
+ function documentScriptFontsDomAttributes(source, slot) {
1510
+ const fonts = normalizeDocumentScriptFonts(source);
1511
+ const normalizedSlot = normalizeDocumentScriptFontSlot(slot);
1512
+ if (!fonts) return {};
1513
+ const serialized = serializeDocumentScriptFonts(fonts);
1514
+ if (!serialized) return {};
1515
+ const family = documentScriptFontFamily(fonts, normalizedSlot ?? documentScriptFontSlotFromHint(fonts.hint));
1516
+ return {
1517
+ [DOCUMENT_SCRIPT_FONTS_ATTRIBUTE]: serialized,
1518
+ ...normalizedSlot ? {
1519
+ [DOCUMENT_SCRIPT_FONT_SLOT_ATTRIBUTE]: normalizedSlot
1520
+ } : {},
1521
+ ...family ? {
1522
+ style: `font-family: ${family}`
1523
+ } : {}
1524
+ };
1525
+ }
1526
+ function documentScriptFontFamily(source, slot) {
1527
+ const fonts = normalizeDocumentScriptFonts(source);
1528
+ if (!fonts) return;
1529
+ const families = [];
1530
+ const seen = new Set();
1531
+ for (const candidate of documentScriptFontFallbackSlots(slot)){
1532
+ const family = documentScriptFontFaceFamily(fonts[candidate]);
1533
+ const key = family?.toLocaleLowerCase();
1534
+ if (!(!family || !key || seen.has(key))) {
1535
+ seen.add(key);
1536
+ families.push(cssFontFamily(family));
1537
+ }
1538
+ }
1539
+ return families.length ? families.join(', ') : void 0;
1540
+ }
1541
+ function documentScriptFontFallbackSlots(slot) {
1542
+ return SLOT_FALLBACK_ORDER[slot];
1543
+ }
1544
+ function documentScriptFontFamilyForRendering(source, slot, currentFontFamily) {
1545
+ const projected = documentScriptFontFamily(source, slot);
1546
+ const safeCurrent = safeCssFontFamilyList(currentFontFamily);
1547
+ if (!safeCurrent || !projected) return projected;
1548
+ const currentPrimary = documentFontNameFromCssFamily(safeCurrent);
1549
+ const projectedPrimary = documentFontNameFromCssFamily(projected);
1550
+ return currentPrimary && projectedPrimary && currentPrimary.toLocaleLowerCase() === projectedPrimary.toLocaleLowerCase() ? safeCurrent : projected;
1551
+ }
1552
+ function documentScriptFontDirectFamily(source, slot) {
1553
+ const fonts = normalizeDocumentScriptFonts(source);
1554
+ return fonts ? documentScriptFontFaceFamily(fonts[slot]) ?? null : null;
1555
+ }
1556
+ function documentScriptFontsForAllText(fontFamily) {
1557
+ const name = documentFontNameFromCssFamily(fontFamily);
1558
+ if (!name) return null;
1559
+ const face = {
1560
+ name,
1561
+ resolved: name
1562
+ };
1563
+ return {
1564
+ ascii: face,
1565
+ highAnsi: face,
1566
+ eastAsia: face,
1567
+ complexScript: face,
1568
+ hint: 'default'
1569
+ };
1570
+ }
1571
+ function patchDocumentScriptFonts(source, patch, fallbackFontFamily) {
1572
+ const current = normalizeDocumentScriptFonts(source) ?? documentScriptFontsForAllText(fallbackFontFamily) ?? {};
1573
+ const next = {
1574
+ ...current
1575
+ };
1576
+ if (void 0 !== patch.latin) {
1577
+ const face = directFontFace(patch.latin);
1578
+ if (face) {
1579
+ next.ascii = face;
1580
+ next.highAnsi = face;
1581
+ } else {
1582
+ delete next.ascii;
1583
+ delete next.highAnsi;
1584
+ }
1585
+ }
1586
+ if (void 0 !== patch.eastAsia) {
1587
+ const face = directFontFace(patch.eastAsia);
1588
+ if (face) next.eastAsia = face;
1589
+ else delete next.eastAsia;
1590
+ }
1591
+ if (void 0 !== patch.complexScript) {
1592
+ const face = directFontFace(patch.complexScript);
1593
+ if (face) next.complexScript = face;
1594
+ else delete next.complexScript;
1595
+ }
1596
+ return normalizeDocumentScriptFonts(next);
1597
+ }
1598
+ function documentScriptFontSegments(text, hint = 'default', forceComplexScript = false) {
1599
+ if (!text) return [];
1600
+ if (forceComplexScript) return [
1601
+ {
1602
+ from: 0,
1603
+ to: text.length,
1604
+ slot: 'complexScript'
1605
+ }
1606
+ ];
1607
+ const characters = [];
1608
+ let offset = 0;
1609
+ for (const character of text){
1610
+ const from = offset;
1611
+ offset += character.length;
1612
+ characters.push({
1613
+ from,
1614
+ to: offset,
1615
+ slot: strongDocumentScriptFontSlot(character)
1616
+ });
1617
+ }
1618
+ const fallback = documentScriptFontSlotFromHint(hint);
1619
+ let previous = null;
1620
+ for(let index = 0; index < characters.length; index += 1){
1621
+ const entry = characters[index];
1622
+ if (!entry) continue;
1623
+ if (entry.slot) {
1624
+ previous = entry.slot;
1625
+ continue;
1626
+ }
1627
+ let next = previous;
1628
+ if (!next) for(let cursor = index + 1; cursor < characters.length; cursor += 1){
1629
+ const candidate = characters[cursor]?.slot;
1630
+ if (candidate) {
1631
+ next = candidate;
1632
+ break;
1633
+ }
1634
+ }
1635
+ entry.slot = next ?? fallback;
1636
+ }
1637
+ const segments = [];
1638
+ for (const entry of characters){
1639
+ const slot = entry.slot ?? fallback;
1640
+ const prior = segments[segments.length - 1];
1641
+ if (prior?.slot === slot && prior.to === entry.from) prior.to = entry.to;
1642
+ else segments.push({
1643
+ from: entry.from,
1644
+ to: entry.to,
1645
+ slot
1646
+ });
1647
+ }
1648
+ return segments;
1649
+ }
1650
+ function normalizeDocumentScriptFontSlot(value) {
1651
+ return scriptFontSlots.includes(value) ? value : null;
1652
+ }
1653
+ function normalizeDocumentScriptFontHint(value) {
1654
+ return SCRIPT_FONT_HINTS.has(value) ? value : null;
1655
+ }
1656
+ function normalizeDocumentThemeFont(value) {
1657
+ return THEME_FONTS.has(value) ? value : null;
1658
+ }
1659
+ function documentScriptFontSlotFromHint(hint) {
1660
+ if ('eastAsia' === hint) return 'eastAsia';
1661
+ if ('cs' === hint) return 'complexScript';
1662
+ return 'ascii';
1663
+ }
1664
+ function documentFontNameFromCssFamily(value) {
1665
+ if ('string' != typeof value) return null;
1666
+ const source = value.trim();
1667
+ if (!source) return null;
1668
+ let family = '';
1669
+ const quote = source[0];
1670
+ if ('"' === quote || "'" === quote) {
1671
+ let closed = false;
1672
+ for(let index = 1; index < source.length; index += 1){
1673
+ const character = source[index];
1674
+ if (character === quote) {
1675
+ closed = true;
1676
+ break;
1677
+ }
1678
+ if ('\\' !== character) {
1679
+ family += character;
1680
+ continue;
1681
+ }
1682
+ const decoded = decodeCssEscape(source, index + 1);
1683
+ if (!decoded) return null;
1684
+ family += decoded.value;
1685
+ index = decoded.end - 1;
1686
+ }
1687
+ if (!closed) return null;
1688
+ } else family = source.split(',')[0] ?? '';
1689
+ return normalizeDocumentFontName(family);
1690
+ }
1691
+ function cssDocumentFontFamily(value) {
1692
+ const family = normalizeDocumentFontName(value);
1693
+ return family ? cssFontFamily(family) : null;
1694
+ }
1695
+ function normalizeDocumentFontName(value) {
1696
+ if ('string' != typeof value) return null;
1697
+ const normalized = value.trim();
1698
+ return normalized && normalized.length <= MAX_FONT_NAME_LENGTH && !/[\p{Cc}\p{Cs}]/u.test(normalized) ? normalized : null;
1699
+ }
1700
+ const scriptFontSlots = [
1701
+ 'ascii',
1702
+ 'highAnsi',
1703
+ 'eastAsia',
1704
+ 'complexScript'
1705
+ ];
1706
+ function normalizeDocumentScriptFontFace(source) {
1707
+ if (!work_document_script_fonts_isRecordWithKeys(source, SCRIPT_FONT_FACE_KEYS)) return null;
1708
+ const name = void 0 === source.name ? void 0 : normalizeDocumentFontName(source.name);
1709
+ const resolved = void 0 === source.resolved ? void 0 : normalizeDocumentFontName(source.resolved);
1710
+ const theme = void 0 === source.theme ? void 0 : normalizeDocumentThemeFont(source.theme);
1711
+ if (void 0 !== source.name && !name || void 0 !== source.resolved && !resolved || null === theme || !name && !theme && !resolved) return null;
1712
+ return {
1713
+ ...name ? {
1714
+ name
1715
+ } : {},
1716
+ ...theme ? {
1717
+ theme
1718
+ } : {},
1719
+ ...resolved ? {
1720
+ resolved
1721
+ } : {}
1722
+ };
1723
+ }
1724
+ function directFontFace(value) {
1725
+ if (null === value) return null;
1726
+ const name = documentFontNameFromCssFamily(value) ?? normalizeDocumentFontName(value);
1727
+ return name ? {
1728
+ name,
1729
+ resolved: name
1730
+ } : null;
1731
+ }
1732
+ function documentScriptFontFaceFamily(face) {
1733
+ return face?.resolved ?? face?.name;
1734
+ }
1735
+ function strongDocumentScriptFontSlot(character) {
1736
+ if (NEUTRAL_SCRIPT_CHARACTER.test(character)) return null;
1737
+ const codePoint = character.codePointAt(0);
1738
+ if (void 0 === codePoint) return null;
1739
+ if (isComplexScriptCodePoint(codePoint)) return 'complexScript';
1740
+ if (isEastAsianCodePoint(codePoint)) return 'eastAsia';
1741
+ return codePoint <= 0x7f ? 'ascii' : 'highAnsi';
1742
+ }
1743
+ function isComplexScriptCodePoint(codePoint) {
1744
+ return codePoint >= 0x0590 && codePoint <= 0x08ff || codePoint >= 0x0900 && codePoint <= 0x109f || codePoint >= 0x1780 && codePoint <= 0x18af || codePoint >= 0x1900 && codePoint <= 0x1cff || codePoint >= 0xa800 && codePoint <= 0xa8ff || codePoint >= 0xa980 && codePoint <= 0xa9df || codePoint >= 0xaa00 && codePoint <= 0xaa7f || codePoint >= 0xabc0 && codePoint <= 0xabff || codePoint >= 0xfb1d && codePoint <= 0xfdff || codePoint >= 0xfe70 && codePoint <= 0xfeff || codePoint >= 0x10a00 && codePoint <= 0x10fff || codePoint >= 0x11000 && codePoint <= 0x11fff || codePoint >= 0x1e900 && codePoint <= 0x1edff || codePoint >= 0x1ee00 && codePoint <= 0x1eeff;
1745
+ }
1746
+ function isEastAsianCodePoint(codePoint) {
1747
+ return codePoint >= 0x1100 && codePoint <= 0x11ff || codePoint >= 0x2e80 && codePoint <= 0xa4cf || codePoint >= 0xac00 && codePoint <= 0xd7af || codePoint >= 0xf900 && codePoint <= 0xfaff || codePoint >= 0xfe10 && codePoint <= 0xfe6f || codePoint >= 0xff00 && codePoint <= 0xffef || codePoint >= 0x20000 && codePoint <= 0x323af;
1748
+ }
1749
+ function cssFontFamily(value) {
1750
+ return /^(?:-?[\p{L}_])[\p{L}\p{N}_-]*$/u.test(value) ? value : `"${Array.from(value, cssStringCharacter).join('')}"`;
1751
+ }
1752
+ function cssStringCharacter(character) {
1753
+ return /[\\":;{}<>]/u.test(character) ? `\\${character.codePointAt(0)?.toString(16)} ` : character;
1754
+ }
1755
+ function safeCssFontFamilyList(value) {
1756
+ if ('string' != typeof value) return null;
1757
+ const source = value.trim();
1758
+ if (!source || source.length > 1024 || /[;{}]/u.test(source)) return null;
1759
+ const tokens = [];
1760
+ let start = 0;
1761
+ let quote = '';
1762
+ for(let index = 0; index < source.length; index += 1){
1763
+ const character = source[index] ?? '';
1764
+ if (quote) {
1765
+ if ('\\' === character) {
1766
+ index += 1;
1767
+ if (index >= source.length) return null;
1768
+ } else if (character === quote) quote = '';
1769
+ continue;
1770
+ }
1771
+ if ('"' === character || "'" === character) {
1772
+ quote = character;
1773
+ continue;
1774
+ }
1775
+ if (',' === character) {
1776
+ tokens.push(source.slice(start, index).trim());
1777
+ start = index + 1;
1778
+ }
1779
+ }
1780
+ if (quote) return null;
1781
+ tokens.push(source.slice(start).trim());
1782
+ return tokens.length && tokens.every(validCssFontFamilyToken) ? source : null;
1783
+ }
1784
+ function validCssFontFamilyToken(value) {
1785
+ if (!value) return false;
1786
+ if (value.startsWith('"')) return /^"(?:[^"\\\r\n\f]|\\(?:[\da-f]{1,6}\s?|[^\r\n\f]))*"$/iu.test(value) && null !== documentFontNameFromCssFamily(value);
1787
+ if (value.startsWith("'")) return /^'(?:[^'\\\r\n\f]|\\(?:[\da-f]{1,6}\s?|[^\r\n\f]))*'$/iu.test(value) && null !== documentFontNameFromCssFamily(value);
1788
+ return /[\p{L}_]/u.test(value) && /^[\p{L}_-][\p{L}\p{N}_ -]*$/u.test(value) && !/^(?:inherit|initial|revert(?:-layer)?|unset)$/iu.test(value);
1789
+ }
1790
+ function decodeCssEscape(source, start) {
1791
+ if (start >= source.length) return null;
1792
+ const hexadecimal = /^[\da-f]{1,6}/i.exec(source.slice(start))?.[0];
1793
+ if (hexadecimal) {
1794
+ const codePoint = Number.parseInt(hexadecimal, 16);
1795
+ if (0 === codePoint || codePoint > 0x10ffff || codePoint >= 0xd800 && codePoint <= 0xdfff) return null;
1796
+ let end = start + hexadecimal.length;
1797
+ if (/\s/u.test(source[end] ?? '')) end += 1;
1798
+ return {
1799
+ value: String.fromCodePoint(codePoint),
1800
+ end
1801
+ };
1802
+ }
1803
+ const value = source[start];
1804
+ return !value || /[\r\n\f]/u.test(value) ? null : {
1805
+ value,
1806
+ end: start + 1
1807
+ };
1808
+ }
1809
+ function work_document_script_fonts_isRecordWithKeys(value, allowed) {
1810
+ return 'object' == typeof value && null !== value && !Array.isArray(value) && Object.keys(value).every((key)=>allowed.has(key));
1811
+ }
1812
+ const DOCUMENT_PROOFING_LANGUAGES_ATTRIBUTE = 'data-office-proofing-languages';
1813
+ const DOCUMENT_NO_PROOF_ATTRIBUTE = 'data-office-no-proof';
1814
+ const PROOFING_LANGUAGE_KEYS = new Set([
1815
+ 'latin',
1816
+ 'eastAsia',
1817
+ 'bidi'
1818
+ ]);
1819
+ const PROOFING_LANGUAGE_ORDER = [
1820
+ 'latin',
1821
+ 'eastAsia',
1822
+ 'bidi'
1823
+ ];
1824
+ const MAX_LANGUAGE_TAG_LENGTH = 85;
1825
+ const MAX_SERIALIZED_PROOFING_LANGUAGES_BYTES = 384;
1826
+ function normalizeDocumentLanguageTag(source) {
1827
+ if ('string' != typeof source) return null;
1828
+ if (!source || source !== source.trim() || source.length > MAX_LANGUAGE_TAG_LENGTH || /[\p{Cc}\p{Cs}]/u.test(source)) return null;
1829
+ return /^(?:x-none|[a-z0-9]{1,8}(?:-[a-z0-9]{1,8})*)$/iu.test(source) ? source : null;
1830
+ }
1831
+ function normalizeDocumentProofingLanguages(source) {
1832
+ if (!isRecord(source)) return null;
1833
+ const keys = Object.keys(source);
1834
+ if (!keys.length || keys.some((key)=>!PROOFING_LANGUAGE_KEYS.has(key))) return null;
1835
+ const normalized = {};
1836
+ for (const key of PROOFING_LANGUAGE_ORDER){
1837
+ if (void 0 === source[key]) continue;
1838
+ const language = normalizeDocumentLanguageTag(source[key]);
1839
+ if (!language) return null;
1840
+ normalized[key] = language;
1841
+ }
1842
+ return Object.keys(normalized).length ? normalized : null;
1843
+ }
1844
+ function serializeDocumentProofingLanguages(source) {
1845
+ const normalized = normalizeDocumentProofingLanguages(source);
1846
+ if (!normalized) return;
1847
+ const serialized = JSON.stringify(normalized);
1848
+ return serialized.length <= MAX_SERIALIZED_PROOFING_LANGUAGES_BYTES ? serialized : void 0;
1849
+ }
1850
+ function parseDocumentProofingLanguages(source) {
1851
+ if ('string' != typeof source) return normalizeDocumentProofingLanguages(source);
1852
+ if (!source || source.length > MAX_SERIALIZED_PROOFING_LANGUAGES_BYTES) return null;
1853
+ try {
1854
+ const normalized = normalizeDocumentProofingLanguages(JSON.parse(source));
1855
+ return normalized && JSON.stringify(normalized) === source ? normalized : null;
1856
+ } catch {
1857
+ return null;
1858
+ }
1859
+ }
1860
+ function normalizeDocumentNoProof(source) {
1861
+ if (true === source || 'true' === source || '1' === source) return true;
1862
+ if (false === source || 'false' === source || '0' === source) return false;
1863
+ return null;
1864
+ }
1865
+ function documentProofingLanguagesFromElement(element) {
1866
+ return parseDocumentProofingLanguages(element.getAttribute(DOCUMENT_PROOFING_LANGUAGES_ATTRIBUTE));
1867
+ }
1868
+ function documentNoProofFromElement(element) {
1869
+ return normalizeDocumentNoProof(element.getAttribute(DOCUMENT_NO_PROOF_ATTRIBUTE));
1870
+ }
1871
+ function documentProofingLanguageForScript(source, slot) {
1872
+ const languages = normalizeDocumentProofingLanguages(source);
1873
+ if (!languages) return;
1874
+ if ('eastAsia' === slot) return languages.eastAsia ?? languages.latin;
1875
+ if ('complexScript' === slot) return languages.bidi ?? languages.latin;
1876
+ return languages.latin ?? languages.eastAsia ?? languages.bidi;
1877
+ }
1878
+ function documentProofingDomAttributes(languagesSource, noProofSource, slot) {
1879
+ const languages = normalizeDocumentProofingLanguages(languagesSource);
1880
+ const serialized = serializeDocumentProofingLanguages(languages);
1881
+ const noProof = normalizeDocumentNoProof(noProofSource);
1882
+ const language = documentProofingLanguageForScript(languages, slot);
1883
+ return {
1884
+ ...serialized ? {
1885
+ [DOCUMENT_PROOFING_LANGUAGES_ATTRIBUTE]: serialized
1886
+ } : {},
1887
+ ...null === noProof ? {} : {
1888
+ [DOCUMENT_NO_PROOF_ATTRIBUTE]: String(noProof)
1889
+ },
1890
+ ...slot ? {
1891
+ [DOCUMENT_SCRIPT_FONT_SLOT_ATTRIBUTE]: slot
1892
+ } : {},
1893
+ ...language && 'x-none' !== language ? {
1894
+ lang: language
1895
+ } : {},
1896
+ ...true === noProof ? {
1897
+ spellcheck: 'false'
1898
+ } : {}
1899
+ };
1900
+ }
1901
+ function patchDocumentProofingLanguages(source, patch) {
1902
+ const current = normalizeDocumentProofingLanguages(source) ?? {};
1903
+ const next = {
1904
+ ...current
1905
+ };
1906
+ for (const slot of PROOFING_LANGUAGE_ORDER){
1907
+ const value = patch[slot];
1908
+ if (void 0 === value) continue;
1909
+ if (null === value) {
1910
+ delete next[slot];
1911
+ continue;
1912
+ }
1913
+ const language = normalizeDocumentLanguageTag(value);
1914
+ if (!language) return null;
1915
+ next[slot] = language;
1916
+ }
1917
+ return Object.keys(next).length ? next : null;
1918
+ }
1919
+ function isRecord(source) {
1920
+ return 'object' == typeof source && null !== source && !Array.isArray(source);
1921
+ }
1922
+ const DEFAULT_DOCUMENT_INDEX_OPTIONS = {
1923
+ columns: 1,
1924
+ format: 'indented',
1925
+ rightAlignPageNumbers: true,
1926
+ leader: 'dot'
1927
+ };
1928
+ const MAX_DOCUMENT_INDEX_ENTRIES = 512;
1929
+ const MAX_DOCUMENT_INDEX_MARKERS = 2048;
1930
+ const MAX_DOCUMENT_INDEX_TERM_LENGTH = 240;
1931
+ const INDEX_ENTRY_SELECTOR = '[data-document-index-entry]';
1932
+ const INDEX_SELECTOR = '[data-document-index]';
1933
+ const INDEX_ID_PATTERN = /^[a-z0-9][a-z0-9._:-]{0,127}$/i;
1934
+ function normalizeDocumentIndexEntryDraft(source) {
1935
+ const mainEntry = normalizedIndexTerm(source?.mainEntry);
1936
+ if (!mainEntry) return null;
1937
+ const subEntry = normalizedIndexTerm(source?.subEntry);
1938
+ const crossReference = normalizedIndexTerm(source?.crossReference);
1939
+ return {
1940
+ mainEntry,
1941
+ subEntry,
1942
+ crossReference,
1943
+ pageBold: !crossReference && Boolean(source?.pageBold),
1944
+ pageItalic: !crossReference && Boolean(source?.pageItalic)
1945
+ };
1946
+ }
1947
+ function normalizeDocumentIndexEntry(source, fallbackId = 'index-entry') {
1948
+ const value = normalizeDocumentIndexEntryDraft(source);
1949
+ if (!value) return null;
1950
+ return {
1951
+ id: validIndexId(source?.id) ?? fallbackId,
1952
+ ...value
1953
+ };
1954
+ }
1955
+ function normalizeDocumentIndexOptions(source) {
1956
+ return {
1957
+ columns: boundedColumns(source?.columns),
1958
+ format: source?.format === 'run-in' ? 'run-in' : 'indented',
1959
+ rightAlignPageNumbers: source?.rightAlignPageNumbers !== false,
1960
+ leader: indexLeader(source?.leader) ?? 'dot'
1961
+ };
1962
+ }
1963
+ function normalizeDocumentIndexValue(source) {
1964
+ return {
1965
+ id: validIndexId(source.id) ?? 'document-index',
1966
+ options: normalizeDocumentIndexOptions(source.options),
1967
+ entries: normalizeGeneratedEntries(source.entries),
1968
+ truncated: Boolean(source.truncated)
1969
+ };
1970
+ }
1971
+ function buildDocumentIndexEntries(document, options = {}) {
1972
+ const grouped = new Map();
1973
+ let markerCount = 0;
1974
+ document.descendants((node, position)=>{
1975
+ if ('documentIndexEntry' !== node.type.name) return;
1976
+ markerCount += 1;
1977
+ if (markerCount > MAX_DOCUMENT_INDEX_MARKERS) return;
1978
+ const marker = normalizeDocumentIndexEntry(node.attrs, `index-entry-${markerCount}`);
1979
+ if (!marker) return;
1980
+ const key = indexEntryKey(marker);
1981
+ let group = grouped.get(key);
1982
+ if (!group) {
1983
+ group = {
1984
+ entry: {
1985
+ mainEntry: marker.mainEntry,
1986
+ subEntry: marker.subEntry,
1987
+ crossReference: marker.crossReference,
1988
+ pages: []
1989
+ },
1990
+ pages: new Map()
1991
+ };
1992
+ grouped.set(key, group);
1993
+ }
1994
+ if (marker.crossReference) return;
1995
+ const pageNumber = positiveInteger(options.resolveContext?.(position)?.pageNumber) ?? fallbackDocumentPageNumber(document, position);
1996
+ const existing = group.pages.get(pageNumber);
1997
+ if (existing) {
1998
+ existing.pageBold ||= marker.pageBold;
1999
+ existing.pageItalic ||= marker.pageItalic;
2000
+ if (!existing.targetIds.includes(marker.id)) existing.targetIds.push(marker.id);
2001
+ return;
2002
+ }
2003
+ group.pages.set(pageNumber, {
2004
+ pageNumber,
2005
+ pageBold: marker.pageBold,
2006
+ pageItalic: marker.pageItalic,
2007
+ targetIds: [
2008
+ marker.id
2009
+ ]
2010
+ });
2011
+ });
2012
+ const collator = new Intl.Collator(void 0, {
2013
+ numeric: true,
2014
+ sensitivity: 'base',
2015
+ usage: 'sort'
2016
+ });
2017
+ const allEntries = Array.from(grouped.values()).map(({ entry, pages })=>({
2018
+ ...entry,
2019
+ pages: Array.from(pages.values()).sort((left, right)=>left.pageNumber - right.pageNumber)
2020
+ })).sort((left, right)=>collator.compare(left.mainEntry, right.mainEntry) || collator.compare(left.subEntry, right.subEntry) || collator.compare(left.crossReference, right.crossReference));
2021
+ return {
2022
+ entries: allEntries.slice(0, MAX_DOCUMENT_INDEX_ENTRIES),
2023
+ truncated: markerCount > MAX_DOCUMENT_INDEX_MARKERS || allEntries.length > MAX_DOCUMENT_INDEX_ENTRIES
2024
+ };
2025
+ }
2026
+ function documentIndexEntryHtml(source) {
2027
+ const value = normalizeDocumentIndexEntry(source);
2028
+ if (!value) return '';
2029
+ const detail = indexEntryDisplay(value);
2030
+ return [
2031
+ `<span data-document-index-entry="true" data-index-entry-id="${escapeHtmlAttribute(value.id)}" data-index-main-entry="${escapeHtmlAttribute(value.mainEntry)}" data-index-sub-entry="${escapeHtmlAttribute(value.subEntry)}" data-index-cross-reference="${escapeHtmlAttribute(value.crossReference)}" data-index-page-bold="${String(value.pageBold)}" data-index-page-italic="${String(value.pageItalic)}" class="work-document-index-entry" contenteditable="false" aria-label="索引项:${escapeHtmlAttribute(detail)}">`,
2032
+ '<span aria-hidden="true">索引项</span>',
2033
+ `<strong>${escapeHtml(detail)}</strong>`,
2034
+ '</span>'
2035
+ ].join('');
2036
+ }
2037
+ function documentIndexHtml(source) {
2038
+ const value = normalizeDocumentIndexValue(source);
2039
+ const rows = value.entries.length ? value.entries.map(documentIndexRowHtml) : [
2040
+ '<li class="work-document-index-empty">没有已标记的索引项</li>'
2041
+ ];
2042
+ const status = value.truncated ? `仅显示前 ${MAX_DOCUMENT_INDEX_ENTRIES} 项` : `${value.entries.length} 项`;
2043
+ return [
2044
+ `<div data-document-index="true" data-index-id="${escapeHtmlAttribute(value.id)}" data-index-columns="${value.options.columns}" data-index-format="${value.options.format}" data-index-right-align-page-numbers="${String(value.options.rightAlignPageNumbers)}" data-index-leader="${value.options.leader}" data-index-entries="${escapeHtmlAttribute(JSON.stringify(value.entries))}" data-index-truncated="${String(value.truncated)}" class="work-document-index" contenteditable="false" aria-label="索引">`,
2045
+ `<div class="work-document-index-header"><strong>索引</strong><span>${status}</span></div>`,
2046
+ '<ol class="work-document-index-list">',
2047
+ ...rows,
2048
+ '</ol></div>'
2049
+ ].join('');
2050
+ }
2051
+ function documentIndexEntryFromElement(element, index = 1) {
2052
+ return normalizeDocumentIndexEntry({
2053
+ id: element.dataset.indexEntryId,
2054
+ mainEntry: element.dataset.indexMainEntry,
2055
+ subEntry: element.dataset.indexSubEntry,
2056
+ crossReference: element.dataset.indexCrossReference,
2057
+ pageBold: 'true' === element.dataset.indexPageBold,
2058
+ pageItalic: 'true' === element.dataset.indexPageItalic
2059
+ }, `index-entry-${index}`);
2060
+ }
2061
+ function documentIndexValueFromElement(element, index = 1) {
2062
+ return normalizeDocumentIndexValue({
2063
+ id: validIndexId(element.dataset.indexId) ?? `document-index-${index}`,
2064
+ options: {
2065
+ columns: Number(element.dataset.indexColumns),
2066
+ format: 'run-in' === element.dataset.indexFormat ? 'run-in' : 'indented',
2067
+ rightAlignPageNumbers: 'false' !== element.dataset.indexRightAlignPageNumbers,
2068
+ leader: indexLeader(element.dataset.indexLeader) ?? 'dot'
2069
+ },
2070
+ entries: parseGeneratedEntries(element.dataset.indexEntries),
2071
+ truncated: 'true' === element.dataset.indexTruncated
2072
+ });
2073
+ }
2074
+ function normalizeDocumentIndexesHtml(source) {
2075
+ const document = new DOMParser().parseFromString(source, 'text/html');
2076
+ const usedEntryIds = new Set();
2077
+ for (const [index, element] of Array.from(document.body.querySelectorAll(INDEX_ENTRY_SELECTOR)).entries()){
2078
+ const value = documentIndexEntryFromElement(element, index + 1);
2079
+ if (!value) {
2080
+ element.remove();
2081
+ continue;
2082
+ }
2083
+ value.id = uniqueIndexId(value.id, 'index-entry', index + 1, usedEntryIds);
2084
+ element.replaceWith(document.createRange().createContextualFragment(documentIndexEntryHtml(value)));
2085
+ }
2086
+ const usedIndexIds = new Set();
2087
+ for (const [index, element] of Array.from(document.body.querySelectorAll(INDEX_SELECTOR)).entries()){
2088
+ const value = documentIndexValueFromElement(element, index + 1);
2089
+ value.id = uniqueIndexId(value.id, 'document-index', index + 1, usedIndexIds);
2090
+ element.replaceWith(document.createRange().createContextualFragment(documentIndexHtml(value)));
2091
+ }
2092
+ return document.body.innerHTML;
2093
+ }
2094
+ function indexLeader(value) {
2095
+ return 'dot' === value || 'dash' === value || 'underline' === value || 'none' === value ? value : null;
2096
+ }
2097
+ function documentIndexRowHtml(entry) {
2098
+ const term = entry.subEntry ? `<span class="work-document-index-main">${escapeHtml(entry.mainEntry)}</span><span class="work-document-index-sub">${escapeHtml(entry.subEntry)}</span>` : `<span class="work-document-index-main">${escapeHtml(entry.mainEntry)}</span>`;
2099
+ const pages = entry.crossReference ? `<span class="work-document-index-cross-reference">参见 ${escapeHtml(entry.crossReference)}</span>` : entry.pages.map((page)=>{
2100
+ const target = page.targetIds[0] ?? '';
2101
+ const classes = [
2102
+ page.pageBold ? 'bold' : '',
2103
+ page.pageItalic ? 'italic' : ''
2104
+ ].filter(Boolean).join(' ');
2105
+ return `<a href="#${escapeHtmlAttribute(target)}" data-index-target="${escapeHtmlAttribute(target)}" tabindex="-1"${classes ? ` class="${classes}"` : ''}>${page.pageNumber}</a>`;
2106
+ }).join('<span aria-hidden="true">, </span>');
2107
+ return `<li data-index-main-entry="${escapeHtmlAttribute(entry.mainEntry)}" data-index-sub-entry="${escapeHtmlAttribute(entry.subEntry)}">${term}<i aria-hidden="true"></i><span class="work-document-index-pages">${pages}</span></li>`;
2108
+ }
2109
+ function normalizeGeneratedEntries(source) {
2110
+ const entries = [];
2111
+ for (const item of source.slice(0, MAX_DOCUMENT_INDEX_ENTRIES)){
2112
+ if (!item || 'object' != typeof item) continue;
2113
+ const candidate = item;
2114
+ const draft = normalizeDocumentIndexEntryDraft({
2115
+ mainEntry: normalizedIndexTerm(candidate.mainEntry),
2116
+ subEntry: normalizedIndexTerm(candidate.subEntry),
2117
+ crossReference: normalizedIndexTerm(candidate.crossReference)
2118
+ });
2119
+ if (draft) entries.push({
2120
+ mainEntry: draft.mainEntry,
2121
+ subEntry: draft.subEntry,
2122
+ crossReference: draft.crossReference,
2123
+ pages: draft.crossReference ? [] : normalizeIndexPages(candidate.pages)
2124
+ });
2125
+ }
2126
+ return entries;
2127
+ }
2128
+ function normalizeIndexPages(source) {
2129
+ if (!Array.isArray(source)) return [];
2130
+ const pages = [];
2131
+ const seen = new Set();
2132
+ for (const item of source.slice(0, MAX_DOCUMENT_INDEX_MARKERS)){
2133
+ if (!item || 'object' != typeof item) continue;
2134
+ const candidate = item;
2135
+ const pageNumber = positiveInteger(candidate.pageNumber);
2136
+ if (!pageNumber || seen.has(pageNumber)) continue;
2137
+ const targetIds = Array.isArray(candidate.targetIds) ? candidate.targetIds.flatMap((value)=>validIndexId(value) ? [
2138
+ String(value)
2139
+ ] : []).slice(0, 64) : [];
2140
+ if (targetIds.length) {
2141
+ seen.add(pageNumber);
2142
+ pages.push({
2143
+ pageNumber,
2144
+ pageBold: Boolean(candidate.pageBold),
2145
+ pageItalic: Boolean(candidate.pageItalic),
2146
+ targetIds
2147
+ });
2148
+ }
2149
+ }
2150
+ return pages.sort((left, right)=>left.pageNumber - right.pageNumber);
2151
+ }
2152
+ function parseGeneratedEntries(source) {
2153
+ if (!source) return [];
2154
+ try {
2155
+ const parsed = JSON.parse(source);
2156
+ return Array.isArray(parsed) ? normalizeGeneratedEntries(parsed) : [];
2157
+ } catch {
2158
+ return [];
2159
+ }
2160
+ }
2161
+ function fallbackDocumentPageNumber(document, position) {
2162
+ let pageNumber = 1;
2163
+ document.descendants((node, offset)=>{
2164
+ if (offset >= position) return false;
2165
+ if ('pageBreak' === node.type.name) pageNumber += 1;
2166
+ return true;
2167
+ });
2168
+ return pageNumber;
2169
+ }
2170
+ function indexEntryKey(entry) {
2171
+ return [
2172
+ entry.mainEntry,
2173
+ entry.subEntry,
2174
+ entry.crossReference
2175
+ ].map((value)=>value.normalize('NFKC').toLocaleLowerCase()).join('\u0000');
2176
+ }
2177
+ function indexEntryDisplay(entry) {
2178
+ const term = entry.subEntry ? `${entry.mainEntry} › ${entry.subEntry}` : entry.mainEntry;
2179
+ return entry.crossReference ? `${term} · 参见 ${entry.crossReference}` : term;
2180
+ }
2181
+ function normalizedIndexTerm(value) {
2182
+ return 'string' == typeof value ? value.replace(/\s+/g, ' ').trim().slice(0, MAX_DOCUMENT_INDEX_TERM_LENGTH) : '';
2183
+ }
2184
+ function boundedColumns(value) {
2185
+ const number = Number(value);
2186
+ return Number.isInteger(number) && number >= 1 && number <= 4 ? number : 1;
2187
+ }
2188
+ function positiveInteger(value) {
2189
+ const number = Number(value);
2190
+ return Number.isSafeInteger(number) && number > 0 ? Math.min(999999, number) : null;
2191
+ }
2192
+ function validIndexId(value) {
2193
+ return 'string' == typeof value && INDEX_ID_PATTERN.test(value) ? value : null;
2194
+ }
2195
+ function uniqueIndexId(source, prefix, index, used) {
2196
+ if (!used.has(source)) {
2197
+ used.add(source);
2198
+ return source;
2199
+ }
2200
+ let suffix = index;
2201
+ while(used.has(`${prefix}-${suffix}`))suffix += 1;
2202
+ const id = `${prefix}-${suffix}`;
2203
+ used.add(id);
2204
+ return id;
2205
+ }
2206
+ function escapeHtml(value) {
2207
+ return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
2208
+ }
2209
+ function escapeHtmlAttribute(value) {
2210
+ return escapeHtml(value).replaceAll('"', '&quot;').replaceAll("'", '&#39;');
2211
+ }
2212
+ const DOCUMENT_PARAGRAPH_ID_ATTRIBUTE = 'data-office-paragraph-id';
2213
+ const DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE = 'data-office-paragraph-text-id';
2214
+ const PARAGRAPH_ID_PATTERN = /^[0-9A-F]{8}$/;
2215
+ const MAX_PARAGRAPH_ID = 0x7fffffff;
2216
+ let fallbackIdentitySequence = 0;
2217
+ const DocumentParagraphIdentity = Extension.create({
2218
+ name: 'documentParagraphIdentity',
2219
+ addOptions () {
2220
+ return {
2221
+ rotateTextId: ()=>true,
2222
+ types: [
2223
+ 'paragraph',
2224
+ 'heading',
2225
+ 'documentCaption'
2226
+ ]
2227
+ };
2228
+ },
2229
+ addGlobalAttributes () {
2230
+ return [
2231
+ {
2232
+ types: this.options.types,
2233
+ attributes: {
2234
+ paragraphId: {
2235
+ default: null,
2236
+ parseHTML: (element)=>normalizeDocumentParagraphId(element.getAttribute(DOCUMENT_PARAGRAPH_ID_ATTRIBUTE)),
2237
+ renderHTML: (attributes)=>{
2238
+ const value = normalizeDocumentParagraphId(attributes.paragraphId);
2239
+ return value ? {
2240
+ [DOCUMENT_PARAGRAPH_ID_ATTRIBUTE]: value
2241
+ } : {};
2242
+ }
2243
+ },
2244
+ textId: {
2245
+ default: null,
2246
+ parseHTML: (element)=>normalizeDocumentParagraphId(element.getAttribute(DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE)),
2247
+ renderHTML: (attributes)=>{
2248
+ const value = normalizeDocumentParagraphId(attributes.textId);
2249
+ return value ? {
2250
+ [DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE]: value
2251
+ } : {};
2252
+ }
2253
+ }
2254
+ }
2255
+ }
2256
+ ];
2257
+ },
2258
+ addProseMirrorPlugins () {
2259
+ return [
2260
+ createDocumentParagraphIdentityPlugin(this.options.types, this.options.rotateTextId)
2261
+ ];
2262
+ }
2263
+ });
2264
+ function normalizeDocumentParagraphId(value) {
2265
+ if ('string' != typeof value) return null;
2266
+ const normalized = value.trim().toUpperCase();
2267
+ if (!PARAGRAPH_ID_PATTERN.test(normalized)) return null;
2268
+ const number = Number.parseInt(normalized, 16);
2269
+ return number > 0 && number <= MAX_PARAGRAPH_ID ? normalized : null;
2270
+ }
2271
+ function createDocumentParagraphIdentityRegistry() {
2272
+ return {
2273
+ paragraphIds: new Set()
2274
+ };
2275
+ }
2276
+ function normalizeDocumentParagraphIdentity(source) {
2277
+ const paragraphId = normalizeDocumentParagraphId(source.paragraphId);
2278
+ const textId = normalizeDocumentParagraphId(source.textId);
2279
+ return paragraphId && textId ? {
2280
+ paragraphId,
2281
+ textId
2282
+ } : null;
2283
+ }
2284
+ function documentParagraphIdentityFromElement(element) {
2285
+ return normalizeDocumentParagraphIdentity({
2286
+ paragraphId: element.getAttribute(DOCUMENT_PARAGRAPH_ID_ATTRIBUTE),
2287
+ textId: element.getAttribute(DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE)
2288
+ });
2289
+ }
2290
+ function applyDocumentParagraphIdentityToElement(element, source) {
2291
+ const identity = normalizeDocumentParagraphIdentity(source);
2292
+ if (!identity) {
2293
+ element.removeAttribute(DOCUMENT_PARAGRAPH_ID_ATTRIBUTE);
2294
+ element.removeAttribute(DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE);
2295
+ return null;
2296
+ }
2297
+ element.setAttribute(DOCUMENT_PARAGRAPH_ID_ATTRIBUTE, identity.paragraphId);
2298
+ element.setAttribute(DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE, identity.textId);
2299
+ return identity;
2300
+ }
2301
+ function createDocumentParagraphIdentityPlugin(types, rotateTextId) {
2302
+ const trackedTypes = new Set(types);
2303
+ return new Plugin({
2304
+ view (view) {
2305
+ const transaction = normalizeDocumentParagraphIdentities(view.state, trackedTypes, rotateTextId);
2306
+ if (transaction) {
2307
+ transaction.setMeta('addToHistory', false);
2308
+ view.dispatch(transaction);
2309
+ }
2310
+ return {};
2311
+ },
2312
+ appendTransaction (transactions, oldState, newState) {
2313
+ if (!transactions.some((transaction)=>transaction.docChanged)) return null;
2314
+ return normalizeDocumentParagraphIdentities(newState, trackedTypes, rotateTextId, oldState, transactions);
2315
+ }
2316
+ });
2317
+ }
2318
+ function normalizeDocumentParagraphIdentities(state, trackedTypes, rotateTextId, oldState, transactions = []) {
2319
+ if (!documentHasIntegrityFeature(state.doc, 16)) return null;
2320
+ const paragraphs = documentParagraphs(state.doc, trackedTypes);
2321
+ if (!paragraphs.length) return null;
2322
+ const retainedPositions = oldState ? retainedDocumentParagraphPositions(oldState, state, transactions, trackedTypes) : new Set();
2323
+ const editedPositions = oldState && rotateTextId() && !transactions.some(isHistoryTransaction) ? editedDocumentParagraphPositions(oldState, state, transactions, trackedTypes) : new Set();
2324
+ const ordered = [
2325
+ ...paragraphs.filter((item)=>retainedPositions.has(item.position)),
2326
+ ...paragraphs.filter((item)=>!retainedPositions.has(item.position))
2327
+ ];
2328
+ const registry = createDocumentParagraphIdentityRegistry();
2329
+ const updates = new Map();
2330
+ for (const paragraph of ordered){
2331
+ const current = paragraphIdentitySourceFromNode(paragraph.node);
2332
+ const source = editedPositions.has(paragraph.position) ? {
2333
+ ...current,
2334
+ textId: nextDocumentParagraphTextId(current.textId)
2335
+ } : current;
2336
+ const identity = uniqueDocumentParagraphIdentity(source, registry);
2337
+ if (!sameDocumentParagraphIdentity(current, identity)) updates.set(paragraph.position, identity);
2338
+ }
2339
+ if (!updates.size) return null;
2340
+ const transaction = state.tr;
2341
+ for (const paragraph of paragraphs){
2342
+ const identity = updates.get(paragraph.position);
2343
+ if (identity) transaction.setNodeMarkup(paragraph.position, void 0, {
2344
+ ...paragraph.node.attrs,
2345
+ ...identity
2346
+ });
2347
+ }
2348
+ if (!transaction.docChanged) return null;
2349
+ transaction.setMeta('addToHistory', false);
2350
+ return transaction;
2351
+ }
2352
+ function hasDocumentParagraphIdentityComponent(node) {
2353
+ return Boolean(normalizeDocumentParagraphId(node.attrs.paragraphId) || normalizeDocumentParagraphId(node.attrs.textId));
2354
+ }
2355
+ function retainedDocumentParagraphPositions(oldState, newState, transactions, trackedTypes) {
2356
+ const mapping = transactionMapping(transactions);
2357
+ const retained = new Set();
2358
+ for (const previous of documentParagraphs(oldState.doc, trackedTypes)){
2359
+ const paragraphId = normalizeDocumentParagraphId(previous.node.attrs.paragraphId);
2360
+ if (!paragraphId) continue;
2361
+ const mapped = mapping.mapResult(previous.position, 1);
2362
+ const current = newState.doc.nodeAt(mapped.pos);
2363
+ if (current && trackedTypes.has(current.type.name) && normalizeDocumentParagraphId(current.attrs.paragraphId) === paragraphId) retained.add(mapped.pos);
2364
+ }
2365
+ return retained;
2366
+ }
2367
+ function editedDocumentParagraphPositions(oldState, newState, transactions, trackedTypes) {
2368
+ const mapping = transactionMapping(transactions);
2369
+ const previousParagraphs = documentParagraphs(oldState.doc, trackedTypes);
2370
+ const currentParagraphs = documentParagraphs(newState.doc, trackedTypes);
2371
+ const previousById = paragraphsById(previousParagraphs);
2372
+ const currentById = paragraphsById(currentParagraphs);
2373
+ const edited = new Set();
2374
+ for (const previous of previousParagraphs){
2375
+ const identity = normalizeDocumentParagraphIdentity(paragraphIdentitySourceFromNode(previous.node));
2376
+ if (!identity) continue;
2377
+ const mapped = mapping.mapResult(previous.position, 1);
2378
+ const current = newState.doc.nodeAt(mapped.pos);
2379
+ if (current && trackedTypes.has(current.type.name) && normalizeDocumentParagraphId(current.attrs.paragraphId) === identity.paragraphId) {
2380
+ if (paragraphTextChanged(previous.node, current, identity.textId)) edited.add(mapped.pos);
2381
+ continue;
2382
+ }
2383
+ const previousMatches = previousById.get(identity.paragraphId) ?? [];
2384
+ const currentMatches = currentById.get(identity.paragraphId) ?? [];
2385
+ if (1 === previousMatches.length && 1 === currentMatches.length && paragraphTextChanged(previous.node, currentMatches[0].node, identity.textId)) edited.add(currentMatches[0].position);
2386
+ }
2387
+ return edited;
2388
+ }
2389
+ function paragraphTextChanged(previous, current, previousTextId) {
2390
+ return previous.textContent !== current.textContent && normalizeDocumentParagraphId(current.attrs.textId) === previousTextId;
2391
+ }
2392
+ function paragraphsById(paragraphs) {
2393
+ const result = new Map();
2394
+ for (const paragraph of paragraphs){
2395
+ const id = normalizeDocumentParagraphId(paragraph.node.attrs.paragraphId);
2396
+ if (!id) continue;
2397
+ const matches = result.get(id) ?? [];
2398
+ matches.push(paragraph);
2399
+ result.set(id, matches);
2400
+ }
2401
+ return result;
2402
+ }
2403
+ function documentParagraphs(document, trackedTypes) {
2404
+ const paragraphs = [];
2405
+ document.descendants((node, position)=>{
2406
+ if (trackedTypes.has(node.type.name) && hasDocumentParagraphIdentityComponent(node)) paragraphs.push({
2407
+ node,
2408
+ position
2409
+ });
2410
+ });
2411
+ return paragraphs;
2412
+ }
2413
+ function paragraphIdentitySourceFromNode(node) {
2414
+ return {
2415
+ paragraphId: node.attrs.paragraphId,
2416
+ textId: node.attrs.textId
2417
+ };
2418
+ }
2419
+ function uniqueDocumentParagraphIdentity(source, registry) {
2420
+ const preferred = normalizeDocumentParagraphIdentity(source);
2421
+ if (preferred && !registry.paragraphIds.has(preferred.paragraphId)) {
2422
+ registry.paragraphIds.add(preferred.paragraphId);
2423
+ return preferred;
2424
+ }
2425
+ for(let attempt = 0; attempt < 8; attempt += 1){
2426
+ const identity = createDocumentParagraphIdentity();
2427
+ if (!registry.paragraphIds.has(identity.paragraphId)) {
2428
+ registry.paragraphIds.add(identity.paragraphId);
2429
+ return identity;
2430
+ }
2431
+ }
2432
+ return sequentialDocumentParagraphIdentity(registry);
2433
+ }
2434
+ function createDocumentParagraphIdentity() {
2435
+ return {
2436
+ paragraphId: randomDocumentParagraphId(),
2437
+ textId: randomDocumentParagraphId()
2438
+ };
2439
+ }
2440
+ function sequentialDocumentParagraphIdentity(registry) {
2441
+ for(let value = 1; value <= MAX_PARAGRAPH_ID; value += 1){
2442
+ const paragraphId = formatDocumentParagraphId(value);
2443
+ if (!registry.paragraphIds.has(paragraphId)) {
2444
+ registry.paragraphIds.add(paragraphId);
2445
+ return {
2446
+ paragraphId,
2447
+ textId: randomDocumentParagraphId()
2448
+ };
2449
+ }
2450
+ }
2451
+ throw new Error('No unique Word paragraph identity is available.');
2452
+ }
2453
+ function nextDocumentParagraphTextId(value) {
2454
+ const current = normalizeDocumentParagraphId(value);
2455
+ if (!current) return randomDocumentParagraphId();
2456
+ const number = Number.parseInt(current, 16);
2457
+ return formatDocumentParagraphId(number >= MAX_PARAGRAPH_ID ? 1 : number + 1);
2458
+ }
2459
+ function randomDocumentParagraphId() {
2460
+ let value = 0;
2461
+ const cryptoApi = globalThis.crypto;
2462
+ if ('function' == typeof cryptoApi?.getRandomValues) {
2463
+ const values = new Uint32Array(1);
2464
+ cryptoApi.getRandomValues(values);
2465
+ value = values[0] ?? 0;
2466
+ } else if ('function' == typeof cryptoApi?.randomUUID) value = Number.parseInt(cryptoApi.randomUUID().replaceAll('-', '').slice(0, 8), 16);
2467
+ if (!value) {
2468
+ fallbackIdentitySequence += 1;
2469
+ value = stableIdentityHash(`${Date.now()}:${Math.random()}:${fallbackIdentitySequence}`);
2470
+ }
2471
+ return formatDocumentParagraphId(value || fallbackIdentitySequence || 1);
2472
+ }
2473
+ function stableIdentityHash(value) {
2474
+ let hash = 0x811c9dc5;
2475
+ for(let index = 0; index < value.length; index += 1){
2476
+ hash ^= value.charCodeAt(index);
2477
+ hash = Math.imul(hash, 0x01000193);
2478
+ }
2479
+ return hash >>> 0 || 1;
2480
+ }
2481
+ function formatDocumentParagraphId(value) {
2482
+ return (value >>> 0 & MAX_PARAGRAPH_ID || 1).toString(16).toUpperCase().padStart(8, '0');
2483
+ }
2484
+ function sameDocumentParagraphIdentity(source, identity) {
2485
+ return normalizeDocumentParagraphId(source.paragraphId) === identity.paragraphId && normalizeDocumentParagraphId(source.textId) === identity.textId;
2486
+ }
2487
+ function transactionMapping(transactions) {
2488
+ const mapping = new Mapping();
2489
+ for (const transaction of transactions)mapping.appendMapping(transaction.mapping);
2490
+ return mapping;
2491
+ }
2492
+ function collectWorkDocumentOutline(document) {
2493
+ const items = [];
2494
+ const hierarchy = [];
2495
+ document.descendants((node, position)=>{
2496
+ const level = workDocumentOutlineLevel(node);
2497
+ if (null === level) return;
2498
+ while((hierarchy.at(-1)?.level ?? 0) >= level)hierarchy.pop();
2499
+ const parent = hierarchy.at(-1);
2500
+ const from = position + 1;
2501
+ const paragraphId = normalizeDocumentParagraphId(node.attrs.paragraphId);
2502
+ const item = {
2503
+ id: paragraphId ? `heading-${paragraphId.toLowerCase()}` : `heading-${position}`,
2504
+ text: normalizedDocumentHeadingText(node.textContent),
2505
+ level,
2506
+ depth: hierarchy.length,
2507
+ from,
2508
+ to: from + node.content.size,
2509
+ ...parent ? {
2510
+ parentId: parent.id
2511
+ } : {}
2512
+ };
2513
+ items.push(item);
2514
+ hierarchy.push(item);
2515
+ });
2516
+ return items.map((item, index)=>({
2517
+ ...item,
2518
+ hasChildren: (items[index + 1]?.depth ?? -1) > item.depth
2519
+ }));
2520
+ }
2521
+ function workDocumentOutlineLevel(node) {
2522
+ if ('heading' === node.type.name) return documentHeadingLevel(node.attrs.level);
2523
+ if ('paragraph' !== node.type.name) return null;
2524
+ const value = node.attrs.outlineLevel;
2525
+ if (null == value || '' === value) return null;
2526
+ const outlineLevel = Number(value);
2527
+ return Number.isInteger(outlineLevel) && outlineLevel >= 0 && outlineLevel <= 8 ? outlineLevel + 1 : null;
2528
+ }
2529
+ function currentWorkDocumentOutlineItem(items, position) {
2530
+ let current = null;
2531
+ for (const item of items){
2532
+ if (item.from > position) break;
2533
+ current = item;
2534
+ }
2535
+ return current;
2536
+ }
2537
+ function visibleWorkDocumentOutlineItems(items, collapsedIds, rawQuery) {
2538
+ const query = normalizedDocumentOutlineQuery(rawQuery);
2539
+ if (query) return items.filter((item)=>normalizedDocumentOutlineQuery(item.text).includes(query));
2540
+ const visible = [];
2541
+ let hiddenBelowDepth = null;
2542
+ for (const item of items){
2543
+ if (null !== hiddenBelowDepth && item.depth <= hiddenBelowDepth) hiddenBelowDepth = null;
2544
+ if (null === hiddenBelowDepth) {
2545
+ visible.push(item);
2546
+ if (item.hasChildren && collapsedIds.has(item.id)) hiddenBelowDepth = item.depth;
2547
+ }
2548
+ }
2549
+ return visible;
2550
+ }
2551
+ function documentHeadingLevel(value) {
2552
+ return 'number' == typeof value && Number.isInteger(value) && value >= 1 && value <= 6 ? value : 1;
2553
+ }
2554
+ function normalizedDocumentHeadingText(value) {
2555
+ return value.replace(/\s+/g, ' ').trim() || '未命名标题';
2556
+ }
2557
+ function normalizedDocumentOutlineQuery(value) {
2558
+ return value.normalize('NFKC').trim().toLocaleLowerCase();
2559
+ }
2560
+ const DEFAULT_DOCUMENT_TABLE_OF_CONTENTS_OPTIONS = {
2561
+ minLevel: 1,
2562
+ maxLevel: 3,
2563
+ hyperlinks: true,
2564
+ showPageNumbers: true,
2565
+ rightAlignPageNumbers: true,
2566
+ leader: 'dot'
2567
+ };
2568
+ const MAX_DOCUMENT_TABLE_OF_CONTENTS_ENTRIES = 512;
2569
+ const TABLE_OF_CONTENTS_SELECTOR = '[data-document-table-of-contents]';
2570
+ const MAX_TABLE_OF_CONTENTS_TITLE_LENGTH = 512;
2571
+ const TABLE_OF_CONTENTS_ID_PATTERN = /^[a-z0-9][a-z0-9._:-]{0,127}$/i;
2572
+ const TABLE_OF_CONTENTS_TARGET_PATTERN = /^heading-[a-z0-9._:-]{1,128}$/i;
2573
+ function normalizeDocumentTableOfContentsOptions(source) {
2574
+ const minLevel = boundedLevel(source?.minLevel, 1);
2575
+ const maxLevel = Math.max(minLevel, boundedLevel(source?.maxLevel, Math.max(3, minLevel)));
2576
+ const showPageNumbers = source?.showPageNumbers !== false;
2577
+ return {
2578
+ minLevel,
2579
+ maxLevel,
2580
+ hyperlinks: source?.hyperlinks !== false,
2581
+ showPageNumbers,
2582
+ rightAlignPageNumbers: showPageNumbers && source?.rightAlignPageNumbers !== false,
2583
+ leader: tableOfContentsLeader(source?.leader) ?? 'dot'
2584
+ };
2585
+ }
2586
+ function buildDocumentTableOfContentsEntries(document, options, buildOptions = {}) {
2587
+ const normalized = normalizeDocumentTableOfContentsOptions(options);
2588
+ const outline = collectWorkDocumentOutline(document).filter((item)=>item.text.length > 0 && item.level >= normalized.minLevel && item.level <= normalized.maxLevel);
2589
+ const entries = outline.slice(0, MAX_DOCUMENT_TABLE_OF_CONTENTS_ENTRIES).map((item)=>tableOfContentsEntryFromOutline(document, item, buildOptions.resolveContext));
2590
+ return {
2591
+ entries,
2592
+ truncated: outline.length > MAX_DOCUMENT_TABLE_OF_CONTENTS_ENTRIES
2593
+ };
2594
+ }
2595
+ function documentTableOfContentsHtml(source) {
2596
+ const value = normalizeDocumentTableOfContentsValue(source);
2597
+ const options = value.options;
2598
+ const rows = value.entries.length ? value.entries.map((entry)=>tableOfContentsEntryHtml(entry, options)) : [
2599
+ '<li class="work-document-table-of-contents-empty">没有符合级别范围的标题</li>'
2600
+ ];
2601
+ const status = value.truncated ? `仅显示前 ${MAX_DOCUMENT_TABLE_OF_CONTENTS_ENTRIES} 项` : `${value.entries.length} 项`;
2602
+ return [
2603
+ `<div data-document-table-of-contents="true" data-toc-id="${work_document_table_of_contents_escapeHtmlAttribute(value.id)}" data-toc-min-level="${options.minLevel}" data-toc-max-level="${options.maxLevel}" data-toc-hyperlinks="${String(options.hyperlinks)}" data-toc-show-page-numbers="${String(options.showPageNumbers)}" data-toc-right-align-page-numbers="${String(options.rightAlignPageNumbers)}" data-toc-leader="${options.leader}" data-toc-entries="${work_document_table_of_contents_escapeHtmlAttribute(JSON.stringify(value.entries))}" data-toc-truncated="${String(value.truncated)}" class="work-document-table-of-contents" contenteditable="false" aria-label="目录">`,
2604
+ '<div class="work-document-table-of-contents-header"><strong>目录</strong>',
2605
+ `<span>${status}</span></div>`,
2606
+ '<ol class="work-document-table-of-contents-list">',
2607
+ ...rows,
2608
+ '</ol></div>'
2609
+ ].join('');
2610
+ }
2611
+ function normalizeDocumentTableOfContentsHtml(source) {
2612
+ const document = new DOMParser().parseFromString(source, 'text/html');
2613
+ const usedIds = new Set();
2614
+ for (const [index, element] of Array.from(document.body.querySelectorAll(TABLE_OF_CONTENTS_SELECTOR)).entries()){
2615
+ const value = documentTableOfContentsValueFromElement(element, index + 1);
2616
+ value.id = uniqueTableOfContentsId(value.id, index + 1, usedIds);
2617
+ const replacement = document.createRange().createContextualFragment(documentTableOfContentsHtml(value));
2618
+ element.replaceWith(replacement);
2619
+ }
2620
+ return document.body.innerHTML;
2621
+ }
2622
+ function documentTableOfContentsValueFromElement(element, index = 1) {
2623
+ const entries = parseTableOfContentsEntries(element.dataset.tocEntries);
2624
+ return normalizeDocumentTableOfContentsValue({
2625
+ id: validTableOfContentsId(element.dataset.tocId) ?? `toc-${index}`,
2626
+ options: {
2627
+ minLevel: Number(element.dataset.tocMinLevel),
2628
+ maxLevel: Number(element.dataset.tocMaxLevel),
2629
+ hyperlinks: 'false' !== element.dataset.tocHyperlinks,
2630
+ showPageNumbers: 'false' !== element.dataset.tocShowPageNumbers,
2631
+ rightAlignPageNumbers: 'false' !== element.dataset.tocRightAlignPageNumbers,
2632
+ leader: tableOfContentsLeader(element.dataset.tocLeader) ?? 'dot'
2633
+ },
2634
+ entries,
2635
+ truncated: 'true' === element.dataset.tocTruncated
2636
+ });
2637
+ }
2638
+ function parseDocumentTableOfContentsInstruction(instruction) {
2639
+ const command = /^\s*TOC\b/i.exec(instruction);
2640
+ if (!command) return {
2641
+ supported: false,
2642
+ reason: 'not-table-of-contents'
2643
+ };
2644
+ const source = instruction.slice(command[0].length);
2645
+ const switches = new Map();
2646
+ const matcher = /\\([a-z])(?:\s+("([^"]*)"|([^\\\s]+)))?/gi;
2647
+ let cursor = 0;
2648
+ for(let match = matcher.exec(source); match; match = matcher.exec(source)){
2649
+ if (source.slice(cursor, match.index).trim()) return {
2650
+ supported: false,
2651
+ reason: 'invalid-instruction'
2652
+ };
2653
+ const name = match[1]?.toLowerCase() ?? '';
2654
+ if (!name || switches.has(name)) return {
2655
+ supported: false,
2656
+ reason: 'invalid-instruction'
2657
+ };
2658
+ switches.set(name, match[3] ?? match[4] ?? null);
2659
+ cursor = matcher.lastIndex;
2660
+ }
2661
+ if (source.slice(cursor).trim()) return {
2662
+ supported: false,
2663
+ reason: 'invalid-instruction'
2664
+ };
2665
+ for (const name of switches.keys())if (![
2666
+ 'o',
2667
+ 'h',
2668
+ 'z',
2669
+ 'u',
2670
+ 'n',
2671
+ 'p'
2672
+ ].includes(name)) return {
2673
+ supported: false,
2674
+ reason: 'unsupported-switch'
2675
+ };
2676
+ const range = switches.has('o') ? parseTableOfContentsRange(switches.get('o')) : {
2677
+ minLevel: 1,
2678
+ maxLevel: 3
2679
+ };
2680
+ if (!range) return {
2681
+ supported: false,
2682
+ reason: 'invalid-level-range'
2683
+ };
2684
+ const pageRange = switches.has('n') ? parseOptionalTableOfContentsRange(switches.get('n')) : null;
2685
+ if (switches.has('n') && void 0 === pageRange) return {
2686
+ supported: false,
2687
+ reason: 'invalid-level-range'
2688
+ };
2689
+ if (pageRange && (pageRange.minLevel !== range.minLevel || pageRange.maxLevel !== range.maxLevel)) return {
2690
+ supported: false,
2691
+ reason: 'unsupported-page-range'
2692
+ };
2693
+ const separator = switches.get('p');
2694
+ if (switches.has('p') && (null == separator || separator.trim())) return {
2695
+ supported: false,
2696
+ reason: 'unsupported-separator'
2697
+ };
2698
+ const showPageNumbers = !switches.has('n');
2699
+ const rightAlignPageNumbers = showPageNumbers && !switches.has('p');
2700
+ return {
2701
+ supported: true,
2702
+ options: {
2703
+ ...range,
2704
+ hyperlinks: switches.has('h'),
2705
+ showPageNumbers,
2706
+ rightAlignPageNumbers,
2707
+ leader: rightAlignPageNumbers ? 'dot' : 'none'
2708
+ }
2709
+ };
2710
+ }
2711
+ function tableOfContentsLeader(value) {
2712
+ return 'dot' === value || 'dash' === value || 'underline' === value || 'none' === value ? value : null;
2713
+ }
2714
+ function normalizeDocumentTableOfContentsValue(source) {
2715
+ return {
2716
+ id: validTableOfContentsId(source.id) ?? 'document-table-of-contents',
2717
+ options: normalizeDocumentTableOfContentsOptions(source.options),
2718
+ entries: normalizeTableOfContentsEntries(source.entries),
2719
+ truncated: Boolean(source.truncated)
2720
+ };
2721
+ }
2722
+ function tableOfContentsEntryFromOutline(document, item, resolveContext) {
2723
+ return {
2724
+ targetId: item.id,
2725
+ title: item.text.slice(0, MAX_TABLE_OF_CONTENTS_TITLE_LENGTH),
2726
+ level: item.level,
2727
+ pageNumber: work_document_table_of_contents_positiveInteger(resolveContext?.(item.from)?.pageNumber) ?? work_document_table_of_contents_fallbackDocumentPageNumber(document, item.from)
2728
+ };
2729
+ }
2730
+ function work_document_table_of_contents_fallbackDocumentPageNumber(document, position) {
2731
+ let pageNumber = 1;
2732
+ document.descendants((node, offset)=>{
2733
+ if (offset >= position) return false;
2734
+ if ('pageBreak' === node.type.name) pageNumber += 1;
2735
+ return true;
2736
+ });
2737
+ return pageNumber;
2738
+ }
2739
+ function tableOfContentsEntryHtml(entry, options) {
2740
+ const title = work_document_table_of_contents_escapeHtml(entry.title);
2741
+ const targetId = work_document_table_of_contents_escapeHtmlAttribute(entry.targetId);
2742
+ const label = options.hyperlinks ? `<a href="#${targetId}" data-toc-target="${targetId}" tabindex="-1">${title}</a>` : `<span>${title}</span>`;
2743
+ const page = options.showPageNumbers ? `<span class="work-document-table-of-contents-page">${entry.pageNumber}</span>` : '';
2744
+ return `<li data-toc-target="${targetId}" data-toc-level="${entry.level}" style="--work-toc-level:${entry.level}">${label}<i aria-hidden="true"></i>${page}</li>`;
2745
+ }
2746
+ function parseTableOfContentsEntries(source) {
2747
+ if (!source) return [];
2748
+ try {
2749
+ const parsed = JSON.parse(source);
2750
+ return Array.isArray(parsed) ? normalizeTableOfContentsEntries(parsed) : [];
2751
+ } catch {
2752
+ return [];
2753
+ }
2754
+ }
2755
+ function normalizeTableOfContentsEntries(source) {
2756
+ const entries = [];
2757
+ for (const value of source.slice(0, MAX_DOCUMENT_TABLE_OF_CONTENTS_ENTRIES)){
2758
+ if (!value || 'object' != typeof value) continue;
2759
+ const candidate = value;
2760
+ const targetId = 'string' == typeof candidate.targetId ? candidate.targetId.trim() : '';
2761
+ const title = 'string' == typeof candidate.title ? candidate.title.replace(/\s+/g, ' ').trim() : '';
2762
+ const level = boundedLevel(candidate.level, 0);
2763
+ const pageNumber = work_document_table_of_contents_positiveInteger(candidate.pageNumber);
2764
+ if (TABLE_OF_CONTENTS_TARGET_PATTERN.test(targetId) && title && level && pageNumber) entries.push({
2765
+ targetId,
2766
+ title: title.slice(0, MAX_TABLE_OF_CONTENTS_TITLE_LENGTH),
2767
+ level,
2768
+ pageNumber
2769
+ });
2770
+ }
2771
+ return entries;
2772
+ }
2773
+ function parseTableOfContentsRange(value) {
2774
+ if (null == value) return null;
2775
+ const match = /^([1-9])-([1-9])$/.exec(value.trim());
2776
+ if (!match) return null;
2777
+ const minLevel = Number(match[1]);
2778
+ const maxLevel = Number(match[2]);
2779
+ return minLevel <= maxLevel ? {
2780
+ minLevel,
2781
+ maxLevel
2782
+ } : null;
2783
+ }
2784
+ function parseOptionalTableOfContentsRange(value) {
2785
+ if (null === value) return null;
2786
+ return parseTableOfContentsRange(value) ?? void 0;
2787
+ }
2788
+ function boundedLevel(value, fallback) {
2789
+ const number = Number(value);
2790
+ return Number.isInteger(number) && number >= 1 && number <= 9 ? number : fallback;
2791
+ }
2792
+ function work_document_table_of_contents_positiveInteger(value) {
2793
+ const number = Number(value);
2794
+ return Number.isSafeInteger(number) && number > 0 ? Math.min(999999, number) : null;
2795
+ }
2796
+ function validTableOfContentsId(value) {
2797
+ return 'string' == typeof value && TABLE_OF_CONTENTS_ID_PATTERN.test(value) ? value : null;
2798
+ }
2799
+ function uniqueTableOfContentsId(source, index, usedIds) {
2800
+ if (!usedIds.has(source)) {
2801
+ usedIds.add(source);
2802
+ return source;
2803
+ }
2804
+ let suffix = index;
2805
+ while(usedIds.has(`document-table-of-contents-${suffix}`))suffix += 1;
2806
+ const id = `document-table-of-contents-${suffix}`;
2807
+ usedIds.add(id);
2808
+ return id;
2809
+ }
2810
+ function work_document_table_of_contents_escapeHtml(value) {
2811
+ return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
2812
+ }
2813
+ function work_document_table_of_contents_escapeHtmlAttribute(value) {
2814
+ return work_document_table_of_contents_escapeHtml(value).replaceAll('"', '&quot;').replaceAll("'", '&#39;');
2815
+ }
974
2816
  const WORK_TEMPLATES = [
975
2817
  {
976
2818
  id: 'blank-document',
@@ -986,6 +2828,20 @@ const WORK_TEMPLATES = [
986
2828
  description: '目标、范围、里程碑与风险',
987
2829
  accent: '#536de2'
988
2830
  },
2831
+ {
2832
+ id: 'table-of-contents',
2833
+ kind: 'document',
2834
+ name: '可更新目录',
2835
+ description: '标题级别、超链接、页码、前导符与原生 DOCX 往返',
2836
+ accent: '#315f9f'
2837
+ },
2838
+ {
2839
+ id: 'document-index',
2840
+ kind: 'document',
2841
+ name: '原生索引',
2842
+ description: '主次索引项、交叉引用、页码样式与原生 DOCX 往返',
2843
+ accent: '#4d6398'
2844
+ },
989
2845
  {
990
2846
  id: 'text-effects',
991
2847
  kind: 'document',
@@ -1000,6 +2856,20 @@ const WORK_TEMPLATES = [
1000
2856
  description: '原生线型、颜色、宽度、间距与阴影',
1001
2857
  accent: '#4472c4'
1002
2858
  },
2859
+ {
2860
+ id: 'run-shading',
2861
+ kind: 'document',
2862
+ name: '字符底纹',
2863
+ description: '原生图案、前景色、背景色与显式重置',
2864
+ accent: '#70ad47'
2865
+ },
2866
+ {
2867
+ id: 'proofing-languages',
2868
+ kind: 'document',
2869
+ name: '校对语言',
2870
+ description: '拉丁、东亚、双向文字与校对排除',
2871
+ accent: '#2f6fed'
2872
+ },
1003
2873
  {
1004
2874
  id: 'blank-markdown',
1005
2875
  kind: 'markdown',
@@ -1021,6 +2891,13 @@ const WORK_TEMPLATES = [
1021
2891
  description: '目标进度与预算跟踪',
1022
2892
  accent: '#168f72'
1023
2893
  },
2894
+ {
2895
+ id: 'data-validation',
2896
+ kind: 'spreadsheet',
2897
+ name: '数据验证',
2898
+ description: '下拉列表、输入提示与错误警告',
2899
+ accent: '#13795b'
2900
+ },
1024
2901
  {
1025
2902
  id: 'blank-presentation',
1026
2903
  kind: 'presentation',
@@ -1058,9 +2935,14 @@ function createWorkId(prefix) {
1058
2935
  function initialTitle(templateId, kind) {
1059
2936
  const titles = {
1060
2937
  'project-brief': '新项目方案',
2938
+ 'table-of-contents': '可更新目录示例',
2939
+ 'document-index': '原生索引示例',
1061
2940
  'text-effects': '文字效果示例',
1062
2941
  'run-borders': '字符边框示例',
2942
+ 'run-shading': '字符底纹示例',
2943
+ 'proofing-languages': '校对语言示例',
1063
2944
  'quarterly-plan': '季度执行计划',
2945
+ 'data-validation': '数据验证示例',
1064
2946
  'strategy-deck': '业务策略汇报'
1065
2947
  };
1066
2948
  if (titles[templateId]) return titles[templateId];
@@ -1075,6 +2957,153 @@ function contentForTemplate(templateId) {
1075
2957
  pageSize: 'a4',
1076
2958
  html: "<h1>新项目方案</h1><p><strong>负责人:</strong>项目团队  <strong>更新日期:</strong>今天</p><blockquote><p>用一句话说明这项工作的目标,以及完成后会带来什么变化。</p></blockquote><h2>背景与目标</h2><p>描述当前情况、核心问题和可衡量的成功标准。</p><h2>工作范围</h2><ul><li><p>需要完成的关键交付物</p></li><li><p>明确不在本期范围内的事项</p></li></ul><h2>里程碑</h2><ol><li><p>方案确认</p></li><li><p>执行与评审</p></li><li><p>交付与复盘</p></li></ol><h2>风险与决策</h2><p>记录尚未解决的问题、依赖和决策负责人。</p>"
1077
2959
  };
2960
+ if ('table-of-contents' === templateId) return {
2961
+ type: 'document',
2962
+ pageSize: 'a4',
2963
+ html: [
2964
+ documentTableOfContentsHtml({
2965
+ id: 'playground-table-of-contents',
2966
+ options: {
2967
+ minLevel: 1,
2968
+ maxLevel: 3,
2969
+ hyperlinks: true,
2970
+ showPageNumbers: true,
2971
+ rightAlignPageNumbers: true,
2972
+ leader: 'dot'
2973
+ },
2974
+ entries: [
2975
+ {
2976
+ targetId: 'heading-00001001',
2977
+ title: '项目概述',
2978
+ level: 1,
2979
+ pageNumber: 1
2980
+ },
2981
+ {
2982
+ targetId: 'heading-00001002',
2983
+ title: '目标与范围',
2984
+ level: 2,
2985
+ pageNumber: 1
2986
+ },
2987
+ {
2988
+ targetId: 'heading-00001003',
2989
+ title: '实施计划',
2990
+ level: 1,
2991
+ pageNumber: 2
2992
+ }
2993
+ ]
2994
+ }),
2995
+ '<h1 data-office-paragraph-id="00001001" data-office-paragraph-text-id="00002001">项目概述</h1>',
2996
+ '<p>目录是一个可选择、不可直接改写的结构化块。请从“引用”选项卡自定义或更新它。</p>',
2997
+ '<h2 data-office-paragraph-id="00001002" data-office-paragraph-text-id="00002002">目标与范围</h2>',
2998
+ '<p>修改标题文字后,使用“更新目录”同步标题与当前分页页码。</p>',
2999
+ '<hr class="work-page-break" data-page-break="true">',
3000
+ '<h1 data-office-paragraph-id="00001003" data-office-paragraph-text-id="00002003">实施计划</h1>',
3001
+ '<p>导出 DOCX 后仍保留原生 TOC 域、缓存目录项、超链接和前导符。</p>'
3002
+ ].join('')
3003
+ };
3004
+ if ('document-index' === templateId) return {
3005
+ type: 'document',
3006
+ pageSize: 'a4',
3007
+ html: [
3008
+ documentIndexHtml({
3009
+ id: 'playground-document-index',
3010
+ options: {
3011
+ columns: 2,
3012
+ format: 'indented',
3013
+ rightAlignPageNumbers: true,
3014
+ leader: 'dot'
3015
+ },
3016
+ entries: [
3017
+ {
3018
+ mainEntry: 'Architecture',
3019
+ subEntry: '',
3020
+ crossReference: '',
3021
+ pages: [
3022
+ {
3023
+ pageNumber: 1,
3024
+ pageBold: false,
3025
+ pageItalic: false,
3026
+ targetIds: [
3027
+ 'index-entry-architecture'
3028
+ ]
3029
+ }
3030
+ ]
3031
+ },
3032
+ {
3033
+ mainEntry: 'Architecture',
3034
+ subEntry: 'Runtime',
3035
+ crossReference: '',
3036
+ pages: [
3037
+ {
3038
+ pageNumber: 1,
3039
+ pageBold: true,
3040
+ pageItalic: false,
3041
+ targetIds: [
3042
+ 'index-entry-runtime'
3043
+ ]
3044
+ }
3045
+ ]
3046
+ },
3047
+ {
3048
+ mainEntry: 'Collaboration',
3049
+ subEntry: '',
3050
+ crossReference: 'Architecture',
3051
+ pages: []
3052
+ },
3053
+ {
3054
+ mainEntry: 'Performance',
3055
+ subEntry: '',
3056
+ crossReference: '',
3057
+ pages: [
3058
+ {
3059
+ pageNumber: 2,
3060
+ pageBold: false,
3061
+ pageItalic: true,
3062
+ targetIds: [
3063
+ 'index-entry-performance'
3064
+ ]
3065
+ }
3066
+ ]
3067
+ }
3068
+ ]
3069
+ }),
3070
+ '<h1>原生索引</h1>',
3071
+ `<p>选择正文后,从“引用 → 标记索引项”创建主索引项、次索引项或交叉引用。${documentIndexEntryHtml({
3072
+ id: 'index-entry-architecture',
3073
+ mainEntry: 'Architecture',
3074
+ subEntry: '',
3075
+ crossReference: '',
3076
+ pageBold: false,
3077
+ pageItalic: false
3078
+ })}</p>`,
3079
+ `<p>Runtime 项的页码使用粗体,并作为 Architecture 的次索引项。${documentIndexEntryHtml({
3080
+ id: 'index-entry-runtime',
3081
+ mainEntry: 'Architecture',
3082
+ subEntry: 'Runtime',
3083
+ crossReference: '',
3084
+ pageBold: true,
3085
+ pageItalic: false
3086
+ })}</p>`,
3087
+ `<p>Collaboration 使用“参见 Architecture”交叉引用,不生成当前页码。${documentIndexEntryHtml({
3088
+ id: 'index-entry-collaboration',
3089
+ mainEntry: 'Collaboration',
3090
+ subEntry: '',
3091
+ crossReference: 'Architecture',
3092
+ pageBold: false,
3093
+ pageItalic: false
3094
+ })}</p>`,
3095
+ '<hr class="work-page-break" data-page-break="true">',
3096
+ `<p>Performance 位于第二页,页码使用斜体。${documentIndexEntryHtml({
3097
+ id: 'index-entry-performance',
3098
+ mainEntry: 'Performance',
3099
+ subEntry: '',
3100
+ crossReference: '',
3101
+ pageBold: false,
3102
+ pageItalic: true
3103
+ })}</p>`,
3104
+ '<p>修改索引项后选择“更新索引”,再导出 DOCX 验证原生 XE 与 INDEX 域。</p>'
3105
+ ].join('')
3106
+ };
1078
3107
  if ('text-effects' === templateId) return {
1079
3108
  type: 'document',
1080
3109
  pageSize: 'a4',
@@ -1124,10 +3153,89 @@ function contentForTemplate(templateId) {
1124
3153
  }, '阴影与框架字符边框')}</p>`
1125
3154
  ].join('')
1126
3155
  };
3156
+ if ('run-shading' === templateId) return {
3157
+ type: 'document',
3158
+ pageSize: 'a4',
3159
+ html: [
3160
+ '<h1>原生字符底纹</h1>',
3161
+ '<p>选择任一示例并打开字体高级设置,可以编辑完整的原生图案、前景色、背景色,或写入显式无底纹重置。</p>',
3162
+ '<h2>基本填充</h2>',
3163
+ `<p>${runShadingTemplateSpan({
3164
+ pattern: 'clear',
3165
+ fill: {
3166
+ value: '#fff2cc'
3167
+ }
3168
+ }, '清除图案使用背景色')}</p>`,
3169
+ `<p>${runShadingTemplateSpan({
3170
+ pattern: 'solid',
3171
+ color: {
3172
+ value: '#4472c4'
3173
+ }
3174
+ }, '实心图案使用前景色')}</p>`,
3175
+ '<h2>图案与密度</h2>',
3176
+ `<p>${runShadingTemplateSpan({
3177
+ pattern: 'diagCross',
3178
+ color: {
3179
+ value: '#c00000'
3180
+ },
3181
+ fill: {
3182
+ value: '#fce4d6'
3183
+ }
3184
+ }, '对角交叉字符底纹')}</p>`,
3185
+ `<p>${runShadingTemplateSpan({
3186
+ pattern: 'pct25',
3187
+ color: {
3188
+ value: '#4472c4'
3189
+ },
3190
+ fill: {
3191
+ value: '#ddebf7'
3192
+ }
3193
+ }, '25% 字符底纹')}</p>`,
3194
+ `<p>${runShadingTemplateSpan({
3195
+ pattern: 'thinHorzStripe',
3196
+ color: {
3197
+ value: '#70ad47'
3198
+ },
3199
+ fill: {
3200
+ value: '#e2f0d9'
3201
+ }
3202
+ }, '细水平条纹字符底纹')}</p>`
3203
+ ].join('')
3204
+ };
3205
+ if ('proofing-languages' === templateId) {
3206
+ const languages = {
3207
+ latin: 'en-US',
3208
+ eastAsia: 'zh-CN',
3209
+ bidi: 'ar-SA'
3210
+ };
3211
+ return {
3212
+ type: 'document',
3213
+ pageSize: 'a4',
3214
+ html: [
3215
+ '<h1>原生校对语言</h1>',
3216
+ '<p>在“审阅”选项卡中打开“设置校对语言”,可以独立编辑拉丁、东亚和双向文字语言,并决定文字是否参与拼写与语法检查。</p>',
3217
+ '<h2>按文字系统设置</h2>',
3218
+ `<p>${proofingLanguageTemplateSpan(languages, false, 'ascii', 'English proofing language')}</p>`,
3219
+ `<p>${proofingLanguageTemplateSpan(languages, false, 'eastAsia', '简体中文校对语言')}</p>`,
3220
+ `<p dir="rtl">${proofingLanguageTemplateSpan(languages, false, 'complexScript', 'لغة التدقيق العربية')}</p>`,
3221
+ '<h2>校对行为</h2>',
3222
+ `<p>${proofingLanguageTemplateSpan({
3223
+ latin: 'en-GB'
3224
+ }, false, 'ascii', 'This text participates in proofing.')}</p>`,
3225
+ `<p>${proofingLanguageTemplateSpan({
3226
+ latin: 'x-none'
3227
+ }, true, 'ascii', 'A3S-API-v2: this product identifier is excluded from proofing.')}</p>`
3228
+ ].join('')
3229
+ };
3230
+ }
1127
3231
  if ('quarterly-plan' === templateId) return {
1128
3232
  type: 'spreadsheet',
1129
3233
  sheets: quarterlyPlanSheets()
1130
3234
  };
3235
+ if ('data-validation' === templateId) return {
3236
+ type: 'spreadsheet',
3237
+ sheets: dataValidationTemplateSheets()
3238
+ };
1131
3239
  if ('strategy-deck' === templateId) return strategyPresentation();
1132
3240
  if ('blank-spreadsheet' === templateId) return {
1133
3241
  type: 'spreadsheet',
@@ -1155,6 +3263,14 @@ function runBorderTemplateSpan(border, text) {
1155
3263
  const attributes = documentRunBorderDomAttributes(border);
1156
3264
  return `<span ${DOCUMENT_RUN_BORDER_ATTRIBUTE}='${attributes[DOCUMENT_RUN_BORDER_ATTRIBUTE]}' style="${attributes.style}">${text}</span>`;
1157
3265
  }
3266
+ function runShadingTemplateSpan(shading, text) {
3267
+ const attributes = documentRunShadingDomAttributes(shading);
3268
+ return `<span ${DOCUMENT_RUN_SHADING_ATTRIBUTE}='${attributes[DOCUMENT_RUN_SHADING_ATTRIBUTE]}' style="${attributes.style}">${text}</span>`;
3269
+ }
3270
+ function proofingLanguageTemplateSpan(languages, noProof, slot, text) {
3271
+ const attributes = documentProofingDomAttributes(languages, noProof, slot);
3272
+ return `<span ${Object.entries(attributes).map(([name, value])=>`${name}='${value}'`).join(' ')}>${text}</span>`;
3273
+ }
1158
3274
  function blankSheet() {
1159
3275
  return {
1160
3276
  id: createWorkId('sheet'),
@@ -1270,6 +3386,229 @@ function quarterlyPlanSheets() {
1270
3386
  }
1271
3387
  ];
1272
3388
  }
3389
+ function dataValidationTemplateSheets() {
3390
+ const inputs = emptyMatrix(24, 8);
3391
+ [
3392
+ 'Task',
3393
+ 'State',
3394
+ 'Due date',
3395
+ 'Priority',
3396
+ 'Owner'
3397
+ ].forEach((value, column)=>{
3398
+ inputs[0][column] = headerCell(value);
3399
+ });
3400
+ const rows = [
3401
+ [
3402
+ 'Confirm requirements',
3403
+ 'Ready',
3404
+ '2026-09-05',
3405
+ 2,
3406
+ 'Avery'
3407
+ ],
3408
+ [
3409
+ 'Review integration',
3410
+ 'In review',
3411
+ '2026-09-12',
3412
+ 3,
3413
+ 'Morgan'
3414
+ ],
3415
+ [
3416
+ 'Resolve blockers',
3417
+ 'Blocked',
3418
+ '2026-09-18',
3419
+ 5,
3420
+ 'Riley'
3421
+ ],
3422
+ [
3423
+ 'Publish preview',
3424
+ 'Ready',
3425
+ '2026-09-24',
3426
+ 1,
3427
+ 'Jordan'
3428
+ ],
3429
+ [
3430
+ 'Ship release',
3431
+ 'In review',
3432
+ '2026-09-30',
3433
+ 4,
3434
+ 'Taylor'
3435
+ ]
3436
+ ];
3437
+ rows.forEach((row, rowIndex)=>{
3438
+ row.forEach((value, columnIndex)=>{
3439
+ inputs[rowIndex + 1][columnIndex] = styledCell(value, {
3440
+ bg: rowIndex % 2 ? '#f4faf7' : '#ffffff'
3441
+ });
3442
+ });
3443
+ });
3444
+ return [
3445
+ {
3446
+ id: createWorkId('sheet'),
3447
+ name: 'Inputs',
3448
+ status: 1,
3449
+ order: 0,
3450
+ row: 24,
3451
+ column: 8,
3452
+ data: inputs,
3453
+ dataValidationRanges: [
3454
+ {
3455
+ ranges: [
3456
+ {
3457
+ row: [
3458
+ 1,
3459
+ 5
3460
+ ],
3461
+ column: [
3462
+ 1,
3463
+ 1
3464
+ ]
3465
+ }
3466
+ ],
3467
+ item: dataValidationTemplateItem({
3468
+ type: 'dropdown',
3469
+ rangeTxt: 'B2:B6',
3470
+ value1: "'Lists'!A1:A3",
3471
+ allowBlank: false,
3472
+ showDropdownArrow: true,
3473
+ errorStyle: 'stop',
3474
+ errorTitle: 'Invalid state',
3475
+ errorMessage: 'Choose a state from the list.',
3476
+ hintShow: true,
3477
+ hintTitle: 'Workflow state',
3478
+ hintValue: 'Choose Ready, Blocked, or In review.'
3479
+ })
3480
+ },
3481
+ {
3482
+ ranges: [
3483
+ {
3484
+ row: [
3485
+ 1,
3486
+ 5
3487
+ ],
3488
+ column: [
3489
+ 2,
3490
+ 2
3491
+ ]
3492
+ }
3493
+ ],
3494
+ item: dataValidationTemplateItem({
3495
+ type: 'date',
3496
+ type2: 'between',
3497
+ rangeTxt: 'C2:C6',
3498
+ value1: '2026-01-01',
3499
+ value2: '2026-12-31',
3500
+ errorStyle: 'information',
3501
+ errorTitle: 'Date outside 2026',
3502
+ errorMessage: 'Enter a date in calendar year 2026.',
3503
+ hintShow: true,
3504
+ hintTitle: 'Due date',
3505
+ hintValue: 'Use a date between 2026-01-01 and 2026-12-31.'
3506
+ })
3507
+ },
3508
+ {
3509
+ ranges: [
3510
+ {
3511
+ row: [
3512
+ 1,
3513
+ 5
3514
+ ],
3515
+ column: [
3516
+ 3,
3517
+ 3
3518
+ ]
3519
+ }
3520
+ ],
3521
+ item: dataValidationTemplateItem({
3522
+ type: 'number_integer',
3523
+ type2: 'between',
3524
+ rangeTxt: 'D2:D6',
3525
+ value1: '1',
3526
+ value2: '5',
3527
+ allowBlank: false,
3528
+ errorStyle: 'warning',
3529
+ errorTitle: 'Priority outside range',
3530
+ errorMessage: 'Enter a whole number from 1 through 5.',
3531
+ hintShow: true,
3532
+ hintTitle: 'Priority',
3533
+ hintValue: '1 is highest priority; 5 is lowest.'
3534
+ })
3535
+ }
3536
+ ],
3537
+ luckysheet_select_save: [
3538
+ {
3539
+ row: [
3540
+ 1,
3541
+ 5
3542
+ ],
3543
+ column: [
3544
+ 1,
3545
+ 1
3546
+ ],
3547
+ row_focus: 1,
3548
+ column_focus: 1
3549
+ }
3550
+ ],
3551
+ config: {
3552
+ columnlen: {
3553
+ 0: 190,
3554
+ 1: 110,
3555
+ 2: 118,
3556
+ 3: 84,
3557
+ 4: 104
3558
+ },
3559
+ rowlen: {
3560
+ 0: 30
3561
+ }
3562
+ }
3563
+ },
3564
+ {
3565
+ id: createWorkId('sheet'),
3566
+ name: 'Lists',
3567
+ status: 0,
3568
+ order: 1,
3569
+ row: 12,
3570
+ column: 3,
3571
+ data: [
3572
+ [
3573
+ styledCell('Ready')
3574
+ ],
3575
+ [
3576
+ styledCell('Blocked')
3577
+ ],
3578
+ [
3579
+ styledCell('In review')
3580
+ ]
3581
+ ],
3582
+ config: {
3583
+ columnlen: {
3584
+ 0: 120
3585
+ }
3586
+ }
3587
+ }
3588
+ ];
3589
+ }
3590
+ function dataValidationTemplateItem(overrides) {
3591
+ return {
3592
+ type: 'dropdown',
3593
+ type2: '',
3594
+ rangeTxt: '',
3595
+ value1: '',
3596
+ value2: '',
3597
+ validity: '',
3598
+ remote: false,
3599
+ allowBlank: true,
3600
+ showDropdownArrow: true,
3601
+ prohibitInput: true,
3602
+ errorStyle: 'stop',
3603
+ errorTitle: '',
3604
+ errorMessage: '',
3605
+ hintShow: false,
3606
+ hintTitle: '',
3607
+ hintValue: '',
3608
+ checked: false,
3609
+ ...overrides
3610
+ };
3611
+ }
1273
3612
  function emptyMatrix(rows, columns) {
1274
3613
  return Array.from({
1275
3614
  length: rows
@@ -1507,4 +3846,4 @@ new TextEncoder();
1507
3846
  function isOfficeKernelSpreadsheetError(value) {
1508
3847
  return 'string' == typeof value && spreadsheetErrors.has(value);
1509
3848
  }
1510
- export { DOCUMENT_PARAGRAPH_BORDERS_ATTRIBUTE, DOCUMENT_PARAGRAPH_BORDER_EDGES, DOCUMENT_PARAGRAPH_BORDER_STYLES, DOCUMENT_RUN_BORDER_ATTRIBUTE, DOCUMENT_RUN_BORDER_STYLES, DocxThemePatchCollector, OFFICE_KERNEL_SPREADSHEET_MAX_ROWS, OoxmlPackage, WORK_TEMPLATES as officeTemplates, attribute, bytesToDataUrl, childPath, contentTypeForPart, createWorkArtifact as createArtifact, createWorkId as createOfficeId, decodeXmlBytes, descendants, directChild, directChildren, documentBorderPresentation, documentParagraphBordersDomAttributes, documentRunBorderDomAttributes, documentRunBorderIsVisible, firstDescendant, isDocumentParagraphArtBorderStyle, isOfficeKernelSpreadsheetError, normalizeCssColor, normalizeDocumentParagraphBorder, normalizeDocumentParagraphBorders, normalizeDocumentRunBorder, parseDocumentParagraphBorders, parseDocumentParagraphBordersElement, parseDocumentRunBorder, parseDocumentRunBorderElement, parseDocxThemeReference, parseXml, patchDocxThemeReferences, resolvePartTarget, serializeDocumentParagraphBorders, serializeDocumentRunBorder, serializeDocxThemeReference, serializeUtf8Xml, xmlContainsAnyElement, xmlNamespacePrefix };
3849
+ export { DEFAULT_DOCUMENT_INDEX_OPTIONS, DEFAULT_DOCUMENT_TABLE_OF_CONTENTS_OPTIONS, DOCUMENT_HIGHLIGHT_ATTRIBUTE, DOCUMENT_NO_PROOF_ATTRIBUTE, DOCUMENT_PARAGRAPH_BORDERS_ATTRIBUTE, DOCUMENT_PARAGRAPH_BORDER_EDGES, DOCUMENT_PARAGRAPH_BORDER_STYLES, DOCUMENT_PARAGRAPH_ID_ATTRIBUTE, DOCUMENT_PARAGRAPH_TEXT_ID_ATTRIBUTE, DOCUMENT_PROOFING_LANGUAGES_ATTRIBUTE, DOCUMENT_RUN_BORDER_ATTRIBUTE, DOCUMENT_RUN_BORDER_STYLES, DOCUMENT_RUN_SHADING_ATTRIBUTE, DOCUMENT_SCRIPT_FONTS_ATTRIBUTE, DOCUMENT_SCRIPT_FONT_SLOT_ATTRIBUTE, DocumentParagraphIdentity, DocxThemePatchCollector, OFFICE_KERNEL_SPREADSHEET_MAX_ROWS, OoxmlPackage, WORK_TEMPLATES as officeTemplates, applyDocumentParagraphIdentityToElement, attribute, buildDocumentIndexEntries, buildDocumentTableOfContentsEntries, bytesToDataUrl, childPath, collectWorkDocumentOutline, contentTypeForPart, createDocumentParagraphIdentity, createDocumentParagraphIdentityRegistry, createWorkArtifact as createArtifact, createWorkId as createOfficeId, cssDocumentFontFamily, currentWorkDocumentOutlineItem, decodeXmlBytes, descendants, directChild, directChildren, documentBorderPresentation, documentFontNameFromCssFamily, documentHasIntegrityFeature, documentHighlightCssColor, documentHighlightDomAttributes, documentHighlightForCssColor, documentHighlightFromDocxValue, documentHighlightFromElement, documentIndexEntryFromElement, documentIndexEntryHtml, documentIndexHtml, documentIndexValueFromElement, documentNoProofFromElement, documentParagraphBordersDomAttributes, documentParagraphIdentityFromElement, documentParagraphShadingDomAttributes, documentProofingDomAttributes, documentProofingLanguagesFromElement, documentRunBorderDomAttributes, documentRunBorderIsVisible, documentRunShadingDomAttributes, documentScriptFontDirectFamily, documentScriptFontFallbackSlots, documentScriptFontFamily, documentScriptFontFamilyForRendering, documentScriptFontSegments, documentScriptFontSlotFromElement, documentScriptFontSlotFromHint, documentScriptFontsDomAttributes, documentScriptFontsForAllText, documentScriptFontsFromElement, documentTableOfContentsHtml, documentTableOfContentsValueFromElement, firstDescendant, isDocumentParagraphArtBorderStyle, isOfficeKernelSpreadsheetError, normalizeCssColor, normalizeDocumentFontName, normalizeDocumentHighlight, normalizeDocumentIndexEntry, normalizeDocumentIndexEntryDraft, normalizeDocumentIndexOptions, normalizeDocumentIndexValue, normalizeDocumentIndexesHtml, normalizeDocumentLanguageTag, normalizeDocumentNoProof, normalizeDocumentParagraphBorder, normalizeDocumentParagraphBorders, normalizeDocumentParagraphId, normalizeDocumentParagraphIdentity, normalizeDocumentProofingLanguages, normalizeDocumentRunBorder, normalizeDocumentRunShading, normalizeDocumentScriptFontHint, normalizeDocumentScriptFontSlot, normalizeDocumentScriptFonts, normalizeDocumentTableOfContentsHtml, normalizeDocumentTableOfContentsOptions, normalizeDocumentTableOfContentsValue, normalizeDocumentThemeFont, parseDocumentParagraphBorders, parseDocumentParagraphBordersElement, parseDocumentParagraphShading, parseDocumentParagraphShadingElement, parseDocumentProofingLanguages, parseDocumentRunBorder, parseDocumentRunBorderElement, parseDocumentRunShading, parseDocumentRunShadingElement, parseDocumentScriptFonts, parseDocumentTableOfContentsInstruction, parseDocxThemeReference, parseXml, patchDocumentProofingLanguages, patchDocumentScriptFonts, patchDocxThemeReferences, primeDocumentIntegrityFeatures, resolvePartTarget, serializeDocumentParagraphBorders, serializeDocumentParagraphShading, serializeDocumentProofingLanguages, serializeDocumentRunBorder, serializeDocumentRunShading, serializeDocumentScriptFonts, serializeDocxThemeReference, serializeUtf8Xml, uniqueDocumentParagraphIdentity, visibleWorkDocumentOutlineItems, workDocumentOutlineLevel, work_document_paragraph_shading_DOCUMENT_PARAGRAPH_SHADING_PATTERNS, xmlContainsAnyElement, xmlNamespacePrefix };