PageSourceSearch

https://www.twik.io/wp-content/themes/twik_website_v2/js/product-page/modules/body-scroll-lock.js

js twik.io collected 2026-09-25 02:41:07 UTC 9,183 bytes, 277 lines download raw bytes

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.