Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kms70847/d0d98dc7fe6d07aff1b1 to your computer and use it in GitHub Desktop.
Save kms70847/d0d98dc7fe6d07aff1b1 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Hacker News Post Sorter
// @namespace .
// @include https://news.ycombinator.com/
// @version 1
// @grant none
// ==/UserScript==
HTMLCollection.prototype.forEach = Array.prototype.forEach;
function keySort(seq, key){
function compare(a,b){
if(a<b){return -1;}
if(a>b){return 1;}
return 0;
}
seq.sort((a,b)=>compare(key(a),key(b)));
}
function Story(titleNode, infoNode, spacerNode){
this.titleNode = titleNode;
this.infoNode = infoNode;
this.spacerNode = spacerNode;
}
Story.prototype.getCommentCount = function(){
var links = this.infoNode.getElementsByTagName("A");
//not sure which link, if any, is the comments link.
//iterate through them all looking for a reasonable match.
for(var i = 0; i < links.length; i+=1){
link = links[i];
var groups = /(\d*) comments?/.exec(link.innerHTML);
if (groups != null){
return parseInt(groups[1]);
}
}
//some posts don't have comments at all.
return 0;
}
Story.prototype.getPoints = function(){
var node = this.infoNode.getElementsByClassName("score")[0];
if (node == undefined){return 0;}
var groups = /(\d*) points?/.exec(node.innerHTML);
if (groups == null){return 0;}
return parseInt(groups[1]);
}
Story.prototype.getRank = function(){
var rankNode = this.titleNode.getElementsByClassName("Rank")[0];
return parseInt(rankNode.innerHTML.replace(/\D/g, ""));
}
function rearrange(func){
var table = document.getElementsByClassName("itemList")[0];
var body = table.getElementsByTagName("tbody")[0];
var rows = body.getElementsByTagName("tr");
var stories = [];
for(var i = 0; i < rows.length-2; i+=3){
stories.push(new Story(rows[i], rows[i+1], rows[i+2]));
}
keySort(stories, func);
while (body.firstChild) {
body.removeChild(body.firstChild);
}
stories.forEach(function(story){
body.appendChild(story.titleNode);
body.appendChild(story.infoNode);
body.appendChild(story.spacerNode);
});
}
function makeRotaryButton(config){
var button = document.createElement("A");
var idx = 0;
button.innerHTML = config[idx]["text"];
button.onclick = function(){
config[idx]["func"]();
idx = (idx + 1) % config.length;
button.innerHTML = config[idx]["text"];
};
return button
}
//this is kind of dumb... We want the label to indicate the effect that the last button press had.
//it's a little awkward that the functions don't match up with their descriptions.
//This makes it harder to rearrange the rotation order.
var button = makeRotaryButton([
{text: "sorting by rank", func: ()=>rearrange(s=>-s.getCommentCount())},
{text: "sorting by comments", func: ()=>rearrange(s=>-s.getPoints())},
{text: "sorting by points", func: ()=>rearrange(s=>s.getRank())}
]);
var x = document.getElementsByClassName("pagetop")[0];
x.innerHTML += "| ";
x.appendChild(button);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment