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