Fix dynamic scroll height sync
This commit is contained in:
parent
bc0da49506
commit
26f9e5daeb
|
|
@ -12,8 +12,15 @@
|
||||||
const MEDIA_HANDLE_BOUND_FLAG = "__nodedcMediaHandleBound";
|
const MEDIA_HANDLE_BOUND_FLAG = "__nodedcMediaHandleBound";
|
||||||
const DOCK_LINK_BOUND_FLAG = "__nodedcDockLinkBound";
|
const DOCK_LINK_BOUND_FLAG = "__nodedcDockLinkBound";
|
||||||
const ORDERED_SLIDER_BOUND_FLAG = "__nodedcOrderedSliderBound";
|
const ORDERED_SLIDER_BOUND_FLAG = "__nodedcOrderedSliderBound";
|
||||||
|
const SCROLL_HEIGHT_SYNC_FLAG = "__nodedcScrollHeightSyncBound";
|
||||||
|
const SCROLL_HEIGHT_SYNC_WARMUP_MS = 14000;
|
||||||
|
const SCROLL_HEIGHT_SYNC_INTERVAL_MS = 90;
|
||||||
const IMAGE_EXTENSIONS = new Set(["avif", "gif", "jpeg", "jpg", "png", "svg", "webp"]);
|
const IMAGE_EXTENSIONS = new Set(["avif", "gif", "jpeg", "jpg", "png", "svg", "webp"]);
|
||||||
const VIDEO_EXTENSIONS = new Set(["m4v", "mov", "mp4", "webm"]);
|
const VIDEO_EXTENSIONS = new Set(["m4v", "mov", "mp4", "webm"]);
|
||||||
|
let lastDocumentScrollHeight = 0;
|
||||||
|
let scrollHeightSyncFrame = 0;
|
||||||
|
let scrollHeightSyncShouldForce = false;
|
||||||
|
let scrollHeightDeferredSync = 0;
|
||||||
|
|
||||||
function isDesktopPointer() {
|
function isDesktopPointer() {
|
||||||
return window.matchMedia?.("(pointer: fine)").matches ?? true;
|
return window.matchMedia?.("(pointer: fine)").matches ?? true;
|
||||||
|
|
@ -55,6 +62,99 @@
|
||||||
return Math.min(max, Math.max(min, value));
|
return Math.min(max, Math.max(min, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDocumentScrollHeight() {
|
||||||
|
return Math.max(document.documentElement.scrollHeight, document.body?.scrollHeight || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function notifyScrollHeightChange(force = false) {
|
||||||
|
const nextHeight = getDocumentScrollHeight();
|
||||||
|
if (!nextHeight) return;
|
||||||
|
if (!force && nextHeight === lastDocumentScrollHeight) return;
|
||||||
|
|
||||||
|
lastDocumentScrollHeight = nextHeight;
|
||||||
|
window.dispatchEvent(new Event("resize"));
|
||||||
|
|
||||||
|
if (scrollHeightDeferredSync) {
|
||||||
|
window.clearTimeout(scrollHeightDeferredSync);
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollHeightDeferredSync = window.setTimeout(() => {
|
||||||
|
scrollHeightDeferredSync = 0;
|
||||||
|
if (getDocumentScrollHeight() === lastDocumentScrollHeight) {
|
||||||
|
window.dispatchEvent(new Event("resize"));
|
||||||
|
} else {
|
||||||
|
scheduleScrollHeightSync();
|
||||||
|
}
|
||||||
|
}, 320);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleScrollHeightSync(force = false) {
|
||||||
|
scrollHeightSyncShouldForce = scrollHeightSyncShouldForce || force;
|
||||||
|
if (scrollHeightSyncFrame) return;
|
||||||
|
|
||||||
|
scrollHeightSyncFrame = window.requestAnimationFrame(() => {
|
||||||
|
const shouldForce = scrollHeightSyncShouldForce;
|
||||||
|
|
||||||
|
scrollHeightSyncShouldForce = false;
|
||||||
|
scrollHeightSyncFrame = 0;
|
||||||
|
notifyScrollHeightChange(shouldForce);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindScrollHeightSync() {
|
||||||
|
if (document[SCROLL_HEIGHT_SYNC_FLAG]) return;
|
||||||
|
document[SCROLL_HEIGHT_SYNC_FLAG] = true;
|
||||||
|
|
||||||
|
scheduleScrollHeightSync(true);
|
||||||
|
|
||||||
|
const resizeObserver =
|
||||||
|
typeof ResizeObserver === "function"
|
||||||
|
? new ResizeObserver(() => {
|
||||||
|
scheduleScrollHeightSync();
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
||||||
|
resizeObserver?.observe(document.documentElement);
|
||||||
|
if (document.body) resizeObserver?.observe(document.body);
|
||||||
|
|
||||||
|
const mutationObserver =
|
||||||
|
typeof MutationObserver === "function"
|
||||||
|
? new MutationObserver(() => {
|
||||||
|
scheduleScrollHeightSync();
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
||||||
|
mutationObserver?.observe(document.documentElement, {
|
||||||
|
attributes: true,
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const interval = window.setInterval(() => {
|
||||||
|
scheduleScrollHeightSync();
|
||||||
|
}, SCROLL_HEIGHT_SYNC_INTERVAL_MS);
|
||||||
|
|
||||||
|
window.setTimeout(() => {
|
||||||
|
window.clearInterval(interval);
|
||||||
|
mutationObserver?.disconnect();
|
||||||
|
}, SCROLL_HEIGHT_SYNC_WARMUP_MS);
|
||||||
|
|
||||||
|
window.addEventListener("load", () => scheduleScrollHeightSync(true), { once: true });
|
||||||
|
if (document.fonts?.ready) {
|
||||||
|
document.fonts.ready.then(() => scheduleScrollHeightSync(true)).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener(
|
||||||
|
"load",
|
||||||
|
(event) => {
|
||||||
|
if (event.target instanceof HTMLImageElement || event.target instanceof HTMLVideoElement) {
|
||||||
|
scheduleScrollHeightSync();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function getScrollSpeed(surface) {
|
function getScrollSpeed(surface) {
|
||||||
const rawValue = surface?.dataset?.scrollSpeed ?? surface?.closest?.("[data-scroll-speed]")?.dataset?.scrollSpeed;
|
const rawValue = surface?.dataset?.scrollSpeed ?? surface?.closest?.("[data-scroll-speed]")?.dataset?.scrollSpeed;
|
||||||
const value = Number.parseFloat(rawValue);
|
const value = Number.parseFloat(rawValue);
|
||||||
|
|
@ -358,40 +458,48 @@
|
||||||
document.querySelectorAll("[data-adaptive-video] video").forEach(bindAdaptiveVideo);
|
document.querySelectorAll("[data-adaptive-video] video").forEach(bindAdaptiveVideo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindScrollHeightSync();
|
||||||
hydrateMediaHandles();
|
hydrateMediaHandles();
|
||||||
|
|
||||||
if (document.readyState === "loading") {
|
if (document.readyState === "loading") {
|
||||||
document.addEventListener(
|
document.addEventListener(
|
||||||
"DOMContentLoaded",
|
"DOMContentLoaded",
|
||||||
() => {
|
() => {
|
||||||
|
bindScrollHeightSync();
|
||||||
hydrateMediaHandles();
|
hydrateMediaHandles();
|
||||||
bindInteractiveScroll();
|
bindInteractiveScroll();
|
||||||
bindOrderedSliders();
|
bindOrderedSliders();
|
||||||
bindDockLinks();
|
bindDockLinks();
|
||||||
bindAdaptiveVideos();
|
bindAdaptiveVideos();
|
||||||
|
scheduleScrollHeightSync(true);
|
||||||
},
|
},
|
||||||
{ once: true },
|
{ once: true },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
bindScrollHeightSync();
|
||||||
hydrateMediaHandles();
|
hydrateMediaHandles();
|
||||||
bindInteractiveScroll();
|
bindInteractiveScroll();
|
||||||
bindOrderedSliders();
|
bindOrderedSliders();
|
||||||
bindDockLinks();
|
bindDockLinks();
|
||||||
bindAdaptiveVideos();
|
bindAdaptiveVideos();
|
||||||
|
scheduleScrollHeightSync(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
|
bindScrollHeightSync();
|
||||||
hydrateMediaHandles();
|
hydrateMediaHandles();
|
||||||
bindInteractiveScroll();
|
bindInteractiveScroll();
|
||||||
bindOrderedSliders();
|
bindOrderedSliders();
|
||||||
bindDockLinks();
|
bindDockLinks();
|
||||||
bindAdaptiveVideos();
|
bindAdaptiveVideos();
|
||||||
|
scheduleScrollHeightSync(true);
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
hydrateMediaHandles();
|
hydrateMediaHandles();
|
||||||
bindInteractiveScroll();
|
bindInteractiveScroll();
|
||||||
bindOrderedSliders();
|
bindOrderedSliders();
|
||||||
bindDockLinks();
|
bindDockLinks();
|
||||||
bindAdaptiveVideos();
|
bindAdaptiveVideos();
|
||||||
|
scheduleScrollHeightSync(true);
|
||||||
}, 500);
|
}, 500);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue