Google Dilbert browser
By Johan Sundström
—
Last update Jul 20, 2006
—
Installed
1,914 times.
// ==UserScript==
// @name Google Dilbert browser
// @namespace http://www.lysator.liu.se/~jhs/userscript
// @include http://*google.*/
// @include http://*google.*/#*
// @include http://*google.*/webhp*
// @include http://www.comics.com/*
// @description Adds the comic strip of the day from Dilbert.com or any other UnitedMedia comic of your preference from www.comics.com to Google's search page, just below the Search / "I'm feeling lucky" buttons. Clicking the left/right thirds of the strip browses the previous/next strip, center portion loads the full comics.com page for this strip (access keys [Alt+] P/N and T respectively work too). When on comics.com, click the "Show this comic at Google" link by the comic selection box to change to your preferred comic.
// ==/UserScript==
if( location.hostname == 'www.comics.com' )
return configure();
if( !location.pathname.match( /^\/($|webhp)/ ) ||
!location.hostname.match( /\bgoogle\.[a-z.]{1,10}$/i ) )
return; // don't hook on to Google Reader, for instance.
var debug = 0; // 1 for call log, 2 for profiling, 3 for both
var inject_after = '//form'; // comic injection point XPath selector
foreach( '(//br)[position() >= last()-1]', remove_node ); // drop some padding
var hostname = 'http://www.comics.com';
var strip = GM_getValue( 'name', 'dilbert' );
var archive = GM_getValue( 'path', '/comics/' ) + strip +'/archive/';
var page_re = new RegExp( archive + strip +'-\\d+.html', 'gm' );
var strip_re = new RegExp( archive + 'images/'+ strip +'[^&"\']*' );
var urls = []; // page urls, by date
var strips = {}; // page url:strip url, populated incrementally
var strip = make_tag( 'img', { usemap:'#prev-next', vspace:14, border:0 } );
var prev = make_tag( 'area', { accessKey:'P',shape:'rect',coords:'0,0,0,0' } );
var curr = make_tag( 'area', { accessKey:'T',shape:'rect',coords:'0,0,0,0' } );
var next = make_tag( 'area', { accessKey:'N',shape:'rect',coords:'0,0,0,0' } );
var map = make_tag( 'map', { name:'prev-next' }, [prev, curr, next] );
var count = 0; // number of strips seen; only used for profiling
load_comic();
function configure()
{
if( location.pathname.match( /\//g ).length > 2 )
foreach( '(//select[count(option)>40])[1]', install_handler );
}
function install_handler( select )
{
var link = document.createElement( 'a' );
var space = document.createTextNode( ' ' );
link.title = 'Show this comic at www.google.com';
link.href = 'http://www.google.com/#'+ location.pathname;
link.innerHTML = 'Show\xA0this\xA0comic\xA0at\xA0Google';
select.parentNode.insertBefore( link, select.nextSibling );
select.parentNode.insertBefore( space, select.nextSibling );
link.addEventListener( 'click', save_preferences, false );
window.addEventListener( 'unload', function() {
link.removeEventListener( 'click', save_preferences, false );
}, false );
}
function save_preferences()
{
var bits = location.pathname.match( /^(.[^\/]+.)([^\/]*)/ );
GM_setValue( 'path', bits[1] );
GM_setValue( 'name', bits[2] );
}
function make_tag( name, attr, children )
{
var tag = document.createElement( name );
if( attr )
for( var name in attr )
tag.setAttribute( name, attr[name] );
if( children )
for( var i=0; i<children.length; i++ )
tag.appendChild( children[i] );
return tag;
}
function remove_node( node )
{
node.parentNode.removeChild( node );
}
function $x( xpath, root )
{
var doc = root ? root.evaluate ? root : root.ownerDocument : document, next;
var got = doc.evaluate( xpath, root||doc, null, 0, null ), result = [];
while( next = got.iterateNext() )
result.push( next );
return result;
}
// run the passed cb( node, index ) on all nodes matching the expression
function foreach( xpath, cb, root )
{
var nodes = $x( xpath, root ), i, e = 0;
for( i=0; i<nodes.length; i++ )
e += cb( nodes[i], i ) || 0;
return e;
}
// Fetch a web page and call cb( http_response, args[0], ..., args[N] )
function get( url, cb, args )
{
if( args ) cb = make_caller( cb, args );
GM_xmlhttpRequest( { method:'GET', url:url, onload:function( rq )
{ log( 'got %s', url ); cb( rq.responseText ); } } );
}
function log()
{
if( !(debug & 1) ) return;
var args = Array.prototype.slice.call( arguments );
return unsafeWindow.console.log.apply( this, args );
}
function time( name, endp )
{
if( debug & 2 )
return unsafeWindow.console[ endp ? 'timeEnd':'time' ]( name );
}
function make_caller( f, args, self )
{
return function()
{
args = Array.prototype.slice.call( arguments ).concat( args||[] );
f.apply( self||f, args );
};
}
function draw_comic( url )
{
log( 'draw_comic( %s )', url );
if( !strip.parentNode )
{
$x( inject_after )[0].appendChild( strip );
document.body.appendChild( map );
prev.addEventListener( 'click', load_comic, true );
next.addEventListener( 'click', load_comic, true );
strip.addEventListener( 'load', set_coords, false );
}
time( strips[ url ] );
strip.src = strips[ url ];
var i = urls.indexOf( url );
prev.href = urls[ bound( i-1, urls.length ) ];
curr.href = urls[ i ] || url;
next.href = urls[ bound( i+1, urls.length ) ];
}
function bound( n, max )
{
return n < 0 ? n + max : n % max;
}
function set_coords()
{
time( 'Display comic '+ count, 1 );
time( strip.src, 1 );
var w = strip.width, W = Math.floor( w/3 ), h = strip.height;
log( 'set_coords( %d, %d )', w, h );
prev.coords = '0,0,'+ W +','+ h;
curr.coords = W +',0,'+ (w-W) +','+ h;
next.coords = (w-W) +',0,'+ (--w) +','+ h;
//prev.title = 'Previous strip';
//next.title = 'Next strip';
}
function parse_strip_url( html, page_url )
{
log( 'parse_strip_url( %d bytes of HTML, %s )', html.length, page_url );
var url = strip_re.exec( html );
if( url )
strips[page_url] = hostname + url[0];
draw_comic( page_url );
}
function parse_page_urls( html, page_url )
{
time( 'parse_page_urls' );
log( 'parse_page_urls( %d bytes of HTML, %s )', html.length, page_url );
for( var url; url = page_re.exec( html ); )
{
url = hostname + url[0];
if( typeof strips[url] != 'undefined' )
continue; // only add page once per page url
if( !strips[url] ) // no image url stored yet?
strips[url] = null; // to be had there later
urls.push( url );
}
urls.sort();
var today = new Date;
if( today.getMonth()==3 && today.getDate()==1 && !page_url )
{
var url = 'http://www.sinfest.net/archive_page.php?comicID=73';
strips[url] = 'http://sinfest.net/comikaze/comics/2000-04-07.gif';
draw_comic( url );
}
else
parse_strip_url( html, page_url || urls[ urls.length-1 ] );
time( 'parse_page_urls', 1 );
}
function load_comic( e )
{
time( 'Display comic '+ (++count) );
log( 'load_comic(%o)', e );
if( e && e.preventDefault )
{
e.preventDefault();
e.stopPropagation();
}
var url = e && e.target && e.target.href;
if( location.hash.length && !url )
url = hostname + location.hash.substring( 1 );
if( strips[ url ] )
{
log( 'already had '+url );
draw_comic( url );
}
else
{
log( 'loading %s', url||'archive' );
get( url || hostname+archive, parse_page_urls, url );
}
}