Recently Written · git

scan-subread

PDF reader that follows an audiobook with the SubRead suite

git clone https://github.com/equwal/scan-subread

Log | Files | Refs


commit 41adec05fcc2ede8260870bce8476aca72832987
truex <truex@equwal.com>
2026-09-26 14:51:23 -0700

Mark only one cue in the list, and scroll a new page after a resize

After a new PDF, the cue list could keep the mark of the old cue,
because the list removed the mark by the index of the cue before. The
list now removes the mark from the item that has it.

The page view decided "new page" when the render started. A resize
during a page turn then showed the new page without a scroll to its
mark or its top. The view now decides when the render ends, from the
page on the canvas.

 src/main.ts |  5 ++---
 src/view.ts | 16 ++++++++++------
 2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/src/main.ts b/src/main.ts
index 27486c4..48e750e 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -477,9 +477,8 @@ function renderCueList(): void {
 }
 
 function markCueInList(i: number): void {
-  const items = ui.cues.children;
-  items[state.activeCue]?.classList.remove('active');
-  items[i]?.classList.add('active');
+  ui.cues.querySelector('.active')?.classList.remove('active');
+  ui.cues.children[i]?.classList.add('active');
   scrollCueList(i);
 }
 
diff --git a/src/view.ts b/src/view.ts
index 46e4f87..7951c0a 100644
--- a/src/view.ts
+++ b/src/view.ts
@@ -104,8 +104,12 @@ export function createPageView(
     scrollTo(scrollTarget(extent, view, v.scrollHeight - v.clientHeight), smooth);
   }
 
-  /** Renders the page. `turn`: a new page, so scroll to its mark or to its top. */
-  async function render(turn: boolean): Promise<void> {
+  /**
+   * Renders the page to show. When it is another page than the page on
+   * the canvas, the viewer scrolls to its mark, else to its top. Else the
+   * mark stays in view.
+   */
+  async function render(): Promise<void> {
     const doc = pdf;
     if (!doc || index < 0) return;
     const my = ++seq;
@@ -115,6 +119,7 @@ export function createPageView(
     const width = Math.round(Math.min(MAX_RENDER, Math.max(300, cssWidth * dpr)));
     const c = await doc.renderPage(at, width);
     if (my !== seq) return; // A newer render replaced this one.
+    const turn = doc !== shown.pdf || at !== shown.index;
     // A new canvas can change the height of the content, and the browser
     // then moves the scroll position. That scroll does not come from the user.
     autoUntil = performance.now() + AUTO_SCROLL_MS;
@@ -155,7 +160,7 @@ export function createPageView(
   }
 
   // Render again when the width of the page changes, for example after a
-  // rotation. The canvas stretches at once; the new render makes it sharp.
+  // rotation. The canvas stretches at once. The new render makes it sharp.
   let resizeTimer: ReturnType<typeof setTimeout> | undefined;
   new ResizeObserver(() => {
     clearTimeout(resizeTimer);
@@ -163,17 +168,16 @@ export function createPageView(
       const dpr = window.devicePixelRatio || 1;
       const width = ui.page.clientWidth;
       if (width > 0 && (Math.abs(width - shown.cssWidth) >= 1 || dpr !== shown.dpr)) {
-        void render(false);
+        void render();
       }
     }, RESIZE_MS);
   }).observe(ui.viewer);
 
   return {
     show(doc, i) {
-      const turn = doc !== shown.pdf || i !== shown.index;
       pdf = doc;
       index = i;
-      return render(turn);
+      return render();
     },
     mark() {
       keepInView(draw(), true);