Fix mobile scroll through slider sections

This commit is contained in:
dcconstructions
2026-07-10 01:21:42 +03:00
parent 0e13de36cf
commit e08ad18253
5 changed files with 69 additions and 4 deletions
+63
View File
@@ -12,17 +12,21 @@
const MEDIA_HANDLE_BOUND_FLAG = "__nodedcMediaHandleBound";
const DOCK_LINK_BOUND_FLAG = "__nodedcDockLinkBound";
const ORDERED_SLIDER_BOUND_FLAG = "__nodedcOrderedSliderBound";
const SLIDER_TOUCH_GUARD_FLAG = "__nodedcSliderTouchGuardBound";
const LAZY_MEDIA_VIDEO_BOUND_FLAG = "__nodedcLazyMediaVideoBound";
const SCROLL_HEIGHT_SYNC_FLAG = "__nodedcScrollHeightSyncBound";
const NOTIFICATION_STACK_BOUND_FLAG = "__nodedcNotificationStackBound";
const SCROLL_HEIGHT_SYNC_WARMUP_MS = 14000;
const SCROLL_HEIGHT_SYNC_INTERVAL_MS = 90;
const SLIDER_TOUCH_INTENT_DISTANCE = 8;
const SLIDER_HORIZONTAL_INTENT_RATIO = 1.35;
const IMAGE_EXTENSIONS = new Set(["avif", "gif", "jpeg", "jpg", "png", "svg", "webp"]);
const VIDEO_EXTENSIONS = new Set(["m4v", "mov", "mp4", "webm"]);
let lastDocumentScrollHeight = 0;
let scrollHeightSyncFrame = 0;
let scrollHeightSyncShouldForce = false;
let scrollHeightDeferredSync = 0;
let activeSliderTouch = null;
function isDesktopPointer() {
return window.matchMedia?.("(pointer: fine)").matches ?? true;
@@ -333,6 +337,61 @@
document.querySelectorAll('[data-module="mail-list"]').forEach(bindMailListWheel);
}
function bindSliderTouchGuard() {
if (document[SLIDER_TOUCH_GUARD_FLAG]) return;
document[SLIDER_TOUCH_GUARD_FLAG] = true;
window.addEventListener(
"touchstart",
(event) => {
const slider = event.target?.closest?.('[data-module="slider"]');
const touch = event.touches?.[0];
activeSliderTouch = slider && touch
? {
identifier: touch.identifier,
startX: touch.clientX,
startY: touch.clientY,
intent: "",
}
: null;
},
{ capture: true, passive: true },
);
window.addEventListener(
"touchmove",
(event) => {
if (!activeSliderTouch) return;
const touch = Array.from(event.touches || []).find(
(candidate) => candidate.identifier === activeSliderTouch.identifier,
);
if (!touch) return;
const deltaX = Math.abs(touch.clientX - activeSliderTouch.startX);
const deltaY = Math.abs(touch.clientY - activeSliderTouch.startY);
if (!activeSliderTouch.intent) {
if (Math.max(deltaX, deltaY) < SLIDER_TOUCH_INTENT_DISTANCE) {
event.stopImmediatePropagation();
return;
}
activeSliderTouch.intent = deltaX > deltaY * SLIDER_HORIZONTAL_INTENT_RATIO ? "horizontal" : "vertical";
}
if (activeSliderTouch.intent === "vertical") {
event.stopImmediatePropagation();
}
},
{ capture: true, passive: false },
);
const clearTouch = () => {
activeSliderTouch = null;
};
window.addEventListener("touchend", clearTouch, { capture: true, passive: true });
window.addEventListener("touchcancel", clearTouch, { capture: true, passive: true });
}
function bindOrderedSlider(surface) {
if (!surface || surface[ORDERED_SLIDER_BOUND_FLAG]) return;
@@ -582,6 +641,7 @@
}
bindScrollHeightSync();
bindSliderTouchGuard();
hydrateMediaHandles();
bindNotificationStacks();
@@ -590,6 +650,7 @@
"DOMContentLoaded",
() => {
bindScrollHeightSync();
bindSliderTouchGuard();
hydrateMediaHandles();
bindInteractiveScroll();
bindOrderedSliders();
@@ -603,6 +664,7 @@
);
} else {
bindScrollHeightSync();
bindSliderTouchGuard();
hydrateMediaHandles();
bindInteractiveScroll();
bindOrderedSliders();
@@ -615,6 +677,7 @@
window.addEventListener("load", () => {
bindScrollHeightSync();
bindSliderTouchGuard();
hydrateMediaHandles();
bindInteractiveScroll();
bindOrderedSliders();