@file-viewer/renderer-archive 2.1.2 → 2.1.3
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/archive.js +43 -30
- package/package.json +2 -2
package/dist/archive.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveFileViewerArchiveWasmUrl, resolveFileViewerArchiveWorkerUrl, } from '@file-viewer/core/assets';
|
|
2
|
-
import { disposeFileViewerRendered, } from '@file-viewer/core';
|
|
2
|
+
import { createFileViewerTranslator, disposeFileViewerRendered, } from '@file-viewer/core';
|
|
3
3
|
import { buildArchiveNestedRenderContext, createArchiveCacheKey, flattenArchiveObject, formatArchiveBytes, getArchiveEntryExtension, } from './archiveShared.js';
|
|
4
4
|
import { readArchiveCache, writeArchiveCache } from './archiveCache.js';
|
|
5
5
|
import { loadArchiveEntriesWithoutWorker } from './archiveFallback.js';
|
|
@@ -98,7 +98,7 @@ const getWorkerConstructor = (documentRef) => {
|
|
|
98
98
|
const WorkerCtor = ((_a = documentRef.defaultView) === null || _a === void 0 ? void 0 : _a.Worker) ||
|
|
99
99
|
(typeof Worker !== 'undefined' ? Worker : undefined);
|
|
100
100
|
if (!WorkerCtor) {
|
|
101
|
-
throw new Error('
|
|
101
|
+
throw new Error('Web Worker is not supported by this browser.');
|
|
102
102
|
}
|
|
103
103
|
return WorkerCtor;
|
|
104
104
|
};
|
|
@@ -157,7 +157,7 @@ const prepareWorkerUrl = async (candidate, objectUrls) => {
|
|
|
157
157
|
}
|
|
158
158
|
const response = await fetch(candidate.workerUrl, { cache: 'no-cache' });
|
|
159
159
|
if (!response.ok) {
|
|
160
|
-
throw new Error(
|
|
160
|
+
throw new Error(`Unable to read libarchive Worker: ${response.status}`);
|
|
161
161
|
}
|
|
162
162
|
const source = await response.text();
|
|
163
163
|
const workerUrl = URL.createObjectURL(new Blob([
|
|
@@ -174,7 +174,7 @@ const resolveWorkerCandidates = async (documentRef, options) => {
|
|
|
174
174
|
: undefined;
|
|
175
175
|
if (options === null || options === void 0 ? void 0 : options.workerUrl) {
|
|
176
176
|
candidates.push({
|
|
177
|
-
label: '
|
|
177
|
+
label: 'custom libarchive Worker',
|
|
178
178
|
workerUrl: resolveFileViewerArchiveWorkerUrl(options, baseUrl),
|
|
179
179
|
wasmUrl,
|
|
180
180
|
});
|
|
@@ -183,7 +183,7 @@ const resolveWorkerCandidates = async (documentRef, options) => {
|
|
|
183
183
|
const publicWorkerUrl = resolveFileViewerArchiveWorkerUrl(undefined, baseUrl);
|
|
184
184
|
if (await probeWorkerUrl(publicWorkerUrl)) {
|
|
185
185
|
candidates.push({
|
|
186
|
-
label: '
|
|
186
|
+
label: 'static libarchive Worker',
|
|
187
187
|
workerUrl: publicWorkerUrl,
|
|
188
188
|
wasmUrl,
|
|
189
189
|
});
|
|
@@ -191,10 +191,11 @@ const resolveWorkerCandidates = async (documentRef, options) => {
|
|
|
191
191
|
return candidates;
|
|
192
192
|
};
|
|
193
193
|
const renderNestedWithCoreFallback = async (buffer, type, target, context) => {
|
|
194
|
+
const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
|
|
194
195
|
const { fileViewerCoreRendererDispatcher } = await import('@file-viewer/core');
|
|
195
196
|
const handler = fileViewerCoreRendererDispatcher.resolve(type);
|
|
196
197
|
if (!handler) {
|
|
197
|
-
target.textContent =
|
|
198
|
+
target.textContent = t('archive.error.nestedUnsupported', { type });
|
|
198
199
|
return undefined;
|
|
199
200
|
}
|
|
200
201
|
return handler(buffer, target, type, {
|
|
@@ -219,8 +220,9 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
219
220
|
let selectedEntry = null;
|
|
220
221
|
let nestedRendered;
|
|
221
222
|
let loading = false;
|
|
222
|
-
|
|
223
|
-
let
|
|
223
|
+
const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
|
|
224
|
+
let loadingText = t('archive.loading.readingDirectory');
|
|
225
|
+
let loadingHint = t('archive.loading.readingDirectoryHint');
|
|
224
226
|
let errorText = '';
|
|
225
227
|
let archiveNotice = '';
|
|
226
228
|
let encrypted = null;
|
|
@@ -237,15 +239,15 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
237
239
|
const info = createElement(documentRef, 'div', 'archive-info');
|
|
238
240
|
const search = createElement(documentRef, 'input', 'archive-search');
|
|
239
241
|
search.type = 'search';
|
|
240
|
-
search.placeholder = '
|
|
242
|
+
search.placeholder = t('archive.search.placeholder');
|
|
241
243
|
const list = createElement(documentRef, 'div', 'archive-list');
|
|
242
244
|
list.setAttribute('role', 'list');
|
|
243
245
|
sidebar.append(head, warning, info, search, list);
|
|
244
246
|
const preview = createElement(documentRef, 'main', 'archive-preview');
|
|
245
247
|
const toolbar = createElement(documentRef, 'div', 'archive-preview-toolbar');
|
|
246
248
|
const toolbarTitle = createElement(documentRef, 'div');
|
|
247
|
-
toolbarTitle.append(createElement(documentRef, 'span', undefined, '
|
|
248
|
-
const downloadButton = createElement(documentRef, 'button', undefined, '
|
|
249
|
+
toolbarTitle.append(createElement(documentRef, 'span', undefined, t('archive.preview.title')), createElement(documentRef, 'strong', undefined, t('archive.preview.chooseFile')));
|
|
250
|
+
const downloadButton = createElement(documentRef, 'button', undefined, t('archive.preview.downloadFile'));
|
|
249
251
|
downloadButton.type = 'button';
|
|
250
252
|
toolbar.append(toolbarTitle, downloadButton);
|
|
251
253
|
const nestedTarget = createElement(documentRef, 'div', 'archive-nested-target');
|
|
@@ -262,7 +264,7 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
262
264
|
state.append(stateContent);
|
|
263
265
|
root.append(state);
|
|
264
266
|
const error = createElement(documentRef, 'div', 'archive-error');
|
|
265
|
-
const errorTitle = createElement(documentRef, 'strong', undefined, '
|
|
267
|
+
const errorTitle = createElement(documentRef, 'strong', undefined, t('archive.error.title'));
|
|
266
268
|
const errorMessage = createElement(documentRef, 'p');
|
|
267
269
|
error.append(errorTitle, errorMessage);
|
|
268
270
|
root.append(error);
|
|
@@ -299,8 +301,12 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
299
301
|
};
|
|
300
302
|
const syncState = () => {
|
|
301
303
|
const archiveStats = getArchiveStats();
|
|
302
|
-
stats.textContent =
|
|
303
|
-
|
|
304
|
+
stats.textContent = t('archive.stats.summary', {
|
|
305
|
+
count: archiveStats.count,
|
|
306
|
+
size: formatArchiveBytes(archiveStats.totalSize),
|
|
307
|
+
previewable: archiveStats.previewableCount,
|
|
308
|
+
});
|
|
309
|
+
warning.textContent = t('archive.warning.encrypted');
|
|
304
310
|
warning.classList.toggle('archive-hidden', !encrypted);
|
|
305
311
|
info.textContent = archiveNotice;
|
|
306
312
|
info.classList.toggle('archive-hidden', !archiveNotice);
|
|
@@ -312,7 +318,7 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
312
318
|
downloadButton.hidden = !selectedEntry;
|
|
313
319
|
const activeTitle = toolbarTitle.querySelector('strong');
|
|
314
320
|
if (activeTitle) {
|
|
315
|
-
activeTitle.textContent = (selectedEntry === null || selectedEntry === void 0 ? void 0 : selectedEntry.name) || '
|
|
321
|
+
activeTitle.textContent = (selectedEntry === null || selectedEntry === void 0 ? void 0 : selectedEntry.name) || t('archive.preview.chooseFile');
|
|
316
322
|
}
|
|
317
323
|
};
|
|
318
324
|
const renderEmptyState = () => {
|
|
@@ -320,7 +326,7 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
320
326
|
return;
|
|
321
327
|
}
|
|
322
328
|
const empty = createElement(documentRef, 'div', 'archive-empty');
|
|
323
|
-
empty.append(createElement(documentRef, 'strong', undefined, '
|
|
329
|
+
empty.append(createElement(documentRef, 'strong', undefined, t('archive.empty.title')), createElement(documentRef, 'p', undefined, t('archive.empty.message')));
|
|
324
330
|
nestedTarget.replaceChildren(empty);
|
|
325
331
|
};
|
|
326
332
|
const renderEntryList = () => {
|
|
@@ -371,13 +377,13 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
371
377
|
return worker;
|
|
372
378
|
},
|
|
373
379
|
});
|
|
374
|
-
setLoading(true,
|
|
380
|
+
setLoading(true, t('archive.loading.initializingCandidate', { label: candidate.label }), t('archive.loading.initializingCandidateHint'));
|
|
375
381
|
const archiveFile = createArchiveFile(documentRef, buffer, filename);
|
|
376
|
-
const archive = await withTimeout(Archive.open(archiveFile), workerTimeoutMs,
|
|
382
|
+
const archive = await withTimeout(Archive.open(archiveFile), workerTimeoutMs, t('archive.error.candidateInitTimeout', { label: candidate.label }), targetWindow);
|
|
377
383
|
archiveReader = archive;
|
|
378
|
-
encrypted = await withTimeout(archive.hasEncryptedData(), workerTimeoutMs,
|
|
379
|
-
setLoading(true, '
|
|
380
|
-
const fileTree = await withTimeout(archive.getFilesObject(), workerTimeoutMs,
|
|
384
|
+
encrypted = await withTimeout(archive.hasEncryptedData(), workerTimeoutMs, t('archive.error.encryptedCheckTimeout', { label: candidate.label }), targetWindow).catch(() => null);
|
|
385
|
+
setLoading(true, t('archive.loading.readingDirectory'), t('archive.loading.directoryReadyHint'));
|
|
386
|
+
const fileTree = await withTimeout(archive.getFilesObject(), workerTimeoutMs, t('archive.error.candidateReadTimeout', { label: candidate.label }), targetWindow);
|
|
381
387
|
entries = flattenArchiveObject(fileTree)
|
|
382
388
|
.sort((left, right) => left.path.localeCompare(right.path));
|
|
383
389
|
syncState();
|
|
@@ -393,14 +399,14 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
393
399
|
}
|
|
394
400
|
};
|
|
395
401
|
const tryOpenArchiveWithFallback = async () => {
|
|
396
|
-
setLoading(true, '
|
|
402
|
+
setLoading(true, t('archive.loading.workerFallback'), t('archive.loading.workerFallbackHint'));
|
|
397
403
|
const fallbackEntries = await loadArchiveEntriesWithoutWorker(buffer, filename);
|
|
398
404
|
if (!fallbackEntries) {
|
|
399
405
|
return false;
|
|
400
406
|
}
|
|
401
407
|
entries = fallbackEntries.sort((left, right) => left.path.localeCompare(right.path));
|
|
402
408
|
encrypted = null;
|
|
403
|
-
archiveNotice = '
|
|
409
|
+
archiveNotice = t('archive.notice.workerFallback');
|
|
404
410
|
syncState();
|
|
405
411
|
renderEntryList();
|
|
406
412
|
renderEmptyState();
|
|
@@ -408,10 +414,13 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
408
414
|
};
|
|
409
415
|
const openArchive = async () => {
|
|
410
416
|
if (buffer.byteLength > maxArchiveSize) {
|
|
411
|
-
setError(
|
|
417
|
+
setError(t('archive.error.tooLarge', {
|
|
418
|
+
size: formatArchiveBytes(buffer.byteLength),
|
|
419
|
+
limit: formatArchiveBytes(maxArchiveSize),
|
|
420
|
+
}));
|
|
412
421
|
return;
|
|
413
422
|
}
|
|
414
|
-
setLoading(true, '
|
|
423
|
+
setLoading(true, t('archive.loading.initializingWorker'), t('archive.loading.initializingWorkerHint'));
|
|
415
424
|
setError('');
|
|
416
425
|
archiveNotice = '';
|
|
417
426
|
try {
|
|
@@ -434,7 +443,7 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
434
443
|
if (await tryOpenArchiveWithFallback()) {
|
|
435
444
|
return;
|
|
436
445
|
}
|
|
437
|
-
throw new Error(errors.join('
|
|
446
|
+
throw new Error(errors.join('; ') || t('archive.error.workerInitFailed'));
|
|
438
447
|
}
|
|
439
448
|
catch (nextError) {
|
|
440
449
|
console.error(nextError);
|
|
@@ -479,14 +488,18 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
479
488
|
renderEntryList();
|
|
480
489
|
syncState();
|
|
481
490
|
if (entry.size > maxEntryPreviewSize) {
|
|
482
|
-
setError(
|
|
491
|
+
setError(t('archive.error.entryTooLarge', {
|
|
492
|
+
name: entry.name,
|
|
493
|
+
size: formatArchiveBytes(entry.size),
|
|
494
|
+
limit: formatArchiveBytes(maxEntryPreviewSize),
|
|
495
|
+
}));
|
|
483
496
|
return;
|
|
484
497
|
}
|
|
485
|
-
setLoading(true,
|
|
498
|
+
setLoading(true, t('archive.loading.extracting', { name: entry.name }));
|
|
486
499
|
setError('');
|
|
487
500
|
try {
|
|
488
501
|
const entryBuffer = await extractEntryBuffer(entry);
|
|
489
|
-
setLoading(true,
|
|
502
|
+
setLoading(true, t('archive.loading.rendering', { name: entry.name }));
|
|
490
503
|
await renderEntryBuffer(entry, entryBuffer);
|
|
491
504
|
}
|
|
492
505
|
catch (nextError) {
|
|
@@ -498,7 +511,7 @@ export default async function renderArchive(buffer, target, _type, context) {
|
|
|
498
511
|
}
|
|
499
512
|
}
|
|
500
513
|
const downloadEntry = async (entry) => {
|
|
501
|
-
setLoading(true,
|
|
514
|
+
setLoading(true, t('archive.loading.exporting', { name: entry.name }));
|
|
502
515
|
try {
|
|
503
516
|
const entryBuffer = await extractEntryBuffer(entry);
|
|
504
517
|
const url = URL.createObjectURL(new Blob([entryBuffer]));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/renderer-archive",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone archive renderer plugin for Flyfish File Viewer with libarchive worker, ZIP/TAR fallback, IndexedDB cache, and nested previews.",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"LICENSE"
|
|
57
57
|
],
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@file-viewer/core": "^2.1.
|
|
59
|
+
"@file-viewer/core": "^2.1.3",
|
|
60
60
|
"jszip": "^3.10.1",
|
|
61
61
|
"libarchive.js": "^2.0.2"
|
|
62
62
|
},
|