@a3s-lab/office 0.46.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/{0~2133.js → 0~3320.js} +1252 -830
- package/dist/{0~4042.js → 0~3534.js} +510 -4
- package/dist/0~document-editor.js +4065 -3775
- package/dist/0~work-docx-export.js +417 -669
- package/dist/0~work-docx-import.js +56 -9
- package/dist/0~work-office-diagnostics.js +26 -8
- package/dist/4174.js +18815 -18200
- 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-document-field-node.d.ts +2 -2
- package/dist/internal/features/work/work-document-fields.d.ts +36 -2
- package/dist/internal/features/work/work-docx-bookmark-import.d.ts +1 -1
- 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-field-import.d.ts +5 -1
- package/dist/internal/features/work/work-docx-import.d.ts +4 -2
- package/dist/styles.css +125 -0
- package/package.json +6 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import jszip from "jszip";
|
|
2
2
|
import { normalizeDocumentIndexEntryDraft, serializeUtf8Xml, directChildren, xmlNamespacePrefix, normalizeDocumentLanguageTag, parseXml, firstDescendant, decodeXmlBytes, directChild, descendants, normalizeDocumentProofingLanguages, attribute as work_ooxml_package_attribute, normalizeDocumentIndexOptions } from "./6968.js";
|
|
3
3
|
import { normalizeDocumentEmphasisMark, normalizeDocumentCharacterScalePercent, documentCitationStyle, normalizeDocumentCharacterPositionHalfPoints, normalizeDocumentCharacterSpacingTwips, normalizeDocumentKerningThresholdHalfPoints, normalizeDocumentOpenTypeNumberSpacing, createDocumentBibliography, normalizeDocumentImageTransform, normalizeDocumentOpenTypeLigatures, normalizeDocumentOpenTypeNumberForm, normalizeDocumentTabStops, documentCitationStyleDetails, normalizeDocumentOpenTypeStylisticSets } from "./4174.js";
|
|
4
|
+
import { normalizeDocumentHref } from "./0~work-document-links.js";
|
|
4
5
|
const BIBLIOGRAPHY_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/bibliography';
|
|
5
6
|
const CUSTOM_XML_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/customXml';
|
|
6
7
|
const OFFICE_RELATIONSHIPS_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
|
|
@@ -708,6 +709,511 @@ function isAllowedExtensionNamespace(namespace, context) {
|
|
|
708
709
|
function isNamespacePrefix(value) {
|
|
709
710
|
return /^[A-Za-z_][A-Za-z0-9_.-]*$/.test(value) && 'xml' !== value;
|
|
710
711
|
}
|
|
712
|
+
const PACKAGE_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/package/2006/relationships';
|
|
713
|
+
const TRANSITIONAL_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
|
|
714
|
+
const STRICT_RELATIONSHIP_NAMESPACE = 'http://purl.oclc.org/ooxml/officeDocument/relationships';
|
|
715
|
+
const work_docx_note_comment_hyperlink_relationships_RELATIONSHIP_NAMESPACES = new Set([
|
|
716
|
+
TRANSITIONAL_RELATIONSHIP_NAMESPACE,
|
|
717
|
+
STRICT_RELATIONSHIP_NAMESPACE
|
|
718
|
+
]);
|
|
719
|
+
const HYPERLINK_RELATIONSHIP_TYPES = new Set([
|
|
720
|
+
`${TRANSITIONAL_RELATIONSHIP_NAMESPACE}/hyperlink`,
|
|
721
|
+
`${STRICT_RELATIONSHIP_NAMESPACE}/hyperlink`
|
|
722
|
+
]);
|
|
723
|
+
const GENERATED_HYPERLINK_RELATIONSHIP_TYPE = `${TRANSITIONAL_RELATIONSHIP_NAMESPACE}/hyperlink`;
|
|
724
|
+
const RELATIONSHIP_ID_PATTERN = /^[A-Za-z_][A-Za-z0-9_.-]{0,254}$/;
|
|
725
|
+
const MAX_RELATIONSHIPS = 65536;
|
|
726
|
+
async function loadDocxHyperlinkRelationshipState(generatedArchive, sourceArchive, ownerPart) {
|
|
727
|
+
const path = work_docx_note_comment_hyperlink_relationships_relationshipPartPath(ownerPart);
|
|
728
|
+
const [generated, source] = await Promise.all([
|
|
729
|
+
loadRelationships(generatedArchive, path, 'generated'),
|
|
730
|
+
loadRelationships(sourceArchive, path, 'source')
|
|
731
|
+
]);
|
|
732
|
+
return {
|
|
733
|
+
archive: generatedArchive,
|
|
734
|
+
dirty: false,
|
|
735
|
+
generated: generated.document,
|
|
736
|
+
generatedMalformed: generated.malformed,
|
|
737
|
+
path,
|
|
738
|
+
source: source.document
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
function readDocxHyperlinkDestination(hyperlink, state, role) {
|
|
742
|
+
if (!DOCX_WORDPROCESSING_NAMESPACES.has(hyperlink.namespaceURI ?? '')) return null;
|
|
743
|
+
const anchor = uniqueNamespacedAttribute(hyperlink, 'anchor', DOCX_WORDPROCESSING_NAMESPACES);
|
|
744
|
+
const relationshipId = uniqueNamespacedAttribute(hyperlink, 'id', work_docx_note_comment_hyperlink_relationships_RELATIONSHIP_NAMESPACES);
|
|
745
|
+
if (void 0 === anchor || void 0 === relationshipId) return null;
|
|
746
|
+
const normalizedAnchor = null === anchor ? null : normalizeAnchor(anchor);
|
|
747
|
+
if (null !== anchor && !normalizedAnchor) return null;
|
|
748
|
+
if (normalizedAnchor && relationshipId) return null;
|
|
749
|
+
if (normalizedAnchor) return {
|
|
750
|
+
kind: 'internal',
|
|
751
|
+
target: normalizedAnchor
|
|
752
|
+
};
|
|
753
|
+
if (!relationshipId || !RELATIONSHIP_ID_PATTERN.test(relationshipId)) return null;
|
|
754
|
+
const relationships = 'generated' === role ? state.generated : state.source;
|
|
755
|
+
const relationship = relationships?.byId.get(relationshipId);
|
|
756
|
+
if (!relationship || !isExternalHyperlinkRelationship(relationship)) return null;
|
|
757
|
+
const target = normalizeDocumentHref(relationship.target);
|
|
758
|
+
if (!target || target.startsWith('#')) return null;
|
|
759
|
+
return {
|
|
760
|
+
kind: 'external',
|
|
761
|
+
relationshipId,
|
|
762
|
+
target
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
function ensureDocxExternalHyperlinkRelationships(state, requests) {
|
|
766
|
+
if (!requests.length) return [];
|
|
767
|
+
if (state.generatedMalformed) return null;
|
|
768
|
+
const relationships = state.generated ?? createRelationshipsDocument();
|
|
769
|
+
const usedIds = new Set(relationships.usedIds);
|
|
770
|
+
const idByTarget = new Map(Array.from(relationships.byId.values()).flatMap((item)=>{
|
|
771
|
+
const target = isExternalHyperlinkRelationship(item) ? normalizeDocumentHref(item.target) : null;
|
|
772
|
+
return target && !target.startsWith('#') ? [
|
|
773
|
+
[
|
|
774
|
+
target,
|
|
775
|
+
item.id
|
|
776
|
+
]
|
|
777
|
+
] : [];
|
|
778
|
+
}));
|
|
779
|
+
const pending = [];
|
|
780
|
+
const result = [];
|
|
781
|
+
for (const request of requests){
|
|
782
|
+
if (!RELATIONSHIP_ID_PATTERN.test(request.sourceId)) return null;
|
|
783
|
+
const target = normalizeDocumentHref(request.target);
|
|
784
|
+
if (!target || target.startsWith('#')) return null;
|
|
785
|
+
const existingId = idByTarget.get(target);
|
|
786
|
+
if (existingId) {
|
|
787
|
+
result.push(existingId);
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
if (usedIds.size >= MAX_RELATIONSHIPS) return null;
|
|
791
|
+
const id = usedIds.has(request.sourceId) ? work_docx_note_comment_hyperlink_relationships_nextRelationshipId(usedIds) : request.sourceId;
|
|
792
|
+
usedIds.add(id);
|
|
793
|
+
idByTarget.set(target, id);
|
|
794
|
+
pending.push({
|
|
795
|
+
id,
|
|
796
|
+
target
|
|
797
|
+
});
|
|
798
|
+
result.push(id);
|
|
799
|
+
}
|
|
800
|
+
if (!pending.length) return result;
|
|
801
|
+
state.generated = relationships;
|
|
802
|
+
for (const item of pending)appendExternalHyperlinkRelationship(relationships, item.id, item.target);
|
|
803
|
+
state.dirty = true;
|
|
804
|
+
return result;
|
|
805
|
+
}
|
|
806
|
+
function setDocxHyperlinkDestination(hyperlink, root, destination, relationshipId) {
|
|
807
|
+
removeNamespacedAttribute(hyperlink, 'anchor', DOCX_WORDPROCESSING_NAMESPACES);
|
|
808
|
+
removeNamespacedAttribute(hyperlink, 'id', work_docx_note_comment_hyperlink_relationships_RELATIONSHIP_NAMESPACES);
|
|
809
|
+
if ('internal' === destination.kind) {
|
|
810
|
+
const namespace = hyperlink.namespaceURI;
|
|
811
|
+
if (!namespace || !DOCX_WORDPROCESSING_NAMESPACES.has(namespace)) return false;
|
|
812
|
+
setNamespacedAttribute(hyperlink, root, namespace, 'w', 'anchor', destination.target);
|
|
813
|
+
return true;
|
|
814
|
+
}
|
|
815
|
+
if (!relationshipId || !RELATIONSHIP_ID_PATTERN.test(relationshipId)) return false;
|
|
816
|
+
setNamespacedAttribute(hyperlink, root, TRANSITIONAL_RELATIONSHIP_NAMESPACE, 'r', 'id', relationshipId);
|
|
817
|
+
return true;
|
|
818
|
+
}
|
|
819
|
+
function flushDocxHyperlinkRelationships(state) {
|
|
820
|
+
if (!state.dirty || !state.generated) return;
|
|
821
|
+
state.archive.file(state.path, serializeUtf8Xml(state.generated.document));
|
|
822
|
+
}
|
|
823
|
+
function normalizeAnchor(value) {
|
|
824
|
+
const anchor = value.trim();
|
|
825
|
+
return anchor.length <= 255 && normalizeDocumentHref(`#${anchor}`) ? anchor : null;
|
|
826
|
+
}
|
|
827
|
+
function isExternalHyperlinkRelationship(relationship) {
|
|
828
|
+
return HYPERLINK_RELATIONSHIP_TYPES.has(relationship.type) && 'external' === relationship.targetMode.toLowerCase();
|
|
829
|
+
}
|
|
830
|
+
async function loadRelationships(archive, path, role) {
|
|
831
|
+
const entry = archive.file(path);
|
|
832
|
+
if (!entry) return {
|
|
833
|
+
document: null,
|
|
834
|
+
malformed: false
|
|
835
|
+
};
|
|
836
|
+
try {
|
|
837
|
+
const document = parseXml(decodeXmlBytes(await entry.async('uint8array'), `${role} DOCX ${path}`), `${role} DOCX ${path}`);
|
|
838
|
+
const root = document.documentElement;
|
|
839
|
+
if ('Relationships' !== root.localName || root.namespaceURI !== PACKAGE_RELATIONSHIP_NAMESPACE) return {
|
|
840
|
+
document: null,
|
|
841
|
+
malformed: true
|
|
842
|
+
};
|
|
843
|
+
const byId = new Map();
|
|
844
|
+
const usedIds = new Set();
|
|
845
|
+
const elements = directChildren(root);
|
|
846
|
+
if (elements.length > MAX_RELATIONSHIPS) return {
|
|
847
|
+
document: null,
|
|
848
|
+
malformed: true
|
|
849
|
+
};
|
|
850
|
+
for (const element of elements){
|
|
851
|
+
if ('Relationship' !== element.localName || element.namespaceURI !== PACKAGE_RELATIONSHIP_NAMESPACE) return {
|
|
852
|
+
document: null,
|
|
853
|
+
malformed: true
|
|
854
|
+
};
|
|
855
|
+
const record = relationshipRecord(element);
|
|
856
|
+
if (!record || usedIds.has(record.id)) return {
|
|
857
|
+
document: null,
|
|
858
|
+
malformed: true
|
|
859
|
+
};
|
|
860
|
+
byId.set(record.id, record);
|
|
861
|
+
usedIds.add(record.id);
|
|
862
|
+
}
|
|
863
|
+
return {
|
|
864
|
+
document: {
|
|
865
|
+
byId,
|
|
866
|
+
document,
|
|
867
|
+
usedIds
|
|
868
|
+
},
|
|
869
|
+
malformed: false
|
|
870
|
+
};
|
|
871
|
+
} catch {
|
|
872
|
+
return {
|
|
873
|
+
document: null,
|
|
874
|
+
malformed: true
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
function relationshipRecord(element) {
|
|
879
|
+
const id = element.getAttribute('Id')?.trim() ?? '';
|
|
880
|
+
const target = element.getAttribute('Target')?.trim() ?? '';
|
|
881
|
+
const type = element.getAttribute('Type')?.trim() ?? '';
|
|
882
|
+
const targetMode = element.getAttribute('TargetMode')?.trim() ?? '';
|
|
883
|
+
if (!RELATIONSHIP_ID_PATTERN.test(id) || !target || !type) return null;
|
|
884
|
+
return {
|
|
885
|
+
id,
|
|
886
|
+
target,
|
|
887
|
+
targetMode,
|
|
888
|
+
type
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
function createRelationshipsDocument() {
|
|
892
|
+
const document = parseXml(`<Relationships xmlns="${PACKAGE_RELATIONSHIP_NAMESPACE}"/>`, 'generated DOCX hyperlink relationships');
|
|
893
|
+
return {
|
|
894
|
+
byId: new Map(),
|
|
895
|
+
document,
|
|
896
|
+
usedIds: new Set()
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
function appendExternalHyperlinkRelationship(relationships, id, target) {
|
|
900
|
+
const element = relationships.document.createElementNS(PACKAGE_RELATIONSHIP_NAMESPACE, 'Relationship');
|
|
901
|
+
element.setAttribute('Id', id);
|
|
902
|
+
element.setAttribute('Type', GENERATED_HYPERLINK_RELATIONSHIP_TYPE);
|
|
903
|
+
element.setAttribute('Target', target);
|
|
904
|
+
element.setAttribute('TargetMode', 'External');
|
|
905
|
+
relationships.document.documentElement.append(element);
|
|
906
|
+
relationships.byId.set(id, {
|
|
907
|
+
id,
|
|
908
|
+
target,
|
|
909
|
+
targetMode: 'External',
|
|
910
|
+
type: GENERATED_HYPERLINK_RELATIONSHIP_TYPE
|
|
911
|
+
});
|
|
912
|
+
relationships.usedIds.add(id);
|
|
913
|
+
}
|
|
914
|
+
function uniqueNamespacedAttribute(element, localName, namespaces) {
|
|
915
|
+
const matches = Array.from(element.attributes).filter((item)=>xmlAttributeLocalName(item) === localName && namespaces.has(xmlAttributeNamespace(element, item) ?? ''));
|
|
916
|
+
return matches.length <= 1 ? matches[0]?.value.trim() ?? null : void 0;
|
|
917
|
+
}
|
|
918
|
+
function removeNamespacedAttribute(element, localName, namespaces) {
|
|
919
|
+
for (const item of Array.from(element.attributes))if (xmlAttributeLocalName(item) === localName && namespaces.has(xmlAttributeNamespace(element, item) ?? '')) element.removeAttributeNode(item);
|
|
920
|
+
}
|
|
921
|
+
function setNamespacedAttribute(element, root, namespace, preferredPrefix, localName, value) {
|
|
922
|
+
let prefix = xmlDeclaredPrefix(element, namespace) ?? xmlDeclaredPrefix(root, namespace);
|
|
923
|
+
if (!prefix) {
|
|
924
|
+
prefix = availablePrefix(root, preferredPrefix);
|
|
925
|
+
root.setAttributeNS(XMLNS_NAMESPACE, `xmlns:${prefix}`, namespace);
|
|
926
|
+
}
|
|
927
|
+
element.setAttributeNS(namespace, `${prefix}:${localName}`, value);
|
|
928
|
+
}
|
|
929
|
+
function availablePrefix(root, preferred) {
|
|
930
|
+
if (!xmlNamespaceUri(root, preferred)) return preferred;
|
|
931
|
+
let index = 1;
|
|
932
|
+
while(xmlNamespaceUri(root, `${preferred}${index}`))index += 1;
|
|
933
|
+
return `${preferred}${index}`;
|
|
934
|
+
}
|
|
935
|
+
function work_docx_note_comment_hyperlink_relationships_nextRelationshipId(used) {
|
|
936
|
+
let index = 1;
|
|
937
|
+
while(used.has(`rId${index}`))index += 1;
|
|
938
|
+
return `rId${index}`;
|
|
939
|
+
}
|
|
940
|
+
function work_docx_note_comment_hyperlink_relationships_relationshipPartPath(ownerPart) {
|
|
941
|
+
const separator = ownerPart.lastIndexOf('/');
|
|
942
|
+
const directory = separator < 0 ? '' : ownerPart.slice(0, separator + 1);
|
|
943
|
+
const file = ownerPart.slice(separator + 1);
|
|
944
|
+
return `${directory}_rels/${file}.rels`;
|
|
945
|
+
}
|
|
946
|
+
const work_docx_note_comment_hyperlink_content_MARKUP_COMPATIBILITY_NAMESPACE = 'http://schemas.openxmlformats.org/markup-compatibility/2006';
|
|
947
|
+
const MAX_PARAGRAPHS = 65536;
|
|
948
|
+
const MAX_RUNS = 262144;
|
|
949
|
+
const MAX_COMMENT_RUN_SEGMENTS = 4096;
|
|
950
|
+
function noteCommentContentParagraphs(scope, role, relationships, limits) {
|
|
951
|
+
const paragraphs = descendants(scope, 'p').filter(isWordElement);
|
|
952
|
+
const paragraphKey = `${role}Paragraphs`;
|
|
953
|
+
limits[paragraphKey] += paragraphs.length;
|
|
954
|
+
if (limits[paragraphKey] > MAX_PARAGRAPHS) throw new Error(`${roleLabel(role)} DOCX exceeds the stable note/comment hyperlink paragraph limit.`);
|
|
955
|
+
const result = [];
|
|
956
|
+
for (const paragraph of paragraphs){
|
|
957
|
+
const runKey = `${role}Runs`;
|
|
958
|
+
limits[runKey] += directContentRunCount(paragraph);
|
|
959
|
+
if (limits[runKey] > MAX_RUNS) throw new Error(`${roleLabel(role)} DOCX exceeds the stable note/comment hyperlink run limit.`);
|
|
960
|
+
const content = noteCommentParagraphContent(paragraph, relationships, role);
|
|
961
|
+
if (!content?.text) continue;
|
|
962
|
+
const ancestry = paragraphAncestry(paragraph, scope);
|
|
963
|
+
if (ancestry) result.push({
|
|
964
|
+
element: paragraph,
|
|
965
|
+
hyperlinks: content.hyperlinks,
|
|
966
|
+
identity: `${ancestry}\u0000${content.text}`,
|
|
967
|
+
runs: content.runs,
|
|
968
|
+
text: content.text
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
return result;
|
|
972
|
+
}
|
|
973
|
+
function directContentRunCount(paragraph) {
|
|
974
|
+
let count = 0;
|
|
975
|
+
for (const child of Array.from(paragraph.children))if (isWordElement(child)) {
|
|
976
|
+
if ('r' === child.localName) count += 1;
|
|
977
|
+
if ('hyperlink' === child.localName) count += wordDirectChildren(child, 'r').length;
|
|
978
|
+
}
|
|
979
|
+
return count;
|
|
980
|
+
}
|
|
981
|
+
function noteCommentParagraphContent(paragraph, relationships, role) {
|
|
982
|
+
const runs = [];
|
|
983
|
+
const hyperlinks = [];
|
|
984
|
+
let offset = 0;
|
|
985
|
+
let paragraphProperties = 0;
|
|
986
|
+
for (const child of Array.from(paragraph.children)){
|
|
987
|
+
if (!isWordElement(child)) {
|
|
988
|
+
if (isContentSemanticNamespace(child.namespaceURI ?? '')) return null;
|
|
989
|
+
continue;
|
|
990
|
+
}
|
|
991
|
+
if ('pPr' === child.localName) {
|
|
992
|
+
paragraphProperties += 1;
|
|
993
|
+
if (paragraphProperties > 1) return null;
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
996
|
+
if ('r' === child.localName) {
|
|
997
|
+
const text = contentRunText(child);
|
|
998
|
+
if (null === text) return null;
|
|
999
|
+
const start = offset;
|
|
1000
|
+
offset += text.length;
|
|
1001
|
+
if (text) runs.push({
|
|
1002
|
+
container: null,
|
|
1003
|
+
element: child,
|
|
1004
|
+
start,
|
|
1005
|
+
end: offset,
|
|
1006
|
+
text
|
|
1007
|
+
});
|
|
1008
|
+
continue;
|
|
1009
|
+
}
|
|
1010
|
+
if ('hyperlink' !== child.localName) return null;
|
|
1011
|
+
const start = offset;
|
|
1012
|
+
for (const hyperlinkChild of Array.from(child.children)){
|
|
1013
|
+
if (!isWordElement(hyperlinkChild)) {
|
|
1014
|
+
if (isContentSemanticNamespace(hyperlinkChild.namespaceURI ?? '')) return null;
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
if ('r' !== hyperlinkChild.localName) return null;
|
|
1018
|
+
const text = contentRunText(hyperlinkChild);
|
|
1019
|
+
if (null === text) return null;
|
|
1020
|
+
const runStart = offset;
|
|
1021
|
+
offset += text.length;
|
|
1022
|
+
if (text) runs.push({
|
|
1023
|
+
container: child,
|
|
1024
|
+
element: hyperlinkChild,
|
|
1025
|
+
start: runStart,
|
|
1026
|
+
end: offset,
|
|
1027
|
+
text
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
if (offset > start) hyperlinks.push({
|
|
1031
|
+
destination: readDocxHyperlinkDestination(child, relationships, role),
|
|
1032
|
+
element: child,
|
|
1033
|
+
start,
|
|
1034
|
+
end: offset,
|
|
1035
|
+
text: runs.filter((run)=>run.container === child).map((run)=>run.text).join('')
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
return {
|
|
1039
|
+
hyperlinks,
|
|
1040
|
+
runs,
|
|
1041
|
+
text: runs.map((run)=>run.text).join('')
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
function groupNoteCommentParagraphs(paragraphs) {
|
|
1045
|
+
const result = new Map();
|
|
1046
|
+
for (const paragraph of paragraphs){
|
|
1047
|
+
const matches = result.get(paragraph.identity) ?? [];
|
|
1048
|
+
matches.push(paragraph);
|
|
1049
|
+
result.set(paragraph.identity, matches);
|
|
1050
|
+
}
|
|
1051
|
+
return result;
|
|
1052
|
+
}
|
|
1053
|
+
function groupNoteCommentHyperlinks(hyperlinks) {
|
|
1054
|
+
const result = new Map();
|
|
1055
|
+
for (const hyperlink of hyperlinks){
|
|
1056
|
+
const key = noteCommentHyperlinkSpanKey(hyperlink);
|
|
1057
|
+
const matches = result.get(key) ?? [];
|
|
1058
|
+
matches.push(hyperlink);
|
|
1059
|
+
result.set(key, matches);
|
|
1060
|
+
}
|
|
1061
|
+
return result;
|
|
1062
|
+
}
|
|
1063
|
+
function noteCommentHyperlinkSpanKey(item) {
|
|
1064
|
+
return `${item.start}:${item.end}:${item.text}`;
|
|
1065
|
+
}
|
|
1066
|
+
function noteCommentHyperlinksOverlap(left, right) {
|
|
1067
|
+
return left.start < right.end && right.start < left.end;
|
|
1068
|
+
}
|
|
1069
|
+
function restoreElementChildren(element, children) {
|
|
1070
|
+
while(element.firstChild)element.removeChild(element.firstChild);
|
|
1071
|
+
for (const child of children)element.append(child);
|
|
1072
|
+
}
|
|
1073
|
+
function alignCommentRunBoundaries(generated, source) {
|
|
1074
|
+
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;
|
|
1075
|
+
const original = generated.runs[0].element;
|
|
1076
|
+
if (!original.parentNode) return false;
|
|
1077
|
+
const clones = [];
|
|
1078
|
+
for (const sourceRun of source.runs){
|
|
1079
|
+
const clone = original.cloneNode(true);
|
|
1080
|
+
const textElement = wordDirectChildren(clone, 't')[0];
|
|
1081
|
+
if (!textElement) return false;
|
|
1082
|
+
textElement.textContent = sourceRun.text;
|
|
1083
|
+
setTextSpacePreservation(textElement, sourceRun.text);
|
|
1084
|
+
clones.push(clone);
|
|
1085
|
+
}
|
|
1086
|
+
for (const clone of clones)original.parentNode.insertBefore(clone, original);
|
|
1087
|
+
original.remove();
|
|
1088
|
+
return true;
|
|
1089
|
+
}
|
|
1090
|
+
function isKnownOoxmlNamespace(namespace) {
|
|
1091
|
+
if (namespace === work_docx_note_comment_hyperlink_content_MARKUP_COMPATIBILITY_NAMESPACE) return false;
|
|
1092
|
+
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:');
|
|
1093
|
+
}
|
|
1094
|
+
function contentRunText(run) {
|
|
1095
|
+
let text = '';
|
|
1096
|
+
for (const child of Array.from(run.children)){
|
|
1097
|
+
if (!isWordElement(child)) {
|
|
1098
|
+
if (isContentSemanticNamespace(child.namespaceURI ?? '')) return null;
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
if ('rPr' !== child.localName) {
|
|
1102
|
+
if ('t' === child.localName || 'delText' === child.localName) text += child.textContent ?? '';
|
|
1103
|
+
else if ('tab' === child.localName) text += '\t';
|
|
1104
|
+
else if ('br' === child.localName || 'cr' === child.localName) text += '\n';
|
|
1105
|
+
else if ('noBreakHyphen' === child.localName) text += '\u2011';
|
|
1106
|
+
else if ('softHyphen' === child.localName) text += '\u00ad';
|
|
1107
|
+
else if ('footnoteRef' !== child.localName && 'endnoteRef' !== child.localName) return null;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
return text;
|
|
1111
|
+
}
|
|
1112
|
+
function isSimpleTextRun(run) {
|
|
1113
|
+
const children = Array.from(run.children).filter(isWordElement);
|
|
1114
|
+
return 1 === children.filter((child)=>'t' === child.localName).length && children.every((child)=>'rPr' === child.localName || 't' === child.localName);
|
|
1115
|
+
}
|
|
1116
|
+
function setTextSpacePreservation(element, text) {
|
|
1117
|
+
for (const item of Array.from(element.attributes))if ('space' === xmlAttributeLocalName(item) && xmlAttributeNamespace(element, item) === XML_NAMESPACE) element.removeAttributeNode(item);
|
|
1118
|
+
if (/^\s|\s$/u.test(text)) element.setAttributeNS(XML_NAMESPACE, 'xml:space', 'preserve');
|
|
1119
|
+
}
|
|
1120
|
+
function paragraphAncestry(paragraph, scope) {
|
|
1121
|
+
const path = [];
|
|
1122
|
+
let current = paragraph;
|
|
1123
|
+
while(current && current !== scope){
|
|
1124
|
+
if (!isWordElement(current)) return null;
|
|
1125
|
+
path.push(current.localName);
|
|
1126
|
+
current = current.parentElement;
|
|
1127
|
+
}
|
|
1128
|
+
return current === scope ? path.reverse().join('/') : null;
|
|
1129
|
+
}
|
|
1130
|
+
function isContentSemanticNamespace(namespace) {
|
|
1131
|
+
return namespace === work_docx_note_comment_hyperlink_content_MARKUP_COMPATIBILITY_NAMESPACE || isKnownOoxmlNamespace(namespace);
|
|
1132
|
+
}
|
|
1133
|
+
function wordDirectChildren(element, localName) {
|
|
1134
|
+
return Array.from(element.children).filter((child)=>child.localName === localName && isWordElement(child));
|
|
1135
|
+
}
|
|
1136
|
+
function isWordElement(element) {
|
|
1137
|
+
return DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '');
|
|
1138
|
+
}
|
|
1139
|
+
function roleLabel(role) {
|
|
1140
|
+
return 'source' === role ? 'Registered source' : 'Generated';
|
|
1141
|
+
}
|
|
1142
|
+
const CONTENT_CONTROL_MC_NAMESPACE = 'http://schemas.openxmlformats.org/markup-compatibility/2006';
|
|
1143
|
+
const CONTENT_CONTROL_RELATIONSHIP_NAMESPACES = new Set([
|
|
1144
|
+
'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
|
|
1145
|
+
'http://purl.oclc.org/ooxml/officeDocument/relationships'
|
|
1146
|
+
]);
|
|
1147
|
+
const CONTENT_CONTROL_WORD_2012_NAMESPACE = 'http://schemas.microsoft.com/office/word/2012/wordml';
|
|
1148
|
+
function isContentControlSemanticNamespace(namespace) {
|
|
1149
|
+
return namespace === CONTENT_CONTROL_MC_NAMESPACE || CONTENT_CONTROL_RELATIONSHIP_NAMESPACES.has(namespace) || isKnownOoxmlNamespace(namespace);
|
|
1150
|
+
}
|
|
1151
|
+
function isDocxWordElement(element) {
|
|
1152
|
+
return DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '');
|
|
1153
|
+
}
|
|
1154
|
+
function work_docx_note_comment_content_control_xml_wordDirectChildren(element, localName) {
|
|
1155
|
+
return Array.from(element.children).filter((child)=>child.localName === localName && isDocxWordElement(child));
|
|
1156
|
+
}
|
|
1157
|
+
function hasOnlyPassiveContentControlAttributes(element) {
|
|
1158
|
+
return Array.from(element.attributes).every((item)=>{
|
|
1159
|
+
const namespace = xmlAttributeNamespace(element, item);
|
|
1160
|
+
return Boolean(namespace === XMLNS_NAMESPACE || namespace === CONTENT_CONTROL_MC_NAMESPACE || namespace && !CONTENT_CONTROL_RELATIONSHIP_NAMESPACES.has(namespace) && !isKnownOoxmlNamespace(namespace));
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
function hasUnsupportedContentControlSemanticChild(element) {
|
|
1164
|
+
return Array.from(element.children).some((child)=>!isDocxWordElement(child) && isContentControlSemanticNamespace(child.namespaceURI ?? ''));
|
|
1165
|
+
}
|
|
1166
|
+
function hasContentControlRelationshipReference(root) {
|
|
1167
|
+
return [
|
|
1168
|
+
root,
|
|
1169
|
+
...Array.from(root.querySelectorAll('*'))
|
|
1170
|
+
].some((element)=>Array.from(element.attributes).some((item)=>CONTENT_CONTROL_RELATIONSHIP_NAMESPACES.has(xmlAttributeNamespace(element, item) ?? '')));
|
|
1171
|
+
}
|
|
1172
|
+
function createWordElement(document, context, localName) {
|
|
1173
|
+
const namespace = context.namespaceURI ?? [
|
|
1174
|
+
...DOCX_WORDPROCESSING_NAMESPACES
|
|
1175
|
+
][0];
|
|
1176
|
+
const prefix = xmlNamespacePrefix(context, namespace) ?? 'w';
|
|
1177
|
+
return document.createElementNS(namespace, `${prefix}:${localName}`);
|
|
1178
|
+
}
|
|
1179
|
+
function createNamespacedElement(document, context, namespace, preferredPrefix, localName) {
|
|
1180
|
+
const prefix = availableNamespacePrefix(context.ownerDocument.documentElement, namespace, preferredPrefix);
|
|
1181
|
+
return document.createElementNS(namespace, `${prefix}:${localName}`);
|
|
1182
|
+
}
|
|
1183
|
+
function setWordContentControlAttribute(element, context, localName, value) {
|
|
1184
|
+
const namespace = context.namespaceURI ?? [
|
|
1185
|
+
...DOCX_WORDPROCESSING_NAMESPACES
|
|
1186
|
+
][0];
|
|
1187
|
+
const prefix = xmlNamespacePrefix(context, namespace) ?? 'w';
|
|
1188
|
+
element.setAttributeNS(namespace, `${prefix}:${localName}`, value);
|
|
1189
|
+
}
|
|
1190
|
+
function setNamespacedContentControlAttribute(element, context, namespace, preferredPrefix, localName, value) {
|
|
1191
|
+
const prefix = availableNamespacePrefix(context.ownerDocument.documentElement, namespace, preferredPrefix);
|
|
1192
|
+
element.setAttributeNS(namespace, `${prefix}:${localName}`, value);
|
|
1193
|
+
}
|
|
1194
|
+
function ensureIgnorableContentControlNamespace(root, namespace, preferredPrefix) {
|
|
1195
|
+
const prefix = availableNamespacePrefix(root, namespace, preferredPrefix);
|
|
1196
|
+
if (!xmlNamespacePrefix(root, namespace)) root.setAttributeNS(XMLNS_NAMESPACE, `xmlns:${prefix}`, namespace);
|
|
1197
|
+
const mcPrefix = availableNamespacePrefix(root, CONTENT_CONTROL_MC_NAMESPACE, 'mc');
|
|
1198
|
+
if (!xmlNamespacePrefix(root, CONTENT_CONTROL_MC_NAMESPACE)) root.setAttributeNS(XMLNS_NAMESPACE, `xmlns:${mcPrefix}`, CONTENT_CONTROL_MC_NAMESPACE);
|
|
1199
|
+
const existing = Array.from(root.attributes).find((item)=>'Ignorable' === xmlAttributeLocalName(item) && xmlAttributeNamespace(root, item) === CONTENT_CONTROL_MC_NAMESPACE);
|
|
1200
|
+
const prefixes = new Set((existing?.value ?? '').trim().split(/\s+/u).filter(Boolean));
|
|
1201
|
+
prefixes.add(prefix);
|
|
1202
|
+
const value = Array.from(prefixes).join(' ');
|
|
1203
|
+
if (existing) existing.value = value;
|
|
1204
|
+
else root.setAttributeNS(CONTENT_CONTROL_MC_NAMESPACE, `${mcPrefix}:Ignorable`, value);
|
|
1205
|
+
}
|
|
1206
|
+
function availableNamespacePrefix(root, namespace, preferred) {
|
|
1207
|
+
const existing = xmlNamespacePrefix(root, namespace);
|
|
1208
|
+
if (existing) return existing;
|
|
1209
|
+
let prefix = preferred;
|
|
1210
|
+
let index = 1;
|
|
1211
|
+
while(xmlNamespaceUri(root, prefix)){
|
|
1212
|
+
prefix = `${preferred}${index}`;
|
|
1213
|
+
index += 1;
|
|
1214
|
+
}
|
|
1215
|
+
return prefix;
|
|
1216
|
+
}
|
|
711
1217
|
const DOCX_ROTATION_UNITS_PER_DEGREE = 60000;
|
|
712
1218
|
const DOCX_QUADRANT_ROTATION_UNITS = 5400000;
|
|
713
1219
|
function readDocxImageTransform(drawing) {
|
|
@@ -1718,7 +2224,7 @@ function inspectDocxProofingLanguages(properties) {
|
|
|
1718
2224
|
status: 'absent',
|
|
1719
2225
|
spoofedCount: 0
|
|
1720
2226
|
};
|
|
1721
|
-
const native = matches.filter((element)=>
|
|
2227
|
+
const native = matches.filter((element)=>work_docx_proofing_isWordElement(element));
|
|
1722
2228
|
const spoofedCount = matches.length - native.length;
|
|
1723
2229
|
if (1 !== matches.length || 1 !== native.length) return {
|
|
1724
2230
|
status: 'invalid',
|
|
@@ -1764,7 +2270,7 @@ function inspectDocxNoProof(properties) {
|
|
|
1764
2270
|
status: 'absent',
|
|
1765
2271
|
spoofedCount: 0
|
|
1766
2272
|
};
|
|
1767
|
-
const native = matches.filter((element)=>
|
|
2273
|
+
const native = matches.filter((element)=>work_docx_proofing_isWordElement(element));
|
|
1768
2274
|
const spoofedCount = matches.length - native.length;
|
|
1769
2275
|
if (1 !== matches.length || 1 !== native.length) return {
|
|
1770
2276
|
status: 'invalid',
|
|
@@ -1835,7 +2341,7 @@ function documentProofingLanguageDocxOptions(source) {
|
|
|
1835
2341
|
} : {}
|
|
1836
2342
|
};
|
|
1837
2343
|
}
|
|
1838
|
-
function
|
|
2344
|
+
function work_docx_proofing_isWordElement(element) {
|
|
1839
2345
|
return DOCX_WORDPROCESSING_NAMESPACES.has(element.namespaceURI ?? '');
|
|
1840
2346
|
}
|
|
1841
2347
|
function work_docx_proofing_isNamespaceDeclaration(attribute) {
|
|
@@ -2180,4 +2686,4 @@ function isParagraphPartRoot(root, path) {
|
|
|
2180
2686
|
const expected = /^word\/header\d*\.xml$/i.test(path) ? 'hdr' : /^word\/footer\d*\.xml$/i.test(path) ? 'ftr' : /^word\/footnotes\.xml$/i.test(path) ? 'footnotes' : /^word\/endnotes\.xml$/i.test(path) ? 'endnotes' : 'document';
|
|
2181
2687
|
return root.localName === expected && DOCX_WORDPROCESSING_NAMESPACES.has(root.namespaceURI ?? '');
|
|
2182
2688
|
}
|
|
2183
|
-
export { DOCX_COLOR_SCHEME_MAPPING_ATTRIBUTES, DOCX_WORDPROCESSING_NAMESPACES, DOCX_WORD_2010_NAMESPACE, DocxImageTransformPatchCollector, DocxParagraphDefaultCollapsedPatchCollector, STRICT_WORDPROCESSING_NAMESPACE, XMLNS_NAMESPACE, XML_NAMESPACE, assertXmlRoot, cloneXmlElement, createDocxThemeResolver, cssColorToHex, cssFontFamily, cssFontSize, dataBoolean, documentIndexEntryInstruction, documentIndexInstruction, documentProofingLanguageDocxOptions, docxCharacterPositionHalfPointsFromProperties, docxCharacterPositionValue, docxCharacterScalePercentFromProperties, docxCharacterScaleValue, docxCharacterSpacingTwipsFromProperties, docxCharacterSpacingValue, docxEmphasisMarkRunOptions, docxKerningThresholdValue, docxThemeColor, docxThemeFont, domDirection, hasNonWhitespaceXmlText, inspectDocxEmphasisMark, inspectDocxKerningThresholdHalfPoints, inspectDocxNoProof, inspectDocxProofingLanguages, mergeDocxIgnorableExtensions, mergeDocxIgnorableExtensionsAtPairs, paragraphAlignment, paragraphBidirectional, paragraphDirectionOptions, paragraphIndent, paragraphPaginationOptions, paragraphSpacingOptions, paragraphTabStops, parseBoundedDocxInteger, parseDocumentIndexEntryInstruction, parseDocumentIndexInstruction, parseDocxColorSchemeMappingElement, parseDocxParagraphDefaultCollapsed, parseDocxTwipsMeasure, patchDocxBibliography, patchDocxExplicitZeroCharacterSpacing, patchDocxExplicitZeroKerningThresholds, patchDocxImageTransforms, patchDocxParagraphDefaultCollapsed, readDocxBibliography, readDocxImageTransform, resolveDocxEmphasisMark, resolveDocxKerningThresholdHalfPoints, resolveDocxOpenTypeFeatures, resolveDocxProofing, resolveDocxThemeResolver, xmlAttributeLocalName, xmlAttributeNamespace, xmlDeclaredPrefix, xmlNamespaceUri };
|
|
2689
|
+
export { CONTENT_CONTROL_MC_NAMESPACE, CONTENT_CONTROL_RELATIONSHIP_NAMESPACES, CONTENT_CONTROL_WORD_2012_NAMESPACE, DOCX_COLOR_SCHEME_MAPPING_ATTRIBUTES, DOCX_WORDPROCESSING_NAMESPACES, DOCX_WORD_2010_NAMESPACE, DocxImageTransformPatchCollector, DocxParagraphDefaultCollapsedPatchCollector, STRICT_WORDPROCESSING_NAMESPACE, XMLNS_NAMESPACE, XML_NAMESPACE, alignCommentRunBoundaries, assertXmlRoot, cloneXmlElement, createDocxThemeResolver, createNamespacedElement, createWordElement, cssColorToHex, cssFontFamily, cssFontSize, dataBoolean, documentIndexEntryInstruction, documentIndexInstruction, documentProofingLanguageDocxOptions, docxCharacterPositionHalfPointsFromProperties, docxCharacterPositionValue, docxCharacterScalePercentFromProperties, docxCharacterScaleValue, docxCharacterSpacingTwipsFromProperties, docxCharacterSpacingValue, docxEmphasisMarkRunOptions, docxKerningThresholdValue, docxThemeColor, docxThemeFont, domDirection, ensureDocxExternalHyperlinkRelationships, ensureIgnorableContentControlNamespace, flushDocxHyperlinkRelationships, groupNoteCommentHyperlinks, groupNoteCommentParagraphs, hasContentControlRelationshipReference, hasNonWhitespaceXmlText, hasOnlyPassiveContentControlAttributes, hasUnsupportedContentControlSemanticChild, inspectDocxEmphasisMark, inspectDocxKerningThresholdHalfPoints, inspectDocxNoProof, inspectDocxProofingLanguages, isContentControlSemanticNamespace, isDocxWordElement, isKnownOoxmlNamespace, loadDocxHyperlinkRelationshipState, mergeDocxIgnorableExtensions, mergeDocxIgnorableExtensionsAtPairs, noteCommentContentParagraphs, noteCommentHyperlinkSpanKey, noteCommentHyperlinksOverlap, noteCommentParagraphContent, paragraphAlignment, paragraphBidirectional, paragraphDirectionOptions, paragraphIndent, paragraphPaginationOptions, paragraphSpacingOptions, paragraphTabStops, parseBoundedDocxInteger, parseDocumentIndexEntryInstruction, parseDocumentIndexInstruction, parseDocxColorSchemeMappingElement, parseDocxParagraphDefaultCollapsed, parseDocxTwipsMeasure, patchDocxBibliography, patchDocxExplicitZeroCharacterSpacing, patchDocxExplicitZeroKerningThresholds, patchDocxImageTransforms, patchDocxParagraphDefaultCollapsed, readDocxBibliography, readDocxImageTransform, resolveDocxEmphasisMark, resolveDocxKerningThresholdHalfPoints, resolveDocxOpenTypeFeatures, resolveDocxProofing, resolveDocxThemeResolver, restoreElementChildren, setDocxHyperlinkDestination, setNamespacedContentControlAttribute, setWordContentControlAttribute, work_docx_note_comment_content_control_xml_wordDirectChildren, xmlAttributeLocalName, xmlAttributeNamespace, xmlDeclaredPrefix, xmlNamespaceUri };
|