96 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
/*
 | 
						|
 * Modal
 | 
						|
 *
 | 
						|
 * Pico.css - https://picocss.com
 | 
						|
 * Copyright 2019-2023 - Licensed under MIT
 | 
						|
 */
 | 
						|
 | 
						|
// Config
 | 
						|
const isOpenClass = 'modal-is-open';
 | 
						|
const openingClass = 'modal-is-opening';
 | 
						|
const closingClass = 'modal-is-closing';
 | 
						|
const animationDuration = 400; // ms
 | 
						|
let visibleModal = null;
 | 
						|
 | 
						|
 | 
						|
// Toggle modal
 | 
						|
const toggleModal = event => {
 | 
						|
  event.preventDefault();
 | 
						|
  const modal = document.getElementById(event.currentTarget.getAttribute('data-target'));
 | 
						|
  (typeof(modal) != 'undefined' && modal != null)
 | 
						|
    && isModalOpen(modal) ? closeModal(modal) : openModal(modal)
 | 
						|
}
 | 
						|
 | 
						|
// Is modal open
 | 
						|
const isModalOpen = modal => {
 | 
						|
  return modal.hasAttribute('open') && modal.getAttribute('open') != 'false' ? true : false;
 | 
						|
}
 | 
						|
 | 
						|
// Open modal
 | 
						|
const openModal = modal => {
 | 
						|
  if (isScrollbarVisible()) {
 | 
						|
    document.documentElement.style.setProperty('--scrollbar-width', `${getScrollbarWidth()}px`);
 | 
						|
  }
 | 
						|
  document.documentElement.classList.add(isOpenClass, openingClass);
 | 
						|
  setTimeout(() => {
 | 
						|
    visibleModal = modal;
 | 
						|
    document.documentElement.classList.remove(openingClass);
 | 
						|
  }, animationDuration);
 | 
						|
  modal.setAttribute('open', true);
 | 
						|
}
 | 
						|
 | 
						|
// Close modal
 | 
						|
const closeModal = modal => {
 | 
						|
  visibleModal = null;
 | 
						|
  document.documentElement.classList.add(closingClass);
 | 
						|
  setTimeout(() => {
 | 
						|
    document.documentElement.classList.remove(closingClass, isOpenClass);
 | 
						|
    document.documentElement.style.removeProperty('--scrollbar-width');
 | 
						|
    modal.removeAttribute('open');
 | 
						|
  }, animationDuration);
 | 
						|
}
 | 
						|
 | 
						|
// Close with a click outside
 | 
						|
document.addEventListener('click', event => {
 | 
						|
  if (visibleModal != null) {
 | 
						|
    const modalContent = visibleModal.querySelector('article');
 | 
						|
    const isClickInside = modalContent.contains(event.target);
 | 
						|
    !isClickInside && closeModal(visibleModal);
 | 
						|
  }
 | 
						|
});
 | 
						|
 | 
						|
// Close with Esc key
 | 
						|
document.addEventListener('keydown', event => {
 | 
						|
  if (event.key === 'Escape' && visibleModal != null) {
 | 
						|
    closeModal(visibleModal);
 | 
						|
  }
 | 
						|
});
 | 
						|
 | 
						|
// Get scrollbar width
 | 
						|
const getScrollbarWidth = () => {
 | 
						|
 | 
						|
  // Creating invisible container
 | 
						|
  const outer = document.createElement('div');
 | 
						|
  outer.style.visibility = 'hidden';
 | 
						|
  outer.style.overflow = 'scroll'; // forcing scrollbar to appear
 | 
						|
  outer.style.msOverflowStyle = 'scrollbar'; // needed for WinJS apps
 | 
						|
  document.body.appendChild(outer);
 | 
						|
 | 
						|
  // Creating inner element and placing it in the container
 | 
						|
  const inner = document.createElement('div');
 | 
						|
  outer.appendChild(inner);
 | 
						|
 | 
						|
  // Calculating difference between container's full width and the child width
 | 
						|
  const scrollbarWidth = (outer.offsetWidth - inner.offsetWidth);
 | 
						|
 | 
						|
  // Removing temporary elements from the DOM
 | 
						|
  outer.parentNode.removeChild(outer);
 | 
						|
 | 
						|
  return scrollbarWidth;
 | 
						|
}
 | 
						|
 | 
						|
// Is scrollbar visible
 | 
						|
const isScrollbarVisible = () => {
 | 
						|
  return document.body.scrollHeight > screen.height;
 | 
						|
}
 |