Ensure scrollers with all visible cards have scrolling disabled

This commit is contained in:
HighImKevin
2026-09-27 07:49:39 -04:00
parent 942c505919
commit b47f74afd7
+79 -1
View File
@@ -5484,6 +5484,7 @@
const showAllButton = verticalSection.querySelector('.show-all-button');
const scrollButtons = verticalSection.querySelector('.emby-scrollbuttons');
itemsContainer.setAttribute('data-layout', resolved);
verticalSection.setAttribute('data-layout', resolved);
itemsContainer.removeAttribute('data-expanded');
if (gapless === true) {
itemsContainer.setAttribute('data-gapless', 'true');
@@ -5939,6 +5940,42 @@
return readCardPadding(sampleCard);
}
function getFullyVisibleCardCount(scroller, cards) {
const epsilon = 1;
const pad = readScrollerPadding(scroller);
const cardPad = readSampleCardPadding(scroller);
const endInset = Math.max(pad.right, pad.left);
const scrollerRect = scroller.getBoundingClientRect();
const currentPosition = getCurrentPosition(scroller);
const contentWidth = Math.max(
0,
scroller.clientWidth - pad.left - endInset
);
const visibleLeft = scrollerRect.left + currentPosition + pad.left;
const visibleRight = visibleLeft + contentWidth;
let count = 0;
cards.forEach((card, index) => {
const cardRect = card.getBoundingClientRect();
if (cardRect.width <= 0) return;
// Use content box (inside card padding) for visibility
const cardContentLeft = cardRect.left + cardPad.left;
const cardContentRight = cardRect.right - cardPad.right;
if (cardContentLeft >= visibleLeft - epsilon && cardContentRight <= visibleRight + epsilon) {
count++;
}
});
return count;
}
function getCurrentPosition(scroller) {
const v = scroller.style.getPropertyValue('--scroll-x');
if (v !== '' && !isNaN(parseFloat(v))) return parseFloat(v);
const matrix = new DOMMatrixReadOnly(window.getComputedStyle(scroller).transform);
const translateX = matrix.m41 || 0;
return Math.abs(translateX);
}
/**
* Max transform/scroll offset so the trailing content edge matches the leading
* gutter when the skin only pads the left (e.g. Fin --sidePadding), plus the
@@ -5952,6 +5989,13 @@
return parseFloat(scroller.style.getPropertyValue('--max-scroll'));
}
// Check if all cards are visible
const cards = scroller.querySelectorAll('.itemsContainer > .card:not(.card-layout-dummy):not(.skeleton-card)');
const fullyVisible = getFullyVisibleCardCount(scroller, cards);
if (fullyVisible === cards.length) {
return 0;
}
const { left, right } = pad || { left: 0, right: 0 };
const cp = cardPad || { left: 0, right: 0 };
@@ -6571,7 +6615,7 @@
verticalSection.appendChild(scrollButtons);
verticalSection.appendChild(scroller);
registerScrollSectionScrollButtons(verticalSection);
return verticalSection;
}
@@ -7180,6 +7224,40 @@
applyScrollButtonState(verticalSection);
}
/**
* Ensure scroll section visibility observer exists. When a section becomes visible, runs updateScrollButtonStateForSection once then unobserves.
*/
function getScrollSectionVisibilityObserver() {
if (scrollSectionVisibilityObserver) return scrollSectionVisibilityObserver;
scrollSectionVisibilityObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (!entry.isIntersecting) return;
const verticalSection = entry.target;
scrollSectionVisibilityObserver.unobserve(verticalSection);
updateScrollButtonStateForSection(verticalSection);
});
}, { root: null, threshold: 0.01 });
return scrollSectionVisibilityObserver;
}
/**
* Register a scrollable section: when it becomes visible, set --max-scroll once and apply initial button state.
*/
function registerScrollSectionScrollButtons(verticalSection) {
const itemsContainer = verticalSection.querySelector('.itemsContainer');
const scroller = verticalSection.querySelector('.emby-scroller');
const first = itemsContainer && itemsContainer.firstElementChild;
const last = itemsContainer && itemsContainer.lastElementChild;
if (!first || !last) {
if (scroller) {
scroller.style.setProperty('--max-scroll', '0');
applyScrollButtonState(verticalSection);
}
return;
}
getScrollSectionVisibilityObserver().observe(verticalSection);
}
/**
* Initialize the smart lazy loading system
* Scans existing elements and starts both observers