1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00
jellyfin-web/src/scripts/scrollHelper.ts

139 lines
4.2 KiB
TypeScript
Raw Normal View History

2020-08-14 08:46:34 +02:00
import focusManager from '../components/focusManager';
import dom from './dom';
import '../styles/scrollstyles.scss';
2020-07-26 22:52:55 +02:00
2024-02-18 12:46:34 -08:00
function getBoundingClientRect(elem: Element) {
2020-07-26 22:52:55 +02:00
// Support: BlackBerry 5, iOS 3 (original iPhone)
// If we don't have gBCR, just use 0,0 rather than error
if (elem.getBoundingClientRect) {
return elem.getBoundingClientRect();
} else {
2024-02-18 12:46:34 -08:00
return { top: 0, left: 0, width: undefined, height: undefined };
2020-07-26 22:52:55 +02:00
}
}
2018-10-23 01:05:09 +03:00
2024-02-18 12:46:34 -08:00
export function getPosition(scrollContainer: HTMLElement, item: HTMLElement, horizontal: boolean) {
2020-07-26 22:52:55 +02:00
const slideeOffset = getBoundingClientRect(scrollContainer);
const itemOffset = getBoundingClientRect(item);
2018-10-23 01:05:09 +03:00
2020-07-26 22:52:55 +02:00
let offset = horizontal ? itemOffset.left - slideeOffset.left : itemOffset.top - slideeOffset.top;
let size = horizontal ? itemOffset.width : itemOffset.height;
if (!size && size !== 0) {
size = item[horizontal ? 'offsetWidth' : 'offsetHeight'];
}
2020-07-26 22:52:55 +02:00
const currentStart = horizontal ? scrollContainer.scrollLeft : scrollContainer.scrollTop;
2020-07-26 22:52:55 +02:00
offset += currentStart;
2020-07-26 22:52:55 +02:00
const frameSize = horizontal ? scrollContainer.offsetWidth : scrollContainer.offsetHeight;
2020-07-26 22:52:55 +02:00
const currentEnd = currentStart + frameSize;
2020-07-26 22:52:55 +02:00
const isVisible = offset >= currentStart && (offset + size) <= currentEnd;
2020-07-26 22:52:55 +02:00
return {
start: offset,
center: (offset - (frameSize / 2) + (size / 2)),
end: offset - frameSize + size,
size: size,
isVisible: isVisible
};
}
2024-02-18 12:46:34 -08:00
export function toCenter(container: HTMLElement, elem: HTMLElement, horizontal: boolean, skipWhenVisible?: boolean) {
2020-07-26 22:52:55 +02:00
const pos = getPosition(container, elem, horizontal);
2020-07-26 22:52:55 +02:00
if (skipWhenVisible && pos.isVisible) {
return;
2018-10-23 01:05:09 +03:00
}
2020-07-26 22:52:55 +02:00
if (container.scrollTo) {
if (horizontal) {
container.scrollTo(pos.center, 0);
} else {
container.scrollTo(0, pos.center);
}
2023-09-12 17:02:06 -04:00
} else if (horizontal) {
container.scrollLeft = Math.round(pos.center);
2020-07-26 22:52:55 +02:00
} else {
2023-09-12 17:02:06 -04:00
container.scrollTop = Math.round(pos.center);
2018-10-23 01:05:09 +03:00
}
2020-07-26 22:52:55 +02:00
}
2018-10-23 01:05:09 +03:00
2024-02-18 12:46:34 -08:00
export function toStart(container: HTMLElement, elem: HTMLElement, horizontal: boolean, skipWhenVisible?: boolean) {
2020-07-26 22:52:55 +02:00
const pos = getPosition(container, elem, horizontal);
2020-07-26 22:52:55 +02:00
if (skipWhenVisible && pos.isVisible) {
return;
}
2020-07-26 22:52:55 +02:00
if (container.scrollTo) {
if (horizontal) {
container.scrollTo(pos.start, 0);
} else {
2020-07-26 22:52:55 +02:00
container.scrollTo(0, pos.start);
}
2023-09-12 17:02:06 -04:00
} else if (horizontal) {
container.scrollLeft = Math.round(pos.start);
2020-07-26 22:52:55 +02:00
} else {
2023-09-12 17:02:06 -04:00
container.scrollTop = Math.round(pos.start);
2018-10-23 01:05:09 +03:00
}
2020-07-26 22:52:55 +02:00
}
2018-10-23 01:05:09 +03:00
2024-02-18 12:46:34 -08:00
function centerOnFocus(e: Event, scrollSlider: HTMLElement, horizontal: boolean) {
2020-07-26 22:52:55 +02:00
const focused = focusManager.focusableParent(e.target);
2020-07-26 22:52:55 +02:00
if (focused) {
toCenter(scrollSlider, focused, horizontal);
}
}
2024-02-18 12:46:34 -08:00
function centerOnFocusHorizontal(this: HTMLElement, e: Event) {
2020-07-26 22:52:55 +02:00
centerOnFocus(e, this, true);
}
2020-08-06 22:28:52 +02:00
2024-02-18 12:46:34 -08:00
function centerOnFocusVertical(this: HTMLElement, e: Event) {
2020-07-26 22:52:55 +02:00
centerOnFocus(e, this, false);
}
2020-08-06 22:28:52 +02:00
export const centerFocus = {
2024-02-18 12:46:34 -08:00
on: function (element: Element, horizontal: boolean) {
2021-04-24 21:30:40 +03:00
element.setAttribute(`data-scroll-mode-${horizontal ? 'x' : 'y'}`, 'custom');
2020-08-06 22:28:52 +02:00
if (horizontal) {
dom.addEventListener(element, 'focus', centerOnFocusHorizontal, {
capture: true,
passive: true
});
} else {
dom.addEventListener(element, 'focus', centerOnFocusVertical, {
capture: true,
passive: true
});
2020-07-26 22:52:55 +02:00
}
},
2024-02-18 12:46:34 -08:00
off: function (element: Element, horizontal: boolean) {
2021-04-24 21:30:40 +03:00
element.removeAttribute(`data-scroll-mode-${horizontal ? 'x' : 'y'}`);
2020-08-06 22:28:52 +02:00
if (horizontal) {
dom.removeEventListener(element, 'focus', centerOnFocusHorizontal, {
capture: true,
passive: true
});
} else {
dom.removeEventListener(element, 'focus', centerOnFocusVertical, {
capture: true,
passive: true
});
}
}
2020-08-06 22:48:26 +02:00
};
2020-08-06 22:28:52 +02:00
export default {
getPosition: getPosition,
centerFocus: centerFocus,
2020-07-26 22:52:55 +02:00
toCenter: toCenter,
toStart: toStart
};