367 lines
10 KiB
JavaScript
367 lines
10 KiB
JavaScript
/**
|
|
* OEDB Embed Script
|
|
* Script d'intégration pour afficher les événements OEDB sur des sites externes
|
|
*/
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
// Configuration par défaut
|
|
const defaultConfig = {
|
|
apiUrl: 'https://api.oedb.fr',
|
|
theme: 'light',
|
|
limit: 50,
|
|
width: '100%',
|
|
height: '400px',
|
|
showMap: true,
|
|
showList: true,
|
|
autoRefresh: false,
|
|
refreshInterval: 300000 // 5 minutes
|
|
};
|
|
|
|
// Thèmes CSS
|
|
const themes = {
|
|
light: {
|
|
background: '#ffffff',
|
|
text: '#2c3e50',
|
|
border: '#ecf0f1',
|
|
primary: '#3498db',
|
|
secondary: '#95a5a6'
|
|
},
|
|
dark: {
|
|
background: '#2c3e50',
|
|
text: '#ecf0f1',
|
|
border: '#34495e',
|
|
primary: '#3498db',
|
|
secondary: '#7f8c8d'
|
|
}
|
|
};
|
|
|
|
class OEDBEmbed {
|
|
constructor(container, config) {
|
|
this.container = typeof container === 'string' ? document.querySelector(container) : container;
|
|
this.config = { ...defaultConfig, ...config };
|
|
this.events = [];
|
|
this.isLoading = false;
|
|
this.refreshTimer = null;
|
|
|
|
if (!this.container) {
|
|
console.error('OEDB Embed: Container not found');
|
|
return;
|
|
}
|
|
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
this.injectStyles();
|
|
this.render();
|
|
this.loadEvents();
|
|
|
|
if (this.config.autoRefresh) {
|
|
this.startAutoRefresh();
|
|
}
|
|
}
|
|
|
|
injectStyles() {
|
|
if (document.getElementById('oedb-embed-styles')) return;
|
|
|
|
const theme = themes[this.config.theme] || themes.light;
|
|
const styles = `
|
|
<style id="oedb-embed-styles">
|
|
.oedb-embed {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background: ${theme.background};
|
|
color: ${theme.text};
|
|
border: 1px solid ${theme.border};
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
width: ${this.config.width};
|
|
height: ${this.config.height};
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.oedb-embed-header {
|
|
background: ${theme.primary};
|
|
color: white;
|
|
padding: 1rem;
|
|
text-align: center;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.oedb-embed-content {
|
|
flex: 1;
|
|
display: flex;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.oedb-embed-map {
|
|
flex: 1;
|
|
min-height: 200px;
|
|
background: #f8f9fa;
|
|
position: relative;
|
|
}
|
|
|
|
.oedb-embed-list {
|
|
width: 300px;
|
|
overflow-y: auto;
|
|
border-left: 1px solid ${theme.border};
|
|
background: ${theme.background};
|
|
}
|
|
|
|
.oedb-embed-list-only {
|
|
width: 100%;
|
|
}
|
|
|
|
.oedb-embed-map-only {
|
|
width: 100%;
|
|
}
|
|
|
|
.oedb-event-item {
|
|
padding: 1rem;
|
|
border-bottom: 1px solid ${theme.border};
|
|
cursor: pointer;
|
|
transition: background-color 0.2s;
|
|
}
|
|
|
|
.oedb-event-item:hover {
|
|
background: ${theme.border};
|
|
}
|
|
|
|
.oedb-event-title {
|
|
font-weight: 600;
|
|
margin-bottom: 0.5rem;
|
|
color: ${theme.text};
|
|
}
|
|
|
|
.oedb-event-meta {
|
|
font-size: 0.9rem;
|
|
color: ${theme.secondary};
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
}
|
|
|
|
.oedb-loading {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 200px;
|
|
color: ${theme.secondary};
|
|
}
|
|
|
|
.oedb-error {
|
|
padding: 2rem;
|
|
text-align: center;
|
|
color: #e74c3c;
|
|
background: #fdf2f2;
|
|
}
|
|
|
|
.oedb-no-events {
|
|
padding: 2rem;
|
|
text-align: center;
|
|
color: ${theme.secondary};
|
|
}
|
|
|
|
.oedb-map-placeholder {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100%;
|
|
background: #f8f9fa;
|
|
color: ${theme.secondary};
|
|
font-style: italic;
|
|
}
|
|
</style>
|
|
`;
|
|
|
|
document.head.insertAdjacentHTML('beforeend', styles);
|
|
}
|
|
|
|
render() {
|
|
this.container.innerHTML = `
|
|
<div class="oedb-embed">
|
|
<div class="oedb-embed-header">
|
|
Événements OEDB
|
|
</div>
|
|
<div class="oedb-embed-content">
|
|
${this.config.showMap ? '<div class="oedb-embed-map" id="oedb-map"></div>' : ''}
|
|
${this.config.showList ? `<div class="oedb-embed-list ${!this.config.showMap ? 'oedb-embed-list-only' : ''}" id="oedb-list"></div>` : ''}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
async loadEvents() {
|
|
if (this.isLoading) return;
|
|
|
|
this.isLoading = true;
|
|
this.showLoading();
|
|
|
|
try {
|
|
const params = new URLSearchParams();
|
|
if (this.config.what) params.set('what', this.config.what);
|
|
if (this.config.start) params.set('start', this.config.start);
|
|
if (this.config.end) params.set('end', this.config.end);
|
|
if (this.config.limit) params.set('limit', this.config.limit.toString());
|
|
if (this.config.bbox) params.set('bbox', this.config.bbox);
|
|
|
|
const response = await fetch(`${this.config.apiUrl}/events?${params.toString()}`);
|
|
const data = await response.json();
|
|
|
|
this.events = data.features || [];
|
|
this.renderEvents();
|
|
this.renderMap();
|
|
} catch (error) {
|
|
console.error('OEDB Embed: Error loading events', error);
|
|
this.showError('Erreur lors du chargement des événements');
|
|
} finally {
|
|
this.isLoading = false;
|
|
}
|
|
}
|
|
|
|
showLoading() {
|
|
const listContainer = document.getElementById('oedb-list');
|
|
if (listContainer) {
|
|
listContainer.innerHTML = '<div class="oedb-loading">Chargement des événements...</div>';
|
|
}
|
|
}
|
|
|
|
showError(message) {
|
|
const listContainer = document.getElementById('oedb-list');
|
|
if (listContainer) {
|
|
listContainer.innerHTML = `<div class="oedb-error">${message}</div>`;
|
|
}
|
|
}
|
|
|
|
renderEvents() {
|
|
const listContainer = document.getElementById('oedb-list');
|
|
if (!listContainer) return;
|
|
|
|
if (this.events.length === 0) {
|
|
listContainer.innerHTML = '<div class="oedb-no-events">Aucun événement trouvé</div>';
|
|
return;
|
|
}
|
|
|
|
const eventsHtml = this.events.map(event => {
|
|
const title = event.properties?.label || event.properties?.name || 'Événement sans nom';
|
|
const date = event.properties?.start || event.properties?.when || '';
|
|
const location = event.properties?.where || '';
|
|
const type = event.properties?.what || '';
|
|
|
|
return `
|
|
<div class="oedb-event-item" data-event-id="${event.id || ''}">
|
|
<div class="oedb-event-title">${this.escapeHtml(title)}</div>
|
|
<div class="oedb-event-meta">
|
|
${date ? `<div>📅 ${this.formatDate(date)}</div>` : ''}
|
|
${location ? `<div>📍 ${this.escapeHtml(location)}</div>` : ''}
|
|
${type ? `<div>🏷️ ${this.escapeHtml(type)}</div>` : ''}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
listContainer.innerHTML = eventsHtml;
|
|
|
|
// Ajouter les événements de clic
|
|
listContainer.querySelectorAll('.oedb-event-item').forEach(item => {
|
|
item.addEventListener('click', () => {
|
|
const eventId = item.dataset.eventId;
|
|
this.onEventClick(eventId);
|
|
});
|
|
});
|
|
}
|
|
|
|
renderMap() {
|
|
const mapContainer = document.getElementById('oedb-map');
|
|
if (!mapContainer) return;
|
|
|
|
if (this.events.length === 0) {
|
|
mapContainer.innerHTML = '<div class="oedb-map-placeholder">Aucun événement à afficher sur la carte</div>';
|
|
return;
|
|
}
|
|
|
|
// Pour l'instant, afficher un placeholder
|
|
// Dans une vraie implémentation, on utiliserait Leaflet ou une autre librairie de cartes
|
|
mapContainer.innerHTML = `
|
|
<div class="oedb-map-placeholder">
|
|
Carte interactive<br>
|
|
${this.events.length} événement(s) trouvé(s)
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
onEventClick(eventId) {
|
|
// Émettre un événement personnalisé
|
|
const event = new CustomEvent('oedb-event-click', {
|
|
detail: { eventId, event: this.events.find(e => e.id === eventId) }
|
|
});
|
|
this.container.dispatchEvent(event);
|
|
}
|
|
|
|
startAutoRefresh() {
|
|
if (this.refreshTimer) {
|
|
clearInterval(this.refreshTimer);
|
|
}
|
|
|
|
this.refreshTimer = setInterval(() => {
|
|
this.loadEvents();
|
|
}, this.config.refreshInterval);
|
|
}
|
|
|
|
stopAutoRefresh() {
|
|
if (this.refreshTimer) {
|
|
clearInterval(this.refreshTimer);
|
|
this.refreshTimer = null;
|
|
}
|
|
}
|
|
|
|
destroy() {
|
|
this.stopAutoRefresh();
|
|
this.container.innerHTML = '';
|
|
}
|
|
|
|
// Utilitaires
|
|
escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
formatDate(dateString) {
|
|
try {
|
|
const date = new Date(dateString);
|
|
return date.toLocaleDateString('fr-FR', {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
});
|
|
} catch {
|
|
return dateString;
|
|
}
|
|
}
|
|
}
|
|
|
|
// API publique
|
|
window.OEDBEmbed = {
|
|
init: function(config) {
|
|
return new OEDBEmbed(config.container, config);
|
|
}
|
|
};
|
|
|
|
// Auto-initialisation si des éléments avec data-oedb-embed sont présents
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const embedElements = document.querySelectorAll('[data-oedb-embed]');
|
|
embedElements.forEach(element => {
|
|
const config = {
|
|
container: element,
|
|
...JSON.parse(element.dataset.oedbEmbed || '{}')
|
|
};
|
|
new OEDBEmbed(config.container, config);
|
|
});
|
|
});
|
|
|
|
})();
|