Skip to content

Instantly share code, notes, and snippets.

@robinbastien
Last active April 20, 2018 15:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robinbastien/2d95b6130f10e589249c to your computer and use it in GitHub Desktop.
Save robinbastien/2d95b6130f10e589249c to your computer and use it in GitHub Desktop.
jQuery Simple Modal
/*!
* jQuery.modal.js
*
* Creates a modal to use with images
*
* @author Robin Bastien <robin@machine-agency.com>
* @version 1.0.1
*
* @example
* $('.section--gallery').modal();
*
* @example with parameters
$('.section--gallery').modal({
attribute: 'data-modal',
class: 'modal__target',
close_button: '<i class="icon icon-close"></i>',
arrows: false,
arrow_next: '<i class="icon icon-arrow-right"></i>',
arrow_prev: '<i class="icon icon-arrow-left"></i>',
keycodes: true
});
*
*/
;(function($, window, document, undefined) {
/**
* Add the example function to the jQuery functions.
*
* @param Object options An object containing options for the plugin.
* @return Object Returns the jQuery object.
*/
$.fn.modal = function(options) {
// The default options for the plugin.
var defaults = {
attribute: 'data-modal', // attribute to pull the URL from
class: 'modal__target', // what class should we append to these to make them modal targets?
close_button: true,
close_html: '<i class="icon icon--close"></i>', // the HTML used in the close button
arrows: false,
arrow_next: '<i class="icon icon--arrow-right"></i>',
arrow_prev: '<i class="icon icon--arrow-left"></i>',
keycodes: true
};
var body = $('body');
var modal_wrapper = false;
var modal_content = false;
var modal_overlay = false;
var modal_close = false;
var modal_structure = '';
var $modal = $(this);
// Extend the options with all the defaults and overwrite any supplied
// options.
options = $.extend(defaults, options);
// If modal container doesn't exist...
if( !body.find('.modal__wrapper').length ) {
// Create the structure
modal_structure = '<div class="modal__wrapper"><div class="modal__overlay"></div><div class="modal">';
// Add the close button?
if( options.close_button ) modal_structure += '<div class="modal__close">'+ options.close_html+'</div>';
// Add the next/prev arrows?
if( options.arrows ) modal_structure += '<nav class="modal__arrows"><ul><li class="modal__arrow modal__arrow--prev">'+ options.arrow_prev+'</li><li class="modal__arrow modal__arrow--next">'+ options.arrow_next+'</li></ul></nav>';
// Add the innards
modal_structure += '<div class="modal__content"></div></div><!--.modal--></div><!--.modal__wrapper-->';
// Append it
body.append( modal_structure );
modal_wrapper = body.find('.modal__wrapper');
modal_content = body.find('.modal__content');
modal_overlay = body.find('.modal__overlay');
modal_close = body.find('.modal__close');
if( options.keycodes ) document.addEventListener("keyup", keyEvents, false);
}
function keyEvents( event ) {
if(event.keyCode==27) closeModal();
if(event.keyCode==37) nextImage();
if(event.keyCode==39) prevImage();
}
function openModal() {
modal_wrapper.addClass('is-active');
}
function closeModal() {
modal_wrapper.removeClass('is-active');
modal_content.html('');
body.find('.modal__active').removeClass('modal__active');
}
function nextImage() {
var active = $modal.find('.modal__active');
if( active.length ) {
// Get index + 1
var new_index = $modal.find('.' + options.class).index(active) + 1;
var new_image = $modal.find('.' + options.class + ':eq('+new_index+')');
var set_content;
// Unset the active item
active.removeClass('modal__active');
if( new_image.length ) {
new_image.addClass('modal__active');
// Get the new content
set_content = new_image.attr( options.attribute );
// Update the modal
setModalContent( set_content );
} else {
// Set the first one as the active item
new_image = $modal.find('.' + options.class + ':first');
new_image.addClass('modal__active');
// Get the new content
set_content = new_image.attr( options.attribute );
// Update the modal
setModalContent( set_content );
}
}
}
function prevImage() {
var active = $modal.find('.modal__active');
if( active.length ) {
// Get index + 1
var new_index = $modal.find('.' + options.class).index(active) - 1;
var new_image = $modal.find('.' + options.class + ':eq('+new_index+')');
if( new_image.length ) {
// Unset the active item
active.removeClass('modal__active');
new_image.addClass('modal__active');
// Get the new content
var set_content = new_image.attr( options.attribute );
// Update the modal
setModalContent( set_content );
}
}
}
function setModalContent( content ) {
modal_content.html( '<img src="' + content + '" class="modal__image">' );
}
// Loop through each item that the plugin is attached to.
this.each(function() {
// Make it a single object
$(this).find('[' + options.attribute + ']').each( function() {
$(this).addClass(options.class);
});
});
// attach a click event
body.on('click', '.' + options.class, function( event ) {
// Reset default func
event.preventDefault();
// Set Content
$this = $(this);
// If this has data-content, use that. Otherwise use itself
if( $this.attr(options.attribute) ) {
// Set as active
$this.addClass('modal__active');
// Update content
setModalContent($this.attr(options.attribute));
} else {
console.log('No modal attribute found on target element (' + options.attribute + ')');
}
// Open er up
openModal();
});
// On Close click
body.on('click', '.modal__overlay, .modal__close', closeModal);
// Arrows Click
if( options.arrows ) {
// Next
body.on('click', '.modal__arrow--next', nextImage);
// Prev
body.on('click', '.modal__arrow--prev', prevImage);
}
// Return the object for chaining.
return this;
};
})(jQuery, window, document);
/* ==========================================================================
Modal
========================================================================== */
.modal__wrapper {
display: none;
content: '';
position: fixed;
visibility: hidden;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: rgba(0,0,0,0);
z-index: -1;
-webkit-transition: background-color 0.6s ease-out;
transition: background-color 0.6s ease-out;
}
.modal__overlay {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
z-index: -1;
background-color: rgba(0,0,0,0);
pointer-events: none;
-webkit-transition: background-color 0.6s ease-out;
transition: background-color 0.6s ease-out;
}
.modal {
visibility: hidden;
width: auto;
height: auto;
padding: 2rem;
border-radius: 4px;
position: fixed;
top: 50%;
left: 50%;
background-color: #fff;
text-align: center;
z-index: 999;
-webkit-transform: translateX(-50%) translateY(-30%) scale(0.8);
transform: translateX(-50%) translateY(-30%) scale(0.8);
-webkit-transition: -webkit-transform 0.3s ease-out;
transition: transform 0.3s ease-out;
}
/* States */
.modal__wrapper.is-active {
display: block;
z-index: 998;
}
.modal__wrapper.is-active .modal__overlay {
background-color: rgba(0,0,0,0.5);
visibility: visible;
z-index: 998;
pointer-events: all;
}
.modal__wrapper.is-active .modal {
visibility: visible;
-webkit-transform: translateX(-50%) translateY(-50%) scale(1);
transform: translateX(-50%) translateY(-50%) scale(1);
}
.modal__image {
max-height: 90vh;
max-width: 90vw;
width: auto;
}
.modal__close {
position: absolute;
right: -0.5rem;
top: -0.5rem;
background-color: white;
border-radius: 99px;
line-height: 1;
padding: 0.1rem;
font-size: 1.3rem;
cursor: pointer;
}
/* Modal Arrows */
.modal__arrows {
position: absolute;
width: 100%;
left: 0;
bottom: -3rem;
}
.modal__arrows > ul {
list-style-type: none;
padding: 0;
margin: 0;
text-align: center;
}
.modal__arrow {
display: inline-block;
color: white;
font-size: 2rem;
cursor: pointer;
}
.modal__arrow--disabled {
cursor: not-allowed;
color: #bbb;
opacity: 0.7;
pointer-events: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment