@papyrus-sdk/ui-react-native 0.2.20 → 0.2.22
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 +12 -1
- package/dist/index.d.mts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +1025 -265
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1151 -387
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/runtime/comicRuntime.js +107 -0
- package/runtime/comicRuntime.test.ts +90 -0
- package/runtime/index.html +829 -248
- package/runtime/runtime.js +744 -3
- package/runtime/syncComicRuntime.mjs +41 -0
package/dist/index.js
CHANGED
|
@@ -20403,9 +20403,121 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20403
20403
|
]).default;
|
|
20404
20404
|
});
|
|
20405
20405
|
</script>
|
|
20406
|
+
<!-- @papyrus-comic-runtime:start -->
|
|
20407
|
+
<script>
|
|
20408
|
+
(function (root, factory) {
|
|
20409
|
+
if (typeof module === "object" && module.exports) {
|
|
20410
|
+
module.exports = factory();
|
|
20411
|
+
} else {
|
|
20412
|
+
root.PapyrusComicRuntime = Object.assign(
|
|
20413
|
+
factory(),
|
|
20414
|
+
root.PapyrusComicRuntime || {}
|
|
20415
|
+
);
|
|
20416
|
+
}
|
|
20417
|
+
})(typeof self === "object" ? self : this, function () {
|
|
20418
|
+
var IMAGE_EXTENSIONS = /\\.(?:gif|jpe?g|png|svg|webp)$/i;
|
|
20419
|
+
|
|
20420
|
+
function isComicImageName(name) {
|
|
20421
|
+
return typeof name === "string" && IMAGE_EXTENSIONS.test(name);
|
|
20422
|
+
}
|
|
20423
|
+
|
|
20424
|
+
function naturalCompare(left, right) {
|
|
20425
|
+
var leftParts = String(left).split(/(\\d+)/);
|
|
20426
|
+
var rightParts = String(right).split(/(\\d+)/);
|
|
20427
|
+
var length = Math.max(leftParts.length, rightParts.length);
|
|
20428
|
+
|
|
20429
|
+
for (var index = 0; index < length; index += 1) {
|
|
20430
|
+
var leftPart = leftParts[index] || "";
|
|
20431
|
+
var rightPart = rightParts[index] || "";
|
|
20432
|
+
if (leftPart === rightPart) continue;
|
|
20433
|
+
|
|
20434
|
+
var leftNumber = /^\\d+$/.test(leftPart) ? Number(leftPart) : null;
|
|
20435
|
+
var rightNumber = /^\\d+$/.test(rightPart) ? Number(rightPart) : null;
|
|
20436
|
+
if (leftNumber !== null && rightNumber !== null) {
|
|
20437
|
+
return leftNumber - rightNumber;
|
|
20438
|
+
}
|
|
20439
|
+
return leftPart.localeCompare(rightPart, undefined, {
|
|
20440
|
+
numeric: true,
|
|
20441
|
+
sensitivity: "base",
|
|
20442
|
+
});
|
|
20443
|
+
}
|
|
20444
|
+
|
|
20445
|
+
return 0;
|
|
20446
|
+
}
|
|
20447
|
+
|
|
20448
|
+
function sortComicPageNames(names) {
|
|
20449
|
+
return names.slice().sort(naturalCompare);
|
|
20450
|
+
}
|
|
20451
|
+
|
|
20452
|
+
function patchCbrWorkerSource(workerSource, wasmUrl) {
|
|
20453
|
+
return workerSource.replace(
|
|
20454
|
+
/new URL\\("libarchive\\.wasm",import\\.meta\\.url\\)\\.href/g,
|
|
20455
|
+
JSON.stringify(wasmUrl)
|
|
20456
|
+
);
|
|
20457
|
+
}
|
|
20458
|
+
|
|
20459
|
+
function getComicPreviewSize(width, height, maxWidth, maxHeight) {
|
|
20460
|
+
var safeWidth = Math.max(1, Number(width) || 1);
|
|
20461
|
+
var safeHeight = Math.max(1, Number(height) || 1);
|
|
20462
|
+
var widthLimit = maxWidth || 240;
|
|
20463
|
+
var heightLimit = maxHeight || 360;
|
|
20464
|
+
var scale = Math.min(1, widthLimit / safeWidth, heightLimit / safeHeight);
|
|
20465
|
+
return {
|
|
20466
|
+
width: Math.max(1, Math.round(safeWidth * scale)),
|
|
20467
|
+
height: Math.max(1, Math.round(safeHeight * scale)),
|
|
20468
|
+
};
|
|
20469
|
+
}
|
|
20470
|
+
|
|
20471
|
+
function getComicPageAspectRatio(width, height) {
|
|
20472
|
+
var safeWidth = Math.max(1, Number(width) || 1);
|
|
20473
|
+
var safeHeight = Math.max(1, Number(height) || 1);
|
|
20474
|
+
return safeWidth + " / " + safeHeight;
|
|
20475
|
+
}
|
|
20476
|
+
|
|
20477
|
+
function getProtectedComicPageIndexes(
|
|
20478
|
+
currentPage,
|
|
20479
|
+
visiblePageIndexes,
|
|
20480
|
+
loadingPageIndexes
|
|
20481
|
+
) {
|
|
20482
|
+
var protectedIndexes = new Set([
|
|
20483
|
+
currentPage - 1,
|
|
20484
|
+
currentPage,
|
|
20485
|
+
currentPage - 2,
|
|
20486
|
+
]);
|
|
20487
|
+
(visiblePageIndexes || []).forEach(function (pageIndex) {
|
|
20488
|
+
protectedIndexes.add(pageIndex);
|
|
20489
|
+
});
|
|
20490
|
+
(loadingPageIndexes || []).forEach(function (pageIndex) {
|
|
20491
|
+
protectedIndexes.add(pageIndex);
|
|
20492
|
+
});
|
|
20493
|
+
return protectedIndexes;
|
|
20494
|
+
}
|
|
20495
|
+
|
|
20496
|
+
function isCurrentComicPageLoad(
|
|
20497
|
+
loadGeneration,
|
|
20498
|
+
currentGeneration,
|
|
20499
|
+
entry,
|
|
20500
|
+
currentEntry
|
|
20501
|
+
) {
|
|
20502
|
+
return loadGeneration === currentGeneration && entry === currentEntry;
|
|
20503
|
+
}
|
|
20504
|
+
|
|
20505
|
+
return {
|
|
20506
|
+
isComicImageName: isComicImageName,
|
|
20507
|
+
sortComicPageNames: sortComicPageNames,
|
|
20508
|
+
patchCbrWorkerSource: patchCbrWorkerSource,
|
|
20509
|
+
getComicPreviewSize: getComicPreviewSize,
|
|
20510
|
+
getComicPageAspectRatio: getComicPageAspectRatio,
|
|
20511
|
+
getProtectedComicPageIndexes: getProtectedComicPageIndexes,
|
|
20512
|
+
isCurrentComicPageLoad: isCurrentComicPageLoad,
|
|
20513
|
+
};
|
|
20514
|
+
});
|
|
20515
|
+
|
|
20516
|
+
</script>
|
|
20517
|
+
<!-- @papyrus-comic-runtime:end -->
|
|
20406
20518
|
<script>
|
|
20407
20519
|
(function () {
|
|
20408
|
-
const viewer = document.getElementById(
|
|
20520
|
+
const viewer = document.getElementById('viewer');
|
|
20409
20521
|
const DEFAULT_FONT_SIZE = 16;
|
|
20410
20522
|
const TEXT_PAGE_CHUNK = 1600;
|
|
20411
20523
|
|
|
@@ -20418,27 +20530,116 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20418
20530
|
let currentPage = 1;
|
|
20419
20531
|
let pageCount = 0;
|
|
20420
20532
|
let zoom = 1.0;
|
|
20533
|
+
let rotation = 0;
|
|
20534
|
+
let comicArchive = null;
|
|
20535
|
+
let comicEntries = [];
|
|
20536
|
+
let comicContainer = null;
|
|
20537
|
+
let comicPages = [];
|
|
20538
|
+
let comicObserver = null;
|
|
20539
|
+
let comicScrollFrame = null;
|
|
20540
|
+
const comicObjectUrls = new Map();
|
|
20541
|
+
const comicLoading = new Map();
|
|
20542
|
+
const comicDimensions = new Map();
|
|
20543
|
+
const comicPreviewCache = new Map();
|
|
20544
|
+
const comicPreviewLoading = new Map();
|
|
20545
|
+
const COMIC_CACHE_LIMIT = 16;
|
|
20546
|
+
const COMIC_PREVIEW_CACHE_LIMIT = 8;
|
|
20547
|
+
const comicHelpers = window.PapyrusComicRuntime || {};
|
|
20548
|
+
const runtimeConfig = window.__PAPYRUS_RUNTIME_CONFIG__ || {};
|
|
20549
|
+
let comicDispose = null;
|
|
20550
|
+
let comicGeneration = 0;
|
|
20421
20551
|
|
|
20422
20552
|
const sendMessage = (payload) => {
|
|
20423
|
-
if (
|
|
20424
|
-
window.ReactNativeWebView &&
|
|
20425
|
-
window.ReactNativeWebView.postMessage
|
|
20426
|
-
) {
|
|
20553
|
+
if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
|
|
20427
20554
|
window.ReactNativeWebView.postMessage(JSON.stringify(payload));
|
|
20428
20555
|
return;
|
|
20429
20556
|
}
|
|
20430
20557
|
if (window.parent && window.parent !== window) {
|
|
20431
|
-
window.parent.postMessage(payload,
|
|
20558
|
+
window.parent.postMessage(payload, '*');
|
|
20432
20559
|
}
|
|
20433
20560
|
};
|
|
20434
20561
|
|
|
20435
20562
|
const sendResponse = (id, ok, data, error) => {
|
|
20436
|
-
sendMessage({ type:
|
|
20563
|
+
sendMessage({ type: 'response', id, ok, data, error });
|
|
20564
|
+
};
|
|
20565
|
+
|
|
20566
|
+
const runtimeAssetRequests = new Map();
|
|
20567
|
+
const fileChunkRequests = new Map();
|
|
20568
|
+
|
|
20569
|
+
const requestRuntimeAsset = (url, encoding) =>
|
|
20570
|
+
new Promise((resolve, reject) => {
|
|
20571
|
+
const id = \`runtime-asset-\${Date.now()}-\${Math.random()}\`;
|
|
20572
|
+
const timeout = setTimeout(() => {
|
|
20573
|
+
runtimeAssetRequests.delete(id);
|
|
20574
|
+
reject(new Error(\`Tempo esgotado ao carregar asset CBR: \${url}\`));
|
|
20575
|
+
}, 15000);
|
|
20576
|
+
runtimeAssetRequests.set(id, {resolve, reject, timeout});
|
|
20577
|
+
sendMessage({type: 'asset-request', id, url, encoding});
|
|
20578
|
+
});
|
|
20579
|
+
|
|
20580
|
+
const encodeArrayBufferAsDataUrl = async (buffer) => {
|
|
20581
|
+
const bytes = new Uint8Array(buffer);
|
|
20582
|
+
let binary = '';
|
|
20583
|
+
const chunkSize = 0x8000;
|
|
20584
|
+
for (let offset = 0; offset < bytes.length; offset += chunkSize) {
|
|
20585
|
+
binary += String.fromCharCode(
|
|
20586
|
+
...bytes.subarray(offset, Math.min(offset + chunkSize, bytes.length)),
|
|
20587
|
+
);
|
|
20588
|
+
}
|
|
20589
|
+
return \`data:application/wasm;base64,\${btoa(binary)}\`;
|
|
20590
|
+
};
|
|
20591
|
+
|
|
20592
|
+
const fetchRuntimeAsset = async (url, encoding) => {
|
|
20593
|
+
try {
|
|
20594
|
+
const response = await fetch(url);
|
|
20595
|
+
if (!response.ok) throw new Error(\`status \${response.status}\`);
|
|
20596
|
+
if (encoding === 'text') return await response.text();
|
|
20597
|
+
return await encodeArrayBufferAsDataUrl(await response.arrayBuffer());
|
|
20598
|
+
} catch {
|
|
20599
|
+
return await requestRuntimeAsset(url, encoding);
|
|
20600
|
+
}
|
|
20601
|
+
};
|
|
20602
|
+
|
|
20603
|
+
const requestLocalFileChunk = (uri, offset, length) =>
|
|
20604
|
+
new Promise((resolve, reject) => {
|
|
20605
|
+
const id = \`file-chunk-\${Date.now()}-\${Math.random()}\`;
|
|
20606
|
+
const timeout = setTimeout(() => {
|
|
20607
|
+
fileChunkRequests.delete(id);
|
|
20608
|
+
reject(new Error(\`Tempo esgotado ao ler arquivo local: \${uri}\`));
|
|
20609
|
+
}, 30000);
|
|
20610
|
+
fileChunkRequests.set(id, {resolve, reject, timeout});
|
|
20611
|
+
sendMessage({type: 'file-chunk-request', id, uri, offset, length});
|
|
20612
|
+
});
|
|
20613
|
+
|
|
20614
|
+
const readLocalFile = async (uri) => {
|
|
20615
|
+
const chunkSize = 1024 * 1024;
|
|
20616
|
+
const chunks = [];
|
|
20617
|
+
let offset = 0;
|
|
20618
|
+
let totalLength = 0;
|
|
20619
|
+
while (true) {
|
|
20620
|
+
const result = await requestLocalFileChunk(uri, offset, chunkSize);
|
|
20621
|
+
const bytes = decodeBase64(result.data || '');
|
|
20622
|
+
if (bytes.length === 0 && !result.done) {
|
|
20623
|
+
throw new Error('Leitura nativa retornou um chunk vazio.');
|
|
20624
|
+
}
|
|
20625
|
+
chunks.push(bytes);
|
|
20626
|
+
totalLength += bytes.length;
|
|
20627
|
+
offset += bytes.length;
|
|
20628
|
+
if (result.done) break;
|
|
20629
|
+
}
|
|
20630
|
+
|
|
20631
|
+
const output = new Uint8Array(totalLength);
|
|
20632
|
+
let outputOffset = 0;
|
|
20633
|
+
chunks.forEach((chunk) => {
|
|
20634
|
+
output.set(chunk, outputOffset);
|
|
20635
|
+
outputOffset += chunk.length;
|
|
20636
|
+
});
|
|
20637
|
+
return output.buffer;
|
|
20437
20638
|
};
|
|
20438
20639
|
|
|
20439
20640
|
const sendState = (extra) => {
|
|
20440
20641
|
sendMessage({
|
|
20441
|
-
type:
|
|
20642
|
+
type: 'state',
|
|
20442
20643
|
payload: {
|
|
20443
20644
|
pageCount,
|
|
20444
20645
|
currentPage,
|
|
@@ -20449,70 +20650,66 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20449
20650
|
};
|
|
20450
20651
|
|
|
20451
20652
|
const sendEvent = (name, payload) => {
|
|
20452
|
-
sendMessage({ type:
|
|
20453
|
-
};
|
|
20454
|
-
|
|
20455
|
-
const log = (...args) => {
|
|
20456
|
-
sendEvent("RUNTIME_LOG", {
|
|
20457
|
-
message: args.map((value) => String(value)).join(" "),
|
|
20458
|
-
});
|
|
20653
|
+
sendMessage({ type: 'event', name, payload });
|
|
20459
20654
|
};
|
|
20460
20655
|
|
|
20461
20656
|
const reportError = (error, context) => {
|
|
20462
|
-
const message =
|
|
20463
|
-
error && error.message ? error.message : String(error);
|
|
20657
|
+
const message = error && error.message ? error.message : String(error);
|
|
20464
20658
|
const stack = error && error.stack ? error.stack : null;
|
|
20465
|
-
sendEvent(
|
|
20466
|
-
};
|
|
20467
|
-
|
|
20468
|
-
const EPUB_OPEN_TIMEOUT_MS = 180000;
|
|
20469
|
-
const EPUB_READY_TIMEOUT_MS = 180000;
|
|
20470
|
-
const EPUB_DISPLAY_TIMEOUT_MS = 30000;
|
|
20471
|
-
|
|
20472
|
-
const withTimeout = async (promise, ms, label) => {
|
|
20473
|
-
let timer = null;
|
|
20474
|
-
try {
|
|
20475
|
-
return await Promise.race([
|
|
20476
|
-
promise,
|
|
20477
|
-
new Promise((_, reject) => {
|
|
20478
|
-
timer = setTimeout(
|
|
20479
|
-
() => reject(new Error(\`Timeout: \${label}\`)),
|
|
20480
|
-
ms
|
|
20481
|
-
);
|
|
20482
|
-
}),
|
|
20483
|
-
]);
|
|
20484
|
-
} finally {
|
|
20485
|
-
if (timer) {
|
|
20486
|
-
clearTimeout(timer);
|
|
20487
|
-
}
|
|
20488
|
-
}
|
|
20659
|
+
sendEvent('RUNTIME_ERROR', { message, context, stack });
|
|
20489
20660
|
};
|
|
20490
20661
|
|
|
20491
20662
|
const shouldIgnoreError = (error) => {
|
|
20492
|
-
const message =
|
|
20493
|
-
|
|
20494
|
-
return message.includes("ResizeObserver loop");
|
|
20663
|
+
const message = error && error.message ? error.message : String(error || '');
|
|
20664
|
+
return message.includes('ResizeObserver loop');
|
|
20495
20665
|
};
|
|
20496
20666
|
|
|
20497
|
-
window.addEventListener(
|
|
20667
|
+
window.addEventListener('error', (event) => {
|
|
20498
20668
|
const error = event.error || event.message;
|
|
20499
20669
|
if (shouldIgnoreError(error)) return;
|
|
20500
|
-
reportError(error,
|
|
20670
|
+
reportError(error, 'window.error');
|
|
20501
20671
|
});
|
|
20502
20672
|
|
|
20503
|
-
window.addEventListener(
|
|
20673
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
20504
20674
|
if (shouldIgnoreError(event.reason)) return;
|
|
20505
|
-
reportError(event.reason,
|
|
20675
|
+
reportError(event.reason, 'unhandledrejection');
|
|
20506
20676
|
});
|
|
20507
20677
|
|
|
20678
|
+
const clearComicState = () => {
|
|
20679
|
+
comicGeneration += 1;
|
|
20680
|
+
if (comicObserver) {
|
|
20681
|
+
comicObserver.disconnect();
|
|
20682
|
+
comicObserver = null;
|
|
20683
|
+
}
|
|
20684
|
+
if (comicScrollFrame !== null) {
|
|
20685
|
+
cancelAnimationFrame(comicScrollFrame);
|
|
20686
|
+
comicScrollFrame = null;
|
|
20687
|
+
}
|
|
20688
|
+
comicObjectUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
20689
|
+
comicObjectUrls.clear();
|
|
20690
|
+
comicLoading.clear();
|
|
20691
|
+
comicDimensions.clear();
|
|
20692
|
+
comicPreviewCache.clear();
|
|
20693
|
+
comicPreviewLoading.clear();
|
|
20694
|
+
if (comicDispose) {
|
|
20695
|
+
void comicDispose();
|
|
20696
|
+
comicDispose = null;
|
|
20697
|
+
}
|
|
20698
|
+
comicArchive = null;
|
|
20699
|
+
comicEntries = [];
|
|
20700
|
+
comicContainer = null;
|
|
20701
|
+
comicPages = [];
|
|
20702
|
+
};
|
|
20703
|
+
|
|
20508
20704
|
const clearViewer = () => {
|
|
20705
|
+
clearComicState();
|
|
20509
20706
|
while (viewer.firstChild) {
|
|
20510
20707
|
viewer.removeChild(viewer.firstChild);
|
|
20511
20708
|
}
|
|
20512
20709
|
};
|
|
20513
20710
|
|
|
20514
20711
|
const decodeBase64 = (value) => {
|
|
20515
|
-
const clean = value.replace(/\\s/g,
|
|
20712
|
+
const clean = value.replace(/\\s/g, '');
|
|
20516
20713
|
const binary = atob(clean);
|
|
20517
20714
|
const len = binary.length;
|
|
20518
20715
|
const bytes = new Uint8Array(len);
|
|
@@ -20524,41 +20721,438 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20524
20721
|
|
|
20525
20722
|
const decodeBase64ToText = (value) => {
|
|
20526
20723
|
const bytes = decodeBase64(value);
|
|
20527
|
-
return new TextDecoder(
|
|
20724
|
+
return new TextDecoder('utf-8').decode(bytes);
|
|
20528
20725
|
};
|
|
20529
20726
|
|
|
20530
|
-
const
|
|
20531
|
-
|
|
20532
|
-
|
|
20533
|
-
|
|
20534
|
-
|
|
20535
|
-
|
|
20727
|
+
const sourceToArrayBuffer = async (source) => {
|
|
20728
|
+
if (source.kind === 'uri') {
|
|
20729
|
+
if (/^(?:file|content):\\/\\//i.test(source.uri)) {
|
|
20730
|
+
return readLocalFile(source.uri);
|
|
20731
|
+
}
|
|
20732
|
+
const response = await fetch(source.uri);
|
|
20733
|
+
if (!response.ok && response.status !== 0) {
|
|
20734
|
+
throw new Error(\`Falha ao carregar quadrinho (\${response.status})\`);
|
|
20735
|
+
}
|
|
20736
|
+
return response.arrayBuffer();
|
|
20737
|
+
}
|
|
20738
|
+
if (source.kind === 'base64') {
|
|
20739
|
+
return decodeBase64(source.data).buffer;
|
|
20740
|
+
}
|
|
20741
|
+
throw new Error('Fonte de quadrinho inv\xE1lida.');
|
|
20742
|
+
};
|
|
20743
|
+
|
|
20744
|
+
const comicMimeType = (name) => {
|
|
20745
|
+
const extension = name.split('.').pop()?.toLowerCase();
|
|
20746
|
+
if (extension === 'png') return 'image/png';
|
|
20747
|
+
if (extension === 'gif') return 'image/gif';
|
|
20748
|
+
if (extension === 'svg') return 'image/svg+xml';
|
|
20749
|
+
if (extension === 'webp') return 'image/webp';
|
|
20750
|
+
return 'image/jpeg';
|
|
20751
|
+
};
|
|
20752
|
+
|
|
20753
|
+
const updateComicCurrentPage = () => {
|
|
20754
|
+
if (!comicContainer || comicPages.length === 0) return;
|
|
20755
|
+
const viewportTop = comicContainer.scrollTop;
|
|
20756
|
+
let closestIndex = currentPage - 1;
|
|
20757
|
+
let closestDistance = Number.POSITIVE_INFINITY;
|
|
20758
|
+
comicPages.forEach((page, index) => {
|
|
20759
|
+
const distance = Math.abs(page.offsetTop - viewportTop);
|
|
20760
|
+
if (distance < closestDistance) {
|
|
20761
|
+
closestDistance = distance;
|
|
20762
|
+
closestIndex = index;
|
|
20763
|
+
}
|
|
20764
|
+
});
|
|
20765
|
+
const nextPage = Math.max(1, Math.min(pageCount, closestIndex + 1));
|
|
20766
|
+
if (nextPage !== currentPage) {
|
|
20767
|
+
currentPage = nextPage;
|
|
20768
|
+
sendState();
|
|
20769
|
+
}
|
|
20770
|
+
};
|
|
20771
|
+
|
|
20772
|
+
const scheduleComicCurrentPage = () => {
|
|
20773
|
+
if (comicScrollFrame !== null) return;
|
|
20774
|
+
comicScrollFrame = requestAnimationFrame(() => {
|
|
20775
|
+
comicScrollFrame = null;
|
|
20776
|
+
updateComicCurrentPage();
|
|
20777
|
+
});
|
|
20778
|
+
};
|
|
20779
|
+
|
|
20780
|
+
const evictComicUrls = () => {
|
|
20781
|
+
if (comicObjectUrls.size <= COMIC_CACHE_LIMIT) return;
|
|
20782
|
+
const protectedIndexes = new Set([
|
|
20783
|
+
currentPage - 1,
|
|
20784
|
+
currentPage,
|
|
20785
|
+
currentPage - 2,
|
|
20786
|
+
]);
|
|
20787
|
+
for (const [index, url] of comicObjectUrls) {
|
|
20788
|
+
if (comicObjectUrls.size <= COMIC_CACHE_LIMIT) break;
|
|
20789
|
+
if (protectedIndexes.has(index)) continue;
|
|
20790
|
+
URL.revokeObjectURL(url);
|
|
20791
|
+
comicObjectUrls.delete(index);
|
|
20792
|
+
const image = comicPages[index]?.querySelector('img');
|
|
20793
|
+
const page = comicPages[index];
|
|
20794
|
+
const dimensions = comicDimensions.get(index);
|
|
20795
|
+
const width = dimensions?.width || image?.naturalWidth || 0;
|
|
20796
|
+
const height = dimensions?.height || image?.naturalHeight || 0;
|
|
20797
|
+
if (page && width > 0 && height > 0) {
|
|
20798
|
+
page.style.aspectRatio = comicHelpers.getComicPageAspectRatio(
|
|
20799
|
+
width,
|
|
20800
|
+
height
|
|
20801
|
+
);
|
|
20802
|
+
}
|
|
20803
|
+
if (image) image.removeAttribute('src');
|
|
20804
|
+
}
|
|
20805
|
+
};
|
|
20806
|
+
|
|
20807
|
+
const ensureComicPage = async (pageIndex) => {
|
|
20808
|
+
if (comicObjectUrls.has(pageIndex)) {
|
|
20809
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
20810
|
+
if (image && !image.src) image.src = comicObjectUrls.get(pageIndex);
|
|
20811
|
+
return comicObjectUrls.get(pageIndex);
|
|
20812
|
+
}
|
|
20813
|
+
if (comicLoading.has(pageIndex)) return comicLoading.get(pageIndex);
|
|
20814
|
+
|
|
20815
|
+
const entry = comicEntries[pageIndex];
|
|
20816
|
+
if (!entry) throw new Error(\`P\xE1gina de quadrinho inv\xE1lida: \${pageIndex}\`);
|
|
20817
|
+
const loadGeneration = comicGeneration;
|
|
20818
|
+
const pending = entry.async('blob').then((blob) => {
|
|
20819
|
+
if (
|
|
20820
|
+
!comicHelpers.isCurrentComicPageLoad(
|
|
20821
|
+
loadGeneration,
|
|
20822
|
+
comicGeneration,
|
|
20823
|
+
entry,
|
|
20824
|
+
comicEntries[pageIndex]
|
|
20825
|
+
)
|
|
20826
|
+
) {
|
|
20827
|
+
return null;
|
|
20828
|
+
}
|
|
20829
|
+
const url = URL.createObjectURL(
|
|
20830
|
+
new Blob([blob], { type: comicMimeType(entry.name) })
|
|
20536
20831
|
);
|
|
20832
|
+
comicObjectUrls.set(pageIndex, url);
|
|
20833
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
20834
|
+
if (image) image.src = url;
|
|
20835
|
+
evictComicUrls();
|
|
20836
|
+
return url;
|
|
20837
|
+
});
|
|
20838
|
+
comicLoading.set(pageIndex, pending);
|
|
20839
|
+
try {
|
|
20840
|
+
return await pending;
|
|
20841
|
+
} finally {
|
|
20842
|
+
if (comicLoading.get(pageIndex) === pending) {
|
|
20843
|
+
comicLoading.delete(pageIndex);
|
|
20844
|
+
}
|
|
20537
20845
|
}
|
|
20538
|
-
|
|
20539
|
-
|
|
20846
|
+
};
|
|
20847
|
+
|
|
20848
|
+
const renderComicPage = (pageIndex) => {
|
|
20849
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
20850
|
+
if (!image) return;
|
|
20851
|
+
image.style.width = \`\${Math.max(40, Math.round(100 * zoom))}%\`;
|
|
20852
|
+
image.style.transform = \`rotate(\${rotation}deg)\`;
|
|
20853
|
+
};
|
|
20854
|
+
|
|
20855
|
+
const applyComicLayout = () => {
|
|
20856
|
+
comicPages.forEach((_, pageIndex) => renderComicPage(pageIndex));
|
|
20857
|
+
};
|
|
20858
|
+
|
|
20859
|
+
const loadComic = async (source, format) => {
|
|
20860
|
+
clearViewer();
|
|
20861
|
+
let entries;
|
|
20862
|
+
if (format === 'cbr') {
|
|
20863
|
+
const clientUrl = runtimeConfig.cbrClientUrl;
|
|
20864
|
+
const workerUrl = runtimeConfig.cbrWorkerUrl;
|
|
20865
|
+
const wasmUrl = runtimeConfig.cbrWasmUrl;
|
|
20866
|
+
if (!clientUrl || !workerUrl || !wasmUrl) {
|
|
20867
|
+
throw new Error(
|
|
20868
|
+
'CBR no mobile exige o pacote opcional de runtime libarchive.'
|
|
20869
|
+
);
|
|
20870
|
+
}
|
|
20871
|
+
|
|
20872
|
+
const [clientSource, workerSource, wasmSource] = await Promise.all([
|
|
20873
|
+
fetchRuntimeAsset(clientUrl, 'text'),
|
|
20874
|
+
fetchRuntimeAsset(workerUrl, 'text'),
|
|
20875
|
+
runtimeConfig.cbrWasmDataUrl ||
|
|
20876
|
+
fetchRuntimeAsset(wasmUrl, 'base64'),
|
|
20877
|
+
]);
|
|
20878
|
+
const patchedWorkerSource = comicHelpers.patchCbrWorkerSource(
|
|
20879
|
+
workerSource,
|
|
20880
|
+
wasmSource
|
|
20881
|
+
);
|
|
20882
|
+
const workerObjectUrl = URL.createObjectURL(
|
|
20883
|
+
new Blob([patchedWorkerSource], {type: 'text/javascript'})
|
|
20884
|
+
);
|
|
20885
|
+
const clientObjectUrl = URL.createObjectURL(
|
|
20886
|
+
new Blob([clientSource], { type: 'text/javascript' })
|
|
20887
|
+
);
|
|
20888
|
+
try {
|
|
20889
|
+
const archiveModule = await import(clientObjectUrl);
|
|
20890
|
+
const createCbrWorker = () => {
|
|
20891
|
+
const worker = new Worker(workerObjectUrl, {type: 'module'});
|
|
20892
|
+
worker.addEventListener('error', (event) => {
|
|
20893
|
+
sendEvent('RUNTIME_ERROR', {
|
|
20894
|
+
message: \`CBR worker: \${event?.message || 'falha ao executar o worker'}\`,
|
|
20895
|
+
context: 'comic.worker',
|
|
20896
|
+
});
|
|
20897
|
+
});
|
|
20898
|
+
worker.addEventListener('messageerror', () => {
|
|
20899
|
+
sendEvent('RUNTIME_ERROR', {
|
|
20900
|
+
message: 'CBR worker: falha ao transferir mensagem',
|
|
20901
|
+
context: 'comic.worker',
|
|
20902
|
+
});
|
|
20903
|
+
});
|
|
20904
|
+
return worker;
|
|
20905
|
+
};
|
|
20906
|
+
archiveModule.Archive.init({getWorker: createCbrWorker});
|
|
20907
|
+
const bytes = await sourceToArrayBuffer(source);
|
|
20908
|
+
const file = new Blob([bytes], {
|
|
20909
|
+
type: 'application/vnd.comicbook-rar',
|
|
20910
|
+
});
|
|
20911
|
+
const archive = await archiveModule.Archive.open(file);
|
|
20912
|
+
const files = await archive.getFilesArray();
|
|
20913
|
+
entries = files
|
|
20914
|
+
.filter(
|
|
20915
|
+
(item) => {
|
|
20916
|
+
const name = \`\${item?.path || ''}\${item?.file?.name || ''}\`;
|
|
20917
|
+
return item?.file && comicHelpers.isComicImageName(name);
|
|
20918
|
+
}
|
|
20919
|
+
)
|
|
20920
|
+
.map((item) => {
|
|
20921
|
+
const name = \`\${item.path || ''}\${item.file.name}\`;
|
|
20922
|
+
return {
|
|
20923
|
+
name,
|
|
20924
|
+
async: async () => item.file.extract(),
|
|
20925
|
+
};
|
|
20926
|
+
});
|
|
20927
|
+
comicDispose = async () => {
|
|
20928
|
+
await archive.close();
|
|
20929
|
+
URL.revokeObjectURL(workerObjectUrl);
|
|
20930
|
+
URL.revokeObjectURL(clientObjectUrl);
|
|
20931
|
+
};
|
|
20932
|
+
} catch (error) {
|
|
20933
|
+
URL.revokeObjectURL(workerObjectUrl);
|
|
20934
|
+
URL.revokeObjectURL(clientObjectUrl);
|
|
20935
|
+
throw error;
|
|
20936
|
+
}
|
|
20937
|
+
} else {
|
|
20938
|
+
if (!window.JSZip) {
|
|
20939
|
+
throw new Error('O runtime ZIP do leitor mobile n\xE3o foi carregado.');
|
|
20940
|
+
}
|
|
20941
|
+
|
|
20942
|
+
const bytes = await sourceToArrayBuffer(source);
|
|
20943
|
+
comicArchive = await window.JSZip.loadAsync(bytes);
|
|
20944
|
+
entries = Object.keys(comicArchive.files)
|
|
20945
|
+
.filter((name) => {
|
|
20946
|
+
const entry = comicArchive.files[name];
|
|
20947
|
+
return !entry.dir && comicHelpers.isComicImageName(name);
|
|
20948
|
+
})
|
|
20949
|
+
.map((name) => comicArchive.files[name]);
|
|
20950
|
+
}
|
|
20951
|
+
|
|
20952
|
+
const names = comicHelpers.sortComicPageNames(
|
|
20953
|
+
entries.map((entry) => entry.name)
|
|
20954
|
+
);
|
|
20955
|
+
const entriesByName = new Map(entries.map((entry) => [entry.name, entry]));
|
|
20956
|
+
comicEntries = names.map((name) => entriesByName.get(name));
|
|
20957
|
+
if (comicEntries.length === 0) {
|
|
20958
|
+
if (comicDispose) {
|
|
20959
|
+
await comicDispose();
|
|
20960
|
+
comicDispose = null;
|
|
20961
|
+
}
|
|
20962
|
+
throw new Error('O arquivo n\xE3o cont\xE9m p\xE1ginas de imagem.');
|
|
20963
|
+
}
|
|
20964
|
+
|
|
20965
|
+
comicContainer = document.createElement('div');
|
|
20966
|
+
comicContainer.style.width = '100%';
|
|
20967
|
+
comicContainer.style.height = '100%';
|
|
20968
|
+
comicContainer.style.overflow = 'auto';
|
|
20969
|
+
comicContainer.style.padding = '16px 0 120px';
|
|
20970
|
+
comicContainer.style.boxSizing = 'border-box';
|
|
20971
|
+
comicContainer.style.background = '#ffffff';
|
|
20972
|
+
comicContainer.addEventListener('scroll', scheduleComicCurrentPage, {
|
|
20973
|
+
passive: true,
|
|
20974
|
+
});
|
|
20975
|
+
viewer.style.overflow = 'hidden';
|
|
20976
|
+
viewer.appendChild(comicContainer);
|
|
20977
|
+
|
|
20978
|
+
comicPages = comicEntries.map((entry, pageIndex) => {
|
|
20979
|
+
const page = document.createElement('div');
|
|
20980
|
+
page.dataset.pageIndex = String(pageIndex);
|
|
20981
|
+
page.style.width = '100%';
|
|
20982
|
+
page.style.minHeight = '80px';
|
|
20983
|
+
page.style.display = 'flex';
|
|
20984
|
+
page.style.justifyContent = 'center';
|
|
20985
|
+
page.style.alignItems = 'flex-start';
|
|
20986
|
+
page.style.padding = '0 12px 20px';
|
|
20987
|
+
page.style.boxSizing = 'border-box';
|
|
20988
|
+
|
|
20989
|
+
const image = document.createElement('img');
|
|
20990
|
+
image.alt = \`P\xE1gina \${pageIndex + 1}\`;
|
|
20991
|
+
image.draggable = false;
|
|
20992
|
+
image.decoding = 'async';
|
|
20993
|
+
image.loading = 'lazy';
|
|
20994
|
+
image.style.display = 'block';
|
|
20995
|
+
image.style.maxWidth = 'none';
|
|
20996
|
+
image.style.height = 'auto';
|
|
20997
|
+
image.style.userSelect = 'none';
|
|
20998
|
+
image.addEventListener('load', () => {
|
|
20999
|
+
if (image.naturalWidth > 0 && image.naturalHeight > 0) {
|
|
21000
|
+
comicDimensions.set(pageIndex, {
|
|
21001
|
+
width: image.naturalWidth,
|
|
21002
|
+
height: image.naturalHeight,
|
|
21003
|
+
});
|
|
21004
|
+
page.style.aspectRatio = comicHelpers.getComicPageAspectRatio(
|
|
21005
|
+
image.naturalWidth,
|
|
21006
|
+
image.naturalHeight
|
|
21007
|
+
);
|
|
21008
|
+
}
|
|
21009
|
+
});
|
|
21010
|
+
page.appendChild(image);
|
|
21011
|
+
comicContainer.appendChild(page);
|
|
21012
|
+
return page;
|
|
21013
|
+
});
|
|
21014
|
+
|
|
21015
|
+
if (typeof IntersectionObserver === 'function') {
|
|
21016
|
+
comicObserver = new IntersectionObserver(
|
|
21017
|
+
(observations) => {
|
|
21018
|
+
observations.forEach((observation) => {
|
|
21019
|
+
if (!observation.isIntersecting) return;
|
|
21020
|
+
const pageIndex = Number(observation.target.dataset.pageIndex);
|
|
21021
|
+
void ensureComicPage(pageIndex).catch((error) =>
|
|
21022
|
+
sendEvent('RUNTIME_ERROR', {
|
|
21023
|
+
message: error?.message || String(error),
|
|
21024
|
+
context: 'comic.page',
|
|
21025
|
+
})
|
|
21026
|
+
);
|
|
21027
|
+
});
|
|
21028
|
+
scheduleComicCurrentPage();
|
|
21029
|
+
},
|
|
21030
|
+
{ root: comicContainer, rootMargin: '600px 0px' }
|
|
21031
|
+
);
|
|
21032
|
+
comicPages.forEach((page) => comicObserver.observe(page));
|
|
21033
|
+
} else {
|
|
21034
|
+
for (let pageIndex = 0; pageIndex < Math.min(3, comicPages.length); pageIndex += 1) {
|
|
21035
|
+
void ensureComicPage(pageIndex);
|
|
21036
|
+
}
|
|
20540
21037
|
}
|
|
20541
|
-
|
|
20542
|
-
|
|
21038
|
+
pageCount = comicPages.length;
|
|
21039
|
+
currentPage = 1;
|
|
21040
|
+
await ensureComicPage(0);
|
|
21041
|
+
applyComicLayout();
|
|
21042
|
+
return { pageCount };
|
|
21043
|
+
};
|
|
21044
|
+
|
|
21045
|
+
const readComicBlobAsDataUrl = (blob, mimeType) =>
|
|
21046
|
+
new Promise((resolve, reject) => {
|
|
20543
21047
|
const reader = new FileReader();
|
|
20544
|
-
reader.onerror = () =>
|
|
20545
|
-
reject(new Error("Failed to read epub blob"));
|
|
21048
|
+
reader.onerror = () => reject(new Error('Falha ao gerar preview.'));
|
|
20546
21049
|
reader.onload = () => resolve(reader.result);
|
|
20547
|
-
reader.
|
|
21050
|
+
reader.readAsDataURL(new Blob([blob], { type: mimeType }));
|
|
20548
21051
|
});
|
|
21052
|
+
|
|
21053
|
+
const createComicPagePreview = async (pageIndex) => {
|
|
21054
|
+
const entry = comicEntries[pageIndex];
|
|
21055
|
+
if (!entry) return null;
|
|
21056
|
+
const mimeType = comicMimeType(entry.name);
|
|
21057
|
+
const sourceUrl = await ensureComicPage(pageIndex);
|
|
21058
|
+
if (!sourceUrl) return null;
|
|
21059
|
+
try {
|
|
21060
|
+
const image = new Image();
|
|
21061
|
+
image.decoding = 'async';
|
|
21062
|
+
await new Promise((resolve, reject) => {
|
|
21063
|
+
image.onload = resolve;
|
|
21064
|
+
image.onerror = () => reject(new Error('Falha ao decodificar preview.'));
|
|
21065
|
+
image.src = sourceUrl;
|
|
21066
|
+
});
|
|
21067
|
+
const size = comicHelpers.getComicPreviewSize(
|
|
21068
|
+
image.naturalWidth || image.width,
|
|
21069
|
+
image.naturalHeight || image.height
|
|
21070
|
+
);
|
|
21071
|
+
const canvas = document.createElement('canvas');
|
|
21072
|
+
canvas.width = size.width;
|
|
21073
|
+
canvas.height = size.height;
|
|
21074
|
+
const context = canvas.getContext('2d');
|
|
21075
|
+
if (!context) throw new Error('Canvas indispon\xEDvel para preview.');
|
|
21076
|
+
context.fillStyle = '#ffffff';
|
|
21077
|
+
context.fillRect(0, 0, size.width, size.height);
|
|
21078
|
+
context.drawImage(image, 0, 0, size.width, size.height);
|
|
21079
|
+
return canvas.toDataURL('image/jpeg', 0.78);
|
|
21080
|
+
} catch {
|
|
21081
|
+
try {
|
|
21082
|
+
const response = await fetch(sourceUrl);
|
|
21083
|
+
const blob = await response.blob();
|
|
21084
|
+
return await readComicBlobAsDataUrl(blob, mimeType);
|
|
21085
|
+
} catch {
|
|
21086
|
+
return null;
|
|
21087
|
+
}
|
|
21088
|
+
}
|
|
21089
|
+
};
|
|
21090
|
+
|
|
21091
|
+
const getComicPagePreview = async (pageIndex) => {
|
|
21092
|
+
const entry = comicEntries[pageIndex];
|
|
21093
|
+
if (!entry) return null;
|
|
21094
|
+
if (comicPreviewCache.has(pageIndex)) {
|
|
21095
|
+
return comicPreviewCache.get(pageIndex);
|
|
21096
|
+
}
|
|
21097
|
+
if (comicPreviewLoading.has(pageIndex)) {
|
|
21098
|
+
return comicPreviewLoading.get(pageIndex);
|
|
21099
|
+
}
|
|
21100
|
+
const loadGeneration = comicGeneration;
|
|
21101
|
+
const pending = createComicPagePreview(pageIndex).then((preview) => {
|
|
21102
|
+
if (
|
|
21103
|
+
!comicHelpers.isCurrentComicPageLoad(
|
|
21104
|
+
loadGeneration,
|
|
21105
|
+
comicGeneration,
|
|
21106
|
+
entry,
|
|
21107
|
+
comicEntries[pageIndex]
|
|
21108
|
+
)
|
|
21109
|
+
) {
|
|
21110
|
+
return null;
|
|
21111
|
+
}
|
|
21112
|
+
comicPreviewCache.set(pageIndex, preview);
|
|
21113
|
+
while (comicPreviewCache.size > COMIC_PREVIEW_CACHE_LIMIT) {
|
|
21114
|
+
comicPreviewCache.delete(comicPreviewCache.keys().next().value);
|
|
21115
|
+
}
|
|
21116
|
+
return preview;
|
|
21117
|
+
});
|
|
21118
|
+
comicPreviewLoading.set(pageIndex, pending);
|
|
21119
|
+
try {
|
|
21120
|
+
return await pending;
|
|
21121
|
+
} finally {
|
|
21122
|
+
if (comicPreviewLoading.get(pageIndex) === pending) {
|
|
21123
|
+
comicPreviewLoading.delete(pageIndex);
|
|
21124
|
+
}
|
|
21125
|
+
}
|
|
21126
|
+
};
|
|
21127
|
+
|
|
21128
|
+
const getComicPageDimensions = async (pageIndex) => {
|
|
21129
|
+
const known = comicDimensions.get(pageIndex);
|
|
21130
|
+
if (known) return known;
|
|
21131
|
+
await ensureComicPage(pageIndex);
|
|
21132
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
21133
|
+
if (image && !image.complete) {
|
|
21134
|
+
await new Promise((resolve) => {
|
|
21135
|
+
image.addEventListener('load', resolve, { once: true });
|
|
21136
|
+
image.addEventListener('error', resolve, { once: true });
|
|
21137
|
+
});
|
|
21138
|
+
}
|
|
21139
|
+
return (
|
|
21140
|
+
comicDimensions.get(pageIndex) || {
|
|
21141
|
+
width: image?.naturalWidth || 0,
|
|
21142
|
+
height: image?.naturalHeight || 0,
|
|
21143
|
+
}
|
|
21144
|
+
);
|
|
20549
21145
|
};
|
|
20550
21146
|
|
|
20551
21147
|
const normalizeHref = (href) => {
|
|
20552
|
-
if (!href) return
|
|
20553
|
-
return href.split(
|
|
21148
|
+
if (!href) return '';
|
|
21149
|
+
return href.split('#')[0];
|
|
20554
21150
|
};
|
|
20555
21151
|
|
|
20556
21152
|
const getSpineIndexByHref = (href) => {
|
|
20557
21153
|
const normalized = normalizeHref(href);
|
|
20558
21154
|
if (!normalized) return -1;
|
|
20559
|
-
return spineItems.findIndex(
|
|
20560
|
-
(item) => normalizeHref(item.href) === normalized
|
|
20561
|
-
);
|
|
21155
|
+
return spineItems.findIndex((item) => normalizeHref(item.href) === normalized);
|
|
20562
21156
|
};
|
|
20563
21157
|
|
|
20564
21158
|
const buildOutline = async () => {
|
|
@@ -20567,11 +21161,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20567
21161
|
const toc = nav && nav.toc ? nav.toc : [];
|
|
20568
21162
|
|
|
20569
21163
|
const mapItem = (item) => {
|
|
20570
|
-
const title = item.label || item.title ||
|
|
20571
|
-
const pageIndex = getSpineIndexByHref(item.href ||
|
|
20572
|
-
const children = Array.isArray(item.subitems)
|
|
20573
|
-
? item.subitems.map(mapItem)
|
|
20574
|
-
: [];
|
|
21164
|
+
const title = item.label || item.title || '';
|
|
21165
|
+
const pageIndex = getSpineIndexByHref(item.href || '');
|
|
21166
|
+
const children = Array.isArray(item.subitems) ? item.subitems.map(mapItem) : [];
|
|
20575
21167
|
const outlineItem = { title, pageIndex };
|
|
20576
21168
|
if (children.length > 0) outlineItem.children = children;
|
|
20577
21169
|
return outlineItem;
|
|
@@ -20583,10 +21175,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20583
21175
|
const applyEpubZoom = () => {
|
|
20584
21176
|
if (!rendition || !rendition.themes) return;
|
|
20585
21177
|
const fontSize = \`\${Math.round(zoom * 100)}%\`;
|
|
20586
|
-
if (typeof rendition.themes.fontSize ===
|
|
21178
|
+
if (typeof rendition.themes.fontSize === 'function') {
|
|
20587
21179
|
rendition.themes.fontSize(fontSize);
|
|
20588
|
-
} else if (typeof rendition.themes.override ===
|
|
20589
|
-
rendition.themes.override(
|
|
21180
|
+
} else if (typeof rendition.themes.override === 'function') {
|
|
21181
|
+
rendition.themes.override('font-size', fontSize);
|
|
20590
21182
|
}
|
|
20591
21183
|
};
|
|
20592
21184
|
|
|
@@ -20597,14 +21189,13 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20597
21189
|
};
|
|
20598
21190
|
|
|
20599
21191
|
const renderTextPage = (pageIndex) => {
|
|
20600
|
-
const text = textPages[pageIndex] ||
|
|
21192
|
+
const text = textPages[pageIndex] || '';
|
|
20601
21193
|
if (!textContainer) {
|
|
20602
|
-
textContainer = document.createElement(
|
|
20603
|
-
textContainer.style.padding =
|
|
20604
|
-
textContainer.style.lineHeight =
|
|
20605
|
-
textContainer.style.whiteSpace =
|
|
20606
|
-
textContainer.style.fontFamily =
|
|
20607
|
-
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace';
|
|
21194
|
+
textContainer = document.createElement('div');
|
|
21195
|
+
textContainer.style.padding = '24px';
|
|
21196
|
+
textContainer.style.lineHeight = '1.6';
|
|
21197
|
+
textContainer.style.whiteSpace = 'pre-wrap';
|
|
21198
|
+
textContainer.style.fontFamily = 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace';
|
|
20608
21199
|
viewer.appendChild(textContainer);
|
|
20609
21200
|
}
|
|
20610
21201
|
textContainer.textContent = text;
|
|
@@ -20616,18 +21207,18 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20616
21207
|
for (let i = 0; i < text.length; i += TEXT_PAGE_CHUNK) {
|
|
20617
21208
|
pages.push(text.slice(i, i + TEXT_PAGE_CHUNK));
|
|
20618
21209
|
}
|
|
20619
|
-
return pages.length > 0 ? pages : [
|
|
21210
|
+
return pages.length > 0 ? pages : [''];
|
|
20620
21211
|
};
|
|
20621
21212
|
|
|
20622
21213
|
const loadText = async (source) => {
|
|
20623
|
-
let text =
|
|
20624
|
-
if (source.kind ===
|
|
21214
|
+
let text = '';
|
|
21215
|
+
if (source.kind === 'uri') {
|
|
20625
21216
|
const res = await fetch(source.uri);
|
|
20626
21217
|
text = await res.text();
|
|
20627
|
-
} else if (source.kind ===
|
|
21218
|
+
} else if (source.kind === 'base64') {
|
|
20628
21219
|
text = decodeBase64ToText(source.data);
|
|
20629
|
-
} else if (source.kind ===
|
|
20630
|
-
text = source.text ||
|
|
21220
|
+
} else if (source.kind === 'text') {
|
|
21221
|
+
text = source.text || '';
|
|
20631
21222
|
}
|
|
20632
21223
|
|
|
20633
21224
|
clearViewer();
|
|
@@ -20640,44 +21231,25 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20640
21231
|
};
|
|
20641
21232
|
|
|
20642
21233
|
const loadEpub = async (source) => {
|
|
20643
|
-
|
|
20644
|
-
if (rendition && typeof rendition.destroy === "function") {
|
|
21234
|
+
if (rendition && typeof rendition.destroy === 'function') {
|
|
20645
21235
|
rendition.destroy();
|
|
20646
21236
|
}
|
|
20647
|
-
if (book && typeof book.destroy ===
|
|
21237
|
+
if (book && typeof book.destroy === 'function') {
|
|
20648
21238
|
book.destroy();
|
|
20649
21239
|
}
|
|
20650
21240
|
|
|
20651
|
-
|
|
20652
|
-
|
|
20653
|
-
|
|
20654
|
-
|
|
20655
|
-
|
|
20656
|
-
|
|
20657
|
-
);
|
|
20658
|
-
|
|
20659
|
-
log("epub.load:fetch-uri");
|
|
20660
|
-
const data = await withTimeout(
|
|
20661
|
-
fetchUriAsArrayBuffer(source.uri),
|
|
20662
|
-
EPUB_OPEN_TIMEOUT_MS,
|
|
20663
|
-
"epub.fetch"
|
|
20664
|
-
);
|
|
20665
|
-
const input = data instanceof Uint8Array ? data.buffer : data;
|
|
20666
|
-
book = ePub(input, { openAs: "epub" });
|
|
20667
|
-
} else {
|
|
20668
|
-
let data = null;
|
|
20669
|
-
if (source.kind === "text") {
|
|
20670
|
-
const encoder = new TextEncoder();
|
|
20671
|
-
data = encoder.encode(source.text || "").buffer;
|
|
20672
|
-
}
|
|
20673
|
-
const input = data instanceof Uint8Array ? data.buffer : data;
|
|
20674
|
-
book = ePub(input, { openAs: "epub" });
|
|
21241
|
+
let data = null;
|
|
21242
|
+
if (source.kind === 'uri') {
|
|
21243
|
+
data = source.uri;
|
|
21244
|
+
} else if (source.kind === 'base64') {
|
|
21245
|
+
data = decodeBase64(source.data);
|
|
21246
|
+
} else if (source.kind === 'text') {
|
|
21247
|
+
const encoder = new TextEncoder();
|
|
21248
|
+
data = encoder.encode(source.text || '').buffer;
|
|
20675
21249
|
}
|
|
20676
|
-
|
|
20677
|
-
|
|
20678
|
-
|
|
20679
|
-
await withTimeout(book.ready, EPUB_READY_TIMEOUT_MS, "epub.ready");
|
|
20680
|
-
log("epub.load:ready");
|
|
21250
|
+
|
|
21251
|
+
book = ePub(data);
|
|
21252
|
+
await book.ready;
|
|
20681
21253
|
|
|
20682
21254
|
spineItems = book.spine && book.spine.items ? book.spine.items : [];
|
|
20683
21255
|
pageCount = spineItems.length;
|
|
@@ -20685,64 +21257,38 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20685
21257
|
|
|
20686
21258
|
clearViewer();
|
|
20687
21259
|
rendition = book.renderTo(viewer, {
|
|
20688
|
-
width:
|
|
20689
|
-
height:
|
|
20690
|
-
flow:
|
|
20691
|
-
spread:
|
|
21260
|
+
width: '100%',
|
|
21261
|
+
height: '100%',
|
|
21262
|
+
flow: 'paginated',
|
|
21263
|
+
spread: 'none',
|
|
20692
21264
|
});
|
|
20693
21265
|
|
|
20694
21266
|
if (rendition && rendition.hooks && rendition.hooks.content) {
|
|
20695
21267
|
rendition.hooks.content.register((contents) => {
|
|
20696
|
-
const frame =
|
|
20697
|
-
contents && contents.document
|
|
20698
|
-
? contents.document.defaultView.frameElement
|
|
20699
|
-
: null;
|
|
21268
|
+
const frame = contents && contents.document ? contents.document.defaultView.frameElement : null;
|
|
20700
21269
|
if (frame) {
|
|
20701
|
-
frame.setAttribute(
|
|
20702
|
-
"sandbox",
|
|
20703
|
-
"allow-scripts allow-same-origin"
|
|
20704
|
-
);
|
|
21270
|
+
frame.setAttribute('sandbox', 'allow-scripts allow-same-origin');
|
|
20705
21271
|
}
|
|
20706
21272
|
});
|
|
20707
21273
|
}
|
|
20708
21274
|
|
|
20709
|
-
if (rendition && typeof rendition.on ===
|
|
20710
|
-
rendition.on(
|
|
20711
|
-
const selection =
|
|
20712
|
-
|
|
20713
|
-
? contents.window.getSelection()
|
|
20714
|
-
: null;
|
|
20715
|
-
const text = selection ? selection.toString().trim() : "";
|
|
21275
|
+
if (rendition && typeof rendition.on === 'function') {
|
|
21276
|
+
rendition.on('selected', (cfiRange, contents) => {
|
|
21277
|
+
const selection = contents && contents.window ? contents.window.getSelection() : null;
|
|
21278
|
+
const text = selection ? selection.toString().trim() : '';
|
|
20716
21279
|
if (text) {
|
|
20717
|
-
sendEvent(
|
|
20718
|
-
text,
|
|
20719
|
-
pageIndex: Math.max(0, currentPage - 1),
|
|
20720
|
-
});
|
|
21280
|
+
sendEvent('TEXT_SELECTED', { text, pageIndex: Math.max(0, currentPage - 1) });
|
|
20721
21281
|
}
|
|
20722
|
-
if (
|
|
20723
|
-
rendition
|
|
20724
|
-
rendition.annotations &&
|
|
20725
|
-
typeof rendition.annotations.remove === "function"
|
|
20726
|
-
) {
|
|
20727
|
-
rendition.annotations.remove(cfiRange, "highlight");
|
|
21282
|
+
if (rendition && rendition.annotations && typeof rendition.annotations.remove === 'function') {
|
|
21283
|
+
rendition.annotations.remove(cfiRange, 'highlight');
|
|
20728
21284
|
}
|
|
20729
21285
|
});
|
|
20730
21286
|
}
|
|
20731
21287
|
|
|
20732
|
-
|
|
20733
|
-
await withTimeout(
|
|
20734
|
-
displayEpubPage(0),
|
|
20735
|
-
EPUB_DISPLAY_TIMEOUT_MS,
|
|
20736
|
-
"epub.display"
|
|
20737
|
-
);
|
|
20738
|
-
log("epub.load:displayed");
|
|
20739
|
-
} catch (err) {
|
|
20740
|
-
reportError(err, "epub.display");
|
|
20741
|
-
}
|
|
21288
|
+
await displayEpubPage(0);
|
|
20742
21289
|
applyEpubZoom();
|
|
20743
21290
|
|
|
20744
21291
|
const outline = await buildOutline();
|
|
20745
|
-
log("epub.load:outline", outline.length);
|
|
20746
21292
|
return { pageCount, outline };
|
|
20747
21293
|
};
|
|
20748
21294
|
|
|
@@ -20757,41 +21303,34 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20757
21303
|
};
|
|
20758
21304
|
|
|
20759
21305
|
const getTextContent = async (pageIndex) => {
|
|
20760
|
-
if (currentType ===
|
|
20761
|
-
const text = textPages[pageIndex] ||
|
|
20762
|
-
return [
|
|
20763
|
-
|
|
20764
|
-
|
|
20765
|
-
|
|
20766
|
-
|
|
20767
|
-
|
|
20768
|
-
|
|
20769
|
-
|
|
20770
|
-
},
|
|
20771
|
-
];
|
|
21306
|
+
if (currentType === 'text') {
|
|
21307
|
+
const text = textPages[pageIndex] || '';
|
|
21308
|
+
return [{
|
|
21309
|
+
str: text,
|
|
21310
|
+
dir: 'ltr',
|
|
21311
|
+
width: 0,
|
|
21312
|
+
height: 0,
|
|
21313
|
+
transform: [1, 0, 0, 1, 0, 0],
|
|
21314
|
+
fontName: 'default',
|
|
21315
|
+
}];
|
|
20772
21316
|
}
|
|
20773
21317
|
|
|
20774
|
-
if (currentType ===
|
|
21318
|
+
if (currentType === 'epub') {
|
|
20775
21319
|
if (!book) return [];
|
|
20776
21320
|
const item = spineItems[pageIndex];
|
|
20777
21321
|
if (!item) return [];
|
|
20778
21322
|
try {
|
|
20779
21323
|
const section = book.spine.get(item.idref || item.href);
|
|
20780
|
-
const text =
|
|
20781
|
-
section && typeof section.text === "function"
|
|
20782
|
-
? await section.text()
|
|
20783
|
-
: "";
|
|
21324
|
+
const text = section && typeof section.text === 'function' ? await section.text() : '';
|
|
20784
21325
|
if (!text) return [];
|
|
20785
|
-
return [
|
|
20786
|
-
|
|
20787
|
-
|
|
20788
|
-
|
|
20789
|
-
|
|
20790
|
-
|
|
20791
|
-
|
|
20792
|
-
|
|
20793
|
-
},
|
|
20794
|
-
];
|
|
21326
|
+
return [{
|
|
21327
|
+
str: text,
|
|
21328
|
+
dir: 'ltr',
|
|
21329
|
+
width: 0,
|
|
21330
|
+
height: 0,
|
|
21331
|
+
transform: [1, 0, 0, 1, 0, 0],
|
|
21332
|
+
fontName: 'default',
|
|
21333
|
+
}];
|
|
20795
21334
|
} catch (err) {
|
|
20796
21335
|
return [];
|
|
20797
21336
|
}
|
|
@@ -20802,7 +21341,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20802
21341
|
|
|
20803
21342
|
const getPageText = async (pageIndex) => {
|
|
20804
21343
|
const items = await getTextContent(pageIndex);
|
|
20805
|
-
return items.map((item) => item.str).join(
|
|
21344
|
+
return items.map((item) => item.str).join(' ');
|
|
20806
21345
|
};
|
|
20807
21346
|
|
|
20808
21347
|
const searchText = async (query) => {
|
|
@@ -20818,11 +21357,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20818
21357
|
while (pos !== -1) {
|
|
20819
21358
|
const start = Math.max(0, pos - 20);
|
|
20820
21359
|
const end = Math.min(text.length, pos + query.length + 20);
|
|
20821
|
-
results.push({
|
|
20822
|
-
pageIndex: i,
|
|
20823
|
-
text: text.substring(start, end),
|
|
20824
|
-
matchIndex,
|
|
20825
|
-
});
|
|
21360
|
+
results.push({ pageIndex: i, text: text.substring(start, end), matchIndex });
|
|
20826
21361
|
matchIndex += 1;
|
|
20827
21362
|
pos = lower.indexOf(normalized, pos + 1);
|
|
20828
21363
|
}
|
|
@@ -20838,11 +21373,11 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20838
21373
|
|
|
20839
21374
|
const getPageIndex = (dest) => {
|
|
20840
21375
|
if (!dest) return null;
|
|
20841
|
-
if (typeof dest ===
|
|
20842
|
-
if (typeof dest !==
|
|
20843
|
-
if (dest.kind ===
|
|
20844
|
-
if (dest.kind ===
|
|
20845
|
-
if (dest.kind ===
|
|
21376
|
+
if (typeof dest === 'string') return getSpineIndexByHref(dest);
|
|
21377
|
+
if (typeof dest !== 'object') return null;
|
|
21378
|
+
if (dest.kind === 'href') return getSpineIndexByHref(dest.value);
|
|
21379
|
+
if (dest.kind === 'pageIndex') return dest.value;
|
|
21380
|
+
if (dest.kind === 'pageNumber') return Math.max(0, dest.value - 1);
|
|
20846
21381
|
return null;
|
|
20847
21382
|
};
|
|
20848
21383
|
|
|
@@ -20856,53 +21391,70 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20856
21391
|
};
|
|
20857
21392
|
|
|
20858
21393
|
const applyZoom = () => {
|
|
20859
|
-
if (currentType ===
|
|
21394
|
+
if (currentType === 'text') {
|
|
20860
21395
|
applyTextZoom();
|
|
20861
|
-
} else if (currentType ===
|
|
21396
|
+
} else if (currentType === 'epub') {
|
|
20862
21397
|
applyEpubZoom();
|
|
21398
|
+
} else if (currentType === 'comic') {
|
|
21399
|
+
applyComicLayout();
|
|
20863
21400
|
}
|
|
20864
21401
|
};
|
|
20865
21402
|
|
|
20866
21403
|
const handleCommand = async (message) => {
|
|
20867
21404
|
const { id, kind, payload } = message;
|
|
20868
|
-
log("command", kind);
|
|
20869
21405
|
|
|
20870
21406
|
try {
|
|
20871
|
-
if (kind ===
|
|
21407
|
+
if (kind === 'load') {
|
|
20872
21408
|
currentType = payload.type;
|
|
20873
21409
|
zoom = 1.0;
|
|
20874
21410
|
|
|
20875
|
-
if (currentType ===
|
|
21411
|
+
if (currentType === 'text') {
|
|
20876
21412
|
const result = await loadText(payload.source);
|
|
20877
21413
|
sendState();
|
|
20878
21414
|
sendResponse(id, true, result);
|
|
20879
21415
|
return;
|
|
20880
21416
|
}
|
|
20881
21417
|
|
|
20882
|
-
if (currentType ===
|
|
21418
|
+
if (currentType === 'epub') {
|
|
20883
21419
|
const result = await loadEpub(payload.source);
|
|
20884
21420
|
sendState({ outline: result.outline || [] });
|
|
20885
21421
|
sendResponse(id, true, result);
|
|
20886
21422
|
return;
|
|
20887
21423
|
}
|
|
20888
21424
|
|
|
20889
|
-
|
|
21425
|
+
if (currentType === 'comic') {
|
|
21426
|
+
const result = await loadComic(payload.source, payload.format || 'cbz');
|
|
21427
|
+
sendState();
|
|
21428
|
+
sendResponse(id, true, result);
|
|
21429
|
+
return;
|
|
21430
|
+
}
|
|
21431
|
+
|
|
21432
|
+
throw new Error('Unsupported document type');
|
|
20890
21433
|
}
|
|
20891
21434
|
|
|
20892
|
-
if (kind ===
|
|
21435
|
+
if (kind === 'go-to-page') {
|
|
20893
21436
|
const page = Math.max(1, payload.page || 1);
|
|
20894
|
-
if (currentType ===
|
|
21437
|
+
if (currentType === 'text') {
|
|
20895
21438
|
currentPage = page;
|
|
20896
21439
|
renderTextPage(page - 1);
|
|
20897
21440
|
sendState();
|
|
20898
|
-
} else if (currentType ===
|
|
21441
|
+
} else if (currentType === 'epub') {
|
|
20899
21442
|
await displayEpubPage(page - 1);
|
|
21443
|
+
} else if (currentType === 'comic') {
|
|
21444
|
+
currentPage = page;
|
|
21445
|
+
const target = comicPages[page - 1];
|
|
21446
|
+
if (target) {
|
|
21447
|
+
await ensureComicPage(page - 1);
|
|
21448
|
+
target.scrollIntoView({ block: 'start' });
|
|
21449
|
+
renderComicPage(page - 1);
|
|
21450
|
+
sendState();
|
|
21451
|
+
}
|
|
20900
21452
|
}
|
|
20901
21453
|
sendResponse(id, true, { currentPage });
|
|
20902
21454
|
return;
|
|
20903
21455
|
}
|
|
20904
21456
|
|
|
20905
|
-
if (kind ===
|
|
21457
|
+
if (kind === 'set-zoom') {
|
|
20906
21458
|
zoom = Math.max(0.5, Math.min(4.0, payload.zoom || 1.0));
|
|
20907
21459
|
applyZoom();
|
|
20908
21460
|
sendState();
|
|
@@ -20910,103 +21462,132 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20910
21462
|
return;
|
|
20911
21463
|
}
|
|
20912
21464
|
|
|
20913
|
-
if (kind ===
|
|
21465
|
+
if (kind === 'set-rotation') {
|
|
21466
|
+
rotation = ((payload.rotation || 0) % 360 + 360) % 360;
|
|
21467
|
+
if (currentType === 'comic') applyComicLayout();
|
|
20914
21468
|
sendResponse(id, true, {});
|
|
20915
21469
|
return;
|
|
20916
21470
|
}
|
|
20917
21471
|
|
|
20918
|
-
if (kind ===
|
|
21472
|
+
if (kind === 'get-text-content') {
|
|
20919
21473
|
const items = await getTextContent(payload.pageIndex || 0);
|
|
20920
21474
|
sendResponse(id, true, items);
|
|
20921
21475
|
return;
|
|
20922
21476
|
}
|
|
20923
21477
|
|
|
20924
|
-
if (kind ===
|
|
20925
|
-
|
|
21478
|
+
if (kind === 'get-page-dimensions') {
|
|
21479
|
+
if (currentType === 'comic') {
|
|
21480
|
+
sendResponse(
|
|
21481
|
+
id,
|
|
21482
|
+
true,
|
|
21483
|
+
await getComicPageDimensions(payload.pageIndex || 0)
|
|
21484
|
+
);
|
|
21485
|
+
} else {
|
|
21486
|
+
sendResponse(id, true, getPageDimensions());
|
|
21487
|
+
}
|
|
20926
21488
|
return;
|
|
20927
21489
|
}
|
|
20928
21490
|
|
|
20929
|
-
if (kind ===
|
|
20930
|
-
|
|
21491
|
+
if (kind === 'get-page-preview') {
|
|
21492
|
+
if (currentType !== 'comic') {
|
|
21493
|
+
sendResponse(id, true, null);
|
|
21494
|
+
return;
|
|
21495
|
+
}
|
|
21496
|
+
sendResponse(
|
|
21497
|
+
id,
|
|
21498
|
+
true,
|
|
21499
|
+
await getComicPagePreview(payload.pageIndex || 0)
|
|
21500
|
+
);
|
|
21501
|
+
return;
|
|
21502
|
+
}
|
|
21503
|
+
|
|
21504
|
+
if (kind === 'search-text') {
|
|
21505
|
+
const results = await searchText(payload.query || '');
|
|
20931
21506
|
sendResponse(id, true, results);
|
|
20932
21507
|
return;
|
|
20933
21508
|
}
|
|
20934
21509
|
|
|
20935
|
-
if (kind ===
|
|
21510
|
+
if (kind === 'select-text') {
|
|
20936
21511
|
const selection = await selectText(payload.pageIndex || 0);
|
|
20937
21512
|
sendResponse(id, true, selection);
|
|
20938
21513
|
return;
|
|
20939
21514
|
}
|
|
20940
21515
|
|
|
20941
|
-
if (kind ===
|
|
21516
|
+
if (kind === 'get-outline') {
|
|
20942
21517
|
const outline = await buildOutline();
|
|
20943
21518
|
sendResponse(id, true, outline);
|
|
20944
21519
|
return;
|
|
20945
21520
|
}
|
|
20946
21521
|
|
|
20947
|
-
if (kind ===
|
|
21522
|
+
if (kind === 'get-page-index') {
|
|
20948
21523
|
const index = getPageIndex(payload.dest);
|
|
20949
21524
|
sendResponse(id, true, index);
|
|
20950
21525
|
return;
|
|
20951
21526
|
}
|
|
20952
21527
|
|
|
20953
|
-
if (kind ===
|
|
21528
|
+
if (kind === 'destroy') {
|
|
20954
21529
|
clearViewer();
|
|
20955
21530
|
sendResponse(id, true, {});
|
|
20956
21531
|
return;
|
|
20957
21532
|
}
|
|
20958
21533
|
|
|
20959
|
-
sendResponse(id, false, null,
|
|
21534
|
+
sendResponse(id, false, null, 'Unknown command');
|
|
20960
21535
|
} catch (err) {
|
|
20961
|
-
sendResponse(
|
|
20962
|
-
id,
|
|
20963
|
-
false,
|
|
20964
|
-
null,
|
|
20965
|
-
err && err.message ? err.message : String(err)
|
|
20966
|
-
);
|
|
21536
|
+
sendResponse(id, false, null, err && err.message ? err.message : String(err));
|
|
20967
21537
|
}
|
|
20968
21538
|
};
|
|
20969
21539
|
|
|
20970
21540
|
const onMessage = (event) => {
|
|
20971
21541
|
let message = null;
|
|
20972
|
-
const raw = event && typeof event ===
|
|
21542
|
+
const raw = event && typeof event === 'object' ? event.data : null;
|
|
20973
21543
|
|
|
20974
|
-
if (raw && typeof raw ===
|
|
21544
|
+
if (raw && typeof raw === 'object' && (raw.kind || raw.type) && raw.id) {
|
|
20975
21545
|
message = raw;
|
|
20976
|
-
} else if (typeof raw ===
|
|
20977
|
-
if (raw.startsWith(
|
|
20978
|
-
return;
|
|
20979
|
-
}
|
|
21546
|
+
} else if (typeof raw === 'string') {
|
|
21547
|
+
if (raw.startsWith('setImmediate$')) return;
|
|
20980
21548
|
const trimmed = raw.trim();
|
|
20981
|
-
if (
|
|
20982
|
-
!trimmed ||
|
|
20983
|
-
(!trimmed.startsWith("{") && !trimmed.startsWith("["))
|
|
20984
|
-
) {
|
|
21549
|
+
if (!trimmed || (!trimmed.startsWith('{') && !trimmed.startsWith('['))) {
|
|
20985
21550
|
return;
|
|
20986
21551
|
}
|
|
20987
21552
|
try {
|
|
20988
21553
|
message = JSON.parse(trimmed);
|
|
20989
21554
|
} catch (err) {
|
|
20990
|
-
sendEvent("RUNTIME_ERROR", {
|
|
20991
|
-
message: "Failed to parse message",
|
|
20992
|
-
context: "runtime.onMessage",
|
|
20993
|
-
stack: err && err.stack ? err.stack : null,
|
|
20994
|
-
preview: trimmed.slice(0, 200),
|
|
20995
|
-
});
|
|
20996
21555
|
return;
|
|
20997
21556
|
}
|
|
20998
21557
|
} else {
|
|
20999
21558
|
return;
|
|
21000
21559
|
}
|
|
21001
21560
|
|
|
21002
|
-
|
|
21003
|
-
|
|
21561
|
+
if (!message || message.id == null) return;
|
|
21562
|
+
|
|
21563
|
+
if (message.type === 'asset-response') {
|
|
21564
|
+
const pending = runtimeAssetRequests.get(message.id);
|
|
21565
|
+
if (!pending) return;
|
|
21566
|
+
runtimeAssetRequests.delete(message.id);
|
|
21567
|
+
clearTimeout(pending.timeout);
|
|
21568
|
+
if (message.ok) pending.resolve(message.data);
|
|
21569
|
+
else pending.reject(new Error(message.error || 'Falha ao carregar asset CBR.'));
|
|
21570
|
+
return;
|
|
21571
|
+
}
|
|
21572
|
+
|
|
21573
|
+
if (message.type === 'file-chunk-response') {
|
|
21574
|
+
const pending = fileChunkRequests.get(message.id);
|
|
21575
|
+
if (!pending) return;
|
|
21576
|
+
fileChunkRequests.delete(message.id);
|
|
21577
|
+
clearTimeout(pending.timeout);
|
|
21578
|
+
if (message.ok) pending.resolve(message);
|
|
21579
|
+
else pending.reject(new Error(message.error || 'Falha ao ler arquivo local.'));
|
|
21580
|
+
return;
|
|
21581
|
+
}
|
|
21582
|
+
|
|
21583
|
+
if (!message.kind) return;
|
|
21584
|
+
handleCommand(message);
|
|
21004
21585
|
};
|
|
21005
21586
|
|
|
21006
|
-
window.addEventListener(
|
|
21007
|
-
document.addEventListener(
|
|
21587
|
+
window.addEventListener('message', onMessage);
|
|
21588
|
+
document.addEventListener('message', onMessage);
|
|
21008
21589
|
|
|
21009
|
-
sendMessage({ type:
|
|
21590
|
+
sendMessage({ type: 'ready' });
|
|
21010
21591
|
})();
|
|
21011
21592
|
</script>
|
|
21012
21593
|
</body>
|
|
@@ -21051,6 +21632,7 @@ var import_react_native = require("react-native");
|
|
|
21051
21632
|
var import_react_native_gesture_handler = require("react-native-gesture-handler");
|
|
21052
21633
|
var import_react_native_svg = __toESM(require("react-native-svg"));
|
|
21053
21634
|
var import_core = require("@papyrus-sdk/core");
|
|
21635
|
+
var import_types = require("@papyrus-sdk/types");
|
|
21054
21636
|
var import_engine_native = require("@papyrus-sdk/engine-native");
|
|
21055
21637
|
|
|
21056
21638
|
// perf/mobilePerf.ts
|
|
@@ -21507,6 +22089,14 @@ var resolvePdfBasePageWidth = ({
|
|
|
21507
22089
|
horizontalPadding
|
|
21508
22090
|
}) => Math.max(0, viewportWidth - horizontalPadding * 2);
|
|
21509
22091
|
|
|
22092
|
+
// components/selectionEvent.ts
|
|
22093
|
+
var notifyTextSelection = (handler, payload) => {
|
|
22094
|
+
const text = payload.text.replace(/\s+/g, " ").trim();
|
|
22095
|
+
if (!text) return false;
|
|
22096
|
+
handler?.({ ...payload, text });
|
|
22097
|
+
return Boolean(handler);
|
|
22098
|
+
};
|
|
22099
|
+
|
|
21510
22100
|
// components/PageRenderer.tsx
|
|
21511
22101
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
21512
22102
|
var TEXT_MARKUP_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -21581,6 +22171,8 @@ var PageRenderer = ({
|
|
|
21581
22171
|
horizontalPadding = 16,
|
|
21582
22172
|
spacing = 24,
|
|
21583
22173
|
onSelectionDragActiveChange,
|
|
22174
|
+
onTextSelected,
|
|
22175
|
+
onDefineSelection,
|
|
21584
22176
|
gestureScrollLockActive = false,
|
|
21585
22177
|
lastPinchEndedAt = null,
|
|
21586
22178
|
requestSelectionVerticalAutoscroll
|
|
@@ -21926,6 +22518,17 @@ var PageRenderer = ({
|
|
|
21926
22518
|
return;
|
|
21927
22519
|
}
|
|
21928
22520
|
const selectedText = selection.text || "";
|
|
22521
|
+
const normalizedText = selectedText.replace(/\s+/g, " ").trim();
|
|
22522
|
+
if (normalizedText) {
|
|
22523
|
+
import_core.papyrusEvents.emit(import_types.PapyrusEventType.TEXT_SELECTED, {
|
|
22524
|
+
text: normalizedText,
|
|
22525
|
+
pageIndex
|
|
22526
|
+
});
|
|
22527
|
+
}
|
|
22528
|
+
notifyTextSelection(onTextSelected, {
|
|
22529
|
+
text: normalizedText,
|
|
22530
|
+
pageIndex
|
|
22531
|
+
});
|
|
21929
22532
|
logSelectionPerf("selection.ready", {
|
|
21930
22533
|
tool: activeTool,
|
|
21931
22534
|
sourceRectCount: selection.rects.length,
|
|
@@ -22861,6 +23464,20 @@ var PageRenderer = ({
|
|
|
22861
23464
|
}
|
|
22862
23465
|
],
|
|
22863
23466
|
children: [
|
|
23467
|
+
onDefineSelection ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
23468
|
+
import_react_native.Pressable,
|
|
23469
|
+
{
|
|
23470
|
+
onPress: (event) => {
|
|
23471
|
+
stopPressPropagation(event);
|
|
23472
|
+
onDefineSelection({
|
|
23473
|
+
text: selectionText,
|
|
23474
|
+
pageIndex
|
|
23475
|
+
});
|
|
23476
|
+
},
|
|
23477
|
+
style: [styles.selectionAction, styles.defineSelectionAction],
|
|
23478
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Text, { style: styles.defineSelectionText, children: "Definir" })
|
|
23479
|
+
}
|
|
23480
|
+
) : null,
|
|
22864
23481
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
22865
23482
|
import_react_native.Pressable,
|
|
22866
23483
|
{
|
|
@@ -23160,6 +23777,15 @@ var styles = import_react_native.StyleSheet.create({
|
|
|
23160
23777
|
justifyContent: "center",
|
|
23161
23778
|
marginRight: 10
|
|
23162
23779
|
},
|
|
23780
|
+
defineSelectionAction: {
|
|
23781
|
+
width: 58,
|
|
23782
|
+
paddingHorizontal: 6
|
|
23783
|
+
},
|
|
23784
|
+
defineSelectionText: {
|
|
23785
|
+
color: "#FFFFFF",
|
|
23786
|
+
fontSize: 11,
|
|
23787
|
+
fontWeight: "700"
|
|
23788
|
+
},
|
|
23163
23789
|
selectionActionLast: {
|
|
23164
23790
|
marginRight: 0
|
|
23165
23791
|
},
|
|
@@ -23191,7 +23817,7 @@ var styles = import_react_native.StyleSheet.create({
|
|
|
23191
23817
|
borderRadius: 3
|
|
23192
23818
|
}
|
|
23193
23819
|
});
|
|
23194
|
-
var arePageRendererPropsEqual = (previous, next) => previous.engine === next.engine && previous.pageIndex === next.pageIndex && previous.scale === next.scale && previous.PageViewComponent === next.PageViewComponent && previous.availableWidth === next.availableWidth && previous.pageViewportWidth === next.pageViewportWidth && previous.horizontalPadding === next.horizontalPadding && previous.spacing === next.spacing && previous.onSelectionDragActiveChange === next.onSelectionDragActiveChange && previous.gestureScrollLockActive === next.gestureScrollLockActive && previous.lastPinchEndedAt === next.lastPinchEndedAt && previous.requestSelectionVerticalAutoscroll === next.requestSelectionVerticalAutoscroll;
|
|
23820
|
+
var arePageRendererPropsEqual = (previous, next) => previous.engine === next.engine && previous.pageIndex === next.pageIndex && previous.scale === next.scale && previous.PageViewComponent === next.PageViewComponent && previous.availableWidth === next.availableWidth && previous.pageViewportWidth === next.pageViewportWidth && previous.horizontalPadding === next.horizontalPadding && previous.spacing === next.spacing && previous.onSelectionDragActiveChange === next.onSelectionDragActiveChange && previous.onTextSelected === next.onTextSelected && previous.onDefineSelection === next.onDefineSelection && previous.gestureScrollLockActive === next.gestureScrollLockActive && previous.lastPinchEndedAt === next.lastPinchEndedAt && previous.requestSelectionVerticalAutoscroll === next.requestSelectionVerticalAutoscroll;
|
|
23195
23821
|
var PageRenderer_default = (0, import_react.memo)(PageRenderer, arePageRendererPropsEqual);
|
|
23196
23822
|
|
|
23197
23823
|
// components/WebViewViewer.tsx
|
|
@@ -23199,29 +23825,100 @@ var import_react2 = require("react");
|
|
|
23199
23825
|
var import_react_native2 = require("react-native");
|
|
23200
23826
|
var import_react_native_webview = __toESM(require("react-native-webview"));
|
|
23201
23827
|
var import_core2 = require("@papyrus-sdk/core");
|
|
23828
|
+
|
|
23829
|
+
// components/webViewState.ts
|
|
23830
|
+
var parseWebViewState = (raw) => {
|
|
23831
|
+
try {
|
|
23832
|
+
const message = JSON.parse(raw);
|
|
23833
|
+
if (!message || typeof message !== "object") return null;
|
|
23834
|
+
const typedMessage = message;
|
|
23835
|
+
if (typedMessage.type !== "state") return null;
|
|
23836
|
+
if (!typedMessage.payload || typeof typedMessage.payload !== "object") {
|
|
23837
|
+
return null;
|
|
23838
|
+
}
|
|
23839
|
+
const payload = typedMessage.payload;
|
|
23840
|
+
const update = {};
|
|
23841
|
+
if (typeof payload.currentPage === "number" && Number.isInteger(payload.currentPage) && payload.currentPage >= 1) {
|
|
23842
|
+
update.currentPage = payload.currentPage;
|
|
23843
|
+
}
|
|
23844
|
+
if (typeof payload.pageCount === "number" && Number.isInteger(payload.pageCount) && payload.pageCount >= 0) {
|
|
23845
|
+
update.pageCount = payload.pageCount;
|
|
23846
|
+
}
|
|
23847
|
+
return Object.keys(update).length > 0 ? update : null;
|
|
23848
|
+
} catch {
|
|
23849
|
+
return null;
|
|
23850
|
+
}
|
|
23851
|
+
};
|
|
23852
|
+
|
|
23853
|
+
// components/WebViewViewer.tsx
|
|
23202
23854
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
23203
23855
|
var runtimeAsset = require_runtime();
|
|
23204
|
-
var
|
|
23205
|
-
if (typeof
|
|
23206
|
-
return { html:
|
|
23856
|
+
var resolveRuntimeSource = (asset) => {
|
|
23857
|
+
if (typeof asset === "string") {
|
|
23858
|
+
return { html: asset };
|
|
23207
23859
|
}
|
|
23208
|
-
if (typeof
|
|
23209
|
-
const resolved = import_react_native2.Image.resolveAssetSource(
|
|
23860
|
+
if (typeof asset === "number") {
|
|
23861
|
+
const resolved = import_react_native2.Image.resolveAssetSource(asset);
|
|
23210
23862
|
if (resolved?.uri) {
|
|
23211
23863
|
return { uri: resolved.uri };
|
|
23212
23864
|
}
|
|
23213
23865
|
}
|
|
23214
|
-
if (
|
|
23215
|
-
const uri =
|
|
23866
|
+
if (asset && typeof asset === "object" && "uri" in asset) {
|
|
23867
|
+
const uri = asset.uri;
|
|
23216
23868
|
if (uri) return { uri };
|
|
23217
23869
|
}
|
|
23218
23870
|
return { html: "" };
|
|
23219
|
-
}
|
|
23871
|
+
};
|
|
23220
23872
|
var WebViewViewer = ({ engine }) => {
|
|
23221
23873
|
const webViewRef = (0, import_react2.useRef)(null);
|
|
23222
23874
|
const { pageTheme } = (0, import_core2.useViewerStore)();
|
|
23875
|
+
const bridgeEngine = engine;
|
|
23876
|
+
const runtimeSource = (0, import_react2.useMemo)(
|
|
23877
|
+
() => resolveRuntimeSource(
|
|
23878
|
+
bridgeEngine.getWebViewRuntimeSource?.() ?? runtimeAsset
|
|
23879
|
+
),
|
|
23880
|
+
[bridgeEngine]
|
|
23881
|
+
);
|
|
23882
|
+
const [runtimeHtml, setRuntimeHtml] = (0, import_react2.useState)(null);
|
|
23883
|
+
(0, import_react2.useEffect)(() => {
|
|
23884
|
+
let active = true;
|
|
23885
|
+
if ("html" in runtimeSource) {
|
|
23886
|
+
setRuntimeHtml(runtimeSource.html);
|
|
23887
|
+
return () => {
|
|
23888
|
+
active = false;
|
|
23889
|
+
};
|
|
23890
|
+
}
|
|
23891
|
+
setRuntimeHtml(null);
|
|
23892
|
+
void fetch(runtimeSource.uri).then((response) => {
|
|
23893
|
+
if (!response.ok) throw new Error(`status ${response.status}`);
|
|
23894
|
+
return response.text();
|
|
23895
|
+
}).then((html) => {
|
|
23896
|
+
if (active) setRuntimeHtml(html);
|
|
23897
|
+
}).catch(() => {
|
|
23898
|
+
if (active) setRuntimeHtml(null);
|
|
23899
|
+
});
|
|
23900
|
+
return () => {
|
|
23901
|
+
active = false;
|
|
23902
|
+
};
|
|
23903
|
+
}, [runtimeSource]);
|
|
23904
|
+
const webViewSource = (0, import_react2.useMemo)(() => {
|
|
23905
|
+
if (runtimeHtml !== null) {
|
|
23906
|
+
return {
|
|
23907
|
+
html: runtimeHtml,
|
|
23908
|
+
baseUrl: "http://localhost:3005/"
|
|
23909
|
+
};
|
|
23910
|
+
}
|
|
23911
|
+
if ("uri" in runtimeSource) return { html: "" };
|
|
23912
|
+
return runtimeSource;
|
|
23913
|
+
}, [runtimeHtml, runtimeSource]);
|
|
23914
|
+
const runtimeConfig = bridgeEngine.getWebViewRuntimeConfig?.();
|
|
23915
|
+
const runtimeConfigScript = (0, import_react2.useMemo)(() => {
|
|
23916
|
+
if (!runtimeConfig) return void 0;
|
|
23917
|
+
return `window.__PAPYRUS_RUNTIME_CONFIG__=${JSON.stringify(
|
|
23918
|
+
runtimeConfig
|
|
23919
|
+
)};true;`;
|
|
23920
|
+
}, [runtimeConfig]);
|
|
23223
23921
|
(0, import_react2.useEffect)(() => {
|
|
23224
|
-
const bridgeEngine = engine;
|
|
23225
23922
|
bridgeEngine.attachWebView?.({
|
|
23226
23923
|
postMessage: (message) => {
|
|
23227
23924
|
if (__DEV__) {
|
|
@@ -23231,9 +23928,22 @@ var WebViewViewer = ({ engine }) => {
|
|
|
23231
23928
|
webViewRef.current?.postMessage(message);
|
|
23232
23929
|
}
|
|
23233
23930
|
});
|
|
23234
|
-
}, [
|
|
23931
|
+
}, [bridgeEngine]);
|
|
23235
23932
|
const handleMessage = (event) => {
|
|
23236
|
-
const
|
|
23933
|
+
const state = parseWebViewState(event.nativeEvent.data);
|
|
23934
|
+
if (state) {
|
|
23935
|
+
const viewerState = import_core2.useViewerStore.getState();
|
|
23936
|
+
const nextState = {};
|
|
23937
|
+
if (state.currentPage !== void 0 && state.currentPage !== viewerState.currentPage) {
|
|
23938
|
+
nextState.currentPage = state.currentPage;
|
|
23939
|
+
}
|
|
23940
|
+
if (state.pageCount !== void 0 && state.pageCount !== viewerState.pageCount) {
|
|
23941
|
+
nextState.pageCount = state.pageCount;
|
|
23942
|
+
}
|
|
23943
|
+
if (Object.keys(nextState).length > 0) {
|
|
23944
|
+
viewerState.setDocumentState(nextState);
|
|
23945
|
+
}
|
|
23946
|
+
}
|
|
23237
23947
|
if (__DEV__) {
|
|
23238
23948
|
console.log("[Papyrus WebView] message", event.nativeEvent.data);
|
|
23239
23949
|
}
|
|
@@ -23273,11 +23983,12 @@ var WebViewViewer = ({ engine }) => {
|
|
|
23273
23983
|
import_react_native_webview.default,
|
|
23274
23984
|
{
|
|
23275
23985
|
ref: webViewRef,
|
|
23276
|
-
source:
|
|
23986
|
+
source: webViewSource,
|
|
23277
23987
|
originWhitelist: ["*"],
|
|
23278
23988
|
onMessage: handleMessage,
|
|
23279
23989
|
onLoadEnd: handleLoadEnd,
|
|
23280
23990
|
onError: handleError,
|
|
23991
|
+
injectedJavaScriptBeforeContentLoaded: runtimeConfigScript,
|
|
23281
23992
|
javaScriptEnabled: true,
|
|
23282
23993
|
domStorageEnabled: true,
|
|
23283
23994
|
scalesPageToFit: true,
|
|
@@ -24260,7 +24971,9 @@ var Viewer = ({
|
|
|
24260
24971
|
maxToRenderPerBatch,
|
|
24261
24972
|
removeClippedSubviews,
|
|
24262
24973
|
useDedicatedAndroidPdfViewer,
|
|
24263
|
-
viewerMode
|
|
24974
|
+
viewerMode,
|
|
24975
|
+
onTextSelected,
|
|
24976
|
+
onDefineSelection
|
|
24264
24977
|
}) => {
|
|
24265
24978
|
const pageCount = (0, import_core4.useViewerStore)((state) => state.pageCount);
|
|
24266
24979
|
const currentPage = (0, import_core4.useViewerStore)((state) => state.currentPage);
|
|
@@ -25396,6 +26109,8 @@ var Viewer = ({
|
|
|
25396
26109
|
pageViewportWidth: columnWidth,
|
|
25397
26110
|
spacing: DOUBLE_PAGE_SPACING,
|
|
25398
26111
|
onSelectionDragActiveChange: setSelectionDragActive,
|
|
26112
|
+
onTextSelected,
|
|
26113
|
+
onDefineSelection,
|
|
25399
26114
|
gestureScrollLockActive,
|
|
25400
26115
|
lastPinchEndedAt,
|
|
25401
26116
|
requestSelectionVerticalAutoscroll: handleSelectionVerticalAutoscroll
|
|
@@ -25412,6 +26127,8 @@ var Viewer = ({
|
|
|
25412
26127
|
pageViewportWidth: columnWidth,
|
|
25413
26128
|
spacing: DOUBLE_PAGE_SPACING,
|
|
25414
26129
|
onSelectionDragActiveChange: setSelectionDragActive,
|
|
26130
|
+
onTextSelected,
|
|
26131
|
+
onDefineSelection,
|
|
25415
26132
|
gestureScrollLockActive,
|
|
25416
26133
|
lastPinchEndedAt,
|
|
25417
26134
|
requestSelectionVerticalAutoscroll: handleSelectionVerticalAutoscroll
|
|
@@ -25431,6 +26148,8 @@ var Viewer = ({
|
|
|
25431
26148
|
pageViewportWidth: documentSurfaceWidth,
|
|
25432
26149
|
spacing: CONTINUOUS_PAGE_SPACING,
|
|
25433
26150
|
onSelectionDragActiveChange: setSelectionDragActive,
|
|
26151
|
+
onTextSelected,
|
|
26152
|
+
onDefineSelection,
|
|
25434
26153
|
gestureScrollLockActive,
|
|
25435
26154
|
lastPinchEndedAt,
|
|
25436
26155
|
requestSelectionVerticalAutoscroll: handleSelectionVerticalAutoscroll
|
|
@@ -25520,6 +26239,8 @@ var Viewer = ({
|
|
|
25520
26239
|
pageViewportWidth: documentSurfaceWidth,
|
|
25521
26240
|
spacing: 32,
|
|
25522
26241
|
onSelectionDragActiveChange: setSelectionDragActive,
|
|
26242
|
+
onTextSelected,
|
|
26243
|
+
onDefineSelection,
|
|
25523
26244
|
gestureScrollLockActive,
|
|
25524
26245
|
lastPinchEndedAt,
|
|
25525
26246
|
requestSelectionVerticalAutoscroll: handleSelectionVerticalAutoscroll
|
|
@@ -27406,11 +28127,13 @@ var PageThumbnail = ({
|
|
|
27406
28127
|
frameHeight,
|
|
27407
28128
|
accentColor,
|
|
27408
28129
|
useNativePreview,
|
|
28130
|
+
useImagePreview,
|
|
27409
28131
|
shouldRenderPreview,
|
|
27410
28132
|
onPress
|
|
27411
28133
|
}) => {
|
|
27412
28134
|
const viewRef = (0, import_react8.useRef)(null);
|
|
27413
28135
|
const [layoutReady, setLayoutReady] = (0, import_react8.useState)(false);
|
|
28136
|
+
const [previewUri, setPreviewUri] = (0, import_react8.useState)(null);
|
|
27414
28137
|
(0, import_react8.useEffect)(() => {
|
|
27415
28138
|
if (!layoutReady || !useNativePreview || !shouldRenderPreview) return;
|
|
27416
28139
|
const viewTag = (0, import_react_native9.findNodeHandle)(viewRef.current);
|
|
@@ -27426,6 +28149,24 @@ var PageThumbnail = ({
|
|
|
27426
28149
|
useNativePreview,
|
|
27427
28150
|
zoom
|
|
27428
28151
|
]);
|
|
28152
|
+
(0, import_react8.useEffect)(() => {
|
|
28153
|
+
if (!useImagePreview || !shouldRenderPreview) {
|
|
28154
|
+
setPreviewUri(null);
|
|
28155
|
+
return;
|
|
28156
|
+
}
|
|
28157
|
+
let active = true;
|
|
28158
|
+
const previewEngine = engine;
|
|
28159
|
+
const request = previewEngine.getPagePreview?.(pageIndex);
|
|
28160
|
+
if (!request) return;
|
|
28161
|
+
void request.then((uri) => {
|
|
28162
|
+
if (active) setPreviewUri(uri);
|
|
28163
|
+
}).catch(() => {
|
|
28164
|
+
if (active) setPreviewUri(null);
|
|
28165
|
+
});
|
|
28166
|
+
return () => {
|
|
28167
|
+
active = false;
|
|
28168
|
+
};
|
|
28169
|
+
}, [engine, pageIndex, shouldRenderPreview, useImagePreview]);
|
|
27429
28170
|
const handleLayout = (event) => {
|
|
27430
28171
|
if (event.nativeEvent.layout.width && event.nativeEvent.layout.height) {
|
|
27431
28172
|
setLayoutReady(true);
|
|
@@ -27448,7 +28189,14 @@ var PageThumbnail = ({
|
|
|
27448
28189
|
{
|
|
27449
28190
|
onLayout: handleLayout,
|
|
27450
28191
|
style: [styles9.thumbFrame, { width: frameWidth, height: frameHeight }],
|
|
27451
|
-
children: useNativePreview && shouldRenderPreview ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_engine_native3.PapyrusPageView, { ref: viewRef, style: styles9.thumbView }) :
|
|
28192
|
+
children: useNativePreview && shouldRenderPreview ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_engine_native3.PapyrusPageView, { ref: viewRef, style: styles9.thumbView }) : useImagePreview && shouldRenderPreview && previewUri ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
28193
|
+
import_react_native9.Image,
|
|
28194
|
+
{
|
|
28195
|
+
source: { uri: previewUri },
|
|
28196
|
+
resizeMode: "contain",
|
|
28197
|
+
style: styles9.thumbImage
|
|
28198
|
+
}
|
|
28199
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native9.View, { style: [styles9.thumbFallback, isDark && styles9.thumbFallbackDark], children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
27452
28200
|
import_react_native9.Text,
|
|
27453
28201
|
{
|
|
27454
28202
|
style: [
|
|
@@ -27526,8 +28274,13 @@ var RightSheet = ({
|
|
|
27526
28274
|
accentColor
|
|
27527
28275
|
} = (0, import_core7.useViewerStore)();
|
|
27528
28276
|
const [pagesMode, setPagesMode] = (0, import_react8.useState)(
|
|
27529
|
-
documentType === "pdf" ? "thumbnails" : "summary"
|
|
28277
|
+
documentType === "pdf" || documentType === "comic" ? "thumbnails" : "summary"
|
|
27530
28278
|
);
|
|
28279
|
+
(0, import_react8.useEffect)(() => {
|
|
28280
|
+
setPagesMode(
|
|
28281
|
+
documentType === "pdf" || documentType === "comic" ? "thumbnails" : "summary"
|
|
28282
|
+
);
|
|
28283
|
+
}, [documentType]);
|
|
27531
28284
|
const isDark = uiTheme === "dark";
|
|
27532
28285
|
const t = getStrings(locale);
|
|
27533
28286
|
const showingNotes = sidebarRightTab === "annotations";
|
|
@@ -27545,6 +28298,7 @@ var RightSheet = ({
|
|
|
27545
28298
|
import_react_native9.UIManager.getViewManagerConfig?.("PapyrusPageView")
|
|
27546
28299
|
);
|
|
27547
28300
|
const useNativePreview = renderTarget !== "webview" && hasNativePageView;
|
|
28301
|
+
const useImagePreview = documentType === "comic" && renderTarget === "webview" && typeof engine.getPagePreview === "function";
|
|
27548
28302
|
const thumbnailDimensionsCacheRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
|
|
27549
28303
|
const thumbnailDimensionsPendingRef = (0, import_react8.useRef)(/* @__PURE__ */ new Set());
|
|
27550
28304
|
const thumbnailRefreshTimeoutRef = (0, import_react8.useRef)(null);
|
|
@@ -27701,7 +28455,7 @@ var RightSheet = ({
|
|
|
27701
28455
|
);
|
|
27702
28456
|
const renderThumbnailItem = (0, import_react8.useCallback)(
|
|
27703
28457
|
({ item }) => {
|
|
27704
|
-
const shouldRenderPreview = useNativePreview && (visibleThumbnailPages.has(item) || item < resolvedThumbsPrewarmCount || Math.abs(item + 1 - currentPage) <= 1);
|
|
28458
|
+
const shouldRenderPreview = (useNativePreview || useImagePreview) && (visibleThumbnailPages.has(item) || item < resolvedThumbsPrewarmCount || Math.abs(item + 1 - currentPage) <= 1);
|
|
27705
28459
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
27706
28460
|
PageThumbnail,
|
|
27707
28461
|
{
|
|
@@ -27715,6 +28469,7 @@ var RightSheet = ({
|
|
|
27715
28469
|
frameHeight: getThumbnailFrameHeight(item),
|
|
27716
28470
|
accentColor,
|
|
27717
28471
|
useNativePreview,
|
|
28472
|
+
useImagePreview,
|
|
27718
28473
|
shouldRenderPreview,
|
|
27719
28474
|
onPress: () => jumpToPage(item)
|
|
27720
28475
|
}
|
|
@@ -27731,6 +28486,7 @@ var RightSheet = ({
|
|
|
27731
28486
|
jumpToPage,
|
|
27732
28487
|
resolvedThumbsPrewarmCount,
|
|
27733
28488
|
useNativePreview,
|
|
28489
|
+
useImagePreview,
|
|
27734
28490
|
visibleThumbnailPages,
|
|
27735
28491
|
zoom
|
|
27736
28492
|
]
|
|
@@ -28062,6 +28818,10 @@ var styles9 = import_react_native9.StyleSheet.create({
|
|
|
28062
28818
|
width: "100%",
|
|
28063
28819
|
height: "100%"
|
|
28064
28820
|
},
|
|
28821
|
+
thumbImage: {
|
|
28822
|
+
width: "100%",
|
|
28823
|
+
height: "100%"
|
|
28824
|
+
},
|
|
28065
28825
|
thumbFallback: {
|
|
28066
28826
|
flex: 1,
|
|
28067
28827
|
alignItems: "center",
|