]> git.ipfire.org Git - thirdparty/foundation/foundation-sites.git/commitdiff
refactor: split stop scroll propagation method
authorRastislav Chynoransky <rastislav.chynoransky@gmail.com>
Tue, 25 Feb 2020 04:22:09 +0000 (05:22 +0100)
committerJoe Workman <joe@workmanmail.com>
Fri, 27 Aug 2021 19:58:07 +0000 (12:58 -0700)
js/foundation.offcanvas.js

index 18ff5963f91d87b67b7c3c66afa17281b1427ac9..37c6b17b24eebd680b00602385371fa3c7fea669 100644 (file)
@@ -323,44 +323,71 @@ class OffCanvas extends Plugin {
     return false;
   }
 
+  /**
+   * Save current finger y-position
+   * @param event
+   * @private
+   */
   _recordScrollable(event) {
-    this.lastY = event.touches[0].pageY;
+    const elem = this;
+    elem.lastY = event.touches[0].pageY;
   }
 
   /**
-   * Prevent the given event propagation if the element given as context can scroll.
-   * Used to preserve the element scrolling on mobile (`touchmove`) when the document
-   * scrolling is prevented. See https://git.io/zf-9707.
-   * @function
+   * Prevent further scrolling when it hits the edges
+   * @param event
    * @private
    */
-  _stopScrollPropagation(event) {
-    let elem = this; // called from event handler context with this as elem
+  _preventDefaultAtEdges(event) {
+    const elem = this;
+    const _this = event.data;
     const delta = elem.lastY - event.touches[0].pageY;
-    const up = delta < 0;
-    const down = delta > 0;
-    const allowUp = elem.scrollTop > 0;
-    const allowDown = elem.scrollTop < elem.scrollHeight - elem.clientHeight;
     elem.lastY = event.touches[0].pageY;
 
-    if (up && allowUp || down && allowDown) {
-      // It is not recommended to stop event propagation (the user cannot watch it),
-      // but in this case this is the only solution we have.
-      event.stopPropagation();
-    } else if (elem.hasAttribute('data-off-canvas-scrollbox')) {
-      // If elem is inner scrollbox we are scrolling the outer off-canvas down/up once the box end has been reached
-      // This lets the user continue to touch move the off-canvas without the need to place the finger outside the scrollbox
-      const parent = elem.closest('[data-off-canvas], [data-off-canvas-scrollbox-outer]');
-      const allowParentScrollUp = parent.scrollTop > 0;
-      const allowParentScrollDown = parent.scrollTop < parent.scrollHeight - parent.clientHeight;
-      if (up && allowParentScrollUp || down && allowParentScrollDown) {
+    if (!_this._canScroll(delta, elem)) {
+      event.preventDefault();
+    }
+  }
+
+  /**
+   * Handle continuous scrolling of scrollbox
+   * Don't bubble up to _preventDefaultAtEdges
+   * @param event
+   * @private
+   */
+  _scrollboxTouchMoved(event) {
+    const elem = this;
+    const _this = event.data;
+    const parent = elem.closest('[data-off-canvas], [data-off-canvas-scrollbox-outer]');
+    const delta = elem.lastY - event.touches[0].pageY;
+    parent.lastY = elem.lastY = event.touches[0].pageY;
+
+    event.stopPropagation();
+
+    if (!_this._canScroll(delta, elem)) {
+      if (!_this._canScroll(delta, parent)) {
+        event.preventDefault();
+      } else {
         parent.scrollTop += delta;
       }
-    } else {
-      event.preventDefault();
     }
   }
 
+  /**
+   * Detect possibility of scrolling
+   * @param delta
+   * @param elem
+   * @returns boolean
+   * @private
+   */
+  _canScroll(delta, elem) {
+    const up = delta < 0;
+    const down = delta > 0;
+    const allowUp = elem.scrollTop > 0;
+    const allowDown = elem.scrollTop < elem.scrollHeight - elem.clientHeight;
+    return up && allowUp || down && allowDown;
+  }
+
   /**
    * Opens the off-canvas menu.
    * @function
@@ -400,9 +427,9 @@ class OffCanvas extends Plugin {
     if (this.options.contentScroll === false) {
       $('body').addClass('is-off-canvas-open').on('touchmove', this._stopScrolling);
       this.$element.on('touchstart', this._recordScrollable);
-      this.$element.on('touchmove', this._stopScrollPropagation);
+      this.$element.on('touchmove', this, this._preventDefaultAtEdges);
       this.$element.on('touchstart', '[data-off-canvas-scrollbox]', this._recordScrollable);
-      this.$element.on('touchmove', '[data-off-canvas-scrollbox]', this._stopScrollPropagation);
+      this.$element.on('touchmove', '[data-off-canvas-scrollbox]', this, this._scrollboxTouchMoved);
     }
 
     if (this.options.contentOverlay === true) {
@@ -502,9 +529,9 @@ class OffCanvas extends Plugin {
       if (this.options.contentScroll === false) {
         $('body').removeClass('is-off-canvas-open').off('touchmove', this._stopScrolling);
         this.$element.off('touchstart', this._recordScrollable);
-        this.$element.off('touchmove', this._stopScrollPropagation);
+        this.$element.off('touchmove', this._preventDefaultAtEdges);
         this.$element.off('touchstart', '[data-off-canvas-scrollbox]', this._recordScrollable);
-        this.$element.off('touchmove', '[data-off-canvas-scrollbox]', this._stopScrollPropagation);
+        this.$element.off('touchmove', '[data-off-canvas-scrollbox]', this._scrollboxTouchMoved);
       }
 
       if (this.options.trapFocus === true) {