@file-viewer/renderer-ofd 2.2.5 → 2.2.7
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/ofd.js +150 -5
- package/package.json +4 -3
package/dist/ofd.js
CHANGED
|
@@ -3,9 +3,17 @@ const OFD_MIN_SCALE = 0.35;
|
|
|
3
3
|
const OFD_MAX_SCALE = 3;
|
|
4
4
|
const OFD_ZOOM_STEP = 0.1;
|
|
5
5
|
const ofdStyle = `
|
|
6
|
-
.ofd-viewer{position:relative;box-sizing:border-box;min-height:100%;background:var(--file-viewer-render-surface-background,#e9edf2);color:#172033;font-family:Aptos,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif}
|
|
6
|
+
.ofd-viewer{position:relative;display:flex;box-sizing:border-box;min-height:100%;min-width:0;flex-direction:column;background:var(--file-viewer-render-surface-background,#e9edf2);color:#172033;font-family:Aptos,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif}
|
|
7
7
|
.ofd-viewer *{box-sizing:border-box}
|
|
8
|
-
.ofd-
|
|
8
|
+
.ofd-toolbar{position:sticky;top:0;z-index:4;display:flex;min-height:44px;align-items:center;justify-content:center;border-bottom:1px solid rgba(148,163,184,.32);background:rgba(255,255,255,.92);box-shadow:0 4px 14px rgba(15,23,42,.06);backdrop-filter:blur(10px)}
|
|
9
|
+
.ofd-toolbar-group{display:inline-flex;align-items:center;gap:8px;padding:5px 8px;border:1px solid #d7dee8;border-radius:9px;background:#fff;box-shadow:0 2px 8px rgba(15,23,42,.06)}
|
|
10
|
+
.ofd-page-button{display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;border:1px solid transparent;border-radius:7px;color:#334155;background:transparent;font:700 22px/1 Aptos,'Segoe UI',sans-serif;cursor:pointer}
|
|
11
|
+
.ofd-page-button:hover:not(:disabled){border-color:#b9d4f6;color:#1769d8;background:#edf5ff}
|
|
12
|
+
.ofd-page-button:focus-visible{outline:2px solid #408fff;outline-offset:1px}
|
|
13
|
+
.ofd-page-button:disabled{color:#a7b0bd;cursor:not-allowed}
|
|
14
|
+
.ofd-page-meter{display:inline-flex;min-width:92px;align-items:baseline;justify-content:center;gap:5px;color:#64748b;font-size:12px;white-space:nowrap}
|
|
15
|
+
.ofd-page-meter strong{color:#172033;font-size:13px}
|
|
16
|
+
.ofd-stage{position:relative;flex:1;min-width:0;min-height:0;padding:18px 0 28px;overflow:auto;scrollbar-gutter:stable}
|
|
9
17
|
.ofd-state{position:absolute;inset:0;z-index:1;display:flex;align-items:center;justify-content:center;background:rgba(246,248,250,.92);color:#64748b;font-size:14px}
|
|
10
18
|
.ofd-state[hidden]{display:none!important}
|
|
11
19
|
.ofd-state.error{color:#b42318}
|
|
@@ -15,8 +23,15 @@ const ofdStyle = `
|
|
|
15
23
|
.ofd-page svg,.ofd-page canvas,.ofd-page img{filter:none!important;mix-blend-mode:normal!important}
|
|
16
24
|
[data-viewer-theme='dark'] .ofd-viewer{background:var(--file-viewer-render-surface-background,#172033);color:#e5eef8}
|
|
17
25
|
[data-viewer-theme='dark'] .ofd-state{background:rgba(15,23,42,.9);color:#cbd5e1}
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
[data-viewer-theme='dark'] .ofd-toolbar{border-color:rgba(100,116,139,.5);background:rgba(15,23,42,.9)}
|
|
27
|
+
[data-viewer-theme='dark'] .ofd-toolbar-group{border-color:#475569;background:#1e293b}
|
|
28
|
+
[data-viewer-theme='dark'] .ofd-page-button{color:#e2e8f0}
|
|
29
|
+
[data-viewer-theme='dark'] .ofd-page-button:hover:not(:disabled){border-color:#4d79ad;color:#93c5fd;background:#263b55}
|
|
30
|
+
[data-viewer-theme='dark'] .ofd-page-button:disabled{color:#64748b}
|
|
31
|
+
[data-viewer-theme='dark'] .ofd-page-meter{color:#94a3b8}
|
|
32
|
+
[data-viewer-theme='dark'] .ofd-page-meter strong{color:#f1f5f9}
|
|
33
|
+
@media (prefers-color-scheme:dark){[data-viewer-theme='system'] .ofd-viewer{background:var(--file-viewer-render-surface-background,#172033);color:#e5eef8}[data-viewer-theme='system'] .ofd-state{background:rgba(15,23,42,.9);color:#cbd5e1}[data-viewer-theme='system'] .ofd-toolbar{border-color:rgba(100,116,139,.5);background:rgba(15,23,42,.9)}[data-viewer-theme='system'] .ofd-toolbar-group{border-color:#475569;background:#1e293b}[data-viewer-theme='system'] .ofd-page-button{color:#e2e8f0}[data-viewer-theme='system'] .ofd-page-button:hover:not(:disabled){border-color:#4d79ad;color:#93c5fd;background:#263b55}[data-viewer-theme='system'] .ofd-page-button:disabled{color:#64748b}[data-viewer-theme='system'] .ofd-page-meter{color:#94a3b8}[data-viewer-theme='system'] .ofd-page-meter strong{color:#f1f5f9}}
|
|
34
|
+
@media print{.ofd-viewer{display:block;background:#fff!important}.ofd-toolbar{display:none!important}.ofd-stage{padding:0!important;overflow:visible!important}.ofd-page-frame{break-after:page;page-break-after:always;margin:0 auto!important}.ofd-page-frame:last-child{break-after:auto;page-break-after:auto}.ofd-page{box-shadow:none!important;transition:none!important}}
|
|
20
35
|
`;
|
|
21
36
|
const loadOfdModule = (() => {
|
|
22
37
|
let modulePromise = null;
|
|
@@ -131,14 +146,38 @@ export default async function renderOfd(buffer, target, context) {
|
|
|
131
146
|
let state = 'loading';
|
|
132
147
|
let errorMessage = '';
|
|
133
148
|
let zoom = 1;
|
|
149
|
+
let currentPage = 1;
|
|
150
|
+
let pageCount = 0;
|
|
151
|
+
let scrollFrame = 0;
|
|
134
152
|
let ofdDocumentPromise = null;
|
|
135
153
|
const style = createStyle(documentRef);
|
|
136
154
|
const viewer = createElement(documentRef, 'div', 'ofd-viewer');
|
|
137
155
|
viewer.dataset.viewerZoomProvider = 'ofd';
|
|
138
156
|
const stateNode = createElement(documentRef, 'div', 'ofd-state', t('ofd.state.loading'));
|
|
139
157
|
stateNode.setAttribute('aria-live', 'polite');
|
|
158
|
+
const toolbar = createElement(documentRef, 'div', 'ofd-toolbar');
|
|
159
|
+
toolbar.setAttribute('role', 'toolbar');
|
|
160
|
+
toolbar.setAttribute('aria-label', t('ofd.toolbar.pageNavigation'));
|
|
161
|
+
const pageGroup = createElement(documentRef, 'div', 'ofd-toolbar-group');
|
|
162
|
+
const previousPageButton = createElement(documentRef, 'button', 'ofd-page-button', '‹');
|
|
163
|
+
previousPageButton.type = 'button';
|
|
164
|
+
previousPageButton.title = t('ofd.toolbar.previousPage');
|
|
165
|
+
previousPageButton.setAttribute('aria-label', t('ofd.toolbar.previousPage'));
|
|
166
|
+
const pageMeter = createElement(documentRef, 'span', 'ofd-page-meter');
|
|
167
|
+
pageMeter.setAttribute('aria-live', 'polite');
|
|
168
|
+
const pageMeterCurrent = createElement(documentRef, 'strong', undefined, '1');
|
|
169
|
+
const pageMeterTotal = createElement(documentRef, 'span', undefined, '/ -');
|
|
170
|
+
pageMeter.append(pageMeterCurrent, pageMeterTotal);
|
|
171
|
+
const nextPageButton = createElement(documentRef, 'button', 'ofd-page-button', '›');
|
|
172
|
+
nextPageButton.type = 'button';
|
|
173
|
+
nextPageButton.title = t('ofd.toolbar.nextPage');
|
|
174
|
+
nextPageButton.setAttribute('aria-label', t('ofd.toolbar.nextPage'));
|
|
175
|
+
pageGroup.append(previousPageButton, pageMeter, nextPageButton);
|
|
176
|
+
toolbar.append(pageGroup);
|
|
140
177
|
const stage = createElement(documentRef, 'div', 'ofd-stage');
|
|
141
|
-
|
|
178
|
+
stage.tabIndex = 0;
|
|
179
|
+
stage.setAttribute('aria-label', t('ofd.toolbar.documentPages'));
|
|
180
|
+
viewer.append(toolbar, stateNode, stage);
|
|
142
181
|
target.replaceChildren(style, viewer);
|
|
143
182
|
const clearStage = () => {
|
|
144
183
|
stage.replaceChildren();
|
|
@@ -148,6 +187,77 @@ export default async function renderOfd(buffer, target, context) {
|
|
|
148
187
|
stateNode.classList.toggle('error', state === 'error');
|
|
149
188
|
stateNode.textContent = state === 'error' ? errorMessage : t('ofd.state.loading');
|
|
150
189
|
};
|
|
190
|
+
const getPageFrames = () => Array.from(stage.querySelectorAll('.ofd-page-frame'));
|
|
191
|
+
const syncPageNavigation = () => {
|
|
192
|
+
pageCount = getPageFrames().length;
|
|
193
|
+
currentPage = pageCount ? Math.min(pageCount, Math.max(1, currentPage)) : 0;
|
|
194
|
+
pageMeterCurrent.textContent = pageCount ? String(currentPage) : '-';
|
|
195
|
+
pageMeterTotal.textContent = `/ ${pageCount || '-'}`;
|
|
196
|
+
pageMeter.setAttribute('aria-label', pageCount
|
|
197
|
+
? t('ofd.toolbar.pageStatus', { current: currentPage, total: pageCount })
|
|
198
|
+
: t('ofd.toolbar.noPages'));
|
|
199
|
+
previousPageButton.disabled = currentPage <= 1;
|
|
200
|
+
nextPageButton.disabled = currentPage <= 0 || currentPage >= pageCount;
|
|
201
|
+
};
|
|
202
|
+
const scrollToPage = (requestedPage, behavior = 'smooth') => {
|
|
203
|
+
const frames = getPageFrames();
|
|
204
|
+
if (!frames.length) {
|
|
205
|
+
currentPage = 0;
|
|
206
|
+
syncPageNavigation();
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
const nextPage = Math.min(frames.length, Math.max(1, Math.round(requestedPage)));
|
|
210
|
+
currentPage = nextPage;
|
|
211
|
+
syncPageNavigation();
|
|
212
|
+
const frame = frames[nextPage - 1];
|
|
213
|
+
if (typeof (frame === null || frame === void 0 ? void 0 : frame.scrollIntoView) === 'function') {
|
|
214
|
+
frame.scrollIntoView({ block: 'start', inline: 'nearest', behavior });
|
|
215
|
+
}
|
|
216
|
+
return true;
|
|
217
|
+
};
|
|
218
|
+
const detectCurrentPage = () => {
|
|
219
|
+
const frames = getPageFrames();
|
|
220
|
+
if (!frames.length) {
|
|
221
|
+
currentPage = 0;
|
|
222
|
+
syncPageNavigation();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const stageRect = stage.getBoundingClientRect();
|
|
226
|
+
const viewportCenter = stageRect.top + stage.clientHeight / 2;
|
|
227
|
+
let closestIndex = 0;
|
|
228
|
+
let closestDistance = Number.POSITIVE_INFINITY;
|
|
229
|
+
frames.forEach((frame, index) => {
|
|
230
|
+
const rect = frame.getBoundingClientRect();
|
|
231
|
+
const center = rect.top + rect.height / 2;
|
|
232
|
+
const distance = Math.abs(center - viewportCenter);
|
|
233
|
+
if (distance < closestDistance) {
|
|
234
|
+
closestDistance = distance;
|
|
235
|
+
closestIndex = index;
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
const detectedPage = closestIndex + 1;
|
|
239
|
+
if (detectedPage !== currentPage) {
|
|
240
|
+
currentPage = detectedPage;
|
|
241
|
+
syncPageNavigation();
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
const scheduleCurrentPageDetection = () => {
|
|
245
|
+
var _a;
|
|
246
|
+
if (scrollFrame)
|
|
247
|
+
return;
|
|
248
|
+
const requestFrame = (_a = targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.requestAnimationFrame) === null || _a === void 0 ? void 0 : _a.bind(targetWindow);
|
|
249
|
+
if (requestFrame) {
|
|
250
|
+
scrollFrame = requestFrame(() => {
|
|
251
|
+
scrollFrame = 0;
|
|
252
|
+
detectCurrentPage();
|
|
253
|
+
});
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
scrollFrame = (targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.setTimeout(() => {
|
|
257
|
+
scrollFrame = 0;
|
|
258
|
+
detectCurrentPage();
|
|
259
|
+
}, 0)) || 0;
|
|
260
|
+
};
|
|
151
261
|
const getOfdDocument = async (ofd) => {
|
|
152
262
|
// OFD 解压和 XML 解析成本较高,尺寸变化只重排页面,不重复解析压缩包。
|
|
153
263
|
ofdDocumentPromise || (ofdDocumentPromise = parseWithOfdJs(ofd, buffer).then(documents => {
|
|
@@ -251,6 +361,9 @@ export default async function renderOfd(buffer, target, context) {
|
|
|
251
361
|
lastRenderedWidth = width;
|
|
252
362
|
await waitForPaint(targetWindow);
|
|
253
363
|
syncPageZoom();
|
|
364
|
+
syncPageNavigation();
|
|
365
|
+
if (currentPage > 1)
|
|
366
|
+
scrollToPage(currentPage, 'auto');
|
|
254
367
|
state = 'ready';
|
|
255
368
|
syncState();
|
|
256
369
|
zoomEmitter.emit();
|
|
@@ -281,6 +394,31 @@ export default async function renderOfd(buffer, target, context) {
|
|
|
281
394
|
});
|
|
282
395
|
resizeObserver.observe(viewer);
|
|
283
396
|
};
|
|
397
|
+
previousPageButton.addEventListener('click', () => {
|
|
398
|
+
scrollToPage(currentPage - 1);
|
|
399
|
+
});
|
|
400
|
+
nextPageButton.addEventListener('click', () => {
|
|
401
|
+
scrollToPage(currentPage + 1);
|
|
402
|
+
});
|
|
403
|
+
stage.addEventListener('scroll', scheduleCurrentPageDetection, { passive: true });
|
|
404
|
+
stage.addEventListener('keydown', event => {
|
|
405
|
+
if (event.key === 'PageUp') {
|
|
406
|
+
event.preventDefault();
|
|
407
|
+
scrollToPage(currentPage - 1);
|
|
408
|
+
}
|
|
409
|
+
else if (event.key === 'PageDown') {
|
|
410
|
+
event.preventDefault();
|
|
411
|
+
scrollToPage(currentPage + 1);
|
|
412
|
+
}
|
|
413
|
+
else if (event.key === 'Home' && (event.ctrlKey || event.metaKey)) {
|
|
414
|
+
event.preventDefault();
|
|
415
|
+
scrollToPage(1);
|
|
416
|
+
}
|
|
417
|
+
else if (event.key === 'End' && (event.ctrlKey || event.metaKey)) {
|
|
418
|
+
event.preventDefault();
|
|
419
|
+
scrollToPage(pageCount);
|
|
420
|
+
}
|
|
421
|
+
});
|
|
284
422
|
try {
|
|
285
423
|
// Do not report the renderer as loaded until page surfaces exist. This
|
|
286
424
|
// keeps immediate print/mask operations page-aware and propagates initial
|
|
@@ -333,6 +471,13 @@ export default async function renderOfd(buffer, target, context) {
|
|
|
333
471
|
disposed = true;
|
|
334
472
|
renderVersion += 1;
|
|
335
473
|
targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.clearTimeout(resizeTimer);
|
|
474
|
+
if (scrollFrame) {
|
|
475
|
+
if (targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.cancelAnimationFrame)
|
|
476
|
+
targetWindow.cancelAnimationFrame(scrollFrame);
|
|
477
|
+
else
|
|
478
|
+
targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.clearTimeout(scrollFrame);
|
|
479
|
+
}
|
|
480
|
+
scrollFrame = 0;
|
|
336
481
|
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
|
|
337
482
|
resizeObserver = null;
|
|
338
483
|
unregisterFileViewerZoomProvider(viewer);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/renderer-ofd",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone OFD renderer plugin for File Viewer powered by DLTech21/ofd.js.",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"LICENSE"
|
|
54
54
|
],
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@file-viewer/core": "2.2.
|
|
56
|
+
"@file-viewer/core": "2.2.7",
|
|
57
57
|
"jszip": "^3.10.1"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"verify:github-94": "node scripts/verify-github-94.mjs",
|
|
68
68
|
"verify:image-placement": "node scripts/verify-image-placement.mjs",
|
|
69
69
|
"verify:pageblock-render": "node scripts/verify-pageblock-render.mjs",
|
|
70
|
-
"verify:render-fidelity": "node scripts/verify-render-fidelity.mjs"
|
|
70
|
+
"verify:render-fidelity": "node scripts/verify-render-fidelity.mjs",
|
|
71
|
+
"verify:github-177": "pnpm --filter @file-viewer/core build && pnpm exec tsc -b tsconfig.json --force && node scripts/verify-github-177.mjs"
|
|
71
72
|
}
|
|
72
73
|
}
|