FundacionLQDVI_Web/src/wp-content/plugins/simple-lightbox/js/dev/lightbox.js

867 lines
23 KiB
JavaScript
Raw Normal View History

// -----------------------------------------------------------------------------------
//
// Simple Lightbox
// by Archetyped - http://archetyped.com/tools/simple-lightbox/
// Updated: 2011-01-27
//
// Originally based on Lightbox Slideshow v1.1
// by Justin Barkhuff - http://www.justinbarkhuff.com/lab/lightbox_slideshow/
// 2007/08/15
//
// Largely based on Lightbox v2.02
// by Lokesh Dhakar - http://huddletogether.com/projects/lightbox2/
// 2006/03/31
//
// Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
//
// The code inserts HTML at the bottom of the page for displaying content in a non-modal dialog
//
// -----------------------------------------------------------------------------------
/**
* Lightbox object
*/
//var SLB = null;
(function($) {
SLB = {
activeImage : null,
badObjects : ['select','object','embed'],
container : null,
enableSlideshow : null,
groupName : null,
imageArray : [],
options : null,
overlayDuration : null,
overlayOpacity : null,
playSlides : null,
refTags : ['a'],
relAttribute : null,
resizeDuration : null,
slideShowTimer : null,
startImage : null,
prefix : 'slb',
checkedUrls : {},
/**
* Initialize lightbox instance
* @param object options Instance options
*/
initialize: function(options) {
this.options = $.extend(true, {
animate : true, // resizing animations
validateLinks : false, //Validate links before adding them to lightbox
captionEnabled: true, //Display caption
captionSrc : true, //Use image source URI if title not set
autoPlay : true, // should slideshow start automatically
borderSize : 10, // if you adjust the padding in the CSS, you will need to update this variable
containerID : document, // lightbox container object
enableSlideshow : true, // enable slideshow feature
googleAnalytics : false, // track individual image views using Google Analytics
imageDataLocation : 'south', // location of image caption information
initImage : '', // ID of image link to automatically launch when upon script initialization
loop : true, // whether to continuously loop slideshow images
overlayDuration : .2, // time to fade in shadow overlay
overlayOpacity : .8, // transparency of shadow overlay
relAttribute : 'lightbox', // specifies the rel attribute value that triggers lightbox
resizeSpeed : 400, // controls the speed of the image resizing (milliseconds)
showGroupName : false, // show group name of images in image details
slideTime : 4, // time to display images during slideshow
altsrc : 'src',
strings : { // allows for localization
closeLink : 'close',
loadingMsg : 'loading',
nextLink : 'next »',
prevLink : '« prev',
startSlideshow : 'start slideshow',
stopSlideshow : 'stop slideshow',
numDisplayPrefix : 'Image',
numDisplaySeparator : 'of'
},
placeholders : {
slbContent: '<img id="slb_slbContent" />',
slbLoading: '<span id="slb_slbLoading">loading</span>',
slbClose: '<a class="slb_slbClose" href="#">close</a>',
navPrev: '<a class="slb_navPrev slb_nav" href="#">&laquo; prev</a>',
navNext: '<a class="slb_navNext slb_nav" href="#">&raquo; next</a>',
navSlideControl: '<a class="slb_navSlideControl" href="#">Stop</a>',
dataCaption: '<span class="slb_dataCaption"></span>',
dataNumber: '<span class="slb_dataNumber"></span>'
},
layout : null
}, options);
//Stop if no layout is defined
if (!this.options.layout || this.options.layout.toString().length == 0)
this.end();
//Validate options
if ( this.options.animate ) {
this.overlayDuration = Math.max(this.options.overlayDuration,0);
this.resizeDuration = this.options.resizeSpeed;
} else {
this.overlayDuration = 0;
this.resizeDuration = 0;
}
this.enableSlideshow = this.options.enableSlideshow;
this.overlayOpacity = Math.max(Math.min(this.options.overlayOpacity,1),0);
this.playSlides = this.options.autoPlay;
this.container = $(this.options.containerID);
this.relAttribute = this.options.relAttribute;
this.updateImageList();
var t = this;
var objBody = $(this.container).get(0) != document ? this.container : $('body');
var objOverlay = $('<div/>', {
'id': this.getID('overlay'),
'css': {'display': 'none'}
}).appendTo(objBody)
.click(function() {t.end()});
var objLightbox = $('<div/>', {
'id': this.getID('lightbox'),
'css': {'display': 'none'}
}).appendTo(objBody)
.click(function() {t.end()});
//Build layout from template
var layout = this.getLayout();
//Append to container
$(layout).appendTo(objLightbox);
//Set UI
this.setUI();
//Add events
this.setEvents();
if (this.options.initImage != '') {
this.start($(this.options.initImage));
}
},
/**
* Build layout from template
* @uses options.layout
* @return string Layout markup (HTML)
*/
getLayout: function() {
var l = this.options.layout;
//Expand placeholders
var ph, phs, phr;
for (ph in this.options.placeholders) {
phs = '{' + ph + '}';
//Continue to next placeholder if current one is not in layout
if (l.indexOf(phs) == -1)
continue;
phr = new RegExp(phs, "g");
l = l.replace(phr, this.options.placeholders[ph]);
}
//Return final layout
return l;
},
/**
* Set localized values for UI elements
*/
setUI: function() {
var s = this.options.strings;
this.get('slbClose').html(s.closeLink);
this.get('navNext').html(s.nextLink);
this.get('navPrev').html(s.prevLink);
this.get('navSlideControl').html(((this.playSlides) ? s.stopSlideshow : s.startSlideshow));
},
/**
* Add events to various UI elements
*/
setEvents: function() {
var t = this, delay = 500;
this.get('container,details').click(function(ev) {
ev.stopPropagation();
});
var clickP = function() {
t.get('navPrev').unbind('click').click(false);
setTimeout(function() {t.get('navPrev').click(clickP)}, delay);
t.showPrev();
return false;
};
this.get('navPrev').click(function(){
return clickP();
});
var clickN = function() {
t.get('navNext').unbind('click').click(false);
setTimeout(function() {t.get('navNext').click(clickN)}, delay);
t.showNext();
return false;
};
this.get('navNext').click(function() {
return clickN();
});
this.get('navSlideControl').click(function() {
t.toggleSlideShow();
return false;
});
this.get('slbClose').click(function() {
t.end();
return false;
});
},
/**
* Finds all compatible image links on page
*/
updateImageList: function() {
var el, els, rel, t = this;
sel = [], selBase = '[href][rel*="' + this.relAttribute + '"]';
//Define event handler
var handler = function() {
//Check if element is valid for lightbox
t.start(this);
return false;
};
//Build selector
for (var i = 0; i < this.refTags.length; i++) {
sel.push(this.refTags[i] + selBase);
}
sel = sel.join(',');
//Add event handler to links
$(sel, $(this.container)).live('click', handler);
},
/**
* Build caption for displayed caption
* @param {Object} imageLink
*/
getCaption: function(imageLink) {
imageLink = $(imageLink);
var caption = '';
if (this.options.captionEnabled) {
caption = imageLink.attr('title') || '';
if (caption == '') {
var inner = $(imageLink).find('img').first();
if ($(inner).length)
caption = $(inner).attr('title') || $(inner).attr('alt');
if (!caption) {
if (imageLink.text().length)
caption = imageLink.text();
else
if (this.options.captionSrc)
caption = imageLink.attr('href');
}
if (!caption)
caption = '';
}
}
return caption;
},
/**
* Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
* @param node imageLink Link element containing image URL
*/
start: function(imageLink) {
imageLink = $(imageLink);
this.hideBadObjects();
this.imageArray = [];
this.groupName = this.getGroup(imageLink);
var rel = $(imageLink).attr('rel') || '';
var imageTitle = '';
var t = this;
var groupTemp = {};
this.fileExists(this.getSourceFile(imageLink),
function() { //File exists
// Stretch overlay to fill page and fade in
t.get('overlay')
.height($(document).height())
.fadeTo(t.overlayDuration, t.overlayOpacity);
// Add image to array closure
var addLink = function(el, idx) {
groupTemp[idx] = el;
return groupTemp.length;
};
//Build final image array & launch lightbox
var proceed = function() {
t.startImage = 0;
//Sort links by document order
var order = [], el;
for (var x in groupTemp) {
order.push(x);
}
order.sort(function(a, b) { return (a - b); });
for (x = 0; x < order.length; x++) {
el = groupTemp[order[x]];
//Check if link being evaluated is the same as the clicked link
if ($(el).get(0) == $(imageLink).get(0)) {
t.startImage = x;
}
t.imageArray.push({'link':t.getSourceFile($(el)), 'title':t.getCaption(el)});
}
// Calculate top offset for the lightbox and display
var lightboxTop = $(document).scrollTop() + ($(window).height() / 15);
t.get('lightbox').css('top', lightboxTop + 'px').show();
t.changeImage(t.startImage);
}
// If image is NOT part of a group..
if (null == t.groupName) {
// Add single image to imageArray
addLink(imageLink, 0);
t.startImage = 0;
proceed();
} else {
// If image is part of a group
var els = $(t.container).find($(imageLink).get(0).tagName.toLowerCase());
// Loop through links on page & find other images in group
var grpLinks = [];
var i, el;
for (i = 0; i < els.length; i++) {
el = $(els[i]);
if (t.getSourceFile(el) && (t.getGroup(el) == t.groupName)) {
//Add links in same group to temp array
grpLinks.push(el);
}
}
//Loop through group links, validate, and add to imageArray
var processed = 0;
for (i = 0; i < grpLinks.length; i++) {
el = grpLinks[i];
t.fileExists(t.getSourceFile($(el)),
function(args) { //File exists
var el = args.els[args.idx];
var il = addLink(el, args.idx);
processed++;
if (processed == args.els.length)
proceed();
},
function(args) { //File does not exist
processed++;
if (args.idx == args.els.length)
proceed();
},
{'idx': i, 'els': grpLinks});
}
}
},
function() { //File does not exist
t.end();
});
},
/**
* Retrieve source URI in link
* @param {Object} el
* @return string Source file URI
*/
getSourceFile: function(el) {
var src = $(el).attr('href');
var rel = $(el).attr('rel') || '';
var reSrc = new RegExp('\\b' + this.options.altsrc + '\\[(.+?)\\](?:\\b|$)');
if ( reSrc.test(rel) ) {
src = reSrc.exec(rel)[1];
}
return src;
},
/**
* Extract group name from
* @param obj el Element to extract group name from
* @return string Group name
*/
getGroup: function(el) {
//Get full attribute value
var g = null;
var rel = $(el).attr('rel') || '';
if (rel != '') {
var gTmp = '';
var gSt = '[';
var gEnd = ']';
var search = this.relAttribute;
var searching = true;
var idx;
var prefix = ' ';
while (searching) {
idx = rel.indexOf(search);
//Stop processing if value is not found
if (idx == -1)
return g;
//Prefix with space to find whole word
if (prefix != search.charAt(0) && idx > 0) {
search = prefix + search;
}
else {
searching = false;
}
}
gTmp = $.trim(rel.substring(idx).replace(search, ''));
//Check if group defined
if (gTmp.length && gSt == gTmp.charAt(0) && gTmp.indexOf(gEnd) != -1) {
//Extract group name
g = gTmp.substring(1, gTmp.indexOf(gEnd));
}
}
return g;
},
/**
* Preload requested image prior to displaying it in lightbox
* @param int imageNum Index of image in imageArray property
* @uses imageArray to retrieve index at specified image
* @uses resizeImageContainer() to resize lightbox after image has loaded
*/
changeImage: function(imageNum) {
this.activeImage = imageNum;
this.disableKeyboardNav();
this.pauseSlideShow();
// hide elements during transition
this.get('slbLoading').show();
this.get('slbContent').hide();
this.get('details').hide();
var imgPreloader = new Image();
var t = this;
// once image is preloaded, resize image container
$(imgPreloader).bind('load', function() {
t.get('slbContent').attr('src', imgPreloader.src);
t.resizeImageContainer(imgPreloader.width, imgPreloader.height);
//Restart slideshow if active
if ( t.isSlideShowActive() )
t.startSlideShow();
});
//Load image
imgPreloader.src = this.imageArray[this.activeImage].link;
},
/**
* Resizes lightbox to fit image
* @param int imgWidth Image width in pixels
* @param int imgHeight Image height in pixels
*/
resizeImageContainer: function(imgWidth, imgHeight) {
// get current height and width
var el = this.get('container');
var borderSize = this.options.borderSize * 2;
this.get('container').animate({width: imgWidth + borderSize, height: imgHeight + borderSize}, this.resizeDuration)
this.showImage();
},
/**
* Display image and begin preloading neighbors.
*/
showImage: function() {
this.get('slbLoading').hide();
var t = this;
this.get('slbContent').fadeIn(500, function() { t.updateDetails(); });
this.preloadNeighborImages();
},
/**
* Display caption, image number, and bottom nav
*/
updateDetails: function() {
if (this.options.captionEnabled) {
this.get('dataCaption').text(this.imageArray[this.activeImage].title);
this.get('dataCaption').show();
} else {
this.get('dataCaption').hide();
}
// if image is part of set display 'Image x of y'
if (this.hasImages()) {
var num_display = this.options.strings.numDisplayPrefix + ' ' + (this.activeImage + 1) + ' ' + this.options.strings.numDisplaySeparator + ' ' + this.imageArray.length;
if (this.options.showGroupName && this.groupName != '') {
num_display += ' ' + this.options.strings.numDisplaySeparator + ' ' + this.groupName;
}
this.get('dataNumber')
.text(num_display)
.show();
}
this.get('details').width(this.get('slbContent').width() + (this.options.borderSize * 2));
this.updateNav();
var t = this;
this.get('details').animate({height: 'show', opacity: 'show'}, 650);
},
/**
* Display appropriate previous and next hover navigation.
*/
updateNav: function() {
if (this.hasImages()) {
this.get('navPrev').show();
this.get('navNext').show();
if (this.enableSlideshow) {
this.get('navSlideControl').show();
if (this.playSlides) {
this.startSlideShow();
} else {
this.stopSlideShow();
}
} else {
this.get('navSlideControl').hide();
}
} else {
// Hide navigation controls when only one image exists
this.get('dataNumber').hide();
this.get('navPrev').hide();
this.get('navNext').hide();
this.get('navSlideControl').hide();
}
this.enableKeyboardNav();
},
/**
* Checks if slideshow is currently activated
* @return bool TRUE if slideshow is active, FALSE otherwise
* @uses playSlides to check slideshow activation status
*/
isSlideShowActive: function() {
return this.playSlides;
},
/**
* Start the slideshow
*/
startSlideShow: function() {
this.playSlides = true;
var t = this;
clearInterval(this.slideShowTimer);
this.slideShowTimer = setInterval(function() { t.showNext(); t.pauseSlideShow(); }, this.options.slideTime * 1000);
this.get('navSlideControl').text(this.options.strings.stopSlideshow);
},
/**
* Stop the slideshow
*/
stopSlideShow: function() {
this.playSlides = false;
if (this.slideShowTimer) {
clearInterval(this.slideShowTimer);
}
this.get('navSlideControl').text(this.options.strings.startSlideshow);
},
/**
* Toggles the slideshow status
*/
toggleSlideShow: function() {
if (this.playSlides) {
this.stopSlideShow();
}else{
this.startSlideShow();
}
},
/**
* Pauses the slideshow
* Stops the slideshow but does not change the slideshow's activation status
*/
pauseSlideShow: function() {
if (this.slideShowTimer) {
clearInterval(this.slideShowTimer);
}
},
/**
* Check if there is at least one image to display in the lightbox
* @return bool TRUE if at least one image is found
* @uses imageArray to check for images
*/
hasImage: function() {
return ( this.imageArray.length > 0 );
},
/**
* Check if there are multiple images to display in the lightbox
* @return bool TRUE if there are multiple images
* @uses imageArray to determine the number of images
*/
hasImages: function() {
return ( this.imageArray.length > 1 );
},
/**
* Check if the current image is the first image in the list
* @return bool TRUE if image is first
* @uses activeImage to check index of current image
*/
isFirstImage: function() {
return ( this.activeImage == 0 );
},
/**
* Check if the current image is the last image in the list
* @return bool TRUE if image is last
* @uses activeImage to check index of current image
* @uses imageArray to compare current image to total number of images
*/
isLastImage: function() {
return ( this.activeImage == this.imageArray.length - 1 );
},
/**
* Show the next image in the list
*/
showNext : function() {
if (this.hasImages()) {
if ( !this.options.loop && this.isLastImage() ) {
return this.end();
}
if ( this.isLastImage() ) {
this.showFirst();
} else {
this.changeImage(this.activeImage + 1);
}
}
},
/**
* Show the previous image in the list
*/
showPrev : function() {
if (this.hasImages()) {
if ( !this.options.loop && this.isFirstImage() )
return this.end();
if (this.activeImage == 0) {
this.showLast();
} else {
this.changeImage(this.activeImage - 1);
}
}
},
/**
* Show the first image in the list
*/
showFirst : function() {
if (this.hasImages()) {
this.changeImage(0);
}
},
/**
* Show the last image in the list
*/
showLast : function() {
if (this.hasImages()) {
this.changeImage(this.imageArray.length - 1);
}
},
/**
* Enable image navigation via the keyboard
*/
enableKeyboardNav: function() {
var t = this;
$(document).keydown(function(e) {
t.keyboardAction(e);
});
},
/**
* Disable image navigation via the keyboard
*/
disableKeyboardNav: function() {
$(document).unbind('keydown');
},
/**
* Handler for keyboard events
* @param event e Keyboard event data
*/
keyboardAction: function(e) {
if (e == null) { // ie
keycode = event.keyCode;
} else { // mozilla
keycode = e.which;
}
key = String.fromCharCode(keycode).toLowerCase();
if (keycode == 27 || key == 'x' || key == 'o' || key == 'c') { // close lightbox
this.end();
} else if (key == 'p' || key == '%') { // display previous image
this.showPrev();
} else if (key == 'n' || key =='\'') { // display next image
this.showNext();
} else if (key == 'f') { // display first image
this.showFirst();
} else if (key == 'l') { // display last image
this.showLast();
} else if (key == 's') { // toggle slideshow
if (this.hasImage() && this.options.enableSlideshow) {
this.toggleSlideShow();
}
}
},
/**
* Preloads images before/after current image
*/
preloadNeighborImages: function() {
var nextImageID = this.imageArray.length - 1 == this.activeImage ? 0 : this.activeImage + 1;
nextImage = new Image();
nextImage.src = this.imageArray[nextImageID].link;
var prevImageID = this.activeImage == 0 ? this.imageArray.length - 1 : this.activeImage - 1;
prevImage = new Image();
prevImage.src = this.imageArray[prevImageID].link;
},
/**
* Close the lightbox
*/
end: function() {
this.disableKeyboardNav();
this.pauseSlideShow();
this.get('lightbox').hide();
this.get('overlay').fadeOut(this.overlayDuration);
this.showBadObjects();
},
/**
* Displays objects that may conflict with the lightbox
* @param bool show (optional) Whether or not to show objects (Default: TRUE)
*/
showBadObjects: function (show) {
show = ( typeof(show) == 'undefined' ) ? true : !!show;
var vis = (show) ? 'visible' : 'hidden';
$(this.badObjects.join(',')).css('visibility', vis);
},
/**
* Hides objects that may conflict with the lightbox
* @uses showBadObjects() to hide objects
*/
hideBadObjects: function () {
this.showBadObjects(false);
},
/**
* Add prefix to text
* @param string txt Text to add prefix to
* @return string Prefixed text
*/
addPrefix: function(txt) {
return this.prefix + '_' + txt;
},
/**
* Generate formatted ID for lightbox-specific elements
* @param string id Base ID of element
* @return string Formatted ID
*/
getID: function(id) {
return this.addPrefix(id);
},
/**
* Generate formatted selector for lightbox-specific elements
* Compares specified ID to placeholders first, then named elements
* Multiple selectors can be included and separated by commas (',')
* @param string id Base ID of element
* @uses options.placeholders to compare id to placeholder names
* @return string Formatted selector
*/
getSel: function(id) {
//Process multiple selectors
var delim = ',', prefix = '#', sel;
if (id.toString().indexOf(delim) != -1) {
//Split
var sels = id.toString().split(delim);
//Build selector
for (var x = 0; x < sels.length; x++) {
sels[x] = this.getSel($.trim(sels[x]));
}
//Join
sel = sels.join(delim);
} else {
//Single selector
if (id in this.options.placeholders) {
var ph = $(this.options.placeholders[id]);
if (!ph.attr('id')) {
//Class selector
prefix = '.';
}
}
sel = prefix + this.getID(id);
}
return sel;
},
/**
* Retrieve lightbox-specific element
* @param string id Base ID of element
* @uses getSel() to generate formatted selector for element
* @return object jQuery object of selected element(s)
*/
get: function(id) {
return $(this.getSel(id));
},
/**
* Checks if file exists using AJAX request
* @param string url File URL
* @param callback success Callback to run if file exists
* @param callback failure Callback to run if file does not exist
* @param obj args Arguments for callback
*/
fileExists: function(url, success, failure, args) {
if (!this.options.validateLinks)
return success(args);
var statusFail = 400;
var stateCheck = 4;
var t = this;
var proceed = function(res) {
if (res.status < statusFail) {
if ($.isFunction(success))
success(args);
} else {
if ($.isFunction(failure))
failure(args);
}
};
//Check if URL already processed
if (url in this.checkedUrls) {
proceed(this.checkedUrls[url]);
} else {
var req = new XMLHttpRequest();
req.open('HEAD', url, true);
req.onreadystatechange = function() {
if (stateCheck == this.readyState) {
t.addUrl(url, this);
proceed(this);
}
};
req.send();
}
},
addUrl: function(url, res) {
if (!(url in this.checkedUrls))
this.checkedUrls[url] = res;
}
}
})(jQuery);