doc.yeswiki.pro/node_modules/body-scroll-lock/lib/bodyScrollLock.esm.js
2023-05-20 19:38:02 +03:00

278 lines
9 KiB
JavaScript

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
// Older browsers don't support event options, feature detect it.
// Adopted and modified solution from Bohdan Didukh (2017)
// https://stackoverflow.com/questions/41594997/ios-10-safari-prevent-scrolling-behind-a-fixed-overlay-and-maintain-scroll-posi
var hasPassiveEvents = false;
if (typeof window !== 'undefined') {
var passiveTestOptions = {
get passive() {
hasPassiveEvents = true;
return undefined;
}
};
window.addEventListener('testPassive', null, passiveTestOptions);
window.removeEventListener('testPassive', null, passiveTestOptions);
}
var isIosDevice = typeof window !== 'undefined' && window.navigator && window.navigator.platform && (/iP(ad|hone|od)/.test(window.navigator.platform) || window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1);
var locks = [];
var documentListenerAdded = false;
var initialClientY = -1;
var previousBodyOverflowSetting = void 0;
var previousBodyPosition = void 0;
var previousBodyPaddingRight = void 0;
// returns true if `el` should be allowed to receive touchmove events.
var allowTouchMove = function allowTouchMove(el) {
return locks.some(function (lock) {
if (lock.options.allowTouchMove && lock.options.allowTouchMove(el)) {
return true;
}
return false;
});
};
var preventDefault = function preventDefault(rawEvent) {
var e = rawEvent || window.event;
// For the case whereby consumers adds a touchmove event listener to document.
// Recall that we do document.addEventListener('touchmove', preventDefault, { passive: false })
// in disableBodyScroll - so if we provide this opportunity to allowTouchMove, then
// the touchmove event on document will break.
if (allowTouchMove(e.target)) {
return true;
}
// Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom).
if (e.touches.length > 1) return true;
if (e.preventDefault) e.preventDefault();
return false;
};
var setOverflowHidden = function setOverflowHidden(options) {
// If previousBodyPaddingRight is already set, don't set it again.
if (previousBodyPaddingRight === undefined) {
var _reserveScrollBarGap = !!options && options.reserveScrollBarGap === true;
var scrollBarGap = window.innerWidth - document.documentElement.clientWidth;
if (_reserveScrollBarGap && scrollBarGap > 0) {
var computedBodyPaddingRight = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right'), 10);
previousBodyPaddingRight = document.body.style.paddingRight;
document.body.style.paddingRight = computedBodyPaddingRight + scrollBarGap + 'px';
}
}
// If previousBodyOverflowSetting is already set, don't set it again.
if (previousBodyOverflowSetting === undefined) {
previousBodyOverflowSetting = document.body.style.overflow;
document.body.style.overflow = 'hidden';
}
};
var restoreOverflowSetting = function restoreOverflowSetting() {
if (previousBodyPaddingRight !== undefined) {
document.body.style.paddingRight = previousBodyPaddingRight;
// Restore previousBodyPaddingRight to undefined so setOverflowHidden knows it
// can be set again.
previousBodyPaddingRight = undefined;
}
if (previousBodyOverflowSetting !== undefined) {
document.body.style.overflow = previousBodyOverflowSetting;
// Restore previousBodyOverflowSetting to undefined
// so setOverflowHidden knows it can be set again.
previousBodyOverflowSetting = undefined;
}
};
var setPositionFixed = function setPositionFixed() {
return window.requestAnimationFrame(function () {
// If previousBodyPosition is already set, don't set it again.
if (previousBodyPosition === undefined) {
previousBodyPosition = {
position: document.body.style.position,
top: document.body.style.top,
left: document.body.style.left
};
// Update the dom inside an animation frame
var _window = window,
scrollY = _window.scrollY,
scrollX = _window.scrollX,
innerHeight = _window.innerHeight;
document.body.style.position = 'fixed';
document.body.style.top = -scrollY;
document.body.style.left = -scrollX;
setTimeout(function () {
return window.requestAnimationFrame(function () {
// Attempt to check if the bottom bar appeared due to the position change
var bottomBarHeight = innerHeight - window.innerHeight;
if (bottomBarHeight && scrollY >= innerHeight) {
// Move the content further up so that the bottom bar doesn't hide it
document.body.style.top = -(scrollY + bottomBarHeight);
}
});
}, 300);
}
});
};
var restorePositionSetting = function restorePositionSetting() {
if (previousBodyPosition !== undefined) {
// Convert the position from "px" to Int
var y = -parseInt(document.body.style.top, 10);
var x = -parseInt(document.body.style.left, 10);
// Restore styles
document.body.style.position = previousBodyPosition.position;
document.body.style.top = previousBodyPosition.top;
document.body.style.left = previousBodyPosition.left;
// Restore scroll
window.scrollTo(x, y);
previousBodyPosition = undefined;
}
};
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions
var isTargetElementTotallyScrolled = function isTargetElementTotallyScrolled(targetElement) {
return targetElement ? targetElement.scrollHeight - targetElement.scrollTop <= targetElement.clientHeight : false;
};
var handleScroll = function handleScroll(event, targetElement) {
var clientY = event.targetTouches[0].clientY - initialClientY;
if (allowTouchMove(event.target)) {
return false;
}
if (targetElement && targetElement.scrollTop === 0 && clientY > 0) {
// element is at the top of its scroll.
return preventDefault(event);
}
if (isTargetElementTotallyScrolled(targetElement) && clientY < 0) {
// element is at the bottom of its scroll.
return preventDefault(event);
}
event.stopPropagation();
return true;
};
export var disableBodyScroll = function disableBodyScroll(targetElement, options) {
// targetElement must be provided
if (!targetElement) {
// eslint-disable-next-line no-console
console.error('disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.');
return;
}
// disableBodyScroll must not have been called on this targetElement before
if (locks.some(function (lock) {
return lock.targetElement === targetElement;
})) {
return;
}
var lock = {
targetElement: targetElement,
options: options || {}
};
locks = [].concat(_toConsumableArray(locks), [lock]);
if (isIosDevice) {
setPositionFixed();
} else {
setOverflowHidden(options);
}
if (isIosDevice) {
targetElement.ontouchstart = function (event) {
if (event.targetTouches.length === 1) {
// detect single touch.
initialClientY = event.targetTouches[0].clientY;
}
};
targetElement.ontouchmove = function (event) {
if (event.targetTouches.length === 1) {
// detect single touch.
handleScroll(event, targetElement);
}
};
if (!documentListenerAdded) {
document.addEventListener('touchmove', preventDefault, hasPassiveEvents ? { passive: false } : undefined);
documentListenerAdded = true;
}
}
};
export var clearAllBodyScrollLocks = function clearAllBodyScrollLocks() {
if (isIosDevice) {
// Clear all locks ontouchstart/ontouchmove handlers, and the references.
locks.forEach(function (lock) {
lock.targetElement.ontouchstart = null;
lock.targetElement.ontouchmove = null;
});
if (documentListenerAdded) {
document.removeEventListener('touchmove', preventDefault, hasPassiveEvents ? { passive: false } : undefined);
documentListenerAdded = false;
}
// Reset initial clientY.
initialClientY = -1;
}
if (isIosDevice) {
restorePositionSetting();
} else {
restoreOverflowSetting();
}
locks = [];
};
export var enableBodyScroll = function enableBodyScroll(targetElement) {
if (!targetElement) {
// eslint-disable-next-line no-console
console.error('enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.');
return;
}
locks = locks.filter(function (lock) {
return lock.targetElement !== targetElement;
});
if (isIosDevice) {
targetElement.ontouchstart = null;
targetElement.ontouchmove = null;
if (documentListenerAdded && locks.length === 0) {
document.removeEventListener('touchmove', preventDefault, hasPassiveEvents ? { passive: false } : undefined);
documentListenerAdded = false;
}
}
if (isIosDevice) {
restorePositionSetting();
} else {
restoreOverflowSetting();
}
};