/* * jQuery Lightbox Plugin (balupton edition) * * Based upon / Inspired by / Credits to: * - Warren Krewenki's jQuery Lightbox Plugin v0.5 {@link http://jquery-lightbox.googlecode.com/} * - Leandro Vieira Pinho's jQuery Lightbox Plugin v0.4 {@link http://leandrovieira.com/projects/jquery/lightbox/} * - Lokesh Dhakar's Lightbox 2 {@link http://www.huddletogether.com/projects/lightbox2/} * * @name jquerylightbox_bal: jquery.lightbox.js * @author Benjamin "balupton" Lupton {@link http://www.balupton.com} * @version 0.2.0-beta * @date December 04, 2007 * @category jQuery plugin * @copyright (c) 2007 Benjamin "balupton" Lupton {@link http://www.balupton.com} * @license Attribution-Share Alike 2.5 Australia - {@link http://creativecommons.org/licenses/by-sa/2.5/au/} * @example Visit {@link http://jquery.com/plugins/project/jquerylightbox_bal} for more information. */ // Start of our jQuery Plugin (function($) { // Create our Plugin function, with $ as the argument (we pass the jQuery object over later) // More info: http://docs.jquery.com/Plugins/Authoring#Custom_Alias // Declare our class $.LightboxClass = function ( ) { // This is the handler for our constructor this.construct(); } // Extend jQuery elements for Lightbox $.fn.lightbox = function ( options ) { // Init a el for Lightbox // Eg. $('#gallery a').lightbox(); // If need be: Instantiate $.LightboxClass to $.Lightbox $.Lightbox = $.Lightbox || new $.LightboxClass(); // Establish options options = $.extend({start:false,events:true}, options); // Get group var group = $(this); // Events? if ( options.events ) { // Add events $(group).click(function(){ // Get obj var obj = $(this); // Get rel var rel = $(obj).attr('rel'); // Init group if ( !$.Lightbox.init($(obj)[0], group) ) return false; // Display lightbox if ( !$.Lightbox.start() ) return false; // Cancel href return false; }); } // Start? if ( options.start ) { // Start // Get obj var obj = $(this); // Get rel var rel = $(obj).attr('rel'); // Init group if ( !$.Lightbox.init($(obj)[0], group) ) return this; // Display lightbox if ( !$.Lightbox.start() ) return this; } // And chain return this; } // Define our class $.extend($.LightboxClass.prototype, { // Our LightboxClass definition // ----------------- // Everyting to do with images images: { // ----------------- // Variables // Our array of images list:[], /* [ { src: 'url to image', link: 'a link to a page', title: 'title of the image', description: 'description of the image' } ], */ // The current active image image: false, // ----------------- // Functions prev: function ( image ) { // Get previous image // Get previous from current? if ( typeof image == 'undefined' ) { image = this.active(); if ( !image ) return image; } // Is there a previous? if ( this.first(image) ) return false; // Get the previous return this.get(image.index-1); }, next: function ( image ) { // Get next image // Get next from current? if ( typeof image == 'undefined' ) { image = this.active(); if ( !image ) return image; } // Is there a next? if ( this.last(image) ) return false; // Get the next return this.get(image.index+1); }, first: function ( image ) { // // Get the first image? if ( typeof image == 'undefined' ) { return this.get(0); } // Are we the first? return image.index == 0; }, last: function ( image ) { // // Get the last image? if ( typeof image == 'undefined' ) { return this.get(this.size()-1); } // Are we the last? return image.index == this.size()-1; }, single: function ( ) { // Are we only one return this.size() == 1; }, size: function ( ) { // How many images do we have return this.list.length; }, empty: function ( ) { // Are we empty return this.size() == 0; }, clear: function ( ) { // Clear image arrray this.list = []; this.image = false; }, active: function ( image ) { // Set or get the active image // Get the active image? if ( typeof image == 'undefined' ) { return this.image; } // Set the ative image // Make sure image exists image = this.get(image); if ( !image ) return image; // Make it the active this.image = image; // Done return true; }, add: function ( obj ) { // Do we need to recurse? if ( obj[0] ) { // We have a lot of images for ( var i = 0; i < obj.length; i++ ) { this.add(obj[i]); } return true; } // Default image // Try and create a image var image = this.create(obj); if ( !image ) return image; // Set image index image.index = this.size(); // Push image this.list.push(image); // Success return true; }, create: function ( obj ) { // Create image // Define var image = { // default src: '', title: 'Untitled', description: '', index: -1, image: true }; // Create if ( obj.image ) { // Already a image, so copy over values image.src = obj.src || image.src; image.title = obj.title || image.title; image.description = obj.description || image.description; image.index = obj.index || image.index; } else if ( obj.tagName ) { // We are an element obj = $(obj); if (obj.attr('src') || obj.attr('href') ) { image.src = obj.attr('src') || obj.attr('href'); image.title = obj.attr('title') || obj.attr('alt') || image.title; // Extract description from title var s = image.title.indexOf(': '); if ( s > 0 ) { // Description exists image.description = image.title.substring(s+2) || image.description; image.title = image.title.substring(0,s) || image.title; } } else { // Unsupported element image = false; } } else { // Unknown image = false; } if ( !image ) { // Error this.debug('We dont know what we have:', obj); return false; } // Success return image; }, get: function ( image ) { // Get the active, or specified image // Establish image if ( image == undefined || image == NaN || image == null ) { // Get the active image return this.active(); } else if ( (typeof image) == 'number' ) { // We have a index // Get image image = this.list[image] || false; } else { // Create image = this.create(image); if ( !image ) return false; // Find var f = false; for ( var i = 0; i < this.size(); i++ ) { var c = this.list[i]; if ( c.src == image.src ) f = c; } // Found? image = f; } // Determine image if ( !image ) { // Image doesn't exist this.debug('The desired image doesn\'t exist: ', image, this.list); return false; } // Return image return image; }, debug: function ( ) { if ( typeof console != 'undefined' ) console.log(arguments); else if (typeof window.console != 'undefined' && typeof window.console.log != 'undefined') window.console.log(arguments); } }, // ----------------- // Locations baseurl: '', files: { js: { lightbox: 'js/jquery.lightbox.js' }, css: { lightbox: 'css/jquery.lightbox.css' }, images: { prev: 'images/prev.gif', next: 'images/next.gif', close: 'images/close.gif', blank: 'images/blank.gif', loading: 'images/loading.gif' } }, text: { image: 'Image', of: 'of', close: 'Close X', closeInfo: 'You can also click anywhere outside the image to close' }, keys: { close: 'c', prev: 'p', next: 'n' }, opacity: 0.9, padding: 1, // autodetected speed: 400, // Duration of effect, milliseconds rel: 'lightbox', // What to look for in the rels // ----------------- // Functions construct: function( ) { // Construct our Lightbox // Set baseurl this.baseurl = $('script[src$='+this.files.js.lightbox+']').attr('src'); this.baseurl = this.baseurl.substring(0, this.baseurl.length-this.files.js.lightbox.length); // Apply baseurl to files - redundant i know, please find a better way this.files.js.lightbox = this.baseurl+this.files.js.lightbox; this.files.css.lightbox = this.baseurl+this.files.css.lightbox; this.files.images.prev = this.baseurl+this.files.images.prev; this.files.images.next = this.baseurl+this.files.images.next; this.files.images.close = this.baseurl+this.files.images.close; this.files.images.blank = this.baseurl+this.files.images.blank; // All good return true; }, domReady: function ( ) { // ------------------- // Append display // Append markup $('body').append('
'); // Include stylesheet $('head').append(''); // Hide $('#lightbox,#lightbox-overlay').hide(); // ------------------- // Apply events // If the window resizes, act appropriatly $(window).resize(function () { $.Lightbox.resizeBoxes(); }); // Prev $('#lightbox-nav-btnPrev').hover(function() { // over $(this).css({ 'background' : 'url(' + $.Lightbox.files.images.prev + ') left 45% no-repeat' }); },function() { // out $(this).css({ 'background' : 'transparent url(' + $.Lightbox.files.images.blank + ') no-repeat' }); }).click(function() { $.Lightbox.showImage($.Lightbox.images.prev()); return false; }); // Next $('#lightbox-nav-btnNext').hover(function() { // over $(this).css({ 'background' : 'url(' + $.Lightbox.files.images.next + ') right 45% no-repeat' }); },function() { // out $(this).css({ 'background' : 'transparent url(' + $.Lightbox.files.images.blank + ') no-repeat' }); }).click(function() { $.Lightbox.showImage($.Lightbox.images.next()); return false; }); // Relify $.Lightbox.relify(); // All good return true; }, relify: function ( ) { // Create event // var groups = {}; var groups_n = 0; var orig_rel = this.rel; // Create the groups $.each($('[@rel*='+orig_rel+']'), function(index, obj){ // Get the group var rel = $(obj).attr('rel'); // Are we really a group if ( rel == orig_rel ) { // We aren't rel = groups_n; // we are individual } // Does the group exist if ( typeof groups[rel] == 'undefined' ) { // Make the group groups[rel] = []; groups_n++; } // Append the image groups[rel].push(obj); }); // Lightbox groups $.each(groups, function(index, group){ $(group).lightbox(); }); // Done return true; }, init: function ( image /*int*/, images /*[]*/ ) { // Init a batch of lightboxes // Establish images if ( typeof images == 'undefined' ) { images = image; image = 0; } // Clear this.images.clear(); // Add images if ( !this.images.add(images) ) return false; // Do we need to bother if ( this.images.empty() ) { // No images this.debug('Lightbox started, but no images: ', image, images); return false; } // Set active if ( !this.images.active(image) ) return false; // Done return true; }, start: function ( ) { // Display the lightbox // Get container border this.padding = parseInt($('#lightbox-imageContainer').css('padding-left')); // Fix attention seekers $('embed, object, select').css({ 'visibility' : 'hidden' });//.hide(); - don't use this, give it a go, find out why! // Resize the boxes appropriatly this.resizeBoxes(); // Hide things $('#lightbox-infoFooter').hide(); // we hide this here because it makes the display smoother // Display the boxes $('#lightbox-overlay').css({ opacity: this.opacity }).fadeIn(); $('#lightbox').show(); // Assign close clicks $('#lightbox-overlay, #lightbox, #lightbox-loading-link, #lightbox-btnClose').click(function() { $.Lightbox.finish(); return false; }); // Display first image if ( !this.showImage(this.images.active()) ) { this.finish(); return false; } // All done return true; }, finish: function ( ) { // Get rid of lightbox $('#lightbox').hide(); $('#lightbox-overlay').fadeOut(function() { $('#lightbox-overlay').hide(); }); // Fix attention seekers $('embed, object, select').css({ 'visibility' : 'visible' });//.show(); }, resizeBoxes: function ( ) { // Get the page size var pageSize = this.getPageSize(); // Get page scroll var pageScroll = this.getPageScroll(); // Style overlay and show it $('#lightbox-overlay').css({ width: pageSize.pageWidth, height: pageSize.pageHeight }); // Display lightbox in center $('#lightbox').css({ top: pageScroll.yScroll + (pageSize.windowWidth / 10), left: pageScroll.xScroll }); }, showImage: function ( image, options ) { // Establish image image = this.images.get(image); if ( !image ) return image; // Establish options options = $.extend({step:1}, options); if ( (options.step > 1 && this.images.active().src != image.src) || (options.step > 2 && $('#lightbox-image').attr('src') != image.src) ){ // Force step 1 this.debug('We wanted to skip a few steps: ', options, image); options.step = 1; } // What do we need to do switch ( options.step ) { // --------------------------------- // We need to preload case 1: // Disable keyboard nav this.KeyboardNav_Disable(); // Show the loading image $('#lightbox-loading').show(); // Hide things $('#lightbox-image,#lightbox-nav,#lightbox-nav-btnPrev,#lightbox-nav-btnNext,#lightbox-infoBox').hide(); // Remove show info events $('#lightbox-imageBox').unbind(); // Preload the image var preloader = new Image(); preloader.onload = function() { $.Lightbox.showImage(null, {step:2, width:preloader.width, height:preloader.height}); preloader.onload = null; preloader = null; } preloader.src = image.src; // Make active image if ( !this.images.active(image) ) return false; // Done break; // --------------------------------- // Resize the container case 2: // Set image src $('#lightbox-image').attr('src', image.src); // Establish options options = $.extend({width:null, height:null}, options); // Resize image box // i:image, c:current, n:new, d:difference // Get image dimensions var iWidth = options.width; var iHeight = options.height; // Get current width and height var cWidth = $('#lightbox-imageBox').width(); var cHeight = $('#lightbox-imageBox').height(); // Get the width and height of the selected image plus the padding var nWidth = (iWidth + (this.padding * 2)); // Plus the imageīs width and the left and right padding value var nHeight = (iHeight + (this.padding * 2)); // Plus the imageīs height and the left and right padding value // Diferences var dWidth = cWidth - nWidth; var dHeight = cHeight - nHeight; // Lets do this here because we can - NO because we know the heights here $('#lightbox-nav-btnPrev,#lightbox-nav-btnNext').css({ height: iHeight + (this.padding * 2) }); $('#lightbox-infoBox').css({ width: iWidth+this.padding*2 }); // Do we need to wait? if ( dWidth == 0 && dHeight == 0 ) { // We are the same size if ( $.browser.msie ) { this.pause(250); } else { this.pause(100); } $.Lightbox.showImage(null, {step:3}); } else { // We are not the same size // Animate $('#lightbox-imageBox').animate({ width: nWidth, height: nHeight }, this.speed, function ( ) { $.Lightbox.showImage(null, {step:3}); } ); } // Done break; // --------------------------------- // Display the image case 3: // Hide loading $('#lightbox-loading').hide(); // Animate image $('#lightbox-image').fadeIn('normal', function() {$.Lightbox.showImage(null, {step:4}); }); // Start the proloading of other images this.preloadNeighbours(); // Done break; // --------------------------------- // Set image info / Set navigation case 4: // --------------------------------- // Set image info // Hide and set image info $('#lightbox-caption-title').html(image.title + (image.description ? ': ' : '') || 'Untitled'); $('#lightbox-caption-description').html(image.description || ' '); // If we have a set, display image position if ( this.images.size() > 1 ) $('#lightbox-currentNumber').html(this.text.image + ' ' + ( image.index + 1 ) + ' ' + this.text.of + ' ' + this.images.size()); else $('#lightbox-currentNumber').html(' '); // Apply event $('#lightbox-imageBox').unbind('mouseover').mouseover(function(){ $('#lightbox-infoBox').slideDown('fast'); }); // Apply event $('#lightbox-infoBox').unbind('mouseover').mouseover(function(){ $('#lightbox-infoFooter').slideDown('fast'); }); // --------------------------------- // Set navigation // Instead to define this configuration in CSS file, we define here. And itīs need to IE. Just. $('#lightbox-nav-btnPrev, #lightbox-nav-btnNext').css({ 'background' : 'transparent url(' + this.files.images.blank + ') no-repeat' }); // If not first, show previous button if ( !this.images.first(image) ) { // Not first, show button $('#lightbox-nav-btnPrev').show(); } // If not last, show next button if ( !this.images.last(image) ) { // Not first, show button $('#lightbox-nav-btnNext').show(); } // Make navigation active / show it $('#lightbox-nav').show(); // Enable keyboard navigation this.KeyboardNav_Enable(); // Done break; // --------------------------------- // Error handling default: this.debug('Don\'t know what to do: ',options); return this.showImage(image, {step:1}); break; } // All done return true; }, preloadNeighbours: function ( ) { // Preload all neighbour images // Do we need to do this? if ( this.images.single() || this.images.empty() ) return true; // Get active image var image = this.images.active(); if ( !image ) return image; // Load previous var prev = this.images.prev(image); if ( prev ) { objNext = new Image(); objNext.src = prev.src; } // Load next var next = this.images.next(image); if ( next ) { objNext = new Image(); objNext.src = next.src; } }, // -------------------------------------------------- // Things we don't really care about debug: function ( ) { if ( typeof console != 'undefined' ) console.log(arguments); else if (typeof window.console != 'undefined' && typeof window.console.log != 'undefined') window.console.log(arguments); }, KeyboardNav_Enable: function ( ) { $(document).keydown(function(objEvent) { $.Lightbox.KeyboardNav_Action(objEvent); }); }, KeyboardNav_Disable: function ( ) { $(document).unbind(); }, KeyboardNav_Action: function ( objEvent ) { // Get the keycode if ( objEvent == null ) { // ie keycode = event.keyCode; escapeKey = 27; } else { // moz keycode = objEvent.keyCode; escapeKey = objEvent.DOM_VK_ESCAPE; } // Get key key = String.fromCharCode(keycode).toLowerCase(); // Close? if ( key == this.keys.close || keycode == escapeKey ) return $.Lightbox.finish(); // Prev? if ( key == this.keys.prev || keycode == 37 ) { // We want previous return $.Lightbox.showImage($.Lightbox.images.prev()); } // Next? if ( key == this.keys.next || keycode == 39 ) { // We want next return $.Lightbox.showImage($.Lightbox.images.next()); } // Unknown return true; }, getPageSize: function ( ) { var xScroll, yScroll; if (window.innerHeight && window.scrollMaxY) { xScroll = window.innerWidth + window.scrollMaxX; yScroll = window.innerHeight + window.scrollMaxY; } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac xScroll = document.body.scrollWidth; yScroll = document.body.scrollHeight; } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari xScroll = document.body.offsetWidth; yScroll = document.body.offsetHeight; } var windowWidth, windowHeight; if (self.innerHeight) { // all except Explorer if(document.documentElement.clientWidth){ windowWidth = document.documentElement.clientWidth; } else { windowWidth = self.innerWidth; } windowHeight = self.innerHeight; } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode windowWidth = document.documentElement.clientWidth; windowHeight = document.documentElement.clientHeight; } else if (document.body) { // other Explorers windowWidth = document.body.clientWidth; windowHeight = document.body.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; } var arrayPageSize = {'pageWidth':pageWidth,'pageHeight':pageHeight,'windowWidth':windowWidth,'windowHeight':windowHeight} return arrayPageSize; }, getPageScroll: function ( ) { var xScroll, yScroll; if (self.pageYOffset) { yScroll = self.pageYOffset; xScroll = self.pageXOffset; } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict yScroll = document.documentElement.scrollTop; xScroll = document.documentElement.scrollLeft; } else if (document.body) {// all other Explorers yScroll = document.body.scrollTop; xScroll = document.body.scrollLeft; } var arrayPageScroll = {'xScroll':xScroll,'yScroll':yScroll}; return arrayPageScroll; }, pause: function ( ms ) { var date = new Date(); curDate = null; do { var curDate = new Date(); } while ( curDate - date < ms); } }); // We have finished extending/defining our LightboxClass // -------------------------------------------------- // Finish up // On document load, Instantiate our class $(function() { // Instantiate $.Lightbox = $.Lightbox || new $.LightboxClass(); // domReady $.Lightbox.domReady(); }); // Finished definition })(jQuery); // We are done with our plugin, so lets call it with jQuery as the argument