@papyrus-sdk/ui-react-native 0.2.35-beta.11 → 0.2.35-beta.11.epub.1
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/LICENSE +21 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +371 -231
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +315 -175
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -13
- package/runtime/epubAnnotations.js +7 -4
- package/runtime/epubAnnotations.test.ts +6 -2
- package/runtime/epubReader.js +33 -0
- package/runtime/epubReader.test.ts +22 -0
- package/runtime/epubRuntime.test.ts +45 -0
- package/runtime/index.html +134 -91
- package/runtime/runtime.js +134 -91
- package/runtime/syncComicRuntime.mjs +6 -3
package/runtime/runtime.js
CHANGED
|
@@ -109,6 +109,42 @@
|
|
|
109
109
|
/* @papyrus-comic-runtime:end */
|
|
110
110
|
|
|
111
111
|
(function () {
|
|
112
|
+
/* @papyrus-epub-reader:start */
|
|
113
|
+
(function(root){
|
|
114
|
+
function mode(value){return value==='chapter-scroll'?'chapter-scroll':'paged';}
|
|
115
|
+
function validCfi(value){return typeof value==='string' && value.length<=4096 && /^epubcfi\([^\n<>]+\)$/.test(value);}
|
|
116
|
+
function options(value){return {manager:'default',flow:mode(value)==='paged'?'paginated':'scrolled-doc',spread:'none',width:'100%',height:'100%',allowScriptedContent:false};}
|
|
117
|
+
function gesture(start,end,state){
|
|
118
|
+
if(!start || !end || state.selected || state.interactive || state.multitouch)return null;
|
|
119
|
+
var dx=end.x-start.x,dy=end.y-start.y,elapsed=end.time-start.time;
|
|
120
|
+
if(state.mode==='paged' && Math.abs(dx)>=48 && Math.abs(dx)>Math.abs(dy)*1.5 && elapsed>=0 && elapsed<1500)return (dx<0)!==Boolean(state.rtl)?'next':'prev';
|
|
121
|
+
if(elapsed>=0 && elapsed<450 && Math.hypot(dx,dy)<=12)return 'tap';
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function location(raw,count,readingMode){
|
|
125
|
+
var start=raw && raw.start;if(!start || !validCfi(start.cfi))return null;
|
|
126
|
+
var displayed=start.displayed||{},chapter=Math.max(1,(Number(start.index)||0)+1);
|
|
127
|
+
var visualPage=mode(readingMode)==='paged' && Number.isFinite(displayed.page)?displayed.page:null;
|
|
128
|
+
var total=mode(readingMode)==='paged' && Number.isFinite(displayed.total)?displayed.total:null;
|
|
129
|
+
var fraction=total?Math.max(0,(visualPage-1)/total):0;
|
|
130
|
+
return {version:1,cfi:start.cfi,href:start.href||'',chapter:chapter,chapterCount:count,visualPage:visualPage,visualPageCount:total,progress:Math.min(1,Math.max(0,(chapter-1+fraction)/Math.max(1,count))),mode:mode(readingMode),atStart:Boolean(raw.atStart),atEnd:Boolean(raw.atEnd)};
|
|
131
|
+
}
|
|
132
|
+
function install(contents,config){
|
|
133
|
+
var doc=contents.document,win=contents.window,start=null,blocked=false;
|
|
134
|
+
function point(e){var t=e.changedTouches&&e.changedTouches[0]||e.touches&&e.touches[0];return t?{x:t.clientX,y:t.clientY,time:Date.now()}:null;}
|
|
135
|
+
function selected(){return Boolean(String(win.getSelection()||'').trim()) || config.blocked();}
|
|
136
|
+
function interactive(target){return Boolean(target && target.closest && target.closest('a,button,input,textarea,select,[contenteditable="true"],[data-papyrus-overlay]'));}
|
|
137
|
+
function begin(e){start=point(e);blocked=e.touches.length!==1 || selected() || interactive(e.target);}
|
|
138
|
+
function move(e){if(e.touches.length!==1)blocked=true;}
|
|
139
|
+
function end(e){var action=gesture(start,point(e),{mode:config.mode(),rtl:config.rtl(),selected:selected(),interactive:blocked||interactive(e.target)||Boolean(config.annotationHit && config.annotationHit(point(e))),multitouch:blocked});start=null;if(!config.current())return;if(action==='tap')config.tap();else if(action)config.turn(action==='next'?1:-1);}
|
|
140
|
+
function cancel(){start=null;blocked=true;}
|
|
141
|
+
doc.addEventListener('touchstart',begin,{passive:true});doc.addEventListener('touchmove',move,{passive:true});doc.addEventListener('touchend',end,{passive:true});doc.addEventListener('touchcancel',cancel,{passive:true});
|
|
142
|
+
return function(){doc.removeEventListener('touchstart',begin);doc.removeEventListener('touchmove',move);doc.removeEventListener('touchend',end);doc.removeEventListener('touchcancel',cancel);};
|
|
143
|
+
}
|
|
144
|
+
root.PapyrusEpubReader={mode:mode,validCfi:validCfi,options:options,gesture:gesture,location:location,install:install};
|
|
145
|
+
})(typeof window==='undefined'?globalThis:window);
|
|
146
|
+
|
|
147
|
+
/* @papyrus-epub-reader:end */
|
|
112
148
|
/* @papyrus-epub-annotations:start */
|
|
113
149
|
(function (root, factory) {
|
|
114
150
|
if (typeof module === 'object' && module.exports) module.exports = factory();
|
|
@@ -187,6 +223,7 @@
|
|
|
187
223
|
var color = /^#[0-9a-f]{6}$/i.test(annotation.color) ? annotation.color : '#FFC928';
|
|
188
224
|
var style = annotation.markupStyle || annotation.type;
|
|
189
225
|
var opacity = Number.isFinite(annotation.opacity) ? Math.max(0,Math.min(1,annotation.opacity)) : 0.35;
|
|
226
|
+
if(style === 'highlight')opacity=Math.min(0.35,opacity);
|
|
190
227
|
rects.forEach(function(rect) {
|
|
191
228
|
var mark = doc.createElement('div');
|
|
192
229
|
var bodyRect=doc.body.getBoundingClientRect();
|
|
@@ -199,8 +236,10 @@
|
|
|
199
236
|
if (hasNote) {
|
|
200
237
|
var last = rects[rects.length-1], button = doc.createElement('button');
|
|
201
238
|
button.textContent = '●'; button.setAttribute('aria-label',options.labels().comment || '');
|
|
202
|
-
|
|
203
|
-
var
|
|
239
|
+
var pageWidth=Math.max(44, options.pageWidth ? options.pageWidth() : win.innerWidth);
|
|
240
|
+
var bodyRect=doc.body.getBoundingClientRect(), column=Math.max(0,Math.floor((last.left-bodyRect.left)/pageWidth));
|
|
241
|
+
button.style.cssText = 'position:absolute;pointer-events:auto;border:0;background:transparent;color:'+color+';width:44px;height:44px;left:'+((column+1)*pageWidth-44)+'px;top:'+(Math.floor(last.top/44)*44-doc.body.getBoundingClientRect().top)+'px';
|
|
242
|
+
var key = column+":"+Math.floor(last.top/44);
|
|
204
243
|
var neighbors=noteGroups.get(key);
|
|
205
244
|
if(!neighbors){neighbors={button:button,ids:[]};noteGroups.set(key,neighbors);group.appendChild(button);}
|
|
206
245
|
neighbors.ids.push(annotation.id);
|
|
@@ -221,10 +260,10 @@
|
|
|
221
260
|
doc.addEventListener('click',tapMarkup);
|
|
222
261
|
var observer = typeof win.ResizeObserver === 'function' ? new win.ResizeObserver(schedule) : null;
|
|
223
262
|
if (observer) observer.observe(doc.body);
|
|
224
|
-
win.addEventListener('resize',schedule); doc.addEventListener('load',schedule,true);
|
|
263
|
+
win.addEventListener('resize',schedule);win.addEventListener('scroll',schedule); doc.addEventListener('load',schedule,true);
|
|
225
264
|
if (doc.fonts && doc.fonts.ready) doc.fonts.ready.then(schedule);
|
|
226
265
|
schedule();
|
|
227
|
-
return {schedule:schedule, range:function(anchor){return resolveRange(contents,anchor);}, destroy:function(){alive=false;if(frame)win.cancelAnimationFrame(frame);if(observer)observer.disconnect();win.removeEventListener('resize',schedule);doc.removeEventListener('load',schedule,true);doc.removeEventListener('click',tapMarkup);overlay.remove();doc.body.style.position=originalPosition;registry.clear();}};
|
|
266
|
+
return {schedule:schedule, hit:function(x,y){return hitRegions.some(function(item){return item.rects.some(function(r){return x>=r.left && x<=r.right && y>=r.top && y<=r.bottom;});});}, range:function(anchor){return resolveRange(contents,anchor);}, destroy:function(){alive=false;if(frame)win.cancelAnimationFrame(frame);if(observer)observer.disconnect();win.removeEventListener('resize',schedule);win.removeEventListener('scroll',schedule);doc.removeEventListener('load',schedule,true);doc.removeEventListener('click',tapMarkup);overlay.remove();doc.body.style.position=originalPosition;registry.clear();}};
|
|
228
267
|
}
|
|
229
268
|
return {validAnchor:validAnchor,recoverRange:recoverRange,resolveRange:resolveRange,selection:selection,install:install};
|
|
230
269
|
});
|
|
@@ -1305,26 +1344,55 @@
|
|
|
1305
1344
|
pageCount,
|
|
1306
1345
|
});
|
|
1307
1346
|
|
|
1347
|
+
if (book.locations?.generate) {
|
|
1348
|
+
const activeBook=book;
|
|
1349
|
+
activeBook.locations.generate(150).then(() => {
|
|
1350
|
+
if (isCurrentLoad() && activeBook===book && epubLocation) {
|
|
1351
|
+
epubLocation.progress=activeBook.locations.percentageFromCfi(epubLocation.cfi);
|
|
1352
|
+
sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
|
|
1353
|
+
}
|
|
1354
|
+
}).catch(() => {});
|
|
1355
|
+
}
|
|
1356
|
+
return renderEpubRendition(loadId,generation,null);
|
|
1357
|
+
};
|
|
1358
|
+
|
|
1359
|
+
const renderEpubRendition = async (loadId,generation,target) => {
|
|
1360
|
+
const diagnosticPayload={loadId};
|
|
1361
|
+
const isCurrentLoad=()=>generation===epubLoadGeneration;
|
|
1362
|
+
if(epubInteractionCleanup)epubInteractionCleanup();
|
|
1363
|
+
if(rendition)rendition.destroy();
|
|
1308
1364
|
clearViewer();
|
|
1309
|
-
rendition = book.renderTo(viewer,
|
|
1310
|
-
manager: 'continuous',
|
|
1311
|
-
allowScriptedContent: false,
|
|
1312
|
-
width: '100%',
|
|
1313
|
-
height: '100%',
|
|
1314
|
-
flow: 'scrolled-continuous',
|
|
1315
|
-
spread: 'none',
|
|
1316
|
-
});
|
|
1365
|
+
rendition = book.renderTo(viewer, window.PapyrusEpubReader.options(epubViewMode === 'single' ? 'paged' : 'chapter-scroll'));
|
|
1317
1366
|
sendEpubDiagnostic('epub.rendition.created', diagnosticPayload);
|
|
1318
1367
|
|
|
1319
1368
|
if (rendition && rendition.hooks && rendition.hooks.content) {
|
|
1320
1369
|
const session = documentSessionId;
|
|
1321
1370
|
const activeRendition = rendition;
|
|
1322
1371
|
rendition.hooks.content.register((contents) => {
|
|
1372
|
+
const removeGestureListeners = window.PapyrusEpubReader.install(contents, {
|
|
1373
|
+
mode: () => epubViewMode === 'single' ? 'paged' : 'chapter-scroll',
|
|
1374
|
+
rtl: () => book.package?.metadata?.direction === 'rtl' || book.spine?.direction === 'rtl',
|
|
1375
|
+
blocked: () => Boolean(nativeMenuSelection && String(nativeMenuSelection.contents?.window?.getSelection() || '').trim()),
|
|
1376
|
+
annotationHit: point => epubAnnotationRenderers.get(contents)?.hit(point.x,point.y),
|
|
1377
|
+
current: () => session === documentSessionId && activeRendition === rendition,
|
|
1378
|
+
tap: () => sendEvent('EPUB_CONTENT_TAP',{documentSessionId:session}),
|
|
1379
|
+
turn: direction => {
|
|
1380
|
+
epubNavigationQueue = epubNavigationQueue.catch(()=>{}).then(() => {
|
|
1381
|
+
if(session !== documentSessionId || activeRendition !== rendition)return;
|
|
1382
|
+
return direction<0?activeRendition.prev():activeRendition.next();
|
|
1383
|
+
});
|
|
1384
|
+
epubNavigationQueue.catch(error => sendEvent('EPUB_NAVIGATION_ERROR',{message:String(error)}));
|
|
1385
|
+
},
|
|
1386
|
+
});
|
|
1387
|
+
const gestureCleanup = () => {removeGestureListeners();epubSelectionCleanups.delete(gestureCleanup);};
|
|
1388
|
+
epubSelectionCleanups.add(gestureCleanup);
|
|
1389
|
+
contents.__papyrusGestureCleanup=gestureCleanup;
|
|
1323
1390
|
const href = spineItems[contents.sectionIndex]?.href;
|
|
1324
1391
|
if (href && window.PapyrusEpubAnnotations) {
|
|
1325
1392
|
const renderer = window.PapyrusEpubAnnotations.install(contents, {
|
|
1326
1393
|
href, get documentId() { return annotationDocumentId; },
|
|
1327
1394
|
isCurrent: () => session === documentSessionId && activeRendition === rendition,
|
|
1395
|
+
pageWidth: () => activeRendition.layout?.width || viewer.clientWidth,
|
|
1328
1396
|
annotations: () => epubAnnotations, labels: () => annotationLabels,
|
|
1329
1397
|
onTap: (id, ids) => sendEvent("EPUB_ANNOTATION_TAP", {documentSessionId: session, id, ids}),
|
|
1330
1398
|
});
|
|
@@ -1343,8 +1411,7 @@
|
|
|
1343
1411
|
typeof selectionWindow.getSelection === 'function'
|
|
1344
1412
|
) {
|
|
1345
1413
|
let selectionTimer = null;
|
|
1346
|
-
|
|
1347
|
-
let lastSelectionAt = 0;
|
|
1414
|
+
|
|
1348
1415
|
const reportSelection = () => {
|
|
1349
1416
|
selectionTimer = null;
|
|
1350
1417
|
if (session !== documentSessionId || activeRendition !== rendition) return;
|
|
@@ -1359,11 +1426,7 @@
|
|
|
1359
1426
|
try { cfi = contents.cfiFromRange(range); } catch (_) { return; }
|
|
1360
1427
|
const anchor = window.PapyrusEpubAnnotations?.selection(contents, cfi, href, annotationDocumentId);
|
|
1361
1428
|
if (!anchor) return;
|
|
1362
|
-
|
|
1363
|
-
const now = Date.now();
|
|
1364
|
-
if (key === lastSelectionKey && now - lastSelectionAt < 750) return;
|
|
1365
|
-
lastSelectionKey = key;
|
|
1366
|
-
lastSelectionAt = now;
|
|
1429
|
+
if (nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
|
|
1367
1430
|
const payload = {documentSessionId: session, text: anchor.quote,
|
|
1368
1431
|
pageIndex: contents.sectionIndex + 1, anchor};
|
|
1369
1432
|
nativeMenuSelection = {contents, payload};
|
|
@@ -1378,6 +1441,7 @@
|
|
|
1378
1441
|
// The content document still emits selectionchange, so resolve its
|
|
1379
1442
|
// live Range to a CFI before the native menu action can fire.
|
|
1380
1443
|
if (text) reportSelection();
|
|
1444
|
+
else if (nativeMenuSelection?.contents === contents) nativeMenuSelection = null;
|
|
1381
1445
|
};
|
|
1382
1446
|
selectionDocument.addEventListener('selectionchange', handleSelectionChange);
|
|
1383
1447
|
const selectionCleanup = () => {
|
|
@@ -1400,6 +1464,7 @@
|
|
|
1400
1464
|
typeof rendition.hooks.unloaded.register === 'function'
|
|
1401
1465
|
) {
|
|
1402
1466
|
rendition.hooks.unloaded.register((view) => {
|
|
1467
|
+
view?.contents?.__papyrusGestureCleanup?.();
|
|
1403
1468
|
const cleanup = view && view.contents && view.contents.__papyrusSelectionCleanup;
|
|
1404
1469
|
if (typeof cleanup === 'function') cleanup();
|
|
1405
1470
|
const renderer = epubAnnotationRenderers.get(view?.contents);
|
|
@@ -1415,13 +1480,13 @@
|
|
|
1415
1480
|
if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
|
|
1416
1481
|
const href = spineItems[contents.sectionIndex]?.href;
|
|
1417
1482
|
const anchor = href && window.PapyrusEpubAnnotations?.selection(contents,cfiRange,href,annotationDocumentId);
|
|
1418
|
-
if (!anchor) return;
|
|
1483
|
+
if (!anchor || nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
|
|
1419
1484
|
epubScrollDiagnostics && epubScrollDiagnostics.setSelectionActive(true);
|
|
1420
1485
|
const payload = {documentSessionId: selectionSession, text: anchor.quote, pageIndex: contents.sectionIndex+1, anchor};
|
|
1421
1486
|
nativeMenuSelection = {contents, payload};
|
|
1422
1487
|
sendEvent('EPUB_TEXT_SELECTED', payload);
|
|
1423
1488
|
});
|
|
1424
|
-
['rendered','resized','layout'].forEach(name => rendition.on(name, () => {
|
|
1489
|
+
['rendered','resized','layout','relocated'].forEach(name => rendition.on(name, () => {
|
|
1425
1490
|
if (selectionSession === documentSessionId && selectionRendition === rendition) epubAnnotationRenderers.forEach(renderer => renderer.schedule());
|
|
1426
1491
|
}));
|
|
1427
1492
|
rendition.on('relocated', (location) => {
|
|
@@ -1431,6 +1496,11 @@
|
|
|
1431
1496
|
if (index < 0 && start && start.href) index = getSpineIndexByHref(start.href);
|
|
1432
1497
|
if (index < 0 || index >= spineItems.length) return;
|
|
1433
1498
|
epubScrollDiagnostics && epubScrollDiagnostics.relocated(location);
|
|
1499
|
+
epubLocation=window.PapyrusEpubReader.location(location,spineItems.length,epubViewMode==='single'?'paged':'chapter-scroll');
|
|
1500
|
+
if(epubLocation){
|
|
1501
|
+
if(book.locations?.length?.()>0)epubLocation.progress=book.locations.percentageFromCfi(epubLocation.cfi);
|
|
1502
|
+
sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
|
|
1503
|
+
}
|
|
1434
1504
|
const nextPage = index + 1;
|
|
1435
1505
|
if (nextPage === currentPage) return;
|
|
1436
1506
|
currentPage = nextPage;
|
|
@@ -1438,9 +1508,10 @@
|
|
|
1438
1508
|
});
|
|
1439
1509
|
}
|
|
1440
1510
|
|
|
1511
|
+
applyEpubZoom();
|
|
1441
1512
|
sendEpubDiagnostic('epub.display.start', diagnosticPayload);
|
|
1442
1513
|
await withEpubStageTimeout(
|
|
1443
|
-
|
|
1514
|
+
rendition.display(target || spineItems[0]?.href),
|
|
1444
1515
|
'rendition.display',
|
|
1445
1516
|
diagnosticPayload,
|
|
1446
1517
|
);
|
|
@@ -1452,7 +1523,6 @@
|
|
|
1452
1523
|
typeof rendition.manager.on === 'function' &&
|
|
1453
1524
|
typeof rendition.on === 'function'
|
|
1454
1525
|
) {
|
|
1455
|
-
let touchStart = null;
|
|
1456
1526
|
let lastScrollOffset = -1;
|
|
1457
1527
|
const manager = rendition.manager;
|
|
1458
1528
|
epubScrollDiagnostics = createEpubScrollDiagnostics(manager);
|
|
@@ -1527,57 +1597,19 @@
|
|
|
1527
1597
|
return result;
|
|
1528
1598
|
};
|
|
1529
1599
|
}
|
|
1530
|
-
const
|
|
1531
|
-
const touch =
|
|
1532
|
-
(event && event.changedTouches && event.changedTouches[0]) ||
|
|
1533
|
-
(event && event.touches && event.touches[0]);
|
|
1534
|
-
if (!touch) return null;
|
|
1535
|
-
const x = Number(touch.screenX ?? touch.clientX);
|
|
1536
|
-
const y = Number(touch.screenY ?? touch.clientY);
|
|
1537
|
-
return Number.isFinite(x) && Number.isFinite(y) ? { x, y } : null;
|
|
1538
|
-
};
|
|
1539
|
-
const handleScroll = (event) => {
|
|
1600
|
+
const handleScroll = event => {
|
|
1540
1601
|
const offsetY = Math.max(0, Number(event && event.top) || 0);
|
|
1541
1602
|
epubScrollDiagnostics && epubScrollDiagnostics.scroll(event);
|
|
1542
|
-
if (Math.abs(offsetY
|
|
1543
|
-
lastScrollOffset
|
|
1544
|
-
sendEvent('VIEWER_SCROLL',
|
|
1545
|
-
};
|
|
1546
|
-
const handleTouchStart = (event) => {
|
|
1547
|
-
touchStart = event?.touches?.length > 1 ? null : getTouchPoint(event);
|
|
1548
|
-
epubScrollDiagnostics && epubScrollDiagnostics.touchStart(event);
|
|
1549
|
-
};
|
|
1550
|
-
const handleTouchMove = (event) => {
|
|
1551
|
-
if (event?.touches?.length > 1) touchStart = null;
|
|
1552
|
-
epubScrollDiagnostics && epubScrollDiagnostics.touchMove(event);
|
|
1553
|
-
};
|
|
1554
|
-
const handleTouchEnd = (event) => {
|
|
1555
|
-
const end = getTouchPoint(event);
|
|
1556
|
-
const start = touchStart;
|
|
1557
|
-
touchStart = null;
|
|
1558
|
-
const selectedText = event?.target?.ownerDocument?.defaultView?.getSelection?.()?.toString().trim() || '';
|
|
1559
|
-
if (!selectedText && start && end && epubViewMode === 'single' && Math.abs(end.x-start.x) >= 48 && Math.abs(end.x-start.x) > Math.abs(end.y-start.y)*1.5) {
|
|
1560
|
-
const active = rendition;
|
|
1561
|
-
const interactionSession = documentSessionId;
|
|
1562
|
-
epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
|
|
1563
|
-
if (active !== rendition || interactionSession !== documentSessionId) return;
|
|
1564
|
-
return end.x < start.x ? active.next() : active.prev();
|
|
1565
|
-
});
|
|
1566
|
-
epubNavigationQueue.catch(error => sendEvent('EPUB_NAVIGATION_ERROR', {message:String(error)}));
|
|
1567
|
-
} else if (!selectedText && start && end && Math.hypot(end.x - start.x, end.y - start.y) <= 12) {
|
|
1568
|
-
sendEvent('VIEWER_TAP', {});
|
|
1569
|
-
}
|
|
1570
|
-
epubScrollDiagnostics && epubScrollDiagnostics.touchEnd(event);
|
|
1603
|
+
if (Math.abs(offsetY-lastScrollOffset)<1) return;
|
|
1604
|
+
lastScrollOffset=offsetY;
|
|
1605
|
+
sendEvent('VIEWER_SCROLL',{offsetY});
|
|
1571
1606
|
};
|
|
1572
|
-
|
|
1573
1607
|
manager.on('scroll', handleScroll);
|
|
1574
1608
|
const handleScrolled = (event) => {
|
|
1575
1609
|
epubScrollDiagnostics && epubScrollDiagnostics.settled(event);
|
|
1576
1610
|
};
|
|
1577
1611
|
manager.on('scrolled', handleScrolled);
|
|
1578
|
-
|
|
1579
|
-
rendition.on('touchmove', handleTouchMove);
|
|
1580
|
-
rendition.on('touchend', handleTouchEnd);
|
|
1612
|
+
|
|
1581
1613
|
epubInteractionCleanup = () => {
|
|
1582
1614
|
epubSelectionCleanups.forEach((cleanup) => cleanup());
|
|
1583
1615
|
epubSelectionCleanups.clear();
|
|
@@ -1586,16 +1618,9 @@
|
|
|
1586
1618
|
if (originalEnqueue) queue.enqueue = originalEnqueue;
|
|
1587
1619
|
if (typeof manager.off === 'function') manager.off('scroll', handleScroll);
|
|
1588
1620
|
if (typeof manager.off === 'function') manager.off('scrolled', handleScrolled);
|
|
1589
|
-
if (typeof rendition.off === 'function') {
|
|
1590
|
-
rendition.off('touchstart', handleTouchStart);
|
|
1591
|
-
rendition.off('touchmove', handleTouchMove);
|
|
1592
|
-
rendition.off('touchend', handleTouchEnd);
|
|
1593
|
-
}
|
|
1594
1621
|
epubScrollDiagnostics = null;
|
|
1595
1622
|
};
|
|
1596
1623
|
}
|
|
1597
|
-
applyEpubZoom();
|
|
1598
|
-
|
|
1599
1624
|
const outline = await withEpubStageTimeout(
|
|
1600
1625
|
buildOutline(),
|
|
1601
1626
|
'outline',
|
|
@@ -1733,7 +1758,8 @@
|
|
|
1733
1758
|
};
|
|
1734
1759
|
|
|
1735
1760
|
let nativeMenuSelection = null;
|
|
1736
|
-
let epubViewMode = "
|
|
1761
|
+
let epubViewMode = "single";
|
|
1762
|
+
let epubLocation = null;
|
|
1737
1763
|
|
|
1738
1764
|
const handleCommand = async (message) => {
|
|
1739
1765
|
const { id, kind, payload } = message;
|
|
@@ -1746,7 +1772,9 @@
|
|
|
1746
1772
|
epubAnnotations = [];
|
|
1747
1773
|
annotationDocumentId = undefined;
|
|
1748
1774
|
zoom = 1.0;
|
|
1749
|
-
epubViewMode = "continuous";
|
|
1775
|
+
epubViewMode = payload.epubMode === "chapter-scroll" ? "continuous" : "single";
|
|
1776
|
+
epubLocation = null;
|
|
1777
|
+
nativeMenuSelection = null;
|
|
1750
1778
|
epubNavigationRequest += 1;
|
|
1751
1779
|
epubNavigationQueue = Promise.resolve();
|
|
1752
1780
|
|
|
@@ -1860,25 +1888,40 @@
|
|
|
1860
1888
|
|
|
1861
1889
|
if (kind === 'set-epub-view-mode') {
|
|
1862
1890
|
if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB layout session');
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
sendResponse(id,true,null);
|
|
1891
|
+
const next=payload.epubMode ? (payload.epubMode==='paged'?'single':'continuous') : (payload.viewMode==='single'?'single':'continuous');
|
|
1892
|
+
{
|
|
1893
|
+
epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
|
|
1894
|
+
if(payload.documentSessionId!==documentSessionId || next===epubViewMode)return;
|
|
1895
|
+
const target=epubLocation?.cfi;
|
|
1896
|
+
epubViewMode=next;
|
|
1897
|
+
await renderEpubRendition('layout',epubLoadGeneration,target);
|
|
1898
|
+
});
|
|
1899
|
+
await epubNavigationQueue;
|
|
1900
|
+
}
|
|
1901
|
+
sendResponse(id,true,null);return;
|
|
1902
|
+
}
|
|
1903
|
+
if(kind === 'epub-go-to-location'){
|
|
1904
|
+
if(currentType!=='epub' || payload.documentSessionId!==documentSessionId || !window.PapyrusEpubReader.validCfi(payload.cfi))throw new Error('Invalid EPUB location');
|
|
1905
|
+
epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(()=>payload.documentSessionId===documentSessionId?rendition.display(payload.cfi):undefined);
|
|
1906
|
+
await epubNavigationQueue;sendResponse(id,true,null);return;
|
|
1874
1907
|
}
|
|
1875
1908
|
|
|
1876
1909
|
if (kind === 'set-zoom') {
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1910
|
+
const requestedZoom=Math.max(0.5,Math.min(4.0,payload.zoom || 1.0));
|
|
1911
|
+
if(currentType === 'epub') {
|
|
1912
|
+
const session=documentSessionId;
|
|
1913
|
+
epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
|
|
1914
|
+
if(session!==documentSessionId)return;
|
|
1915
|
+
const active=rendition;
|
|
1916
|
+
const cfi=epubLocation?.cfi;
|
|
1917
|
+
zoom=requestedZoom;applyEpubZoom();
|
|
1918
|
+
// Let the content CSS update before redisplaying the logical anchor.
|
|
1919
|
+
await new Promise(resolve=>(window.requestAnimationFrame || (callback=>setTimeout(callback,0)))(resolve));
|
|
1920
|
+
if(cfi && active===rendition && session===documentSessionId)await active.display(cfi);
|
|
1921
|
+
});
|
|
1922
|
+
await epubNavigationQueue;
|
|
1923
|
+
} else {zoom=requestedZoom;applyZoom();}
|
|
1924
|
+
sendState();sendResponse(id,true,{zoom});return;
|
|
1882
1925
|
}
|
|
1883
1926
|
|
|
1884
1927
|
if (kind === 'set-rotation') {
|
|
@@ -24,11 +24,13 @@ const runtimeBodyStart = runtime.indexOf("\n(function () {", runtime.indexOf(com
|
|
|
24
24
|
if (runtimeBodyStart < 0) {
|
|
25
25
|
throw new Error("Main runtime body not found");
|
|
26
26
|
}
|
|
27
|
-
const
|
|
27
|
+
const readerSource=await readFile(resolve(runtimeDirectory,"epubReader.js"),"utf8");
|
|
28
|
+
const readerRuntime=replaceMarkedSource(runtime,"/* @papyrus-epub-reader:start */","/* @papyrus-epub-reader:end */",`\n${readerSource}\n`);
|
|
29
|
+
const runtimeBody = readerRuntime.slice(readerRuntime.indexOf("\n(function () {",readerRuntime.indexOf(comicRuntimeEnd))+1).trim();
|
|
28
30
|
await writeFile(
|
|
29
31
|
runtimePath,
|
|
30
32
|
replaceMarkedSource(
|
|
31
|
-
|
|
33
|
+
readerRuntime,
|
|
32
34
|
"/* @papyrus-comic-runtime:start */",
|
|
33
35
|
"/* @papyrus-comic-runtime:end */",
|
|
34
36
|
`\n${source.trim()}\n`
|
|
@@ -37,12 +39,13 @@ await writeFile(
|
|
|
37
39
|
|
|
38
40
|
const htmlPath = resolve(runtimeDirectory, "index.html");
|
|
39
41
|
const html = await readFile(htmlPath, "utf8");
|
|
40
|
-
|
|
42
|
+
let htmlWithComicRuntime = replaceMarkedSource(
|
|
41
43
|
html,
|
|
42
44
|
"<!-- @papyrus-comic-runtime:start -->",
|
|
43
45
|
"<!-- @papyrus-comic-runtime:end -->",
|
|
44
46
|
`\n <script>\n${source}\n </script>\n`
|
|
45
47
|
);
|
|
48
|
+
htmlWithComicRuntime=htmlWithComicRuntime.replace(/<!-- @papyrus-epub-reader:start -->[\s\S]*?<!-- @papyrus-epub-reader:end -->\n?/g,"");
|
|
46
49
|
const htmlComicRuntimeEnd = "<!-- @papyrus-comic-runtime:end -->";
|
|
47
50
|
const htmlBodyStart = htmlWithComicRuntime.indexOf(
|
|
48
51
|
"<script>",
|