// lazyflat — Leaflet flat map // Initialised LAZILY: we only build the Leaflet instance when the container // actually has a rendered size (> 0 height). Building it on a hidden 0×0 // container leaves Leaflet in a state where tiles never load. let mapInstance = null; const BERLIN_CENTER = [52.52, 13.405]; const BERLIN_ZOOM = 11; function buildMap(el) { if (mapInstance) { try { mapInstance.remove(); } catch (e) {} mapInstance = null; } mapInstance = L.map(el, { zoomControl: false, scrollWheelZoom: false, doubleClickZoom: false, boxZoom: false, touchZoom: false, keyboard: false, }).setView(BERLIN_CENTER, BERLIN_ZOOM); L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: "© OpenStreetMap", maxZoom: 18, subdomains: "abc", }).addTo(mapInstance); let data = []; try { data = JSON.parse(el.dataset.flats || "[]"); } catch (e) {} const bounds = []; data.forEach((f) => { if (typeof f.lat !== "number" || typeof f.lng !== "number") return; const rent = f.rent ? Math.round(f.rent) + " €" : ""; const rooms = f.rooms ? f.rooms + " Zi" : ""; const size = f.size ? Math.round(f.size) + " m²" : ""; const meta = [rooms, size, rent].filter(Boolean).join(" · "); const safeAddr = (f.address || "").replace(/${safeAddr}` + (meta ? `
${meta}` : "") + `
Zur Anzeige →`, ); bounds.push([f.lat, f.lng]); }); if (bounds.length === 1) { mapInstance.setView(bounds[0], 14); } else if (bounds.length > 1) { mapInstance.fitBounds(bounds, { padding: [30, 30] }); } } function ensureMap() { const el = document.getElementById("flats-map"); if (!el || typeof L === "undefined") return; // Container not actually visible yet → bail, we'll retry when the view toggles. if (el.clientHeight < 10) return; // Existing instance bound to THIS element → just recheck size. if (mapInstance && mapInstance._container === el) { try { mapInstance.invalidateSize(); } catch (e) {} return; } buildMap(el); } function wireViewToggle() { document.querySelectorAll('input[name="view_mode"]').forEach((r) => { if (r.dataset.wired === "1") return; r.dataset.wired = "1"; r.addEventListener("change", (e) => { try { localStorage.setItem("lazyflat_view_mode", e.target.value); } catch (err) {} // Wait for CSS :has() to reflow, then build/size the map. requestAnimationFrame(() => requestAnimationFrame(ensureMap)); // belt & suspenders — re-check a couple more times in case of layout shifts. setTimeout(ensureMap, 120); setTimeout(ensureMap, 400); }); }); } function restoreView() { let stored = null; try { stored = localStorage.getItem("lazyflat_view_mode"); } catch (e) {} if (!stored) return; const el = document.querySelector(`input[name="view_mode"][value="${stored}"]`); if (el && !el.checked) { el.checked = true; // Manually dispatching change would bubble and double-fire; call directly. requestAnimationFrame(() => requestAnimationFrame(ensureMap)); setTimeout(ensureMap, 120); setTimeout(ensureMap, 400); } } function onReady() { wireViewToggle(); restoreView(); ensureMap(); // handles the case where map view is already visible } document.addEventListener("DOMContentLoaded", onReady); document.body && document.body.addEventListener("htmx:afterSwap", onReady);