224 lines
6.9 KiB
JavaScript
224 lines
6.9 KiB
JavaScript
// 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 = `
|
|
<div class="overlay-dialog-content">
|
|
<div class="overlay-dialog-header">
|
|
<h3 class="overlay-dialog-title">${this.escapeHtml(this.title)}</h3>
|
|
${this.showCloseButton ? `
|
|
<button class="overlay-dialog-close" type="button" aria-label="Close">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="20" height="20">
|
|
<line x1="18" y1="6" x2="6" y2="18"/>
|
|
<line x1="6" y1="6" x2="18" y2="18"/>
|
|
</svg>
|
|
</button>
|
|
` : ''}
|
|
</div>
|
|
<div class="overlay-dialog-body">
|
|
<p class="overlay-dialog-message">${this.message}</p>
|
|
</div>
|
|
<div class="overlay-dialog-footer">
|
|
${this.cancelText ? `
|
|
<button class="overlay-dialog-btn overlay-dialog-btn-cancel" type="button">
|
|
${this.escapeHtml(this.cancelText)}
|
|
</button>
|
|
` : ''}
|
|
<button class="overlay-dialog-btn ${this.confirmClass}" type="button">
|
|
${this.escapeHtml(this.confirmText)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
// 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
|
|
});
|
|
};
|