Bündel 1 aus dem Duplikat-Audit: existierende zentrale Helper nutzen
statt lokale Duplikate.
Pure Migration ohne neuen Code:
- 1167 _esc()-Aufrufe in 36 Page-Modulen migriert auf UI.escape()
- 24 lokale _esc/_escape-Definitionen entfernt
- lost.js hatte _escape() (Variante) — 17 Aufrufe ebenfalls migriert
- jobs.js + breeder.js: tote Alias-Wrapper entfernt
UI.escape() existierte schon — wurde nur überall lokal nochmal
implementiert. Funktional identisch (gleiche 4-replace-chain für
& < > ").
Tests 19/19 grün. Frontend-LOC um ~120 Zeilen reduziert.
Hinweis: _emptyState (7 Stellen) und _icon (8 Stellen) wurden NICHT
migriert — sie haben abweichende Signaturen von UI.emptyState({...})
bzw. UI.icon(name). Eigener Sprint nötig.
User-Report: trotz onerror-Fallback weiter Fragezeichen.
Ursache: Das _preview.webp-System wurde damals nur konsequent für
Diary-Uploads ausgerollt. User-Avatare und Hund-Profilbilder haben
keine Preview-Variante → 404 vom _preview triggert kurz das
Browser-Default-Broken-Image-Icon BEVOR der onerror-Fallback das
Original lädt (Race-Condition).
Pragmatischer Fix: Preview-System in friends.js rückgebaut. Bilder
werden direkt mit Original-URL geladen. Performance kommt durch:
- loading=\"lazy\" (off-screen Bilder erst beim Scrollen)
- decoding=\"async\" (Main-Thread bleibt frei)
- onerror=\"this.style.display='none'\" (kaputte Bilder verschwinden
statt Fragezeichen zu zeigen)
UI.previewUrl + UI.previewFallback bleiben als Helper verfügbar
für später falls das Preview-System app-weit ausgerollt wird.
Symptom: Friends-Seite lädt Avatare langsam — Original-Bilder
(z.B. 4-12MB iPhone-Fotos) statt der vorhandenen _preview.webp
Vorschauen.
Neue zentrale Helper in ui.js:
- UI.previewUrl(url): ersetzt /media/...jpg → /media/..._preview.webp
- UI.previewFallback(originalUrl): onerror-Handler der Original
nachlädt falls _preview nicht existiert (für ältere Uploads)
friends.js 3 Stellen migriert:
- _userAvatar (Freundes-Karte + Aktivitäts-Feed)
- Activity-Avatar (dog_foto + avatar_url)
- Dog-Mini-Thumbs im Profil-Modal
Zusätzlich auf allen drei Stellen:
- loading="lazy" für off-screen Bilder
- decoding="async" damit der Hauptthread nicht blockiert
Reuse-Potential: wiki.js, dog-profile.js und andere können später
auf die zentralen Helper umgestellt werden.
Neue Notiz-Buttons:
- Tagebuch: in der Detail-Ansicht (nicht Edit-Form)
- Trainingspläne: im Plan-Header pro Plan
- Freunde: in jedem Freund-Karten-Bereich
- Giftköder: in jedem Meldungs-Karten (private Umstände)
- Verlorener Hund: in jedem Eintrag
Notizblock:
- 4 neue RUBRIKEN: trainingsplan, friends, poison, lost
- Datenschutz-Hinweis: "Alle Notizen sind privat"
- lock-simple Icon zum Sprite hinzugefügt
- friends.py: forum_threads im Activity-Feed (mit entry_id)
- Filter-Chip 'Forum' ergänzt
- Klick öffnet direkt den Forum-Thread via App.callModule('forum','openThread',id)
- diary → Tagebuch, health → Gesundheit, walk → Gassi-Treffen
- Items als <button> für iOS-Tap-Zuverlässigkeit
- fr-activity-item--link mit Hover/Tap-Stil
- Backend: friends-API liefert jetzt bio, wohnort, erfahrung, social_link,
profil_sichtbarkeit, avatar_url für friends/search/incoming
- Frontend: User-Cards (Suche + Freundesliste) zeigen Avatar-Foto (statt
Buchstaben-Kreis wenn avatar_url vorhanden), Wohnort mit Pin-Icon,
Bio-Vorschau (2 Zeilen, max 120 Zeichen, bei private ausgeblendet) und
Erfahrungs-Badge neben dem Namen
- Profil-Modal erweitert um Wohnort, Erfahrung, vollständige Bio und Social-Link