@papyrus-sdk/ui-react-native 0.2.19 → 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 +990 -267
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1032 -308
- 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/runtime/index.html
CHANGED
|
@@ -20369,9 +20369,121 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20369
20369
|
]).default;
|
|
20370
20370
|
});
|
|
20371
20371
|
</script>
|
|
20372
|
+
<!-- @papyrus-comic-runtime:start -->
|
|
20373
|
+
<script>
|
|
20374
|
+
(function (root, factory) {
|
|
20375
|
+
if (typeof module === "object" && module.exports) {
|
|
20376
|
+
module.exports = factory();
|
|
20377
|
+
} else {
|
|
20378
|
+
root.PapyrusComicRuntime = Object.assign(
|
|
20379
|
+
factory(),
|
|
20380
|
+
root.PapyrusComicRuntime || {}
|
|
20381
|
+
);
|
|
20382
|
+
}
|
|
20383
|
+
})(typeof self === "object" ? self : this, function () {
|
|
20384
|
+
var IMAGE_EXTENSIONS = /\.(?:gif|jpe?g|png|svg|webp)$/i;
|
|
20385
|
+
|
|
20386
|
+
function isComicImageName(name) {
|
|
20387
|
+
return typeof name === "string" && IMAGE_EXTENSIONS.test(name);
|
|
20388
|
+
}
|
|
20389
|
+
|
|
20390
|
+
function naturalCompare(left, right) {
|
|
20391
|
+
var leftParts = String(left).split(/(\d+)/);
|
|
20392
|
+
var rightParts = String(right).split(/(\d+)/);
|
|
20393
|
+
var length = Math.max(leftParts.length, rightParts.length);
|
|
20394
|
+
|
|
20395
|
+
for (var index = 0; index < length; index += 1) {
|
|
20396
|
+
var leftPart = leftParts[index] || "";
|
|
20397
|
+
var rightPart = rightParts[index] || "";
|
|
20398
|
+
if (leftPart === rightPart) continue;
|
|
20399
|
+
|
|
20400
|
+
var leftNumber = /^\d+$/.test(leftPart) ? Number(leftPart) : null;
|
|
20401
|
+
var rightNumber = /^\d+$/.test(rightPart) ? Number(rightPart) : null;
|
|
20402
|
+
if (leftNumber !== null && rightNumber !== null) {
|
|
20403
|
+
return leftNumber - rightNumber;
|
|
20404
|
+
}
|
|
20405
|
+
return leftPart.localeCompare(rightPart, undefined, {
|
|
20406
|
+
numeric: true,
|
|
20407
|
+
sensitivity: "base",
|
|
20408
|
+
});
|
|
20409
|
+
}
|
|
20410
|
+
|
|
20411
|
+
return 0;
|
|
20412
|
+
}
|
|
20413
|
+
|
|
20414
|
+
function sortComicPageNames(names) {
|
|
20415
|
+
return names.slice().sort(naturalCompare);
|
|
20416
|
+
}
|
|
20417
|
+
|
|
20418
|
+
function patchCbrWorkerSource(workerSource, wasmUrl) {
|
|
20419
|
+
return workerSource.replace(
|
|
20420
|
+
/new URL\("libarchive\.wasm",import\.meta\.url\)\.href/g,
|
|
20421
|
+
JSON.stringify(wasmUrl)
|
|
20422
|
+
);
|
|
20423
|
+
}
|
|
20424
|
+
|
|
20425
|
+
function getComicPreviewSize(width, height, maxWidth, maxHeight) {
|
|
20426
|
+
var safeWidth = Math.max(1, Number(width) || 1);
|
|
20427
|
+
var safeHeight = Math.max(1, Number(height) || 1);
|
|
20428
|
+
var widthLimit = maxWidth || 240;
|
|
20429
|
+
var heightLimit = maxHeight || 360;
|
|
20430
|
+
var scale = Math.min(1, widthLimit / safeWidth, heightLimit / safeHeight);
|
|
20431
|
+
return {
|
|
20432
|
+
width: Math.max(1, Math.round(safeWidth * scale)),
|
|
20433
|
+
height: Math.max(1, Math.round(safeHeight * scale)),
|
|
20434
|
+
};
|
|
20435
|
+
}
|
|
20436
|
+
|
|
20437
|
+
function getComicPageAspectRatio(width, height) {
|
|
20438
|
+
var safeWidth = Math.max(1, Number(width) || 1);
|
|
20439
|
+
var safeHeight = Math.max(1, Number(height) || 1);
|
|
20440
|
+
return safeWidth + " / " + safeHeight;
|
|
20441
|
+
}
|
|
20442
|
+
|
|
20443
|
+
function getProtectedComicPageIndexes(
|
|
20444
|
+
currentPage,
|
|
20445
|
+
visiblePageIndexes,
|
|
20446
|
+
loadingPageIndexes
|
|
20447
|
+
) {
|
|
20448
|
+
var protectedIndexes = new Set([
|
|
20449
|
+
currentPage - 1,
|
|
20450
|
+
currentPage,
|
|
20451
|
+
currentPage - 2,
|
|
20452
|
+
]);
|
|
20453
|
+
(visiblePageIndexes || []).forEach(function (pageIndex) {
|
|
20454
|
+
protectedIndexes.add(pageIndex);
|
|
20455
|
+
});
|
|
20456
|
+
(loadingPageIndexes || []).forEach(function (pageIndex) {
|
|
20457
|
+
protectedIndexes.add(pageIndex);
|
|
20458
|
+
});
|
|
20459
|
+
return protectedIndexes;
|
|
20460
|
+
}
|
|
20461
|
+
|
|
20462
|
+
function isCurrentComicPageLoad(
|
|
20463
|
+
loadGeneration,
|
|
20464
|
+
currentGeneration,
|
|
20465
|
+
entry,
|
|
20466
|
+
currentEntry
|
|
20467
|
+
) {
|
|
20468
|
+
return loadGeneration === currentGeneration && entry === currentEntry;
|
|
20469
|
+
}
|
|
20470
|
+
|
|
20471
|
+
return {
|
|
20472
|
+
isComicImageName: isComicImageName,
|
|
20473
|
+
sortComicPageNames: sortComicPageNames,
|
|
20474
|
+
patchCbrWorkerSource: patchCbrWorkerSource,
|
|
20475
|
+
getComicPreviewSize: getComicPreviewSize,
|
|
20476
|
+
getComicPageAspectRatio: getComicPageAspectRatio,
|
|
20477
|
+
getProtectedComicPageIndexes: getProtectedComicPageIndexes,
|
|
20478
|
+
isCurrentComicPageLoad: isCurrentComicPageLoad,
|
|
20479
|
+
};
|
|
20480
|
+
});
|
|
20481
|
+
|
|
20482
|
+
</script>
|
|
20483
|
+
<!-- @papyrus-comic-runtime:end -->
|
|
20372
20484
|
<script>
|
|
20373
20485
|
(function () {
|
|
20374
|
-
const viewer = document.getElementById(
|
|
20486
|
+
const viewer = document.getElementById('viewer');
|
|
20375
20487
|
const DEFAULT_FONT_SIZE = 16;
|
|
20376
20488
|
const TEXT_PAGE_CHUNK = 1600;
|
|
20377
20489
|
|
|
@@ -20384,27 +20496,116 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20384
20496
|
let currentPage = 1;
|
|
20385
20497
|
let pageCount = 0;
|
|
20386
20498
|
let zoom = 1.0;
|
|
20499
|
+
let rotation = 0;
|
|
20500
|
+
let comicArchive = null;
|
|
20501
|
+
let comicEntries = [];
|
|
20502
|
+
let comicContainer = null;
|
|
20503
|
+
let comicPages = [];
|
|
20504
|
+
let comicObserver = null;
|
|
20505
|
+
let comicScrollFrame = null;
|
|
20506
|
+
const comicObjectUrls = new Map();
|
|
20507
|
+
const comicLoading = new Map();
|
|
20508
|
+
const comicDimensions = new Map();
|
|
20509
|
+
const comicPreviewCache = new Map();
|
|
20510
|
+
const comicPreviewLoading = new Map();
|
|
20511
|
+
const COMIC_CACHE_LIMIT = 16;
|
|
20512
|
+
const COMIC_PREVIEW_CACHE_LIMIT = 8;
|
|
20513
|
+
const comicHelpers = window.PapyrusComicRuntime || {};
|
|
20514
|
+
const runtimeConfig = window.__PAPYRUS_RUNTIME_CONFIG__ || {};
|
|
20515
|
+
let comicDispose = null;
|
|
20516
|
+
let comicGeneration = 0;
|
|
20387
20517
|
|
|
20388
20518
|
const sendMessage = (payload) => {
|
|
20389
|
-
if (
|
|
20390
|
-
window.ReactNativeWebView &&
|
|
20391
|
-
window.ReactNativeWebView.postMessage
|
|
20392
|
-
) {
|
|
20519
|
+
if (window.ReactNativeWebView && window.ReactNativeWebView.postMessage) {
|
|
20393
20520
|
window.ReactNativeWebView.postMessage(JSON.stringify(payload));
|
|
20394
20521
|
return;
|
|
20395
20522
|
}
|
|
20396
20523
|
if (window.parent && window.parent !== window) {
|
|
20397
|
-
window.parent.postMessage(payload,
|
|
20524
|
+
window.parent.postMessage(payload, '*');
|
|
20398
20525
|
}
|
|
20399
20526
|
};
|
|
20400
20527
|
|
|
20401
20528
|
const sendResponse = (id, ok, data, error) => {
|
|
20402
|
-
sendMessage({ type:
|
|
20529
|
+
sendMessage({ type: 'response', id, ok, data, error });
|
|
20530
|
+
};
|
|
20531
|
+
|
|
20532
|
+
const runtimeAssetRequests = new Map();
|
|
20533
|
+
const fileChunkRequests = new Map();
|
|
20534
|
+
|
|
20535
|
+
const requestRuntimeAsset = (url, encoding) =>
|
|
20536
|
+
new Promise((resolve, reject) => {
|
|
20537
|
+
const id = `runtime-asset-${Date.now()}-${Math.random()}`;
|
|
20538
|
+
const timeout = setTimeout(() => {
|
|
20539
|
+
runtimeAssetRequests.delete(id);
|
|
20540
|
+
reject(new Error(`Tempo esgotado ao carregar asset CBR: ${url}`));
|
|
20541
|
+
}, 15000);
|
|
20542
|
+
runtimeAssetRequests.set(id, {resolve, reject, timeout});
|
|
20543
|
+
sendMessage({type: 'asset-request', id, url, encoding});
|
|
20544
|
+
});
|
|
20545
|
+
|
|
20546
|
+
const encodeArrayBufferAsDataUrl = async (buffer) => {
|
|
20547
|
+
const bytes = new Uint8Array(buffer);
|
|
20548
|
+
let binary = '';
|
|
20549
|
+
const chunkSize = 0x8000;
|
|
20550
|
+
for (let offset = 0; offset < bytes.length; offset += chunkSize) {
|
|
20551
|
+
binary += String.fromCharCode(
|
|
20552
|
+
...bytes.subarray(offset, Math.min(offset + chunkSize, bytes.length)),
|
|
20553
|
+
);
|
|
20554
|
+
}
|
|
20555
|
+
return `data:application/wasm;base64,${btoa(binary)}`;
|
|
20556
|
+
};
|
|
20557
|
+
|
|
20558
|
+
const fetchRuntimeAsset = async (url, encoding) => {
|
|
20559
|
+
try {
|
|
20560
|
+
const response = await fetch(url);
|
|
20561
|
+
if (!response.ok) throw new Error(`status ${response.status}`);
|
|
20562
|
+
if (encoding === 'text') return await response.text();
|
|
20563
|
+
return await encodeArrayBufferAsDataUrl(await response.arrayBuffer());
|
|
20564
|
+
} catch {
|
|
20565
|
+
return await requestRuntimeAsset(url, encoding);
|
|
20566
|
+
}
|
|
20567
|
+
};
|
|
20568
|
+
|
|
20569
|
+
const requestLocalFileChunk = (uri, offset, length) =>
|
|
20570
|
+
new Promise((resolve, reject) => {
|
|
20571
|
+
const id = `file-chunk-${Date.now()}-${Math.random()}`;
|
|
20572
|
+
const timeout = setTimeout(() => {
|
|
20573
|
+
fileChunkRequests.delete(id);
|
|
20574
|
+
reject(new Error(`Tempo esgotado ao ler arquivo local: ${uri}`));
|
|
20575
|
+
}, 30000);
|
|
20576
|
+
fileChunkRequests.set(id, {resolve, reject, timeout});
|
|
20577
|
+
sendMessage({type: 'file-chunk-request', id, uri, offset, length});
|
|
20578
|
+
});
|
|
20579
|
+
|
|
20580
|
+
const readLocalFile = async (uri) => {
|
|
20581
|
+
const chunkSize = 1024 * 1024;
|
|
20582
|
+
const chunks = [];
|
|
20583
|
+
let offset = 0;
|
|
20584
|
+
let totalLength = 0;
|
|
20585
|
+
while (true) {
|
|
20586
|
+
const result = await requestLocalFileChunk(uri, offset, chunkSize);
|
|
20587
|
+
const bytes = decodeBase64(result.data || '');
|
|
20588
|
+
if (bytes.length === 0 && !result.done) {
|
|
20589
|
+
throw new Error('Leitura nativa retornou um chunk vazio.');
|
|
20590
|
+
}
|
|
20591
|
+
chunks.push(bytes);
|
|
20592
|
+
totalLength += bytes.length;
|
|
20593
|
+
offset += bytes.length;
|
|
20594
|
+
if (result.done) break;
|
|
20595
|
+
}
|
|
20596
|
+
|
|
20597
|
+
const output = new Uint8Array(totalLength);
|
|
20598
|
+
let outputOffset = 0;
|
|
20599
|
+
chunks.forEach((chunk) => {
|
|
20600
|
+
output.set(chunk, outputOffset);
|
|
20601
|
+
outputOffset += chunk.length;
|
|
20602
|
+
});
|
|
20603
|
+
return output.buffer;
|
|
20403
20604
|
};
|
|
20404
20605
|
|
|
20405
20606
|
const sendState = (extra) => {
|
|
20406
20607
|
sendMessage({
|
|
20407
|
-
type:
|
|
20608
|
+
type: 'state',
|
|
20408
20609
|
payload: {
|
|
20409
20610
|
pageCount,
|
|
20410
20611
|
currentPage,
|
|
@@ -20415,70 +20616,66 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20415
20616
|
};
|
|
20416
20617
|
|
|
20417
20618
|
const sendEvent = (name, payload) => {
|
|
20418
|
-
sendMessage({ type:
|
|
20419
|
-
};
|
|
20420
|
-
|
|
20421
|
-
const log = (...args) => {
|
|
20422
|
-
sendEvent("RUNTIME_LOG", {
|
|
20423
|
-
message: args.map((value) => String(value)).join(" "),
|
|
20424
|
-
});
|
|
20619
|
+
sendMessage({ type: 'event', name, payload });
|
|
20425
20620
|
};
|
|
20426
20621
|
|
|
20427
20622
|
const reportError = (error, context) => {
|
|
20428
|
-
const message =
|
|
20429
|
-
error && error.message ? error.message : String(error);
|
|
20623
|
+
const message = error && error.message ? error.message : String(error);
|
|
20430
20624
|
const stack = error && error.stack ? error.stack : null;
|
|
20431
|
-
sendEvent(
|
|
20432
|
-
};
|
|
20433
|
-
|
|
20434
|
-
const EPUB_OPEN_TIMEOUT_MS = 180000;
|
|
20435
|
-
const EPUB_READY_TIMEOUT_MS = 180000;
|
|
20436
|
-
const EPUB_DISPLAY_TIMEOUT_MS = 30000;
|
|
20437
|
-
|
|
20438
|
-
const withTimeout = async (promise, ms, label) => {
|
|
20439
|
-
let timer = null;
|
|
20440
|
-
try {
|
|
20441
|
-
return await Promise.race([
|
|
20442
|
-
promise,
|
|
20443
|
-
new Promise((_, reject) => {
|
|
20444
|
-
timer = setTimeout(
|
|
20445
|
-
() => reject(new Error(`Timeout: ${label}`)),
|
|
20446
|
-
ms
|
|
20447
|
-
);
|
|
20448
|
-
}),
|
|
20449
|
-
]);
|
|
20450
|
-
} finally {
|
|
20451
|
-
if (timer) {
|
|
20452
|
-
clearTimeout(timer);
|
|
20453
|
-
}
|
|
20454
|
-
}
|
|
20625
|
+
sendEvent('RUNTIME_ERROR', { message, context, stack });
|
|
20455
20626
|
};
|
|
20456
20627
|
|
|
20457
20628
|
const shouldIgnoreError = (error) => {
|
|
20458
|
-
const message =
|
|
20459
|
-
|
|
20460
|
-
return message.includes("ResizeObserver loop");
|
|
20629
|
+
const message = error && error.message ? error.message : String(error || '');
|
|
20630
|
+
return message.includes('ResizeObserver loop');
|
|
20461
20631
|
};
|
|
20462
20632
|
|
|
20463
|
-
window.addEventListener(
|
|
20633
|
+
window.addEventListener('error', (event) => {
|
|
20464
20634
|
const error = event.error || event.message;
|
|
20465
20635
|
if (shouldIgnoreError(error)) return;
|
|
20466
|
-
reportError(error,
|
|
20636
|
+
reportError(error, 'window.error');
|
|
20467
20637
|
});
|
|
20468
20638
|
|
|
20469
|
-
window.addEventListener(
|
|
20639
|
+
window.addEventListener('unhandledrejection', (event) => {
|
|
20470
20640
|
if (shouldIgnoreError(event.reason)) return;
|
|
20471
|
-
reportError(event.reason,
|
|
20641
|
+
reportError(event.reason, 'unhandledrejection');
|
|
20472
20642
|
});
|
|
20473
20643
|
|
|
20644
|
+
const clearComicState = () => {
|
|
20645
|
+
comicGeneration += 1;
|
|
20646
|
+
if (comicObserver) {
|
|
20647
|
+
comicObserver.disconnect();
|
|
20648
|
+
comicObserver = null;
|
|
20649
|
+
}
|
|
20650
|
+
if (comicScrollFrame !== null) {
|
|
20651
|
+
cancelAnimationFrame(comicScrollFrame);
|
|
20652
|
+
comicScrollFrame = null;
|
|
20653
|
+
}
|
|
20654
|
+
comicObjectUrls.forEach((url) => URL.revokeObjectURL(url));
|
|
20655
|
+
comicObjectUrls.clear();
|
|
20656
|
+
comicLoading.clear();
|
|
20657
|
+
comicDimensions.clear();
|
|
20658
|
+
comicPreviewCache.clear();
|
|
20659
|
+
comicPreviewLoading.clear();
|
|
20660
|
+
if (comicDispose) {
|
|
20661
|
+
void comicDispose();
|
|
20662
|
+
comicDispose = null;
|
|
20663
|
+
}
|
|
20664
|
+
comicArchive = null;
|
|
20665
|
+
comicEntries = [];
|
|
20666
|
+
comicContainer = null;
|
|
20667
|
+
comicPages = [];
|
|
20668
|
+
};
|
|
20669
|
+
|
|
20474
20670
|
const clearViewer = () => {
|
|
20671
|
+
clearComicState();
|
|
20475
20672
|
while (viewer.firstChild) {
|
|
20476
20673
|
viewer.removeChild(viewer.firstChild);
|
|
20477
20674
|
}
|
|
20478
20675
|
};
|
|
20479
20676
|
|
|
20480
20677
|
const decodeBase64 = (value) => {
|
|
20481
|
-
const clean = value.replace(/\s/g,
|
|
20678
|
+
const clean = value.replace(/\s/g, '');
|
|
20482
20679
|
const binary = atob(clean);
|
|
20483
20680
|
const len = binary.length;
|
|
20484
20681
|
const bytes = new Uint8Array(len);
|
|
@@ -20490,41 +20687,438 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20490
20687
|
|
|
20491
20688
|
const decodeBase64ToText = (value) => {
|
|
20492
20689
|
const bytes = decodeBase64(value);
|
|
20493
|
-
return new TextDecoder(
|
|
20690
|
+
return new TextDecoder('utf-8').decode(bytes);
|
|
20691
|
+
};
|
|
20692
|
+
|
|
20693
|
+
const sourceToArrayBuffer = async (source) => {
|
|
20694
|
+
if (source.kind === 'uri') {
|
|
20695
|
+
if (/^(?:file|content):\/\//i.test(source.uri)) {
|
|
20696
|
+
return readLocalFile(source.uri);
|
|
20697
|
+
}
|
|
20698
|
+
const response = await fetch(source.uri);
|
|
20699
|
+
if (!response.ok && response.status !== 0) {
|
|
20700
|
+
throw new Error(`Falha ao carregar quadrinho (${response.status})`);
|
|
20701
|
+
}
|
|
20702
|
+
return response.arrayBuffer();
|
|
20703
|
+
}
|
|
20704
|
+
if (source.kind === 'base64') {
|
|
20705
|
+
return decodeBase64(source.data).buffer;
|
|
20706
|
+
}
|
|
20707
|
+
throw new Error('Fonte de quadrinho inválida.');
|
|
20494
20708
|
};
|
|
20495
20709
|
|
|
20496
|
-
const
|
|
20497
|
-
const
|
|
20498
|
-
|
|
20499
|
-
if (
|
|
20500
|
-
|
|
20501
|
-
|
|
20710
|
+
const comicMimeType = (name) => {
|
|
20711
|
+
const extension = name.split('.').pop()?.toLowerCase();
|
|
20712
|
+
if (extension === 'png') return 'image/png';
|
|
20713
|
+
if (extension === 'gif') return 'image/gif';
|
|
20714
|
+
if (extension === 'svg') return 'image/svg+xml';
|
|
20715
|
+
if (extension === 'webp') return 'image/webp';
|
|
20716
|
+
return 'image/jpeg';
|
|
20717
|
+
};
|
|
20718
|
+
|
|
20719
|
+
const updateComicCurrentPage = () => {
|
|
20720
|
+
if (!comicContainer || comicPages.length === 0) return;
|
|
20721
|
+
const viewportTop = comicContainer.scrollTop;
|
|
20722
|
+
let closestIndex = currentPage - 1;
|
|
20723
|
+
let closestDistance = Number.POSITIVE_INFINITY;
|
|
20724
|
+
comicPages.forEach((page, index) => {
|
|
20725
|
+
const distance = Math.abs(page.offsetTop - viewportTop);
|
|
20726
|
+
if (distance < closestDistance) {
|
|
20727
|
+
closestDistance = distance;
|
|
20728
|
+
closestIndex = index;
|
|
20729
|
+
}
|
|
20730
|
+
});
|
|
20731
|
+
const nextPage = Math.max(1, Math.min(pageCount, closestIndex + 1));
|
|
20732
|
+
if (nextPage !== currentPage) {
|
|
20733
|
+
currentPage = nextPage;
|
|
20734
|
+
sendState();
|
|
20735
|
+
}
|
|
20736
|
+
};
|
|
20737
|
+
|
|
20738
|
+
const scheduleComicCurrentPage = () => {
|
|
20739
|
+
if (comicScrollFrame !== null) return;
|
|
20740
|
+
comicScrollFrame = requestAnimationFrame(() => {
|
|
20741
|
+
comicScrollFrame = null;
|
|
20742
|
+
updateComicCurrentPage();
|
|
20743
|
+
});
|
|
20744
|
+
};
|
|
20745
|
+
|
|
20746
|
+
const evictComicUrls = () => {
|
|
20747
|
+
if (comicObjectUrls.size <= COMIC_CACHE_LIMIT) return;
|
|
20748
|
+
const protectedIndexes = new Set([
|
|
20749
|
+
currentPage - 1,
|
|
20750
|
+
currentPage,
|
|
20751
|
+
currentPage - 2,
|
|
20752
|
+
]);
|
|
20753
|
+
for (const [index, url] of comicObjectUrls) {
|
|
20754
|
+
if (comicObjectUrls.size <= COMIC_CACHE_LIMIT) break;
|
|
20755
|
+
if (protectedIndexes.has(index)) continue;
|
|
20756
|
+
URL.revokeObjectURL(url);
|
|
20757
|
+
comicObjectUrls.delete(index);
|
|
20758
|
+
const image = comicPages[index]?.querySelector('img');
|
|
20759
|
+
const page = comicPages[index];
|
|
20760
|
+
const dimensions = comicDimensions.get(index);
|
|
20761
|
+
const width = dimensions?.width || image?.naturalWidth || 0;
|
|
20762
|
+
const height = dimensions?.height || image?.naturalHeight || 0;
|
|
20763
|
+
if (page && width > 0 && height > 0) {
|
|
20764
|
+
page.style.aspectRatio = comicHelpers.getComicPageAspectRatio(
|
|
20765
|
+
width,
|
|
20766
|
+
height
|
|
20767
|
+
);
|
|
20768
|
+
}
|
|
20769
|
+
if (image) image.removeAttribute('src');
|
|
20770
|
+
}
|
|
20771
|
+
};
|
|
20772
|
+
|
|
20773
|
+
const ensureComicPage = async (pageIndex) => {
|
|
20774
|
+
if (comicObjectUrls.has(pageIndex)) {
|
|
20775
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
20776
|
+
if (image && !image.src) image.src = comicObjectUrls.get(pageIndex);
|
|
20777
|
+
return comicObjectUrls.get(pageIndex);
|
|
20778
|
+
}
|
|
20779
|
+
if (comicLoading.has(pageIndex)) return comicLoading.get(pageIndex);
|
|
20780
|
+
|
|
20781
|
+
const entry = comicEntries[pageIndex];
|
|
20782
|
+
if (!entry) throw new Error(`Página de quadrinho inválida: ${pageIndex}`);
|
|
20783
|
+
const loadGeneration = comicGeneration;
|
|
20784
|
+
const pending = entry.async('blob').then((blob) => {
|
|
20785
|
+
if (
|
|
20786
|
+
!comicHelpers.isCurrentComicPageLoad(
|
|
20787
|
+
loadGeneration,
|
|
20788
|
+
comicGeneration,
|
|
20789
|
+
entry,
|
|
20790
|
+
comicEntries[pageIndex]
|
|
20791
|
+
)
|
|
20792
|
+
) {
|
|
20793
|
+
return null;
|
|
20794
|
+
}
|
|
20795
|
+
const url = URL.createObjectURL(
|
|
20796
|
+
new Blob([blob], { type: comicMimeType(entry.name) })
|
|
20502
20797
|
);
|
|
20798
|
+
comicObjectUrls.set(pageIndex, url);
|
|
20799
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
20800
|
+
if (image) image.src = url;
|
|
20801
|
+
evictComicUrls();
|
|
20802
|
+
return url;
|
|
20803
|
+
});
|
|
20804
|
+
comicLoading.set(pageIndex, pending);
|
|
20805
|
+
try {
|
|
20806
|
+
return await pending;
|
|
20807
|
+
} finally {
|
|
20808
|
+
if (comicLoading.get(pageIndex) === pending) {
|
|
20809
|
+
comicLoading.delete(pageIndex);
|
|
20810
|
+
}
|
|
20503
20811
|
}
|
|
20504
|
-
|
|
20505
|
-
|
|
20812
|
+
};
|
|
20813
|
+
|
|
20814
|
+
const renderComicPage = (pageIndex) => {
|
|
20815
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
20816
|
+
if (!image) return;
|
|
20817
|
+
image.style.width = `${Math.max(40, Math.round(100 * zoom))}%`;
|
|
20818
|
+
image.style.transform = `rotate(${rotation}deg)`;
|
|
20819
|
+
};
|
|
20820
|
+
|
|
20821
|
+
const applyComicLayout = () => {
|
|
20822
|
+
comicPages.forEach((_, pageIndex) => renderComicPage(pageIndex));
|
|
20823
|
+
};
|
|
20824
|
+
|
|
20825
|
+
const loadComic = async (source, format) => {
|
|
20826
|
+
clearViewer();
|
|
20827
|
+
let entries;
|
|
20828
|
+
if (format === 'cbr') {
|
|
20829
|
+
const clientUrl = runtimeConfig.cbrClientUrl;
|
|
20830
|
+
const workerUrl = runtimeConfig.cbrWorkerUrl;
|
|
20831
|
+
const wasmUrl = runtimeConfig.cbrWasmUrl;
|
|
20832
|
+
if (!clientUrl || !workerUrl || !wasmUrl) {
|
|
20833
|
+
throw new Error(
|
|
20834
|
+
'CBR no mobile exige o pacote opcional de runtime libarchive.'
|
|
20835
|
+
);
|
|
20836
|
+
}
|
|
20837
|
+
|
|
20838
|
+
const [clientSource, workerSource, wasmSource] = await Promise.all([
|
|
20839
|
+
fetchRuntimeAsset(clientUrl, 'text'),
|
|
20840
|
+
fetchRuntimeAsset(workerUrl, 'text'),
|
|
20841
|
+
runtimeConfig.cbrWasmDataUrl ||
|
|
20842
|
+
fetchRuntimeAsset(wasmUrl, 'base64'),
|
|
20843
|
+
]);
|
|
20844
|
+
const patchedWorkerSource = comicHelpers.patchCbrWorkerSource(
|
|
20845
|
+
workerSource,
|
|
20846
|
+
wasmSource
|
|
20847
|
+
);
|
|
20848
|
+
const workerObjectUrl = URL.createObjectURL(
|
|
20849
|
+
new Blob([patchedWorkerSource], {type: 'text/javascript'})
|
|
20850
|
+
);
|
|
20851
|
+
const clientObjectUrl = URL.createObjectURL(
|
|
20852
|
+
new Blob([clientSource], { type: 'text/javascript' })
|
|
20853
|
+
);
|
|
20854
|
+
try {
|
|
20855
|
+
const archiveModule = await import(clientObjectUrl);
|
|
20856
|
+
const createCbrWorker = () => {
|
|
20857
|
+
const worker = new Worker(workerObjectUrl, {type: 'module'});
|
|
20858
|
+
worker.addEventListener('error', (event) => {
|
|
20859
|
+
sendEvent('RUNTIME_ERROR', {
|
|
20860
|
+
message: `CBR worker: ${event?.message || 'falha ao executar o worker'}`,
|
|
20861
|
+
context: 'comic.worker',
|
|
20862
|
+
});
|
|
20863
|
+
});
|
|
20864
|
+
worker.addEventListener('messageerror', () => {
|
|
20865
|
+
sendEvent('RUNTIME_ERROR', {
|
|
20866
|
+
message: 'CBR worker: falha ao transferir mensagem',
|
|
20867
|
+
context: 'comic.worker',
|
|
20868
|
+
});
|
|
20869
|
+
});
|
|
20870
|
+
return worker;
|
|
20871
|
+
};
|
|
20872
|
+
archiveModule.Archive.init({getWorker: createCbrWorker});
|
|
20873
|
+
const bytes = await sourceToArrayBuffer(source);
|
|
20874
|
+
const file = new Blob([bytes], {
|
|
20875
|
+
type: 'application/vnd.comicbook-rar',
|
|
20876
|
+
});
|
|
20877
|
+
const archive = await archiveModule.Archive.open(file);
|
|
20878
|
+
const files = await archive.getFilesArray();
|
|
20879
|
+
entries = files
|
|
20880
|
+
.filter(
|
|
20881
|
+
(item) => {
|
|
20882
|
+
const name = `${item?.path || ''}${item?.file?.name || ''}`;
|
|
20883
|
+
return item?.file && comicHelpers.isComicImageName(name);
|
|
20884
|
+
}
|
|
20885
|
+
)
|
|
20886
|
+
.map((item) => {
|
|
20887
|
+
const name = `${item.path || ''}${item.file.name}`;
|
|
20888
|
+
return {
|
|
20889
|
+
name,
|
|
20890
|
+
async: async () => item.file.extract(),
|
|
20891
|
+
};
|
|
20892
|
+
});
|
|
20893
|
+
comicDispose = async () => {
|
|
20894
|
+
await archive.close();
|
|
20895
|
+
URL.revokeObjectURL(workerObjectUrl);
|
|
20896
|
+
URL.revokeObjectURL(clientObjectUrl);
|
|
20897
|
+
};
|
|
20898
|
+
} catch (error) {
|
|
20899
|
+
URL.revokeObjectURL(workerObjectUrl);
|
|
20900
|
+
URL.revokeObjectURL(clientObjectUrl);
|
|
20901
|
+
throw error;
|
|
20902
|
+
}
|
|
20903
|
+
} else {
|
|
20904
|
+
if (!window.JSZip) {
|
|
20905
|
+
throw new Error('O runtime ZIP do leitor mobile não foi carregado.');
|
|
20906
|
+
}
|
|
20907
|
+
|
|
20908
|
+
const bytes = await sourceToArrayBuffer(source);
|
|
20909
|
+
comicArchive = await window.JSZip.loadAsync(bytes);
|
|
20910
|
+
entries = Object.keys(comicArchive.files)
|
|
20911
|
+
.filter((name) => {
|
|
20912
|
+
const entry = comicArchive.files[name];
|
|
20913
|
+
return !entry.dir && comicHelpers.isComicImageName(name);
|
|
20914
|
+
})
|
|
20915
|
+
.map((name) => comicArchive.files[name]);
|
|
20916
|
+
}
|
|
20917
|
+
|
|
20918
|
+
const names = comicHelpers.sortComicPageNames(
|
|
20919
|
+
entries.map((entry) => entry.name)
|
|
20920
|
+
);
|
|
20921
|
+
const entriesByName = new Map(entries.map((entry) => [entry.name, entry]));
|
|
20922
|
+
comicEntries = names.map((name) => entriesByName.get(name));
|
|
20923
|
+
if (comicEntries.length === 0) {
|
|
20924
|
+
if (comicDispose) {
|
|
20925
|
+
await comicDispose();
|
|
20926
|
+
comicDispose = null;
|
|
20927
|
+
}
|
|
20928
|
+
throw new Error('O arquivo não contém páginas de imagem.');
|
|
20506
20929
|
}
|
|
20507
|
-
|
|
20508
|
-
|
|
20930
|
+
|
|
20931
|
+
comicContainer = document.createElement('div');
|
|
20932
|
+
comicContainer.style.width = '100%';
|
|
20933
|
+
comicContainer.style.height = '100%';
|
|
20934
|
+
comicContainer.style.overflow = 'auto';
|
|
20935
|
+
comicContainer.style.padding = '16px 0 120px';
|
|
20936
|
+
comicContainer.style.boxSizing = 'border-box';
|
|
20937
|
+
comicContainer.style.background = '#ffffff';
|
|
20938
|
+
comicContainer.addEventListener('scroll', scheduleComicCurrentPage, {
|
|
20939
|
+
passive: true,
|
|
20940
|
+
});
|
|
20941
|
+
viewer.style.overflow = 'hidden';
|
|
20942
|
+
viewer.appendChild(comicContainer);
|
|
20943
|
+
|
|
20944
|
+
comicPages = comicEntries.map((entry, pageIndex) => {
|
|
20945
|
+
const page = document.createElement('div');
|
|
20946
|
+
page.dataset.pageIndex = String(pageIndex);
|
|
20947
|
+
page.style.width = '100%';
|
|
20948
|
+
page.style.minHeight = '80px';
|
|
20949
|
+
page.style.display = 'flex';
|
|
20950
|
+
page.style.justifyContent = 'center';
|
|
20951
|
+
page.style.alignItems = 'flex-start';
|
|
20952
|
+
page.style.padding = '0 12px 20px';
|
|
20953
|
+
page.style.boxSizing = 'border-box';
|
|
20954
|
+
|
|
20955
|
+
const image = document.createElement('img');
|
|
20956
|
+
image.alt = `Página ${pageIndex + 1}`;
|
|
20957
|
+
image.draggable = false;
|
|
20958
|
+
image.decoding = 'async';
|
|
20959
|
+
image.loading = 'lazy';
|
|
20960
|
+
image.style.display = 'block';
|
|
20961
|
+
image.style.maxWidth = 'none';
|
|
20962
|
+
image.style.height = 'auto';
|
|
20963
|
+
image.style.userSelect = 'none';
|
|
20964
|
+
image.addEventListener('load', () => {
|
|
20965
|
+
if (image.naturalWidth > 0 && image.naturalHeight > 0) {
|
|
20966
|
+
comicDimensions.set(pageIndex, {
|
|
20967
|
+
width: image.naturalWidth,
|
|
20968
|
+
height: image.naturalHeight,
|
|
20969
|
+
});
|
|
20970
|
+
page.style.aspectRatio = comicHelpers.getComicPageAspectRatio(
|
|
20971
|
+
image.naturalWidth,
|
|
20972
|
+
image.naturalHeight
|
|
20973
|
+
);
|
|
20974
|
+
}
|
|
20975
|
+
});
|
|
20976
|
+
page.appendChild(image);
|
|
20977
|
+
comicContainer.appendChild(page);
|
|
20978
|
+
return page;
|
|
20979
|
+
});
|
|
20980
|
+
|
|
20981
|
+
if (typeof IntersectionObserver === 'function') {
|
|
20982
|
+
comicObserver = new IntersectionObserver(
|
|
20983
|
+
(observations) => {
|
|
20984
|
+
observations.forEach((observation) => {
|
|
20985
|
+
if (!observation.isIntersecting) return;
|
|
20986
|
+
const pageIndex = Number(observation.target.dataset.pageIndex);
|
|
20987
|
+
void ensureComicPage(pageIndex).catch((error) =>
|
|
20988
|
+
sendEvent('RUNTIME_ERROR', {
|
|
20989
|
+
message: error?.message || String(error),
|
|
20990
|
+
context: 'comic.page',
|
|
20991
|
+
})
|
|
20992
|
+
);
|
|
20993
|
+
});
|
|
20994
|
+
scheduleComicCurrentPage();
|
|
20995
|
+
},
|
|
20996
|
+
{ root: comicContainer, rootMargin: '600px 0px' }
|
|
20997
|
+
);
|
|
20998
|
+
comicPages.forEach((page) => comicObserver.observe(page));
|
|
20999
|
+
} else {
|
|
21000
|
+
for (let pageIndex = 0; pageIndex < Math.min(3, comicPages.length); pageIndex += 1) {
|
|
21001
|
+
void ensureComicPage(pageIndex);
|
|
21002
|
+
}
|
|
21003
|
+
}
|
|
21004
|
+
pageCount = comicPages.length;
|
|
21005
|
+
currentPage = 1;
|
|
21006
|
+
await ensureComicPage(0);
|
|
21007
|
+
applyComicLayout();
|
|
21008
|
+
return { pageCount };
|
|
21009
|
+
};
|
|
21010
|
+
|
|
21011
|
+
const readComicBlobAsDataUrl = (blob, mimeType) =>
|
|
21012
|
+
new Promise((resolve, reject) => {
|
|
20509
21013
|
const reader = new FileReader();
|
|
20510
|
-
reader.onerror = () =>
|
|
20511
|
-
reject(new Error("Failed to read epub blob"));
|
|
21014
|
+
reader.onerror = () => reject(new Error('Falha ao gerar preview.'));
|
|
20512
21015
|
reader.onload = () => resolve(reader.result);
|
|
20513
|
-
reader.
|
|
21016
|
+
reader.readAsDataURL(new Blob([blob], { type: mimeType }));
|
|
21017
|
+
});
|
|
21018
|
+
|
|
21019
|
+
const createComicPagePreview = async (pageIndex) => {
|
|
21020
|
+
const entry = comicEntries[pageIndex];
|
|
21021
|
+
if (!entry) return null;
|
|
21022
|
+
const mimeType = comicMimeType(entry.name);
|
|
21023
|
+
const sourceUrl = await ensureComicPage(pageIndex);
|
|
21024
|
+
if (!sourceUrl) return null;
|
|
21025
|
+
try {
|
|
21026
|
+
const image = new Image();
|
|
21027
|
+
image.decoding = 'async';
|
|
21028
|
+
await new Promise((resolve, reject) => {
|
|
21029
|
+
image.onload = resolve;
|
|
21030
|
+
image.onerror = () => reject(new Error('Falha ao decodificar preview.'));
|
|
21031
|
+
image.src = sourceUrl;
|
|
21032
|
+
});
|
|
21033
|
+
const size = comicHelpers.getComicPreviewSize(
|
|
21034
|
+
image.naturalWidth || image.width,
|
|
21035
|
+
image.naturalHeight || image.height
|
|
21036
|
+
);
|
|
21037
|
+
const canvas = document.createElement('canvas');
|
|
21038
|
+
canvas.width = size.width;
|
|
21039
|
+
canvas.height = size.height;
|
|
21040
|
+
const context = canvas.getContext('2d');
|
|
21041
|
+
if (!context) throw new Error('Canvas indisponível para preview.');
|
|
21042
|
+
context.fillStyle = '#ffffff';
|
|
21043
|
+
context.fillRect(0, 0, size.width, size.height);
|
|
21044
|
+
context.drawImage(image, 0, 0, size.width, size.height);
|
|
21045
|
+
return canvas.toDataURL('image/jpeg', 0.78);
|
|
21046
|
+
} catch {
|
|
21047
|
+
try {
|
|
21048
|
+
const response = await fetch(sourceUrl);
|
|
21049
|
+
const blob = await response.blob();
|
|
21050
|
+
return await readComicBlobAsDataUrl(blob, mimeType);
|
|
21051
|
+
} catch {
|
|
21052
|
+
return null;
|
|
21053
|
+
}
|
|
21054
|
+
}
|
|
21055
|
+
};
|
|
21056
|
+
|
|
21057
|
+
const getComicPagePreview = async (pageIndex) => {
|
|
21058
|
+
const entry = comicEntries[pageIndex];
|
|
21059
|
+
if (!entry) return null;
|
|
21060
|
+
if (comicPreviewCache.has(pageIndex)) {
|
|
21061
|
+
return comicPreviewCache.get(pageIndex);
|
|
21062
|
+
}
|
|
21063
|
+
if (comicPreviewLoading.has(pageIndex)) {
|
|
21064
|
+
return comicPreviewLoading.get(pageIndex);
|
|
21065
|
+
}
|
|
21066
|
+
const loadGeneration = comicGeneration;
|
|
21067
|
+
const pending = createComicPagePreview(pageIndex).then((preview) => {
|
|
21068
|
+
if (
|
|
21069
|
+
!comicHelpers.isCurrentComicPageLoad(
|
|
21070
|
+
loadGeneration,
|
|
21071
|
+
comicGeneration,
|
|
21072
|
+
entry,
|
|
21073
|
+
comicEntries[pageIndex]
|
|
21074
|
+
)
|
|
21075
|
+
) {
|
|
21076
|
+
return null;
|
|
21077
|
+
}
|
|
21078
|
+
comicPreviewCache.set(pageIndex, preview);
|
|
21079
|
+
while (comicPreviewCache.size > COMIC_PREVIEW_CACHE_LIMIT) {
|
|
21080
|
+
comicPreviewCache.delete(comicPreviewCache.keys().next().value);
|
|
21081
|
+
}
|
|
21082
|
+
return preview;
|
|
20514
21083
|
});
|
|
21084
|
+
comicPreviewLoading.set(pageIndex, pending);
|
|
21085
|
+
try {
|
|
21086
|
+
return await pending;
|
|
21087
|
+
} finally {
|
|
21088
|
+
if (comicPreviewLoading.get(pageIndex) === pending) {
|
|
21089
|
+
comicPreviewLoading.delete(pageIndex);
|
|
21090
|
+
}
|
|
21091
|
+
}
|
|
21092
|
+
};
|
|
21093
|
+
|
|
21094
|
+
const getComicPageDimensions = async (pageIndex) => {
|
|
21095
|
+
const known = comicDimensions.get(pageIndex);
|
|
21096
|
+
if (known) return known;
|
|
21097
|
+
await ensureComicPage(pageIndex);
|
|
21098
|
+
const image = comicPages[pageIndex]?.querySelector('img');
|
|
21099
|
+
if (image && !image.complete) {
|
|
21100
|
+
await new Promise((resolve) => {
|
|
21101
|
+
image.addEventListener('load', resolve, { once: true });
|
|
21102
|
+
image.addEventListener('error', resolve, { once: true });
|
|
21103
|
+
});
|
|
21104
|
+
}
|
|
21105
|
+
return (
|
|
21106
|
+
comicDimensions.get(pageIndex) || {
|
|
21107
|
+
width: image?.naturalWidth || 0,
|
|
21108
|
+
height: image?.naturalHeight || 0,
|
|
21109
|
+
}
|
|
21110
|
+
);
|
|
20515
21111
|
};
|
|
20516
21112
|
|
|
20517
21113
|
const normalizeHref = (href) => {
|
|
20518
|
-
if (!href) return
|
|
20519
|
-
return href.split(
|
|
21114
|
+
if (!href) return '';
|
|
21115
|
+
return href.split('#')[0];
|
|
20520
21116
|
};
|
|
20521
21117
|
|
|
20522
21118
|
const getSpineIndexByHref = (href) => {
|
|
20523
21119
|
const normalized = normalizeHref(href);
|
|
20524
21120
|
if (!normalized) return -1;
|
|
20525
|
-
return spineItems.findIndex(
|
|
20526
|
-
(item) => normalizeHref(item.href) === normalized
|
|
20527
|
-
);
|
|
21121
|
+
return spineItems.findIndex((item) => normalizeHref(item.href) === normalized);
|
|
20528
21122
|
};
|
|
20529
21123
|
|
|
20530
21124
|
const buildOutline = async () => {
|
|
@@ -20533,11 +21127,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20533
21127
|
const toc = nav && nav.toc ? nav.toc : [];
|
|
20534
21128
|
|
|
20535
21129
|
const mapItem = (item) => {
|
|
20536
|
-
const title = item.label || item.title ||
|
|
20537
|
-
const pageIndex = getSpineIndexByHref(item.href ||
|
|
20538
|
-
const children = Array.isArray(item.subitems)
|
|
20539
|
-
? item.subitems.map(mapItem)
|
|
20540
|
-
: [];
|
|
21130
|
+
const title = item.label || item.title || '';
|
|
21131
|
+
const pageIndex = getSpineIndexByHref(item.href || '');
|
|
21132
|
+
const children = Array.isArray(item.subitems) ? item.subitems.map(mapItem) : [];
|
|
20541
21133
|
const outlineItem = { title, pageIndex };
|
|
20542
21134
|
if (children.length > 0) outlineItem.children = children;
|
|
20543
21135
|
return outlineItem;
|
|
@@ -20549,10 +21141,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20549
21141
|
const applyEpubZoom = () => {
|
|
20550
21142
|
if (!rendition || !rendition.themes) return;
|
|
20551
21143
|
const fontSize = `${Math.round(zoom * 100)}%`;
|
|
20552
|
-
if (typeof rendition.themes.fontSize ===
|
|
21144
|
+
if (typeof rendition.themes.fontSize === 'function') {
|
|
20553
21145
|
rendition.themes.fontSize(fontSize);
|
|
20554
|
-
} else if (typeof rendition.themes.override ===
|
|
20555
|
-
rendition.themes.override(
|
|
21146
|
+
} else if (typeof rendition.themes.override === 'function') {
|
|
21147
|
+
rendition.themes.override('font-size', fontSize);
|
|
20556
21148
|
}
|
|
20557
21149
|
};
|
|
20558
21150
|
|
|
@@ -20563,14 +21155,13 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20563
21155
|
};
|
|
20564
21156
|
|
|
20565
21157
|
const renderTextPage = (pageIndex) => {
|
|
20566
|
-
const text = textPages[pageIndex] ||
|
|
21158
|
+
const text = textPages[pageIndex] || '';
|
|
20567
21159
|
if (!textContainer) {
|
|
20568
|
-
textContainer = document.createElement(
|
|
20569
|
-
textContainer.style.padding =
|
|
20570
|
-
textContainer.style.lineHeight =
|
|
20571
|
-
textContainer.style.whiteSpace =
|
|
20572
|
-
textContainer.style.fontFamily =
|
|
20573
|
-
'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace';
|
|
21160
|
+
textContainer = document.createElement('div');
|
|
21161
|
+
textContainer.style.padding = '24px';
|
|
21162
|
+
textContainer.style.lineHeight = '1.6';
|
|
21163
|
+
textContainer.style.whiteSpace = 'pre-wrap';
|
|
21164
|
+
textContainer.style.fontFamily = 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace';
|
|
20574
21165
|
viewer.appendChild(textContainer);
|
|
20575
21166
|
}
|
|
20576
21167
|
textContainer.textContent = text;
|
|
@@ -20582,18 +21173,18 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20582
21173
|
for (let i = 0; i < text.length; i += TEXT_PAGE_CHUNK) {
|
|
20583
21174
|
pages.push(text.slice(i, i + TEXT_PAGE_CHUNK));
|
|
20584
21175
|
}
|
|
20585
|
-
return pages.length > 0 ? pages : [
|
|
21176
|
+
return pages.length > 0 ? pages : [''];
|
|
20586
21177
|
};
|
|
20587
21178
|
|
|
20588
21179
|
const loadText = async (source) => {
|
|
20589
|
-
let text =
|
|
20590
|
-
if (source.kind ===
|
|
21180
|
+
let text = '';
|
|
21181
|
+
if (source.kind === 'uri') {
|
|
20591
21182
|
const res = await fetch(source.uri);
|
|
20592
21183
|
text = await res.text();
|
|
20593
|
-
} else if (source.kind ===
|
|
21184
|
+
} else if (source.kind === 'base64') {
|
|
20594
21185
|
text = decodeBase64ToText(source.data);
|
|
20595
|
-
} else if (source.kind ===
|
|
20596
|
-
text = source.text ||
|
|
21186
|
+
} else if (source.kind === 'text') {
|
|
21187
|
+
text = source.text || '';
|
|
20597
21188
|
}
|
|
20598
21189
|
|
|
20599
21190
|
clearViewer();
|
|
@@ -20606,44 +21197,25 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20606
21197
|
};
|
|
20607
21198
|
|
|
20608
21199
|
const loadEpub = async (source) => {
|
|
20609
|
-
|
|
20610
|
-
if (rendition && typeof rendition.destroy === "function") {
|
|
21200
|
+
if (rendition && typeof rendition.destroy === 'function') {
|
|
20611
21201
|
rendition.destroy();
|
|
20612
21202
|
}
|
|
20613
|
-
if (book && typeof book.destroy ===
|
|
21203
|
+
if (book && typeof book.destroy === 'function') {
|
|
20614
21204
|
book.destroy();
|
|
20615
21205
|
}
|
|
20616
21206
|
|
|
20617
|
-
|
|
20618
|
-
|
|
20619
|
-
|
|
20620
|
-
|
|
20621
|
-
|
|
20622
|
-
|
|
20623
|
-
);
|
|
20624
|
-
|
|
20625
|
-
log("epub.load:fetch-uri");
|
|
20626
|
-
const data = await withTimeout(
|
|
20627
|
-
fetchUriAsArrayBuffer(source.uri),
|
|
20628
|
-
EPUB_OPEN_TIMEOUT_MS,
|
|
20629
|
-
"epub.fetch"
|
|
20630
|
-
);
|
|
20631
|
-
const input = data instanceof Uint8Array ? data.buffer : data;
|
|
20632
|
-
book = ePub(input, { openAs: "epub" });
|
|
20633
|
-
} else {
|
|
20634
|
-
let data = null;
|
|
20635
|
-
if (source.kind === "text") {
|
|
20636
|
-
const encoder = new TextEncoder();
|
|
20637
|
-
data = encoder.encode(source.text || "").buffer;
|
|
20638
|
-
}
|
|
20639
|
-
const input = data instanceof Uint8Array ? data.buffer : data;
|
|
20640
|
-
book = ePub(input, { openAs: "epub" });
|
|
20641
|
-
}
|
|
20642
|
-
if (book && book.opened) {
|
|
20643
|
-
await withTimeout(book.opened, EPUB_OPEN_TIMEOUT_MS, "epub.opened");
|
|
21207
|
+
let data = null;
|
|
21208
|
+
if (source.kind === 'uri') {
|
|
21209
|
+
data = source.uri;
|
|
21210
|
+
} else if (source.kind === 'base64') {
|
|
21211
|
+
data = decodeBase64(source.data);
|
|
21212
|
+
} else if (source.kind === 'text') {
|
|
21213
|
+
const encoder = new TextEncoder();
|
|
21214
|
+
data = encoder.encode(source.text || '').buffer;
|
|
20644
21215
|
}
|
|
20645
|
-
|
|
20646
|
-
|
|
21216
|
+
|
|
21217
|
+
book = ePub(data);
|
|
21218
|
+
await book.ready;
|
|
20647
21219
|
|
|
20648
21220
|
spineItems = book.spine && book.spine.items ? book.spine.items : [];
|
|
20649
21221
|
pageCount = spineItems.length;
|
|
@@ -20651,64 +21223,38 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20651
21223
|
|
|
20652
21224
|
clearViewer();
|
|
20653
21225
|
rendition = book.renderTo(viewer, {
|
|
20654
|
-
width:
|
|
20655
|
-
height:
|
|
20656
|
-
flow:
|
|
20657
|
-
spread:
|
|
21226
|
+
width: '100%',
|
|
21227
|
+
height: '100%',
|
|
21228
|
+
flow: 'paginated',
|
|
21229
|
+
spread: 'none',
|
|
20658
21230
|
});
|
|
20659
21231
|
|
|
20660
21232
|
if (rendition && rendition.hooks && rendition.hooks.content) {
|
|
20661
21233
|
rendition.hooks.content.register((contents) => {
|
|
20662
|
-
const frame =
|
|
20663
|
-
contents && contents.document
|
|
20664
|
-
? contents.document.defaultView.frameElement
|
|
20665
|
-
: null;
|
|
21234
|
+
const frame = contents && contents.document ? contents.document.defaultView.frameElement : null;
|
|
20666
21235
|
if (frame) {
|
|
20667
|
-
frame.setAttribute(
|
|
20668
|
-
"sandbox",
|
|
20669
|
-
"allow-scripts allow-same-origin"
|
|
20670
|
-
);
|
|
21236
|
+
frame.setAttribute('sandbox', 'allow-scripts allow-same-origin');
|
|
20671
21237
|
}
|
|
20672
21238
|
});
|
|
20673
21239
|
}
|
|
20674
21240
|
|
|
20675
|
-
if (rendition && typeof rendition.on ===
|
|
20676
|
-
rendition.on(
|
|
20677
|
-
const selection =
|
|
20678
|
-
|
|
20679
|
-
? contents.window.getSelection()
|
|
20680
|
-
: null;
|
|
20681
|
-
const text = selection ? selection.toString().trim() : "";
|
|
21241
|
+
if (rendition && typeof rendition.on === 'function') {
|
|
21242
|
+
rendition.on('selected', (cfiRange, contents) => {
|
|
21243
|
+
const selection = contents && contents.window ? contents.window.getSelection() : null;
|
|
21244
|
+
const text = selection ? selection.toString().trim() : '';
|
|
20682
21245
|
if (text) {
|
|
20683
|
-
sendEvent(
|
|
20684
|
-
text,
|
|
20685
|
-
pageIndex: Math.max(0, currentPage - 1),
|
|
20686
|
-
});
|
|
21246
|
+
sendEvent('TEXT_SELECTED', { text, pageIndex: Math.max(0, currentPage - 1) });
|
|
20687
21247
|
}
|
|
20688
|
-
if (
|
|
20689
|
-
rendition
|
|
20690
|
-
rendition.annotations &&
|
|
20691
|
-
typeof rendition.annotations.remove === "function"
|
|
20692
|
-
) {
|
|
20693
|
-
rendition.annotations.remove(cfiRange, "highlight");
|
|
21248
|
+
if (rendition && rendition.annotations && typeof rendition.annotations.remove === 'function') {
|
|
21249
|
+
rendition.annotations.remove(cfiRange, 'highlight');
|
|
20694
21250
|
}
|
|
20695
21251
|
});
|
|
20696
21252
|
}
|
|
20697
21253
|
|
|
20698
|
-
|
|
20699
|
-
await withTimeout(
|
|
20700
|
-
displayEpubPage(0),
|
|
20701
|
-
EPUB_DISPLAY_TIMEOUT_MS,
|
|
20702
|
-
"epub.display"
|
|
20703
|
-
);
|
|
20704
|
-
log("epub.load:displayed");
|
|
20705
|
-
} catch (err) {
|
|
20706
|
-
reportError(err, "epub.display");
|
|
20707
|
-
}
|
|
21254
|
+
await displayEpubPage(0);
|
|
20708
21255
|
applyEpubZoom();
|
|
20709
21256
|
|
|
20710
21257
|
const outline = await buildOutline();
|
|
20711
|
-
log("epub.load:outline", outline.length);
|
|
20712
21258
|
return { pageCount, outline };
|
|
20713
21259
|
};
|
|
20714
21260
|
|
|
@@ -20723,41 +21269,34 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20723
21269
|
};
|
|
20724
21270
|
|
|
20725
21271
|
const getTextContent = async (pageIndex) => {
|
|
20726
|
-
if (currentType ===
|
|
20727
|
-
const text = textPages[pageIndex] ||
|
|
20728
|
-
return [
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
|
|
20732
|
-
|
|
20733
|
-
|
|
20734
|
-
|
|
20735
|
-
|
|
20736
|
-
},
|
|
20737
|
-
];
|
|
21272
|
+
if (currentType === 'text') {
|
|
21273
|
+
const text = textPages[pageIndex] || '';
|
|
21274
|
+
return [{
|
|
21275
|
+
str: text,
|
|
21276
|
+
dir: 'ltr',
|
|
21277
|
+
width: 0,
|
|
21278
|
+
height: 0,
|
|
21279
|
+
transform: [1, 0, 0, 1, 0, 0],
|
|
21280
|
+
fontName: 'default',
|
|
21281
|
+
}];
|
|
20738
21282
|
}
|
|
20739
21283
|
|
|
20740
|
-
if (currentType ===
|
|
21284
|
+
if (currentType === 'epub') {
|
|
20741
21285
|
if (!book) return [];
|
|
20742
21286
|
const item = spineItems[pageIndex];
|
|
20743
21287
|
if (!item) return [];
|
|
20744
21288
|
try {
|
|
20745
21289
|
const section = book.spine.get(item.idref || item.href);
|
|
20746
|
-
const text =
|
|
20747
|
-
section && typeof section.text === "function"
|
|
20748
|
-
? await section.text()
|
|
20749
|
-
: "";
|
|
21290
|
+
const text = section && typeof section.text === 'function' ? await section.text() : '';
|
|
20750
21291
|
if (!text) return [];
|
|
20751
|
-
return [
|
|
20752
|
-
|
|
20753
|
-
|
|
20754
|
-
|
|
20755
|
-
|
|
20756
|
-
|
|
20757
|
-
|
|
20758
|
-
|
|
20759
|
-
},
|
|
20760
|
-
];
|
|
21292
|
+
return [{
|
|
21293
|
+
str: text,
|
|
21294
|
+
dir: 'ltr',
|
|
21295
|
+
width: 0,
|
|
21296
|
+
height: 0,
|
|
21297
|
+
transform: [1, 0, 0, 1, 0, 0],
|
|
21298
|
+
fontName: 'default',
|
|
21299
|
+
}];
|
|
20761
21300
|
} catch (err) {
|
|
20762
21301
|
return [];
|
|
20763
21302
|
}
|
|
@@ -20768,7 +21307,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20768
21307
|
|
|
20769
21308
|
const getPageText = async (pageIndex) => {
|
|
20770
21309
|
const items = await getTextContent(pageIndex);
|
|
20771
|
-
return items.map((item) => item.str).join(
|
|
21310
|
+
return items.map((item) => item.str).join(' ');
|
|
20772
21311
|
};
|
|
20773
21312
|
|
|
20774
21313
|
const searchText = async (query) => {
|
|
@@ -20784,11 +21323,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20784
21323
|
while (pos !== -1) {
|
|
20785
21324
|
const start = Math.max(0, pos - 20);
|
|
20786
21325
|
const end = Math.min(text.length, pos + query.length + 20);
|
|
20787
|
-
results.push({
|
|
20788
|
-
pageIndex: i,
|
|
20789
|
-
text: text.substring(start, end),
|
|
20790
|
-
matchIndex,
|
|
20791
|
-
});
|
|
21326
|
+
results.push({ pageIndex: i, text: text.substring(start, end), matchIndex });
|
|
20792
21327
|
matchIndex += 1;
|
|
20793
21328
|
pos = lower.indexOf(normalized, pos + 1);
|
|
20794
21329
|
}
|
|
@@ -20804,11 +21339,11 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20804
21339
|
|
|
20805
21340
|
const getPageIndex = (dest) => {
|
|
20806
21341
|
if (!dest) return null;
|
|
20807
|
-
if (typeof dest ===
|
|
20808
|
-
if (typeof dest !==
|
|
20809
|
-
if (dest.kind ===
|
|
20810
|
-
if (dest.kind ===
|
|
20811
|
-
if (dest.kind ===
|
|
21342
|
+
if (typeof dest === 'string') return getSpineIndexByHref(dest);
|
|
21343
|
+
if (typeof dest !== 'object') return null;
|
|
21344
|
+
if (dest.kind === 'href') return getSpineIndexByHref(dest.value);
|
|
21345
|
+
if (dest.kind === 'pageIndex') return dest.value;
|
|
21346
|
+
if (dest.kind === 'pageNumber') return Math.max(0, dest.value - 1);
|
|
20812
21347
|
return null;
|
|
20813
21348
|
};
|
|
20814
21349
|
|
|
@@ -20822,53 +21357,70 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20822
21357
|
};
|
|
20823
21358
|
|
|
20824
21359
|
const applyZoom = () => {
|
|
20825
|
-
if (currentType ===
|
|
21360
|
+
if (currentType === 'text') {
|
|
20826
21361
|
applyTextZoom();
|
|
20827
|
-
} else if (currentType ===
|
|
21362
|
+
} else if (currentType === 'epub') {
|
|
20828
21363
|
applyEpubZoom();
|
|
21364
|
+
} else if (currentType === 'comic') {
|
|
21365
|
+
applyComicLayout();
|
|
20829
21366
|
}
|
|
20830
21367
|
};
|
|
20831
21368
|
|
|
20832
21369
|
const handleCommand = async (message) => {
|
|
20833
21370
|
const { id, kind, payload } = message;
|
|
20834
|
-
log("command", kind);
|
|
20835
21371
|
|
|
20836
21372
|
try {
|
|
20837
|
-
if (kind ===
|
|
21373
|
+
if (kind === 'load') {
|
|
20838
21374
|
currentType = payload.type;
|
|
20839
21375
|
zoom = 1.0;
|
|
20840
21376
|
|
|
20841
|
-
if (currentType ===
|
|
21377
|
+
if (currentType === 'text') {
|
|
20842
21378
|
const result = await loadText(payload.source);
|
|
20843
21379
|
sendState();
|
|
20844
21380
|
sendResponse(id, true, result);
|
|
20845
21381
|
return;
|
|
20846
21382
|
}
|
|
20847
21383
|
|
|
20848
|
-
if (currentType ===
|
|
21384
|
+
if (currentType === 'epub') {
|
|
20849
21385
|
const result = await loadEpub(payload.source);
|
|
20850
21386
|
sendState({ outline: result.outline || [] });
|
|
20851
21387
|
sendResponse(id, true, result);
|
|
20852
21388
|
return;
|
|
20853
21389
|
}
|
|
20854
21390
|
|
|
20855
|
-
|
|
21391
|
+
if (currentType === 'comic') {
|
|
21392
|
+
const result = await loadComic(payload.source, payload.format || 'cbz');
|
|
21393
|
+
sendState();
|
|
21394
|
+
sendResponse(id, true, result);
|
|
21395
|
+
return;
|
|
21396
|
+
}
|
|
21397
|
+
|
|
21398
|
+
throw new Error('Unsupported document type');
|
|
20856
21399
|
}
|
|
20857
21400
|
|
|
20858
|
-
if (kind ===
|
|
21401
|
+
if (kind === 'go-to-page') {
|
|
20859
21402
|
const page = Math.max(1, payload.page || 1);
|
|
20860
|
-
if (currentType ===
|
|
21403
|
+
if (currentType === 'text') {
|
|
20861
21404
|
currentPage = page;
|
|
20862
21405
|
renderTextPage(page - 1);
|
|
20863
21406
|
sendState();
|
|
20864
|
-
} else if (currentType ===
|
|
21407
|
+
} else if (currentType === 'epub') {
|
|
20865
21408
|
await displayEpubPage(page - 1);
|
|
21409
|
+
} else if (currentType === 'comic') {
|
|
21410
|
+
currentPage = page;
|
|
21411
|
+
const target = comicPages[page - 1];
|
|
21412
|
+
if (target) {
|
|
21413
|
+
await ensureComicPage(page - 1);
|
|
21414
|
+
target.scrollIntoView({ block: 'start' });
|
|
21415
|
+
renderComicPage(page - 1);
|
|
21416
|
+
sendState();
|
|
21417
|
+
}
|
|
20866
21418
|
}
|
|
20867
21419
|
sendResponse(id, true, { currentPage });
|
|
20868
21420
|
return;
|
|
20869
21421
|
}
|
|
20870
21422
|
|
|
20871
|
-
if (kind ===
|
|
21423
|
+
if (kind === 'set-zoom') {
|
|
20872
21424
|
zoom = Math.max(0.5, Math.min(4.0, payload.zoom || 1.0));
|
|
20873
21425
|
applyZoom();
|
|
20874
21426
|
sendState();
|
|
@@ -20876,103 +21428,132 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20876
21428
|
return;
|
|
20877
21429
|
}
|
|
20878
21430
|
|
|
20879
|
-
if (kind ===
|
|
21431
|
+
if (kind === 'set-rotation') {
|
|
21432
|
+
rotation = ((payload.rotation || 0) % 360 + 360) % 360;
|
|
21433
|
+
if (currentType === 'comic') applyComicLayout();
|
|
20880
21434
|
sendResponse(id, true, {});
|
|
20881
21435
|
return;
|
|
20882
21436
|
}
|
|
20883
21437
|
|
|
20884
|
-
if (kind ===
|
|
21438
|
+
if (kind === 'get-text-content') {
|
|
20885
21439
|
const items = await getTextContent(payload.pageIndex || 0);
|
|
20886
21440
|
sendResponse(id, true, items);
|
|
20887
21441
|
return;
|
|
20888
21442
|
}
|
|
20889
21443
|
|
|
20890
|
-
if (kind ===
|
|
20891
|
-
|
|
21444
|
+
if (kind === 'get-page-dimensions') {
|
|
21445
|
+
if (currentType === 'comic') {
|
|
21446
|
+
sendResponse(
|
|
21447
|
+
id,
|
|
21448
|
+
true,
|
|
21449
|
+
await getComicPageDimensions(payload.pageIndex || 0)
|
|
21450
|
+
);
|
|
21451
|
+
} else {
|
|
21452
|
+
sendResponse(id, true, getPageDimensions());
|
|
21453
|
+
}
|
|
21454
|
+
return;
|
|
21455
|
+
}
|
|
21456
|
+
|
|
21457
|
+
if (kind === 'get-page-preview') {
|
|
21458
|
+
if (currentType !== 'comic') {
|
|
21459
|
+
sendResponse(id, true, null);
|
|
21460
|
+
return;
|
|
21461
|
+
}
|
|
21462
|
+
sendResponse(
|
|
21463
|
+
id,
|
|
21464
|
+
true,
|
|
21465
|
+
await getComicPagePreview(payload.pageIndex || 0)
|
|
21466
|
+
);
|
|
20892
21467
|
return;
|
|
20893
21468
|
}
|
|
20894
21469
|
|
|
20895
|
-
if (kind ===
|
|
20896
|
-
const results = await searchText(payload.query ||
|
|
21470
|
+
if (kind === 'search-text') {
|
|
21471
|
+
const results = await searchText(payload.query || '');
|
|
20897
21472
|
sendResponse(id, true, results);
|
|
20898
21473
|
return;
|
|
20899
21474
|
}
|
|
20900
21475
|
|
|
20901
|
-
if (kind ===
|
|
21476
|
+
if (kind === 'select-text') {
|
|
20902
21477
|
const selection = await selectText(payload.pageIndex || 0);
|
|
20903
21478
|
sendResponse(id, true, selection);
|
|
20904
21479
|
return;
|
|
20905
21480
|
}
|
|
20906
21481
|
|
|
20907
|
-
if (kind ===
|
|
21482
|
+
if (kind === 'get-outline') {
|
|
20908
21483
|
const outline = await buildOutline();
|
|
20909
21484
|
sendResponse(id, true, outline);
|
|
20910
21485
|
return;
|
|
20911
21486
|
}
|
|
20912
21487
|
|
|
20913
|
-
if (kind ===
|
|
21488
|
+
if (kind === 'get-page-index') {
|
|
20914
21489
|
const index = getPageIndex(payload.dest);
|
|
20915
21490
|
sendResponse(id, true, index);
|
|
20916
21491
|
return;
|
|
20917
21492
|
}
|
|
20918
21493
|
|
|
20919
|
-
if (kind ===
|
|
21494
|
+
if (kind === 'destroy') {
|
|
20920
21495
|
clearViewer();
|
|
20921
21496
|
sendResponse(id, true, {});
|
|
20922
21497
|
return;
|
|
20923
21498
|
}
|
|
20924
21499
|
|
|
20925
|
-
sendResponse(id, false, null,
|
|
21500
|
+
sendResponse(id, false, null, 'Unknown command');
|
|
20926
21501
|
} catch (err) {
|
|
20927
|
-
sendResponse(
|
|
20928
|
-
id,
|
|
20929
|
-
false,
|
|
20930
|
-
null,
|
|
20931
|
-
err && err.message ? err.message : String(err)
|
|
20932
|
-
);
|
|
21502
|
+
sendResponse(id, false, null, err && err.message ? err.message : String(err));
|
|
20933
21503
|
}
|
|
20934
21504
|
};
|
|
20935
21505
|
|
|
20936
21506
|
const onMessage = (event) => {
|
|
20937
21507
|
let message = null;
|
|
20938
|
-
const raw = event && typeof event ===
|
|
21508
|
+
const raw = event && typeof event === 'object' ? event.data : null;
|
|
20939
21509
|
|
|
20940
|
-
if (raw && typeof raw ===
|
|
21510
|
+
if (raw && typeof raw === 'object' && (raw.kind || raw.type) && raw.id) {
|
|
20941
21511
|
message = raw;
|
|
20942
|
-
} else if (typeof raw ===
|
|
20943
|
-
if (raw.startsWith(
|
|
20944
|
-
return;
|
|
20945
|
-
}
|
|
21512
|
+
} else if (typeof raw === 'string') {
|
|
21513
|
+
if (raw.startsWith('setImmediate$')) return;
|
|
20946
21514
|
const trimmed = raw.trim();
|
|
20947
|
-
if (
|
|
20948
|
-
!trimmed ||
|
|
20949
|
-
(!trimmed.startsWith("{") && !trimmed.startsWith("["))
|
|
20950
|
-
) {
|
|
21515
|
+
if (!trimmed || (!trimmed.startsWith('{') && !trimmed.startsWith('['))) {
|
|
20951
21516
|
return;
|
|
20952
21517
|
}
|
|
20953
21518
|
try {
|
|
20954
21519
|
message = JSON.parse(trimmed);
|
|
20955
21520
|
} catch (err) {
|
|
20956
|
-
sendEvent("RUNTIME_ERROR", {
|
|
20957
|
-
message: "Failed to parse message",
|
|
20958
|
-
context: "runtime.onMessage",
|
|
20959
|
-
stack: err && err.stack ? err.stack : null,
|
|
20960
|
-
preview: trimmed.slice(0, 200),
|
|
20961
|
-
});
|
|
20962
21521
|
return;
|
|
20963
21522
|
}
|
|
20964
21523
|
} else {
|
|
20965
21524
|
return;
|
|
20966
21525
|
}
|
|
20967
21526
|
|
|
20968
|
-
|
|
20969
|
-
|
|
21527
|
+
if (!message || message.id == null) return;
|
|
21528
|
+
|
|
21529
|
+
if (message.type === 'asset-response') {
|
|
21530
|
+
const pending = runtimeAssetRequests.get(message.id);
|
|
21531
|
+
if (!pending) return;
|
|
21532
|
+
runtimeAssetRequests.delete(message.id);
|
|
21533
|
+
clearTimeout(pending.timeout);
|
|
21534
|
+
if (message.ok) pending.resolve(message.data);
|
|
21535
|
+
else pending.reject(new Error(message.error || 'Falha ao carregar asset CBR.'));
|
|
21536
|
+
return;
|
|
21537
|
+
}
|
|
21538
|
+
|
|
21539
|
+
if (message.type === 'file-chunk-response') {
|
|
21540
|
+
const pending = fileChunkRequests.get(message.id);
|
|
21541
|
+
if (!pending) return;
|
|
21542
|
+
fileChunkRequests.delete(message.id);
|
|
21543
|
+
clearTimeout(pending.timeout);
|
|
21544
|
+
if (message.ok) pending.resolve(message);
|
|
21545
|
+
else pending.reject(new Error(message.error || 'Falha ao ler arquivo local.'));
|
|
21546
|
+
return;
|
|
21547
|
+
}
|
|
21548
|
+
|
|
21549
|
+
if (!message.kind) return;
|
|
21550
|
+
handleCommand(message);
|
|
20970
21551
|
};
|
|
20971
21552
|
|
|
20972
|
-
window.addEventListener(
|
|
20973
|
-
document.addEventListener(
|
|
21553
|
+
window.addEventListener('message', onMessage);
|
|
21554
|
+
document.addEventListener('message', onMessage);
|
|
20974
21555
|
|
|
20975
|
-
sendMessage({ type:
|
|
21556
|
+
sendMessage({ type: 'ready' });
|
|
20976
21557
|
})();
|
|
20977
21558
|
</script>
|
|
20978
21559
|
</body>
|