1(function (global, factory) { 2 if (typeof define === 'function' && define.amd) { 3 define(['exports'], factory); 4 } else if (typeof exports !== 'undefined') { 5 factory(exports); 6 } else { 7 var mod = { 8 exports: {}, 9 }; 10 factory(mod.exports); 11 global.bodyScrollLock = mod.exports; 12 } 13})(this, function (exports) { 14 'use strict'; 15 16 Object.defineProperty(exports, '__esModule', { 17 value: true, 18 }); 19 20 function _toConsumableArray(arr) { 21 if (Array.isArray(arr)) { 22 for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { 23 arr2[i] = arr[i]; 24 } 25 26 return arr2; 27 } else { 28 return Array.from(arr); 29 } 30 } 31 32 // Older browsers don't support event options, feature detect it. 33 34 // Adopted and modified solution from Bohdan Didukh (2017) 35 // https://stackoverflow.com/questions/41594997/ios-10-safari-prevent-scrolling-behind-a-fixed-overlay-and-maintain-scroll-posi 36 37 var hasPassiveEvents = false; 38 if (typeof window !== 'undefined') { 39 var passiveTestOptions = { 40 get passive() { 41 hasPassiveEvents = true; 42 return undefined; 43 }, 44 }; 45 window.addEventListener('testPassive', null, passiveTestOptions); 46 window.removeEventListener('testPassive', null, passiveTestOptions); 47 } 48 49 var isIosDevice = 50 typeof window !== 'undefined' && 51 window.navigator && 52 window.navigator.platform && 53 (/iP(ad|hone|od)/.test(window.navigator.platform) || 54 (window.navigator.platform === 'MacIntel' && 55 window.navigator.maxTouchPoints > 1)); 56 57 var locks = []; 58 var documentListenerAdded = false; 59 var initialClientY = -1; 60 var previousBodyOverflowSetting = void 0; 61 var previousBodyPosition = void 0; 62 var previousBodyPaddingRight = void 0; 63 64 // returns true if `el` should be allowed to receive touchmove events. 65 var allowTouchMove = function allowTouchMove(el) { 66 return locks.some(function (lock) { 67 if (lock.options.allowTouchMove && lock.options.allowTouchMove(el)) { 68 return true; 69 } 70 71 return false; 72 }); 73 }; 74 75 var preventDefault = function preventDefault(rawEvent) { 76 var e = rawEvent || window.event; 77 78 // For the case whereby consumers adds a touchmove event listener to document. 79 // Recall that we do document.addEventListener('touchmove', preventDefault, { passive: false }) 80 // in disableBodyScroll - so if we provide this opportunity to allowTouchMove, then 81 // the touchmove event on document will break. 82 if (allowTouchMove(e.target)) { 83 return true; 84 } 85 86 // Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom). 87 if (e.touches.length > 1) return true; 88 89 if (e.preventDefault) e.preventDefault(); 90 91 return false; 92 }; 93 94 var setOverflowHidden = function setOverflowHidden(options) { 95 // If previousBodyPaddingRight is already set, don't set it again. 96 if (previousBodyPaddingRight === undefined) { 97 var _reserveScrollBarGap = 98 !!options && options.reserveScrollBarGap === true; 99 var scrollBarGap = 100 window.innerWidth - document.documentElement.clientWidth; 101 102 if (_reserveScrollBarGap && scrollBarGap > 0) { 103 var computedBodyPaddingRight = parseInt( 104 window 105 .getComputedStyle(document.body) 106 .getPropertyValue('padding-right'), 107 10 108 ); 109 previousBodyPaddingRight = document.body.style.paddingRight; 110 document.body.style.paddingRight = 111 computedBodyPaddingRight + scrollBarGap + 'px'; 112 } 113 } 114 115 // If previousBodyOverflowSetting is already set, don't set it again. 116 if (previousBodyOverflowSetting === undefined) { 117 previousBodyOverflowSetting = document.body.style.overflow; 118 document.body.style.overflow = 'hidden'; 119 } 120 }; 121 122 var restoreOverflowSetting = function restoreOverflowSetting() { 123 if (previousBodyPaddingRight !== undefined) { 124 document.body.style.paddingRight = previousBodyPaddingRight; 125 126 // Restore previousBodyPaddingRight to undefined so setOverflowHidden knows it 127 // can be set again. 128 previousBodyPaddingRight = undefined; 129 } 130 131 if (previousBodyOverflowSetting !== undefined) { 132 document.body.style.overflow = previousBodyOverflowSetting; 133 134 // Restore previousBodyOverflowSetting to undefined 135 // so setOverflowHidden knows it can be set again. 136 previousBodyOverflowSetting = undefined; 137 } 138 }; 139 140 var setPositionFixed = function setPositionFixed() { 141 return window.requestAnimationFrame(function () { 142 // If previousBodyPosition is already set, don't set it again. 143 if (previousBodyPosition === undefined) { 144 previousBodyPosition = { 145 position: document.body.style.position, 146 top: document.body.style.top, 147 left: document.body.style.left, 148 }; 149 150 // Update the dom inside an animation frame 151 var _window = window, 152 scrollY = _window.scrollY, 153 scrollX = _window.scrollX, 154 innerHeight = _window.innerHeight; 155 156 document.body.style.position = 'fixed'; 157 document.body.style.top = -scrollY; 158 document.body.style.left = -scrollX; 159 160 setTimeout(function () { 161 return window.requestAnimationFrame(function () { 162 // Attempt to check if the bottom bar appeared due to the position change
163 var bottomBarHeight = innerHeight - window.innerHeight; 164 if (bottomBarHeight && scrollY >= innerHeight) { 165 // Move the content further up so that the bottom bar doesn't hide it 166 document.body.style.top = -(scrollY + bottomBarHeight); 167 } 168 }); 169 }, 300); 170 } 171 }); 172 }; 173 174 var restorePositionSetting = function restorePositionSetting() { 175 if (previousBodyPosition !== undefined) { 176 // Convert the position from "px" to Int 177 var y = -parseInt(document.body.style.top, 10); 178 var x = -parseInt(document.body.style.left, 10); 179 180 // Restore styles 181 document.body.style.position = previousBodyPosition.position; 182 document.body.style.top = previousBodyPosition.top; 183 document.body.style.left = previousBodyPosition.left; 184 185 // Restore scroll 186 window.scrollTo(x, y); 187 188 previousBodyPosition = undefined; 189 } 190 }; 191 192 // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions 193 var isTargetElementTotallyScrolled = function isTargetElementTotallyScrolled( 194 targetElement 195 ) { 196 return targetElement 197 ? targetElement.scrollHeight - targetElement.scrollTop <= 198 targetElement.clientHeight 199 : false; 200 }; 201 202 var handleScroll = function handleScroll(event, targetElement) { 203 var clientY = event.targetTouches[0].clientY - initialClientY; 204 205 if (allowTouchMove(event.target)) { 206 return false; 207 } 208 209 if (targetElement && targetElement.scrollTop === 0 && clientY > 0) { 210 // element is at the top of its scroll. 211 return preventDefault(event); 212 } 213 214 if (isTargetElementTotallyScrolled(targetElement) && clientY < 0) { 215 // element is at the bottom of its scroll. 216 return preventDefault(event); 217 } 218 219 event.stopPropagation(); 220 return true; 221 }; 222 223 var disableBodyScroll = (exports.disableBodyScroll = 224 function disableBodyScroll(targetElement, options) { 225 // targetElement must be provided 226 if (!targetElement) { 227 // eslint-disable-next-line no-console 228 console.error( 229 'disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.' 230 ); 231 return; 232 } 233 234 // disableBodyScroll must not have been called on this targetElement before 235 if ( 236 locks.some(function (lock) { 237 return lock.targetElement === targetElement; 238 }) 239 ) { 240 return; 241 } 242 243 var lock = { 244 targetElement: targetElement, 245 options: options || {}, 246 }; 247 248 locks = [].concat(_toConsumableArray(locks), [lock]); 249 250 if (isIosDevice) { 251 setPositionFixed(); 252 } else { 253 setOverflowHidden(options); 254 } 255 256 if (isIosDevice) { 257 targetElement.ontouchstart = function (event) { 258 if (event.targetTouches.length === 1) { 259 // detect single touch. 260 initialClientY = event.targetTouches[0].clientY; 261 } 262 }; 263 targetElement.ontouchmove = function (event) { 264 if (event.targetTouches.length === 1) { 265 // detect single touch. 266 handleScroll(event, targetElement); 267 } 268 }; 269 270 if (!documentListenerAdded) { 271 document.addEventListener( 272 'touchmove', 273 preventDefault, 274 hasPassiveEvents ? { passive: false } : undefined 275 ); 276 documentListenerAdded = true; 277 } 278 } 279 }); 280 281 var clearAllBodyScrollLocks = (exports.clearAllBodyScrollLocks = 282 function clearAllBodyScrollLocks() { 283 if (isIosDevice) { 284 // Clear all locks ontouchstart/ontouchmove handlers, and the references. 285 locks.forEach(function (lock) { 286 lock.targetElement.ontouchstart = null; 287 lock.targetElement.ontouchmove = null; 288 }); 289 290 if (documentListenerAdded) { 291 document.removeEventListener( 292 'touchmove', 293 preventDefault, 294 hasPassiveEvents ? { passive: false } : undefined 295 ); 296 documentListenerAdded = false;
297 } 298 299 // Reset initial clientY. 300 initialClientY = -1; 301 } 302 303 if (isIosDevice) { 304 restorePositionSetting(); 305 } else { 306 restoreOverflowSetting(); 307 } 308 309 locks = []; 310 }); 311 312 var enableBodyScroll = (exports.enableBodyScroll = function enableBodyScroll( 313 targetElement 314 ) { 315 if (!targetElement) { 316 // eslint-disable-next-line no-console 317 console.error( 318 'enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.' 319 ); 320 return; 321 } 322 323 locks = locks.filter(function (lock) { 324 return lock.targetElement !== targetElement; 325 }); 326 327 if (isIosDevice) { 328 targetElement.ontouchstart = null; 329 targetElement.ontouchmove = null; 330 331 if (documentListenerAdded && locks.length === 0) { 332 document.removeEventListener( 333 'touchmove', 334 preventDefault, 335 hasPassiveEvents ? { passive: false } : undefined 336 ); 337 documentListenerAdded = false; 338 } 339 } 340 341 if (isIosDevice) { 342 restorePositionSetting(); 343 } else { 344 restoreOverflowSetting(); 345 } 346 }); 347});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.