/*! * 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 }; }));