@a3s-lab/office 0.26.0 → 0.28.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 +89 -2
- package/dist/0~4595.js +16 -2
- package/dist/0~5093.js +563 -201
- package/dist/0~6090.js +77 -77
- package/dist/{0~2805.js → 0~7043.js} +305 -2
- package/dist/0~document-editor.js +2633 -976
- package/dist/0~spreadsheet-editor.js +1324 -378
- package/dist/0~work-docx-export.js +737 -17
- package/dist/0~work-docx-import.js +173 -98
- package/dist/0~work-office-diagnostics.js +250 -5
- package/dist/{164.js → 1544.js} +1083 -785
- package/dist/4104.js +145 -29
- package/dist/5184.js +13 -0
- package/dist/6282.js +1898 -345
- package/dist/core.js +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/features/work/editors/document-command-catalog.d.ts +102 -0
- package/dist/internal/features/work/editors/document-font-dialog-model.d.ts +111 -0
- package/dist/internal/features/work/editors/document-font-dialog-script-font-model.d.ts +18 -0
- package/dist/internal/features/work/editors/document-font-dialog.d.ts +9 -0
- package/dist/internal/features/work/editors/document-home-ribbon.d.ts +2 -1
- package/dist/internal/features/work/editors/document-page-chrome-editor.d.ts +6 -0
- package/dist/internal/features/work/editors/document-page-chrome-ribbon.d.ts +2 -1
- package/dist/internal/features/work/editors/document-strike-ribbon.d.ts +7 -0
- package/dist/internal/features/work/editors/document-text-case-ribbon.d.ts +4 -0
- package/dist/internal/features/work/editors/document-toolbar.d.ts +3 -1
- package/dist/internal/features/work/editors/document-underline-ribbon.d.ts +9 -0
- package/dist/internal/features/work/editors/document-wps-shortcuts.d.ts +1 -0
- package/dist/internal/features/work/editors/spreadsheet-cell-fill-format.d.ts +11 -0
- package/dist/internal/features/work/editors/spreadsheet-cell-format.d.ts +2 -1
- package/dist/internal/features/work/editors/spreadsheet-format-cells-dialog-model.d.ts +13 -2
- package/dist/internal/features/work/editors/spreadsheet-format-cells-fill-panel.d.ts +13 -0
- package/dist/internal/features/work/editors/spreadsheet-format-cells-fill-preview.d.ts +6 -0
- package/dist/internal/features/work/editors/spreadsheet-format-painter.d.ts +1 -1
- package/dist/internal/features/work/editors/work-office-chrome.d.ts +9 -1
- package/dist/internal/features/work/work-document-character-formatting.d.ts +16 -1
- package/dist/internal/features/work/work-document-character-position.d.ts +9 -0
- package/dist/internal/features/work/work-document-character-scale.d.ts +8 -0
- package/dist/internal/features/work/work-document-character-spacing.d.ts +8 -0
- package/dist/internal/features/work/work-document-emphasis.d.ts +7 -0
- package/dist/internal/features/work/work-document-equations.d.ts +2 -1
- package/dist/internal/features/work/work-document-format-changes.d.ts +20 -2
- package/dist/internal/features/work/work-document-hidden-text.d.ts +5 -0
- package/dist/internal/features/work/work-document-kerning.d.ts +10 -0
- package/dist/internal/features/work/work-document-legacy-text-effects.d.ts +27 -0
- package/dist/internal/features/work/work-document-script-font-extension.d.ts +2 -0
- package/dist/internal/features/work/work-document-script-fonts.d.ts +51 -0
- package/dist/internal/features/work/work-document-strike.d.ts +21 -0
- package/dist/internal/features/work/work-document-text-case.d.ts +10 -0
- package/dist/internal/features/work/work-document-underline.d.ts +37 -0
- package/dist/internal/features/work/work-document-word-line-metrics.d.ts +16 -0
- package/dist/internal/features/work/work-docx-character-position.d.ts +2 -0
- package/dist/internal/features/work/work-docx-character-scale.d.ts +2 -0
- package/dist/internal/features/work/work-docx-character-spacing.d.ts +4 -0
- package/dist/internal/features/work/work-docx-emphasis-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-emphasis.d.ts +14 -0
- package/dist/internal/features/work/work-docx-hidden-text-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-hidden-text-export.d.ts +17 -0
- package/dist/internal/features/work/work-docx-hidden-text.d.ts +11 -0
- package/dist/internal/features/work/work-docx-kerning-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-kerning.d.ts +14 -0
- package/dist/internal/features/work/work-docx-legacy-text-effects-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-legacy-text-effects-export.d.ts +18 -0
- package/dist/internal/features/work/work-docx-legacy-text-effects.d.ts +12 -0
- package/dist/internal/features/work/work-docx-run-fonts-diagnostics.d.ts +3 -0
- package/dist/internal/features/work/work-docx-run-fonts-export.d.ts +14 -0
- package/dist/internal/features/work/work-docx-run-fonts.d.ts +13 -0
- package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +27 -2
- package/dist/internal/features/work/work-docx-run-property-order.d.ts +2 -0
- package/dist/internal/features/work/work-docx-run-script-font-import.d.ts +9 -0
- package/dist/internal/features/work/work-docx-strike.d.ts +8 -0
- package/dist/internal/features/work/work-docx-theme-reference.d.ts +1 -1
- package/dist/internal/features/work/work-docx-twips.d.ts +6 -0
- package/dist/internal/features/work/work-docx-underline.d.ts +3 -0
- package/dist/internal/features/work/work-spreadsheet-gradient-fill-canvas.d.ts +10 -0
- package/dist/internal/features/work/work-spreadsheet-native-fill-canvas.d.ts +8 -0
- package/dist/internal/features/work/work-spreadsheet-pattern-fill-canvas.d.ts +8 -0
- package/dist/internal/features/work/work-xlsx-cell-style-origin.d.ts +2 -1
- package/dist/internal/features/work/work-xlsx-cell-style-writer.d.ts +3 -0
- package/dist/internal/features/work/work-xlsx-cell-styles.d.ts +4 -0
- package/dist/internal/features/work/work-xlsx-gradient-fill.d.ts +31 -0
- package/dist/internal/features/work/work-xlsx-native-fill.d.ts +17 -0
- package/dist/internal/features/work/work-xlsx-pattern-fill.d.ts +21 -0
- package/dist/office-kernel.wasm +0 -0
- package/dist/styles.css +809 -78
- package/docs/latest/en/browser-editor-architecture.md +24 -0
- package/package.json +35 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import jszip from "jszip";
|
|
2
|
-
import { normalizeDocumentBookmarkName, applyDocumentImageIdentityToElement, DOCUMENT_PAGE_BORDER_EDGES,
|
|
2
|
+
import { normalizeDocumentBookmarkName, normalizeDocumentEmphasisMark, DOCUMENT_STRIKE_STYLE_ATTRIBUTE, applyDocumentImageIdentityToElement, documentEmphasisMarkFromElement, DOCUMENT_PAGE_BORDER_EDGES, DOCUMENT_UNDERLINE_STYLE_ATTRIBUTE, documentScriptFontSlotFromElement, normalizeDocumentColumns, createDocumentImageIdentityRegistry, serializeDocumentScriptFonts, documentCharacterSpacingTwipsFromElement, uniqueDocumentParagraphIdentity, documentCharacterPositionHalfPointsFromElement, normalizeDocumentTableVerticalAlign, documentTableColumnPercentagesFromElement, normalizeDocumentTextCase, documentTableCellMarginOverridesFromElement, applyDocumentTableRowIdentityToElement, normalizeDocumentBookmarksHtml, documentImageIdentityFromElement, documentTableGeometryFromElement, normalizeDocumentTableRowHeightRule, normalizeDocumentScriptFonts, documentNoteKey, DOCUMENT_LEGACY_TEXT_EMBOSS_ATTRIBUTE, normalizeDocumentHiddenText, normalizeDocumentParagraphBorders, documentLegacyTextEffectsConflict, normalizeDocumentTableBorderWidth, normalizeDocumentCharacterSpacingTwips, normalizeDocumentParagraphId, documentStrikeFormattingFromElement, normalizeDocumentTableBorderStyle, normalizeDocumentBookmarkReferencesHtml, documentCitationInstruction, parseDocumentParagraphBordersElement, documentImageWrapContourFromElement, documentImagePositionFromElement, normalizeDocumentCharacterScalePercent, documentScriptFontsFromElement, normalizeDocumentUnderlineStyle, documentPageMarginsForLayout, normalizeDocumentPageChrome, normalizeDocumentImageLayer, documentFontNameFromCssFamily, documentBookmarkReferenceInstruction, documentImageCropFromElement, documentKerningThresholdHalfPointsFromElement, normalizeDocumentPageBorders, documentImageLayerFromElement, normalizeDocumentLegacyTextEffects, documentCaptionLabel, documentCaptionKind, applyDocumentParagraphIdentityToElement, DOCUMENT_LEGACY_TEXT_IMPRINT_ATTRIBUTE, isContourImageLayout, parseDocumentScriptFonts, normalizeDocumentStrikeStyle, parseDocxThemeReference, createDocumentParagraphIdentityRegistry, documentCitationTags, docxDocumentFieldKind, normalizeDocumentImageIdentity, normalizeTableColor, documentTableBordersFromElement, wrapsBesideImage, normalizeDocumentCharacterPositionHalfPoints, normalizeDocumentKerningThresholdHalfPoints, DocxThemePatchCollector, defaultDocumentImageWrapContour, documentSections, normalizeDocumentParagraphIdentity, normalizeDocumentPaperSource, DOCUMENT_LEGACY_TEXT_OUTLINE_ATTRIBUTE, documentEquationFromElement, DOCUMENT_PARAGRAPH_BORDER_EDGES, documentLegacyTextEffectsFromElement, parseDocumentCharacterFormatting, documentScriptFontFamily, documentParagraphIdentityFromElement, DOCUMENT_LEGACY_TEXT_SHADOW_ATTRIBUTE, normalizeDocumentEquation, documentUnderlineFormattingFromElement, normalizeDocumentBookmarkNativeId, patchDocxThemeReferences, DOCUMENT_PAGE_MARGIN_KEYS, uniqueDocumentImageIdentity, documentHiddenTextFromElement, parseDocumentParagraphShadingElement, documentImageLayoutFromElement, documentScriptFontSlotFromHint, parseDocumentParagraphFormatting, documentPageHorizontalMarginTwips, documentTableRowIdentityFromElement, collectDocumentNotes, documentPageGeometryForLayout, normalizeDocumentScriptFontSlot, DOCUMENT_LEGACY_TEXT_EFFECT_NAMES, documentCharacterScalePercentFromElement, normalizeDocumentPageMargins, normalizeDocumentLegacyTextEffect, documentNoteKind } from "./6282.js";
|
|
3
3
|
import { serializeUtf8Xml, directChildren, xmlNamespacePrefix, parseXml, decodeXmlBytes, descendants, resolvePartTarget, directChild, attribute as work_ooxml_package_attribute } from "./5184.js";
|
|
4
4
|
import { assignDocxNoteIds, patchDocxPageColor, normalizeDocxCommentId, assignDocxCommentThreads } from "./0~4980.js";
|
|
5
|
-
import { paragraphTabStops, mergeDocxIgnorableExtensionsAtPairs, patchDocxBibliography, XMLNS_NAMESPACE as work_docx_settings_xml_XMLNS_NAMESPACE, paragraphAlignment, paragraphSpacingOptions, xmlNamespaceUri, hasNonWhitespaceXmlText, cloneXmlElement, cssColorToHex, DocxParagraphDefaultCollapsedPatchCollector, assertXmlRoot, xmlDeclaredPrefix, paragraphIndent, domDirection, DOCX_WORDPROCESSING_NAMESPACES, paragraphBidirectional, XML_NAMESPACE as work_docx_settings_xml_XML_NAMESPACE, patchDocxParagraphDefaultCollapsed, xmlAttributeNamespace, dataBoolean, mergeDocxIgnorableExtensions, parseDocxColorSchemeMappingElement, paragraphPaginationOptions, DOCX_COLOR_SCHEME_MAPPING_ATTRIBUTES, xmlAttributeLocalName, cssFontSize, paragraphDirectionOptions, cssFontFamily } from "./0~
|
|
5
|
+
import { paragraphTabStops, mergeDocxIgnorableExtensionsAtPairs, patchDocxBibliography, docxKerningThresholdValue, docxCharacterPositionValue, docxCharacterScaleValue, docxEmphasisMarkRunOptions, XMLNS_NAMESPACE as work_docx_settings_xml_XMLNS_NAMESPACE, paragraphAlignment, paragraphSpacingOptions, xmlNamespaceUri, hasNonWhitespaceXmlText, patchDocxExplicitZeroCharacterSpacing, cloneXmlElement, cssColorToHex, DocxParagraphDefaultCollapsedPatchCollector, assertXmlRoot, xmlDeclaredPrefix, paragraphIndent, domDirection, DOCX_WORDPROCESSING_NAMESPACES, paragraphBidirectional, XML_NAMESPACE as work_docx_settings_xml_XML_NAMESPACE, patchDocxParagraphDefaultCollapsed, xmlAttributeNamespace, dataBoolean, mergeDocxIgnorableExtensions, patchDocxExplicitZeroKerningThresholds, parseDocxColorSchemeMappingElement, paragraphPaginationOptions, DOCX_COLOR_SCHEME_MAPPING_ATTRIBUTES, xmlAttributeLocalName, cssFontSize, paragraphDirectionOptions, cssFontFamily, docxCharacterSpacingValue } from "./0~7043.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 {
|
|
@@ -757,6 +757,285 @@ function hasAncestor(element, localName) {
|
|
|
757
757
|
}
|
|
758
758
|
return false;
|
|
759
759
|
}
|
|
760
|
+
const DOCX_RUN_PROPERTY_ORDER = [
|
|
761
|
+
'rStyle',
|
|
762
|
+
'rFonts',
|
|
763
|
+
'b',
|
|
764
|
+
'bCs',
|
|
765
|
+
'i',
|
|
766
|
+
'iCs',
|
|
767
|
+
'caps',
|
|
768
|
+
'smallCaps',
|
|
769
|
+
'strike',
|
|
770
|
+
'dstrike',
|
|
771
|
+
'outline',
|
|
772
|
+
'shadow',
|
|
773
|
+
'emboss',
|
|
774
|
+
'imprint',
|
|
775
|
+
'noProof',
|
|
776
|
+
'snapToGrid',
|
|
777
|
+
'vanish',
|
|
778
|
+
'webHidden',
|
|
779
|
+
'color',
|
|
780
|
+
'spacing',
|
|
781
|
+
'w',
|
|
782
|
+
'kern',
|
|
783
|
+
'position',
|
|
784
|
+
'sz',
|
|
785
|
+
'szCs',
|
|
786
|
+
'highlight',
|
|
787
|
+
'u',
|
|
788
|
+
'effect',
|
|
789
|
+
'bdr',
|
|
790
|
+
'shd',
|
|
791
|
+
'fitText',
|
|
792
|
+
'vertAlign',
|
|
793
|
+
'rtl',
|
|
794
|
+
'cs',
|
|
795
|
+
'em',
|
|
796
|
+
'lang',
|
|
797
|
+
'eastAsianLayout',
|
|
798
|
+
'specVanish',
|
|
799
|
+
'rPrChange'
|
|
800
|
+
];
|
|
801
|
+
const DOCX_RUN_PROPERTY_RANK = new Map(DOCX_RUN_PROPERTY_ORDER.map((name, index)=>[
|
|
802
|
+
name,
|
|
803
|
+
index
|
|
804
|
+
]));
|
|
805
|
+
const HIDDEN_TEXT_PART_PATTERN = /^word\/(?:document|header\d*|footer\d*|footnotes|endnotes|comments)\.xml$/i;
|
|
806
|
+
const VANISH_RANK = DOCX_RUN_PROPERTY_RANK.get('vanish') ?? 0;
|
|
807
|
+
class DocxHiddenTextPatchCollector {
|
|
808
|
+
patches = [];
|
|
809
|
+
nextMarker = 1;
|
|
810
|
+
occupied;
|
|
811
|
+
patchesByMarker = new Map();
|
|
812
|
+
markersByValueAndStyle = new Map();
|
|
813
|
+
constructor(source){
|
|
814
|
+
this.occupied = source;
|
|
815
|
+
}
|
|
816
|
+
marker(value, inheritedStyle) {
|
|
817
|
+
const style = this.originalStyle(inheritedStyle);
|
|
818
|
+
const key = JSON.stringify([
|
|
819
|
+
value,
|
|
820
|
+
style ?? null
|
|
821
|
+
]);
|
|
822
|
+
const existing = this.markersByValueAndStyle.get(key);
|
|
823
|
+
if (existing) return existing;
|
|
824
|
+
let marker = '';
|
|
825
|
+
do {
|
|
826
|
+
marker = `A3SOfficeHiddenText${value ? 'On' : 'Off'}${String(this.nextMarker).padStart(8, '0')}`;
|
|
827
|
+
this.nextMarker += 1;
|
|
828
|
+
}while (this.occupied.includes(marker) || this.patches.some((patch)=>patch.marker === marker))
|
|
829
|
+
const patch = {
|
|
830
|
+
marker,
|
|
831
|
+
value,
|
|
832
|
+
...style ? {
|
|
833
|
+
style
|
|
834
|
+
} : {}
|
|
835
|
+
};
|
|
836
|
+
this.patches.push(patch);
|
|
837
|
+
this.patchesByMarker.set(marker, patch);
|
|
838
|
+
this.markersByValueAndStyle.set(key, marker);
|
|
839
|
+
return marker;
|
|
840
|
+
}
|
|
841
|
+
lookup(marker) {
|
|
842
|
+
return marker ? this.patchesByMarker.get(marker) : void 0;
|
|
843
|
+
}
|
|
844
|
+
originalStyle(style) {
|
|
845
|
+
let current = style;
|
|
846
|
+
const seen = new Set();
|
|
847
|
+
while(current && !seen.has(current)){
|
|
848
|
+
seen.add(current);
|
|
849
|
+
const patch = this.patchesByMarker.get(current);
|
|
850
|
+
if (!patch) break;
|
|
851
|
+
current = patch.style;
|
|
852
|
+
}
|
|
853
|
+
return current;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
async function patchDocxHiddenText(buffer, patches) {
|
|
857
|
+
if (!patches.length) return buffer;
|
|
858
|
+
const archive = await jszip.loadAsync(buffer);
|
|
859
|
+
const byMarker = new Map(patches.map((patch)=>[
|
|
860
|
+
patch.marker,
|
|
861
|
+
patch
|
|
862
|
+
]));
|
|
863
|
+
const applied = new Set();
|
|
864
|
+
for (const entry of Object.values(archive.files)){
|
|
865
|
+
if (entry.dir || !HIDDEN_TEXT_PART_PATTERN.test(entry.name)) continue;
|
|
866
|
+
const document = parseXml(decodeXmlBytes(await entry.async('uint8array'), `generated DOCX ${entry.name}`), `generated DOCX ${entry.name}`);
|
|
867
|
+
let changed = false;
|
|
868
|
+
for (const properties of descendants(document, 'rPr')){
|
|
869
|
+
if (!DOCX_WORDPROCESSING_NAMESPACES.has(properties.namespaceURI ?? '')) continue;
|
|
870
|
+
const markerStyles = directChildren(properties, 'rStyle').filter((style)=>{
|
|
871
|
+
if (!DOCX_WORDPROCESSING_NAMESPACES.has(style.namespaceURI ?? '')) return false;
|
|
872
|
+
const marker = wordValue(style);
|
|
873
|
+
return null !== marker && byMarker.has(marker);
|
|
874
|
+
});
|
|
875
|
+
if (!markerStyles.length) continue;
|
|
876
|
+
if (1 !== markerStyles.length) throw new Error('Generated DOCX hidden-text marker is duplicated in one run.');
|
|
877
|
+
const marker = wordValue(markerStyles[0]);
|
|
878
|
+
const patch = marker ? byMarker.get(marker) : void 0;
|
|
879
|
+
if (!marker || !patch) continue;
|
|
880
|
+
const existing = directChildren(properties, 'vanish').filter((element)=>DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? ''));
|
|
881
|
+
if (existing.length) throw new Error('Generated DOCX hidden-text marker unexpectedly has a native value.');
|
|
882
|
+
if (patch.style) setWordValue(markerStyles[0], patch.style);
|
|
883
|
+
else markerStyles[0].remove();
|
|
884
|
+
insertHiddenTextProperty(document, properties, patch.value);
|
|
885
|
+
applied.add(marker);
|
|
886
|
+
changed = true;
|
|
887
|
+
}
|
|
888
|
+
if (changed) archive.file(entry.name, serializeUtf8Xml(document));
|
|
889
|
+
}
|
|
890
|
+
const missing = patches.filter((patch)=>!applied.has(patch.marker));
|
|
891
|
+
if (missing.length) throw new Error(`DOCX hidden-text markers were not emitted: ${missing.map((patch)=>patch.marker).join(', ')}.`);
|
|
892
|
+
return archive.generateAsync({
|
|
893
|
+
type: 'arraybuffer'
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
function insertHiddenTextProperty(document, properties, value) {
|
|
897
|
+
const namespace = properties.namespaceURI ?? '';
|
|
898
|
+
const prefix = properties.prefix || 'w';
|
|
899
|
+
const vanish = document.createElementNS(namespace, `${prefix}:vanish`);
|
|
900
|
+
if (!value) vanish.setAttributeNS(namespace, `${prefix}:val`, '0');
|
|
901
|
+
const next = directChildren(properties).find((child)=>{
|
|
902
|
+
if (!DOCX_WORDPROCESSING_NAMESPACES.has(child.namespaceURI ?? '')) return true;
|
|
903
|
+
return (DOCX_RUN_PROPERTY_RANK.get(child.localName) ?? 1 / 0) > VANISH_RANK;
|
|
904
|
+
});
|
|
905
|
+
properties.insertBefore(vanish, next ?? null);
|
|
906
|
+
}
|
|
907
|
+
function wordValue(element) {
|
|
908
|
+
const values = Array.from(element.attributes).filter((attribute)=>'val' === xmlAttributeLocalName(attribute) && DOCX_WORDPROCESSING_NAMESPACES.has(xmlAttributeNamespace(element, attribute) ?? ''));
|
|
909
|
+
return 1 === values.length ? values[0].value : null;
|
|
910
|
+
}
|
|
911
|
+
function setWordValue(element, value) {
|
|
912
|
+
const namespace = element.namespaceURI ?? '';
|
|
913
|
+
const prefix = element.prefix || 'w';
|
|
914
|
+
for (const attribute of Array.from(element.attributes))if ('val' === xmlAttributeLocalName(attribute) && DOCX_WORDPROCESSING_NAMESPACES.has(xmlAttributeNamespace(element, attribute) ?? '')) element.removeAttributeNode(attribute);
|
|
915
|
+
element.setAttributeNS(namespace, `${prefix}:val`, value);
|
|
916
|
+
}
|
|
917
|
+
const LEGACY_TEXT_EFFECTS_PART_PATTERN = /^word\/(?:document|header\d*|footer\d*|footnotes|endnotes|comments)\.xml$/i;
|
|
918
|
+
class DocxLegacyTextEffectsPatchCollector {
|
|
919
|
+
patches = [];
|
|
920
|
+
nextMarker = 1;
|
|
921
|
+
occupied;
|
|
922
|
+
patchesByMarker = new Map();
|
|
923
|
+
markersByEffectsAndStyle = new Map();
|
|
924
|
+
constructor(source){
|
|
925
|
+
this.occupied = source;
|
|
926
|
+
}
|
|
927
|
+
marker(value, inheritedStyle) {
|
|
928
|
+
const effects = normalizeDocumentLegacyTextEffects(value);
|
|
929
|
+
if (!effects || !Object.keys(effects).length) throw new Error('Document contains invalid legacy text effects.');
|
|
930
|
+
const style = this.originalStyle(inheritedStyle);
|
|
931
|
+
const key = JSON.stringify([
|
|
932
|
+
DOCUMENT_LEGACY_TEXT_EFFECT_NAMES.map((name)=>effects[name] ?? null),
|
|
933
|
+
style ?? null
|
|
934
|
+
]);
|
|
935
|
+
const existing = this.markersByEffectsAndStyle.get(key);
|
|
936
|
+
if (existing) return existing;
|
|
937
|
+
let marker = '';
|
|
938
|
+
do {
|
|
939
|
+
marker = `A3SOfficeLegacyTextEffects${String(this.nextMarker).padStart(8, '0')}`;
|
|
940
|
+
this.nextMarker += 1;
|
|
941
|
+
}while (this.occupied.includes(marker) || this.patches.some((patch)=>patch.marker === marker))
|
|
942
|
+
const patch = {
|
|
943
|
+
marker,
|
|
944
|
+
effects,
|
|
945
|
+
...style ? {
|
|
946
|
+
style
|
|
947
|
+
} : {}
|
|
948
|
+
};
|
|
949
|
+
this.patches.push(patch);
|
|
950
|
+
this.patchesByMarker.set(marker, patch);
|
|
951
|
+
this.markersByEffectsAndStyle.set(key, marker);
|
|
952
|
+
return marker;
|
|
953
|
+
}
|
|
954
|
+
lookup(marker) {
|
|
955
|
+
return marker ? this.patchesByMarker.get(marker) : void 0;
|
|
956
|
+
}
|
|
957
|
+
originalStyle(style) {
|
|
958
|
+
let current = style;
|
|
959
|
+
const seen = new Set();
|
|
960
|
+
while(current && !seen.has(current)){
|
|
961
|
+
seen.add(current);
|
|
962
|
+
const patch = this.patchesByMarker.get(current);
|
|
963
|
+
if (!patch) break;
|
|
964
|
+
current = patch.style;
|
|
965
|
+
}
|
|
966
|
+
return current;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
async function patchDocxLegacyTextEffects(buffer, patches) {
|
|
970
|
+
if (!patches.length) return buffer;
|
|
971
|
+
const byMarker = new Map();
|
|
972
|
+
for (const patch of patches){
|
|
973
|
+
const effects = normalizeDocumentLegacyTextEffects(patch.effects);
|
|
974
|
+
if (!patch.marker || !effects || !Object.keys(effects).length || byMarker.has(patch.marker)) throw new Error('Document contains invalid legacy text-effect patches.');
|
|
975
|
+
byMarker.set(patch.marker, {
|
|
976
|
+
...patch,
|
|
977
|
+
effects
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
const archive = await jszip.loadAsync(buffer);
|
|
981
|
+
const applied = new Set();
|
|
982
|
+
for (const entry of Object.values(archive.files)){
|
|
983
|
+
if (entry.dir || !LEGACY_TEXT_EFFECTS_PART_PATTERN.test(entry.name)) continue;
|
|
984
|
+
const document = parseXml(decodeXmlBytes(await entry.async('uint8array'), `generated DOCX ${entry.name}`), `generated DOCX ${entry.name}`);
|
|
985
|
+
let changed = false;
|
|
986
|
+
for (const properties of descendants(document, 'rPr')){
|
|
987
|
+
if (!DOCX_WORDPROCESSING_NAMESPACES.has(properties.namespaceURI ?? '')) continue;
|
|
988
|
+
const markerStyles = directChildren(properties, 'rStyle').filter((style)=>{
|
|
989
|
+
if (!DOCX_WORDPROCESSING_NAMESPACES.has(style.namespaceURI ?? '')) return false;
|
|
990
|
+
const marker = work_docx_legacy_text_effects_export_wordValue(style);
|
|
991
|
+
return null !== marker && byMarker.has(marker);
|
|
992
|
+
});
|
|
993
|
+
if (!markerStyles.length) continue;
|
|
994
|
+
if (1 !== markerStyles.length) throw new Error('Generated DOCX legacy text-effect marker is duplicated in one run.');
|
|
995
|
+
const marker = work_docx_legacy_text_effects_export_wordValue(markerStyles[0]);
|
|
996
|
+
const patch = marker ? byMarker.get(marker) : void 0;
|
|
997
|
+
if (marker && patch) {
|
|
998
|
+
if (DOCUMENT_LEGACY_TEXT_EFFECT_NAMES.some((name)=>directChildren(properties, name).length > 0)) throw new Error('Generated DOCX legacy text-effect marker unexpectedly has a native value.');
|
|
999
|
+
if (patch.style) work_docx_legacy_text_effects_export_setWordValue(markerStyles[0], patch.style);
|
|
1000
|
+
else markerStyles[0].remove();
|
|
1001
|
+
for (const name of DOCUMENT_LEGACY_TEXT_EFFECT_NAMES){
|
|
1002
|
+
const value = patch.effects[name];
|
|
1003
|
+
if (void 0 !== value) insertLegacyTextEffectProperty(document, properties, name, value);
|
|
1004
|
+
}
|
|
1005
|
+
applied.add(marker);
|
|
1006
|
+
changed = true;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
if (changed) archive.file(entry.name, serializeUtf8Xml(document));
|
|
1010
|
+
}
|
|
1011
|
+
const missing = patches.filter((patch)=>!applied.has(patch.marker));
|
|
1012
|
+
if (missing.length) throw new Error(`DOCX legacy text-effect markers were not emitted: ${missing.map((patch)=>patch.marker).join(', ')}.`);
|
|
1013
|
+
return archive.generateAsync({
|
|
1014
|
+
type: 'arraybuffer'
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
function insertLegacyTextEffectProperty(document, properties, name, value) {
|
|
1018
|
+
const namespace = properties.namespaceURI ?? '';
|
|
1019
|
+
const prefix = properties.prefix || 'w';
|
|
1020
|
+
const effect = document.createElementNS(namespace, `${prefix}:${name}`);
|
|
1021
|
+
if (!value) effect.setAttributeNS(namespace, `${prefix}:val`, '0');
|
|
1022
|
+
const rank = DOCX_RUN_PROPERTY_RANK.get(name) ?? 0;
|
|
1023
|
+
const next = directChildren(properties).find((child)=>{
|
|
1024
|
+
if (!DOCX_WORDPROCESSING_NAMESPACES.has(child.namespaceURI ?? '')) return true;
|
|
1025
|
+
return (DOCX_RUN_PROPERTY_RANK.get(child.localName) ?? 1 / 0) > rank;
|
|
1026
|
+
});
|
|
1027
|
+
properties.insertBefore(effect, next ?? null);
|
|
1028
|
+
}
|
|
1029
|
+
function work_docx_legacy_text_effects_export_wordValue(element) {
|
|
1030
|
+
const values = Array.from(element.attributes).filter((attribute)=>'val' === xmlAttributeLocalName(attribute) && DOCX_WORDPROCESSING_NAMESPACES.has(xmlAttributeNamespace(element, attribute) ?? ''));
|
|
1031
|
+
return 1 === values.length ? values[0].value : null;
|
|
1032
|
+
}
|
|
1033
|
+
function work_docx_legacy_text_effects_export_setWordValue(element, value) {
|
|
1034
|
+
const namespace = element.namespaceURI ?? '';
|
|
1035
|
+
const prefix = element.prefix || 'w';
|
|
1036
|
+
for (const attribute of Array.from(element.attributes))if ('val' === xmlAttributeLocalName(attribute) && DOCX_WORDPROCESSING_NAMESPACES.has(xmlAttributeNamespace(element, attribute) ?? '')) element.removeAttributeNode(attribute);
|
|
1037
|
+
element.setAttributeNS(namespace, `${prefix}:val`, value);
|
|
1038
|
+
}
|
|
760
1039
|
const MATH_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/math';
|
|
761
1040
|
const work_docx_equation_export_WORD_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
|
|
762
1041
|
const WORD_DATE_UTC_NAMESPACE = 'http://schemas.microsoft.com/office/word/2023/wordml/word16du';
|
|
@@ -2221,15 +2500,129 @@ function appendFormattingProperties(document, properties, namespace, prefix, ser
|
|
|
2221
2500
|
appendBooleanProperty(document, properties, namespace, prefix, byType, 'bold', 'bCs');
|
|
2222
2501
|
appendBooleanProperty(document, properties, namespace, prefix, byType, 'italic', 'i');
|
|
2223
2502
|
appendBooleanProperty(document, properties, namespace, prefix, byType, 'italic', 'iCs');
|
|
2224
|
-
|
|
2225
|
-
|
|
2503
|
+
appendTextCaseProperties(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2504
|
+
appendStrikeProperties(document, properties, namespace, prefix, byType.get('strike'));
|
|
2505
|
+
appendLegacyTextEffectsProperties(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2506
|
+
appendSnapToGridProperty(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2507
|
+
appendHiddenTextProperty(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2226
2508
|
appendColorProperty(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2509
|
+
appendCharacterSpacingProperty(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2510
|
+
appendCharacterScaleProperty(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2511
|
+
appendKerningThresholdProperty(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2512
|
+
appendCharacterPositionProperty(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2227
2513
|
appendFontSizeProperties(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2228
2514
|
appendHighlightProperty(document, properties, namespace, prefix, byType.get('highlight'));
|
|
2229
|
-
|
|
2515
|
+
appendUnderlineProperty(document, properties, namespace, prefix, byType.get('underline'));
|
|
2230
2516
|
appendVerticalAlignProperty(document, properties, namespace, prefix, byType);
|
|
2517
|
+
appendEmphasisMarkProperty(document, properties, namespace, prefix, byType.get('textStyle'));
|
|
2518
|
+
}
|
|
2519
|
+
function appendLegacyTextEffectsProperties(document, properties, namespace, prefix, mark) {
|
|
2520
|
+
const effects = {};
|
|
2521
|
+
const attributes = [
|
|
2522
|
+
[
|
|
2523
|
+
'outline',
|
|
2524
|
+
'legacyTextOutline'
|
|
2525
|
+
],
|
|
2526
|
+
[
|
|
2527
|
+
'shadow',
|
|
2528
|
+
'legacyTextShadow'
|
|
2529
|
+
],
|
|
2530
|
+
[
|
|
2531
|
+
'emboss',
|
|
2532
|
+
'legacyTextEmboss'
|
|
2533
|
+
],
|
|
2534
|
+
[
|
|
2535
|
+
'imprint',
|
|
2536
|
+
'legacyTextImprint'
|
|
2537
|
+
]
|
|
2538
|
+
];
|
|
2539
|
+
for (const [effect, attribute] of attributes){
|
|
2540
|
+
const value = normalizeDocumentLegacyTextEffect(mark?.attrs?.[attribute]);
|
|
2541
|
+
if (null !== value) effects[effect] = value;
|
|
2542
|
+
}
|
|
2543
|
+
if (documentLegacyTextEffectsConflict(effects)) throw new Error('Document contains conflicting legacy text effects.');
|
|
2544
|
+
for (const name of DOCUMENT_LEGACY_TEXT_EFFECT_NAMES){
|
|
2545
|
+
const value = effects[name];
|
|
2546
|
+
if (void 0 !== value) if (value) properties.append(wordElement(document, namespace, prefix, name));
|
|
2547
|
+
else appendValuedProperty(document, properties, namespace, prefix, name, '0');
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
function appendHiddenTextProperty(document, properties, namespace, prefix, mark) {
|
|
2551
|
+
const hiddenText = normalizeDocumentHiddenText(mark?.attrs?.hiddenText);
|
|
2552
|
+
if (null === hiddenText) return;
|
|
2553
|
+
if (hiddenText) properties.append(wordElement(document, namespace, prefix, 'vanish'));
|
|
2554
|
+
else appendValuedProperty(document, properties, namespace, prefix, 'vanish', '0');
|
|
2555
|
+
}
|
|
2556
|
+
function appendEmphasisMarkProperty(document, properties, namespace, prefix, mark) {
|
|
2557
|
+
const emphasisMark = normalizeDocumentEmphasisMark(mark?.attrs?.emphasisMark);
|
|
2558
|
+
if (null === emphasisMark) return;
|
|
2559
|
+
appendValuedProperty(document, properties, namespace, prefix, 'em', emphasisMark);
|
|
2560
|
+
}
|
|
2561
|
+
function appendCharacterScaleProperty(document, properties, namespace, prefix, mark) {
|
|
2562
|
+
const scale = normalizeDocumentCharacterScalePercent(mark?.attrs?.characterScalePercent);
|
|
2563
|
+
if (null === scale) return;
|
|
2564
|
+
appendValuedProperty(document, properties, namespace, prefix, 'w', String(scale));
|
|
2565
|
+
}
|
|
2566
|
+
function appendKerningThresholdProperty(document, properties, namespace, prefix, mark) {
|
|
2567
|
+
const threshold = normalizeDocumentKerningThresholdHalfPoints(mark?.attrs?.kerningThresholdHalfPoints);
|
|
2568
|
+
if (null === threshold) return;
|
|
2569
|
+
appendValuedProperty(document, properties, namespace, prefix, 'kern', String(threshold));
|
|
2570
|
+
}
|
|
2571
|
+
function appendCharacterPositionProperty(document, properties, namespace, prefix, mark) {
|
|
2572
|
+
const position = normalizeDocumentCharacterPositionHalfPoints(mark?.attrs?.characterPositionHalfPoints);
|
|
2573
|
+
if (null === position) return;
|
|
2574
|
+
appendValuedProperty(document, properties, namespace, prefix, 'position', String(position));
|
|
2575
|
+
}
|
|
2576
|
+
function appendCharacterSpacingProperty(document, properties, namespace, prefix, mark) {
|
|
2577
|
+
const spacing = normalizeDocumentCharacterSpacingTwips(mark?.attrs?.characterSpacingTwips);
|
|
2578
|
+
if (null === spacing) return;
|
|
2579
|
+
appendValuedProperty(document, properties, namespace, prefix, 'spacing', String(spacing));
|
|
2231
2580
|
}
|
|
2232
2581
|
function appendFontProperties(document, properties, namespace, prefix, mark) {
|
|
2582
|
+
const scriptFonts = parseDocumentScriptFonts('string' == typeof mark?.attrs?.scriptFonts ? mark.attrs.scriptFonts : void 0);
|
|
2583
|
+
if (scriptFonts) {
|
|
2584
|
+
const fonts = wordElement(document, namespace, prefix, 'rFonts');
|
|
2585
|
+
for (const [name, value] of [
|
|
2586
|
+
[
|
|
2587
|
+
'ascii',
|
|
2588
|
+
scriptFonts.ascii?.name
|
|
2589
|
+
],
|
|
2590
|
+
[
|
|
2591
|
+
'hAnsi',
|
|
2592
|
+
scriptFonts.highAnsi?.name
|
|
2593
|
+
],
|
|
2594
|
+
[
|
|
2595
|
+
'eastAsia',
|
|
2596
|
+
scriptFonts.eastAsia?.name
|
|
2597
|
+
],
|
|
2598
|
+
[
|
|
2599
|
+
'cs',
|
|
2600
|
+
scriptFonts.complexScript?.name
|
|
2601
|
+
],
|
|
2602
|
+
[
|
|
2603
|
+
'asciiTheme',
|
|
2604
|
+
scriptFonts.ascii?.theme
|
|
2605
|
+
],
|
|
2606
|
+
[
|
|
2607
|
+
'hAnsiTheme',
|
|
2608
|
+
scriptFonts.highAnsi?.theme
|
|
2609
|
+
],
|
|
2610
|
+
[
|
|
2611
|
+
'eastAsiaTheme',
|
|
2612
|
+
scriptFonts.eastAsia?.theme
|
|
2613
|
+
],
|
|
2614
|
+
[
|
|
2615
|
+
'cstheme',
|
|
2616
|
+
scriptFonts.complexScript?.theme
|
|
2617
|
+
],
|
|
2618
|
+
[
|
|
2619
|
+
'hint',
|
|
2620
|
+
scriptFonts.hint
|
|
2621
|
+
]
|
|
2622
|
+
])if (value) work_docx_format_change_export_setWordAttribute(fonts, namespace, prefix, name, value);
|
|
2623
|
+
properties.append(fonts);
|
|
2624
|
+
return;
|
|
2625
|
+
}
|
|
2233
2626
|
const family = firstFontFamily(mark?.attrs?.fontFamily);
|
|
2234
2627
|
if (!family) return;
|
|
2235
2628
|
const fonts = wordElement(document, namespace, prefix, 'rFonts');
|
|
@@ -2241,14 +2634,41 @@ function appendFontProperties(document, properties, namespace, prefix, mark) {
|
|
|
2241
2634
|
])work_docx_format_change_export_setWordAttribute(fonts, namespace, prefix, name, family);
|
|
2242
2635
|
properties.append(fonts);
|
|
2243
2636
|
}
|
|
2637
|
+
function appendUnderlineProperty(document, properties, namespace, prefix, mark) {
|
|
2638
|
+
if (!mark) return;
|
|
2639
|
+
const style = normalizeDocumentUnderlineStyle(mark.attrs?.underlineStyle) ?? 'single';
|
|
2640
|
+
const color = normalizedHex(mark.attrs?.underlineColor);
|
|
2641
|
+
const theme = themeReference(mark.attrs?.underlineThemeColor);
|
|
2642
|
+
const underline = wordElement(document, namespace, prefix, 'u');
|
|
2643
|
+
work_docx_format_change_export_setWordAttribute(underline, namespace, prefix, 'val', style);
|
|
2644
|
+
const resolved = color ?? normalizedHex(theme?.resolved);
|
|
2645
|
+
if (resolved) work_docx_format_change_export_setWordAttribute(underline, namespace, prefix, 'color', resolved);
|
|
2646
|
+
if (theme) setThemeAttributes(underline, namespace, prefix, theme, 'themeColor');
|
|
2647
|
+
properties.append(underline);
|
|
2648
|
+
}
|
|
2244
2649
|
function appendBooleanProperty(document, properties, namespace, prefix, marks, mark, property) {
|
|
2245
2650
|
if (marks.has(mark)) properties.append(wordElement(document, namespace, prefix, property));
|
|
2246
2651
|
}
|
|
2652
|
+
function appendStrikeProperties(document, properties, namespace, prefix, mark) {
|
|
2653
|
+
if (!mark) return;
|
|
2654
|
+
const style = normalizeDocumentStrikeStyle(mark.attrs?.strikeStyle) ?? 'single';
|
|
2655
|
+
appendValuedProperty(document, properties, namespace, prefix, 'strike', 'single' === style ? '1' : '0');
|
|
2656
|
+
appendValuedProperty(document, properties, namespace, prefix, 'dstrike', 'double' === style ? '1' : '0');
|
|
2657
|
+
}
|
|
2247
2658
|
function appendValuedProperty(document, properties, namespace, prefix, property, value) {
|
|
2248
2659
|
const element = wordElement(document, namespace, prefix, property);
|
|
2249
2660
|
work_docx_format_change_export_setWordAttribute(element, namespace, prefix, 'val', value);
|
|
2250
2661
|
properties.append(element);
|
|
2251
2662
|
}
|
|
2663
|
+
function appendTextCaseProperties(document, properties, namespace, prefix, mark) {
|
|
2664
|
+
const textCase = mark?.attrs?.textCase;
|
|
2665
|
+
if ('all-caps' === textCase) properties.append(wordElement(document, namespace, prefix, 'caps'));
|
|
2666
|
+
else if ('small-caps' === textCase) properties.append(wordElement(document, namespace, prefix, 'smallCaps'));
|
|
2667
|
+
else if ('none' === textCase) {
|
|
2668
|
+
appendValuedProperty(document, properties, namespace, prefix, 'caps', '0');
|
|
2669
|
+
appendValuedProperty(document, properties, namespace, prefix, 'smallCaps', '0');
|
|
2670
|
+
}
|
|
2671
|
+
}
|
|
2252
2672
|
function appendColorProperty(document, properties, namespace, prefix, mark) {
|
|
2253
2673
|
const color = normalizedHex(mark?.attrs?.color);
|
|
2254
2674
|
const theme = themeReference(mark?.attrs?.themeColor);
|
|
@@ -7283,6 +7703,131 @@ function docxParagraphPartPaths(pathsByLower, contentTypes) {
|
|
|
7283
7703
|
function isObfuscatedFontContentType(type) {
|
|
7284
7704
|
return type?.trim().toLowerCase() === 'application/vnd.openxmlformats-officedocument.obfuscatedfont';
|
|
7285
7705
|
}
|
|
7706
|
+
const RUN_FONT_PART_PATTERN = /^word\/(?:document|header\d*|footer\d*|footnotes|endnotes|comments)\.xml$/i;
|
|
7707
|
+
const WORD_FONT_ATTRIBUTE_NAMES = new Set([
|
|
7708
|
+
'ascii',
|
|
7709
|
+
'hAnsi',
|
|
7710
|
+
'eastAsia',
|
|
7711
|
+
'cs',
|
|
7712
|
+
'asciiTheme',
|
|
7713
|
+
'hAnsiTheme',
|
|
7714
|
+
'eastAsiaTheme',
|
|
7715
|
+
'cstheme',
|
|
7716
|
+
'hint'
|
|
7717
|
+
]);
|
|
7718
|
+
class DocxRunFontsPatchCollector {
|
|
7719
|
+
patches = [];
|
|
7720
|
+
nextMarker = 1;
|
|
7721
|
+
occupied;
|
|
7722
|
+
markersByFonts = new Map();
|
|
7723
|
+
constructor(source){
|
|
7724
|
+
this.occupied = source;
|
|
7725
|
+
}
|
|
7726
|
+
marker(source, slot, currentFontFamily) {
|
|
7727
|
+
const fonts = normalizeDocumentScriptFonts(source);
|
|
7728
|
+
const normalizedSlot = normalizeDocumentScriptFontSlot(slot) ?? documentScriptFontSlotFromHint(fonts?.hint);
|
|
7729
|
+
const expected = fonts ? documentScriptFontFamily(fonts, normalizedSlot) : void 0;
|
|
7730
|
+
const current = documentFontNameFromCssFamily(currentFontFamily);
|
|
7731
|
+
if (!fonts || (expected ? documentFontNameFromCssFamily(expected)?.toLocaleLowerCase() !== current?.toLocaleLowerCase() : Boolean(currentFontFamily.trim()))) return null;
|
|
7732
|
+
const key = serializeDocumentScriptFonts(fonts);
|
|
7733
|
+
if (!key) return null;
|
|
7734
|
+
const existing = this.markersByFonts.get(key);
|
|
7735
|
+
if (existing) return existing;
|
|
7736
|
+
let marker = '';
|
|
7737
|
+
do {
|
|
7738
|
+
marker = `A3SOfficeRunFonts${String(this.nextMarker).padStart(8, '0')}`;
|
|
7739
|
+
this.nextMarker += 1;
|
|
7740
|
+
}while (this.occupied.includes(marker) || this.patches.some((patch)=>patch.marker === marker))
|
|
7741
|
+
this.patches.push({
|
|
7742
|
+
marker,
|
|
7743
|
+
fonts
|
|
7744
|
+
});
|
|
7745
|
+
this.markersByFonts.set(key, marker);
|
|
7746
|
+
return marker;
|
|
7747
|
+
}
|
|
7748
|
+
}
|
|
7749
|
+
async function patchDocxRunFonts(buffer, patches) {
|
|
7750
|
+
if (!patches.length) return buffer;
|
|
7751
|
+
const archive = await jszip.loadAsync(buffer);
|
|
7752
|
+
const byMarker = new Map(patches.map((patch)=>[
|
|
7753
|
+
patch.marker,
|
|
7754
|
+
patch.fonts
|
|
7755
|
+
]));
|
|
7756
|
+
const applied = new Set();
|
|
7757
|
+
for (const entry of Object.values(archive.files)){
|
|
7758
|
+
if (entry.dir || !RUN_FONT_PART_PATTERN.test(entry.name)) continue;
|
|
7759
|
+
const document = parseXml(decodeXmlBytes(await entry.async('uint8array'), `generated DOCX ${entry.name}`), `generated DOCX ${entry.name}`);
|
|
7760
|
+
let changedPart = false;
|
|
7761
|
+
for (const element of descendants(document, 'rFonts')){
|
|
7762
|
+
if (!DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '')) continue;
|
|
7763
|
+
const marker = wordFontAttribute(element, 'ascii');
|
|
7764
|
+
if (!marker) continue;
|
|
7765
|
+
const fonts = byMarker.get(marker);
|
|
7766
|
+
if (fonts) {
|
|
7767
|
+
replaceWordFontAttributes(element, fonts);
|
|
7768
|
+
applied.add(marker);
|
|
7769
|
+
changedPart = true;
|
|
7770
|
+
}
|
|
7771
|
+
}
|
|
7772
|
+
if (changedPart) archive.file(entry.name, serializeUtf8Xml(document));
|
|
7773
|
+
}
|
|
7774
|
+
const missing = patches.filter((patch)=>!applied.has(patch.marker));
|
|
7775
|
+
if (missing.length) throw new Error(`DOCX run-font markers were not emitted: ${missing.map((patch)=>patch.marker).join(', ')}.`);
|
|
7776
|
+
return archive.generateAsync({
|
|
7777
|
+
type: 'arraybuffer'
|
|
7778
|
+
});
|
|
7779
|
+
}
|
|
7780
|
+
function replaceWordFontAttributes(element, fonts) {
|
|
7781
|
+
for (const item of Array.from(element.attributes))if (item.namespaceURI !== work_docx_settings_xml_XMLNS_NAMESPACE && WORD_FONT_ATTRIBUTE_NAMES.has(xmlAttributeLocalName(item)) && DOCX_WORDPROCESSING_NAMESPACES.has(xmlAttributeNamespace(element, item) ?? '')) element.removeAttributeNode(item);
|
|
7782
|
+
const values = [
|
|
7783
|
+
[
|
|
7784
|
+
'ascii',
|
|
7785
|
+
fonts.ascii?.name
|
|
7786
|
+
],
|
|
7787
|
+
[
|
|
7788
|
+
'hAnsi',
|
|
7789
|
+
fonts.highAnsi?.name
|
|
7790
|
+
],
|
|
7791
|
+
[
|
|
7792
|
+
'eastAsia',
|
|
7793
|
+
fonts.eastAsia?.name
|
|
7794
|
+
],
|
|
7795
|
+
[
|
|
7796
|
+
'cs',
|
|
7797
|
+
fonts.complexScript?.name
|
|
7798
|
+
],
|
|
7799
|
+
[
|
|
7800
|
+
'asciiTheme',
|
|
7801
|
+
fonts.ascii?.theme
|
|
7802
|
+
],
|
|
7803
|
+
[
|
|
7804
|
+
'hAnsiTheme',
|
|
7805
|
+
fonts.highAnsi?.theme
|
|
7806
|
+
],
|
|
7807
|
+
[
|
|
7808
|
+
'eastAsiaTheme',
|
|
7809
|
+
fonts.eastAsia?.theme
|
|
7810
|
+
],
|
|
7811
|
+
[
|
|
7812
|
+
'cstheme',
|
|
7813
|
+
fonts.complexScript?.theme
|
|
7814
|
+
],
|
|
7815
|
+
[
|
|
7816
|
+
'hint',
|
|
7817
|
+
fonts.hint
|
|
7818
|
+
]
|
|
7819
|
+
];
|
|
7820
|
+
for (const [name, value] of values)if (value) setWordFontAttribute(element, name, value);
|
|
7821
|
+
}
|
|
7822
|
+
function wordFontAttribute(element, name) {
|
|
7823
|
+
const values = Array.from(element.attributes).filter((item)=>xmlAttributeLocalName(item) === name && DOCX_WORDPROCESSING_NAMESPACES.has(xmlAttributeNamespace(element, item) ?? ''));
|
|
7824
|
+
return 1 === values.length ? values[0]?.value ?? null : null;
|
|
7825
|
+
}
|
|
7826
|
+
function setWordFontAttribute(element, name, value) {
|
|
7827
|
+
const namespace = element.namespaceURI ?? '';
|
|
7828
|
+
const prefix = element.prefix || 'w';
|
|
7829
|
+
element.setAttributeNS(namespace, `${prefix}:${name}`, value);
|
|
7830
|
+
}
|
|
7286
7831
|
async function createDocxBlob(content, sourcePackage) {
|
|
7287
7832
|
const docx = await import("docx");
|
|
7288
7833
|
const normalizedContent = {
|
|
@@ -7317,7 +7862,13 @@ async function createDocxBlob(content, sourcePackage) {
|
|
|
7317
7862
|
paragraphIdentityPatches: new DocxParagraphIdentityPatchCollector(JSON.stringify(normalizedContent)),
|
|
7318
7863
|
equationPatches: new DocxEquationPatchCollector(JSON.stringify(normalizedContent)),
|
|
7319
7864
|
formattingChangePatches: new DocxRunFormattingChangePatchCollector(),
|
|
7320
|
-
|
|
7865
|
+
runFontPatches: new DocxRunFontsPatchCollector(JSON.stringify(normalizedContent)),
|
|
7866
|
+
hiddenTextPatches: new DocxHiddenTextPatchCollector(JSON.stringify(normalizedContent)),
|
|
7867
|
+
legacyTextEffectsPatches: new DocxLegacyTextEffectsPatchCollector(JSON.stringify(normalizedContent)),
|
|
7868
|
+
usedNativeTextEffectMarkers: new Set(),
|
|
7869
|
+
paragraphFormattingChangePatches: new DocxParagraphFormattingChangePatchCollector(),
|
|
7870
|
+
hasExplicitZeroCharacterSpacing: false,
|
|
7871
|
+
hasExplicitZeroKerningThreshold: false
|
|
7321
7872
|
};
|
|
7322
7873
|
const commentRecords = createDocxCommentRecords(commentThreads, docx, noteContext.commentIds);
|
|
7323
7874
|
const sections = [];
|
|
@@ -7364,7 +7915,12 @@ async function createDocxBlob(content, sourcePackage) {
|
|
|
7364
7915
|
}
|
|
7365
7916
|
});
|
|
7366
7917
|
const packed = await docx.Packer.toBlob(document);
|
|
7367
|
-
const
|
|
7918
|
+
const characterSpacingPatched = noteContext.hasExplicitZeroCharacterSpacing ? await patchDocxExplicitZeroCharacterSpacing(await packed.arrayBuffer()) : await packed.arrayBuffer();
|
|
7919
|
+
const kerningPatched = noteContext.hasExplicitZeroKerningThreshold ? await patchDocxExplicitZeroKerningThresholds(characterSpacingPatched) : characterSpacingPatched;
|
|
7920
|
+
const runFontsPatched = await patchDocxRunFonts(kerningPatched, noteContext.runFontPatches.patches);
|
|
7921
|
+
const hiddenTextPatched = await patchDocxHiddenText(runFontsPatched, noteContext.hiddenTextPatches.patches.filter((patch)=>noteContext.usedNativeTextEffectMarkers.has(patch.marker)));
|
|
7922
|
+
const legacyTextEffectsPatched = await patchDocxLegacyTextEffects(hiddenTextPatched, noteContext.legacyTextEffectsPatches.patches.filter((patch)=>noteContext.usedNativeTextEffectMarkers.has(patch.marker)));
|
|
7923
|
+
const formattingChangesPatched = await patchDocxRunFormattingChanges(legacyTextEffectsPatched, noteContext.formattingChangePatches.patches);
|
|
7368
7924
|
const noteImageRelationshipsPatched = await patchDocxNoteImageRelationships(formattingChangesPatched);
|
|
7369
7925
|
const commentMetadataPatched = await patchDocxCommentMetadata(noteImageRelationshipsPatched, commentThreads);
|
|
7370
7926
|
const numberingPatched = await patchDocxNumberingRestartRules(commentMetadataPatched, noteContext.numberingRestartRules);
|
|
@@ -7391,6 +7947,60 @@ async function createDocxBlob(content, sourcePackage) {
|
|
|
7391
7947
|
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
|
7392
7948
|
});
|
|
7393
7949
|
}
|
|
7950
|
+
function docxNativeTextEffectState(style, context) {
|
|
7951
|
+
let current = style;
|
|
7952
|
+
let hiddenText;
|
|
7953
|
+
const legacyTextEffects = {};
|
|
7954
|
+
const seen = new Set();
|
|
7955
|
+
while(current && !seen.has(current)){
|
|
7956
|
+
seen.add(current);
|
|
7957
|
+
const hiddenPatch = context.hiddenTextPatches.lookup(current);
|
|
7958
|
+
if (hiddenPatch) {
|
|
7959
|
+
hiddenText ??= hiddenPatch.value;
|
|
7960
|
+
current = hiddenPatch.style;
|
|
7961
|
+
continue;
|
|
7962
|
+
}
|
|
7963
|
+
const legacyPatch = context.legacyTextEffectsPatches.lookup(current);
|
|
7964
|
+
if (legacyPatch) {
|
|
7965
|
+
for (const [name, value] of Object.entries(legacyPatch.effects)){
|
|
7966
|
+
const effect = name;
|
|
7967
|
+
if (void 0 === legacyTextEffects[effect]) legacyTextEffects[effect] = value;
|
|
7968
|
+
}
|
|
7969
|
+
current = legacyPatch.style;
|
|
7970
|
+
continue;
|
|
7971
|
+
}
|
|
7972
|
+
break;
|
|
7973
|
+
}
|
|
7974
|
+
return {
|
|
7975
|
+
...current ? {
|
|
7976
|
+
baseStyle: current
|
|
7977
|
+
} : {},
|
|
7978
|
+
...void 0 !== hiddenText ? {
|
|
7979
|
+
hiddenText
|
|
7980
|
+
} : {},
|
|
7981
|
+
legacyTextEffects
|
|
7982
|
+
};
|
|
7983
|
+
}
|
|
7984
|
+
function markDocxNativeTextEffectStyleUsed(style, context) {
|
|
7985
|
+
let current = style;
|
|
7986
|
+
const seen = new Set();
|
|
7987
|
+
while(current && !seen.has(current)){
|
|
7988
|
+
seen.add(current);
|
|
7989
|
+
const hiddenPatch = context.hiddenTextPatches.lookup(current);
|
|
7990
|
+
if (hiddenPatch) {
|
|
7991
|
+
context.usedNativeTextEffectMarkers.add(current);
|
|
7992
|
+
current = hiddenPatch.style;
|
|
7993
|
+
continue;
|
|
7994
|
+
}
|
|
7995
|
+
const legacyPatch = context.legacyTextEffectsPatches.lookup(current);
|
|
7996
|
+
if (legacyPatch) {
|
|
7997
|
+
context.usedNativeTextEffectMarkers.add(current);
|
|
7998
|
+
current = legacyPatch.style;
|
|
7999
|
+
continue;
|
|
8000
|
+
}
|
|
8001
|
+
break;
|
|
8002
|
+
}
|
|
8003
|
+
}
|
|
7394
8004
|
function work_docx_export_sectionProperties(layout, docx) {
|
|
7395
8005
|
const landscape = 'landscape' === layout.orientation;
|
|
7396
8006
|
const dimensions = documentPageGeometryForLayout(layout);
|
|
@@ -7560,6 +8170,7 @@ async function work_docx_export_inlineRuns(root, docx, noteContext) {
|
|
|
7560
8170
|
const visit = async (node, inherited = {}, revision)=>{
|
|
7561
8171
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
7562
8172
|
if (!node.textContent) return [];
|
|
8173
|
+
markDocxNativeTextEffectStyleUsed(inherited.style, noteContext);
|
|
7563
8174
|
if (revision?.kind === 'insertion') return [
|
|
7564
8175
|
new docx.InsertedTextRun({
|
|
7565
8176
|
...inherited,
|
|
@@ -7624,29 +8235,80 @@ async function work_docx_export_inlineRuns(root, docx, noteContext) {
|
|
|
7624
8235
|
fill: backgroundColor
|
|
7625
8236
|
} : inherited.shading;
|
|
7626
8237
|
const themeFillMarker = noteContext.themePatches.marker('fill', parseDocxThemeReference(node.dataset.officeThemeFill), resolvedShading?.fill ? `#${resolvedShading.fill}` : null);
|
|
8238
|
+
const explicitTextCase = normalizeDocumentTextCase(node.dataset.officeTextCase);
|
|
8239
|
+
const explicitCharacterSpacing = documentCharacterSpacingTwipsFromElement(node);
|
|
8240
|
+
const explicitCharacterScale = documentCharacterScalePercentFromElement(node);
|
|
8241
|
+
const explicitKerningThreshold = documentKerningThresholdHalfPointsFromElement(node);
|
|
8242
|
+
const explicitEmphasisMark = documentEmphasisMarkFromElement(node);
|
|
8243
|
+
const explicitHiddenText = documentHiddenTextFromElement(node);
|
|
8244
|
+
const hasExplicitLegacyTextEffects = 'span' === tag && [
|
|
8245
|
+
DOCUMENT_LEGACY_TEXT_OUTLINE_ATTRIBUTE,
|
|
8246
|
+
DOCUMENT_LEGACY_TEXT_SHADOW_ATTRIBUTE,
|
|
8247
|
+
DOCUMENT_LEGACY_TEXT_EMBOSS_ATTRIBUTE,
|
|
8248
|
+
DOCUMENT_LEGACY_TEXT_IMPRINT_ATTRIBUTE
|
|
8249
|
+
].some((attribute)=>node.hasAttribute(attribute));
|
|
8250
|
+
const explicitLegacyTextEffects = hasExplicitLegacyTextEffects ? documentLegacyTextEffectsFromElement(node) : {};
|
|
8251
|
+
if (hasExplicitLegacyTextEffects && !explicitLegacyTextEffects) throw new Error('Document contains invalid legacy text effects.');
|
|
8252
|
+
const explicitCharacterPosition = documentCharacterPositionHalfPointsFromElement(node);
|
|
8253
|
+
if (0 === explicitCharacterSpacing) noteContext.hasExplicitZeroCharacterSpacing = true;
|
|
8254
|
+
if (0 === explicitKerningThreshold) noteContext.hasExplicitZeroKerningThreshold = true;
|
|
8255
|
+
const characterSpacing = null === explicitCharacterSpacing ? inherited.characterSpacing : docxCharacterSpacingValue(explicitCharacterSpacing);
|
|
8256
|
+
const scale = null === explicitCharacterScale ? inherited.scale : docxCharacterScaleValue(explicitCharacterScale);
|
|
8257
|
+
const kern = null === explicitKerningThreshold ? inherited.kern : docxKerningThresholdValue(explicitKerningThreshold);
|
|
8258
|
+
const position = null === explicitCharacterPosition ? inherited.position : docxCharacterPositionValue(explicitCharacterPosition);
|
|
8259
|
+
const emphasisMark = null === explicitEmphasisMark ? inherited.emphasisMark : docxEmphasisMarkRunOptions(explicitEmphasisMark);
|
|
8260
|
+
const textCaseOptions = docxTextCaseRunOptions(explicitTextCase, inherited);
|
|
8261
|
+
const inheritedNativeTextEffects = docxNativeTextEffectState(inherited.style, noteContext);
|
|
8262
|
+
const legacyTextEffects = {
|
|
8263
|
+
...inheritedNativeTextEffects.legacyTextEffects,
|
|
8264
|
+
...explicitLegacyTextEffects ?? {}
|
|
8265
|
+
};
|
|
8266
|
+
if (documentLegacyTextEffectsConflict(legacyTextEffects)) throw new Error('Document contains conflicting legacy text effects.');
|
|
8267
|
+
const hiddenText = null === explicitHiddenText ? inheritedNativeTextEffects.hiddenText : explicitHiddenText;
|
|
8268
|
+
let nativeTextEffectStyle = inherited.style;
|
|
8269
|
+
if (hasExplicitLegacyTextEffects || null !== explicitHiddenText) {
|
|
8270
|
+
nativeTextEffectStyle = inheritedNativeTextEffects.baseStyle;
|
|
8271
|
+
if (Object.keys(legacyTextEffects).length) nativeTextEffectStyle = noteContext.legacyTextEffectsPatches.marker(legacyTextEffects, nativeTextEffectStyle);
|
|
8272
|
+
if (void 0 !== hiddenText) nativeTextEffectStyle = noteContext.hiddenTextPatches.marker(hiddenText, nativeTextEffectStyle);
|
|
8273
|
+
}
|
|
8274
|
+
const underline = docxUnderlineRunOptions(node, inherited.underline, noteContext.themePatches);
|
|
8275
|
+
const strike = docxStrikeRunOptions(node, inherited);
|
|
8276
|
+
const scriptFontMarker = noteContext.runFontPatches.marker(documentScriptFontsFromElement(node), documentScriptFontSlotFromElement(node), node.style.fontFamily);
|
|
7627
8277
|
const style = {
|
|
7628
8278
|
...inherited,
|
|
8279
|
+
style: nativeTextEffectStyle,
|
|
7629
8280
|
bold: inherited.bold || 'strong' === tag || 'b' === tag,
|
|
7630
8281
|
italics: inherited.italics || 'em' === tag || 'i' === tag,
|
|
7631
|
-
underline
|
|
7632
|
-
strike
|
|
8282
|
+
underline,
|
|
8283
|
+
...strike,
|
|
7633
8284
|
subScript: inherited.subScript || 'sub' === tag,
|
|
7634
8285
|
superScript: inherited.superScript || 'sup' === tag,
|
|
7635
8286
|
color: themeColorMarker ?? resolvedColor,
|
|
7636
|
-
font:
|
|
8287
|
+
font: scriptFontMarker ? {
|
|
8288
|
+
ascii: scriptFontMarker
|
|
8289
|
+
} : cssFontFamily(node.style.fontFamily) ?? inherited.font,
|
|
7637
8290
|
size: cssFontSize(node.style.fontSize) ?? inherited.size,
|
|
8291
|
+
characterSpacing,
|
|
8292
|
+
scale,
|
|
8293
|
+
kern,
|
|
8294
|
+
position,
|
|
8295
|
+
emphasisMark,
|
|
7638
8296
|
shading: themeFillMarker ? {
|
|
7639
8297
|
fill: themeFillMarker
|
|
7640
8298
|
} : resolvedShading,
|
|
7641
8299
|
snapToGrid: dataBoolean(node.dataset.officeWordSnapToGrid) ?? inherited.snapToGrid,
|
|
7642
|
-
rightToLeft: void 0 === direction ? inherited.rightToLeft : 'rtl' === direction
|
|
8300
|
+
rightToLeft: void 0 === direction ? inherited.rightToLeft : 'rtl' === direction,
|
|
8301
|
+
...textCaseOptions
|
|
7643
8302
|
};
|
|
7644
|
-
if ('br' === tag)
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
8303
|
+
if ('br' === tag) {
|
|
8304
|
+
markDocxNativeTextEffectStyleUsed(style.style, noteContext);
|
|
8305
|
+
return [
|
|
8306
|
+
new docx.TextRun({
|
|
8307
|
+
...style,
|
|
8308
|
+
break: 1
|
|
8309
|
+
})
|
|
8310
|
+
];
|
|
8311
|
+
}
|
|
7650
8312
|
if ('img' === tag) return [
|
|
7651
8313
|
await imageToDocx(node, docx, noteContext.imageCropPatches, noteContext.imageWrapPatches, noteContext.imageLayerPatches, noteContext.imageIdentityPatches)
|
|
7652
8314
|
];
|
|
@@ -7692,6 +8354,64 @@ async function work_docx_export_inlineRuns(root, docx, noteContext) {
|
|
|
7692
8354
|
for (const node of root.childNodes)runs.push(...await visit(node, inheritedDirection));
|
|
7693
8355
|
return runs;
|
|
7694
8356
|
}
|
|
8357
|
+
function docxStrikeRunOptions(element, inherited) {
|
|
8358
|
+
if (element.hasAttribute(DOCUMENT_UNDERLINE_STYLE_ATTRIBUTE) && !element.hasAttribute(DOCUMENT_STRIKE_STYLE_ATTRIBUTE)) return {
|
|
8359
|
+
doubleStrike: inherited.doubleStrike,
|
|
8360
|
+
strike: inherited.strike
|
|
8361
|
+
};
|
|
8362
|
+
const formatting = documentStrikeFormattingFromElement(element);
|
|
8363
|
+
if (!formatting) return {
|
|
8364
|
+
doubleStrike: inherited.doubleStrike,
|
|
8365
|
+
strike: inherited.strike
|
|
8366
|
+
};
|
|
8367
|
+
return {
|
|
8368
|
+
doubleStrike: 'double' === formatting.style,
|
|
8369
|
+
strike: 'single' === formatting.style
|
|
8370
|
+
};
|
|
8371
|
+
}
|
|
8372
|
+
function docxUnderlineRunOptions(element, inherited, themePatches) {
|
|
8373
|
+
if (element.hasAttribute(DOCUMENT_STRIKE_STYLE_ATTRIBUTE) && !element.hasAttribute(DOCUMENT_UNDERLINE_STYLE_ATTRIBUTE)) return inherited;
|
|
8374
|
+
const formatting = documentUnderlineFormattingFromElement(element);
|
|
8375
|
+
if (!formatting) return inherited;
|
|
8376
|
+
const color = docxUnderlineColor(formatting, themePatches);
|
|
8377
|
+
return {
|
|
8378
|
+
type: formatting.style,
|
|
8379
|
+
...color ? {
|
|
8380
|
+
color
|
|
8381
|
+
} : {}
|
|
8382
|
+
};
|
|
8383
|
+
}
|
|
8384
|
+
function docxUnderlineColor(formatting, themePatches) {
|
|
8385
|
+
const direct = formatting.color ? cssColorToHex(formatting.color) : void 0;
|
|
8386
|
+
return themePatches.marker('underline', formatting.themeColor ?? null, direct ? `#${direct}` : null) ?? direct;
|
|
8387
|
+
}
|
|
8388
|
+
function docxTextCaseRunOptions(explicitTextCase, inherited) {
|
|
8389
|
+
if (null === explicitTextCase) {
|
|
8390
|
+
if (void 0 !== inherited.smallCaps) return {
|
|
8391
|
+
allCaps: void 0,
|
|
8392
|
+
smallCaps: inherited.smallCaps
|
|
8393
|
+
};
|
|
8394
|
+
return void 0 === inherited.allCaps ? {} : {
|
|
8395
|
+
allCaps: inherited.allCaps,
|
|
8396
|
+
smallCaps: void 0
|
|
8397
|
+
};
|
|
8398
|
+
}
|
|
8399
|
+
if ('all-caps' === explicitTextCase) return {
|
|
8400
|
+
allCaps: true,
|
|
8401
|
+
smallCaps: void 0
|
|
8402
|
+
};
|
|
8403
|
+
if ('small-caps' === explicitTextCase) return {
|
|
8404
|
+
allCaps: void 0,
|
|
8405
|
+
smallCaps: true
|
|
8406
|
+
};
|
|
8407
|
+
return inherited.smallCaps ? {
|
|
8408
|
+
allCaps: void 0,
|
|
8409
|
+
smallCaps: false
|
|
8410
|
+
} : {
|
|
8411
|
+
allCaps: false,
|
|
8412
|
+
smallCaps: void 0
|
|
8413
|
+
};
|
|
8414
|
+
}
|
|
7695
8415
|
function docxTextRevision(element, kind, context) {
|
|
7696
8416
|
const id = docxRevisionId(element, context);
|
|
7697
8417
|
const sourceDate = element.dataset.changeDate?.trim() ?? '';
|