From a352821495aa14d8d3586fbd064cfa3ce42b4156 Mon Sep 17 00:00:00 2001 From: Your Autistic Life Date: Tue, 8 Aug 2023 16:59:32 -0400 Subject: [PATCH] fix: take into account when the document body is scrolled --- .../mastodon/components/scrollable_list.jsx | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/app/javascript/mastodon/components/scrollable_list.jsx b/app/javascript/mastodon/components/scrollable_list.jsx index f1f92595fa..b2cb23617f 100644 --- a/app/javascript/mastodon/components/scrollable_list.jsx +++ b/app/javascript/mastodon/components/scrollable_list.jsx @@ -88,6 +88,7 @@ class ScrollableList extends PureComponent { intersectionObserverWrapper = new IntersectionObserverWrapper(); firstSeenArticle = null; + scrollAdjustment = 0; handleScroll = throttle(() => { if (this.node) { @@ -132,6 +133,12 @@ class ScrollableList extends PureComponent { // Handle initial scroll position this.handleScroll(); + + // If we are bound to the document, the stuff above the scrollable has to + // be taken into account when we focus back to the article we want. + if (this.props.bindToDocument) { + this.scrollAdjustment = this.node.getBoundingClientRect().top; + } } getScrollPosition = () => { @@ -160,27 +167,6 @@ class ScrollableList extends PureComponent { this.setScrollTop(newScrollTop); }; - getSnapshotBeforeUpdate (prevProps) { - const someItemInserted = Children.count(prevProps.children) > 0 && - Children.count(prevProps.children) < Children.count(this.props.children) && - this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props); - const pendingChanged = (prevProps.numPending > 0) !== (this.props.numPending > 0); - - if (pendingChanged || someItemInserted && (this.getScrollTop() > 0 || this.props.preventScroll)) { - return this.getScrollHeight() - this.getScrollTop(); - } else { - return null; - } - } - - componentDidUpdate (prevProps, prevState, snapshot) { - // Reset the scroll position when a new child comes in in order not to - // jerk the scrollbar around if you're already scrolled down the page. - if (snapshot !== null) { - this.setScrollTop(this.getScrollHeight() - snapshot); - } - } - cacheMediaWidth = (width) => { if (width && this.state.cachedMediaWidth !== width) { this.setState({ cachedMediaWidth: width }); @@ -248,11 +234,14 @@ class ScrollableList extends PureComponent { preLoad = () => { // Here we record the first visible article so that when we mouseUp on // the LoadX element, were able to scroll back to it. + + // Note that it does not matter whether we are binding to the document, or + // not. The node we have to test is always that of the scrollable itself. const scrollableRect = this.node.getBoundingClientRect(); const articles = this.node.querySelectorAll("article"); for (const article of articles) { const articleRect = article.getBoundingClientRect(); - if (articleRect.top > scrollableRect.top) { + if (articleRect.top >= scrollableRect.top) { this.firstSeenArticle = article; break; } @@ -260,14 +249,21 @@ class ScrollableList extends PureComponent { } returnToFirstArticle () { - if (this.firstSeenArticle !== null) { - // Scroll the firstSeenArticle back into view once we're done with - // everything else. - setTimeout(() => { - firstSeenArticle.scrollIntoView(); - firstSeenArticle.querySelector("div.status__wrapper").focus(); - }, 0); + const first = this.firstSeenArticle; + if (first === null) { + return; } + + // Scroll the firstSeenArticle back into view once we're done with + // everything else. + setTimeout(() => { + // We need to adjust with the scrollAdjustment. It is non-zero only when + // we bind to the document. + this.setScrollTop(this.getScrollTop() + + first.getBoundingClientRect().top - + this.scrollAdjustment); + first.querySelector("div.status__wrapper").focus(); + }, 0); }