diff --git a/CHANGELOG.md b/CHANGELOG.md index d759fcb223..a4ea4a3fd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,11 @@ Changelog _Note: Gaps between patch versions are faulty, broken or test releases._ -## v3.??.? (2023-??-??) +## v3.62.2 (2023-12-07) + +#### :bug: Bug Fix + +* Fixed a bug with clearing event listeners on ios `traits/i-lock-page-scroll` #### :house: Internal diff --git a/package.json b/package.json index b826bdc938..e0bbe1493a 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "src/core/index.js", "typings": "index.d.ts", "license": "MIT", - "version": "3.62.1", + "version": "3.62.2", "author": { "name": "kobezzza", "email": "kobezzza@gmail.com", diff --git a/src/traits/i-lock-page-scroll/CHANGELOG.md b/src/traits/i-lock-page-scroll/CHANGELOG.md index facf35c2b0..12ee1901a1 100644 --- a/src/traits/i-lock-page-scroll/CHANGELOG.md +++ b/src/traits/i-lock-page-scroll/CHANGELOG.md @@ -9,6 +9,12 @@ Changelog > - :house: [Internal] > - :nail_care: [Polish] +## v3.62.2 (2023-12-07) + +#### :bug: Bug Fix + +* Fixed a bug with clearing event listeners on ios + ## v3.57.0 (2023-08-28) #### :bug: Bug Fix diff --git a/src/traits/i-lock-page-scroll/i-lock-page-scroll.ts b/src/traits/i-lock-page-scroll/i-lock-page-scroll.ts index 67f392da1f..59fe26c989 100644 --- a/src/traits/i-lock-page-scroll/i-lock-page-scroll.ts +++ b/src/traits/i-lock-page-scroll/i-lock-page-scroll.ts @@ -33,11 +33,14 @@ export default abstract class iLockPageScroll { r: {unsafe: {async: $a}} } = component; + if (is.mobile !== false && is.iOS !== false) { + iLockPageScroll.initIOSScrollableNodeListeners(component, scrollableNode); + } + let promise = Promise.resolve(); if (r[$$.isLocked] === true) { - $a.clearAll({group}); return promise; } @@ -49,52 +52,6 @@ export default abstract class iLockPageScroll { if (is.mobile !== false) { if (is.iOS !== false) { - if (scrollableNode) { - const - onTouchStart = (e: TouchEvent) => component[$$.initialY] = e.targetTouches[0].clientY; - - $a.on(scrollableNode, 'touchstart', onTouchStart, { - group, - label: $$.touchstart - }); - - const onTouchMove = (e: TouchEvent) => { - let - scrollTarget = (e.target ?? scrollableNode); - - while (scrollTarget !== scrollableNode) { - if (scrollTarget.scrollHeight > scrollTarget.clientHeight || !scrollTarget.parentElement) { - break; - } - - scrollTarget = scrollTarget.parentElement; - } - - const { - scrollTop, - scrollHeight, - clientHeight - } = scrollTarget; - - const - clientY = e.targetTouches[0].clientY - component[$$.initialY], - isOnTop = clientY > 0 && scrollTop === 0, - isOnBottom = clientY < 0 && scrollTop + clientHeight + 1 >= scrollHeight; - - if ((isOnTop || isOnBottom) && e.cancelable) { - return e.preventDefault(); - } - - e.stopPropagation(); - }; - - $a.on(scrollableNode, 'touchmove', onTouchMove, { - group, - label: $$.touchmove, - options: {passive: false} - }); - } - $a.on(document, 'touchmove', (e: TouchEvent) => e.cancelable && e.preventDefault(), { group, label: $$.preventTouchMove, @@ -114,7 +71,7 @@ export default abstract class iLockPageScroll { body.scrollTop; r[$$.scrollTop] = scrollTop; - body.style.top = `-${scrollTop}px`; + body.style.top = (-scrollTop).px; r.setRootMod('lockScrollMobile', true); r[$$.isLocked] = true; @@ -133,7 +90,7 @@ export default abstract class iLockPageScroll { scrollBarWidth = globalThis.innerWidth - body.clientWidth; r[$$.paddingRight] = body.style.paddingRight; - body.style.paddingRight = `${scrollBarWidth}px`; + body.style.paddingRight = scrollBarWidth.px; r.setRootMod('lockScrollDesktop', true); r[$$.isLocked] = true; @@ -164,6 +121,7 @@ export default abstract class iLockPageScroll { r.removeRootMod('lockScrollMobile', true); r.removeRootMod('lockScrollDesktop', true); r[$$.isLocked] = false; + iLockPageScroll.scrollableNodes = new WeakSet(); if (is.mobile !== false) { globalThis.scrollTo(0, r[$$.scrollTop]); @@ -211,6 +169,70 @@ export default abstract class iLockPageScroll { }); } + /** + * A set of scrollable nodes for the iOS platform + */ + protected static scrollableNodes: WeakSet = new WeakSet(); + + /** + * Initializes touch event listeners for the provided node on the iOS platform + * @see https://stackoverflow.com/questions/59193062/how-to-disable-scrolling-on-body-in-ios-13-safari-when-saved-as-pwa-to-the-hom + * + * @param component + * @param [scrollableNode] + */ + protected static initIOSScrollableNodeListeners(component: iBlock, scrollableNode?: Element): void { + const + {r: {unsafe: {async: $a}}} = component; + + if (scrollableNode == null || iLockPageScroll.scrollableNodes.has(scrollableNode)) { + return; + } + + iLockPageScroll.scrollableNodes.add(scrollableNode); + + const + onTouchStart = (e: TouchEvent) => component[$$.initialY] = e.targetTouches[0].clientY; + + $a.on(scrollableNode, 'touchstart', onTouchStart, { + group + }); + + const onTouchMove = (e: TouchEvent) => { + let + scrollTarget = (e.target ?? scrollableNode); + + while ( + scrollTarget !== scrollableNode && + scrollTarget.scrollHeight <= scrollTarget.clientHeight && scrollTarget.parentElement + ) { + scrollTarget = scrollTarget.parentElement; + } + + const { + scrollTop, + scrollHeight, + clientHeight + } = scrollTarget; + + const + clientY = e.targetTouches[0].clientY - component[$$.initialY], + isOnTop = clientY > 0 && scrollTop === 0, + isOnBottom = clientY < 0 && scrollTop + clientHeight + 1 >= scrollHeight; + + if ((isOnTop || isOnBottom) && e.cancelable) { + return e.preventDefault(); + } + + e.stopPropagation(); + }; + + $a.on(scrollableNode, 'touchmove', onTouchMove, { + group, + options: {passive: false} + }); + } + /** * Locks the document scroll, i.e., * it prevents any scrolling on the document except withing the specified node