Skip to content

Commit 14615eb

Browse files
committed
πŸ› Order-agnostic page-range cfi test for inverted epub.js spans
epub.js can report a page's start cfi *after* its end cfi for a reflowable chapter wedged between fixed-layout image spreads (same root cause as the TTS-start fix). Two range checks assumed start <= end and silently broke on such pages: - isSegmentOnCurrentPage: always false β†’ during listen, TTS needlessly re-navigated the reader on every segment. - openPlayer staleness check: a still-on-page stored TTS index could be misclassified as stale. Extract one shared `isCFIWithinPageRange` (app/utils/epub.ts) that tests membership without assuming bound order β€” two compares, no allocation, no duplicated logic or cross-referencing comments. No-op for normal pages where start <= end already.
1 parent 43936df commit 14615eb

3 files changed

Lines changed: 24 additions & 5 deletions

File tree

β€Žapp/composables/use-tts-player-modal.tsβ€Ž

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@ export function useTTSPlayerModal(options: TTSPlayerOptions) {
7878
let isStoredIndexStale = false
7979
if (storedSegmentCFI && cfi && pageEndCFI) {
8080
try {
81-
isStoredIndexStale = epubCFI.compare(storedSegmentCFI, cfi) < 0
82-
|| epubCFI.compare(storedSegmentCFI, pageEndCFI) > 0
81+
isStoredIndexStale = !isCFIWithinPageRange(epubCFI, storedSegmentCFI, cfi, pageEndCFI)
8382
}
8483
catch {
8584
// Treat malformed/unsupported CFIs as stale so we fall back to the

β€Žapp/pages/reader/epub.vueβ€Ž

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,10 +538,11 @@ let pendingTTSDisplayCfi: string | null = null
538538
const epubCFI = new EpubCFI()
539539
540540
function isSegmentOnCurrentPage(segmentCfi: string): boolean {
541-
if (!currentPageStartCfi.value || !currentPageEndCfi.value) return false
541+
const start = currentPageStartCfi.value
542+
const end = currentPageEndCfi.value
543+
if (!start || !end) return false
542544
try {
543-
return epubCFI.compare(segmentCfi, currentPageStartCfi.value) >= 0
544-
&& epubCFI.compare(segmentCfi, currentPageEndCfi.value) <= 0
545+
return isCFIWithinPageRange(epubCFI, segmentCfi, start, end)
545546
}
546547
catch {
547548
return false

β€Žapp/utils/epub.tsβ€Ž

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
import { EpubCFI } from '@likecoin/epub-ts'
22

3+
/**
4+
* Whether `cfi` lies within the page span bounded by `pageBoundA` and
5+
* `pageBoundB` (inclusive), without assuming which bound is the lower one.
6+
* epub.js can report a page's start cfi *after* its end cfi for a reflowable
7+
* chapter wedged between fixed-layout image spreads, so the membership test
8+
* must be order-agnostic. May throw on a malformed cfi (via `compare`);
9+
* callers guard with try/catch.
10+
*/
11+
export function isCFIWithinPageRange(
12+
epubCFI: EpubCFI,
13+
cfi: string,
14+
pageBoundA: string,
15+
pageBoundB: string,
16+
): boolean {
17+
const a = epubCFI.compare(cfi, pageBoundA)
18+
const b = epubCFI.compare(cfi, pageBoundB)
19+
return (a >= 0 && b <= 0) || (a <= 0 && b >= 0)
20+
}
21+
322
/**
423
* Resolve the first text node at or after the DOM position (container, offset).
524
* For element containers, `offset` indexes into childNodes per the DOM Range spec,

0 commit comments

Comments
Β (0)