Compare commits

...

2 Commits

Author SHA1 Message Date
team3
7b60b20856 Buchansicht: Sprung beim Laden überschreibt die Lesemodus-Position nicht mehr
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 17:04:01 +02:00
team3
20f33c07bb Revert "Buchansicht startet beim Laden immer oben; nur der Lesemodus setzt fort"
This reverts commit af935b8cbd.
2026-10-08 17:03:49 +02:00

View File

@@ -19,6 +19,17 @@ function idVonNr(nr) {
} }
return '' return ''
} }
// Lesemodus-Schlüssel (vorwort, k3, a03-4:2, ende) → Element-ID der Buchansicht, wenn zuletzt dort gelesen wurde
function idVonLesemodus(pos) {
if (pos.zuletzt !== 'lesen' || !pos.lesemodus || !daten.value) return ''
const m = pos.lesemodus
if (m === 'vorwort') return 'vorwort'
const kap = /^k(\d+)$/.exec(m)
if (kap) return 'k' + (daten.value.kapitel[Number(kap[1]) - 1]?.id || '')
const abs = /^(a[\d-]+):/.exec(m)
if (abs) return abs[1]
return ''
}
function nrVonId(id) { function nrVonId(id) {
if (!id || !daten.value) return '' if (!id || !daten.value) return ''
if (id === 'vorwort') return 'vorwort' if (id === 'vorwort') return 'vorwort'
@@ -57,7 +68,8 @@ const aktiv = ref('')
const lese = ref(null) const lese = ref(null)
let beobachter = null let beobachter = null
let ladeSeq = 0 let ladeSeq = 0
// Leseposition auf dem Server merken (geräteübergreifend), gebündelt alle 1,5 s // Leseposition auf dem Server merken (geräteübergreifend), gebündelt alle 1,5 s; nicht während des Sprungs beim Laden
let ruhe = false, ruheTimer = null
let merkTimer = null let merkTimer = null
function merken(id) { function merken(id) {
clearTimeout(merkTimer) clearTimeout(merkTimer)
@@ -75,9 +87,14 @@ async function laden() {
daten.value = d daten.value = d
await nextTick() await nextTick()
spy() spy()
// Die Buchansicht beginnt beim Laden immer oben; nur der Lesemodus setzt an der gemerkten Stelle fort. // Gemerkte Position hat Vorrang (die Adresse spiegelt nur den letzten Scrollstand); zuletzt im Lesemodus gelesen → dessen Stelle
// Zum Abschnitt springen nur bei Klicks im Inhaltsverzeichnis und über die Zurück-Taste (siehe watch auf props.nr). const ziel = idVonLesemodus(pos) || pos.abschnitt || idVonNr(props.nr)
void pos // Der Sprung beim Laden darf die gemerkte Position nicht überschreiben; erst eigenes Scrollen zählt wieder
ruhe = true
clearTimeout(ruheTimer)
ruheTimer = setTimeout(() => { ruhe = false }, 2500)
// Am Buchanfang (Vorwort) nicht scrollen, damit Titel und Knopfleiste sichtbar bleiben
if (ziel && ziel !== 'vorwort' && !aktiv.value) scrollZu(ziel)
} }
watch(() => [props.slug, props.version], () => { aktiv.value = ''; cache.clear(); laden() }, { immediate: true }) watch(() => [props.slug, props.version], () => { aktiv.value = ''; cache.clear(); laden() }, { immediate: true })
// Zurück-Taste oder getippte Adresse: zum Abschnitt springen, wenn er nicht schon aktiv ist // Zurück-Taste oder getippte Adresse: zum Abschnitt springen, wenn er nicht schon aktiv ist
@@ -119,7 +136,7 @@ function spy() {
beobachter?.disconnect() beobachter?.disconnect()
beobachter = new IntersectionObserver((es) => { beobachter = new IntersectionObserver((es) => {
if (lesemodus.value) return if (lesemodus.value) return
for (const e of es) if (e.isIntersecting) { aktiv.value = e.target.id; merken(e.target.id); emit('nr', { nr: nrVonId(e.target.id), push: false }) } for (const e of es) if (e.isIntersecting) { aktiv.value = e.target.id; if (!ruhe) merken(e.target.id); emit('nr', { nr: nrVonId(e.target.id), push: false }) }
}, { root: lese.value, rootMargin: '0px 0px -75% 0px' }) }, { root: lese.value, rootMargin: '0px 0px -75% 0px' })
document.querySelectorAll('.buch [data-spy]').forEach((el) => beobachter.observe(el)) document.querySelectorAll('.buch [data-spy]').forEach((el) => beobachter.observe(el))
} }