From 1b09cd5167299c9e3577efcbacc38068c49d14c9 Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Thu, 10 Sep 2026 06:32:54 +0200 Subject: [PATCH] fix(login): 2FA-Feld erst nach dem Layout fokussieren MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- frontend/js/app.js | 11 ++++++++++- frontend/js/version.js | 2 +- frontend/sw.js | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/frontend/js/app.js b/frontend/js/app.js index 87fba01..a2938d9 100644 --- a/frontend/js/app.js +++ b/frontend/js/app.js @@ -288,7 +288,16 @@ function bindLoginForm() { } catch (err) { if (err.message === '2fa_required') { totpRow.classList.remove('hidden'); - document.getElementById('login-totp').focus(); + // 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(); + }, 0); } else { errEl.textContent = err.message; errEl.classList.remove('hidden'); diff --git a/frontend/js/version.js b/frontend/js/version.js index d8186c2..ec1f667 100644 --- a/frontend/js/version.js +++ b/frontend/js/version.js @@ -1,2 +1,2 @@ // Increment APP_VERSION with every code change -export const APP_VERSION = 'v93'; +export const APP_VERSION = 'v94'; diff --git a/frontend/sw.js b/frontend/sw.js index 6c3e4c4..ce13429 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -7,7 +7,7 @@ // the entry HTML / version files). New releases take effect on the next // reload, no manual SW unregister required. -const CACHE_VERSION = 'calendarr-v39'; +const CACHE_VERSION = 'calendarr-v40'; const OFFLINE_SHELL = ['/', '/index.html']; self.addEventListener('install', event => {