// Configuration partagée des types d'événements avec leurs emojis et descriptions window.EVENT_TYPES = { // Community / OSM 'community.osm.event': { emoji: '🗺️', label: 'Événement OpenStreetMap', category: 'Communauté', description: 'Événement lié à la communauté OpenStreetMap' }, // Culture / Arts 'culture.arts': { emoji: '🎨', label: 'Arts et culture', category: 'Culture', description: 'Événement artistique et culturel' }, 'culture.geek': { emoji: '🤓', label: 'Culture geek', category: 'Culture', description: 'Événement geek, technologie, gaming' }, 'culture.music': { emoji: '🎵', label: 'Musique', category: 'Culture', description: 'Événement musical général' }, // Music specific 'music.festival': { emoji: '🎪', label: 'Festival de musique', category: 'Musique', description: 'Festival musical' }, // Power / Energy 'power.production.unavail': { emoji: '⚡', label: 'Production électrique indisponible', category: 'Énergie', description: 'Arrêt ou réduction de production électrique' }, // Sale / Commerce 'sale': { emoji: '🛒', label: 'Vente / Commerce', category: 'Commerce', description: 'Événement commercial, vente, marché' }, // Time / Temporal 'time.daylight.summer': { emoji: '☀️', label: 'Heure d\'été', category: 'Temps', description: 'Passage à l\'heure d\'été' }, // Tourism 'tourism.exhibition': { emoji: '🖼️', label: 'Exposition', category: 'Tourisme', description: 'Exposition, salon, foire' }, // Traffic / Transportation 'traffic.accident': { emoji: '💥', label: 'Accident', category: 'Circulation', description: 'Accident de la circulation' }, 'traffic.incident': { emoji: '⚠️', label: 'Incident de circulation', category: 'Circulation', description: 'Incident sur la route' }, 'traffic.obstacle': { emoji: '🚧', label: 'Obstacle', category: 'Circulation', description: 'Obstacle sur la voie' }, 'traffic.partially_closed': { emoji: '🚦', label: 'Voie partiellement fermée', category: 'Circulation', description: 'Fermeture partielle de voie' }, 'traffic.roadwork': { emoji: '', label: 'Travaux routiers', category: 'Circulation', description: 'Travaux sur la chaussée' }, 'wildlife': { emoji: '🦌', label: 'Animal', category: 'Vie sauvage', description: 'Détection d\'animaux' }, 'traffic.mammoth': { emoji: '🦣', label: 'Mammouth laineux', category: 'Obstacle', description: 'Un mammouth laineux bloque la route' }, 'hazard.piranha': { emoji: '🐟', label: 'Piranha dans la piscine', category: 'Danger', description: 'Des pirana attaquent dans cette piscine' } }; // Fonction pour obtenir les suggestions d'autocomplétion function getEventTypeSuggestions(input) { const inputLower = input.toLowerCase(); const suggestions = []; for (const [key, config] of Object.entries(window.EVENT_TYPES)) { // Recherche dans la clé, le label et la catégorie const searchableText = `${key} ${config.label} ${config.category}`.toLowerCase(); if (searchableText.includes(inputLower)) { suggestions.push({ value: key, label: `${config.emoji} ${config.label}`, category: config.category, fullText: `${key} - ${config.label}` }); } } // Trier par pertinence (correspondance exacte en premier) suggestions.sort((a, b) => { const aExact = a.value.toLowerCase().startsWith(inputLower); const bExact = b.value.toLowerCase().startsWith(inputLower); if (aExact && !bExact) return -1; if (!aExact && bExact) return 1; return a.value.localeCompare(b.value); }); return suggestions.slice(0, 10); // Limiter à 10 suggestions } // Fonction pour initialiser l'autocomplétion sur un champ function initializeEventTypeAutocomplete(inputElement, onSelect) { if (!inputElement) return; let suggestionsContainer = null; let currentSuggestions = []; let selectedIndex = -1; let selectorButton = null; // Créer le bouton de sélection function createSelectorButton() { selectorButton = document.createElement('button'); selectorButton.type = 'button'; selectorButton.className = 'event-type-selector-btn'; selectorButton.innerHTML = '📋 Types d\'événements'; selectorButton.style.cssText = ` margin-top: 5px; padding: 6px 12px; background-color: #0078ff; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px; display: inline-block; `; selectorButton.addEventListener('click', function() { showAllEventTypes(); }); const parent = inputElement.parentElement; parent.appendChild(selectorButton); } // Créer le conteneur de suggestions function createSuggestionsContainer() { suggestionsContainer = document.createElement('div'); suggestionsContainer.className = 'autocomplete-suggestions'; suggestionsContainer.style.cssText = ` position: absolute; top: 100%; left: 0; right: 0; max-height: 300px; overflow-y: auto; background: white; border: 1px solid #ddd; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 1000; display: none; margin-top: 2px; `; // Positionner le conteneur parent en relatif const parent = inputElement.parentElement; if (parent.style.position !== 'relative') { parent.style.position = 'relative'; } parent.appendChild(suggestionsContainer); } // Afficher tous les types d'événements dans un beau sélecteur function showAllEventTypes() { const allTypes = Object.entries(window.EVENT_TYPES).map(([key, config]) => ({ value: key, emoji: config.emoji, label: config.label, category: config.category, description: config.description || '', fullText: `${key} - ${config.label}` })); showEventTypeSelector(allTypes); } // Afficher le sélecteur de types d'événements function showEventTypeSelector(types) { if (!suggestionsContainer) return; currentSuggestions = types; selectedIndex = -1; // Grouper par catégorie const groupedTypes = {}; types.forEach(type => { if (!groupedTypes[type.category]) { groupedTypes[type.category] = []; } groupedTypes[type.category].push(type); }); let html = `
🏷️ Types d'événements disponibles
`; // Afficher chaque catégorie Object.entries(groupedTypes).forEach(([category, categoryTypes]) => { html += `
${category}
`; categoryTypes.forEach((type, index) => { const globalIndex = types.indexOf(type); html += `
${type.emoji}
${type.label}
${type.value}
${type.description ? `
${type.description}
` : ''}
`; }); html += '
'; }); suggestionsContainer.innerHTML = html; suggestionsContainer.style.display = 'block'; // Ajouter les gestionnaires d'événements const suggestionItems = suggestionsContainer.querySelectorAll('.suggestion-item'); suggestionItems.forEach((item, index) => { const dataIndex = parseInt(item.dataset.index); item.addEventListener('click', () => selectSuggestion(dataIndex)); }); } // Afficher les suggestions function showSuggestions(suggestions) { if (!suggestionsContainer) return; currentSuggestions = suggestions; selectedIndex = -1; if (suggestions.length === 0) { suggestionsContainer.style.display = 'none'; return; } suggestionsContainer.innerHTML = suggestions.map((suggestion, index) => `
${suggestion.label.split(' ')[0]} ${suggestion.fullText} ${suggestion.category}
`).join(''); suggestionsContainer.style.display = 'block'; // Ajouter les gestionnaires d'événements aux suggestions const suggestionItems = suggestionsContainer.querySelectorAll('.suggestion-item'); suggestionItems.forEach((item, index) => { item.addEventListener('click', () => selectSuggestion(index)); item.addEventListener('mouseenter', () => highlightSuggestion(index)); }); } // Mettre en surbrillance une suggestion function highlightSuggestion(index) { const items = suggestionsContainer.querySelectorAll('.suggestion-item'); items.forEach((item, i) => { item.style.backgroundColor = i === index ? '#f0f8ff' : 'white'; }); selectedIndex = index; } // Sélectionner une suggestion function selectSuggestion(index) { if (index >= 0 && index < currentSuggestions.length) { const suggestion = currentSuggestions[index]; inputElement.value = suggestion.value; suggestionsContainer.style.display = 'none'; if (onSelect) { onSelect(suggestion); } // Déclencher l'événement input pour les validations inputElement.dispatchEvent(new Event('input', { bubbles: true })); } } // Masquer les suggestions function hideSuggestions() { if (suggestionsContainer) { suggestionsContainer.style.display = 'none'; } } // Créer le conteneur de suggestions et le bouton createSuggestionsContainer(); createSelectorButton(); // Gestionnaire d'événements pour l'input inputElement.addEventListener('input', function(e) { const value = e.target.value.trim(); if (value.length === 0) { showAllEventTypes(); return; } if (value.length < 2) { hideSuggestions(); return; } const suggestions = getEventTypeSuggestions(value); showFilteredSuggestions(suggestions); }); // Afficher l'autocomplétion au focus inputElement.addEventListener('focus', function(e) { const value = e.target.value.trim(); if (value.length === 0) { showAllEventTypes(); } else if (value.length >= 2) { const suggestions = getEventTypeSuggestions(value); showFilteredSuggestions(suggestions); } }); // Afficher l'autocomplétion au keyup inputElement.addEventListener('keyup', function(e) { // Ignorer les touches de navigation if (['ArrowDown', 'ArrowUp', 'Enter', 'Escape'].includes(e.key)) { return; } const value = e.target.value.trim(); if (value.length === 0) { showAllEventTypes(); } else if (value.length >= 2) { const suggestions = getEventTypeSuggestions(value); showFilteredSuggestions(suggestions); } }); // Fonction pour afficher les suggestions filtrées function showFilteredSuggestions(suggestions) { if (!suggestionsContainer) return; currentSuggestions = suggestions; selectedIndex = -1; if (suggestions.length === 0) { suggestionsContainer.innerHTML = `
Aucun type d'événement trouvé
`; suggestionsContainer.style.display = 'block'; return; } let html = `
${suggestions.length} résultat${suggestions.length > 1 ? 's' : ''} trouvé${suggestions.length > 1 ? 's' : ''}
`; suggestions.forEach((suggestion, index) => { const config = window.EVENT_TYPES[suggestion.value] || {}; html += `
${config.emoji || '📍'}
${config.label || suggestion.value}
${suggestion.value}
${config.category || ''}
`; }); suggestionsContainer.innerHTML = html; suggestionsContainer.style.display = 'block'; // Ajouter les gestionnaires d'événements aux suggestions const suggestionItems = suggestionsContainer.querySelectorAll('.suggestion-item'); suggestionItems.forEach((item, index) => { item.addEventListener('click', () => selectSuggestion(index)); }); } // Gestionnaire d'événements pour le clavier inputElement.addEventListener('keydown', function(e) { if (!suggestionsContainer || suggestionsContainer.style.display === 'none') { return; } switch (e.key) { case 'ArrowDown': e.preventDefault(); const nextIndex = selectedIndex < currentSuggestions.length - 1 ? selectedIndex + 1 : 0; highlightSuggestion(nextIndex); break; case 'ArrowUp': e.preventDefault(); const prevIndex = selectedIndex > 0 ? selectedIndex - 1 : currentSuggestions.length - 1; highlightSuggestion(prevIndex); break; case 'Enter': e.preventDefault(); if (selectedIndex >= 0) { selectSuggestion(selectedIndex); } break; case 'Escape': hideSuggestions(); break; } }); // Masquer les suggestions quand on clique ailleurs document.addEventListener('click', function(e) { if (!inputElement.contains(e.target) && !suggestionsContainer?.contains(e.target)) { hideSuggestions(); } }); // Masquer les suggestions quand le champ perd le focus inputElement.addEventListener('blur', function() { // Délai pour permettre le clic sur une suggestion setTimeout(hideSuggestions, 200); }); }