// Overlay Dialog Component - Reusable confirmation dialog class OverlayDialogComponent extends Component { constructor(container, viewModel, eventBus) { super(container, viewModel, eventBus); this.isVisible = false; this.onConfirm = null; this.onCancel = null; this.title = ''; this.message = ''; this.confirmText = 'Yes'; this.cancelText = 'No'; this.confirmClass = 'overlay-dialog-btn-confirm'; this.showCloseButton = true; } mount() { super.mount(); this.setupEventListeners(); } setupEventListeners() { // Close overlay when clicking outside or pressing escape this.addEventListener(this.container, 'click', (e) => { if (!this.isVisible) return; if (e.target === this.container) { this.hide(); } }); this.addEventListener(document, 'keydown', (e) => { if (e.key === 'Escape' && this.isVisible) { this.hide(); } }); } show(options = {}) { const { title = 'Confirm Action', message = 'Are you sure you want to proceed?', confirmText = 'Yes', cancelText = 'No', confirmClass = 'overlay-dialog-btn-confirm', showCloseButton = true, onConfirm = null, onCancel = null } = options; this.title = title; this.message = message; this.confirmText = confirmText; this.cancelText = cancelText; this.confirmClass = confirmClass; this.showCloseButton = showCloseButton; this.onConfirm = onConfirm; this.onCancel = onCancel; this.render(); // Add visible class with small delay for animation setTimeout(() => { this.container.classList.add('visible'); }, 10); this.isVisible = true; } hide() { this.container.classList.remove('visible'); setTimeout(() => { this.isVisible = false; // Call cancel callback if provided if (this.onCancel) { this.onCancel(); this.onCancel = null; } }, 300); } handleConfirm() { this.container.classList.remove('visible'); setTimeout(() => { this.isVisible = false; // Call confirm callback if provided if (this.onConfirm) { this.onConfirm(); this.onConfirm = null; } }, 300); } render() { this.container.innerHTML = `
`; // Add event listeners to buttons const closeBtn = this.container.querySelector('.overlay-dialog-close'); const cancelBtn = this.container.querySelector('.overlay-dialog-btn-cancel'); const confirmBtn = this.container.querySelector(`.${this.confirmClass}`); if (closeBtn) { this.addEventListener(closeBtn, 'click', () => this.hide()); } if (cancelBtn) { this.addEventListener(cancelBtn, 'click', () => this.hide()); } if (confirmBtn) { this.addEventListener(confirmBtn, 'click', () => this.handleConfirm()); } } escapeHtml(text) { if (typeof text !== 'string') return text; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } unmount() { // Clean up event listeners this.removeAllEventListeners(); // Call parent unmount super.unmount(); } } // Static utility methods for easy usage without mounting OverlayDialogComponent.show = function(options) { // Create a temporary container const container = document.createElement('div'); container.className = 'overlay-dialog'; document.body.appendChild(container); // Create component instance const dialog = new OverlayDialogComponent(container, null, null); // Override hide to clean up container const originalHide = dialog.hide.bind(dialog); dialog.hide = function() { originalHide(); setTimeout(() => { if (container.parentNode) { document.body.removeChild(container); } }, 350); }; // Override handleConfirm to clean up container const originalHandleConfirm = dialog.handleConfirm.bind(dialog); dialog.handleConfirm = function() { originalHandleConfirm(); setTimeout(() => { if (container.parentNode) { document.body.removeChild(container); } }, 350); }; dialog.mount(); dialog.show(options); return dialog; }; // Convenience method for confirmation dialogs OverlayDialogComponent.confirm = function(options) { return OverlayDialogComponent.show({ ...options, confirmClass: options.confirmClass || 'overlay-dialog-btn-confirm' }); }; // Convenience method for danger/delete confirmations OverlayDialogComponent.danger = function(options) { return OverlayDialogComponent.show({ ...options, confirmClass: 'overlay-dialog-btn-danger' }); }; // Convenience method for alerts OverlayDialogComponent.alert = function(message, title = 'Notice') { return OverlayDialogComponent.show({ title, message, confirmText: 'OK', cancelText: null, showCloseButton: false }); };