Add station arrivals/departures pages
This commit is contained in:
		
							parent
							
								
									e4b8a25b60
								
							
						
					
					
						commit
						35b19ffe80
					
				
					 7 changed files with 613 additions and 1 deletions
				
			
		| 
						 | 
					@ -20,7 +20,7 @@
 | 
				
			||||||
		<ul>
 | 
							<ul>
 | 
				
			||||||
			<li><a class="items disabled" href="">Train routes</a></li>
 | 
								<li><a class="items disabled" href="">Train routes</a></li>
 | 
				
			||||||
			<li><a class="items" href="train.html">My train</a></li>
 | 
								<li><a class="items" href="train.html">My train</a></li>
 | 
				
			||||||
			<li><a class="items disabled" href="station.html">Station departures/arrivals</a></li>
 | 
								<li><a class="items" href="station.html">Station departures/arrivals</a></li>
 | 
				
			||||||
			<li><a class="items" href="about.html">About</a></li>
 | 
								<li><a class="items" href="about.html">About</a></li>
 | 
				
			||||||
		</ul>
 | 
							</ul>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										35
									
								
								station.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								station.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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>
 | 
				
			||||||
							
								
								
									
										211
									
								
								station.js
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										211
									
								
								station.js
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -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()
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										8
									
								
								sw.js
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								sw.js
									
										
									
									
									
								
							| 
						 | 
					@ -16,6 +16,7 @@ self.addEventListener('install', (event) => {
 | 
				
			||||||
          '/common/worker.js',
 | 
					          '/common/worker.js',
 | 
				
			||||||
          '/common/items.js',
 | 
					          '/common/items.js',
 | 
				
			||||||
          '/common/back.js',
 | 
					          '/common/back.js',
 | 
				
			||||||
 | 
					          '/common/tabs.js',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          // Base
 | 
					          // Base
 | 
				
			||||||
          '/base.css',
 | 
					          '/base.css',
 | 
				
			||||||
| 
						 | 
					@ -32,6 +33,13 @@ self.addEventListener('install', (event) => {
 | 
				
			||||||
          '/view-train.js',
 | 
					          '/view-train.js',
 | 
				
			||||||
          '/view-train.css',
 | 
					          '/view-train.css',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          '/station.html',
 | 
				
			||||||
 | 
					          '/station.js',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          '/view-station.html',
 | 
				
			||||||
 | 
					          '/view-station.js',
 | 
				
			||||||
 | 
					          '/view-station.css',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          // API
 | 
					          // API
 | 
				
			||||||
          API_TRAINS,
 | 
					          API_TRAINS,
 | 
				
			||||||
          API_STATIONS,
 | 
					          API_STATIONS,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										115
									
								
								view-station.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								view-station.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										44
									
								
								view-station.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								view-station.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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>
 | 
				
			||||||
							
								
								
									
										199
									
								
								view-station.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								view-station.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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…
	
	Add table
		
		Reference in a new issue