//
// Lightbox version 3.0.0
// by Lokesh Dhakar - http://www.huddletogether.com
// 04/03/2008
//
// For more information on this script, visit:
// http://huddletogether.com/projects/lightbox2/
//
// Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
//
// Credit also due to those who have helped, inspired, and made their code available to the public.
// Including: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.org), Thomas Fuchs(mir.aculo.us), and others.
//
/*
Table of Contents
-----------------
Extending Built-in Objects
- Object.extend(Element)
- Array.prototype.removeDuplicates()
Lightbox Class Declaration
- block()
- onload()
- updateImageList()
Miscellaneous Functions
- getPageScroll()
- getPageSize()
- showSelectBoxes()
- hideSelectBoxes()
- showObjects()
- hideObjects()
- pause()
*/
// Additional methods for Element added by SU, Couloir
// - further additions by Lokesh Dhakar (huddletogether.com)
Object.extend(Element, {
setWidth: function (element, width) {
$(element).style.width = width + "px";
},
setHeight: function (element, height) {
$(element).style.height = height + "px";
},
setTop: function (element, top) {
$(element).style.top = top + "px";
},
setLeft: function (element, left) {
$(element).style.left = left + "px";
},
setSrc: function (element, src) {
$(element).src = src;
},
setInnerHTML: function (element, content) {
$(element).innerHTML = content;
}
});
// Extending built-in Array object
// - array.removeDuplicates()
Array.prototype.removeDuplicates = function () {
for (i = 1; i < this.length; i++) {
if (this[i][0] == this[i - 1][0]) { this.splice(i, 1); }
}
}
// Lightbox Class Declaration
// - block()
// - onload()
// - updateImageList()
// Structuring of code inspired by Scott Upton (http://www.uptonic.com/)
var Lightbox = {
onload: function (event) {
// preload image.
loadingImage = new Image();
loadingImage.src = Lightbox._imagePath + "loading.gif";
var options = { 'minWidth' : 650};
return Lightbox._create(options);
},
// Fades to overlay and runs an animated loading gif (e.g after form submit)
loading: function(options) {
if (!document.getElementsByTagName) { return true; }
Lightbox._options(options);
var buttons = document.getElementsByClassName("buttons");
buttons[0].style.visibility = "hidden";
var parent = document.getElementsByTagName("body").item(0);
var overlay = Lightbox._createElement("div", "overlay", "none", null, null, function (event) {} );
parent.appendChild(overlay);
var pageSize = getPageSize();
Element.setWidth('overlay', pageSize[0]);
Element.setHeight('overlay', pageSize[1]);
if (Lightbox._animate) {
new Effect.Appear('overlay', { duration: Lightbox._overlayBlockDuration, from: 0.0, to: Lightbox._blockOpacity });
}
else {
Element.setOpacity('overlay', Lightbox._opacity);
}
if (Lightbox._animate) {
var loading = Lightbox._createElement("div", 'loading');
parent.appendChild(loading);
// document.all should be detected in IE and Opera, workaround for IE gif freezing.
if(document.all) {
new Effect.Pulsate(loading, { pulses: 800, duration: 532 });
}
else {
Element.show('loading');
}
}
},
// Blocks the page (after form submit)
block: function(message, options) {
if (!document.getElementsByTagName) { return true; }
Lightbox._options(options);
var parent = document.getElementsByTagName("body").item(0);
var overlay = Lightbox._createElement("div", "overlay", "none", null, null, function (event) {} );
parent.appendChild(overlay);
// The rest of this code inserts html at the bottom of the page that looks similar to this:
//
//
var lightbox = Lightbox._createElement("div", "lightbox", "none");
parent.appendChild(lightbox);
var outerImageContainer = Lightbox._createElement("div", "outerImageContainer");
lightbox.appendChild(outerImageContainer);
var imageContainer = Lightbox._createElement("div", 'imageContainer');
outerImageContainer.appendChild(imageContainer);
imageContainer.appendChild(Lightbox._createElement("div", 'loading'));
imageDataContainer = Lightbox._createElement("div", 'imageDataContainer');
imageContainer.appendChild(imageDataContainer);
imageDataContainer.appendChild(document.createTextNode(message));
hideSelectBoxes();
hideObjects();
var pageSize = getPageSize();
Element.setWidth('overlay', pageSize[0]);
Element.setHeight('overlay', pageSize[1]);
Element.setOpacity('overlay', Lightbox._blockOpacity);
Element.show('overlay');
Element.setTop('lightbox', Number(getPageScroll()[1] + (getPageSize()[3] / 15)).toFixed());
Element.show('lightbox');
Element.show('loading');
return true;
},
// Loops through anchor tags looking for 'lightbox' references and applies onclick
// events to appropriate links. You can rerun after dynamically adding images w/ajax.
updateImageList: function () {
if (!document.getElementsByTagName) { return; }
// loop through all anchor tags
var anchors = document.getElementsByTagName('a');
for (var i = 0, l = anchors.length; i < l; i++) {
var anchor = anchors[i];
// use the string.match() method to catch 'lightbox' references in the rel attribute
var relAttribute = String(anchor.getAttribute('rel'));
if (anchor.getAttribute('href') && (relAttribute.toLowerCase().match('lightbox'))) {
anchor.onclick = function () { return Lightbox._start(this); };
}
}
// loop through all area tags
// todo: combine anchor & area tag loops
var areas = document.getElementsByTagName('area');
for (var i = 0, l = areas.length; i < l; i++) {
var area = areas[i];
// use the string.match() method to catch 'lightbox' references in the rel attribute
var relAttribute = String(area.getAttribute('rel'));
if (area.getAttribute('href') && (relAttribute.toLowerCase().match('lightbox'))) {
Area.onclick = function () { return Lightbox.start(this); }
}
}
},
// Loops through anchor tags looking for 'lightbox' references and applies onclick events
// to appropriate links. The 2nd section of the function inserts html at the bottom of the
// page which is used to display the shadow overlay and the image container.
_create: function(options) {
if (!document.getElementsByTagName) return;
Lightbox._options(options);
var parent = document.getElementsByTagName("body").item(0);
var overlay = Lightbox._createElement("div", "overlay", "none", null, null, Lightbox._overlayEnd);
parent.appendChild(overlay);
Lightbox.updateImageList();
// The rest of this code inserts html at the bottom of the page that looks similar to this:
//
//
//
//
//
//
//
//
//
//
//
var lightbox = Lightbox._createElement("div", "lightbox", "none", null, null, Lightbox._overlayEnd);
parent.appendChild(lightbox);
var outerImageContainer = Lightbox._createElement("div", "outerImageContainer");
lightbox.appendChild(outerImageContainer);
// When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
// If animations are turned off, it will be hidden as to prevent a flicker of a
// white 250 by 250 box.
if (Lightbox._animate) {
Element.setWidth('outerImageContainer', 250);
Element.setHeight('outerImageContainer', 250);
}
else {
Element.setWidth('outerImageContainer', 1);
Element.setHeight('outerImageContainer', 1);
}
var imageContainer = Lightbox._createElement("div", 'imageContainer');
outerImageContainer.appendChild(imageContainer);
imageContainer.appendChild(Lightbox._createElement("img", 'lightboxImage'));
var hoverNav = Lightbox._createElement("div", 'hoverNav');
imageContainer.appendChild(hoverNav);
hoverNav.appendChild(Lightbox._createElement("a", 'prevLink', null, null, '#'));
hoverNav.appendChild(Lightbox._createElement("a", 'nextLink', null, null, '#'));
imageContainer.appendChild(Lightbox._createElement("div", 'loading', null, null, null, Lightbox._end));
imageDataContainer = Lightbox._createElement("div", 'imageDataContainer');
lightbox.appendChild(imageDataContainer);
imageData = Lightbox._createElement("div", 'imageData');
imageDataContainer.appendChild(imageData);
var imageDetails = Lightbox._createElement("div", 'imageDetails');
imageData.appendChild(imageDetails);
imageDetails.appendChild(Lightbox._createElement("span", 'caption'));
imageDetails.appendChild(Lightbox._createElement("span", 'numberDisplay'));
bottomNav = Lightbox._createElement("div", 'bottomNav');
imageData.appendChild(bottomNav);
bottomNav.appendChild(Lightbox._createElement("img", 'bottomNavPrev', null, Lightbox._imagePath + "miniprev.jpg", null, Lightbox._prevImage));
bottomNav.appendChild(Lightbox._createElement("img", 'bottomNavNext', null, Lightbox._imagePath + "mininext.jpg", null, Lightbox._nextImage));
bottomNav.appendChild(Lightbox._createElement("img", 'bottomNavClose', null, Lightbox._imagePath + "closelabel.gif", null, Lightbox._end));
},
_createElement: function (type, id, display, src, href, onclick) {
elem = document.createElement(type);
if (id) { elem.setAttribute('id', id); }
if (display) { elem.style.display = display; }
if (src) { elem.setAttribute('src', src); }
if (href) { elem.setAttribute('href', href); }
if (onclick) { elem.onclick = onclick; }
return elem;
},
_options: function(options) {
if (options) {
var option = options['borderSize'];
if (option) { Lightbox._borderSize = option; }
option = options['overlayDuration'];
if (option) { Lightbox._overlayDuration = option; }
option = options['resizeDuration'];
if (option) { Lightbox._resizeDuration = option; }
option = options['minWidth'];
if (option) { Lightbox._minWidth = option; }
option = options['imagePath'];
if (option) { Lightbox._imagePath = option; }
option = options['opacity'];
if (option) { Lightbox._opacity = option; }
option = options['blockOpacity'];
if (option) { Lightbox._blockOpacity = option; }
option = options['animate'];
if (option) { Lightbox._animate = option; }
option = options['text'];
if (option) { Lightbox._text = option; }
}
},
// Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
_start: function (imageLink) {
hideSelectBoxes();
hideObjects();
// stretch overlay to fill page and fade in
var pageSize = getPageSize();
Element.setWidth('overlay', pageSize[0]);
Element.setHeight('overlay', pageSize[1]);
if (Lightbox._animate) {
new Effect.Appear('overlay', { duration: Lightbox._overlayDuration, from: 0.0, to: Lightbox._opacity });
}
else {
Element.setOpacity('overlay', Lightbox._opacity);
}
Lightbox._activeImage = 0;
Lightbox._imageArray = [];
var imageNum = 0;
if ((imageLink.getAttribute('rel') == 'lightbox')) { // if image is NOT part of a set..
Lightbox._imageArray.push(new Array(imageLink.getAttribute('href'), imageLink.getAttribute('title')));
}
else { // if image is part of a set..
// loop through anchors, find other images in set, and add them to imageArray
var rel = imageLink.getAttribute('rel');
var anchors = document.getElementsByTagName(imageLink.tagName);
for (var i = 0, l = anchors.length; i < l; i++) {
var anchor = anchors[i];
if (anchor.getAttribute('href') && (anchor.getAttribute('rel') == rel)) {
Lightbox._imageArray.push(new Array(anchor.getAttribute('href'), anchor.getAttribute('title')));
}
}
Lightbox._imageArray.removeDuplicates();
var href = imageLink.getAttribute('href');
while (Lightbox._imageArray[imageNum][0] != href) { imageNum++; }
}
// calculate top offset for the lightbox and display
var pageScroll = getPageScroll();
Element.setTop('lightbox', Number(pageScroll[1] + (pageSize[3] / 10)).toFixed());
Element.setLeft('lightbox', Number(pageScroll[0]).toFixed());
Element.show('lightbox');
Lightbox._changeImage(imageNum);
return false;
},
_overlayEnd: function (event) {
if (!event) { event = window.event; }
var id = Event.element(event).id;
if (id == 'overlay' || id == 'lightbox') { return Lightbox._end(); }
return true;
},
_end: function (event) {
Lightbox._disableKeyboardNav();
Element.hide('lightbox');
if (Lightbox._animate) {
new Effect.Fade('overlay', { duration: Lightbox._overlayDuration });
}
else {
Element.hide('overlay');
}
showSelectBoxes();
showObjects();
return false;
},
_hasNext: function () {
return Lightbox._activeImage < (Lightbox._imageArray.length - 1);
},
_nextImage: function () {
Lightbox._changeImage(Lightbox._activeImage + 1);
return false;
},
_hasPrev: function () {
return Lightbox._activeImage > 0;
},
_prevImage: function () {
Lightbox._changeImage(Lightbox._activeImage - 1);
return false;
},
// Hide most elements and preload image in preparation for resizing image container.
_changeImage: function (imageNum) {
Lightbox._activeImage = imageNum;
// hide elements during transition
if (Lightbox._animate) { Element.show('loading'); }
Element.hide('lightboxImage');
Element.hide('hoverNav');
Element.hide('prevLink');
Element.hide('nextLink');
Element.hide('bottomNavPrev');
Element.hide('bottomNavNext');
Element.hide('imageDataContainer');
Element.hide('caption');
Element.hide('numberDisplay');
// once image is preloaded, resize image container
Lightbox._preloader = new Image();
Lightbox._preloader.onload = function () {
Element.setSrc('lightboxImage', Lightbox._imageArray[imageNum][0]);
Lightbox._preloader.onload = function () { }; // clear onLoad, IE behaves irratically with animated gifs otherwise
Lightbox._resizeImageContainer(Lightbox._preloader.width, Lightbox._preloader.height);
};
Lightbox._preloader.src = Lightbox._imageArray[imageNum][0];
},
_resizeImageContainer: function (imgWidth, imgHeight) {
var borders = Lightbox._borderSize * 2;
// keep to a minimum width, if specified
if (Lightbox._minWidth > 0 && (imgWidth + borders) < Lightbox._minWidth) {
imgWidth = Lightbox._minWidth - borders;
}
// get current height and width
var widthCurrent = Element.getWidth('outerImageContainer');
var heightCurrent = Element.getHeight('outerImageContainer');
// get new width and height
var widthNew = imgWidth + borders;
var heightNew = imgHeight + borders;
// scalars based on change from old to new
var xScale = (widthNew / widthCurrent) * 100;
var yScale = (heightNew / heightCurrent) * 100;
// calculate size difference between new and old image, and resize if necessary
var widthDiff = widthCurrent - widthNew;
var heightDiff = heightCurrent - heightNew;
if (heightDiff != 0) {
new Effect.Scale('outerImageContainer', yScale, { scaleX: false, duration: Lightbox._resizeDuration, queue: 'front' });
}
if (widthDiff != 0) {
new Effect.Scale('outerImageContainer', xScale, { scaleY: false, duration: Lightbox._resizeDuration, delay: Lightbox._resizeDuration });
}
// if new and old image are same size and no scaling transition is necessary,
// do a quick pause to prevent image flicker.
if ((heightDiff == 0) && (widthDiff == 0)) {
if (navigator.appVersion.indexOf("MSIE") != -1) { pause(250); } else { pause(100); }
}
Element.setHeight('prevLink', imgHeight);
Element.setHeight('nextLink', imgHeight);
Element.setWidth('imageDataContainer', widthNew);
Lightbox._showImage();
},
// Display image.
_showImage: function () {
Element.hide('loading');
new Effect.Appear('lightboxImage', { duration: Lightbox._resizeDuration, queue: 'end', afterFinish: Lightbox._updateDetails });
Lightbox._preloadNeighborImages();
},
// Display caption, image number, and bottom nav.
_updateDetails: function () {
// if caption is not null
var caption = Lightbox._imageArray[Lightbox._activeImage][1];
if (caption) {
Element.show('caption');
Element.setInnerHTML('caption', caption);
}
// if image is part of set display 'Image x of x'
if (Lightbox._imageArray.length > 1) {
Element.show('numberDisplay');
var text = Lightbox._text.replace("*", (Lightbox._activeImage + 1));
text = text.replace("*", Lightbox._imageArray.length);
Element.setInnerHTML('numberDisplay', text);
}
if (Lightbox._hasPrev()) { Element.show('bottomNavPrev'); }
if (Lightbox._hasNext()) { Element.show('bottomNavNext'); }
new Effect.Parallel(
[ new Effect.SlideDown('imageDataContainer', { sync: true, duration: Lightbox._resizeDuration }),
new Effect.Appear('imageDataContainer', { sync: true, duration: Lightbox._resizeDuration }) ],
{ duration: Lightbox._resizeDuration, afterFinish: Lightbox._updateNav });
},
// Display appropriate previous and next hover navigation.
_updateNav: function () {
$('imageDataContainer').style.overflow = 'auto'; // css float fix
Element.setHeight('overlay', getPageSize()[1]);
Element.show('hoverNav');
// if not first image in set, display prev image button
if (Lightbox._hasPrev()) {
document.getElementById('prevLink').onclick = Lightbox._prevImage;
Element.show('prevLink');
}
// if not last image in set, display next image button
if (Lightbox._hasNext()) {
document.getElementById('nextLink').onclick = Lightbox._nextImage;
Element.show('nextLink');
}
Lightbox._enableKeyboardNav();
},
_enableKeyboardNav: function () {
document.onkeydown = Lightbox._keyboardAction;
},
_disableKeyboardNav: function () {
document.onkeydown = '';
},
_keyboardAction: function (evnt) {
var keycode = 0, escapeKey = 0, key = 0;
if (evnt == null) { // ie
keycode = event.keyCode;
escapeKey = 27;
}
else { // mozilla
keycode = evnt.keyCode;
escapeKey = evnt.DOM_VK_ESCAPE;
}
key = String.fromCharCode(keycode).toLowerCase();
if ((key == 'x') || (key == 'o') || (key == 'c') || (keycode == escapeKey)) { // close lightbox
Lightbox._end();
return true;
}
else if((key == 'p') || (keycode == 37)) { // display previous image
if (Lightbox._hasPrev()) {
Lightbox._disableKeyboardNav();
Lightbox._prevImage();
return true;
}
}
else if((key == 'n') || (keycode == 39)) { // display next image
if (Lightbox._hasNext()) {
Lightbox._disableKeyboardNav();
Lightbox._nextImage();
return true;
}
}
return false;
},
_preloadNeighborImages: function () {
if (Lightbox._hasNext()) {
Lightbox._preloadNextImage = new Image();
Lightbox._preloadNextImage.src = Lightbox._imageArray[Lightbox._activeImage + 1][0];
}
if (Lightbox._hasPrev()) {
Lightbox._preloadPrevImage = new Image();
Lightbox._preloadPrevImage.src = Lightbox._imageArray[Lightbox._activeImage - 1][0];
}
},
_borderSize: 10,
_overlayDuration: 0.2,
_overlayBlockDuration: 0.6,
_resizeDuration: 0.4,
_minWidth: 0,
_imagePath: '/' + location.pathname.split('/',2)[1] + '/images/',
_opacity: 0.6,
_blockOpacity: 0.1,
_animate: true,
_text: "Image * of *",
_activeImage: 0,
_imageArray: []
}
// Returns array with x, y page scroll values.
// Core code from - quirksmode.org
function getPageScroll(){
var xScroll = 0, yScroll = 0;
if (self.pageYOffset) {
xScroll = self.pageXOffset;
yScroll = self.pageYOffset;
}
else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
xScroll = document.documentElement.scrollLeft;
yScroll = document.documentElement.scrollTop;
}
else if (document.body) { // all other Explorers
xScroll = document.body.scrollLeft;
yScroll = document.body.scrollTop;
}
return new Array(xScroll, yScroll)
}
// Returns array with page width, height and window width, height
// Core code from - quirksmode.org
// Edit for Firefox by pHaez
function getPageSize() {
var xScroll = 0, yScroll = 0;
var docBody = document.body;
var docElem = document.documentElement;
if (window.innerHeight && window.scrollMaxY) {
xScroll = window.innerWidth + window.scrollMaxX;
yScroll = window.innerHeight + window.scrollMaxY;
}
else if (docBody.scrollHeight > docBody.offsetHeight) { // all but Explorer Mac
xScroll = docBody.scrollWidth;
yScroll = docBody.scrollHeight;
}
else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
xScroll = docBody.offsetWidth;
yScroll = docBody.offsetHeight;
}
var windowWidth = 0, windowHeight = 0, pageHeight = 0, pageWidth = 0;
if (self.innerHeight) { // all except Explorer
if(docElem.clientWidth) {
windowWidth = docElem.clientWidth;
}
else {
windowWidth = self.innerWidth;
}
windowHeight = self.innerHeight;
}
else if (docElem && docElem.clientHeight) { // Explorer 6 Strict Mode
windowWidth = docElem.clientWidth;
windowHeight = docElem.clientHeight;
}
else { // other Explorers
windowWidth = docBody.clientWidth;
windowHeight = docBody.clientHeight;
}
// for small pages with total height less then height of the viewport
if (yScroll < windowHeight) {
pageHeight = windowHeight;
}
else {
pageHeight = yScroll;
}
// for small pages with total width less then width of the viewport
if (xScroll < windowWidth) {
pageWidth = xScroll;
}
else {
pageWidth = windowWidth;
}
return new Array(pageWidth, pageHeight, windowWidth, windowHeight)
}
function showSelectBoxes() {
var selects = document.getElementsByTagName("select");
for (var i = 0, l = selects.length; i < l; i++) {
selects[i].style.visibility = "visible";
}
}
function hideSelectBoxes() {
var selects = document.getElementsByTagName("select");
for (var i = 0, l = selects.length; i < l; i++) {
selects[i].style.visibility = "hidden";
}
}
function showObjects() {
var objects = document.getElementsByTagName("object");
for (var i = 0, l = objects.length; i < l; i++) {
objects[i].style.visibility = "visible";
}
var embeds = document.getElementsByTagName("embed");
for (var i = 0, l = embeds.length; i < l; i++) {
embeds[i].style.visibility = "visible";
}
}
function hideObjects() {
var objects = document.getElementsByTagName("object");
for (var i = 0, l = objects.length; i < l; i++) {
objects[i].style.visibility = "hidden";
}
var embeds = document.getElementsByTagName("embed");
for (var i = 0, l = embeds.length; i < l; i++) {
embeds[i].style.visibility = "hidden";
}
}
// pause(numberMillis)
// Pauses code execution for specified time. Uses busy code, not good.
// Code from http://www.faqts.com/knowledge_base/view.phtml/aid/1602
// Help from Ran Bar-On [ran2103@gmail.com]
function pause(ms) {
var date = new Date();
var curDate = null;
do {
curDate = new Date();
} while (curDate - date < ms);
}