@a3s-lab/office 0.46.0 → 0.48.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.
@@ -1,6 +1,6 @@
1
1
  import { documentRunBorderDomAttributes, normalizeDocumentRunBorder, normalizeDocumentParagraphBorder, serializeDocumentRunBorder, serializeDocumentRunShading, documentIndexEntryHtml, attribute as work_ooxml_package_attribute, documentScriptFontFallbackSlots, documentScriptFontsDomAttributes, documentHighlightFromDocxValue, serializeDocxThemeReference, directChildren as work_ooxml_package_directChildren, documentParagraphShadingDomAttributes, documentTableOfContentsHtml, documentParagraphBordersDomAttributes, normalizeDocumentScriptFontHint, normalizeDocumentScriptFonts, DOCUMENT_PARAGRAPH_BORDER_STYLES, normalizeDocumentParagraphBorders as work_document_paragraph_borders_normalizeDocumentParagraphBorders, DOCUMENT_PARAGRAPH_BORDER_EDGES, documentScriptFontFamily, normalizeDocumentThemeFont, normalizeDocumentParagraphId, documentHighlightDomAttributes, descendants, documentIndexHtml, documentHighlightCssColor, xmlNamespacePrefix, normalizeDocumentFontName, documentProofingDomAttributes, work_document_paragraph_shading_DOCUMENT_PARAGRAPH_SHADING_PATTERNS, directChild, documentScriptFontSegments, childPath, parseDocumentTableOfContentsInstruction, documentRunShadingDomAttributes } from "./6968.js";
