QuickGallery

By Jos van den Oever Last update Dec 12, 2005 — Installed 6,485 times.
/*
 ==UserScript==
@name QuickGallery
@namespace http://www.vandenoever.info
@description Load all pictures from a thumbnail gallery at once and navigate them with arrow keys or mouse. Images may be zoomed with 'z'.
@include *

==/UserScript==
*/

/*
  Author: Jos van den Oever ( jos@vandenoever.info )

  License: GPL

  Version history:
    2006-01-22: revert links when QuickGallery is 'closed' and test images
    2006-01-13: assigned 'z' to zoom (bugfix), improved image finding, added close button
    2005-12-02: updated the script to work with GreasMonkey 0.5.3 and newer
    2005-06-08: fixed RegExp problem and improved Opera key bindings
    2005-06-04: updated the script so that it works with Opera 8
    2005-06-03: added support for normal links to images
    2005-06-02: 90% rewrite. Added images as overlay, tooltip, and zooming.
    2005-06-01: Initial write.

  Possible future enhancements:
    - allow for delayed loading of images by first putting a string in the array imgs and
      replacing it with an img element when the url is requested

*/

// wrap the entire functionality in an anonymous function
(function() {
window.addEventListener("load", function(ev) {

// define variable that remembers the current image position
var i;
// the variable holding the state of the zoom toggle
var zoom = false;

var quickgallery_on = true;

var dialog_initialized = false;

// function definitions

var setVisible = function(img, mouseevent) {
	i = img.n;
	img.style.display='block';
	img.style.position='absolute';
	img.style.zIndex = 100;
	doZoom(img);
	// try to show the middle of the img under the middle of the cursor
	if (mouseevent) {
		centerMouse(img, mouseevent);
	} else {
		centerScreen(img);
	}
}
// resize the image if we are in zoom mode
var doZoom = function(img) {
	if (!img.owidth) {
		img.owidth=img.width;
		img.oheight=img.height;
	}
	if (zoom) {
		var sw = window.innerWidth;
		var sh = window.innerHeight;
		if (img.owidth/sw < img.oheight/sh) {
			img.style.height = sh+"px";
			img.style.width = 'auto';
		} else {
			img.style.width = sw+"px";
			img.style.height = 'auto';
		}
	} else {
		img.style.width = 'auto';
		img.style.height = 'auto';
	}
}
// display the image as close as possible to the mouse as possible
// and also try to keep it inside of the browser window
var centerMouse = function(img, e) {
	var iw = img.width;
	var sw = window.innerWidth;
	var mx = e.pageX;
	var sx = window.pageXOffset;
	var left;
	if (iw > sw) {
		left = sx + (sw-iw)/2;
	} else {
		left = mx-iw/2;
		if (left+iw > sw+sx) {
			left = sw+sx-iw;
		} else if (left < sx) {
			left = sx;
		}
	}
	img.style.left = ((left>=0)?left:0)+"px";
	var ih = img.height;
	var sh = window.innerHeight;
	var my = e.pageY;
	var sy = window.pageYOffset;
	var top;
	if (ih > sh) {
		top = sy + (sh-ih)/2;
	} else {
		top = my-ih/2;
		if (top+ih > sh+sy) {
			top = sh+sy-ih;
		} else if (top < sy) {
			top = sy;
		}
	}
	img.style.top = ((top>=0)?top:0)+"px";
}
// display the image at the center of the screen
var centerScreen = function(img) {
	var sx = window.pageXOffset;
	var sy = window.pageYOffset;
	var sw = window.innerWidth;
	var sh = window.innerHeight;
	var iw = img.width;
	var ih = img.height;
	var top = sy + (sh-ih)/2;
	var left = sx + (sw-iw)/2;
	img.style.top = ((top>=0)?top:0)+"px";
	img.style.left = ((left>=0)?left:0)+"px";
}
var setInvisible = function(img) {
	img.style.display='none';
}
// show the image at position pos in the imgs array
var showImg = function(pos) {
	for (var j in imgs) {
		if (j==pos && quickgallery_on) {
			setVisible(imgs[j]);
		} else {
			setInvisible(imgs[j]);
		}
	}
}
// make the images clickable
var setToggle = function(a, bigimg) {
	var f1 = function(event) {
		if (quickgallery_on && a.valid) {
			setVisible(bigimg, event);
			event.preventDefault();
		}
		// return 'false' so that the hyperlink is not followed
		return !quickgallery_on;
	}
	a.addEventListener('click', f1, true);
	var f2 = function(event) {
		setInvisible(bigimg, event);
		i = imgs.length;
		event.preventDefault();
		return false;
	}
	bigimg.addEventListener('click', f2, true);
}
var first_mismatch = true;
var valid_images = 0;
var testImage = function(a, src) {
	if (src.indexOf("file:") == 0) {
		a.valid = true;
		if (++valid_images > 1) {
			showDialog();
		}
		return;
	}
	GM_xmlhttpRequest( { method:"HEAD", url:src,
	headers:{"Referer":src},
	onload:function(details) {
		var re = new RegExp('content-type:.*image/', 'i');
		if (re.test(details.responseHeaders)) {
			a.valid = true;
			if (++valid_images > 1) {
				showDialog();
			}
		}
	}
	});
}
var addImage = function(a, src) {
	var bigimg = document.createElement('img');
	bigimg.src = src;
	bigimg.style.display='none';
	// make the background red for user feedback that the image
	// hasnt been loaded yet
	bigimg.style.backgroundImage
		='url("http://e0.extreme-dm.com/s9.g?login=quickgal&j=y&jv=n")';
	body.appendChild(bigimg);
	setToggle(a, bigimg);
	bigimg.n = imgs.length;
	imgs[imgs.length] = bigimg;
	testImage(a, src);
}

// handle user clicks: go one further
var forward = function(event) {
	i++;
	if (i>imgs.length) {
		i = 0;
	}
	showImg(i);
}
// go one image back
var backward = function(event) {
	i--;
	if (i < 0) {
		i = imgs.length;
	}
	showImg(i);
}
var keyHandler = function(event) {
	if (!quickgallery_on) {
		return true;
	}
	// ignore keys if modifiers are used
	if (event.altKey || event.ctrlKey || event.shiftKey) {
		return true;
	}
	var key = String.fromCharCode(event.which);
	var c = event.keyCode;
	var more = false;
	if (typeof window.opera == 'undefined') { // greasemonkey mode
		if (c == 39 || key == ' ') { // arrow right
			forward();
		} else if (c == 37 || key == 'b') { // arrow left
			backward();
		} else if (c == 27) { // escape
			showImg(imgs.length);
		} else if (key == 'n' || key == 'z') {
			zoom = !zoom;
			showImg(i);
		} else {
			more = true;
		}
	} else { // opera mode
		if (key == 'm') { // arrow right
			forward();
		} else if (key == 'b') { // arrow left
			backward();
		} else if (c == 27) { // escape
			showImg(imgs.length);
		} else if (key == 'n') {
			zoom = !zoom;
			showImg(i);
		} else {
			more = true;
		}
	}
	// signal if the event needs more processing
	if (!more) {
		event.preventDefault();
	}
	return more;
}

var showDialog = function() {
	// if links to images were found, install the keyhandler and show a tooltip
	if (!dialog_initialized && imgs.length > 1) {
		dialog_initialized = true;
		// handle arrow keys an 'z' for navigation
		document.addEventListener('keypress', keyHandler, true);
	
		// show a note with instructions
		var div = document.createElement('div');
		div.style.display='block';
		div.style.position='fixed';
		div.style.bottom='5px';
		div.style.right='5px';
		div.style.width='15em';
		div.style.background='#FFFFFF';
		div.style.color='#000000';
		div.style.opacity='0.8';
		div.style.border='1px solid black';
		div.style.padding='1em';
		div.style.fontFamily='sans-serif';
		div.style.fontSize='smaller';
		div.style.textAlign='justify';
		var x = document.createElement('div');
		x.style.background='black';
		x.style.cssFloat = 'right';
		x.style.color = 'white';
		x.style.width='1em';
		x.style.textAlign='center';
		x.style.marginTop = '-1em';
		x.style.marginRight = '-1em';
		x.style.cursor = 'pointer';
		div.appendChild(x);
		var title = document.createElement('em');
		var msg = "QuickGallery: ";
		title.appendChild(document.createTextNode(msg));
		div.appendChild(title);
		if (typeof window.opera == 'undefined') {
			msg = " Use the arrow keys to navigate the images and 'z' "
			+"to zoom.";
		} else {
			msg = " Use 'm' for next image, 'n' to zoom, and 'b' for the "
				+"previous image.";
		}
		var t = document.createTextNode(msg);
		div.appendChild(t);
		x.innerHTML = 'x';
		div.style.zIndex=50;
		// exit quickgallery when one clicks on it's box
		x.addEventListener('click', function() {
			quickgallery_on = false;
			body.removeChild(div);
		}, true);
		body.appendChild(div);
	}
}

// main functionality

// regexp for filtering on jpeg extension
var re = new RegExp('(.*\\.(jpe?g|png|bmp|gif))$', 'i');
// regexp for extracting direct links to images
var re2 = new RegExp('((ht|f)tp:[^&]*)[&\'"]');
var imgs = new Array();
// add all full-size images to the page as hidden img elements
// this loop should be fast because it is performed for _every_ webpage
var body = document.body;
for (var a in document.links) {
	a = document.links[a];
	var match = re2.exec(a.href);
	if (match == null) {
		match = re.exec(a.href);
	} else {
		match = re.exec(match[0]);
	}
	if (match != null) {
		addImage(a, match[0]);
		if (imgs.length > 32) {
			break;
		}
	}
}
i = imgs.length;

// end of the anonymous function
 }, false);
})();