Initial routing/itineraries implementation
This commit is contained in:
		
							parent
							
								
									7645effd5f
								
							
						
					
					
						commit
						fbebd1557c
					
				
					 5 changed files with 578 additions and 2 deletions
				
			
		| 
						 | 
					@ -20,7 +20,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	<div class="content">
 | 
						<div class="content">
 | 
				
			||||||
		<ul>
 | 
							<ul>
 | 
				
			||||||
			<li><a class="items disabled" href="">Train routes</a></li>
 | 
								<li><a class="items" href="route.html">Train routes</a></li>
 | 
				
			||||||
			<li id="my-train-li"><a class="items" href="train.html">My train</a></li>
 | 
								<li id="my-train-li"><a class="items" href="train.html">My train</a></li>
 | 
				
			||||||
			<li id="station-arr-dep-li"><a class="items" href="station.html">Station departures/arrivals</a></li>
 | 
								<li id="station-arr-dep-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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										60
									
								
								route.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								route.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,60 @@
 | 
				
			||||||
 | 
					.itinerary-train {
 | 
				
			||||||
 | 
					    display: grid;
 | 
				
			||||||
 | 
					    grid-template-columns: auto 1fr;
 | 
				
			||||||
 | 
					    grid-template-rows: repeat(auto-fit, auto);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train:not(:last-child) {
 | 
				
			||||||
 | 
					    grid-template-areas:
 | 
				
			||||||
 | 
					        "dep-time  dep-station"
 | 
				
			||||||
 | 
					        "train     train"
 | 
				
			||||||
 | 
					        "arr-time  arrdep-station"
 | 
				
			||||||
 | 
					        "dep2-time arrdep-station";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train:last-child {
 | 
				
			||||||
 | 
					    grid-template-areas:
 | 
				
			||||||
 | 
					        "train     train"
 | 
				
			||||||
 | 
					        "arr-time  arr-station";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train:only-child {
 | 
				
			||||||
 | 
					    grid-template-areas:
 | 
				
			||||||
 | 
					        "dep-time  dep-station"
 | 
				
			||||||
 | 
					        "train     train"
 | 
				
			||||||
 | 
					        "arr-time  arr-station";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train .departure.time {
 | 
				
			||||||
 | 
					    grid-area: dep-time;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train .next-departure.time {
 | 
				
			||||||
 | 
					    grid-area: dep2-time;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train .departure.station {
 | 
				
			||||||
 | 
					    grid-area: dep-station;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train .train {
 | 
				
			||||||
 | 
					    grid-area: train;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train .arrival.time {
 | 
				
			||||||
 | 
					    grid-area: arr-time;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train:not(:last-child) .arrival.station {
 | 
				
			||||||
 | 
					    grid-area: arrdep-station;
 | 
				
			||||||
 | 
					    align-self: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train .arrival.station {
 | 
				
			||||||
 | 
					    grid-area: arr-station;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.itinerary-train .time {
 | 
				
			||||||
 | 
					    margin-left: 2px;
 | 
				
			||||||
 | 
					    margin-right: 2px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										44
									
								
								route.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								route.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>Route - InfoTren</title>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<link rel="manifest" href="/manifest.json">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<link rel="stylesheet" href="/base.css">
 | 
				
			||||||
 | 
						<link rel="stylesheet" href="route.css">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<script src="/common/worker.js"></script>
 | 
				
			||||||
 | 
						<script defer src="/common/back.js"></script>
 | 
				
			||||||
 | 
						<script defer src="/common/items.js"></script>
 | 
				
			||||||
 | 
						<script defer src="/common/trainId.js"></script>
 | 
				
			||||||
 | 
						<script defer src="route.js"></script>
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
						<header>
 | 
				
			||||||
 | 
							<div class="left">
 | 
				
			||||||
 | 
								<img id="back-button" class="back" src="/common/back.svg"></img>
 | 
				
			||||||
 | 
							</div>
 | 
				
			||||||
 | 
							<h1>Find Route</h1>
 | 
				
			||||||
 | 
							<div class="right"></div>
 | 
				
			||||||
 | 
						</header>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!--	<h4><label for="stationName">Station Name</label></h4>-->
 | 
				
			||||||
 | 
					<!--	<input type="search" class="items" 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="csk"></div>
 | 
				
			||||||
 | 
							<div class="rsk"></div>
 | 
				
			||||||
 | 
						</footer>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										466
									
								
								route.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										466
									
								
								route.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,466 @@
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @type {string | null}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					var fromStation = null
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @type {string | null}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					var toStation = null
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @type {Date | null}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					var departureDate = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @type {{ name: string, stoppedAtBy: string[] }[]}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					var knownStations = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function goToStation(station) {
 | 
				
			||||||
 | 
					    var url = new URL(window.location.href)
 | 
				
			||||||
 | 
					    if (!fromStation) {
 | 
				
			||||||
 | 
					        url.searchParams.set('from', station)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (!toStation) {
 | 
				
			||||||
 | 
					        url.searchParams.set('to', station)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 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 _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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @typedef ItineraryTrain
 | 
				
			||||||
 | 
					 * @property {string} from
 | 
				
			||||||
 | 
					 * @property {string} to
 | 
				
			||||||
 | 
					 * @property {string[]} intermediateStops
 | 
				
			||||||
 | 
					 * @property {string} departureDate
 | 
				
			||||||
 | 
					 * @property {string} arrivalDate
 | 
				
			||||||
 | 
					 * @property {number} km
 | 
				
			||||||
 | 
					 * @property {string} operator
 | 
				
			||||||
 | 
					 * @property {string} trainRank
 | 
				
			||||||
 | 
					 * @property {string} trainNumber
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @typedef Itinerary
 | 
				
			||||||
 | 
					 * @property {ItineraryTrain[]} trains
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @param {Itinerary[]} 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.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[i].trains.forEach(function (train, idx) {
 | 
				
			||||||
 | 
					            var last = idx === data[i].trains.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.departureDate)
 | 
				
			||||||
 | 
					                departureTimePre.textContent = departure.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var departureHeading = document.createElement('h3')
 | 
				
			||||||
 | 
					                trainDiv.appendChild(departureHeading)
 | 
				
			||||||
 | 
					                departureHeading.classList.add('departure', 'station')
 | 
				
			||||||
 | 
					                departureHeading.textContent = train.from
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var trainP = document.createElement('p')
 | 
				
			||||||
 | 
					            trainDiv.appendChild(trainP)
 | 
				
			||||||
 | 
					            trainP.classList.add('pri', 'train')
 | 
				
			||||||
 | 
					            trainIdSpan(train.trainRank, train.trainNumber, trainP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            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.arrivalDate)
 | 
				
			||||||
 | 
					            arrivalTimePre.textContent = arrival.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var arrivalHeading = document.createElement('h3')
 | 
				
			||||||
 | 
					            trainDiv.appendChild(arrivalHeading)
 | 
				
			||||||
 | 
					            arrivalHeading.classList.add('arrival', 'station')
 | 
				
			||||||
 | 
					            arrivalHeading.textContent = train.to
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!last) {
 | 
				
			||||||
 | 
					                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(data[i].trains[idx + 1].departureDate)
 | 
				
			||||||
 | 
					                departureTimePre.textContent = departure.toLocaleTimeString([], { 'hour': '2-digit', 'minute': '2-digit' })
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 sp = new URL(window.location.href).searchParams
 | 
				
			||||||
 | 
					    fromStation = sp.get('from')
 | 
				
			||||||
 | 
					    toStation = sp.get('to')
 | 
				
			||||||
 | 
					    var departureDateStr = sp.get('departureDate')
 | 
				
			||||||
 | 
					    if (departureDateStr) {
 | 
				
			||||||
 | 
					        departureDate = new Date(departureDateStr)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var titleH1 = document.querySelector("header > h1")
 | 
				
			||||||
 | 
					    if (!fromStation) {
 | 
				
			||||||
 | 
					        titleH1.textContent = 'Find Route - From'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (!toStation) {
 | 
				
			||||||
 | 
					        titleH1.textContent = 'Find Route - To'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if (!departureDate) {
 | 
				
			||||||
 | 
					        titleH1.textContent = 'Find Route - Departure Date'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        titleH1.textContent = `${fromStation} - ${toStation}`
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var footer = document.querySelector('footer')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!fromStation || !toStation) {
 | 
				
			||||||
 | 
					        // Build station selection UI
 | 
				
			||||||
 | 
					        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'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var stationNameInput = document.createElement('input')
 | 
				
			||||||
 | 
					        document.body.insertBefore(stationNameInput, footer)
 | 
				
			||||||
 | 
					        stationNameInput.type = 'search'
 | 
				
			||||||
 | 
					        stationNameInput.classList.add('items')
 | 
				
			||||||
 | 
					        stationNameInput.name = 'stationName'
 | 
				
			||||||
 | 
					        stationNameInput.id = 'stationName'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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) {
 | 
				
			||||||
 | 
					            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())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fetch('https://scraper.infotren.dcdev.ro/v3/stations')
 | 
				
			||||||
 | 
					            .then(function (response) {
 | 
				
			||||||
 | 
					                return response.json()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(function (response) {
 | 
				
			||||||
 | 
					                knownStations = response
 | 
				
			||||||
 | 
					                knownStations = knownStations.filter((s) => ![fromStation, toStation].includes(s.name))
 | 
				
			||||||
 | 
					                knownStations.sort(function(a, b) { return b.stoppedAtBy.length - a.stoppedAtBy.length })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(function () {
 | 
				
			||||||
 | 
					                rebuildSuggestions()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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 = 0, departureOption = new Date(); 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
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })()
 | 
				
			||||||
 | 
					            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')}`
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        document.querySelector('.csk').textContent = 'Select'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else {
 | 
				
			||||||
 | 
					        var contentDiv = document.createElement('div')
 | 
				
			||||||
 | 
					        document.body.insertBefore(contentDiv, footer)
 | 
				
			||||||
 | 
					        contentDiv.classList.add('content')
 | 
				
			||||||
 | 
					        contentDiv.style.display = 'flex'
 | 
				
			||||||
 | 
					        contentDiv.style.flexDirection = 'column'
 | 
				
			||||||
 | 
					        contentDiv.style.alignItems = 'center'
 | 
				
			||||||
 | 
					        contentDiv.style.justifyContent = 'center'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var loadingP = document.createElement('p')
 | 
				
			||||||
 | 
					        contentDiv.appendChild(loadingP)
 | 
				
			||||||
 | 
					        loadingP.classList.add('pri')
 | 
				
			||||||
 | 
					        loadingP.textContent = 'Loading data...'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var url = new URL('https://scraper.infotren.dcdev.ro/v3/itineraries')
 | 
				
			||||||
 | 
					        url.searchParams.set('from', fromStation)
 | 
				
			||||||
 | 
					        url.searchParams.set('to', toStation)
 | 
				
			||||||
 | 
					        url.searchParams.set('date', departureDate.toISOString())
 | 
				
			||||||
 | 
					        fetch(url.toString())
 | 
				
			||||||
 | 
					            .then(function (response) {
 | 
				
			||||||
 | 
					                return response.json()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(function (data) {
 | 
				
			||||||
 | 
					                contentDiv.remove()
 | 
				
			||||||
 | 
					                onItineraries(data)
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(function (e) {
 | 
				
			||||||
 | 
					                loadingP.textContent = 'An error has occured'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var errorP = document.createElement('p')
 | 
				
			||||||
 | 
					                contentDiv.appendChild(errorP)
 | 
				
			||||||
 | 
					                errorP.classList.add('sec')
 | 
				
			||||||
 | 
					                errorP.textContent = e.toString()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var retryLink = document.createElement('a')
 | 
				
			||||||
 | 
					                contentDiv.appendChild(retryLink)
 | 
				
			||||||
 | 
					                retryLink.classList.add('items')
 | 
				
			||||||
 | 
					                retryLink.textContent = 'Retry'
 | 
				
			||||||
 | 
					                retryLink.href = ''
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										8
									
								
								sw.js
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								sw.js
									
										
									
									
									
								
							| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
const VERSION = 'v24'
 | 
					const VERSION = 'v25'
 | 
				
			||||||
const API_ORIGIN = 'https://scraper.infotren.dcdev.ro/'
 | 
					const API_ORIGIN = 'https://scraper.infotren.dcdev.ro/'
 | 
				
			||||||
const API_TRAINS = `${API_ORIGIN}v3/trains`
 | 
					const API_TRAINS = `${API_ORIGIN}v3/trains`
 | 
				
			||||||
const API_STATIONS = `${API_ORIGIN}v3/stations`
 | 
					const API_STATIONS = `${API_ORIGIN}v3/stations`
 | 
				
			||||||
 | 
					const API_ITINERARIES = `${API_ORIGIN}v3/itineraries`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const CACHE_FIRST = [
 | 
					const CACHE_FIRST = [
 | 
				
			||||||
	// Root
 | 
						// Root
 | 
				
			||||||
| 
						 | 
					@ -41,9 +42,14 @@ const CACHE_FIRST = [
 | 
				
			||||||
	'/view-station.js',
 | 
						'/view-station.js',
 | 
				
			||||||
	'/view-station.css',
 | 
						'/view-station.css',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						'/route.html',
 | 
				
			||||||
 | 
						'/route.js',
 | 
				
			||||||
 | 
						'/route.css',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// API
 | 
						// API
 | 
				
			||||||
	API_TRAINS,
 | 
						API_TRAINS,
 | 
				
			||||||
	API_STATIONS,
 | 
						API_STATIONS,
 | 
				
			||||||
 | 
						API_ITINERARIES,
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue