|
|
|
var stationId
|
|
|
|
var date
|
|
|
|
|
|
|
|
var stationData = {
|
|
|
|
departures: [],
|
|
|
|
arrivals: [],
|
|
|
|
}
|
|
|
|
var lastSuccessfulFetch = null
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef StationArrDep
|
|
|
|
* @property {string} tripId
|
|
|
|
* @property {DbStop} stop
|
|
|
|
* @property {string | null} when
|
|
|
|
* @property {string} plannedWhen
|
|
|
|
* @property {number | null} delay
|
|
|
|
* @property {string | null} platform
|
|
|
|
* @property {string | null} plannedPlatform
|
|
|
|
* @property {string | null} prognosisType
|
|
|
|
* @property {string | null} direction
|
|
|
|
* @property {string | null} provenance
|
|
|
|
* @property {DbLine} line
|
|
|
|
* @property {DbRemark[]} remarks
|
|
|
|
* @property {DbStop | null} origin
|
|
|
|
* @property {DbStop | null} destionation
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef StationData
|
|
|
|
* @prop {StationArrDep[]} departures
|
|
|
|
* @prop {StationArrDep[]} arrivals
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {?StationData} data
|
|
|
|
*/
|
|
|
|
function onStationData(data) {
|
|
|
|
if (!data || !data.arrivals && !data?.departures) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var title = document.getElementById('title')
|
|
|
|
title.textContent = (data.departures[0] || data.arrivals[0]).stop.name
|
|
|
|
|
|
|
|
// document.getElementById('date').textContent = data.date
|
|
|
|
|
|
|
|
document.getElementById('loading').classList.add('hidden')
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {HTMLElement} elem
|
|
|
|
* @param {StationArrDep[]} trains
|
|
|
|
*/
|
|
|
|
function addTrains(elem, trains) {
|
|
|
|
while (elem.childNodes.length > 0) {
|
|
|
|
elem.childNodes[0].remove()
|
|
|
|
}
|
|
|
|
|
|
|
|
var trainsList = document.createElement('ul')
|
|
|
|
elem.appendChild(trainsList)
|
|
|
|
|
|
|
|
trains.forEach(function (train, tIdx) {
|
|
|
|
var trainItem = document.createElement('li')
|
|
|
|
trainsList.appendChild(trainItem)
|
|
|
|
trainItem.classList.add('train-item')
|
|
|
|
// if (train.status && train.status.cancelled) {
|
|
|
|
// trainItem.classList.add('cancelled')
|
|
|
|
// }
|
|
|
|
|
|
|
|
var timeDiv = document.createElement('p')
|
|
|
|
trainItem.appendChild(timeDiv)
|
|
|
|
timeDiv.classList.add('pri', 'time')
|
|
|
|
var timeDivPre = document.createElement('pre')
|
|
|
|
timeDiv.appendChild(timeDivPre)
|
|
|
|
timeDivPre.textContent = new Date(train.plannedWhen).toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
|
|
|
|
|
|
|
|
if (train.delay && train.delay != 0) {
|
|
|
|
var delayDiv = document.createElement('p')
|
|
|
|
trainItem.appendChild(delayDiv)
|
|
|
|
delayDiv.classList.add('thi', 'delay')
|
|
|
|
delayDiv.textContent = `${train.delay / 60} min `
|
|
|
|
// delayDiv.appendChild(document.createElement('br'))
|
|
|
|
var descSpan = document.createElement('span')
|
|
|
|
delayDiv.appendChild(descSpan)
|
|
|
|
if (train.delay > 0) {
|
|
|
|
descSpan.classList.add('late')
|
|
|
|
descSpan.textContent = 'late'
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
descSpan.classList.add('early')
|
|
|
|
descSpan.textContent = 'early'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// var rankDiv = document.createElement('p')
|
|
|
|
// trainItem.appendChild(rankDiv)
|
|
|
|
// rankDiv.classList.add('sec', 'rank', train.train.rank)
|
|
|
|
// var rankDivPre = document.createElement('pre')
|
|
|
|
// rankDiv.appendChild(rankDivPre)
|
|
|
|
// rankDivPre.textContent = train.train.rank
|
|
|
|
|
|
|
|
var trainDiv = document.createElement('p')
|
|
|
|
trainItem.appendChild(trainDiv)
|
|
|
|
trainDiv.classList.add('pri', 'train')
|
|
|
|
var trainDivHref = document.createElement('a')
|
|
|
|
trainDiv.appendChild(trainDivHref)
|
|
|
|
trainDivHref.classList.add('no-a-custom')
|
|
|
|
var trainUrl = new URL('/view-train.html', window.location.origin)
|
|
|
|
trainUrl.searchParams.append('tripId', train.tripId)
|
|
|
|
trainDivHref.href = trainUrl.toString()
|
|
|
|
var trainDivHrefPre = document.createElement('pre')
|
|
|
|
trainDivHref.appendChild(trainDivHrefPre)
|
|
|
|
trainDivHrefPre.textContent = train.line.name
|
|
|
|
|
|
|
|
var terminusDiv = document.createElement('p')
|
|
|
|
trainItem.appendChild(terminusDiv)
|
|
|
|
terminusDiv.classList.add('pri', 'terminus')
|
|
|
|
terminusDiv.textContent = train.direction
|
|
|
|
|
|
|
|
if (train.platform) {
|
|
|
|
var platformDiv = document.createElement('div')
|
|
|
|
trainItem.appendChild(platformDiv)
|
|
|
|
platformDiv.classList.add('thi', 'platform')
|
|
|
|
if (train.platform && train.platform !== train.plannedPlatform) {
|
|
|
|
platformDiv.classList.add('changed')
|
|
|
|
}
|
|
|
|
var platformDivPre = document.createElement('pre')
|
|
|
|
platformDiv.appendChild(platformDivPre)
|
|
|
|
platformDivPre.textContent = train.platform || train.plannedPlatform
|
|
|
|
}
|
|
|
|
|
|
|
|
if (train.cancelled) {
|
|
|
|
trainItem.classList.add('cancelled')
|
|
|
|
var statusDiv = document.createElement('p')
|
|
|
|
trainItem.appendChild(statusDiv)
|
|
|
|
statusDiv.classList.add('sec', 'status', 'status-cancel')
|
|
|
|
statusDiv.textContent = 'This journey is cancelled'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
addTrains(document.getElementById('arrivals'), data.arrivals)
|
|
|
|
addTrains(document.getElementById('departures'), data.departures)
|
|
|
|
}
|
|
|
|
|
|
|
|
var refreshStopToken = null
|
|
|
|
function refresh() {
|
|
|
|
function reschedule(timeout) {
|
|
|
|
if (refreshStopToken != null) {
|
|
|
|
clearTimeout(refreshStopToken)
|
|
|
|
}
|
|
|
|
refreshStopToken = setTimeout(function () {
|
|
|
|
refresh()
|
|
|
|
}, timeout || 90000)
|
|
|
|
}
|
|
|
|
var reqDate = new Date(date.valueOf())
|
|
|
|
// reqDate.setHours(0, 0, 0, 0)
|
|
|
|
reqDate.setMinutes(reqDate.getMinutes() - 15)
|
|
|
|
return Promise.all([
|
|
|
|
fetch(
|
|
|
|
`https://v6.db.transport.rest/stops/${stationId}/arrivals?when=${reqDate.toISOString()}&duration=1440`,
|
|
|
|
{
|
|
|
|
cache: 'no-store',
|
|
|
|
},
|
|
|
|
),
|
|
|
|
fetch(
|
|
|
|
`https://v6.db.transport.rest/stops/${stationId}/departures?when=${reqDate.toISOString()}&duration=1440`,
|
|
|
|
{
|
|
|
|
cache: 'no-store',
|
|
|
|
},
|
|
|
|
),
|
|
|
|
]).then(function (responses) {
|
|
|
|
if (!responses[0].ok || !responses[1].ok) {
|
|
|
|
// Check in 10 seconds if server returned error
|
|
|
|
reschedule(10000)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var cacheDate = responses[0].headers.get('SW-Cached-At')
|
|
|
|
return Promise.all(responses.map(function (r) {return r.json() })).then(function (data) {
|
|
|
|
data['$cacheDate'] = cacheDate
|
|
|
|
return data
|
|
|
|
})
|
|
|
|
}).then(function (responses) {
|
|
|
|
if (!responses) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var cacheDate = responses['$cacheDate']
|
|
|
|
if (cacheDate) {
|
|
|
|
cacheDate = new Date(cacheDate)
|
|
|
|
}
|
|
|
|
var success = !cacheDate
|
|
|
|
stationData.arrivals = responses[0].arrivals
|
|
|
|
stationData.departures = responses[1].departures
|
|
|
|
onStationData(stationData)
|
|
|
|
// Check in 1 seconds if network error
|
|
|
|
reschedule(success ? undefined : 1000)
|
|
|
|
return success
|
|
|
|
}).catch(function (e) {
|
|
|
|
// Check in 1 second if network error
|
|
|
|
reschedule(1000)
|
|
|
|
throw e
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
window.addEventListener('unload', function (e) {
|
|
|
|
if (refreshStopToken != null) {
|
|
|
|
clearTimeout(refreshStopToken)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
function rsk() {
|
|
|
|
function changeRskText(newText) {
|
|
|
|
document.querySelectorAll('.rsk').forEach(function (elem) {
|
|
|
|
elem.textContent = newText
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
changeRskText('Refreshing...')
|
|
|
|
refresh().catch(function () { return false}).then(function (success) {
|
|
|
|
if (!success) {
|
|
|
|
changeRskText('Refreshing failed')
|
|
|
|
setTimeout(function (_) {
|
|
|
|
changeRskText('Refresh')
|
|
|
|
}, 3000)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
changeRskText('Refresh')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
window.addEventListener('load', function (e) {
|
|
|
|
if (!new URL(window.location.href).searchParams.has('stationId')) {
|
|
|
|
window.history.back()
|
|
|
|
this.setTimeout(function () {
|
|
|
|
var url = new URL(window.location.href)
|
|
|
|
url.pathname = 'station.html'
|
|
|
|
window.location.href = url.toString()
|
|
|
|
}, 100)
|
|
|
|
}
|
|
|
|
|
|
|
|
var sp = new URL(window.location.href).searchParams
|
|
|
|
|
|
|
|
stationId = sp.get('stationId')
|
|
|
|
date = sp.has('date') ? new Date(sp.get('date')) : new Date()
|
|
|
|
|
|
|
|
// View departures first
|
|
|
|
selectedTab = 1
|
|
|
|
selectTab(selectedTab)
|
|
|
|
|
|
|
|
document.querySelectorAll('.rsk').forEach(function (rskElem) {
|
|
|
|
rskElem.addEventListener('click', function (e) {
|
|
|
|
rsk()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
if (navigator.canShare && navigator.canShare({ url: '' })) {
|
|
|
|
document.getElementById('title').addEventListener('click', function () {
|
|
|
|
navigator.share({ url: '' });
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
refresh()
|
|
|
|
|
|
|
|
setInterval(function () {
|
|
|
|
if (!lastSuccessfulFetch) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var millis = new Date() - lastSuccessfulFetch
|
|
|
|
var secs = Math.floor(millis / 1000)
|
|
|
|
|
|
|
|
var timeStr = ''
|
|
|
|
if (secs / 3600 >= 1) {
|
|
|
|
timeStr += `${Math.floor(secs / 3600)}h`
|
|
|
|
secs = secs % 3600
|
|
|
|
}
|
|
|
|
if (secs / 60 >= 1) {
|
|
|
|
timeStr += `${Math.floor(secs / 60)}m`
|
|
|
|
secs = secs % 60
|
|
|
|
}
|
|
|
|
if (secs >= 1) {
|
|
|
|
timeStr += `${Math.floor(secs)}s`
|
|
|
|
}
|
|
|
|
if (!timeStr) {
|
|
|
|
document.querySelectorAll('.lsk').forEach(function (elem) {
|
|
|
|
elem.textContent = 'Last refreshed now'
|
|
|
|
elem.classList.add('last-refreshed')
|
|
|
|
})
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
document.querySelectorAll('.lsk').forEach(function (elem) {
|
|
|
|
elem.textContent = `Last refreshed ${timeStr} ago`
|
|
|
|
elem.classList.add('last-refreshed')
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}, 500)
|
|
|
|
})
|