280 lines
No EOL
11 KiB
HTML
280 lines
No EOL
11 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>View Saved Events - OpenEventDatabase</title>
|
|
<script src="https://unpkg.com/maplibre-gl@3.0.0/dist/maplibre-gl.js"></script>
|
|
<link href="https://unpkg.com/maplibre-gl@3.0.0/dist/maplibre-gl.css" rel="stylesheet" />
|
|
<link rel="stylesheet" href="/static/demo/demo_styles.css">
|
|
<script defer src="https://use.fontawesome.com/releases/v5.15.4/js/all.js"></script>
|
|
<script src="/static/demo/demo_auth.js"></script>
|
|
<style>
|
|
#map {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
width: 100%;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="map"></div>
|
|
|
|
<!-- Hidden OAuth2 configuration for the JavaScript module -->
|
|
<input type="hidden" id="osmClientId" value="{{ client_id }}">
|
|
<input type="hidden" id="osmClientSecret" value="{{ client_secret }}">
|
|
<input type="hidden" id="osmRedirectUri" value="{{ client_redirect }}">
|
|
|
|
<div class="map-overlay">
|
|
<h2>Your Saved Events</h2>
|
|
{% include 'partials/demo_nav.html' %}
|
|
|
|
<!-- Authentication section -->
|
|
<div id="auth-section" class="auth-section">
|
|
<h3>OpenStreetMap Authentication</h3>
|
|
<p>Authenticate with your OpenStreetMap account to include your username in reports.</p>
|
|
<a href="https://www.openstreetmap.org/oauth2/authorize?client_id={{ client_id }}&redirect_uri={{ client_redirect }}&response_type=code&scope=read_prefs" class="osm-login-btn">
|
|
<span class="osm-logo"></span>
|
|
Login with OpenStreetMap
|
|
</a>
|
|
<script>
|
|
// Replace server-side auth section with JavaScript-rendered version if available
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
if (window.osmAuth) {
|
|
const clientId = document.getElementById('osmClientId').value;
|
|
const redirectUri = document.getElementById('osmRedirectUri').value;
|
|
const authSection = document.getElementById('auth-section');
|
|
|
|
// Only replace if osmAuth is loaded and has renderAuthSection method
|
|
if (osmAuth.renderAuthSection) {
|
|
authSection.innerHTML = osmAuth.renderAuthSection(clientId, redirectUri);
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
</div>
|
|
|
|
<div id="event-count"></div>
|
|
|
|
<div id="event-list" class="event-list"></div>
|
|
|
|
<div class="controls">
|
|
<button id="refresh-btn">
|
|
<i class="fas fa-sync-alt"></i> Refresh
|
|
</button>
|
|
<button id="clear-btn" class="danger">
|
|
<i class="fas fa-trash-alt"></i> Clear All
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Initialize the map
|
|
const map = new maplibregl.Map({
|
|
container: 'map',
|
|
style: 'https://tiles.openfreemap.org/styles/liberty',
|
|
center: [2.2137, 46.2276], // Default center (center of metropolitan France)
|
|
zoom: 5
|
|
});
|
|
|
|
// Add navigation controls
|
|
map.addControl(new maplibregl.NavigationControl());
|
|
|
|
// Add attribution control with OpenStreetMap attribution
|
|
map.addControl(new maplibregl.AttributionControl({
|
|
customAttribution: '© <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors'
|
|
}));
|
|
|
|
// Store markers for later reference
|
|
let markers = [];
|
|
|
|
// Load events when the map is loaded
|
|
map.on('load', function() {
|
|
loadEvents();
|
|
});
|
|
|
|
// Function to load events from localStorage
|
|
function loadEvents() {
|
|
// Clear existing markers
|
|
markers.forEach(marker => marker.remove());
|
|
markers = [];
|
|
|
|
// Get events from localStorage
|
|
const savedEvents = JSON.parse(localStorage.getItem('oedb_events') || '[]');
|
|
|
|
// Update event count
|
|
document.getElementById('event-count').textContent =
|
|
`${savedEvents.length} event${savedEvents.length !== 1 ? 's' : ''} found`;
|
|
|
|
// Clear event list
|
|
const eventList = document.getElementById('event-list');
|
|
eventList.innerHTML = '';
|
|
|
|
if (savedEvents.length === 0) {
|
|
// Show message if no events
|
|
eventList.innerHTML = `
|
|
<div class="no-events">
|
|
<i class="fas fa-info-circle"></i>
|
|
<p>No saved events found.</p>
|
|
<p>Report road issues using the <a href="/demo/traffic">Report Issue</a> page.</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
// Sort events by timestamp (newest first)
|
|
savedEvents.sort((a, b) => {
|
|
return new Date(b.timestamp) - new Date(a.timestamp);
|
|
});
|
|
|
|
// Create bounds object for fitting map to events
|
|
const bounds = new maplibregl.LngLatBounds();
|
|
|
|
// Add each event to the map and list
|
|
savedEvents.forEach((event, index) => {
|
|
// Get event properties
|
|
const properties = event.properties;
|
|
const coordinates = event.geometry.coordinates;
|
|
const label = properties.label || 'Unnamed Event';
|
|
const what = properties.what || 'unknown';
|
|
const timestamp = event.timestamp ? new Date(event.timestamp) : new Date();
|
|
const formattedDate = timestamp.toLocaleString();
|
|
|
|
// Determine event type and color
|
|
let eventType = 'other';
|
|
let markerColor = '#777';
|
|
|
|
if (what.includes('pothole')) {
|
|
eventType = 'pothole';
|
|
markerColor = '#ff9800';
|
|
} else if (what.includes('obstacle')) {
|
|
eventType = 'obstacle';
|
|
markerColor = '#f44336';
|
|
} else if (what.includes('vehicle')) {
|
|
eventType = 'vehicle';
|
|
markerColor = '#2196f3';
|
|
} else if (what.includes('danger')) {
|
|
eventType = 'danger';
|
|
markerColor = '#9c27b0';
|
|
} else if (what.includes('traffic')) {
|
|
eventType = 'traffic';
|
|
markerColor = '#ff3860';
|
|
}
|
|
|
|
// Create marker
|
|
const marker = new maplibregl.Marker({
|
|
color: markerColor
|
|
})
|
|
.setLngLat(coordinates)
|
|
.addTo(map);
|
|
|
|
// Store marker reference
|
|
markers.push(marker);
|
|
|
|
// Extend bounds with event coordinates
|
|
bounds.extend(coordinates);
|
|
|
|
// Create popup content
|
|
let popupContent = `<div class="popup-content">
|
|
<h3>${label}</h3>
|
|
<table>`;
|
|
|
|
// Add event properties to popup
|
|
for (const key in properties) {
|
|
if (key === 'label') continue; // Skip label as it's already in the title
|
|
|
|
let displayValue = properties[key];
|
|
let displayKey = key;
|
|
|
|
// Format key for display
|
|
displayKey = displayKey.replace(/:/g, ' ').replace(/([A-Z])/g, ' $1');
|
|
displayKey = displayKey.charAt(0).toUpperCase() + displayKey.slice(1);
|
|
|
|
// Format value for display
|
|
if (key === 'start' || key === 'stop') {
|
|
try {
|
|
displayValue = new Date(displayValue).toLocaleString();
|
|
} catch (e) {
|
|
// Keep original value if date parsing fails
|
|
}
|
|
}
|
|
|
|
popupContent += `
|
|
<tr>
|
|
<td>${displayKey}</td>
|
|
<td>${displayValue}</td>
|
|
</tr>`;
|
|
}
|
|
|
|
// Add timestamp to popup
|
|
popupContent += `
|
|
<tr>
|
|
<td>Reported</td>
|
|
<td>${formattedDate}</td>
|
|
</tr>`;
|
|
|
|
popupContent += `</table></div>`;
|
|
|
|
// Create popup
|
|
const popup = new maplibregl.Popup({
|
|
closeButton: true,
|
|
closeOnClick: true
|
|
}).setHTML(popupContent);
|
|
|
|
// Attach popup to marker
|
|
marker.setPopup(popup);
|
|
|
|
// Add event to list
|
|
const eventItem = document.createElement('div');
|
|
eventItem.className = 'event-item';
|
|
eventItem.innerHTML = `
|
|
<span class="event-type ${eventType}">${eventType}</span>
|
|
<h3>${label}</h3>
|
|
<p>${properties.where || 'Unknown location'}</p>
|
|
<p class="event-date">${formattedDate}</p>
|
|
`;
|
|
|
|
// Add click event to list item
|
|
eventItem.addEventListener('click', () => {
|
|
// Fly to event location
|
|
map.flyTo({
|
|
center: coordinates,
|
|
zoom: 14
|
|
});
|
|
|
|
// Open popup
|
|
marker.togglePopup();
|
|
});
|
|
|
|
// Add to list
|
|
eventList.appendChild(eventItem);
|
|
});
|
|
|
|
// Fit map to bounds if there are events
|
|
if (!bounds.isEmpty()) {
|
|
map.fitBounds(bounds, {
|
|
padding: 50,
|
|
maxZoom: 12
|
|
});
|
|
}
|
|
}
|
|
|
|
// Handle refresh button click
|
|
document.getElementById('refresh-btn').addEventListener('click', function() {
|
|
loadEvents();
|
|
});
|
|
|
|
// Handle clear button click
|
|
document.getElementById('clear-btn').addEventListener('click', function() {
|
|
if (confirm('Are you sure you want to clear all saved events? This cannot be undone.')) {
|
|
// Clear localStorage
|
|
localStorage.removeItem('oedb_events');
|
|
|
|
// Reload events
|
|
loadEvents();
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |