mirror of
https://github.com/VTECRM/vtenext.git
synced 2026-02-27 00:28:47 +00:00
265 lines
8.8 KiB
JavaScript
265 lines
8.8 KiB
JavaScript
/*************************************
|
|
* SPDX-FileCopyrightText: 2009-2020 Vtenext S.r.l. <info@vtenext.com>
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
************************************/
|
|
(function (global, factory) {
|
|
if (typeof define === "function" && define.amd) {
|
|
define(['exports'], factory);
|
|
} else if (typeof exports !== "undefined") {
|
|
factory(exports);
|
|
} else {
|
|
var mod = {
|
|
exports: {}
|
|
};
|
|
factory(mod.exports);
|
|
global.bodyScrollLock = mod.exports;
|
|
}
|
|
})(this, function (exports) {
|
|
'use strict';
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
|
|
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);
|
|
|
|
|
|
var locks = [];
|
|
var documentListenerAdded = false;
|
|
var initialClientY = -1;
|
|
var previousBodyOverflowSetting = 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) {
|
|
// Setting overflow on body/documentElement synchronously in Desktop Safari slows down
|
|
// the responsiveness for some reason. Setting within a setTimeout fixes this.
|
|
setTimeout(function () {
|
|
// 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) {
|
|
previousBodyPaddingRight = document.body.style.paddingRight;
|
|
document.body.style.paddingRight = 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() {
|
|
// Setting overflow on body/documentElement synchronously in Desktop Safari slows down
|
|
// the responsiveness for some reason. Setting within a setTimeout fixes this.
|
|
setTimeout(function () {
|
|
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;
|
|
}
|
|
});
|
|
};
|
|
|
|
// 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 top of its scroll.
|
|
return preventDefault(event);
|
|
}
|
|
|
|
event.stopPropagation();
|
|
return true;
|
|
};
|
|
|
|
var disableBodyScroll = exports.disableBodyScroll = function disableBodyScroll(targetElement, options) {
|
|
if (isIosDevice) {
|
|
// targetElement must be provided, and disableBodyScroll must not have been
|
|
// called on this targetElement before.
|
|
if (!targetElement) {
|
|
// eslint-disable-next-line no-console
|
|
console.error('disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.');
|
|
return;
|
|
}
|
|
|
|
if (targetElement && !locks.some(function (lock) {
|
|
return lock.targetElement === targetElement;
|
|
})) {
|
|
var lock = {
|
|
targetElement: targetElement,
|
|
options: options || {}
|
|
};
|
|
|
|
locks = [].concat(_toConsumableArray(locks), [lock]);
|
|
|
|
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;
|
|
}
|
|
}
|
|
} else {
|
|
setOverflowHidden(options);
|
|
var _lock = {
|
|
targetElement: targetElement,
|
|
options: options || {}
|
|
};
|
|
|
|
locks = [].concat(_toConsumableArray(locks), [_lock]);
|
|
}
|
|
};
|
|
|
|
var clearAllBodyScrollLocks = exports.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;
|
|
}
|
|
|
|
locks = [];
|
|
|
|
// Reset initial clientY.
|
|
initialClientY = -1;
|
|
} else {
|
|
restoreOverflowSetting();
|
|
locks = [];
|
|
}
|
|
};
|
|
|
|
var enableBodyScroll = exports.enableBodyScroll = function enableBodyScroll(targetElement) {
|
|
if (isIosDevice) {
|
|
if (!targetElement) {
|
|
// eslint-disable-next-line no-console
|
|
console.error('enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.');
|
|
return;
|
|
}
|
|
|
|
targetElement.ontouchstart = null;
|
|
targetElement.ontouchmove = null;
|
|
|
|
locks = locks.filter(function (lock) {
|
|
return lock.targetElement !== targetElement;
|
|
});
|
|
|
|
if (documentListenerAdded && locks.length === 0) {
|
|
document.removeEventListener('touchmove', preventDefault, hasPassiveEvents ? { passive: false } : undefined);
|
|
|
|
documentListenerAdded = false;
|
|
}
|
|
} else {
|
|
locks = locks.filter(function (lock) {
|
|
return lock.targetElement !== targetElement;
|
|
});
|
|
if (!locks.length) {
|
|
restoreOverflowSetting();
|
|
}
|
|
}
|
|
};
|
|
});
|