@papyrus-sdk/ui-react-native 0.2.35-beta.8 → 0.2.35
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 +17 -3
- package/dist/index.d.ts +17 -3
- package/dist/index.js +2423 -1793
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2033 -1409
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -13
- package/runtime/comicRuntime.test.ts +9 -9
- package/runtime/epubAnnotations.js +121 -0
- package/runtime/epubAnnotations.test.ts +35 -0
- package/runtime/epubReader.js +58 -0
- package/runtime/epubReader.test.ts +74 -0
- package/runtime/epubRuntime.test.ts +48 -0
- package/runtime/epubSelectionMenu.test.ts +39 -0
- package/runtime/index.html +449 -67
- package/runtime/runtime.js +449 -67
- package/runtime/syncComicRuntime.mjs +8 -4
package/runtime/index.html
CHANGED
|
@@ -20483,6 +20483,191 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20483
20483
|
<!-- @papyrus-comic-runtime:end -->
|
|
20484
20484
|
<script>
|
|
20485
20485
|
(function () {
|
|
20486
|
+
/* @papyrus-epub-reader:start */
|
|
20487
|
+
(function(root){
|
|
20488
|
+
function mode(value){return value==='chapter-scroll'?'chapter-scroll':'paged';}
|
|
20489
|
+
function validCfi(value){return typeof value==='string' && value.length<=4096 && /^epubcfi\([^\n<>]+\)$/.test(value);}
|
|
20490
|
+
function options(value){return {manager:'default',flow:mode(value)==='paged'?'paginated':'scrolled-doc',spread:'none',width:'100%',height:'100%',allowScriptedContent:false};}
|
|
20491
|
+
function gesture(start,end,state){
|
|
20492
|
+
if(!start || !end || state.selected || state.interactive || state.multitouch)return null;
|
|
20493
|
+
var dx=end.x-start.x,dy=end.y-start.y,elapsed=end.time-start.time;
|
|
20494
|
+
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';
|
|
20495
|
+
if(elapsed>=0 && elapsed<450 && Math.hypot(dx,dy)<=12)return 'tap';
|
|
20496
|
+
return null;
|
|
20497
|
+
}
|
|
20498
|
+
function location(raw,count,readingMode,geometry){
|
|
20499
|
+
var start=raw && raw.start;if(!start || !validCfi(start.cfi))return null;
|
|
20500
|
+
var displayed=start.displayed||{},chapter=Math.max(1,(Number(start.index)||0)+1);
|
|
20501
|
+
var visualPage=mode(readingMode)==='paged' && Number.isFinite(displayed.page)?displayed.page:null;
|
|
20502
|
+
var total=mode(readingMode)==='paged' && Number.isFinite(displayed.total)?displayed.total:null;
|
|
20503
|
+
var atStart=Boolean(raw.atStart),atEnd=Boolean(raw.atEnd);
|
|
20504
|
+
// Chromium may round a column offset down by a fraction of a CSS pixel.
|
|
20505
|
+
// Keep epub.js authoritative outside a 1px boundary, and for RTL layouts.
|
|
20506
|
+
if(visualPage!==null && total>0 && geometry && geometry.direction==='ltr' && geometry.pageWidth>0 && Number.isFinite(geometry.offset)){
|
|
20507
|
+
var boundary=Math.round(geometry.offset/geometry.pageWidth);
|
|
20508
|
+
if(Math.abs(geometry.offset-boundary*geometry.pageWidth)<=1){
|
|
20509
|
+
visualPage=Math.min(total,Math.max(1,boundary+1));
|
|
20510
|
+
atStart=chapter===(geometry.firstIndex ?? 0)+1 && visualPage===1;
|
|
20511
|
+
atEnd=chapter===(geometry.lastIndex ?? count-1)+1 && visualPage===total;
|
|
20512
|
+
}
|
|
20513
|
+
}
|
|
20514
|
+
var fraction=total?Math.max(0,(visualPage-1)/total):0;
|
|
20515
|
+
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:atStart,atEnd:atEnd};
|
|
20516
|
+
}
|
|
20517
|
+
function installResizeAnchor(manager,readCfi){
|
|
20518
|
+
var original=manager.resize,anchor=null;
|
|
20519
|
+
function resize(width,height,target){
|
|
20520
|
+
if(validCfi(target))anchor=target;
|
|
20521
|
+
if(!anchor){var current=readCfi();if(validCfi(current))anchor=current;}
|
|
20522
|
+
// epub.js accepts a logical target as its third argument. Keep it across
|
|
20523
|
+
// keyboard/dialog reflows instead of adopting each new viewport start.
|
|
20524
|
+
return original.call(this,width,height,anchor || target);
|
|
20525
|
+
}
|
|
20526
|
+
manager.resize=resize;
|
|
20527
|
+
return {cfi:function(){return anchor;},invalidate:function(){anchor=null;},destroy:function(){if(manager.resize===resize)manager.resize=original;anchor=null;}};
|
|
20528
|
+
}
|
|
20529
|
+
function install(contents,config){
|
|
20530
|
+
var doc=contents.document,win=contents.window,start=null,blocked=false;
|
|
20531
|
+
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;}
|
|
20532
|
+
function selected(){return Boolean(String(win.getSelection()||'').trim()) || config.blocked();}
|
|
20533
|
+
function interactive(target){return Boolean(target && target.closest && target.closest('a,button,input,textarea,select,[contenteditable="true"],[data-papyrus-overlay]'));}
|
|
20534
|
+
function begin(e){start=point(e);blocked=e.touches.length!==1 || selected() || interactive(e.target);}
|
|
20535
|
+
function invalidateScroll(finish){if(config.current() && start && finish && config.mode()==='chapter-scroll' && !blocked && !selected() && Math.abs(finish.y-start.y)>12 && Math.abs(finish.y-start.y)>Math.abs(finish.x-start.x) && config.interact)config.interact();}
|
|
20536
|
+
function move(e){if(e.touches.length!==1)blocked=true;invalidateScroll(point(e));}
|
|
20537
|
+
function end(e){var finish=point(e);invalidateScroll(finish);var action=gesture(start,finish,{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);}
|
|
20538
|
+
function cancel(){start=null;blocked=true;}
|
|
20539
|
+
function link(e){if(config.current() && e.target?.closest?.('a') && config.interact)config.interact();}
|
|
20540
|
+
doc.addEventListener('touchstart',begin,{passive:true});doc.addEventListener('touchmove',move,{passive:true});doc.addEventListener('touchend',end,{passive:true});doc.addEventListener('touchcancel',cancel,{passive:true});doc.addEventListener('click',link);
|
|
20541
|
+
return function(){doc.removeEventListener('touchstart',begin);doc.removeEventListener('touchmove',move);doc.removeEventListener('touchend',end);doc.removeEventListener('touchcancel',cancel);doc.removeEventListener('click',link);};
|
|
20542
|
+
}
|
|
20543
|
+
root.PapyrusEpubReader={mode:mode,validCfi:validCfi,options:options,gesture:gesture,location:location,installResizeAnchor:installResizeAnchor,install:install};
|
|
20544
|
+
})(typeof window==='undefined'?globalThis:window);
|
|
20545
|
+
|
|
20546
|
+
/* @papyrus-epub-reader:end */
|
|
20547
|
+
/* @papyrus-epub-annotations:start */
|
|
20548
|
+
(function (root, factory) {
|
|
20549
|
+
if (typeof module === 'object' && module.exports) module.exports = factory();
|
|
20550
|
+
else root.PapyrusEpubAnnotations = factory();
|
|
20551
|
+
})(typeof window !== 'undefined' ? window : globalThis, function () {
|
|
20552
|
+
function validAnchor(anchor) {
|
|
20553
|
+
return anchor && anchor.version === 1 && anchor.kind === 'epub-cfi' &&
|
|
20554
|
+
typeof anchor.cfiRange === 'string' && anchor.cfiRange.length <= 4096 && /^epubcfi\([^\n<>]+\)$/.test(anchor.cfiRange) &&
|
|
20555
|
+
typeof anchor.href === 'string' && !/^(javascript|data):/i.test(anchor.href) &&
|
|
20556
|
+
typeof anchor.quote === 'string' && anchor.quote.length > 0 && anchor.quote.length <= 100000;
|
|
20557
|
+
}
|
|
20558
|
+
function textNodes(document) {
|
|
20559
|
+
var walker = document.createTreeWalker(document.body, 4);
|
|
20560
|
+
var nodes = [], text = '', node;
|
|
20561
|
+
while ((node = walker.nextNode())) {
|
|
20562
|
+
if (node.parentElement.closest('script,style,[data-papyrus-overlay]')) continue;
|
|
20563
|
+
nodes.push({node:node, start:text.length}); text += node.textContent;
|
|
20564
|
+
}
|
|
20565
|
+
return {nodes:nodes,text:text};
|
|
20566
|
+
}
|
|
20567
|
+
function recoverRange(document, anchor) {
|
|
20568
|
+
var source = textNodes(document), match = null, start = source.text.indexOf(anchor.quote);
|
|
20569
|
+
while (start >= 0) {
|
|
20570
|
+
var end = start + anchor.quote.length;
|
|
20571
|
+
if ((!anchor.prefix || source.text.slice(Math.max(0,start-anchor.prefix.length),start) === anchor.prefix) &&
|
|
20572
|
+
(!anchor.suffix || source.text.slice(end,end+anchor.suffix.length) === anchor.suffix)) {
|
|
20573
|
+
if (match) return null; match = {start:start,end:end};
|
|
20574
|
+
}
|
|
20575
|
+
start = source.text.indexOf(anchor.quote,start+1);
|
|
20576
|
+
}
|
|
20577
|
+
if (!match) return null;
|
|
20578
|
+
var range = document.createRange();
|
|
20579
|
+
var first = source.nodes.find(function(n){return n.start+n.node.length > match.start;});
|
|
20580
|
+
var last = source.nodes.find(function(n){return n.start+n.node.length >= match.end;});
|
|
20581
|
+
if (!first || !last) return null;
|
|
20582
|
+
range.setStart(first.node,match.start-first.start); range.setEnd(last.node,match.end-last.start);
|
|
20583
|
+
return range;
|
|
20584
|
+
}
|
|
20585
|
+
function resolveRange(contents, anchor) {
|
|
20586
|
+
if (!validAnchor(anchor)) return null;
|
|
20587
|
+
try { var range = contents.range(anchor.cfiRange); if (range && range.toString() === anchor.quote) return range; } catch (_) {}
|
|
20588
|
+
return recoverRange(contents.document,anchor);
|
|
20589
|
+
}
|
|
20590
|
+
function selection(contents, cfiRange, href, documentId) {
|
|
20591
|
+
var range;
|
|
20592
|
+
try { range = contents.range(cfiRange); } catch (_) { return null; }
|
|
20593
|
+
if (!range || !range.toString()) return null;
|
|
20594
|
+
var before = contents.document.createRange(); before.selectNodeContents(contents.document.body); before.setEnd(range.startContainer,range.startOffset);
|
|
20595
|
+
var after = contents.document.createRange(); after.selectNodeContents(contents.document.body); after.setStart(range.endContainer,range.endOffset);
|
|
20596
|
+
var anchor = {version:1,kind:'epub-cfi',cfiRange:cfiRange,href:href,spineIndex:contents.sectionIndex,documentId:documentId,quote:range.toString(),prefix:before.toString().slice(-48),suffix:after.toString().slice(0,48)};
|
|
20597
|
+
return validAnchor(anchor) ? anchor : null;
|
|
20598
|
+
}
|
|
20599
|
+
function install(contents, options) {
|
|
20600
|
+
var doc = contents.document, win = contents.window, alive = true, frame = 0;
|
|
20601
|
+
var overlay = doc.createElement('div'); overlay.dataset.papyrusOverlay = 'annotations';
|
|
20602
|
+
overlay.style.cssText = 'position:absolute;left:0;top:0;width:100%;height:0;pointer-events:none;z-index:3';
|
|
20603
|
+
var originalPosition=doc.body.style.position;
|
|
20604
|
+
if(win.getComputedStyle(doc.body).position==='static')doc.body.style.position='relative';
|
|
20605
|
+
doc.body.appendChild(overlay);
|
|
20606
|
+
var registry = new Map(), hitRegions = [];
|
|
20607
|
+
function render() {
|
|
20608
|
+
frame = 0; if (!alive || !options.isCurrent()) return;
|
|
20609
|
+
var keep = new Set(), noteGroups = new Map();
|
|
20610
|
+
hitRegions = [];
|
|
20611
|
+
options.annotations().forEach(function(annotation) {
|
|
20612
|
+
var anchor = annotation.anchor;
|
|
20613
|
+
if (!validAnchor(anchor) || anchor.href !== options.href || anchor.documentId && options.documentId && anchor.documentId !== options.documentId) return;
|
|
20614
|
+
var range = resolveRange(contents,anchor); if (!range) return;
|
|
20615
|
+
var rects = Array.from(range.getClientRects()).filter(function(r){return r.width>0 && r.height>0;});
|
|
20616
|
+
if (!rects.length) return;
|
|
20617
|
+
keep.add(annotation.id);
|
|
20618
|
+
var group = registry.get(annotation.id);
|
|
20619
|
+
if (!group) { group = doc.createElement('div'); group.dataset.annotationId = annotation.id; overlay.appendChild(group); registry.set(annotation.id,group); if (!doc.defaultView.matchMedia || !doc.defaultView.matchMedia('(prefers-reduced-motion: reduce)').matches) { if (typeof group.animate === 'function') group.animate([{opacity:0},{opacity:1}],{duration:180,easing:'ease-out'}); } }
|
|
20620
|
+
group.replaceChildren();
|
|
20621
|
+
hitRegions.push({id:annotation.id,rects:rects});
|
|
20622
|
+
var color = /^#[0-9a-f]{6}$/i.test(annotation.color) ? annotation.color : '#FFC928';
|
|
20623
|
+
var style = annotation.markupStyle || annotation.type;
|
|
20624
|
+
var opacity = Number.isFinite(annotation.opacity) ? Math.max(0,Math.min(1,annotation.opacity)) : 0.35;
|
|
20625
|
+
if(style === 'highlight')opacity=Math.min(0.35,opacity);
|
|
20626
|
+
rects.forEach(function(rect) {
|
|
20627
|
+
var mark = doc.createElement('div');
|
|
20628
|
+
var bodyRect=doc.body.getBoundingClientRect();
|
|
20629
|
+
var height = style === 'highlight' ? rect.height : 2;
|
|
20630
|
+
var y = style === 'strikeout' ? rect.top+rect.height/2 : style === 'underline' ? rect.bottom-2 : rect.top;
|
|
20631
|
+
mark.style.cssText = 'position:absolute;pointer-events:none;left:'+(rect.left-bodyRect.left)+'px;top:'+(y-bodyRect.top)+'px;width:'+rect.width+'px;height:'+height+'px;background:'+color+';opacity:'+opacity;
|
|
20632
|
+
if (['highlight','underline','strikeout'].includes(style)) group.appendChild(mark);
|
|
20633
|
+
});
|
|
20634
|
+
var hasNote = annotation.noteContent !== undefined || annotation.type === 'comment' || annotation.type === 'text';
|
|
20635
|
+
if (hasNote) {
|
|
20636
|
+
var last = rects[rects.length-1], button = doc.createElement('button');
|
|
20637
|
+
button.textContent = '●'; button.setAttribute('aria-label',options.labels().comment || '');
|
|
20638
|
+
var pageWidth=Math.max(44, options.pageWidth ? options.pageWidth() : win.innerWidth);
|
|
20639
|
+
var bodyRect=doc.body.getBoundingClientRect(), column=Math.max(0,Math.floor((last.left-bodyRect.left)/pageWidth));
|
|
20640
|
+
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';
|
|
20641
|
+
var key = column+":"+Math.floor(last.top/44);
|
|
20642
|
+
var neighbors=noteGroups.get(key);
|
|
20643
|
+
if(!neighbors){neighbors={button:button,ids:[]};noteGroups.set(key,neighbors);group.appendChild(button);}
|
|
20644
|
+
neighbors.ids.push(annotation.id);
|
|
20645
|
+
}
|
|
20646
|
+
});
|
|
20647
|
+
noteGroups.forEach(function(group){
|
|
20648
|
+
group.button.textContent=group.ids.length>1?String(group.ids.length):'●';
|
|
20649
|
+
group.button.addEventListener('click',function(e){e.stopPropagation();if(options.isCurrent())options.onTap(group.ids[0],group.ids);});
|
|
20650
|
+
});
|
|
20651
|
+
registry.forEach(function(group,id){if (!keep.has(id)) {group.remove();registry.delete(id);}});
|
|
20652
|
+
}
|
|
20653
|
+
function schedule() { if (alive && !frame) frame = win.requestAnimationFrame(render); }
|
|
20654
|
+
function tapMarkup(event) {
|
|
20655
|
+
if(!alive || !options.isCurrent() || String(win.getSelection() || '').length || event.target.closest('[data-papyrus-overlay]'))return;
|
|
20656
|
+
var hit=hitRegions.find(function(item){return item.rects.some(function(r){return event.clientX>=r.left && event.clientX<=r.right && event.clientY>=r.top && event.clientY<=r.bottom;});});
|
|
20657
|
+
if(hit) {event.stopPropagation();options.onTap(hit.id);}
|
|
20658
|
+
}
|
|
20659
|
+
doc.addEventListener('click',tapMarkup);
|
|
20660
|
+
var observer = typeof win.ResizeObserver === 'function' ? new win.ResizeObserver(schedule) : null;
|
|
20661
|
+
if (observer) observer.observe(doc.body);
|
|
20662
|
+
win.addEventListener('resize',schedule);win.addEventListener('scroll',schedule); doc.addEventListener('load',schedule,true);
|
|
20663
|
+
if (doc.fonts && doc.fonts.ready) doc.fonts.ready.then(schedule);
|
|
20664
|
+
schedule();
|
|
20665
|
+
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();}};
|
|
20666
|
+
}
|
|
20667
|
+
return {validAnchor:validAnchor,recoverRange:recoverRange,resolveRange:resolveRange,selection:selection,install:install};
|
|
20668
|
+
});
|
|
20669
|
+
|
|
20670
|
+
/* @papyrus-epub-annotations:end */
|
|
20486
20671
|
const viewer = document.getElementById('viewer');
|
|
20487
20672
|
const DEFAULT_FONT_SIZE = 16;
|
|
20488
20673
|
const TEXT_PAGE_CHUNK = 1600;
|
|
@@ -20490,6 +20675,12 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20490
20675
|
let currentType = null;
|
|
20491
20676
|
let book = null;
|
|
20492
20677
|
let rendition = null;
|
|
20678
|
+
let epubResizeAnchor = null;
|
|
20679
|
+
let documentSessionId = null;
|
|
20680
|
+
let annotationDocumentId;
|
|
20681
|
+
let annotationLabels = {};
|
|
20682
|
+
let epubAnnotations = [];
|
|
20683
|
+
const epubAnnotationRenderers = new Map();
|
|
20493
20684
|
let spineItems = [];
|
|
20494
20685
|
let textPages = [];
|
|
20495
20686
|
let textContainer = null;
|
|
@@ -20897,6 +21088,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20897
21088
|
};
|
|
20898
21089
|
|
|
20899
21090
|
const clearViewer = () => {
|
|
21091
|
+
if(epubResizeAnchor){epubResizeAnchor.destroy();epubResizeAnchor=null;}
|
|
21092
|
+
epubAnnotationRenderers.forEach(renderer => renderer.destroy());
|
|
21093
|
+
epubAnnotationRenderers.clear();
|
|
20900
21094
|
if (epubInteractionCleanup) {
|
|
20901
21095
|
epubInteractionCleanup();
|
|
20902
21096
|
epubInteractionCleanup = null;
|
|
@@ -21551,21 +21745,65 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21551
21745
|
pageCount,
|
|
21552
21746
|
});
|
|
21553
21747
|
|
|
21748
|
+
if (book.locations?.generate) {
|
|
21749
|
+
const activeBook=book;
|
|
21750
|
+
activeBook.locations.generate(150).then(() => {
|
|
21751
|
+
if (isCurrentLoad() && activeBook===book && epubLocation) {
|
|
21752
|
+
epubLocation.progress=activeBook.locations.percentageFromCfi(epubLocation.cfi);
|
|
21753
|
+
sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
|
|
21754
|
+
}
|
|
21755
|
+
}).catch(() => {});
|
|
21756
|
+
}
|
|
21757
|
+
return renderEpubRendition(loadId,generation,null);
|
|
21758
|
+
};
|
|
21759
|
+
|
|
21760
|
+
const renderEpubRendition = async (loadId,generation,target) => {
|
|
21761
|
+
const diagnosticPayload={loadId};
|
|
21762
|
+
const isCurrentLoad=()=>generation===epubLoadGeneration;
|
|
21763
|
+
if(epubInteractionCleanup)epubInteractionCleanup();
|
|
21764
|
+
if(rendition)rendition.destroy();
|
|
21554
21765
|
clearViewer();
|
|
21555
|
-
rendition = book.renderTo(viewer,
|
|
21556
|
-
manager: 'continuous',
|
|
21557
|
-
width: '100%',
|
|
21558
|
-
height: '100%',
|
|
21559
|
-
flow: 'scrolled-continuous',
|
|
21560
|
-
spread: 'none',
|
|
21561
|
-
});
|
|
21766
|
+
rendition = book.renderTo(viewer, window.PapyrusEpubReader.options(epubViewMode === 'single' ? 'paged' : 'chapter-scroll'));
|
|
21562
21767
|
sendEpubDiagnostic('epub.rendition.created', diagnosticPayload);
|
|
21563
21768
|
|
|
21564
21769
|
if (rendition && rendition.hooks && rendition.hooks.content) {
|
|
21770
|
+
const session = documentSessionId;
|
|
21771
|
+
const activeRendition = rendition;
|
|
21565
21772
|
rendition.hooks.content.register((contents) => {
|
|
21773
|
+
const removeGestureListeners = window.PapyrusEpubReader.install(contents, {
|
|
21774
|
+
mode: () => epubViewMode === 'single' ? 'paged' : 'chapter-scroll',
|
|
21775
|
+
rtl: () => book.package?.metadata?.direction === 'rtl' || book.spine?.direction === 'rtl',
|
|
21776
|
+
blocked: () => Boolean(nativeMenuSelection && String(nativeMenuSelection.contents?.window?.getSelection() || '').trim()),
|
|
21777
|
+
annotationHit: point => epubAnnotationRenderers.get(contents)?.hit(point.x,point.y),
|
|
21778
|
+
current: () => session === documentSessionId && activeRendition === rendition,
|
|
21779
|
+
interact: () => epubResizeAnchor?.invalidate(),
|
|
21780
|
+
tap: () => sendEvent('EPUB_CONTENT_TAP',{documentSessionId:session}),
|
|
21781
|
+
turn: direction => {
|
|
21782
|
+
epubNavigationQueue = epubNavigationQueue.catch(()=>{}).then(() => {
|
|
21783
|
+
if(session !== documentSessionId || activeRendition !== rendition)return;
|
|
21784
|
+
epubResizeAnchor?.invalidate();
|
|
21785
|
+
return direction<0?activeRendition.prev():activeRendition.next();
|
|
21786
|
+
});
|
|
21787
|
+
epubNavigationQueue.catch(error => sendEvent('EPUB_NAVIGATION_ERROR',{message:String(error)}));
|
|
21788
|
+
},
|
|
21789
|
+
});
|
|
21790
|
+
const gestureCleanup = () => {removeGestureListeners();epubSelectionCleanups.delete(gestureCleanup);};
|
|
21791
|
+
epubSelectionCleanups.add(gestureCleanup);
|
|
21792
|
+
contents.__papyrusGestureCleanup=gestureCleanup;
|
|
21793
|
+
const href = spineItems[contents.sectionIndex]?.href;
|
|
21794
|
+
if (href && window.PapyrusEpubAnnotations) {
|
|
21795
|
+
const renderer = window.PapyrusEpubAnnotations.install(contents, {
|
|
21796
|
+
href, get documentId() { return annotationDocumentId; },
|
|
21797
|
+
isCurrent: () => session === documentSessionId && activeRendition === rendition,
|
|
21798
|
+
pageWidth: () => activeRendition.layout?.width || viewer.clientWidth,
|
|
21799
|
+
annotations: () => epubAnnotations, labels: () => annotationLabels,
|
|
21800
|
+
onTap: (id, ids) => sendEvent("EPUB_ANNOTATION_TAP", {documentSessionId: session, id, ids}),
|
|
21801
|
+
});
|
|
21802
|
+
epubAnnotationRenderers.set(contents,renderer);
|
|
21803
|
+
}
|
|
21566
21804
|
const frame = contents && contents.document ? contents.document.defaultView.frameElement : null;
|
|
21567
21805
|
if (frame) {
|
|
21568
|
-
frame.setAttribute('sandbox', 'allow-
|
|
21806
|
+
frame.setAttribute('sandbox', 'allow-same-origin');
|
|
21569
21807
|
}
|
|
21570
21808
|
const selectionDocument = contents && contents.document;
|
|
21571
21809
|
const selectionWindow = contents && contents.window;
|
|
@@ -21575,13 +21813,42 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21575
21813
|
selectionWindow &&
|
|
21576
21814
|
typeof selectionWindow.getSelection === 'function'
|
|
21577
21815
|
) {
|
|
21816
|
+
let selectionTimer = null;
|
|
21817
|
+
|
|
21818
|
+
const reportSelection = () => {
|
|
21819
|
+
selectionTimer = null;
|
|
21820
|
+
if (session !== documentSessionId || activeRendition !== rendition) return;
|
|
21821
|
+
const selected = selectionWindow.getSelection();
|
|
21822
|
+
if (!selected || selected.isCollapsed || selected.rangeCount === 0 ||
|
|
21823
|
+
typeof contents.cfiFromRange !== 'function') return;
|
|
21824
|
+
const range = selected.getRangeAt(0).cloneRange();
|
|
21825
|
+
if (!range.toString().trim()) return;
|
|
21826
|
+
const href = spineItems[contents.sectionIndex]?.href;
|
|
21827
|
+
if (!href) return;
|
|
21828
|
+
let cfi;
|
|
21829
|
+
try { cfi = contents.cfiFromRange(range); } catch (_) { return; }
|
|
21830
|
+
const anchor = window.PapyrusEpubAnnotations?.selection(contents, cfi, href, annotationDocumentId);
|
|
21831
|
+
if (!anchor) return;
|
|
21832
|
+
if (nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
|
|
21833
|
+
const payload = {documentSessionId: session, text: anchor.quote,
|
|
21834
|
+
pageIndex: contents.sectionIndex + 1, anchor};
|
|
21835
|
+
nativeMenuSelection = {contents, payload};
|
|
21836
|
+
sendEvent('EPUB_TEXT_SELECTED', payload);
|
|
21837
|
+
};
|
|
21578
21838
|
const handleSelectionChange = () => {
|
|
21579
21839
|
const selection = selectionWindow.getSelection();
|
|
21580
21840
|
const text = selection ? selection.toString().trim() : '';
|
|
21581
21841
|
epubScrollDiagnostics && epubScrollDiagnostics.setSelectionActive(Boolean(text));
|
|
21842
|
+
if (selectionTimer !== null) clearTimeout(selectionTimer);
|
|
21843
|
+
// epub.js "selected" is not reliable on every iOS WKWebView path.
|
|
21844
|
+
// The content document still emits selectionchange, so resolve its
|
|
21845
|
+
// live Range to a CFI before the native menu action can fire.
|
|
21846
|
+
if (text) reportSelection();
|
|
21847
|
+
else if (nativeMenuSelection?.contents === contents) nativeMenuSelection = null;
|
|
21582
21848
|
};
|
|
21583
21849
|
selectionDocument.addEventListener('selectionchange', handleSelectionChange);
|
|
21584
21850
|
const selectionCleanup = () => {
|
|
21851
|
+
if (selectionTimer !== null) clearTimeout(selectionTimer);
|
|
21585
21852
|
selectionDocument.removeEventListener('selectionchange', handleSelectionChange);
|
|
21586
21853
|
epubSelectionCleanups.delete(selectionCleanup);
|
|
21587
21854
|
};
|
|
@@ -21600,29 +21867,53 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21600
21867
|
typeof rendition.hooks.unloaded.register === 'function'
|
|
21601
21868
|
) {
|
|
21602
21869
|
rendition.hooks.unloaded.register((view) => {
|
|
21870
|
+
view?.contents?.__papyrusGestureCleanup?.();
|
|
21603
21871
|
const cleanup = view && view.contents && view.contents.__papyrusSelectionCleanup;
|
|
21604
21872
|
if (typeof cleanup === 'function') cleanup();
|
|
21873
|
+
const renderer = epubAnnotationRenderers.get(view?.contents);
|
|
21874
|
+
if (renderer) renderer.destroy();
|
|
21875
|
+
epubAnnotationRenderers.delete(view?.contents);
|
|
21605
21876
|
});
|
|
21606
21877
|
}
|
|
21607
21878
|
|
|
21608
21879
|
if (rendition && typeof rendition.on === 'function') {
|
|
21880
|
+
const selectionSession = documentSessionId;
|
|
21881
|
+
const selectionRendition = rendition;
|
|
21609
21882
|
rendition.on('selected', (cfiRange, contents) => {
|
|
21610
|
-
|
|
21611
|
-
const
|
|
21612
|
-
|
|
21613
|
-
if (
|
|
21614
|
-
|
|
21615
|
-
}
|
|
21616
|
-
|
|
21617
|
-
|
|
21618
|
-
}
|
|
21883
|
+
if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
|
|
21884
|
+
const href = spineItems[contents.sectionIndex]?.href;
|
|
21885
|
+
const anchor = href && window.PapyrusEpubAnnotations?.selection(contents,cfiRange,href,annotationDocumentId);
|
|
21886
|
+
if (!anchor || nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
|
|
21887
|
+
epubScrollDiagnostics && epubScrollDiagnostics.setSelectionActive(true);
|
|
21888
|
+
const payload = {documentSessionId: selectionSession, text: anchor.quote, pageIndex: contents.sectionIndex+1, anchor};
|
|
21889
|
+
nativeMenuSelection = {contents, payload};
|
|
21890
|
+
sendEvent('EPUB_TEXT_SELECTED', payload);
|
|
21619
21891
|
});
|
|
21892
|
+
['rendered','resized','layout','relocated'].forEach(name => rendition.on(name, () => {
|
|
21893
|
+
if (selectionSession === documentSessionId && selectionRendition === rendition) epubAnnotationRenderers.forEach(renderer => renderer.schedule());
|
|
21894
|
+
}));
|
|
21620
21895
|
rendition.on('relocated', (location) => {
|
|
21896
|
+
if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
|
|
21621
21897
|
const start = location && location.start;
|
|
21622
21898
|
let index = start && Number.isInteger(start.index) ? start.index : -1;
|
|
21623
21899
|
if (index < 0 && start && start.href) index = getSpineIndexByHref(start.href);
|
|
21624
21900
|
if (index < 0 || index >= spineItems.length) return;
|
|
21625
21901
|
epubScrollDiagnostics && epubScrollDiagnostics.relocated(location);
|
|
21902
|
+
let pageGeometry;
|
|
21903
|
+
const manager=rendition.manager,layout=manager?.layout;
|
|
21904
|
+
if(epubViewMode==='single' && layout?.divisor===1 && !manager?.settings?.fullsize && manager?.settings?.direction==='ltr'){
|
|
21905
|
+
const visible=manager.visible?.();
|
|
21906
|
+
const view=visible?.find(view=>view.index===index);
|
|
21907
|
+
if(view && manager.container){
|
|
21908
|
+
pageGeometry={direction:'ltr',firstIndex:book.spine.first()?.index,lastIndex:book.spine.last()?.index,pageWidth:layout.pageWidth,offset:manager.container.getBoundingClientRect().left-view.position().left};
|
|
21909
|
+
}
|
|
21910
|
+
}
|
|
21911
|
+
epubLocation=window.PapyrusEpubReader.location(location,spineItems.length,epubViewMode==='single'?'paged':'chapter-scroll',pageGeometry);
|
|
21912
|
+
if(epubLocation){
|
|
21913
|
+
epubLocation.cfi=epubResizeAnchor?.cfi() || epubLocation.cfi;
|
|
21914
|
+
if(book.locations?.length?.()>0)epubLocation.progress=book.locations.percentageFromCfi(epubLocation.cfi);
|
|
21915
|
+
sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
|
|
21916
|
+
}
|
|
21626
21917
|
const nextPage = index + 1;
|
|
21627
21918
|
if (nextPage === currentPage) return;
|
|
21628
21919
|
currentPage = nextPage;
|
|
@@ -21630,21 +21921,23 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21630
21921
|
});
|
|
21631
21922
|
}
|
|
21632
21923
|
|
|
21924
|
+
applyEpubZoom();
|
|
21633
21925
|
sendEpubDiagnostic('epub.display.start', diagnosticPayload);
|
|
21634
21926
|
await withEpubStageTimeout(
|
|
21635
|
-
|
|
21927
|
+
rendition.display(target || spineItems[0]?.href),
|
|
21636
21928
|
'rendition.display',
|
|
21637
21929
|
diagnosticPayload,
|
|
21638
21930
|
);
|
|
21639
21931
|
if (!isCurrentLoad()) throw new Error('EPUB load superseded by a newer load');
|
|
21640
21932
|
sendEpubDiagnostic('epub.display.end', diagnosticPayload);
|
|
21933
|
+
const resizeRendition=rendition;
|
|
21934
|
+
epubResizeAnchor=window.PapyrusEpubReader.installResizeAnchor(resizeRendition.manager,()=>resizeRendition.location?.start?.cfi);
|
|
21641
21935
|
if (
|
|
21642
21936
|
rendition &&
|
|
21643
21937
|
rendition.manager &&
|
|
21644
21938
|
typeof rendition.manager.on === 'function' &&
|
|
21645
21939
|
typeof rendition.on === 'function'
|
|
21646
21940
|
) {
|
|
21647
|
-
let touchStart = null;
|
|
21648
21941
|
let lastScrollOffset = -1;
|
|
21649
21942
|
const manager = rendition.manager;
|
|
21650
21943
|
epubScrollDiagnostics = createEpubScrollDiagnostics(manager);
|
|
@@ -21719,47 +22012,19 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21719
22012
|
return result;
|
|
21720
22013
|
};
|
|
21721
22014
|
}
|
|
21722
|
-
const
|
|
21723
|
-
const touch =
|
|
21724
|
-
(event && event.changedTouches && event.changedTouches[0]) ||
|
|
21725
|
-
(event && event.touches && event.touches[0]);
|
|
21726
|
-
if (!touch) return null;
|
|
21727
|
-
const x = Number(touch.screenX ?? touch.clientX);
|
|
21728
|
-
const y = Number(touch.screenY ?? touch.clientY);
|
|
21729
|
-
return Number.isFinite(x) && Number.isFinite(y) ? { x, y } : null;
|
|
21730
|
-
};
|
|
21731
|
-
const handleScroll = (event) => {
|
|
22015
|
+
const handleScroll = event => {
|
|
21732
22016
|
const offsetY = Math.max(0, Number(event && event.top) || 0);
|
|
21733
22017
|
epubScrollDiagnostics && epubScrollDiagnostics.scroll(event);
|
|
21734
|
-
if (Math.abs(offsetY
|
|
21735
|
-
lastScrollOffset
|
|
21736
|
-
sendEvent('VIEWER_SCROLL',
|
|
21737
|
-
};
|
|
21738
|
-
const handleTouchStart = (event) => {
|
|
21739
|
-
touchStart = getTouchPoint(event);
|
|
21740
|
-
epubScrollDiagnostics && epubScrollDiagnostics.touchStart(event);
|
|
21741
|
-
};
|
|
21742
|
-
const handleTouchMove = (event) => {
|
|
21743
|
-
epubScrollDiagnostics && epubScrollDiagnostics.touchMove(event);
|
|
21744
|
-
};
|
|
21745
|
-
const handleTouchEnd = (event) => {
|
|
21746
|
-
const end = getTouchPoint(event);
|
|
21747
|
-
const start = touchStart;
|
|
21748
|
-
touchStart = null;
|
|
21749
|
-
if (start && end && Math.hypot(end.x - start.x, end.y - start.y) <= 12) {
|
|
21750
|
-
sendEvent('VIEWER_TAP', {});
|
|
21751
|
-
}
|
|
21752
|
-
epubScrollDiagnostics && epubScrollDiagnostics.touchEnd(event);
|
|
22018
|
+
if (Math.abs(offsetY-lastScrollOffset)<1) return;
|
|
22019
|
+
lastScrollOffset=offsetY;
|
|
22020
|
+
sendEvent('VIEWER_SCROLL',{offsetY});
|
|
21753
22021
|
};
|
|
21754
|
-
|
|
21755
22022
|
manager.on('scroll', handleScroll);
|
|
21756
22023
|
const handleScrolled = (event) => {
|
|
21757
22024
|
epubScrollDiagnostics && epubScrollDiagnostics.settled(event);
|
|
21758
22025
|
};
|
|
21759
22026
|
manager.on('scrolled', handleScrolled);
|
|
21760
|
-
|
|
21761
|
-
rendition.on('touchmove', handleTouchMove);
|
|
21762
|
-
rendition.on('touchend', handleTouchEnd);
|
|
22027
|
+
|
|
21763
22028
|
epubInteractionCleanup = () => {
|
|
21764
22029
|
epubSelectionCleanups.forEach((cleanup) => cleanup());
|
|
21765
22030
|
epubSelectionCleanups.clear();
|
|
@@ -21768,16 +22033,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21768
22033
|
if (originalEnqueue) queue.enqueue = originalEnqueue;
|
|
21769
22034
|
if (typeof manager.off === 'function') manager.off('scroll', handleScroll);
|
|
21770
22035
|
if (typeof manager.off === 'function') manager.off('scrolled', handleScrolled);
|
|
21771
|
-
if (typeof rendition.off === 'function') {
|
|
21772
|
-
rendition.off('touchstart', handleTouchStart);
|
|
21773
|
-
rendition.off('touchmove', handleTouchMove);
|
|
21774
|
-
rendition.off('touchend', handleTouchEnd);
|
|
21775
|
-
}
|
|
21776
22036
|
epubScrollDiagnostics = null;
|
|
21777
22037
|
};
|
|
21778
22038
|
}
|
|
21779
|
-
applyEpubZoom();
|
|
21780
|
-
|
|
21781
22039
|
const outline = await withEpubStageTimeout(
|
|
21782
22040
|
buildOutline(),
|
|
21783
22041
|
'outline',
|
|
@@ -21791,6 +22049,8 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21791
22049
|
return { pageCount, outline };
|
|
21792
22050
|
};
|
|
21793
22051
|
|
|
22052
|
+
let epubNavigationQueue = Promise.resolve();
|
|
22053
|
+
let epubNavigationRequest = 0;
|
|
21794
22054
|
const displayEpubPage = async (pageIndex) => {
|
|
21795
22055
|
if (!rendition) return;
|
|
21796
22056
|
const item = spineItems[pageIndex];
|
|
@@ -21800,9 +22060,19 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21800
22060
|
target,
|
|
21801
22061
|
pageIndex,
|
|
21802
22062
|
});
|
|
21803
|
-
|
|
21804
|
-
|
|
21805
|
-
|
|
22063
|
+
const activeRendition = rendition;
|
|
22064
|
+
const session = documentSessionId;
|
|
22065
|
+
const request = ++epubNavigationRequest;
|
|
22066
|
+
const navigation = epubNavigationQueue.catch(() => {}).then(async () => {
|
|
22067
|
+
if (request !== epubNavigationRequest || session !== documentSessionId || activeRendition !== rendition) return;
|
|
22068
|
+
epubResizeAnchor?.invalidate();
|
|
22069
|
+
await activeRendition.display(target);
|
|
22070
|
+
if (request !== epubNavigationRequest || session !== documentSessionId || activeRendition !== rendition) return;
|
|
22071
|
+
currentPage = pageIndex + 1;
|
|
22072
|
+
sendState();
|
|
22073
|
+
});
|
|
22074
|
+
epubNavigationQueue = navigation;
|
|
22075
|
+
await navigation;
|
|
21806
22076
|
};
|
|
21807
22077
|
|
|
21808
22078
|
const getTextContent = async (pageIndex) => {
|
|
@@ -21903,6 +22173,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21903
22173
|
}
|
|
21904
22174
|
};
|
|
21905
22175
|
|
|
22176
|
+
let nativeMenuSelection = null;
|
|
22177
|
+
let epubViewMode = "single";
|
|
22178
|
+
let epubLocation = null;
|
|
22179
|
+
|
|
21906
22180
|
const handleCommand = async (message) => {
|
|
21907
22181
|
const { id, kind, payload } = message;
|
|
21908
22182
|
|
|
@@ -21910,7 +22184,15 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21910
22184
|
if (kind === 'load') {
|
|
21911
22185
|
const generation = (epubLoadGeneration += 1);
|
|
21912
22186
|
currentType = payload.type;
|
|
22187
|
+
documentSessionId = payload.documentSessionId || null;
|
|
22188
|
+
epubAnnotations = [];
|
|
22189
|
+
annotationDocumentId = undefined;
|
|
21913
22190
|
zoom = 1.0;
|
|
22191
|
+
epubViewMode = payload.epubMode === "chapter-scroll" ? "continuous" : "single";
|
|
22192
|
+
epubLocation = null;
|
|
22193
|
+
nativeMenuSelection = null;
|
|
22194
|
+
epubNavigationRequest += 1;
|
|
22195
|
+
epubNavigationQueue = Promise.resolve();
|
|
21914
22196
|
|
|
21915
22197
|
if (currentType === 'text') {
|
|
21916
22198
|
const result = await loadText(
|
|
@@ -21950,6 +22232,43 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21950
22232
|
throw new Error('Unsupported document type');
|
|
21951
22233
|
}
|
|
21952
22234
|
|
|
22235
|
+
if (kind === 'epub-annotations' || kind === 'epub-annotation-navigate') {
|
|
22236
|
+
if (currentType !== 'epub' || !documentSessionId || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB annotation session');
|
|
22237
|
+
if (kind === 'epub-annotations') {
|
|
22238
|
+
const incoming = payload.annotations;
|
|
22239
|
+
if (!Array.isArray(incoming) || incoming.length > 10000 || incoming.some(a => !a || typeof a.id !== 'string' || a.id.length > 256)) throw new Error('Invalid EPUB annotations');
|
|
22240
|
+
const ids = new Set();
|
|
22241
|
+
epubAnnotations = incoming.filter(a => {
|
|
22242
|
+
if (ids.has(a.id) || !window.PapyrusEpubAnnotations.validAnchor(a.anchor)) return false;
|
|
22243
|
+
ids.add(a.id); return true;
|
|
22244
|
+
});
|
|
22245
|
+
annotationDocumentId = typeof payload.documentId === 'string' ? payload.documentId : undefined;
|
|
22246
|
+
annotationLabels = {comment: typeof payload.labels?.comment === 'string' ? payload.labels.comment.slice(0,128) : ''};
|
|
22247
|
+
epubAnnotationRenderers.forEach(renderer => renderer.schedule());
|
|
22248
|
+
} else {
|
|
22249
|
+
const annotation = epubAnnotations.find(a => a.id === payload.annotationId);
|
|
22250
|
+
if (!annotation || (annotation.anchor.documentId && annotation.anchor.documentId !== annotationDocumentId)) throw new Error('Annotation not available for this document');
|
|
22251
|
+
// Navigation uses the CFI, never a synthetic percentage/page rectangle.
|
|
22252
|
+
const navigationSession = documentSessionId;
|
|
22253
|
+
const activeRendition = rendition;
|
|
22254
|
+
// Open the confirmed chapter first, resolve its quote, then navigate its actual range.
|
|
22255
|
+
epubNavigationRequest += 1;
|
|
22256
|
+
const navigation = epubNavigationQueue.catch(() => {}).then(async () => {
|
|
22257
|
+
if(navigationSession !== documentSessionId || activeRendition !== rendition)throw new Error('Stale EPUB navigation');
|
|
22258
|
+
epubResizeAnchor?.invalidate();
|
|
22259
|
+
await activeRendition.display(annotation.anchor.href);
|
|
22260
|
+
if(navigationSession !== documentSessionId || activeRendition !== rendition)throw new Error('Stale EPUB navigation');
|
|
22261
|
+
const contents = activeRendition.getContents().find(c => spineItems[c.sectionIndex]?.href === annotation.anchor.href);
|
|
22262
|
+
const range = contents && window.PapyrusEpubAnnotations.resolveRange(contents,annotation.anchor);
|
|
22263
|
+
if(!range)throw new Error('EPUB anchor unresolved');
|
|
22264
|
+
await activeRendition.display(contents.cfiFromRange(range));
|
|
22265
|
+
});
|
|
22266
|
+
epubNavigationQueue = navigation;
|
|
22267
|
+
await navigation;
|
|
22268
|
+
}
|
|
22269
|
+
sendResponse(id,true,null); return;
|
|
22270
|
+
}
|
|
22271
|
+
|
|
21953
22272
|
if (kind === 'go-to-page') {
|
|
21954
22273
|
const page = Math.max(1, payload.page || 1);
|
|
21955
22274
|
if (currentType === 'text') {
|
|
@@ -21972,12 +22291,55 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21972
22291
|
return;
|
|
21973
22292
|
}
|
|
21974
22293
|
|
|
22294
|
+
if (kind === 'epub-turn-page') {
|
|
22295
|
+
if (epubViewMode !== 'single') {sendResponse(id,true,null); return;}
|
|
22296
|
+
if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB navigation');
|
|
22297
|
+
const active = rendition;
|
|
22298
|
+
epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
|
|
22299
|
+
if (active !== rendition || payload.documentSessionId !== documentSessionId) return;
|
|
22300
|
+
epubResizeAnchor?.invalidate();
|
|
22301
|
+
return payload.direction < 0 ? active.prev() : active.next();
|
|
22302
|
+
});
|
|
22303
|
+
await epubNavigationQueue;
|
|
22304
|
+
sendResponse(id,true,null); return;
|
|
22305
|
+
}
|
|
22306
|
+
|
|
22307
|
+
if (kind === 'set-epub-view-mode') {
|
|
22308
|
+
if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB layout session');
|
|
22309
|
+
const next=payload.epubMode ? (payload.epubMode==='paged'?'single':'continuous') : (payload.viewMode==='single'?'single':'continuous');
|
|
22310
|
+
{
|
|
22311
|
+
epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
|
|
22312
|
+
if(payload.documentSessionId!==documentSessionId || next===epubViewMode)return;
|
|
22313
|
+
const target=epubResizeAnchor?.cfi() || epubLocation?.cfi;
|
|
22314
|
+
epubViewMode=next;
|
|
22315
|
+
await renderEpubRendition('layout',epubLoadGeneration,target);
|
|
22316
|
+
});
|
|
22317
|
+
await epubNavigationQueue;
|
|
22318
|
+
}
|
|
22319
|
+
sendResponse(id,true,null);return;
|
|
22320
|
+
}
|
|
22321
|
+
if(kind === 'epub-go-to-location'){
|
|
22322
|
+
if(currentType!=='epub' || payload.documentSessionId!==documentSessionId || !window.PapyrusEpubReader.validCfi(payload.cfi))throw new Error('Invalid EPUB location');
|
|
22323
|
+
epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(()=>{if(payload.documentSessionId!==documentSessionId)return;epubResizeAnchor?.invalidate();return rendition.display(payload.cfi);});
|
|
22324
|
+
await epubNavigationQueue;sendResponse(id,true,null);return;
|
|
22325
|
+
}
|
|
22326
|
+
|
|
21975
22327
|
if (kind === 'set-zoom') {
|
|
21976
|
-
|
|
21977
|
-
|
|
21978
|
-
|
|
21979
|
-
|
|
21980
|
-
|
|
22328
|
+
const requestedZoom=Math.max(0.5,Math.min(4.0,payload.zoom || 1.0));
|
|
22329
|
+
if(currentType === 'epub') {
|
|
22330
|
+
const session=documentSessionId;
|
|
22331
|
+
epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
|
|
22332
|
+
if(session!==documentSessionId)return;
|
|
22333
|
+
const active=rendition;
|
|
22334
|
+
const cfi=epubResizeAnchor?.cfi() || epubLocation?.cfi;
|
|
22335
|
+
zoom=requestedZoom;applyEpubZoom();
|
|
22336
|
+
// Let the content CSS update before redisplaying the logical anchor.
|
|
22337
|
+
await new Promise(resolve=>(window.requestAnimationFrame || (callback=>setTimeout(callback,0)))(resolve));
|
|
22338
|
+
if(cfi && active===rendition && session===documentSessionId)await active.display(cfi);
|
|
22339
|
+
});
|
|
22340
|
+
await epubNavigationQueue;
|
|
22341
|
+
} else {zoom=requestedZoom;applyZoom();}
|
|
22342
|
+
sendState();sendResponse(id,true,{zoom});return;
|
|
21981
22343
|
}
|
|
21982
22344
|
|
|
21983
22345
|
if (kind === 'set-rotation') {
|
|
@@ -22119,6 +22481,26 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
22119
22481
|
return;
|
|
22120
22482
|
}
|
|
22121
22483
|
|
|
22484
|
+
if (message.type === 'epub-selection-action') {
|
|
22485
|
+
const selected = nativeMenuSelection;
|
|
22486
|
+
if (!selected || message.documentSessionId !== documentSessionId ||
|
|
22487
|
+
selected.payload.documentSessionId !== documentSessionId) return;
|
|
22488
|
+
if (message.key === 'selectAll') {
|
|
22489
|
+
const doc = selected.contents.document;
|
|
22490
|
+
const range = doc.createRange();
|
|
22491
|
+
range.selectNodeContents(doc.body);
|
|
22492
|
+
const selection = selected.contents.window.getSelection();
|
|
22493
|
+
selection.removeAllRanges();
|
|
22494
|
+
selection.addRange(range);
|
|
22495
|
+
return;
|
|
22496
|
+
}
|
|
22497
|
+
if (!['copy','define','highlight','underline','strikeout','comment'].includes(message.key)) return;
|
|
22498
|
+
sendEvent('EPUB_SELECTION_ACTION', {...selected.payload, action: message.key});
|
|
22499
|
+
selected.contents.window.getSelection()?.removeAllRanges();
|
|
22500
|
+
nativeMenuSelection = null;
|
|
22501
|
+
return;
|
|
22502
|
+
}
|
|
22503
|
+
|
|
22122
22504
|
if (!message.kind) return;
|
|
22123
22505
|
handleCommand(message);
|
|
22124
22506
|
};
|