@papyrus-sdk/ui-react-native 0.2.20 → 0.2.21
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 +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +968 -263
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1010 -304
- 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.mjs
CHANGED
|
@@ -20395,9 +20395,121 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20395
20395
|
]).default;
|
|
20396
20396
|
});
|
|
20397
20397
|
</script>
|
|
20398
|
+
<!-- @papyrus-comic-runtime:start -->
|
|
20399
|
+
<script>
|
|
20400
|
+
(function (root, factory) {
|
|
20401
|
+
if (typeof module === "object" && module.exports) {
|
|
20402
|
+
module.exports = factory();
|
|
20403
|
+
} else {
|
|
20404
|
+
root.PapyrusComicRuntime = Object.assign(
|
|
20405
|
+
factory(),
|
|
20406
|
+
root.PapyrusComicRuntime || {}
|
|
20407
|
+
);
|
|
20408
|
+
}
|
|
20409
|
+
})(typeof self === "object" ? self : this, function () {
|
|
20410
|
+
var IMAGE_EXTENSIONS = /\\.(?:gif|jpe?g|png|svg|webp)$/i;
|
|
20411
|
+
|
|
20412
|
+
function isComicImageName(name) {
|
|
20413
|
+
return typeof name === "string" && IMAGE_EXTENSIONS.test(name);
|
|
20414
|
+
}
|
|
20415
|
+
|
|
20416
|
+
function naturalCompare(left, right) {
|
|
20417
|
+
var leftParts = String(left).split(/(\\d+)/);
|
|
20418
|
+
var rightParts = String(right).split(/(\\d+)/);
|
|
20419
|
+
var length = Math.max(leftParts.length, rightParts.length);
|
|
20420
|
+
|
|
20421
|
+
for (var index = 0; index < length; index += 1) {
|
|
20422
|
+
var leftPart = leftParts[index] || "";
|
|
20423
|
+
var rightPart = rightParts[index] || "";
|
|
20424
|
+
if (leftPart === rightPart) continue;
|
|
20425
|
+
|
|
20426
|
+
var leftNumber = /^\\d+$/.test(leftPart) ? Number(leftPart) : null;
|
|
20427
|
+
var rightNumber = /^\\d+$/.test(rightPart) ? Number(rightPart) : null;
|
|
20428
|
+
if (leftNumber !== null && rightNumber !== null) {
|
|
20429
|
+
return leftNumber - rightNumber;
|
|
20430
|
+
}
|
|
20431
|
+
return leftPart.localeCompare(rightPart, undefined, {
|
|
20432
|
+
numeric: true,
|
|
20433
|
+
sensitivity: "base",
|
|
20434
|
+
});
|
|
20435
|
+
}
|
|
20436
|
+
|
|
20437
|
+
return 0;
|
|
20438
|
+
}
|
|
20439
|
+
|
|
20440
|
+
function sortComicPageNames(names) {
|
|
20441
|
+
return names.slice().sort(naturalCompare);
|
|
20442
|
+
}
|
|
20443
|
+
|
|
20444
|
+
function patchCbrWorkerSource(workerSource, wasmUrl) {
|
|
20445
|
+
return workerSource.replace(
|
|
20446
|
+
/new URL\\("libarchive\\.wasm",import\\.meta\\.url\\)\\.href/g,
|
|
20447
|
+
JSON.stringify(wasmUrl)
|
|
20448
|
+
);
|
|
20449
|
+
}
|
|
20450
|
+
|
|
20451
|
+
function getComicPreviewSize(width, height, maxWidth, maxHeight) {
|
|
20452
|
+
var safeWidth = Math.max(1, Number(width) || 1);
|
|
20453
|
+
var safeHeight = Math.max(1, Number(height) || 1);
|
|
20454
|
+
var widthLimit = maxWidth || 240;
|
|
20455
|
+
var heightLimit = maxHeight || 360;
|
|
20456
|
+
var scale = Math.min(1, widthLimit / safeWidth, heightLimit / safeHeight);
|
|
20457
|
+
return {
|
|
20458
|
+
width: Math.max(1, Math.round(safeWidth * scale)),
|
|
20459
|
+
height: Math.max(1, Math.round(safeHeight * scale)),
|
|
20460
|
+
};
|
|
20461
|
+
}
|
|
20462
|
+
|
|
20463
|
+
function getComicPageAspectRatio(width, height) {
|
|
20464
|
+
var safeWidth = Math.max(1, Number(width) || 1);
|
|
20465
|
+
var safeHeight = Math.max(1, Number(height) || 1);
|
|
20466
|
+
return safeWidth + " / " + safeHeight;
|
|
20467
|
+
}
|
|
20468
|
+
|
|
20469
|
+
function getProtectedComicPageIndexes(
|
|
20470
|
+
currentPage,
|
|
20471
|
+
visiblePageIndexes,
|
|
20472
|
+
loadingPageIndexes
|
|
20473
|
+
) {
|
|
20474
|
+
var protectedIndexes = new Set([
|
|
20475
|
+
currentPage - 1,
|
|
20476
|
+
currentPage,
|
|
20477
|
+
currentPage - 2,
|
|
20478
|
+
]);
|
|
20479
|
+
(visiblePageIndexes || []).forEach(function (pageIndex) {
|
|
20480
|
+
protectedIndexes.add(pageIndex);
|
|
20481
|
+
});
|
|
20482
|
+
(loadingPageIndexes || []).forEach(function (pageIndex) {
|
|
20483
|
+
protectedIndexes.add(pageIndex);
|
|
20484
|
+
});
|
|
20485
|
+
return protectedIndexes;
|
|
20486
|
+
}
|
|
20487
|
+
|
|
20488
|
+
function isCurrentComicPageLoad(
|
|
20489
|
+
loadGeneration,
|
|
20490
|
+
currentGeneration,
|
|
20491
|
+
entry,
|
|
20492
|
+
currentEntry
|
|
20493
|
+
) {
|
|
20494
|
+
return loadGeneration === currentGeneration && entry === currentEntry;
|
|
20495
|
+
}
|
|
20496
|
+
|
|
20497
|
+
return {
|
|
20498
|
+
isComicImageName: isComicImageName,
|
|
20499
|
+
sortComicPageNames: sortComicPageNames,
|
|
20500
|
+
patchCbrWorkerSource: patchCbrWorkerSource,
|
|
20501
|
+
getComicPreviewSize: getComicPreviewSize,
|
|
20502
|
+
getComicPageAspectRatio: getComicPageAspectRatio,
|
|
20503
|
+
getProtectedComicPageIndexes: getProtectedComicPageIndexes,
|
|
20504
|
+
isCurrentComicPageLoad: isCurrentComicPageLoad,
|
|
20505
|
+
};
|
|
20506
|
+
});
|
|
20507
|
+
|
|
20508
|
+
</script>
|
|
20509
|
+
<!-- @papyrus-comic-runtime:end -->
|
|
20398
20510
|
<script>
|
|
20399
20511
|
(function () {
|
|
20400
|
-
const viewer = document.getElementById(
|
|
20512
|
+
const viewer = document.getElementById('viewer');
|
|
20401
20513
|
const DEFAULT_FONT_SIZE = 16;
|
|
20402
20514
|
const TEXT_PAGE_CHUNK = 1600;
|
|
20403
20515
|
|
|
@@ -20410,27 +20522,116 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20410
20522
|
let currentPage = 1;
|
|
20411
20523
|
let pageCount = 0;
|
|
20412
20524
|
let zoom = 1.0;
|
|
20525
|
+
let rotation = 0;
|
|
20526
|
+
let comicArchive = null;
|
|
20527
|
+
let comicEntries = [];
|
|
20528
|
+
let comicContainer = null;
|
|
20529
|
+
let comicPages = [];
|
|
20530
|
+
let comicObserver = null;
|
|
20531
|
+
let comicScrollFrame = null;
|
|
20532
|
+
const comicObjectUrls = new Map();
|
|
20533
|
+
const comicLoading = new Map();
|
|
20534
|
+
const comicDimensions = new Map();
|
|
20535
|
+
const comicPreviewCache = new Map();
|
|
20536
|
+
const comicPreviewLoading = new Map();
|
|
20537
|
+
const COMIC_CACHE_LIMIT = 16;
|
|
20538
|
+
const COMIC_PREVIEW_CACHE_LIMIT = 8;
|
|
20539
|
+
const comicHelpers = window.PapyrusComicRuntime || {};
|
|
20540
|
+
const runtimeConfig = window.__PAPYRUS_RUNTIME_CONFIG__ || {};
|
|
20541
|
+
let comicDispose = null;
|
|
20542
|
+
let comicGeneration = 0;
|
|
20413
20543
|
|
|
20414
20544
|
const sendMessage = (payload) => {
|
|
20415
|
-
if (
|
|
20416
|
-
window.ReactNativeWebView &&
|
|
20417
|
-
window.ReactNativeWebView.postMessage
|
|
20418
|
-
) {
|
|
20545
|
+
if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
|
|
20419
20546
|
window.ReactNativeWebView.postMessage(JSON.stringify(payload));
|
|
20420
20547
|
return;
|
|
20421
20548
|
}
|
|
20422
20549
|
if (window.parent && window.parent !== window) {
|
|
20423
|
-
window.parent.postMessage(payload,
|
|
20550
|
+
window.parent.postMessage(payload, '*');
|
|
20424
20551
|
}
|
|
20425
20552
|
};
|
|
20426
20553
|
|
|
20427
20554
|
const sendResponse = (id, ok, data, error) => {
|
|
20428
|
-
sendMessage({ type:
|
|
20555
|
+
sendMessage({ type: 'response', id, ok, data, error });
|
|
20556
|
+
};
|
|
20557
|
+
|
|
20558
|
+
const runtimeAssetRequests = new Map();
|
|
20559
|
+
const fileChunkRequests = new Map();
|
|
20560
|
+
|
|
20561
|
+
const requestRuntimeAsset = (url, encoding) =>
|
|
20562
|
+
new Promise((resolve, reject) => {
|
|
20563
|
+
const id = \`runtime-asset-\${Date.now()}-\${Math.random()}\`;
|
|
20564
|
+
const timeout = setTimeout(() => {
|
|
20565
|
+
runtimeAssetRequests.delete(id);
|
|
20566
|
+
reject(new Error(\`Tempo esgotado ao carregar asset CBR: \${url}\`));
|
|
20567
|
+
}, 15000);
|
|
20568
|
+
runtimeAssetRequests.set(id, {resolve, reject, timeout});
|
|
20569
|
+
sendMessage({type: 'asset-request', id, url, encoding});
|
|
20570
|
+
});
|
|
20571
|
+
|
|
20572
|
+
const encodeArrayBufferAsDataUrl = async (buffer) => {
|
|
20573
|
+
const bytes = new Uint8Array(buffer);
|
|
20574
|
+
let binary = '';
|
|
20575
|
+
const chunkSize = 0x8000;
|
|
20576
|
+
for (let offset = 0; offset < bytes.length; offset += chunkSize) {
|
|
20577
|
+
binary += String.fromCharCode(
|
|
20578
|
+
...bytes.subarray(offset, Math.min(offset + chunkSize, bytes.length)),
|
|
20579
|
+
);
|
|
20580
|
+
}
|
|
20581
|
+
return \`data:application/wasm;base64,\${btoa(binary)}\`;
|
|
20582
|
+
};
|
|
20583
|
+
|
|
20584
|
+
const fetchRuntimeAsset = async (url, encoding) => {
|
|
20585
|
+
try {
|
|
20586
|
+
const response = await fetch(url);
|
|
20587
|
+
if (!response.ok) throw new Error(\`status \${response.status}\`);
|
|
20588
|
+
if (encoding === 'text') return await response.text();
|
|
20589
|
+
return await encodeArrayBufferAsDataUrl(await response.arrayBuffer());
|
|
20590
|
+
} catch {
|
|
20591
|
+
return await requestRuntimeAsset(url, encoding);
|
|
20592
|
+
}
|
|
20593
|
+
};
|
|
20594
|
+
|
|
20595
|
+
const requestLocalFileChunk = (uri, offset, length) =>
|
|
20596
|
+
new Promise((resolve, reject) => {
|
|
20597
|
+
const id = \`file-chunk-\${Date.now()}-\${Math.random()}\`;
|
|
20598
|
+
const timeout = setTimeout(() => {
|
|
20599
|
+
fileChunkRequests.delete(id);
|
|
20600
|
+
reject(new Error(\`Tempo esgotado ao ler arquivo local: \${uri}\`));
|
|
20601
|
+
}, 30000);
|
|
20602
|
+
fileChunkRequests.set(id, {resolve, reject, timeout});
|
|
20603
|
+
sendMessage({type: 'file-chunk-request', id, uri, offset, length});
|
|
20604
|
+
});
|
|
20605
|
+
|
|
20606
|
+
const readLocalFile = async (uri) => {
|
|
20607
|
+
const chunkSize = 1024 * 1024;
|
|
20608
|
+
const chunks = [];
|
|
20609
|
+
let offset = 0;
|
|
20610
|
+
let totalLength = 0;
|
|
20611
|
+
while (true) {
|
|
20612
|
+
const result = await requestLocalFileChunk(uri, offset, chunkSize);
|
|
20613
|
+
const bytes = decodeBase64(result.data || '');
|
|
20614
|
+
if (bytes.length === 0 && !result.done) {
|
|
20615
|
+
throw new Error('Leitura nativa retornou um chunk vazio.');
|
|
20616
|
+
}
|
|
20617
|
+
chunks.push(bytes);
|
|
20618
|
+
totalLength += bytes.length;
|
|
20619
|
+
offset += bytes.length;
|
|
20620
|
+
if (result.done) break;
|
|
20621
|
+
}
|
|
20622
|
+
|
|
20623
|
+
const output = new Uint8Array(totalLength);
|
|
20624
|
+
let outputOffset = 0;
|
|
20625
|
+
chunks.forEach((chunk) => {
|
|
20626
|
+
output.set(chunk, outputOffset);
|
|
20627
|
+
outputOffset += chunk.length;
|
|
20628
|
+
});
|
|
20629
|
+
return output.buffer;
|
|
20429
20630
|
};
|
|
20430
20631
|
|
|
20431
20632
|
const sendState = (extra) => {
|
|
20432
20633
|
sendMessage({
|
|
20433
|
-
type:
|
|
20634
|
+
type: 'state',
|
|
20434
20635
|
payload: {
|
|
20435
20636
|
pageCount,
|
|
20436
20637
|
currentPage,
|
|
@@ -20441,70 +20642,66 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20441
20642
|
};
|
|
20442
20643
|
|
|
20443
20644
|
const sendEvent = (name, payload) => {
|
|
20444
|
-
sendMessage({ type:
|
|
20445
|
-
};
|
|
20446
|
-
|
|
20447
|
-
const log = (...args) => {
|
|
20448
|
-
sendEvent("RUNTIME_LOG", {
|
|
20449
|
-
message: args.map((value) => String(value)).join(" "),
|
|
20450
|
-
});
|
|
20645
|
+
sendMessage({ type: 'event', name, payload });
|
|
20451
20646
|
};
|
|
20452
20647
|
|
|
20453
20648
|
const reportError = (error, context) => {
|
|
20454
|
-
const message =
|
|
20455
|
-
error && error.message ? error.message : String(error);
|
|
20649
|
+
const message = error && error.message ? error.message : String(error);
|
|
20456
20650
|
const stack = error && error.stack ? error.stack : null;
|
|
20457
|
-
sendEvent(
|
|
20458
|
-
};
|
|
20459
|
-
|
|
20460
|
-
const EPUB_OPEN_TIMEOUT_MS = 180000;
|
|
20461
|
-
const EPUB_READY_TIMEOUT_MS = 180000;
|
|
20462
|
-
const EPUB_DISPLAY_TIMEOUT_MS = 30000;
|
|
20463
|
-
|
|
20464
|
-
const withTimeout = async (promise, ms, label) => {
|
|
20465
|
-
let timer = null;
|
|
20466
|
-
try {
|
|
20467
|
-
return await Promise.race([
|
|
20468
|
-
promise,
|
|
20469
|
-
new Promise((_, reject) => {
|
|
20470
|
-
timer = setTimeout(
|
|
20471
|
-
() => reject(new Error(\`Timeout: \${label}\`)),
|
|
20472
|
-
ms
|
|
20473
|
-
);
|
|
20474
|
-
}),
|
|
20475
|
-
]);
|
|
20476
|
-
} finally {
|
|
20477
|
-
if (timer) {
|
|
20478
|
-
clearTimeout(timer);
|
|
20479
|
-
}
|
|
20480
|
-
}
|
|
20651
|
+
sendEvent('RUNTIME_ERROR', { message, context, stack });
|
|
20481
20652
|
};
|
|
20482
20653
|
|
|
20483
20654
|
const shouldIgnoreError = (error) => {
|
|
20484
|
-
const message =
|
|
20485
|
-
|
|
20486
|
-
return message.includes("ResizeObserver loop");
|
|
20655
|
+
const message = error && error.message ? error.message : String(error || '');
|
|
20656
|
+
return message.includes('ResizeObserver loop');
|
|
20487
20657
|
};
|
|
20488
20658
|
|
|
20489
|
-
window.addEventListener(
|
|
20659
|
+
window.addEventListener('error', (event) => {
|
|
20490
20660
|
const error = event.error || event.message;
|
|
20491
20661
|
if (shouldIgnoreError(error)) return;
|
|
20492
|
-
reportError(error,
|
|
20662
|
+
reportError(error, 'window.error');
|
|
20493
20663
|
});
|
|
20494
20664
|
|
|
20495
|
-
window.addEventListener(
|
|
20665
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
20496
20666
|
if (shouldIgnoreError(event.reason)) return;
|
|
20497
|
-
reportError(event.reason,
|
|
20667
|
+
reportError(event.reason, 'unhandledrejection');
|
|
20498
20668
|
});
|
|
20499
20669
|
|
|
20670
|
+
const clearComicState = () => {
|
|
20671
|
+
comicGeneration += 1;
|
|
20672
|
+
if (comicObserver) {
|
|
20673
|
+
comicObserver.disconnect();
|
|
20674
|
+
comicObserver = null;
|
|
20675
|
+
}
|
|
20676
|
+
if (comicScrollFrame !== null) {
|
|
20677
|
+
cancelAnimationFrame(comicScrollFrame);
|
|
20678
|
+
comicScrollFrame = null;
|
|
20679
|
+
}
|
|
20680
|
+
comicObjectUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
20681
|
+
comicObjectUrls.clear();
|
|
20682
|
+
comicLoading.clear();
|
|
20683
|
+
comicDimensions.clear();
|
|
20684
|
+
comicPreviewCache.clear();
|
|
20685
|
+
comicPreviewLoading.clear();
|
|
20686
|
+
if (comicDispose) {
|
|
20687
|
+
void comicDispose();
|
|
20688
|
+
comicDispose = null;
|
|
20689
|
+
}
|
|
20690
|
+
comicArchive = null;
|
|
20691
|
+
comicEntries = [];
|
|
20692
|
+
comicContainer = null;
|
|
20693
|
+
comicPages = [];
|
|
20694
|
+
};
|
|
20695
|
+
|
|
20500
20696
|
const clearViewer = () => {
|
|
20697
|
+
clearComicState();
|
|
20501
20698
|
while (viewer.firstChild) {
|
|
20502
20699
|
viewer.removeChild(viewer.firstChild);
|
|
20503
20700
|
}
|
|
20504
20701
|
};
|
|
20505
20702
|
|
|
20506
20703
|
const decodeBase64 = (value) => {
|
|
20507
|
-
const clean = value.replace(/\\s/g,
|
|
20704
|
+
const clean = value.replace(/\\s/g, '');
|
|
20508
20705
|
const binary = atob(clean);
|
|
20509
20706
|
const len = binary.length;
|
|
20510
20707
|
const bytes = new Uint8Array(len);
|
|
@@ -20516,41 +20713,438 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20516
20713
|
|
|
20517
20714
|
const decodeBase64ToText = (value) => {
|
|
20518
20715
|
const bytes = decodeBase64(value);
|
|
20519
|
-
return new TextDecoder(
|
|
20716
|
+
return new TextDecoder('utf-8').decode(bytes);
|
|
20717
|
+
};
|
|
20718
|
+
|
|
20719
|
+
const sourceToArrayBuffer = async (source) => {
|
|
20720
|
+
if (source.kind === 'uri') {
|
|
20721
|
+
if (/^(?:file|content):\\/\\//i.test(source.uri)) {
|
|
20722
|
+
return readLocalFile(source.uri);
|
|
20723
|
+
}
|
|
20724
|
+
const response = await fetch(source.uri);
|
|
20725
|
+
if (!response.ok && response.status !== 0) {
|
|
20726
|
+
throw new Error(\`Falha ao carregar quadrinho (\${response.status})\`);
|
|
20727
|
+
}
|
|
20728
|
+
return response.arrayBuffer();
|
|
20729
|
+
}
|
|
20730
|
+
if (source.kind === 'base64') {
|
|
20731
|
+
return decodeBase64(source.data).buffer;
|
|
20732
|
+
}
|
|
20733
|
+
throw new Error('Fonte de quadrinho inv\xE1lida.');
|
|
20734
|
+
};
|
|
20735
|
+
|
|
20736
|
+
const comicMimeType = (name) => {
|
|
20737
|
+
const extension = name.split('.').pop()?.toLowerCase();
|
|
20738
|
+
if (extension === 'png') return 'image/png';
|
|
20739
|
+
if (extension === 'gif') return 'image/gif';
|
|
20740
|
+
if (extension === 'svg') return 'image/svg+xml';
|
|
20741
|
+
if (extension === 'webp') return 'image/webp';
|
|
20742
|
+
return 'image/jpeg';
|
|
20520
20743
|
};
|
|
20521
20744
|
|
|
20522
|
-
const
|
|
20523
|
-
|
|
20524
|
-
const
|
|
20525
|
-
|
|
20526
|
-
|
|
20527
|
-
|
|
20745
|
+
const updateComicCurrentPage = () => {
|
|
20746
|
+
if (!comicContainer || comicPages.length === 0) return;
|
|
20747
|
+
const viewportTop = comicContainer.scrollTop;
|
|
20748
|
+
let closestIndex = currentPage - 1;
|
|
20749
|
+
let closestDistance = Number.POSITIVE_INFINITY;
|
|
20750
|
+
comicPages.forEach((page, index) => {
|
|
20751
|
+
const distance = Math.abs(page.offsetTop - viewportTop);
|
|
20752
|
+
if (distance < closestDistance) {
|
|
20753
|
+
closestDistance = distance;
|
|
20754
|
+
closestIndex = index;
|
|
20755
|
+
}
|
|
20756
|
+
});
|
|
20757
|
+
const nextPage = Math.max(1, Math.min(pageCount, closestIndex + 1));
|
|
20758
|
+
if (nextPage !== currentPage) {
|
|
20759
|
+
currentPage = nextPage;
|
|
20760
|
+
sendState();
|
|
20761
|
+
}
|
|
20762
|
+
};
|
|
20763
|
+
|
|
20764
|
+
const scheduleComicCurrentPage = () => {
|
|
20765
|
+
if (comicScrollFrame !== null) return;
|
|
20766
|
+
comicScrollFrame = requestAnimationFrame(() => {
|
|
20767
|
+
comicScrollFrame = null;
|
|
20768
|
+
updateComicCurrentPage();
|
|
20769
|
+
});
|
|
20770
|
+
};
|
|
20771
|
+
|
|
20772
|
+
const evictComicUrls = () => {
|
|
20773
|
+
if (comicObjectUrls.size <= COMIC_CACHE_LIMIT) return;
|
|
20774
|
+
const protectedIndexes = new Set([
|
|
20775
|
+
currentPage - 1,
|
|
20776
|
+
currentPage,
|
|
20777
|
+
currentPage - 2,
|
|
20778
|
+
]);
|
|
20779
|
+
for (const [index, url] of comicObjectUrls) {
|
|
20780
|
+
if (comicObjectUrls.size <= COMIC_CACHE_LIMIT) break;
|
|
20781
|
+
if (protectedIndexes.has(index)) continue;
|
|
20782
|
+
URL.revokeObjectURL(url);
|
|
20783
|
+
comicObjectUrls.delete(index);
|
|
20784
|
+
const image = comicPages[index]?.querySelector('img');
|
|
20785
|
+
const page = comicPages[index];
|
|
20786
|
+
const dimensions = comicDimensions.get(index);
|
|
20787
|
+
const width = dimensions?.width || image?.naturalWidth || 0;
|
|
20788
|
+
const height = dimensions?.height || image?.naturalHeight || 0;
|
|
20789
|
+
if (page && width > 0 && height > 0) {
|
|
20790
|
+
page.style.aspectRatio = comicHelpers.getComicPageAspectRatio(
|
|
20791
|
+
width,
|
|
20792
|
+
height
|
|
20793
|
+
);
|
|
20794
|
+
}
|
|
20795
|
+
if (image) image.removeAttribute('src');
|
|
20796
|
+
}
|
|
20797
|
+
};
|
|
20798
|
+
|
|
20799
|
+
const ensureComicPage = async (pageIndex) => {
|
|
20800
|
+
if (comicObjectUrls.has(pageIndex)) {
|
|
20801
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
20802
|
+
if (image && !image.src) image.src = comicObjectUrls.get(pageIndex);
|
|
20803
|
+
return comicObjectUrls.get(pageIndex);
|
|
20804
|
+
}
|
|
20805
|
+
if (comicLoading.has(pageIndex)) return comicLoading.get(pageIndex);
|
|
20806
|
+
|
|
20807
|
+
const entry = comicEntries[pageIndex];
|
|
20808
|
+
if (!entry) throw new Error(\`P\xE1gina de quadrinho inv\xE1lida: \${pageIndex}\`);
|
|
20809
|
+
const loadGeneration = comicGeneration;
|
|
20810
|
+
const pending = entry.async('blob').then((blob) => {
|
|
20811
|
+
if (
|
|
20812
|
+
!comicHelpers.isCurrentComicPageLoad(
|
|
20813
|
+
loadGeneration,
|
|
20814
|
+
comicGeneration,
|
|
20815
|
+
entry,
|
|
20816
|
+
comicEntries[pageIndex]
|
|
20817
|
+
)
|
|
20818
|
+
) {
|
|
20819
|
+
return null;
|
|
20820
|
+
}
|
|
20821
|
+
const url = URL.createObjectURL(
|
|
20822
|
+
new Blob([blob], { type: comicMimeType(entry.name) })
|
|
20528
20823
|
);
|
|
20824
|
+
comicObjectUrls.set(pageIndex, url);
|
|
20825
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
20826
|
+
if (image) image.src = url;
|
|
20827
|
+
evictComicUrls();
|
|
20828
|
+
return url;
|
|
20829
|
+
});
|
|
20830
|
+
comicLoading.set(pageIndex, pending);
|
|
20831
|
+
try {
|
|
20832
|
+
return await pending;
|
|
20833
|
+
} finally {
|
|
20834
|
+
if (comicLoading.get(pageIndex) === pending) {
|
|
20835
|
+
comicLoading.delete(pageIndex);
|
|
20836
|
+
}
|
|
20529
20837
|
}
|
|
20530
|
-
|
|
20531
|
-
|
|
20838
|
+
};
|
|
20839
|
+
|
|
20840
|
+
const renderComicPage = (pageIndex) => {
|
|
20841
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
20842
|
+
if (!image) return;
|
|
20843
|
+
image.style.width = \`\${Math.max(40, Math.round(100 * zoom))}%\`;
|
|
20844
|
+
image.style.transform = \`rotate(\${rotation}deg)\`;
|
|
20845
|
+
};
|
|
20846
|
+
|
|
20847
|
+
const applyComicLayout = () => {
|
|
20848
|
+
comicPages.forEach((_, pageIndex) => renderComicPage(pageIndex));
|
|
20849
|
+
};
|
|
20850
|
+
|
|
20851
|
+
const loadComic = async (source, format) => {
|
|
20852
|
+
clearViewer();
|
|
20853
|
+
let entries;
|
|
20854
|
+
if (format === 'cbr') {
|
|
20855
|
+
const clientUrl = runtimeConfig.cbrClientUrl;
|
|
20856
|
+
const workerUrl = runtimeConfig.cbrWorkerUrl;
|
|
20857
|
+
const wasmUrl = runtimeConfig.cbrWasmUrl;
|
|
20858
|
+
if (!clientUrl || !workerUrl || !wasmUrl) {
|
|
20859
|
+
throw new Error(
|
|
20860
|
+
'CBR no mobile exige o pacote opcional de runtime libarchive.'
|
|
20861
|
+
);
|
|
20862
|
+
}
|
|
20863
|
+
|
|
20864
|
+
const [clientSource, workerSource, wasmSource] = await Promise.all([
|
|
20865
|
+
fetchRuntimeAsset(clientUrl, 'text'),
|
|
20866
|
+
fetchRuntimeAsset(workerUrl, 'text'),
|
|
20867
|
+
runtimeConfig.cbrWasmDataUrl ||
|
|
20868
|
+
fetchRuntimeAsset(wasmUrl, 'base64'),
|
|
20869
|
+
]);
|
|
20870
|
+
const patchedWorkerSource = comicHelpers.patchCbrWorkerSource(
|
|
20871
|
+
workerSource,
|
|
20872
|
+
wasmSource
|
|
20873
|
+
);
|
|
20874
|
+
const workerObjectUrl = URL.createObjectURL(
|
|
20875
|
+
new Blob([patchedWorkerSource], {type: 'text/javascript'})
|
|
20876
|
+
);
|
|
20877
|
+
const clientObjectUrl = URL.createObjectURL(
|
|
20878
|
+
new Blob([clientSource], { type: 'text/javascript' })
|
|
20879
|
+
);
|
|
20880
|
+
try {
|
|
20881
|
+
const archiveModule = await import(clientObjectUrl);
|
|
20882
|
+
const createCbrWorker = () => {
|
|
20883
|
+
const worker = new Worker(workerObjectUrl, {type: 'module'});
|
|
20884
|
+
worker.addEventListener('error', (event) => {
|
|
20885
|
+
sendEvent('RUNTIME_ERROR', {
|
|
20886
|
+
message: \`CBR worker: \${event?.message || 'falha ao executar o worker'}\`,
|
|
20887
|
+
context: 'comic.worker',
|
|
20888
|
+
});
|
|
20889
|
+
});
|
|
20890
|
+
worker.addEventListener('messageerror', () => {
|
|
20891
|
+
sendEvent('RUNTIME_ERROR', {
|
|
20892
|
+
message: 'CBR worker: falha ao transferir mensagem',
|
|
20893
|
+
context: 'comic.worker',
|
|
20894
|
+
});
|
|
20895
|
+
});
|
|
20896
|
+
return worker;
|
|
20897
|
+
};
|
|
20898
|
+
archiveModule.Archive.init({getWorker: createCbrWorker});
|
|
20899
|
+
const bytes = await sourceToArrayBuffer(source);
|
|
20900
|
+
const file = new Blob([bytes], {
|
|
20901
|
+
type: 'application/vnd.comicbook-rar',
|
|
20902
|
+
});
|
|
20903
|
+
const archive = await archiveModule.Archive.open(file);
|
|
20904
|
+
const files = await archive.getFilesArray();
|
|
20905
|
+
entries = files
|
|
20906
|
+
.filter(
|
|
20907
|
+
(item) => {
|
|
20908
|
+
const name = \`\${item?.path || ''}\${item?.file?.name || ''}\`;
|
|
20909
|
+
return item?.file && comicHelpers.isComicImageName(name);
|
|
20910
|
+
}
|
|
20911
|
+
)
|
|
20912
|
+
.map((item) => {
|
|
20913
|
+
const name = \`\${item.path || ''}\${item.file.name}\`;
|
|
20914
|
+
return {
|
|
20915
|
+
name,
|
|
20916
|
+
async: async () => item.file.extract(),
|
|
20917
|
+
};
|
|
20918
|
+
});
|
|
20919
|
+
comicDispose = async () => {
|
|
20920
|
+
await archive.close();
|
|
20921
|
+
URL.revokeObjectURL(workerObjectUrl);
|
|
20922
|
+
URL.revokeObjectURL(clientObjectUrl);
|
|
20923
|
+
};
|
|
20924
|
+
} catch (error) {
|
|
20925
|
+
URL.revokeObjectURL(workerObjectUrl);
|
|
20926
|
+
URL.revokeObjectURL(clientObjectUrl);
|
|
20927
|
+
throw error;
|
|
20928
|
+
}
|
|
20929
|
+
} else {
|
|
20930
|
+
if (!window.JSZip) {
|
|
20931
|
+
throw new Error('O runtime ZIP do leitor mobile n\xE3o foi carregado.');
|
|
20932
|
+
}
|
|
20933
|
+
|
|
20934
|
+
const bytes = await sourceToArrayBuffer(source);
|
|
20935
|
+
comicArchive = await window.JSZip.loadAsync(bytes);
|
|
20936
|
+
entries = Object.keys(comicArchive.files)
|
|
20937
|
+
.filter((name) => {
|
|
20938
|
+
const entry = comicArchive.files[name];
|
|
20939
|
+
return !entry.dir && comicHelpers.isComicImageName(name);
|
|
20940
|
+
})
|
|
20941
|
+
.map((name) => comicArchive.files[name]);
|
|
20532
20942
|
}
|
|
20533
|
-
|
|
20534
|
-
|
|
20943
|
+
|
|
20944
|
+
const names = comicHelpers.sortComicPageNames(
|
|
20945
|
+
entries.map((entry) => entry.name)
|
|
20946
|
+
);
|
|
20947
|
+
const entriesByName = new Map(entries.map((entry) => [entry.name, entry]));
|
|
20948
|
+
comicEntries = names.map((name) => entriesByName.get(name));
|
|
20949
|
+
if (comicEntries.length === 0) {
|
|
20950
|
+
if (comicDispose) {
|
|
20951
|
+
await comicDispose();
|
|
20952
|
+
comicDispose = null;
|
|
20953
|
+
}
|
|
20954
|
+
throw new Error('O arquivo n\xE3o cont\xE9m p\xE1ginas de imagem.');
|
|
20955
|
+
}
|
|
20956
|
+
|
|
20957
|
+
comicContainer = document.createElement('div');
|
|
20958
|
+
comicContainer.style.width = '100%';
|
|
20959
|
+
comicContainer.style.height = '100%';
|
|
20960
|
+
comicContainer.style.overflow = 'auto';
|
|
20961
|
+
comicContainer.style.padding = '16px 0 120px';
|
|
20962
|
+
comicContainer.style.boxSizing = 'border-box';
|
|
20963
|
+
comicContainer.style.background = '#ffffff';
|
|
20964
|
+
comicContainer.addEventListener('scroll', scheduleComicCurrentPage, {
|
|
20965
|
+
passive: true,
|
|
20966
|
+
});
|
|
20967
|
+
viewer.style.overflow = 'hidden';
|
|
20968
|
+
viewer.appendChild(comicContainer);
|
|
20969
|
+
|
|
20970
|
+
comicPages = comicEntries.map((entry, pageIndex) => {
|
|
20971
|
+
const page = document.createElement('div');
|
|
20972
|
+
page.dataset.pageIndex = String(pageIndex);
|
|
20973
|
+
page.style.width = '100%';
|
|
20974
|
+
page.style.minHeight = '80px';
|
|
20975
|
+
page.style.display = 'flex';
|
|
20976
|
+
page.style.justifyContent = 'center';
|
|
20977
|
+
page.style.alignItems = 'flex-start';
|
|
20978
|
+
page.style.padding = '0 12px 20px';
|
|
20979
|
+
page.style.boxSizing = 'border-box';
|
|
20980
|
+
|
|
20981
|
+
const image = document.createElement('img');
|
|
20982
|
+
image.alt = \`P\xE1gina \${pageIndex + 1}\`;
|
|
20983
|
+
image.draggable = false;
|
|
20984
|
+
image.decoding = 'async';
|
|
20985
|
+
image.loading = 'lazy';
|
|
20986
|
+
image.style.display = 'block';
|
|
20987
|
+
image.style.maxWidth = 'none';
|
|
20988
|
+
image.style.height = 'auto';
|
|
20989
|
+
image.style.userSelect = 'none';
|
|
20990
|
+
image.addEventListener('load', () => {
|
|
20991
|
+
if (image.naturalWidth > 0 && image.naturalHeight > 0) {
|
|
20992
|
+
comicDimensions.set(pageIndex, {
|
|
20993
|
+
width: image.naturalWidth,
|
|
20994
|
+
height: image.naturalHeight,
|
|
20995
|
+
});
|
|
20996
|
+
page.style.aspectRatio = comicHelpers.getComicPageAspectRatio(
|
|
20997
|
+
image.naturalWidth,
|
|
20998
|
+
image.naturalHeight
|
|
20999
|
+
);
|
|
21000
|
+
}
|
|
21001
|
+
});
|
|
21002
|
+
page.appendChild(image);
|
|
21003
|
+
comicContainer.appendChild(page);
|
|
21004
|
+
return page;
|
|
21005
|
+
});
|
|
21006
|
+
|
|
21007
|
+
if (typeof IntersectionObserver === 'function') {
|
|
21008
|
+
comicObserver = new IntersectionObserver(
|
|
21009
|
+
(observations) => {
|
|
21010
|
+
observations.forEach((observation) => {
|
|
21011
|
+
if (!observation.isIntersecting) return;
|
|
21012
|
+
const pageIndex = Number(observation.target.dataset.pageIndex);
|
|
21013
|
+
void ensureComicPage(pageIndex).catch((error) =>
|
|
21014
|
+
sendEvent('RUNTIME_ERROR', {
|
|
21015
|
+
message: error?.message || String(error),
|
|
21016
|
+
context: 'comic.page',
|
|
21017
|
+
})
|
|
21018
|
+
);
|
|
21019
|
+
});
|
|
21020
|
+
scheduleComicCurrentPage();
|
|
21021
|
+
},
|
|
21022
|
+
{ root: comicContainer, rootMargin: '600px 0px' }
|
|
21023
|
+
);
|
|
21024
|
+
comicPages.forEach((page) => comicObserver.observe(page));
|
|
21025
|
+
} else {
|
|
21026
|
+
for (let pageIndex = 0; pageIndex < Math.min(3, comicPages.length); pageIndex += 1) {
|
|
21027
|
+
void ensureComicPage(pageIndex);
|
|
21028
|
+
}
|
|
21029
|
+
}
|
|
21030
|
+
pageCount = comicPages.length;
|
|
21031
|
+
currentPage = 1;
|
|
21032
|
+
await ensureComicPage(0);
|
|
21033
|
+
applyComicLayout();
|
|
21034
|
+
return { pageCount };
|
|
21035
|
+
};
|
|
21036
|
+
|
|
21037
|
+
const readComicBlobAsDataUrl = (blob, mimeType) =>
|
|
21038
|
+
new Promise((resolve, reject) => {
|
|
20535
21039
|
const reader = new FileReader();
|
|
20536
|
-
reader.onerror = () =>
|
|
20537
|
-
reject(new Error("Failed to read epub blob"));
|
|
21040
|
+
reader.onerror = () => reject(new Error('Falha ao gerar preview.'));
|
|
20538
21041
|
reader.onload = () => resolve(reader.result);
|
|
20539
|
-
reader.
|
|
21042
|
+
reader.readAsDataURL(new Blob([blob], { type: mimeType }));
|
|
20540
21043
|
});
|
|
21044
|
+
|
|
21045
|
+
const createComicPagePreview = async (pageIndex) => {
|
|
21046
|
+
const entry = comicEntries[pageIndex];
|
|
21047
|
+
if (!entry) return null;
|
|
21048
|
+
const mimeType = comicMimeType(entry.name);
|
|
21049
|
+
const sourceUrl = await ensureComicPage(pageIndex);
|
|
21050
|
+
if (!sourceUrl) return null;
|
|
21051
|
+
try {
|
|
21052
|
+
const image = new Image();
|
|
21053
|
+
image.decoding = 'async';
|
|
21054
|
+
await new Promise((resolve, reject) => {
|
|
21055
|
+
image.onload = resolve;
|
|
21056
|
+
image.onerror = () => reject(new Error('Falha ao decodificar preview.'));
|
|
21057
|
+
image.src = sourceUrl;
|
|
21058
|
+
});
|
|
21059
|
+
const size = comicHelpers.getComicPreviewSize(
|
|
21060
|
+
image.naturalWidth || image.width,
|
|
21061
|
+
image.naturalHeight || image.height
|
|
21062
|
+
);
|
|
21063
|
+
const canvas = document.createElement('canvas');
|
|
21064
|
+
canvas.width = size.width;
|
|
21065
|
+
canvas.height = size.height;
|
|
21066
|
+
const context = canvas.getContext('2d');
|
|
21067
|
+
if (!context) throw new Error('Canvas indispon\xEDvel para preview.');
|
|
21068
|
+
context.fillStyle = '#ffffff';
|
|
21069
|
+
context.fillRect(0, 0, size.width, size.height);
|
|
21070
|
+
context.drawImage(image, 0, 0, size.width, size.height);
|
|
21071
|
+
return canvas.toDataURL('image/jpeg', 0.78);
|
|
21072
|
+
} catch {
|
|
21073
|
+
try {
|
|
21074
|
+
const response = await fetch(sourceUrl);
|
|
21075
|
+
const blob = await response.blob();
|
|
21076
|
+
return await readComicBlobAsDataUrl(blob, mimeType);
|
|
21077
|
+
} catch {
|
|
21078
|
+
return null;
|
|
21079
|
+
}
|
|
21080
|
+
}
|
|
21081
|
+
};
|
|
21082
|
+
|
|
21083
|
+
const getComicPagePreview = async (pageIndex) => {
|
|
21084
|
+
const entry = comicEntries[pageIndex];
|
|
21085
|
+
if (!entry) return null;
|
|
21086
|
+
if (comicPreviewCache.has(pageIndex)) {
|
|
21087
|
+
return comicPreviewCache.get(pageIndex);
|
|
21088
|
+
}
|
|
21089
|
+
if (comicPreviewLoading.has(pageIndex)) {
|
|
21090
|
+
return comicPreviewLoading.get(pageIndex);
|
|
21091
|
+
}
|
|
21092
|
+
const loadGeneration = comicGeneration;
|
|
21093
|
+
const pending = createComicPagePreview(pageIndex).then((preview) => {
|
|
21094
|
+
if (
|
|
21095
|
+
!comicHelpers.isCurrentComicPageLoad(
|
|
21096
|
+
loadGeneration,
|
|
21097
|
+
comicGeneration,
|
|
21098
|
+
entry,
|
|
21099
|
+
comicEntries[pageIndex]
|
|
21100
|
+
)
|
|
21101
|
+
) {
|
|
21102
|
+
return null;
|
|
21103
|
+
}
|
|
21104
|
+
comicPreviewCache.set(pageIndex, preview);
|
|
21105
|
+
while (comicPreviewCache.size > COMIC_PREVIEW_CACHE_LIMIT) {
|
|
21106
|
+
comicPreviewCache.delete(comicPreviewCache.keys().next().value);
|
|
21107
|
+
}
|
|
21108
|
+
return preview;
|
|
21109
|
+
});
|
|
21110
|
+
comicPreviewLoading.set(pageIndex, pending);
|
|
21111
|
+
try {
|
|
21112
|
+
return await pending;
|
|
21113
|
+
} finally {
|
|
21114
|
+
if (comicPreviewLoading.get(pageIndex) === pending) {
|
|
21115
|
+
comicPreviewLoading.delete(pageIndex);
|
|
21116
|
+
}
|
|
21117
|
+
}
|
|
21118
|
+
};
|
|
21119
|
+
|
|
21120
|
+
const getComicPageDimensions = async (pageIndex) => {
|
|
21121
|
+
const known = comicDimensions.get(pageIndex);
|
|
21122
|
+
if (known) return known;
|
|
21123
|
+
await ensureComicPage(pageIndex);
|
|
21124
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
21125
|
+
if (image && !image.complete) {
|
|
21126
|
+
await new Promise((resolve) => {
|
|
21127
|
+
image.addEventListener('load', resolve, { once: true });
|
|
21128
|
+
image.addEventListener('error', resolve, { once: true });
|
|
21129
|
+
});
|
|
21130
|
+
}
|
|
21131
|
+
return (
|
|
21132
|
+
comicDimensions.get(pageIndex) || {
|
|
21133
|
+
width: image?.naturalWidth || 0,
|
|
21134
|
+
height: image?.naturalHeight || 0,
|
|
21135
|
+
}
|
|
21136
|
+
);
|
|
20541
21137
|
};
|
|
20542
21138
|
|
|
20543
21139
|
const normalizeHref = (href) => {
|
|
20544
|
-
if (!href) return
|
|
20545
|
-
return href.split(
|
|
21140
|
+
if (!href) return '';
|
|
21141
|
+
return href.split('#')[0];
|
|
20546
21142
|
};
|
|
20547
21143
|
|
|
20548
21144
|
const getSpineIndexByHref = (href) => {
|
|
20549
21145
|
const normalized = normalizeHref(href);
|
|
20550
21146
|
if (!normalized) return -1;
|
|
20551
|
-
return spineItems.findIndex(
|
|
20552
|
-
(item) => normalizeHref(item.href) === normalized
|
|
20553
|
-
);
|
|
21147
|
+
return spineItems.findIndex((item) => normalizeHref(item.href) === normalized);
|
|
20554
21148
|
};
|
|
20555
21149
|
|
|
20556
21150
|
const buildOutline = async () => {
|
|
@@ -20559,11 +21153,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20559
21153
|
const toc = nav && nav.toc ? nav.toc : [];
|
|
20560
21154
|
|
|
20561
21155
|
const mapItem = (item) => {
|
|
20562
|
-
const title = item.label || item.title ||
|
|
20563
|
-
const pageIndex = getSpineIndexByHref(item.href ||
|
|
20564
|
-
const children = Array.isArray(item.subitems)
|
|
20565
|
-
? item.subitems.map(mapItem)
|
|
20566
|
-
: [];
|
|
21156
|
+
const title = item.label || item.title || '';
|
|
21157
|
+
const pageIndex = getSpineIndexByHref(item.href || '');
|
|
21158
|
+
const children = Array.isArray(item.subitems) ? item.subitems.map(mapItem) : [];
|
|
20567
21159
|
const outlineItem = { title, pageIndex };
|
|
20568
21160
|
if (children.length > 0) outlineItem.children = children;
|
|
20569
21161
|
return outlineItem;
|
|
@@ -20575,10 +21167,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20575
21167
|
const applyEpubZoom = () => {
|
|
20576
21168
|
if (!rendition || !rendition.themes) return;
|
|
20577
21169
|
const fontSize = \`\${Math.round(zoom * 100)}%\`;
|
|
20578
|
-
if (typeof rendition.themes.fontSize ===
|
|
21170
|
+
if (typeof rendition.themes.fontSize === 'function') {
|
|
20579
21171
|
rendition.themes.fontSize(fontSize);
|
|
20580
|
-
} else if (typeof rendition.themes.override ===
|
|
20581
|
-
rendition.themes.override(
|
|
21172
|
+
} else if (typeof rendition.themes.override === 'function') {
|
|
21173
|
+
rendition.themes.override('font-size', fontSize);
|
|
20582
21174
|
}
|
|
20583
21175
|
};
|
|
20584
21176
|
|
|
@@ -20589,14 +21181,13 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20589
21181
|
};
|
|
20590
21182
|
|
|
20591
21183
|
const renderTextPage = (pageIndex) => {
|
|
20592
|
-
const text = textPages[pageIndex] ||
|
|
21184
|
+
const text = textPages[pageIndex] || '';
|
|
20593
21185
|
if (!textContainer) {
|
|
20594
|
-
textContainer = document.createElement(
|
|
20595
|
-
textContainer.style.padding =
|
|
20596
|
-
textContainer.style.lineHeight =
|
|
20597
|
-
textContainer.style.whiteSpace =
|
|
20598
|
-
textContainer.style.fontFamily =
|
|
20599
|
-
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace';
|
|
21186
|
+
textContainer = document.createElement('div');
|
|
21187
|
+
textContainer.style.padding = '24px';
|
|
21188
|
+
textContainer.style.lineHeight = '1.6';
|
|
21189
|
+
textContainer.style.whiteSpace = 'pre-wrap';
|
|
21190
|
+
textContainer.style.fontFamily = 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace';
|
|
20600
21191
|
viewer.appendChild(textContainer);
|
|
20601
21192
|
}
|
|
20602
21193
|
textContainer.textContent = text;
|
|
@@ -20608,18 +21199,18 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20608
21199
|
for (let i = 0; i < text.length; i += TEXT_PAGE_CHUNK) {
|
|
20609
21200
|
pages.push(text.slice(i, i + TEXT_PAGE_CHUNK));
|
|
20610
21201
|
}
|
|
20611
|
-
return pages.length > 0 ? pages : [
|
|
21202
|
+
return pages.length > 0 ? pages : [''];
|
|
20612
21203
|
};
|
|
20613
21204
|
|
|
20614
21205
|
const loadText = async (source) => {
|
|
20615
|
-
let text =
|
|
20616
|
-
if (source.kind ===
|
|
21206
|
+
let text = '';
|
|
21207
|
+
if (source.kind === 'uri') {
|
|
20617
21208
|
const res = await fetch(source.uri);
|
|
20618
21209
|
text = await res.text();
|
|
20619
|
-
} else if (source.kind ===
|
|
21210
|
+
} else if (source.kind === 'base64') {
|
|
20620
21211
|
text = decodeBase64ToText(source.data);
|
|
20621
|
-
} else if (source.kind ===
|
|
20622
|
-
text = source.text ||
|
|
21212
|
+
} else if (source.kind === 'text') {
|
|
21213
|
+
text = source.text || '';
|
|
20623
21214
|
}
|
|
20624
21215
|
|
|
20625
21216
|
clearViewer();
|
|
@@ -20632,44 +21223,25 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20632
21223
|
};
|
|
20633
21224
|
|
|
20634
21225
|
const loadEpub = async (source) => {
|
|
20635
|
-
|
|
20636
|
-
if (rendition && typeof rendition.destroy === "function") {
|
|
21226
|
+
if (rendition && typeof rendition.destroy === 'function') {
|
|
20637
21227
|
rendition.destroy();
|
|
20638
21228
|
}
|
|
20639
|
-
if (book && typeof book.destroy ===
|
|
21229
|
+
if (book && typeof book.destroy === 'function') {
|
|
20640
21230
|
book.destroy();
|
|
20641
21231
|
}
|
|
20642
21232
|
|
|
20643
|
-
|
|
20644
|
-
|
|
20645
|
-
|
|
20646
|
-
|
|
20647
|
-
|
|
20648
|
-
|
|
20649
|
-
);
|
|
20650
|
-
|
|
20651
|
-
log("epub.load:fetch-uri");
|
|
20652
|
-
const data = await withTimeout(
|
|
20653
|
-
fetchUriAsArrayBuffer(source.uri),
|
|
20654
|
-
EPUB_OPEN_TIMEOUT_MS,
|
|
20655
|
-
"epub.fetch"
|
|
20656
|
-
);
|
|
20657
|
-
const input = data instanceof Uint8Array ? data.buffer : data;
|
|
20658
|
-
book = ePub(input, { openAs: "epub" });
|
|
20659
|
-
} else {
|
|
20660
|
-
let data = null;
|
|
20661
|
-
if (source.kind === "text") {
|
|
20662
|
-
const encoder = new TextEncoder();
|
|
20663
|
-
data = encoder.encode(source.text || "").buffer;
|
|
20664
|
-
}
|
|
20665
|
-
const input = data instanceof Uint8Array ? data.buffer : data;
|
|
20666
|
-
book = ePub(input, { openAs: "epub" });
|
|
20667
|
-
}
|
|
20668
|
-
if (book && book.opened) {
|
|
20669
|
-
await withTimeout(book.opened, EPUB_OPEN_TIMEOUT_MS, "epub.opened");
|
|
21233
|
+
let data = null;
|
|
21234
|
+
if (source.kind === 'uri') {
|
|
21235
|
+
data = source.uri;
|
|
21236
|
+
} else if (source.kind === 'base64') {
|
|
21237
|
+
data = decodeBase64(source.data);
|
|
21238
|
+
} else if (source.kind === 'text') {
|
|
21239
|
+
const encoder = new TextEncoder();
|
|
21240
|
+
data = encoder.encode(source.text || '').buffer;
|
|
20670
21241
|
}
|
|
20671
|
-
|
|
20672
|
-
|
|
21242
|
+
|
|
21243
|
+
book = ePub(data);
|
|
21244
|
+
await book.ready;
|
|
20673
21245
|
|
|
20674
21246
|
spineItems = book.spine && book.spine.items ? book.spine.items : [];
|
|
20675
21247
|
pageCount = spineItems.length;
|
|
@@ -20677,64 +21249,38 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20677
21249
|
|
|
20678
21250
|
clearViewer();
|
|
20679
21251
|
rendition = book.renderTo(viewer, {
|
|
20680
|
-
width:
|
|
20681
|
-
height:
|
|
20682
|
-
flow:
|
|
20683
|
-
spread:
|
|
21252
|
+
width: '100%',
|
|
21253
|
+
height: '100%',
|
|
21254
|
+
flow: 'paginated',
|
|
21255
|
+
spread: 'none',
|
|
20684
21256
|
});
|
|
20685
21257
|
|
|
20686
21258
|
if (rendition && rendition.hooks && rendition.hooks.content) {
|
|
20687
21259
|
rendition.hooks.content.register((contents) => {
|
|
20688
|
-
const frame =
|
|
20689
|
-
contents && contents.document
|
|
20690
|
-
? contents.document.defaultView.frameElement
|
|
20691
|
-
: null;
|
|
21260
|
+
const frame = contents && contents.document ? contents.document.defaultView.frameElement : null;
|
|
20692
21261
|
if (frame) {
|
|
20693
|
-
frame.setAttribute(
|
|
20694
|
-
"sandbox",
|
|
20695
|
-
"allow-scripts allow-same-origin"
|
|
20696
|
-
);
|
|
21262
|
+
frame.setAttribute('sandbox', 'allow-scripts allow-same-origin');
|
|
20697
21263
|
}
|
|
20698
21264
|
});
|
|
20699
21265
|
}
|
|
20700
21266
|
|
|
20701
|
-
if (rendition && typeof rendition.on ===
|
|
20702
|
-
rendition.on(
|
|
20703
|
-
const selection =
|
|
20704
|
-
|
|
20705
|
-
? contents.window.getSelection()
|
|
20706
|
-
: null;
|
|
20707
|
-
const text = selection ? selection.toString().trim() : "";
|
|
21267
|
+
if (rendition && typeof rendition.on === 'function') {
|
|
21268
|
+
rendition.on('selected', (cfiRange, contents) => {
|
|
21269
|
+
const selection = contents && contents.window ? contents.window.getSelection() : null;
|
|
21270
|
+
const text = selection ? selection.toString().trim() : '';
|
|
20708
21271
|
if (text) {
|
|
20709
|
-
sendEvent(
|
|
20710
|
-
text,
|
|
20711
|
-
pageIndex: Math.max(0, currentPage - 1),
|
|
20712
|
-
});
|
|
21272
|
+
sendEvent('TEXT_SELECTED', { text, pageIndex: Math.max(0, currentPage - 1) });
|
|
20713
21273
|
}
|
|
20714
|
-
if (
|
|
20715
|
-
rendition
|
|
20716
|
-
rendition.annotations &&
|
|
20717
|
-
typeof rendition.annotations.remove === "function"
|
|
20718
|
-
) {
|
|
20719
|
-
rendition.annotations.remove(cfiRange, "highlight");
|
|
21274
|
+
if (rendition && rendition.annotations && typeof rendition.annotations.remove === 'function') {
|
|
21275
|
+
rendition.annotations.remove(cfiRange, 'highlight');
|
|
20720
21276
|
}
|
|
20721
21277
|
});
|
|
20722
21278
|
}
|
|
20723
21279
|
|
|
20724
|
-
|
|
20725
|
-
await withTimeout(
|
|
20726
|
-
displayEpubPage(0),
|
|
20727
|
-
EPUB_DISPLAY_TIMEOUT_MS,
|
|
20728
|
-
"epub.display"
|
|
20729
|
-
);
|
|
20730
|
-
log("epub.load:displayed");
|
|
20731
|
-
} catch (err) {
|
|
20732
|
-
reportError(err, "epub.display");
|
|
20733
|
-
}
|
|
21280
|
+
await displayEpubPage(0);
|
|
20734
21281
|
applyEpubZoom();
|
|
20735
21282
|
|
|
20736
21283
|
const outline = await buildOutline();
|
|
20737
|
-
log("epub.load:outline", outline.length);
|
|
20738
21284
|
return { pageCount, outline };
|
|
20739
21285
|
};
|
|
20740
21286
|
|
|
@@ -20749,41 +21295,34 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20749
21295
|
};
|
|
20750
21296
|
|
|
20751
21297
|
const getTextContent = async (pageIndex) => {
|
|
20752
|
-
if (currentType ===
|
|
20753
|
-
const text = textPages[pageIndex] ||
|
|
20754
|
-
return [
|
|
20755
|
-
|
|
20756
|
-
|
|
20757
|
-
|
|
20758
|
-
|
|
20759
|
-
|
|
20760
|
-
|
|
20761
|
-
|
|
20762
|
-
},
|
|
20763
|
-
];
|
|
21298
|
+
if (currentType === 'text') {
|
|
21299
|
+
const text = textPages[pageIndex] || '';
|
|
21300
|
+
return [{
|
|
21301
|
+
str: text,
|
|
21302
|
+
dir: 'ltr',
|
|
21303
|
+
width: 0,
|
|
21304
|
+
height: 0,
|
|
21305
|
+
transform: [1, 0, 0, 1, 0, 0],
|
|
21306
|
+
fontName: 'default',
|
|
21307
|
+
}];
|
|
20764
21308
|
}
|
|
20765
21309
|
|
|
20766
|
-
if (currentType ===
|
|
21310
|
+
if (currentType === 'epub') {
|
|
20767
21311
|
if (!book) return [];
|
|
20768
21312
|
const item = spineItems[pageIndex];
|
|
20769
21313
|
if (!item) return [];
|
|
20770
21314
|
try {
|
|
20771
21315
|
const section = book.spine.get(item.idref || item.href);
|
|
20772
|
-
const text =
|
|
20773
|
-
section && typeof section.text === "function"
|
|
20774
|
-
? await section.text()
|
|
20775
|
-
: "";
|
|
21316
|
+
const text = section && typeof section.text === 'function' ? await section.text() : '';
|
|
20776
21317
|
if (!text) return [];
|
|
20777
|
-
return [
|
|
20778
|
-
|
|
20779
|
-
|
|
20780
|
-
|
|
20781
|
-
|
|
20782
|
-
|
|
20783
|
-
|
|
20784
|
-
|
|
20785
|
-
},
|
|
20786
|
-
];
|
|
21318
|
+
return [{
|
|
21319
|
+
str: text,
|
|
21320
|
+
dir: 'ltr',
|
|
21321
|
+
width: 0,
|
|
21322
|
+
height: 0,
|
|
21323
|
+
transform: [1, 0, 0, 1, 0, 0],
|
|
21324
|
+
fontName: 'default',
|
|
21325
|
+
}];
|
|
20787
21326
|
} catch (err) {
|
|
20788
21327
|
return [];
|
|
20789
21328
|
}
|
|
@@ -20794,7 +21333,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20794
21333
|
|
|
20795
21334
|
const getPageText = async (pageIndex) => {
|
|
20796
21335
|
const items = await getTextContent(pageIndex);
|
|
20797
|
-
return items.map((item) => item.str).join(
|
|
21336
|
+
return items.map((item) => item.str).join(' ');
|
|
20798
21337
|
};
|
|
20799
21338
|
|
|
20800
21339
|
const searchText = async (query) => {
|
|
@@ -20810,11 +21349,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20810
21349
|
while (pos !== -1) {
|
|
20811
21350
|
const start = Math.max(0, pos - 20);
|
|
20812
21351
|
const end = Math.min(text.length, pos + query.length + 20);
|
|
20813
|
-
results.push({
|
|
20814
|
-
pageIndex: i,
|
|
20815
|
-
text: text.substring(start, end),
|
|
20816
|
-
matchIndex,
|
|
20817
|
-
});
|
|
21352
|
+
results.push({ pageIndex: i, text: text.substring(start, end), matchIndex });
|
|
20818
21353
|
matchIndex += 1;
|
|
20819
21354
|
pos = lower.indexOf(normalized, pos + 1);
|
|
20820
21355
|
}
|
|
@@ -20830,11 +21365,11 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20830
21365
|
|
|
20831
21366
|
const getPageIndex = (dest) => {
|
|
20832
21367
|
if (!dest) return null;
|
|
20833
|
-
if (typeof dest ===
|
|
20834
|
-
if (typeof dest !==
|
|
20835
|
-
if (dest.kind ===
|
|
20836
|
-
if (dest.kind ===
|
|
20837
|
-
if (dest.kind ===
|
|
21368
|
+
if (typeof dest === 'string') return getSpineIndexByHref(dest);
|
|
21369
|
+
if (typeof dest !== 'object') return null;
|
|
21370
|
+
if (dest.kind === 'href') return getSpineIndexByHref(dest.value);
|
|
21371
|
+
if (dest.kind === 'pageIndex') return dest.value;
|
|
21372
|
+
if (dest.kind === 'pageNumber') return Math.max(0, dest.value - 1);
|
|
20838
21373
|
return null;
|
|
20839
21374
|
};
|
|
20840
21375
|
|
|
@@ -20848,53 +21383,70 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20848
21383
|
};
|
|
20849
21384
|
|
|
20850
21385
|
const applyZoom = () => {
|
|
20851
|
-
if (currentType ===
|
|
21386
|
+
if (currentType === 'text') {
|
|
20852
21387
|
applyTextZoom();
|
|
20853
|
-
} else if (currentType ===
|
|
21388
|
+
} else if (currentType === 'epub') {
|
|
20854
21389
|
applyEpubZoom();
|
|
21390
|
+
} else if (currentType === 'comic') {
|
|
21391
|
+
applyComicLayout();
|
|
20855
21392
|
}
|
|
20856
21393
|
};
|
|
20857
21394
|
|
|
20858
21395
|
const handleCommand = async (message) => {
|
|
20859
21396
|
const { id, kind, payload } = message;
|
|
20860
|
-
log("command", kind);
|
|
20861
21397
|
|
|
20862
21398
|
try {
|
|
20863
|
-
if (kind ===
|
|
21399
|
+
if (kind === 'load') {
|
|
20864
21400
|
currentType = payload.type;
|
|
20865
21401
|
zoom = 1.0;
|
|
20866
21402
|
|
|
20867
|
-
if (currentType ===
|
|
21403
|
+
if (currentType === 'text') {
|
|
20868
21404
|
const result = await loadText(payload.source);
|
|
20869
21405
|
sendState();
|
|
20870
21406
|
sendResponse(id, true, result);
|
|
20871
21407
|
return;
|
|
20872
21408
|
}
|
|
20873
21409
|
|
|
20874
|
-
if (currentType ===
|
|
21410
|
+
if (currentType === 'epub') {
|
|
20875
21411
|
const result = await loadEpub(payload.source);
|
|
20876
21412
|
sendState({ outline: result.outline || [] });
|
|
20877
21413
|
sendResponse(id, true, result);
|
|
20878
21414
|
return;
|
|
20879
21415
|
}
|
|
20880
21416
|
|
|
20881
|
-
|
|
21417
|
+
if (currentType === 'comic') {
|
|
21418
|
+
const result = await loadComic(payload.source, payload.format || 'cbz');
|
|
21419
|
+
sendState();
|
|
21420
|
+
sendResponse(id, true, result);
|
|
21421
|
+
return;
|
|
21422
|
+
}
|
|
21423
|
+
|
|
21424
|
+
throw new Error('Unsupported document type');
|
|
20882
21425
|
}
|
|
20883
21426
|
|
|
20884
|
-
if (kind ===
|
|
21427
|
+
if (kind === 'go-to-page') {
|
|
20885
21428
|
const page = Math.max(1, payload.page || 1);
|
|
20886
|
-
if (currentType ===
|
|
21429
|
+
if (currentType === 'text') {
|
|
20887
21430
|
currentPage = page;
|
|
20888
21431
|
renderTextPage(page - 1);
|
|
20889
21432
|
sendState();
|
|
20890
|
-
} else if (currentType ===
|
|
21433
|
+
} else if (currentType === 'epub') {
|
|
20891
21434
|
await displayEpubPage(page - 1);
|
|
21435
|
+
} else if (currentType === 'comic') {
|
|
21436
|
+
currentPage = page;
|
|
21437
|
+
const target = comicPages[page - 1];
|
|
21438
|
+
if (target) {
|
|
21439
|
+
await ensureComicPage(page - 1);
|
|
21440
|
+
target.scrollIntoView({ block: 'start' });
|
|
21441
|
+
renderComicPage(page - 1);
|
|
21442
|
+
sendState();
|
|
21443
|
+
}
|
|
20892
21444
|
}
|
|
20893
21445
|
sendResponse(id, true, { currentPage });
|
|
20894
21446
|
return;
|
|
20895
21447
|
}
|
|
20896
21448
|
|
|
20897
|
-
if (kind ===
|
|
21449
|
+
if (kind === 'set-zoom') {
|
|
20898
21450
|
zoom = Math.max(0.5, Math.min(4.0, payload.zoom || 1.0));
|
|
20899
21451
|
applyZoom();
|
|
20900
21452
|
sendState();
|
|
@@ -20902,103 +21454,132 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20902
21454
|
return;
|
|
20903
21455
|
}
|
|
20904
21456
|
|
|
20905
|
-
if (kind ===
|
|
21457
|
+
if (kind === 'set-rotation') {
|
|
21458
|
+
rotation = ((payload.rotation || 0) % 360 + 360) % 360;
|
|
21459
|
+
if (currentType === 'comic') applyComicLayout();
|
|
20906
21460
|
sendResponse(id, true, {});
|
|
20907
21461
|
return;
|
|
20908
21462
|
}
|
|
20909
21463
|
|
|
20910
|
-
if (kind ===
|
|
21464
|
+
if (kind === 'get-text-content') {
|
|
20911
21465
|
const items = await getTextContent(payload.pageIndex || 0);
|
|
20912
21466
|
sendResponse(id, true, items);
|
|
20913
21467
|
return;
|
|
20914
21468
|
}
|
|
20915
21469
|
|
|
20916
|
-
if (kind ===
|
|
20917
|
-
|
|
21470
|
+
if (kind === 'get-page-dimensions') {
|
|
21471
|
+
if (currentType === 'comic') {
|
|
21472
|
+
sendResponse(
|
|
21473
|
+
id,
|
|
21474
|
+
true,
|
|
21475
|
+
await getComicPageDimensions(payload.pageIndex || 0)
|
|
21476
|
+
);
|
|
21477
|
+
} else {
|
|
21478
|
+
sendResponse(id, true, getPageDimensions());
|
|
21479
|
+
}
|
|
20918
21480
|
return;
|
|
20919
21481
|
}
|
|
20920
21482
|
|
|
20921
|
-
if (kind ===
|
|
20922
|
-
|
|
21483
|
+
if (kind === 'get-page-preview') {
|
|
21484
|
+
if (currentType !== 'comic') {
|
|
21485
|
+
sendResponse(id, true, null);
|
|
21486
|
+
return;
|
|
21487
|
+
}
|
|
21488
|
+
sendResponse(
|
|
21489
|
+
id,
|
|
21490
|
+
true,
|
|
21491
|
+
await getComicPagePreview(payload.pageIndex || 0)
|
|
21492
|
+
);
|
|
21493
|
+
return;
|
|
21494
|
+
}
|
|
21495
|
+
|
|
21496
|
+
if (kind === 'search-text') {
|
|
21497
|
+
const results = await searchText(payload.query || '');
|
|
20923
21498
|
sendResponse(id, true, results);
|
|
20924
21499
|
return;
|
|
20925
21500
|
}
|
|
20926
21501
|
|
|
20927
|
-
if (kind ===
|
|
21502
|
+
if (kind === 'select-text') {
|
|
20928
21503
|
const selection = await selectText(payload.pageIndex || 0);
|
|
20929
21504
|
sendResponse(id, true, selection);
|
|
20930
21505
|
return;
|
|
20931
21506
|
}
|
|
20932
21507
|
|
|
20933
|
-
if (kind ===
|
|
21508
|
+
if (kind === 'get-outline') {
|
|
20934
21509
|
const outline = await buildOutline();
|
|
20935
21510
|
sendResponse(id, true, outline);
|
|
20936
21511
|
return;
|
|
20937
21512
|
}
|
|
20938
21513
|
|
|
20939
|
-
if (kind ===
|
|
21514
|
+
if (kind === 'get-page-index') {
|
|
20940
21515
|
const index = getPageIndex(payload.dest);
|
|
20941
21516
|
sendResponse(id, true, index);
|
|
20942
21517
|
return;
|
|
20943
21518
|
}
|
|
20944
21519
|
|
|
20945
|
-
if (kind ===
|
|
21520
|
+
if (kind === 'destroy') {
|
|
20946
21521
|
clearViewer();
|
|
20947
21522
|
sendResponse(id, true, {});
|
|
20948
21523
|
return;
|
|
20949
21524
|
}
|
|
20950
21525
|
|
|
20951
|
-
sendResponse(id, false, null,
|
|
21526
|
+
sendResponse(id, false, null, 'Unknown command');
|
|
20952
21527
|
} catch (err) {
|
|
20953
|
-
sendResponse(
|
|
20954
|
-
id,
|
|
20955
|
-
false,
|
|
20956
|
-
null,
|
|
20957
|
-
err && err.message ? err.message : String(err)
|
|
20958
|
-
);
|
|
21528
|
+
sendResponse(id, false, null, err && err.message ? err.message : String(err));
|
|
20959
21529
|
}
|
|
20960
21530
|
};
|
|
20961
21531
|
|
|
20962
21532
|
const onMessage = (event) => {
|
|
20963
21533
|
let message = null;
|
|
20964
|
-
const raw = event && typeof event ===
|
|
21534
|
+
const raw = event && typeof event === 'object' ? event.data : null;
|
|
20965
21535
|
|
|
20966
|
-
if (raw && typeof raw ===
|
|
21536
|
+
if (raw && typeof raw === 'object' && (raw.kind || raw.type) && raw.id) {
|
|
20967
21537
|
message = raw;
|
|
20968
|
-
} else if (typeof raw ===
|
|
20969
|
-
if (raw.startsWith(
|
|
20970
|
-
return;
|
|
20971
|
-
}
|
|
21538
|
+
} else if (typeof raw === 'string') {
|
|
21539
|
+
if (raw.startsWith('setImmediate$')) return;
|
|
20972
21540
|
const trimmed = raw.trim();
|
|
20973
|
-
if (
|
|
20974
|
-
!trimmed ||
|
|
20975
|
-
(!trimmed.startsWith("{") && !trimmed.startsWith("["))
|
|
20976
|
-
) {
|
|
21541
|
+
if (!trimmed || (!trimmed.startsWith('{') && !trimmed.startsWith('['))) {
|
|
20977
21542
|
return;
|
|
20978
21543
|
}
|
|
20979
21544
|
try {
|
|
20980
21545
|
message = JSON.parse(trimmed);
|
|
20981
21546
|
} catch (err) {
|
|
20982
|
-
sendEvent("RUNTIME_ERROR", {
|
|
20983
|
-
message: "Failed to parse message",
|
|
20984
|
-
context: "runtime.onMessage",
|
|
20985
|
-
stack: err && err.stack ? err.stack : null,
|
|
20986
|
-
preview: trimmed.slice(0, 200),
|
|
20987
|
-
});
|
|
20988
21547
|
return;
|
|
20989
21548
|
}
|
|
20990
21549
|
} else {
|
|
20991
21550
|
return;
|
|
20992
21551
|
}
|
|
20993
21552
|
|
|
20994
|
-
|
|
20995
|
-
|
|
21553
|
+
if (!message || message.id == null) return;
|
|
21554
|
+
|
|
21555
|
+
if (message.type === 'asset-response') {
|
|
21556
|
+
const pending = runtimeAssetRequests.get(message.id);
|
|
21557
|
+
if (!pending) return;
|
|
21558
|
+
runtimeAssetRequests.delete(message.id);
|
|
21559
|
+
clearTimeout(pending.timeout);
|
|
21560
|
+
if (message.ok) pending.resolve(message.data);
|
|
21561
|
+
else pending.reject(new Error(message.error || 'Falha ao carregar asset CBR.'));
|
|
21562
|
+
return;
|
|
21563
|
+
}
|
|
21564
|
+
|
|
21565
|
+
if (message.type === 'file-chunk-response') {
|
|
21566
|
+
const pending = fileChunkRequests.get(message.id);
|
|
21567
|
+
if (!pending) return;
|
|
21568
|
+
fileChunkRequests.delete(message.id);
|
|
21569
|
+
clearTimeout(pending.timeout);
|
|
21570
|
+
if (message.ok) pending.resolve(message);
|
|
21571
|
+
else pending.reject(new Error(message.error || 'Falha ao ler arquivo local.'));
|
|
21572
|
+
return;
|
|
21573
|
+
}
|
|
21574
|
+
|
|
21575
|
+
if (!message.kind) return;
|
|
21576
|
+
handleCommand(message);
|
|
20996
21577
|
};
|
|
20997
21578
|
|
|
20998
|
-
window.addEventListener(
|
|
20999
|
-
document.addEventListener(
|
|
21579
|
+
window.addEventListener('message', onMessage);
|
|
21580
|
+
document.addEventListener('message', onMessage);
|
|
21000
21581
|
|
|
21001
|
-
sendMessage({ type:
|
|
21582
|
+
sendMessage({ type: 'ready' });
|
|
21002
21583
|
})();
|
|
21003
21584
|
</script>
|
|
21004
21585
|
</body>
|
|
@@ -21013,7 +21594,7 @@ import {
|
|
|
21013
21594
|
useRef as useRef4,
|
|
21014
21595
|
useEffect as useEffect4,
|
|
21015
21596
|
useCallback as useCallback3,
|
|
21016
|
-
useState as
|
|
21597
|
+
useState as useState4
|
|
21017
21598
|
} from "react";
|
|
21018
21599
|
import {
|
|
21019
21600
|
FlatList,
|
|
@@ -23004,33 +23585,104 @@ var arePageRendererPropsEqual = (previous, next) => previous.engine === next.eng
|
|
|
23004
23585
|
var PageRenderer_default = memo(PageRenderer, arePageRendererPropsEqual);
|
|
23005
23586
|
|
|
23006
23587
|
// components/WebViewViewer.tsx
|
|
23007
|
-
import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
|
|
23588
|
+
import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
23008
23589
|
import { Image, StyleSheet as StyleSheet2, View as View2 } from "react-native";
|
|
23009
23590
|
import WebView from "react-native-webview";
|
|
23010
23591
|
import { useViewerStore as useViewerStore2 } from "@papyrus-sdk/core";
|
|
23592
|
+
|
|
23593
|
+
// components/webViewState.ts
|
|
23594
|
+
var parseWebViewState = (raw) => {
|
|
23595
|
+
try {
|
|
23596
|
+
const message = JSON.parse(raw);
|
|
23597
|
+
if (!message || typeof message !== "object") return null;
|
|
23598
|
+
const typedMessage = message;
|
|
23599
|
+
if (typedMessage.type !== "state") return null;
|
|
23600
|
+
if (!typedMessage.payload || typeof typedMessage.payload !== "object") {
|
|
23601
|
+
return null;
|
|
23602
|
+
}
|
|
23603
|
+
const payload = typedMessage.payload;
|
|
23604
|
+
const update = {};
|
|
23605
|
+
if (typeof payload.currentPage === "number" && Number.isInteger(payload.currentPage) && payload.currentPage >= 1) {
|
|
23606
|
+
update.currentPage = payload.currentPage;
|
|
23607
|
+
}
|
|
23608
|
+
if (typeof payload.pageCount === "number" && Number.isInteger(payload.pageCount) && payload.pageCount >= 0) {
|
|
23609
|
+
update.pageCount = payload.pageCount;
|
|
23610
|
+
}
|
|
23611
|
+
return Object.keys(update).length > 0 ? update : null;
|
|
23612
|
+
} catch {
|
|
23613
|
+
return null;
|
|
23614
|
+
}
|
|
23615
|
+
};
|
|
23616
|
+
|
|
23617
|
+
// components/WebViewViewer.tsx
|
|
23011
23618
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
23012
23619
|
var runtimeAsset = require_runtime();
|
|
23013
|
-
var
|
|
23014
|
-
if (typeof
|
|
23015
|
-
return { html:
|
|
23620
|
+
var resolveRuntimeSource = (asset) => {
|
|
23621
|
+
if (typeof asset === "string") {
|
|
23622
|
+
return { html: asset };
|
|
23016
23623
|
}
|
|
23017
|
-
if (typeof
|
|
23018
|
-
const resolved = Image.resolveAssetSource(
|
|
23624
|
+
if (typeof asset === "number") {
|
|
23625
|
+
const resolved = Image.resolveAssetSource(asset);
|
|
23019
23626
|
if (resolved?.uri) {
|
|
23020
23627
|
return { uri: resolved.uri };
|
|
23021
23628
|
}
|
|
23022
23629
|
}
|
|
23023
|
-
if (
|
|
23024
|
-
const uri =
|
|
23630
|
+
if (asset && typeof asset === "object" && "uri" in asset) {
|
|
23631
|
+
const uri = asset.uri;
|
|
23025
23632
|
if (uri) return { uri };
|
|
23026
23633
|
}
|
|
23027
23634
|
return { html: "" };
|
|
23028
|
-
}
|
|
23635
|
+
};
|
|
23029
23636
|
var WebViewViewer = ({ engine }) => {
|
|
23030
23637
|
const webViewRef = useRef2(null);
|
|
23031
23638
|
const { pageTheme } = useViewerStore2();
|
|
23639
|
+
const bridgeEngine = engine;
|
|
23640
|
+
const runtimeSource = useMemo2(
|
|
23641
|
+
() => resolveRuntimeSource(
|
|
23642
|
+
bridgeEngine.getWebViewRuntimeSource?.() ?? runtimeAsset
|
|
23643
|
+
),
|
|
23644
|
+
[bridgeEngine]
|
|
23645
|
+
);
|
|
23646
|
+
const [runtimeHtml, setRuntimeHtml] = useState2(null);
|
|
23647
|
+
useEffect2(() => {
|
|
23648
|
+
let active = true;
|
|
23649
|
+
if ("html" in runtimeSource) {
|
|
23650
|
+
setRuntimeHtml(runtimeSource.html);
|
|
23651
|
+
return () => {
|
|
23652
|
+
active = false;
|
|
23653
|
+
};
|
|
23654
|
+
}
|
|
23655
|
+
setRuntimeHtml(null);
|
|
23656
|
+
void fetch(runtimeSource.uri).then((response) => {
|
|
23657
|
+
if (!response.ok) throw new Error(`status ${response.status}`);
|
|
23658
|
+
return response.text();
|
|
23659
|
+
}).then((html) => {
|
|
23660
|
+
if (active) setRuntimeHtml(html);
|
|
23661
|
+
}).catch(() => {
|
|
23662
|
+
if (active) setRuntimeHtml(null);
|
|
23663
|
+
});
|
|
23664
|
+
return () => {
|
|
23665
|
+
active = false;
|
|
23666
|
+
};
|
|
23667
|
+
}, [runtimeSource]);
|
|
23668
|
+
const webViewSource = useMemo2(() => {
|
|
23669
|
+
if (runtimeHtml !== null) {
|
|
23670
|
+
return {
|
|
23671
|
+
html: runtimeHtml,
|
|
23672
|
+
baseUrl: "http://localhost:3005/"
|
|
23673
|
+
};
|
|
23674
|
+
}
|
|
23675
|
+
if ("uri" in runtimeSource) return { html: "" };
|
|
23676
|
+
return runtimeSource;
|
|
23677
|
+
}, [runtimeHtml, runtimeSource]);
|
|
23678
|
+
const runtimeConfig = bridgeEngine.getWebViewRuntimeConfig?.();
|
|
23679
|
+
const runtimeConfigScript = useMemo2(() => {
|
|
23680
|
+
if (!runtimeConfig) return void 0;
|
|
23681
|
+
return `window.__PAPYRUS_RUNTIME_CONFIG__=${JSON.stringify(
|
|
23682
|
+
runtimeConfig
|
|
23683
|
+
)};true;`;
|
|
23684
|
+
}, [runtimeConfig]);
|
|
23032
23685
|
useEffect2(() => {
|
|
23033
|
-
const bridgeEngine = engine;
|
|
23034
23686
|
bridgeEngine.attachWebView?.({
|
|
23035
23687
|
postMessage: (message) => {
|
|
23036
23688
|
if (__DEV__) {
|
|
@@ -23040,9 +23692,22 @@ var WebViewViewer = ({ engine }) => {
|
|
|
23040
23692
|
webViewRef.current?.postMessage(message);
|
|
23041
23693
|
}
|
|
23042
23694
|
});
|
|
23043
|
-
}, [
|
|
23695
|
+
}, [bridgeEngine]);
|
|
23044
23696
|
const handleMessage = (event) => {
|
|
23045
|
-
const
|
|
23697
|
+
const state = parseWebViewState(event.nativeEvent.data);
|
|
23698
|
+
if (state) {
|
|
23699
|
+
const viewerState = useViewerStore2.getState();
|
|
23700
|
+
const nextState = {};
|
|
23701
|
+
if (state.currentPage !== void 0 && state.currentPage !== viewerState.currentPage) {
|
|
23702
|
+
nextState.currentPage = state.currentPage;
|
|
23703
|
+
}
|
|
23704
|
+
if (state.pageCount !== void 0 && state.pageCount !== viewerState.pageCount) {
|
|
23705
|
+
nextState.pageCount = state.pageCount;
|
|
23706
|
+
}
|
|
23707
|
+
if (Object.keys(nextState).length > 0) {
|
|
23708
|
+
viewerState.setDocumentState(nextState);
|
|
23709
|
+
}
|
|
23710
|
+
}
|
|
23046
23711
|
if (__DEV__) {
|
|
23047
23712
|
console.log("[Papyrus WebView] message", event.nativeEvent.data);
|
|
23048
23713
|
}
|
|
@@ -23082,11 +23747,12 @@ var WebViewViewer = ({ engine }) => {
|
|
|
23082
23747
|
WebView,
|
|
23083
23748
|
{
|
|
23084
23749
|
ref: webViewRef,
|
|
23085
|
-
source:
|
|
23750
|
+
source: webViewSource,
|
|
23086
23751
|
originWhitelist: ["*"],
|
|
23087
23752
|
onMessage: handleMessage,
|
|
23088
23753
|
onLoadEnd: handleLoadEnd,
|
|
23089
23754
|
onError: handleError,
|
|
23755
|
+
injectedJavaScriptBeforeContentLoaded: runtimeConfigScript,
|
|
23090
23756
|
javaScriptEnabled: true,
|
|
23091
23757
|
domStorageEnabled: true,
|
|
23092
23758
|
scalesPageToFit: true,
|
|
@@ -23136,7 +23802,7 @@ var styles2 = StyleSheet2.create({
|
|
|
23136
23802
|
var WebViewViewer_default = WebViewViewer;
|
|
23137
23803
|
|
|
23138
23804
|
// components/DedicatedAndroidPdfViewer.tsx
|
|
23139
|
-
import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef3, useState as
|
|
23805
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
23140
23806
|
import { Pressable as Pressable2, StyleSheet as StyleSheet3, View as View3 } from "react-native";
|
|
23141
23807
|
import { useViewerStore as useViewerStore3 } from "@papyrus-sdk/core";
|
|
23142
23808
|
import { PapyrusPdfDocumentView } from "@papyrus-sdk/engine-native";
|
|
@@ -23782,7 +24448,7 @@ function DedicatedAndroidPdfViewer({
|
|
|
23782
24448
|
const addAnnotation = useViewerStore3((state) => state.addAnnotation);
|
|
23783
24449
|
const setSelectedAnnotation = useViewerStore3((state) => state.setSelectedAnnotation);
|
|
23784
24450
|
const engineId = getDedicatedAndroidPdfEngineId(engine);
|
|
23785
|
-
const [selection, setSelection] =
|
|
24451
|
+
const [selection, setSelection] = useState3(null);
|
|
23786
24452
|
const selectionRef = useRef3(null);
|
|
23787
24453
|
const lastVisiblePagesKeyRef = useRef3("");
|
|
23788
24454
|
const lastScrollOffsetYRef = useRef3(0);
|
|
@@ -24135,13 +24801,13 @@ var Viewer = ({
|
|
|
24135
24801
|
const lastScrollOffsetYRef = useRef4(0);
|
|
24136
24802
|
const scrollDownAccumRef = useRef4(0);
|
|
24137
24803
|
const scrollUpAccumRef = useRef4(0);
|
|
24138
|
-
const [layoutRevision, setLayoutRevision] =
|
|
24139
|
-
const [selectionDragActive, setSelectionDragActive] =
|
|
24804
|
+
const [layoutRevision, setLayoutRevision] = useState4(0);
|
|
24805
|
+
const [selectionDragActive, setSelectionDragActive] = useState4(false);
|
|
24140
24806
|
const selectionDragActiveRef = useRef4(false);
|
|
24141
|
-
const [gestureScrollLockActive, setGestureScrollLockActive] =
|
|
24807
|
+
const [gestureScrollLockActive, setGestureScrollLockActive] = useState4(false);
|
|
24142
24808
|
const gestureScrollLockActiveRef = useRef4(false);
|
|
24143
|
-
const [pinchPreviewScale, setPinchPreviewScale] =
|
|
24144
|
-
const [lastPinchEndedAt, setLastPinchEndedAt] =
|
|
24809
|
+
const [pinchPreviewScale, setPinchPreviewScale] = useState4(1);
|
|
24810
|
+
const [lastPinchEndedAt, setLastPinchEndedAt] = useState4(null);
|
|
24145
24811
|
const pinchGestureActiveRef = useRef4(false);
|
|
24146
24812
|
const pinchStartZoomRef = useRef4(1);
|
|
24147
24813
|
const pinchPreviewZoomRef = useRef4(1);
|
|
@@ -25474,7 +26140,7 @@ var styles4 = StyleSheet4.create({
|
|
|
25474
26140
|
var Viewer_default = Viewer;
|
|
25475
26141
|
|
|
25476
26142
|
// components/Topbar.tsx
|
|
25477
|
-
import { useState as
|
|
26143
|
+
import { useState as useState6 } from "react";
|
|
25478
26144
|
import { View as View6, Text as Text2, Pressable as Pressable4, StyleSheet as StyleSheet6, useWindowDimensions as useWindowDimensions3 } from "react-native";
|
|
25479
26145
|
import { useViewerStore as useViewerStore5 } from "@papyrus-sdk/core";
|
|
25480
26146
|
|
|
@@ -25497,7 +26163,7 @@ var MOBILE_CHROME_METRICS = {
|
|
|
25497
26163
|
};
|
|
25498
26164
|
|
|
25499
26165
|
// components/PageJumpModal.tsx
|
|
25500
|
-
import { useEffect as useEffect5, useState as
|
|
26166
|
+
import { useEffect as useEffect5, useState as useState5 } from "react";
|
|
25501
26167
|
import { Modal, Pressable as Pressable3, StyleSheet as StyleSheet5, Text, TextInput, View as View5 } from "react-native";
|
|
25502
26168
|
|
|
25503
26169
|
// components/pageJumpModel.ts
|
|
@@ -25519,7 +26185,7 @@ function PageJumpModal({
|
|
|
25519
26185
|
onClose,
|
|
25520
26186
|
onConfirm
|
|
25521
26187
|
}) {
|
|
25522
|
-
const [value, setValue] =
|
|
26188
|
+
const [value, setValue] = useState5(`${currentPage}`);
|
|
25523
26189
|
useEffect5(() => {
|
|
25524
26190
|
if (visible) setValue(`${currentPage}`);
|
|
25525
26191
|
}, [currentPage, visible]);
|
|
@@ -25680,7 +26346,7 @@ var Topbar = ({
|
|
|
25680
26346
|
accentColor,
|
|
25681
26347
|
mobileChromeVisible
|
|
25682
26348
|
} = useViewerStore5();
|
|
25683
|
-
const [jumpModalOpen, setJumpModalOpen] =
|
|
26349
|
+
const [jumpModalOpen, setJumpModalOpen] = useState6(false);
|
|
25684
26350
|
const isDark = uiTheme === "dark";
|
|
25685
26351
|
const navIconColor = isDark ? "#e5e7eb" : "#111827";
|
|
25686
26352
|
const { width, height } = useWindowDimensions3();
|
|
@@ -25983,7 +26649,7 @@ var styles6 = StyleSheet6.create({
|
|
|
25983
26649
|
var Topbar_default = Topbar;
|
|
25984
26650
|
|
|
25985
26651
|
// components/ToolDock.tsx
|
|
25986
|
-
import React7, { useEffect as useEffect6, useMemo as useMemo4, useRef as useRef5, useState as
|
|
26652
|
+
import React7, { useEffect as useEffect6, useMemo as useMemo4, useRef as useRef5, useState as useState7 } from "react";
|
|
25987
26653
|
import {
|
|
25988
26654
|
View as View7,
|
|
25989
26655
|
Text as Text3,
|
|
@@ -26221,8 +26887,8 @@ var OpacitySlider = React7.memo(function OpacitySlider2({
|
|
|
26221
26887
|
isDark,
|
|
26222
26888
|
onCommit
|
|
26223
26889
|
}) {
|
|
26224
|
-
const [trackWidth, setTrackWidth] =
|
|
26225
|
-
const [draftValue, setDraftValue] =
|
|
26890
|
+
const [trackWidth, setTrackWidth] = useState7(0);
|
|
26891
|
+
const [draftValue, setDraftValue] = useState7(value);
|
|
26226
26892
|
const dragValueRef = useRef5(draftValue);
|
|
26227
26893
|
const isDraggingRef = useRef5(false);
|
|
26228
26894
|
const frameRef = useRef5(null);
|
|
@@ -26331,8 +26997,8 @@ var ToolDock = () => {
|
|
|
26331
26997
|
undoAnnotations,
|
|
26332
26998
|
redoAnnotations
|
|
26333
26999
|
} = useViewerStore6();
|
|
26334
|
-
const [paletteExpanded, setPaletteExpanded] =
|
|
26335
|
-
const [extrasExpanded, setExtrasExpanded] =
|
|
27000
|
+
const [paletteExpanded, setPaletteExpanded] = useState7(false);
|
|
27001
|
+
const [extrasExpanded, setExtrasExpanded] = useState7(false);
|
|
26336
27002
|
const isDark = uiTheme === "dark";
|
|
26337
27003
|
const { width: windowWidth } = useWindowDimensions4();
|
|
26338
27004
|
const t = getStrings(locale);
|
|
@@ -27055,9 +27721,10 @@ var withInkAlpha = (hex, alpha) => {
|
|
|
27055
27721
|
var ToolDock_default = ToolDock;
|
|
27056
27722
|
|
|
27057
27723
|
// components/RightSheet.tsx
|
|
27058
|
-
import { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo5, useRef as useRef6, useState as
|
|
27724
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo5, useRef as useRef6, useState as useState8 } from "react";
|
|
27059
27725
|
import {
|
|
27060
27726
|
Dimensions,
|
|
27727
|
+
Image as Image2,
|
|
27061
27728
|
Platform as Platform3,
|
|
27062
27729
|
Pressable as Pressable7,
|
|
27063
27730
|
StyleSheet as StyleSheet9,
|
|
@@ -27248,11 +27915,13 @@ var PageThumbnail = ({
|
|
|
27248
27915
|
frameHeight,
|
|
27249
27916
|
accentColor,
|
|
27250
27917
|
useNativePreview,
|
|
27918
|
+
useImagePreview,
|
|
27251
27919
|
shouldRenderPreview,
|
|
27252
27920
|
onPress
|
|
27253
27921
|
}) => {
|
|
27254
27922
|
const viewRef = useRef6(null);
|
|
27255
|
-
const [layoutReady, setLayoutReady] =
|
|
27923
|
+
const [layoutReady, setLayoutReady] = useState8(false);
|
|
27924
|
+
const [previewUri, setPreviewUri] = useState8(null);
|
|
27256
27925
|
useEffect7(() => {
|
|
27257
27926
|
if (!layoutReady || !useNativePreview || !shouldRenderPreview) return;
|
|
27258
27927
|
const viewTag = findNodeHandle2(viewRef.current);
|
|
@@ -27268,6 +27937,24 @@ var PageThumbnail = ({
|
|
|
27268
27937
|
useNativePreview,
|
|
27269
27938
|
zoom
|
|
27270
27939
|
]);
|
|
27940
|
+
useEffect7(() => {
|
|
27941
|
+
if (!useImagePreview || !shouldRenderPreview) {
|
|
27942
|
+
setPreviewUri(null);
|
|
27943
|
+
return;
|
|
27944
|
+
}
|
|
27945
|
+
let active = true;
|
|
27946
|
+
const previewEngine = engine;
|
|
27947
|
+
const request = previewEngine.getPagePreview?.(pageIndex);
|
|
27948
|
+
if (!request) return;
|
|
27949
|
+
void request.then((uri) => {
|
|
27950
|
+
if (active) setPreviewUri(uri);
|
|
27951
|
+
}).catch(() => {
|
|
27952
|
+
if (active) setPreviewUri(null);
|
|
27953
|
+
});
|
|
27954
|
+
return () => {
|
|
27955
|
+
active = false;
|
|
27956
|
+
};
|
|
27957
|
+
}, [engine, pageIndex, shouldRenderPreview, useImagePreview]);
|
|
27271
27958
|
const handleLayout = (event) => {
|
|
27272
27959
|
if (event.nativeEvent.layout.width && event.nativeEvent.layout.height) {
|
|
27273
27960
|
setLayoutReady(true);
|
|
@@ -27290,7 +27977,14 @@ var PageThumbnail = ({
|
|
|
27290
27977
|
{
|
|
27291
27978
|
onLayout: handleLayout,
|
|
27292
27979
|
style: [styles9.thumbFrame, { width: frameWidth, height: frameHeight }],
|
|
27293
|
-
children: useNativePreview && shouldRenderPreview ? /* @__PURE__ */ jsx10(PapyrusPageView2, { ref: viewRef, style: styles9.thumbView }) :
|
|
27980
|
+
children: useNativePreview && shouldRenderPreview ? /* @__PURE__ */ jsx10(PapyrusPageView2, { ref: viewRef, style: styles9.thumbView }) : useImagePreview && shouldRenderPreview && previewUri ? /* @__PURE__ */ jsx10(
|
|
27981
|
+
Image2,
|
|
27982
|
+
{
|
|
27983
|
+
source: { uri: previewUri },
|
|
27984
|
+
resizeMode: "contain",
|
|
27985
|
+
style: styles9.thumbImage
|
|
27986
|
+
}
|
|
27987
|
+
) : /* @__PURE__ */ jsx10(View9, { style: [styles9.thumbFallback, isDark && styles9.thumbFallbackDark], children: /* @__PURE__ */ jsx10(
|
|
27294
27988
|
Text5,
|
|
27295
27989
|
{
|
|
27296
27990
|
style: [
|
|
@@ -27367,9 +28061,14 @@ var RightSheet = ({
|
|
|
27367
28061
|
locale,
|
|
27368
28062
|
accentColor
|
|
27369
28063
|
} = useViewerStore7();
|
|
27370
|
-
const [pagesMode, setPagesMode] =
|
|
27371
|
-
documentType === "pdf" ? "thumbnails" : "summary"
|
|
28064
|
+
const [pagesMode, setPagesMode] = useState8(
|
|
28065
|
+
documentType === "pdf" || documentType === "comic" ? "thumbnails" : "summary"
|
|
27372
28066
|
);
|
|
28067
|
+
useEffect7(() => {
|
|
28068
|
+
setPagesMode(
|
|
28069
|
+
documentType === "pdf" || documentType === "comic" ? "thumbnails" : "summary"
|
|
28070
|
+
);
|
|
28071
|
+
}, [documentType]);
|
|
27373
28072
|
const isDark = uiTheme === "dark";
|
|
27374
28073
|
const t = getStrings(locale);
|
|
27375
28074
|
const showingNotes = sidebarRightTab === "annotations";
|
|
@@ -27387,11 +28086,12 @@ var RightSheet = ({
|
|
|
27387
28086
|
UIManager.getViewManagerConfig?.("PapyrusPageView")
|
|
27388
28087
|
);
|
|
27389
28088
|
const useNativePreview = renderTarget !== "webview" && hasNativePageView;
|
|
28089
|
+
const useImagePreview = documentType === "comic" && renderTarget === "webview" && typeof engine.getPagePreview === "function";
|
|
27390
28090
|
const thumbnailDimensionsCacheRef = useRef6(/* @__PURE__ */ new Map());
|
|
27391
28091
|
const thumbnailDimensionsPendingRef = useRef6(/* @__PURE__ */ new Set());
|
|
27392
28092
|
const thumbnailRefreshTimeoutRef = useRef6(null);
|
|
27393
|
-
const [thumbnailLayoutRevision, setThumbnailLayoutRevision] =
|
|
27394
|
-
const [visibleThumbnailPages, setVisibleThumbnailPages] =
|
|
28093
|
+
const [thumbnailLayoutRevision, setThumbnailLayoutRevision] = useState8(0);
|
|
28094
|
+
const [visibleThumbnailPages, setVisibleThumbnailPages] = useState8(
|
|
27395
28095
|
() => /* @__PURE__ */ new Set()
|
|
27396
28096
|
);
|
|
27397
28097
|
const resolvedThumbsInitialCount = useMemo5(
|
|
@@ -27543,7 +28243,7 @@ var RightSheet = ({
|
|
|
27543
28243
|
);
|
|
27544
28244
|
const renderThumbnailItem = useCallback4(
|
|
27545
28245
|
({ item }) => {
|
|
27546
|
-
const shouldRenderPreview = useNativePreview && (visibleThumbnailPages.has(item) || item < resolvedThumbsPrewarmCount || Math.abs(item + 1 - currentPage) <= 1);
|
|
28246
|
+
const shouldRenderPreview = (useNativePreview || useImagePreview) && (visibleThumbnailPages.has(item) || item < resolvedThumbsPrewarmCount || Math.abs(item + 1 - currentPage) <= 1);
|
|
27547
28247
|
return /* @__PURE__ */ jsx10(
|
|
27548
28248
|
PageThumbnail,
|
|
27549
28249
|
{
|
|
@@ -27557,6 +28257,7 @@ var RightSheet = ({
|
|
|
27557
28257
|
frameHeight: getThumbnailFrameHeight(item),
|
|
27558
28258
|
accentColor,
|
|
27559
28259
|
useNativePreview,
|
|
28260
|
+
useImagePreview,
|
|
27560
28261
|
shouldRenderPreview,
|
|
27561
28262
|
onPress: () => jumpToPage(item)
|
|
27562
28263
|
}
|
|
@@ -27573,6 +28274,7 @@ var RightSheet = ({
|
|
|
27573
28274
|
jumpToPage,
|
|
27574
28275
|
resolvedThumbsPrewarmCount,
|
|
27575
28276
|
useNativePreview,
|
|
28277
|
+
useImagePreview,
|
|
27576
28278
|
visibleThumbnailPages,
|
|
27577
28279
|
zoom
|
|
27578
28280
|
]
|
|
@@ -27904,6 +28606,10 @@ var styles9 = StyleSheet9.create({
|
|
|
27904
28606
|
width: "100%",
|
|
27905
28607
|
height: "100%"
|
|
27906
28608
|
},
|
|
28609
|
+
thumbImage: {
|
|
28610
|
+
width: "100%",
|
|
28611
|
+
height: "100%"
|
|
28612
|
+
},
|
|
27907
28613
|
thumbFallback: {
|
|
27908
28614
|
flex: 1,
|
|
27909
28615
|
alignItems: "center",
|
|
@@ -28044,7 +28750,7 @@ var styles9 = StyleSheet9.create({
|
|
|
28044
28750
|
var RightSheet_default = RightSheet;
|
|
28045
28751
|
|
|
28046
28752
|
// components/AnnotationEditor.tsx
|
|
28047
|
-
import { useEffect as useEffect8, useState as
|
|
28753
|
+
import { useEffect as useEffect8, useState as useState9 } from "react";
|
|
28048
28754
|
import {
|
|
28049
28755
|
Modal as Modal3,
|
|
28050
28756
|
View as View10,
|
|
@@ -28067,7 +28773,7 @@ var AnnotationEditor = () => {
|
|
|
28067
28773
|
} = useViewerStore8();
|
|
28068
28774
|
const annotation = annotations.find((ann) => ann.id === selectedAnnotationId);
|
|
28069
28775
|
const isEditable = annotation && (annotation.type === "text" || annotation.type === "comment");
|
|
28070
|
-
const [draft, setDraft] =
|
|
28776
|
+
const [draft, setDraft] = useState9("");
|
|
28071
28777
|
const isDark = uiTheme === "dark";
|
|
28072
28778
|
const t = getStrings(locale);
|
|
28073
28779
|
useEffect8(() => {
|
|
@@ -29050,7 +29756,7 @@ var styles12 = StyleSheet12.create({
|
|
|
29050
29756
|
var SettingsSheet_default = SettingsSheet;
|
|
29051
29757
|
|
|
29052
29758
|
// components/CoverPreview.tsx
|
|
29053
|
-
import { useEffect as useEffect9, useMemo as useMemo6, useRef as useRef7, useState as
|
|
29759
|
+
import { useEffect as useEffect9, useMemo as useMemo6, useRef as useRef7, useState as useState10 } from "react";
|
|
29054
29760
|
import {
|
|
29055
29761
|
ActivityIndicator,
|
|
29056
29762
|
StyleSheet as StyleSheet13,
|
|
@@ -29108,11 +29814,11 @@ var CoverPreview = ({
|
|
|
29108
29814
|
onLoadEnd,
|
|
29109
29815
|
onError
|
|
29110
29816
|
}) => {
|
|
29111
|
-
const [engine, setEngine] =
|
|
29112
|
-
const [layoutReady, setLayoutReady] =
|
|
29113
|
-
const [loaded, setLoaded] =
|
|
29114
|
-
const [loading, setLoading] =
|
|
29115
|
-
const [error, setError] =
|
|
29817
|
+
const [engine, setEngine] = useState10(null);
|
|
29818
|
+
const [layoutReady, setLayoutReady] = useState10(false);
|
|
29819
|
+
const [loaded, setLoaded] = useState10(false);
|
|
29820
|
+
const [loading, setLoading] = useState10(false);
|
|
29821
|
+
const [error, setError] = useState10(null);
|
|
29116
29822
|
const viewRef = useRef7(null);
|
|
29117
29823
|
const resolvedType = useMemo6(() => inferDocumentType(source, type), [source, type]);
|
|
29118
29824
|
const isPdf = resolvedType === "pdf";
|
|
@@ -29232,7 +29938,7 @@ var styles13 = StyleSheet13.create({
|
|
|
29232
29938
|
var CoverPreview_default = CoverPreview;
|
|
29233
29939
|
|
|
29234
29940
|
// components/ReadingShell.tsx
|
|
29235
|
-
import React13, { useState as
|
|
29941
|
+
import React13, { useState as useState12 } from "react";
|
|
29236
29942
|
import { Keyboard as Keyboard2, View as View20, StyleSheet as StyleSheet20 } from "react-native";
|
|
29237
29943
|
import { useViewerStore as useViewerStore17 } from "@papyrus-sdk/core";
|
|
29238
29944
|
|
|
@@ -29857,7 +30563,7 @@ var styles17 = StyleSheet17.create({
|
|
|
29857
30563
|
});
|
|
29858
30564
|
|
|
29859
30565
|
// components/SearchOverlay.tsx
|
|
29860
|
-
import { useEffect as useEffect10, useMemo as useMemo8, useState as
|
|
30566
|
+
import { useEffect as useEffect10, useMemo as useMemo8, useState as useState11 } from "react";
|
|
29861
30567
|
import {
|
|
29862
30568
|
Keyboard,
|
|
29863
30569
|
Pressable as Pressable15,
|
|
@@ -29886,8 +30592,8 @@ function SearchOverlay({
|
|
|
29886
30592
|
uiTheme,
|
|
29887
30593
|
accentColor
|
|
29888
30594
|
} = useViewerStore15();
|
|
29889
|
-
const [draft, setDraft] =
|
|
29890
|
-
const [isSearching, setIsSearching] =
|
|
30595
|
+
const [draft, setDraft] = useState11(searchQuery);
|
|
30596
|
+
const [isSearching, setIsSearching] = useState11(false);
|
|
29891
30597
|
const isDark = uiTheme === "dark";
|
|
29892
30598
|
const t = getStrings(locale);
|
|
29893
30599
|
const searchService = useMemo8(() => new SearchService(engine), [engine]);
|
|
@@ -30378,12 +31084,12 @@ function ReadingShell({
|
|
|
30378
31084
|
uiTheme,
|
|
30379
31085
|
accentColor
|
|
30380
31086
|
} = useViewerStore17();
|
|
30381
|
-
const [overflowOpen, setOverflowOpen] =
|
|
30382
|
-
const [infoOpen, setInfoOpen] =
|
|
30383
|
-
const [actionsOpen, setActionsOpen] =
|
|
30384
|
-
const [settingsOpen, setSettingsOpen] =
|
|
30385
|
-
const [searchResultsOpen, setSearchResultsOpen] =
|
|
30386
|
-
const [pageJumpOpen, setPageJumpOpen] =
|
|
31087
|
+
const [overflowOpen, setOverflowOpen] = useState12(false);
|
|
31088
|
+
const [infoOpen, setInfoOpen] = useState12(false);
|
|
31089
|
+
const [actionsOpen, setActionsOpen] = useState12(false);
|
|
31090
|
+
const [settingsOpen, setSettingsOpen] = useState12(false);
|
|
31091
|
+
const [searchResultsOpen, setSearchResultsOpen] = useState12(false);
|
|
31092
|
+
const [pageJumpOpen, setPageJumpOpen] = useState12(false);
|
|
30387
31093
|
const isDark = uiTheme === "dark";
|
|
30388
31094
|
React13.useEffect(() => {
|
|
30389
31095
|
const showSubscription = Keyboard2.addListener("keyboardDidShow", () => {
|