@file-viewer/renderer-word 2.2.4 → 2.2.6
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/wordDocx.d.ts +14 -1
- package/dist/wordDocx.js +168 -5
- package/package.json +3 -3
package/dist/wordDocx.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { Options, renderAsync } from '@file-viewer/docx';
|
|
2
|
-
import { type FileRenderContext, type FileViewerRenderedInstance as AppWrapper } from '@file-viewer/core';
|
|
2
|
+
import { type FileRenderContext, type FileViewerDocxOptions, type FileViewerRenderedInstance as AppWrapper } from '@file-viewer/core';
|
|
3
3
|
type DocxRenderAsync = typeof renderAsync;
|
|
4
|
+
type DocxExternalLinkPolicy = NonNullable<FileViewerDocxOptions['externalLinkPolicy']>;
|
|
5
|
+
type DocxRenderOptions = Partial<Options> & {
|
|
6
|
+
externalLinkPolicy: DocxExternalLinkPolicy;
|
|
7
|
+
};
|
|
4
8
|
export declare const isMissingDocxHeaderFooterRootError: (error: unknown) => boolean;
|
|
5
9
|
/**
|
|
6
10
|
* Some malformed or partially generated DOCX files reference a header/footer
|
|
@@ -9,6 +13,15 @@ export declare const isMissingDocxHeaderFooterRootError: (error: unknown) => boo
|
|
|
9
13
|
* rolls through lockfiles and private registries.
|
|
10
14
|
*/
|
|
11
15
|
export declare const renderDocxWithHeaderFooterFallback: (render: DocxRenderAsync, buffer: ArrayBuffer, target: HTMLDivElement, options: Options) => Promise<boolean>;
|
|
16
|
+
/**
|
|
17
|
+
* WPS and Word can store a page background as a document-level VML fill. The
|
|
18
|
+
* DOCX engine intentionally ignores that legacy drawing node, so resolve only
|
|
19
|
+
* its package-local image relationship here and leave all body layout to it.
|
|
20
|
+
*/
|
|
21
|
+
export declare const resolveDocxPageBackgroundImage: (buffer: ArrayBuffer, createXmlParser?: () => Pick<DOMParser, "parseFromString">) => Promise<string | undefined>;
|
|
22
|
+
export declare const applyDocxPageBackgroundImage: (target: HTMLDivElement, imageUrl: string | undefined) => number;
|
|
23
|
+
export declare const applyDocxExternalLinkPolicy: (target: Pick<ParentNode, "querySelectorAll">, policy: DocxExternalLinkPolicy) => number;
|
|
24
|
+
export declare const createDocxOptions: (target: HTMLDivElement, context: FileRenderContext | undefined, notifyProgressiveRender: () => void) => DocxRenderOptions;
|
|
12
25
|
/**
|
|
13
26
|
* 渲染docx文件
|
|
14
27
|
*/
|
package/dist/wordDocx.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import JSZip from 'jszip';
|
|
1
2
|
import { resolveFileViewerDocxWorkerJsZipUrl, resolveFileViewerDocxWorkerUrl, resolveFileViewerRuntimeAssetBaseUrl, } from '@file-viewer/core/assets';
|
|
2
3
|
import { applyPrintPageSize, buildPrintPageStyle, createFileViewerTranslator, createFileViewerZoomChangeEmitter as createZoomChangeEmitter, formatCssPixels, getElementPrintPageSize, normalizeFileViewerTheme, registerFileViewerZoomProvider, resolveFileViewerFitScale, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
|
|
3
4
|
const DOCX_DEFAULT_PAGE_SIZE = {
|
|
@@ -10,6 +11,24 @@ const DOCX_MAX_SCALE = 3;
|
|
|
10
11
|
const DOCX_ZOOM_STEP = 0.15;
|
|
11
12
|
const DOCX_VENDOR_ASSET_VERSION = '0.3.26';
|
|
12
13
|
const ZIP_SIGNATURE_PK = 0x504b;
|
|
14
|
+
const WORDPROCESSINGML_NAMESPACE = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
|
|
15
|
+
const OFFICE_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
|
|
16
|
+
const PACKAGE_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/package/2006/relationships';
|
|
17
|
+
const VML_NAMESPACE = 'urn:schemas-microsoft-com:vml';
|
|
18
|
+
const DOCX_DOCUMENT_PART = 'word/document.xml';
|
|
19
|
+
const DOCX_DOCUMENT_RELATIONSHIPS_PART = 'word/_rels/document.xml.rels';
|
|
20
|
+
const DOCX_PAGE_BACKGROUND_CLASS = 'docx-page-background';
|
|
21
|
+
const DOCX_BACKGROUND_MIME_TYPES = {
|
|
22
|
+
bmp: 'image/bmp',
|
|
23
|
+
gif: 'image/gif',
|
|
24
|
+
jpeg: 'image/jpeg',
|
|
25
|
+
jpg: 'image/jpeg',
|
|
26
|
+
png: 'image/png',
|
|
27
|
+
svg: 'image/svg+xml',
|
|
28
|
+
tif: 'image/tiff',
|
|
29
|
+
tiff: 'image/tiff',
|
|
30
|
+
webp: 'image/webp'
|
|
31
|
+
};
|
|
13
32
|
// Modern bundlers expose the ESM named exports, while some legacy webpack
|
|
14
33
|
// configurations wrap the CommonJS browser API in `default`.
|
|
15
34
|
const resolveDocxLibrary = (module) => {
|
|
@@ -79,6 +98,11 @@ const assertValidDocxPackage = (buffer, context) => {
|
|
|
79
98
|
const getTargetWindow = (target) => {
|
|
80
99
|
return target.ownerDocument.defaultView;
|
|
81
100
|
};
|
|
101
|
+
const createTargetXmlParser = (target) => {
|
|
102
|
+
var _a, _b;
|
|
103
|
+
const DOMParserCtor = (_b = (_a = getTargetWindow(target)) === null || _a === void 0 ? void 0 : _a.DOMParser) !== null && _b !== void 0 ? _b : globalThis.DOMParser;
|
|
104
|
+
return new DOMParserCtor();
|
|
105
|
+
};
|
|
82
106
|
const getTargetProtocol = (target) => {
|
|
83
107
|
var _a, _b, _c;
|
|
84
108
|
const candidates = [
|
|
@@ -96,6 +120,103 @@ const getTargetProtocol = (target) => {
|
|
|
96
120
|
}
|
|
97
121
|
return '';
|
|
98
122
|
};
|
|
123
|
+
const getElementsByLocalName = (root, namespace, localName) => {
|
|
124
|
+
const namespaced = Array.from(root.getElementsByTagNameNS(namespace, localName));
|
|
125
|
+
if (namespaced.length) {
|
|
126
|
+
return namespaced;
|
|
127
|
+
}
|
|
128
|
+
return Array.from(root.getElementsByTagName('*')).filter(element => element.localName === localName);
|
|
129
|
+
};
|
|
130
|
+
const parseDocxXml = (source, parser) => {
|
|
131
|
+
const xml = parser.parseFromString(source, 'application/xml');
|
|
132
|
+
return getElementsByLocalName(xml, 'http://www.mozilla.org/newlayout/xml/parsererror.xml', 'parsererror').length
|
|
133
|
+
? null
|
|
134
|
+
: xml;
|
|
135
|
+
};
|
|
136
|
+
const resolvePackagePartPath = (basePart, relationshipTarget) => {
|
|
137
|
+
const segments = relationshipTarget.startsWith('/') ? [] : basePart.split('/').slice(0, -1);
|
|
138
|
+
relationshipTarget
|
|
139
|
+
.replace(/^\/+/, '')
|
|
140
|
+
.split('/')
|
|
141
|
+
.forEach(segment => {
|
|
142
|
+
if (!segment || segment === '.') {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (segment === '..') {
|
|
146
|
+
segments.pop();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
segments.push(segment);
|
|
150
|
+
});
|
|
151
|
+
return segments.join('/');
|
|
152
|
+
};
|
|
153
|
+
const resolveDocxImageMimeType = (partName) => {
|
|
154
|
+
var _a;
|
|
155
|
+
const extension = ((_a = partName.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
|
|
156
|
+
return DOCX_BACKGROUND_MIME_TYPES[extension];
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* WPS and Word can store a page background as a document-level VML fill. The
|
|
160
|
+
* DOCX engine intentionally ignores that legacy drawing node, so resolve only
|
|
161
|
+
* its package-local image relationship here and leave all body layout to it.
|
|
162
|
+
*/
|
|
163
|
+
export const resolveDocxPageBackgroundImage = async (buffer, createXmlParser = () => new DOMParser()) => {
|
|
164
|
+
try {
|
|
165
|
+
const archive = await JSZip.loadAsync(buffer);
|
|
166
|
+
const documentEntry = archive.file(DOCX_DOCUMENT_PART);
|
|
167
|
+
const relationshipsEntry = archive.file(DOCX_DOCUMENT_RELATIONSHIPS_PART);
|
|
168
|
+
if (!documentEntry || !relationshipsEntry) {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
const parser = createXmlParser();
|
|
172
|
+
const documentXml = parseDocxXml(await documentEntry.async('string'), parser);
|
|
173
|
+
const relationshipsXml = parseDocxXml(await relationshipsEntry.async('string'), parser);
|
|
174
|
+
if (!documentXml || !relationshipsXml) {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
const background = getElementsByLocalName(documentXml, WORDPROCESSINGML_NAMESPACE, 'background')[0];
|
|
178
|
+
const fill = background && getElementsByLocalName(background, VML_NAMESPACE, 'fill')[0];
|
|
179
|
+
const relationshipId = (fill === null || fill === void 0 ? void 0 : fill.getAttributeNS(OFFICE_RELATIONSHIP_NAMESPACE, 'id')) || (fill === null || fill === void 0 ? void 0 : fill.getAttribute('r:id'));
|
|
180
|
+
if (!relationshipId) {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
const relationship = getElementsByLocalName(relationshipsXml, PACKAGE_RELATIONSHIP_NAMESPACE, 'Relationship').find(candidate => candidate.getAttribute('Id') === relationshipId);
|
|
184
|
+
const target = relationship === null || relationship === void 0 ? void 0 : relationship.getAttribute('Target');
|
|
185
|
+
if (!target || (relationship === null || relationship === void 0 ? void 0 : relationship.getAttribute('TargetMode')) === 'External') {
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
const partName = resolvePackagePartPath(DOCX_DOCUMENT_PART, target);
|
|
189
|
+
const mimeType = resolveDocxImageMimeType(partName);
|
|
190
|
+
const imageEntry = archive.file(partName) || archive.file(decodeURIComponent(partName));
|
|
191
|
+
if (!mimeType || !imageEntry) {
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
return `data:${mimeType};base64,${await imageEntry.async('base64')}`;
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// A page background is optional and must never make an otherwise readable
|
|
198
|
+
// document fail. The DOCX engine remains responsible for package errors.
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
export const applyDocxPageBackgroundImage = (target, imageUrl) => {
|
|
203
|
+
if (!imageUrl) {
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
let applied = 0;
|
|
207
|
+
target.querySelectorAll('section.docx').forEach(page => {
|
|
208
|
+
const existing = Array.from(page.children).find(child => child.classList.contains(DOCX_PAGE_BACKGROUND_CLASS));
|
|
209
|
+
const background = existing || target.ownerDocument.createElement('div');
|
|
210
|
+
background.className = DOCX_PAGE_BACKGROUND_CLASS;
|
|
211
|
+
background.setAttribute('aria-hidden', 'true');
|
|
212
|
+
background.style.backgroundImage = `url("${imageUrl}")`;
|
|
213
|
+
if (!existing) {
|
|
214
|
+
page.prepend(background);
|
|
215
|
+
}
|
|
216
|
+
applied += 1;
|
|
217
|
+
});
|
|
218
|
+
return applied;
|
|
219
|
+
};
|
|
99
220
|
const shouldUseDocxWorker = (target, docxOptions) => {
|
|
100
221
|
var _a, _b;
|
|
101
222
|
if ((docxOptions === null || docxOptions === void 0 ? void 0 : docxOptions.worker) === false) {
|
|
@@ -139,8 +260,27 @@ const appendDocxVendorAssetVersion = (url, explicitUrl) => {
|
|
|
139
260
|
}
|
|
140
261
|
return `${url}${url.includes('?') ? '&' : '?'}file-viewer-docx=${DOCX_VENDOR_ASSET_VERSION}`;
|
|
141
262
|
};
|
|
142
|
-
const
|
|
143
|
-
|
|
263
|
+
export const applyDocxExternalLinkPolicy = (target, policy) => {
|
|
264
|
+
if (policy === 'allow') {
|
|
265
|
+
return 0;
|
|
266
|
+
}
|
|
267
|
+
let blocked = 0;
|
|
268
|
+
target.querySelectorAll('a[href]').forEach(anchor => {
|
|
269
|
+
const href = anchor.getAttribute('href');
|
|
270
|
+
if (!href || href.startsWith('#')) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (!anchor.hasAttribute('data-docx-external-href')) {
|
|
274
|
+
anchor.setAttribute('data-docx-external-href', href);
|
|
275
|
+
}
|
|
276
|
+
anchor.removeAttribute('href');
|
|
277
|
+
anchor.setAttribute('aria-disabled', 'true');
|
|
278
|
+
blocked += 1;
|
|
279
|
+
});
|
|
280
|
+
return blocked;
|
|
281
|
+
};
|
|
282
|
+
export const createDocxOptions = (target, context, notifyProgressiveRender) => {
|
|
283
|
+
var _a, _b, _c;
|
|
144
284
|
const docxOptions = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.docx;
|
|
145
285
|
const documentBaseUrl = resolveFileViewerRuntimeAssetBaseUrl(target.ownerDocument);
|
|
146
286
|
const useWorker = shouldUseDocxWorker(target, docxOptions);
|
|
@@ -151,12 +291,19 @@ const createDocxOptions = (target, context, notifyProgressiveRender) => {
|
|
|
151
291
|
notifyProgressiveRender();
|
|
152
292
|
}
|
|
153
293
|
};
|
|
294
|
+
const externalLinkPolicy = (_b = docxOptions === null || docxOptions === void 0 ? void 0 : docxOptions.externalLinkPolicy) !== null && _b !== void 0 ? _b : 'block';
|
|
154
295
|
const options = {
|
|
155
296
|
useWorker,
|
|
156
297
|
breakPages: usePagedLayout,
|
|
157
|
-
ignoreLastRenderedPageBreak: (
|
|
298
|
+
ignoreLastRenderedPageBreak: (_c = docxOptions === null || docxOptions === void 0 ? void 0 : docxOptions.ignoreLastRenderedPageBreak) !== null && _c !== void 0 ? _c : !usePagedLayout,
|
|
299
|
+
externalLinkPolicy,
|
|
158
300
|
darkMode,
|
|
159
|
-
progress
|
|
301
|
+
progress: event => {
|
|
302
|
+
if (event.phase === 'render' || event.phase === 'layout' || event.phase === 'done') {
|
|
303
|
+
applyDocxExternalLinkPolicy(target, externalLinkPolicy);
|
|
304
|
+
}
|
|
305
|
+
progress(event);
|
|
306
|
+
}
|
|
160
307
|
};
|
|
161
308
|
if (useWorker) {
|
|
162
309
|
options.workerUrl = appendDocxVendorAssetVersion(resolveFileViewerDocxWorkerUrl(docxOptions, documentBaseUrl), !!(docxOptions === null || docxOptions === void 0 ? void 0 : docxOptions.workerUrl));
|
|
@@ -250,6 +397,15 @@ const DOCX_RESPONSIVE_CSS = `
|
|
|
250
397
|
overflow: hidden;
|
|
251
398
|
transform-origin: top center;
|
|
252
399
|
}
|
|
400
|
+
.docx-fit-viewer .docx-page-background {
|
|
401
|
+
position: absolute;
|
|
402
|
+
inset: 0;
|
|
403
|
+
z-index: 0;
|
|
404
|
+
pointer-events: none;
|
|
405
|
+
background-position: center;
|
|
406
|
+
background-repeat: no-repeat;
|
|
407
|
+
background-size: 100% 100%;
|
|
408
|
+
}
|
|
253
409
|
.docx-fit-viewer[data-docx-dark-mode='true'] .docx-page-frame > section.docx,
|
|
254
410
|
.docx-fit-viewer[data-docx-dark-mode='true'] .docx-flow-frame > section.docx {
|
|
255
411
|
background: rgb(51, 51, 51) !important;
|
|
@@ -552,14 +708,20 @@ export default async function (buffer, target, context) {
|
|
|
552
708
|
(_a = context === null || context === void 0 ? void 0 : context.onProgressiveRender) === null || _a === void 0 ? void 0 : _a.call(context);
|
|
553
709
|
};
|
|
554
710
|
const docxOptions = createDocxOptions(target, context, notifyProgressiveRender);
|
|
555
|
-
const { defaultOptions, renderAsync } = await
|
|
711
|
+
const [{ defaultOptions, renderAsync }, pageBackgroundImage] = await Promise.all([
|
|
712
|
+
loadLibrary(),
|
|
713
|
+
resolveDocxPageBackgroundImage(buffer, () => createTargetXmlParser(target))
|
|
714
|
+
]);
|
|
556
715
|
target.dataset.docxWorker = docxOptions.useWorker ? 'self' : 'false';
|
|
557
716
|
target.dataset.docxDarkMode = docxOptions.darkMode ? 'true' : 'false';
|
|
558
717
|
const usedHeaderFooterFallback = await renderDocxWithHeaderFooterFallback(renderAsync, buffer, target, {
|
|
559
718
|
...defaultOptions,
|
|
560
719
|
...docxOptions
|
|
561
720
|
});
|
|
721
|
+
applyDocxExternalLinkPolicy(target, docxOptions.externalLinkPolicy);
|
|
562
722
|
target.dataset.docxHeaderFooterFallback = usedHeaderFooterFallback ? 'true' : 'false';
|
|
723
|
+
target.dataset.docxPageBackground =
|
|
724
|
+
applyDocxPageBackgroundImage(target, pageBackgroundImage) > 0 ? 'true' : 'false';
|
|
563
725
|
notifyProgressiveRender();
|
|
564
726
|
const disposeResponsive = makeDocxResponsive(target, context);
|
|
565
727
|
(_a = context === null || context === void 0 ? void 0 : context.registerExportAdapter) === null || _a === void 0 ? void 0 : _a.call(context, {
|
|
@@ -587,6 +749,7 @@ export default async function (buffer, target, context) {
|
|
|
587
749
|
delete target.dataset.docxWorker;
|
|
588
750
|
delete target.dataset.docxDarkMode;
|
|
589
751
|
delete target.dataset.docxHeaderFooterFallback;
|
|
752
|
+
delete target.dataset.docxPageBackground;
|
|
590
753
|
target.innerHTML = '';
|
|
591
754
|
}
|
|
592
755
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/renderer-word",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone Word and compatible document renderer plugin for File Viewer powered by @file-viewer/docx, @file-viewer/doc, and RTF/ODF parsing.",
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"LICENSE"
|
|
58
58
|
],
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@file-viewer/core": "2.2.
|
|
61
|
-
"@file-viewer/doc": "2.2.
|
|
60
|
+
"@file-viewer/core": "2.2.6",
|
|
61
|
+
"@file-viewer/doc": "2.2.6",
|
|
62
62
|
"@file-viewer/docx": "^0.3.26",
|
|
63
63
|
"jszip": "^3.10.1",
|
|
64
64
|
"rtf.js": "^3.0.9"
|