UNPKG

os-scroll-chain

Version:

OverlayScrollbars Extension to prevent scroll chaining

180 lines (160 loc) 7.37 kB
/** * os-scroll-chain v2.0.2 * (c) 2022 Hamed Ehtesham * Released under the MIT License. */ (function () { 'use strict'; OverlayScrollbars.extension('scroll-chain', function (defaultOptions, framework, compatibility) { defaultOptions = defaultOptions || {}; var osInstance = this; var instanceElements = osInstance.getElements(); var $viewport = framework(instanceElements.viewport); var preventVertical = defaultOptions.vertical || true; var preventHorizontal = defaultOptions.horizontal || true; /* * each event should be processed by the nearest parent scrollbar */ function shouldProcess(event) { var foundViewport = false; var self = event.target; while (!foundViewport) { if (!self) { return false; } else if (self.className && self.className.startsWith('os-viewport')) { foundViewport = true; if (self !== instanceElements.viewport) return false; } self = self.parentNode; } return true; } var trapWheel = function trapWheel(event) { if (!shouldProcess(event)) return; var isHorizontal = event.shiftKey || false; if (isHorizontal) { if (preventHorizontal) { // cross-browser wheel delta event = window.event || event; var delta = Math.min(1, Math.max(-1, -event.wheelDelta || event.deltaY || event.detail)); var xScrollPos = $viewport.scrollLeft() + 0.5; // only trap events once we've scrolled to the end or beginning if (delta > 0 && xScrollPos >= osInstance.scroll().max.x || delta < 0 && xScrollPos <= 1) { compatibility.prvD(event); return false; } } } else if (preventVertical) { // cross-browser wheel delta event = window.event || event; var _delta = Math.min(1, Math.max(-1, -event.wheelDelta || event.deltaY || event.detail)); var yScrollPos = $viewport.scrollTop() + 0.5; // only trap events once we've scrolled to the end or beginning if (_delta > 0 && yScrollPos >= osInstance.scroll().max.y || _delta < 0 && yScrollPos <= 1) { compatibility.prvD(event); return false; } } }; var xStart = void 0, yStart = void 0, firstTime = void 0, parentScroll = void 0; var handleTouchStart = function handleTouchStart(event) { xStart = event.touches[0].clientX; yStart = event.touches[0].clientY; firstTime = true; parentScroll = false; }; /* * detect significant axis between x, y */ function significant(x, y) { var xAbs = Math.abs(x); var yAbs = Math.abs(y); var xSignificant = true; var ySignificant = true; if (xAbs - yAbs > 0) { if (xAbs / yAbs >= 2) ySignificant = false; } else { if (yAbs / xAbs >= 2) xSignificant = false; } return { ySignificant: ySignificant, xSignificant: xSignificant }; } var handleTouchMove = function handleTouchMove(event) { if (!shouldProcess(event)) return; if (parentScroll) { compatibility.prvD(event); return false; } else if (!firstTime) return; if (!yStart || !xStart) return; var yEnd = event.touches[0].clientY; var xEnd = event.touches[0].clientX; var yDiff = yStart - yEnd; var xDiff = xStart - xEnd; // detect significant axis var _significant = significant(xDiff, yDiff), ySignificant = _significant.ySignificant, xSignificant = _significant.xSignificant; if (preventVertical && ySignificant) { var yScrollPos = $viewport.scrollTop() + 0.5; if (yDiff > 0 && yScrollPos >= osInstance.scroll().max.y || yDiff < 0 && yScrollPos <= 1) { if (firstTime) { parentScroll = true; } compatibility.prvD(event); } } if (preventHorizontal && xSignificant) { var xScrollPos = $viewport.scrollLeft() + 0.5; if (xDiff > 0 && xScrollPos >= osInstance.scroll().max.x || xDiff < 0 && xScrollPos <= 1) { if (firstTime) { parentScroll = true; } compatibility.prvD(event); } } firstTime = false; }; var isEventSupported = function isEventSupported(eventName) { var TAGNAMES = { 'select': 'input', 'change': 'input', 'submit': 'form', 'reset': 'form', 'error': 'img', 'load': 'img', 'abort': 'img' }; var el = document.createElement(TAGNAMES[eventName] || 'div'); eventName = 'on' + eventName; var isSupported = eventName in el; if (!isSupported) { el.setAttribute(eventName, 'return;'); isSupported = typeof el[eventName] == 'function'; } el = null; return isSupported; }; return { added: function added(options) { options = options || {}; preventVertical = options.vertical !== undefined ? !!options.vertical : preventVertical; preventHorizontal = options.horizontal !== undefined ? !!options.horizontal : preventHorizontal; if (isEventSupported('wheel')) $viewport.on('wheel', trapWheel);else $viewport.on('mousewheel DOMMouseScroll', trapWheel); $viewport.on('touchstart', handleTouchStart); $viewport.on('touchmove', handleTouchMove); if (preventVertical && preventHorizontal) $viewport.css('overscroll-behavior', 'none');else { if (preventVertical) $viewport.css('overscroll-behavior-y', 'none'); if (preventHorizontal) $viewport.css('overscroll-behavior-x', 'none'); } }, removed: function removed() { if (isEventSupported('wheel')) $viewport.off('wheel', trapWheel);else $viewport.off('mousewheel DOMMouseScroll', trapWheel); $viewport.off('touchstart', handleTouchStart); $viewport.off('touchmove', handleTouchMove); if (preventVertical && preventHorizontal) $viewport.css('overscroll-behavior', 'unset');else { if (preventVertical) $viewport.css('overscroll-behavior-y', 'unset'); if (preventHorizontal) $viewport.css('overscroll-behavior-x', 'unset'); } } }; }); })(); //# sourceMappingURL=os-scroll-chain.js.map