@papyrus-sdk/ui-react-native 0.2.35 → 0.2.36
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/dist/index.js +313 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +314 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -8
- package/runtime/epubAnnotations.js +271 -6
- package/runtime/epubReader.js +1 -1
- package/runtime/index.html +284 -8
- package/runtime/runtime.js +284 -8
- package/runtime/comicRuntime.test.ts +0 -241
- package/runtime/documentLoadRuntime.test.ts +0 -172
- package/runtime/epubAnnotations.test.ts +0 -35
- package/runtime/epubReader.test.ts +0 -74
- package/runtime/epubRuntime.test.ts +0 -48
- package/runtime/epubScrollDiagnostics.test.ts +0 -107
- package/runtime/epubSelectionMenu.test.ts +0 -39
package/runtime/index.html
CHANGED
|
@@ -20530,7 +20530,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20530
20530
|
var doc=contents.document,win=contents.window,start=null,blocked=false;
|
|
20531
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
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]'));}
|
|
20533
|
+
function interactive(target){return Boolean(target && target.closest && target.closest('a,button,input,textarea,select,[contenteditable="true"],[data-papyrus-overlay],[data-papyrus-ink-capture]'));}
|
|
20534
20534
|
function begin(e){start=point(e);blocked=e.touches.length!==1 || selected() || interactive(e.target);}
|
|
20535
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
20536
|
function move(e){if(e.touches.length!==1)blocked=true;invalidateScroll(point(e));}
|
|
@@ -20555,6 +20555,84 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20555
20555
|
typeof anchor.href === 'string' && !/^(javascript|data):/i.test(anchor.href) &&
|
|
20556
20556
|
typeof anchor.quote === 'string' && anchor.quote.length > 0 && anchor.quote.length <= 100000;
|
|
20557
20557
|
}
|
|
20558
|
+
function simplifyPath(points, tolerance, maxPoints) {
|
|
20559
|
+
if (!Array.isArray(points) || points.length <= 2) return Array.isArray(points) ? points.slice() : [];
|
|
20560
|
+
tolerance = Number.isFinite(tolerance) ? Math.max(0, tolerance) : 1.5;
|
|
20561
|
+
maxPoints = Number.isSafeInteger(maxPoints) ? Math.max(2, maxPoints) : 512;
|
|
20562
|
+
var keep = new Uint8Array(points.length); keep[0] = 1; keep[points.length - 1] = 1;
|
|
20563
|
+
var stack = [[0, points.length - 1]], toleranceSquared = tolerance * tolerance;
|
|
20564
|
+
while (stack.length) {
|
|
20565
|
+
var interval = stack.pop(), first = interval[0], last = interval[1], a = points[first], b = points[last];
|
|
20566
|
+
var dx = b.x - a.x, dy = b.y - a.y, lengthSquared = dx * dx + dy * dy, maxDistance = toleranceSquared, split = -1;
|
|
20567
|
+
for (var i = first + 1; i < last; i++) {
|
|
20568
|
+
var p = points[i], ratio = lengthSquared ? Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / lengthSquared)) : 0;
|
|
20569
|
+
var px = a.x + ratio * dx, py = a.y + ratio * dy, ox = p.x - px, oy = p.y - py, distance = ox * ox + oy * oy;
|
|
20570
|
+
if (distance > maxDistance) { maxDistance = distance; split = i; }
|
|
20571
|
+
}
|
|
20572
|
+
if (split >= 0) { keep[split] = 1; stack.push([first, split], [split, last]); }
|
|
20573
|
+
}
|
|
20574
|
+
var result = []; for (var j = 0; j < points.length; j++) if (keep[j]) result.push(points[j]);
|
|
20575
|
+
if (result.length <= maxPoints) return result;
|
|
20576
|
+
var capped = []; for (var k = 0; k < maxPoints; k++) capped.push(result[Math.round(k * (result.length - 1) / (maxPoints - 1))]);
|
|
20577
|
+
return capped;
|
|
20578
|
+
}
|
|
20579
|
+
function compactGesturePoints(points, maxPoints) {
|
|
20580
|
+
if (!Array.isArray(points)) return [];
|
|
20581
|
+
maxPoints = Number.isSafeInteger(maxPoints) ? Math.max(2, maxPoints) : 1024;
|
|
20582
|
+
if (points.length <= maxPoints) return points.slice();
|
|
20583
|
+
var compacted = [];
|
|
20584
|
+
for (var i = 0; i < maxPoints; i++) compacted.push(points[Math.round(i * (points.length - 1) / (maxPoints - 1))]);
|
|
20585
|
+
return compacted;
|
|
20586
|
+
}
|
|
20587
|
+
function densifyPath(points, maxStep, maxPoints) {
|
|
20588
|
+
if (!Array.isArray(points) || !points.length) return [];
|
|
20589
|
+
if (points.length === 1) return points.slice();
|
|
20590
|
+
maxStep = Number.isFinite(maxStep) ? Math.max(1, maxStep) : 12;
|
|
20591
|
+
maxPoints = Number.isSafeInteger(maxPoints) ? Math.max(2, maxPoints) : 512;
|
|
20592
|
+
var cumulative = [0], total = 0;
|
|
20593
|
+
for (var i = 1; i < points.length; i++) {
|
|
20594
|
+
if (![points[i-1].x,points[i-1].y,points[i].x,points[i].y].every(Number.isFinite)) return [];
|
|
20595
|
+
total += Math.hypot(points[i].x-points[i-1].x, points[i].y-points[i-1].y);
|
|
20596
|
+
cumulative.push(total);
|
|
20597
|
+
}
|
|
20598
|
+
if (!total) return [points[0], points[points.length-1]];
|
|
20599
|
+
var intervals = Math.min(maxPoints-1, Math.max(1, Math.ceil(total/maxStep))), result = [], segment = 1;
|
|
20600
|
+
for (var sample = 0; sample <= intervals; sample++) {
|
|
20601
|
+
var distance = total*sample/intervals;
|
|
20602
|
+
while (segment < cumulative.length-1 && cumulative[segment] < distance) segment++;
|
|
20603
|
+
var start = points[segment-1], end = points[segment], span = cumulative[segment]-cumulative[segment-1];
|
|
20604
|
+
var ratio = span ? (distance-cumulative[segment-1])/span : 0;
|
|
20605
|
+
result.push({x:start.x+(end.x-start.x)*ratio,y:start.y+(end.y-start.y)*ratio});
|
|
20606
|
+
}
|
|
20607
|
+
return result;
|
|
20608
|
+
}
|
|
20609
|
+
function createSpatialIndex(entries, cellSize) {
|
|
20610
|
+
cellSize = Number.isFinite(cellSize) ? Math.max(8, cellSize) : 64;
|
|
20611
|
+
var cells = new Map();
|
|
20612
|
+
entries.forEach(function(entry) {
|
|
20613
|
+
var left = Math.floor(entry.left / cellSize), right = Math.floor(entry.right / cellSize);
|
|
20614
|
+
var top = Math.floor(entry.top / cellSize), bottom = Math.floor(entry.bottom / cellSize);
|
|
20615
|
+
for (var x = left; x <= right; x++) for (var y = top; y <= bottom; y++) {
|
|
20616
|
+
var key = x + ':' + y, bucket = cells.get(key); if (!bucket) { bucket = []; cells.set(key, bucket); } bucket.push(entry);
|
|
20617
|
+
}
|
|
20618
|
+
});
|
|
20619
|
+
return {cells:cells,cellSize:cellSize};
|
|
20620
|
+
}
|
|
20621
|
+
function queryNearestTextRect(index, x, y, maxDistance) {
|
|
20622
|
+
if (!index || !Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(maxDistance) || maxDistance < 0) return null;
|
|
20623
|
+
var size = index.cellSize, minX = Math.floor((x-maxDistance)/size), maxX = Math.floor((x+maxDistance)/size);
|
|
20624
|
+
var minY = Math.floor((y-maxDistance)/size), maxY = Math.floor((y+maxDistance)/size), seen = new Set(), best = null;
|
|
20625
|
+
for (var cx=minX; cx<=maxX; cx++) for (var cy=minY; cy<=maxY; cy++) {
|
|
20626
|
+
var bucket = index.cells.get(cx+':'+cy); if (!bucket) continue;
|
|
20627
|
+
bucket.forEach(function(entry) {
|
|
20628
|
+
if (seen.has(entry)) return; seen.add(entry);
|
|
20629
|
+
var nearestX = Math.max(entry.left,Math.min(entry.right,x)), nearestY = Math.max(entry.top,Math.min(entry.bottom,y));
|
|
20630
|
+
var dx=x-nearestX,dy=y-nearestY,distance=Math.sqrt(dx*dx+dy*dy);
|
|
20631
|
+
if (distance<=maxDistance && (!best || distance<best.distance)) best={entry:entry,distance:distance,x:nearestX,y:nearestY};
|
|
20632
|
+
});
|
|
20633
|
+
}
|
|
20634
|
+
return best;
|
|
20635
|
+
}
|
|
20558
20636
|
function textNodes(document) {
|
|
20559
20637
|
var walker = document.createTreeWalker(document.body, 4);
|
|
20560
20638
|
var nodes = [], text = '', node;
|
|
@@ -20604,13 +20682,196 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20604
20682
|
if(win.getComputedStyle(doc.body).position==='static')doc.body.style.position='relative';
|
|
20605
20683
|
doc.body.appendChild(overlay);
|
|
20606
20684
|
var registry = new Map(), hitRegions = [];
|
|
20685
|
+
var inkRegistry = new Map(), rangeCache = new Map(), spatialIndex = null, activeGesture = null, inkConfig = {enabled:false,preset:'ink'};
|
|
20686
|
+
var inkSvg = doc.createElementNS('http://www.w3.org/2000/svg','svg');
|
|
20687
|
+
inkSvg.setAttribute('data-papyrus-ink-overlay','');
|
|
20688
|
+
inkSvg.style.cssText = 'position:absolute;left:0;top:0;overflow:visible;pointer-events:none;z-index:1';
|
|
20689
|
+
overlay.appendChild(inkSvg);
|
|
20690
|
+
var inkCanvas = doc.createElement('canvas');
|
|
20691
|
+
inkCanvas.dataset.papyrusInkCapture = '';
|
|
20692
|
+
inkCanvas.style.cssText = 'position:fixed;left:0;top:0;width:1px;height:1px;z-index:2147483000;background:transparent;pointer-events:none;touch-action:none';
|
|
20693
|
+
doc.body.appendChild(inkCanvas);
|
|
20694
|
+
var inkContext = null; try { if(typeof win.CanvasRenderingContext2D==='function')inkContext = inkCanvas.getContext('2d'); } catch (_) {}
|
|
20695
|
+
function resizeCanvas() {
|
|
20696
|
+
var bodyRect=doc.body.getBoundingClientRect(), ratio = Math.max(1,Math.min(3,win.devicePixelRatio || 1));
|
|
20697
|
+
var width=Math.max(1,Math.min(4096,doc.body.clientWidth||bodyRect.width||Math.min(4096,win.innerWidth||1)));
|
|
20698
|
+
var height=Math.max(1,Math.min(4096,doc.body.clientHeight||bodyRect.height||Math.min(4096,win.innerHeight||1)));
|
|
20699
|
+
inkCanvas.style.width=width+'px';inkCanvas.style.height=height+'px';
|
|
20700
|
+
inkCanvas.width = Math.round(width*ratio); inkCanvas.height = Math.round(height*ratio);
|
|
20701
|
+
if (inkContext) { inkContext.setTransform(ratio,0,0,ratio,0,0); inkContext.clearRect(0,0,width,height); }
|
|
20702
|
+
}
|
|
20703
|
+
function collectTextRects() {
|
|
20704
|
+
var walker = doc.createTreeWalker(doc.body,4), node, entries=[];
|
|
20705
|
+
while ((node=walker.nextNode())) {
|
|
20706
|
+
var parent=node.parentElement;
|
|
20707
|
+
if (!parent || parent.closest('script,style,noscript,textarea,[data-papyrus-overlay],[data-papyrus-ink-capture]')) continue;
|
|
20708
|
+
var text=node.nodeValue || '', style=win.getComputedStyle(parent), computed=parseFloat(style.lineHeight);
|
|
20709
|
+
for (var start=0; start<text.length;) {
|
|
20710
|
+
var end=Math.min(text.length,start+24), last=text.charCodeAt(end-1), next=text.charCodeAt(end);
|
|
20711
|
+
if(end<text.length&&last>=0xD800&&last<=0xDBFF&&next>=0xDC00&&next<=0xDFFF)end++;
|
|
20712
|
+
var range=doc.createRange(); range.setStart(node,start); range.setEnd(node,end);
|
|
20713
|
+
var rects=[]; try { rects=Array.from(range.getClientRects()); } catch (_) {}
|
|
20714
|
+
rects.forEach(function(rect) {
|
|
20715
|
+
if (!(rect.width>0 && rect.height>0)) return;
|
|
20716
|
+
entries.push({left:rect.left+win.scrollX,top:rect.top+win.scrollY,right:rect.right+win.scrollX,bottom:rect.bottom+win.scrollY,width:rect.width,height:rect.height,
|
|
20717
|
+
node:node,start:start,end:end,lineHeight:Number.isFinite(computed)&&computed>0?computed:rect.height});
|
|
20718
|
+
});
|
|
20719
|
+
start=end;
|
|
20720
|
+
}
|
|
20721
|
+
}
|
|
20722
|
+
return entries;
|
|
20723
|
+
}
|
|
20724
|
+
function rebuildSpatialIndex() { spatialIndex=createSpatialIndex(collectTextRects(),64); rangeCache.clear(); }
|
|
20725
|
+
function inkViewportExtent() {
|
|
20726
|
+
var root=doc.documentElement,body=doc.body,bodyRect=body.getBoundingClientRect();
|
|
20727
|
+
var width=root.clientWidth||body.clientWidth||bodyRect.width||win.innerWidth||1;
|
|
20728
|
+
var height=root.clientHeight||body.clientHeight||bodyRect.height||win.innerHeight||1;
|
|
20729
|
+
return Math.max(1,Math.min(4096,width),Math.min(4096,height));
|
|
20730
|
+
}
|
|
20731
|
+
function inkStrokeWidthPx(width,preset) {
|
|
20732
|
+
var scale=preset==='highlight'?0.8:preset==='underline'?0.1:0.15;
|
|
20733
|
+
return Math.max(1,Math.min(24,(Number.isFinite(width)?width:0.006)*inkViewportExtent()*scale));
|
|
20734
|
+
}
|
|
20735
|
+
function closestGlyph(entry,x,y,maxDistance) {
|
|
20736
|
+
var source=(entry.node.nodeValue || '').slice(entry.start,entry.end), best=null, offset=0;
|
|
20737
|
+
for (var glyph of source) {
|
|
20738
|
+
var range=doc.createRange(); range.setStart(entry.node,entry.start+offset); range.setEnd(entry.node,entry.start+offset+glyph.length); offset+=glyph.length;
|
|
20739
|
+
var rects=[]; try { rects=Array.from(range.getClientRects()); } catch (_) {}
|
|
20740
|
+
rects.forEach(function(rect) {
|
|
20741
|
+
if (!(rect.width>0 && rect.height>0)) return;
|
|
20742
|
+
var nx=Math.max(rect.left+win.scrollX,Math.min(rect.right+win.scrollX,x)), ny=Math.max(rect.top+win.scrollY,Math.min(rect.bottom+win.scrollY,y));
|
|
20743
|
+
var dx=x-nx,dy=y-ny,distance=Math.sqrt(dx*dx+dy*dy);
|
|
20744
|
+
if (distance<=maxDistance && (!best || distance<best.distance)) best={range:range,rect:rect,distance:distance};
|
|
20745
|
+
});
|
|
20746
|
+
}
|
|
20747
|
+
if (!best || typeof contents.cfiFromRange!=='function') return null;
|
|
20748
|
+
var quote=best.range.toString(), cfiRange; try { cfiRange=contents.cfiFromRange(best.range); } catch (_) { return null; }
|
|
20749
|
+
if (!quote || typeof cfiRange!=='string' || !/^epubcfi\([^\n<>]+\)$/.test(cfiRange)) return null;
|
|
20750
|
+
var lineHeight=Math.max(1,entry.lineHeight || best.rect.height), px=x-(best.rect.left+win.scrollX), py=y-(best.rect.top+win.scrollY);
|
|
20751
|
+
return {cfiRange:cfiRange,quote:quote,x:Math.max(-3,Math.min(3,px/lineHeight)),y:Math.max(-3,Math.min(3,py/lineHeight))};
|
|
20752
|
+
}
|
|
20753
|
+
function renderInkAnnotation(annotation,keep,bodyRect) {
|
|
20754
|
+
var baseRect=bodyRect || doc.body.getBoundingClientRect() || {left:0,top:0};
|
|
20755
|
+
var data=annotation.epubInk;
|
|
20756
|
+
if (!data || data.version!==1 || data.kind!=='epub-ink' || !Array.isArray(data.segments)) return;
|
|
20757
|
+
keep.add(annotation.id);
|
|
20758
|
+
var group=inkRegistry.get(annotation.id);
|
|
20759
|
+
if (!group) { group=doc.createElementNS('http://www.w3.org/2000/svg','g'); group.setAttribute('data-epub-ink-id',annotation.id); inkSvg.appendChild(group); inkRegistry.set(annotation.id,group); }
|
|
20760
|
+
group.replaceChildren();
|
|
20761
|
+
var color=/^#[0-9a-f]{6}$/i.test(annotation.color)?annotation.color:'#2563eb';
|
|
20762
|
+
var opacity=Number.isFinite(annotation.opacity)?Math.max(0,Math.min(1,annotation.opacity)):1;
|
|
20763
|
+
var preset=['ink','highlight','underline'].indexOf(data.preset)>=0?data.preset:'ink';
|
|
20764
|
+
var stroke=inkStrokeWidthPx(annotation.strokeWidth,preset);
|
|
20765
|
+
data.segments.forEach(function(segment) {
|
|
20766
|
+
if (segment.href!==options.href || !Array.isArray(segment.points)) return;
|
|
20767
|
+
var paths=[], current=[];
|
|
20768
|
+
segment.points.forEach(function(point) {
|
|
20769
|
+
var range=rangeCache.get(point.cfiRange);
|
|
20770
|
+
if (!range) { try { range=contents.range(point.cfiRange); } catch (_) { range=null; } if (range) rangeCache.set(point.cfiRange,range); }
|
|
20771
|
+
if (!range || range.toString()!==point.quote) { if(current.length>1)paths.push(current);current=[];return; }
|
|
20772
|
+
var rect; try { rect=range.getBoundingClientRect(); } catch (_) { rect=null; }
|
|
20773
|
+
if (!rect || !(rect.width>0 && rect.height>0)) { if(current.length>1)paths.push(current);current=[];return; }
|
|
20774
|
+
var lineHeight=Math.max(1,rect.height), x=rect.left-baseRect.left+point.x*lineHeight, y=rect.top-baseRect.top+point.y*lineHeight;
|
|
20775
|
+
var previous=current[current.length-1], jumpLimit=Math.max(24,lineHeight*2.5);
|
|
20776
|
+
if (previous && Math.hypot(x-previous.x,y-previous.y)>jumpLimit) { if(current.length>1)paths.push(current);current=[]; }
|
|
20777
|
+
current.push({x:x,y:y,lineHeight:lineHeight});
|
|
20778
|
+
});
|
|
20779
|
+
if(current.length>1)paths.push(current);
|
|
20780
|
+
paths.forEach(function(points) {
|
|
20781
|
+
var d='M '+points[0].x.toFixed(1)+' '+points[0].y.toFixed(1);
|
|
20782
|
+
for(var i=1;i<points.length;i++){var prev=points[i-1],point=points[i],mx=(prev.x+point.x)/2,my=(prev.y+point.y)/2;d+=' Q '+prev.x.toFixed(1)+' '+prev.y.toFixed(1)+' '+mx.toFixed(1)+' '+my.toFixed(1);}
|
|
20783
|
+
var last=points[points.length-1];d+=' L '+last.x.toFixed(1)+' '+last.y.toFixed(1);
|
|
20784
|
+
var path=doc.createElementNS('http://www.w3.org/2000/svg','path');path.setAttribute('d',d);path.setAttribute('fill','none');path.setAttribute('stroke',color);path.setAttribute('stroke-width',String(stroke));path.setAttribute('stroke-linecap','round');path.setAttribute('stroke-linejoin','round');path.setAttribute('opacity',String(opacity));group.appendChild(path);
|
|
20785
|
+
});
|
|
20786
|
+
});
|
|
20787
|
+
}
|
|
20788
|
+
function clearPreview() {
|
|
20789
|
+
if(inkContext)inkContext.clearRect(0,0,inkCanvas.width,inkCanvas.height);
|
|
20790
|
+
inkSvg.querySelectorAll('[data-papyrus-ink-preview]').forEach(function(path){path.remove();});
|
|
20791
|
+
}
|
|
20792
|
+
function createPreviewPath(x,y) {
|
|
20793
|
+
var path=doc.createElementNS('http://www.w3.org/2000/svg','path');
|
|
20794
|
+
path.setAttribute('data-papyrus-ink-preview','');path.setAttribute('d','M '+x.toFixed(1)+' '+y.toFixed(1));path.setAttribute('fill','none');
|
|
20795
|
+
path.setAttribute('stroke',inkConfig.color);path.setAttribute('stroke-width',String(inkStrokeWidthPx(inkConfig.strokeWidth,inkConfig.preset)));
|
|
20796
|
+
path.setAttribute('stroke-linecap','round');path.setAttribute('stroke-linejoin','round');path.setAttribute('opacity',String(inkConfig.opacity));
|
|
20797
|
+
path.style.pointerEvents='none';inkSvg.appendChild(path);return path;
|
|
20798
|
+
}
|
|
20799
|
+
function updatePreviewPath(clientX,clientY) {
|
|
20800
|
+
var bodyRect=doc.body.getBoundingClientRect(),x=clientX-bodyRect.left,y=clientY-bodyRect.top;
|
|
20801
|
+
var gesture=activeGesture;
|
|
20802
|
+
if(!gesture.previewPath||gesture.previewPathPoints>=32){
|
|
20803
|
+
gesture.previewPath=createPreviewPath(gesture.previewLast?gesture.previewLast.x:x,gesture.previewLast?gesture.previewLast.y:y);
|
|
20804
|
+
gesture.previewPathPoints=1;
|
|
20805
|
+
}
|
|
20806
|
+
var pathData=gesture.previewPath.getAttribute('d')||'';
|
|
20807
|
+
gesture.previewPath.setAttribute('d',pathData+' L '+x.toFixed(1)+' '+y.toFixed(1));
|
|
20808
|
+
gesture.previewPathPoints++;
|
|
20809
|
+
gesture.previewLast={x:x,y:y};
|
|
20810
|
+
}
|
|
20811
|
+
function cancelGesture() {
|
|
20812
|
+
var gesture=activeGesture; activeGesture=null; clearPreview();
|
|
20813
|
+
if(gesture)try{inkCanvas.releasePointerCapture(gesture.pointerId);}catch(_){}
|
|
20814
|
+
}
|
|
20815
|
+
function commitGesture() {
|
|
20816
|
+
var gesture=activeGesture; activeGesture=null; clearPreview();
|
|
20817
|
+
if(!gesture || !alive || !options.isCurrent() || !inkConfig.enabled || !spatialIndex) return;
|
|
20818
|
+
var simplified=simplifyPath(gesture.points,1.5,512), anchorSamples=densifyPath(simplified,12,512), segments=[], current=[];
|
|
20819
|
+
anchorSamples.forEach(function(point) {
|
|
20820
|
+
var coarse=queryNearestTextRect(spatialIndex,point.x,point.y,28);
|
|
20821
|
+
var cutoff=coarse?Math.max(12,Math.min(28,0.8*coarse.entry.lineHeight)):12;
|
|
20822
|
+
var anchored=coarse && closestGlyph(coarse.entry,point.x,point.y,cutoff);
|
|
20823
|
+
if(!anchored){if(current.length>1)segments.push({href:options.href,spineIndex:options.spineIndex,points:current});current=[];return;}
|
|
20824
|
+
current.push(anchored);
|
|
20825
|
+
});
|
|
20826
|
+
if(current.length>1)segments.push({href:options.href,spineIndex:options.spineIndex,points:current});
|
|
20827
|
+
segments=segments.slice(0,64);
|
|
20828
|
+
var pointCount=segments.reduce(function(total,segment){return total+segment.points.length;},0);
|
|
20829
|
+
if(!pointCount)return;
|
|
20830
|
+
var width=Math.max(1,doc.documentElement.scrollWidth,win.innerWidth),height=Math.max(1,doc.documentElement.scrollHeight,win.innerHeight);
|
|
20831
|
+
var normalized=simplified.map(function(p){return {x:Math.max(0,Math.min(1,p.x/width)),y:Math.max(0,Math.min(1,p.y/height))};});
|
|
20832
|
+
var minX=Math.min.apply(null,normalized.map(function(p){return p.x;})),maxX=Math.max.apply(null,normalized.map(function(p){return p.x;}));
|
|
20833
|
+
var minY=Math.min.apply(null,normalized.map(function(p){return p.y;})),maxY=Math.max.apply(null,normalized.map(function(p){return p.y;}));
|
|
20834
|
+
var first=segments[0].points[0], href=segments[0].href, documentId=typeof options.documentId==='function'?options.documentId():options.documentId;
|
|
20835
|
+
var annotation={id:'epub-ink-'+Date.now()+'-'+Math.random().toString(36).slice(2,9),type:'ink',pageIndex:(options.spineIndex||0)+1,
|
|
20836
|
+
rect:{x:minX,y:minY,width:Math.min(1-minX,Math.max(0.001,maxX-minX)),height:Math.min(1-minY,Math.max(0.001,maxY-minY))},path:normalized,color:inkConfig.color,opacity:inkConfig.opacity,strokeWidth:inkConfig.strokeWidth,createdAt:Date.now(),content:first.quote,
|
|
20837
|
+
anchor:{version:1,kind:'epub-cfi',cfiRange:first.cfiRange,href:href,spineIndex:options.spineIndex,documentId:documentId,quote:first.quote},
|
|
20838
|
+
epubInk:{version:1,kind:'epub-ink',documentId:documentId,preset:inkConfig.preset,segments:segments}};
|
|
20839
|
+
if(typeof options.onInkCommit==='function')options.onInkCommit(annotation);
|
|
20840
|
+
}
|
|
20841
|
+
function pointerDown(event) {
|
|
20842
|
+
if(!inkConfig.enabled || !alive || !options.isCurrent() || event.button!==undefined && event.button!==0)return;
|
|
20843
|
+
if(activeGesture){cancelGesture();return;}
|
|
20844
|
+
event.preventDefault();event.stopPropagation();
|
|
20845
|
+
activeGesture={pointerId:event.pointerId,points:[{x:event.clientX+win.scrollX,y:event.clientY+win.scrollY}],last:{x:event.clientX,y:event.clientY},previewPath:null,previewPathPoints:0,previewLast:null};
|
|
20846
|
+
updatePreviewPath(event.clientX,event.clientY);
|
|
20847
|
+
try{inkCanvas.setPointerCapture(event.pointerId);}catch(_){}
|
|
20848
|
+
}
|
|
20849
|
+
function pointerMove(event) {
|
|
20850
|
+
if(!activeGesture || activeGesture.pointerId!==event.pointerId)return;
|
|
20851
|
+
if(!options.isCurrent()||!inkConfig.enabled){cancelGesture();return;}
|
|
20852
|
+
event.preventDefault();event.stopPropagation();
|
|
20853
|
+
var point={x:event.clientX+win.scrollX,y:event.clientY+win.scrollY};activeGesture.points.push(point);
|
|
20854
|
+
if(activeGesture.points.length>2048)activeGesture.points=compactGesturePoints(activeGesture.points,1024);
|
|
20855
|
+
if(inkContext){inkContext.beginPath();inkContext.moveTo(activeGesture.last.x,activeGesture.last.y);inkContext.lineTo(event.clientX,event.clientY);inkContext.strokeStyle=inkConfig.color;inkContext.globalAlpha=inkConfig.opacity;inkContext.lineWidth=inkStrokeWidthPx(inkConfig.strokeWidth,inkConfig.preset);inkContext.lineCap='round';inkContext.lineJoin='round';inkContext.stroke();}
|
|
20856
|
+
updatePreviewPath(event.clientX,event.clientY);
|
|
20857
|
+
activeGesture.last={x:event.clientX,y:event.clientY};
|
|
20858
|
+
}
|
|
20859
|
+
function pointerUp(event) {if(!activeGesture || activeGesture.pointerId!==event.pointerId)return;event.preventDefault();event.stopPropagation();var end={x:event.clientX+win.scrollX,y:event.clientY+win.scrollY},last=activeGesture.points[activeGesture.points.length-1];if(Math.hypot(end.x-last.x,end.y-last.y)>0.5){activeGesture.points.push(end);updatePreviewPath(event.clientX,event.clientY);}commitGesture();}
|
|
20860
|
+
function pointerCancel(event) {if(activeGesture && (event.pointerId===undefined || activeGesture.pointerId===event.pointerId))cancelGesture();}
|
|
20861
|
+
resizeCanvas();rebuildSpatialIndex();
|
|
20862
|
+
inkCanvas.addEventListener('pointerdown',pointerDown);inkCanvas.addEventListener('pointermove',pointerMove);inkCanvas.addEventListener('pointerup',pointerUp);inkCanvas.addEventListener('pointercancel',pointerCancel);inkCanvas.addEventListener('lostpointercapture',pointerCancel);
|
|
20863
|
+
win.addEventListener('blur',pointerCancel);win.addEventListener('resize',resizeCanvas);
|
|
20607
20864
|
function render() {
|
|
20608
20865
|
frame = 0; if (!alive || !options.isCurrent()) return;
|
|
20609
|
-
var keep = new Set(), noteGroups = new Map();
|
|
20866
|
+
var keep = new Set(), keepInk = new Set(), noteGroups = new Map();
|
|
20610
20867
|
hitRegions = [];
|
|
20868
|
+
var bodyRect=doc.body.getBoundingClientRect() || {left:0,top:0};
|
|
20869
|
+
inkSvg.setAttribute('width',String(Math.max(doc.documentElement.scrollWidth,win.innerWidth)));
|
|
20870
|
+
inkSvg.setAttribute('height',String(Math.max(doc.documentElement.scrollHeight,win.innerHeight)));
|
|
20611
20871
|
options.annotations().forEach(function(annotation) {
|
|
20612
20872
|
var anchor = annotation.anchor;
|
|
20613
20873
|
if (!validAnchor(anchor) || anchor.href !== options.href || anchor.documentId && options.documentId && anchor.documentId !== options.documentId) return;
|
|
20874
|
+
if(annotation.type==='ink' && annotation.epubInk){renderInkAnnotation(annotation,keepInk,bodyRect);return;}
|
|
20614
20875
|
var range = resolveRange(contents,anchor); if (!range) return;
|
|
20615
20876
|
var rects = Array.from(range.getClientRects()).filter(function(r){return r.width>0 && r.height>0;});
|
|
20616
20877
|
if (!rects.length) return;
|
|
@@ -20649,22 +20910,26 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20649
20910
|
group.button.addEventListener('click',function(e){e.stopPropagation();if(options.isCurrent())options.onTap(group.ids[0],group.ids);});
|
|
20650
20911
|
});
|
|
20651
20912
|
registry.forEach(function(group,id){if (!keep.has(id)) {group.remove();registry.delete(id);}});
|
|
20913
|
+
inkRegistry.forEach(function(group,id){if (!keepInk.has(id)) {group.remove();inkRegistry.delete(id);}});
|
|
20652
20914
|
}
|
|
20653
20915
|
function schedule() { if (alive && !frame) frame = win.requestAnimationFrame(render); }
|
|
20916
|
+
function rebuildAndSchedule(){if(!alive)return;rebuildSpatialIndex();schedule();}
|
|
20917
|
+
function handleResize(){resizeCanvas();rebuildAndSchedule();}
|
|
20918
|
+
function handleDocumentLoad(){rebuildAndSchedule();}
|
|
20654
20919
|
function tapMarkup(event) {
|
|
20655
20920
|
if(!alive || !options.isCurrent() || String(win.getSelection() || '').length || event.target.closest('[data-papyrus-overlay]'))return;
|
|
20656
20921
|
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
20922
|
if(hit) {event.stopPropagation();options.onTap(hit.id);}
|
|
20658
20923
|
}
|
|
20659
20924
|
doc.addEventListener('click',tapMarkup);
|
|
20660
|
-
var observer = typeof win.ResizeObserver === 'function' ? new win.ResizeObserver(
|
|
20925
|
+
var observer = typeof win.ResizeObserver === 'function' ? new win.ResizeObserver(rebuildAndSchedule) : null;
|
|
20661
20926
|
if (observer) observer.observe(doc.body);
|
|
20662
|
-
win.addEventListener('resize',
|
|
20663
|
-
if (doc.fonts && doc.fonts.ready) doc.fonts.ready.then(schedule);
|
|
20927
|
+
win.addEventListener('resize',handleResize);win.addEventListener('scroll',schedule); doc.addEventListener('load',handleDocumentLoad,true);
|
|
20928
|
+
if (doc.fonts && doc.fonts.ready) doc.fonts.ready.then(function(){if(alive){rebuildSpatialIndex();schedule();}});
|
|
20664
20929
|
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',
|
|
20930
|
+
return {schedule:schedule, setInkMode:function(config){var preset=['ink','highlight','underline'].indexOf(config?.preset)>=0?config.preset:'ink';inkConfig={enabled:!!config?.enabled,preset:preset,color:/^#[0-9a-f]{6}$/i.test(config?.color)?config.color:'#2563eb',opacity:Number.isFinite(config?.opacity)?Math.max(0,Math.min(1,config.opacity)):1,strokeWidth:Number.isFinite(config?.strokeWidth)?Math.max(0.0025,Math.min(0.02,config.strokeWidth)):0.006};inkCanvas.style.pointerEvents=inkConfig.enabled?'auto':'none';if(!inkConfig.enabled)cancelGesture();}, invalidateLayout:rebuildAndSchedule, 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;cancelGesture();if(frame)win.cancelAnimationFrame(frame);if(observer)observer.disconnect();win.removeEventListener('resize',handleResize);win.removeEventListener('scroll',schedule);win.removeEventListener('blur',pointerCancel);doc.removeEventListener('load',handleDocumentLoad,true);doc.removeEventListener('click',tapMarkup);inkCanvas.removeEventListener('pointerdown',pointerDown);inkCanvas.removeEventListener('pointermove',pointerMove);inkCanvas.removeEventListener('pointerup',pointerUp);inkCanvas.removeEventListener('pointercancel',pointerCancel);inkCanvas.removeEventListener('lostpointercapture',pointerCancel);inkCanvas.remove();overlay.remove();doc.body.style.position=originalPosition;registry.clear();inkRegistry.clear();rangeCache.clear();}};
|
|
20666
20931
|
}
|
|
20667
|
-
return {validAnchor:validAnchor,recoverRange:recoverRange,resolveRange:resolveRange,selection:selection,install:install};
|
|
20932
|
+
return {validAnchor:validAnchor,simplifyPath:simplifyPath,compactGesturePoints:compactGesturePoints,densifyPath:densifyPath,createSpatialIndex:createSpatialIndex,queryNearestTextRect:queryNearestTextRect,recoverRange:recoverRange,resolveRange:resolveRange,selection:selection,install:install};
|
|
20668
20933
|
});
|
|
20669
20934
|
|
|
20670
20935
|
/* @papyrus-epub-annotations:end */
|
|
@@ -20680,6 +20945,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
20680
20945
|
let annotationDocumentId;
|
|
20681
20946
|
let annotationLabels = {};
|
|
20682
20947
|
let epubAnnotations = [];
|
|
20948
|
+
let epubInkMode = {enabled:false,color:'#2563eb',opacity:1,strokeWidth:0.006};
|
|
20683
20949
|
const epubAnnotationRenderers = new Map();
|
|
20684
20950
|
let spineItems = [];
|
|
20685
20951
|
let textPages = [];
|
|
@@ -21794,11 +22060,14 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21794
22060
|
if (href && window.PapyrusEpubAnnotations) {
|
|
21795
22061
|
const renderer = window.PapyrusEpubAnnotations.install(contents, {
|
|
21796
22062
|
href, get documentId() { return annotationDocumentId; },
|
|
22063
|
+
spineIndex:contents.sectionIndex,
|
|
21797
22064
|
isCurrent: () => session === documentSessionId && activeRendition === rendition,
|
|
21798
22065
|
pageWidth: () => activeRendition.layout?.width || viewer.clientWidth,
|
|
21799
22066
|
annotations: () => epubAnnotations, labels: () => annotationLabels,
|
|
22067
|
+
onInkCommit: annotation => sendEvent('EPUB_INK_CREATED',{documentSessionId:session,annotation}),
|
|
21800
22068
|
onTap: (id, ids) => sendEvent("EPUB_ANNOTATION_TAP", {documentSessionId: session, id, ids}),
|
|
21801
22069
|
});
|
|
22070
|
+
renderer.setInkMode(epubInkMode);
|
|
21802
22071
|
epubAnnotationRenderers.set(contents,renderer);
|
|
21803
22072
|
}
|
|
21804
22073
|
const frame = contents && contents.document ? contents.document.defaultView.frameElement : null;
|
|
@@ -21890,7 +22159,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
21890
22159
|
sendEvent('EPUB_TEXT_SELECTED', payload);
|
|
21891
22160
|
});
|
|
21892
22161
|
['rendered','resized','layout','relocated'].forEach(name => rendition.on(name, () => {
|
|
21893
|
-
if (selectionSession === documentSessionId && selectionRendition === rendition) epubAnnotationRenderers.forEach(renderer => renderer.schedule());
|
|
22162
|
+
if (selectionSession === documentSessionId && selectionRendition === rendition) epubAnnotationRenderers.forEach(renderer => name==='relocated'?renderer.schedule():renderer.invalidateLayout());
|
|
21894
22163
|
}));
|
|
21895
22164
|
rendition.on('relocated', (location) => {
|
|
21896
22165
|
if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
|
|
@@ -22187,6 +22456,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
22187
22456
|
documentSessionId = payload.documentSessionId || null;
|
|
22188
22457
|
epubAnnotations = [];
|
|
22189
22458
|
annotationDocumentId = undefined;
|
|
22459
|
+
epubInkMode = {enabled:false,color:'#2563eb',opacity:1,strokeWidth:0.006};
|
|
22190
22460
|
zoom = 1.0;
|
|
22191
22461
|
epubViewMode = payload.epubMode === "chapter-scroll" ? "continuous" : "single";
|
|
22192
22462
|
epubLocation = null;
|
|
@@ -22318,6 +22588,12 @@ https://github.com/nodeca/pako/blob/main/LICENSE
|
|
|
22318
22588
|
}
|
|
22319
22589
|
sendResponse(id,true,null);return;
|
|
22320
22590
|
}
|
|
22591
|
+
if (kind === 'set-epub-ink-mode') {
|
|
22592
|
+
if(currentType!=='epub'||!documentSessionId||payload.documentSessionId!==documentSessionId)throw new Error('Stale EPUB ink session');
|
|
22593
|
+
epubInkMode={enabled:payload.enabled===true,preset:['ink','highlight','underline'].indexOf(payload.preset)>=0?payload.preset:'ink',color:/^#[0-9a-f]{6}$/i.test(payload.color||'')?payload.color:'#2563eb',opacity:Number.isFinite(payload.opacity)?Math.max(0,Math.min(1,payload.opacity)):1,strokeWidth:Number.isFinite(payload.strokeWidth)?Math.max(0.0025,Math.min(0.02,payload.strokeWidth)):0.006};
|
|
22594
|
+
epubAnnotationRenderers.forEach(renderer=>renderer.setInkMode(epubInkMode));
|
|
22595
|
+
sendResponse(id,true,null);return;
|
|
22596
|
+
}
|
|
22321
22597
|
if(kind === 'epub-go-to-location'){
|
|
22322
22598
|
if(currentType!=='epub' || payload.documentSessionId!==documentSessionId || !window.PapyrusEpubReader.validCfi(payload.cfi))throw new Error('Invalid EPUB location');
|
|
22323
22599
|
epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(()=>{if(payload.documentSessionId!==documentSessionId)return;epubResizeAnchor?.invalidate();return rendition.display(payload.cfi);});
|