vvjl-1.0.3/js/vvjl.js

js/vvjl.js
/**
 * @file
 * VVJ Lightbox.
 *
 * Filename:     vvjl.js
 * Website:      https://www.flashwebcenter.com
 * Developer:    Alaa Haddad https://www.alaahaddad.com.
 */
((Drupal, once) => {
  'use strict';
  Drupal.behaviors.vvjLightbox = {
    attach: (context, settings) => {
      const currModal = context.querySelector('.lightbox-modal');
      if (!currModal) {
        return; // Exit if modal is not found in the context
      }

      const modalContent = currModal.querySelector('.lightbox-modal-content');
      const currentImageSpan = context.getElementById('current-image');
      let currentIndex = -1;
      let items = Array.from(context.querySelectorAll('.lightbox-row'));
      let lastFocusedElement;

      const updateItemCountClass = () => {
        const wrappers = context.querySelectorAll('.vvjl-inner');
        wrappers.forEach(wrapper => {
          const itemCount = wrapper.children.length - 1;
          wrapper.className = wrapper.className.replace(/\bgrid-count-\d+\b/g, '');
          wrapper.classList.add(`grid-count-${itemCount}`);
        });
      };

      const disableLinksInItems = (disable) => {
        items.forEach(item => {
          const links = item.querySelectorAll('a');
          links.forEach(link => {
            if (disable) {
              link.setAttribute('tabindex', '-1');
              link.addEventListener('click', preventDefaultHandler);
            } else {
              link.removeAttribute('tabindex');
              link.removeEventListener('click', preventDefaultHandler);
            }
          });
        });
      };

      const preventDefaultHandler = (event) => {
        event.preventDefault();
      };

      const updateModalContent = () => {
        const clonedElement = items[currentIndex].cloneNode(true);
        const imageElement = clonedElement.querySelector('.lightbox-image img');
        if (imageElement) {
          const fullImageUrl = imageElement.getAttribute('src');
          imageElement.src = fullImageUrl;
          imageElement.removeAttribute('height');
          imageElement.removeAttribute('width');
        }
        modalContent.innerHTML = '';
        modalContent.appendChild(clonedElement);
        modalContent.offsetHeight;
        modalContent.style.opacity = '1';
        modalContent.classList.remove('fade-in', 'fade-out');
        requestAnimationFrame(() => {
          modalContent.classList.add('fade-in');
        });
        updateCurrentImageIndex();
      };

      const updateCurrentImageIndex = () => {
        currentImageSpan.textContent = currentIndex + 1;
      };

      const openModal = (event) => {
        lastFocusedElement = document.activeElement;
        const lightboxRow = event.currentTarget.closest('.lightbox-row');
        currentIndex = items.indexOf(lightboxRow);
        updateModalContent();
        lightboxRow.setAttribute('aria-expanded', 'true');
        currModal.setAttribute('aria-hidden', 'false');
        currModal.style.display = 'block';
        currModal.focus();
        document.addEventListener('keydown', trapFocus);
        event.stopPropagation();
        disableLinksInItems(false); // Re-enable links when the modal is open
      };

      const closeModal = (event) => {
        modalContent.classList.remove('fade-in');
        modalContent.classList.add('fade-out');

        setTimeout(() => {
          currModal.style.display = 'none';
          currModal.setAttribute('aria-hidden', 'true');
          context.querySelectorAll('.lightbox-row[aria-expanded="true"]').forEach(row => row.setAttribute('aria-expanded', 'false'));
          currentIndex = -1;
          if (lastFocusedElement) {
            lastFocusedElement.focus();
          }
          document.removeEventListener('keydown', trapFocus);

          modalContent.classList.remove('fade-out');
          disableLinksInItems(true); // Disable links when the modal is closed
        }, 500);

        if (event) event.stopPropagation();
      };

      const navigateModal = (direction) => {
        context.querySelectorAll('.lightbox-row[aria-expanded="true"]').forEach(row => row.setAttribute('aria-expanded', 'false'));

        if (direction === 'next') {
          currentIndex = (currentIndex + 1) % items.length;
        } else if (direction === 'prev') {
          currentIndex = (currentIndex - 1 + items.length) % items.length;
        }

        items[currentIndex].setAttribute('aria-expanded', 'true');
        updateModalContent();
      };

      const trapFocus = (event) => {
        const focusableElements = currModal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
        const firstElement = focusableElements[0];
        const lastElement = focusableElements[focusableElements.length - 1];

        if (event.key === 'Tab') {
          if (event.shiftKey) {
            if (document.activeElement === firstElement) {
              lastElement.focus();
              event.preventDefault();
            }
          } else {
            if (document.activeElement === lastElement) {
              firstElement.focus();
              event.preventDefault();
            }
          }
        } else if (event.key === 'Escape') {
          closeModal(event);
        }
      };

      const initializeAriaAttributes = () => {
        // Ensure initial state of aria-hidden and aria-expanded on load
        items.forEach(item => {
          item.setAttribute('aria-expanded', 'false');
        });
        currModal.setAttribute('aria-hidden', 'true');
        disableLinksInItems(true); // Disable links initially when the page loads
      };

      once('modalExpand', '.lightbox-row', context).forEach(row => row.addEventListener('click', openModal));
      once('modalNavigation', '.modal-next, .modal-prev', context).forEach(button => button.addEventListener('click', event => {
        const direction = button.classList.contains('modal-next') ? 'next' : 'prev';
        navigateModal(direction);
        event.stopPropagation();
      }));

      context.addEventListener('click', event => {
        if (event.target.matches('.modal-close') || event.target.closest('.modal-close') || event.target === modalContent) {
          closeModal(event);
        }
      });

      window.addEventListener('load', () => {
        updateItemCountClass();
        initializeAriaAttributes(); // Initialize ARIA attributes on load
      });
    }
  };
})(Drupal, once);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc