160 lines
6.2 KiB
JavaScript
160 lines
6.2 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function() {
|
|
function geocode(query, callback) {
|
|
fetch('/geocode?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(`/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 formatAddress(item) {
|
|
if (!item.address) return item.display_name;
|
|
const addr = item.address;
|
|
let street = addr.road || addr.pedestrian || addr.cycleway || addr.footway || addr.street || '';
|
|
let number = addr.house_number || '';
|
|
let postcode = addr.postcode || '';
|
|
let city = addr.city || addr.town || addr.village || addr.hamlet || addr.municipality || addr.county || '';
|
|
// Build formatted string: Street Number, Postal code City
|
|
let address = '';
|
|
if (street) address += street;
|
|
if (number) address += (address ? ' ' : '') + number;
|
|
if (postcode || city) {
|
|
address += (address ? ', ' : '');
|
|
address += postcode;
|
|
if (postcode && city) address += ' ';
|
|
address += city;
|
|
}
|
|
return address;
|
|
}
|
|
|
|
function showSuggestions(inputId, suggestionsId, value) {
|
|
var suggestionsBox = document.getElementById(suggestionsId);
|
|
if (!value) {
|
|
suggestionsBox.innerHTML = '';
|
|
suggestionsBox.style.display = 'none';
|
|
return;
|
|
}
|
|
fetch('/geocode?format=json&addressdetails=1&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 = formatAddress(item);
|
|
option.title = item.display_name; // Show full address on hover
|
|
option.onclick = function() {
|
|
var input = document.getElementById(inputId);
|
|
input.value = formatAddress(item);
|
|
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;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}); |