Files
freemoto/app/web/static/geolocate.js
2025-07-28 20:20:29 +02:00

139 lines
5.4 KiB
JavaScript

document.addEventListener('DOMContentLoaded', function() {
function geocode(query, callback) {
fetch('https://nominatim.openstreetmap.org/search?format=json&q=' + encodeURIComponent(query))
.then(response => response.json())
.then(data => {
if (data && data.length > 0) {
callback(data[0]);
} else {
callback(null);
}
});
}
function setInputToCurrentLocation(inputId) {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;
fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lon}`)
.then(response => response.json())
.then(data => {
document.getElementById(inputId).value = data.display_name || `${lat},${lon}`;
document.getElementById(inputId).dataset.lat = lat;
document.getElementById(inputId).dataset.lon = lon;
});
});
}
}
function showSuggestions(inputId, suggestionsId, value) {
var suggestionsBox = document.getElementById(suggestionsId);
if (!value) {
suggestionsBox.innerHTML = '';
suggestionsBox.style.display = 'none';
return;
}
fetch('https://nominatim.openstreetmap.org/search?format=json&q=' + encodeURIComponent(value))
.then(response => response.json())
.then(data => {
suggestionsBox.innerHTML = '';
if (data && data.length > 0) {
data.slice(0, 5).forEach(function(item) {
var option = document.createElement('button');
option.type = 'button';
option.className = 'list-group-item list-group-item-action';
option.textContent = item.display_name;
option.onclick = function() {
var input = document.getElementById(inputId);
input.value = item.display_name;
input.dataset.lat = item.lat;
input.dataset.lon = item.lon;
suggestionsBox.innerHTML = '';
suggestionsBox.style.display = 'none';
};
suggestionsBox.appendChild(option);
});
suggestionsBox.style.display = 'block';
} else {
suggestionsBox.style.display = 'none';
}
});
}
// Debounce helper
function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
function handleInput(e) {
var val = e.target.value;
if (val) {
geocode(val, function(result) {
if (result) {
e.target.dataset.lat = result.lat;
e.target.dataset.lon = result.lon;
} else {
delete e.target.dataset.lat;
delete e.target.dataset.lon;
}
});
} else {
delete e.target.dataset.lat;
delete e.target.dataset.lon;
}
}
document.getElementById('sourceInput').addEventListener('input', debounce(function(e) {
showSuggestions('sourceInput', 'sourceSuggestions', e.target.value);
}, 400));
document.getElementById('destInput').addEventListener('input', debounce(function(e) {
showSuggestions('destInput', 'destSuggestions', e.target.value);
}, 400));
// Hide suggestions when input loses focus (with a slight delay for click)
document.getElementById('sourceInput').addEventListener('blur', function() {
setTimeout(() => {
document.getElementById('sourceSuggestions').style.display = 'none';
}, 200);
});
document.getElementById('destInput').addEventListener('blur', function() {
setTimeout(() => {
document.getElementById('destSuggestions').style.display = 'none';
}, 200);
});
document.getElementById('useCurrentSource').onclick = function() {
setInputToCurrentLocation('sourceInput');
};
document.getElementById('useCurrentDest').onclick = function() {
setInputToCurrentLocation('destInput');
};
document.getElementById('sourceInput').addEventListener('blur', function(e) {
var val = e.target.value;
if (val && !e.target.dataset.lat) {
geocode(val, function(result) {
if (result) {
e.target.dataset.lat = result.lat;
e.target.dataset.lon = result.lon;
}
});
}
});
document.getElementById('destInput').addEventListener('blur', function(e) {
var val = e.target.value;
if (val && !e.target.dataset.lat) {
geocode(val, function(result) {
if (result) {
e.target.dataset.lat = result.lat;
e.target.dataset.lon = result.lon;
}
});
}
});
});