From b24eba6feacdd92020bb061d85c6410eac20df9c Mon Sep 17 00:00:00 2001 From: Dessalines Date: Sun, 7 Feb 2021 23:23:31 -0500 Subject: [PATCH] Comments and posts no longer live-sorted. Fixes #51 - Only changing the view or sort, or reloading the page will resort. - New comments by default added to the top, and left unsorted. --- src/shared/components/comment-node.tsx | 11 +-- src/shared/components/comment-nodes.tsx | 25 +---- src/shared/components/community.tsx | 2 - src/shared/components/main.tsx | 2 - src/shared/components/post-listings.tsx | 8 +- src/shared/components/post.tsx | 59 +++++------- src/shared/utils.ts | 123 ++++++++++++++---------- 7 files changed, 102 insertions(+), 128 deletions(-) diff --git a/src/shared/components/comment-node.tsx b/src/shared/components/comment-node.tsx index 26eeaf0a..bf57a59d 100644 --- a/src/shared/components/comment-node.tsx +++ b/src/shared/components/comment-node.tsx @@ -15,15 +15,10 @@ import { AddAdmin, TransferCommunity, TransferSite, - SortType, CommentView, UserMentionView, } from 'lemmy-js-client'; -import { - CommentSortType, - CommentNode as CommentNodeI, - BanType, -} from '../interfaces'; +import { CommentNode as CommentNodeI, BanType } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { mdToHtml, @@ -82,8 +77,6 @@ interface CommentNodeProps { // TODO is this necessary, can't I get it from the node itself? postCreatorId?: number; showCommunity?: boolean; - sort?: CommentSortType; - sortType?: SortType; enableDownvotes: boolean; } @@ -745,8 +738,6 @@ export class CommentNode extends Component { moderators={this.props.moderators} admins={this.props.admins} postCreatorId={this.props.postCreatorId} - sort={this.props.sort} - sortType={this.props.sortType} enableDownvotes={this.props.enableDownvotes} /> )} diff --git a/src/shared/components/comment-nodes.tsx b/src/shared/components/comment-nodes.tsx index 90a7783a..327c9a47 100644 --- a/src/shared/components/comment-nodes.tsx +++ b/src/shared/components/comment-nodes.tsx @@ -1,11 +1,6 @@ import { Component } from 'inferno'; -import { CommentSortType, CommentNode as CommentNodeI } from '../interfaces'; -import { - CommunityModeratorView, - UserViewSafe, - SortType, -} from 'lemmy-js-client'; -import { commentSort, commentSortSortType } from '../utils'; +import { CommentNode as CommentNodeI } from '../interfaces'; +import { CommunityModeratorView, UserViewSafe } from 'lemmy-js-client'; import { CommentNode } from './comment-node'; interface CommentNodesState {} @@ -22,8 +17,6 @@ interface CommentNodesProps { markable?: boolean; showContext?: boolean; showCommunity?: boolean; - sort?: CommentSortType; - sortType?: SortType; enableDownvotes: boolean; } @@ -38,7 +31,7 @@ export class CommentNodes extends Component< render() { return (
- {this.sorter().map(node => ( + {this.props.nodes.map(node => ( ))}
); } - - sorter(): CommentNodeI[] { - if (this.props.sort !== undefined) { - commentSort(this.props.nodes, this.props.sort); - } else if (this.props.sortType !== undefined) { - commentSortSortType(this.props.nodes, this.props.sortType); - } - - return this.props.nodes; - } } diff --git a/src/shared/components/community.tsx b/src/shared/components/community.tsx index 4c4e6d1b..2865a252 100644 --- a/src/shared/components/community.tsx +++ b/src/shared/components/community.tsx @@ -291,7 +291,6 @@ export class Community extends Component { @@ -306,7 +305,6 @@ export class Community extends Component { diff --git a/src/shared/components/main.tsx b/src/shared/components/main.tsx index 28795b56..2d4b7d78 100644 --- a/src/shared/components/main.tsx +++ b/src/shared/components/main.tsx @@ -561,7 +561,6 @@ export class Main extends Component { posts={this.state.posts} showCommunity removeDuplicates - sort={this.state.sort} enableDownvotes={site.enable_downvotes} enableNsfw={site.enable_nsfw} /> @@ -570,7 +569,6 @@ export class Main extends Component { nodes={commentsToFlatNodes(this.state.comments)} noIndent showCommunity - sortType={this.state.sort} showContext enableDownvotes={site.enable_downvotes} /> diff --git a/src/shared/components/post-listings.tsx b/src/shared/components/post-listings.tsx index a7e06937..07803627 100644 --- a/src/shared/components/post-listings.tsx +++ b/src/shared/components/post-listings.tsx @@ -1,7 +1,6 @@ import { Component } from 'inferno'; import { Link } from 'inferno-router'; -import { PostView, SortType } from 'lemmy-js-client'; -import { postSort } from '../utils'; +import { PostView } from 'lemmy-js-client'; import { PostListing } from './post-listing'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -10,7 +9,6 @@ interface PostListingsProps { posts: PostView[]; showCommunity?: boolean; removeDuplicates?: boolean; - sort?: SortType; enableDownvotes: boolean; enableNsfw: boolean; } @@ -58,10 +56,6 @@ export class PostListings extends Component { out = this.removeDuplicates(out); } - if (this.props.sort !== undefined) { - postSort(out, this.props.sort, this.props.showCommunity == undefined); - } - return out; } diff --git a/src/shared/components/post.tsx b/src/shared/components/post.tsx index 2e6d31e8..6db6104a 100644 --- a/src/shared/components/post.tsx +++ b/src/shared/components/post.tsx @@ -52,6 +52,8 @@ import { setOptionalAuth, saveScrollPosition, restoreScrollPosition, + buildCommentsTree, + insertCommentIntoTree, } from '../utils'; import { PostListing } from './post-listing'; import { Sidebar } from './sidebar'; @@ -63,6 +65,7 @@ import { i18n } from '../i18next'; interface PostState { postRes: GetPostResponse; postId: number; + commentTree: CommentNodeI[]; commentId?: number; commentSort: CommentSortType; commentViewType: CommentViewType; @@ -79,6 +82,7 @@ export class Post extends Component { private emptyState: PostState = { postRes: null, postId: getIdFromProps(this.props), + commentTree: [], commentId: getCommentIdFromProps(this.props), commentSort: CommentSortType.Hot, commentViewType: CommentViewType.Tree, @@ -100,6 +104,10 @@ export class Post extends Component { // Only fetch the data if coming from another route if (this.isoData.path == this.context.router.route.match.url) { this.state.postRes = this.isoData.routeData[0]; + this.state.commentTree = buildCommentsTree( + this.state.postRes.comments, + this.state.commentSort + ); this.state.categories = this.isoData.routeData[1].categories; this.state.loading = false; @@ -368,6 +376,7 @@ export class Post extends Component { } commentsFlat() { + // These are already sorted by new return (
{ postCreatorId={this.state.postRes.post_view.creator.id} showContext enableDownvotes={this.state.siteRes.site_view.site.enable_downvotes} - sort={this.state.commentSort} />
); @@ -404,58 +412,32 @@ export class Post extends Component { handleCommentSortChange(i: Post, event: any) { i.state.commentSort = Number(event.target.value); i.state.commentViewType = CommentViewType.Tree; + i.state.commentTree = buildCommentsTree( + i.state.postRes.comments, + i.state.commentSort + ); i.setState(i.state); } handleCommentViewTypeChange(i: Post, event: any) { i.state.commentViewType = Number(event.target.value); i.state.commentSort = CommentSortType.New; + i.state.commentTree = buildCommentsTree( + i.state.postRes.comments, + i.state.commentSort + ); i.setState(i.state); } - buildCommentsTree(): CommentNodeI[] { - let map = new Map(); - for (let comment_view of this.state.postRes.comments) { - let node: CommentNodeI = { - comment_view: comment_view, - children: [], - }; - map.set(comment_view.comment.id, { ...node }); - } - let tree: CommentNodeI[] = []; - for (let comment_view of this.state.postRes.comments) { - let child = map.get(comment_view.comment.id); - if (comment_view.comment.parent_id) { - let parent_ = map.get(comment_view.comment.parent_id); - parent_.children.push(child); - } else { - tree.push(child); - } - - this.setDepth(child); - } - - return tree; - } - - setDepth(node: CommentNodeI, i: number = 0): void { - for (let child of node.children) { - child.depth = i; - this.setDepth(child, i + 1); - } - } - commentsTree() { - let nodes = this.buildCommentsTree(); return (
@@ -480,6 +462,10 @@ export class Post extends Component { } else if (op == UserOperation.GetPost) { let data = wsJsonToRes(msg).data; this.state.postRes = data; + this.state.commentTree = buildCommentsTree( + this.state.postRes.comments, + this.state.commentSort + ); this.state.loading = false; // Get cross-posts @@ -493,6 +479,7 @@ export class Post extends Component { // Necessary since it might be a user reply, which has the recipients, to avoid double if (data.recipient_ids.length == 0) { this.state.postRes.comments.unshift(data.comment_view); + insertCommentIntoTree(this.state.commentTree, data.comment_view); this.state.postRes.post_view.counts.comments++; this.setState(this.state); setupTippy(); diff --git a/src/shared/utils.ts b/src/shared/utils.ts index 33f9ff19..2f441428 100644 --- a/src/shared/utils.ts +++ b/src/shared/utils.ts @@ -942,7 +942,7 @@ export function commentsToFlatNodes(comments: CommentView[]): CommentNodeI[] { return nodes; } -export function commentSort(tree: CommentNodeI[], sort: CommentSortType) { +function commentSort(tree: CommentNodeI[], sort: CommentSortType) { // First, put removed and deleted comments at the bottom, then do your other sorts if (sort == CommentSortType.Top) { tree.sort( @@ -1008,51 +1008,80 @@ function convertCommentSortType(sort: SortType): CommentSortType { } } -export function postSort( - posts: PostView[], - sort: SortType, - communityType: boolean -) { - // First, put removed and deleted comments at the bottom, then do your other sorts - if ( - sort == SortType.TopAll || - sort == SortType.TopDay || - sort == SortType.TopWeek || - sort == SortType.TopMonth || - sort == SortType.TopYear - ) { - posts.sort( - (a, b) => - +a.post.removed - +b.post.removed || - +a.post.deleted - +b.post.deleted || - (communityType && +b.post.stickied - +a.post.stickied) || - b.counts.score - a.counts.score - ); - } else if (sort == SortType.New) { - posts.sort( - (a, b) => - +a.post.removed - +b.post.removed || - +a.post.deleted - +b.post.deleted || - (communityType && +b.post.stickied - +a.post.stickied) || - b.post.published.localeCompare(a.post.published) - ); - } else if (sort == SortType.Hot) { - posts.sort( - (a, b) => - +a.post.removed - +b.post.removed || - +a.post.deleted - +b.post.deleted || - (communityType && +b.post.stickied - +a.post.stickied) || - hotRankPost(b) - hotRankPost(a) - ); - } else if (sort == SortType.Active) { - posts.sort( - (a, b) => - +a.post.removed - +b.post.removed || - +a.post.deleted - +b.post.deleted || - (communityType && +b.post.stickied - +a.post.stickied) || - hotRankActivePost(b) - hotRankActivePost(a) - ); +export function buildCommentsTree( + comments: CommentView[], + commentSortType: CommentSortType +): CommentNodeI[] { + let map = new Map(); + for (let comment_view of comments) { + let node: CommentNodeI = { + comment_view: comment_view, + children: [], + }; + map.set(comment_view.comment.id, { ...node }); } + let tree: CommentNodeI[] = []; + for (let comment_view of comments) { + let child = map.get(comment_view.comment.id); + if (comment_view.comment.parent_id) { + let parent_ = map.get(comment_view.comment.parent_id); + parent_.children.push(child); + } else { + tree.push(child); + } + + setDepth(child); + } + + commentSort(tree, commentSortType); + + return tree; +} + +function setDepth(node: CommentNodeI, i: number = 0) { + for (let child of node.children) { + child.depth = i; + setDepth(child, i + 1); + } +} + +export function insertCommentIntoTree(tree: CommentNodeI[], cv: CommentView) { + // Building a fake node to be used for later + let node: CommentNodeI = { + comment_view: cv, + children: [], + depth: 0, + }; + + if (cv.comment.parent_id) { + let parentComment = searchCommentTree(tree, cv.comment.parent_id); + if (parentComment) { + node.depth = parentComment.depth + 1; + parentComment.children.unshift(node); + } + } else { + tree.unshift(node); + } +} + +export function searchCommentTree( + tree: CommentNodeI[], + id: number +): CommentNodeI { + for (let node of tree) { + if (node.comment_view.comment.id === id) { + return node; + } + + for (const child of node.children) { + const res = searchCommentTree([child], id); + + if (res) { + return res; + } + } + } + return null; } export const colorList: string[] = [ @@ -1068,10 +1097,6 @@ function hsl(num: number) { return `hsla(${num}, 35%, 50%, 1)`; } -// function randomHsl() { -// return `hsla(${Math.random() * 360}, 100%, 50%, 1)`; -// } - export function previewLines( text: string, maxChars: number = 300,