The Open Code Project

Reddit Uppers and Downers Enhanced - JSLint, Fragment, and Chunking Update

July 9th,2010 by Allan Bogh

Below is the updated Reddit Uppers and Downers Enhanced. This update forces RUDE to wait for 25ms after processing for 50ms to allow the UI to update. One complaint that I've often had is that the UI gets stuck when there are a lot of comments on the page. This update should fix that issue. It also speeds up the code quite a bit by processing the objects slightly better than before.

A known bug that might occur is on some comments the script doesn't create the ups/downs span. This only happens on hidden comments which can be shown by clicking the "load more comments" link. The link queries the server, then updates a layer with the new information from the server. The RUDE script doesn't get called to process those new results, so I will have to attach a method to call the RUDE script on those results after they've loaded.

The code is included here because it has yet to be published on the UserScripts website.

Here's the original RUDE script from UserScripts.org
 

// ==UserScript==
// @name Reddit Uppers and Downers Enhanced
// @namespace mistercow
// @description Show up-votes and down-votes next to the total score on reddit comments.
// @include http://www.reddit.com/*/comments/*
// @include http://www.reddit.com/user/*
// ==/UserScript==

/*jslint strict:false, browser:true, plusplus:false, newcap:false*/
/*global window:false, GM_addStyle:false, GM_xmlhttpRequest:false*/

/*
This code is provided as is, with no warranty of any kind.

I hacked it together in one night for my own use, and have not tested it extensively.

The script can slow down comment page load time; if the lag is noticeable, you may want
to change your preferences to load fewer comments per page.

Note that this runs once and does not install any persistent code on the page. So any votes
you cast will not affect the numbers displayed until you reload.

Also note that the ups and downs will not always add up to the score displayed on reddit.
I think this is because of caching on reddit's part. It's usually within one or two points though.

Update: Allan Bogh contributed code which significantly sped up the processing of comments.
1500 comments could be processed in 113ms, over previous cases of 3000+ms.

skeww contributed code which chunks the rendering of comments into 50ms time slots, then pauses
for 25ms. Additionally, he cleaned up various parts of the code to enable faster processing.

Allan included skeww's contribution and also cleaned up the code to further improve speed.
Time testing code (in comments) are left in quick user tests. 1500 records processed at 6ms,
although this may be related to when the function returns, but not when it's actually complete.

Code contributors: Allan Bogh - http://www.opencodeproject.com
brasso - http://userscripts.org/scripts/show/56641
savetheclocktower - http://gist.github.com/174069
skeww (jslint, fragment, chunking) - http://kaioa.com
*/

var loc, jsonURL, voteTable, onloadJSON, displayVotes, processTree, isComment, processChildren, processReplies, chunker;

//Get the URL for the JSON details of this comments page
var loc = ""+location;
var jsonURL = loc + "/.json";
if(loc.indexOf("?") != -1) {
jsonURL = loc.replace("?","/.json?");
}


var voteTable = {};

function onloadJSON(response) {
var jsonText = response.responseText,data;
//Parse the json text
// Use native JSON (if it's available) because it's much faster.
// code by savetheclocktower - http://gist.github.com/174069
if (window.JSON && JSON.parse) {
data = JSON.parse(jsonText);
}else{
data = eval("("+jsonText+")");
}
//Load the vote table by processing the tree
processTree(data); //this takes up no time (4ms on 4000 records)

//Display the loaded votes
//date1 = new Date();
//milliseconds1 = date1.getTime();
displayVotes();
//date2 = new Date();
//milliseconds2 = date2.getTime();

//difference = milliseconds2 - milliseconds1;
//alert(difference+"ms - ");
};

// spend up to 50msec a time with a task, wait for 25msec and continue if necessary
chunker = function (items, process) {
var todo = items.concat();

setTimeout(function () {
var start = Date.now();
do {
process(todo.shift());
} while (todo.length && Date.now() - start < 50);
if (todo.length) {
setTimeout(arguments.callee, 25);
}
}, 25);
};

