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">
 | 
			
		||||
		<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="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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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_TRAINS = `${API_ORIGIN}v3/trains`
 | 
			
		||||
const API_STATIONS = `${API_ORIGIN}v3/stations`
 | 
			
		||||
const API_ITINERARIES = `${API_ORIGIN}v3/itineraries`
 | 
			
		||||
 | 
			
		||||
const CACHE_FIRST = [
 | 
			
		||||
	// Root
 | 
			
		||||
| 
						 | 
				
			
			@ -41,9 +42,14 @@ const CACHE_FIRST = [
 | 
			
		|||
	'/view-station.js',
 | 
			
		||||
	'/view-station.css',
 | 
			
		||||
 | 
			
		||||
	'/route.html',
 | 
			
		||||
	'/route.js',
 | 
			
		||||
	'/route.css',
 | 
			
		||||
 | 
			
		||||
	// API
 | 
			
		||||
	API_TRAINS,
 | 
			
		||||
	API_STATIONS,
 | 
			
		||||
	API_ITINERARIES,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue