IMDb More Photos

By Brent Charbonneau Last update May 14, 2008 — Installed 2,025 times. Daily Installs: 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 2, 0, 2, 1, 0, 0, 0, 0, 1, 2, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0
// IMDb More Photos
// version 0.2.2
// 2008-05-13
// Copyright (c) 2007, Brent Charbonneau
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html
//
// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.
//
// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
// Then restart Firefox and revisit this script.
// Under Tools, there will be a new menu item to "Install User Script".
// Accept the default configuration and install.
//
// To uninstall, go to Tools/Manage User Scripts,
// select "IMDb More Photos", and click Uninstall.
//
// --------------------------------------------------------------------
//
// ==UserScript==
// @name           IMDb More Photos
// @namespace      http://projects.apathyant.com/imdbmorephotos/
// @description    Adds a button to actor pages that opens an inline window with more photos of the actor (from Google Images).
// @include        http://*.imdb.com/name/*
// @include        http://imdb.com/name/*
// ==/UserScript==

var prefix = 'imp-';

var windowWidthPercentage = 0.75;
var windowHeightPercentage = 0.45;
var windowPadding = 6;
var windowTextPadding = 5;
var windowFontSize = 10;
var windowBorderSize = 1;
var windowBorderColor = '#E0E0E0';
var windowButtonHeight = 13;
var windowButtonTextSize = 11;
var windowButtonBorderSize = 1;
var windowButtonBorderColor = windowBorderColor;
var windowButtonTextColor = 'black';
var windowButtonBgColor = '#DDD';
var windowButtonBgColorHover = '#EEE';
var windowButtonMargin = 4;
var windowButtonRadius = 5;
var windowTitleMarginTop = 6;
var windowTitleMarginLeft = 18;
var windowTitleFontSize = 12;
var windowBgColor = '#FFFFE0';
var windowInnerBorderColor = '#E0E0E0';
var windowInnerBorderSize = 1;
var windowInnerBgColor = 'white';
var buttonBgColor = '#F9F9F9';
var buttonBgColorHover = windowBgColor;
var buttonPadding = 4;
var buttonFontSize = 11;
var buttonBorderColor = windowBorderColor;
var buttonBorderSize = 1;
var buttonRadius = 5;
var buttonText = document.createTextNode('More Photos');

function getElementOffset(element,whichCoord) {
	var count = 0
	while (element!=null) {
	 	count += element['offset' + whichCoord];
		element = element.offsetParent;
	}
	return count;
}

