Commit Graph
8 Commits
Author SHA1 Message Date
dapelza c7e3246b44 Fix: Nutzerstandort auf der Karte anzeigen
Behebt Gitea Issue #2 "Standort auf Karte anzeigen": der per
Browser-Geolocation ermittelte oder manuell eingegebene Standort
(state.userLocation) wurde bisher nur zum Zentrieren/Entfernungsfilter
verwendet, aber nie selbst auf der Karte dargestellt.

Neuer, nicht interaktiver "Hier bist du"-Marker (blauer Punkt mit
Puls-Ring, js/map/markers.js: createUserLocationMarker()) wird direkt
auf die Karte gelegt (ausserhalb der clusterGroup, damit er nie mit
Ausflugsziel-Markern geclustert wird) und reagiert reaktiv auf
Aenderungen von state.userLocation in js/map/mapController.js.
2026-07-24 12:52:09 +02:00
dapelza 39321d680f Phase 7: KI-JSON-Import und Backup-Export/Import
Neues Modul js/import/ mit reiner Validierungslogik
(importValidator.js: parseAndValidate(), findDuplicate()). Jeder
Ausflugsziel-Eintrag im importierten KI-JSON wird einzeln bewertet statt
alles-oder-nichts: fehlender Name/Kategorie oder ungueltige Koordinaten
fuehren zur Ablehnung, weiche Probleme (unbekannte Kategorie, unsichere
website/image-URL, ungueltige Bewertung, falscher Feldtyp) erzeugen nur
eine Warnung. sanitizeEntry() setzt sicherheitskritische Felder vor der
Uebernahme zurueck (z.B. javascript:-URLs), da normalizePlace() selbst
keine Sicherheitspruefung vornimmt. findDuplicate() erkennt
wahrscheinliche Duplikate gegen den bestehenden Datenbestand.

UI (js/ui/import.js): Modal mit zwei Tabs - KI-Ausflugsziele importieren
(Text einfuegen oder Datei hochladen, Vorschau mit
gueltig/Warnung/abgelehnt, Duplikat-Toggle, Bestaetigen) und Backup
sichern/wiederherstellen (js/import/backup.js: Export als JSON-Datei,
Wiederherstellen mit Ersetzen/Ergaenzen-Wahl). Vorschau-Rendering
ausschliesslich ueber el()/textContent, da es sich um echte, ungepruefte
Fremddaten handelt.

Damit sind alle Kernfunktionen aus anforderung.md umgesetzt.
docs/plan.md entsprechend fortgeschrieben.
2026-07-24 12:50:05 +02:00
dapelza b49b8f4f47 Fix: Standort-Fehlermeldung schliessbar, manuelle Standorteingabe
Behebt Gitea Issue #1 "Eigenen Standort verwenden" (zwei Teilprobleme):

