From fd8814677ec81eff5358c102b6b424ec1c23c2fb Mon Sep 17 00:00:00 2001 From: Dessalines Date: Sun, 9 Feb 2020 11:44:24 -0500 Subject: [PATCH] Live post and comment resorting. Fixes #522 - Moving sorting to utils. --- ui/src/components/comment-node.tsx | 6 ++ ui/src/components/comment-nodes.tsx | 19 ++++- ui/src/components/community.tsx | 12 +++- ui/src/components/main.tsx | 9 ++- ui/src/components/post-listings.tsx | 22 ++++-- ui/src/components/post.tsx | 41 +---------- ui/src/utils.ts | 108 ++++++++++++++++++++++++++-- 7 files changed, 164 insertions(+), 53 deletions(-) diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index a67b1c35..0e511063 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -15,6 +15,8 @@ import { TransferCommunityForm, TransferSiteForm, BanType, + CommentSortType, + SortType, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { @@ -61,6 +63,8 @@ interface CommentNodeProps { // TODO is this necessary, can't I get it from the node itself? postCreatorId?: number; showCommunity?: boolean; + sort?: CommentSortType; + sortType?: SortType; } export class CommentNode extends Component { @@ -630,6 +634,8 @@ 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} /> )} {/* A collapsed clearfix */} diff --git a/ui/src/components/comment-nodes.tsx b/ui/src/components/comment-nodes.tsx index fb700cc4..b15da520 100644 --- a/ui/src/components/comment-nodes.tsx +++ b/ui/src/components/comment-nodes.tsx @@ -3,7 +3,10 @@ import { CommentNode as CommentNodeI, CommunityUser, UserView, + CommentSortType, + SortType, } from '../interfaces'; +import { commentSort, commentSortSortType } from '../utils'; import { CommentNode } from './comment-node'; interface CommentNodesState {} @@ -18,6 +21,8 @@ interface CommentNodesProps { locked?: boolean; markable?: boolean; showCommunity?: boolean; + sort?: CommentSortType; + sortType?: SortType; } export class CommentNodes extends Component< @@ -31,7 +36,7 @@ export class CommentNodes extends Component< render() { return (
- {this.props.nodes.map(node => ( + {this.sorter().map(node => ( ))}
); } + + sorter(): Array { + 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/ui/src/components/community.tsx b/ui/src/components/community.tsx index 32392ca1..e28c99bc 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -178,9 +178,17 @@ export class Community extends Component { listings() { return this.state.dataType == DataType.Post ? ( - + ) : ( - + ); } diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx index 99b1618d..c8e132f7 100644 --- a/ui/src/components/main.tsx +++ b/ui/src/components/main.tsx @@ -51,6 +51,7 @@ import { createPostLikeFindRes, editPostFindRes, commentsToFlatNodes, + commentSortSortType, } from '../utils'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -404,12 +405,18 @@ export class Main extends Component { listings() { return this.state.dataType == DataType.Post ? ( - + ) : ( ); } diff --git a/ui/src/components/post-listings.tsx b/ui/src/components/post-listings.tsx index 005c4fe0..d61f624d 100644 --- a/ui/src/components/post-listings.tsx +++ b/ui/src/components/post-listings.tsx @@ -1,6 +1,7 @@ import { Component } from 'inferno'; import { Link } from 'inferno-router'; -import { Post } from '../interfaces'; +import { Post, SortType } from '../interfaces'; +import { postSort } from '../utils'; import { PostListing } from './post-listing'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -9,6 +10,7 @@ interface PostListingsProps { posts: Array; showCommunity?: boolean; removeDuplicates?: boolean; + sort?: SortType; } export class PostListings extends Component { @@ -20,10 +22,7 @@ export class PostListings extends Component { return (
{this.props.posts.length > 0 ? ( - (this.props.removeDuplicates - ? this.removeDuplicates(this.props.posts) - : this.props.posts - ).map(post => ( + this.outer().map(post => ( <> { ); } + outer(): Array { + let out = this.props.posts; + if (this.props.removeDuplicates) { + out = this.removeDuplicates(out); + } + + if (this.props.sort !== undefined) { + postSort(out, this.props.sort); + } + + return out; + } + removeDuplicates(posts: Array): Array { // A map from post url to list of posts (dupes) let urlMap = new Map>(); diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index 1f2e40ba..b5b1fce3 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -31,7 +31,6 @@ import { import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, - hotRank, toast, editCommentRes, saveCommentRes, @@ -314,48 +313,9 @@ export class Post extends Component { } } - this.sortTree(tree); - return tree; } - sortTree(tree: Array) { - // First, put removed and deleted comments at the bottom, then do your other sorts - if (this.state.commentSort == CommentSortType.Top) { - tree.sort( - (a, b) => - +a.comment.removed - +b.comment.removed || - +a.comment.deleted - +b.comment.deleted || - b.comment.score - a.comment.score - ); - } else if (this.state.commentSort == CommentSortType.New) { - tree.sort( - (a, b) => - +a.comment.removed - +b.comment.removed || - +a.comment.deleted - +b.comment.deleted || - b.comment.published.localeCompare(a.comment.published) - ); - } else if (this.state.commentSort == CommentSortType.Old) { - tree.sort( - (a, b) => - +a.comment.removed - +b.comment.removed || - +a.comment.deleted - +b.comment.deleted || - a.comment.published.localeCompare(b.comment.published) - ); - } else if (this.state.commentSort == CommentSortType.Hot) { - tree.sort( - (a, b) => - +a.comment.removed - +b.comment.removed || - +a.comment.deleted - +b.comment.deleted || - hotRank(b.comment) - hotRank(a.comment) - ); - } - - for (let node of tree) { - this.sortTree(node.children); - } - } - commentsTree() { let nodes = this.buildCommentsTree(); return ( @@ -366,6 +326,7 @@ export class Post extends Component { moderators={this.state.moderators} admins={this.state.admins} postCreatorId={this.state.post.creator_id} + sort={this.state.commentSort} />
); diff --git a/ui/src/utils.ts b/ui/src/utils.ts index 8cdc02f0..929877fc 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -20,6 +20,7 @@ import { PrivateMessage, User, SortType, + CommentSortType, ListingType, DataType, SearchType, @@ -93,15 +94,22 @@ md.renderer.rules.emoji = function(token, idx) { return twemoji.parse(token[idx].content); }; -export function hotRank(comment: Comment): number { - // Rank = ScaleFactor * sign(Score) * log(1 + abs(Score)) / (Time + 2)^Gravity +export function hotRankComment(comment: Comment): number { + return hotRank(comment.score, comment.published); +} - let date: Date = new Date(comment.published + 'Z'); // Add Z to convert from UTC date +export function hotRankPost(post: Post): number { + return hotRank(post.score, post.newest_activity_time); +} + +export function hotRank(score: number, timeStr: string): number { + // Rank = ScaleFactor * sign(Score) * log(1 + abs(Score)) / (Time + 2)^Gravity + let date: Date = new Date(timeStr + 'Z'); // Add Z to convert from UTC date let now: Date = new Date(); let hoursElapsed: number = (now.getTime() - date.getTime()) / 36e5; let rank = - (10000 * Math.log10(Math.max(1, 3 + comment.score))) / + (10000 * Math.log10(Math.max(1, 3 + score))) / Math.pow(hoursElapsed + 2, 1.8); // console.log(`Comment: ${comment.content}\nRank: ${rank}\nScore: ${comment.score}\nHours: ${hoursElapsed}`); @@ -639,3 +647,95 @@ export function commentsToFlatNodes( } return nodes; } + +export function commentSort(tree: Array, sort: CommentSortType) { + // First, put removed and deleted comments at the bottom, then do your other sorts + if (sort == CommentSortType.Top) { + tree.sort( + (a, b) => + +a.comment.removed - +b.comment.removed || + +a.comment.deleted - +b.comment.deleted || + b.comment.score - a.comment.score + ); + } else if (sort == CommentSortType.New) { + tree.sort( + (a, b) => + +a.comment.removed - +b.comment.removed || + +a.comment.deleted - +b.comment.deleted || + b.comment.published.localeCompare(a.comment.published) + ); + } else if (sort == CommentSortType.Old) { + tree.sort( + (a, b) => + +a.comment.removed - +b.comment.removed || + +a.comment.deleted - +b.comment.deleted || + a.comment.published.localeCompare(b.comment.published) + ); + } else if (sort == CommentSortType.Hot) { + tree.sort( + (a, b) => + +a.comment.removed - +b.comment.removed || + +a.comment.deleted - +b.comment.deleted || + hotRankComment(b.comment) - hotRankComment(a.comment) + ); + } + + // Go through the children recursively + for (let node of tree) { + if (node.children) { + commentSort(node.children, sort); + } + } +} + +export function commentSortSortType(tree: Array, sort: SortType) { + commentSort(tree, convertCommentSortType(sort)); +} + +function convertCommentSortType(sort: SortType): CommentSortType { + if ( + sort == SortType.TopAll || + sort == SortType.TopDay || + sort == SortType.TopWeek || + sort == SortType.TopMonth || + sort == SortType.TopYear + ) { + return CommentSortType.Top; + } else if (sort == SortType.New) { + return CommentSortType.New; + } else if (sort == SortType.Hot) { + return CommentSortType.Hot; + } else { + return CommentSortType.Hot; + } +} + +export function postSort(posts: Array, sort: SortType) { + // 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.removed - +b.removed || +a.deleted - +b.deleted || b.score - a.score + ); + } else if (sort == SortType.New) { + posts.sort( + (a, b) => + +a.removed - +b.removed || + +a.deleted - +b.deleted || + b.published.localeCompare(a.published) + ); + } else if (sort == SortType.Hot) { + posts.sort( + (a, b) => + +a.removed - +b.removed || + +a.deleted - +b.deleted || + hotRankPost(b) - hotRankPost(a) + ); + } +}