108 lines
4.2 KiB
JavaScript
108 lines
4.2 KiB
JavaScript
var alwaysContainsScroll = function (node) {
|
|
// textarea will always _contain_ scroll inside self. It only can be hidden
|
|
return node.tagName === 'TEXTAREA';
|
|
};
|
|
var elementCanBeScrolled = function (node, overflow) {
|
|
if (!(node instanceof Element)) {
|
|
return false;
|
|
}
|
|
var styles = window.getComputedStyle(node);
|
|
return (
|
|
// not-not-scrollable
|
|
styles[overflow] !== 'hidden' &&
|
|
// contains scroll inside self
|
|
!(styles.overflowY === styles.overflowX && !alwaysContainsScroll(node) && styles[overflow] === 'visible'));
|
|
};
|
|
var elementCouldBeVScrolled = function (node) { return elementCanBeScrolled(node, 'overflowY'); };
|
|
var elementCouldBeHScrolled = function (node) { return elementCanBeScrolled(node, 'overflowX'); };
|
|
export var locationCouldBeScrolled = function (axis, node) {
|
|
var ownerDocument = node.ownerDocument;
|
|
var current = node;
|
|
do {
|
|
// Skip over shadow root
|
|
if (typeof ShadowRoot !== 'undefined' && current instanceof ShadowRoot) {
|
|
current = current.host;
|
|
}
|
|
var isScrollable = elementCouldBeScrolled(axis, current);
|
|
if (isScrollable) {
|
|
var _a = getScrollVariables(axis, current), scrollHeight = _a[1], clientHeight = _a[2];
|
|
if (scrollHeight > clientHeight) {
|
|
return true;
|
|
}
|
|
}
|
|
current = current.parentNode;
|
|
} while (current && current !== ownerDocument.body);
|
|
return false;
|
|
};
|
|
var getVScrollVariables = function (_a) {
|
|
var scrollTop = _a.scrollTop, scrollHeight = _a.scrollHeight, clientHeight = _a.clientHeight;
|
|
return [
|
|
scrollTop,
|
|
scrollHeight,
|
|
clientHeight,
|
|
];
|
|
};
|
|
var getHScrollVariables = function (_a) {
|
|
var scrollLeft = _a.scrollLeft, scrollWidth = _a.scrollWidth, clientWidth = _a.clientWidth;
|
|
return [
|
|
scrollLeft,
|
|
scrollWidth,
|
|
clientWidth,
|
|
];
|
|
};
|
|
var elementCouldBeScrolled = function (axis, node) {
|
|
return axis === 'v' ? elementCouldBeVScrolled(node) : elementCouldBeHScrolled(node);
|
|
};
|
|
var getScrollVariables = function (axis, node) {
|
|
return axis === 'v' ? getVScrollVariables(node) : getHScrollVariables(node);
|
|
};
|
|
var getDirectionFactor = function (axis, direction) {
|
|
/**
|
|
* If the element's direction is rtl (right-to-left), then scrollLeft is 0 when the scrollbar is at its rightmost position,
|
|
* and then increasingly negative as you scroll towards the end of the content.
|
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
|
|
*/
|
|
return axis === 'h' && direction === 'rtl' ? -1 : 1;
|
|
};
|
|
export var handleScroll = function (axis, endTarget, event, sourceDelta, noOverscroll) {
|
|
var directionFactor = getDirectionFactor(axis, window.getComputedStyle(endTarget).direction);
|
|
var delta = directionFactor * sourceDelta;
|
|
// find scrollable target
|
|
var target = event.target;
|
|
var targetInLock = endTarget.contains(target);
|
|
var shouldCancelScroll = false;
|
|
var isDeltaPositive = delta > 0;
|
|
var availableScroll = 0;
|
|
var availableScrollTop = 0;
|
|
do {
|
|
var _a = getScrollVariables(axis, target), position = _a[0], scroll_1 = _a[1], capacity = _a[2];
|
|
var elementScroll = scroll_1 - capacity - directionFactor * position;
|
|
if (position || elementScroll) {
|
|
if (elementCouldBeScrolled(axis, target)) {
|
|
availableScroll += elementScroll;
|
|
availableScrollTop += position;
|
|
}
|
|
}
|
|
if (target instanceof ShadowRoot) {
|
|
target = target.host;
|
|
}
|
|
else {
|
|
target = target.parentNode;
|
|
}
|
|
} while (
|
|
// portaled content
|
|
(!targetInLock && target !== document.body) ||
|
|
// self content
|
|
(targetInLock && (endTarget.contains(target) || endTarget === target)));
|
|
// handle epsilon around 0 (non standard zoom levels)
|
|
if (isDeltaPositive &&
|
|
((noOverscroll && Math.abs(availableScroll) < 1) || (!noOverscroll && delta > availableScroll))) {
|
|
shouldCancelScroll = true;
|
|
}
|
|
else if (!isDeltaPositive &&
|
|
((noOverscroll && Math.abs(availableScrollTop) < 1) || (!noOverscroll && -delta > availableScrollTop))) {
|
|
shouldCancelScroll = true;
|
|
}
|
|
return shouldCancelScroll;
|
|
};
|