server_photo_s85js/public/js/activityModal.js
2026-08-11 08:45:04 +02:00

292 lines
7.2 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

// public/js/activityModal.js
let activityMap = null;
function closeActivityModal() {
const modal = document.getElementById("activityModal");
const container = document.getElementById("activityModalContent");
if (activityMap) {
activityMap.remove();
activityMap = null;
}
if (container) {
container.innerHTML = "";
}
if (modal) {
modal.classList.remove("open");
modal.setAttribute("aria-hidden", "true");
}
window.currentActivity = null;
if (typeof window.closeInfoPanel === "function") {
window.closeInfoPanel();
}
document.body.style.overflow = "";
}
window.openActivityModal = async function(item, list = [], index = 0) {
window.closeBottomSheet?.();
const modal = document.getElementById("activityModal");
const container = document.getElementById("activityModalContent");
if (!modal || !container) {
console.error("[activity modal] Mancano activityModal o activityModalContent");
return;
}
if (!item) return;
let points = [];
try {
if (typeof window.getActivityRoutePoints === "function") {
points = await window.getActivityRoutePoints(item);
} else if (typeof getActivityRoutePoints === "function") {
points = await getActivityRoutePoints(item);
}
} catch (error) {
console.error("[activity modal] Errore traccia:", error);
}
if (activityMap) {
activityMap.remove();
activityMap = null;
}
window.currentActivity = item;
window.activityModalList = Array.isArray(list) ? list : [];
window.activityModalIndex = Number.isInteger(index) ? index : 0;
const title =
item.display_name ||
item.route_name ||
item.title ||
item.file_name ||
item.name ||
"Attività";
const distance = Number(item.distance_meters);
const duration = Number(item.duration_millis);
const elevation = Number(item.elevation_gain_meters);
container.innerHTML = `
<div class="activity-modal-wrapper">
<div id="activityMap"></div>
<button
id="activityInfoBtn"
class="modal-info-btn activity-info-btn"
type="button"
aria-label="Informazioni attività"
>
</button>
<div class="activity-modal-info">
<div class="activity-modal-title">
${escapeActivityHtml(title)}
</div>
${
item.sport
? `<div class="activity-modal-meta">
${escapeActivityHtml(item.sport)}
</div>`
: ""
}
<div class="activity-modal-meta">
${
Number.isFinite(distance)
? `${(distance / 1000).toFixed(1)} km`
: "Distanza non disponibile"
}
·
${formatActivityModalDuration(duration)}
</div>
${
Number.isFinite(elevation) && elevation > 0
? `<div class="activity-modal-meta">
${Math.round(elevation)} m D+
</div>`
: ""
}
</div>
</div>
`;
modal.classList.add("open");
modal.setAttribute("aria-hidden", "false");
document.body.style.overflow = "hidden";
const activityInfoBtn = document.getElementById("activityInfoBtn");
if (activityInfoBtn) {
activityInfoBtn.onclick = event => {
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
window.currentActivity = item;
if (typeof window.toggleInfoPanel === "function") {
window.toggleInfoPanel(item);
} else if (typeof window.openInfoPanel === "function") {
window.openInfoPanel(item);
} else {
console.error("[activity info] Nessuna funzione info panel disponibile");
}
};
}
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const mapElement = document.getElementById("activityMap");
if (!mapElement || typeof L === "undefined") {
console.error("[activity modal] Leaflet o contenitore non disponibile");
return;
}
activityMap = L.map(mapElement, {
zoomControl: true,
attributionControl: true
});
L.tileLayer(
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
{
subdomains: "abc",
maxZoom: 19,
attribution: "&copy; OpenStreetMap"
}
).addTo(activityMap);
const latlngs = Array.isArray(points)
? points
.map(point => [
Number(point?.lat),
Number(point?.lng)
])
.filter(
point =>
Number.isFinite(point[0]) &&
Number.isFinite(point[1])
)
: [];
if (latlngs.length >= 2) {
const route = L.polyline(latlngs, {
color: "#2b8cff",
weight: 5,
opacity: 1,
lineCap: "round",
lineJoin: "round"
}).addTo(activityMap);
L.circleMarker(latlngs[0], {
radius: 6,
color: "#087f23",
fillColor: "#18b83f",
fillOpacity: 1
})
.bindTooltip("Partenza")
.addTo(activityMap);
L.circleMarker(latlngs[latlngs.length - 1], {
radius: 6,
color: "#b00020",
fillColor: "#e32636",
fillOpacity: 1
})
.bindTooltip("Arrivo")
.addTo(activityMap);
activityMap.fitBounds(route.getBounds(), {
paddingTopLeft: [30, 70],
paddingBottomRight: [30, 120],
maxZoom: 16
});
} else {
const latitude = Number(item.center_latitude);
const longitude = Number(item.center_longitude);
const hasCenter =
Number.isFinite(latitude) &&
Number.isFinite(longitude);
activityMap.setView(
hasCenter ? [latitude, longitude] : [42.5, 12.5],
hasCenter ? 12 : 6
);
}
activityMap.invalidateSize(true);
setTimeout(() => {
activityMap?.invalidateSize(true);
}, 150);
setTimeout(() => {
activityMap?.invalidateSize(true);
}, 400);
});
});
};
function formatActivityModalDuration(milliseconds) {
if (!Number.isFinite(milliseconds)) {
return "Durata non disponibile";
}
const totalSeconds = Math.round(milliseconds / 1000);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
return hours > 0
? `${hours}h ${minutes}m`
: `${minutes}m`;
}
function escapeActivityHtml(value) {
return String(value ?? "")
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;")
.replaceAll("'", "&#039;");
}
window.closeActivityModal = closeActivityModal;
document.addEventListener("DOMContentLoaded", () => {
const modal = document.getElementById("activityModal");
const closeButton = document.getElementById("activityModalClose");
closeButton?.addEventListener("click", event => {
event.stopPropagation();
closeActivityModal();
});
modal?.addEventListener("click", event => {
if (event.target === modal) {
closeActivityModal();
}
});
document.addEventListener("keydown", event => {
if (
event.key === "Escape" &&
modal?.classList.contains("open")
) {
closeActivityModal();
}
});
});