1. Die Fehlermeldung bei fehlgeschlagener Geolocation-Abfrage (#app-status)
   liess sich bisher nicht schliessen und blockierte dauerhaft die UI.
   Neuer Schliessen-Button (#app-status-close), unabhaengig vom restlichen
   Bootstrap-Ablauf verdrahtet, damit er auch bei einem fruehen Init-Fehler
   funktioniert.

2. Es gab keine Moeglichkeit, den Standort manuell zu setzen, wenn die
   Browser-Geolocation fehlschlaegt oder nicht verfuegbar ist. Neues Modal
   (js/ui/manualLocation.js) mit Breiten-/Laengengrad-Eingabe, Validierung
   (aria-invalid/Inline-Fehler analog zum Ausflugsziel-Formular), setzt bei
   gueltiger Eingabe state.userLocation direkt - Karte, Liste und
   Entfernungsfilter reagieren automatisch darauf.
2026-07-24 12:38:16 +02:00
dapelza 5e2197ec24 Phase 6: KI-Prompt-Generator
Neues Modul js/ai/promptBuilder.js: reine Funktion buildPrompt(), deckt
alle 10 Pflichtpunkte aus anforderung.md explizit ab (Region+Radius,
Kategorien, Alter, wichtige Eigenschaften, Anzahl Ergebnisse, keine
erfundenen Informationen, unsichere Angaben kennzeichnen, ausschliesslich
gueltiges JSON, genaue Koordinaten, direkte Importierbarkeit) und bettet
das exakte JSON-Zielschema aus anforderung.md unveraendert ein.

UI (js/ui/promptGenerator.js): Modal mit allen Eingabefeldern aus der
Anforderung (Region, Radius, Kategorien, Altersgruppe, Indoor/Outdoor,
Kostenrahmen, max. Ergebnisse, besondere Anforderungen als Checkboxen +
Freitext, Ausgabesprache), Live-Vorschau des generierten Prompts,
Copy-to-Clipboard mit execCommand-Fallback (js/utils/clipboard.js) und
Speichern als Textdatei (js/utils/download.js). Neuer Toolbar-Button
oeffnet den Generator.

JSON-Import der KI-Antwort ist bewusst nicht Teil dieser Phase, sondern
folgt in Phase 7. docs/plan.md entsprechend fortgeschrieben.
2026-07-24 12:32:37 +02:00
dapelza dac952fbf9 Phase 4: Filter- und Suchfunktion
Neues Modul js/filters/ mit reiner Filterlogik (filterEngine.js:
applyFilters(), getDistanceKm()) und UI (filterPanel.js) fuer alle Filter
aus anforderung.md Abschnitt 3: Kategorie, Entfernung (mit "Standort
verwenden"-Button), Alter der Kinder, Kosten, Indoor/Outdoor, 5
Ausstattungsmerkmale, Aufenthaltsdauer, Mindestbewertung sowie
Freitextsuche ueber Name/Ort/Region/Adresse. Trefferzaehler, "Filter
zuruecksetzen" und "Auf Ergebnisse zoomen" ergaenzt.

Store erweitert um updateFilters()/getFilteredPlaces() (Selector).
Karte und Liste rendern jetzt die gefilterte statt die volle
Ausflugsziel-Liste; die Karten-Rerender-Optimierung vergleicht dafuer
die Trefferliste per Id-Schluessel statt nur state.places, damit reine
Filter-/Standortaenderungen ohne Places-Aenderung erkannt werden.

Layout: Filter-Panel als aufklappbares <details> auf Mobile, eigener
Grid-Bereich neben der Karte auf Desktop. docs/plan.md entsprechend
fortgeschrieben (Phase 2-5 als umgesetzt markiert, Phase 5
Navigation war bereits Teil von Phase 2).
2026-07-24 12:21:07 +02:00
dapelza 10f9170d61 Phase 3: Formular zum Anlegen und Bearbeiten
Neues Modal (js/ui/form.js) mit allen Feldern aus anforderung.md
Abschnitt 6: Name, Kategorie, Kurz-/Volltext-Beschreibung, Adresse, Ort,
Koordinaten, Altersgruppe, Kosten, Oeffnungszeiten, Aufenthaltsdauer,
Ausstattungs-Checkboxen, Indoor/Outdoor, Bild-URL, Website, Tags.

Validierung: Pflichtfelder (Name, Kategorie, Koordinaten), Koordinaten-
Bereichspruefung, Alter min<=max, Bild-/Website-URL nur http/https.
Fehler erscheinen inline je Feld (aria-invalid/aria-describedby), erstes
fehlerhaftes Feld wird fokussiert.

EventMap.ui.openPlaceForm(place) dient als Einstiegspunkt: ohne Argument
zum Neuanlegen, mit Place-Objekt zum Bearbeiten. Speichern aktualisiert
den Store mit neuer Array-Referenz (Karte/Liste reagieren automatisch)
und persistiert nach LocalStorage.

Verdrahtung: neuer "+ Neues Ausflugsziel hinzufuegen"-Button in der
Karten-Toolbar; der bisherige Bearbeiten-Platzhalter in der
Detailansicht (js/ui/detail.js) oeffnet jetzt das Formular vorausgefuellt
mit dem aktuell angezeigten Ausflugsziel.
2026-07-24 11:43:01 +02:00
dapelza 2812e03530 Phase 2: Detailansicht
Modal, das sich bei Marker- oder Listen-Auswahl (state.selectedPlaceId)
oeffnet: Titelbild/Platzhalter, vollstaendige Beschreibung, Adresse,
Mini-Karte mit Positionsmarker, Oeffnungszeiten, Kosten, Altersempfehlung,
Ausstattung (inkl. klar markierter negativer Werte), Hinweise fuer
Familien, Website-Link. Navigation-Button zu OSM Directions. Loeschen ist
bereits voll funktional (mit Bestaetigung), Bearbeiten ist als Platzhalter
fuer Phase 3 markiert.

Neuer Helper isSafeHttpUrl() in dom.js: nur http/https als Link- oder
Bildquelle zulaessig, schuetzt vor javascript:-URLs in Fremddaten
(Vorbereitung fuer KI-JSON-Import). Rendering weiterhin ausschliesslich
ueber textContent/el(), kein innerHTML mit Place-Daten.
2026-07-24 11:32:32 +02:00
dapelza ee55fb1cf9 Phase 0+1: Scaffold, Datenmodell, Karte und Liste
Reines HTML5/CSS3/JavaScript ohne Build-Tooling, lauffaehig direkt per
Doppelklick auf index.html (file://, kein Server noetig):

- Datenmodell fuer Ausflugsziele mit allen Feldern aus der Anforderung,
  15 feste Kategorien inkl. Farbe/Icon
- Zentraler Pub/Sub-Store mit LocalStorage-Persistenz und
  Migrations-Grundgeruest
- Interaktive Karte (Leaflet + Leaflet.markercluster, lokal vendored)
  mit kategoriefarbenen Markern, Clustering, Popups, Geolocation-Button
- Kartengrundlage ueber CARTO-Basemaps statt tile.openstreetmap.org, da
  dessen Referer-Pflicht file://-Aufrufe blockiert
- Seed-Daten als eingebettetes Script (data/seed.js) statt JSON-Datei,
  da fetch() auf lokale Dateien unter file:// nicht zuverlaessig
  funktioniert
- Ergebnisliste mit 10 Beispiel-Ausflugszielen, sicher gerendert ueber
  textContent/DOM-APIs statt innerHTML (Vorbereitung fuer spaeteren
  KI-JSON-Import mit Fremddaten)
- Responsives Layout (Desktop nebeneinander, Mobile gestapelt)
2026-07-24 11:24:47 +02:00