@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.
- package/README.md +17 -0
- package/dist/{0~2133.js → 0~3320.js} +446 -24
- package/dist/{0~4042.js → 0~3534.js} +510 -4
- package/dist/0~document-editor.js +263 -3
- package/dist/0~work-docx-export.js +416 -668
- package/dist/0~work-docx-import.js +15 -4
- package/dist/0~work-office-diagnostics.js +5 -2
- package/dist/4174.js +5113 -4750
- package/dist/internal/features/work/editors/document-command-catalog.d.ts +9 -0
- package/dist/internal/features/work/editors/document-content-control-dialog.d.ts +10 -0
- package/dist/internal/features/work/editors/document-toolbar.d.ts +2 -1
- package/dist/internal/features/work/editors/use-document-insert-commands.d.ts +1 -0
- package/dist/internal/features/work/work-document-content-control.d.ts +59 -0
- package/dist/internal/features/work/work-docx-content-control-export.d.ts +24 -0
- package/dist/internal/features/work/work-docx-content-control-import.d.ts +28 -0
- package/dist/internal/features/work/work-docx-import.d.ts +3 -1
- package/dist/styles.css +125 -0
- package/package.json +6 -3
|
@@ -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,
|
|
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 {
|
|
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
|
-
|
|
780
|
+
work_docx_paragraph_borders_export_setWordAttribute(document, element, 'val', border.style);
|
|
535
781
|
setBorderColor(document, element, border);
|
|
536
|
-
if (void 0 !== border.size)
|
|
537
|
-
if (void 0 !== border.space)
|
|
538
|
-
if (void 0 !== border.shadow)
|
|
539
|
-
if (void 0 !== border.frame)
|
|
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
|
-
|
|
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
|
-
|
|
547
|
-
if (color.theme.tint)
|
|
548
|
-
if (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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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(
|
|
2713
|
-
else if ('small-caps' === textCase) properties.append(
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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',
|
|
5420
|
-
assertXmlRoot(sourceDocument.documentElement, 'fonts',
|
|
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)=>
|
|
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)=>
|
|
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 (
|
|
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 &&
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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 &&
|
|
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
|
|
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) && !
|
|
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
|
|
6796
|
-
const
|
|
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 (!
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 ?
|
|
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:
|
|
7342
|
-
allowExtensionNamespace: (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
|
|
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 &&
|
|
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:
|
|
7491
|
-
allowExtensionNamespace: (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:
|
|
7500
|
-
allowExtensionNamespace: (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
|
|
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
|
|
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)
|
|
7572
|
-
const generatedRuns =
|
|
7573
|
-
const sourceRuns =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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 !
|
|
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 (
|
|
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
|
|
7721
|
-
const generatedRuns =
|
|
7722
|
-
const sourceRuns =
|
|
7723
|
-
if (!generatedRuns || !sourceRuns || 1 !== generatedRuns.length || sourceRuns.length < 2 || sourceRuns.length >
|
|
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:
|
|
7750
|
-
allowExtensionNamespace: (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
|
|
7496
|
+
return isKnownOoxmlNamespace(element.namespaceURI ?? '') ? `{semantic}${element.localName}` : `{${element.namespaceURI ?? ''}}${element.localName}`;
|
|
7756
7497
|
}
|
|
7757
|
-
function
|
|
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
|
|
7762
|
-
return namespace === work_docx_note_comment_run_preservation_MARKUP_COMPATIBILITY_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
|
|
8611
|
+
const contentControlsPatched = await patchDocxContentControls(patched, noteContext.contentControlPatches.patches);
|
|
8612
|
+
const preserved = sourcePackage ? await preserveDocxSourcePackage(contentControlsPatched, sourcePackage, {
|
|
8870
8613
|
numberingIdentities: noteContext.numberingSourceIdentities
|
|
8871
|
-
}) :
|
|
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;
|