fix(busy): make the page inert so the keyboard cannot reach controls behind the overlay
The overlay covers the page, which stops the mouse but not Tab and Space. The inert attribute removes the subtree from focus, hit-testing and the accessibility tree in one go - applied to every body-level sibling except the overlay, and always cleared in hideBusy.
This commit is contained in:
@@ -5973,16 +5973,32 @@ function promptDialog(opts) {
|
||||
return new Promise(res => { confirmResolver = res; });
|
||||
}
|
||||
|
||||
// The overlay stops the MOUSE — it covers the page — but not the keyboard:
|
||||
// Tab still walked into the controls behind it and Space activated them. `inert`
|
||||
// is the platform's answer: it removes a subtree from focus, hit-testing and
|
||||
// the accessibility tree in one attribute. Applied to every body-level sibling
|
||||
// except the overlay itself.
|
||||
function setAppInert(on) {
|
||||
Array.from(document.body.children).forEach(node => {
|
||||
if (node.id === 'busyOverlay') return;
|
||||
node.inert = !!on;
|
||||
});
|
||||
}
|
||||
|
||||
// Global busy overlay for long operations (export, big file saves).
|
||||
function showBusy(text) {
|
||||
const t = $('#busyText'); if (t) t.textContent = text || 'Working…';
|
||||
const o = $('#busyOverlay'); if (o) o.classList.remove('is-hidden');
|
||||
setAppInert(true);
|
||||
}
|
||||
function updateBusy(text) {
|
||||
const t = $('#busyText'); if (t) t.textContent = text || '';
|
||||
}
|
||||
function hideBusy() {
|
||||
const o = $('#busyOverlay'); if (o) o.classList.add('is-hidden');
|
||||
// Unconditionally, whatever happened above: leaving the page inert would
|
||||
// look exactly like a frozen app.
|
||||
setAppInert(false);
|
||||
}
|
||||
// True while a blocking operation owns the screen. Anything that would open a
|
||||
// dialog has to check this: the overlay is above every modal, so a dialog
|
||||
|
||||
Reference in New Issue
Block a user