/** * A lightweight light box script. * * @author Matthias Kittsteiner * @package rh-60 * @version 1.0.2 */ var lightBoxBox = null; var lightBoxContainer = null; var lightBoxContent = null; var lightBoxGallery = ''; var lightBoxGalleryCurrentItem = 0; var lightBoxIcon = null; var lightBoxLoading = null; var lightBoxNavigation = null; var lightBoxOverlay = null; var lightBoxType = 'normal'; document.addEventListener( 'DOMContentLoaded', function( event ) { var lightBoxes = document.getElementsByClassName( 'lightbox' ); // event listeners for ( var i = 0; i < lightBoxes.length; i++ ) { lightBoxes[ i ].addEventListener( 'click', clickLink ); } document.onkeydown = function( event ) { if ( event.keyCode === 27 ) { removeContent( event ); } // left arrow key if ( event.keyCode === 37 ) { var leftEvent = new CustomEvent( 'click', { 'bubbles': true, 'cancelable': true } ); var leftElement = document.querySelector( '.lightBoxLink.prev' ); if ( leftElement ) { leftElement.dispatchEvent( leftEvent ); } } // right arrow key if ( event.keyCode === 39 ) { var rightEvent = new CustomEvent( 'click', { 'bubbles': true, 'cancelable': true } ); var rightElement = document.querySelector( '.lightBoxLink.next' ); if ( rightElement ) { rightElement.dispatchEvent( rightEvent ); } } }; if ( lightBoxes !== undefined && lightBoxes.length ) { init(); } else { return false; } /** * Initialize the lightBox container. */ function init() { // don’t rearrange lightBoxOverlay = createElement( 'div', 'lightBoxOverlay', document.body ); lightBoxContainer = createElement( 'div', 'lightBoxContainer', lightBoxOverlay ); lightBoxBox = createElement( 'div', 'lightBoxBox', lightBoxContainer ); lightBoxIcon = createElement( 'div', 'lightBoxIcon', lightBoxContainer ); lightBoxContent = createElement( 'div', 'lightBoxContent', lightBoxBox ); lightBoxLoading = createElement( 'div', 'lightBoxLoading', lightBoxOverlay ); lightBoxOverlay.addEventListener( 'click', removeContent ); lightBoxIcon.addEventListener( 'click', removeContent ); document.body.addEventListener( 'click', removeContent ); } /** * Add a gallery navigation item. * * @param {Element} item * @param {String} type */ function addGalleryNavigationItem( item, type ) { // make sure to create the list element for styling purposes var listElement = createElement( 'li', '', lightBoxNavigation ); if ( document.body.contains( item ) ) { var link = createElement( 'a', 'lightBoxLink', listElement ); link.setAttribute( 'data-lightbox-gallery', item.getAttribute( 'data-lightbox-gallery' ) ); link.setAttribute( 'data-lightbox-item', item.getAttribute( 'data-lightbox-item' ) ); link.setAttribute( 'href', item.getAttribute( 'href' ) ); link.classList.add( type ); link.addEventListener( 'click', function( event ) { clickLink( event ); } ); } } /** * Click on a link with class `.lightbox`. * * @param {Event} event */ function clickLink( event ) { event.preventDefault(); event.stopPropagation(); var currentTarget = event.target || event.srcElement; var linkItem = currentTarget.closest( 'a' ); if ( linkItem && linkItem.href.match( /\.(jpeg|jpg|gif|png)$/ ) === null ) { lightBoxType = 'iframe'; } else { lightBoxType = 'normal'; } lightBoxGallery = linkItem.getAttribute( 'data-lightbox-gallery' ) ? linkItem.getAttribute( 'data-lightbox-gallery' ) : ''; lightBoxGalleryCurrentItem = linkItem.getAttribute( 'data-lightbox-item' ) ? linkItem.getAttribute( 'data-lightbox-item' ) : 0; var nextItem = null; var prevItem = null; // get gallery items if ( lightBoxGallery && lightBoxGalleryCurrentItem ) { nextItem = getNextGalleryItem(); prevItem = getPrevGalleryItem(); } // remove navigation if ( lightBoxNavigation !== null ) { lightBoxNavigation.remove(); } removeContent( event ); getContent( currentTarget, nextItem, prevItem ); } /** * Create the navigation. * * @param {Element} nextItem * @param {Element} prevItem */ function createNavigation( nextItem, prevItem ) { if ( ( nextItem !== null || prevItem !== null ) && document.body.contains( nextItem ) || document.body.contains( prevItem ) ) { lightBoxNavigation = createElement( 'ul', 'lightBoxNavigation', lightBoxContainer ); lightBoxContainer.classList.add( 'has-navigation' ); // add next|prev links addGalleryNavigationItem( prevItem, 'prev' ); addGalleryNavigationItem( nextItem, 'next' ); } } /** * Show the light box content. * * @param {Element} currentTarget * @param {Element} nextItem * @param {Element} prevItem */ function getContent( currentTarget, nextItem, prevItem ) { var linkItem = currentTarget.closest( 'a' ); var href = linkItem.getAttribute( 'href' ); lightBoxOverlay.classList.add( 'visible' ); // add navigation createNavigation( nextItem, prevItem ); if ( lightBoxType === 'iframe' ) { lightBoxContainer.classList.add( 'lightBoxIframe' ); var element = createElement( 'iframe', 'iframe-content', lightBoxContent ); element.src = href; // allow fullscreen applications element.setAttribute( 'allowfullscreen', true ); if ( href.match( /\.pdf$/ ) ) { // handle pdf element.src += '#view=fit'; lightBoxContainer.classList.add( 'pdf-content' ); lightBoxContainer.classList.add( 'visible' ); positionElement( lightBoxContainer ); } else { element.onload = function() { lightBoxContainer.classList.add( 'visible' ); positionElement( lightBoxContainer ); }; } } else { var img = new Image(); lightBoxContent.innerHTML = ''; img.onload = function() { lightBoxContainer.classList.add( 'visible' ); positionElement( lightBoxContainer ); }; img.src = href; } document.body.classList.add( 'lightbox-open' ); } /** * Get next item of a gallery. * * @returns {Element|Null} */ function getNextGalleryItem() { var nextGalleryItemID = parseInt( lightBoxGalleryCurrentItem ) + 1; var nextGalleryItem = document.querySelector( 'a[data-lightbox-gallery="' + lightBoxGallery + '"][data-lightbox-item="' + nextGalleryItemID + '"]' ); if ( document.body.contains( nextGalleryItem ) ) { return nextGalleryItem; } else { return null; } } /** * Get previous item of a gallery. * * @returns {Element|Null} */ function getPrevGalleryItem() { var prevGalleryItemID = parseInt( lightBoxGalleryCurrentItem ) - 1; var prevGalleryItem = document.querySelector( 'a[data-lightbox-gallery="' + lightBoxGallery + '"][data-lightbox-item="' + prevGalleryItemID + '"]' ); if ( document.body.contains( prevGalleryItem ) ) { return prevGalleryItem; } else { return null; } } /** * Remove content of the light box. * * @param {Event} event */ function removeContent( event ) { var currentTarget = event.target; var isNode = currentTarget instanceof Node; if ( isNode && lightBoxContainer !== null && lightBoxContainer.contains( currentTarget ) && ! currentTarget.classList.contains( 'lightBoxIcon' ) ) { return; } if ( lightBoxContent !== null ) { lightBoxContent.innerHTML = ''; lightBoxContent.removeAttribute( 'style' ); lightBoxBox.removeAttribute( 'style' ); } if ( lightBoxNavigation !== null ) { lightBoxNavigation.remove(); } if ( lightBoxOverlay !== null ) { lightBoxOverlay.classList.remove( 'visible' ); } if ( lightBoxContainer !== null ) { lightBoxContainer.classList.remove( 'has-navigation' ); lightBoxContainer.classList.remove( 'lightBoxIframe' ); lightBoxContainer.classList.remove( 'too-big' ); lightBoxContainer.classList.remove( 'visible' ); lightBoxContainer.removeAttribute( 'style' ); } document.body.classList.remove( 'lightbox-open' ); } } ); /** * Create a new HTML element. * * @param {String} name * @param {String} newClass * @param {Element} parent * @returns {Element} */ function createElement( name, newClass, parent ) { var element = document.createElement( name ); if ( newClass.length ) { element.classList.add( newClass ); } parent.appendChild( element ); return element; } /** * Position an element at the center of the browser window. * * @param {Element} element */ function positionElement( element ) { var bodyHeight = window.innerHeight; var bodyWidth = window.innerWidth; var content = element.querySelector( '.lightBoxContent' ); // reset element.style.opacity = 0; element.classList.remove( 'too-high' ); element.classList.remove( 'too-wide' ); content.removeAttribute( 'style' ); var height = element.offsetHeight; var width = element.offsetWidth; // if light box is too high if ( bodyHeight <= height + 60 ) { element.classList.add( 'too-high' ); } // if light box is too wide if ( bodyWidth < width + 60 && lightBoxType !== 'iframe' ) { element.classList.add( 'too-wide' ); } // horizontal centering if ( window.matchMedia( '(min-width: 840px)' ).matches ) { if ( bodyWidth >= width + 20 && ! element.classList.contains( 'too-wide' ) || lightBoxType === 'iframe' ) { setTimeout( function() { var contentImage = lightBoxContainer.querySelector('.lightBoxContent > img'); var contentHeight = content.offsetHeight; var contentWidth = content.offsetWidth; // set height manually for non-Webkit browsers if ( contentImage ) { lightBoxBox.style.height = contentHeight + 'px'; lightBoxBox.style.width = contentWidth + 'px'; } // check if container height and width match the element height and width // due to the fact that large image are getting resized if ( height !== contentHeight) height = contentHeight + 6; if ( width !== contentWidth ) width = contentWidth + 6; element.style.left = ( bodyWidth - width ) / 2 + 'px'; element.style.right = 'auto'; }, 10 ); } } // if element is too high and too wide and contains an image // calculate if the resized height or width is the limit var image = lightBoxContainer.querySelector('.lightBoxContent > img'); if ( image ) { var imageWidth = image.offsetWidth; if ( element.classList.contains( 'too-high' ) && element.classList.contains( 'too-wide' ) ) { var imageHeight = image.offsetHeight; if ( bodyWidth >= imageWidth + 60 ) { element.classList.remove( 'too-high' ); element.classList.remove( 'too-wide' ); // center again element.style.left = ( bodyWidth - imageWidth ) / 2 + 'px'; element.style.right = ( bodyWidth - imageWidth ) / 2 + 'px'; } else if ( bodyHeight > imageHeight + 60 ) { element.classList.remove( 'too-high' ); } } else if ( element.classList.contains( 'too-high' ) && ! element.classList.contains( 'too-wide' ) ) { // set width manually if ( image ) { lightBoxBox.style.width = imageWidth + 'px'; } // center again element.style.left = ( bodyWidth - imageWidth ) / 2 + 'px'; element.style.right = ( bodyWidth - imageWidth ) / 2 + 'px'; } } setTimeout( function() { element.style.removeProperty( 'opacity' ); }, 10 ); // fix wrong image width in Chrome document.body.style.zoom = 1.0000001; setTimeout( function() { document.body.style.zoom = 1; }, 50 ); // allow some time to flush the css buffer } // IE fix for `closest` if ( ! Element.prototype.matches ) Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; if ( ! Element.prototype.closest ) Element.prototype.closest = function( s ) { var el = this; var ancestor = this; if ( ! document.documentElement.contains( el ) ) return null; do { if ( ancestor.matches( s ) ) return ancestor; ancestor = ancestor.parentElement; } while ( ancestor !== null ); return null; }; // from:https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/remove()/remove().md ( function ( arr ) { arr.forEach( function ( item ) { if ( item.hasOwnProperty( 'remove' ) ) { return; } Object.defineProperty( item, 'remove', { configurable: true, enumerable: true, writable: true, value: function remove() { if ( this.parentNode !== null ) this.parentNode.removeChild( this ); } } ); } ); } )( [Element.prototype, CharacterData.prototype, DocumentType.prototype] ); (function () { if ( typeof window.CustomEvent === "function" ) return false; //If not IE function CustomEvent ( event, params ) { params = params || { bubbles: false, cancelable: false, detail: undefined }; var evt = document.createEvent( 'CustomEvent' ); evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); return evt; } CustomEvent.prototype = window.Event.prototype; window.CustomEvent = CustomEvent; } )();