// Shared date-range handling for Browse Events and both maps — remembered // across pages the way location.js remembers the place, validated in one // spot, and bound to German-format (dd.mm.yyyy) date pickers. Pages still // own what a range *does* (a server-side filter on Browse, a client-side // one on the maps); this only owns the range itself. (function (window) { var KEY = 'vindn:dateRange'; var DAY_RE = /^\d{4}-\d{2}-\d{2}$/; // "Y-m-d" for today in Germany — the site's audience and data are // German-local, so "today" must not flip at UTC midnight. sv-SE happens // to format dates as ISO, which is the only reason it's used here. function today() { return new Date().toLocaleDateString('sv-SE', { timeZone: 'Europe/Berlin' }); } // Valid "Y-m-d" strings or null for each end, and reversed ends swapped. function normalize(from, to) { from = DAY_RE.test(from || '') ? from : null; to = DAY_RE.test(to || '') ? to : null; if (from && to && from > to) { var swap = from; from = to; to = swap; } return { from: from, to: to }; } // The remembered range, or null. A range that already ended is dropped // (nothing it could match is shown anymore), and a start in the past is // moved up to today so the pickers never show a date they can't select. function load() { try { var raw = window.localStorage && localStorage.getItem(KEY); if (!raw) return null; var parsed = JSON.parse(raw); var range = normalize(parsed.from, parsed.to); if (!range.from && !range.to) return null; var now = today(); if (range.to && range.to < now) { clear(); return null; } if (range.from && range.from < now) range.from = now; return range; } catch (e) { /* localStorage disabled/unavailable, or corrupt value — just skip it */ } return null; } function save(from, to) { var range = normalize(from, to); if (!range.from && !range.to) { clear(); return; } try { if (window.localStorage) localStorage.setItem(KEY, JSON.stringify(range)); } catch (e) { /* localStorage disabled/unavailable — nothing to persist to */ } } function clear() { try { if (window.localStorage) localStorage.removeItem(KEY); } catch (e) { /* localStorage disabled/unavailable */ } } // Turns a pair of into German-format pickers when // flatpickr is loaded. A native date input displays in the *browser's* // locale and can't be forced to dd.mm.yyyy, so the visible field is // flatpickr's alt input (d.m.Y, German calendar) while the original input // keeps holding the machine-readable "Y-m-d" value everything else reads. // Without flatpickr (e.g. its CDN is unreachable) the native inputs keep // working as they are. // // onChange(from, to) fires when the *user* edits either field — never for // updates made through the returned setter, so applying a remembered // range doesn't trigger the page's own change handling. function bindInputs(fromEl, toEl, onChange) { var pickers = []; if (window.flatpickr) { var options = { locale: 'de', dateFormat: 'Y-m-d', altInput: true, altFormat: 'd.m.Y', allowInput: true, disableMobile: true, // the native mobile picker would bring the device locale back static: true, // rendered inside the card, so it also shows in a fullscreen map minDate: 'today', // The popup renders inside its card/dialog; in a scrolling container // (the Browse filter popup) it can open partly out of view. onOpen: function (selected, str, instance) { setTimeout(function () { instance.calendarContainer.scrollIntoView({ block: 'nearest' }); }, 0); } }; pickers = [fromEl, toEl].map(function (el) { var picker = window.flatpickr(el, options); // The original input turns into a hidden one, so the visible alt // input has to take over its id and label — otherwise the