Files
changedetection.io/changedetectionio/static/js/modal.js
T
dgtlmoon 3d14df6a11 Development branch merge into release/master
Multi-language / Translations Support (#3696)
  - Complete internationalization system implemented
  - Support for 7 languages: Czech (cs), German (de), French (fr), Italian (it), Korean (ko), Chinese Simplified (zh), Chinese Traditional (zh_TW)
  - Language selector with localized flags and theming
  - Flash message translations
  - Multiple translation fixes and improvements across all languages
  - Language setting preserved across redirects

  Pluggable Content Fetchers (#3653)
  - New architecture for extensible content fetcher system
  - Allows custom fetcher implementations

  Image / Screenshot Comparison Processor (#3680)
  - New processor for visual change detection (disabled for this release)
  - Supporting CSS/JS infrastructure added

  UI Improvements

  Design & Layout
  - Auto-generated tag color schemes
  - Simplified login form styling
  - Removed hard-coded CSS, moved to SCSS variables
  - Tag UI cleanup and improvements
  - Automatic tab wrapper functionality
  - Menu refactoring for better organization
  - Cleanup of offset settings
  - Hide sticky tabs on narrow viewports
  - Improved responsive layout (#3702)

  User Experience
  - Modal alerts/confirmations on delete/clear operations (#3693, #3598, #3382)
  - Auto-add https:// to URLs in quickwatch form if not present
  - Better redirect handling on login (#3699)
  - 'Recheck all' now returns to correct group/tag (#3673)
  - Language set redirect keeps hash fragment
  - More friendly human-readable text throughout UI

  Performance & Reliability

  Scheduler & Processing
  - Soft delays instead of blocking time.sleep() calls (#3710)
  - More resilient handling of same UUID being processed (#3700)
  - Better Puppeteer timeout handling
  - Improved Puppeteer shutdown/cleanup (#3692)
  - Requests cleanup now properly async

  History & Rendering
  - Faster server-side "difference" rendering on History page (#3442)
  - Show ignored/triggered rows in history
  - API: Retry watch data if watch dict changed (more reliable)

  API Improvements

  - Watch get endpoint: retry mechanism for changed watch data
  - WatchHistoryDiff API endpoint includes extra format args (#3703)

  Testing Improvements

  - Replace time.sleep with wait_for_notification_endpoint_output (#3716)
  - Test for mode switching (#3701)
  - Test for #3720 added (#3725)
  - Extract-text difference test fixes
  - Improved dev workflow

  Bug Fixes

  - Notification error text output (#3672, #3669, #3280)
  - HTML validation fixes (#3704)
  - Template discovery path fixes
  - Notification debug log now uses system locale for dates/times
  - Puppeteer spelling mistake in log output
  - Recalculation on anchor change
  - Queue bubble update disabled temporarily

  Dependency Updates

  - beautifulsoup4 updated (#3724)
  - psutil 7.1.0 → 7.2.1 (#3723)
  - python-engineio ~=4.12.3 → ~=4.13.0 (#3707)
  - python-socketio ~=5.14.3 → ~=5.16.0 (#3706)
  - flask-socketio ~=5.5.1 → ~=5.6.0 (#3691)
  - brotli ~=1.1 → ~=1.2 (#3687)
  - lxml updated (#3590)
  - pytest ~=7.2 → ~=9.0 (#3676)
  - jsonschema ~=4.0 → ~=4.25 (#3618)
  - pluggy ~=1.5 → ~=1.6 (#3616)
  - cryptography 44.0.1 → 46.0.3 (security) (#3589)

  Documentation

  - README updated with viewport size setup information

  Development Infrastructure

  - Dev container only built on dev branch
  - Improved dev workflow tooling
2026-01-12 17:50:53 +01:00

195 lines
6.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
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);
});
});