fix(reader): PDF search returned nothing — reactive proxy broke pdf.js; add back-to-location
PDF search diagnosis: extraction and matching were proven correct
against the real 609-page library PDF (pdfjs 5.5.207, incl. the exact
range-transport setup makePDF uses — 841 hits for 'SELECT'), and the
served bundle had every piece. The failure was Alpine's reactivity:
this.book is a plain object, so reading .pdf through component state
returns a reactive Proxy around the PDFDocumentProxy — and pdf.js
v5 uses #private fields, so getPage() through the proxy throws
'cannot read private member', which the empty catch rendered as a
silent empty result set. runPdfSearch now unwraps via Alpine.raw
(falls back to the raw read), and search failures surface in the
drawer ('Search failed — see console') plus console.warn instead of
masquerading as 'No matches'.
Back-to-location stack (research/footnote workflow): the current
position is recorded before every programmatic jump — search-result
clicks, TOC entries, bookmark and highlight jumps — and on every
internal link click (footnotes, cross-references) via foliate's
'link' event. A ↩ button appears in the topbar once a return target
exists; Alt+← works everywhere. Ordinary paging never pollutes the
stack (max depth 50, consecutive duplicates collapse).
This commit is contained in:
+14
-2
@@ -243,6 +243,17 @@ templ ReaderChrome(metadata ReaderMetadata, progress ReadingProgress) {
|
||||
<a id="reader-back" href={ "/media/" + metadata.MediaItemID } class="text-base sm:text-lg hover:underline">
|
||||
← Back
|
||||
</a>
|
||||
<button
|
||||
x-show="backStack.length > 0"
|
||||
@click="goBackToLocation()"
|
||||
class="p-1.5 sm:p-2 rounded-lg hover:bg-gray-700"
|
||||
title="Return to previous location (Alt+←)"
|
||||
aria-label="Return to previous location"
|
||||
>
|
||||
<svg class="reader-icon" width="18" height="18" aria-hidden="true">
|
||||
<path d="M 9 4 A 6 6 0 1 1 4.5 14 M 4.5 14 L 2 11 M 4.5 14 L 8 15"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="text-base sm:text-lg font-semibold hidden sm:block sm:truncate">{ metadata.Title }</h1>
|
||||
<div class="flex items-center gap-1">
|
||||
<button @click="addBookmark()" class="p-1.5 sm:p-2 rounded-lg hover:bg-gray-700" title="Bookmark this position (b)">🏷️</button>
|
||||
@@ -531,10 +542,11 @@ templ ReaderSearchDrawer() {
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
<div class="reader-search-status" x-show="searchQuery || searching || searchGroups.length">
|
||||
<div class="reader-search-status" x-show="searchQuery || searching || searchGroups.length || searchError">
|
||||
<span x-show="searching" x-text="'Searching… ' + Math.round(searchProgress * 100) + '%'">Searching…</span>
|
||||
<span x-show="!searching && searchGroups.length" x-text="searchMatchCount + ' match' + (searchMatchCount === 1 ? '' : 'es')">0 matches</span>
|
||||
<span x-show="!searching && searchQuery && !searchGroups.length">No matches</span>
|
||||
<span x-show="!searching && searchQuery && !searchGroups.length && !searchError">No matches</span>
|
||||
<span x-show="searchError" x-text="searchError" style="color: #f87171;">Search failed</span>
|
||||
</div>
|
||||
<div class="reader-drawer-body">
|
||||
<template x-for="(group, gi) in searchGroups" :key="gi">
|
||||
|
||||
Reference in New Issue
Block a user