function displayVotes(){
//Add the style sheets for up and down ratings
GM_addStyle(".moo_ups { color:rgb(255, 139, 36); font-weight:bold; }");
GM_addStyle(".moo_downs { color:rgb(148,148,255); font-weight:bold; }");

var taglines,
commentID = null,
toArray;



toArray = function(col){
var a = [], i, len;
for(i=0, len=col.length; i< len; i++){
a[i] = col[i];
}
return a;
};

taglines = toArray(document.getElementsByClassName("tagline"));


chunker(taglines, function(item){
var votes, openparen, mooups, pipe, moodowns, voteDowns, voteUps, closeparen, frag;

if(item.nextSibling.nodeName === "FORM"){ //the first item is the title of the post
commentID = item.nextSibling.firstChild.value;
if(voteTable[commentID]){
frag = document.createDocumentFragment(); //using a fragment speeds this up by a factor of about 2

votes = voteTable[commentID];

openparen = document.createTextNode(" (");
frag.appendChild(openparen);

mooups = document.createElement("span");
mooups.className = "moo_ups";
voteUps = document.createTextNode(votes.ups);

mooups.appendChild(voteUps);
frag.appendChild(mooups);

pipe = document.createTextNode("|");
item.appendChild(pipe);

moodowns = document.createElement("span");
moodowns.className = "moo_downs";

voteDowns = document.createTextNode(votes.downs);
moodowns.appendChild(voteDowns);

frag.appendChild(moodowns);

closeparen = document.createTextNode(")");
frag.appendChild(closeparen);

frag.appendChild(openparen);
frag.appendChild(mooups);
frag.appendChild(pipe);
frag.appendChild(moodowns);
frag.appendChild(closeparen);

item.appendChild(frag);
}
}

});

/*var commentID = null;
for(i=0, il=taglines.length; i < il; i++){
if(taglines[i].nextSibling.nodeName === "FORM"){ //the first item is the title of the post
commentID = taglines[i].nextSibling.firstChild.value;
if(voteTable[commentID]){
votes = voteTable[commentID];

var parent = taglines[i];

var openparen = document.createTextNode(" (");
parent.appendChild(openparen);
var mooups = document.createElement("span");
mooups.className = "moo_ups";
var voteUps = document.createTextNode(votes.ups);
mooups.appendChild(voteUps);
parent.appendChild(mooups);
var pipe = document.createTextNode("|");
parent.appendChild(pipe);
var moodowns = document.createElement("span");
moodowns.className = "moo_downs";
var voteDowns = document.createTextNode(votes.downs);
moodowns.appendChild(voteDowns);
parent.appendChild(moodowns);
var closeparen = document.createTextNode(")");
parent.appendChild(closeparen);


parent.appendChild(openparen);
parent.appendChild(mooups);
parent.appendChild(pipe);
parent.appendChild(moodowns);
parent.appendChild(closeparen);
}
}
}*/
}

//Recursively process the comment tree
function processTree(obj) {
var i, il, data, name;
if(obj instanceof Array) {
for(var i=0, il=obj.length; i < il; i++) {
processTree(obj[i]);
}
}

data = obj.data;
if(data) { //Data found
if(isComment(obj) && data.author !== "[deleted]") {
name = data.name;
if(name) { //Store the votes in the vote table
voteTable[name] = {
downs:data.downs || 0,
ups:data.ups || 0
};
}
}

//Process any subtrees
processChildren(data);
processReplies(data);

}
};

function isComment(obj) {
return obj.kind === "t1";
};

function processChildren(data) {
var children = data.children, i, il;
if(children) {
for(i=0, il=children.length; i < il; i++){
processTree(children[i]);
}
}
};

function processReplies(data) {
var replies = data.replies;
if(replies) processTree(replies);
};

//load the JSON
if (jsonURL.indexOf('/comscore-iframe/') === -1) {
GM_xmlhttpRequest({
method: "GET",
url: jsonURL,
onload: onloadJSON
});
}

Comments (0)


:

:

:


: formatting help
Close

Formatting instructions:

You can use <a> tags but everything else will be stripped and your comment will look funny.

I swear, don't use html except the <a> tag or else some random star will supernova. Remember, we have a star right next to us, so don't try it.

This isn't bbcode either so don't use it. That is all.