2026-09-07 11:52:41 +10:00

133 lines
6.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const locationInput = document.querySelector('#location-input');
const latitudeInput = document.querySelector('#latitude-input');
const longitudeInput = document.querySelector('#longitude-input');
const options = document.querySelector('#location-options');
let locationTimer;
if (locationInput) {
locationInput.addEventListener('input', () => {
latitudeInput.value = '';
longitudeInput.value = '';
clearTimeout(locationTimer);
const query = locationInput.value.trim();
if (query.length < 3) { options.hidden = true; return; }
locationTimer = setTimeout(async () => {
try {
const response = await fetch(`/api/locations?q=${encodeURIComponent(query)}`);
const places = await response.json();
options.replaceChildren();
places.forEach(place => {
const button = document.createElement('button');
button.type = 'button';
button.textContent = place.label;
button.addEventListener('click', () => {
locationInput.value = place.label;
latitudeInput.value = place.latitude;
longitudeInput.value = place.longitude;
options.hidden = true;
});
options.append(button);
});
if (places.length === 0) {
const message = document.createElement('div');
message.className = 'location-message';
message.textContent = 'No geographic locations found. Try a suburb, town, or postcode.';
options.append(message);
}
options.hidden = false;
} catch (_) { options.hidden = true; }
}, 300);
});
document.addEventListener('click', event => { if (!event.target.closest('.location-field')) options.hidden = true; });
}
const tagToggle = document.querySelector('#tag-toggle');
const tagOptions = document.querySelector('#tag-options');
if (tagToggle && tagOptions) {
tagToggle.addEventListener('click', () => { tagOptions.hidden = !tagOptions.hidden; });
tagOptions.addEventListener('change', () => {
const count = tagOptions.querySelectorAll('input:checked').length;
tagToggle.textContent = count ? `${count} selected` : 'All types';
});
document.addEventListener('click', event => {
if (!event.target.closest('.tag-field')) tagOptions.hidden = true;
});
}
const tabs = document.querySelectorAll('.tab');
let map;
tabs.forEach(tab => tab.addEventListener('click', () => {
tabs.forEach(item => item.classList.toggle('active', item === tab));
document.querySelectorAll('.view-panel').forEach(panel => panel.classList.toggle('active', panel.id === tab.dataset.view));
if (tab.dataset.view === 'map-view') initialiseMap();
}));
const eventRows = [...document.querySelectorAll('[data-event-start]')];
const visibleCount = document.querySelector('#visible-event-count');
const clearDay = document.querySelector('#clear-day');
const dayEmpty = document.querySelector('#day-empty');
const rangeStatus = document.querySelector('#range-status');
let rangeStart = '';
let rangeEnd = '';
function formatDay(dayKey) {
return new Date(`${dayKey}T00:00:00`).toLocaleDateString(undefined, { day: 'numeric', month: 'short' });
}
function filterToRange(startDay, endDay = startDay) {
let count = 0;
eventRows.forEach(row => {
row.hidden = Boolean(startDay) && (row.dataset.eventStart > endDay || row.dataset.eventEnd < startDay);
if (!row.hidden) count += 1;
});
document.querySelectorAll('.calendar-day').forEach(day => {
const inRange = Boolean(startDay) && day.dataset.day >= startDay && day.dataset.day <= endDay;
day.classList.toggle('selected', inRange);
day.classList.toggle('range-start', day.dataset.day === startDay);
day.classList.toggle('range-end', day.dataset.day === endDay && endDay !== startDay);
});
if (visibleCount) visibleCount.textContent = count;
if (clearDay) clearDay.hidden = !startDay;
if (dayEmpty) dayEmpty.hidden = count !== 0;
}
document.querySelectorAll('.calendar-day').forEach(day => day.addEventListener('click', event => {
event.preventDefault();
const clicked = day.dataset.day;
if (!rangeStart || rangeEnd) {
rangeStart = clicked;
rangeEnd = '';
filterToRange(rangeStart);
if (rangeStatus) rangeStatus.textContent = `${formatDay(rangeStart)} selected · choose an end date`;
} else {
rangeEnd = clicked;
if (rangeEnd < rangeStart) [rangeStart, rangeEnd] = [rangeEnd, rangeStart];
filterToRange(rangeStart, rangeEnd);
if (rangeStatus) rangeStatus.textContent = `${formatDay(rangeStart)} – ${formatDay(rangeEnd)}`;
document.querySelector('#event-list')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}));
if (clearDay) clearDay.addEventListener('click', event => {
event.preventDefault(); rangeStart = ''; rangeEnd = ''; filterToRange('');
if (rangeStatus) rangeStatus.textContent = 'Select a start date';
});
function initialiseMap() {
if (map || !window.maplibregl) return;
const events = JSON.parse(document.querySelector('#map-events').textContent);
const center = events.length ? [events[0].longitude, events[0].latitude] : [150.8931, -34.4278];
map = new maplibregl.Map({ container: 'events-map', style: { version: 8, sources: { osm: { type: 'raster', tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'], tileSize: 256, attribution: '© OpenStreetMap contributors' } }, layers: [{ id: 'osm', type: 'raster', source: 'osm' }] }, center, zoom: 12 });
map.addControl(new maplibregl.NavigationControl(), 'top-right');
const bounds = new maplibregl.LngLatBounds();
events.forEach(event => {
const popup = new maplibregl.Popup({ offset: 20 }).setHTML(`<strong>${escapeHtml(event.title)}</strong><br>${escapeHtml(event.venue)}<br><a href="/events/${event.id}">View event</a>`);
new maplibregl.Marker({ color: '#dd5b32' }).setLngLat([event.longitude, event.latitude]).setPopup(popup).addTo(map);
bounds.extend([event.longitude, event.latitude]);
});
if (events.length > 1) map.fitBounds(bounds, { padding: 60, maxZoom: 14 });
}
function escapeHtml(value) {
const node = document.createElement('div'); node.textContent = value; return node.innerHTML;
}