[object Object]

← back to All Designerwallcoverings

Fix stuck infinite scroll: pump on live sentinel geometry, not stale observer flag

5cdaf8ab40796b4c7596fc9b105d35594cd890ee · 2026-07-08 08:47:36 -0700 · Steve

Files touched

Diff

commit 5cdaf8ab40796b4c7596fc9b105d35594cd890ee
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jul 8 08:47:36 2026 -0700

    Fix stuck infinite scroll: pump on live sentinel geometry, not stale observer flag
---
 public/index.html | 38 ++++++++++++++++++++++++++++----------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/public/index.html b/public/index.html
index 14a33ba..f32e25a 100644
--- a/public/index.html
+++ b/public/index.html
@@ -345,7 +345,7 @@ function facetParams(extra = {}) {
   });
 }
 
-function reset() { grid.innerHTML = ''; tbody.innerHTML = ''; state.offset = 0; state.done = false; statusEl.textContent = 'loading…'; load().then(() => { if (sentVisible && !state.done) pump(); }); }
+function reset() { window.scrollTo(0, 0); grid.innerHTML = ''; tbody.innerHTML = ''; state.offset = 0; state.done = false; statusEl.textContent = 'loading…'; load().then(() => pump()); }
 function applyFilterChange() { persistFacets(); refreshFacets(); reset(); }
 function toggleSet(set, val) { set.has(val) ? set.delete(val) : set.add(val); applyFilterChange(); }
 
@@ -606,20 +606,38 @@ async function load() {
   }
 }
 
-// Robust infinite scroll: a "pump" loop keeps loading WHILE the sentinel stays visible,
-// instead of relying on a single false→true intersection event. Fixes the stall where a
-// user parked at the bottom (or a load in-flight when they arrive) never re-triggers,
-// leaving "scroll for more…" stuck (IntersectionObserver only fires on transitions).
+// Robust infinite scroll: a "pump" loop keeps loading WHILE the sentinel sits in (or near)
+// the viewport. It re-measures the sentinel's geometry each iteration with getBoundingClientRect
+// instead of trusting the IntersectionObserver's cached `sentVisible` flag — that flag only
+// updates on an intersection TRANSITION, so after a reset() (filter/sort/view/search) that
+// empties the grid and reloads a short first page, no transition fires and the stale flag
+// (often false when the user changed a facet from near the top) left "scroll for more…"
+// permanently stuck until the user manually scrolled. Geometry is always current, so the
+// pump now self-sustains on initial load and after every reset regardless of observer timing.
+const SENT_MARGIN = 600; // must match the observer rootMargin below
+const sentEl = document.getElementById('sentinel');
+function sentinelInView() {
+  const r = sentEl.getBoundingClientRect();
+  const vh = window.innerHeight || document.documentElement.clientHeight;
+  return r.top <= vh + SENT_MARGIN && r.bottom >= -SENT_MARGIN;
+}
 let sentVisible = false, pumping = false;
 async function pump() {
   if (pumping) return;
   pumping = true;
-  try { while (sentVisible && !state.done) { const before = state.offset; await load(); if (state.offset === before) break; } }
-  finally { pumping = false; }
+  try {
+    while (!state.done && sentinelInView()) {
+      const before = state.offset;
+      await load();
+      if (state.offset === before) break; // no progress (error/empty) — bail, don't spin
+    }
+  } finally { pumping = false; }
 }
-new IntersectionObserver((es) => { sentVisible = es[0].isIntersecting; if (sentVisible) pump(); }, { rootMargin: '600px' })
-  .observe(document.getElementById('sentinel'));
-refreshFacets(); load();
+new IntersectionObserver((es) => { sentVisible = es[0].isIntersecting; if (sentVisible) pump(); }, { rootMargin: SENT_MARGIN + 'px' })
+  .observe(sentEl);
+// Re-pump on window resize too (a wider viewport can reveal the sentinel with no scroll event).
+window.addEventListener('resize', () => { if (!state.done) pump(); });
+refreshFacets(); load().then(() => pump());
 </script>
 </body>
 </html>

← 59f752c auto-save: 2026-07-07T20:32:33 (2 files) — config/known-subd  ·  back to All Designerwallcoverings  ·  Deploy staged +Koroseal live-stock build to prod (Kamatera 4 053a837 →