@a3s-lab/office 0.47.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,8 +1,8 @@
1
1
  import jszip from "jszip";
2
- import { normalizeDocumentBookmarkName, normalizeDocumentEmphasisMark, DOCUMENT_STRIKE_STYLE_ATTRIBUTE, applyDocumentImageIdentityToElement, documentEmphasisMarkFromElement, DOCUMENT_PAGE_BORDER_EDGES, DOCUMENT_UNDERLINE_STYLE_ATTRIBUTE, createDocumentImageIdentityRegistry, normalizeDocumentColumns, normalizeDocumentTableVerticalAlign, normalizeDocumentTextCase, documentCharacterSpacingTwipsFromElement, documentCharacterPositionHalfPointsFromElement, documentTableColumnPercentagesFromElement, documentTableCellMarginOverridesFromElement, applyDocumentTableRowIdentityToElement, normalizeDocumentBookmarksHtml, documentImageIdentityFromElement, documentTableGeometryFromElement, normalizeDocumentTableRowHeightRule, documentNoteKey, DOCUMENT_LEGACY_TEXT_EMBOSS_ATTRIBUTE, normalizeDocumentHiddenText, documentLegacyTextEffectsConflict, normalizeDocumentTableBorderWidth, normalizeDocumentCharacterSpacingTwips, documentStrikeFormattingFromElement, normalizeDocumentTableBorderStyle, parseDocumentNumberingChange, normalizeDocumentBookmarkReferencesHtml, documentCitationInstruction, documentImageWrapContourFromElement, documentImagePositionFromElement, normalizeDocumentCharacterScalePercent, normalizeDocumentUnderlineStyle, normalizeDocumentPageChrome, documentPageMarginsForLayout, normalizeDocumentImageLayer, documentKerningThresholdHalfPointsFromElement, documentImageCropFromElement, documentBookmarkReferenceInstruction, normalizeDocumentPageBorders, documentImageLayerFromElement, serializeDocumentOpenTypeFeatures, documentCaptionLabel, documentCaptionKind, isContourImageLayout, normalizeDocumentLegacyTextEffects, DOCUMENT_LEGACY_TEXT_IMPRINT_ATTRIBUTE, normalizeDocumentImageIdentity, supportedDocxDocumentFieldInstruction, normalizeDocumentStrikeStyle, normalizeDocumentOpenTypeFeatures, documentCitationTags, docxDocumentFieldKind, normalizeTableColor, documentTableBordersFromElement, documentSections, wrapsBesideImage, normalizeDocumentCharacterPositionHalfPoints, normalizeDocumentKerningThresholdHalfPoints, documentTextBoxPropertiesFromElement, defaultDocumentImageWrapContour, parseDocumentOpenTypeFeatures, normalizeDocumentPaperSource, DOCUMENT_LEGACY_TEXT_OUTLINE_ATTRIBUTE, documentEquationFromElement, documentImageTransformFromElement, parseDocumentCharacterFormatting, documentLegacyTextEffectsFromElement, documentUnderlineFormattingFromElement, DOCUMENT_LEGACY_TEXT_SHADOW_ATTRIBUTE, normalizeDocumentEquation, parseDocumentParagraphFormatting, documentOpenTypeFeaturesFromElement, normalizeDocumentBookmarkNativeId, documentTableRowIdentityFromElement, DOCUMENT_PAGE_MARGIN_KEYS, uniqueDocumentImageIdentity, documentHiddenTextFromElement, collectDocumentNotes, documentImageLayoutFromElement, documentPageHorizontalMarginTwips, DOCUMENT_OPEN_TYPE_ATTRIBUTE, MAX_DOCUMENT_NUMBERING_START, documentPageGeometryForLayout, DOCUMENT_LEGACY_TEXT_EFFECT_NAMES, documentCharacterScalePercentFromElement, normalizeDocumentPageMargins, normalizeDocumentLegacyTextEffect, documentNoteKind } from "./4174.js";
2
+ import { normalizeDocumentBookmarkName, normalizeDocumentEmphasisMark, DOCUMENT_STRIKE_STYLE_ATTRIBUTE, applyDocumentImageIdentityToElement, documentEmphasisMarkFromElement, DOCUMENT_PAGE_BORDER_EDGES, DOCUMENT_UNDERLINE_STYLE_ATTRIBUTE, createDocumentImageIdentityRegistry, normalizeDocumentColumns, normalizeDocumentTableVerticalAlign, normalizeDocumentTextCase, documentCharacterSpacingTwipsFromElement, documentCharacterPositionHalfPointsFromElement, documentTableColumnPercentagesFromElement, documentTableCellMarginOverridesFromElement, applyDocumentTableRowIdentityToElement, normalizeDocumentBookmarksHtml, documentImageIdentityFromElement, documentTableGeometryFromElement, normalizeDocumentTableRowHeightRule, documentNoteKey, DOCUMENT_LEGACY_TEXT_EMBOSS_ATTRIBUTE, normalizeDocumentHiddenText, documentLegacyTextEffectsConflict, normalizeDocumentTableBorderWidth, normalizeDocumentCharacterSpacingTwips, documentStrikeFormattingFromElement, normalizeDocumentTableBorderStyle, parseDocumentNumberingChange, normalizeDocumentBookmarkReferencesHtml, documentCitationInstruction, documentImageWrapContourFromElement, documentImagePositionFromElement, normalizeDocumentCharacterScalePercent, normalizeDocumentUnderlineStyle, normalizeDocumentPageChrome, documentPageMarginsForLayout, normalizeDocumentImageLayer, documentBookmarkReferenceInstruction, documentContentControlPropertiesFromElement, documentImageCropFromElement, normalizeDocumentPageBorders, documentImageLayerFromElement, serializeDocumentOpenTypeFeatures, documentCaptionLabel, documentCaptionKind, isContourImageLayout, normalizeDocumentLegacyTextEffects, DOCUMENT_LEGACY_TEXT_IMPRINT_ATTRIBUTE, documentKerningThresholdHalfPointsFromElement, supportedDocxDocumentFieldInstruction, normalizeDocumentStrikeStyle, normalizeDocumentOpenTypeFeatures, documentCitationTags, docxDocumentFieldKind, normalizeDocumentImageIdentity, normalizeTableColor, documentTableBordersFromElement, wrapsBesideImage, normalizeDocumentCharacterPositionHalfPoints, normalizeDocumentKerningThresholdHalfPoints, documentSections, defaultDocumentImageWrapContour, documentTextBoxPropertiesFromElement, parseDocumentOpenTypeFeatures, normalizeDocumentContentControlProperties, normalizeDocumentPaperSource, DOCUMENT_LEGACY_TEXT_OUTLINE_ATTRIBUTE, documentEquationFromElement, documentImageTransformFromElement, parseDocumentCharacterFormatting, documentLegacyTextEffectsFromElement, documentUnderlineFormattingFromElement, DOCUMENT_LEGACY_TEXT_SHADOW_ATTRIBUTE, normalizeDocumentEquation, parseDocumentParagraphFormatting, documentOpenTypeFeaturesFromElement, normalizeDocumentBookmarkNativeId, documentTableRowIdentityFromElement, DOCUMENT_PAGE_MARGIN_KEYS, uniqueDocumentImageIdentity, documentHiddenTextFromElement, collectDocumentNotes, documentImageLayoutFromElement, documentPageHorizontalMarginTwips, DOCUMENT_OPEN_TYPE_ATTRIBUTE, MAX_DOCUMENT_NUMBERING_START, documentPageGeometryForLayout, DOCUMENT_LEGACY_TEXT_EFFECT_NAMES, documentCharacterScalePercentFromElement, normalizeDocumentPageMargins, normalizeDocumentLegacyTextEffect, documentNoteKind } from "./4174.js";
3
3
  import { normalizeDocumentRunBorder, parseDocumentScriptFonts, parseDocxThemeReference, parseXml, parseDocumentRunShading, applyDocumentParagraphIdentityToElement, DOCUMENT_RUN_SHADING_ATTRIBUTE, documentScriptFontSlotFromElement, DOCUMENT_HIGHLIGHT_ATTRIBUTE, normalizeDocumentIndexesHtml, serializeDocumentScriptFonts, attribute as work_ooxml_package_attribute, createDocumentParagraphIdentityRegistry, uniqueDocumentParagraphIdentity, DOCUMENT_NO_PROOF_ATTRIBUTE, documentHighlightForCssColor, directChildren, documentTableOfContentsValueFromElement, DOCUMENT_PROOFING_LANGUAGES_ATTRIBUTE, DocxThemePatchCollector, normalizeDocumentScriptFonts, normalizeDocumentParagraphIdentity, normalizeDocumentHighlight, normalizeDocumentParagraphBorders, serializeUtf8Xml, DOCUMENT_PARAGRAPH_BORDER_EDGES, parseDocumentRunBorder, normalizeDocumentNoProof, decodeXmlBytes, documentParagraphIdentityFromElement, normalizeDocumentParagraphId, documentScriptFontFamily, descendants, resolvePartTarget, documentProofingLanguagesFromElement, documentHighlightFromElement, parseDocumentRunShadingElement, parseDocumentProofingLanguages, patchDocxThemeReferences, parseDocumentParagraphBordersElement, DOCUMENT_RUN_BORDER_ATTRIBUTE, parseDocumentRunBorderElement, xmlNamespacePrefix, documentScriptFontSlotFromHint, documentNoProofFromElement, documentScriptFontsFromElement, normalizeDocumentRunShading, normalizeDocumentScriptFontSlot, directChild, documentIndexEntryFromElement, documentIndexValueFromElement, parseDocumentParagraphShadingElement, documentFontNameFromCssFamily } from "./6968.js";
4
4
  import { assignDocxNoteIds, patchDocxPageColor, normalizeDocxCommentId, assignDocxCommentThreads } from "./0~4980.js";
5
- import { DocxImageTransformPatchCollector, paragraphTabStops, patchDocxImageTransforms, mergeDocxIgnorableExtensionsAtPairs, DOCX_WORD_2010_NAMESPACE, docxKerningThresholdValue, patchDocxBibliography, documentIndexInstruction, docxCharacterScaleValue, XMLNS_NAMESPACE as work_docx_settings_xml_XMLNS_NAMESPACE, paragraphAlignment, xmlNamespaceUri, paragraphSpacingOptions, docxCharacterPositionValue, documentIndexEntryInstruction, docxEmphasisMarkRunOptions, hasNonWhitespaceXmlText, patchDocxExplicitZeroCharacterSpacing, cloneXmlElement, cssColorToHex, xmlDeclaredPrefix, assertXmlRoot, DOCX_WORDPROCESSING_NAMESPACES, paragraphIndent, domDirection, xmlAttributeNamespace, paragraphBidirectional, XML_NAMESPACE as work_docx_settings_xml_XML_NAMESPACE, mergeDocxIgnorableExtensions, DocxParagraphDefaultCollapsedPatchCollector, dataBoolean, patchDocxParagraphDefaultCollapsed, patchDocxExplicitZeroKerningThresholds, parseDocxColorSchemeMappingElement, paragraphPaginationOptions, DOCX_COLOR_SCHEME_MAPPING_ATTRIBUTES, documentProofingLanguageDocxOptions, xmlAttributeLocalName, cssFontSize, paragraphDirectionOptions, cssFontFamily, docxCharacterSpacingValue } from "./0~4042.js";
5
+ import { hasUnsupportedContentControlSemanticChild, hasContentControlRelationshipReference, hasOnlyPassiveContentControlAttributes, paragraphTabStops, patchDocxImageTransforms, docxEmphasisMarkRunOptions, patchDocxBibliography, docxKerningThresholdValue, docxCharacterScaleValue, XMLNS_NAMESPACE as work_docx_settings_xml_XMLNS_NAMESPACE, paragraphAlignment, isKnownOoxmlNamespace as work_docx_note_comment_hyperlink_content_isKnownOoxmlNamespace, noteCommentParagraphContent, documentIndexEntryInstruction, groupNoteCommentHyperlinks, ensureDocxExternalHyperlinkRelationships, hasNonWhitespaceXmlText, patchDocxExplicitZeroCharacterSpacing, cloneXmlElement, cssColorToHex, xmlDeclaredPrefix, assertXmlRoot, DOCX_WORDPROCESSING_NAMESPACES, xmlAttributeNamespace, mergeDocxIgnorableExtensions, createNamespacedElement, domDirection, documentProofingLanguageDocxOptions, patchDocxParagraphDefaultCollapsed, setWordContentControlAttribute, parseDocxColorSchemeMappingElement, CONTENT_CONTROL_MC_NAMESPACE, paragraphPaginationOptions, DOCX_COLOR_SCHEME_MAPPING_ATTRIBUTES, xmlAttributeLocalName, isDocxWordElement, setNamespacedContentControlAttribute, work_docx_note_comment_content_control_xml_wordDirectChildren, docxCharacterSpacingValue, noteCommentHyperlinksOverlap, DocxImageTransformPatchCollector, mergeDocxIgnorableExtensionsAtPairs, createWordElement as work_docx_note_comment_content_control_xml_createWordElement, DOCX_WORD_2010_NAMESPACE, docxCharacterPositionValue, documentIndexInstruction, xmlNamespaceUri, paragraphSpacingOptions, CONTENT_CONTROL_RELATIONSHIP_NAMESPACES, noteCommentContentParagraphs, DocxParagraphDefaultCollapsedPatchCollector, paragraphIndent, isContentControlSemanticNamespace, ensureIgnorableContentControlNamespace, XML_NAMESPACE as work_docx_settings_xml_XML_NAMESPACE, paragraphBidirectional, restoreElementChildren, dataBoolean, noteCommentHyperlinkSpanKey, CONTENT_CONTROL_WORD_2012_NAMESPACE, flushDocxHyperlinkRelationships, patchDocxExplicitZeroKerningThresholds, groupNoteCommentParagraphs, cssFontSize, loadDocxHyperlinkRelationshipState, paragraphDirectionOptions, alignCommentRunBoundaries as work_docx_note_comment_hyperlink_content_alignCommentRunBoundaries, setDocxHyperlinkDestination, cssFontFamily } from "./0~3534.js";
6
6
  import { normalizeDocumentHref } from "./0~work-document-links.js";
7
7
  const WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
