Skip to content

Commit 35ab10e

Browse files
committed
wip
1 parent b377f15 commit 35ab10e

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

src/resources/views/crud/components/dataform/modal-form-scripts.blade.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,65 @@ function attachSelect2PositioningFix($field, $modal) {
6868
});
6969
}
7070
71+
/**
72+
* Prevent infinite focus loops when third-party overlays (like Colorbox)
73+
* attempt to grab focus while a Bootstrap modal is open.
74+
*/
75+
(function installFocusGuard() {
76+
if (window._backpackFocusGuardInstalled) return;
77+
window._backpackFocusGuardInstalled = true;
78+
79+
// Keep a short-lived map of recently-handled targets to avoid rapid re-entrancy
80+
const recentFocusTargets = new WeakMap();
81+
const REENTRANCY_WINDOW_MS = 50;
82+
83+
document.addEventListener('focusin', function (e) {
84+
try {
85+
// If there's no Bootstrap modal shown, do nothing.
86+
const openModal = document.querySelector('.modal.show');
87+
if (!openModal) return;
88+
89+
const target = e.target;
90+
91+
// If the focus is inside the open modal, allow it.
92+
if (openModal.contains(target)) return;
93+
94+
// If the event is user-initiated, allow it.
95+
if (e.isTrusted) return;
96+
97+
// If we've recently handled focus for this target, bail out to prevent loops
98+
const last = recentFocusTargets.get(target) || 0;
99+
const now = Date.now();
100+
if (now - last < REENTRANCY_WINDOW_MS) {
101+
if (typeof e.stopImmediatePropagation === 'function') e.stopImmediatePropagation();
102+
if (typeof e.preventDefault === 'function') e.preventDefault();
103+
return;
104+
}
105+
106+
// Mark this target as handled for a short window
107+
recentFocusTargets.set(target, now);
108+
109+
// Stop other listeners from handling this focusin to avoid re-entrant focus loops
110+
if (typeof e.stopImmediatePropagation === 'function') {
111+
e.stopImmediatePropagation();
112+
}
113+
114+
// restore focus to a sensible element inside the modal
115+
setTimeout(function () {
116+
const restore = openModal.querySelector('[autofocus], input, select, textarea, button, [tabindex]:not([tabindex="-1"])');
117+
if (restore && typeof restore.focus === 'function') {
118+
try { restore.focus(); } catch (err) { /* ignore */ }
119+
} else {
120+
// fallback: focus the modal itself
121+
try { openModal.focus(); } catch (err) { /* ignore */ }
122+
}
123+
}, 0);
124+
} catch (err) {
125+
// ignore any errors from the guard
126+
}
127+
}, true); // capture phase so we can stop propagation before bubble handlers
128+
})();
129+
71130
/**
72131
* Set up MutationObserver for repeatable fields in a specific modal
73132
* Watches for new rows and initializes their fields automatically

0 commit comments

Comments
 (0)