Greasy Fork is available in English.

Collapse HackerNews Parent Comments

Adds vertical bars to the left of the comments, enabling you to easily collapse the parent comments. It also can leave only a specified number of comments expanded and auto-collapse the rest

Versión del día 13/02/2021. Echa un vistazo a la versión más reciente.

// ==UserScript==
// @name            Collapse HackerNews Parent Comments
// @description     Adds vertical bars to the left of the comments, enabling you to easily collapse the parent comments. It also can leave only a specified number of comments expanded and auto-collapse the rest
// @author          BLBC (github.com/hjk789, gf.zukizuki.org/users/679182-hjk789)
// @copyright       2020+, BLBC (github.com/hjk789, gf.zukizuki.org/users/679182-hjk789)
// @version         1.1
// @homepage        https://github.com/hjk789/Creations/tree/master/Userscripts/Collapse-HackerNews-Parent-Comments
// @license         https://github.com/hjk789/Creations/tree/master/Userscripts/Collapse-HackerNews-Parent-Comments#license
// @grant           none
// @include         https://news.ycombinator.com/item*
// @namespace https://gf.zukizuki.org/users/679182
// ==/UserScript==


//--------------- Settings -----------------

const collapse = true   // Whether all comments, other than the number of comments below, should be collapsed.
                        // If set to false, all comments will be left expanded and the settings below have no effect.
    const numberOfRoots = 3
    const numberOfReplies = 2
    const numberOfRepliesOfReplies = 1
//------------------------------------------

const fadeOnHoverStyle = document.createElement("style")
fadeOnHoverStyle.innerHTML = ".verticalBar:hover { background-color: gray !important; }"
document.body.appendChild(fadeOnHoverStyle)

// HackerNews puts a 1x1 image before each comment and sets it's width according to each comment depth. Each level of depth adds
// 40px of width to this image, starting from 0 which are the root comments. The ones with a 14px width are flagged comments and
// the "More comments" link. And because HackerNews layout doesn't have any easier way of identifying the hierarchy of the
// comments (it's just a list of comments pushed to the right), that's the only way I've found to achieve this.

spacingImgs = document.querySelectorAll(".ind img[height='1']:not([width='14'])")

let root = 0
let i = 0
let commentHier = []

if (collapse)   spacingImgs[0].parentElement.parentElement.querySelector(".togg").click()

collapseAll = setInterval(function()   // An interval of 1ms is being used to prevent the page from freezing until it finishes. Also, it creates a cool effect when
{                                      // the comments are being collapsed. It does make it take a few more seconds to finish in comment-heavy posts (150+) though.
    const level = spacingImgs[i].width / 40

    let commentToggle = spacingImgs[i].parentElement.parentElement.querySelector(".togg")
    if (collapse)   commentToggle.click()  // Collapse the first comment so it's expanded again below and you can read the first comment while the collapsing is under process


    // Store the current hierarchy in an array

    if (commentHier[level] == null)
        commentHier.push(commentToggle)
    else
        commentHier[level] = commentToggle

    const commentContainer = spacingImgs[i].parentElement.parentElement.parentElement.parentElement.parentElement
    commentContainer.style = "border-top: 5px transparent solid"  // To visually separate each vertical bar
    spacingImgs[i].parentElement.style = "position: relative"

    let divs = []
    for (j = spacingImgs[i].width; j >= 0; j -= 40)  // Start adding the vertical bar from the current depth and go backwards
    {
        // Create the vertical bar

        const div = document.createElement("div")
        div.className = "verticalBar"
        div.commentHier = commentHier[j/40]  // Store in an attribute of the element this comment's parent respective to the level of the vertical bar, for easy access
        div.onclick = commentHier[j/40].onclick  // When a vertical bar is clicked, collapse the respective parent comment
        div.onmouseup = function(e)
        {
            if (e.target.commentHier.getBoundingClientRect().y < 0)  // If the parent comment is off-screen above,
                e.target.commentHier.scrollIntoView()                // scroll to it
        }

        let style = "left: " + (-5 + j) + "px; width: 12px; background-color: lightgray; position: absolute; z-index: 99; transition: 0.15s; "

        // Make it so that the vertical bars are only separated when followed by comments of same level of depth

        if (j == spacingImgs[i].width && spacingImgs[i-1] != null && spacingImgs[i].width <= spacingImgs[i-1].width)
            style += "top: 5px; height: calc(100% + 8px); "
        else
            style += "top: 0px; height: calc(100% + 13px); "

        div.style = style

        divs.push(div)
    }

    for (j = divs.length - 1; j >= 0; j--)
        spacingImgs[i].parentElement.appendChild(divs[j])

    i++

    if (i == spacingImgs.length)  // When finished collapsing and adding the vertical bars to all comments, now it's time to expand only a few of the first comments
    {
        clearInterval(collapseAll)

        if (collapse)
        {
            spacingImgs[0].parentElement.parentElement.querySelector(".togg").click()  // Expand the first comment
            root = 0
            for (i=0; i < spacingImgs.length; i++)
            {
                commentToggle = spacingImgs[i].parentElement.parentElement.querySelector(".togg")

                if (spacingImgs[i].width == 0)  // If it's a root comment
                {
                    root++
                    if (root == numberOfRoots + 1)  break  // If there's already <numberOfRoots> comments expanded, then stop expanding

                    commentToggle.click()
                    sub40 = 0
                    sub80 = 0
                }
                else if (spacingImgs[i].width == 40 && sub40 < numberOfReplies)  // If it's a reply to the root comment, only expand up to <numberOfReplies>
                {
                    commentToggle.click()
                    sub40++
                    sub80 = 0
                }
                else if (spacingImgs[i].width == 80 && sub80 < numberOfRepliesOfReplies)  // If it's a reply to the reply, only expand up to <numberOfRepliesOfReplies>
                {
                    commentToggle.click()
                    sub80++
                }
            }
        }
    }

}, 1)