Created
September 12, 2023 18:23
-
-
Save kodie/73e923a3dc5eb6d8f680463ac43d1af4 to your computer and use it in GitHub Desktop.
A modal function created by a former HM developer - Simply here so we can pull it in remotely until it can be replaced
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// BUG | |
// Sometimes a newly opened modal sets the image height to zero | |
// Stupid ios menu bar showing/hiding counts as a screen resize | |
// Can't calculate height with padding before resize to adjust top positioning | |
// - After resize, calculate the difference between the height of the content | |
// and the height of the image-holder and set the top of the content to | |
// scrollTop + the difference in top height | |
// ------------------------------------------------------------------------------- | |
jQuery(function($) { | |
$('a[data-hmodal]').on('click', function(e) { | |
e.preventDefault(); | |
var currentHmodalElement = $(this), | |
hmodalId = currentHmodalElement.data('hmodal'), | |
liveImages = [], | |
liveImageIdx = 0, | |
fadeSpeed = 400, | |
resizeSpeed = 400, | |
imageBound = false, | |
customOrder = false, | |
activeAnimation = false, | |
resizingImageActive = false, | |
swappingCaption = false, | |
$hmodalContent, | |
$activeImage, | |
imgPaddingTop, | |
imgPaddingRight, | |
imgPaddingBottom, | |
imgPaddingLeft; | |
// Get custom settings | |
// ------------------------------------------------------------------------------- | |
if($('[data-for-hmodal="' + hmodalId + '"]').length) { | |
var $theModal = $('[data-for-hmodal="' + hmodalId + '"]'); | |
if($theModal.data('hmodal-imagebound') == true) { | |
imageBound = true; | |
} | |
if($theModal.data('hmodal-custom-order').length) { | |
customOrder = true; | |
} | |
} | |
// Give each hmodal element an index | |
// ------------------------------------------------------------------------------- | |
$('[data-hmodal="' + hmodalId + '"]').each(function(i) { | |
if(!$(this).data('hmodal-idx')) { | |
$(this).attr('data-hmodal-idx', i); | |
} | |
}); | |
/** | |
* Detect if the image being displayed is portrait or landscape | |
* param DOM Object img Image being activated | |
* return String portrait/landscape Image orientation | |
*/ | |
function portraitOrLandscape(img) { | |
if(img[0].naturalHeight > img[0].naturalWidth) { | |
return 'portrait'; | |
} else { | |
return 'landscape'; | |
} | |
} | |
/** | |
* Resize everything when the modal is opened for the firs time or an image changes | |
* return Void | |
*/ | |
function resizeModal() { | |
if(resizingImageActive == false) { | |
resizingImageActive = true; | |
getUpdatedPadding(); | |
var maxImageHeight = $activeImage[0].naturalHeight, | |
maxImageWidth = $activeImage[0].naturalWidth, | |
containerHeight = ($('#hmodal-content').outerHeight()), | |
containerWidth = $('#hmodal-content').outerWidth() - (imgPaddingLeft + imgPaddingRight), | |
waitTime = 0; | |
// If for some reason the sizes are 0 then wait a moment and retry | |
// ------------------------------------------------------------------------------- | |
if(maxImageHeight == 0 || maxImageHeight == 0) { | |
waitTime = 500; | |
} | |
setTimeout(function() { | |
maxImageHeight = $activeImage[0].naturalHeight; | |
maxImageWidth = $activeImage[0].naturalWidth; | |
// Make adjustment of top position to account for possible padding | |
$('#hmodal').animate({'top': $(window).scrollTop()}); | |
// Reset the content height so we can compare | |
// ------------------------------------------------------------------------------- | |
$('#hmodal-content').css({height: $('body').height()}); | |
containerHeight = $('#hmodal-content').height(); | |
// Check if the raw image height is taller than allowed. If so, then base the | |
// height off of the raw image height | |
// ------------------------------------------------------------------------------- | |
var adjustedHeight = maxImageHeight < containerHeight ? maxImageHeight : containerHeight - (imgPaddingTop + imgPaddingBottom); | |
// Base the new width off of the maximum image height since the image is shorter than our content | |
var newWidth = adjustedHeight * (maxImageWidth / maxImageHeight); | |
// If the image is wider than the body, then we're either on mobile or have a | |
// massive image. We'll want to adjust by width and not height | |
// ------------------------------------------------------------------------------- | |
if(newWidth + (imgPaddingLeft + imgPaddingRight) > containerWidth) { | |
var newAdjustedHeight = containerWidth * (maxImageHeight / maxImageWidth); | |
$activeImage.animate({height: newAdjustedHeight, width: containerWidth}, resizeSpeed); | |
// If imageBound, then keep all content and controlls no wider than the image | |
if(imageBound) { | |
$('#hmodal-counter, #hmodal-caption-wrap, #hmodal-controller').css('max-width', containerWidth) | |
} | |
} else { | |
$activeImage.animate({height: adjustedHeight, width: newWidth}, resizeSpeed); | |
// If imageBound, then keep all content and controlls no wider than the image | |
if(imageBound) { | |
$('#hmodal-counter, #hmodal-caption-wrap, #hmodal-controller').css('max-width', newWidth) | |
} | |
} | |
$activeImage.animate({opacity: 1}, fadeSpeed, function() { | |
// Reset this variable to indicate animation done so we can do other stuff | |
activeAnimation = false; | |
resizingImageActive = false; | |
}); | |
}, waitTime); | |
} | |
} | |
/** | |
* Switch to the next image | |
* return Void | |
*/ | |
function nextImg() { | |
if(activeAnimation == false) { | |
activeAnimation = true; | |
liveImageIdx += 1; | |
if(liveImageIdx > liveImages.length - 1) { | |
liveImageIdx = 0 | |
} | |
$('#hmodal-caption-wrap').height($('#hmodal-caption').height()); | |
updateSlideCount(); | |
$activeImage.animate({opacity: 0}, fadeSpeed, function() { | |
$activeImage.attr('src', liveImages[liveImageIdx].link).attr('alt', liveImages[liveImageIdx].alt); | |
$activeImage.load(function() { | |
if(imageBound) { | |
if(swappingCaption == false) { | |
swappingCaption = true; | |
$('#hmodal-caption').html(liveImages[liveImageIdx].caption); | |
$('#hmodal-caption-wrap').animate({height: $('#hmodal-caption').height()}, resizeSpeed, function() { | |
swappingCaption = false; | |
}); | |
} | |
} else { | |
$('#hmodal-caption').html(liveImages[liveImageIdx].caption); | |
} | |
resizeModal(); | |
}); | |
}); | |
} | |
} | |
/** | |
* Switch to the previous image | |
* return Void | |
*/ | |
function prevImg() { | |
if(activeAnimation == false) { | |
activeAnimation = true; | |
liveImageIdx -= 1; | |
if(liveImageIdx < 0) { | |
liveImageIdx = liveImages.length - 1; | |
} | |
$('#hmodal-caption-wrap').height($('#hmodal-caption').height()); | |
updateSlideCount(); | |
$activeImage.animate({opacity: 0}, fadeSpeed, function() { | |
$activeImage.attr('src', liveImages[liveImageIdx].link).attr('alt', liveImages[liveImageIdx].alt); | |
$activeImage.load(function() { | |
if(imageBound) { | |
if(swappingCaption == false) { | |
swappingCaption = true; | |
$('#hmodal-caption').html(liveImages[liveImageIdx].caption); | |
$('#hmodal-caption-wrap').animate({height: $('#hmodal-caption').height()}, resizeSpeed, function() { | |
swappingCaption = false; | |
}); | |
} | |
} else { | |
$('#hmodal-caption').html(liveImages[liveImageIdx].caption); | |
} | |
resizeModal(); | |
}); | |
}); | |
} | |
} | |
/** | |
* Update the slide counter as images are clicked through | |
* return Void | |
*/ | |
function updateSlideCount() { | |
$('#hmodal-img-idx').html(liveImageIdx + 1); | |
} | |
/** | |
* Close the modal when the close button is clicked | |
* return Void | |
*/ | |
function closeModal() { | |
// Can only run the callback on one element. Otherwise | |
// the callback runs once for each one. | |
// ------------------------------------------------------------------------------- | |
liveImageIdx = 0; | |
$('#hmodal-next').off('click'); | |
$('#hmodal-prev').off('click'); | |
$('#hmodal, #hmodal-overlay').fadeOut(fadeSpeed, function() { | |
// $activeImage.css('opacity', 0); | |
$('#hmodal').remove(); | |
}); | |
} | |
/** | |
* Get padding since it might have been updated via CSS | |
* return Void | |
*/ | |
function getUpdatedPadding() { | |
imgPaddingTop = parseInt($('#hmodal-image-container').css('padding-top')); | |
imgPaddingRight = parseInt($('#hmodal-image-container').css('padding-right')); | |
imgPaddingBottom = parseInt($('#hmodal-image-container').css('padding-bottom')); | |
imgPaddingLeft = parseInt($('#hmodal-image-container').css('padding-left')); | |
} | |
/** | |
* Cycle through each modal item and build the modal image data | |
* return Void | |
*/ | |
function storeLiveImages(id) { | |
$('a[data-hmodal="' + id + '"]:not(.hmodal-exclude)').each(function(i) { | |
liveImages.push( | |
{ | |
'link': $(this).attr('href'), | |
'caption': $(this).data('hmodal-caption'), | |
'alt': $(this).children('img').attr('alt') ? $(this).children('img').attr('alt') : '', | |
'idx': $(this).data('hmodal-idx') | |
} | |
); | |
}); | |
} | |
/** | |
* Set the image index based on what image was clicked to open the modal | |
* param String path Image path to check for | |
* return Void | |
*/ | |
function setLiveIndex(el) { | |
liveImageIdx = el.data('hmodal-idx'); | |
} | |
var resizeTimer; | |
$(window).on('resize', function(e) { | |
clearTimeout(resizeTimer); | |
resizeTimer = setTimeout(function() { | |
$('#hmodal-caption-wrap').height($('#hmodal-caption').height()); | |
resizeModal(); | |
if(swappingCaption == false) { | |
swappingCaption = true; | |
$('#hmodal-caption-wrap').animate({height: $('#hmodal-caption').height()}, resizeSpeed, function() { | |
swappingCaption = false; | |
}); | |
} | |
}, 350); | |
}); | |
// Begin generating the base modal wrappers | |
// ------------------------------------------------------------------------------- | |
$('body').append('<div id="hmodal" />'); | |
var $hmodal = $('#hmodal'); | |
$hmodal.append('<div id="hmodal-content" />'); | |
$hmodalContent = $('#hmodal-content'); | |
$hmodalContent.append('<div id="hmodal-image-container" />'); | |
storeLiveImages(hmodalId); | |
setLiveIndex(currentHmodalElement); | |
$('#hmodal-image-container').append('<img id="active-hmodal-img" src="' + liveImages[liveImageIdx].link + '" alt="' + liveImages[liveImageIdx].caption + '" />'); | |
// imgPadding is used to adjust the math when resizing image to account for CSS padding | |
getUpdatedPadding(); | |
var $activeImage = $('#active-hmodal-img'); | |
var bindingElement = imageBound ? $('#hmodal-image-container') : $hmodalContent; | |
// Add controls and info elements | |
// ------------------------------------------------------------------------------- | |
if(customOrder) { | |
var settings = $('[data-for-hmodal="' + hmodalId + '"]').data('hmodal-custom-order').split(' '); | |
for(var i=0; i<settings.length; i++) { | |
switch(settings[i]) { | |
case 'controls': | |
bindingElement.append('<div id="hmodal-controller" />'); | |
$('#hmodal-controller').html('<a href="javascript:void(0)" id="hmodal-prev"></a><a href="javascript:void(0)" id="hmodal-next"></a>'); | |
$('#hmodal-next').off().on('click', nextImg); | |
$('#hmodal-prev').off().on('click', prevImg); | |
break; | |
case 'close': | |
bindingElement.append('<div id="hmodal-close" />'); | |
$('#hmodal-close').html('<a href="javascript:void(0)" id="hmodal-close-button"></a>'); | |
$('#hmodal-close').off().on('click', closeModal); | |
break; | |
case 'counter': | |
bindingElement.append('<div id="hmodal-counter" />'); | |
$('#hmodal-counter').html('<span id="hmodal-img-idx">' + (liveImageIdx + 1) + '</span><span id="hmodal-count-delimiter">/</span><span id="hmodal-total-images">' + liveImages.length + '</span>'); | |
break; | |
case 'caption': | |
bindingElement.append('<div id="hmodal-caption-wrap" />'); | |
$('#hmodal-caption-wrap').html('<span id="hmodal-caption">' + currentHmodalElement.data('hmodal-caption') + '</span>'); | |
break; | |
} | |
} | |
} else { | |
bindingElement.append('<div id="hmodal-controller" />'); | |
$('#hmodal-controller').html('<a href="javascript:void(0)" id="hmodal-prev"></a><a href="javascript:void(0)" id="hmodal-next"></a>'); | |
$('#hmodal-next').off().on('click', nextImg); | |
$('#hmodal-prev').off().on('click', prevImg); | |
bindingElement.append('<div id="hmodal-close" />'); | |
$('#hmodal-close').html('<a href="javascript:void(0)" id="hmodal-close-button"></a>'); | |
$('#hmodal-close').off().on('click', closeModal); | |
bindingElement.append('<div id="hmodal-counter" />'); | |
$('#hmodal-counter').html('<span id="hmodal-img-idx">' + (liveImageIdx + 1) + '</span><span id="hmodal-count-delimiter">/</span><span id="hmodal-total-images">' + liveImages.length + '</span>'); | |
bindingElement.append('<div id="hmodal-caption-wrap" />'); | |
$('#hmodal-caption-wrap').html('<span id="hmodal-caption">' + currentHmodalElement.data('hmodal-caption') + '</span>'); | |
} | |
$hmodal.append('<div id="hmodal-overlay" />'); | |
$('#hmodal-overlay').fadeTo(400, $('#hmodal-overlay').css('opacity')); | |
$('#hmodal-overlay').off().on('click', closeModal); | |
// Position the modal to be 32px from the to of the current window position | |
// ------------------------------------------------------------------------------- | |
$('#hmodal').css({'top': $(window).scrollTop()}); | |
resizeModal(); | |
setTimeout(function() { | |
$hmodalContent.css('visibility', 'visible').animate({opacity: 1}, fadeSpeed); | |
}, 500); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#hmodal { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
top: 0; | |
left: 0; | |
z-index: 99999; | |
#hmodal-content { | |
visibility: hidden; | |
opacity: 0; | |
position: absolute; | |
top: 0; | |
left: 0; | |
right: 0; | |
margin: 0 auto; | |
height: 100%; | |
width: 90%; | |
max-height: 75%; | |
z-index: 99999; | |
opacity: 0; | |
overflow: visible !important; | |
#hmodal-image-container { | |
position: absolute; | |
left: 50%; | |
top: 50%; | |
background: #fff; | |
padding: .5rem; | |
// max-width: 100%; | |
-moz-transform: translate(-50%, -50%); | |
-o-transform: translate(-50%, -50%); | |
-ms-transform: translate(-50%, -50%); | |
-webkit-transform: translate(-50%, -50%); | |
transform: translate(-50%, -50%); | |
-moz-transition: all 0.15s ease-in-out; | |
-o-transition: all 0.15s ease-in-out; | |
-ms-transition: all 0.15s ease-in-out; | |
-webkit-transition: all 0.15s ease-in-out; | |
transition: all 0.15s ease-in-out; | |
img { | |
height: auto; | |
width: auto; | |
max-height: 100%; | |
max-width: none; | |
opacity: 0; | |
display: block; | |
} | |
} | |
} | |
#hmodal-overlay { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: #000; | |
opacity: .75; | |
display: none; | |
z-index: 88888; | |
} | |
#hmodal-close-button { | |
color: #fff; | |
&:after { | |
content: "Close"; | |
} | |
} | |
#hmodal-next { | |
color: #fff; | |
&:after { | |
content: "Next"; | |
} | |
} | |
#hmodal-prev { | |
color: #fff; | |
&:after { | |
content: "Prev"; | |
} | |
} | |
#hmodal-counter, #hmodal-caption-wrap, #hmodal-controller { | |
color: #fff; | |
} | |
#hmodal-caption { | |
display: inline-block; | |
overflow: hidden; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment