import './highest-rated-comment.css'; import mem from 'mem'; import React from 'dom-chef'; import select from 'select-dom'; import * as pageDetect from 'github-url-detection'; import {ArrowDownIcon, CheckCircleFillIcon} from '@primer/octicons-react'; import features from '../feature-manager.js'; import looseParseInt from '../helpers/loose-parse-int.js'; import isLowQualityComment from '../helpers/is-low-quality-comment.js'; import {singleParagraphCommentSelector} from './hide-low-quality-comments.js'; // `.js-timeline-item` gets the nearest comment excluding the very first comment (OP post) const commentSelector = '.js-timeline-item'; const positiveReactionsSelector = ` ${commentSelector} [aria-label="react with thumbs up"], ${commentSelector} [aria-label="react with hooray"], ${commentSelector} [aria-label="react with heart"] `; const negativeReactionsSelector = ` ${commentSelector} [aria-label="react with thumbs down"] `; const getPositiveReactions = mem((comment: HTMLElement): number | void => { const count = selectSum(positiveReactionsSelector, comment); if ( // It needs to be upvoted enough times count >= 10 // It can't be a controversial comment && selectSum(negativeReactionsSelector, comment) < count / 2 ) { return count; } }); function getBestComment(): HTMLElement | undefined { let highest; for (const reaction of select.all(positiveReactionsSelector)) { const comment = reaction.closest(commentSelector)!; const positiveReactions = getPositiveReactions(comment); if (positiveReactions && (!highest || positiveReactions > highest.count)) { highest = {comment, count: positiveReactions}; } } return highest?.comment; } function highlightBestComment(bestComment: Element): void { select('.unminimized-comment', bestComment)!.classList.add('rgh-highest-rated-comment'); select('.unminimized-comment .timeline-comment-header > h3', bestComment)!.before( , ); } function linkBestComment(bestComment: HTMLElement): void { // Find position of comment in thread const position = select.all(commentSelector).indexOf(bestComment); // Only link to it if it doesn't already appear at the top of the conversation if (position < 3) { return; } const text = select('.comment-body', bestComment)!.textContent!.slice(0, 100); const {hash} = select('a.js-timestamp', bestComment)!; const avatar = select('img.avatar', bestComment)!.cloneNode(); bestComment.parentElement!.firstElementChild!.after( {avatar}

Highest-rated{text}

Jump to comment
, ); } function selectSum(selector: string, container: HTMLElement): number { return select.all(selector, container).reduce((sum, element) => sum + looseParseInt(element), 0); } function init(): false | void { const bestComment = getBestComment(); if (!bestComment) { return false; } const commentText = select(singleParagraphCommentSelector, bestComment)?.textContent; if (commentText && isLowQualityComment(commentText)) { // #5567 return false; } linkBestComment(bestComment); highlightBestComment(bestComment); } void features.add(import.meta.url, { include: [ pageDetect.isIssue, ], deduplicate: 'has-rgh-inner', awaitDomReady: true, // Must wait for all to pick the best one init, }); /* Test URLs: - 8th comment, has link: https://github.com/refined-github/refined-github/issues/4166 - 2nd comment, no link: https://github.com/refined-github/refined-github/issues/825 */