// Wyszukiwarka lokalizacji + mapa (OpenStreetMap / Leaflet, bez klucza API). // Wpina się do formularza z polami input[name=lat] / input[name=lon]: // - wpisanie nazwy/adresu/POI -> /geocode -> lista trafień -> klik ustawia lat/lon, // - klik na mapie lub przeciągnięcie pineski -> ustawia lat/lon + /reverse pokazuje nazwę, // - „Tu i teraz" (now.js) emituje event 'astrololo:coords' -> mapa się synchronizuje. // Bez internetu wyszukiwarka/kafelki nie działają, ale ręczne lat/lon dalej tak. (function () { function ready(fn) { if (document.readyState !== 'loading') fn(); else document.addEventListener('DOMContentLoaded', fn); } ready(function () { var picker = document.getElementById('geoPicker'); if (!picker || typeof L === 'undefined') return; // brak Leafleta = po cichu pas var latEl = document.querySelector('input[name=lat]'); var lonEl = document.querySelector('input[name=lon]'); if (!latEl || !lonEl) return; var searchEl = document.getElementById('geoSearch'); var searchBtn = document.getElementById('geoSearchBtn'); var mapToggle = document.getElementById('geoMapToggle'); var resultsEl = document.getElementById('geoResults'); var mapEl = document.getElementById('map'); var num = function (el) { var v = parseFloat(el.value); return isNaN(v) ? 0 : v; }; var curLat = function () { return num(latEl); }; var curLon = function () { return num(lonEl); }; var pin = L.divIcon({ className: 'geo-pin', html: '📍', iconSize: [24, 24], iconAnchor: [12, 24] }); var map = L.map(mapEl).setView([curLat(), curLon()], 12); L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap contributors' }).addTo(map); var marker = L.marker([curLat(), curLon()], { draggable: true, icon: pin }).addTo(map); // Kontener mógł być renderowany zanim ustaliła się jego szerokość — poprawka. setTimeout(function () { map.invalidateSize(); }, 60); function setCoords(lat, lon, fromMap) { latEl.value = lat.toFixed(4); lonEl.value = lon.toFixed(4); marker.setLatLng([lat, lon]); if (!fromMap) map.setView([lat, lon], Math.max(map.getZoom(), 12)); if (fromMap) reverseName(lat, lon); } function reverseName(lat, lon) { fetch('/reverse?lat=' + lat + '&lon=' + lon) .then(function (r) { return r.ok ? r.json() : null; }) .then(function (d) { if (d && d.name) searchEl.value = d.name; }) .catch(function () {}); } marker.on('dragend', function () { var p = marker.getLatLng(); setCoords(p.lat, p.lng, true); }); map.on('click', function (e) { setCoords(e.latlng.lat, e.latlng.lng, true); }); // ---- wyszukiwanie po nazwie ---- function renderResults(items) { resultsEl.innerHTML = ''; if (!items.length) { resultsEl.hidden = true; return; } items.forEach(function (it) { var li = document.createElement('li'); li.textContent = it.name; li.addEventListener('click', function () { setCoords(it.lat, it.lon, false); searchEl.value = it.name; resultsEl.hidden = true; }); resultsEl.appendChild(li); }); resultsEl.hidden = false; } function doSearch() { var q = searchEl.value.trim(); if (q.length < 3) { resultsEl.hidden = true; return; } fetch('/geocode?q=' + encodeURIComponent(q)) .then(function (r) { return r.ok ? r.json() : { results: [] }; }) .then(function (d) { renderResults(d.results || []); }) .catch(function () { renderResults([]); }); } var timer = null; searchBtn.addEventListener('click', doSearch); searchEl.addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); doSearch(); } // nie wysyłaj formularza }); searchEl.addEventListener('input', function () { clearTimeout(timer); timer = setTimeout(doSearch, 500); // debounce (limit Nominatim) }); // ---- zwijanie/rozwijanie mapy ---- mapToggle.addEventListener('click', function () { var hidden = mapEl.hasAttribute('hidden'); if (hidden) { mapEl.removeAttribute('hidden'); mapToggle.textContent = 'Ukryj mapę'; setTimeout(function () { map.invalidateSize(); map.setView([curLat(), curLon()]); }, 60); } else { mapEl.setAttribute('hidden', ''); mapToggle.textContent = 'Pokaż mapę'; } }); // ---- synchronizacja z „Tu i teraz" ---- document.addEventListener('astrololo:coords', function () { marker.setLatLng([curLat(), curLon()]); map.setView([curLat(), curLon()], Math.max(map.getZoom(), 12)); }); }); })();