@file-viewer/renderer-word 3.0.0 → 3.0.1
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/dist/docxChart.d.ts +4 -0
- package/dist/docxChart.js +149 -0
- package/dist/wordDocx.js +58 -22
- package/package.json +3 -3
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
type DOMParserConstructor = new () => DOMParser;
|
|
2
|
+
export declare const collectDocxChartSeriesNames: (buffer: ArrayBuffer, DOMParserCtor: DOMParserConstructor) => Promise<string[][]>;
|
|
3
|
+
export declare const applyDocxChartSeriesNames: (buffer: ArrayBuffer, target: HTMLDivElement) => Promise<void>;
|
|
4
|
+
export {};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import JSZip from 'jszip';
|
|
2
|
+
const localName = (node) => {
|
|
3
|
+
const name = node.localName || node.nodeName;
|
|
4
|
+
return name.split(':').pop() || name;
|
|
5
|
+
};
|
|
6
|
+
const elementsByLocal = (node, name) => {
|
|
7
|
+
const result = [];
|
|
8
|
+
const visit = (current) => {
|
|
9
|
+
childElements(current).forEach((child) => {
|
|
10
|
+
if (localName(child) === name) {
|
|
11
|
+
result.push(child);
|
|
12
|
+
}
|
|
13
|
+
visit(child);
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
if (node) {
|
|
17
|
+
visit(node);
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
const childElements = (node) => {
|
|
22
|
+
return node
|
|
23
|
+
? Array.from(node.childNodes).filter((child) => child.nodeType === 1)
|
|
24
|
+
: [];
|
|
25
|
+
};
|
|
26
|
+
const firstChildByLocal = (node, name) => {
|
|
27
|
+
return childElements(node).find((child) => localName(child) === name);
|
|
28
|
+
};
|
|
29
|
+
const relationshipId = (element) => {
|
|
30
|
+
return (element.getAttribute('r:id') ||
|
|
31
|
+
element.getAttributeNS('http://schemas.openxmlformats.org/officeDocument/2006/relationships', 'id') ||
|
|
32
|
+
'');
|
|
33
|
+
};
|
|
34
|
+
const resolvePartPath = (sourcePart, target) => {
|
|
35
|
+
const sourceDirectory = sourcePart.slice(0, Math.max(0, sourcePart.lastIndexOf('/')));
|
|
36
|
+
const parts = (target.startsWith('/') ? target.slice(1) : `${sourceDirectory}/${target}`).split('/');
|
|
37
|
+
const normalized = [];
|
|
38
|
+
for (const part of parts) {
|
|
39
|
+
if (!part || part === '.') {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (part === '..') {
|
|
43
|
+
normalized.pop();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
normalized.push(part);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return normalized.join('/');
|
|
50
|
+
};
|
|
51
|
+
const readXml = async (zip, path, DOMParserCtor) => {
|
|
52
|
+
const file = zip.file(path);
|
|
53
|
+
if (!file) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return new DOMParserCtor().parseFromString(await file.async('text'), 'application/xml');
|
|
57
|
+
};
|
|
58
|
+
const extractSeriesName = (series) => {
|
|
59
|
+
var _a, _b;
|
|
60
|
+
const tx = firstChildByLocal(series, 'tx');
|
|
61
|
+
if (!tx) {
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
const points = elementsByLocal(tx, 'pt')
|
|
65
|
+
.map((point) => {
|
|
66
|
+
var _a, _b;
|
|
67
|
+
return ({
|
|
68
|
+
index: Number(point.getAttribute('idx')) || 0,
|
|
69
|
+
value: ((_b = (_a = firstChildByLocal(point, 'v')) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim()) || ''
|
|
70
|
+
});
|
|
71
|
+
})
|
|
72
|
+
.sort((left, right) => left.index - right.index)
|
|
73
|
+
.map((point) => point.value)
|
|
74
|
+
.filter(Boolean);
|
|
75
|
+
if (points.length) {
|
|
76
|
+
return points.join(' ');
|
|
77
|
+
}
|
|
78
|
+
const richText = elementsByLocal(tx, 't')
|
|
79
|
+
.map((text) => { var _a; return ((_a = text.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || ''; })
|
|
80
|
+
.filter(Boolean)
|
|
81
|
+
.join(' ');
|
|
82
|
+
if (richText) {
|
|
83
|
+
return richText;
|
|
84
|
+
}
|
|
85
|
+
return ((_b = (_a = elementsByLocal(tx, 'v')[0]) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim()) || '';
|
|
86
|
+
};
|
|
87
|
+
export const collectDocxChartSeriesNames = async (buffer, DOMParserCtor) => {
|
|
88
|
+
const zip = await JSZip.loadAsync(buffer);
|
|
89
|
+
const documentPart = 'word/document.xml';
|
|
90
|
+
const [documentXml, relationshipsXml] = await Promise.all([
|
|
91
|
+
readXml(zip, documentPart, DOMParserCtor),
|
|
92
|
+
readXml(zip, 'word/_rels/document.xml.rels', DOMParserCtor)
|
|
93
|
+
]);
|
|
94
|
+
if (!documentXml || !relationshipsXml) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
const relationships = new Map(elementsByLocal(relationshipsXml.documentElement, 'Relationship').map((relationship) => [
|
|
98
|
+
relationship.getAttribute('Id') || '',
|
|
99
|
+
{
|
|
100
|
+
target: relationship.getAttribute('Target') || '',
|
|
101
|
+
type: relationship.getAttribute('Type') || ''
|
|
102
|
+
}
|
|
103
|
+
]));
|
|
104
|
+
const chartParts = elementsByLocal(documentXml.documentElement, 'chart').flatMap((chart) => {
|
|
105
|
+
const relationship = relationships.get(relationshipId(chart));
|
|
106
|
+
if (!(relationship === null || relationship === void 0 ? void 0 : relationship.target) || !relationship.type.endsWith('/chart')) {
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
return [resolvePartPath(documentPart, relationship.target)];
|
|
110
|
+
});
|
|
111
|
+
return Promise.all(chartParts.map(async (chartPart) => {
|
|
112
|
+
const chartXml = await readXml(zip, chartPart, DOMParserCtor);
|
|
113
|
+
return chartXml ? elementsByLocal(chartXml.documentElement, 'ser').map(extractSeriesName) : [];
|
|
114
|
+
}));
|
|
115
|
+
};
|
|
116
|
+
export const applyDocxChartSeriesNames = async (buffer, target) => {
|
|
117
|
+
var _a;
|
|
118
|
+
const charts = Array.from(target.querySelectorAll('.docx-chart'));
|
|
119
|
+
const hasFallbackLegend = charts.some((chart) => /Series\s+\d+/.test(chart.textContent || ''));
|
|
120
|
+
if (!hasFallbackLegend) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const DOMParserCtor = ((_a = target.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.DOMParser) || globalThis.DOMParser;
|
|
124
|
+
if (!DOMParserCtor) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const namesByChart = await collectDocxChartSeriesNames(buffer, DOMParserCtor);
|
|
129
|
+
charts.forEach((chart, chartIndex) => {
|
|
130
|
+
var _a;
|
|
131
|
+
const names = ((_a = namesByChart[chartIndex]) === null || _a === void 0 ? void 0 : _a.filter(Boolean)) || [];
|
|
132
|
+
if (!names.length) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
chart.dataset.chartSeriesNames = JSON.stringify(names);
|
|
136
|
+
const textElements = Array.from(chart.querySelectorAll('text'));
|
|
137
|
+
names.forEach((name, seriesIndex) => {
|
|
138
|
+
const fallback = `Series ${seriesIndex + 1}`;
|
|
139
|
+
const legend = textElements.find((text) => { var _a; return ((_a = text.textContent) === null || _a === void 0 ? void 0 : _a.trim()) === fallback; });
|
|
140
|
+
if (legend) {
|
|
141
|
+
legend.textContent = name;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.warn('[file-viewer] DOCX 图表系列名修复失败,保留基础图表结果。', error);
|
|
148
|
+
}
|
|
149
|
+
};
|
package/dist/wordDocx.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import JSZip from 'jszip';
|
|
2
2
|
import { resolveFileViewerDocxWorkerJsZipUrl, resolveFileViewerDocxWorkerUrl, resolveFileViewerRuntimeAssetBaseUrl, } from '@file-viewer/core/assets';
|
|
3
|
-
import { applyPrintPageSize, buildPrintPageStyle, createFileViewerTranslator, createFileViewerZoomChangeEmitter as createZoomChangeEmitter, formatCssPixels, getElementPrintPageSize, normalizeFileViewerTheme, registerFileViewerZoomProvider, resolveFileViewerFitScale, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
|
|
3
|
+
import { applyPrintPageSize, buildPrintPageStyle, createFileViewerTranslator, createFileViewerZoomChangeEmitter as createZoomChangeEmitter, formatCssPixels, getElementPrintPageSize, normalizeFileViewerTheme, replaceFileViewerCanvasWithImages, registerFileViewerZoomProvider, resolveFileViewerFitScale, unregisterFileViewerZoomProvider, waitForFileViewerNextPaint, } from '@file-viewer/core';
|
|
4
4
|
const DOCX_DEFAULT_PAGE_SIZE = {
|
|
5
5
|
width: 794,
|
|
6
6
|
height: 1123
|
|
@@ -628,6 +628,9 @@ function getDocxPageElement(frame) {
|
|
|
628
628
|
function isDocxFlowFrame(frame) {
|
|
629
629
|
return !!(frame === null || frame === void 0 ? void 0 : frame.classList.contains('docx-flow-frame'));
|
|
630
630
|
}
|
|
631
|
+
function isDocxCanvasSheet(frame) {
|
|
632
|
+
return !!(frame === null || frame === void 0 ? void 0 : frame.classList.contains('docx-canvas-sheet'));
|
|
633
|
+
}
|
|
631
634
|
function getDocxFramePrintSize(frame) {
|
|
632
635
|
const page = frame ? getDocxPageElement(frame) : null;
|
|
633
636
|
if (!page) {
|
|
@@ -643,6 +646,17 @@ function getDocxFramePrintSize(frame) {
|
|
|
643
646
|
};
|
|
644
647
|
}
|
|
645
648
|
function normalizeDocxPageForPrint(frame, pageSize) {
|
|
649
|
+
var _a;
|
|
650
|
+
if (isDocxCanvasSheet(frame)) {
|
|
651
|
+
applyPrintPageSize(frame, pageSize);
|
|
652
|
+
(_a = frame.dataset).viewerPrintPageIndex || (_a.viewerPrintPageIndex = '0');
|
|
653
|
+
frame.classList.remove('docx-canvas-sheet-pending', 'docx-canvas-sheet-virtualized');
|
|
654
|
+
frame.style.position = 'relative';
|
|
655
|
+
frame.style.contain = 'none';
|
|
656
|
+
frame.style.margin = '0 auto 18px';
|
|
657
|
+
frame.style.boxShadow = 'none';
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
646
660
|
const flowLayout = isDocxFlowFrame(frame);
|
|
647
661
|
const pageWidth = formatCssPixels(pageSize.width);
|
|
648
662
|
const pageHeight = formatCssPixels(pageSize.height);
|
|
@@ -666,11 +680,13 @@ function normalizeDocxPageForPrint(frame, pageSize) {
|
|
|
666
680
|
page.style.boxShadow = 'none';
|
|
667
681
|
}
|
|
668
682
|
function buildDocxPrintStyle(target) {
|
|
669
|
-
const firstFrame = target.querySelector('.docx-page-frame, .docx-flow-frame');
|
|
683
|
+
const firstFrame = target.querySelector('.docx-page-frame, .docx-flow-frame, .docx-canvas-sheet');
|
|
670
684
|
const pageSize = getDocxFramePrintSize(firstFrame || undefined);
|
|
671
|
-
const selector = (firstFrame
|
|
672
|
-
? '.viewer-export-content .docx-
|
|
673
|
-
:
|
|
685
|
+
const selector = isDocxCanvasSheet(firstFrame || undefined)
|
|
686
|
+
? '.viewer-export-content .docx-canvas-sheet'
|
|
687
|
+
: (firstFrame === null || firstFrame === void 0 ? void 0 : firstFrame.classList.contains('docx-flow-frame'))
|
|
688
|
+
? '.viewer-export-content .docx-flow-frame'
|
|
689
|
+
: '.viewer-export-content .docx-page-frame';
|
|
674
690
|
return buildPrintPageStyle({
|
|
675
691
|
selector,
|
|
676
692
|
width: pageSize.width,
|
|
@@ -680,21 +696,41 @@ function buildDocxPrintStyle(target) {
|
|
|
680
696
|
heightMode: (firstFrame === null || firstFrame === void 0 ? void 0 : firstFrame.classList.contains('docx-flow-frame')) ? 'min' : 'fixed'
|
|
681
697
|
});
|
|
682
698
|
}
|
|
683
|
-
function prepareDocxCloneForExport(target) {
|
|
684
|
-
const
|
|
685
|
-
const
|
|
686
|
-
const
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
.
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
699
|
+
async function prepareDocxCloneForExport(target) {
|
|
700
|
+
const view = getTargetWindow(target);
|
|
701
|
+
const usesVirtualCanvas = !!target.querySelector('.docx-canvas-sheet');
|
|
702
|
+
const materializeAllPages = view === null || view === void 0 ? void 0 : view.__docxCanvasMaterializeAllPages;
|
|
703
|
+
let materializedForSnapshot = false;
|
|
704
|
+
if (usesVirtualCanvas && typeof materializeAllPages === 'function') {
|
|
705
|
+
await materializeAllPages.call(view, 'file-viewer-print-snapshot');
|
|
706
|
+
await waitForFileViewerNextPaint(view);
|
|
707
|
+
materializedForSnapshot = true;
|
|
708
|
+
}
|
|
709
|
+
try {
|
|
710
|
+
const selector = '.docx-page-frame, .docx-flow-frame, .docx-canvas-sheet';
|
|
711
|
+
const liveFrames = Array.from(target.querySelectorAll(selector));
|
|
712
|
+
const clone = target.cloneNode(true);
|
|
713
|
+
replaceFileViewerCanvasWithImages(target, clone);
|
|
714
|
+
const printDocument = target.ownerDocument.createElement('div');
|
|
715
|
+
printDocument.className = 'docx-print-document';
|
|
716
|
+
const scopedStyles = Array.from(clone.querySelectorAll('style'))
|
|
717
|
+
.filter(style => { var _a; return !((_a = style.textContent) === null || _a === void 0 ? void 0 : _a.includes('.docx-fit-viewer')); })
|
|
718
|
+
.map(style => style.outerHTML)
|
|
719
|
+
.join('');
|
|
720
|
+
clone.querySelectorAll(selector).forEach((frame, index) => {
|
|
721
|
+
frame.dataset.viewerPrintPageIndex = String(index);
|
|
722
|
+
normalizeDocxPageForPrint(frame, getDocxFramePrintSize(liveFrames[index]));
|
|
723
|
+
printDocument.appendChild(frame.cloneNode(true));
|
|
724
|
+
});
|
|
725
|
+
return printDocument.childElementCount ? `${scopedStyles}${printDocument.outerHTML}` : clone.innerHTML;
|
|
726
|
+
}
|
|
727
|
+
finally {
|
|
728
|
+
if (materializedForSnapshot && view) {
|
|
729
|
+
const afterPrint = target.ownerDocument.createEvent('Event');
|
|
730
|
+
afterPrint.initEvent('afterprint', false, false);
|
|
731
|
+
view.dispatchEvent(afterPrint);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
698
734
|
}
|
|
699
735
|
/**
|
|
700
736
|
* 渲染docx文件
|
|
@@ -731,7 +767,7 @@ export default async function (buffer, target, context) {
|
|
|
731
767
|
const disposeResponsive = makeDocxResponsive(target, context);
|
|
732
768
|
(_a = context === null || context === void 0 ? void 0 : context.registerExportAdapter) === null || _a === void 0 ? void 0 : _a.call(context, {
|
|
733
769
|
includeDocumentStyles: false,
|
|
734
|
-
getPrintMaskPages: () => Array.from(target.querySelectorAll('.docx-page-frame, .docx-flow-frame')),
|
|
770
|
+
getPrintMaskPages: () => Array.from(target.querySelectorAll('.docx-page-frame, .docx-flow-frame, .docx-canvas-sheet')),
|
|
735
771
|
beforeSnapshot: () => {
|
|
736
772
|
const view = getTargetWindow(target);
|
|
737
773
|
if (view) {
|
|
@@ -742,7 +778,7 @@ export default async function (buffer, target, context) {
|
|
|
742
778
|
toHtml: () => prepareDocxCloneForExport(target)
|
|
743
779
|
});
|
|
744
780
|
(_b = context === null || context === void 0 ? void 0 : context.registerThumbnailAdapter) === null || _b === void 0 ? void 0 : _b.call(context, {
|
|
745
|
-
getTarget: () => target.querySelector('.docx-page-frame, .docx-flow-frame') || target
|
|
781
|
+
getTarget: () => target.querySelector('.docx-page-frame, .docx-flow-frame, .docx-canvas-sheet') || target
|
|
746
782
|
});
|
|
747
783
|
return {
|
|
748
784
|
$el: target,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/renderer-word",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone DOCX, DOC, and OpenDocument renderer for File Viewer; RTF parsing is an explicit opt-in capability.",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"LICENSE"
|
|
59
59
|
],
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@file-viewer/core": "3.0.
|
|
62
|
-
"@file-viewer/doc": "3.0.
|
|
61
|
+
"@file-viewer/core": "3.0.1",
|
|
62
|
+
"@file-viewer/doc": "3.0.1",
|
|
63
63
|
"@file-viewer/docx": "0.3.28",
|
|
64
64
|
"jszip": "^3.10.1"
|
|
65
65
|
},
|