function inlineViewClickHandler(event) {
	// Event handler which takes clicks from our injected inline view icon links...
	var href, link;
	
	// Create the new dhtml frame
	if ( event.target.tagName.toLowerCase() == 'a' ) {
		// user managed to click the actual anchor and not the icon
		href = event.target.href;
		link = event.target;
	} else if ( event.target.tagName.toLowerCase() == 'img' ) { 
		// user clicked the icon
		href = event.target.parentNode.href;
		link = event.target.parentNode;
	}else{
		// No idea how this function was launched, so we cannot proceed.
		GM_log('inlineViewClickHandler triggered from unknown element. Cannot proceed.');
		return false;
	}
	
	// check to see if the window is open and if so close it, otherwise pop a new window
	var openWindow = document.getElementById(prefix + 'giInlineWindow');
	if(openWindow) {
		openWindow.parentNode.removeChild(openWindow);
	} else {
		inlineWindow = newInlineWindow(event, href, link);
	}
	
	event.preventDefault();
	return true;
}
function newInlineWindow(event, href, link){
	// Setup some constants for use in creating the inline window...
	var windowWidth = Math.round(document.width * windowWidthPercentage);
	var windowHeight = Math.round(window.innerHeight * windowHeightPercentage);
	var windowFullID = prefix + 'giInlineWindow';
	
	// stop the window before getting this close to the left/right/top/bottom of the screen
	var pageBoundPadding = 10;
	
	var xpos, ypos;
	
	// get the position of the element that was clicked on...
	var elementTop = getElementOffset(link,'Top');
	var elementLeft = getElementOffset(link,'Left');
	var linkLineHeight = window.getComputedStyle(link,"").getPropertyValue('line-height')

	var elementHeight;
	if(linkLineHeight == 'normal') {
		elementHeight = 12;
	} else {
		elementHeight = parseInt(window.getComputedStyle(link,"").getPropertyValue('line-height'));
	}


	// setup the x-position of the inline window...
	/*
	// check to see if the left 1/3 of the window will overlap the left page bound..
	if ( elementLeft - (windowWidth/3) < pageBoundPadding ) {
		xpos = pageBoundPadding;
	} 
	// check to see if the right 2/3 of the window will overlap the right page bound...
	else if ( elementLeft + (windowWidth*2/3) > document.width - pageBoundPadding ) {
		xpos = document.width - pageBoundPadding - windowWidth;
	}
	else {
		// if we're not going to hit either wall, set the window to be offset
		// by 1/3 to the left of where we clicked (looks better than centering
		xpos = elementLeft - (windowWidth/3);
	}
*/
	if(elementLeft + windowWidth > document.width - pageBoundPadding) { 
		xpos = document.width - pageBoundPadding - windowWidth;
	} else {
		xpos = elementLeft;
	}
	// setup the y-positioning of the inline window...

	// check to see if the window goes beyond the bottom of the viewport...
	if ( elementTop + windowHeight + pageBoundPadding > window.pageYOffset + window.innerHeight ) {
		ypos = elementTop - windowHeight;
	} else { 
		ypos = elementTop + elementHeight;
	}

	
	var cssBoxWidth = Math.round((windowWidth - (windowPadding+windowBorderSize)*2)/document.width*100);
	var cssBoxHeight = windowHeight - windowBorderSize*2 - windowPadding;

	var frame = document.createElement('div');
	frame.id = windowFullID;
	frame.className = prefix + 'frame';	

	frame.style.marginTop = ypos + 'px';
	frame.style.marginLeft = xpos + 'px';
	frame.style.width = cssBoxWidth + '%'
	frame.style.height = cssBoxHeight + 'px';

	var closeButton = document.createElement('a');
	closeButton.className = 'button';
	closeButton.addEventListener('click', function(event) {
		frame = event.target.parentNode; frame.parentNode.removeChild(frame); return false;
		}, true); 
	closeButton.href = '#';
	closeButton.appendChild(document.createTextNode('x'));
	frame.appendChild(closeButton);
	
	var linkButton = document.createElement('a');
	linkButton.className = 'button';
	linkButton.href = giFullLink;
	linkButton.appendChild(document.createTextNode('more...'));
	frame.appendChild(linkButton);

	var title = document.createElement('h1');
	title.appendChild(document.createTextNode('More Photos From Google Images...'));
	frame.appendChild(title);
	
	var contents = document.createElement('div');
	contents.className = 'contents clearfix';
	contents.id = prefix + 'content';
	contents.style.height = (windowHeight  - (windowButtonMargin + windowButtonHeight + windowButtonBorderSize*2) - ((windowBorderSize + windowPadding + windowInnerBorderSize + windowTextPadding)*2) ) + 'px';
	contents.appendChild(document.createTextNode('Loading'));
	contents.setAttribute('loading','true');
	
	var loadIndicator = document.createElement('span');
	loadIndicator.style.textDecoration = 'blink';
	loadIndicator.appendChild(document.createTextNode('...'));
	contents.appendChild(loadIndicator);

		
	frame.appendChild(contents);

	document.body.insertBefore(frame, document.body.firstChild);
	
	populateContents(href,contents);
}

