about summary refs log tree commit diff
path: root/app/javascript/mastodon/components/status_list.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/mastodon/components/status_list.js')
-rw-r--r--app/javascript/mastodon/components/status_list.js58
1 files changed, 54 insertions, 4 deletions
diff --git a/app/javascript/mastodon/components/status_list.js b/app/javascript/mastodon/components/status_list.js
index 87a95fd12..b82c63a84 100644
--- a/app/javascript/mastodon/components/status_list.js
+++ b/app/javascript/mastodon/components/status_list.js
@@ -26,6 +26,12 @@ class StatusList extends ImmutablePureComponent {
     trackScroll: true,
   };
 
+  state = {
+    isIntersecting: [{ }],
+  }
+
+  statusRefQueue = []
+
   handleScroll = (e) => {
     const { scrollTop, scrollHeight, clientHeight } = e.target;
     const offset = scrollHeight - scrollTop - clientHeight;
@@ -42,6 +48,7 @@ class StatusList extends ImmutablePureComponent {
 
   componentDidMount () {
     this.attachScrollListener();
+    this.attachIntersectionObserver();
   }
 
   componentDidUpdate (prevProps) {
@@ -52,6 +59,39 @@ class StatusList extends ImmutablePureComponent {
 
   componentWillUnmount () {
     this.detachScrollListener();
+    this.detachIntersectionObserver();
+  }
+
+  attachIntersectionObserver () {
+    const onIntersection = (entries) => {
+      this.setState(state => {
+        const isIntersecting = { };
+
+        entries.forEach(entry => {
+          const statusId = entry.target.getAttribute('data-id');
+
+          state.isIntersecting[0][statusId] = entry.isIntersecting;
+        });
+
+        return { isIntersecting: [state.isIntersecting[0]] };
+      });
+    };
+
+    const options = {
+      root: this.node,
+      rootMargin: '300% 0px',
+    };
+
+    this.intersectionObserver = new IntersectionObserver(onIntersection, options);
+
+    if (this.statusRefQueue.length) {
+      this.statusRefQueue.forEach(node => this.intersectionObserver.observe(node));
+      this.statusRefQueue = [];
+    }
+  }
+
+  detachIntersectionObserver () {
+    this.intersectionObserver.disconnect();
   }
 
   attachScrollListener () {
@@ -66,6 +106,15 @@ class StatusList extends ImmutablePureComponent {
     this.node = c;
   }
 
+  handleStatusRef = (node) => {
+    if (node && this.intersectionObserver) {
+      const statusId = node.getAttribute('data-id');
+      this.intersectionObserver.observe(node);
+    } else {
+      this.statusRefQueue.push(node);
+    }
+  }
+
   handleLoadMore = (e) => {
     e.preventDefault();
     this.props.onScrollToBottom();
@@ -73,10 +122,11 @@ class StatusList extends ImmutablePureComponent {
 
   render () {
     const { statusIds, onScrollToBottom, scrollKey, shouldUpdateScroll, isLoading, isUnread, hasMore, prepend, emptyMessage } = this.props;
+    const isIntersecting = this.state.isIntersecting[0];
 
-    let loadMore       = '';
-    let scrollableArea = '';
-    let unread         = '';
+    let loadMore       = null;
+    let scrollableArea = null;
+    let unread         = null;
 
     if (!isLoading && statusIds.size > 0 && hasMore) {
       loadMore = <LoadMore onClick={this.handleLoadMore} />;
@@ -95,7 +145,7 @@ class StatusList extends ImmutablePureComponent {
             {prepend}
 
             {statusIds.map((statusId) => {
-              return <StatusContainer key={statusId} id={statusId} />;
+              return <StatusContainer key={statusId} id={statusId} isIntersecting={isIntersecting[statusId]} onRef={this.handleStatusRef} />;
             })}
 
             {loadMore}