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

当前为 2021-02-13 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Collapse HackerNews Parent Comments
  3. // @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
  4. // @author BLBC (github.com/hjk789, greasyfork.org/users/679182-hjk789)
  5. // @copyright 2020+, BLBC (github.com/hjk789, greasyfork.org/users/679182-hjk789)
  6. // @version 1.1
  7. // @homepage https://github.com/hjk789/Creations/tree/master/Userscripts/Collapse-HackerNews-Parent-Comments
  8. // @license https://github.com/hjk789/Creations/tree/master/Userscripts/Collapse-HackerNews-Parent-Comments#license
  9. // @grant none
  10. // @include https://news.ycombinator.com/item*
  11. // @namespace https://greasyfork.org/users/679182
  12. // ==/UserScript==
  13.  
  14.  
  15. //--------------- Settings -----------------
  16.  
  17. const collapse = true // Whether all comments, other than the number of comments below, should be collapsed.
  18. // If set to false, all comments will be left expanded and the settings below have no effect.
  19. const numberOfRoots = 3
  20. const numberOfReplies = 2
  21. const numberOfRepliesOfReplies = 1
  22. //------------------------------------------
  23.  
  24. const fadeOnHoverStyle = document.createElement("style")
  25. fadeOnHoverStyle.innerHTML = ".verticalBar:hover { background-color: gray !important; }"
  26. document.body.appendChild(fadeOnHoverStyle)
  27.  
  28. // HackerNews puts a 1x1 image before each comment and sets it's width according to each comment depth. Each level of depth adds
  29. // 40px of width to this image, starting from 0 which are the root comments. The ones with a 14px width are flagged comments and
  30. // the "More comments" link. And because HackerNews layout doesn't have any easier way of identifying the hierarchy of the
  31. // comments (it's just a list of comments pushed to the right), that's the only way I've found to achieve this.
  32.  
  33. spacingImgs = document.querySelectorAll(".ind img[height='1']:not([width='14'])")
  34.  
  35. let root = 0
  36. let i = 0
  37. let commentHier = []
  38.  
  39. if (collapse) spacingImgs[0].parentElement.parentElement.querySelector(".togg").click()
  40.  
  41. 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
  42. { // the comments are being collapsed. It does make it take a few more seconds to finish in comment-heavy posts (150+) though.
  43. const level = spacingImgs[i].width / 40
  44.  
  45. let commentToggle = spacingImgs[i].parentElement.parentElement.querySelector(".togg")
  46. 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
  47.  
  48.  
  49. // Store the current hierarchy in an array
  50.  
  51. if (commentHier[level] == null)
  52. commentHier.push(commentToggle)
  53. else
  54. commentHier[level] = commentToggle
  55.  
  56. const commentContainer = spacingImgs[i].parentElement.parentElement.parentElement.parentElement.parentElement
  57. commentContainer.style = "border-top: 5px transparent solid" // To visually separate each vertical bar
  58. spacingImgs[i].parentElement.style = "position: relative"
  59.  
  60. let divs = []
  61. for (j = spacingImgs[i].width; j >= 0; j -= 40) // Start adding the vertical bar from the current depth and go backwards
  62. {
  63. // Create the vertical bar
  64.  
  65. const div = document.createElement("div")
  66. div.className = "verticalBar"
  67. 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
  68. div.onclick = commentHier[j/40].onclick // When a vertical bar is clicked, collapse the respective parent comment
  69. div.onmouseup = function(e)
  70. {
  71. if (e.target.commentHier.getBoundingClientRect().y < 0) // If the parent comment is off-screen above,
  72. e.target.commentHier.scrollIntoView() // scroll to it
  73. }
  74.  
  75. let style = "left: " + (-5 + j) + "px; width: 12px; background-color: lightgray; position: absolute; z-index: 99; transition: 0.15s; "
  76.  
  77. // Make it so that the vertical bars are only separated when followed by comments of same level of depth
  78.  
  79. if (j == spacingImgs[i].width && spacingImgs[i-1] != null && spacingImgs[i].width <= spacingImgs[i-1].width)
  80. style += "top: 5px; height: calc(100% + 8px); "
  81. else
  82. style += "top: 0px; height: calc(100% + 13px); "
  83.  
  84. div.style = style
  85.  
  86. divs.push(div)
  87. }
  88.  
  89. for (j = divs.length - 1; j >= 0; j--)
  90. spacingImgs[i].parentElement.appendChild(divs[j])
  91.  
  92. i++
  93.  
  94. 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
  95. {
  96. clearInterval(collapseAll)
  97.  
  98. if (collapse)
  99. {
  100. spacingImgs[0].parentElement.parentElement.querySelector(".togg").click() // Expand the first comment
  101. root = 0
  102. for (i=0; i < spacingImgs.length; i++)
  103. {
  104. commentToggle = spacingImgs[i].parentElement.parentElement.querySelector(".togg")
  105.  
  106. if (spacingImgs[i].width == 0) // If it's a root comment
  107. {
  108. root++
  109. if (root == numberOfRoots + 1) break // If there's already <numberOfRoots> comments expanded, then stop expanding
  110.  
  111. commentToggle.click()
  112. sub40 = 0
  113. sub80 = 0
  114. }
  115. else if (spacingImgs[i].width == 40 && sub40 < numberOfReplies) // If it's a reply to the root comment, only expand up to <numberOfReplies>
  116. {
  117. commentToggle.click()
  118. sub40++
  119. sub80 = 0
  120. }
  121. else if (spacingImgs[i].width == 80 && sub80 < numberOfRepliesOfReplies) // If it's a reply to the reply, only expand up to <numberOfRepliesOfReplies>
  122. {
  123. commentToggle.click()
  124. sub80++
  125. }
  126. }
  127. }
  128. }
  129.  
  130. }, 1)
  131.