Addictive Hacker News Horse Race Bookmarklet

I like to read Hacker News at Y Combinator. And I like to see how comments and points build up over time.

Some days ago I got this very stupid idea: what about making news run like horses in a race. In this way I could instantly spot the leading news.

So I wrote this bookmarklet and now I’m hooked. I can’t give up on it. Many times I just hit reload to see who’s leading the race now. I’m totally addicted.

BEFORE

This is what you see before clicking the bookmarklet.

AFTER

This is what you see after clicking the bookmarklet.

The bookmarklet

Drag and drop this link to your bookmarks bar, and rename it to HN Horse Race.

javascript:(function () {
	function core($) { 
        function getNumber(that$, type) { 
            var result = that$.find('*:contains(' + type + ')'); 
            result = result.length ? result.text() : '0'; 
            result = parseInt(result.replace(/D/, ''), 10); 
            return result; 
        } 
        var maxDistance = 0.618 * $('table:eq(0)').width(); 
        var maxPoints = 0; 
        var maxComments = 0; 
        $('td:nth-child(3).title').each(function () { 
            var this$ = $(this); 
            var next$ = this$.parent().next().find('td.subtext'); 
            this$.data('next$', next$); 
            var points = getNumber(next$, 'point'); 
            this$.data('points', points); 
            maxPoints = points > maxPoints ? points : maxPoints; 
            var comments = getNumber(next$, 'comment'); 
            this$.data('comments', comments); 
            maxComments = comments > maxComments ? comments : maxComments; 
        }).each(function () { 
            var this$ = $(this); 
            var next$ = this$.data('next$'); 
            var points = this$.data('points'); 
            var deltaPoints = maxPoints - points; 
            var comments = this$.data('comments'); 
            var deltaComments = maxComments - comments; 
            var distance = (deltaPoints + deltaComments) / (maxPoints + maxComments) * maxDistance; 
            this$.css('paddingLeft', distance); 
            next$.css('paddingLeft', distance); 
        }); 
    }
	
	var wasUndefined = typeof jQuery == 'undefined';
    if (wasUndefined) {
        var s = document.createElement('script'); 
        s.setAttribute('src', 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js'); 
        document.getElementsByTagName('head')[0].appendChild(s); 
    } 
    
    var time = 0; 
    var id = setInterval(function () {
    	function show_msg(text) {
    		var $ = jQuery;
    		$('<div style="display:none; position: absolute; padding: 5px; background: beige; font-size: 1.0em; z-index: 1000000"></div>')
    		.appendTo('body')
    		.css({ top: $(document).scrollTop() + 10, left: $(document).scrollLeft() + 10 })
    		.html(text)
    		.fadeToggle('fast', 'linear', function() {
    			$(this).fadeToggle(3000, 'linear', function() { 
    				$(this).remove(); 
    			}); 
    		});
        }
    	
        var isUndefined = typeof jQuery == 'undefined';
        if (! isUndefined) { 
            clearInterval(id); 
            if (wasUndefined) {
              jQuery.noConflict();
              show_msg('jQuery ' + jQuery.fn.jquery + ' has been injected.'); 
            }
            else {
              show_msg('jQuery ' + jQuery.fn.jquery + ' was already available.'); 
            }
            core(jQuery);
            return;
        }
        ++time;
        if (time == 10) { 
            clearInterval(id); 
            show_msg('Sorry, unable to inject jQuery now.'); 
        } 
    }, 500);
})();