fix: toggle aria-hidden on modal open/close for screen reader accessibility
This commit is contained in:
+39
-13
@@ -1909,7 +1909,7 @@
|
|||||||
═══════════════════════════════════════════════════════════════════════ -->
|
═══════════════════════════════════════════════════════════════════════ -->
|
||||||
<div id="tabNavigate" class="tab-panel">
|
<div id="tabNavigate" class="tab-panel">
|
||||||
<div class="detail-header">
|
<div class="detail-header">
|
||||||
<button class="back-btn" onclick="closeNavigate()">← Back</button>
|
<button class="back-btn" onclick="navBackToPrevious()">← Back</button>
|
||||||
<div class="dh-info">
|
<div class="dh-info">
|
||||||
<div id="navDestName" style="font-size:18px;font-weight:700;">Navigate</div>
|
<div id="navDestName" style="font-size:18px;font-weight:700;">Navigate</div>
|
||||||
<div id="navDestAddr" style="font-size:12px;color:var(--text2);"></div>
|
<div id="navDestAddr" style="font-size:12px;color:var(--text2);"></div>
|
||||||
@@ -2373,7 +2373,7 @@
|
|||||||
<!-- ═══════════════════════════════════════════════════════════════════════
|
<!-- ═══════════════════════════════════════════════════════════════════════
|
||||||
MODAL
|
MODAL
|
||||||
═══════════════════════════════════════════════════════════════════════ -->
|
═══════════════════════════════════════════════════════════════════════ -->
|
||||||
<div class="modal-overlay" id="modalOverlay">
|
<div class="modal-overlay" id="modalOverlay" aria-hidden="true">
|
||||||
<div class="modal" id="modalDialog" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
|
<div class="modal" id="modalDialog" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
|
||||||
<div class="modal-title" id="modalTitle">Confirm</div>
|
<div class="modal-title" id="modalTitle">Confirm</div>
|
||||||
<div class="modal-body" id="modalBody">Are you sure?</div>
|
<div class="modal-body" id="modalBody">Are you sure?</div>
|
||||||
@@ -2920,7 +2920,9 @@
|
|||||||
|
|
||||||
// Save focus and show
|
// Save focus and show
|
||||||
modalFocusRestore = document.activeElement;
|
modalFocusRestore = document.activeElement;
|
||||||
document.getElementById('modalOverlay').classList.add('open');
|
const overlay = document.getElementById('modalOverlay');
|
||||||
|
overlay.setAttribute('aria-hidden', 'false');
|
||||||
|
overlay.classList.add('open');
|
||||||
|
|
||||||
// Focus the right element
|
// Focus the right element
|
||||||
if (opts.type === 'prompt') {
|
if (opts.type === 'prompt') {
|
||||||
@@ -2937,7 +2939,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveModal(value) {
|
function resolveModal(value) {
|
||||||
document.getElementById('modalOverlay').classList.remove('open');
|
const overlay = document.getElementById('modalOverlay');
|
||||||
|
overlay.classList.remove('open');
|
||||||
|
overlay.setAttribute('aria-hidden', 'true');
|
||||||
if (modalResolve) {
|
if (modalResolve) {
|
||||||
// For form type, collect input values
|
// For form type, collect input values
|
||||||
if (modalType === 'form') {
|
if (modalType === 'form') {
|
||||||
@@ -4639,7 +4643,10 @@
|
|||||||
async function navigateToAsset() {
|
async function navigateToAsset() {
|
||||||
if (!AppState.currentAssetId) return;
|
if (!AppState.currentAssetId) return;
|
||||||
if (!AppState.gpsLat || !AppState.gpsLng) {
|
if (!AppState.gpsLat || !AppState.gpsLng) {
|
||||||
showToast('GPS location not available. Tap ◎ My Location first.', true);
|
showToast('GPS location not available — enable location access to navigate', true);
|
||||||
|
// Still go to navigate tab to show the GPS warning UI
|
||||||
|
AppState._navData = null;
|
||||||
|
switchTab('tabNavigate');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -4818,24 +4825,40 @@
|
|||||||
const clearBtn = document.getElementById('clearNavSearch');
|
const clearBtn = document.getElementById('clearNavSearch');
|
||||||
if (clearBtn) clearBtn.style.display = q ? '' : 'none';
|
if (clearBtn) clearBtn.style.display = q ? '' : 'none';
|
||||||
if (!q) { results.innerHTML = ''; return; }
|
if (!q) { results.innerHTML = ''; return; }
|
||||||
|
|
||||||
|
const hasGPS = !!(AppState.gpsLat && AppState.gpsLng);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const assets = await api('/api/assets?q=' + encodeURIComponent(q) + '&limit=8');
|
const assets = await api('/api/assets?q=' + encodeURIComponent(q) + '&limit=8');
|
||||||
|
|
||||||
|
// Build results header with GPS status
|
||||||
|
let html = '';
|
||||||
|
if (!hasGPS) {
|
||||||
|
html += '<div style="font-size:12px;color:var(--amber);padding:4px 4px 8px;">📍 GPS off — straight-line routing only · <span style="text-decoration:underline;cursor:pointer;" onclick="reEnableGPS()">enable</span></div>';
|
||||||
|
}
|
||||||
|
|
||||||
if (!assets.length) {
|
if (!assets.length) {
|
||||||
results.innerHTML = '<div class="empty-state" style="padding:12px;">No assets found</div>';
|
html += '<div class="empty-state" style="padding:12px;">No assets found</div>';
|
||||||
|
results.innerHTML = html;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
results.innerHTML = assets.map(a => {
|
|
||||||
|
html += assets.map(a => {
|
||||||
const hasLocation = a.latitude != null && a.longitude != null;
|
const hasLocation = a.latitude != null && a.longitude != null;
|
||||||
return `<div class="asset-item" style="${hasLocation ? '' : 'opacity:0.5;'}"
|
const canNavigate = hasLocation && hasGPS;
|
||||||
onclick="navToSearchedAsset(${a.id})">
|
const clickAttr = canNavigate ? ` onclick="navToSearchedAsset(${a.id})" style="cursor:pointer;"` : ' style="opacity:0.45;cursor:default;"';
|
||||||
<div class="ai-icon cat-${cssSafe(a.category)}">📍</div>
|
const badge = !hasLocation ? '⚠ No GPS' : (!hasGPS ? '📍' : '🧭');
|
||||||
|
return `<div class="asset-item"${clickAttr}>
|
||||||
|
<div class="ai-icon cat-${cssSafe(a.category)}">${catIcon(a.category)}</div>
|
||||||
<div class="ai-info">
|
<div class="ai-info">
|
||||||
<div class="ai-name">${esc(a.name)}</div>
|
<div class="ai-name">${esc(a.name)}</div>
|
||||||
<div class="ai-meta">${esc(a.machine_id || '')} ${hasLocation ? '📍 ' + esc(a.address || 'GPS tagged') : '⚠ No location'}</div>
|
<div class="ai-meta">${esc(a.machine_id || '')} · ${badge} ${hasLocation ? esc(a.address || 'GPS tagged') : 'No coordinates'}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ai-arrow">→</div>
|
<div class="ai-arrow">${canNavigate ? '→' : ''}</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
|
results.innerHTML = html;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
results.innerHTML = '<div class="empty-state" style="padding:12px;">Search failed</div>';
|
results.innerHTML = '<div class="empty-state" style="padding:12px;">Search failed</div>';
|
||||||
}
|
}
|
||||||
@@ -4853,9 +4876,12 @@
|
|||||||
async function navToSearchedAsset(assetId) {
|
async function navToSearchedAsset(assetId) {
|
||||||
// Fetch asset details to get navigation data
|
// Fetch asset details to get navigation data
|
||||||
if (!AppState.gpsLat || !AppState.gpsLng) {
|
if (!AppState.gpsLat || !AppState.gpsLng) {
|
||||||
showToast('GPS location not available. Tap ◎ My Location first.', true);
|
showToast('GPS location not available — enable location access to navigate', true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Show loading feedback
|
||||||
|
const btn = document.querySelector(`#navSearchResults .asset-item[onclick*="${assetId}"]`);
|
||||||
|
if (btn) btn.style.opacity = '0.5';
|
||||||
try {
|
try {
|
||||||
const nav = await api('/api/assets/' + assetId +
|
const nav = await api('/api/assets/' + assetId +
|
||||||
'/navigation?lat=' + AppState.gpsLat + '&lng=' + AppState.gpsLng);
|
'/navigation?lat=' + AppState.gpsLat + '&lng=' + AppState.gpsLng);
|
||||||
|
|||||||
Reference in New Issue
Block a user