|
|
|
var starred = []
|
|
|
|
var knownStations = []
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @type {'unavailable' | 'notRequested' | 'waiting' | 'gotData'}
|
|
|
|
*/
|
|
|
|
var nearbyStatus = 'notRequested'
|
|
|
|
var nearbyStations = []
|
|
|
|
|
|
|
|
function goToStation(stationId) {
|
|
|
|
var url = new URL(window.location.href)
|
|
|
|
url.pathname = 'view-station.html'
|
|
|
|
url.searchParams.set('stationId', stationId)
|
|
|
|
url.searchParams.set('date', new Date().toISOString())
|
|
|
|
window.location.href = url.toString()
|
|
|
|
}
|
|
|
|
|
|
|
|
function searchNormalize(str) {
|
|
|
|
return str
|
|
|
|
.toLowerCase()
|
|
|
|
.replaceAll('ă', 'a')
|
|
|
|
.replaceAll('â', 'a')
|
|
|
|
.replaceAll('î', 'i')
|
|
|
|
.replaceAll('ș', 's')
|
|
|
|
.replaceAll('ț', 't')
|
|
|
|
}
|
|
|
|
|
|
|
|
var focusedElement = null
|
|
|
|
|
|
|
|
var _rebuildDebounce = null
|
|
|
|
var _rebuildRequested = false
|
|
|
|
function createSuggestion(suggestion, index) {
|
|
|
|
delete suggestion['products']
|
|
|
|
var suggestionDiv = document.createElement('div')
|
|
|
|
suggestionDiv.classList.add('suggestion')
|
|
|
|
|
|
|
|
var suggestionLi = document.createElement('li')
|
|
|
|
suggestionDiv.appendChild(suggestionLi)
|
|
|
|
|
|
|
|
suggestionLi.classList.add('items')
|
|
|
|
if (index) {
|
|
|
|
suggestionLi.tabIndex = index + 1
|
|
|
|
}
|
|
|
|
suggestionLi.style.padding = '2px 0'
|
|
|
|
|
|
|
|
function onAction(e) {
|
|
|
|
goToStation(JSON.stringify(suggestion))
|
|
|
|
}
|
|
|
|
suggestionLi.addEventListener('click', onAction)
|
|
|
|
suggestionLi.addEventListener('keypress', function (e) {
|
|
|
|
if (e.key == 'Enter') {
|
|
|
|
onAction(e)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
suggestionLi.addEventListener('focus', function (e) {
|
|
|
|
focusedElement = suggestionLi
|
|
|
|
})
|
|
|
|
|
|
|
|
var stationNameP = document.createElement('p')
|
|
|
|
suggestionLi.appendChild(stationNameP)
|
|
|
|
|
|
|
|
var stationNameSpan = document.createElement('span')
|
|
|
|
stationNameP.append(stationNameSpan)
|
|
|
|
stationNameSpan.textContent = suggestion.name || suggestion.address
|
|
|
|
stationNameSpan.classList.add('pri', 'stationName')
|
|
|
|
|
|
|
|
if (suggestion.distance) {
|
|
|
|
stationNameP.append(' ')
|
|
|
|
var stationDistanceSpan = document.createElement('span')
|
|
|
|
stationNameP.append(stationDistanceSpan)
|
|
|
|
stationDistanceSpan.append('(', suggestion.distance.toString(), ' m)')
|
|
|
|
stationDistanceSpan.classList.add('stationDistance')
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (window.localStorage) {
|
|
|
|
var suggestionDistance = suggestion['distance']
|
|
|
|
delete suggestion['distance']
|
|
|
|
var suggestionLink = document.createElement('a')
|
|
|
|
suggestionLink.classList.add('no-custom-a')
|
|
|
|
|
|
|
|
var suggestionStar = document.createElement('object')
|
|
|
|
suggestionLink.appendChild(suggestionStar)
|
|
|
|
suggestionStar.classList.add('star')
|
|
|
|
suggestionStar.type = 'image/svg+xml'
|
|
|
|
function setStar() {
|
|
|
|
if (starred.includes(JSON.stringify(suggestion))) {
|
|
|
|
suggestionStar.data = '/icons/star_full.svg'
|
|
|
|
suggestionStar.classList.add('checked')
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
suggestionStar.data = '/icons/star_empty.svg'
|
|
|
|
suggestionStar.classList.remove('checked')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
suggestionLink.addEventListener('click', function (event) {
|
|
|
|
event.preventDefault()
|
|
|
|
if (starred.includes(JSON.stringify(suggestion))) {
|
|
|
|
starred = starred.filter(function (s) {
|
|
|
|
return s !== suggestion
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
starred.push(JSON.stringify(suggestion))
|
|
|
|
}
|
|
|
|
setStar()
|
|
|
|
localStorage.setItem('stations/starred', JSON.stringify(starred))
|
|
|
|
})
|
|
|
|
setStar()
|
|
|
|
suggestionDiv.appendChild(suggestionLink)
|
|
|
|
suggestion['distance'] = suggestionDistance
|
|
|
|
}
|
|
|
|
|
|
|
|
// var trainCompanyP = document.createElement('p')
|
|
|
|
// suggestionLi.appendChild(trainCompanyP)
|
|
|
|
|
|
|
|
// trainCompanyP.textContent = suggestion.company
|
|
|
|
// trainCompanyP.classList.add('thi')
|
|
|
|
return suggestionDiv
|
|
|
|
}
|
|
|
|
function rebuildSuggestions() {
|
|
|
|
if (_rebuildDebounce !== null) {
|
|
|
|
_rebuildRequested = true
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
_rebuildRequested = false
|
|
|
|
_rebuildDebounce = 123
|
|
|
|
|
|
|
|
var suggestionsArea = document.getElementById('suggestionsArea')
|
|
|
|
while (suggestionsArea.childNodes.length > 0) {
|
|
|
|
suggestionsArea.childNodes[0].remove()
|
|
|
|
}
|
|
|
|
|
|
|
|
var suggestions = knownStations.slice()
|
|
|
|
if (suggestions.length === 0) {
|
|
|
|
suggestions = starred.map(function (s) { return JSON.parse(s) })
|
|
|
|
}
|
|
|
|
|
|
|
|
suggestions.forEach(function (suggestion, index) {
|
|
|
|
suggestionsArea.append(createSuggestion(suggestion, index))
|
|
|
|
})
|
|
|
|
|
|
|
|
if (nearbyStatus !== 'unavailable') {
|
|
|
|
suggestionsArea.appendChild(h4('Nearby stations'))
|
|
|
|
if (nearbyStatus === 'notRequested') {
|
|
|
|
suggestionsArea.appendChild(a('', 'Load nearby stations').event$('click', function (event) {
|
|
|
|
event.preventDefault()
|
|
|
|
var latitude = 0
|
|
|
|
var longitude = 0
|
|
|
|
var watchId = navigator.geolocation.watchPosition(
|
|
|
|
function (data) {
|
|
|
|
if (data.coords.latitude !== latitude || data.coords.longitude !== longitude) {
|
|
|
|
latitude = data.coords.latitude
|
|
|
|
longitude = data.coords.longitude
|
|
|
|
var geoUrl = new URL('https://v6.db.transport.rest/locations/nearby')
|
|
|
|
geoUrl.searchParams.append('latitude', data.coords.latitude.toString())
|
|
|
|
geoUrl.searchParams.append('longitude', data.coords.longitude.toString())
|
|
|
|
geoUrl.searchParams.append('results', '10')
|
|
|
|
fetch(geoUrl)
|
|
|
|
.then(function (response) {
|
|
|
|
return response.json()
|
|
|
|
})
|
|
|
|
.then(function (data) {
|
|
|
|
nearbyStatus = 'gotData'
|
|
|
|
nearbyStations = data
|
|
|
|
rebuildSuggestions()
|
|
|
|
})
|
|
|
|
.catch(function () {
|
|
|
|
nearbyStatus = 'unavailable'
|
|
|
|
rebuildSuggestions()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
|
|
|
function (error) {
|
|
|
|
if (nearbyStations.length === 0) {
|
|
|
|
nearbyStatus = 'unavailable'
|
|
|
|
rebuildSuggestions()
|
|
|
|
}
|
|
|
|
navigator.geolocation.clearWatch(watchId)
|
|
|
|
},
|
|
|
|
{
|
|
|
|
enableHighAccuracy: true,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
nearbyStatus = 'waiting'
|
|
|
|
rebuildSuggestions()
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
else if (nearbyStatus === 'waiting') {
|
|
|
|
var waitingP = document.createElement('p')
|
|
|
|
suggestionsArea.append(waitingP)
|
|
|
|
waitingP.append('Loading...')
|
|
|
|
waitingP.classList.add('pri')
|
|
|
|
}
|
|
|
|
else if (nearbyStatus === 'gotData') {
|
|
|
|
nearbyStations.forEach(function (suggestion, index) {
|
|
|
|
suggestionsArea.appendChild(createSuggestion(suggestion, suggestions.length + index))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
_rebuildDebounce = null
|
|
|
|
if (_rebuildRequested) {
|
|
|
|
rebuildSuggestions()
|
|
|
|
}
|
|
|
|
}, 500)
|
|
|
|
}
|
|
|
|
|
|
|
|
var fetchAbortController = new AbortController()
|
|
|
|
function reloadSuggestions() {
|
|
|
|
var stationNameInput = document.getElementById('stationName')
|
|
|
|
var stationName = searchNormalize(stationNameInput.value.trim())
|
|
|
|
|
|
|
|
var locationsUrl = new URL('https://v6.db.transport.rest/locations')
|
|
|
|
locationsUrl.searchParams.set('query', stationName)
|
|
|
|
locationsUrl.searchParams.set('limit', '25')
|
|
|
|
locationsUrl.searchParams.set('fuzzy', 'true')
|
|
|
|
locationsUrl.searchParams.set('stops', 'true')
|
|
|
|
|
|
|
|
fetchAbortController.abort()
|
|
|
|
fetchAbortController = new AbortController()
|
|
|
|
fetch(locationsUrl.toString(), { signal: fetchAbortController.signal })
|
|
|
|
.then(function (response) {
|
|
|
|
if (response.ok) {
|
|
|
|
return response.json()
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return {}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.then(function (data) {
|
|
|
|
if (data) {
|
|
|
|
knownStations = Object.values(data)
|
|
|
|
rebuildSuggestions()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function lsk() {
|
|
|
|
document.getElementById('stationName').focus()
|
|
|
|
}
|
|
|
|
|
|
|
|
function csk() {
|
|
|
|
if (focusedElement == null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
focusedElement.click()
|
|
|
|
}
|
|
|
|
|
|
|
|
window.addEventListener('load', function (e) {
|
|
|
|
if (window.localStorage) {
|
|
|
|
var maybeStarred = JSON.parse(localStorage.getItem('stations/starred'))
|
|
|
|
if (maybeStarred) {
|
|
|
|
starred = maybeStarred.filter(function (item) { return item.id })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var stationName = document.getElementById('stationName')
|
|
|
|
stationName.addEventListener('input', function (e) {
|
|
|
|
reloadSuggestions()
|
|
|
|
})
|
|
|
|
stationName.addEventListener('focus', function (e) {
|
|
|
|
focusedElement = stationName
|
|
|
|
document.getElementsByClassName('lsk')[0].textContent = ''
|
|
|
|
document.getElementsByClassName('csk')[0].textContent = 'Search'
|
|
|
|
})
|
|
|
|
stationName.addEventListener('blur', function (e) {
|
|
|
|
document.getElementsByClassName('lsk')[0].textContent = 'Search'
|
|
|
|
document.getElementsByClassName('csk')[0].textContent = 'Select'
|
|
|
|
})
|
|
|
|
stationName.addEventListener('keypress', function (e) {
|
|
|
|
if (e.key == 'Enter') {
|
|
|
|
goToStation(stationName.value.trim())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
document.querySelectorAll('.lsk').forEach(function (lskElem) {
|
|
|
|
lskElem.addEventListener('click', function (e) {
|
|
|
|
lsk()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
document.querySelectorAll('.csk').forEach(function (cskElem) {
|
|
|
|
cskElem.addEventListener('click', function (e) {
|
|
|
|
csk()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
document.body.addEventListener('keydown', function (e) {
|
|
|
|
if (e.key == 'SoftLeft') {
|
|
|
|
lsk()
|
|
|
|
}
|
|
|
|
else if (e.key == 'Enter') {
|
|
|
|
csk()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
reloadSuggestions()
|
|
|
|
})
|