/*!
* baguetteBox.js
* @author feimosi
* @version 1.5.0
* @url https://github.com/feimosi/baguetteBox.js
*/
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.baguetteBox = factory();
}
}(this, function () {
// SVG shapes used on the buttons
var leftArrow = '',
rightArrow = '',
closeX = '';
// Global options and their defaults
var options = {}, defaults = {
captions: true,
fullScreen: false,
noScrollbars: false,
titleTag: false,
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,
overlayBackgroundColor: 'rgba(0, 0, 0, .8)',
};
// 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 (Array od NodeList elements)
var galleries = [];
// 2D array of galleries and images inside them
var imagesMap = [];
// Array containing temporary images DOM elements
var imagesElements = [];
// Event handlers
var imagedEventHandlers = {};
var overlayClickHandler = function(event) {
// When clicked on the overlay (outside displayed image) close it
if(event.target && event.target.nodeName !== 'IMG' && event.target.nodeName !== 'FIGCAPTION')
hideOverlay();
};
var previousButtonClickHandler = function(event) {
/*jshint -W030 */
event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;
showPreviousImage();
};
var nextButtonClickHandler = function(event) {
/*jshint -W030 */
event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;
showNextImage();
};
var closeButtonClickHandler = function(event) {
/*jshint -W030 */
event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;
hideOverlay();
};
var touchstartHandler = function(event) {
// Save x axis position
touchStartX = event.changedTouches[0].pageX;
};
var touchmoveHandler = function(event) {
// If action was already triggered return
if(touchFlag)
return;
/*jshint -W030 */
event.preventDefault ? event.preventDefault() : event.returnValue = false;
touch = event.touches[0] || event.changedTouches[0];
// Move at least 40 pixels to trigger the action
if(touch.pageX - touchStartX > 40) {
touchFlag = true;
showPreviousImage();
} else if (touch.pageX - touchStartX < -40) {
touchFlag = true;
showNextImage();
}
};
var touchendHandler = function(event) {
touchFlag = false;
};
// 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' +
'' +
'';
// 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);
if(options.titleTag && imageCaption)
image.title = imageCaption;
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 unbind(element, event, callback) {
if(element.removeEventListener)
element.removeEventListener(event, callback, false);
else // IE8 fallback
element.detachEvent('on' + event, callback);
}
function getByID(id) {
return document.getElementById(id);
}
function create(element) {
return document.createElement(element);
}
function destroyPlugin() {
unbindEvents();
unbindImageClickListeners();
unbind(document, 'keydown', keyDownHandler);
document.getElementsByTagName('body')[0].removeChild(document.getElementById('baguetteBox-overlay'));
currentIndex = 0;
currentGallery = -1;
galleries.length = 0;
imagesMap.length = 0;
}
return {
run: run,
destroy: destroyPlugin,
showNext: showNextImage,
showPrevious: showPreviousImage
};
}));