Files
dgtlmoon 48e21226a1
Some checks failed
Build and push containers / metadata (push) Has been cancelled
Build and push containers / build-push-containers (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/amd64 (alpine) (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/arm64 (alpine) (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/amd64 (main) (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/arm/v7 (main) (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/arm/v8 (main) (push) Has been cancelled
ChangeDetection.io Container Build Test / Build linux/arm64 (main) (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
UI - Add modal alert/confirmations on delete/clear #3598 #3382 (#3693)
2025-12-30 19:03:26 +01:00

195 lines
6.0 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Modern modal dialog system using HTML5 <dialog> element
* Provides accessible, animated confirmation dialogs
*/
const ModalDialog = {
/**
* Show a confirmation dialog
* @param {Object} options - Configuration options
* @param {string} options.title - Dialog title
* @param {string} options.message - Dialog message (can include HTML)
* @param {string} options.type - Dialog type: 'danger', 'warning', or 'info' (default: 'info')
* @param {string} options.confirmText - Confirm button text (default: 'Confirm')
* @param {string} options.cancelText - Cancel button text (default: 'Cancel')
* @param {Function} options.onConfirm - Callback when confirmed
* @param {Function} options.onCancel - Callback when cancelled (optional)
* @returns {Promise} Resolves with true if confirmed, false if cancelled
*/
confirm: function(options) {
return new Promise((resolve) => {
const defaults = {
title: 'Confirm Action',
message: 'Are you sure?',
type: 'info',
confirmText: 'Confirm',
cancelText: 'Cancel',
onConfirm: null,
onCancel: null
};
const config = { ...defaults, ...options };
// Icon mapping
const icons = {
danger: '⚠️',
warning: '⚠️',
info: ''
};
// Create dialog element
const dialog = document.createElement('dialog');
dialog.className = 'modal-dialog';
dialog.setAttribute('aria-labelledby', 'modal-title');
dialog.setAttribute('aria-describedby', 'modal-body');
// Build dialog content
dialog.innerHTML = `
<div class="modal-header">
<span class="modal-icon ${config.type}">${icons[config.type] || icons.info}</span>
<h2 class="modal-title" id="modal-title">${config.title}</h2>
</div>
<div class="modal-body" id="modal-body">
${config.message}
</div>
<div class="modal-footer">
<button type="button" class="modal-btn-cancel pure-button" data-action="cancel">
${config.cancelText}
</button>
<button type="button" class="modal-btn-${config.type} pure-button" data-action="confirm">
${config.confirmText}
</button>
</div>
`;
// Append to body
document.body.appendChild(dialog);
// Handle button clicks
const handleClose = (confirmed) => {
dialog.close();
setTimeout(() => {
dialog.remove();
}, 200);
if (confirmed && config.onConfirm) {
config.onConfirm();
} else if (!confirmed && config.onCancel) {
config.onCancel();
}
resolve(confirmed);
};
// Attach event listeners
dialog.querySelector('[data-action="confirm"]').addEventListener('click', () => {
handleClose(true);
});
dialog.querySelector('[data-action="cancel"]').addEventListener('click', () => {
handleClose(false);
});
// Handle Escape key
dialog.addEventListener('cancel', (e) => {
e.preventDefault();
handleClose(false);
});
// Handle backdrop click
dialog.addEventListener('click', (e) => {
const rect = dialog.getBoundingClientRect();
if (
e.clientY < rect.top ||
e.clientY > rect.bottom ||
e.clientX < rect.left ||
e.clientX > rect.right
) {
handleClose(false);
}
});
// Show dialog
dialog.showModal();
// Focus confirm button for accessibility
setTimeout(() => {
dialog.querySelector('[data-action="confirm"]').focus();
}, 100);
});
},
/**
* Helper method for delete confirmations
* @param {string} itemName - Name of the item being deleted
* @param {Function} onConfirm - Callback when confirmed
*/
confirmDelete: function(itemName, onConfirm) {
return this.confirm({
title: 'Delete ' + itemName + '?',
message: `<p>Are you sure you want to delete <strong>${itemName}</strong>?</p><p>This action cannot be undone.</p>`,
type: 'danger',
confirmText: 'Delete',
cancelText: 'Cancel',
onConfirm: onConfirm
});
},
/**
* Helper method for unlink confirmations
* @param {string} itemName - Name of the item being unlinked
* @param {Function} onConfirm - Callback when confirmed
*/
confirmUnlink: function(itemName, onConfirm) {
return this.confirm({
title: 'Unlink ' + itemName + '?',
message: `<p>Are you sure you want to unlink all watches from <strong>${itemName}</strong>?</p><p>The tag will be kept but watches will be removed from it.</p>`,
type: 'warning',
confirmText: 'Unlink',
cancelText: 'Cancel',
onConfirm: onConfirm
});
}
};
// Make available globally
window.ModalDialog = ModalDialog;
/**
* Auto-attach modal confirmations to links with data-requires-confirm attribute
* Usage in HTML:
* <a href="/delete"
* data-requires-confirm
* data-confirm-type="danger"
* data-confirm-title="Delete Item?"
* data-confirm-message="Are you sure?"
* data-confirm-button="Delete">
*/
$(document).ready(function() {
$(document).on('click', 'a[data-requires-confirm], button[data-requires-confirm]', function(e) {
e.preventDefault();
const $element = $(this);
const url = $element.attr('href');
const config = {
type: $element.data('confirm-type') || 'danger',
title: $element.data('confirm-title') || 'Confirm Action',
message: $element.data('confirm-message') || '<p>Are you sure you want to proceed?</p>',
confirmText: $element.data('confirm-button') || 'Confirm',
cancelText: $element.data('cancel-button') || 'Cancel',
onConfirm: function() {
// If it's a link, navigate to the URL
if ($element.is('a')) {
window.location.href = url;
}
// If it's a button in a form, submit the form
else if ($element.is('button')) {
$element.closest('form').submit();
}
}
};
ModalDialog.confirm(config);
});
});