Restore previous focus when modal dialogs close.
This commit is contained in:
@@ -36,6 +36,7 @@ const renameIdValue = ref('')
|
||||
const editingPermDisplay = ref(null)
|
||||
const renameDisplayValue = ref('')
|
||||
const dialog = ref({ type: null, data: null, busy: false, error: '' })
|
||||
const dialogPreviousFocus = ref(null) // Track element that had focus before dialog opened
|
||||
const safeIdRegex = /[^A-Za-z0-9:._~-]/g
|
||||
|
||||
// Template refs for navigation
|
||||
@@ -404,8 +405,77 @@ async function toggleOrgPermission(org, permId, checked) {
|
||||
}
|
||||
}
|
||||
|
||||
function openDialog(type, data) { dialog.value = { type, data, busy: false, error: '' } }
|
||||
function closeDialog() { dialog.value = { type: null, data: null, busy: false, error: '' } }
|
||||
function openDialog(type, data) {
|
||||
const focused = document.activeElement
|
||||
dialogPreviousFocus.value = focused
|
||||
|
||||
// For delete operations, store sibling info to help restore focus after deletion
|
||||
if (type === 'confirm' && focused) {
|
||||
const row = focused.closest('tr')
|
||||
if (row) {
|
||||
const tbody = row.closest('tbody')
|
||||
if (tbody) {
|
||||
const rows = Array.from(tbody.querySelectorAll('tr'))
|
||||
const idx = rows.indexOf(row)
|
||||
// Store context to find next/prev row after deletion
|
||||
dialog.value.focusContext = {
|
||||
tbody,
|
||||
index: idx,
|
||||
total: rows.length,
|
||||
selector: 'button:not([disabled]), a'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dialog.value = { ...dialog.value, type, data, busy: false, error: '' }
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
const prev = dialogPreviousFocus.value
|
||||
const context = dialog.value.focusContext
|
||||
dialog.value = { type: null, data: null, busy: false, error: '' }
|
||||
// Restore focus after dialog closes
|
||||
restoreFocusAfterDialog(prev, context)
|
||||
dialogPreviousFocus.value = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore focus to the previously focused element, or find a sibling if deleted.
|
||||
*/
|
||||
function restoreFocusAfterDialog(prev, context) {
|
||||
if (!prev) return
|
||||
|
||||
// Check if the original element still exists in DOM and is focusable
|
||||
if (document.body.contains(prev) && !prev.disabled) {
|
||||
prev.focus()
|
||||
return
|
||||
}
|
||||
|
||||
// Element was deleted - try to find a sibling using stored context
|
||||
if (context?.tbody && context.selector) {
|
||||
const rows = Array.from(context.tbody.querySelectorAll('tr'))
|
||||
if (rows.length > 0) {
|
||||
// Try the same index (next row moved up) or the last row
|
||||
const targetIdx = Math.min(context.index, rows.length - 1)
|
||||
const targetRow = rows[targetIdx]
|
||||
const focusable = targetRow?.querySelector(context.selector)
|
||||
if (focusable) {
|
||||
focusable.focus()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: try to find any focusable element in the admin panels
|
||||
const container = document.querySelector('.admin-panels')
|
||||
if (!container) return
|
||||
|
||||
const focusable = container.querySelector('button:not([disabled]), a, input:not([disabled]), [tabindex="0"]')
|
||||
if (focusable) {
|
||||
focusable.focus()
|
||||
}
|
||||
}
|
||||
|
||||
// Keyboard navigation handlers
|
||||
function handleBreadcrumbKeydown(event) {
|
||||
|
||||
Reference in New Issue
Block a user