/*!
* baguettebox.js
* @author feimosi
* @version 1.3.1
* @url https://github.com/feimosi/baguettebox.js
*/
var baguettebox = (function() {
// svg shapes used within the buttons
var leftarrow = '',
rightarrow = '',
closex = '';
// global options and their defaults
var options = {}, defaults = {
captions: true,
buttons: 'auto',
async: false,
preload: 2,
animation: 'slidein',
aftershow: null,
afterhide: null,
// callback when image changes with `currentindex` and `imageselements.length` as parameters
onchange: null
};
// object containing information about features compatibility
var supports = {};
// dom elements references
var overlay, slider, previousbutton, nextbutton, closebutton;
// current image index inside the slider and displayed gallery index
var currentindex = 0, currentgallery = -1;
// touch event start position (for slide gesture)
var touchstartx;
// if set to true ignore touch events because animation was already fired
var touchflag = false;
// regex pattern to match image files
var regex = /.+\.(gif|jpe?g|png|webp)/i;
// array of all used galleries (dom elements)
var galleries = [];
// 2d array of galleries and images inside them
var imagesmap = [];
// array containing temporary images dom elements
var imageselements = [];
// foreach polyfill for ie8
// http://stackoverflow.com/a/14827443/1077846
if(![].foreach) {
array.prototype.foreach = function(callback, thisarg) {
for(var i = 0; i < this.length; i++)
callback.call(thisarg, this[i], i, this);
};
}
// filter polyfill for ie8
// https://gist.github.com/eliperelman/1031656
if(![].filter) {
array.prototype.filter = function(a, b, c, d, e) {
/*jshint -w030 */
c=this;d=[];for(e=0;e 40) {
touchflag = true;
showpreviousimage();
} else if (touch.pagex - touchstartx < -40) {
touchflag = true;
shownextimage();
}
});
bind(overlay, 'touchend', function(event) {
touchflag = false;
});
// activate keyboard shortcuts
bind(document, 'keydown', function(event) {
switch(event.keycode) {
case 37: // left arrow
showpreviousimage();
break;
case 39: // right arrow
shownextimage();
break;
case 27: // esc
hideoverlay();
break;
}
});
}
function prepareoverlay(galleryindex) {
// if the same gallery is being opened prevent from loading it once again
if(currentgallery === galleryindex)
return;
currentgallery = galleryindex;
// update gallery specific options
setoptions(imagesmap[galleryindex].options);
// empty slider of previous contents (more effective than .innerhtml = "")
while(slider.firstchild)
slider.removechild(slider.firstchild);
imageselements.length = 0;
// prepare and append images containers
for(var i = 0, fullimage; i < imagesmap[galleryindex].length; i++) {
fullimage = create('div');
fullimage.classname = 'full-image';
fullimage.id = 'baguette-img-' + i;
imageselements.push(fullimage);
slider.appendchild(imageselements[i]);
}
}
function setoptions(newoptions) {
if(!newoptions)
newoptions = {};
// fill options object
for(var item in defaults) {
options[item] = defaults[item];
if(typeof newoptions[item] !== 'undefined')
options[item] = newoptions[item];
}
/* apply new options */
// change transition for proper animation
slider.style.transition = slider.style.webkittransition = (options.animation === 'fadein' ? 'opacity .4s ease' :
options.animation === 'slidein' ? '' : 'none');
// hide buttons if necessary
if(options.buttons === 'auto' && ('ontouchstart' in window || imagesmap[currentgallery].length === 1))
options.buttons = false;
// set buttons style to hide or display them
previousbutton.style.display = nextbutton.style.display = (options.buttons ? '' : 'none');
}
function showoverlay(index) {
// return if overlay is already visible
if(overlay.style.display === 'block')
return;
// set current index to a new value and load proper image
currentindex = index;
loadimage(currentindex, function() {
preloadnext(currentindex);
preloadprev(currentindex);
});
updateoffset();
overlay.style.display = 'block';
// fade in overlay
settimeout(function() {
overlay.classname = 'visible';
if(options.aftershow)
options.aftershow();
}, 50);
if(options.onchange)
options.onchange(currentindex, imageselements.length);
}
function hideoverlay() {
// return if overlay is already hidden
if(overlay.style.display === 'none')
return;
// fade out and hide the overlay
overlay.classname = '';
settimeout(function() {
overlay.style.display = 'none';
if(options.afterhide)
options.afterhide();
}, 500);
}
function loadimage(index, callback) {
var imagecontainer = imageselements[index];
// if index is invalid return
if(typeof imagecontainer === 'undefined')
return;
// if image is already loaded run callback and return
if(imagecontainer.getelementsbytagname('img')[0]) {
if(callback)
callback();
return;
}
// get element reference, optional caption and source path
imageelement = imagesmap[currentgallery][index];
imagecaption = (typeof(options.captions) === 'function') ?
options.captions.call(imagesmap[currentgallery], imageelement) :
imageelement.getattribute('data-caption') || imageelement.title;
imagesrc = getimagesrc(imageelement);
// prepare image container elements
var figure = create('figure');
var image = create('img');
var figcaption = create('figcaption');
imagecontainer.appendchild(figure);
// add loader element
figure.innerhtml = '';
// set callback function when image loads
image.onload = function() {
// remove loader element
var spinner = document.queryselector('#baguette-img-' + index + ' .spinner');
figure.removechild(spinner);
if(!options.async && callback)
callback();
};
image.setattribute('src', imagesrc);
figure.appendchild(image);
// insert caption if available
if(options.captions && imagecaption) {
figcaption.innerhtml = imagecaption;
figure.appendchild(figcaption);
}
// run callback
if(options.async && callback)
callback();
}
// get image source location, mostly used for responsive images
function getimagesrc(image) {
// set default image path from href
var result = imageelement.href;
// if dataset is supported find the most suitable image
if(image.dataset) {
var srcs = [];
// get all possible image versions depending on the resolution
for(var item in image.dataset) {
if(item.substring(0, 3) === 'at-' && !isnan(item.substring(3)))
srcs[item.replace('at-', '')] = image.dataset[item];
}
// sort resolutions ascending
keys = object.keys(srcs).sort(function(a, b) {
return parseint(a) < parseint(b) ? -1 : 1;
});
// get real screen resolution
var width = window.innerwidth * window.devicepixelratio;
// find the first image bigger than or equal to the current width
var i = 0;
while(i < keys.length - 1 && keys[i] < width)
i++;
result = srcs[keys[i]] || result;
}
return result;
}
// return false at the right end of the gallery
function shownextimage() {
var returnvalue;
// check if next image exists
if(currentindex <= imageselements.length - 2) {
currentindex++;
updateoffset();
preloadnext(currentindex);
returnvalue = true;
} else if(options.animation) {
slider.classname = 'bounce-from-right';
settimeout(function() {
slider.classname = '';
}, 400);
returnvalue = false;
}
if(options.onchange)
options.onchange(currentindex, imageselements.length);
return returnvalue;
}
// return false at the left end of the gallery
function showpreviousimage() {
var returnvalue;
// check if previous image exists
if(currentindex >= 1) {
currentindex--;
updateoffset();
preloadprev(currentindex);
returnvalue = true;
} else if(options.animation) {
slider.classname = 'bounce-from-left';
settimeout(function() {
slider.classname = '';
}, 400);
returnvalue = false;
}
if(options.onchange)
options.onchange(currentindex, imageselements.length);
return returnvalue;
}
function updateoffset() {
var offset = -currentindex * 100 + '%';
if(options.animation === 'fadein') {
slider.style.opacity = 0;
settimeout(function() {
/*jshint -w030 */
supports.transforms ?
slider.style.transform = slider.style.webkittransform = 'translate3d(' + offset + ',0,0)'
: slider.style.left = offset;
slider.style.opacity = 1;
}, 400);
} else {
/*jshint -w030 */
supports.transforms ?
slider.style.transform = slider.style.webkittransform = 'translate3d(' + offset + ',0,0)'
: slider.style.left = offset;
}
}
// css 3d transforms test
function testtransformssupport() {
var div = create('div');
return typeof div.style.perspective !== 'undefined' || typeof div.style.webkitperspective !== 'undefined';
}
// inline svg test
function testsvgsupport() {
var div = create('div');
div.innerhtml = '';
return (div.firstchild && div.firstchild.namespaceuri) == 'http://www.w3.org/2000/svg';
}
function preloadnext(index) {
if(index - currentindex >= options.preload)
return;
loadimage(index + 1, function() { preloadnext(index + 1); });
}
function preloadprev(index) {
if(currentindex - index >= options.preload)
return;
loadimage(index - 1, function() { preloadprev(index - 1); });
}
function bind(element, event, callback) {
if(element.addeventlistener)
element.addeventlistener(event, callback, false);
else // ie8 fallback
element.attachevent('on' + event, callback);
}
function getbyid(id) {
return document.getelementbyid(id);
}
function create(element) {
return document.createelement(element);
}
return {
run: run,
shownext: shownextimage,
showprevious: showpreviousimage
};
})();