Accessibility pass: ARIA roles, label associations, CSS class migrations
- Add role=dialog/aria-modal/aria-labelledby to all 12 modal overlays (JS + PHP)
- Add aria-label="Close" to all 14 modal close buttons
- Add full ARIA combobox pattern to @mention autocomplete (listbox, option, aria-selected, aria-expanded)
- Add for= attributes to admin filter form labels (AuditLog, UserActivity, ApiKeys)
- Remove dead closeOnAdvancedSearchBackdropClick() from advanced-search.js
CSS/JS style cleanup:
- Move .ascii-banner static styles from JS inline to CSS class; add .ascii-banner--glow
- Add .ascii-banner-cursor, .loading-overlay--hiding, .has-overlay, tr[data-clickable]
- Add .animate-fadein/.animate-fadeout/.comment--deleting to ticket.css
- Add .lt-toast--hiding to base.css; remove opacity/transition inline JS
- Remove redundant cursor:pointer JS (already in th{} CSS rule)
- Remove trailing space in lt-select class attributes
Bug fixes:
- base.js: boot overlay opacity inline style was overriding .fade-out class opacity via
specificity (1000 vs 20), preventing the fade-out animation — removed
- ascii-banner.js: cursor used blink-caret (border-color only) instead of blink-cursor
(opacity-based), so the █ cursor never actually blinked — fixed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -51,14 +51,13 @@ $nonce = SecurityHeadersMiddleware::getNonce();
|
||||
<title>Ticket #<?php echo $ticket['ticket_id']; ?></title>
|
||||
<link rel="icon" type="image/png" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/images/favicon.png">
|
||||
<link rel="stylesheet" href="/assets/css/base.css">
|
||||
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/dashboard.css?v=20260319d">
|
||||
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/ticket.css?v=20260319d">
|
||||
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/dashboard.css?v=20260320">
|
||||
<link rel="stylesheet" href="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/css/ticket.css?v=20260320">
|
||||
<script nonce="<?php echo $nonce; ?>" src="/assets/js/base.js"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/toast.js"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/utils.js"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/markdown.js?v=20260131e"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/dashboard.js?v=20260205"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/ticket.js?v=20260131e"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/utils.js?v=20260320"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/markdown.js?v=20260320"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/dashboard.js?v=20260320"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/ticket.js?v=20260320"></script>
|
||||
<script nonce="<?php echo $nonce; ?>">
|
||||
// CSRF Token for AJAX requests
|
||||
window.CSRF_TOKEN = '<?php echo CsrfMiddleware::getToken(); ?>';
|
||||
@@ -428,7 +427,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
|
||||
<p>Drag and drop files here or click to browse</p>
|
||||
<p class="upload-hint">Max file size: <?php echo $GLOBALS['config']['MAX_UPLOAD_SIZE'] ? number_format($GLOBALS['config']['MAX_UPLOAD_SIZE'] / 1048576, 0) . 'MB' : '10MB'; ?></p>
|
||||
<input type="file" id="fileInput" multiple class="sr-only" aria-label="Upload files">
|
||||
<button type="button" id="browseFilesBtn" class="btn upload-browse-btn">Browse Files</button>
|
||||
<button type="button" id="browseFilesBtn" class="btn upload-browse-btn">BROWSE FILES</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="uploadProgress" class="upload-progress" style="display: none;">
|
||||
@@ -561,39 +560,36 @@ $nonce = SecurityHeadersMiddleware::getNonce();
|
||||
var cloneBtn = document.getElementById('cloneButton');
|
||||
if (cloneBtn) {
|
||||
cloneBtn.addEventListener('click', function() {
|
||||
if (confirm('Create a copy of this ticket? The new ticket will have the same title, description, priority, category, and type.')) {
|
||||
cloneBtn.disabled = true;
|
||||
cloneBtn.textContent = 'Cloning...';
|
||||
showConfirmModal(
|
||||
'Clone Ticket',
|
||||
'Create a copy of this ticket? The new ticket will have the same title, description, priority, category, and type.',
|
||||
'warning',
|
||||
function() {
|
||||
cloneBtn.disabled = true;
|
||||
cloneBtn.textContent = 'Cloning...';
|
||||
|
||||
fetch('/api/clone_ticket.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': window.CSRF_TOKEN
|
||||
},
|
||||
body: JSON.stringify({
|
||||
lt.api.post('/api/clone_ticket.php', {
|
||||
ticket_id: window.ticketData.ticket_id
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
toast.success('Ticket cloned successfully!');
|
||||
setTimeout(function() {
|
||||
window.location.href = '/ticket/' + data.new_ticket_id;
|
||||
}, 1000);
|
||||
} else {
|
||||
toast.error('Failed to clone ticket: ' + (data.error || 'Unknown error'));
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
lt.toast.success('Ticket cloned successfully!');
|
||||
setTimeout(function() {
|
||||
window.location.href = '/ticket/' + data.new_ticket_id;
|
||||
}, 1000);
|
||||
} else {
|
||||
lt.toast.error('Failed to clone ticket: ' + (data.error || 'Unknown error'));
|
||||
cloneBtn.disabled = false;
|
||||
cloneBtn.textContent = 'Clone';
|
||||
}
|
||||
})
|
||||
.catch(function(error) {
|
||||
lt.toast.error('Failed to clone ticket: ' + error.message);
|
||||
cloneBtn.disabled = false;
|
||||
cloneBtn.textContent = 'Clone';
|
||||
}
|
||||
})
|
||||
.catch(function(error) {
|
||||
toast.error('Failed to clone ticket: ' + error.message);
|
||||
cloneBtn.disabled = false;
|
||||
cloneBtn.textContent = 'Clone';
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -817,8 +813,8 @@ $nonce = SecurityHeadersMiddleware::getNonce();
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/keyboard-shortcuts.js"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/settings.js"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/keyboard-shortcuts.js?v=20260320"></script>
|
||||
<script nonce="<?php echo $nonce; ?>" src="<?php echo $GLOBALS['config']['ASSETS_URL']; ?>/js/settings.js?v=20260320"></script>
|
||||
<script nonce="<?php echo $nonce; ?>">if (window.lt) lt.keys.initDefaults();</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user