300 lines
9.4 KiB
JavaScript
300 lines
9.4 KiB
JavaScript
/**
|
|
* MicroModal Global Utilities
|
|
* Provides helper functions for MicroModal management
|
|
*/
|
|
|
|
class ModalManager {
|
|
constructor() {
|
|
this.initialized = false;
|
|
this.modals = new Map();
|
|
this.init();
|
|
}
|
|
|
|
/**
|
|
* Initialize MicroModal with default settings
|
|
*/
|
|
init() {
|
|
if (typeof MicroModal === 'undefined') {
|
|
console.warn('MicroModal is not loaded');
|
|
return;
|
|
}
|
|
|
|
if (this.initialized) {
|
|
return;
|
|
}
|
|
|
|
MicroModal.init({
|
|
onShow: (modal) => {
|
|
this.onModalShow(modal);
|
|
},
|
|
onClose: (modal) => {
|
|
this.onModalClose(modal);
|
|
},
|
|
openTrigger: 'data-micromodal-trigger',
|
|
closeTrigger: 'data-micromodal-close',
|
|
openClass: 'is-open',
|
|
disableScroll: true,
|
|
disableFocus: false,
|
|
awaitOpenAnimation: false,
|
|
awaitCloseAnimation: false,
|
|
debugMode: false
|
|
});
|
|
|
|
this.initialized = true;
|
|
console.log('MicroModal initialized');
|
|
}
|
|
|
|
/**
|
|
* Called when modal is shown
|
|
*/
|
|
onModalShow(modal) {
|
|
// Re-initialize Lucide icons when modal opens
|
|
if (typeof lucide !== 'undefined') {
|
|
lucide.createIcons();
|
|
}
|
|
|
|
// Add body class to prevent scrolling
|
|
document.body.classList.add('modal-open');
|
|
|
|
// Execute custom show callback if exists
|
|
if (modal && this.modals.has(modal.id)) {
|
|
const config = this.modals.get(modal.id);
|
|
if (config.onShow && typeof config.onShow === 'function') {
|
|
config.onShow(modal);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Called when modal is closed
|
|
*/
|
|
onModalClose(modal) {
|
|
// Remove body class
|
|
document.body.classList.remove('modal-open');
|
|
|
|
// Execute custom close callback if exists
|
|
if (modal && this.modals.has(modal.id)) {
|
|
const config = this.modals.get(modal.id);
|
|
if (config.onClose && typeof config.onClose === 'function') {
|
|
config.onClose(modal);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show modal with optional data
|
|
*/
|
|
show(modalId, data = {}) {
|
|
if (typeof MicroModal === 'undefined') {
|
|
console.error('MicroModal is not available');
|
|
return;
|
|
}
|
|
|
|
// Update modal content if data is provided
|
|
if (Object.keys(data).length > 0) {
|
|
this.updateModalContent(modalId, data);
|
|
}
|
|
|
|
MicroModal.show(modalId);
|
|
}
|
|
|
|
/**
|
|
* Close modal
|
|
*/
|
|
close(modalId) {
|
|
if (typeof MicroModal === 'undefined') {
|
|
console.error('MicroModal is not available');
|
|
return;
|
|
}
|
|
|
|
MicroModal.close(modalId);
|
|
}
|
|
|
|
/**
|
|
* Register a modal with custom configuration
|
|
*/
|
|
register(modalId, config = {}) {
|
|
this.modals.set(modalId, config);
|
|
}
|
|
|
|
/**
|
|
* Update modal content dynamically
|
|
*/
|
|
updateModalContent(modalId, data) {
|
|
const modal = document.getElementById(modalId);
|
|
if (!modal) {
|
|
console.error(`Modal ${modalId} not found`);
|
|
return;
|
|
}
|
|
|
|
// Update text content for elements with data-modal-* attributes
|
|
Object.keys(data).forEach(key => {
|
|
const element = modal.querySelector(`[data-modal-${key}]`);
|
|
if (element) {
|
|
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
|
|
element.value = data[key];
|
|
} else {
|
|
element.textContent = data[key];
|
|
}
|
|
}
|
|
|
|
// Also support getElementById for backward compatibility
|
|
const elementById = modal.querySelector(`#${key}`);
|
|
if (elementById) {
|
|
if (elementById.tagName === 'INPUT' || elementById.tagName === 'TEXTAREA') {
|
|
elementById.value = data[key];
|
|
} else {
|
|
elementById.textContent = data[key];
|
|
}
|
|
}
|
|
});
|
|
|
|
// Update form action if provided
|
|
if (data.formAction) {
|
|
const form = modal.querySelector('form');
|
|
if (form) {
|
|
form.action = data.formAction;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a confirmation modal dynamically
|
|
*/
|
|
showConfirmation(options = {}) {
|
|
const defaults = {
|
|
modalId: 'confirmationModal',
|
|
title: 'Confirm Action',
|
|
message: 'Are you sure?',
|
|
confirmText: 'Confirm',
|
|
cancelText: 'Cancel',
|
|
confirmClass: 'btn btn-primary btn-sm',
|
|
cancelClass: 'btn btn-outline-secondary btn-sm',
|
|
onConfirm: null,
|
|
onCancel: null
|
|
};
|
|
|
|
const config = { ...defaults, ...options };
|
|
|
|
// Create modal HTML if it doesn't exist
|
|
let modal = document.getElementById(config.modalId);
|
|
if (!modal) {
|
|
modal = this.createConfirmationModal(config);
|
|
document.body.appendChild(modal);
|
|
} else {
|
|
// Update existing modal
|
|
this.updateConfirmationModal(modal, config);
|
|
}
|
|
|
|
// Register callbacks
|
|
this.register(config.modalId, {
|
|
onShow: () => {
|
|
const confirmBtn = modal.querySelector('.modal__confirm');
|
|
const cancelBtn = modal.querySelector('.modal__cancel');
|
|
|
|
// Remove existing event listeners
|
|
confirmBtn.replaceWith(confirmBtn.cloneNode(true));
|
|
cancelBtn.replaceWith(cancelBtn.cloneNode(true));
|
|
|
|
// Add new event listeners
|
|
modal.querySelector('.modal__confirm').addEventListener('click', (e) => {
|
|
if (config.onConfirm && typeof config.onConfirm === 'function') {
|
|
config.onConfirm(e);
|
|
}
|
|
this.close(config.modalId);
|
|
});
|
|
|
|
modal.querySelector('.modal__cancel').addEventListener('click', (e) => {
|
|
if (config.onCancel && typeof config.onCancel === 'function') {
|
|
config.onCancel(e);
|
|
}
|
|
this.close(config.modalId);
|
|
});
|
|
}
|
|
});
|
|
|
|
this.show(config.modalId);
|
|
}
|
|
|
|
/**
|
|
* Create confirmation modal HTML
|
|
*/
|
|
createConfirmationModal(config) {
|
|
const modalHtml = `
|
|
<div class="modal micromodal-slide" id="${config.modalId}" aria-hidden="true">
|
|
<div class="modal__overlay" tabindex="-1" data-micromodal-close>
|
|
<div class="modal__container modal--sm" role="dialog" aria-modal="true">
|
|
<header class="modal__header bg-primary text-white">
|
|
<h6 class="modal__title">${config.title}</h6>
|
|
<button class="modal__close" aria-label="Close modal" data-micromodal-close>
|
|
<i data-lucide="x"></i>
|
|
</button>
|
|
</header>
|
|
<main class="modal__content">
|
|
<div class="text-center">
|
|
<p class="mb-0">${config.message}</p>
|
|
</div>
|
|
</main>
|
|
<footer class="modal__footer justify-content-center">
|
|
<button type="button" class="modal__cancel ${config.cancelClass}" data-micromodal-close>
|
|
${config.cancelText}
|
|
</button>
|
|
<button type="button" class="modal__confirm ${config.confirmClass}">
|
|
${config.confirmText}
|
|
</button>
|
|
</footer>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
const div = document.createElement('div');
|
|
div.innerHTML = modalHtml;
|
|
return div.firstElementChild;
|
|
}
|
|
|
|
/**
|
|
* Update existing confirmation modal
|
|
*/
|
|
updateConfirmationModal(modal, config) {
|
|
modal.querySelector('.modal__title').textContent = config.title;
|
|
modal.querySelector('.modal__content p').textContent = config.message;
|
|
modal.querySelector('.modal__confirm').textContent = config.confirmText;
|
|
modal.querySelector('.modal__cancel').textContent = config.cancelText;
|
|
|
|
// Update button classes
|
|
modal.querySelector('.modal__confirm').className = `modal__confirm ${config.confirmClass}`;
|
|
modal.querySelector('.modal__cancel').className = `modal__cancel ${config.cancelClass}`;
|
|
}
|
|
}
|
|
|
|
// Global instance
|
|
window.ModalManager = new ModalManager();
|
|
|
|
// Helper functions for backward compatibility
|
|
window.showModal = (modalId, data = {}) => {
|
|
window.ModalManager.show(modalId, data);
|
|
};
|
|
|
|
window.closeModal = (modalId) => {
|
|
window.ModalManager.close(modalId);
|
|
};
|
|
|
|
window.showConfirmation = (options) => {
|
|
window.ModalManager.showConfirmation(options);
|
|
};
|
|
|
|
// Auto-initialize when DOM is loaded
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Initialize Lucide icons
|
|
if (typeof lucide !== 'undefined') {
|
|
lucide.createIcons();
|
|
}
|
|
|
|
console.log('Modal utilities loaded');
|
|
});
|
|
|
|
// Export for ES modules
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = ModalManager;
|
|
} |