Compare commits

..

5 commits

12 changed files with 525 additions and 600 deletions

View file

@ -351,6 +351,35 @@ pre {
border-bottom-right-radius: 5%; border-bottom-right-radius: 5%;
} }
.early {
color: green;
}
.late {
color: red;
}
.suggestion {
display: flex;
flex-direction: row;
align-items: center;
}
.suggestion :first-child {
flex: 1;
}
.suggestion .star {
flex: 0;
pointer-events: none;
width: 24px;
height: 24px;
}
.suggestion .star.checked {
filter: invert(90%) sepia(49%) saturate(704%) hue-rotate(359deg) brightness(94%) contrast(99%);
}
.product-suburban { .product-suburban {
color: green !important; color: green !important;
} }

View file

@ -35,6 +35,22 @@
filter: invert(1); filter: invert(1);
} }
.early {
color: lightgreen;
}
.late {
color: #ff3333;
}
.suggestion .star {
filter: invert(100%);
}
.suggestion .star.checked {
filter: invert(86%) sepia(79%) saturate(2126%) hue-rotate(357deg) brightness(108%) contrast(104%);
}
.product-suburban { .product-suburban {
color: #33ff33 !important; color: #33ff33 !important;
} }

View file

@ -115,32 +115,3 @@ div.checkbox p {
div.checkbox input { div.checkbox input {
flex: 0; flex: 0;
} }
.suggestion {
display: flex;
flex-direction: row;
align-items: center;
}
.suggestion :first-child {
flex: 1;
}
.suggestion .star {
flex: 0;
pointer-events: none;
}
.suggestion .star.checked {
filter: invert(90%) sepia(49%) saturate(704%) hue-rotate(359deg) brightness(94%) contrast(99%);
}
@media (prefers-color-scheme: dark) {
.suggestion .star {
filter: invert(100%);
}
.suggestion .star.checked {
filter: invert(86%) sepia(79%) saturate(2126%) hue-rotate(357deg) brightness(108%) contrast(104%);
}
}

View file

@ -10,6 +10,7 @@ var toStation = null
* @type {Date | null} * @type {Date | null}
*/ */
var departureDate = null var departureDate = null
var arrivalInsteadOfDeparture = false
var transitKind = { var transitKind = {
ice: true, ice: true,
ic: true, ic: true,
@ -28,7 +29,11 @@ var starred = []
*/ */
var knownStations = [] var knownStations = []
var itineraries = null /**
* @type {'unavailable' | 'notRequested' | 'waiting' | 'gotData'}
*/
var nearbyStatus = 'notRequested'
var nearbyStations = []
function goToStation(stationId) { function goToStation(stationId) {
var url = new URL(window.location.href) var url = new URL(window.location.href)
@ -62,26 +67,8 @@ var focusedElement = null
var _rebuildDebounce = null var _rebuildDebounce = null
var _rebuildRequested = false var _rebuildRequested = false
function rebuildSuggestions() { function createSuggestion(suggestion, index) {
if (_rebuildDebounce !== null) { delete suggestion['products']
_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) {
var suggestionDiv = document.createElement('div') var suggestionDiv = document.createElement('div')
suggestionDiv.classList.add('suggestion') suggestionDiv.classList.add('suggestion')
@ -89,7 +76,9 @@ function rebuildSuggestions() {
suggestionDiv.appendChild(suggestionLi) suggestionDiv.appendChild(suggestionLi)
suggestionLi.classList.add('items') suggestionLi.classList.add('items')
if (index) {
suggestionLi.tabIndex = index + 1 suggestionLi.tabIndex = index + 1
}
suggestionLi.style.padding = '2px 0' suggestionLi.style.padding = '2px 0'
function onAction(e) { function onAction(e) {
@ -108,12 +97,24 @@ function rebuildSuggestions() {
var stationNameP = document.createElement('p') var stationNameP = document.createElement('p')
suggestionLi.appendChild(stationNameP) suggestionLi.appendChild(stationNameP)
stationNameP.textContent = suggestion.name || suggestion.address var stationNameSpan = document.createElement('span')
stationNameP.classList.add('pri', 'stationName') 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) { if (window.localStorage) {
var suggestionDistance = suggestion['distance']
delete suggestion['distance']
var suggestionLink = document.createElement('a') var suggestionLink = document.createElement('a')
suggestionDiv.appendChild(suggestionLink)
suggestionLink.classList.add('no-custom-a') suggestionLink.classList.add('no-custom-a')
var suggestionStar = document.createElement('object') var suggestionStar = document.createElement('object')
@ -143,6 +144,8 @@ function rebuildSuggestions() {
localStorage.setItem('stations/starred', JSON.stringify(starred)) localStorage.setItem('stations/starred', JSON.stringify(starred))
}) })
setStar() setStar()
suggestionDiv.appendChild(suggestionLink)
suggestion['distance'] = suggestionDistance
} }
// var trainCompanyP = document.createElement('p') // var trainCompanyP = document.createElement('p')
@ -150,9 +153,84 @@ function rebuildSuggestions() {
// trainCompanyP.textContent = suggestion.company // trainCompanyP.textContent = suggestion.company
// trainCompanyP.classList.add('thi') // trainCompanyP.classList.add('thi')
suggestionsArea.appendChild(suggestionDiv) 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.appendChild(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 watchId = navigator.geolocation.watchPosition(
function (data) {
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 () { setTimeout(function () {
_rebuildDebounce = null _rebuildDebounce = null
if (_rebuildRequested) { if (_rebuildRequested) {
@ -193,165 +271,6 @@ function reloadSuggestions() {
}) })
} }
/**
* @typedef DbJourney
* @prop {'journey'} type
* @prop {(DbTrip & DbArrDep & {tripId: string})[]} legs
* @prop {string} refreshToken
* @prop {DbRemark[]} remarks
*/
/**
* @param {{journeys: DbJourney[]}} data
*/
function onItineraries(data) {
var contentDiv = document.createElement('div')
document.body.insertBefore(contentDiv, document.querySelector('footer'))
contentDiv.classList.add('content')
for (var i = 0; i < data.journeys.length; i++) {
var itineraryDiv = document.createElement('div')
contentDiv.appendChild(itineraryDiv)
var heading = document.createElement('h4')
itineraryDiv.appendChild(heading)
heading.textContent = `Itinerary ${i + 1}`
var trainsDiv = document.createElement('div')
itineraryDiv.appendChild(trainsDiv)
trainsDiv.classList.add('itinerary-trains')
data.journeys[i].legs.forEach(function (train, idx) {
var last = idx === data.journeys[i].legs.length - 1
var trainDiv = document.createElement('div')
trainsDiv.appendChild(trainDiv)
trainDiv.classList.add('itinerary-train')
if (idx === 0) {
var departureTimeP = document.createElement('p')
trainDiv.appendChild(departureTimeP)
departureTimeP.classList.add('sec', 'departure', 'time')
var departureTimePre = document.createElement('pre')
departureTimeP.appendChild(departureTimePre)
var departure = new Date(train.plannedDeparture)
departureTimePre.textContent = departure.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
var departureHeading = document.createElement('h3')
trainDiv.appendChild(departureHeading)
departureHeading.classList.add('departure', 'station')
if (train.origin.type === 'stop' || train.origin.type === 'station') {
var departureLink = document.createElement('a')
departureHeading.appendChild(departureLink)
departureLink.textContent = train.origin.name
departureLink.classList.add('no-custom-a', 'items')
var departureUrl = new URL('/view-station.html', window.location.origin)
departureUrl.searchParams.set('stationId', train.origin.id)
departureLink.href = departureUrl.toString()
}
else {
var departureSpan = document.createElement('span')
departureHeading.append(departureSpan)
departureSpan.innerText = train.origin.name || train.origin.address
}
if (train.departurePlatform || train.plannedDeparturePlatform) {
var departurePlatformP = document.createElement('p')
trainDiv.append(departurePlatformP)
departurePlatformP.classList.add('sec', 'departure', 'platform')
if (train.departurePlatform && train.departurePlatform != train.plannedDeparturePlatform) {
departurePlatformP.classList.add('changed')
}
departurePlatformP.textContent = `${train.departurePlatform || train.plannedDeparturePlatform}`
}
}
var trainP = document.createElement('p')
trainDiv.appendChild(trainP)
trainP.classList.add('pri', 'train')
if (!train.walking) {
var trainLink = document.createElement('a')
trainP.appendChild(trainLink)
trainLink.innerText = train.line.name
trainLink.classList.add('no-custom-a', 'items')
var trainUrl = new URL('/view-train.html', window.location.origin)
trainUrl.searchParams.set('tripId', train.tripId)
trainLink.href = trainUrl.toString()
trainP.appendChild(document.createTextNode(' '))
if (train.line.operator) {
var trainCompany = document.createElement('span')
trainP.appendChild(trainCompany)
trainCompany.textContent = '(' + train.line.operator.name + ')'
trainCompany.classList.add('company')
}
}
else {
var walkingSpan = document.createElement('span')
trainP.append(walkingSpan)
walkingSpan.classList.add('walking')
walkingSpan.innerText = `Walking (${train.distance} m)`
}
var arrivalTimeP = document.createElement('p')
trainDiv.appendChild(arrivalTimeP)
arrivalTimeP.classList.add('sec', 'arrival', 'time')
var arrivalTimePre = document.createElement('pre')
arrivalTimeP.appendChild(arrivalTimePre)
var arrival = new Date(train.plannedArrival)
arrivalTimePre.textContent = arrival.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
var arrivalHeading = document.createElement('h3')
trainDiv.appendChild(arrivalHeading)
arrivalHeading.classList.add('arrival', 'station')
if (train.destination.type === 'stop' || train.destination.type === 'station') {
var arrivalLink = document.createElement('a')
arrivalHeading.appendChild(arrivalLink)
arrivalLink.textContent = train.destination.name
arrivalLink.classList.add('no-custom-a', 'items')
var arrivalUrl = new URL('/view-station.html', window.location.origin)
arrivalUrl.searchParams.set('stationId', train.destination.id)
arrivalLink.href = arrivalUrl.toString()
}
else {
var arrivalSpan = document.createElement('span')
arrivalHeading.append(arrivalSpan)
arrivalSpan.innerText = train.destination.name || train.origin.address
}
if (train.arrivalPlatform || train.plannedArrivalPlatform) {
var arrivalPlatformP = document.createElement('p')
trainDiv.append(arrivalPlatformP)
arrivalPlatformP.classList.add('sec', 'arrival', 'platform')
if (train.arrivalPlatform && train.arrivalPlatform != train.plannedArrivalPlatform) {
arrivalPlatformP.classList.add('changed')
}
arrivalPlatformP.textContent = `${train.arrivalPlatform || train.plannedArrivalPlatform}`
}
if (!last) {
var nextTrain = data.journeys[i].legs[idx + 1]
var nextDepartureTimeP = document.createElement('p')
trainDiv.appendChild(nextDepartureTimeP)
nextDepartureTimeP.classList.add('sec', 'next-departure', 'time')
var departureTimePre = document.createElement('pre')
nextDepartureTimeP.appendChild(departureTimePre)
var departure = new Date(nextTrain.plannedDeparture)
departureTimePre.textContent = departure.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
if (nextTrain.departurePlatform || nextTrain.plannedDeparturePlatform) {
var departurePlatformP = document.createElement('p')
trainDiv.append(departurePlatformP)
departurePlatformP.classList.add('sec', 'next-departure', 'platform')
if (nextTrain.departurePlatform && nextTrain.departurePlatform != nextTrain.plannedDeparturePlatform) {
departurePlatformP.classList.add('changed')
}
departurePlatformP.textContent = `${nextTrain.departurePlatform || nextTrain.plannedDeparturePlatform}`
}
}
})
}
}
function lsk() { function lsk() {
document.getElementById('stationName').focus() document.getElementById('stationName').focus()
} }
@ -361,15 +280,15 @@ function csk() {
return return
} }
if (focusedElement.id === 'stationName') {
goToTrain(document.activeElement.value.trim())
}
else {
focusedElement.click() focusedElement.click()
} }
}
window.addEventListener('load', function (e) { window.addEventListener('load', function (e) {
if ('geolocation' in navigator) {}
else {
nearbyStatus = 'unavailable'
}
var sp = new URL(window.location.href).searchParams var sp = new URL(window.location.href).searchParams
fromStation = sp.get('from') fromStation = sp.get('from')
var fromJson = JSON.parse(fromStation || 'null') var fromJson = JSON.parse(fromStation || 'null')
@ -388,7 +307,7 @@ window.addEventListener('load', function (e) {
titleH1.textContent = 'Find Route - To' titleH1.textContent = 'Find Route - To'
} }
else if (!departureDate) { else if (!departureDate) {
titleH1.textContent = 'Find Route - Departure Date' titleH1.textContent = 'Find Route - Date'
} }
else { else {
// titleH1.textContent = `${fromJson.name || fromJson.address} - ${toJson.name || toJson.address}` // titleH1.textContent = `${fromJson.name || fromJson.address} - ${toJson.name || toJson.address}`
@ -529,7 +448,14 @@ window.addEventListener('load', function (e) {
var a = document.getElementById('search-link') var a = document.getElementById('search-link')
var url = new URL(window.location.href) var url = new URL(window.location.href)
url.pathname = 'route.html' url.pathname = 'route.html'
if (arrivalInsteadOfDeparture) {
url.searchParams.delete('departureDate')
url.searchParams.set('arrivalDate', departureDate.toISOString())
}
else {
url.searchParams.delete('arrivalDate')
url.searchParams.set('departureDate', departureDate.toISOString()) url.searchParams.set('departureDate', departureDate.toISOString())
}
url.searchParams.set('from', JSON.stringify(fromJson)) url.searchParams.set('from', JSON.stringify(fromJson))
url.searchParams.set('to', JSON.stringify(toJson)) url.searchParams.set('to', JSON.stringify(toJson))
url.searchParams.set('transitKind', JSON.stringify(transitKind)) url.searchParams.set('transitKind', JSON.stringify(transitKind))
@ -544,6 +470,17 @@ window.addEventListener('load', function (e) {
updateSearchLink() updateSearchLink()
} }
function timeKindRadioChanged(event) {
var kind = event.target.id.split('-')[2]
if (kind === 'arrival') {
arrivalInsteadOfDeparture = true
}
else if (kind === 'departure') {
arrivalInsteadOfDeparture = false
}
updateSearchLink()
}
var contentDiv = div( var contentDiv = div(
h4('Route'), h4('Route'),
p('From').class$('thi'), p('From').class$('thi'),
@ -552,6 +489,26 @@ window.addEventListener('load', function (e) {
p(toJson.name || toJson.address).class$('pri'), p(toJson.name || toJson.address).class$('pri'),
// a('', 'Configure via...'), // a('', 'Configure via...'),
h4('Date and time'), h4('Date and time'),
div(
p(label('Departure time').att$('for', 'time-kind-departure')),
input('radio')
.checked$(!arrivalInsteadOfDeparture)
.id$('time-kind-departure')
.att$('name', 'time-kind')
.class$('time-kind')
.class$('items')
.event$('change', timeKindRadioChanged),
).class$('checkbox'),
div(
p(label('Arrival time').att$('for', 'time-kind-arrival')),
input('radio')
.checked$(arrivalInsteadOfDeparture)
.id$('time-kind-arrival')
.att$('name', 'time-kind')
.class$('time-kind')
.class$('items')
.event$('change', timeKindRadioChanged),
).class$('checkbox'),
p('Date').class$('thi'), p('Date').class$('thi'),
p(departureDate.toDateString()).class$('pri'), p(departureDate.toDateString()).class$('pri'),
p(label('Time').att$('for', 'time')).class$('thi'), p(label('Time').att$('for', 'time')).class$('thi'),
@ -559,6 +516,7 @@ window.addEventListener('load', function (e) {
input('time') input('time')
.id$('time') .id$('time')
.att$('value', departureDate.getHours().toString().padStart(2, '0') + ':' + departureDate.getMinutes().toString().padStart(2, '0')) .att$('value', departureDate.getHours().toString().padStart(2, '0') + ':' + departureDate.getMinutes().toString().padStart(2, '0'))
.class$('items')
.event$('input', function(event) { .event$('input', function(event) {
var text = event.target.value var text = event.target.value
var splitted = text.toString().split(':') var splitted = text.toString().split(':')
@ -568,13 +526,14 @@ window.addEventListener('load', function (e) {
updateSearchLink() updateSearchLink()
}), }),
), ),
h4('Train categories'), h4('Transport categories'),
div( div(
p(label('ICE, RJX, High speed').class$('product-nationalExpress').att$('for', 'transit-kind-ice')), p(label('ICE, RJX, High speed').class$('product-nationalExpress').att$('for', 'transit-kind-ice')),
input('checkbox') input('checkbox')
.checked$(transitKind.ice) .checked$(transitKind.ice)
.id$('transit-kind-ice') .id$('transit-kind-ice')
.class$('transit-kind') .class$('transit-kind')
.class$('items')
.event$('change', transitKindCheckChanged), .event$('change', transitKindCheckChanged),
).class$('checkbox'), ).class$('checkbox'),
div( div(
@ -583,6 +542,7 @@ window.addEventListener('load', function (e) {
.checked$(transitKind.ic) .checked$(transitKind.ic)
.id$('transit-kind-ic') .id$('transit-kind-ic')
.class$('transit-kind') .class$('transit-kind')
.class$('items')
.event$('change', transitKindCheckChanged), .event$('change', transitKindCheckChanged),
).class$('checkbox'), ).class$('checkbox'),
div( div(
@ -591,6 +551,7 @@ window.addEventListener('load', function (e) {
.checked$(transitKind.re) .checked$(transitKind.re)
.id$('transit-kind-re') .id$('transit-kind-re')
.class$('transit-kind') .class$('transit-kind')
.class$('items')
.event$('change', transitKindCheckChanged), .event$('change', transitKindCheckChanged),
).class$('checkbox'), ).class$('checkbox'),
div( div(
@ -599,6 +560,7 @@ window.addEventListener('load', function (e) {
.checked$(transitKind.rb) .checked$(transitKind.rb)
.id$('transit-kind-rb') .id$('transit-kind-rb')
.class$('transit-kind') .class$('transit-kind')
.class$('items')
.event$('change', transitKindCheckChanged), .event$('change', transitKindCheckChanged),
).class$('checkbox'), ).class$('checkbox'),
div( div(
@ -607,6 +569,7 @@ window.addEventListener('load', function (e) {
.checked$(transitKind.s) .checked$(transitKind.s)
.id$('transit-kind-s') .id$('transit-kind-s')
.class$('transit-kind') .class$('transit-kind')
.class$('items')
.event$('change', transitKindCheckChanged), .event$('change', transitKindCheckChanged),
).class$('checkbox'), ).class$('checkbox'),
div( div(
@ -615,6 +578,7 @@ window.addEventListener('load', function (e) {
.checked$(transitKind.u) .checked$(transitKind.u)
.id$('transit-kind-u') .id$('transit-kind-u')
.class$('transit-kind') .class$('transit-kind')
.class$('items')
.event$('change', transitKindCheckChanged), .event$('change', transitKindCheckChanged),
).class$('checkbox'), ).class$('checkbox'),
div( div(
@ -623,6 +587,7 @@ window.addEventListener('load', function (e) {
.checked$(transitKind.tram) .checked$(transitKind.tram)
.id$('transit-kind-tram') .id$('transit-kind-tram')
.class$('transit-kind') .class$('transit-kind')
.class$('items')
.event$('change', transitKindCheckChanged), .event$('change', transitKindCheckChanged),
).class$('checkbox'), ).class$('checkbox'),
div( div(
@ -631,6 +596,7 @@ window.addEventListener('load', function (e) {
.checked$(transitKind.bus) .checked$(transitKind.bus)
.id$('transit-kind-bus') .id$('transit-kind-bus')
.class$('transit-kind') .class$('transit-kind')
.class$('items')
.event$('change', transitKindCheckChanged), .event$('change', transitKindCheckChanged),
).class$('checkbox'), ).class$('checkbox'),
div( div(
@ -639,10 +605,11 @@ window.addEventListener('load', function (e) {
.checked$(transitKind.ferry) .checked$(transitKind.ferry)
.id$('transit-kind-ferry') .id$('transit-kind-ferry')
.class$('transit-kind') .class$('transit-kind')
.class$('items')
.event$('change', transitKindCheckChanged), .event$('change', transitKindCheckChanged),
).class$('checkbox'), ).class$('checkbox'),
h4('Start search'), h4('Start search'),
a('', 'Search').id$('search-link'), a('', 'Search').id$('search-link').class$('items'),
).class$('content') ).class$('content')
document.body.insertBefore(contentDiv, footer) document.body.insertBefore(contentDiv, footer)
contentDiv.style.display = 'flex' contentDiv.style.display = 'flex'

View file

@ -73,6 +73,20 @@
align-self: center; align-self: center;
} }
.itinerary-train .time .original {
color: #a0a0a0;
text-decoration: line-through;
}
.itinerary-train .time .delay {
padding-left: 4px;
padding-right: 4px;
}
.itinerary-train .time .original, .itinerary-train .time .delay {
font-size: 0.8em;
}
.itinerary-train .platform { .itinerary-train .platform {
margin: 2px; margin: 2px;
padding: 2px; padding: 2px;

View file

@ -8,4 +8,8 @@
border-color: #ff3333; border-color: #ff3333;
} }
.itinerary-train .time .original {
color: #afafaf;
}
} }

303
route.js
View file

@ -10,6 +10,10 @@ var toStation = null
* @type {Date | null} * @type {Date | null}
*/ */
var departureDate = null var departureDate = null
/**
* @type {Date | null}
*/
var arrivalDate = null
var transitKind = { var transitKind = {
ice: true, ice: true,
ic: true, ic: true,
@ -22,132 +26,10 @@ var transitKind = {
tram: true, tram: true,
} }
/**
* @type {{id: string, name: string}[]}
*/
var knownStations = []
var itineraries = null var itineraries = null
function goToStation(stationId) {
var url = new URL(window.location.href)
if (!fromStation) {
url.searchParams.set('from', stationId)
}
else if (!toStation) {
url.searchParams.set('to', stationId)
}
// url.searchParams.set('date', new Date().toISOString())
window.location.href = url.toString()
}
function setDepartureDate(departureDate) {
var url = new URL(window.location.href)
url.searchParams.set('departureDate', departureDate.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 focusedElement = null
var _rebuildDebounce = null
var _rebuildRequested = false
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()
suggestions.forEach(function (suggestion, index) {
var suggestionLi = document.createElement('li')
suggestionsArea.appendChild(suggestionLi)
setTimeout(function () {
suggestionLi.classList.add('items')
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)
stationNameP.textContent = suggestion.name || suggestion.address
stationNameP.classList.add('pri', 'stationName')
// var trainCompanyP = document.createElement('p')
// suggestionLi.appendChild(trainCompanyP)
// trainCompanyP.textContent = suggestion.company
// trainCompanyP.classList.add('thi')
}, 0)
})
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')
locationsUrl.searchParams.set('addresses', 'true')
locationsUrl.searchParams.set('poi', 'true')
fetchAbortController.abort()
fetchAbortController = new AbortController()
fetch(locationsUrl.toString(), { signal: fetchAbortController.signal })
.then(function (response) {
return response.json()
})
.then(function (data) {
if (data) {
knownStations = Object.values(data)
rebuildSuggestions()
}
})
}
/** /**
* @typedef DbJourney * @typedef DbJourney
* @prop {'journey'} type * @prop {'journey'} type
@ -199,6 +81,19 @@ function onItineraries(data) {
departureTimeP.appendChild(departureTimePre) departureTimeP.appendChild(departureTimePre)
var departure = new Date(train.plannedDeparture) var departure = new Date(train.plannedDeparture)
departureTimePre.textContent = departure.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' }) departureTimePre.textContent = departure.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
if (train.departureDelay) {
departureTimePre.classList.add('original')
var departureDelayPre = document.createElement('pre')
departureTimeP.append(departureDelayPre)
departureDelayPre.append(train.departureDelay > 0 ? '+' : '-', Math.floor(Math.abs(train.departureDelay) / 60).toString())
departureDelayPre.classList.add('delay', train.departureDelay > 0 ? 'late' : 'early')
var actualDeparturePre = document.createElement('pre')
departureTimeP.append(actualDeparturePre)
actualDeparturePre.textContent = new Date(train.departure).toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
actualDeparturePre.classList.add('actual-time', train.departureDelay > 0 ? 'late' : 'early')
}
var departureHeading = document.createElement('h3') var departureHeading = document.createElement('h3')
trainDiv.appendChild(departureHeading) trainDiv.appendChild(departureHeading)
@ -285,6 +180,19 @@ function onItineraries(data) {
arrivalTimeP.appendChild(arrivalTimePre) arrivalTimeP.appendChild(arrivalTimePre)
var arrival = new Date(train.plannedArrival) var arrival = new Date(train.plannedArrival)
arrivalTimePre.textContent = arrival.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' }) arrivalTimePre.textContent = arrival.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
if (train.arrivalDelay) {
arrivalTimePre.classList.add('original')
var arrivalDelayPre = document.createElement('pre')
arrivalTimeP.append(arrivalDelayPre)
arrivalDelayPre.append(train.arrivalDelay > 0 ? '+' : '-', Math.floor(Math.abs(train.arrivalDelay) / 60).toString())
arrivalDelayPre.classList.add('delay', train.arrivalDelay > 0 ? 'late' : 'early')
var actualArrivalPre = document.createElement('pre')
arrivalTimeP.append(actualArrivalPre)
actualArrivalPre.textContent = new Date(train.arrival).toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
actualArrivalPre.classList.add('actual-time', train.arrivalDelay > 0 ? 'late' : 'early')
}
var arrivalHeading = document.createElement('h3') var arrivalHeading = document.createElement('h3')
trainDiv.appendChild(arrivalHeading) trainDiv.appendChild(arrivalHeading)
@ -339,7 +247,7 @@ function onItineraries(data) {
} }
function lsk() { function lsk() {
document.getElementById('stationName').focus()
} }
function csk() { function csk() {
@ -347,13 +255,8 @@ function csk() {
return return
} }
if (focusedElement.id === 'stationName') {
goToTrain(document.activeElement.value.trim())
}
else {
focusedElement.click() focusedElement.click()
} }
}
window.addEventListener('load', function (e) { window.addEventListener('load', function (e) {
var sp = new URL(window.location.href).searchParams var sp = new URL(window.location.href).searchParams
@ -365,16 +268,14 @@ window.addEventListener('load', function (e) {
if (departureDateStr) { if (departureDateStr) {
departureDate = new Date(departureDateStr) departureDate = new Date(departureDateStr)
} }
var arrivalDateStr = sp.get('arrivalDate')
if (arrivalDateStr) {
arrivalDate = new Date(arrivalDateStr)
}
var titleH1 = document.querySelector("header > h1") var titleH1 = document.querySelector("header > h1")
if (!fromStation) { if (!fromJson || !toJson) {
titleH1.textContent = 'Find Route - From' titleH1.textContent = 'Find Route'
}
else if (!toStation) {
titleH1.textContent = 'Find Route - To'
}
else if (!departureDate) {
titleH1.textContent = 'Find Route - Departure Date'
} }
else { else {
titleH1.textContent = `${fromJson.name || fromJson.address} - ${toJson.name || toJson.address}` titleH1.textContent = `${fromJson.name || fromJson.address} - ${toJson.name || toJson.address}`
@ -387,113 +288,11 @@ window.addEventListener('load', function (e) {
var footer = document.querySelector('footer') var footer = document.querySelector('footer')
if (!fromStation || !toStation) { if (!fromStation || !toStation || (!departureDate && !arrivalDate)) {
// Build station selection UI // Send to config page
document.body.insertBefore( var url = new URL(window.location.href)
h4( url.pathname = '/config-route.html'
label('Station Name').att$('for', 'stationName'), window.location.href = url.toString()
),
footer,
)
// var stationNameH4 = document.createElement('h4')
// document.body.insertBefore(stationNameH4, footer)
// var stationNameLabel = document.createElement('label')
// stationNameH4.appendChild(stationNameLabel)
// stationNameLabel.htmlFor = 'stationName'
// stationNameLabel.textContent = 'Station Name'
document.body.insertBefore(
input('search').id$('stationName').att$('name', 'stationName').class$('items'),
footer,
)
// var stationNameInput = document.createElement('input')
// document.body.insertBefore(stationNameInput, footer)
// stationNameInput.type = 'search'
// stationNameInput.classList.add('items')
// stationNameInput.name = 'stationName'
// stationNameInput.id = 'stationName'
document.body.insertBefore(h4('Suggestions'), footer)
// var suggestionsH4 = document.createElement('h4')
// document.body.insertBefore(suggestionsH4, footer)
// suggestionsH4.textContent = 'Suggestions'
var contentDiv = document.createElement('div')
document.body.insertBefore(contentDiv, footer)
contentDiv.classList.add('content')
var suggestionsUl = document.createElement('ul')
contentDiv.appendChild(suggestionsUl)
suggestionsUl.id = 'suggestionsArea'
document.querySelector('.csk').textContent = 'Search'
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())
}
})
}
else if (!departureDate) {
var departureDateH4 = document.createElement('h4')
document.body.insertBefore(departureDateH4, footer)
departureDateH4.textContent = 'Departure Date'
var contentDiv = document.createElement('div')
document.body.insertBefore(contentDiv, footer)
contentDiv.classList.add('content')
var departureDateUl = document.createElement('ul')
contentDiv.appendChild(departureDateUl)
departureDateUl.id = 'suggestionsArea'
for (var i = -1, departureOption = (function () { var d = new Date(); d.setDate(d.getDate() - 1); return d })(); i < 30; i++, departureOption.setDate(departureOption.getDate() + 1)) {
var suggestionLi = document.createElement('li')
departureDateUl.appendChild(suggestionLi)
suggestionLi.classList.add('items')
suggestionLi.tabIndex = i + 10
// Capture
;(function () {
var d = new Date(departureOption.getTime())
function onAction() {
setDepartureDate(d)
}
suggestionLi.addEventListener('click', onAction)
suggestionLi.addEventListener('keypress', function (e) {
if (e.key == 'Enter') {
onAction(e)
}
})
suggestionLi.addEventListener('focus', function (e) {
focusedElement = suggestionLi
})
if (i === 0) {
suggestionLi.focus()
}
})()
var innerP = document.createElement('p')
suggestionLi.appendChild(innerP)
innerP.classList.add('pri')
var innerPre = document.createElement('pre')
innerP.appendChild(innerPre)
innerPre.textContent = `${departureOption.getDate().toString().padStart(2, '0')}.${(departureOption.getMonth() + 1).toString().padStart(2, '0')}.${departureOption.getFullYear().toString().padStart(4, '0')}`
if (i === 0) {
innerPre.textContent += ' (today)'
}
}
document.querySelector('.csk').textContent = 'Select'
} }
else { else {
var contentDiv = document.createElement('div') var contentDiv = document.createElement('div')
@ -532,7 +331,12 @@ window.addEventListener('load', function (e) {
url.searchParams.set(`to.${key}`, toJson[key]) url.searchParams.set(`to.${key}`, toJson[key])
}) })
} }
if (departureDate) {
url.searchParams.set('departure', departureDate.toISOString()) url.searchParams.set('departure', departureDate.toISOString())
}
if (arrivalDate) {
url.searchParams.set('arrival', arrivalDate.toISOString())
}
url.searchParams.set('results', '20') url.searchParams.set('results', '20')
url.searchParams.set('stopovers', 'true') url.searchParams.set('stopovers', 'true')
url.searchParams.set('nationalExpress', transitKind.ice) url.searchParams.set('nationalExpress', transitKind.ice)
@ -562,10 +366,11 @@ window.addEventListener('load', function (e) {
contentDiv.remove() contentDiv.remove()
onItineraries(data) onItineraries(data)
itineraries = data itineraries = data
function fetchMore() { function fetchMore(timeoutMs) {
console.debug(`Got ${itineraries.journeys.length} journeys, fetching more`) console.debug(`Got ${itineraries.journeys.length} journeys, fetching more`)
var moreUrl = new URL(url.toString()) var moreUrl = new URL(url.toString())
moreUrl.searchParams.delete('departure') moreUrl.searchParams.delete('departure')
moreUrl.searchParams.delete('arrival')
moreUrl.searchParams.set('laterThan', itineraries.laterRef) moreUrl.searchParams.set('laterThan', itineraries.laterRef)
fetch(moreUrl.toString()) fetch(moreUrl.toString())
.then(function (result) { .then(function (result) {
@ -582,13 +387,21 @@ window.addEventListener('load', function (e) {
var lastLeg = lastJourney.legs[lastJourney.legs.length - 1] var lastLeg = lastJourney.legs[lastJourney.legs.length - 1]
var departureDate = new Date(lastLeg.plannedDeparture) var departureDate = new Date(lastLeg.plannedDeparture)
if (departureDate.getTime() - Date.now() < 86400000) { if (departureDate.getTime() - Date.now() < 86400000) {
setTimeout(fetchMore, 500) setTimeout(
function () {
fetchMore((timeoutMs || 500) * 1.5)
},
timeoutMs || 500,
)
} }
} }
} }
}) })
} }
if (departureDate) {
fetchMore() fetchMore()
}
}) })
.catch(function (e) { .catch(function (e) {
loadingP.textContent = 'An error has occured' loadingP.textContent = 'An error has occured'

View file

@ -15,6 +15,7 @@
<script src="/common/worker.js"></script> <script src="/common/worker.js"></script>
<script defer src="/common/back.js"></script> <script defer src="/common/back.js"></script>
<script defer src="/common/items.js"></script> <script defer src="/common/items.js"></script>
<script defer src="/common/components.js"></script>
<script defer src="station.js"></script> <script defer src="station.js"></script>
</head> </head>
<body> <body>

View file

@ -1,5 +1,12 @@
var starred = []
var knownStations = [] var knownStations = []
/**
* @type {'unavailable' | 'notRequested' | 'waiting' | 'gotData'}
*/
var nearbyStatus = 'notRequested'
var nearbyStations = []
function goToStation(stationId) { function goToStation(stationId) {
var url = new URL(window.location.href) var url = new URL(window.location.href)
url.pathname = 'view-station.html' url.pathname = 'view-station.html'
@ -22,6 +29,94 @@ var focusedElement = null
var _rebuildDebounce = null var _rebuildDebounce = null
var _rebuildRequested = false 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() { function rebuildSuggestions() {
if (_rebuildDebounce !== null) { if (_rebuildDebounce !== null) {
_rebuildRequested = true _rebuildRequested = true
@ -37,42 +132,66 @@ function rebuildSuggestions() {
} }
var suggestions = knownStations.slice() var suggestions = knownStations.slice()
if (suggestions.length === 0) {
suggestions = starred.map(function (s) { return JSON.parse(s) })
}
suggestions.forEach(function (suggestion, index) { suggestions.forEach(function (suggestion, index) {
var suggestionLi = document.createElement('li') suggestionsArea.append(createSuggestion(suggestion, index))
suggestionsArea.appendChild(suggestionLi) })
setTimeout(function () { if (nearbyStatus !== 'unavailable') {
suggestionLi.classList.add('items') suggestionsArea.appendChild(h4('Nearby stations'))
suggestionLi.tabIndex = index + 1 if (nearbyStatus === 'notRequested') {
suggestionLi.style.padding = '2px 0' suggestionsArea.appendChild(a('', 'Load nearby stations').event$('click', function (event) {
event.preventDefault()
function onAction(e) { var watchId = navigator.geolocation.watchPosition(
goToStation(suggestion.id) function (data) {
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()
} }
suggestionLi.addEventListener('click', onAction) navigator.geolocation.clearWatch(watchId)
suggestionLi.addEventListener('keypress', function (e) { },
if (e.key == 'Enter') { {
onAction(e) 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))
}) })
suggestionLi.addEventListener('focus', function (e) { }
focusedElement = suggestionLi }
})
var stationNameP = document.createElement('p')
suggestionLi.appendChild(stationNameP)
stationNameP.textContent = suggestion.name
stationNameP.classList.add('pri', 'stationName')
// var trainCompanyP = document.createElement('p')
// suggestionLi.appendChild(trainCompanyP)
// trainCompanyP.textContent = suggestion.company
// trainCompanyP.classList.add('thi')
}, 0)
})
setTimeout(function () { setTimeout(function () {
_rebuildDebounce = null _rebuildDebounce = null
@ -97,7 +216,12 @@ function reloadSuggestions() {
fetchAbortController = new AbortController() fetchAbortController = new AbortController()
fetch(locationsUrl.toString(), { signal: fetchAbortController.signal }) fetch(locationsUrl.toString(), { signal: fetchAbortController.signal })
.then(function (response) { .then(function (response) {
if (response.ok) {
return response.json() return response.json()
}
else {
return {}
}
}) })
.then(function (data) { .then(function (data) {
if (data) { if (data) {
@ -125,6 +249,13 @@ function csk() {
} }
window.addEventListener('load', function (e) { window.addEventListener('load', function (e) {
if (window.localStorage) {
var maybeStarred = JSON.parse(localStorage.getItem('stations/starred'))
if (maybeStarred) {
starred = maybeStarred
}
}
var stationName = document.getElementById('stationName') var stationName = document.getElementById('stationName')
stationName.addEventListener('input', function (e) { stationName.addEventListener('input', function (e) {
reloadSuggestions() reloadSuggestions()

62
sw.js
View file

@ -1,8 +1,4 @@
const VERSION = 'v15' const VERSION = 'v17'
const API_ORIGIN = 'https://scraper.infotren.dcdev.ro/'
const API_TRAINS = `${API_ORIGIN}v3/trains`
const API_STATIONS = `${API_ORIGIN}v3/stations`
const API_ITINERARIES = `${API_ORIGIN}v3/itineraries`
const CACHE_FIRST = [ const CACHE_FIRST = [
// Root // Root
@ -12,52 +8,48 @@ const CACHE_FIRST = [
'/common/back.svg', '/common/back.svg',
// Utility JS // Utility JS
'/common/worker.js',
'/common/items.js',
'/common/back.js', '/common/back.js',
'/common/components.js',
'/common/items.js',
'/common/tabs.js', '/common/tabs.js',
'/common/trainId.js', '/common/trainId.js',
'/common/worker.js',
// Base // Base
'/base.css', '/base.css',
'/base.dark.css', '/base.dark.css',
// Pages // Pages
'/index.html',
'/index.js',
'/about.html', '/about.html',
'/about.js', '/about.js',
'/train.html',
'/train.js',
'/view-train.html',
'/view-train.js',
'/view-train.css',
'/view-train.dark.css',
'/station.html',
'/station.js',
'/view-station.html',
'/view-station.js',
'/view-station.css',
'/view-station.dark.css',
'/config-route.html', '/config-route.html',
'/config-route.js', '/config-route.js',
'/config-route.css', '/config-route.css',
'/index.html',
'/index.js',
'/route.html', '/route.html',
'/route.js', '/route.js',
'/route.css', '/route.css',
'/route.dark.css', '/route.dark.css',
// API '/station.html',
API_TRAINS, '/station.js',
API_STATIONS,
// API_ITINERARIES, '/train.html',
'/train.js',
'/view-station.html',
'/view-station.js',
'/view-station.css',
'/view-station.dark.css',
'/view-train.html',
'/view-train.js',
'/view-train.css',
'/view-train.dark.css',
]; ];
/** /**
@ -140,7 +132,9 @@ const putInCache = async (request, response) => {
const cacheFirst = async ({ request, preloadResponsePromise, refreshAnyway }) => { const cacheFirst = async ({ request, preloadResponsePromise, refreshAnyway }) => {
// First try to get the resource from the cache // First try to get the resource from the cache
const responseFromCache = await caches.match(request) const responseFromCache = await caches.match(request, {
ignoreSearch: true,
})
if (responseFromCache) { if (responseFromCache) {
if (refreshAnyway || (responseFromCache.headers.has('SW-Cached-At') && Date.now() - new Date(responseFromCache.headers.get('SW-Cached-At')).valueOf() > 86400000)) { if (refreshAnyway || (responseFromCache.headers.has('SW-Cached-At') && Date.now() - new Date(responseFromCache.headers.get('SW-Cached-At')).valueOf() > 86400000)) {
console.log('[cf] using cache response; refreshing anyway but returning cache', responseFromCache); console.log('[cf] using cache response; refreshing anyway but returning cache', responseFromCache);
@ -232,7 +226,9 @@ const networkFirst = async ({ request, preloadResponsePromise }) => {
} }
// Response from network wasn't ok, try to find in cache // Response from network wasn't ok, try to find in cache
const responseFromCache = await caches.match(request) const responseFromCache = await caches.match(request, {
ignoreSearch: true,
})
if (responseFromCache) { if (responseFromCache) {
console.log('[nf] using cache response', responseFromCache) console.log('[nf] using cache response', responseFromCache)
return responseFromCache return responseFromCache
@ -255,7 +251,7 @@ self.addEventListener('fetch', (event) => {
cacheFirst({ cacheFirst({
request: event.request, request: event.request,
preloadResponsePromise: event.preloadResponse, preloadResponsePromise: event.preloadResponse,
refreshAnyway: [API_STATIONS, API_TRAINS].includes(event.request.url.split('?')[0]), refreshAnyway: [].includes(event.request.url.split('?')[0]),
}) })
) )
} }

View file

@ -1,11 +1,3 @@
.early {
color: green;
}
.late {
color: red;
}
.station { .station {
color: black; color: black;
} }

View file

@ -1,13 +1,4 @@
@media(prefers-color-scheme: dark) { @media(prefers-color-scheme: dark) {
.early {
color: lightgreen;
}
.late {
color: #ff3333;
}
.station { .station {
color: white; color: white;
} }