Fix linked-comment auto scroll

## Ticket
6946: Linked-comment scroll position is inconsistent

## Issues
- If it is a deeply-nested reply, the positioning is incorrect.
- If there are pinned comments, the positioning is way off.
- If there is a delay in mounting, the positioning doesn't happen.
- When clicking on the comment's date to highlight it, the comment goes missing and the scroll position is weird.

## Changes
- Take into account that replies can be linked-comments.
- Perform a "one-time" search for the linked-comment after the initial fetch, if necessary. The expensive DOM search is only be executed minimally.
This commit is contained in:
infinite-persistence 2021-09-01 15:55:00 +08:00
parent a9672a4b5c
commit be9dca362d
No known key found for this signature in database
GPG key ID: B9C3252EDC3D0AA0
3 changed files with 22 additions and 7 deletions

View file

@ -1,6 +1,7 @@
// @flow
import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages';
import { COMMENT_HIGHLIGHTED } from 'constants/classnames';
import { SORT_BY, COMMENT_PAGE_SIZE_REPLIES } from 'constants/comment';
import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field';
import { SITE_NAME, SIMPLE_SITE, ENABLE_COMMENT_REACTIONS } from 'config';
@ -220,7 +221,7 @@ function Comment(props: Props) {
>
<div
className={classnames('comment__content', {
'comment--highlighted': linkedCommentId && linkedCommentId === commentId,
[COMMENT_HIGHLIGHTED]: linkedCommentId && linkedCommentId === commentId,
'comment--slimed': slimedToDeath && !displayDeadComment,
})}
>

View file

@ -1,6 +1,7 @@
// @flow
import * as REACTION_TYPES from 'constants/reactions';
import * as ICONS from 'constants/icons';
import { COMMENT_HIGHLIGHTED } from 'constants/classnames';
import { COMMENT_PAGE_SIZE_TOP_LEVEL, SORT_BY } from 'constants/comment';
import React, { useEffect } from 'react';
import classnames from 'classnames';
@ -18,6 +19,9 @@ import { getChannelIdFromClaim } from 'util/claim';
const DEBOUNCE_SCROLL_HANDLER_MS = 200;
// "3" due to 2 separate fetches needed + 1 buffer just in case.
const MAX_LINKED_COMMENT_SCROLL_ATTEMPTS = 3;
function scaleToDevicePixelRatio(value) {
const devicePixelRatio = window.devicePixelRatio || 1.0;
if (devicePixelRatio < 1.0) {
@ -75,11 +79,13 @@ function CommentList(props: Props) {
settingsByChannelId,
} = props;
const commentRef = React.useRef();
const spinnerRef = React.useRef();
const DEFAULT_SORT = ENABLE_COMMENT_REACTIONS ? SORT_BY.POPULARITY : SORT_BY.NEWEST;
const [sort, setSort] = usePersistedState('comment-sort-by', DEFAULT_SORT);
const [page, setPage] = React.useState(0);
const [lcScrollAttempts, setLcScrollAttempts] = React.useState(
linkedCommentId ? 0 : MAX_LINKED_COMMENT_SCROLL_ATTEMPTS
);
const isMobile = useIsMobile();
const [expandedComments, setExpandedComments] = React.useState(!isMobile);
const totalFetchedComments = allCommentIds ? allCommentIds.length : 0;
@ -196,11 +202,19 @@ function CommentList(props: Props) {
// Scroll to linked-comment
useEffect(() => {
if (readyToDisplayComments && linkedCommentId && commentRef && commentRef.current) {
commentRef.current.scrollIntoView({ block: 'start' });
window.scrollBy(0, -125);
if (lcScrollAttempts < MAX_LINKED_COMMENT_SCROLL_ATTEMPTS && readyToDisplayComments && !isFetchingComments) {
const elems = document.getElementsByClassName(COMMENT_HIGHLIGHTED);
if (elems.length > 0) {
setLcScrollAttempts(MAX_LINKED_COMMENT_SCROLL_ATTEMPTS);
const linkedComment = elems[0];
linkedComment.scrollIntoView({ block: 'start' });
window.scrollBy(0, -125);
} else {
setLcScrollAttempts(lcScrollAttempts + 1);
}
}
}, [readyToDisplayComments, linkedCommentId]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [readyToDisplayComments, isFetchingComments]); // We just want to respond to these, nothing else.
// Infinite scroll
useEffect(() => {
@ -321,7 +335,6 @@ function CommentList(props: Props) {
comments: expandedComments,
'comments--contracted': !expandedComments,
})}
ref={commentRef}
>
{readyToDisplayComments && pinnedComments && getCommentElems(pinnedComments)}
{readyToDisplayComments && topLevelComments && getCommentElems(topLevelComments)}

View file

@ -0,0 +1 @@
export const COMMENT_HIGHLIGHTED = 'comment--highlighted';