fix(login): 2FA-Feld erst nach dem Layout fokussieren

Benutzername und Passwort liegen ab Seitenaufbau im Layout, das 2FA-Feld
taucht erst aus display:none auf — und der Fokus wurde im selben Tick
gesetzt. Passwortmanager oeffnen ihr Inline-Overlay beim Fokus und messen die
Feldposition in genau dem Moment; Bitwarden platzierte sein Symbol dadurch
weit neben dem Feld.

Der Fokus laeuft jetzt ueber setTimeout(0), sodass das Layout vorher steht,
plus ein resize-Event als Anstoss zum Neupositionieren. Bewusst kein
requestAnimationFrame: das feuert in einem nicht sichtbaren Tab nicht und
haette den Fokus ganz verschluckt.

Nicht gegen Bitwarden verifizierbar — hier ist keine Erweiterung installiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-09-10 06:32:54 +02:00
co-authored by Claude Opus 5
parent a977ee3c2b
commit 1b09cd5167
3 changed files with 12 additions and 3 deletions
+9
View File
@@ -288,7 +288,16 @@ function bindLoginForm() {
} catch (err) { } catch (err) {
if (err.message === '2fa_required') { if (err.message === '2fa_required') {
totpRow.classList.remove('hidden'); totpRow.classList.remove('hidden');
// Focus only after the revealed row has been laid out. Password
// managers position their inline icon from the field's bounding box at
// the moment focus fires, and focusing in the same tick as the unhide
// can hand them a stale rect. setTimeout rather than
// requestAnimationFrame on purpose: rAF does not run in a backgrounded
// tab, which would swallow the focus entirely.
setTimeout(() => {
window.dispatchEvent(new Event('resize')); // nudge overlay repositioning
document.getElementById('login-totp').focus(); document.getElementById('login-totp').focus();
}, 0);
} else { } else {
errEl.textContent = err.message; errEl.textContent = err.message;
errEl.classList.remove('hidden'); errEl.classList.remove('hidden');
+1 -1
View File
@@ -1,2 +1,2 @@
// Increment APP_VERSION with every code change // Increment APP_VERSION with every code change
export const APP_VERSION = 'v93'; export const APP_VERSION = 'v94';
+1 -1
View File
@@ -7,7 +7,7 @@
// the entry HTML / version files). New releases take effect on the next // the entry HTML / version files). New releases take effect on the next
// reload, no manual SW unregister required. // reload, no manual SW unregister required.
const CACHE_VERSION = 'calendarr-v39'; const CACHE_VERSION = 'calendarr-v40';
const OFFLINE_SHELL = ['/', '/index.html']; const OFFLINE_SHELL = ['/', '/index.html'];
self.addEventListener('install', event => { self.addEventListener('install', event => {