Skip to content

Instantly share code, notes, and snippets.

@AsafGartner
Created February 26, 2025 15:13
Show Gist options
  • Select an option

  • Save AsafGartner/38867fc1440bb78332e4b99e575a998c to your computer and use it in GitHub Desktop.

Select an option

Save AsafGartner/38867fc1440bb78332e4b99e575a998c to your computer and use it in GitHub Desktop.
Hackernews helper - bookmarklet that lists comments by date and greys out comments that you've replied to
javascript: (() => { let commentEls = document.querySelectorAll(".comment-tree tr[id]"); let comments = []; let commentMap = {}; let myUsername = ""; myUsername = localStorage.getItem("__my_username") || ""; for (let i = 0; i < commentEls.length; ++i) { let el = commentEls[i]; let navs = el.querySelectorAll(".navs a"); let parent = null; if (navs[0].textContent == "parent") { parent = navs[0].getAttribute("href").slice(1); } if (navs[1].textContent == "parent") { parent = navs[1].getAttribute("href").slice(1); } let comment = { el: el, id: el.id, timestamp: parseInt(el.querySelector(".age").title.split(" ")[1], 10), age: el.querySelector(".age a").textContent, parent: parent, answered: false, answeredChild: false, author: el.querySelector(".hnuser").textContent, }; comments.push(comment); commentMap[comment.id] = comment; } comments.sort(function(a, b) { return b.timestamp - a.timestamp; }); function updateAnswered() { function markGrandparents(c) { if (c.parent) { c = commentMap[c.parent]; c.answeredChild = true; markGrandparents(c); } } for (let i = 0; i < comments.length; ++i) { let comment = comments[i]; comment.answered = false; comment.answeredChild = false; } for (let i = 0; i < comments.length; ++i) { let comment = comments[i]; if (comment.author == myUsername) { comment.answered = true; if (comment.parent) { let parent = commentMap[comment.parent]; parent.answered = true; markGrandparents(parent); } } } } let container = null; let list = null; let usernameInput = null; function usernameUpdated() { let val = usernameInput.value; myUsername = val; localStorage.setItem("__my_username", myUsername); updateAnswered(); render(); } function click(ev) { let id = ev.target.getAttribute("data-id"); let comment = commentMap[id]; comment.el.scrollIntoView({ behavior: "smooth", block: "center" }); for (let i = 0; i < comments.length; ++i) { comments[i].el.classList.remove("__active"); } comment.el.classList.add("__active"); ev.preventDefault(); return false; } function render() { if (!container) { container = document.createElement("DIV"); container.style.boxSizing = "border-box"; container.style.position = "fixed"; container.style.right = "0px"; container.style.top = "0px"; container.style.height = "100vh"; container.style.width = "15vw"; container.style.background = "black"; container.style.padding = "8px"; container.style.overflowY = "scroll"; container.style.borderLeft = "2px solid skyblue"; usernameInput = document.createElement("INPUT"); usernameInput.style.width = "100%"; usernameInput.value = myUsername; usernameInput.addEventListener("input", usernameUpdated); container.appendChild(usernameInput); list = document.createElement("DIV"); container.appendChild(list); document.body.appendChild(container); document.querySelector(".comment-tree").style.marginRight = "15vw"; let style = document.createElement("STYLE"); style.textContent = ` .comment-tree tr[id] { transition: background 0.5s linear; } .__active { background: burlywood; } `; document.head.appendChild(style); } list.innerHTML = ""; for (let i = 0; i < comments.length; ++i) { let comment = comments[i]; let el = document.createElement("A"); el.href = "#" + comment.id; el.textContent = comment.age + " | " + comment.author; el.style.color = (comment.answered ? "grey" : (comment.answeredChild ? "purple" : "skyblue")); el.style.display = "block"; el.style.padding = "4px"; el.setAttribute("data-id", comment.id); el.addEventListener("click", click); list.appendChild(el); } } updateAnswered(); render(); })();
let commentEls = document.querySelectorAll(".comment-tree tr[id]");
let comments = [];
let commentMap = {};
let myUsername = "";
myUsername = localStorage.getItem("__my_username") || "";
for (let i = 0; i < commentEls.length; ++i) {
let el = commentEls[i];
let navs = el.querySelectorAll(".navs a");
let parent = null;
if (navs[0].textContent == "parent") {
parent = navs[0].getAttribute("href").slice(1);
}
if (navs[1].textContent == "parent") {
parent = navs[1].getAttribute("href").slice(1);
}
let comment = {
el: el,
id: el.id,
timestamp: parseInt(el.querySelector(".age").title.split(" ")[1], 10),
age: el.querySelector(".age a").textContent,
parent: parent,
answered: false,
answeredChild: false,
author: el.querySelector(".hnuser").textContent,
};
comments.push(comment);
commentMap[comment.id] = comment;
}
comments.sort(function(a, b) {
return b.timestamp - a.timestamp;
});
function updateAnswered() {
function markGrandparents(c) {
if (c.parent) {
c = commentMap[c.parent];
c.answeredChild = true;
markGrandparents(c);
}
}
for (let i = 0; i < comments.length; ++i) {
let comment = comments[i];
comment.answered = false;
comment.answeredChild = false;
}
for (let i = 0; i < comments.length; ++i) {
let comment = comments[i];
if (comment.author == myUsername) {
comment.answered = true;
if (comment.parent) {
let parent = commentMap[comment.parent];
parent.answered = true;
markGrandparents(parent);
}
}
}
}
let container = null;
let list = null;
let usernameInput = null;
function usernameUpdated() {
let val = usernameInput.value;
myUsername = val;
localStorage.setItem("__my_username", myUsername);
updateAnswered();
render();
}
function click(ev) {
let id = ev.target.getAttribute("data-id");
let comment = commentMap[id];
comment.el.scrollIntoView({ behavior: "smooth", block: "center" });
for (let i = 0; i < comments.length; ++i) {
comments[i].el.classList.remove("__active");
}
comment.el.classList.add("__active");
ev.preventDefault();
return false;
}
function render() {
if (!container) {
container = document.createElement("DIV");
container.style.boxSizing = "border-box";
container.style.position = "fixed";
container.style.right = "0px";
container.style.top = "0px";
container.style.height = "100vh";
container.style.width = "15vw";
container.style.background = "black";
container.style.padding = "8px";
container.style.overflowY = "scroll";
container.style.borderLeft = "2px solid skyblue";
usernameInput = document.createElement("INPUT");
usernameInput.style.width = "100%";
usernameInput.value = myUsername;
usernameInput.addEventListener("input", usernameUpdated);
container.appendChild(usernameInput);
list = document.createElement("DIV");
container.appendChild(list);
document.body.appendChild(container);
document.querySelector(".comment-tree").style.marginRight = "15vw";
let style = document.createElement("STYLE");
style.textContent = `
.comment-tree tr[id] {
transition: background 0.5s linear;
}
.__active {
background: burlywood;
}
`;
document.head.appendChild(style);
}
list.innerHTML = "";
for (let i = 0; i < comments.length; ++i) {
let comment = comments[i];
let el = document.createElement("A");
el.href = "#" + comment.id;
el.textContent = comment.age + " | " + comment.author;
el.style.color = (comment.answered ? "grey" : (comment.answeredChild ? "purple" : "skyblue"));
el.style.display = "block";
el.style.padding = "4px";
el.setAttribute("data-id", comment.id);
el.addEventListener("click", click);
list.appendChild(el);
}
}
updateAnswered();
render();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment