112 lines
No EOL
3.1 KiB
Smarty
112 lines
No EOL
3.1 KiB
Smarty
<!-- Script d'autocomplétion ville/département — API Géo (gouvernement français) -->
|
|
<script>
|
|
(function () {
|
|
const input = document.getElementById('user_location');
|
|
const suggestions = document.getElementById('location-suggestions');
|
|
let debounceTimer = null;
|
|
|
|
// Ferme la liste si on clique ailleurs
|
|
document.addEventListener('click', function (e) {
|
|
if (!input.contains(e.target) && !suggestions.contains(e.target)) {
|
|
hideSuggestions();
|
|
}
|
|
});
|
|
|
|
input.addEventListener('input', function () {
|
|
const query = this.value.trim();
|
|
|
|
clearTimeout(debounceTimer);
|
|
|
|
if (query.length < 2) {
|
|
hideSuggestions();
|
|
return;
|
|
}
|
|
|
|
// Délai de 300 ms pour éviter trop d'appels API
|
|
debounceTimer = setTimeout(function () {
|
|
fetchCities(query);
|
|
}, 300);
|
|
});
|
|
|
|
// Navigation clavier dans la liste
|
|
input.addEventListener('keydown', function (e) {
|
|
const items = suggestions.querySelectorAll('.list-group-item');
|
|
const active = suggestions.querySelector('.list-group-item.active');
|
|
let index = Array.from(items).indexOf(active);
|
|
|
|
if (e.key === 'ArrowDown') {
|
|
e.preventDefault();
|
|
if (index < items.length - 1) setActive(items, index + 1);
|
|
} else if (e.key === 'ArrowUp') {
|
|
e.preventDefault();
|
|
if (index > 0) setActive(items, index - 1);
|
|
} else if (e.key === 'Enter' && active) {
|
|
e.preventDefault();
|
|
selectItem(active.dataset.value);
|
|
} else if (e.key === 'Escape') {
|
|
hideSuggestions();
|
|
}
|
|
});
|
|
|
|
function fetchCities(query) {
|
|
// On cherche par nom de commune, on récupère aussi le département
|
|
const url = 'https://geo.api.gouv.fr/communes?nom=' + encodeURIComponent(query)
|
|
+ '&fields=nom,departement&boost=population&limit=8';
|
|
|
|
fetch(url)
|
|
.then(function (res) { return res.json(); })
|
|
.then(function (data) { renderSuggestions(data); })
|
|
.catch(function () { hideSuggestions(); });
|
|
}
|
|
|
|
function renderSuggestions(cities) {
|
|
suggestions.innerHTML = '';
|
|
|
|
if (!cities || cities.length === 0) {
|
|
hideSuggestions();
|
|
return;
|
|
}
|
|
|
|
cities.forEach(function (city) {
|
|
const dept = city.departement
|
|
? city.departement.nom + ' (' + city.departement.code + ')'
|
|
: '';
|
|
const label = city.nom + (dept ? ' — ' + dept : '');
|
|
// Valeur stockée : "Ville (Département)"
|
|
const value = city.nom + (city.departement ? ' (' + city.departement.nom + ')' : '');
|
|
|
|
const li = document.createElement('li');
|
|
li.className = 'list-group-item list-group-item-action py-2 px-3';
|
|
li.style.cursor = 'pointer';
|
|
li.dataset.value = value;
|
|
li.textContent = label;
|
|
|
|
li.addEventListener('mousedown', function (e) {
|
|
// mousedown avant blur pour éviter que la liste disparaisse avant le clic
|
|
e.preventDefault();
|
|
selectItem(value);
|
|
});
|
|
|
|
suggestions.appendChild(li);
|
|
});
|
|
|
|
suggestions.style.display = 'block';
|
|
}
|
|
|
|
function selectItem(value) {
|
|
input.value = value;
|
|
hideSuggestions();
|
|
}
|
|
|
|
function hideSuggestions() {
|
|
suggestions.style.display = 'none';
|
|
suggestions.innerHTML = '';
|
|
}
|
|
|
|
function setActive(items, index) {
|
|
items.forEach(function (item) { item.classList.remove('active'); });
|
|
items[index].classList.add('active');
|
|
input.value = items[index].dataset.value;
|
|
}
|
|
})();
|
|
</script> |