photo_server_json_flutter_c.../public/js/main.js
2026-02-26 13:59:36 +01:00

261 lines
No EOL
8.1 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.

// ===============================
// AVVIO
// ===============================
console.log("main.js avviato");
// ===============================
// PATCH: misura l'altezza reale dell'header e aggiorna --header-h
// (serve per far partire la mappa subito sotto lheader, anche su mobile)
// ===============================
(function () {
const root = document.documentElement;
const header = document.querySelector('header');
function setHeaderHeight() {
const h = header ? Math.round(header.getBoundingClientRect().height) : 60;
root.style.setProperty('--header-h', h + 'px');
}
setHeaderHeight();
if (window.ResizeObserver && header) {
const ro = new ResizeObserver(setHeaderHeight);
ro.observe(header);
} else {
window.addEventListener('resize', setHeaderHeight);
window.addEventListener('orientationchange', setHeaderHeight);
}
window.addEventListener('load', setHeaderHeight);
})();
// ===============================
// PATCH: quando si apre la mappa (#globalMap.open) invalida le dimensioni Leaflet
// (utile perché prima era display:none; invalidateSize evita “tagli” o tile sfasati)
// ===============================
(function () {
const mapEl = document.getElementById('globalMap');
if (!mapEl) return;
function invalidateWhenOpen() {
if (!mapEl.classList.contains('open')) return;
// Aspetta un tick così il layout è aggiornato
setTimeout(() => {
try {
// In mapGlobal.js imposta: window.leafletMapInstance = window.globalMap;
window.leafletMapInstance?.invalidateSize();
} catch (e) {
console.warn('invalidateSize non eseguito:', e);
}
}, 0);
}
// 1) Osserva il cambio classe (quando aggiungi .open)
const mo = new MutationObserver((mutations) => {
if (mutations.some(m => m.attributeName === 'class')) {
invalidateWhenOpen();
}
});
mo.observe(mapEl, { attributes: true, attributeFilter: ['class'] });
// 2) Fallback: se usi il bottone #openMapBtn per aprire/chiudere
document.getElementById('openMapBtn')?.addEventListener('click', () => {
setTimeout(invalidateWhenOpen, 0);
});
})();
// ===============================
// MENU ⋮ (toggle apri/chiudi con lo stesso bottone, senza global conflicts)
// ===============================
(() => {
const optBtn = document.getElementById("optionsBtn");
const optSheet = document.getElementById("optionsSheet");
const overlayEl= document.getElementById("sheetOverlay");
if (!optBtn || !optSheet) return;
function openOptionsSheet() {
try { window.closeBottomSheet?.(); } catch {}
optSheet.classList.add("open");
overlayEl?.classList.add("open");
// ARIA (facoltativo)
optBtn.setAttribute("aria-expanded", "true");
optSheet.setAttribute("aria-hidden", "false");
}
function closeOptionsSheet() {
optSheet.classList.remove("open");
overlayEl?.classList.remove("open");
// ARIA (facoltativo)
optBtn.setAttribute("aria-expanded", "false");
optSheet.setAttribute("aria-hidden", "true");
}
function toggleOptionsSheet(e) {
e?.preventDefault();
e?.stopPropagation();
if (optSheet.classList.contains("open")) closeOptionsSheet();
else openOptionsSheet();
}
// Click sul bottone: toggle (fase di cattura per battere eventuali altri handler)
optBtn.addEventListener("click", toggleOptionsSheet, { capture: true });
// Chiudi clic overlay
overlayEl?.addEventListener("click", (e) => {
e.stopPropagation();
closeOptionsSheet();
});
// Chiudi con ESC
document.addEventListener("keydown", (e) => {
if (e.key === "Escape" && optSheet.classList.contains("open")) {
closeOptionsSheet();
}
});
// Evita chiusure involontarie per click interni
optSheet.addEventListener("click", (e) => e.stopPropagation());
// Espone una close per usarla altrove (es. dopo la scelta)
window.closeOptionsSheet = closeOptionsSheet;
})();
// ===============================
// LOGIN AUTOMATICO SU INDEX
// ===============================
document.addEventListener("DOMContentLoaded", async () => {
try {
// 1) Carica config
const cfgRes = await fetch('/config');
const cfg = await cfgRes.json();
window.BASE_URL = cfg.baseUrl;
// 2) Recupera token salvato
const savedToken = localStorage.getItem("token");
// Se non c'è token → mostra login
if (!savedToken) {
document.getElementById("loginModal").style.display = "flex";
return;
}
// 3) Verifica token
const ping = await fetch(`${window.BASE_URL}/photos`, {
headers: { "Authorization": "Bearer " + savedToken }
});
if (!ping.ok) {
// Token invalido → cancella e mostra login
localStorage.removeItem("token");
document.getElementById("loginModal").style.display = "flex";
return;
}
// 4) Token valido → salva e carica gallery
window.token = savedToken;
loadPhotos();
} catch (err) {
console.error("Errore autenticazione:", err);
document.getElementById("loginModal").style.display = "flex";
}
});
// ===============================
// VARIABILI GLOBALI
// ===============================
let currentSort = "desc";
let currentGroup = "auto";
let currentFilter = null;
window.currentSort = currentSort;
window.currentGroup = currentGroup;
window.currentFilter = currentFilter;
// ===============================
// BOTTONI OPZIONI
// ===============================
document.querySelectorAll("#optionsSheet .sheet-btn").forEach(btn => {
btn.addEventListener("click", () => {
if (btn.dataset.sort) window.currentSort = currentSort = btn.dataset.sort;
if (btn.dataset.group) window.currentGroup = currentGroup = btn.dataset.group;
if (btn.dataset.filter) window.currentFilter = currentFilter = btn.dataset.filter;
// Chiudi sheet e overlay dopo la scelta (usa lAPI esposta sopra)
window.closeOptionsSheet?.();
refreshGallery();
});
});
// ===============================
// REFRESH GALLERY
// ===============================
function refreshGallery() {
console.log("Aggiornamento galleria...");
const data = Array.isArray(window.photosData) ? window.photosData : [];
let photos = [...data];
if (typeof applyFilters === 'function') photos = applyFilters(photos);
if (typeof sortByDate === 'function') photos = sortByDate(photos, currentSort);
let sections = [{ label: 'Tutte', photos }];
if (typeof groupByDate === 'function') sections = groupByDate(photos, currentGroup);
if (typeof renderGallery === 'function') {
renderGallery(sections);
}
}
window.refreshGallery = refreshGallery;
// ===============================
// SETTINGS (⚙️) — apre admin.html
// ===============================
const settingsBtn = document.getElementById('settingsBtn');
settingsBtn?.addEventListener('click', () => {
window.location.href = "admin.html";
});
// ===============================
// LOGIN SUBMIT
// ===============================
document.getElementById("loginSubmit").addEventListener("click", async () => {
const email = document.getElementById("loginEmail").value;
const password = document.getElementById("loginPassword").value;
const errorEl = document.getElementById("loginError");
errorEl.textContent = "";
try {
const res = await fetch(`${window.BASE_URL}/auth/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password })
});
if (!res.ok) {
errorEl.textContent = "Utente o password errati";
return;
}
const data = await res.json();
const token = data.token;
// Salva token
localStorage.setItem("token", token);
window.token = token;
// Chiudi login
document.getElementById("loginModal").style.display = "none";
// Carica gallery
loadPhotos();
} catch (err) {
console.error("Errore login:", err);
errorEl.textContent = "Errore di connessione al server";
}
});