2
- import { docxThemeFont, XML_NAMESPACE as work_docx_settings_xml_XML_NAMESPACE, parseDocumentIndexEntryInstruction, resolveDocxProofing, parseDocumentIndexInstruction, DOCX_WORD_2010_NAMESPACE, XMLNS_NAMESPACE as work_docx_settings_xml_XMLNS_NAMESPACE, STRICT_WORDPROCESSING_NAMESPACE, docxCharacterSpacingTwipsFromProperties, parseBoundedDocxInteger, xmlAttributeLocalName, resolveDocxOpenTypeFeatures, docxCharacterScalePercentFromProperties, resolveDocxEmphasisMark, docxCharacterPositionHalfPointsFromProperties, docxThemeColor, parseDocxParagraphDefaultCollapsed, resolveDocxKerningThresholdHalfPoints, resolveDocxThemeResolver as work_docx_theme_resolveDocxThemeResolver, DOCX_WORDPROCESSING_NAMESPACES, xmlAttributeNamespace, parseDocxTwipsMeasure } from "./0~4042.js";
3
- import { normalizeDocumentEmphasisMark, normalizeDocumentPageBorders, textBoxCss, documentCharacterPositionDomAttributes, DOCUMENT_PAGE_BORDER_EDGES, normalizeDocumentTabStops, documentTextCaseFromWordFlags, documentStrikeDomAttributes, serializeDocumentNumberingChange, numberingTypeFromFormat, normalizeDocumentUnderlineColor, documentAutoLineHeight, textBoxDomAttributes, documentCharacterScaleDomAttributes, documentKerningDomAttributes, serializeDocumentParagraphFormatting, normalizeDocumentPaperSource, documentEquationText, documentLegacyTextEffectsDomAttributes, documentLegacyTextEffectsConflict, documentCharacterSpacingDomAttributes, normalizeDocumentParagraphIndent, normalizeDocumentEquation, documentOpenTypeDomAttributes, normalizeDocumentTextBoxProperties, renderDocumentAutoLineHeight, documentUnderlineDomAttributes, MAX_DOCUMENT_NUMBERING_START, normalizeDocumentUnderlineStyle, applyDocumentTextCaseStyle, documentHiddenTextDomAttributes, importedDocumentCharacterFormatting, DOCUMENT_LEGACY_TEXT_EFFECT_NAMES, createDocumentEquationElement, normalizeDocumentPageGeometry, serializeDocumentTabStops, documentEmphasisMarkDomAttributes, normalizeDocumentPageMargins, documentWordLineHeightFactor } from "./4174.js";
2
+ import { normalizeDocumentEmphasisMark, normalizeDocumentPageBorders, textBoxCss, documentCharacterPositionDomAttributes, DOCUMENT_PAGE_BORDER_EDGES, normalizeDocumentTabStops, documentTextCaseFromWordFlags, documentStrikeDomAttributes, serializeDocumentNumberingChange, numberingTypeFromFormat, normalizeDocumentUnderlineColor, documentAutoLineHeight, documentKerningDomAttributes, documentCharacterScaleDomAttributes, textBoxDomAttributes, serializeDocumentParagraphFormatting, normalizeDocumentContentControlProperties, documentEquationText, normalizeDocumentPaperSource, documentLegacyTextEffectsDomAttributes, documentLegacyTextEffectsConflict, documentCharacterSpacingDomAttributes, normalizeDocumentParagraphIndent, normalizeDocumentEquation, documentOpenTypeDomAttributes, normalizeDocumentTextBoxProperties, renderDocumentAutoLineHeight, contentControlDomAttributes, documentUnderlineDomAttributes, MAX_DOCUMENT_NUMBERING_START, normalizeDocumentUnderlineStyle, applyDocumentTextCaseStyle, documentHiddenTextDomAttributes, importedDocumentCharacterFormatting, DOCUMENT_LEGACY_TEXT_EFFECT_NAMES, normalizeDocumentPageGeometry, createDocumentEquationElement, serializeDocumentTabStops, documentEmphasisMarkDomAttributes, normalizeDocumentPageMargins, documentWordLineHeightFactor } from "./4174.js";
3
+ import { hasUnsupportedContentControlSemanticChild, docxThemeFont, hasContentControlRelationshipReference, XML_NAMESPACE as work_docx_settings_xml_XML_NAMESPACE, parseDocumentIndexEntryInstruction, resolveDocxProofing, parseDocumentIndexInstruction, CONTENT_CONTROL_WORD_2012_NAMESPACE, DOCX_WORD_2010_NAMESPACE, XMLNS_NAMESPACE as work_docx_settings_xml_XMLNS_NAMESPACE, STRICT_WORDPROCESSING_NAMESPACE, docxCharacterSpacingTwipsFromProperties, parseBoundedDocxInteger, isDocxWordElement, xmlAttributeLocalName, resolveDocxOpenTypeFeatures, resolveDocxEmphasisMark, docxCharacterScalePercentFromProperties, docxCharacterPositionHalfPointsFromProperties, docxThemeColor, parseDocxParagraphDefaultCollapsed, resolveDocxKerningThresholdHalfPoints, resolveDocxThemeResolver as work_docx_theme_resolveDocxThemeResolver, DOCX_WORDPROCESSING_NAMESPACES, xmlAttributeNamespace, parseDocxTwipsMeasure } from "./0~3534.js";
4
4
  function docxCaptionSequenceKind(instruction) {
5
5
  const identifier = /^\s*SEQ\s+([^\s\\]+)/i.exec(instruction)?.[1]?.toLowerCase();
6
6
  if (!identifier) return null;
@@ -158,6 +158,428 @@ function fieldRange(field, indexes) {
158
158
  function containsRange(outer, inner) {
159
159
  return outer.start >= 0 && inner.start >= 0 && outer.start < inner.start && outer.end >= inner.end;
160
160
  }
161
+ const WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
162
+ const STRICT_WORD_NAMESPACE = 'http://purl.oclc.org/ooxml/wordprocessingml/main';
163
+ const WORD_NAMESPACES = new Set([
164
+ WORD_NAMESPACE,
165
+ STRICT_WORD_NAMESPACE
166
+ ]);
167
+ const MARKUP_COMPATIBILITY_NAMESPACE = 'http://schemas.openxmlformats.org/markup-compatibility/2006';
168
+ const MAX_IMPORTED_CONTENT_CONTROLS = 4096;
169
+ const MAX_CONTENT_CONTROL_TEXT = 1000000;
170
+ const RUN_CONTENT_NAMES = new Set([
171
+ 'br',
172
+ 'cr',
173
+ 'noBreakHyphen',
174
+ 'softHyphen',
175
+ 'tab',
176
+ 't'
177
+ ]);
178
+ const PROPERTY_NAMES = new Set([
179
+ 'alias',
180
+ 'id',
181
+ 'lock',
182
+ 'richText',
183
+ 'tag',
184
+ 'text'
185
+ ]);
186
+ const LOCK_VALUES = new Set([
187
+ 'contentLocked',
188
+ 'sdtContentLocked',
189
+ 'sdtLocked',
190
+ 'unlocked'
191
+ ]);
192
+ const APPEARANCE_VALUES = new Set([
193
+ 'boundingBox',
194
+ 'hidden',
195
+ 'tags'
196
+ ]);
197
+ function inspectDocxContentControls(document) {
198
+ let supported = 0;
199
+ let unsupported = 0;
200
+ for (const control of descendants(document, 'sdt'))if (!hasContentControlAncestor(control)) {
201
+ if (!isStructuralContentControl(control)) if (isDirectParagraphControl(control) && readContentControl(control, 0)) supported += 1;
202
+ else unsupported += 1;
203
+ }
204
+ return {
205
+ supported,
206
+ unsupported
207
+ };
208
+ }
209
+ function markDocxContentControls(document) {
210
+ const controls = [];
211
+ let unsupported = 0;
212
+ const candidates = descendants(document, 'sdt').filter((control)=>!hasContentControlAncestor(control) && !isStructuralContentControl(control));
213
+ for (const [index, control] of candidates.entries()){
214
+ if (!isDirectParagraphControl(control)) {
215
+ unsupported += 1;
216
+ continue;
217
+ }
218
+ const properties = readContentControl(control, index + 1);
219
+ if (!properties) {
220
+ unsupported += 1;
221
+ continue;
222
+ }
223
+ if (controls.length >= MAX_IMPORTED_CONTENT_CONTROLS) throw new Error('Imported DOCX exceeds the content-control limit.');
224
+ const [start, end] = contentControlMarkers(document, controls.length + 1);
225
+ if (!replaceControlWithMarkers(document, control, start, end)) {
226
+ unsupported += 1;
227
+ continue;
228
+ }
229
+ controls.push({
230
+ start,
231
+ end,
232
+ properties
233
+ });
234
+ }
235
+ return {
236
+ controls,
237
+ unsupported
238
+ };
239
+ }
240
+ function contentControlMarkers(document, initialIndex) {
241
+ const occupiedText = document.documentElement.textContent ?? '';
242
+ let index = initialIndex;
243
+ for(let attempts = 0; attempts < 1000000; attempts += 1){
244
+ const start = `__A3S_WORK_CONTENT_CONTROL_START_${index}__`;
245
+ const end = `__A3S_WORK_CONTENT_CONTROL_END_${index}__`;
246
+ if (!occupiedText.includes(start) && !occupiedText.includes(end)) return [
247
+ start,
248
+ end
249
+ ];
250
+ index += 1;
251
+ }
252
+ throw new Error('Imported DOCX content-control marker space is exhausted.');
253
+ }
254
+ function applyImportedDocxContentControlMarkers(document, markers) {
255
+ if (!markers.controls.length) return;
256
+ for (const marker of markers.controls){
257
+ const wrapper = document.createElement('span');
258
+ for (const [name, value] of Object.entries(contentControlDomAttributes(marker.properties)))if (void 0 !== value) wrapper.setAttribute(name, value);
259
+ wrapper.className = 'work-document-content-control';
260
+ wrapper.setAttribute('role', 'textbox');
261
+ wrapper.setAttribute('aria-label', marker.properties.alias || marker.properties.tag || '内容控件');
262
+ if ('contentLocked' === marker.properties.lock || 'sdtContentLocked' === marker.properties.lock) wrapper.setAttribute('contenteditable', 'false');
263
+ replaceMarkerRange(document.body, marker.start, marker.end, wrapper);
264
+ }
265
+ document.body.normalize();
266
+ }
267
+ function hasImportedDocxContentControlMarkers(markers) {
268
+ return markers.controls.length > 0;
269
+ }
270
+ function readContentControl(control, sequence) {
271
+ const definition = readDefinition(control);
272
+ if (!definition) return null;
273
+ const metadata = readProperties(definition.properties);
274
+ if (!metadata) return null;
275
+ const runs = Array.from(definition.content.children);
276
+ if (!runs.length || runs.some((run)=>!isDocxWordElement(run) || 'r' !== run.localName) || hasUnsupportedContentControlSemanticChild(definition.content) || runs.some((run)=>!validRun(run))) {
277
+ if (runs.length) return null;
278
+ }
279
+ const text = runs.map(work_docx_content_control_import_runText).join('');
280
+ if (text.length > MAX_CONTENT_CONTROL_TEXT) throw new Error('Imported DOCX content control text is too large.');
281
+ if ('text' === metadata.type && !metadata.multiLine && text.includes('\n')) return null;
282
+ const nativeId = metadata.nativeId;
283
+ return normalizeDocumentContentControlProperties({
284
+ id: `docx-content-control-${sequence}`,
285
+ nativeId,
286
+ type: metadata.type,
287
+ alias: metadata.alias,
288
+ tag: metadata.tag,
289
+ lock: metadata.lock,
290
+ multiLine: metadata.multiLine,
291
+ appearance: metadata.appearance,
292
+ color: metadata.color
293
+ });
294
+ }
295
+ function readDefinition(control) {
296
+ if (!isDocxWordElement(control) || 'sdt' !== control.localName || !isDirectParagraphControl(control) || hasContentControlRelationshipReference(control) || hasUnsupportedContentControlSemanticChild(control) || !validControlAttributes(control)) return null;
297
+ const children = Array.from(control.children);
298
+ const properties = children.filter((child)=>isDocxWordElement(child) && 'sdtPr' === child.localName);
299
+ const content = children.filter((child)=>isDocxWordElement(child) && 'sdtContent' === child.localName);
300
+ const endProperties = children.filter((child)=>isDocxWordElement(child) && 'sdtEndPr' === child.localName);
301
+ if (1 !== properties.length || 1 !== content.length || endProperties.length > 1 || children.some((child)=>!isDocxWordElement(child) || 'sdtPr' !== child.localName && 'sdtContent' !== child.localName && 'sdtEndPr' !== child.localName)) return null;
302
+ if ([
303
+ control,
304
+ properties[0],
305
+ content[0],
306
+ endProperties[0]
307
+ ].some((element)=>element && hasNonWhitespaceText(element))) return null;
308
+ if (endProperties[0] && (endProperties[0].children.length > 0 || !validContainerAttributes(endProperties[0]))) return null;
309
+ if (!validContainerAttributes(properties[0]) || !validContainerAttributes(content[0])) return null;
310
+ return {
311
+ control,
312
+ content: content[0],
313
+ properties: properties[0]
314
+ };
315
+ }
316
+ function readProperties(properties) {
317
+ if (hasContentControlRelationshipReference(properties)) return null;
318
+ const children = Array.from(properties.children);
319
+ const groups = new Map();
320
+ let appearance = 'boundingBox';
321
+ let color = null;
322
+ for (const child of children){
323
+ const namespace = child.namespaceURI ?? '';
324
+ if (isDocxWordElement(child)) {
325
+ if (!PROPERTY_NAMES.has(child.localName)) return null;
326
+ const matches = groups.get(child.localName) ?? [];
327
+ matches.push(child);
328
+ groups.set(child.localName, matches);
329
+ continue;
330
+ }
331
+ if (namespace === CONTENT_CONTROL_WORD_2012_NAMESPACE) {
332
+ if ('appearance' !== child.localName && 'color' !== child.localName) return null;
333
+ const matches = groups.get(`w15:${child.localName}`) ?? [];
334
+ matches.push(child);
335
+ groups.set(`w15:${child.localName}`, matches);
336
+ continue;
337
+ }
338
+ if (namespace !== MARKUP_COMPATIBILITY_NAMESPACE) return null;
339
+ }
340
+ if (Array.from(groups.values()).some((items)=>items.length > 1)) return null;
341
+ const id = groups.get('id')?.[0];
342
+ if (id && !validLeaf(id, new Set([
343
+ 'val'
344
+ ]))) return null;
345
+ const nativeId = id ? parseNativeId(wordAttribute(id, 'val')) : null;
346
+ if (id && null === nativeId) return null;
347
+ const alias = readStringProperty(groups.get('alias')?.[0]);
348
+ const tag = readStringProperty(groups.get('tag')?.[0]);
349
+ if (null === alias || null === tag) return null;
350
+ const lockElement = groups.get('lock')?.[0];
351
+ if (lockElement && !validLeaf(lockElement, new Set([
352
+ 'val'
353
+ ]))) return null;
354
+ const lockValue = lockElement ? wordAttribute(lockElement, 'val') : null;
355
+ const lock = lockValue ?? 'unlocked';
356
+ if (!LOCK_VALUES.has(lock)) return null;
357
+ const textElement = groups.get('text')?.[0];
358
+ const richTextElement = groups.get('richText')?.[0];
359
+ if (textElement && richTextElement) return null;
360
+ if (textElement && !validLeaf(textElement, new Set([
361
+ 'multiLine'
362
+ ]))) return null;
363
+ if (richTextElement && !validLeaf(richTextElement, new Set())) return null;
364
+ const multilineValue = textElement ? wordAttribute(textElement, 'multiLine') : null;
365
+ if (null !== multilineValue && ![
366
+ '0',
367
+ '1',
368
+ 'false',
369
+ 'off',
370
+ 'on',
371
+ 'true'
372
+ ].includes(multilineValue)) return null;
373
+ const appearanceElement = groups.get('w15:appearance')?.[0];
374
+ if (appearanceElement) {
375
+ if (!validNamespacedLeaf(appearanceElement, new Set([
376
+ 'val'
377
+ ]), CONTENT_CONTROL_WORD_2012_NAMESPACE)) return null;
378
+ const value = namespacedAttribute(appearanceElement, 'val', CONTENT_CONTROL_WORD_2012_NAMESPACE);
379
+ if (!value || !APPEARANCE_VALUES.has(value)) return null;
380
+ appearance = value;
381
+ }
382
+ const colorElement = groups.get('w15:color')?.[0];
383
+ if (colorElement) {
384
+ if (!validNamespacedLeaf(colorElement, new Set([
385
+ 'val'
386
+ ]), CONTENT_CONTROL_WORD_2012_NAMESPACE)) return null;
387
+ const value = namespacedAttribute(colorElement, 'val', CONTENT_CONTROL_WORD_2012_NAMESPACE);
388
+ if (!value || !/^[0-9a-f]{6}$/i.test(value)) return null;
389
+ color = `#${value.toLowerCase()}`;
390
+ }
391
+ return {
392
+ alias: alias ?? '',
393
+ appearance,
394
+ color,
395
+ lock: lock,
396
+ multiLine: null !== multilineValue && [
397
+ '1',
398
+ 'on',
399
+ 'true'
400
+ ].includes(multilineValue),
401
+ nativeId,
402
+ tag: tag ?? '',
403
+ type: textElement ? 'text' : 'richText'
404
+ };
405
+ }
406
+ function replaceControlWithMarkers(document, control, start, end) {
407
+ const paragraph = control.parentElement;
408
+ const content = Array.from(control.children).find((child)=>isDocxWordElement(child) && 'sdtContent' === child.localName);
409
+ if (!paragraph || !content) return false;
410
+ const startRun = work_docx_content_control_import_markerRun(document, paragraph, start);
411
+ const endRun = work_docx_content_control_import_markerRun(document, paragraph, end);
412
+ paragraph.insertBefore(startRun, control);
413
+ const runs = Array.from(content.children);
414
+ for (const run of runs)paragraph.insertBefore(run, control);
415
+ paragraph.insertBefore(endRun, control);
416
+ control.remove();
417
+ return true;
418
+ }
419
+ function work_docx_content_control_import_markerRun(document, context, value) {
420
+ const namespace = context.namespaceURI ?? WORD_NAMESPACE;
421
+ const prefix = xmlNamespacePrefix(context, namespace) ?? 'w';
422
+ const run = document.createElementNS(namespace, `${prefix}:r`);
423
+ const text = document.createElementNS(namespace, `${prefix}:t`);
424
+ text.setAttributeNS(work_docx_settings_xml_XML_NAMESPACE, 'xml:space', 'preserve');
425
+ text.textContent = value;
426
+ run.append(text);
427
+ return run;
428
+ }
429
+ function replaceMarkerRange(root, start, end, replacement) {
430
+ const startElement = replaceMarkerWithBoundary(root, start, 'start');
431
+ const endElement = replaceMarkerWithBoundary(root, end, 'end');
432
+ if (!startElement || !endElement) return;
433
+ if (startElement.parentNode === endElement.parentNode) {
434
+ const parent = startElement.parentNode;
435
+ let current = startElement.nextSibling;
436
+ while(current && current !== endElement){
437
+ const next = current.nextSibling;
438
+ replacement.append(current);
439
+ current = next;
440
+ }
441
+ if (current === endElement) {
442
+ startElement.replaceWith(replacement);
443
+ endElement.remove();
444
+ return;
445
+ }
446
+ parent?.append(replacement);
447
+ startElement.remove();
448
+ endElement.remove();
449
+ return;
450
+ }
451
+ const range = root.ownerDocument.createRange();
452
+ try {
453
+ range.setStartAfter(startElement);
454
+ range.setEndBefore(endElement);
455
+ const content = range.extractContents();
456
+ replacement.append(content);
457
+ startElement.replaceWith(replacement);
458
+ endElement.remove();
459
+ } catch {
460
+ startElement.remove();
461
+ endElement.remove();
462
+ }
463
+ }
464
+ function replaceMarkerWithBoundary(root, marker, kind) {
465
+ const node = textNodes(root).find((candidate)=>candidate.data.includes(marker));
466
+ if (!node?.parentNode) return null;
467
+ const ownerDocument = root.ownerDocument;
468
+ if (!ownerDocument) return null;
469
+ const offset = node.data.indexOf(marker);
470
+ const before = node.data.slice(0, offset);
471
+ const after = node.data.slice(offset + marker.length);
472
+ const boundary = ownerDocument.createElement('span');
473
+ boundary.dataset.contentControlBoundary = kind;
474
+ node.parentNode.insertBefore(ownerDocument.createTextNode(before), node);
475
+ node.parentNode.insertBefore(boundary, node);
476
+ if (after) node.parentNode.insertBefore(ownerDocument.createTextNode(after), node);
477
+ node.remove();
478
+ return boundary;
479
+ }
480
+ function textNodes(root) {
481
+ const walker = root.ownerDocument?.createTreeWalker(root, NodeFilter.SHOW_TEXT);
482
+ const nodes = [];
483
+ if (!walker) return nodes;
484
+ while(walker.nextNode())nodes.push(walker.currentNode);
485
+ return nodes;
486
+ }
487
+ function validControlAttributes(element) {
488
+ return validContainerAttributes(element);
489
+ }
490
+ function validRun(run) {
491
+ if (hasNonWhitespaceText(run)) return false;
492
+ let sawContent = false;
493
+ let properties = 0;
494
+ for (const child of Array.from(run.children)){
495
+ if (!isDocxWordElement(child)) return false;
496
+ if ('rPr' === child.localName) {
497
+ properties += 1;
498
+ if (properties > 1 || sawContent) return false;
499
+ if (hasContentControlRelationshipReference(child)) return false;
500
+ continue;
501
+ }
502
+ if (!RUN_CONTENT_NAMES.has(child.localName)) return false;
503
+ sawContent = true;
504
+ if ('t' === child.localName && (child.textContent?.length ?? 0) > MAX_CONTENT_CONTROL_TEXT) return false;
505
+ }
506
+ return true;
507
+ }
508
+ function work_docx_content_control_import_runText(run) {
509
+ let value = '';
510
+ for (const child of Array.from(run.children))if (isDocxWordElement(child)) {
511
+ if ('t' === child.localName) value += child.textContent ?? '';
512
+ else if ('tab' === child.localName) value += '\t';
513
+ else if ('br' === child.localName || 'cr' === child.localName) value += '\n';
514
+ else if ('noBreakHyphen' === child.localName) value += '\u2011';
515
+ else if ('softHyphen' === child.localName) value += '\u00ad';
516
+ }
517
+ return value;
518
+ }
519
+ function isDirectParagraphControl(control) {
520
+ return isDocxWordElement(control) && Boolean(control.parentElement && isDocxWordElement(control.parentElement) && 'p' === control.parentElement.localName);
521
+ }
522
+ function hasContentControlAncestor(control) {
523
+ let current = control.parentElement;
524
+ while(current){
525
+ if (isDocxWordElement(current) && 'sdt' === current.localName) return true;
526
+ current = current.parentElement;
527
+ }
528
+ return false;
529
+ }
530
+ function isStructuralContentControl(control) {
531
+ const properties = Array.from(control.children).find((child)=>isDocxWordElement(child) && 'sdtPr' === child.localName);
532
+ if (!properties) return false;
533
+ return Array.from(properties.children).some((child)=>isDocxWordElement(child) && [
534
+ 'docPartObj',
535
+ 'docPartList'
536
+ ].includes(child.localName));
537
+ }
538
+ function wordAttribute(element, localName) {
539
+ const matches = Array.from(element.attributes).filter((item)=>xmlAttributeLocalName(item) === localName && xmlAttributeNamespace(element, item) === element.namespaceURI && WORD_NAMESPACES.has(element.namespaceURI ?? ''));
540
+ return 1 === matches.length ? matches[0].value : null;
541
+ }
542
+ function namespacedAttribute(element, localName, namespace) {
543
+ const matches = Array.from(element.attributes).filter((item)=>xmlAttributeLocalName(item) === localName && xmlAttributeNamespace(element, item) === namespace);
544
+ return 1 === matches.length ? matches[0].value : null;
545
+ }
546
+ function readStringProperty(element) {
547
+ if (!element) return '';
548
+ if (!validLeaf(element, new Set([
549
+ 'val'
550
+ ]))) return null;
551
+ const value = wordAttribute(element, 'val');
552
+ if (null === value || /[\u0000-\u001f\u007f]/u.test(value)) return null;
553
+ return value.slice(0, 255);
554
+ }
555
+ function validContainerAttributes(element) {
556
+ return Array.from(element.attributes).every((item)=>{
557
+ const namespace = xmlAttributeNamespace(element, item);
558
+ return 'http://www.w3.org/2000/xmlns/' === namespace || namespace === MARKUP_COMPATIBILITY_NAMESPACE;
559
+ });
560
+ }
561
+ function hasNonWhitespaceText(element) {
562
+ return Array.from(element.childNodes).some((child)=>child.nodeType === Node.TEXT_NODE && Boolean(child.textContent?.trim()));
563
+ }
564
+ function validLeaf(element, allowedAttributes) {
565
+ return 0 === element.children.length && Array.from(element.childNodes).every((child)=>child.nodeType !== Node.TEXT_NODE || !(child.textContent ?? '').trim()) && Array.from(element.attributes).every((item)=>{
566
+ const namespace = xmlAttributeNamespace(element, item);
567
+ if ('http://www.w3.org/2000/xmlns/' === namespace) return true;
568
+ if (namespace === MARKUP_COMPATIBILITY_NAMESPACE) return true;
569
+ return namespace === element.namespaceURI && WORD_NAMESPACES.has(element.namespaceURI ?? '') && allowedAttributes.has(xmlAttributeLocalName(item));
570
+ });
571
+ }
572
+ function validNamespacedLeaf(element, allowedAttributes, namespace) {
573
+ return 0 === element.children.length && Array.from(element.childNodes).every((child)=>child.nodeType !== Node.TEXT_NODE || !(child.textContent ?? '').trim()) && Array.from(element.attributes).every((item)=>{
574
+ const attributeNamespace = xmlAttributeNamespace(element, item);
575
+ return 'http://www.w3.org/2000/xmlns/' === attributeNamespace || attributeNamespace === namespace && allowedAttributes.has(xmlAttributeLocalName(item));
576
+ });
577
+ }
578
+ function parseNativeId(value) {
579
+ if (null === value || !/^-?(0|[1-9][0-9]{0,9})$/u.test(value)) return null;
580
+ const parsed = Number(value);
581
+ return Number.isSafeInteger(parsed) && parsed >= -2147483648 && parsed <= 2147483647 ? parsed : null;
582
+ }
161
583
  function isDocxEquationLikeRoot(element) {
162
584
  return 'oMath' === element.localName || 'oMathPara' === element.localName;
163
585
  }
@@ -276,7 +698,7 @@ function wordPrefix(element, namespace) {
276
698
  }
277
699
  const TRANSITIONAL_MATH_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/math';
278
700
  const STRICT_MATH_NAMESPACE = 'http://purl.oclc.org/ooxml/officeDocument/math';
279
- const STRICT_WORD_NAMESPACE = 'http://purl.oclc.org/ooxml/wordprocessingml/main';
701
+ const work_docx_equation_import_STRICT_WORD_NAMESPACE = 'http://purl.oclc.org/ooxml/wordprocessingml/main';
280
702
  const DOCX_MATH_NAMESPACES = new Set([
281
703
  TRANSITIONAL_MATH_NAMESPACE,
282
704
  STRICT_MATH_NAMESPACE
@@ -1982,7 +2404,7 @@ function parseWordPosition(element) {
1982
2404
  const source = attributes.get('val')?.trim() ?? '';
1983
2405
  const integer = wordIntegerValue(source, MIN_WORD_POSITION_HALF_POINTS, MAX_WORD_POSITION_HALF_POINTS);
1984
2406
  if (null !== integer) return integer;
1985
- return element.namespaceURI === STRICT_WORD_NAMESPACE ? strictUniversalHalfPoints(source, MIN_WORD_POSITION_HALF_POINTS, MAX_WORD_POSITION_HALF_POINTS) : null;
2407
+ return element.namespaceURI === work_docx_equation_import_STRICT_WORD_NAMESPACE ? strictUniversalHalfPoints(source, MIN_WORD_POSITION_HALF_POINTS, MAX_WORD_POSITION_HALF_POINTS) : null;
1986
2408
  }
1987
2409
  function parseWordHalfPointSize(element) {
1988
2410
  if (!element) return;
@@ -1992,7 +2414,7 @@ function parseWordHalfPointSize(element) {
1992
2414
  if (!attributes || 1 !== attributes.size) return null;
1993
2415
  const source = attributes.get('val')?.trim() ?? '';
1994
2416
  const integer = wordIntegerValue(source, 1, MAX_WORD_HALF_POINT_SIZE);
1995
- const halfPoints = integer ?? (element.namespaceURI === STRICT_WORD_NAMESPACE ? strictUniversalHalfPoints(source, 1, MAX_WORD_HALF_POINT_SIZE) : null);
2417
+ const halfPoints = integer ?? (element.namespaceURI === work_docx_equation_import_STRICT_WORD_NAMESPACE ? strictUniversalHalfPoints(source, 1, MAX_WORD_HALF_POINT_SIZE) : null);
1996
2418
  return null === halfPoints ? null : halfPoints / 2;
1997
2419
  }
1998
2420
  function wordIntegerValue(source, minimum, maximum) {
@@ -2138,7 +2560,7 @@ function parseWordFitText(element) {
2138
2560
  if (!attributes?.has('val')) return null;
2139
2561
  const source = attributes.get('val')?.trim() ?? '';
2140
2562
  const integer = wordIntegerValue(source, 0, MAX_WORD_FIT_TEXT_WIDTH_TWIPS);
2141
- const widthTwips = integer ?? (element.namespaceURI === STRICT_WORD_NAMESPACE ? strictUniversalTwips(source, 0, MAX_WORD_FIT_TEXT_WIDTH_TWIPS) : null);
2563
+ const widthTwips = integer ?? (element.namespaceURI === work_docx_equation_import_STRICT_WORD_NAMESPACE ? strictUniversalTwips(source, 0, MAX_WORD_FIT_TEXT_WIDTH_TWIPS) : null);
2142
2564
  const id = attributes.has('id') ? wordIntegerValue(attributes.get('id')?.trim() ?? '', MIN_WORD_FIT_TEXT_ID, MAX_WORD_FIT_TEXT_ID) : void 0;
2143
2565
  return null === widthTwips || null === id ? null : {
2144
2566
  widthTwips,
@@ -4073,293 +4495,222 @@ function nextEquationMarker(state) {
4073
4495
  state.occupiedText += marker;
4074
4496
  return marker;
4075
4497
  }
4076
- const WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
4077
- const work_docx_text_box_import_STRICT_WORD_NAMESPACE = 'http://purl.oclc.org/ooxml/wordprocessingml/main';
4078
- const WORDPROCESSING_DRAWING_NAMESPACES = new Set([
4079
- 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',
4080
- 'http://purl.oclc.org/ooxml/drawingml/wordprocessingDrawing'
4081
- ]);
4082
- const DRAWING_NAMESPACES = new Set([
4083
- 'http://schemas.openxmlformats.org/drawingml/2006/main',
4084
- 'http://purl.oclc.org/ooxml/drawingml/main'
4085
- ]);
4086
- const WORDPROCESSING_SHAPE_NAMESPACES = new Set([
4087
- 'http://schemas.microsoft.com/office/word/2010/wordprocessingShape'
4088
- ]);
4089
- const work_docx_text_box_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
4090
- const WORDPROCESSING_SHAPE_URI = 'http://schemas.microsoft.com/office/word/2010/wordprocessingShape';
4091
- const EMUS_PER_MILLIMETER = 36000;
4092
- const MAX_IMPORTED_TEXT_BOXES = 1024;
4093
- const TEXT_BOX_MARKER_PATTERN = /__A3S_WORK_TEXT_BOX_\d+__/g;
4094
- const TEXT_BOX_RUN_CONTENT_NAMES = new Set([
4095
- 'br',
4096
- 'cr',
4097
- 'noBreakHyphen',
4098
- 'softHyphen',
4099
- 'sym',
4100
- 'tab',
4101
- 't'
4102
- ]);
4103
- function markDocxTextBoxes(document) {
4104
- const textBoxes = [];
4105
- const drawings = docxDrawings(document);
4106
- let nextMarker = 1;
4107
- for (const drawing of drawings){
4108
- const shape = supportedTextBoxShape(drawing);
4109
- if (!shape) continue;
4110
- const paragraph = work_docx_text_box_import_closestAncestor(drawing, 'p');
4111
- const run = work_docx_text_box_import_closestAncestor(drawing, 'r');
4112
- if (!paragraph || !run || !isSoleDrawingParagraph(paragraph, run)) continue;
4113
- if (textBoxes.length >= MAX_IMPORTED_TEXT_BOXES) throw new Error('Imported DOCX exceeds the text-box limit.');
4114
- const marker = nextTextBoxMarker(document, nextMarker);
4115
- nextMarker += 1;
4116
- const properties = textBoxProperties(drawing, shape, textBoxes.length + 1);
4117
- replaceParagraphWithTextBoxRuns(document, paragraph, shape.content, marker);
4118
- textBoxes.push({
4119
- marker,
4120
- properties
4121
- });
4498
+ const work_docx_index_import_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
4499
+ const work_docx_index_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
4500
+ function markDocxIndexes(document) {
4501
+ const fields = docxFieldOccurrences(document);
4502
+ const entries = fields.flatMap((field, index)=>{
4503
+ const parsed = parseDocumentIndexEntryInstruction(field.instruction);
4504
+ if (!parsed.supported || !docxFieldOccurrenceIsInlineEditable(field)) return [];
4505
+ const marker = {
4506
+ start: `__A3S_WORK_INDEX_ENTRY_START_${index + 1}__`,
4507
+ end: `__A3S_WORK_INDEX_ENTRY_END_${index + 1}__`,
4508
+ id: `index-entry-import-${index + 1}`,
4509
+ value: parsed.value
4510
+ };
4511
+ insertFieldBoundaryMarkers(document, field, marker.start, marker.end);
4512
+ return [
4513
+ marker
4514
+ ];
4515
+ });
4516
+ const indexes = [];
4517
+ for (const field of fields){
4518
+ if (!supportedDocxIndexField(field)) continue;
4519
+ const parsed = parseDocumentIndexInstruction(field.instruction);
4520
+ if (!parsed.supported) continue;
4521
+ const control = work_docx_index_import_closestAncestor(field.start, 'sdt');
4522
+ if (!control || !document.documentElement.contains(control)) continue;
4523
+ const index = indexes.length + 1;
4524
+ const marker = {
4525
+ marker: `__A3S_WORK_DOCUMENT_INDEX_${index}__`,
4526
+ id: `document-index-import-${index}`,
4527
+ options: {
4528
+ ...parsed.options,
4529
+ leader: importedIndexLeader(control, parsed.options)
4530
+ },
4531
+ entries: importedIndexEntries(control, index)
4532
+ };
4533
+ control.replaceWith(markerParagraph(document, marker.marker));
4534
+ indexes.push(marker);
4122
4535
  }
4123
4536
  return {
4124
- textBoxes
4537
+ entries,
4538
+ indexes
4125
4539
  };
4126
4540
  }
4127
- function inspectDocxTextBoxes(document) {
4128
- let supported = 0;
4129
- let unsupported = 0;
4130
- for (const drawing of docxDrawings(document)){
4131
- if (!textBoxShapeCandidate(drawing)) continue;
4132
- const shape = supportedTextBoxShape(drawing);
4133
- if (!shape) {
4134
- unsupported += 1;
4135
- continue;
4136
- }
4137
- const paragraph = work_docx_text_box_import_closestAncestor(drawing, 'p');
4138
- const run = work_docx_text_box_import_closestAncestor(drawing, 'r');
4139
- if (paragraph && run && isSoleDrawingParagraph(paragraph, run)) supported += 1;
4140
- else unsupported += 1;
4541
+ function applyImportedDocxIndexMarkers(document, markers) {
4542
+ for (const entry of markers.entries){
4543
+ const html = documentIndexEntryHtml({
4544
+ id: entry.id,
4545
+ ...entry.value
4546
+ });
4547
+ const parsed = document.createRange().createContextualFragment(html);
4548
+ const replacement = parsed.firstElementChild;
4549
+ if (replacement instanceof HTMLElement) work_docx_index_import_replaceMarkerRange(document.body, entry.start, entry.end, replacement);
4141
4550
  }
4142
- return {
4143
- supported,
4144
- unsupported
4145
- };
4146
- }
4147
- function applyImportedDocxTextBoxMarkers(document, markers) {
4148
- if (!markers.textBoxes.length) return;
4149
- const byMarker = new Map(markers.textBoxes.map((textBox)=>[
4150
- textBox.marker,
4151
- textBox
4152
- ]));
4153
- const nodes = textNodes(document.body);
4154
- for (const node of nodes){
4155
- if (!node.data.includes('__A3S_WORK_TEXT_BOX_')) continue;
4156
- const match = node.data.match(TEXT_BOX_MARKER_PATTERN)?.find((value)=>byMarker.has(value));
4157
- if (!match) continue;
4158
- const textBox = byMarker.get(match);
4159
- if (!textBox) continue;
4160
- node.data = node.data.replace(match, '');
4161
- const block = closestHtmlBlock(node.parentElement);
4162
- if (!block) continue;
4163
- const wrapper = document.createElement('div');
4164
- for (const attribute of Array.from(block.attributes))if (attribute.name.startsWith('data-office-') || attribute.name.startsWith('data-document-')) wrapper.setAttribute(attribute.name, attribute.value);
4165
- for (const [name, value] of Object.entries(textBoxDomAttributes(textBox.properties)))if (void 0 !== value) wrapper.setAttribute(name, value);
4166
- wrapper.className = 'work-document-text-box';
4167
- wrapper.setAttribute('role', 'textbox');
4168
- wrapper.setAttribute('aria-label', '文本框');
4169
- wrapper.setAttribute('style', textBoxCss(textBox.properties));
4170
- while(block.firstChild)wrapper.append(block.firstChild);
4171
- block.replaceWith(wrapper);
4551
+ const importedEntries = Array.from(document.body.querySelectorAll('[data-document-index-entry]'));
4552
+ for (const index of markers.indexes){
4553
+ const text = work_docx_index_import_textNodes(document.body).find((node)=>node.data.includes(index.marker));
4554
+ if (!text) continue;
4555
+ const entries = index.entries.map((entry, entryIndex)=>{
4556
+ const targets = importedEntries.filter((candidate)=>normalizedTerm(candidate.dataset.indexMainEntry) === normalizedTerm(entry.mainEntry) && normalizedTerm(candidate.dataset.indexSubEntry) === normalizedTerm(entry.subEntry));
4557
+ const targetIds = targets.flatMap((candidate)=>{
4558
+ const id = candidate.dataset.indexEntryId?.trim();
4559
+ return id ? [
4560
+ id
4561
+ ] : [];
4562
+ });
4563
+ return {
4564
+ ...entry,
4565
+ pages: entry.pages.map((page)=>({
4566
+ ...page,
4567
+ targetIds: targetIds.length ? targetIds : [
4568
+ `index-entry-import-${index.id}-${entryIndex + 1}`
4569
+ ]
4570
+ }))
4571
+ };
4572
+ });
4573
+ const fragment = document.createRange().createContextualFragment(documentIndexHtml({
4574
+ id: index.id,
4575
+ options: index.options,
4576
+ entries
4577
+ }));
4578
+ closestHtmlBlock(text.parentElement)?.replaceWith(fragment);
4172
4579
  }
4173
- document.body.normalize();
4174
4580
  }
4175
- function hasImportedDocxTextBoxMarkers(markers) {
4176
- return markers.textBoxes.length > 0;
4581
+ function hasImportedDocxIndexMarkers(markers) {
4582
+ return markers.entries.length > 0 || markers.indexes.length > 0;
4177
4583
  }
4178
- function textBoxShapeCandidate(drawing) {
4179
- if (!WORDPROCESSING_DRAWING_NAMESPACES.has(drawing.namespaceURI ?? '')) return null;
4180
- const graphicData = descendants(drawing, 'graphicData').find((element)=>DRAWING_NAMESPACES.has(element.namespaceURI ?? '') && work_ooxml_package_attribute(element, 'uri') === WORDPROCESSING_SHAPE_URI);
4181
- if (!graphicData) return null;
4182
- const shape = directChild(graphicData, 'wsp');
4183
- if (!shape || !WORDPROCESSING_SHAPE_NAMESPACES.has(shape.namespaceURI ?? '')) return null;
4184
- const nonVisual = directChild(shape, 'cNvSpPr');
4185
- if (nonVisual && !WORDPROCESSING_SHAPE_NAMESPACES.has(nonVisual.namespaceURI ?? '')) return null;
4186
- const txBox = work_ooxml_package_attribute(nonVisual ?? shape, 'txBox')?.trim().toLowerCase();
4187
- if ('1' !== txBox && 'true' !== txBox) return null;
4188
- return shape;
4584
+ function supportedDocxIndexEntryField(field) {
4585
+ return parseDocumentIndexEntryInstruction(field.instruction).supported && docxFieldOccurrenceIsInlineEditable(field);
4189
4586
  }
4190
- function supportedTextBoxShape(drawing) {
4191
- const shape = textBoxShapeCandidate(drawing);
4192
- if (!shape) return null;
4193
- const txbx = directChild(shape, 'txbx');
4194
- if (txbx && !WORDPROCESSING_SHAPE_NAMESPACES.has(txbx.namespaceURI ?? '')) return null;
4195
- const content = txbx ? directChild(txbx, 'txbxContent') : void 0;
4196
- return content && isWordElement(content, 'txbxContent') && isSupportedTextBoxContent(content) ? {
4197
- shape,
4198
- content
4199
- } : null;
4587
+ function supportedDocxIndexField(field) {
4588
+ return parseDocumentIndexInstruction(field.instruction).supported && field.complete && !field.nested && !field.inDeletion && Boolean(work_docx_index_import_closestAncestor(field.start, 'sdt'));
4200
4589
  }
4201
- function isSupportedTextBoxContent(content) {
4202
- const paragraphs = work_ooxml_package_directChildren(content);
4203
- if (!paragraphs.length) return false;
4204
- for (const paragraph of paragraphs){
4205
- if (!isWordElement(paragraph, 'p')) return false;
4206
- const children = work_ooxml_package_directChildren(paragraph).filter((element)=>'pPr' !== element.localName);
4207
- for (const child of children){
4208
- if (!isWordElement(child, 'r')) return false;
4209
- const runChildren = work_ooxml_package_directChildren(child).filter((element)=>'rPr' !== element.localName);
4210
- if (runChildren.some((element)=>!isWordNamespace(element) || !TEXT_BOX_RUN_CONTENT_NAMES.has(element.localName))) return false;
4590
+ function importedIndexEntries(control, indexNumber) {
4591
+ const entries = [];
4592
+ let currentMain = '';
4593
+ let row = 0;
4594
+ for (const paragraph of descendants(control, 'p')){
4595
+ const style = directChild(directChild(paragraph, 'pPr') ?? paragraph, 'pStyle');
4596
+ const styleName = work_ooxml_package_attribute(style ?? paragraph, 'val') ?? '';
4597
+ const level = /^Index([12])$/i.exec(styleName)?.[1];
4598
+ if (!level) continue;
4599
+ row += 1;
4600
+ const parsed = importedIndexParagraph(paragraph, indexNumber, row);
4601
+ if (parsed) {
4602
+ if ('1' === level) {
4603
+ currentMain = parsed.term;
4604
+ if (!parsed.pages.length && !parsed.crossReference) continue;
4605
+ entries.push({
4606
+ mainEntry: parsed.term,
4607
+ subEntry: '',
4608
+ crossReference: parsed.crossReference,
4609
+ pages: parsed.pages
4610
+ });
4611
+ continue;
4612
+ }
4613
+ if (currentMain) entries.push({
4614
+ mainEntry: currentMain,
4615
+ subEntry: parsed.term,
4616
+ crossReference: parsed.crossReference,
4617
+ pages: parsed.pages
4618
+ });
4211
4619
  }
4212
4620
  }
4213
- return true;
4214
- }
4215
- function isWordElement(element, localName) {
4216
- return element.localName === localName && isWordNamespace(element);
4217
- }
4218
- function isWordNamespace(element) {
4219
- return element.namespaceURI === WORD_NAMESPACE || element.namespaceURI === work_docx_text_box_import_STRICT_WORD_NAMESPACE;
4621
+ return entries;
4220
4622
  }
4221
- function docxDrawings(document) {
4222
- return [
4223
- ...descendants(document, 'anchor'),
4224
- ...descendants(document, 'inline')
4225
- ].filter((element)=>WORDPROCESSING_DRAWING_NAMESPACES.has(element.namespaceURI ?? ''));
4623
+ function importedIndexParagraph(paragraph, indexNumber, row) {
4624
+ const textElements = descendants(paragraph, 't');
4625
+ const values = textElements.map((element)=>element.textContent ?? '');
4626
+ const combined = values.join('').replace(/\s+/g, ' ').trim();
4627
+ if (!combined) return null;
4628
+ const crossReference = /^(.+?),\s*(?:see|参见)\s+(.+)$/i.exec(combined);
4629
+ if (crossReference?.[1] && crossReference[2]) return {
4630
+ term: crossReference[1].trim(),
4631
+ crossReference: crossReference[2].trim(),
4632
+ pages: []
4633
+ };
4634
+ const pageElements = textElements.filter((element)=>/^\d{1,6}$/.test((element.textContent ?? '').trim()));
4635
+ const pages = pageElements.map((element, pageIndex)=>{
4636
+ const properties = directChild(work_docx_index_import_closestAncestor(element, 'r') ?? element, 'rPr');
4637
+ return {
4638
+ pageNumber: Number((element.textContent ?? '').trim()),
4639
+ pageBold: Boolean(properties && directChild(properties, 'b')),
4640
+ pageItalic: Boolean(properties && directChild(properties, 'i')),
4641
+ targetIds: [
4642
+ `index-entry-import-${indexNumber}-${row}-${pageIndex + 1}`
4643
+ ]
4644
+ };
4645
+ });
4646
+ const pageText = pageElements.map((element)=>element.textContent ?? '');
4647
+ let term = combined;
4648
+ for (const value of pageText)term = term.replace(new RegExp(`(?:,\\s*)?${escapeRegExp(value)}\\s*$`), '');
4649
+ term = term.replace(/[,\s]+$/, '').trim();
4650
+ return term ? {
4651
+ term,
4652
+ crossReference: '',
4653
+ pages
4654
+ } : null;
4226
4655
  }
4227
- function isSoleDrawingParagraph(paragraph, run) {
4228
- const meaningful = work_ooxml_package_directChildren(paragraph).filter((element)=>'pPr' !== element.localName);
4229
- if (1 !== meaningful.length || meaningful[0] !== run) return false;
4230
- const runContent = work_ooxml_package_directChildren(run).filter((element)=>'rPr' !== element.localName);
4231
- return 1 === runContent.length && runContent[0]?.localName === 'drawing';
4656
+ function importedIndexLeader(control, options) {
4657
+ if (!options.rightAlignPageNumbers) return 'none';
4658
+ const tab = descendants(control, 'tab').find((candidate)=>candidate.parentElement?.localName === 'tabs' && 'right' === work_ooxml_package_attribute(candidate, 'val'));
4659
+ const leader = work_ooxml_package_attribute(tab ?? control, 'leader');
4660
+ if ('hyphen' === leader) return 'dash';
4661
+ if ('underscore' === leader) return 'underline';
4662
+ if (!leader || 'none' === leader) return 'none';
4663
+ return 'dot';
4232
4664
  }
4233
- function replaceParagraphWithTextBoxRuns(document, paragraph, content, marker) {
4234
- const namespace = paragraph.namespaceURI || WORD_NAMESPACE;
4235
- const prefix = paragraph.prefix ? `${paragraph.prefix}:` : 'w:';
4236
- const paragraphProperties = directChild(paragraph, 'pPr');
4237
- const runs = [];
4238
- const sourceParagraphs = work_ooxml_package_directChildren(content, 'p');
4239
- for (const [paragraphIndex, sourceParagraph] of sourceParagraphs.entries()){
4240
- if (paragraphIndex > 0) runs.push(createBreakRun(document, namespace, prefix));
4241
- const sourceRuns = work_ooxml_package_directChildren(sourceParagraph, 'r');
4242
- for (const sourceRun of sourceRuns)runs.push(document.importNode(sourceRun, true));
4665
+ function insertFieldBoundaryMarkers(document, field, start, end) {
4666
+ if ('fldChar' === field.start.localName && 'fldChar' === field.end.localName) {
4667
+ field.start.parentNode?.insertBefore(markerText(document, start), field.start);
4668
+ field.end.parentNode?.insertBefore(markerText(document, end), field.end.nextSibling);
4669
+ return;
4243
4670
  }
4244
- const markerRun = createTextRun(document, namespace, prefix, marker);
4245
- paragraph.replaceChildren(...paragraphProperties ? [
4246
- paragraphProperties
4247
- ] : [], markerRun, ...runs);
4671
+ field.start.parentNode?.insertBefore(work_docx_index_import_markerRun(document, start), field.start);
4672
+ field.end.parentNode?.insertBefore(work_docx_index_import_markerRun(document, end), field.end.nextSibling);
4248
4673
  }
4249
- function createTextRun(document, namespace, prefix, textValue) {
4250
- const run = document.createElementNS(namespace, `${prefix}r`);
4251
- const text = document.createElementNS(namespace, `${prefix}t`);
4252
- text.setAttributeNS(work_docx_text_box_import_XML_NAMESPACE, 'xml:space', 'preserve');
4253
- text.textContent = textValue;
4254
- run.append(text);
4255
- return run;
4674
+ function markerParagraph(document, marker) {
4675
+ const paragraph = document.createElementNS(work_docx_index_import_WORD_NAMESPACE, 'w:p');
4676
+ paragraph.append(work_docx_index_import_markerRun(document, marker));
4677
+ return paragraph;
4256
4678
  }
4257
- function createBreakRun(document, namespace, prefix) {
4258
- const run = document.createElementNS(namespace, `${prefix}r`);
4259
- run.append(document.createElementNS(namespace, `${prefix}br`));
4679
+ function work_docx_index_import_markerRun(document, value) {
4680
+ const run = document.createElementNS(work_docx_index_import_WORD_NAMESPACE, 'w:r');
4681
+ run.append(markerText(document, value));
4260
4682
  return run;
4261
4683
  }
4262
- function textBoxProperties(drawing, shape, index) {
4263
- const extent = directChild(drawing, 'extent');
4264
- const shapeProperties = directChild(shape.shape, 'spPr');
4265
- const transform = shapeProperties ? directChild(shapeProperties, 'xfrm') : void 0;
4266
- const extension = directChild(transform ?? shapeProperties ?? shape.shape, 'ext');
4267
- const width = emuMillimeters(work_ooxml_package_attribute(extent ?? extension ?? shape.shape, 'cx') ?? work_ooxml_package_attribute(extent ?? extension ?? shape.shape, 'x'), 120);
4268
- const height = emuMillimeters(work_ooxml_package_attribute(extent ?? extension ?? shape.shape, 'cy') ?? work_ooxml_package_attribute(extent ?? extension ?? shape.shape, 'y'), 45);
4269
- const docProperties = directChild(drawing, 'docPr');
4270
- const docPropertiesId = integerAttribute(docProperties, 'id');
4271
- const sourceName = attributeOptional(docProperties, 'name')?.trim() ?? '';
4272
- const id = sourceName.startsWith('A3S Text Box ') ? sourceName.slice(13).trim() : null === docPropertiesId ? `docx-text-box-${index}` : `docx-text-box-${docPropertiesId}`;
4273
- const bodyProperties = directChild(shape.shape, 'bodyPr');
4274
- const horizontal = directChild(drawing, 'positionH');
4275
- const vertical = directChild(drawing, 'positionV');
4276
- const layout = 'anchor' === drawing.localName ? 'floating' : 'inline';
4277
- const fill = shapeFill(shapeProperties);
4278
- const border = shapeBorder(shapeProperties);
4279
- return normalizeDocumentTextBoxProperties({
4280
- id,
4281
- width,
4282
- height,
4283
- layout,
4284
- horizontalOffset: positionOffset(horizontal),
4285
- verticalOffset: positionOffset(vertical),
4286
- horizontalReference: positionReference(horizontal, 'column'),
4287
- verticalReference: positionReference(vertical, 'paragraph'),
4288
- fill,
4289
- borderColor: border.color,
4290
- borderWidth: border.width,
4291
- padding: bodyPadding(bodyProperties),
4292
- verticalAlign: bodyVerticalAlign(bodyProperties),
4293
- docPropertiesId
4294
- });
4295
- }
4296
- function shapeFill(shapeProperties) {
4297
- if (!shapeProperties || directChild(shapeProperties, 'noFill')) return 'transparent';
4298
- const fill = directChild(shapeProperties, 'solidFill');
4299
- const rgb = fill ? directChild(fill, 'srgbClr') : void 0;
4300
- const value = attributeOptional(rgb, 'val')?.trim();
4301
- return value && /^[0-9a-f]{6}$/i.test(value) ? `#${value}` : 'transparent';
4684
+ function markerText(document, value) {
4685
+ const text = document.createElementNS(work_docx_index_import_WORD_NAMESPACE, 'w:t');
4686
+ text.setAttributeNS(work_docx_index_import_XML_NAMESPACE, 'xml:space', 'preserve');
4687
+ text.textContent = value;
4688
+ return text;
4302
4689
  }
4303
- function shapeBorder(shapeProperties) {
4304
- const line = shapeProperties ? directChild(shapeProperties, 'ln') : void 0;
4305
- if (!line || directChild(line, 'noFill')) return {
4306
- color: 'none',
4307
- width: 0
4308
- };
4309
- const fill = directChild(line, 'solidFill');
4310
- const rgb = fill ? directChild(fill, 'srgbClr') : void 0;
4311
- const value = attributeOptional(rgb, 'val')?.trim();
4312
- return {
4313
- color: value && /^[0-9a-f]{6}$/i.test(value) ? `#${value}` : '#4472c4',
4314
- width: emuMillimeters(work_ooxml_package_attribute(line, 'w'), 0.35)
4315
- };
4690
+ function work_docx_index_import_replaceMarkerRange(root, start, end, replacement) {
4691
+ const nodes = work_docx_index_import_textNodes(root);
4692
+ const startNode = nodes.find((node)=>node.data.includes(start));
4693
+ const endNode = nodes.find((node)=>node.data.includes(end));
4694
+ if (!startNode || !endNode) return;
4695
+ const range = root.ownerDocument.createRange();
4696
+ range.setStart(startNode, startNode.data.indexOf(start));
4697
+ range.setEnd(endNode, endNode.data.indexOf(end) + end.length);
4698
+ range.deleteContents();
4699
+ range.insertNode(replacement);
4316
4700
  }
4317
- function bodyPadding(bodyProperties) {
4318
- if (!bodyProperties) return 3;
4319
- const values = [
4320
- 'lIns',
4321
- 'rIns',
4322
- 'tIns',
4323
- 'bIns'
4324
- ].map((name)=>emuMillimeters(attributeOptional(bodyProperties, name), 3));
4325
- return Math.min(...values);
4326
- }
4327
- function bodyVerticalAlign(bodyProperties) {
4328
- const value = attributeOptional(bodyProperties, 'anchor');
4329
- if ('ctr' === value) return 'center';
4330
- if ('b' === value) return 'bottom';
4331
- return 'top';
4332
- }
4333
- function positionOffset(element) {
4334
- const offset = element ? directChild(element, 'posOffset') : void 0;
4335
- if (!offset?.textContent?.trim()) return null;
4336
- const value = Number(offset.textContent);
4337
- return Number.isFinite(value) ? value / EMUS_PER_MILLIMETER : null;
4338
- }
4339
- function positionReference(element, fallback) {
4340
- const value = attributeOptional(element, 'relativeFrom');
4341
- if ('margin' === value || 'page' === value || 'column' === value) return value;
4342
- if ('paragraph' === value) return value;
4343
- return fallback;
4344
- }
4345
- function emuMillimeters(value, fallback) {
4346
- const number = null === value ? NaN : Number(value);
4347
- return Number.isFinite(number) && number >= 0 ? number / EMUS_PER_MILLIMETER : fallback;
4348
- }
4349
- function integerAttribute(element, name) {
4350
- if (!element) return null;
4351
- const value = Number(attributeOptional(element, name));
4352
- return Number.isSafeInteger(value) && value >= 0 ? value : null;
4353
- }
4354
- function attributeOptional(element, name) {
4355
- return element ? work_ooxml_package_attribute(element, name) : null;
4701
+ function work_docx_index_import_textNodes(root) {
4702
+ const walker = root.ownerDocument?.createTreeWalker(root, NodeFilter.SHOW_TEXT);
4703
+ const nodes = [];
4704
+ if (!walker) return nodes;
4705
+ while(walker.nextNode())nodes.push(walker.currentNode);
4706
+ return nodes;
4356
4707
  }
4357
- function nextTextBoxMarker(document, start) {
4358
- let index = start;
4359
- while(document.documentElement.textContent?.includes(`__A3S_WORK_TEXT_BOX_${index}__`))index += 1;
4360
- return `__A3S_WORK_TEXT_BOX_${index}__`;
4708
+ function closestHtmlBlock(element) {
4709
+ let current = element;
4710
+ while(current && current.parentElement?.tagName.toLowerCase() !== 'body')current = current.parentElement;
4711
+ return current;
4361
4712
  }
4362
- function work_docx_text_box_import_closestAncestor(element, localName) {
4713
+ function work_docx_index_import_closestAncestor(element, localName) {
4363
4714
  let current = element;
4364
4715
  while(current){
4365
4716
  if (current.localName === localName) return current;
@@ -4367,327 +4718,92 @@ function work_docx_text_box_import_closestAncestor(element, localName) {
4367
4718
  }
4368
4719
  return null;
4369
4720
  }
4370
- function closestHtmlBlock(element) {
4371
- if (!element) return null;
4372
- const block = element.closest('p, h1, h2, h3, h4, h5, h6, li, blockquote, td, th');
4373
- return block instanceof HTMLElement ? block : null;
4721
+ function normalizedTerm(value) {
4722
+ return (value ?? '').normalize('NFKC').replace(/\s+/g, ' ').trim().toLowerCase();
4374
4723
  }
4375
- function textNodes(root) {
4376
- const walker = root.ownerDocument?.createTreeWalker(root, NodeFilter.SHOW_TEXT);
4377
- const nodes = [];
4378
- if (!walker) return nodes;
4379
- while(walker.nextNode())nodes.push(walker.currentNode);
4380
- return nodes;
4724
+ function escapeRegExp(value) {
4725
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
4381
4726
  }
4382
- const work_docx_index_import_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
4383
- const work_docx_index_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
4384
- function markDocxIndexes(document) {
4385
- const fields = docxFieldOccurrences(document);
4386
- const entries = fields.flatMap((field, index)=>{
4387
- const parsed = parseDocumentIndexEntryInstruction(field.instruction);
4388
- if (!parsed.supported || !docxFieldOccurrenceIsInlineEditable(field)) return [];
4389
- const marker = {
4390
- start: `__A3S_WORK_INDEX_ENTRY_START_${index + 1}__`,
4391
- end: `__A3S_WORK_INDEX_ENTRY_END_${index + 1}__`,
4392
- id: `index-entry-import-${index + 1}`,
4393
- value: parsed.value
4394
- };
4395
- insertFieldBoundaryMarkers(document, field, marker.start, marker.end);
4396
- return [
4397
- marker
4398
- ];
4399
- });
4400
- const indexes = [];
4401
- for (const field of fields){
4402
- if (!supportedDocxIndexField(field)) continue;
4403
- const parsed = parseDocumentIndexInstruction(field.instruction);
4404
- if (!parsed.supported) continue;
4405
- const control = work_docx_index_import_closestAncestor(field.start, 'sdt');
4406
- if (!control || !document.documentElement.contains(control)) continue;
4407
- const index = indexes.length + 1;
4408
- const marker = {
4409
- marker: `__A3S_WORK_DOCUMENT_INDEX_${index}__`,
4410
- id: `document-index-import-${index}`,
4411
- options: {
4412
- ...parsed.options,
4413
- leader: importedIndexLeader(control, parsed.options)
4414
- },
4415
- entries: importedIndexEntries(control, index)
4416
- };
4417
- control.replaceWith(markerParagraph(document, marker.marker));
4418
- indexes.push(marker);
4727
+ const work_docx_numbering_change_import_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
4728
+ const work_docx_numbering_change_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
4729
+ const MAX_NUMBERING_CHANGES = 65536;
4730
+ const NUMBERING_CHANGE_MARKER_PATTERN = /__A3S_WORK_NUMBERING_CHANGE_\d+__/g;
4731
+ const ORIGINAL_SEGMENT_PATTERN = /%([1-9]):([1-9]\d{0,9}):(\d{1,2}):([^%\u0000-\u001f\u007f]{1,32})/gy;
4732
+ function markDocxNumberingChanges(document) {
4733
+ const groups = [];
4734
+ let active;
4735
+ let markerIndex = 0;
4736
+ for (const paragraph of descendants(document, 'p')){
4737
+ if (!isWordElement(paragraph)) {
4738
+ active = void 0;
4739
+ continue;
4740
+ }
4741
+ const change = supportedNumberingChangeInParagraph(paragraph);
4742
+ if (!change || markerIndex >= MAX_NUMBERING_CHANGES) {
4743
+ active = void 0;
4744
+ continue;
4745
+ }
4746
+ const continues = active && continuesGroup(active.change, change);
4747
+ if (!continues) {
4748
+ const group = {
4749
+ markers: [],
4750
+ id: `docx-numbering-change-${change.id}`,
4751
+ author: change.author,
4752
+ date: change.date,
4753
+ start: change.value,
4754
+ level: change.level,
4755
+ format: change.format,
4756
+ suffix: change.suffix
4757
+ };
4758
+ groups.push(group);
4759
+ active = {
4760
+ change,
4761
+ group
4762
+ };
4763
+ }
4764
+ markerIndex += 1;
4765
+ const marker = `__A3S_WORK_NUMBERING_CHANGE_${markerIndex}__`;
4766
+ insertParagraphMarker(document, change.paragraph, change.properties, marker);
4767
+ active?.group.markers.push(marker);
4768
+ if (active) active.change = change;
4419
4769
  }
4420
4770
  return {
4421
- entries,
4422
- indexes
4771
+ groups
4423
4772
  };
4424
4773
  }
4425
- function applyImportedDocxIndexMarkers(document, markers) {
4426
- for (const entry of markers.entries){
4427
- const html = documentIndexEntryHtml({
4428
- id: entry.id,
4429
- ...entry.value
4430
- });
4431
- const parsed = document.createRange().createContextualFragment(html);
4432
- const replacement = parsed.firstElementChild;
4433
- if (replacement instanceof HTMLElement) replaceMarkerRange(document.body, entry.start, entry.end, replacement);
4434
- }
4435
- const importedEntries = Array.from(document.body.querySelectorAll('[data-document-index-entry]'));
4436
- for (const index of markers.indexes){
4437
- const text = work_docx_index_import_textNodes(document.body).find((node)=>node.data.includes(index.marker));
4438
- if (!text) continue;
4439
- const entries = index.entries.map((entry, entryIndex)=>{
4440
- const targets = importedEntries.filter((candidate)=>normalizedTerm(candidate.dataset.indexMainEntry) === normalizedTerm(entry.mainEntry) && normalizedTerm(candidate.dataset.indexSubEntry) === normalizedTerm(entry.subEntry));
4441
- const targetIds = targets.flatMap((candidate)=>{
4442
- const id = candidate.dataset.indexEntryId?.trim();
4443
- return id ? [
4444
- id
4445
- ] : [];
4446
- });
4447
- return {
4448
- ...entry,
4449
- pages: entry.pages.map((page)=>({
4450
- ...page,
4451
- targetIds: targetIds.length ? targetIds : [
4452
- `index-entry-import-${index.id}-${entryIndex + 1}`
4453
- ]
4454
- }))
4455
- };
4456
- });
4457
- const fragment = document.createRange().createContextualFragment(documentIndexHtml({
4458
- id: index.id,
4459
- options: index.options,
4460
- entries
4461
- }));
4462
- work_docx_index_import_closestHtmlBlock(text.parentElement)?.replaceWith(fragment);
4774
+ function applyImportedDocxNumberingChangeMarkers(document, markers) {
4775
+ const nodesByMarker = numberingMarkerNodes(document.body);
4776
+ const groupsByList = new Map();
4777
+ for (const group of markers.groups){
4778
+ const list = numberingChangeList(group, nodesByMarker);
4779
+ if (!list) continue;
4780
+ const groups = groupsByList.get(list) ?? [];
4781
+ groups.push(group);
4782
+ groupsByList.set(list, groups);
4463
4783
  }
4784
+ for (const [list, groups] of groupsByList)if (1 === groups.length && groups[0]) applyNumberingChange(list, groups[0]);
4785
+ for (const nodes of nodesByMarker.values())for (const node of nodes)node.data = node.data.replace(NUMBERING_CHANGE_MARKER_PATTERN, '');
4786
+ document.body.normalize();
4464
4787
  }
4465
- function hasImportedDocxIndexMarkers(markers) {
4466
- return markers.entries.length > 0 || markers.indexes.length > 0;
4467
- }
4468
- function supportedDocxIndexEntryField(field) {
4469
- return parseDocumentIndexEntryInstruction(field.instruction).supported && docxFieldOccurrenceIsInlineEditable(field);
4788
+ function hasImportedDocxNumberingChangeMarkers(markers) {
4789
+ return markers.groups.length > 0;
4470
4790
  }
4471
- function supportedDocxIndexField(field) {
4472
- return parseDocumentIndexInstruction(field.instruction).supported && field.complete && !field.nested && !field.inDeletion && Boolean(work_docx_index_import_closestAncestor(field.start, 'sdt'));
4791
+ function isSupportedDocxNumberingChange(change) {
4792
+ return null !== supportedNumberingChange(change);
4473
4793
  }
4474
- function importedIndexEntries(control, indexNumber) {
4475
- const entries = [];
4476
- let currentMain = '';
4477
- let row = 0;
4478
- for (const paragraph of descendants(control, 'p')){
4479
- const style = directChild(directChild(paragraph, 'pPr') ?? paragraph, 'pStyle');
4480
- const styleName = work_ooxml_package_attribute(style ?? paragraph, 'val') ?? '';
4481
- const level = /^Index([12])$/i.exec(styleName)?.[1];
4482
- if (!level) continue;
4483
- row += 1;
4484
- const parsed = importedIndexParagraph(paragraph, indexNumber, row);
4485
- if (parsed) {
4486
- if ('1' === level) {
4487
- currentMain = parsed.term;
4488
- if (!parsed.pages.length && !parsed.crossReference) continue;
4489
- entries.push({
4490
- mainEntry: parsed.term,
4491
- subEntry: '',
4492
- crossReference: parsed.crossReference,
4493
- pages: parsed.pages
4494
- });
4495
- continue;
4496
- }
4497
- if (currentMain) entries.push({
4498
- mainEntry: currentMain,
4499
- subEntry: parsed.term,
4500
- crossReference: parsed.crossReference,
4501
- pages: parsed.pages
4502
- });
4503
- }
4504
- }
4505
- return entries;
4506
- }
4507
- function importedIndexParagraph(paragraph, indexNumber, row) {
4508
- const textElements = descendants(paragraph, 't');
4509
- const values = textElements.map((element)=>element.textContent ?? '');
4510
- const combined = values.join('').replace(/\s+/g, ' ').trim();
4511
- if (!combined) return null;
4512
- const crossReference = /^(.+?),\s*(?:see|参见)\s+(.+)$/i.exec(combined);
4513
- if (crossReference?.[1] && crossReference[2]) return {
4514
- term: crossReference[1].trim(),
4515
- crossReference: crossReference[2].trim(),
4516
- pages: []
4517
- };
4518
- const pageElements = textElements.filter((element)=>/^\d{1,6}$/.test((element.textContent ?? '').trim()));
4519
- const pages = pageElements.map((element, pageIndex)=>{
4520
- const properties = directChild(work_docx_index_import_closestAncestor(element, 'r') ?? element, 'rPr');
4521
- return {
4522
- pageNumber: Number((element.textContent ?? '').trim()),
4523
- pageBold: Boolean(properties && directChild(properties, 'b')),
4524
- pageItalic: Boolean(properties && directChild(properties, 'i')),
4525
- targetIds: [
4526
- `index-entry-import-${indexNumber}-${row}-${pageIndex + 1}`
4527
- ]
4528
- };
4529
- });
4530
- const pageText = pageElements.map((element)=>element.textContent ?? '');
4531
- let term = combined;
4532
- for (const value of pageText)term = term.replace(new RegExp(`(?:,\\s*)?${escapeRegExp(value)}\\s*$`), '');
4533
- term = term.replace(/[,\s]+$/, '').trim();
4534
- return term ? {
4535
- term,
4536
- crossReference: '',
4537
- pages
4538
- } : null;
4539
- }
4540
- function importedIndexLeader(control, options) {
4541
- if (!options.rightAlignPageNumbers) return 'none';
4542
- const tab = descendants(control, 'tab').find((candidate)=>candidate.parentElement?.localName === 'tabs' && 'right' === work_ooxml_package_attribute(candidate, 'val'));
4543
- const leader = work_ooxml_package_attribute(tab ?? control, 'leader');
4544
- if ('hyphen' === leader) return 'dash';
4545
- if ('underscore' === leader) return 'underline';
4546
- if (!leader || 'none' === leader) return 'none';
4547
- return 'dot';
4548
- }
4549
- function insertFieldBoundaryMarkers(document, field, start, end) {
4550
- if ('fldChar' === field.start.localName && 'fldChar' === field.end.localName) {
4551
- field.start.parentNode?.insertBefore(markerText(document, start), field.start);
4552
- field.end.parentNode?.insertBefore(markerText(document, end), field.end.nextSibling);
4553
- return;
4554
- }
4555
- field.start.parentNode?.insertBefore(work_docx_index_import_markerRun(document, start), field.start);
4556
- field.end.parentNode?.insertBefore(work_docx_index_import_markerRun(document, end), field.end.nextSibling);
4557
- }
4558
- function markerParagraph(document, marker) {
4559
- const paragraph = document.createElementNS(work_docx_index_import_WORD_NAMESPACE, 'w:p');
4560
- paragraph.append(work_docx_index_import_markerRun(document, marker));
4561
- return paragraph;
4562
- }
4563
- function work_docx_index_import_markerRun(document, value) {
4564
- const run = document.createElementNS(work_docx_index_import_WORD_NAMESPACE, 'w:r');
4565
- run.append(markerText(document, value));
4566
- return run;
4567
- }
4568
- function markerText(document, value) {
4569
- const text = document.createElementNS(work_docx_index_import_WORD_NAMESPACE, 'w:t');
4570
- text.setAttributeNS(work_docx_index_import_XML_NAMESPACE, 'xml:space', 'preserve');
4571
- text.textContent = value;
4572
- return text;
4573
- }
4574
- function replaceMarkerRange(root, start, end, replacement) {
4575
- const nodes = work_docx_index_import_textNodes(root);
4576
- const startNode = nodes.find((node)=>node.data.includes(start));
4577
- const endNode = nodes.find((node)=>node.data.includes(end));
4578
- if (!startNode || !endNode) return;
4579
- const range = root.ownerDocument.createRange();
4580
- range.setStart(startNode, startNode.data.indexOf(start));
4581
- range.setEnd(endNode, endNode.data.indexOf(end) + end.length);
4582
- range.deleteContents();
4583
- range.insertNode(replacement);
4584
- }
4585
- function work_docx_index_import_textNodes(root) {
4586
- const walker = root.ownerDocument?.createTreeWalker(root, NodeFilter.SHOW_TEXT);
4587
- const nodes = [];
4588
- if (!walker) return nodes;
4589
- while(walker.nextNode())nodes.push(walker.currentNode);
4590
- return nodes;
4591
- }
4592
- function work_docx_index_import_closestHtmlBlock(element) {
4593
- let current = element;
4594
- while(current && current.parentElement?.tagName.toLowerCase() !== 'body')current = current.parentElement;
4595
- return current;
4596
- }
4597
- function work_docx_index_import_closestAncestor(element, localName) {
4598
- let current = element;
4599
- while(current){
4600
- if (current.localName === localName) return current;
4601
- current = current.parentElement;
4602
- }
4603
- return null;
4604
- }
4605
- function normalizedTerm(value) {
4606
- return (value ?? '').normalize('NFKC').replace(/\s+/g, ' ').trim().toLowerCase();
4607
- }
4608
- function escapeRegExp(value) {
4609
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
4610
- }
4611
- const work_docx_numbering_change_import_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
4612
- const work_docx_numbering_change_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
4613
- const MAX_NUMBERING_CHANGES = 65536;
4614
- const NUMBERING_CHANGE_MARKER_PATTERN = /__A3S_WORK_NUMBERING_CHANGE_\d+__/g;
4615
- const ORIGINAL_SEGMENT_PATTERN = /%([1-9]):([1-9]\d{0,9}):(\d{1,2}):([^%\u0000-\u001f\u007f]{1,32})/gy;
4616
- function markDocxNumberingChanges(document) {
4617
- const groups = [];
4618
- let active;
4619
- let markerIndex = 0;
4620
- for (const paragraph of descendants(document, 'p')){
4621
- if (!work_docx_numbering_change_import_isWordElement(paragraph)) {
4622
- active = void 0;
4623
- continue;
4624
- }
4625
- const change = supportedNumberingChangeInParagraph(paragraph);
4626
- if (!change || markerIndex >= MAX_NUMBERING_CHANGES) {
4627
- active = void 0;
4628
- continue;
4629
- }
4630
- const continues = active && continuesGroup(active.change, change);
4631
- if (!continues) {
4632
- const group = {
4633
- markers: [],
4634
- id: `docx-numbering-change-${change.id}`,
4635
- author: change.author,
4636
- date: change.date,
4637
- start: change.value,
4638
- level: change.level,
4639
- format: change.format,
4640
- suffix: change.suffix
4641
- };
4642
- groups.push(group);
4643
- active = {
4644
- change,
4645
- group
4646
- };
4647
- }
4648
- markerIndex += 1;
4649
- const marker = `__A3S_WORK_NUMBERING_CHANGE_${markerIndex}__`;
4650
- insertParagraphMarker(document, change.paragraph, change.properties, marker);
4651
- active?.group.markers.push(marker);
4652
- if (active) active.change = change;
4653
- }
4654
- return {
4655
- groups
4656
- };
4657
- }
4658
- function applyImportedDocxNumberingChangeMarkers(document, markers) {
4659
- const nodesByMarker = numberingMarkerNodes(document.body);
4660
- const groupsByList = new Map();
4661
- for (const group of markers.groups){
4662
- const list = numberingChangeList(group, nodesByMarker);
4663
- if (!list) continue;
4664
- const groups = groupsByList.get(list) ?? [];
4665
- groups.push(group);
4666
- groupsByList.set(list, groups);
4667
- }
4668
- for (const [list, groups] of groupsByList)if (1 === groups.length && groups[0]) applyNumberingChange(list, groups[0]);
4669
- for (const nodes of nodesByMarker.values())for (const node of nodes)node.data = node.data.replace(NUMBERING_CHANGE_MARKER_PATTERN, '');
4670
- document.body.normalize();
4671
- }
4672
- function hasImportedDocxNumberingChangeMarkers(markers) {
4673
- return markers.groups.length > 0;
4674
- }
4675
- function isSupportedDocxNumberingChange(change) {
4676
- return null !== supportedNumberingChange(change);
4677
- }
4678
- function supportedNumberingChangeInParagraph(paragraph) {
4679
- const propertyNodes = directWordChildren(paragraph, 'pPr');
4680
- if (1 !== propertyNodes.length) return null;
4681
- const properties = propertyNodes[0];
4682
- if (!properties) return null;
4683
- const numberingNodes = directWordChildren(properties, 'numPr');
4684
- if (1 !== numberingNodes.length) return null;
4685
- const changes = work_ooxml_package_directChildren(numberingNodes[0], 'numberingChange');
4686
- if (1 !== changes.length) return null;
4687
- return supportedNumberingChange(changes[0]);
4794
+ function supportedNumberingChangeInParagraph(paragraph) {
4795
+ const propertyNodes = directWordChildren(paragraph, 'pPr');
4796
+ if (1 !== propertyNodes.length) return null;
4797
+ const properties = propertyNodes[0];
4798
+ if (!properties) return null;
4799
+ const numberingNodes = directWordChildren(properties, 'numPr');
4800
+ if (1 !== numberingNodes.length) return null;
4801
+ const changes = work_ooxml_package_directChildren(numberingNodes[0], 'numberingChange');
4802
+ if (1 !== changes.length) return null;
4803
+ return supportedNumberingChange(changes[0]);
4688
4804
  }
4689
4805
  function supportedNumberingChange(change) {
4690
- if (!change || 'numberingChange' !== change.localName || !work_docx_numbering_change_import_isWordElement(change)) return null;
4806
+ if (!change || 'numberingChange' !== change.localName || !isWordElement(change)) return null;
4691
4807
  const namespace = change.namespaceURI ?? '';
4692
4808
  const numbering = change.parentElement;
4693
4809
  const properties = numbering?.parentElement;
@@ -4700,10 +4816,10 @@ function supportedNumberingChange(change) {
4700
4816
  if (1 !== levels.length || 1 !== numberingIds.length) return null;
4701
4817
  const level = boundedWordInteger(levels[0], 'val', 0, 8);
4702
4818
  const numberingId = boundedWordInteger(numberingIds[0], 'val', 0, MAX_DOCUMENT_NUMBERING_START);
4703
- const id = wordAttribute(change, 'id')?.trim() ?? '';
4704
- const author = wordAttribute(change, 'author')?.trim() ?? '';
4705
- const rawDate = wordAttribute(change, 'date');
4706
- const original = wordAttribute(change, 'original') ?? '';
4819
+ const id = work_docx_numbering_change_import_wordAttribute(change, 'id')?.trim() ?? '';
4820
+ const author = work_docx_numbering_change_import_wordAttribute(change, 'author')?.trim() ?? '';
4821
+ const rawDate = work_docx_numbering_change_import_wordAttribute(change, 'date');
4822
+ const original = work_docx_numbering_change_import_wordAttribute(change, 'original') ?? '';
4707
4823
  if (null === level || null === numberingId || !/^\+?\d{1,10}$/.test(id) || !author || author.length > 255 || /[\u0000-\u001f\u007f]/.test(author) || null !== rawDate && !Number.isFinite(Date.parse(rawDate))) return null;
4708
4824
  const definitions = parseOriginalNumbering(original);
4709
4825
  const definition = definitions?.get(level + 1);
@@ -4809,16 +4925,16 @@ function insertParagraphMarker(document, paragraph, properties, marker) {
4809
4925
  }
4810
4926
  function directWordChildren(parent, localName) {
4811
4927
  const namespace = parent.namespaceURI;
4812
- return work_ooxml_package_directChildren(parent, localName).filter((element)=>element.namespaceURI === namespace && work_docx_numbering_change_import_isWordElement(element));
4928
+ return work_ooxml_package_directChildren(parent, localName).filter((element)=>element.namespaceURI === namespace && isWordElement(element));
4813
4929
  }
4814
4930
  function boundedWordInteger(element, name, minimum, maximum) {
4815
4931
  if (!element) return null;
4816
- const raw = wordAttribute(element, name);
4932
+ const raw = work_docx_numbering_change_import_wordAttribute(element, name);
4817
4933
  if (!raw || !/^\d{1,10}$/.test(raw)) return null;
4818
4934
  const value = Number(raw);
4819
4935
  return Number.isSafeInteger(value) && value >= minimum && value <= maximum ? value : null;
4820
4936
  }
4821
- function wordAttribute(element, localName) {
4937
+ function work_docx_numbering_change_import_wordAttribute(element, localName) {
4822
4938
  const namespace = element.namespaceURI;
4823
4939
  if (!namespace) return null;
4824
4940
  const attributes = Array.from(element.attributes).filter((attribute)=>xmlAttributeLocalName(attribute) === localName && xmlAttributeNamespace(element, attribute) === namespace);
@@ -4850,7 +4966,7 @@ function normalizeRevisionDate(value) {
4850
4966
  const time = Date.parse(value);
4851
4967
  return Number.isFinite(time) ? new Date(time).toISOString() : '';
4852
4968
  }
4853
- function work_docx_numbering_change_import_isWordElement(element) {
4969
+ function isWordElement(element) {
4854
4970
  return DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '');
4855
4971
  }
4856
4972
  function isTextNode(value) {
@@ -5620,7 +5736,7 @@ function inspectDocxPageBorders(sectionProperties, themeSource) {
5620
5736
  spoofedCount: spoofedContainers
5621
5737
  };
5622
5738
  const attributes = wordContainerAttributes(container);
5623
- if (!attributes || hasNonWhitespaceText(container)) return {
5739
+ if (!attributes || work_docx_page_borders_import_hasNonWhitespaceText(container)) return {
5624
5740
  status: 'invalid',
5625
5741
  invalidCount: 1,
5626
5742
  spoofedCount: spoofedContainers
@@ -5716,7 +5832,7 @@ function pageBorderZOrder(value) {
5716
5832
  const normalized = value.trim();
5717
5833
  return PAGE_BORDER_Z_ORDERS.has(normalized) ? normalized : null;
5718
5834
  }
5719
- function hasNonWhitespaceText(element) {
5835
+ function work_docx_page_borders_import_hasNonWhitespaceText(element) {
5720
5836
  return Array.from(element.childNodes).some((node)=>node.nodeType === Node.TEXT_NODE && node.textContent?.trim());
5721
5837
  }
5722
5838
  function work_docx_page_borders_import_isNamespaceDeclaration(attribute) {
@@ -8227,280 +8343,577 @@ function importedRunFormattingChange(runProperties, paragraphProperties, styles,
8227
8343
  function isSupportedDocxRunFormattingChange(change) {
8228
8344
  return Boolean(supportedRunFormattingChangeElement(change));
8229
8345
  }
8230
- function supportedRunFormattingChange(runProperties) {
8231
- if (!runProperties) return null;
8232
- const changes = Array.from(runProperties.children).filter((child)=>'rPrChange' === child.localName);
8233
- return 1 === changes.length ? supportedRunFormattingChangeElement(changes[0]) : null;
8346
+ function supportedRunFormattingChange(runProperties) {
8347
+ if (!runProperties) return null;
8348
+ const changes = Array.from(runProperties.children).filter((child)=>'rPrChange' === child.localName);
8349
+ return 1 === changes.length ? supportedRunFormattingChangeElement(changes[0]) : null;
8350
+ }
8351
+ function supportedRunFormattingChangeElement(change) {
8352
+ if ('rPrChange' !== change.localName || !DOCX_WORDPROCESSING_NAMESPACES.has(change.namespaceURI ?? '')) return null;
8353
+ const properties = Array.from(change.children).filter((child)=>'rPr' === child.localName && DOCX_WORDPROCESSING_NAMESPACES.has(child.namespaceURI ?? ''));
8354
+ if (1 !== properties.length || 1 !== change.children.length) return null;
8355
+ const source = properties[0];
8356
+ const names = new Set();
8357
+ for (const child of Array.from(source.children)){
8358
+ const supportedWordProperty = DOCX_WORDPROCESSING_NAMESPACES.has(child.namespaceURI ?? '') && SUPPORTED_RUN_PROPERTY_CHANGE_CHILDREN.has(child.localName);
8359
+ const supportedOpenTypeProperty = child.namespaceURI === DOCX_WORD_2010_NAMESPACE && SUPPORTED_OPEN_TYPE_PROPERTY_CHANGE_CHILDREN.has(child.localName);
8360
+ const key = `${child.namespaceURI ?? ''}|${child.localName}`;
8361
+ if (!supportedWordProperty && !supportedOpenTypeProperty || names.has(key)) return null;
8362
+ names.add(key);
8363
+ }
8364
+ if (Array.from(source.children).some((child)=>child.namespaceURI === DOCX_WORD_2010_NAMESPACE)) {
8365
+ const openType = resolveDocxOpenTypeFeatures([
8366
+ source
8367
+ ]);
8368
+ if (!openType.features || openType.invalidCount || openType.spoofedCount) return null;
8369
+ }
8370
+ const id = work_ooxml_package_attribute(change, 'id')?.trim() ?? '';
8371
+ const author = work_ooxml_package_attribute(change, 'author')?.trim() ?? '';
8372
+ const date = work_ooxml_package_attribute(change, 'date');
8373
+ if (!/^\+?\d{1,10}$/.test(id) || !author || author.length > 255) return null;
8374
+ if (date && !Number.isFinite(Date.parse(date))) return null;
8375
+ return {
8376
+ id,
8377
+ author,
8378
+ date,
8379
+ properties: source
8380
+ };
8381
+ }
8382
+ function formattingChangeMarkup(document, change) {
8383
+ const span = document.createElement('span');
8384
+ span.dataset.documentChange = 'true';
8385
+ span.dataset.changeKind = 'formatting';
8386
+ span.dataset.changeId = change.id;
8387
+ span.dataset.changeAuthor = change.author;
8388
+ span.dataset.changeDate = change.date;
8389
+ span.dataset.changeBefore = change.before;
8390
+ const html = span.outerHTML;
8391
+ return {
8392
+ start: html.slice(0, html.indexOf('>') + 1),
8393
+ end: '</span>'
8394
+ };
8395
+ }
8396
+ function work_docx_run_formatting_import_normalizeRevisionDate(value) {
8397
+ if (!value) return '';
8398
+ const time = Date.parse(value);
8399
+ return Number.isFinite(time) ? new Date(time).toISOString() : '';
8400
+ }
8401
+ function work_docx_run_formatting_import_themeReference(element, themeName, tintName, shadeName, resolved) {
8402
+ const theme = work_docx_run_formatting_import_wordAttribute(element, themeName)?.trim();
8403
+ if (!theme) return;
8404
+ const tint = work_docx_run_formatting_import_normalizedByteHex(work_docx_run_formatting_import_wordAttribute(element, tintName));
8405
+ const shade = work_docx_run_formatting_import_normalizedByteHex(work_docx_run_formatting_import_wordAttribute(element, shadeName));
8406
+ return {
8407
+ theme,
8408
+ resolved,
8409
+ ...tint ? {
8410
+ tint
8411
+ } : {},
8412
+ ...shade ? {
8413
+ shade
8414
+ } : {}
8415
+ };
8416
+ }
8417
+ function work_docx_run_formatting_import_normalizedByteHex(value) {
8418
+ const normalized = value?.trim().toUpperCase();
8419
+ return normalized && /^[0-9A-F]{2}$/.test(normalized) ? normalized : void 0;
8420
+ }
8421
+ function overriddenBoolean(current, next) {
8422
+ return void 0 === next ? current : next;
8423
+ }
8424
+ function overriddenValue(current, next) {
8425
+ return void 0 === next ? current : next;
8426
+ }
8427
+ function propertySourcesUseComplexScript(propertySources) {
8428
+ let complexScript;
8429
+ let rightToLeft;
8430
+ for (const properties of propertySources){
8431
+ complexScript = overriddenBoolean(complexScript, onOffProperty(properties, 'cs'));
8432
+ rightToLeft = overriddenBoolean(rightToLeft, onOffProperty(properties, 'rtl'));
8433
+ }
8434
+ return true === complexScript || true === rightToLeft;
8435
+ }
8436
+ function onOffProperty(properties, propertyName) {
8437
+ const element = directChild(properties, propertyName);
8438
+ if (!element) return;
8439
+ const value = work_docx_run_formatting_import_wordAttribute(element, 'val')?.trim().toLowerCase();
8440
+ return '0' !== value && 'false' !== value && 'off' !== value;
8441
+ }
8442
+ function underlineProperty(properties, theme) {
8443
+ const element = directChild(properties, 'u');
8444
+ if (!element) return;
8445
+ return importedDocxUnderline(element, theme);
8446
+ }
8447
+ function work_docx_run_formatting_import_closestAncestor(element, localName) {
8448
+ let current = element.parentElement;
8449
+ while(current){
8450
+ if (current.localName === localName) return current;
8451
+ current = current.parentElement;
8452
+ }
8453
+ return null;
8454
+ }
8455
+ function defaultThemeFontFamily(theme, preferred) {
8456
+ const fonts = {
8457
+ ascii: docxThemeFont(theme, 'minorAscii'),
8458
+ highAnsi: docxThemeFont(theme, 'minorHAnsi'),
8459
+ eastAsia: docxThemeFont(theme, 'minorEastAsia'),
8460
+ complexScript: docxThemeFont(theme, 'minorBidi')
8461
+ };
8462
+ return uniqueFonts(documentScriptFontFallbackSlots(preferred).map((slot)=>fonts[slot]));
8463
+ }
8464
+ function uniqueFonts(values) {
8465
+ const fonts = [
8466
+ ...new Set(values.filter((value)=>!!value))
8467
+ ];
8468
+ return fonts.length ? fonts.map(cssFontFamily).join(', ') : void 0;
8469
+ }
8470
+ function cssFontFamily(value) {
8471
+ return /[\s"',]/.test(value) ? `"${value.replaceAll('\\', '\\\\').replaceAll('"', '\\"')}"` : value;
8472
+ }
8473
+ function work_docx_run_formatting_import_numericAttribute(element, name) {
8474
+ if (!element) return;
8475
+ const raw = work_docx_run_formatting_import_wordAttribute(element, name);
8476
+ if (null === raw || !raw.trim()) return;
8477
+ const value = Number(raw);
8478
+ return Number.isFinite(value) ? value : void 0;
8479
+ }
8480
+ function work_docx_run_formatting_import_wordAttribute(element, name) {
8481
+ return work_ooxml_package_attribute(element, name) ?? work_ooxml_package_attribute(element, `w:${name}`);
8482
+ }
8483
+ function work_docx_run_formatting_import_formatNumber(value) {
8484
+ return Number(value.toFixed(2)).toString();
8485
+ }
8486
+ function formatLineHeightFactor(value) {
8487
+ return Number(value.toFixed(4)).toString();
8488
+ }
8489
+ const work_docx_table_of_contents_import_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
8490
+ const work_docx_table_of_contents_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
8491
+ function markDocxTablesOfContents(document) {
8492
+ const tables = [];
8493
+ for (const element of descendants(document, 'sdt')){
8494
+ if (!document.documentElement.contains(element)) continue;
8495
+ const field = docxFieldOccurrences(element).find(supportedDocxTableOfContentsField);
8496
+ if (!field) continue;
8497
+ const parsed = parseDocumentTableOfContentsInstruction(field.instruction);
8498
+ if (!parsed.supported) continue;
8499
+ const tableIndex = tables.length + 1;
8500
+ const marker = {
8501
+ marker: `__A3S_WORK_TABLE_OF_CONTENTS_${tableIndex}__`,
8502
+ id: `docx-table-of-contents-${tableIndex}`,
8503
+ options: {
8504
+ ...parsed.options,
8505
+ leader: importedTableOfContentsLeader(element, parsed.options)
8506
+ },
8507
+ entries: importedTableOfContentsEntries(element, tableIndex)
8508
+ };
8509
+ element.replaceWith(work_docx_table_of_contents_import_markerParagraph(document, marker.marker));
8510
+ tables.push(marker);
8511
+ }
8512
+ return {
8513
+ tables
8514
+ };
8515
+ }
8516
+ function applyImportedDocxTableOfContentsMarkers(document, markers) {
8517
+ const headings = importedHtmlHeadings(document);
8518
+ for (const table of markers.tables){
8519
+ const usedHeadingIndexes = new Set();
8520
+ const text = work_docx_table_of_contents_import_textNodes(document.body).find((node)=>node.data.includes(table.marker));
8521
+ if (!text) continue;
8522
+ const entries = table.entries.map((entry)=>{
8523
+ const headingIndex = headings.findIndex((heading, index)=>!usedHeadingIndexes.has(index) && heading.level === entry.level && normalizedTitle(heading.title) === normalizedTitle(entry.title));
8524
+ if (headingIndex < 0) return entry;
8525
+ usedHeadingIndexes.add(headingIndex);
8526
+ const heading = headings[headingIndex];
8527
+ return heading ? {
8528
+ ...entry,
8529
+ targetId: heading.targetId
8530
+ } : entry;
8531
+ });
8532
+ const fragment = document.createRange().createContextualFragment(documentTableOfContentsHtml({
8533
+ id: table.id,
8534
+ options: table.options,
8535
+ entries
8536
+ }));
8537
+ const block = work_docx_table_of_contents_import_closestHtmlBlock(text.parentElement);
8538
+ if (block) block.replaceWith(fragment);
8539
+ }
8540
+ }
8541
+ function hasImportedDocxTableOfContentsMarkers(markers) {
8542
+ return markers.tables.length > 0;
8543
+ }
8544
+ function supportedDocxTableOfContentsField(field) {
8545
+ const parsed = parseDocumentTableOfContentsInstruction(field.instruction);
8546
+ return parsed.supported && field.complete && !field.nested && !field.inDeletion && Boolean(work_docx_table_of_contents_import_closestAncestor(field.start, 'sdt'));
8547
+ }
8548
+ function importedTableOfContentsEntries(element, tableIndex) {
8549
+ const paragraphs = descendants(element, 'p');
8550
+ return paragraphs.flatMap((paragraph, index)=>{
8551
+ const style = directChild(directChild(paragraph, 'pPr') ?? paragraph, 'pStyle');
8552
+ const level = Number(/^TOC([1-9])$/i.exec(work_ooxml_package_attribute(style ?? paragraph, 'val') ?? '')?.[1]);
8553
+ if (!level) return [];
8554
+ const values = descendants(paragraph, 't').map((text)=>text.textContent ?? '').filter(Boolean);
8555
+ const last = values.at(-1)?.trim() ?? '';
8556
+ const hasPageNumber = /^\d{1,6}$/.test(last);
8557
+ const title = (hasPageNumber ? values.slice(0, -1) : values).join('').replace(/\s+/g, ' ').trim();
8558
+ if (!title) return [];
8559
+ const hyperlink = descendants(paragraph, 'hyperlink').find((candidate)=>Boolean(work_ooxml_package_attribute(candidate, 'anchor')));
8560
+ const anchor = work_ooxml_package_attribute(hyperlink ?? paragraph, 'anchor')?.trim();
8561
+ const targetId = /^heading-[a-z0-9._:-]{1,128}$/i.test(anchor ?? '') ? anchor : `heading-import-${tableIndex}-${index + 1}`;
8562
+ return [
8563
+ {
8564
+ targetId,
8565
+ title,
8566
+ level,
8567
+ pageNumber: hasPageNumber ? Number(last) : 1
8568
+ }
8569
+ ];
8570
+ });
8571
+ }
8572
+ function importedTableOfContentsLeader(element, options) {
8573
+ if (!options.showPageNumbers || !options.rightAlignPageNumbers) return 'none';
8574
+ const tab = descendants(element, 'tab').find((candidate)=>candidate.parentElement?.localName === 'tabs' && 'right' === work_ooxml_package_attribute(candidate, 'val'));
8575
+ const leader = work_ooxml_package_attribute(tab ?? element, 'leader');
8576
+ if ('hyphen' === leader) return 'dash';
8577
+ if ('underscore' === leader) return 'underline';
8578
+ if (!leader || 'none' === leader) return 'none';
8579
+ return 'dot';
8580
+ }
8581
+ function work_docx_table_of_contents_import_markerParagraph(document, marker) {
8582
+ const paragraph = document.createElementNS(work_docx_table_of_contents_import_WORD_NAMESPACE, 'w:p');
8583
+ const run = document.createElementNS(work_docx_table_of_contents_import_WORD_NAMESPACE, 'w:r');
8584
+ const text = document.createElementNS(work_docx_table_of_contents_import_WORD_NAMESPACE, 'w:t');
8585
+ text.setAttributeNS(work_docx_table_of_contents_import_XML_NAMESPACE, 'xml:space', 'preserve');
8586
+ text.textContent = marker;
8587
+ run.append(text);
8588
+ paragraph.append(run);
8589
+ return paragraph;
8590
+ }
8591
+ function importedHtmlHeadings(document) {
8592
+ return Array.from(document.body.querySelectorAll('h1,h2,h3,h4,h5,h6,p[data-office-outline-level]')).flatMap((heading, index)=>{
8593
+ const headingLevel = /^H([1-6])$/.exec(heading.tagName)?.[1];
8594
+ const outlineLevel = Number(heading.dataset.officeOutlineLevel);
8595
+ const level = headingLevel ? Number(headingLevel) : Number.isInteger(outlineLevel) && outlineLevel >= 0 && outlineLevel <= 8 ? outlineLevel + 1 : null;
8596
+ if (null === level) return [];
8597
+ const identity = normalizeDocumentParagraphId(heading.dataset.officeParagraphId);
8598
+ return [
8599
+ {
8600
+ title: heading.textContent ?? '',
8601
+ level,
8602
+ targetId: identity ? `heading-${identity.toLowerCase()}` : `heading-imported-${index + 1}`
8603
+ }
8604
+ ];
8605
+ });
8606
+ }
8607
+ function work_docx_table_of_contents_import_textNodes(root) {
8608
+ const walker = root.ownerDocument?.createTreeWalker(root, NodeFilter.SHOW_TEXT);
8609
+ const nodes = [];
8610
+ if (!walker) return nodes;
8611
+ while(walker.nextNode())nodes.push(walker.currentNode);
8612
+ return nodes;
8613
+ }
8614
+ function work_docx_table_of_contents_import_closestHtmlBlock(element) {
8615
+ let current = element;
8616
+ while(current && current.parentElement?.tagName.toLowerCase() !== 'body')current = current.parentElement;
8617
+ return current;
8234
8618
  }
8235
- function supportedRunFormattingChangeElement(change) {
8236
- if ('rPrChange' !== change.localName || !DOCX_WORDPROCESSING_NAMESPACES.has(change.namespaceURI ?? '')) return null;
8237
- const properties = Array.from(change.children).filter((child)=>'rPr' === child.localName && DOCX_WORDPROCESSING_NAMESPACES.has(child.namespaceURI ?? ''));
8238
- if (1 !== properties.length || 1 !== change.children.length) return null;
8239
- const source = properties[0];
8240
- const names = new Set();
8241
- for (const child of Array.from(source.children)){
8242
- const supportedWordProperty = DOCX_WORDPROCESSING_NAMESPACES.has(child.namespaceURI ?? '') && SUPPORTED_RUN_PROPERTY_CHANGE_CHILDREN.has(child.localName);
8243
- const supportedOpenTypeProperty = child.namespaceURI === DOCX_WORD_2010_NAMESPACE && SUPPORTED_OPEN_TYPE_PROPERTY_CHANGE_CHILDREN.has(child.localName);
8244
- const key = `${child.namespaceURI ?? ''}|${child.localName}`;
8245
- if (!supportedWordProperty && !supportedOpenTypeProperty || names.has(key)) return null;
8246
- names.add(key);
8619
+ function work_docx_table_of_contents_import_closestAncestor(element, localName) {
8620
+ let current = element;
8621
+ while(current){
8622
+ if (current.localName === localName) return current;
8623
+ current = current.parentElement;
8247
8624
  }
8248
- if (Array.from(source.children).some((child)=>child.namespaceURI === DOCX_WORD_2010_NAMESPACE)) {
8249
- const openType = resolveDocxOpenTypeFeatures([
8250
- source
8251
- ]);
8252
- if (!openType.features || openType.invalidCount || openType.spoofedCount) return null;
8625
+ return null;
8626
+ }
8627
+ function normalizedTitle(value) {
8628
+ return value.normalize('NFKC').replace(/\s+/g, ' ').trim().toLocaleLowerCase();
8629
+ }
8630
+ const work_docx_text_box_import_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
8631
+ const work_docx_text_box_import_STRICT_WORD_NAMESPACE = 'http://purl.oclc.org/ooxml/wordprocessingml/main';
8632
+ const WORDPROCESSING_DRAWING_NAMESPACES = new Set([
8633
+ 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',
8634
+ 'http://purl.oclc.org/ooxml/drawingml/wordprocessingDrawing'
8635
+ ]);
8636
+ const DRAWING_NAMESPACES = new Set([
8637
+ 'http://schemas.openxmlformats.org/drawingml/2006/main',
8638
+ 'http://purl.oclc.org/ooxml/drawingml/main'
8639
+ ]);
8640
+ const WORDPROCESSING_SHAPE_NAMESPACES = new Set([
8641
+ 'http://schemas.microsoft.com/office/word/2010/wordprocessingShape'
8642
+ ]);
8643
+ const work_docx_text_box_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
8644
+ const WORDPROCESSING_SHAPE_URI = 'http://schemas.microsoft.com/office/word/2010/wordprocessingShape';
8645
+ const EMUS_PER_MILLIMETER = 36000;
8646
+ const MAX_IMPORTED_TEXT_BOXES = 1024;
8647
+ const TEXT_BOX_MARKER_PATTERN = /__A3S_WORK_TEXT_BOX_\d+__/g;
8648
+ const TEXT_BOX_RUN_CONTENT_NAMES = new Set([
8649
+ 'br',
8650
+ 'cr',
8651
+ 'noBreakHyphen',
8652
+ 'softHyphen',
8653
+ 'sym',
8654
+ 'tab',
8655
+ 't'
8656
+ ]);
8657
+ function markDocxTextBoxes(document) {
8658
+ const textBoxes = [];
8659
+ const drawings = docxDrawings(document);
8660
+ let nextMarker = 1;
8661
+ for (const drawing of drawings){
8662
+ const shape = supportedTextBoxShape(drawing);
8663
+ if (!shape) continue;
8664
+ const paragraph = work_docx_text_box_import_closestAncestor(drawing, 'p');
8665
+ const run = work_docx_text_box_import_closestAncestor(drawing, 'r');
8666
+ if (!paragraph || !run || !isSoleDrawingParagraph(paragraph, run)) continue;
8667
+ if (textBoxes.length >= MAX_IMPORTED_TEXT_BOXES) throw new Error('Imported DOCX exceeds the text-box limit.');
8668
+ const marker = nextTextBoxMarker(document, nextMarker);
8669
+ nextMarker += 1;
8670
+ const properties = textBoxProperties(drawing, shape, textBoxes.length + 1);
8671
+ replaceParagraphWithTextBoxRuns(document, paragraph, shape.content, marker);
8672
+ textBoxes.push({
8673
+ marker,
8674
+ properties
8675
+ });
8253
8676
  }
8254
- const id = work_ooxml_package_attribute(change, 'id')?.trim() ?? '';
8255
- const author = work_ooxml_package_attribute(change, 'author')?.trim() ?? '';
8256
- const date = work_ooxml_package_attribute(change, 'date');
8257
- if (!/^\+?\d{1,10}$/.test(id) || !author || author.length > 255) return null;
8258
- if (date && !Number.isFinite(Date.parse(date))) return null;
8259
8677
  return {
8260
- id,
8261
- author,
8262
- date,
8263
- properties: source
8678
+ textBoxes
8264
8679
  };
8265
8680
  }
8266
- function formattingChangeMarkup(document, change) {
8267
- const span = document.createElement('span');
8268
- span.dataset.documentChange = 'true';
8269
- span.dataset.changeKind = 'formatting';
8270
- span.dataset.changeId = change.id;
8271
- span.dataset.changeAuthor = change.author;
8272
- span.dataset.changeDate = change.date;
8273
- span.dataset.changeBefore = change.before;
8274
- const html = span.outerHTML;
8681
+ function inspectDocxTextBoxes(document) {
8682
+ let supported = 0;
8683
+ let unsupported = 0;
8684
+ for (const drawing of docxDrawings(document)){
8685
+ if (!textBoxShapeCandidate(drawing)) continue;
8686
+ const shape = supportedTextBoxShape(drawing);
8687
+ if (!shape) {
8688
+ unsupported += 1;
8689
+ continue;
8690
+ }
8691
+ const paragraph = work_docx_text_box_import_closestAncestor(drawing, 'p');
8692
+ const run = work_docx_text_box_import_closestAncestor(drawing, 'r');
8693
+ if (paragraph && run && isSoleDrawingParagraph(paragraph, run)) supported += 1;
8694
+ else unsupported += 1;
8695
+ }
8275
8696
  return {
8276
- start: html.slice(0, html.indexOf('>') + 1),
8277
- end: '</span>'
8697
+ supported,
8698
+ unsupported
8278
8699
  };
8279
8700
  }
8280
- function work_docx_run_formatting_import_normalizeRevisionDate(value) {
8281
- if (!value) return '';
8282
- const time = Date.parse(value);
8283
- return Number.isFinite(time) ? new Date(time).toISOString() : '';
8284
- }
8285
- function work_docx_run_formatting_import_themeReference(element, themeName, tintName, shadeName, resolved) {
8286
- const theme = work_docx_run_formatting_import_wordAttribute(element, themeName)?.trim();
8287
- if (!theme) return;
8288
- const tint = work_docx_run_formatting_import_normalizedByteHex(work_docx_run_formatting_import_wordAttribute(element, tintName));
8289
- const shade = work_docx_run_formatting_import_normalizedByteHex(work_docx_run_formatting_import_wordAttribute(element, shadeName));
8290
- return {
8291
- theme,
8292
- resolved,
8293
- ...tint ? {
8294
- tint
8295
- } : {},
8296
- ...shade ? {
8297
- shade
8298
- } : {}
8299
- };
8701
+ function applyImportedDocxTextBoxMarkers(document, markers) {
8702
+ if (!markers.textBoxes.length) return;
8703
+ const byMarker = new Map(markers.textBoxes.map((textBox)=>[
8704
+ textBox.marker,
8705
+ textBox
8706
+ ]));
8707
+ const nodes = work_docx_text_box_import_textNodes(document.body);
8708
+ for (const node of nodes){
8709
+ if (!node.data.includes('__A3S_WORK_TEXT_BOX_')) continue;
8710
+ const match = node.data.match(TEXT_BOX_MARKER_PATTERN)?.find((value)=>byMarker.has(value));
8711
+ if (!match) continue;
8712
+ const textBox = byMarker.get(match);
8713
+ if (!textBox) continue;
8714
+ node.data = node.data.replace(match, '');
8715
+ const block = work_docx_text_box_import_closestHtmlBlock(node.parentElement);
8716
+ if (!block) continue;
8717
+ const wrapper = document.createElement('div');
8718
+ for (const attribute of Array.from(block.attributes))if (attribute.name.startsWith('data-office-') || attribute.name.startsWith('data-document-')) wrapper.setAttribute(attribute.name, attribute.value);
8719
+ for (const [name, value] of Object.entries(textBoxDomAttributes(textBox.properties)))if (void 0 !== value) wrapper.setAttribute(name, value);
8720
+ wrapper.className = 'work-document-text-box';
8721
+ wrapper.setAttribute('role', 'textbox');
8722
+ wrapper.setAttribute('aria-label', '文本框');
8723
+ wrapper.setAttribute('style', textBoxCss(textBox.properties));
8724
+ while(block.firstChild)wrapper.append(block.firstChild);
8725
+ block.replaceWith(wrapper);
8726
+ }
8727
+ document.body.normalize();
8300
8728
  }
8301
- function work_docx_run_formatting_import_normalizedByteHex(value) {
8302
- const normalized = value?.trim().toUpperCase();
8303
- return normalized && /^[0-9A-F]{2}$/.test(normalized) ? normalized : void 0;
8729
+ function hasImportedDocxTextBoxMarkers(markers) {
8730
+ return markers.textBoxes.length > 0;
8304
8731
  }
8305
- function overriddenBoolean(current, next) {
8306
- return void 0 === next ? current : next;
8732
+ function textBoxShapeCandidate(drawing) {
8733
+ if (!WORDPROCESSING_DRAWING_NAMESPACES.has(drawing.namespaceURI ?? '')) return null;
8734
+ const graphicData = descendants(drawing, 'graphicData').find((element)=>DRAWING_NAMESPACES.has(element.namespaceURI ?? '') && work_ooxml_package_attribute(element, 'uri') === WORDPROCESSING_SHAPE_URI);
8735
+ if (!graphicData) return null;
8736
+ const shape = directChild(graphicData, 'wsp');
8737
+ if (!shape || !WORDPROCESSING_SHAPE_NAMESPACES.has(shape.namespaceURI ?? '')) return null;
8738
+ const nonVisual = directChild(shape, 'cNvSpPr');
8739
+ if (nonVisual && !WORDPROCESSING_SHAPE_NAMESPACES.has(nonVisual.namespaceURI ?? '')) return null;
8740
+ const txBox = work_ooxml_package_attribute(nonVisual ?? shape, 'txBox')?.trim().toLowerCase();
8741
+ if ('1' !== txBox && 'true' !== txBox) return null;
8742
+ return shape;
8307
8743
  }
8308
- function overriddenValue(current, next) {
8309
- return void 0 === next ? current : next;
8744
+ function supportedTextBoxShape(drawing) {
8745
+ const shape = textBoxShapeCandidate(drawing);
8746
+ if (!shape) return null;
8747
+ const txbx = directChild(shape, 'txbx');
8748
+ if (txbx && !WORDPROCESSING_SHAPE_NAMESPACES.has(txbx.namespaceURI ?? '')) return null;
8749
+ const content = txbx ? directChild(txbx, 'txbxContent') : void 0;
8750
+ return content && work_docx_text_box_import_isWordElement(content, 'txbxContent') && isSupportedTextBoxContent(content) ? {
8751
+ shape,
8752
+ content
8753
+ } : null;
8310
8754
  }
8311
- function propertySourcesUseComplexScript(propertySources) {
8312
- let complexScript;
8313
- let rightToLeft;
8314
- for (const properties of propertySources){
8315
- complexScript = overriddenBoolean(complexScript, onOffProperty(properties, 'cs'));
8316
- rightToLeft = overriddenBoolean(rightToLeft, onOffProperty(properties, 'rtl'));
8755
+ function isSupportedTextBoxContent(content) {
8756
+ const paragraphs = work_ooxml_package_directChildren(content);
8757
+ if (!paragraphs.length) return false;
8758
+ for (const paragraph of paragraphs){
8759
+ if (!work_docx_text_box_import_isWordElement(paragraph, 'p')) return false;
8760
+ const children = work_ooxml_package_directChildren(paragraph).filter((element)=>'pPr' !== element.localName);
8761
+ for (const child of children){
8762
+ if (!work_docx_text_box_import_isWordElement(child, 'r')) return false;
8763
+ const runChildren = work_ooxml_package_directChildren(child).filter((element)=>'rPr' !== element.localName);
8764
+ if (runChildren.some((element)=>!isWordNamespace(element) || !TEXT_BOX_RUN_CONTENT_NAMES.has(element.localName))) return false;
8765
+ }
8317
8766
  }
8318
- return true === complexScript || true === rightToLeft;
8319
- }
8320
- function onOffProperty(properties, propertyName) {
8321
- const element = directChild(properties, propertyName);
8322
- if (!element) return;
8323
- const value = work_docx_run_formatting_import_wordAttribute(element, 'val')?.trim().toLowerCase();
8324
- return '0' !== value && 'false' !== value && 'off' !== value;
8767
+ return true;
8325
8768
  }
8326
- function underlineProperty(properties, theme) {
8327
- const element = directChild(properties, 'u');
8328
- if (!element) return;
8329
- return importedDocxUnderline(element, theme);
8769
+ function work_docx_text_box_import_isWordElement(element, localName) {
8770
+ return element.localName === localName && isWordNamespace(element);
8330
8771
  }
8331
- function work_docx_run_formatting_import_closestAncestor(element, localName) {
8332
- let current = element.parentElement;
8333
- while(current){
8334
- if (current.localName === localName) return current;
8335
- current = current.parentElement;
8336
- }
8337
- return null;
8772
+ function isWordNamespace(element) {
8773
+ return element.namespaceURI === work_docx_text_box_import_WORD_NAMESPACE || element.namespaceURI === work_docx_text_box_import_STRICT_WORD_NAMESPACE;
8338
8774
  }
8339
- function defaultThemeFontFamily(theme, preferred) {
8340
- const fonts = {
8341
- ascii: docxThemeFont(theme, 'minorAscii'),
8342
- highAnsi: docxThemeFont(theme, 'minorHAnsi'),
8343
- eastAsia: docxThemeFont(theme, 'minorEastAsia'),
8344
- complexScript: docxThemeFont(theme, 'minorBidi')
8345
- };
8346
- return uniqueFonts(documentScriptFontFallbackSlots(preferred).map((slot)=>fonts[slot]));
8775
+ function docxDrawings(document) {
8776
+ return [
8777
+ ...descendants(document, 'anchor'),
8778
+ ...descendants(document, 'inline')
8779
+ ].filter((element)=>WORDPROCESSING_DRAWING_NAMESPACES.has(element.namespaceURI ?? ''));
8347
8780
  }
8348
- function uniqueFonts(values) {
8349
- const fonts = [
8350
- ...new Set(values.filter((value)=>!!value))
8351
- ];
8352
- return fonts.length ? fonts.map(cssFontFamily).join(', ') : void 0;
8781
+ function isSoleDrawingParagraph(paragraph, run) {
8782
+ const meaningful = work_ooxml_package_directChildren(paragraph).filter((element)=>'pPr' !== element.localName);
8783
+ if (1 !== meaningful.length || meaningful[0] !== run) return false;
8784
+ const runContent = work_ooxml_package_directChildren(run).filter((element)=>'rPr' !== element.localName);
8785
+ return 1 === runContent.length && runContent[0]?.localName === 'drawing';
8353
8786
  }
8354
- function cssFontFamily(value) {
8355
- return /[\s"',]/.test(value) ? `"${value.replaceAll('\\', '\\\\').replaceAll('"', '\\"')}"` : value;
8787
+ function replaceParagraphWithTextBoxRuns(document, paragraph, content, marker) {
8788
+ const namespace = paragraph.namespaceURI || work_docx_text_box_import_WORD_NAMESPACE;
8789
+ const prefix = paragraph.prefix ? `${paragraph.prefix}:` : 'w:';
8790
+ const paragraphProperties = directChild(paragraph, 'pPr');
8791
+ const runs = [];
8792
+ const sourceParagraphs = work_ooxml_package_directChildren(content, 'p');
8793
+ for (const [paragraphIndex, sourceParagraph] of sourceParagraphs.entries()){
8794
+ if (paragraphIndex > 0) runs.push(createBreakRun(document, namespace, prefix));
8795
+ const sourceRuns = work_ooxml_package_directChildren(sourceParagraph, 'r');
8796
+ for (const sourceRun of sourceRuns)runs.push(document.importNode(sourceRun, true));
8797
+ }
8798
+ const markerRun = createTextRun(document, namespace, prefix, marker);
8799
+ paragraph.replaceChildren(...paragraphProperties ? [
8800
+ paragraphProperties
8801
+ ] : [], markerRun, ...runs);
8356
8802
  }
8357
- function work_docx_run_formatting_import_numericAttribute(element, name) {
8358
- if (!element) return;
8359
- const raw = work_docx_run_formatting_import_wordAttribute(element, name);
8360
- if (null === raw || !raw.trim()) return;
8361
- const value = Number(raw);
8362
- return Number.isFinite(value) ? value : void 0;
8803
+ function createTextRun(document, namespace, prefix, textValue) {
8804
+ const run = document.createElementNS(namespace, `${prefix}r`);
8805
+ const text = document.createElementNS(namespace, `${prefix}t`);
8806
+ text.setAttributeNS(work_docx_text_box_import_XML_NAMESPACE, 'xml:space', 'preserve');
8807
+ text.textContent = textValue;
8808
+ run.append(text);
8809
+ return run;
8363
8810
  }
8364
- function work_docx_run_formatting_import_wordAttribute(element, name) {
8365
- return work_ooxml_package_attribute(element, name) ?? work_ooxml_package_attribute(element, `w:${name}`);
8811
+ function createBreakRun(document, namespace, prefix) {
8812
+ const run = document.createElementNS(namespace, `${prefix}r`);
8813
+ run.append(document.createElementNS(namespace, `${prefix}br`));
8814
+ return run;
8366
8815
  }
8367
- function work_docx_run_formatting_import_formatNumber(value) {
8368
- return Number(value.toFixed(2)).toString();
8816
+ function textBoxProperties(drawing, shape, index) {
8817
+ const extent = directChild(drawing, 'extent');
8818
+ const shapeProperties = directChild(shape.shape, 'spPr');
8819
+ const transform = shapeProperties ? directChild(shapeProperties, 'xfrm') : void 0;
8820
+ const extension = directChild(transform ?? shapeProperties ?? shape.shape, 'ext');
8821
+ const width = emuMillimeters(work_ooxml_package_attribute(extent ?? extension ?? shape.shape, 'cx') ?? work_ooxml_package_attribute(extent ?? extension ?? shape.shape, 'x'), 120);
8822
+ const height = emuMillimeters(work_ooxml_package_attribute(extent ?? extension ?? shape.shape, 'cy') ?? work_ooxml_package_attribute(extent ?? extension ?? shape.shape, 'y'), 45);
8823
+ const docProperties = directChild(drawing, 'docPr');
8824
+ const docPropertiesId = integerAttribute(docProperties, 'id');
8825
+ const sourceName = attributeOptional(docProperties, 'name')?.trim() ?? '';
8826
+ const id = sourceName.startsWith('A3S Text Box ') ? sourceName.slice(13).trim() : null === docPropertiesId ? `docx-text-box-${index}` : `docx-text-box-${docPropertiesId}`;
8827
+ const bodyProperties = directChild(shape.shape, 'bodyPr');
8828
+ const horizontal = directChild(drawing, 'positionH');
8829
+ const vertical = directChild(drawing, 'positionV');
8830
+ const layout = 'anchor' === drawing.localName ? 'floating' : 'inline';
8831
+ const fill = shapeFill(shapeProperties);
8832
+ const border = shapeBorder(shapeProperties);
8833
+ return normalizeDocumentTextBoxProperties({
8834
+ id,
8835
+ width,
8836
+ height,
8837
+ layout,
8838
+ horizontalOffset: positionOffset(horizontal),
8839
+ verticalOffset: positionOffset(vertical),
8840
+ horizontalReference: positionReference(horizontal, 'column'),
8841
+ verticalReference: positionReference(vertical, 'paragraph'),
8842
+ fill,
8843
+ borderColor: border.color,
8844
+ borderWidth: border.width,
8845
+ padding: bodyPadding(bodyProperties),
8846
+ verticalAlign: bodyVerticalAlign(bodyProperties),
8847
+ docPropertiesId
8848
+ });
8369
8849
  }
8370
- function formatLineHeightFactor(value) {
8371
- return Number(value.toFixed(4)).toString();
8850
+ function shapeFill(shapeProperties) {
8851
+ if (!shapeProperties || directChild(shapeProperties, 'noFill')) return 'transparent';
8852
+ const fill = directChild(shapeProperties, 'solidFill');
8853
+ const rgb = fill ? directChild(fill, 'srgbClr') : void 0;
8854
+ const value = attributeOptional(rgb, 'val')?.trim();
8855
+ return value && /^[0-9a-f]{6}$/i.test(value) ? `#${value}` : 'transparent';
8372
8856
  }
8373
- const work_docx_table_of_contents_import_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
8374
- const work_docx_table_of_contents_import_XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
8375
- function markDocxTablesOfContents(document) {
8376
- const tables = [];
8377
- for (const element of descendants(document, 'sdt')){
8378
- if (!document.documentElement.contains(element)) continue;
8379
- const field = docxFieldOccurrences(element).find(supportedDocxTableOfContentsField);
8380
- if (!field) continue;
8381
- const parsed = parseDocumentTableOfContentsInstruction(field.instruction);
8382
- if (!parsed.supported) continue;
8383
- const tableIndex = tables.length + 1;
8384
- const marker = {
8385
- marker: `__A3S_WORK_TABLE_OF_CONTENTS_${tableIndex}__`,
8386
- id: `docx-table-of-contents-${tableIndex}`,
8387
- options: {
8388
- ...parsed.options,
8389
- leader: importedTableOfContentsLeader(element, parsed.options)
8390
- },
8391
- entries: importedTableOfContentsEntries(element, tableIndex)
8392
- };
8393
- element.replaceWith(work_docx_table_of_contents_import_markerParagraph(document, marker.marker));
8394
- tables.push(marker);
8395
- }
8857
+ function shapeBorder(shapeProperties) {
8858
+ const line = shapeProperties ? directChild(shapeProperties, 'ln') : void 0;
8859
+ if (!line || directChild(line, 'noFill')) return {
8860
+ color: 'none',
8861
+ width: 0
8862
+ };
8863
+ const fill = directChild(line, 'solidFill');
8864
+ const rgb = fill ? directChild(fill, 'srgbClr') : void 0;
8865
+ const value = attributeOptional(rgb, 'val')?.trim();
8396
8866
  return {
8397
- tables
8867
+ color: value && /^[0-9a-f]{6}$/i.test(value) ? `#${value}` : '#4472c4',
8868
+ width: emuMillimeters(work_ooxml_package_attribute(line, 'w'), 0.35)
8398
8869
  };
8399
8870
  }
8400
- function applyImportedDocxTableOfContentsMarkers(document, markers) {
8401
- const headings = importedHtmlHeadings(document);
8402
- for (const table of markers.tables){
8403
- const usedHeadingIndexes = new Set();
8404
- const text = work_docx_table_of_contents_import_textNodes(document.body).find((node)=>node.data.includes(table.marker));
8405
- if (!text) continue;
8406
- const entries = table.entries.map((entry)=>{
8407
- const headingIndex = headings.findIndex((heading, index)=>!usedHeadingIndexes.has(index) && heading.level === entry.level && normalizedTitle(heading.title) === normalizedTitle(entry.title));
8408
- if (headingIndex < 0) return entry;
8409
- usedHeadingIndexes.add(headingIndex);
8410
- const heading = headings[headingIndex];
8411
- return heading ? {
8412
- ...entry,
8413
- targetId: heading.targetId
8414
- } : entry;
8415
- });
8416
- const fragment = document.createRange().createContextualFragment(documentTableOfContentsHtml({
8417
- id: table.id,
8418
- options: table.options,
8419
- entries
8420
- }));
8421
- const block = work_docx_table_of_contents_import_closestHtmlBlock(text.parentElement);
8422
- if (block) block.replaceWith(fragment);
8423
- }
8424
- }
8425
- function hasImportedDocxTableOfContentsMarkers(markers) {
8426
- return markers.tables.length > 0;
8871
+ function bodyPadding(bodyProperties) {
8872
+ if (!bodyProperties) return 3;
8873
+ const values = [
8874
+ 'lIns',
8875
+ 'rIns',
8876
+ 'tIns',
8877
+ 'bIns'
8878
+ ].map((name)=>emuMillimeters(attributeOptional(bodyProperties, name), 3));
8879
+ return Math.min(...values);
8427
8880
  }
8428
- function supportedDocxTableOfContentsField(field) {
8429
- const parsed = parseDocumentTableOfContentsInstruction(field.instruction);
8430
- return parsed.supported && field.complete && !field.nested && !field.inDeletion && Boolean(work_docx_table_of_contents_import_closestAncestor(field.start, 'sdt'));
8881
+ function bodyVerticalAlign(bodyProperties) {
8882
+ const value = attributeOptional(bodyProperties, 'anchor');
8883
+ if ('ctr' === value) return 'center';
8884
+ if ('b' === value) return 'bottom';
8885
+ return 'top';
8431
8886
  }
8432
- function importedTableOfContentsEntries(element, tableIndex) {
8433
- const paragraphs = descendants(element, 'p');
8434
- return paragraphs.flatMap((paragraph, index)=>{
8435
- const style = directChild(directChild(paragraph, 'pPr') ?? paragraph, 'pStyle');
8436
- const level = Number(/^TOC([1-9])$/i.exec(work_ooxml_package_attribute(style ?? paragraph, 'val') ?? '')?.[1]);
8437
- if (!level) return [];
8438
- const values = descendants(paragraph, 't').map((text)=>text.textContent ?? '').filter(Boolean);
8439
- const last = values.at(-1)?.trim() ?? '';
8440
- const hasPageNumber = /^\d{1,6}$/.test(last);
8441
- const title = (hasPageNumber ? values.slice(0, -1) : values).join('').replace(/\s+/g, ' ').trim();
8442
- if (!title) return [];
8443
- const hyperlink = descendants(paragraph, 'hyperlink').find((candidate)=>Boolean(work_ooxml_package_attribute(candidate, 'anchor')));
8444
- const anchor = work_ooxml_package_attribute(hyperlink ?? paragraph, 'anchor')?.trim();
8445
- const targetId = /^heading-[a-z0-9._:-]{1,128}$/i.test(anchor ?? '') ? anchor : `heading-import-${tableIndex}-${index + 1}`;
8446
- return [
8447
- {
8448
- targetId,
8449
- title,
8450
- level,
8451
- pageNumber: hasPageNumber ? Number(last) : 1
8452
- }
8453
- ];
8454
- });
8887
+ function positionOffset(element) {
8888
+ const offset = element ? directChild(element, 'posOffset') : void 0;
8889
+ if (!offset?.textContent?.trim()) return null;
8890
+ const value = Number(offset.textContent);
8891
+ return Number.isFinite(value) ? value / EMUS_PER_MILLIMETER : null;
8455
8892
  }
8456
- function importedTableOfContentsLeader(element, options) {
8457
- if (!options.showPageNumbers || !options.rightAlignPageNumbers) return 'none';
8458
- const tab = descendants(element, 'tab').find((candidate)=>candidate.parentElement?.localName === 'tabs' && 'right' === work_ooxml_package_attribute(candidate, 'val'));
8459
- const leader = work_ooxml_package_attribute(tab ?? element, 'leader');
8460
- if ('hyphen' === leader) return 'dash';
8461
- if ('underscore' === leader) return 'underline';
8462
- if (!leader || 'none' === leader) return 'none';
8463
- return 'dot';
8893
+ function positionReference(element, fallback) {
8894
+ const value = attributeOptional(element, 'relativeFrom');
8895
+ if ('margin' === value || 'page' === value || 'column' === value) return value;
8896
+ if ('paragraph' === value) return value;
8897
+ return fallback;
8464
8898
  }
8465
- function work_docx_table_of_contents_import_markerParagraph(document, marker) {
8466
- const paragraph = document.createElementNS(work_docx_table_of_contents_import_WORD_NAMESPACE, 'w:p');
8467
- const run = document.createElementNS(work_docx_table_of_contents_import_WORD_NAMESPACE, 'w:r');
8468
- const text = document.createElementNS(work_docx_table_of_contents_import_WORD_NAMESPACE, 'w:t');
8469
- text.setAttributeNS(work_docx_table_of_contents_import_XML_NAMESPACE, 'xml:space', 'preserve');
8470
- text.textContent = marker;
8471
- run.append(text);
8472
- paragraph.append(run);
8473
- return paragraph;
8899
+ function emuMillimeters(value, fallback) {
8900
+ const number = null === value ? NaN : Number(value);
8901
+ return Number.isFinite(number) && number >= 0 ? number / EMUS_PER_MILLIMETER : fallback;
8474
8902
  }
8475
- function importedHtmlHeadings(document) {
8476
- return Array.from(document.body.querySelectorAll('h1,h2,h3,h4,h5,h6,p[data-office-outline-level]')).flatMap((heading, index)=>{
8477
- const headingLevel = /^H([1-6])$/.exec(heading.tagName)?.[1];
8478
- const outlineLevel = Number(heading.dataset.officeOutlineLevel);
8479
- const level = headingLevel ? Number(headingLevel) : Number.isInteger(outlineLevel) && outlineLevel >= 0 && outlineLevel <= 8 ? outlineLevel + 1 : null;
8480
- if (null === level) return [];
8481
- const identity = normalizeDocumentParagraphId(heading.dataset.officeParagraphId);
8482
- return [
8483
- {
8484
- title: heading.textContent ?? '',
8485
- level,
8486
- targetId: identity ? `heading-${identity.toLowerCase()}` : `heading-imported-${index + 1}`
8487
- }
8488
- ];
8489
- });
8903
+ function integerAttribute(element, name) {
8904
+ if (!element) return null;
8905
+ const value = Number(attributeOptional(element, name));
8906
+ return Number.isSafeInteger(value) && value >= 0 ? value : null;
8490
8907
  }
8491
- function work_docx_table_of_contents_import_textNodes(root) {
8492
- const walker = root.ownerDocument?.createTreeWalker(root, NodeFilter.SHOW_TEXT);
8493
- const nodes = [];
8494
- if (!walker) return nodes;
8495
- while(walker.nextNode())nodes.push(walker.currentNode);
8496
- return nodes;
8908
+ function attributeOptional(element, name) {
8909
+ return element ? work_ooxml_package_attribute(element, name) : null;
8497
8910
  }
8498
- function work_docx_table_of_contents_import_closestHtmlBlock(element) {
8499
- let current = element;
8500
- while(current && current.parentElement?.tagName.toLowerCase() !== 'body')current = current.parentElement;
8501
- return current;
8911
+ function nextTextBoxMarker(document, start) {
8912
+ let index = start;
8913
+ while(document.documentElement.textContent?.includes(`__A3S_WORK_TEXT_BOX_${index}__`))index += 1;
8914
+ return `__A3S_WORK_TEXT_BOX_${index}__`;
8502
8915
  }
8503
- function work_docx_table_of_contents_import_closestAncestor(element, localName) {
8916
+ function work_docx_text_box_import_closestAncestor(element, localName) {
8504
8917
  let current = element;
8505
8918
  while(current){
8506
8919
  if (current.localName === localName) return current;
@@ -8508,7 +8921,16 @@ function work_docx_table_of_contents_import_closestAncestor(element, localName)
8508
8921
  }
8509
8922
  return null;
8510
8923
  }
8511
- function normalizedTitle(value) {
8512
- return value.normalize('NFKC').replace(/\s+/g, ' ').trim().toLocaleLowerCase();
8924
+ function work_docx_text_box_import_closestHtmlBlock(element) {
8925
+ if (!element) return null;
8926
+ const block = element.closest('p, h1, h2, h3, h4, h5, h6, li, blockquote, td, th');
8927
+ return block instanceof HTMLElement ? block : null;
8928
+ }
8929
+ function work_docx_text_box_import_textNodes(root) {
8930
+ const walker = root.ownerDocument?.createTreeWalker(root, NodeFilter.SHOW_TEXT);
8931
+ const nodes = [];
8932
+ if (!walker) return nodes;
8933
+ while(walker.nextNode())nodes.push(walker.currentNode);
8934
+ return nodes;
8513
8935
  }
8514
- export { applyImportedDocxEquationMarkers, applyImportedDocxIndexMarkers, applyImportedDocxNumberingChangeMarkers, applyImportedDocxParagraphAlignmentMarkers, applyImportedDocxParagraphBorderMarkers, applyImportedDocxParagraphDirectionMarkers, applyImportedDocxParagraphFormattingChangeMarkers, applyImportedDocxParagraphIndentMarkers, applyImportedDocxParagraphPaginationMarkers, applyImportedDocxParagraphShadingMarkers, applyImportedDocxParagraphSpacingMarkers, applyImportedDocxParagraphTabStopMarkers, applyImportedDocxRunFormattingMarkers, applyImportedDocxTableOfContentsMarkers, applyImportedDocxTextBoxMarkers, createDocxParagraphStyleResolver, createDocxTableStyleResolver, createImportedDocxRunFormattingMarkerState, docxCaptionBookmark, docxCaptionReferenceTarget, docxCaptionSequenceKind, docxEquationHtml, docxFieldInstructions, docxFieldOccurrenceIsInlineEditable, docxFieldOccurrences, docxFieldResultText, docxRunPropertySources, docxTableCellStyleLayers, docxTablePropertySources, docxTableRunPropertySources, hasImportedDocxIndexMarkers, hasImportedDocxNumberingChangeMarkers, hasImportedDocxParagraphAlignmentMarkers, hasImportedDocxParagraphBorderMarkers, hasImportedDocxParagraphDirectionMarkers, hasImportedDocxParagraphFormattingChangeMarkers, hasImportedDocxParagraphIndentMarkers, hasImportedDocxParagraphPaginationMarkers, hasImportedDocxParagraphShadingMarkers, hasImportedDocxParagraphSpacingMarkers, hasImportedDocxParagraphTabStopMarkers, hasImportedDocxRunFormattingMarkers, hasImportedDocxTableOfContentsMarkers, hasImportedDocxTextBoxMarkers, hasInvalidDocxFieldStructure, importedDocxStrike, importedDocxUnderline, inspectDocxEquation, inspectDocxHiddenText, inspectDocxLegacyTextEffects, inspectDocxPageBorders, inspectDocxPageMarginSettings, inspectDocxPageMargins, inspectDocxPageSize, inspectDocxPaperSource, inspectDocxRunBorder, inspectDocxRunFonts, inspectDocxRunShading, inspectDocxTextBoxes, isDocxEquationLikeRoot, isSupportedDocxEquationPlacement, isSupportedDocxNumberingChange, isSupportedDocxParagraphFormattingChange, isSupportedDocxRunFormattingChange, markDocxIndexes, markDocxNumberingChanges, markDocxPackageEquations, markDocxParagraphAlignments, markDocxParagraphBorders, markDocxParagraphDirections, markDocxParagraphFormattingChanges, markDocxParagraphIndents, markDocxParagraphPagination, markDocxParagraphShading, markDocxParagraphSpacing, markDocxParagraphTabStops, markDocxRunFormattingIntoState, markDocxTablesOfContents, markDocxTextBoxes, parseDirectDocxParagraphShading, parseDocxPageBorders, parseDocxPageGeometry, parseDocxPageMargins, parseDocxPaperSource, resolveDocxHiddenText, resolveDocxLegacyTextEffects, resolveDocxParagraphBordersForParagraph, resolveDocxRunBorder, resolveDocxRunShading, resolveDocxTableStyleResolver, supportedDocxIndexEntryField, supportedDocxIndexField, supportedDocxTableOfContentsField };
8936
+ export { applyImportedDocxContentControlMarkers, applyImportedDocxEquationMarkers, applyImportedDocxIndexMarkers, applyImportedDocxNumberingChangeMarkers, applyImportedDocxParagraphAlignmentMarkers, applyImportedDocxParagraphBorderMarkers, applyImportedDocxParagraphDirectionMarkers, applyImportedDocxParagraphFormattingChangeMarkers, applyImportedDocxParagraphIndentMarkers, applyImportedDocxParagraphPaginationMarkers, applyImportedDocxParagraphShadingMarkers, applyImportedDocxParagraphSpacingMarkers, applyImportedDocxParagraphTabStopMarkers, applyImportedDocxRunFormattingMarkers, applyImportedDocxTableOfContentsMarkers, applyImportedDocxTextBoxMarkers, createDocxParagraphStyleResolver, createDocxTableStyleResolver, createImportedDocxRunFormattingMarkerState, docxCaptionBookmark, docxCaptionReferenceTarget, docxCaptionSequenceKind, docxEquationHtml, docxFieldInstructions, docxFieldOccurrenceIsInlineEditable, docxFieldOccurrences, docxFieldResultText, docxRunPropertySources, docxTableCellStyleLayers, docxTablePropertySources, docxTableRunPropertySources, hasImportedDocxContentControlMarkers, hasImportedDocxIndexMarkers, hasImportedDocxNumberingChangeMarkers, hasImportedDocxParagraphAlignmentMarkers, hasImportedDocxParagraphBorderMarkers, hasImportedDocxParagraphDirectionMarkers, hasImportedDocxParagraphFormattingChangeMarkers, hasImportedDocxParagraphIndentMarkers, hasImportedDocxParagraphPaginationMarkers, hasImportedDocxParagraphShadingMarkers, hasImportedDocxParagraphSpacingMarkers, hasImportedDocxParagraphTabStopMarkers, hasImportedDocxRunFormattingMarkers, hasImportedDocxTableOfContentsMarkers, hasImportedDocxTextBoxMarkers, hasInvalidDocxFieldStructure, importedDocxStrike, importedDocxUnderline, inspectDocxContentControls, inspectDocxEquation, inspectDocxHiddenText, inspectDocxLegacyTextEffects, inspectDocxPageBorders, inspectDocxPageMarginSettings, inspectDocxPageMargins, inspectDocxPageSize, inspectDocxPaperSource, inspectDocxRunBorder, inspectDocxRunFonts, inspectDocxRunShading, inspectDocxTextBoxes, isDocxEquationLikeRoot, isSupportedDocxEquationPlacement, isSupportedDocxNumberingChange, isSupportedDocxParagraphFormattingChange, isSupportedDocxRunFormattingChange, markDocxContentControls, markDocxIndexes, markDocxNumberingChanges, markDocxPackageEquations, markDocxParagraphAlignments, markDocxParagraphBorders, markDocxParagraphDirections, markDocxParagraphFormattingChanges, markDocxParagraphIndents, markDocxParagraphPagination, markDocxParagraphShading, markDocxParagraphSpacing, markDocxParagraphTabStops, markDocxRunFormattingIntoState, markDocxTablesOfContents, markDocxTextBoxes, parseDirectDocxParagraphShading, parseDocxPageBorders, parseDocxPageGeometry, parseDocxPageMargins, parseDocxPaperSource, resolveDocxHiddenText, resolveDocxLegacyTextEffects, resolveDocxParagraphBordersForParagraph, resolveDocxRunBorder, resolveDocxRunShading, resolveDocxTableStyleResolver, supportedDocxIndexEntryField, supportedDocxIndexField, supportedDocxTableOfContentsField };