about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorLes Orchard <me@lmorchard.com>2018-11-08 12:45:20 -0500
committerEugen Rochko <eugen@zeonfederated.com>2018-11-08 18:45:20 +0100
commit9cfd610484541c14bcde3c368a158b9b5d2a6499 (patch)
tree76a024746149f0bf511e9f4a71f5f52188362665 /app
parentb22db8162a936884ba17bc89637d5368e6745df0 (diff)
Cancel list scroll reset after mouse move on wheel scroll (#9233)
- Use object properties rather than component state for
  mouseMovedRecently and scrollToTopOnMouseIdle flags

- Remove redundant scrollToTop prop call, also fixing an attempt to call
  an undefined prop.

Fixes #9217
Diffstat (limited to 'app')
-rw-r--r--app/javascript/mastodon/components/scrollable_list.js41
1 files changed, 20 insertions, 21 deletions
diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js
index e51c83c2b..94e157acf 100644
--- a/app/javascript/mastodon/components/scrollable_list.js
+++ b/app/javascript/mastodon/components/scrollable_list.js
@@ -39,8 +39,6 @@ export default class ScrollableList extends PureComponent {
 
   state = {
     fullscreen: null,
-    mouseMovedRecently: false,
-    scrollToTopOnMouseIdle: false,
   };
 
   intersectionObserverWrapper = new IntersectionObserverWrapper();
@@ -65,6 +63,8 @@ export default class ScrollableList extends PureComponent {
   });
 
   mouseIdleTimer = null;
+  mouseMovedRecently = false;
+  scrollToTopOnMouseIdle = false;
 
   clearMouseIdleTimer = () => {
     if (this.mouseIdleTimer === null) {
@@ -80,29 +80,26 @@ export default class ScrollableList extends PureComponent {
     this.mouseIdleTimer =
       setTimeout(this.handleMouseIdle, MOUSE_IDLE_DELAY);
 
-    this.setState(({
-      mouseMovedRecently,
-      scrollToTopOnMouseIdle,
-    }) => ({
-      mouseMovedRecently: true,
-      // Only set scrollToTopOnMouseIdle if we just started moving and were
-      // scrolled to the top. Otherwise, just retain the previous state.
-      scrollToTopOnMouseIdle:
-        mouseMovedRecently
-          ? scrollToTopOnMouseIdle
-          : (this.node.scrollTop === 0),
-    }));
+    if (!this.mouseMovedRecently && this.node.scrollTop === 0) {
+      // Only set if we just started moving and are scrolled to the top.
+      this.scrollToTopOnMouseIdle = true;
+    }
+    // Save setting this flag for last, so we can do the comparison above.
+    this.mouseMovedRecently = true;
   }, MOUSE_IDLE_DELAY / 2);
 
+  handleWheel = throttle(() => {
+    this.scrollToTopOnMouseIdle = false;
+  }, 150, {
+    trailing: true,
+  });
+
   handleMouseIdle = () => {
-    if (this.state.scrollToTopOnMouseIdle) {
+    if (this.scrollToTopOnMouseIdle) {
       this.node.scrollTop = 0;
-      this.props.onScrollToTop();
     }
-    this.setState({
-      mouseMovedRecently: false,
-      scrollToTopOnMouseIdle: false,
-    });
+    this.mouseMovedRecently = false;
+    this.scrollToTopOnMouseIdle = false;
   }
 
   componentDidMount () {
@@ -118,7 +115,7 @@ export default class ScrollableList extends PureComponent {
     const someItemInserted = React.Children.count(prevProps.children) > 0 &&
       React.Children.count(prevProps.children) < React.Children.count(this.props.children) &&
       this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props);
-    if ((someItemInserted && this.node.scrollTop > 0) || this.state.mouseMovedRecently) {
+    if ((someItemInserted && this.node.scrollTop > 0) || this.mouseMovedRecently) {
       return this.node.scrollHeight - this.node.scrollTop;
     } else {
       return null;
@@ -161,10 +158,12 @@ export default class ScrollableList extends PureComponent {
 
   attachScrollListener () {
     this.node.addEventListener('scroll', this.handleScroll);
+    this.node.addEventListener('wheel', this.handleWheel);
   }
 
   detachScrollListener () {
     this.node.removeEventListener('scroll', this.handleScroll);
+    this.node.removeEventListener('wheel', this.handleWheel);
   }
 
   getFirstChildKey (props) {