Kenneth Bruen
2 years ago
7 changed files with 613 additions and 1 deletions
@ -0,0 +1,35 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||||
|
<title>Station - InfoTren</title> |
||||||
|
|
||||||
|
<link rel="manifest" href="/manifest.json"> |
||||||
|
|
||||||
|
<link rel="stylesheet" href="/base.css"> |
||||||
|
|
||||||
|
<script src="/common/worker.js"></script> |
||||||
|
<script src="/common/back.js"></script> |
||||||
|
<script src="/common/items.js"></script> |
||||||
|
<script src="station.js"></script> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<h1>Station Information</h1> |
||||||
|
|
||||||
|
<h4>Station Name</h4> |
||||||
|
<input class="items" type="tel" name="stationName" id="stationName"> |
||||||
|
|
||||||
|
<h4>Suggestions</h4> |
||||||
|
<div class="content"> |
||||||
|
<ul id="suggestionsArea"></ul> |
||||||
|
</div> |
||||||
|
|
||||||
|
<footer> |
||||||
|
<div class="lsk"></div> |
||||||
|
<div class="csk">Search</div> |
||||||
|
<div class="rsk"></div> |
||||||
|
</footer> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,211 @@ |
|||||||
|
var knownStations = [] |
||||||
|
|
||||||
|
function goToStation(station) { |
||||||
|
var url = new URL(window.location.href) |
||||||
|
url.pathname = 'view-station.html' |
||||||
|
url.searchParams.set('station', station) |
||||||
|
url.searchParams.set('date', new Date().toISOString()) |
||||||
|
window.location.href = url.toString() |
||||||
|
} |
||||||
|
|
||||||
|
function searchNormalize(str) { |
||||||
|
return str |
||||||
|
.toLowerCase() |
||||||
|
.replace('ă', 'a') |
||||||
|
.replace('â', 'a') |
||||||
|
.replace('î', 'i') |
||||||
|
.replace('ș', 's') |
||||||
|
.replace('ț', 't') |
||||||
|
}
|
||||||
|
|
||||||
|
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 stationNameInput = document.getElementById('stationName') |
||||||
|
var stationName = searchNormalize(stationNameInput.value.trim()) |
||||||
|
|
||||||
|
var suggestions = [] |
||||||
|
if (!stationName) { |
||||||
|
suggestions = knownStations.slice() |
||||||
|
} |
||||||
|
else { |
||||||
|
for (var i = 0; i < knownStations.length; i++) { |
||||||
|
if (!searchNormalize(knownStations[i].name).includes(stationName)) { |
||||||
|
continue |
||||||
|
} |
||||||
|
suggestions.push(knownStations[i]) |
||||||
|
} |
||||||
|
suggestions.sort((s1, s2) => { |
||||||
|
var s1n = searchNormalize(s1.name); |
||||||
|
var s2n = searchNormalize(s2.name); |
||||||
|
|
||||||
|
if (s1n.indexOf(stationName) != s2n.indexOf(stationName)) { |
||||||
|
return s1n.indexOf(stationName) - s2n.indexOf(stationName); |
||||||
|
} |
||||||
|
|
||||||
|
if (s1.stoppedAtBy.length != s2.stoppedAtBy.length) { |
||||||
|
return s2.stoppedAtBy.length - s1.stoppedAtBy.length; |
||||||
|
} |
||||||
|
|
||||||
|
return s1.name.localeCompare(s2.name); |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
var foundInput = false |
||||||
|
suggestions.forEach(function (suggestion, index) { |
||||||
|
if (stationName == searchNormalize(suggestion.name)) { |
||||||
|
foundInput = true |
||||||
|
} |
||||||
|
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(suggestion.name) |
||||||
|
} |
||||||
|
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 |
||||||
|
stationNameP.classList.add('pri', 'stationName') |
||||||
|
|
||||||
|
// var trainCompanyP = document.createElement('p')
|
||||||
|
// suggestionLi.appendChild(trainCompanyP)
|
||||||
|
|
||||||
|
// trainCompanyP.textContent = suggestion.company
|
||||||
|
// trainCompanyP.classList.add('thi')
|
||||||
|
}, 0) |
||||||
|
}) |
||||||
|
if (!foundInput && stationName) { |
||||||
|
var suggestionLi = document.createElement('li') |
||||||
|
suggestionsArea.appendChild(suggestionLi) |
||||||
|
|
||||||
|
suggestionLi.classList.add('items') |
||||||
|
suggestionLi.tabIndex = suggestions.length + 2 |
||||||
|
suggestionLi.style.padding = '2px 0' |
||||||
|
|
||||||
|
function onAction(e) { |
||||||
|
goToStation(stationNameInput.value.trim()) |
||||||
|
} |
||||||
|
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 = stationNameInput.value.trim() |
||||||
|
stationNameP.classList.add('pri', 'stationName') |
||||||
|
} |
||||||
|
|
||||||
|
setTimeout(function () { |
||||||
|
_rebuildDebounce = null |
||||||
|
if (_rebuildRequested) { |
||||||
|
rebuildSuggestions() |
||||||
|
} |
||||||
|
}, 500) |
||||||
|
} |
||||||
|
|
||||||
|
function lsk() { |
||||||
|
document.getElementById('stationName').focus() |
||||||
|
} |
||||||
|
|
||||||
|
function csk() { |
||||||
|
if (focusedElement == null) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if (focusedElement.id === 'stationName') { |
||||||
|
goToTrain(document.activeElement.value.trim()) |
||||||
|
} |
||||||
|
else { |
||||||
|
focusedElement.click() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
window.addEventListener('load', function (e) { |
||||||
|
var stationName = document.getElementById('stationName') |
||||||
|
stationName.addEventListener('input', function (e) { |
||||||
|
rebuildSuggestions() |
||||||
|
}) |
||||||
|
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() |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
fetch('https://scraper.infotren.dcdev.ro/v3/stations') |
||||||
|
.then(function (response) { |
||||||
|
return response.json() |
||||||
|
}) |
||||||
|
.then(function (response) { |
||||||
|
knownStations = response |
||||||
|
knownStations.sort(function(a, b) { return b.stoppedAtBy.length - a.stoppedAtBy.length }) |
||||||
|
}) |
||||||
|
.then(function () { |
||||||
|
rebuildSuggestions() |
||||||
|
}) |
||||||
|
}) |
@ -0,0 +1,115 @@ |
|||||||
|
.IR, .IRN { |
||||||
|
color: red !important; |
||||||
|
} |
||||||
|
|
||||||
|
.early { |
||||||
|
color: green !important; |
||||||
|
} |
||||||
|
|
||||||
|
.late { |
||||||
|
color: red !important; |
||||||
|
} |
||||||
|
|
||||||
|
#-date { |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
} |
||||||
|
|
||||||
|
#date { |
||||||
|
text-align: end; |
||||||
|
} |
||||||
|
|
||||||
|
#tabs-arr { |
||||||
|
border-bottom-color: #55ff55; |
||||||
|
} |
||||||
|
|
||||||
|
#tabs-dep { |
||||||
|
border-bottom-color: #5555ff; |
||||||
|
} |
||||||
|
|
||||||
|
#arrivals .train-item { |
||||||
|
background-color: #fafffa; |
||||||
|
} |
||||||
|
|
||||||
|
#arrivals .train-item:nth-of-type(even) { |
||||||
|
background-color: #eaffea; |
||||||
|
} |
||||||
|
|
||||||
|
#departures .train-item { |
||||||
|
background-color: #fafaff; |
||||||
|
} |
||||||
|
|
||||||
|
#departures .train-item:nth-of-type(even) { |
||||||
|
background-color: #eaeaff; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item.cancelled { |
||||||
|
background-color: #ffeaea !important; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item.cancelled + .train-item.cancelled { |
||||||
|
border-top: 1px solid black; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item { |
||||||
|
display: grid; |
||||||
|
grid-template-columns: 30px 60px auto 1fr auto; |
||||||
|
grid-template-rows: auto; |
||||||
|
grid-template-areas: |
||||||
|
"rank train time terminus platform" |
||||||
|
"rank train delay terminus platform" |
||||||
|
"status status status status status"; |
||||||
|
align-items: center; |
||||||
|
padding: 4px 0; |
||||||
|
|
||||||
|
page-break-inside: avoid; |
||||||
|
break-inside: avoid; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item > * { |
||||||
|
margin: 2px; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item .time { |
||||||
|
grid-area: time; |
||||||
|
min-width: 60px; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item .train { |
||||||
|
grid-area: train; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item .rank { |
||||||
|
grid-area: rank; |
||||||
|
white-space: nowrap; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item .delay { |
||||||
|
grid-area: delay; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item .terminus { |
||||||
|
grid-area: terminus; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item .status { |
||||||
|
grid-area: status; |
||||||
|
text-align: center; |
||||||
|
margin: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.train-item .platform { |
||||||
|
grid-area: platform; |
||||||
|
border: 1px solid black; |
||||||
|
padding: 1px; |
||||||
|
margin: 1px; |
||||||
|
border-radius: 5px; |
||||||
|
aspect-ratio: 1 / 1; |
||||||
|
min-width: 22px; |
||||||
|
|
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||||
|
<title>View Station - InfoTren</title> |
||||||
|
|
||||||
|
<link rel="manifest" href="/manifest.json"> |
||||||
|
|
||||||
|
<link rel="stylesheet" href="/base.css"> |
||||||
|
<link rel="stylesheet" href="view-station.css"> |
||||||
|
|
||||||
|
<script src="/common/worker.js"></script> |
||||||
|
<script src="/common/back.js"></script> |
||||||
|
<script src="/common/items.js"></script> |
||||||
|
<script src="/common/tabs.js"></script> |
||||||
|
<script src="view-station.js"></script> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<h1 id="title">View Station</h1> |
||||||
|
<div id="-date" class="hidden"> |
||||||
|
<p></p> |
||||||
|
<p class="sec" id="date"></p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="tabs"> |
||||||
|
<h3 id="tabs-arr">Arrivals</h3> |
||||||
|
<h3 id="tabs-dep">Departures</h3> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div id="arrivals" class="tab-view content"> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div id="departures" class="tab-view content"> |
||||||
|
</div> |
||||||
|
|
||||||
|
<footer> |
||||||
|
<div class="lsk"></div> |
||||||
|
<div class="csk"></div> |
||||||
|
<div class="rsk">Refresh</div> |
||||||
|
</footer> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,199 @@ |
|||||||
|
var station |
||||||
|
var date |
||||||
|
|
||||||
|
var stationData = null |
||||||
|
var lastSuccessfulFetch = null |
||||||
|
|
||||||
|
function onStationData(data) { |
||||||
|
if (!data) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var title = document.getElementById('title') |
||||||
|
title.textContent = data.stationName |
||||||
|
|
||||||
|
document.getElementById('date').textContent = data.date |
||||||
|
|
||||||
|
/** |
||||||
|
* @param {HTMLElement} elem |
||||||
|
* @param {any[]} 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') |
||||||
|
timeDiv.textContent = new Date(train.time).toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' }) |
||||||
|
|
||||||
|
if (train.status && train.status.delay != 0) { |
||||||
|
var delayDiv = document.createElement('p') |
||||||
|
trainItem.appendChild(delayDiv) |
||||||
|
delayDiv.classList.add('thi', 'delay') |
||||||
|
delayDiv.textContent = `${train.status.delay} min ` |
||||||
|
// delayDiv.appendChild(document.createElement('br'))
|
||||||
|
var descSpan = document.createElement('span') |
||||||
|
delayDiv.appendChild(descSpan) |
||||||
|
if (train.status.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.textContent = train.train.rank |
||||||
|
rankDiv.classList.add('sec', 'rank', train.train.rank) |
||||||
|
|
||||||
|
var trainDiv = document.createElement('p') |
||||||
|
trainItem.appendChild(trainDiv) |
||||||
|
trainDiv.classList.add('pri', 'train') |
||||||
|
trainDiv.appendChild(document.createTextNode(`${train.train.number}`)) |
||||||
|
|
||||||
|
var terminusDiv = document.createElement('p') |
||||||
|
trainItem.appendChild(terminusDiv) |
||||||
|
terminusDiv.classList.add('pri', 'terminus') |
||||||
|
terminusDiv.textContent = train.train.terminus |
||||||
|
|
||||||
|
if (train.status && train.status.platform) { |
||||||
|
var platformDiv = document.createElement('div') |
||||||
|
trainItem.appendChild(platformDiv) |
||||||
|
platformDiv.classList.add('thi', 'platform') |
||||||
|
platformDiv.textContent = train.status.platform |
||||||
|
} |
||||||
|
|
||||||
|
if (train.status && train.status.cancelled) { |
||||||
|
var statusDiv = document.createElement('p') |
||||||
|
trainItem.appendChild(statusDiv) |
||||||
|
statusDiv.classList.add('sec', 'status') |
||||||
|
statusDiv.textContent = 'This train 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) |
||||||
|
} |
||||||
|
return fetch( |
||||||
|
`https://scraper.infotren.dcdev.ro/v3/stations/${station}?date=${date.getFullYear().toString()}-${(date.getMonth() + 1).toString().padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`, |
||||||
|
{ |
||||||
|
cache: 'no-store', |
||||||
|
}, |
||||||
|
).then(function (response) { |
||||||
|
if (!response.ok) { |
||||||
|
// Check in 10 seconds if server returned error
|
||||||
|
reschedule(10000) |
||||||
|
return |
||||||
|
} |
||||||
|
return response.json() |
||||||
|
}).then(function (response) { |
||||||
|
if (!response) { |
||||||
|
return |
||||||
|
} |
||||||
|
stationData = response |
||||||
|
onStationData(response) |
||||||
|
reschedule() |
||||||
|
}).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() { |
||||||
|
refresh() |
||||||
|
} |
||||||
|
|
||||||
|
window.addEventListener('load', function (e) { |
||||||
|
if (!new URL(window.location.href).searchParams.has('station')) { |
||||||
|
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 |
||||||
|
|
||||||
|
station = sp.get('station') |
||||||
|
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() |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
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) |
||||||
|
}) |
Loading…
Reference in new issue