(function(root, factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof module === 'object' && module.exports) { module.exports = factory(); } else { root.SimpleLightbox = factory(); } }(this, function() { function assign(target) { for (var i = 1; i < arguments.length; i++) { var obj = arguments[i]; if (obj) { for (var key in obj) { obj.hasOwnProperty(key) && (target[key] = obj[key]); } } } return target; } function addClass(element, className) { if (element && className) { element.className += ' ' + className; } } function removeClass(element, className) { if (element && className) { element.className = element.className.replace( new RegExp('(\\s|^)' + className + '(\\s|$)'), ' ' ).trim(); } } function parseHtml(html) { var div = document.createElement('div'); div.innerHTML = html.trim(); return div.childNodes[0]; } function matches(el, selector) { return (el.matches || el.matchesSelector || el.msMatchesSelector).call(el, selector); } function getWindowHeight() { return 'innerHeight' in window ? window.innerHeight : document.documentElement.offsetHeight; } function SimpleLightbox(options) { this.init.apply(this, arguments); } SimpleLightbox.defaults = { // add custom classes to lightbox elements elementClass: '', elementLoadingClass: 'slbLoading', htmlClass: 'slbActive', closeBtnClass: '', nextBtnClass: '', prevBtnClass: '', loadingTextClass: '', // customize / localize controls captions closeBtnCaption: 'Close', nextBtnCaption: 'Next', prevBtnCaption: 'Previous', loadingCaption: 'Loading...', bindToItems: true, // set click event handler to trigger lightbox on provided $items closeOnOverlayClick: true, closeOnEscapeKey: true, nextOnImageClick: true, showCaptions: true, captionAttribute: 'title', // choose data source for library to glean image caption from urlAttribute: 'href', // where to expect large image startAt: 0, // start gallery at custom index loadingTimeout: 100, // time after loading element will appear appendTarget: 'body', // append elsewhere if needed beforeSetContent: null, // convenient hooks for extending library behavoiur beforeClose: null, afterClose: null, beforeDestroy: null, afterDestroy: null, videoRegex: new RegExp(/youtube.com|vimeo.com/) // regex which tests load url for iframe content }; assign(SimpleLightbox.prototype, { init: function(options) { options = this.options = assign({}, SimpleLightbox.defaults, options); var self = this; var elements; if (options.$items) { elements = options.$items.get(); } if (options.elements) { elements = [].slice.call( typeof options.elements === 'string' ? document.querySelectorAll(options.elements) : options.elements ); } this.eventRegistry = {lightbox: [], thumbnails: []}; this.items = []; this.captions = []; if (elements) { elements.forEach(function(element, index) { self.items.push(element.getAttribute(options.urlAttribute)); self.captions.push(element.getAttribute(options.captionAttribute)); if (options.bindToItems) { self.addEvent(element, 'click', function(e) { e.preventDefault(); self.showPosition(index); }, 'thumbnails'); } }); } if (options.items) { this.items = options.items; } if (options.captions) { this.captions = options.captions; } }, addEvent: function(element, eventName, callback, scope) { this.eventRegistry[scope || 'lightbox'].push({ element: element, eventName: eventName, callback: callback }); element.addEventListener(eventName, callback); return this; }, removeEvents: function(scope) { this.eventRegistry[scope].forEach(function(item) { item.element.removeEventListener(item.eventName, item.callback); }); this.eventRegistry[scope] = []; return this; }, next: function() { return this.showPosition(this.currentPosition + 1); }, prev: function() { return this.showPosition(this.currentPosition - 1); }, normalizePosition: function(position) { if (position >= this.items.length) { position = 0; } else if (position < 0) { position = this.items.length - 1; } return position; }, showPosition: function(position) { var newPosition = this.normalizePosition(position); if (typeof this.currentPosition !== 'undefined') { this.direction = newPosition > this.currentPosition ? 'next' : 'prev'; } this.currentPosition = newPosition; return this.setupLightboxHtml() .prepareItem(this.currentPosition, this.setContent) .show(); }, loading: function(on) { var self = this; var options = this.options; if (on) { this.loadingTimeout = setTimeout(function() { addClass(self.$el, options.elementLoadingClass); self.$content.innerHTML = '

' + options.loadingCaption + '

'; self.show(); }, options.loadingTimeout); } else { removeClass(this.$el, options.elementLoadingClass); clearTimeout(this.loadingTimeout); } }, prepareItem: function(position, callback) { var self = this; var url = this.items[position]; this.loading(true); if (this.options.videoRegex.test(url)) { callback.call(self, parseHtml( '
') ); } else { var $imageCont = parseHtml( '
' ); this.$currentImage = $imageCont.querySelector('.slbImage'); if (this.options.showCaptions && this.captions[position]) { $imageCont.appendChild(parseHtml( '
' + this.captions[position] + '
') ); } this.loadImage(url, function() { self.setImageDimensions(); callback.call(self, $imageCont); self.loadImage(self.items[self.normalizePosition(self.currentPosition + 1)]); }); } return this; }, loadImage: function(url, callback) { if (!this.options.videoRegex.test(url)) { var image = new Image(); callback && (image.onload = callback); image.src = url; } }, setupLightboxHtml: function() { var o = this.options; if (!this.$el) { this.$el = parseHtml( '
' + '
' + '
' + '
' + '
' + '
' + '' + (this.items.length > 1 ? '
' + '' + '' + '
' : '' ) + '
' + '
' + '
' + '
' ); this.$content = this.$el.querySelector('.slbContent'); } this.$content.innerHTML = ''; return this; }, show: function() { if (!this.modalInDom) { document.querySelector(this.options.appendTarget).appendChild(this.$el); addClass(document.documentElement, this.options.htmlClass); this.setupLightboxEvents(); this.modalInDom = true; } return this; }, setContent: function(content) { var $content = typeof content === 'string' ? parseHtml(content) : content ; this.loading(false); this.setupLightboxHtml(); removeClass(this.$content, 'slbDirectionNext'); removeClass(this.$content, 'slbDirectionPrev'); if (this.direction) { addClass(this.$content, this.direction === 'next' ? 'slbDirectionNext' : 'slbDirectionPrev' ); } if (this.options.beforeSetContent) { this.options.beforeSetContent($content, this); } this.$content.appendChild($content); return this; }, setImageDimensions: function() { if (this.$currentImage) { this.$currentImage.style.maxHeight = getWindowHeight() + 'px'; } }, setupLightboxEvents: function() { var self = this; if (this.eventRegistry.lightbox.length) { return this; } this.addEvent(this.$el, 'click', function(e) { var $target = e.target; if (matches($target, '.slbCloseBtn') || (self.options.closeOnOverlayClick && matches($target, '.slbWrap'))) { self.close(); } else if (matches($target, '.slbArrow')) { matches($target, '.next') ? self.next() : self.prev(); } else if (self.options.nextOnImageClick && self.items.length > 1 && matches($target, '.slbImage')) { self.next(); } }).addEvent(document, 'keyup', function(e) { self.options.closeOnEscapeKey && e.keyCode === 27 && self.close(); if (self.items.length > 1) { (e.keyCode === 39 || e.keyCode === 68) && self.next(); (e.keyCode === 37 || e.keyCode === 65) && self.prev(); } }).addEvent(window, 'resize', function() { self.setImageDimensions(); }); return this; }, close: function() { if (this.modalInDom) { this.runHook('beforeClose'); this.removeEvents('lightbox'); this.$el && this.$el.parentNode.removeChild(this.$el); removeClass(document.documentElement, this.options.htmlClass); this.modalInDom = false; this.runHook('afterClose'); } this.direction = undefined; this.currentPosition = this.options.startAt; }, destroy: function() { this.close(); this.runHook('beforeDestroy'); this.removeEvents('thumbnails'); this.runHook('afterDestroy'); }, runHook: function(name) { this.options[name] && this.options[name](this); } }); SimpleLightbox.open = function(options) { var instance = new SimpleLightbox(options); return options.content ? instance.setContent(options.content).show() : instance.showPosition(instance.options.startAt); }; SimpleLightbox.registerAsJqueryPlugin = function($) { $.fn.simpleLightbox = function(options) { var lightboxInstance; var $items = this; return this.each(function() { if (!$.data(this, 'simpleLightbox')) { lightboxInstance = lightboxInstance || new SimpleLightbox($.extend({}, options, {$items: $items})); $.data(this, 'simpleLightbox', lightboxInstance); } }); }; $.SimpleLightbox = SimpleLightbox; }; if (typeof window !== 'undefined' && window.jQuery) { SimpleLightbox.registerAsJqueryPlugin(window.jQuery); } return SimpleLightbox; }));