8
8
  class DocxBookmarkPatchCollector {
@@ -448,6 +448,252 @@ function ensureNamespacePrefix(root, preferred, namespace) {
448
448
  function isWordElement(element) {
449
449
  return DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '');
450
450
  }
451
+ const work_docx_content_control_export_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
452
+ const STRICT_WORD_NAMESPACE = 'http://purl.oclc.org/ooxml/wordprocessingml/main';
453
+ const WORD_NAMESPACES = new Set([
454
+ work_docx_content_control_export_WORD_NAMESPACE,
455
+ STRICT_WORD_NAMESPACE
456
+ ]);
457
+ const STORY_PATTERN = /^word\/(?:document|header\d+|footer\d+|footnotes|endnotes|comments)\.xml$/;
458
+ const work_docx_content_control_export_WORD_2012_NAMESPACE = 'http://schemas.microsoft.com/office/word/2012/wordml';
459
+ class DocxContentControlPatchCollector {
460
+ patches = [];
461
+ nextMarker = 1;
462
+ register(properties) {
463
+ const index = this.nextMarker;
464
+ this.nextMarker += 1;
465
+ const patch = {
466
+ startMarker: `__A3S_WORK_CONTENT_CONTROL_START_${index}__`,
467
+ endMarker: `__A3S_WORK_CONTENT_CONTROL_END_${index}__`,
468
+ properties: normalizeDocumentContentControlProperties(properties)
469
+ };
470
+ this.patches.push(patch);
471
+ return {
472
+ startMarker: patch.startMarker,
473
+ endMarker: patch.endMarker
474
+ };
475
+ }
476
+ }
477
+ function docxContentControlRuns(element, docx, collector, children) {
478
+ const properties = documentContentControlPropertiesFromElement(element);
479
+ if (containsUnsupportedContentControlSemantics(element)) throw new Error('Document content controls support only inline text and rich-text formatting.');
480
+ const marker = collector.register(properties);
481
+ return [
482
+ new docx.TextRun(marker.startMarker),
483
+ ...children,
484
+ new docx.TextRun(marker.endMarker)
485
+ ];
486
+ }
487
+ async function patchDocxContentControls(buffer, patches) {
488
+ if (!patches.length) return buffer;
489
+ const archive = await jszip.loadAsync(buffer);
490
+ const entries = Object.values(archive.files).filter((entry)=>!entry.dir && STORY_PATTERN.test(entry.name));
491
+ const documents = await Promise.all(entries.map(async (entry)=>({
492
+ entry,
493
+ document: parseXml(await entry.async('text'), `generated DOCX ${entry.name}`)
494
+ })));
495
+ const usedIds = new Set();
496
+ for (const { document } of documents)for (const id of descendants(document, 'id')){
497
+ const value = work_docx_content_control_export_wordAttribute(id, 'val');
498
+ const parsed = null === value ? null : Number(value);
499
+ if (null !== parsed && Number.isSafeInteger(parsed) && parsed >= -2147483648 && parsed <= 2147483647) usedIds.add(parsed);
500
+ }
501
+ let nextId = 1;
502
+ const changed = new Set();
503
+ for (const patch of patches){
504
+ const match = findMarkerPair(documents, patch);
505
+ if (!match) throw new Error(`Generated DOCX did not emit both content-control markers ${patch.startMarker} and ${patch.endMarker}.`);
506
+ const nativeId = allocateNativeId(usedIds, patch.properties.nativeId, nextId);
507
+ usedIds.add(nativeId);
508
+ nextId = nativeId + 1;
509
+ wrapMarkerPair(match, patch.properties, nativeId);
510
+ changed.add(match.document);
511
+ }
512
+ for (const { entry, document } of documents)if (changed.has(document)) archive.file(entry.name, new XMLSerializer().serializeToString(document));
513
+ return archive.generateAsync({
514
+ type: 'arraybuffer'
515
+ });
516
+ }
517
+ function findMarkerPair(documents, patch) {
518
+ for (const { document } of documents){
519
+ const start = work_docx_content_control_export_markerRun(document, patch.startMarker);
520
+ const end = work_docx_content_control_export_markerRun(document, patch.endMarker);
521
+ if (!start || !end) continue;
522
+ const startParagraph = work_docx_content_control_export_closestAncestor(start, 'p');
523
+ const endParagraph = work_docx_content_control_export_closestAncestor(end, 'p');
524
+ if (!startParagraph || startParagraph !== endParagraph) break;
525
+ return {
526
+ document,
527
+ paragraph: startParagraph,
528
+ start,
529
+ end
530
+ };
531
+ }
532
+ return null;
533
+ }
534
+ function wrapMarkerPair(match, properties, nativeId) {
535
+ const { document, paragraph, start, end } = match;
536
+ if (start.parentNode !== paragraph || end.parentNode !== paragraph) throw new Error('Generated DOCX content-control markers must be direct paragraph runs.');
537
+ const contentRuns = [];
538
+ let current = start.nextSibling;
539
+ while(current && current !== end){
540
+ const next = current.nextSibling;
541
+ if (!work_docx_content_control_export_isWordElement(current) || 'r' !== current.localName) throw new Error('Generated DOCX content controls cannot contain non-run semantic nodes.');
542
+ contentRuns.push(current);
543
+ current = next;
544
+ }
545
+ if (current !== end) throw new Error('Generated DOCX content-control marker order is invalid.');
546
+ const control = wordElement(document, paragraph, 'sdt');
547
+ const propertiesElement = wordElement(document, paragraph, 'sdtPr');
548
+ appendContentControlProperties(document, paragraph, propertiesElement, properties, nativeId);
549
+ const content = wordElement(document, paragraph, 'sdtContent');
550
+ for (const run of contentRuns)content.append(run);
551
+ if (!contentRuns.length) content.append(emptyRun(document, paragraph));
552
+ control.append(propertiesElement, content);
553
+ paragraph.insertBefore(control, start);
554
+ start.remove();
555
+ end.remove();
556
+ const root = document.documentElement;
557
+ if ('boundingBox' !== properties.appearance || properties.color) ensureIgnorableContentControlNamespace(root, work_docx_content_control_export_WORD_2012_NAMESPACE, 'w15');
558
+ }
559
+ function appendContentControlProperties(document, context, propertiesElement, properties, nativeId) {
560
+ const id = wordElement(document, context, 'id');
561
+ setWordAttribute(id, context, 'val', String(nativeId));
562
+ propertiesElement.append(id);
563
+ if (properties.alias) {
564
+ const alias = wordElement(document, context, 'alias');
565
+ setWordAttribute(alias, context, 'val', properties.alias);
566
+ propertiesElement.append(alias);
567
+ }
568
+ if (properties.tag) {
569
+ const tag = wordElement(document, context, 'tag');
570
+ setWordAttribute(tag, context, 'val', properties.tag);
571
+ propertiesElement.append(tag);
572
+ }
573
+ if ('unlocked' !== properties.lock) {
574
+ const lock = wordElement(document, context, 'lock');
575
+ setWordAttribute(lock, context, 'val', properties.lock);
576
+ propertiesElement.append(lock);
577
+ }
578
+ if ('text' === properties.type) {
579
+ const text = wordElement(document, context, 'text');
580
+ if (properties.multiLine) setWordAttribute(text, context, 'multiLine', '1');
581
+ propertiesElement.append(text);
582
+ } else propertiesElement.append(wordElement(document, context, 'richText'));
583
+ if ('boundingBox' !== properties.appearance) {
584
+ const appearance = namespacedElement(document, context, work_docx_content_control_export_WORD_2012_NAMESPACE, 'w15', 'appearance');
585
+ setNamespacedAttribute(appearance, context, work_docx_content_control_export_WORD_2012_NAMESPACE, 'w15', 'val', properties.appearance);
586
+ propertiesElement.append(appearance);
587
+ }
588
+ if (properties.color) {
589
+ const color = namespacedElement(document, context, work_docx_content_control_export_WORD_2012_NAMESPACE, 'w15', 'color');
590
+ setNamespacedAttribute(color, context, work_docx_content_control_export_WORD_2012_NAMESPACE, 'w15', 'val', properties.color.slice(1).toUpperCase());
591
+ propertiesElement.append(color);
592
+ }
593
+ }
594
+ function emptyRun(document, context) {
595
+ const run = wordElement(document, context, 'r');
596
+ const text = wordElement(document, context, 't');
597
+ text.setAttributeNS(work_docx_settings_xml_XML_NAMESPACE, 'xml:space', 'preserve');
598
+ text.textContent = '';
599
+ run.append(text);
600
+ return run;
601
+ }
602
+ function work_docx_content_control_export_markerRun(document, marker) {
603
+ const texts = descendants(document, 't');
604
+ let occurrences = 0;
605
+ for (const text of texts)occurrences += markerOccurrences(text.textContent ?? '', marker);
606
+ if (occurrences > 1) throw new Error(`Generated DOCX content-control marker ${marker} occurs more than once.`);
607
+ for (const text of texts){
608
+ if (!(text.textContent ?? '').includes(marker)) continue;
609
+ const run = work_docx_content_control_export_closestAncestor(text, 'r');
610
+ if (run) {
611
+ isolateMarkerRun(text, run, marker);
612
+ return findRunContainingMarker(document, marker);
613
+ }
614
+ }
615
+ return null;
616
+ }
617
+ function markerOccurrences(value, marker) {
618
+ if (!marker) return 0;
619
+ let count = 0;
620
+ let offset = 0;
621
+ while(true){
622
+ const index = value.indexOf(marker, offset);
623
+ if (index < 0) return count;
624
+ count += 1;
625
+ offset = index + marker.length;
626
+ }
627
+ }
628
+ function isolateMarkerRun(text, run, marker) {
629
+ const value = text.textContent ?? '';
630
+ const index = value.indexOf(marker);
631
+ if (index < 0 || !run.parentNode) return;
632
+ if (Array.from(run.children).some((child)=>child !== text && 'rPr' !== child.localName)) throw new Error('Generated DOCX content-control marker run is ambiguous.');
633
+ const before = value.slice(0, index);
634
+ const after = value.slice(index + marker.length);
635
+ const parent = run.parentNode;
636
+ if (before) parent.insertBefore(cloneRunWithText(run, before), run);
637
+ parent.insertBefore(cloneRunWithText(run, marker), run);
638
+ if (after) parent.insertBefore(cloneRunWithText(run, after), run);
639
+ run.remove();
640
+ }
641
+ function cloneRunWithText(run, value) {
642
+ const clone = run.cloneNode(true);
643
+ const text = Array.from(clone.children).find((child)=>'t' === child.localName);
644
+ if (!text) throw new Error('Generated DOCX marker run has no text node.');
645
+ for (const child of Array.from(clone.children))if (child !== text && 'rPr' !== child.localName) child.remove();
646
+ text.textContent = value;
647
+ if (/^\s|\s$/u.test(value)) text.setAttributeNS(work_docx_settings_xml_XML_NAMESPACE, 'xml:space', 'preserve');
648
+ return clone;
649
+ }
650
+ function findRunContainingMarker(document, marker) {
651
+ return descendants(document, 'r').find((run)=>Array.from(run.children).some((child)=>'t' === child.localName && (child.textContent ?? '').includes(marker))) ?? null;
652
+ }
653
+ function work_docx_content_control_export_closestAncestor(element, localName) {
654
+ let current = element;
655
+ while(current){
656
+ if (current.localName === localName && work_docx_content_control_export_isWordElement(current)) return current;
657
+ current = current.parentElement;
658
+ }
659
+ return null;
660
+ }
661
+ function allocateNativeId(used, preferred, start) {
662
+ if (null !== preferred && Number.isSafeInteger(preferred) && preferred >= -2147483648 && preferred <= 2147483647 && !used.has(preferred)) return preferred;
663
+ let candidate = Math.max(1, start);
664
+ while(candidate <= 2147483647 && used.has(candidate))candidate += 1;
665
+ if (candidate > 2147483647) throw new Error('DOCX content-control IDs are exhausted.');
666
+ return candidate;
667
+ }
668
+ function containsUnsupportedContentControlSemantics(element) {
669
+ return Boolean(element.querySelector('a, img, [data-document-field], [data-document-equation], [data-document-note-reference], [data-document-content-control]'));
670
+ }
671
+ function work_docx_content_control_export_isWordElement(element) {
672
+ return element instanceof Element && WORD_NAMESPACES.has(element.namespaceURI ?? '');
673
+ }
674
+ function wordElement(document, context, localName) {
675
+ const namespace = context.namespaceURI ?? work_docx_content_control_export_WORD_NAMESPACE;
676
+ const prefix = xmlNamespacePrefix(context, namespace) ?? 'w';
677
+ return document.createElementNS(namespace, `${prefix}:${localName}`);
678
+ }
679
+ function setWordAttribute(element, context, localName, value) {
680
+ const namespace = context.namespaceURI ?? work_docx_content_control_export_WORD_NAMESPACE;
681
+ const prefix = xmlNamespacePrefix(context, namespace) ?? 'w';
682
+ element.setAttributeNS(namespace, `${prefix}:${localName}`, value);
683
+ }
684
+ function namespacedElement(document, context, namespace, preferredPrefix, localName) {
685
+ const root = context.ownerDocument.documentElement;
686
+ const prefix = root.lookupPrefix?.(namespace) ?? Array.from(root.attributes).find((item)=>item.name.startsWith('xmlns:') && item.value === namespace)?.name.slice('xmlns:'.length) ?? preferredPrefix;
687
+ return document.createElementNS(namespace, `${prefix}:${localName}`);
688
+ }
689
+ function setNamespacedAttribute(element, context, namespace, preferredPrefix, localName, value) {
690
+ const prefix = context.ownerDocument.documentElement.lookupPrefix?.(namespace) ?? preferredPrefix;
691
+ element.setAttributeNS(namespace, `${prefix}:${localName}`, value);
692
+ }
693
+ function work_docx_content_control_export_wordAttribute(element, localName) {
694
+ const matches = Array.from(element.attributes).filter((item)=>item.localName === localName && WORD_NAMESPACES.has(xmlAttributeNamespace(element, item) ?? ''));
695
+ return 1 === matches.length ? matches[0].value : null;
696
+ }
451
697
  const work_docx_paragraph_borders_export_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
452
698
  class DocxParagraphBorderPatchCollector {
453
699
  patches = [];
@@ -531,21 +777,21 @@ function replaceParagraphBorders(document, container, borders) {
531
777
  }
532
778
  }
533
779
  function setDocxBorderAttributes(document, element, border) {
534
- setWordAttribute(document, element, 'val', border.style);
780
+ work_docx_paragraph_borders_export_setWordAttribute(document, element, 'val', border.style);
535
781
  setBorderColor(document, element, border);
536
- if (void 0 !== border.size) setWordAttribute(document, element, 'sz', String(border.size));
537
- if (void 0 !== border.space) setWordAttribute(document, element, 'space', String(border.space));
538
- if (void 0 !== border.shadow) setWordAttribute(document, element, 'shadow', border.shadow ? '1' : '0');
539
- if (void 0 !== border.frame) setWordAttribute(document, element, 'frame', border.frame ? '1' : '0');
782
+ if (void 0 !== border.size) work_docx_paragraph_borders_export_setWordAttribute(document, element, 'sz', String(border.size));
783
+ if (void 0 !== border.space) work_docx_paragraph_borders_export_setWordAttribute(document, element, 'space', String(border.space));
784
+ if (void 0 !== border.shadow) work_docx_paragraph_borders_export_setWordAttribute(document, element, 'shadow', border.shadow ? '1' : '0');
785
+ if (void 0 !== border.frame) work_docx_paragraph_borders_export_setWordAttribute(document, element, 'frame', border.frame ? '1' : '0');
540
786
  }
541
787
  function setBorderColor(document, element, border) {
542
788
  const color = border.color;
543
789
  if (!color) return;
544
- setWordAttribute(document, element, 'color', 'auto' === color.value ? 'auto' : color.value.slice(1).toUpperCase());
790
+ work_docx_paragraph_borders_export_setWordAttribute(document, element, 'color', 'auto' === color.value ? 'auto' : color.value.slice(1).toUpperCase());
545
791
  if (!color.theme) return;
546
- setWordAttribute(document, element, 'themeColor', color.theme.theme);
547
- if (color.theme.tint) setWordAttribute(document, element, 'themeTint', color.theme.tint);
548
- if (color.theme.shade) setWordAttribute(document, element, 'themeShade', color.theme.shade);
792
+ work_docx_paragraph_borders_export_setWordAttribute(document, element, 'themeColor', color.theme.theme);
793
+ if (color.theme.tint) work_docx_paragraph_borders_export_setWordAttribute(document, element, 'themeTint', color.theme.tint);
794
+ if (color.theme.shade) work_docx_paragraph_borders_export_setWordAttribute(document, element, 'themeShade', color.theme.shade);
549
795
  }
550
796
  function sourceColors(source) {
551
797
  const colors = new Set();
@@ -559,7 +805,7 @@ function sourceColors(source) {
559
805
  function work_docx_paragraph_borders_export_wordAttribute(element, name) {
560
806
  return element.getAttributeNS(work_docx_paragraph_borders_export_WORD_NAMESPACE, name) ?? element.getAttribute(`w:${name}`);
561
807
  }
562
- function setWordAttribute(document, element, name, value) {
808
+ function work_docx_paragraph_borders_export_setWordAttribute(document, element, name, value) {
563
809
  const prefix = xmlNamespacePrefix(document.documentElement, work_docx_paragraph_borders_export_WORD_NAMESPACE) ?? 'w';
564
810
  element.setAttributeNS(work_docx_paragraph_borders_export_WORD_NAMESPACE, `${prefix}:${name}`, value);
565
811
  }
@@ -2471,17 +2717,17 @@ function setRunFormattingChange(document, run, patch) {
2471
2717
  if (existing.length > 1) throw new Error('Generated DOCX run contains duplicate properties.');
2472
2718
  const properties = existing[0] ?? insertRunProperties(document, run, wordNamespace, prefix);
2473
2719
  if (directChildren(properties, 'rPrChange').some((element)=>element.namespaceURI === wordNamespace)) throw new Error('Generated DOCX run already contains a formatting revision.');
2474
- const change = wordElement(document, wordNamespace, prefix, 'rPrChange');
2720
+ const change = work_docx_format_change_export_wordElement(document, wordNamespace, prefix, 'rPrChange');
2475
2721
  work_docx_format_change_export_setWordAttribute(change, wordNamespace, prefix, 'id', String(patch.id));
2476
2722
  work_docx_format_change_export_setWordAttribute(change, wordNamespace, prefix, 'author', patch.author);
2477
2723
  work_docx_format_change_export_setWordAttribute(change, wordNamespace, prefix, 'date', patch.date);
2478
- const before = wordElement(document, wordNamespace, prefix, 'rPr');
2724
+ const before = work_docx_format_change_export_wordElement(document, wordNamespace, prefix, 'rPr');
2479
2725
  appendFormattingProperties(document, before, wordNamespace, prefix, patch.before);
2480
2726
  change.append(before);
2481
2727
  properties.append(change);
2482
2728
  }
2483
2729
  function insertRunProperties(document, run, namespace, prefix) {
2484
- const properties = wordElement(document, namespace, prefix, 'rPr');
2730
+ const properties = work_docx_format_change_export_wordElement(document, namespace, prefix, 'rPr');
2485
2731
  run.insertBefore(properties, run.firstChild);
2486
2732
  return properties;
2487
2733
  }
@@ -2525,13 +2771,13 @@ function appendOpenTypeProperties(document, properties, mark) {
2525
2771
  function appendNoProofProperty(document, properties, namespace, prefix, mark) {
2526
2772
  const noProof = normalizeDocumentNoProof(mark?.attrs?.noProof);
2527
2773
  if (null === noProof) return;
2528
- if (noProof) properties.append(wordElement(document, namespace, prefix, 'noProof'));
2774
+ if (noProof) properties.append(work_docx_format_change_export_wordElement(document, namespace, prefix, 'noProof'));
2529
2775
  else appendValuedProperty(document, properties, namespace, prefix, 'noProof', '0');
2530
2776
  }
2531
2777
  function appendProofingLanguagesProperty(document, properties, namespace, prefix, mark) {
2532
2778
  const languages = parseDocumentProofingLanguages(mark?.attrs?.proofingLanguages);
2533
2779
  if (!languages) return;
2534
- const element = wordElement(document, namespace, prefix, 'lang');
2780
+ const element = work_docx_format_change_export_wordElement(document, namespace, prefix, 'lang');
2535
2781
  if (languages.latin) work_docx_format_change_export_setWordAttribute(element, namespace, prefix, 'val', languages.latin);
2536
2782
  if (languages.eastAsia) work_docx_format_change_export_setWordAttribute(element, namespace, prefix, 'eastAsia', languages.eastAsia);
2537
2783
  if (languages.bidi) work_docx_format_change_export_setWordAttribute(element, namespace, prefix, 'bidi', languages.bidi);
@@ -2540,7 +2786,7 @@ function appendProofingLanguagesProperty(document, properties, namespace, prefix
2540
2786
  function appendRunBorderProperty(document, properties, namespace, prefix, mark) {
2541
2787
  const border = parseDocumentRunBorder(mark?.attrs?.runBorder);
2542
2788
  if (!border) return;
2543
- const element = wordElement(document, namespace, prefix, 'bdr');
2789
+ const element = work_docx_format_change_export_wordElement(document, namespace, prefix, 'bdr');
2544
2790
  work_docx_format_change_export_setWordAttribute(element, namespace, prefix, 'val', border.style);
2545
2791
  if (border.color) {
2546
2792
  work_docx_format_change_export_setWordAttribute(element, namespace, prefix, 'color', 'auto' === border.color.value ? 'auto' : border.color.value.slice(1).toUpperCase());
@@ -2559,7 +2805,7 @@ function appendRunBorderProperty(document, properties, namespace, prefix, mark)
2559
2805
  function appendRunShadingProperty(document, properties, namespace, prefix, mark) {
2560
2806
  const shading = parseDocumentRunShading(mark?.attrs?.runShading);
2561
2807
  if (!shading) return;
2562
- const element = wordElement(document, namespace, prefix, 'shd');
2808
+ const element = work_docx_format_change_export_wordElement(document, namespace, prefix, 'shd');
2563
2809
  if (!setDocxRunShadingAttributes(document, element, shading)) return;
2564
2810
  properties.append(element);
2565
2811
  }
@@ -2590,14 +2836,14 @@ function appendLegacyTextEffectsProperties(document, properties, namespace, pref
2590
2836
  if (documentLegacyTextEffectsConflict(effects)) throw new Error('Document contains conflicting legacy text effects.');
2591
2837
  for (const name of DOCUMENT_LEGACY_TEXT_EFFECT_NAMES){
2592
2838
  const value = effects[name];
2593
- if (void 0 !== value) if (value) properties.append(wordElement(document, namespace, prefix, name));
2839
+ if (void 0 !== value) if (value) properties.append(work_docx_format_change_export_wordElement(document, namespace, prefix, name));
2594
2840
  else appendValuedProperty(document, properties, namespace, prefix, name, '0');
2595
2841
  }
2596
2842
  }
2597
2843
  function appendHiddenTextProperty(document, properties, namespace, prefix, mark) {
2598
2844
  const hiddenText = normalizeDocumentHiddenText(mark?.attrs?.hiddenText);
2599
2845
  if (null === hiddenText) return;
2600
- if (hiddenText) properties.append(wordElement(document, namespace, prefix, 'vanish'));
2846
+ if (hiddenText) properties.append(work_docx_format_change_export_wordElement(document, namespace, prefix, 'vanish'));
2601
2847
  else appendValuedProperty(document, properties, namespace, prefix, 'vanish', '0');
2602
2848
  }
2603
2849
  function appendEmphasisMarkProperty(document, properties, namespace, prefix, mark) {
@@ -2628,7 +2874,7 @@ function appendCharacterSpacingProperty(document, properties, namespace, prefix,
2628
2874
  function appendFontProperties(document, properties, namespace, prefix, mark) {
2629
2875
  const scriptFonts = parseDocumentScriptFonts('string' == typeof mark?.attrs?.scriptFonts ? mark.attrs.scriptFonts : void 0);
2630
2876
  if (scriptFonts) {
2631
- const fonts = wordElement(document, namespace, prefix, 'rFonts');
2877
+ const fonts = work_docx_format_change_export_wordElement(document, namespace, prefix, 'rFonts');
2632
2878
  for (const [name, value] of [
2633
2879
  [
2634
2880
  'ascii',
@@ -2672,7 +2918,7 @@ function appendFontProperties(document, properties, namespace, prefix, mark) {
2672
2918
  }
2673
2919
  const family = firstFontFamily(mark?.attrs?.fontFamily);
2674
2920
  if (!family) return;
2675
- const fonts = wordElement(document, namespace, prefix, 'rFonts');
2921
+ const fonts = work_docx_format_change_export_wordElement(document, namespace, prefix, 'rFonts');
2676
2922
  for (const name of [
2677
2923
  'ascii',
2678
2924
  'hAnsi',
@@ -2686,7 +2932,7 @@ function appendUnderlineProperty(document, properties, namespace, prefix, mark)
2686
2932
  const style = normalizeDocumentUnderlineStyle(mark.attrs?.underlineStyle) ?? 'single';
2687
2933
  const color = normalizedHex(mark.attrs?.underlineColor);
2688
2934
  const theme = themeReference(mark.attrs?.underlineThemeColor);
2689
- const underline = wordElement(document, namespace, prefix, 'u');
2935
+ const underline = work_docx_format_change_export_wordElement(document, namespace, prefix, 'u');
2690
2936
  work_docx_format_change_export_setWordAttribute(underline, namespace, prefix, 'val', style);
2691
2937
  const resolved = color ?? normalizedHex(theme?.resolved);
2692
2938
  if (resolved) work_docx_format_change_export_setWordAttribute(underline, namespace, prefix, 'color', resolved);
@@ -2694,7 +2940,7 @@ function appendUnderlineProperty(document, properties, namespace, prefix, mark)
2694
2940
  properties.append(underline);
2695
2941
  }
2696
2942
  function appendBooleanProperty(document, properties, namespace, prefix, marks, mark, property) {
2697
- if (marks.has(mark)) properties.append(wordElement(document, namespace, prefix, property));
2943
+ if (marks.has(mark)) properties.append(work_docx_format_change_export_wordElement(document, namespace, prefix, property));
2698
2944
  }
2699
2945
  function appendStrikeProperties(document, properties, namespace, prefix, mark) {
2700
2946
  if (!mark) return;
@@ -2703,14 +2949,14 @@ function appendStrikeProperties(document, properties, namespace, prefix, mark) {
2703
2949
  appendValuedProperty(document, properties, namespace, prefix, 'dstrike', 'double' === style ? '1' : '0');
2704
2950
  }
2705
2951
  function appendValuedProperty(document, properties, namespace, prefix, property, value) {
2706
- const element = wordElement(document, namespace, prefix, property);
2952
+ const element = work_docx_format_change_export_wordElement(document, namespace, prefix, property);
2707
2953
  work_docx_format_change_export_setWordAttribute(element, namespace, prefix, 'val', value);
2708
2954
  properties.append(element);
2709
2955
  }
2710
2956
  function appendTextCaseProperties(document, properties, namespace, prefix, mark) {
2711
2957
  const textCase = mark?.attrs?.textCase;
2712
- if ('all-caps' === textCase) properties.append(wordElement(document, namespace, prefix, 'caps'));
2713
- else if ('small-caps' === textCase) properties.append(wordElement(document, namespace, prefix, 'smallCaps'));
2958
+ if ('all-caps' === textCase) properties.append(work_docx_format_change_export_wordElement(document, namespace, prefix, 'caps'));
2959
+ else if ('small-caps' === textCase) properties.append(work_docx_format_change_export_wordElement(document, namespace, prefix, 'smallCaps'));
2714
2960
  else if ('none' === textCase) {
2715
2961
  appendValuedProperty(document, properties, namespace, prefix, 'caps', '0');
2716
2962
  appendValuedProperty(document, properties, namespace, prefix, 'smallCaps', '0');
@@ -2720,7 +2966,7 @@ function appendColorProperty(document, properties, namespace, prefix, mark) {
2720
2966
  const color = normalizedHex(mark?.attrs?.color);
2721
2967
  const theme = themeReference(mark?.attrs?.themeColor);
2722
2968
  if (!color && !theme) return;
2723
- const element = wordElement(document, namespace, prefix, 'color');
2969
+ const element = work_docx_format_change_export_wordElement(document, namespace, prefix, 'color');
2724
2970
  work_docx_format_change_export_setWordAttribute(element, namespace, prefix, 'val', color ?? normalizedHex(theme?.resolved) ?? '000000');
2725
2971
  if (theme) setThemeAttributes(element, namespace, prefix, theme, 'themeColor');
2726
2972
  properties.append(element);
@@ -2738,7 +2984,7 @@ function appendHighlightProperty(document, properties, namespace, prefix, mark,
2738
2984
  const fill = normalizedHex(mark?.attrs?.color);
2739
2985
  const theme = themeReference(mark?.attrs?.themeFill);
2740
2986
  if (!fill && !theme) return;
2741
- const shading = wordElement(document, namespace, prefix, 'shd');
2987
+ const shading = work_docx_format_change_export_wordElement(document, namespace, prefix, 'shd');
2742
2988
  work_docx_format_change_export_setWordAttribute(shading, namespace, prefix, 'val', 'clear');
2743
2989
  work_docx_format_change_export_setWordAttribute(shading, namespace, prefix, 'color', 'auto');
2744
2990
  work_docx_format_change_export_setWordAttribute(shading, namespace, prefix, 'fill', fill ?? normalizedHex(theme?.resolved) ?? 'FFFFFF');
@@ -2786,7 +3032,7 @@ function normalizedHex(value) {
2786
3032
  const match = /^#?([0-9a-f]{6})$/i.exec(value.trim());
2787
3033
  return match?.[1]?.toUpperCase() ?? null;
2788
3034
  }
2789
- function wordElement(document, namespace, prefix, name) {
3035
+ function work_docx_format_change_export_wordElement(document, namespace, prefix, name) {
2790
3036
  return document.createElementNS(namespace, `${prefix}:${name}`);
2791
3037
  }
2792
3038
  function work_docx_format_change_export_setWordAttribute(element, namespace, prefix, name, value) {
@@ -4906,84 +5152,6 @@ function removeWordAttribute(element, localName) {
4906
5152
  function work_docx_table_of_contents_export_wordQualifiedName(root, localName) {
4907
5153
  return `${xmlNamespacePrefix(root, work_docx_table_of_contents_export_WORD_NAMESPACE) ?? 'w'}:${localName}`;
4908
5154
  }
4909
- const DOC_PROPERTIES_ID_MAX = 0xffffffff;
4910
- const TEXT_BOX_ID_MARKER_PATTERN = /__A3S_TEXT_BOX_ID_\d+__/g;
4911
- class DocxTextBoxIdentityPatchCollector {
4912
- patches = [];
4913
- nextMarker = 1;
4914
- register(properties) {
4915
- const marker = `__A3S_TEXT_BOX_ID_${this.nextMarker}__`;
4916
- this.nextMarker += 1;
4917
- this.patches.push({
4918
- marker,
4919
- preferredId: properties.docPropertiesId
4920
- });
4921
- return {
4922
- marker,
4923
- docPropertiesId: properties.docPropertiesId
4924
- };
4925
- }
4926
- }
4927
- async function patchDocxTextBoxIdentities(buffer, patches) {
4928
- if (!patches.length) return buffer;
4929
- const archive = await jszip.loadAsync(buffer);
4930
- const byMarker = new Map(patches.map((patch)=>[
4931
- patch.marker,
4932
- patch
4933
- ]));
4934
- const entries = Object.values(archive.files).filter((entry)=>!entry.dir && /^word\/(?:document|header\d+|footer\d+|footnotes|endnotes|comments)\.xml$/.test(entry.name));
4935
- const documents = await Promise.all(entries.map(async (entry)=>({
4936
- entry,
4937
- document: parseXml(await entry.async('text'), entry.name)
4938
- })));
4939
- const properties = documents.flatMap(({ document })=>descendants(document, 'docPr'));
4940
- const marked = properties.map((property)=>({
4941
- property,
4942
- patch: textBoxIdentityPatch(property, byMarker)
4943
- })).filter((value)=>Boolean(value.patch));
4944
- if (!marked.length) return buffer;
4945
- const used = new Set();
4946
- for (const property of properties){
4947
- if (marked.some((value)=>value.property === property)) continue;
4948
- const id = parseDocPropertiesId(property.getAttribute('id'));
4949
- if (null !== id) used.add(id);
4950
- }
4951
- let nextId = 1;
4952
- const changedDocuments = new Set();
4953
- for (const { property, patch } of marked){
4954
- removeTextBoxIdentityMarker(property, patch.marker);
4955
- const preferred = null === patch.preferredId || used.has(patch.preferredId) ? nextAvailableDocPropertiesId(used, nextId) : patch.preferredId;
4956
- used.add(preferred);
4957
- nextId = preferred + 1;
4958
- property.setAttribute('id', String(preferred));
4959
- changedDocuments.add(property.ownerDocument);
4960
- }
4961
- for (const { entry, document } of documents)if (changedDocuments.has(document)) archive.file(entry.name, new XMLSerializer().serializeToString(document));
4962
- return archive.generateAsync({
4963
- type: 'arraybuffer'
4964
- });
4965
- }
4966
- function textBoxIdentityPatch(property, byMarker) {
4967
- for (const attribute of Array.from(property.attributes)){
4968
- const marker = attribute.value.match(TEXT_BOX_ID_MARKER_PATTERN)?.find((value)=>byMarker.has(value));
4969
- if (marker) return byMarker.get(marker) ?? null;
4970
- }
4971
- return null;
4972
- }
4973
- function removeTextBoxIdentityMarker(property, marker) {
4974
- for (const attribute of Array.from(property.attributes))if (attribute.value.includes(marker)) attribute.value = attribute.value.replace(marker, '').replace(/\s{2,}/g, ' ').trim();
4975
- }
4976
- function parseDocPropertiesId(value) {
4977
- if (null === value || !/^\d+$/.test(value)) return null;
4978
- const id = Number(value);
4979
- return Number.isSafeInteger(id) && id <= DOC_PROPERTIES_ID_MAX ? id : null;
4980
- }
4981
- function nextAvailableDocPropertiesId(used, start) {
4982
- let candidate = Math.max(1, start);
4983
- while(candidate <= DOC_PROPERTIES_ID_MAX && used.has(candidate))candidate += 1;
4984
- if (candidate > DOC_PROPERTIES_ID_MAX) throw new Error('DOCX drawing-property IDs are exhausted.');
4985
- return candidate;
4986
- }
4987
5155
  const work_docx_table_sizing_export_TWIPS_PER_PIXEL = 15;
4988
5156
  function documentTableSizingDocxOptions(table, docx) {
4989
5157
  const geometry = documentTableGeometryFromElement(table);
@@ -5074,6 +5242,84 @@ function work_docx_table_sizing_export_pixelsToTwips(pixels) {
5074
5242
  function pixelsToNonNegativeTwips(pixels) {
5075
5243
  return Math.max(0, Math.round(pixels * work_docx_table_sizing_export_TWIPS_PER_PIXEL));
5076
5244
  }
5245
+ const DOC_PROPERTIES_ID_MAX = 0xffffffff;
5246
+ const TEXT_BOX_ID_MARKER_PATTERN = /__A3S_TEXT_BOX_ID_\d+__/g;
5247
+ class DocxTextBoxIdentityPatchCollector {
5248
+ patches = [];
5249
+ nextMarker = 1;
5250
+ register(properties) {
5251
+ const marker = `__A3S_TEXT_BOX_ID_${this.nextMarker}__`;
5252
+ this.nextMarker += 1;
5253
+ this.patches.push({
5254
+ marker,
5255
+ preferredId: properties.docPropertiesId
5256
+ });
5257
+ return {
5258
+ marker,
5259
+ docPropertiesId: properties.docPropertiesId
5260
+ };
5261
+ }
5262
+ }
5263
+ async function patchDocxTextBoxIdentities(buffer, patches) {
5264
+ if (!patches.length) return buffer;
5265
+ const archive = await jszip.loadAsync(buffer);
5266
+ const byMarker = new Map(patches.map((patch)=>[
5267
+ patch.marker,
5268
+ patch
5269
+ ]));
5270
+ const entries = Object.values(archive.files).filter((entry)=>!entry.dir && /^word\/(?:document|header\d+|footer\d+|footnotes|endnotes|comments)\.xml$/.test(entry.name));
5271
+ const documents = await Promise.all(entries.map(async (entry)=>({
5272
+ entry,
5273
+ document: parseXml(await entry.async('text'), entry.name)
5274
+ })));
5275
+ const properties = documents.flatMap(({ document })=>descendants(document, 'docPr'));
5276
+ const marked = properties.map((property)=>({
5277
+ property,
5278
+ patch: textBoxIdentityPatch(property, byMarker)
5279
+ })).filter((value)=>Boolean(value.patch));
5280
+ if (!marked.length) return buffer;
5281
+ const used = new Set();
5282
+ for (const property of properties){
5283
+ if (marked.some((value)=>value.property === property)) continue;
5284
+ const id = parseDocPropertiesId(property.getAttribute('id'));
5285
+ if (null !== id) used.add(id);
5286
+ }
5287
+ let nextId = 1;
5288
+ const changedDocuments = new Set();
5289
+ for (const { property, patch } of marked){
5290
+ removeTextBoxIdentityMarker(property, patch.marker);
5291
+ const preferred = null === patch.preferredId || used.has(patch.preferredId) ? nextAvailableDocPropertiesId(used, nextId) : patch.preferredId;
5292
+ used.add(preferred);
5293
+ nextId = preferred + 1;
5294
+ property.setAttribute('id', String(preferred));
5295
+ changedDocuments.add(property.ownerDocument);
5296
+ }
5297
+ for (const { entry, document } of documents)if (changedDocuments.has(document)) archive.file(entry.name, new XMLSerializer().serializeToString(document));
5298
+ return archive.generateAsync({
5299
+ type: 'arraybuffer'
5300
+ });
5301
+ }
5302
+ function textBoxIdentityPatch(property, byMarker) {
5303
+ for (const attribute of Array.from(property.attributes)){
5304
+ const marker = attribute.value.match(TEXT_BOX_ID_MARKER_PATTERN)?.find((value)=>byMarker.has(value));
5305
+ if (marker) return byMarker.get(marker) ?? null;
5306
+ }
5307
+ return null;
5308
+ }
5309
+ function removeTextBoxIdentityMarker(property, marker) {
5310
+ for (const attribute of Array.from(property.attributes))if (attribute.value.includes(marker)) attribute.value = attribute.value.replace(marker, '').replace(/\s{2,}/g, ' ').trim();
5311
+ }
5312
+ function parseDocPropertiesId(value) {
5313
+ if (null === value || !/^\d+$/.test(value)) return null;
5314
+ const id = Number(value);
5315
+ return Number.isSafeInteger(id) && id <= DOC_PROPERTIES_ID_MAX ? id : null;
5316
+ }
5317
+ function nextAvailableDocPropertiesId(used, start) {
5318
+ let candidate = Math.max(1, start);
5319
+ while(candidate <= DOC_PROPERTIES_ID_MAX && used.has(candidate))candidate += 1;
5320
+ if (candidate > DOC_PROPERTIES_ID_MAX) throw new Error('DOCX drawing-property IDs are exhausted.');
5321
+ return candidate;
5322
+ }
5077
5323
  const work_docx_comment_durable_id_preservation_WORD_2010_NAMESPACE = 'http://schemas.microsoft.com/office/word/2010/wordml';
5078
5324
  const COMMENTS_IDS_NAMESPACE = 'http://schemas.microsoft.com/office/word/2016/wordml/cid';
5079
5325
  const work_docx_comment_durable_id_preservation_COMMENTS_PATH = 'word/comments.xml';
@@ -5376,7 +5622,7 @@ function isKnownOoxmlDrawingNamespace(namespace) {
5376
5622
  const FONT_TABLE_PATH = 'word/fontTable.xml';
5377
5623
  const TRANSITIONAL_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
5378
5624
  const TRANSITIONAL_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
5379
- const WORD_NAMESPACES = new Set([
5625
+ const work_docx_font_table_preservation_WORD_NAMESPACES = new Set([
5380
5626
  TRANSITIONAL_WORD_NAMESPACE,
5381
5627
  'http://purl.oclc.org/ooxml/wordprocessingml/main'
5382
5628
  ]);
@@ -5416,8 +5662,8 @@ async function preserveDocxFontTable(generated, source, relationships, fontPartP
5416
5662
  ]);
5417
5663
  const generatedDocument = parseXml(decodeXmlBytes(generatedBytes, `generated DOCX ${generatedPath}`), `generated DOCX ${generatedPath}`);
5418
5664
  const sourceDocument = parseXml(decodeXmlBytes(sourceBytes, `source DOCX ${sourcePath}`), `source DOCX ${sourcePath}`);
5419
- assertXmlRoot(generatedDocument.documentElement, 'fonts', WORD_NAMESPACES, 'Generated DOCX word/fontTable.xml is not a WordprocessingML font table.');
5420
- assertXmlRoot(sourceDocument.documentElement, 'fonts', WORD_NAMESPACES, 'Registered source DOCX word/fontTable.xml is not a WordprocessingML font table.');
5665
+ assertXmlRoot(generatedDocument.documentElement, 'fonts', work_docx_font_table_preservation_WORD_NAMESPACES, 'Generated DOCX word/fontTable.xml is not a WordprocessingML font table.');
5666
+ assertXmlRoot(sourceDocument.documentElement, 'fonts', work_docx_font_table_preservation_WORD_NAMESPACES, 'Registered source DOCX word/fontTable.xml is not a WordprocessingML font table.');
5421
5667
  const generatedFonts = indexFonts(generatedDocument, 'Generated DOCX');
5422
5668
  const sourceFonts = indexFonts(sourceDocument, 'Registered source DOCX');
5423
5669
  const generatedRoot = generatedDocument.documentElement;
@@ -5438,7 +5684,7 @@ async function preserveDocxFontTable(generated, source, relationships, fontPartP
5438
5684
  generated.file(generatedPath, serializeUtf8Xml(generatedDocument));
5439
5685
  }
5440
5686
  function indexFonts(document, label) {
5441
- const fonts = directChildren(document.documentElement, 'font').filter((item)=>WORD_NAMESPACES.has(item.namespaceURI ?? ''));
5687
+ const fonts = directChildren(document.documentElement, 'font').filter((item)=>work_docx_font_table_preservation_WORD_NAMESPACES.has(item.namespaceURI ?? ''));
5442
5688
  if (fonts.length > MAX_FONT_RECORDS) throw new Error(`${label} font table exceeds the supported font-record limit.`);
5443
5689
  const result = new Map();
5444
5690
  for (const font of fonts){
@@ -5451,7 +5697,7 @@ function indexFonts(document, label) {
5451
5697
  return result;
5452
5698
  }
5453
5699
  function mergeFontChildren(document, generated, source, relationships, fontPartPaths, wordNamespace, wordPrefix, relationshipPrefix) {
5454
- const generatedNames = new Set(directChildren(generated).filter((item)=>WORD_NAMESPACES.has(item.namespaceURI ?? '')).map((item)=>item.localName));
5700
+ const generatedNames = new Set(directChildren(generated).filter((item)=>work_docx_font_table_preservation_WORD_NAMESPACES.has(item.namespaceURI ?? '')).map((item)=>item.localName));
5455
5701
  const sourceChildren = supportedFontChildren(source);
5456
5702
  for (const localName of FONT_CHILD_ORDER){
5457
5703
  if (generatedNames.has(localName)) continue;
@@ -5466,7 +5712,7 @@ function mergeFontChildren(document, generated, source, relationships, fontPartP
5466
5712
  }
5467
5713
  function supportedFontChildren(font) {
5468
5714
  const result = new Map();
5469
- for (const child of directChildren(font))if (WORD_NAMESPACES.has(child.namespaceURI ?? '') && FONT_CHILDREN.has(child.localName)) {
5715
+ for (const child of directChildren(font))if (work_docx_font_table_preservation_WORD_NAMESPACES.has(child.namespaceURI ?? '') && FONT_CHILDREN.has(child.localName)) {
5470
5716
  if (result.has(child.localName)) throw new Error(`Registered source DOCX font record ${fontName(font)} contains duplicate ${child.localName} settings.`);
5471
5717
  result.set(child.localName, child);
5472
5718
  }
@@ -5482,7 +5728,7 @@ function copyFontChild(document, source, relationships, fontPartPaths, wordNames
5482
5728
  for (const item of Array.from(source.attributes)){
5483
5729
  const namespace = xmlAttributeNamespace(source, item);
5484
5730
  const localName = xmlAttributeLocalName(item);
5485
- if (namespace && WORD_NAMESPACES.has(namespace)) result.setAttributeNS(wordNamespace, `${wordPrefix}:${localName}`, item.value);
5731
+ if (namespace && work_docx_font_table_preservation_WORD_NAMESPACES.has(namespace)) result.setAttributeNS(wordNamespace, `${wordPrefix}:${localName}`, item.value);
5486
5732
  }
5487
5733
  if (embedded && relationship) result.setAttributeNS(TRANSITIONAL_RELATIONSHIP_NAMESPACE, `${relationshipPrefix}:id`, relationship.id);
5488
5734
  return result;
@@ -5496,7 +5742,7 @@ function insertFontChild(font, child) {
5496
5742
  font.insertBefore(child, anchor ?? null);
5497
5743
  }
5498
5744
  function fontName(font) {
5499
- for (const item of Array.from(font.attributes))if (WORD_NAMESPACES.has(xmlAttributeNamespace(font, item) ?? '') && 'name' === xmlAttributeLocalName(item)) return item.value.trim();
5745
+ for (const item of Array.from(font.attributes))if (work_docx_font_table_preservation_WORD_NAMESPACES.has(xmlAttributeNamespace(font, item) ?? '') && 'name' === xmlAttributeLocalName(item)) return item.value.trim();
5500
5746
  return '';
5501
5747
  }
5502
5748
  function work_docx_font_table_preservation_relationshipAttribute(element, localName) {
@@ -5637,436 +5883,6 @@ function work_docx_numbering_extension_preservation_wordAttribute(element, name)
5637
5883
  for (const item of Array.from(element.attributes))if (DOCX_WORDPROCESSING_NAMESPACES.has(xmlAttributeNamespace(element, item) ?? '') && xmlAttributeLocalName(item) === name) return item.value.trim() || null;
5638
5884
  return null;
5639
5885
  }
5640
- const PACKAGE_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/package/2006/relationships';
5641
- const work_docx_note_comment_hyperlink_relationships_TRANSITIONAL_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
5642
- const STRICT_RELATIONSHIP_NAMESPACE = 'http://purl.oclc.org/ooxml/officeDocument/relationships';
5643
- const work_docx_note_comment_hyperlink_relationships_RELATIONSHIP_NAMESPACES = new Set([
5644
- work_docx_note_comment_hyperlink_relationships_TRANSITIONAL_RELATIONSHIP_NAMESPACE,
5645
- STRICT_RELATIONSHIP_NAMESPACE
5646
- ]);
5647
- const HYPERLINK_RELATIONSHIP_TYPES = new Set([
5648
- `${work_docx_note_comment_hyperlink_relationships_TRANSITIONAL_RELATIONSHIP_NAMESPACE}/hyperlink`,
5649
- `${STRICT_RELATIONSHIP_NAMESPACE}/hyperlink`
5650
- ]);
5651
- const GENERATED_HYPERLINK_RELATIONSHIP_TYPE = `${work_docx_note_comment_hyperlink_relationships_TRANSITIONAL_RELATIONSHIP_NAMESPACE}/hyperlink`;
5652
- const RELATIONSHIP_ID_PATTERN = /^[A-Za-z_][A-Za-z0-9_.-]{0,254}$/;
5653
- const MAX_RELATIONSHIPS = 65536;
5654
- async function loadDocxHyperlinkRelationshipState(generatedArchive, sourceArchive, ownerPart) {
5655
- const path = relationshipPartPath(ownerPart);
5656
- const [generated, source] = await Promise.all([
5657
- loadRelationships(generatedArchive, path, 'generated'),
5658
- loadRelationships(sourceArchive, path, 'source')
5659
- ]);
5660
- return {
5661
- archive: generatedArchive,
5662
- dirty: false,
5663
- generated: generated.document,
5664
- generatedMalformed: generated.malformed,
5665
- path,
5666
- source: source.document
5667
- };
5668
- }
5669
- function readDocxHyperlinkDestination(hyperlink, state, role) {
5670
- if (!DOCX_WORDPROCESSING_NAMESPACES.has(hyperlink.namespaceURI ?? '')) return null;
5671
- const anchor = uniqueNamespacedAttribute(hyperlink, 'anchor', DOCX_WORDPROCESSING_NAMESPACES);
5672
- const relationshipId = uniqueNamespacedAttribute(hyperlink, 'id', work_docx_note_comment_hyperlink_relationships_RELATIONSHIP_NAMESPACES);
5673
- if (void 0 === anchor || void 0 === relationshipId) return null;
5674
- const normalizedAnchor = null === anchor ? null : normalizeAnchor(anchor);
5675
- if (null !== anchor && !normalizedAnchor) return null;
5676
- if (normalizedAnchor && relationshipId) return null;
5677
- if (normalizedAnchor) return {
5678
- kind: 'internal',
5679
- target: normalizedAnchor
5680
- };
5681
- if (!relationshipId || !RELATIONSHIP_ID_PATTERN.test(relationshipId)) return null;
5682
- const relationships = 'generated' === role ? state.generated : state.source;
5683
- const relationship = relationships?.byId.get(relationshipId);
5684
- if (!relationship || !isExternalHyperlinkRelationship(relationship)) return null;
5685
- const target = normalizeDocumentHref(relationship.target);
5686
- if (!target || target.startsWith('#')) return null;
5687
- return {
5688
- kind: 'external',
5689
- relationshipId,
5690
- target
5691
- };
5692
- }
5693
- function ensureDocxExternalHyperlinkRelationships(state, requests) {
5694
- if (!requests.length) return [];
5695
- if (state.generatedMalformed) return null;
5696
- const relationships = state.generated ?? createRelationshipsDocument();
5697
- const usedIds = new Set(relationships.usedIds);
5698
- const idByTarget = new Map(Array.from(relationships.byId.values()).flatMap((item)=>{
5699
- const target = isExternalHyperlinkRelationship(item) ? normalizeDocumentHref(item.target) : null;
5700
- return target && !target.startsWith('#') ? [
5701
- [
5702
- target,
5703
- item.id
5704
- ]
5705
- ] : [];
5706
- }));
5707
- const pending = [];
5708
- const result = [];
5709
- for (const request of requests){
5710
- if (!RELATIONSHIP_ID_PATTERN.test(request.sourceId)) return null;
5711
- const target = normalizeDocumentHref(request.target);
5712
- if (!target || target.startsWith('#')) return null;
5713
- const existingId = idByTarget.get(target);
5714
- if (existingId) {
5715
- result.push(existingId);
5716
- continue;
5717
- }
5718
- if (usedIds.size >= MAX_RELATIONSHIPS) return null;
5719
- const id = usedIds.has(request.sourceId) ? work_docx_note_comment_hyperlink_relationships_nextRelationshipId(usedIds) : request.sourceId;
5720
- usedIds.add(id);
5721
- idByTarget.set(target, id);
5722
- pending.push({
5723
- id,
5724
- target
5725
- });
5726
- result.push(id);
5727
- }
5728
- if (!pending.length) return result;
5729
- state.generated = relationships;
5730
- for (const item of pending)appendExternalHyperlinkRelationship(relationships, item.id, item.target);
5731
- state.dirty = true;
5732
- return result;
5733
- }
5734
- function setDocxHyperlinkDestination(hyperlink, root, destination, relationshipId) {
5735
- work_docx_note_comment_hyperlink_relationships_removeNamespacedAttribute(hyperlink, 'anchor', DOCX_WORDPROCESSING_NAMESPACES);
5736
- work_docx_note_comment_hyperlink_relationships_removeNamespacedAttribute(hyperlink, 'id', work_docx_note_comment_hyperlink_relationships_RELATIONSHIP_NAMESPACES);
5737
- if ('internal' === destination.kind) {
5738
- const namespace = hyperlink.namespaceURI;
5739
- if (!namespace || !DOCX_WORDPROCESSING_NAMESPACES.has(namespace)) return false;
5740
- setNamespacedAttribute(hyperlink, root, namespace, 'w', 'anchor', destination.target);
5741
- return true;
5742
- }
5743
- if (!relationshipId || !RELATIONSHIP_ID_PATTERN.test(relationshipId)) return false;
5744
- setNamespacedAttribute(hyperlink, root, work_docx_note_comment_hyperlink_relationships_TRANSITIONAL_RELATIONSHIP_NAMESPACE, 'r', 'id', relationshipId);
5745
- return true;
5746
- }
5747
- function flushDocxHyperlinkRelationships(state) {
5748
- if (!state.dirty || !state.generated) return;
5749
- state.archive.file(state.path, serializeUtf8Xml(state.generated.document));
5750
- }
5751
- function normalizeAnchor(value) {
5752
- const anchor = value.trim();
5753
- return anchor.length <= 255 && normalizeDocumentHref(`#${anchor}`) ? anchor : null;
5754
- }
5755
- function isExternalHyperlinkRelationship(relationship) {
5756
- return HYPERLINK_RELATIONSHIP_TYPES.has(relationship.type) && 'external' === relationship.targetMode.toLowerCase();
5757
- }
5758
- async function loadRelationships(archive, path, role) {
5759
- const entry = archive.file(path);
5760
- if (!entry) return {
5761
- document: null,
5762
- malformed: false
5763
- };
5764
- try {
5765
- const document = parseXml(decodeXmlBytes(await entry.async('uint8array'), `${role} DOCX ${path}`), `${role} DOCX ${path}`);
5766
- const root = document.documentElement;
5767
- if ('Relationships' !== root.localName || root.namespaceURI !== PACKAGE_RELATIONSHIP_NAMESPACE) return {
5768
- document: null,
5769
- malformed: true
5770
- };
5771
- const byId = new Map();
5772
- const usedIds = new Set();
5773
- const elements = directChildren(root);
5774
- if (elements.length > MAX_RELATIONSHIPS) return {
5775
- document: null,
5776
- malformed: true
5777
- };
5778
- for (const element of elements){
5779
- if ('Relationship' !== element.localName || element.namespaceURI !== PACKAGE_RELATIONSHIP_NAMESPACE) return {
5780
- document: null,
5781
- malformed: true
5782
- };
5783
- const record = relationshipRecord(element);
5784
- if (!record || usedIds.has(record.id)) return {
5785
- document: null,
5786
- malformed: true
5787
- };
5788
- byId.set(record.id, record);
5789
- usedIds.add(record.id);
5790
- }
5791
- return {
5792
- document: {
5793
- byId,
5794
- document,
5795
- usedIds
5796
- },
5797
- malformed: false
5798
- };
5799
- } catch {
5800
- return {
5801
- document: null,
5802
- malformed: true
5803
- };
5804
- }
5805
- }
5806
- function relationshipRecord(element) {
5807
- const id = element.getAttribute('Id')?.trim() ?? '';
5808
- const target = element.getAttribute('Target')?.trim() ?? '';
5809
- const type = element.getAttribute('Type')?.trim() ?? '';
5810
- const targetMode = element.getAttribute('TargetMode')?.trim() ?? '';
5811
- if (!RELATIONSHIP_ID_PATTERN.test(id) || !target || !type) return null;
5812
- return {
5813
- id,
5814
- target,
5815
- targetMode,
5816
- type
5817
- };
5818
- }
5819
- function createRelationshipsDocument() {
5820
- const document = parseXml(`<Relationships xmlns="${PACKAGE_RELATIONSHIP_NAMESPACE}"/>`, 'generated DOCX hyperlink relationships');
5821
- return {
5822
- byId: new Map(),
5823
- document,
5824
- usedIds: new Set()
5825
- };
5826
- }
5827
- function appendExternalHyperlinkRelationship(relationships, id, target) {
5828
- const element = relationships.document.createElementNS(PACKAGE_RELATIONSHIP_NAMESPACE, 'Relationship');
5829
- element.setAttribute('Id', id);
5830
- element.setAttribute('Type', GENERATED_HYPERLINK_RELATIONSHIP_TYPE);
5831
- element.setAttribute('Target', target);
5832
- element.setAttribute('TargetMode', 'External');
5833
- relationships.document.documentElement.append(element);
5834
- relationships.byId.set(id, {
5835
- id,
5836
- target,
5837
- targetMode: 'External',
5838
- type: GENERATED_HYPERLINK_RELATIONSHIP_TYPE
5839
- });
5840
- relationships.usedIds.add(id);
5841
- }
5842
- function uniqueNamespacedAttribute(element, localName, namespaces) {
5843
- const matches = Array.from(element.attributes).filter((item)=>xmlAttributeLocalName(item) === localName && namespaces.has(xmlAttributeNamespace(element, item) ?? ''));
5844
- return matches.length <= 1 ? matches[0]?.value.trim() ?? null : void 0;
5845
- }
5846
- function work_docx_note_comment_hyperlink_relationships_removeNamespacedAttribute(element, localName, namespaces) {
5847
- for (const item of Array.from(element.attributes))if (xmlAttributeLocalName(item) === localName && namespaces.has(xmlAttributeNamespace(element, item) ?? '')) element.removeAttributeNode(item);
5848
- }
5849
- function setNamespacedAttribute(element, root, namespace, preferredPrefix, localName, value) {
5850
- let prefix = xmlDeclaredPrefix(element, namespace) ?? xmlDeclaredPrefix(root, namespace);
5851
- if (!prefix) {
5852
- prefix = work_docx_note_comment_hyperlink_relationships_availablePrefix(root, preferredPrefix);
5853
- root.setAttributeNS(work_docx_settings_xml_XMLNS_NAMESPACE, `xmlns:${prefix}`, namespace);
5854
- }
5855
- element.setAttributeNS(namespace, `${prefix}:${localName}`, value);
5856
- }
5857
- function work_docx_note_comment_hyperlink_relationships_availablePrefix(root, preferred) {
5858
- if (!xmlNamespaceUri(root, preferred)) return preferred;
5859
- let index = 1;
5860
- while(xmlNamespaceUri(root, `${preferred}${index}`))index += 1;
5861
- return `${preferred}${index}`;
5862
- }
5863
- function work_docx_note_comment_hyperlink_relationships_nextRelationshipId(used) {
5864
- let index = 1;
5865
- while(used.has(`rId${index}`))index += 1;
5866
- return `rId${index}`;
5867
- }
5868
- function relationshipPartPath(ownerPart) {
5869
- const separator = ownerPart.lastIndexOf('/');
5870
- const directory = separator < 0 ? '' : ownerPart.slice(0, separator + 1);
5871
- const file = ownerPart.slice(separator + 1);
5872
- return `${directory}_rels/${file}.rels`;
5873
- }
5874
- const work_docx_note_comment_hyperlink_content_MARKUP_COMPATIBILITY_NAMESPACE = 'http://schemas.openxmlformats.org/markup-compatibility/2006';
5875
- const MAX_PARAGRAPHS = 65536;
5876
- const MAX_RUNS = 262144;
5877
- const MAX_COMMENT_RUN_SEGMENTS = 4096;
5878
- function noteCommentContentParagraphs(scope, role, relationships, limits) {
5879
- const paragraphs = descendants(scope, 'p').filter(work_docx_note_comment_hyperlink_content_isWordElement);
5880
- const paragraphKey = `${role}Paragraphs`;
5881
- limits[paragraphKey] += paragraphs.length;
5882
- if (limits[paragraphKey] > MAX_PARAGRAPHS) throw new Error(`${roleLabel(role)} DOCX exceeds the stable note/comment hyperlink paragraph limit.`);
5883
- const result = [];
5884
- for (const paragraph of paragraphs){
5885
- const runKey = `${role}Runs`;
5886
- limits[runKey] += directContentRunCount(paragraph);
5887
- if (limits[runKey] > MAX_RUNS) throw new Error(`${roleLabel(role)} DOCX exceeds the stable note/comment hyperlink run limit.`);
5888
- const content = noteCommentParagraphContent(paragraph, relationships, role);
5889
- if (!content?.text) continue;
5890
- const ancestry = paragraphAncestry(paragraph, scope);
5891
- if (ancestry) result.push({
5892
- element: paragraph,
5893
- hyperlinks: content.hyperlinks,
5894
- identity: `${ancestry}\u0000${content.text}`,
5895
- runs: content.runs,
5896
- text: content.text
5897
- });
5898
- }
5899
- return result;
5900
- }
5901
- function directContentRunCount(paragraph) {
5902
- let count = 0;
5903
- for (const child of Array.from(paragraph.children))if (work_docx_note_comment_hyperlink_content_isWordElement(child)) {
5904
- if ('r' === child.localName) count += 1;
5905
- if ('hyperlink' === child.localName) count += wordDirectChildren(child, 'r').length;
5906
- }
5907
- return count;
5908
- }
5909
- function noteCommentParagraphContent(paragraph, relationships, role) {
5910
- const runs = [];
5911
- const hyperlinks = [];
5912
- let offset = 0;
5913
- let paragraphProperties = 0;
5914
- for (const child of Array.from(paragraph.children)){
5915
- if (!work_docx_note_comment_hyperlink_content_isWordElement(child)) {
5916
- if (isContentSemanticNamespace(child.namespaceURI ?? '')) return null;
5917
- continue;
5918
- }
5919
- if ('pPr' === child.localName) {
5920
- paragraphProperties += 1;
5921
- if (paragraphProperties > 1) return null;
5922
- continue;
5923
- }
5924
- if ('r' === child.localName) {
5925
- const text = contentRunText(child);
5926
- if (null === text) return null;
5927
- const start = offset;
5928
- offset += text.length;
5929
- if (text) runs.push({
5930
- container: null,
5931
- element: child,
5932
- start,
5933
- end: offset,
5934
- text
5935
- });
5936
- continue;
5937
- }
5938
- if ('hyperlink' !== child.localName) return null;
5939
- const start = offset;
5940
- for (const hyperlinkChild of Array.from(child.children)){
5941
- if (!work_docx_note_comment_hyperlink_content_isWordElement(hyperlinkChild)) {
5942
- if (isContentSemanticNamespace(hyperlinkChild.namespaceURI ?? '')) return null;
5943
- continue;
5944
- }
5945
- if ('r' !== hyperlinkChild.localName) return null;
5946
- const text = contentRunText(hyperlinkChild);
5947
- if (null === text) return null;
5948
- const runStart = offset;
5949
- offset += text.length;
5950
- if (text) runs.push({
5951
- container: child,
5952
- element: hyperlinkChild,
5953
- start: runStart,
5954
- end: offset,
5955
- text
5956
- });
5957
- }
5958
- if (offset > start) hyperlinks.push({
5959
- destination: readDocxHyperlinkDestination(child, relationships, role),
5960
- element: child,
5961
- start,
5962
- end: offset,
5963
- text: runs.filter((run)=>run.container === child).map((run)=>run.text).join('')
5964
- });
5965
- }
5966
- return {
5967
- hyperlinks,
5968
- runs,
5969
- text: runs.map((run)=>run.text).join('')
5970
- };
5971
- }
5972
- function groupNoteCommentParagraphs(paragraphs) {
5973
- const result = new Map();
5974
- for (const paragraph of paragraphs){
5975
- const matches = result.get(paragraph.identity) ?? [];
5976
- matches.push(paragraph);
5977
- result.set(paragraph.identity, matches);
5978
- }
5979
- return result;
5980
- }
5981
- function groupNoteCommentHyperlinks(hyperlinks) {
5982
- const result = new Map();
5983
- for (const hyperlink of hyperlinks){
5984
- const key = noteCommentHyperlinkSpanKey(hyperlink);
5985
- const matches = result.get(key) ?? [];
5986
- matches.push(hyperlink);
5987
- result.set(key, matches);
5988
- }
5989
- return result;
5990
- }
5991
- function noteCommentHyperlinkSpanKey(item) {
5992
- return `${item.start}:${item.end}:${item.text}`;
5993
- }
5994
- function noteCommentHyperlinksOverlap(left, right) {
5995
- return left.start < right.end && right.start < left.end;
5996
- }
5997
- function restoreElementChildren(element, children) {
5998
- while(element.firstChild)element.removeChild(element.firstChild);
5999
- for (const child of children)element.append(child);
6000
- }
6001
- function alignCommentRunBoundaries(generated, source) {
6002
- if (generated.hyperlinks.length || 1 !== generated.runs.length || generated.runs[0].container || source.runs.length <= 1 || source.runs.length > MAX_COMMENT_RUN_SEGMENTS || !isSimpleTextRun(generated.runs[0].element) || source.runs.some((run)=>!isSimpleTextRun(run.element))) return false;
6003
- const original = generated.runs[0].element;
6004
- if (!original.parentNode) return false;
6005
- const clones = [];
6006
- for (const sourceRun of source.runs){
6007
- const clone = original.cloneNode(true);
6008
- const textElement = wordDirectChildren(clone, 't')[0];
6009
- if (!textElement) return false;
6010
- textElement.textContent = sourceRun.text;
6011
- setTextSpacePreservation(textElement, sourceRun.text);
6012
- clones.push(clone);
6013
- }
6014
- for (const clone of clones)original.parentNode.insertBefore(clone, original);
6015
- original.remove();
6016
- return true;
6017
- }
6018
- function isKnownOoxmlNamespace(namespace) {
6019
- if (namespace === work_docx_note_comment_hyperlink_content_MARKUP_COMPATIBILITY_NAMESPACE) return false;
6020
- return DOCX_WORDPROCESSING_NAMESPACES.has(namespace) || namespace.startsWith('http://schemas.microsoft.com/office/') || namespace.startsWith('http://schemas.openxmlformats.org/') || namespace.startsWith('http://purl.oclc.org/ooxml/') || namespace.startsWith('urn:schemas-microsoft-com:') || namespace.startsWith('urn:microsoft-com:office:');
6021
- }
6022
- function contentRunText(run) {
6023
- let text = '';
6024
- for (const child of Array.from(run.children)){
6025
- if (!work_docx_note_comment_hyperlink_content_isWordElement(child)) {
6026
- if (isContentSemanticNamespace(child.namespaceURI ?? '')) return null;
6027
- continue;
6028
- }
6029
- if ('rPr' !== child.localName) {
6030
- if ('t' === child.localName || 'delText' === child.localName) text += child.textContent ?? '';
6031
- else if ('tab' === child.localName) text += '\t';
6032
- else if ('br' === child.localName || 'cr' === child.localName) text += '\n';
6033
- else if ('noBreakHyphen' === child.localName) text += '\u2011';
6034
- else if ('softHyphen' === child.localName) text += '\u00ad';
6035
- else if ('footnoteRef' !== child.localName && 'endnoteRef' !== child.localName) return null;
6036
- }
6037
- }
6038
- return text;
6039
- }
6040
- function isSimpleTextRun(run) {
6041
- const children = Array.from(run.children).filter(work_docx_note_comment_hyperlink_content_isWordElement);
6042
- return 1 === children.filter((child)=>'t' === child.localName).length && children.every((child)=>'rPr' === child.localName || 't' === child.localName);
6043
- }
6044
- function setTextSpacePreservation(element, text) {
6045
- for (const item of Array.from(element.attributes))if ('space' === xmlAttributeLocalName(item) && xmlAttributeNamespace(element, item) === work_docx_settings_xml_XML_NAMESPACE) element.removeAttributeNode(item);
6046
- if (/^\s|\s$/u.test(text)) element.setAttributeNS(work_docx_settings_xml_XML_NAMESPACE, 'xml:space', 'preserve');
6047
- }
6048
- function paragraphAncestry(paragraph, scope) {
6049
- const path = [];
6050
- let current = paragraph;
6051
- while(current && current !== scope){
6052
- if (!work_docx_note_comment_hyperlink_content_isWordElement(current)) return null;
6053
- path.push(current.localName);
6054
- current = current.parentElement;
6055
- }
6056
- return current === scope ? path.reverse().join('/') : null;
6057
- }
6058
- function isContentSemanticNamespace(namespace) {
6059
- return namespace === work_docx_note_comment_hyperlink_content_MARKUP_COMPATIBILITY_NAMESPACE || isKnownOoxmlNamespace(namespace);
6060
- }
6061
- function wordDirectChildren(element, localName) {
6062
- return Array.from(element.children).filter((child)=>child.localName === localName && work_docx_note_comment_hyperlink_content_isWordElement(child));
6063
- }
6064
- function work_docx_note_comment_hyperlink_content_isWordElement(element) {
6065
- return DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '');
6066
- }
6067
- function roleLabel(role) {
6068
- return 'source' === role ? 'Registered source' : 'Generated';
6069
- }
6070
5886
  const work_docx_note_comment_run_properties_RELATIONSHIP_NAMESPACES = new Set([
6071
5887
  'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
6072
5888
  'http://purl.oclc.org/ooxml/officeDocument/relationships'
@@ -6135,15 +5951,15 @@ const NOTE_UNMODELED_RUN_PROPERTIES = new Set([
6135
5951
  'webHidden'
6136
5952
  ]);
6137
5953
  function preserveDocxNoteCommentRunProperties(generatedDocument, generatedRun, sourceRun, kind) {
6138
- const sourceProperties = work_docx_note_comment_run_properties_wordDirectChildren(sourceRun, 'rPr')[0];
5954
+ const sourceProperties = wordDirectChildren(sourceRun, 'rPr')[0];
6139
5955
  if (!sourceProperties) return;
6140
5956
  const allowed = 'comment' === kind ? COMMENT_RUN_PROPERTIES : NOTE_UNMODELED_RUN_PROPERTIES;
6141
5957
  const sourceGroups = eligiblePropertyGroups(sourceProperties, allowed);
6142
5958
  if (!sourceGroups.size) return;
6143
- let generatedProperties = work_docx_note_comment_run_properties_wordDirectChildren(generatedRun, 'rPr')[0];
5959
+ let generatedProperties = wordDirectChildren(generatedRun, 'rPr')[0];
6144
5960
  for (const [localName, sourceMatches] of sourceGroups){
6145
5961
  if (1 !== sourceMatches.length) continue;
6146
- if (generatedProperties && work_docx_note_comment_run_properties_wordDirectChildren(generatedProperties, localName).length > 0) continue;
5962
+ if (generatedProperties && wordDirectChildren(generatedProperties, localName).length > 0) continue;
6147
5963
  if (hasRelationshipReference(sourceMatches[0])) continue;
6148
5964
  generatedProperties ??= createRunProperties(generatedDocument, generatedRun);
6149
5965
  const clone = cloneWordProperty(generatedDocument, sourceMatches[0], generatedRun);
@@ -6216,87 +6032,12 @@ function hasRelationshipReference(root) {
6216
6032
  ...Array.from(root.querySelectorAll('*'))
6217
6033
  ].some((element)=>Array.from(element.attributes).some((item)=>work_docx_note_comment_run_properties_RELATIONSHIP_NAMESPACES.has(xmlAttributeNamespace(element, item) ?? '')));
6218
6034
  }
6219
- function work_docx_note_comment_run_properties_wordDirectChildren(element, localName) {
6035
+ function wordDirectChildren(element, localName) {
6220
6036
  return Array.from(element.children).filter((child)=>child.localName === localName && work_docx_note_comment_run_properties_isWordElement(child));
6221
6037
  }
6222
6038
  function work_docx_note_comment_run_properties_isWordElement(element) {
6223
6039
  return DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '');
6224
6040
  }
6225
- const CONTENT_CONTROL_MC_NAMESPACE = 'http://schemas.openxmlformats.org/markup-compatibility/2006';
6226
- const CONTENT_CONTROL_RELATIONSHIP_NAMESPACES = new Set([
6227
- 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
6228
- 'http://purl.oclc.org/ooxml/officeDocument/relationships'
6229
- ]);
6230
- const CONTENT_CONTROL_WORD_2012_NAMESPACE = 'http://schemas.microsoft.com/office/word/2012/wordml';
6231
- function isContentControlSemanticNamespace(namespace) {
6232
- return namespace === CONTENT_CONTROL_MC_NAMESPACE || CONTENT_CONTROL_RELATIONSHIP_NAMESPACES.has(namespace) || isKnownOoxmlNamespace(namespace);
6233
- }
6234
- function isDocxWordElement(element) {
6235
- return DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '');
6236
- }
6237
- function work_docx_note_comment_content_control_xml_wordDirectChildren(element, localName) {
6238
- return Array.from(element.children).filter((child)=>child.localName === localName && isDocxWordElement(child));
6239
- }
6240
- function hasOnlyPassiveContentControlAttributes(element) {
6241
- return Array.from(element.attributes).every((item)=>{
6242
- const namespace = xmlAttributeNamespace(element, item);
6243
- return Boolean(namespace === work_docx_settings_xml_XMLNS_NAMESPACE || namespace === CONTENT_CONTROL_MC_NAMESPACE || namespace && !CONTENT_CONTROL_RELATIONSHIP_NAMESPACES.has(namespace) && !isKnownOoxmlNamespace(namespace));
6244
- });
6245
- }
6246
- function hasUnsupportedContentControlSemanticChild(element) {
6247
- return Array.from(element.children).some((child)=>!isDocxWordElement(child) && isContentControlSemanticNamespace(child.namespaceURI ?? ''));
6248
- }
6249
- function hasContentControlRelationshipReference(root) {
6250
- return [
6251
- root,
6252
- ...Array.from(root.querySelectorAll('*'))
6253
- ].some((element)=>Array.from(element.attributes).some((item)=>CONTENT_CONTROL_RELATIONSHIP_NAMESPACES.has(xmlAttributeNamespace(element, item) ?? '')));
6254
- }
6255
- function work_docx_note_comment_content_control_xml_createWordElement(document, context, localName) {
6256
- const namespace = context.namespaceURI ?? [
6257
- ...DOCX_WORDPROCESSING_NAMESPACES
6258
- ][0];
6259
- const prefix = xmlNamespacePrefix(context, namespace) ?? 'w';
6260
- return document.createElementNS(namespace, `${prefix}:${localName}`);
6261
- }
6262
- function createNamespacedElement(document, context, namespace, preferredPrefix, localName) {
6263
- const prefix = work_docx_note_comment_content_control_xml_availableNamespacePrefix(context.ownerDocument.documentElement, namespace, preferredPrefix);
6264
- return document.createElementNS(namespace, `${prefix}:${localName}`);
6265
- }
6266
- function setWordContentControlAttribute(element, context, localName, value) {
6267
- const namespace = context.namespaceURI ?? [
6268
- ...DOCX_WORDPROCESSING_NAMESPACES
6269
- ][0];
6270
- const prefix = xmlNamespacePrefix(context, namespace) ?? 'w';
6271
- element.setAttributeNS(namespace, `${prefix}:${localName}`, value);
6272
- }
6273
- function setNamespacedContentControlAttribute(element, context, namespace, preferredPrefix, localName, value) {
6274
- const prefix = work_docx_note_comment_content_control_xml_availableNamespacePrefix(context.ownerDocument.documentElement, namespace, preferredPrefix);
6275
- element.setAttributeNS(namespace, `${prefix}:${localName}`, value);
6276
- }
6277
- function ensureIgnorableContentControlNamespace(root, namespace, preferredPrefix) {
6278
- const prefix = work_docx_note_comment_content_control_xml_availableNamespacePrefix(root, namespace, preferredPrefix);
6279
- if (!xmlNamespacePrefix(root, namespace)) root.setAttributeNS(work_docx_settings_xml_XMLNS_NAMESPACE, `xmlns:${prefix}`, namespace);
6280
- const mcPrefix = work_docx_note_comment_content_control_xml_availableNamespacePrefix(root, CONTENT_CONTROL_MC_NAMESPACE, 'mc');
6281
- if (!xmlNamespacePrefix(root, CONTENT_CONTROL_MC_NAMESPACE)) root.setAttributeNS(work_docx_settings_xml_XMLNS_NAMESPACE, `xmlns:${mcPrefix}`, CONTENT_CONTROL_MC_NAMESPACE);
6282
- const existing = Array.from(root.attributes).find((item)=>'Ignorable' === xmlAttributeLocalName(item) && xmlAttributeNamespace(root, item) === CONTENT_CONTROL_MC_NAMESPACE);
6283
- const prefixes = new Set((existing?.value ?? '').trim().split(/\s+/u).filter(Boolean));
6284
- prefixes.add(prefix);
6285
- const value = Array.from(prefixes).join(' ');
6286
- if (existing) existing.value = value;
6287
- else root.setAttributeNS(CONTENT_CONTROL_MC_NAMESPACE, `${mcPrefix}:Ignorable`, value);
6288
- }
6289
- function work_docx_note_comment_content_control_xml_availableNamespacePrefix(root, namespace, preferred) {
6290
- const existing = xmlNamespacePrefix(root, namespace);
6291
- if (existing) return existing;
6292
- let prefix = preferred;
6293
- let index = 1;
6294
- while(xmlNamespaceUri(root, prefix)){
6295
- prefix = `${preferred}${index}`;
6296
- index += 1;
6297
- }
6298
- return prefix;
6299
- }
6300
6041
  const STATIC_CORE_PROPERTIES = new Set([
6301
6042
  'alias',
6302
6043
  'id',
@@ -6547,7 +6288,7 @@ function validLeaf(element, allowedAttributes, namespace = element.namespaceURI
6547
6288
  const itemNamespace = xmlAttributeNamespace(element, item);
6548
6289
  if (itemNamespace === work_docx_settings_xml_XMLNS_NAMESPACE) return true;
6549
6290
  if (itemNamespace === namespace) return allowedAttributes.has(xmlAttributeLocalName(item));
6550
- return Boolean(itemNamespace && itemNamespace !== CONTENT_CONTROL_MC_NAMESPACE && !CONTENT_CONTROL_RELATIONSHIP_NAMESPACES.has(itemNamespace) && !isKnownOoxmlNamespace(itemNamespace));
6291
+ return Boolean(itemNamespace && itemNamespace !== CONTENT_CONTROL_MC_NAMESPACE && !CONTENT_CONTROL_RELATIONSHIP_NAMESPACES.has(itemNamespace) && !work_docx_note_comment_hyperlink_content_isKnownOoxmlNamespace(itemNamespace));
6551
6292
  });
6552
6293
  }
6553
6294
  function normalizeInt32(value) {
@@ -6792,8 +6533,8 @@ function incrementLimit(limits, role, suffix, maximum, label) {
6792
6533
  limits[key] += 1;
6793
6534
  if (limits[key] > maximum) throw new Error(`${'source' === role ? 'Registered source' : 'Generated'} DOCX exceeds the stable note/comment ${label} limit.`);
6794
6535
  }
6795
- const work_docx_note_comment_content_control_model_MAX_PARAGRAPHS = 65536;
6796
- const work_docx_note_comment_content_control_model_MAX_RUNS = 262144;
6536
+ const MAX_PARAGRAPHS = 65536;
6537
+ const MAX_RUNS = 262144;
6797
6538
  const MAX_CONTROLS = 65536;
6798
6539
  const MAX_RUN_SEGMENTS = 4096;
6799
6540
  function createContentControlLimits() {
@@ -6864,7 +6605,7 @@ function alignStaticRunBoundaries(paragraph, boundaries) {
6864
6605
  for (const run of runs){
6865
6606
  const internal = unique.filter((boundary)=>boundary > run.start && boundary < run.end);
6866
6607
  if (!internal.length) continue;
6867
- if (!work_docx_note_comment_content_control_model_isSimpleTextRun(run.element) || !run.element.parentNode) return false;
6608
+ if (!isSimpleTextRun(run.element) || !run.element.parentNode) return false;
6868
6609
  const offsets = [
6869
6610
  run.start,
6870
6611
  ...internal,
@@ -6877,7 +6618,7 @@ function alignStaticRunBoundaries(paragraph, boundaries) {
6877
6618
  if (!textElement) return false;
6878
6619
  const value = text.slice(offsets[index], offsets[index + 1]);
6879
6620
  textElement.textContent = value;
6880
- work_docx_note_comment_content_control_model_setTextSpacePreservation(textElement, value);
6621
+ setTextSpacePreservation(textElement, value);
6881
6622
  parent.insertBefore(clone, run.element);
6882
6623
  }
6883
6624
  run.element.remove();
@@ -6953,7 +6694,7 @@ function readBlock(element, role, limits) {
6953
6694
  }
6954
6695
  function readRun(run, start, role, limits) {
6955
6696
  work_docx_note_comment_content_control_model_incrementLimit(limits, `${role}Runs`, 1, 'run');
6956
- const text = work_docx_note_comment_content_control_model_contentRunText(run);
6697
+ const text = contentRunText(run);
6957
6698
  return null === text ? null : {
6958
6699
  element: run,
6959
6700
  end: start + text.length,
@@ -6978,7 +6719,7 @@ function directRunRecords(paragraph) {
6978
6719
  }
6979
6720
  if ('r' !== child.localName) return null;
6980
6721
  sawContent = true;
6981
- const text = work_docx_note_comment_content_control_model_contentRunText(child);
6722
+ const text = contentRunText(child);
6982
6723
  if (null === text) return null;
6983
6724
  const start = offset;
6984
6725
  offset += text.length;
@@ -6991,7 +6732,7 @@ function directRunRecords(paragraph) {
6991
6732
  }
6992
6733
  return records;
6993
6734
  }
6994
- function work_docx_note_comment_content_control_model_contentRunText(run) {
6735
+ function contentRunText(run) {
6995
6736
  let text = '';
6996
6737
  let properties = 0;
6997
6738
  let sawContent = false;
@@ -7025,17 +6766,17 @@ function work_docx_note_comment_content_control_model_contentRunText(run) {
7025
6766
  }
7026
6767
  return text;
7027
6768
  }
7028
- function work_docx_note_comment_content_control_model_isSimpleTextRun(run) {
6769
+ function isSimpleTextRun(run) {
7029
6770
  const children = Array.from(run.children).filter(isDocxWordElement);
7030
6771
  return 1 === children.filter((child)=>'t' === child.localName).length && children.every((child)=>'rPr' === child.localName || 't' === child.localName);
7031
6772
  }
7032
- function work_docx_note_comment_content_control_model_setTextSpacePreservation(element, text) {
6773
+ function setTextSpacePreservation(element, text) {
7033
6774
  for (const item of Array.from(element.attributes))if ('space' === xmlAttributeLocalName(item) && xmlAttributeNamespace(element, item) === work_docx_settings_xml_XML_NAMESPACE) element.removeAttributeNode(item);
7034
6775
  if (/^\s|\s$/u.test(text)) element.setAttributeNS(work_docx_settings_xml_XML_NAMESPACE, 'xml:space', 'preserve');
7035
6776
  }
7036
6777
  function work_docx_note_comment_content_control_model_incrementLimit(limits, key, count, label) {
7037
6778
  limits[key] += count;
7038
- const maximum = 'run' === label ? work_docx_note_comment_content_control_model_MAX_RUNS : 'paragraph' === label ? work_docx_note_comment_content_control_model_MAX_PARAGRAPHS : MAX_CONTROLS;
6779
+ const maximum = 'run' === label ? MAX_RUNS : 'paragraph' === label ? MAX_PARAGRAPHS : MAX_CONTROLS;
7039
6780
  if (limits[key] > maximum) {
7040
6781
  const role = key.startsWith('source') ? 'Registered source' : 'Generated';
7041
6782
  throw new Error(`${role} DOCX exceeds the stable note/comment ${label} limit.`);
@@ -7338,13 +7079,13 @@ function mergeExtensions(generated, source, pairs, maximumDepth) {
7338
7079
  if (!pairs.length) return;
7339
7080
  mergeDocxIgnorableExtensionsAtPairs(generated, source, pairs, {
7340
7081
  semanticKey: contentSemanticKey,
7341
- isAdditionalSemanticNamespace: isKnownOoxmlNamespace,
7342
- allowExtensionNamespace: (namespace)=>!isKnownOoxmlNamespace(namespace),
7082
+ isAdditionalSemanticNamespace: work_docx_note_comment_hyperlink_content_isKnownOoxmlNamespace,
7083
+ allowExtensionNamespace: (namespace)=>!work_docx_note_comment_hyperlink_content_isKnownOoxmlNamespace(namespace),
7343
7084
  allowMatchedElementMerge: (_generated, _source, depth)=>depth <= maximumDepth
7344
7085
  });
7345
7086
  }
7346
7087
  function contentSemanticKey(element, _role) {
7347
- return isKnownOoxmlNamespace(element.namespaceURI ?? '') ? `{semantic}${element.localName}` : `{${element.namespaceURI ?? ''}}${element.localName}`;
7088
+ return work_docx_note_comment_hyperlink_content_isKnownOoxmlNamespace(element.namespaceURI ?? '') ? `{semantic}${element.localName}` : `{${element.namespaceURI ?? ''}}${element.localName}`;
7348
7089
  }
7349
7090
  function usesWord2012ContentControlExtensions(document) {
7350
7091
  return descendants(document, 'sdt').some((control)=>[
@@ -7390,7 +7131,7 @@ function uniqueParagraphPairs(scope, relationships, limits) {
7390
7131
  function preserveParagraphHyperlinks(generatedDocument, originalGenerated, source, relationships, kind, paragraphPairs, pairs, runPairs) {
7391
7132
  if (!eligibleSourceHyperlinks(source.hyperlinks)) return;
7392
7133
  const originalChildren = 'comment' === kind ? Array.from(originalGenerated.element.childNodes).map((child)=>child.cloneNode(true)) : [];
7393
- const aligned = 'comment' === kind && alignCommentRunBoundaries(originalGenerated, source);
7134
+ const aligned = 'comment' === kind && work_docx_note_comment_hyperlink_content_alignCommentRunBoundaries(originalGenerated, source);
7394
7135
  const generatedContent = noteCommentParagraphContent(originalGenerated.element, relationships, 'generated');
7395
7136
  const plans = generatedContent?.text === source.text ? planParagraphHyperlinks(generatedContent.hyperlinks, generatedContent.runs, source.hyperlinks, relationships, kind) : null;
7396
7137
  if (!plans) {
@@ -7487,8 +7228,8 @@ function mergeTopLevelExtensions(generated, source, pairs) {
7487
7228
  if (!pairs.length) return;
7488
7229
  mergeDocxIgnorableExtensionsAtPairs(generated, source, pairs, {
7489
7230
  semanticKey: work_docx_note_comment_hyperlink_preservation_contentSemanticKey,
7490
- isAdditionalSemanticNamespace: isKnownOoxmlNamespace,
7491
- allowExtensionNamespace: (namespace)=>!isKnownOoxmlNamespace(namespace),
7231
+ isAdditionalSemanticNamespace: work_docx_note_comment_hyperlink_content_isKnownOoxmlNamespace,
7232
+ allowExtensionNamespace: (namespace)=>!work_docx_note_comment_hyperlink_content_isKnownOoxmlNamespace(namespace),
7492
7233
  allowMatchedElementMerge: (_generated, _source, depth)=>0 === depth
7493
7234
  });
7494
7235
  }
@@ -7496,8 +7237,8 @@ function mergeRunExtensions(generated, source, pairs) {
7496
7237
  if (!pairs.length) return;
7497
7238
  mergeDocxIgnorableExtensionsAtPairs(generated, source, pairs, {
7498
7239
  semanticKey: work_docx_note_comment_hyperlink_preservation_contentSemanticKey,
7499
- isAdditionalSemanticNamespace: isKnownOoxmlNamespace,
7500
- allowExtensionNamespace: (namespace)=>!isKnownOoxmlNamespace(namespace),
7240
+ isAdditionalSemanticNamespace: work_docx_note_comment_hyperlink_content_isKnownOoxmlNamespace,
7241
+ allowExtensionNamespace: (namespace)=>!work_docx_note_comment_hyperlink_content_isKnownOoxmlNamespace(namespace),
7501
7242
  allowMatchedElementMerge: (_generated, _source, depth)=>depth <= 4
7502
7243
  });
7503
7244
  }
@@ -7538,7 +7279,7 @@ function sameDestination(left, right) {
7538
7279
  return Boolean(left && left.kind === right.kind && left.target === right.target);
7539
7280
  }
7540
7281
  function work_docx_note_comment_hyperlink_preservation_contentSemanticKey(element, _role) {
7541
- return isKnownOoxmlNamespace(element.namespaceURI ?? '') ? `{semantic}${element.localName}` : `{${element.namespaceURI ?? ''}}${element.localName}`;
7282
+ return work_docx_note_comment_hyperlink_content_isKnownOoxmlNamespace(element.namespaceURI ?? '') ? `{semantic}${element.localName}` : `{${element.namespaceURI ?? ''}}${element.localName}`;
7542
7283
  }
7543
7284
  function work_docx_note_comment_hyperlink_preservation_ensureNamespacePrefix(root, namespace, preferred) {
7544
7285
  const existing = xmlDeclaredPrefix(root, namespace);
@@ -7555,7 +7296,7 @@ function work_docx_note_comment_hyperlink_preservation_ensureNamespacePrefix(roo
7555
7296
  const work_docx_note_comment_run_preservation_MARKUP_COMPATIBILITY_NAMESPACE = 'http://schemas.openxmlformats.org/markup-compatibility/2006';
7556
7297
  const MAX_CONTENT_PARAGRAPHS = 65536;
7557
7298
  const MAX_CONTENT_RUNS = 262144;
7558
- const work_docx_note_comment_run_preservation_MAX_COMMENT_RUN_SEGMENTS = 4096;
7299
+ const MAX_COMMENT_RUN_SEGMENTS = 4096;
7559
7300
  function preserveDocxNoteCommentRunContent(generatedDocument, sourceDocument, scopes, kind) {
7560
7301
  const paragraphPairs = [];
7561
7302
  const runPairs = [];
@@ -7568,9 +7309,9 @@ function preserveDocxNoteCommentRunContent(generatedDocument, sourceDocument, sc
7568
7309
  for (const scope of scopes){
7569
7310
  const pairs = work_docx_note_comment_run_preservation_uniqueParagraphPairs(scope.generated, scope.source, limits);
7570
7311
  for (const pair of pairs){
7571
- if ('comment' === kind) work_docx_note_comment_run_preservation_alignCommentRunBoundaries(pair);
7572
- const generatedRuns = contentRuns(pair.generated);
7573
- const sourceRuns = contentRuns(pair.source);
7312
+ if ('comment' === kind) alignCommentRunBoundaries(pair);
7313
+ const generatedRuns = work_docx_note_comment_run_preservation_contentRuns(pair.generated);
7314
+ const sourceRuns = work_docx_note_comment_run_preservation_contentRuns(pair.source);
7574
7315
  if (!generatedRuns || !sourceRuns) continue;
7575
7316
  const pairsBySpan = work_docx_note_comment_run_preservation_uniqueRunPairs(generatedRuns, sourceRuns);
7576
7317
  for (const runPair of pairsBySpan){
@@ -7606,11 +7347,11 @@ function contentParagraphs(scope, role, limits) {
7606
7347
  for (const paragraph of paragraphs){
7607
7348
  limits[runKey] += work_docx_note_comment_run_preservation_wordDirectChildren(paragraph, 'r').length;
7608
7349
  if (limits[runKey] > MAX_CONTENT_RUNS) throw new Error(`${'source' === role ? 'Registered source' : 'Generated'} DOCX exceeds the stable note/comment run limit.`);
7609
- const runs = contentRuns(paragraph);
7350
+ const runs = work_docx_note_comment_run_preservation_contentRuns(paragraph);
7610
7351
  if (!runs?.length) continue;
7611
7352
  const text = runs.map((run)=>run.text).join('');
7612
7353
  if (!text) continue;
7613
- const ancestry = work_docx_note_comment_run_preservation_paragraphAncestry(paragraph, scope);
7354
+ const ancestry = paragraphAncestry(paragraph, scope);
7614
7355
  if (ancestry) records.push({
7615
7356
  element: paragraph,
7616
7357
  identity: `${ancestry}\u0000${text}`
@@ -7627,7 +7368,7 @@ function groupParagraphs(paragraphs) {
7627
7368
  }
7628
7369
  return result;
7629
7370
  }
7630
- function work_docx_note_comment_run_preservation_paragraphAncestry(paragraph, scope) {
7371
+ function paragraphAncestry(paragraph, scope) {
7631
7372
  const path = [];
7632
7373
  let current = paragraph;
7633
7374
  while(current && current !== scope){
@@ -7637,7 +7378,7 @@ function work_docx_note_comment_run_preservation_paragraphAncestry(paragraph, sc
7637
7378
  }
7638
7379
  return current === scope ? path.reverse().join('/') : null;
7639
7380
  }
7640
- function contentRuns(paragraph) {
7381
+ function work_docx_note_comment_run_preservation_contentRuns(paragraph) {
7641
7382
  if (!eligibleParagraphChildren(paragraph)) return null;
7642
7383
  const records = [];
7643
7384
  let offset = 0;
@@ -7658,14 +7399,14 @@ function contentRuns(paragraph) {
7658
7399
  function eligibleParagraphChildren(paragraph) {
7659
7400
  return Array.from(paragraph.children).every((child)=>{
7660
7401
  if (work_docx_note_comment_run_preservation_isWordElement(child)) return 'pPr' === child.localName || 'r' === child.localName;
7661
- return !work_docx_note_comment_run_preservation_isContentSemanticNamespace(child.namespaceURI ?? '');
7402
+ return !isContentSemanticNamespace(child.namespaceURI ?? '');
7662
7403
  });
7663
7404
  }
7664
7405
  function work_docx_note_comment_run_preservation_contentRunText(run) {
7665
7406
  let text = '';
7666
7407
  for (const child of Array.from(run.children)){
7667
7408
  if (!work_docx_note_comment_run_preservation_isWordElement(child)) {
7668
- if (work_docx_note_comment_run_preservation_isContentSemanticNamespace(child.namespaceURI ?? '')) return null;
7409
+ if (isContentSemanticNamespace(child.namespaceURI ?? '')) return null;
7669
7410
  continue;
7670
7411
  }
7671
7412
  if ('rPr' !== child.localName) {
@@ -7717,10 +7458,10 @@ function work_docx_note_comment_run_preservation_groupRunsBySpan(runs) {
7717
7458
  }
7718
7459
  return result;
7719
7460
  }
7720
- function work_docx_note_comment_run_preservation_alignCommentRunBoundaries(pair) {
7721
- const generatedRuns = contentRuns(pair.generated);
7722
- const sourceRuns = contentRuns(pair.source);
7723
- if (!generatedRuns || !sourceRuns || 1 !== generatedRuns.length || sourceRuns.length < 2 || sourceRuns.length > work_docx_note_comment_run_preservation_MAX_COMMENT_RUN_SEGMENTS || generatedRuns[0].text !== sourceRuns.map((run)=>run.text).join('') || !work_docx_note_comment_run_preservation_isSimpleTextRun(generatedRuns[0].element) || sourceRuns.some((run)=>!work_docx_note_comment_run_preservation_isSimpleTextRun(run.element))) return;
7461
+ function alignCommentRunBoundaries(pair) {
7462
+ const generatedRuns = work_docx_note_comment_run_preservation_contentRuns(pair.generated);
7463
+ const sourceRuns = work_docx_note_comment_run_preservation_contentRuns(pair.source);
7464
+ if (!generatedRuns || !sourceRuns || 1 !== generatedRuns.length || sourceRuns.length < 2 || sourceRuns.length > MAX_COMMENT_RUN_SEGMENTS || generatedRuns[0].text !== sourceRuns.map((run)=>run.text).join('') || !work_docx_note_comment_run_preservation_isSimpleTextRun(generatedRuns[0].element) || sourceRuns.some((run)=>!work_docx_note_comment_run_preservation_isSimpleTextRun(run.element))) return;
7724
7465
  const original = generatedRuns[0].element;
7725
7466
  const textElement = work_docx_note_comment_run_preservation_wordDirectChildren(original, 't')[0];
7726
7467
  if (!textElement || !original.parentNode) return;
@@ -7746,20 +7487,20 @@ function mergeContentExtensions(generatedDocument, sourceDocument, pairs, allowM
7746
7487
  if (!pairs.length) return;
7747
7488
  mergeDocxIgnorableExtensionsAtPairs(generatedDocument, sourceDocument, pairs, {
7748
7489
  semanticKey: work_docx_note_comment_run_preservation_contentSemanticKey,
7749
- isAdditionalSemanticNamespace: work_docx_note_comment_run_preservation_isKnownOoxmlNamespace,
7750
- allowExtensionNamespace: (namespace)=>!work_docx_note_comment_run_preservation_isKnownOoxmlNamespace(namespace),
7490
+ isAdditionalSemanticNamespace: isKnownOoxmlNamespace,
7491
+ allowExtensionNamespace: (namespace)=>!isKnownOoxmlNamespace(namespace),
7751
7492
  allowMatchedElementMerge
7752
7493
  });
7753
7494
  }
7754
7495
  function work_docx_note_comment_run_preservation_contentSemanticKey(element, _role) {
7755
- return work_docx_note_comment_run_preservation_isKnownOoxmlNamespace(element.namespaceURI ?? '') ? `{semantic}${element.localName}` : `{${element.namespaceURI ?? ''}}${element.localName}`;
7496
+ return isKnownOoxmlNamespace(element.namespaceURI ?? '') ? `{semantic}${element.localName}` : `{${element.namespaceURI ?? ''}}${element.localName}`;
7756
7497
  }
7757
- function work_docx_note_comment_run_preservation_isKnownOoxmlNamespace(namespace) {
7498
+ function isKnownOoxmlNamespace(namespace) {
7758
7499
  if (namespace === work_docx_note_comment_run_preservation_MARKUP_COMPATIBILITY_NAMESPACE) return false;
7759
7500
  return DOCX_WORDPROCESSING_NAMESPACES.has(namespace) || namespace.startsWith('http://schemas.microsoft.com/office/') || namespace.startsWith('http://schemas.openxmlformats.org/') || namespace.startsWith('http://purl.oclc.org/ooxml/') || namespace.startsWith('urn:schemas-microsoft-com:') || namespace.startsWith('urn:microsoft-com:office:');
7760
7501
  }
7761
- function work_docx_note_comment_run_preservation_isContentSemanticNamespace(namespace) {
7762
- return namespace === work_docx_note_comment_run_preservation_MARKUP_COMPATIBILITY_NAMESPACE || work_docx_note_comment_run_preservation_isKnownOoxmlNamespace(namespace);
7502
+ function isContentSemanticNamespace(namespace) {
7503
+ return namespace === work_docx_note_comment_run_preservation_MARKUP_COMPATIBILITY_NAMESPACE || isKnownOoxmlNamespace(namespace);
7763
7504
  }
7764
7505
  function work_docx_note_comment_run_preservation_wordDirectChildren(element, localName) {
7765
7506
  return Array.from(element.children).filter((child)=>child.localName === localName && work_docx_note_comment_run_preservation_isWordElement(child));
@@ -8767,6 +8508,7 @@ async function createDocxBlob(content, sourcePackage) {
8767
8508
  imageWrapPatches: new DocxImageWrapPatchCollector(),
8768
8509
  imageTransformPatches: new DocxImageTransformPatchCollector(),
8769
8510
  textBoxIdentityPatches: new DocxTextBoxIdentityPatchCollector(),
8511
+ contentControlPatches: new DocxContentControlPatchCollector(),
8770
8512
  paragraphBorderPatches: new DocxParagraphBorderPatchCollector(JSON.stringify(normalizedContent)),
8771
8513
  paragraphDefaultCollapsedPatches: new DocxParagraphDefaultCollapsedPatchCollector(),
8772
8514
  paragraphIdentityPatches: new DocxParagraphIdentityPatchCollector(JSON.stringify(normalizedContent)),
@@ -8866,9 +8608,10 @@ async function createDocxBlob(content, sourcePackage) {
8866
8608
  const numberingChangesPatched = await patchDocxNumberingChanges(paragraphFormattingChangesPatched, noteContext.numberingChangePatches.patches);
8867
8609
  const equationPatched = await patchDocxEquations(numberingChangesPatched, noteContext.equationPatches.patches);
8868
8610
  const patched = await patchDocxPageColor(equationPatched, normalizedContent.pageColor);
8869
- const preserved = sourcePackage ? await preserveDocxSourcePackage(patched, sourcePackage, {
8611
+ const contentControlsPatched = await patchDocxContentControls(patched, noteContext.contentControlPatches.patches);
8612
+ const preserved = sourcePackage ? await preserveDocxSourcePackage(contentControlsPatched, sourcePackage, {
8870
8613
  numberingIdentities: noteContext.numberingSourceIdentities
8871
- }) : patched;
8614
+ }) : contentControlsPatched;
8872
8615
  return new Blob([
8873
8616
  preserved
8874
8617
  ], {
@@ -9302,6 +9045,11 @@ async function work_docx_export_inlineRuns(root, docx, noteContext) {
9302
9045
  'footnote' === kind ? new docx.FootnoteReferenceRun(noteId) : new docx.EndnoteReferenceRun(noteId)
9303
9046
  ];
9304
9047
  }
9048
+ if (node.hasAttribute('data-document-content-control')) {
9049
+ const children = [];
9050
+ for (const child of node.childNodes)children.push(...await visit(child, inherited, revision));
9051
+ return docxContentControlRuns(node, docx, noteContext.contentControlPatches, children);
9052
+ }
9305
9053
  const textRevisionKind = 'del' === tag ? 'deletion' : 'ins' === tag ? 'insertion' : null;
9306
9054
  const change = node.hasAttribute('data-document-change') && textRevisionKind ? docxTextRevision(node, textRevisionKind, noteContext) : revision;
9307
9055
  const formattingChange = node.hasAttribute('data-document-change') && 'formatting' === node.dataset.changeKind ? noteContext.formattingChangePatches.register(node, docxRevisionId(node, noteContext)) : null;