mirror of
https://github.com/john-okeefe/foliate-js.git
synced 2026-09-09 11:29:14 -04:00
Fix webtoon pages never loading: drop IntersectionObserver for scroll-driven loading
IO with a shadow-host root never delivered intersections in Chromium (verified live: pages stayed blank while the section.load→fetch→img pipeline itself worked fine when probed from outside). Loading is now driven from the rAF-throttled scroll handler that already tracked the reading position: a window of [index-2, index+4] loads around the viewport-center page, with a 'loading' guard against duplicate in-flight loads. connectedCallback kicks the initial load window.
This commit is contained in:
+23
-19
@@ -9,7 +9,7 @@ export class Webtoon extends HTMLElement {
|
|||||||
#pages = [];
|
#pages = [];
|
||||||
#index = -1;
|
#index = -1;
|
||||||
#firstNav = true;
|
#firstNav = true;
|
||||||
#loadIO = null;
|
#connected = false;
|
||||||
#scrollRaf = null;
|
#scrollRaf = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -57,28 +57,24 @@ export class Webtoon extends HTMLElement {
|
|||||||
el.dataset.index = i;
|
el.dataset.index = i;
|
||||||
el.style.minHeight = `${minH}px`;
|
el.style.minHeight = `${minH}px`;
|
||||||
frag.append(el);
|
frag.append(el);
|
||||||
return { el, section, loaded: false, img: null };
|
return { el, section, loaded: false, img: null, loading: false };
|
||||||
});
|
});
|
||||||
this.#root.append(frag);
|
this.#root.append(frag);
|
||||||
|
// Loading is driven from scroll position (#updateIndex), not an
|
||||||
|
// IntersectionObserver: IO with a shadow-host root proved unreliable
|
||||||
|
// in Chromium and would leave pages permanently blank.
|
||||||
|
if (this.#connected) this.#updateIndex();
|
||||||
|
}
|
||||||
|
|
||||||
this.#loadIO = new IntersectionObserver(
|
connectedCallback() {
|
||||||
(entries) => {
|
this.#connected = true;
|
||||||
for (const entry of entries) {
|
if (this.#pages.length) this.#updateIndex();
|
||||||
if (!entry.isIntersecting) continue;
|
|
||||||
this.#loadIO.unobserve(entry.target);
|
|
||||||
this.#loadPage(Number(entry.target.dataset.index));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// generous margin so pages are ready before they scroll into view
|
|
||||||
{ root: this, rootMargin: "150% 0%" },
|
|
||||||
);
|
|
||||||
for (const p of this.#pages) this.#loadIO.observe(p.el);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async #loadPage(i) {
|
async #loadPage(i) {
|
||||||
const p = this.#pages[i];
|
const p = this.#pages[i];
|
||||||
if (!p || p.loaded) return;
|
if (!p || p.loaded || p.loading) return;
|
||||||
p.loaded = true;
|
p.loading = true;
|
||||||
try {
|
try {
|
||||||
const url = await p.section.load?.();
|
const url = await p.section.load?.();
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
@@ -97,12 +93,21 @@ export class Webtoon extends HTMLElement {
|
|||||||
p.el.style.minHeight = "0";
|
p.el.style.minHeight = "0";
|
||||||
p.el.append(img);
|
p.el.append(img);
|
||||||
p.img = img;
|
p.img = img;
|
||||||
|
p.loaded = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
p.loaded = false;
|
|
||||||
console.warn("webtoon: failed to load page", i + 1, e);
|
console.warn("webtoon: failed to load page", i + 1, e);
|
||||||
|
} finally {
|
||||||
|
p.loading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load a window around the reading position (a few pages of lookahead).
|
||||||
|
#loadAround(idx) {
|
||||||
|
const start = Math.max(0, idx - 2);
|
||||||
|
const end = Math.min(this.#pages.length - 1, idx + 4);
|
||||||
|
for (let i = start; i <= end; i++) this.#loadPage(i);
|
||||||
|
}
|
||||||
|
|
||||||
// Free far-away pages (images + their blob URLs) while keeping the
|
// Free far-away pages (images + their blob URLs) while keeping the
|
||||||
// aspect-ratio placeholder, so the column height stays stable.
|
// aspect-ratio placeholder, so the column height stays stable.
|
||||||
#unloadFar(current) {
|
#unloadFar(current) {
|
||||||
@@ -114,7 +119,6 @@ export class Webtoon extends HTMLElement {
|
|||||||
p.img = null;
|
p.img = null;
|
||||||
p.loaded = false;
|
p.loaded = false;
|
||||||
p.section.unload?.();
|
p.section.unload?.();
|
||||||
this.#loadIO.observe(p.el);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,6 +156,7 @@ export class Webtoon extends HTMLElement {
|
|||||||
this.#index = idx;
|
this.#index = idx;
|
||||||
this.#unloadFar(idx);
|
this.#unloadFar(idx);
|
||||||
}
|
}
|
||||||
|
this.#loadAround(idx);
|
||||||
this.#report(fraction);
|
this.#report(fraction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +222,6 @@ export class Webtoon extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
this.#loadIO?.disconnect();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user