diff --git a/frontend/src/components/BausteinFokus.vue b/frontend/src/components/BausteinFokus.vue index 3288034..f2c97e1 100644 --- a/frontend/src/components/BausteinFokus.vue +++ b/frontend/src/components/BausteinFokus.vue @@ -42,7 +42,8 @@ function onKeyUp(e) { } function resetAlt() { altAlone = false } // Fenster-Blur (ALT+Tab) → kein falscher Tipp function toggleInput() { - const el = rightEl.value?.querySelector('textarea') + // Antwortfeld der aktuellen Form: Erklären = textarea, Lückentext-frei = input. + const el = rightEl.value?.querySelector('textarea, input') if (!el) return document.activeElement === el ? el.blur() : el.focus() } diff --git a/frontend/src/components/BausteinPanel.vue b/frontend/src/components/BausteinPanel.vue index 6266bf8..d748b08 100644 --- a/frontend/src/components/BausteinPanel.vue +++ b/frontend/src/components/BausteinPanel.vue @@ -592,14 +592,6 @@ const wahlWidget = computed(() => { if (zeigeForm.value === 'lueckentext' && lueckAktuell.value && !lueckAktuell.value.schwer) return lueckAktuell.value return null }) -// Eingabefeld der aktuellen Form (Lückentext frei / Erklären) — für „Alt fokussiert". -function eingabeFeld() { - if (zeigeForm.value === 'lueckentext' && lueckAktuell.value && lueckAktuell.value.schwer && !lueckAktuell.value.fertig) { - return document.getElementById('bp-lueck-input') - } - if (zeigeForm.value === 'erklaeren' && pruefPhase.value === 'frage_offen') return pruefInputEl.value - return null -} // Nach einer Antwort: bei Meilenstein-Überschreitung in den neuen Abschnitt, sonst nächste Frage. function weiterAktion() { if (abschnittWechsel.value) zumNaechstenAbschnitt() @@ -621,12 +613,9 @@ function primaerAktion() { function onPruefKey(e) { if (e.repeat) return if (props.mode !== 'full' || activeTab.value !== 'pruefung') return - // Alt allein → ins Eingabefeld (Lückentext frei / Erklären), wie bei Frage-Antwort. - if (e.key === 'Alt') { - const el = eingabeFeld() - if (el) { e.preventDefault(); el.focus() } - return - } + // Alt allein toggelt der Fokus (BausteinFokus lone-tap) → hier NICHT fokussieren, + // sonst kämpfen keydown-Fokus (hier) und keyup-Toggle (Fokus) → „nur beim Halten". + if (e.key === 'Alt') return if (!e.altKey) { // Nackte 1–4: Wahl-Widget toggeln — aber nicht, während ein Textfeld den Fokus hat. if (['1', '2', '3', '4'].includes(e.key) && wahlWidget.value && !wahlWidget.value.fertig) { diff --git a/frontend/src/components/TopicDetail.vue b/frontend/src/components/TopicDetail.vue index ef62f56..aa48c1c 100644 --- a/frontend/src/components/TopicDetail.vue +++ b/frontend/src/components/TopicDetail.vue @@ -74,7 +74,7 @@ const bausteine = computed(() => const fokusBaustein = computed(() => (fokusIndex.value === null ? null : bausteine.value[fokusIndex.value])) function openFokus(baustein, tab) { - if (!baustein.pruefbar) return // reine Lese-Sections (Rest/Rand) öffnen keinen Prüfungs-Fokus + if (!istPruefbar(baustein)) return // reine Lese-Sections (Rest/Rand) öffnen keinen Prüfungs-Fokus const i = bausteine.value.findIndex((s) => s.title === baustein.title) if (i === -1) return fokusIndex.value = i @@ -82,10 +82,10 @@ function openFokus(baustein, tab) { } // Nur prüfbare Sections im Fokus anspringen (FullGuide hat dazwischen reine Lese-Sections). function fokusPrev() { - for (let i = fokusIndex.value - 1; i >= 0; i--) if (bausteine.value[i].pruefbar) { fokusIndex.value = i; return } + for (let i = fokusIndex.value - 1; i >= 0; i--) if (istPruefbar(bausteine.value[i])) { fokusIndex.value = i; return } } function fokusNext() { - for (let i = fokusIndex.value + 1; i < bausteine.value.length; i++) if (bausteine.value[i].pruefbar) { fokusIndex.value = i; return } + for (let i = fokusIndex.value + 1; i < bausteine.value.length; i++) if (istPruefbar(bausteine.value[i])) { fokusIndex.value = i; return } } // Erfahrungsleiste: Lernstand über alle Bausteine des Guides (sticky, absolviert ⊇ verstanden ⊇ gemeistert). @@ -103,6 +103,12 @@ const fortschritt = computed(() => { // Prüfung läuft voll 0–30, sobald Guide ODER FullGuide fertig ist (gleicher Baustein-Score). const cap = computed(() => ((props.doneByFormat?.Guide || props.doneByFormat?.FullGuide) ? 30 : 6)) +// Section prüfbar? Rest nie. Sonst prüfbar, außer das Feld ist explizit false (FullGuide-Rand). +// Fehlt das Feld (alte Guides ohne `pruefbar`) → prüfbar, damit Bestands-Guides weiter funktionieren. +function istPruefbar(s) { + return props.previewGuide?.format !== 'Rest' && s.pruefbar !== false +} + // --- Chat (Mechanik in useChat; Kontext-Extraktion bleibt hier) --- const chat = useChat((msgs) => { const { section, outline } = extractContext() @@ -208,9 +214,9 @@ function extractContext() { :key="s.num" :class="['section-card', lernstand[s.title]?.gemeistert ? 'gemeistert' : (lernstand[s.title]?.verstanden ? 'verstanden' : (lernstand[s.title]?.absolviert ? 'absolviert' : ''))]" > -