Skip to content

Commit

Permalink
fix: add the ability to trigger reindex modals bu event-listener.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Thulin committed Dec 3, 2024
1 parent 560f53a commit 19c006f
Showing 1 changed file with 84 additions and 61 deletions.
145 changes: 84 additions & 61 deletions source/js/modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ class Modal {
this.modalId = null;
this.openTrigger = document.querySelectorAll('[data-open]');
this.closeTrigger = document.querySelectorAll('[data-close]');

this.dialogs = document.querySelectorAll('.c-modal');
this.galleryInstance = null;

// Enable modals on initialization
this.enableModals();

// Listen for reindexing events
document.addEventListener('reindexModals', () => this.reindexTriggers());
}

/**
Expand All @@ -22,111 +27,129 @@ class Modal {
enableModals() {
const self = this;

// Attach click handlers to open triggers
for (const trigger of this.openTrigger) {
trigger.addEventListener('click', function (e) {

self.modalId = trigger.getAttribute('data-open'); //this.dataset.open;
const modal = document.getElementById(self.modalId ?? '');

if (modal && !modal.hasAttribute('open')) { // check if the dialog is already open
modal.classList.add('c-modal--visible');

if (modal.nodeName === 'DIALOG') {
(modal as HTMLDialogElement).showModal();
}

}

if (trigger.getAttribute('data-large-img')) {
// Gallery
self.galleryInstance = new Gallery();
self.galleryInstance.enableGallery();
self.galleryInstance.initImage(
self.modalId,
trigger.getAttribute('data-large-img')
);
}

self.lockScroll();
trigger.addEventListener('click', function () {
self.modalId = trigger.getAttribute('data-open');
self.openModal(self.modalId ?? '', trigger.getAttribute('data-large-img') || null);
});

document.dispatchEvent(new CustomEvent('enableStyleguideModals'));
}

// Close
// Attach click handlers to close triggers
for (const trigger of this.closeTrigger) {
trigger.addEventListener('click', function (e) {
e.stopPropagation()
trigger.closest('dialog')?.close()
e.stopPropagation();
const modal = trigger.closest('dialog');
if (modal) {
(modal as HTMLDialogElement).close();
}
self.galleryInstance = null;
});
}

// Attach event listeners to dialog elements
for (const dialog of this.dialogs) {
dialog.addEventListener('close', function () {
dialog.classList.remove('c-modal--visible');
self.unlockScroll();
});

dialog.addEventListener('click', (e) => this.handleClickOutside(e))
dialog.addEventListener('click', (e) => this.handleClickOutside(e));
}

document.dispatchEvent(new CustomEvent('enableStyleguideModals'));
}

/**
* Programmatically open a modal
*/
openModal(modalId: string, largeImgUrl: string | null = null) {
const modal = document.getElementById(modalId);

if (!modal) {
console.warn(`Modal with ID "${modalId}" not found.`);
return;
}

if (!modal.hasAttribute('open')) {
modal.classList.add('c-modal--visible');

if (modal.nodeName === 'DIALOG') {
(modal as HTMLDialogElement).showModal();
}
}

if (largeImgUrl) {
this.galleryInstance = new Gallery();
this.galleryInstance.enableGallery();
this.galleryInstance.initImage(modalId, largeImgUrl);
}

this.lockScroll();
}

/**
* Handle clicks outside the modal
*/
handleClickOutside(e: Event) {
const dialogElement = <Element|null>e.target
const clientX = (e as MouseEvent).clientX ?? null
const clientY = (e as MouseEvent).clientY ?? null
const dialogElement = e.target as Element | null;
const clientX = (e as MouseEvent).clientX ?? null;
const clientY = (e as MouseEvent).clientY ?? null;

if( !dialogElement || !clientX || !clientY ) return
if (!dialogElement || !clientX || !clientY) return;

if (dialogElement && this.clickIsOutsideElement(dialogElement, clientX, clientY)) {
if (this.clickIsOutsideElement(dialogElement, clientX, clientY)) {
if (dialogElement.nodeName === 'DIALOG') {
(dialogElement as HTMLDialogElement).close()
(dialogElement as HTMLDialogElement).close();
}
}
}

/**
* Check if a click is outside the modal
*/
clickIsOutsideElement(element: Element, clientX: number, clientY: number) {
const boundingRect = element.getBoundingClientRect()

if (clientX < boundingRect.left) return true
if (clientX > boundingRect.right) return true
if (clientY < boundingRect.top) return true
if (clientY > boundingRect.bottom) return true

return false
const boundingRect = element.getBoundingClientRect();

return (
clientX < boundingRect.left ||
clientX > boundingRect.right ||
clientY < boundingRect.top ||
clientY > boundingRect.bottom
);
}

/**
* Lock scroll
* @returns {*}
*/
lockScroll() {
const overflowHidden = 'u-overflow--hidden';
document.querySelector(`body`)?.classList.add(overflowHidden);
document.body.classList.add(overflowHidden);
}

/**
* Unlock scroll
* @returns {*}
*/
unlockScroll() {
const overflowHidden = 'u-overflow--hidden';
document.querySelector(`body`)?.classList.remove(overflowHidden);
document.body.classList.remove(overflowHidden);
}
}

export function initializeModal() {
const observer = new MutationObserver((mutationsList, observer) => {
const modalInstance = new Modal();
modalInstance.enableModals();
});
/**
* Reindex triggers and dialogs
*/
reindexTriggers() {
this.openTrigger = document.querySelectorAll('[data-open]');
this.closeTrigger = document.querySelectorAll('[data-close]');
this.dialogs = document.querySelectorAll('.c-modal');

const config = { childList: true, subtree: true };
observer.observe(document.body, config);
// Re-enable modals with updated triggers
this.enableModals();
}
}

const modalInstance = new Modal();
modalInstance.enableModals();
export function initializeModal() {
new Modal();
}

export default Modal;
export default Modal;

0 comments on commit 19c006f

Please sign in to comment.