// // 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) { var options = { 'minWidth' : 300}; 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); } 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: "/gnuMims/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); }