function populateContents(href, contents, start) {
	if(!start) start = 0;

	GM_xmlhttpRequest
	   ({
	   method:'GET',
	   url: href,
	   onload:function(response) {
			var results, content, result, resultLinks;
			var xmlDoc;

			if (typeof(XPCNativeWrapper) == "function") {
				var dp = new XPCNativeWrapper(window, "DOMParser()");
				var parser = new dp.DOMParser();
				//var src = new String(response.responseText).replace(/<html[^>]+>/,'<html>');
				xmlDoc = parser.parseFromString(response.responseText, "application/xhtml+xml");
			}

			if(contents.getAttribute('loading')=='true') {
				while(contents.hasChildNodes()) contents.removeChild(contents.childNodes[0]);
				contents.setAttribute('loading', 'false');
			}
			if(!xmlDoc) {
				if (contents) contents.appendChild(document.createTextNode('Error loading page (no parsed document).'));
				return;
			}

			function resolver() {
				return 'http://www.w3.org/1999/xhtml';
			}
			
			results = xmlDoc.evaluate('//myns:a/myns:img/../..', xmlDoc, resolver, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
			
			if(!results.snapshotLength) {
				if (contents) contents.appendChild(document.createTextNode('Error loading page (no results found).'));
				return;
			}

			for ( var i=0 ; i < results.snapshotLength; i++ ) {
				result = results.snapshotItem(i);
				result.className = 'result';
				result.style.float = 'left';
				result.style.paddingRight = '10px';
				resultLinks = result.getElementsByTagName('a');
				for(var j=0; j < resultLinks.length; j++) {
					if(resultLinks[j].getAttribute('href').substring(0,7)!='http://'){

						resultLinks[j].href = unescape(resultLinks[j].getAttribute('href').match(/&u=(.*)/)[1]);
					}
				}
				contents.appendChild(result);
			}
			
		}});
		if(start < 15) {
			start += 5;
			
			populateContents(new String(href).replace(/&start=[0-9]+&/,'&start=' + start + '&'), contents, start);
		}
		
}


var headshot =  document.evaluate('//div[@id="tn15lhs"]//div[@class="photo"]', document, null,XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if(!headshot) return;

var actorName = document.evaluate('//div[@id="tn15title"]//h1/child::text()', document, null,XPathResult.STRING_TYPE, null).stringValue;;
if(!actorName) return;

var popIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs%2B9AAAABGdBTUEAAK%2' +
					'FINwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAACSSURBVHjaYvz%2F%2Fz8DDK' +
					'xfvx7BQQMs6AKBgScxFK1fb87AhE03SOLMGWEUMbDCM2fO%2FEdWJCt7h0FaWg9FMRPMXTAapMjE5C3D06eX' + 
					'GB4%2FVkF1o4mJCZS7H6wIZBJIEbJ74Z6BKDYBKuqGmwRyBk5fMzA4AvFjoGmBjBieQQYgk2VlZVE8CDcR6B' +
					'EGzPBENREgwADlWjkepo9xFwAAAABJRU5ErkJggg%3D%3D';

var giIcon = 'data:image/gif;base64,R0lGODlhEAAQAOYAAAdj6AD%2F%2FwD8%2FAD7%2BwDv7wDg4ADe3gD' +
	'CwgCengCNjQt2dhz%2F%2FwxfXxdhYRhgYEr%2F%2Fyt5eWb%2F%2FypmZlvDwy5dXTRnZylQUDBZWZ%2F' +
	'%2F%2Fyk3N9X%2F%2FzI7O0VOTjtBQWlzcz5CQlRVVTy1RIODgt0YEkY3N0o%2BPklAQG9nZ2tkZKienmV' +
	'fX7atrZSNjWZhYWxnZ3BsbImFhYB8fGxpaW9tbW1ra4qIiP%2F%2F%2F%2FLy8vHx8fDw8Onp6eLi4tra2' +
	'ri4uLe3t7Ozs7Gxsa6urpycnJmZmZWVlZKSkpCQkIyMjIuLi4iIiIODg4KCgoGBgXx8fHZ2dnR0dHNzc3J' +
	'ycnFxcW9vb21tbWhoaGdnZ2FhYV9fX15eXlhYWFdXV05OTk1NTUNDQ0BAQD09PTs7Ozc3NwAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
	'AAAAAAAAAAAAAAAAAAAAAACwAAAAAEAAQAAAHnYAAIYOEhYYANomKi4sjiIyQiY42NzthUDpFRz05nTg2k' +
	'1NJTiAyKyksXVRNIqCITjw%2FMR4SEBUuQT5ArjZaSDAcCBEaExk0QlG8XksnFAUBDxgOJkNXvF9MKBcGA' +
	'wELDSVEWLxgUjUfCQQCBxsvRlu8YlhLMx0MChYqSlVcvE9WWZzUKEGiBZUpWJJNigRpIcNGjx4qGmGoYqE' +
	'RgQAAOw%3D%3D';					
					
var giLink = 'http://www.google.com/m/search?output=xhtml&site=images&sa=X&oi=image&start=0&q=' + encodeURI('"' + actorName + '"');
var giFullLink = 'http://images.google.com/images?q=' + encodeURI('"' + actorName + '"');

var cssNode = document.createElement('style');
cssNode.type = 'text/css';
cssNode.rel = 'stylesheet';
cssNode.media = 'screen';
cssNode.title = 'dynamicSheet';
document.getElementsByTagName("head")[0].appendChild(cssNode);

var sheet = document.styleSheets[document.styleSheets.length-1]
sheet.insertRule('.' + prefix + 'more-pictures { font-size: 12px; text-align: center; padding:'+ buttonPadding +'px; ' +
		'padding-left: ' + (20+buttonPadding) + 'px; margin: 3px 0 10px; ' +
		'line-height: 16px; background: ' + buttonBgColor + ' url(' + giIcon + ') '+ buttonPadding +'px center no-repeat; ' +
		'border: ' + buttonBorderSize + 'px solid '+ buttonBorderColor + '; ' +
		'-moz-border-radius: ' + buttonRadius + 'px; '+
		'}', sheet.cssRules.length);
sheet.insertRule('div.' + prefix + 'more-pictures:hover { background-color: '+ buttonBgColorHover +'; }', sheet.cssRules.length);
sheet.insertRule('.' + prefix + 'more-pictures a.pop { padding-right: 13px; ' +
		'font-size:'+ buttonFontSize +'px; font-weight: bold; ' +
		'}', sheet.cssRules.length);
sheet.insertRule('div.' + prefix + 'more-pictures:hover a.pop { background: url(' + popIcon + ') center right no-repeat; }', sheet.cssRules.length);
sheet.insertRule('.' + prefix + 'frame { font-family: Arial,Helvetica,sans-serif; position: absolute; ' +
		'background: ' + windowBgColor + ' url(' + giIcon + ') ' + windowPadding + 'px ' + windowPadding + 'px  no-repeat; '+
		'border: ' + windowBorderSize + 'px solid '+ windowBorderColor + '; ' +
		/*'padding: ' + Math.round((windowPadding-windowButtonHeight)/2) +'px ' + windowPadding + 'px ' + windowPadding + 'px; ' +*/
		'padding: ' + windowPadding + 'px; ' +
		'padding-top: 0; ' +
		'-moz-border-radius: 5px; '+
		'z-index: 999; '+
		'opacity: 0.95; '+
		'font-size: ' + windowFontSize + 'pt; ' + '}', sheet.cssRules.length);
sheet.insertRule('.' + prefix + 'frame .button { float: right; text-decoration: none; display: block; '+
		'border: ' + windowButtonBorderSize + 'px solid ' + windowButtonBorderColor + ';' +
		'background-color: '+ windowButtonBgColor + ';' + 
/*		'margin: 0 3px ' + Math.round((windowPadding-windowButtonHeight)/2) +'px; '+*/
		'margin: ' + windowButtonMargin + 'px ' + windowButtonMargin + 'px ' + windowPadding + 'px; ' +
		'padding: 0 3px; '+
		'-moz-border-radius: ' + windowButtonRadius + 'px; '+
		'height: ' + windowButtonHeight + 'px; '+
		'font-size: ' + windowButtonTextSize + 'px; '+
		'line-height: ' + windowButtonTextSize + 'px; '+
		'color: ' + windowButtonTextColor + '; ' +
		'font-weight: bold' + '}', sheet.cssRules.length);
sheet.insertRule('.' + prefix + 'frame .button:hover { background-color: ' + windowButtonBgColorHover +  ' }', sheet.cssRules.length);
sheet.insertRule('.' + prefix + 'frame h1 { margin: ' + (windowTitleMarginTop) + 'px 0 0 ' + (windowTitleMarginLeft) + 'px; font-size: ' +  windowTitleFontSize + 'px; }', sheet.cssRules.length);

sheet.insertRule('.' + prefix + 'frame .contents { border: ' + windowInnerBorderSize + 'px solid '+ windowInnerBorderColor + ';' +
		'background: '+windowInnerBgColor+'; '+
		'padding: ' + windowTextPadding + 'px; '+
		'overflow: auto; '+
		'clear: both; '+ '}', sheet.cssRules.length);
sheet.insertRule('.' + prefix + 'frame .contents .result { width: 150px; float: left; margin-right: 10px; height: 175px; overflow: hidden; }', sheet.cssRules.length);
sheet.insertRule('.' + prefix + 'frame .clearfix:after { clear:both; content:"."; display:block; height:0pt; line-height:0pt; visibility:hidden; }', sheet.cssRules.length);

var morePicturesLink = document.createElement('a');
morePicturesLink.href = giLink; 
morePicturesLink.className = 'pop';
morePicturesLink.appendChild(buttonText);
morePicturesLink.addEventListener('click', inlineViewClickHandler, true); 

var morePictures = document.createElement('div');
morePictures.className = prefix + 'more-pictures';
morePictures.appendChild(morePicturesLink);

headshot.parentNode.insertBefore(morePictures, headshot.nextSibling);