/** * Lightbox library created by binarity s.r.o. * www.binarity.cz * version 1.0.0 * * Vanilla JavaScript lightbox plugin. * * Can use custom invoker passed as first argument or uses a default one - .b-lightbox. * This allows to have more lightbox instances on one site to categorize items. * * Default behaviour: * - Hides on escape keydown event - settable (options.allow_escape). * - Hides on background click - settable (options.allow_backgroundclick). * - Hide button in top right corner - settable (options.close_text). * - Allows usage of arrow keys (left/right) to navigate through images - settable (option.allow_arrows). * * @param options * @param autorun * @constructor */ function BLightBox(options, autorun) { // Instance and instance variables. var BLightBox = this, escape_key_allowed = (!(options !== undefined && options.allow_escape === false)), hide_on_holder_allowed = (!(options !== undefined && options.allow_backgroundclick === false)), arrows_allowed = (!(options !== undefined && options.allow_arrows === false)), close_text = (options !== undefined && options.close_text !== undefined) ? options.close_text : 'Close', // DOM lightbox_holder = document.createElement('div'), invoker_string = (options !== undefined && options.invoker !== undefined) ? options.invoker : '.b-lightbox', invokers = document.querySelectorAll(invoker_string), invokers_length = invokers.length, lightbox_image = document.createElement('img'), close_label = document.createElement('a'), previous_button = document.createElement('a'), next_button = document.createElement('a'), lightbox_label = document.createElement('span'); // BLightBox DOM default settings. lightbox_holder.className = 'b-lightbox-holder'; lightbox_image.className = 'b-lightbox-image'; close_label.className = 'b-lightbox-close-button'; close_label.textContent = close_text; previous_button.className = 'b-lightbox-direction previous'; previous_button.innerHTML = '‹'; next_button.className = 'b-lightbox-direction next'; next_button.innerHTML = '›'; lightbox_label.className = 'b-lightbox-label'; /** * Show new image according to data-newindex attribute on directional button */ this.loadNewImage = function(event) { event.stopPropagation(); var index = event.target.getAttribute('data-newindex'), label = invokers[index].getAttribute('data-label'); if(invokers[index]) { lightbox_image.style.display = 'none'; this.decideFromLoad(invokers[index]); lightbox_image.style.display = 'block'; if(label != '') { lightbox_label.innerHTML = label; } } this.lightboxImageCenter(label != ''); // Center image. // Change indexes to be opened. previous_button.setAttribute('data-newindex', this.getPreviousIndex(index)); next_button.setAttribute('data-newindex', this.getNextIndex(index)); }; /** * Returns first next index possible, or return very first index to allow rotation. * @param index * @returns {number} */ this.getNextIndex = function(index) { // Skip to last image if we are on the first. return (index == invokers_length - 1) ? 0 : parseInt(index) + 1; }; /** * Returns first previous index possible, or returns last array index to allow rotation. * @param index * @returns {number} */ this.getPreviousIndex = function(index) { // Skip to last image if we are on the first. return (index == 0) ? invokers_length - 1 : index - 1; }; /** * Reset ivokers_length variable for re-use. */ this.resetInvokersLength = function() { invokers_length = invokers.length; }; /** * Provides code for closing a lightbox and hiding images. */ this.listenActionClose = function(event) { lightbox_holder.style.display = 'none'; lightbox_image.style.display = 'none'; }; /** * Adds src to lightbox image from element's style background-image. * Removes url() par of the string. * @param el */ this.loadImageFromBackgroundImage = function(el) { lightbox_image.src = el.style.backgroundImage.replace(/url\("?(.*[^"])"?\)/, '$1'); }; /** * Adds src to lightbox image from element's child img tag. * @param el */ this.loadImageFromChildImg = function(el) { var img = el.querySelector('img'); if(img) { lightbox_image.src = img.src; } }; /** * Move lightbox image to the center of screen. */ this.lightboxImageCenter = function(bool_label) { // Image lightbox_image.style.left = ((lightbox_holder.offsetWidth - lightbox_image.offsetWidth) / 2) + 'px'; lightbox_image.style.top = ((lightbox_holder.offsetHeight - lightbox_image.offsetHeight) / 2) + 'px'; // Image label. if(bool_label === true) { lightbox_label.style.width = lightbox_image.offsetWidth + 'px'; lightbox_label.style.left = ((lightbox_holder.offsetWidth - lightbox_image.offsetWidth) / 2) + 'px'; lightbox_label.style.display = 'block'; lightbox_label.style.top = (lightbox_image.offsetTop + lightbox_image.offsetHeight - lightbox_label.offsetHeight) + 'px'; } }; /** * Returns index in invokers array or false on unsuccessful attempt to find the element. * @param el * @returns {*} */ this.getIndexInInvokers = function(el) { var inv_length = invokers_length; while(inv_length--) { if(invokers[inv_length].isEqualNode(el)) { return inv_length; } } return false; }; /** * This method decides from where to load src attribute into lightbox_image. * @param el */ this.decideFromLoad = function(el) { // Decide from which source to get image url. if(el.hasAttribute('data-background')) { this.loadImageFromBackgroundImage(el); } else if(el.hasAttribute('data-img')) { this.loadImageFromChildImg(el); } lightbox_label.style.display = 'none'; lightbox_label.innerHTML = ''; }; /** * Provides code for opening a lightbox and displaying images. */ this.listenActionOpen = function(el, app, event) { var label = el.getAttribute('data-label'); event.stopPropagation(); event.preventDefault(); // If element is a-tag, prevent from href requesting. app.decideFromLoad(el); // Load image into lightbox_image. // Change indexes to be opened. previous_button.setAttribute('data-newindex', app.getPreviousIndex(app.getIndexInInvokers(el))); next_button.setAttribute('data-newindex', app.getNextIndex(app.getIndexInInvokers(el))); // Show lightbox and image. lightbox_holder.style.display = 'block'; lightbox_image.style.display = 'block'; if(label != '') { lightbox_label.innerHTML = label; } // Center lightbox within the screen. app.lightboxImageCenter(label != ''); }; /** * Add lightbox closing method listener to given element. * @param el */ this.addCloseListenerFor = function(el) { el.addEventListener('click', this.listenActionClose.bind(this)); }; /** * Add lightbox opening method listener to given element. * @param el */ this.addOpenListenerFor = function(el) { var app = this; el.addEventListener('click', app.listenActionOpen.bind(app, el, this), true); }; /** * Initializes all possible listeners at once on class instance creation. */ this.initiateListeners = function() { // Open Listeners. while(invokers_length--) { this.addOpenListenerFor(invokers[invokers_length]); } this.resetInvokersLength(); // Close Listeners. // On background click. if(hide_on_holder_allowed){ this.addCloseListenerFor(lightbox_holder); } // On escape key hit, if requested. if(escape_key_allowed) { window.addEventListener('keydown', function (event) { if(event.keyCode === 27) { BLightBox.listenActionClose(); } }); } // Directional buttons. previous_button.addEventListener('click',this.loadNewImage.bind(this)); next_button.addEventListener('click',this.loadNewImage.bind(this)); // Allow directing with arrows when enabled. if(arrows_allowed) { window.addEventListener('keydown', function arrowDirections(event) { if(event.keyCode === 37) { previous_button.click(); } else if(event.keyCode === 39) { next_button.click(); } }); } }; /** * Initialization method that starts BLightBox instance. * @returns {*} */ this.init = function() { // Append lightbox background. document.body.appendChild(lightbox_holder); lightbox_holder.appendChild(previous_button); lightbox_holder.appendChild(lightbox_image); lightbox_holder.appendChild(next_button); lightbox_holder.appendChild(close_label); lightbox_holder.appendChild(lightbox_label); // Add event listeners for invokers. this.initiateListeners(); // Auto centering on window.resize; window.addEventListener('resize', function() { BLightBox.lightboxImageCenter(); }); return BLightBox; }; // If autorun is requested, create instance. if(autorun !== undefined && autorun === true) { return this.init(); } else { return this; } }