Files
jared 914c33ecf3 Fix CSP-blocked chart scripts, undefined CSS classes, and double-firing click handlers
- Add nonce to charts and ticket-preview drawer inline <script> blocks in
  DashboardView.php (both were CSP-blocked — charts never rendered)
- Add .lt-modal-xs (280px) to base.css — used by quickStatus/quickAssign
  modals but was undefined, causing them to use full modal width
- Fix showConfirmModal in utils.js: class="text-center" → "lt-text-center"
  (undefined class); escape newlines as <br> so multi-line messages render
- Remove duplicate click-handler cases from DashboardView.php inline script
  that were already handled by dashboard.js, preventing double-firing
  (export-tickets, open-settings, remove-filter, etc. were all called twice)
- Fix manual-refresh action to use lt.autoRefresh.now() instead of bare
  window.location.reload() so modal/focus guards are respected

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 23:00:35 -04:00

56 lines
2.7 KiB
JavaScript

// XSS prevention helper — delegates to lt.escHtml() from web_template/base.js
function escapeHtml(text) {
return lt.escHtml(text);
}
// Get ticket ID from URL (handles both /ticket/123 and ?id=123 formats)
function getTicketIdFromUrl() {
const pathMatch = window.location.pathname.match(/\/ticket\/(\d+)/);
if (pathMatch) return pathMatch[1];
const params = new URLSearchParams(window.location.search);
return params.get('id');
}
/**
* Show a terminal-style confirmation modal using the lt.modal system.
* @param {string} title - Modal title
* @param {string} message - Confirmation message
* @param {string} type - 'warning' | 'error' | 'info'
* @param {Function} onConfirm - Called when user confirms
* @param {Function|null} onCancel - Called when user cancels
*/
function showConfirmModal(title, message, type = 'warning', onConfirm, onCancel = null) {
const modalId = 'confirmModal' + Date.now();
const colors = { warning: 'var(--terminal-amber)', error: 'var(--status-closed)', info: 'var(--terminal-cyan)' };
const icons = { warning: '[ ! ]', error: '[ X ]', info: '[ i ]' };
const color = colors[type] || colors.warning;
const icon = icons[type] || icons.warning;
const safeTitle = lt.escHtml(title);
const safeMessage = lt.escHtml(message).replace(/\n/g, '<br>');
document.body.insertAdjacentHTML('beforeend', `
<div class="lt-modal-overlay" id="${modalId}" aria-hidden="true" role="dialog" aria-modal="true" aria-labelledby="${modalId}_title">
<div class="lt-modal lt-modal-sm">
<div class="lt-modal-header" style="color:${color};">
<span class="lt-modal-title" id="${modalId}_title">${icon} ${safeTitle}</span>
<button class="lt-modal-close" data-modal-close aria-label="Close">✕</button>
</div>
<div class="lt-modal-body lt-text-center">
<p>${safeMessage}</p>
</div>
<div class="lt-modal-footer">
<button class="lt-btn lt-btn-primary" id="${modalId}_confirm">CONFIRM</button>
<button class="lt-btn lt-btn-ghost" id="${modalId}_cancel">CANCEL</button>
</div>
</div>
</div>
`);
const modal = document.getElementById(modalId);
lt.modal.open(modalId);
const cleanup = (cb) => { lt.modal.close(modalId); setTimeout(() => modal.remove(), 300); if (cb) cb(); };
document.getElementById(`${modalId}_confirm`).addEventListener('click', () => cleanup(onConfirm));
document.getElementById(`${modalId}_cancel`).addEventListener('click', () => cleanup(onCancel));
modal.querySelector('[data-modal-close]').addEventListener('click', () => cleanup(onCancel));
}