about summary refs log tree commit diff
path: root/app/javascript/mastodon/components/scrollable_list.js
diff options
context:
space:
mode:
authorThibG <thib@sitedethib.com>2019-02-11 13:19:59 +0100
committerEugen Rochko <eugen@zeonfederated.com>2019-02-11 13:19:59 +0100
commitaee93bfc9c7169f2e784de8572263de911922760 (patch)
tree4056fd7e74a8a01f4650dbc78bd9f475bd6e7494 /app/javascript/mastodon/components/scrollable_list.js
parentc0a564feaa11c072da9c2be892643db55659ae38 (diff)
Fix timeline jumps (#10001)
* Avoid two-step rendering of statuses as much as possible

Cache width shared by Video player, MediaGallery and Cards at the
ScrollableList level, pass it down through StatusList and Notifications.

* Adjust scroll when new preview cards appear

* Adjust scroll when statuses above the current scroll position are deleted
Diffstat (limited to 'app/javascript/mastodon/components/scrollable_list.js')
-rw-r--r--app/javascript/mastodon/components/scrollable_list.js28
1 files changed, 27 insertions, 1 deletions
diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js
index fec06e263..0376cf85a 100644
--- a/app/javascript/mastodon/components/scrollable_list.js
+++ b/app/javascript/mastodon/components/scrollable_list.js
@@ -40,6 +40,7 @@ export default class ScrollableList extends PureComponent {
 
   state = {
     fullscreen: null,
+    cachedMediaWidth: 250, // Default media/card width using default Mastodon theme
   };
 
   intersectionObserverWrapper = new IntersectionObserverWrapper();
@@ -130,6 +131,20 @@ export default class ScrollableList extends PureComponent {
     this.handleScroll();
   }
 
+  getScrollPosition = () => {
+    if (this.node && (this.node.scrollTop > 0 || this.mouseMovedRecently)) {
+      return { height: this.node.scrollHeight, top: this.node.scrollTop };
+    } else {
+      return null;
+    }
+  }
+
+  updateScrollBottom = (snapshot) => {
+    const newScrollTop = this.node.scrollHeight - snapshot;
+
+    this.setScrollTop(newScrollTop);
+  }
+
   getSnapshotBeforeUpdate (prevProps) {
     const someItemInserted = React.Children.count(prevProps.children) > 0 &&
       React.Children.count(prevProps.children) < React.Children.count(this.props.children) &&
@@ -150,6 +165,12 @@ export default class ScrollableList extends PureComponent {
     }
   }
 
+  cacheMediaWidth = (width) => {
+    if (width && this.state.cachedMediaWidth !== width) {
+      this.setState({ cachedMediaWidth: width });
+    }
+  }
+
   componentWillUnmount () {
     this.clearMouseIdleTimer();
     this.detachScrollListener();
@@ -239,7 +260,12 @@ export default class ScrollableList extends PureComponent {
                 intersectionObserverWrapper={this.intersectionObserverWrapper}
                 saveHeightKey={trackScroll ? `${this.context.router.route.location.key}:${scrollKey}` : null}
               >
-                {child}
+                {React.cloneElement(child, {
+                  getScrollPosition: this.getScrollPosition,
+                  updateScrollBottom: this.updateScrollBottom,
+                  cachedMediaWidth: this.state.cachedMediaWidth,
+                  cacheMediaWidth: this.cacheMediaWidth,
+                })}
               </IntersectionObserverArticleContainer>
             ))}