Add favorites + nearby stations to stations.html
This commit is contained in:
		
							parent
							
								
									e0ad2fa46c
								
							
						
					
					
						commit
						42352a740f
					
				
					 4 changed files with 197 additions and 65 deletions
				
			
		
							
								
								
									
										31
									
								
								base.css
									
										
									
									
									
								
							
							
						
						
									
										31
									
								
								base.css
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -351,6 +351,37 @@ pre {
 | 
			
		|||
	border-bottom-right-radius: 5%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.suggestion {
 | 
			
		||||
	display: flex;
 | 
			
		||||
	flex-direction: row;
 | 
			
		||||
	align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.suggestion :first-child {
 | 
			
		||||
	flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.suggestion .star {
 | 
			
		||||
	flex: 0;
 | 
			
		||||
	pointer-events: none;
 | 
			
		||||
	width: 24px;
 | 
			
		||||
	height: 24px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.suggestion .star.checked {
 | 
			
		||||
	filter: invert(90%) sepia(49%) saturate(704%) hue-rotate(359deg) brightness(94%) contrast(99%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (prefers-color-scheme: dark) {
 | 
			
		||||
	.suggestion .star {
 | 
			
		||||
		filter: invert(100%);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.suggestion .star.checked {
 | 
			
		||||
		filter: invert(86%) sepia(79%) saturate(2126%) hue-rotate(357deg) brightness(108%) contrast(104%);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.product-suburban {
 | 
			
		||||
	color: green !important;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,34 +115,3 @@ div.checkbox p {
 | 
			
		|||
div.checkbox input {
 | 
			
		||||
    flex: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.suggestion {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.suggestion :first-child {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.suggestion .star {
 | 
			
		||||
    flex: 0;
 | 
			
		||||
    pointer-events: none;
 | 
			
		||||
    width: 24px;
 | 
			
		||||
    height: 24px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.suggestion .star.checked {
 | 
			
		||||
    filter: invert(90%) sepia(49%) saturate(704%) hue-rotate(359deg) brightness(94%) contrast(99%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (prefers-color-scheme: dark) {
 | 
			
		||||
    .suggestion .star {
 | 
			
		||||
        filter: invert(100%);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .suggestion .star.checked {
 | 
			
		||||
        filter: invert(86%) sepia(79%) saturate(2126%) hue-rotate(357deg) brightness(108%) contrast(104%);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@
 | 
			
		|||
	<script src="/common/worker.js"></script>
 | 
			
		||||
	<script defer src="/common/back.js"></script>
 | 
			
		||||
	<script defer src="/common/items.js"></script>
 | 
			
		||||
	<script defer src="/common/components.js"></script>
 | 
			
		||||
	<script defer src="station.js"></script>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										191
									
								
								station.js
									
										
									
									
									
								
							
							
						
						
									
										191
									
								
								station.js
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,12 @@
 | 
			
		|||
var starred = []
 | 
			
		||||
var knownStations = []
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @type {'unavailable' | 'notRequested' | 'waiting' | 'gotData'}
 | 
			
		||||
 */
 | 
			
		||||
var nearbyStatus = 'notRequested'
 | 
			
		||||
var nearbyStations = []
 | 
			
		||||
 | 
			
		||||
function goToStation(stationId) {
 | 
			
		||||
	var url = new URL(window.location.href)
 | 
			
		||||
	url.pathname = 'view-station.html'
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +29,94 @@ var focusedElement = null
 | 
			
		|||
 | 
			
		||||
var _rebuildDebounce = null
 | 
			
		||||
var _rebuildRequested = false
 | 
			
		||||
function createSuggestion(suggestion, index) {
 | 
			
		||||
	delete suggestion['products']
 | 
			
		||||
	var suggestionDiv = document.createElement('div')
 | 
			
		||||
	suggestionDiv.classList.add('suggestion')
 | 
			
		||||
 | 
			
		||||
	var suggestionLi = document.createElement('li')
 | 
			
		||||
	suggestionDiv.appendChild(suggestionLi)
 | 
			
		||||
 | 
			
		||||
	suggestionLi.classList.add('items')
 | 
			
		||||
	if (index) {
 | 
			
		||||
		suggestionLi.tabIndex = index + 1
 | 
			
		||||
	}
 | 
			
		||||
	suggestionLi.style.padding = '2px 0'
 | 
			
		||||
 | 
			
		||||
	function onAction(e) {
 | 
			
		||||
		goToStation(JSON.stringify(suggestion))
 | 
			
		||||
	}
 | 
			
		||||
	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)
 | 
			
		||||
 | 
			
		||||
	var stationNameSpan = document.createElement('span')
 | 
			
		||||
	stationNameP.append(stationNameSpan)
 | 
			
		||||
	stationNameSpan.textContent = suggestion.name || suggestion.address
 | 
			
		||||
	stationNameSpan.classList.add('pri', 'stationName')
 | 
			
		||||
 | 
			
		||||
	if (suggestion.distance) {
 | 
			
		||||
		stationNameP.append(' ')
 | 
			
		||||
		var stationDistanceSpan = document.createElement('span')
 | 
			
		||||
		stationNameP.append(stationDistanceSpan)
 | 
			
		||||
		stationDistanceSpan.append('(', suggestion.distance.toString(), ' m)')
 | 
			
		||||
		stationDistanceSpan.classList.add('stationDistance')
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (window.localStorage) {
 | 
			
		||||
		var suggestionDistance = suggestion['distance']
 | 
			
		||||
		delete suggestion['distance']
 | 
			
		||||
		var suggestionLink = document.createElement('a')
 | 
			
		||||
		suggestionLink.classList.add('no-custom-a')
 | 
			
		||||
 | 
			
		||||
		var suggestionStar = document.createElement('object')
 | 
			
		||||
		suggestionLink.appendChild(suggestionStar)
 | 
			
		||||
		suggestionStar.classList.add('star')
 | 
			
		||||
		suggestionStar.type = 'image/svg+xml'
 | 
			
		||||
		function setStar() {
 | 
			
		||||
			if (starred.includes(JSON.stringify(suggestion))) {
 | 
			
		||||
				suggestionStar.data = '/icons/star_full.svg'
 | 
			
		||||
				suggestionStar.classList.add('checked')
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				suggestionStar.data = '/icons/star_empty.svg'
 | 
			
		||||
				suggestionStar.classList.remove('checked')
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		suggestionLink.addEventListener('click', function (event) {
 | 
			
		||||
			event.preventDefault()
 | 
			
		||||
			if (starred.includes(JSON.stringify(suggestion))) {
 | 
			
		||||
				starred = starred.filter(function (s) {
 | 
			
		||||
					return s !== suggestion
 | 
			
		||||
				})
 | 
			
		||||
			} else {
 | 
			
		||||
				starred.push(JSON.stringify(suggestion))
 | 
			
		||||
			}
 | 
			
		||||
			setStar()
 | 
			
		||||
			localStorage.setItem('stations/starred', JSON.stringify(starred))
 | 
			
		||||
		})
 | 
			
		||||
		setStar()
 | 
			
		||||
		suggestionDiv.appendChild(suggestionLink)
 | 
			
		||||
		suggestion['distance'] = suggestionDistance
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// var trainCompanyP = document.createElement('p')
 | 
			
		||||
	// suggestionLi.appendChild(trainCompanyP)
 | 
			
		||||
 | 
			
		||||
	// trainCompanyP.textContent = suggestion.company
 | 
			
		||||
	// trainCompanyP.classList.add('thi')
 | 
			
		||||
	return suggestionDiv
 | 
			
		||||
}
 | 
			
		||||
function rebuildSuggestions() {
 | 
			
		||||
	if (_rebuildDebounce !== null) {
 | 
			
		||||
		_rebuildRequested = true
 | 
			
		||||
| 
						 | 
				
			
			@ -37,42 +132,66 @@ function rebuildSuggestions() {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	var suggestions = knownStations.slice()
 | 
			
		||||
	if (suggestions.length === 0) {
 | 
			
		||||
		suggestions = starred.map(function (s) { return JSON.parse(s) })
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	suggestions.forEach(function (suggestion, index) {
 | 
			
		||||
		var suggestionLi = document.createElement('li')
 | 
			
		||||
		suggestionsArea.appendChild(suggestionLi)
 | 
			
		||||
		suggestionsArea.append(createSuggestion(suggestion, index))
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
		setTimeout(function () {
 | 
			
		||||
			suggestionLi.classList.add('items')
 | 
			
		||||
			suggestionLi.tabIndex = index + 1
 | 
			
		||||
			suggestionLi.style.padding = '2px 0'
 | 
			
		||||
 | 
			
		||||
			function onAction(e) {
 | 
			
		||||
				goToStation(suggestion.id)
 | 
			
		||||
	if (nearbyStatus !== 'unavailable') {
 | 
			
		||||
		suggestionsArea.appendChild(h4('Nearby stations'))
 | 
			
		||||
		if (nearbyStatus === 'notRequested') {
 | 
			
		||||
			suggestionsArea.appendChild(a('', 'Load nearby stations').event$('click', function (event) {
 | 
			
		||||
				event.preventDefault()
 | 
			
		||||
				var watchId = navigator.geolocation.watchPosition(
 | 
			
		||||
					function (data) {
 | 
			
		||||
						var geoUrl = new URL('https://v6.db.transport.rest/locations/nearby')
 | 
			
		||||
						geoUrl.searchParams.append('latitude', data.coords.latitude.toString())
 | 
			
		||||
						geoUrl.searchParams.append('longitude', data.coords.longitude.toString())
 | 
			
		||||
						geoUrl.searchParams.append('results', '10')
 | 
			
		||||
						fetch(geoUrl)
 | 
			
		||||
							.then(function (response) {
 | 
			
		||||
								return response.json()
 | 
			
		||||
							})
 | 
			
		||||
							.then(function (data) {
 | 
			
		||||
								nearbyStatus = 'gotData'
 | 
			
		||||
								nearbyStations = data
 | 
			
		||||
								rebuildSuggestions()
 | 
			
		||||
							})
 | 
			
		||||
							.catch(function () {
 | 
			
		||||
								nearbyStatus = 'unavailable'
 | 
			
		||||
								rebuildSuggestions()
 | 
			
		||||
							})
 | 
			
		||||
					},
 | 
			
		||||
					function (error) {
 | 
			
		||||
						if (nearbyStations.length === 0) {
 | 
			
		||||
							nearbyStatus = 'unavailable'
 | 
			
		||||
							rebuildSuggestions()
 | 
			
		||||
						}
 | 
			
		||||
			suggestionLi.addEventListener('click', onAction)
 | 
			
		||||
			suggestionLi.addEventListener('keypress', function (e) {
 | 
			
		||||
				if (e.key == 'Enter') {
 | 
			
		||||
					onAction(e)
 | 
			
		||||
						navigator.geolocation.clearWatch(watchId)
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						enableHighAccuracy: true,
 | 
			
		||||
					},
 | 
			
		||||
				)
 | 
			
		||||
				nearbyStatus = 'waiting'
 | 
			
		||||
				rebuildSuggestions()
 | 
			
		||||
			}))
 | 
			
		||||
		}
 | 
			
		||||
		else if (nearbyStatus === 'waiting') {
 | 
			
		||||
			var waitingP = document.createElement('p')
 | 
			
		||||
			suggestionsArea.append(waitingP)
 | 
			
		||||
			waitingP.append('Loading...')
 | 
			
		||||
			waitingP.classList.add('pri')
 | 
			
		||||
		}
 | 
			
		||||
		else if (nearbyStatus === 'gotData') {
 | 
			
		||||
			nearbyStations.forEach(function (suggestion, index) {
 | 
			
		||||
				suggestionsArea.appendChild(createSuggestion(suggestion, suggestions.length + index))
 | 
			
		||||
			})
 | 
			
		||||
			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)
 | 
			
		||||
	})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setTimeout(function () {
 | 
			
		||||
		_rebuildDebounce = null
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +216,12 @@ function reloadSuggestions() {
 | 
			
		|||
	fetchAbortController = new AbortController()
 | 
			
		||||
	fetch(locationsUrl.toString(), { signal: fetchAbortController.signal })
 | 
			
		||||
		.then(function (response) {
 | 
			
		||||
			if (response.ok) {
 | 
			
		||||
				return response.json()
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				return {}
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
		.then(function (data) {
 | 
			
		||||
			if (data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -125,6 +249,13 @@ function csk() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
window.addEventListener('load', function (e) {
 | 
			
		||||
	if (window.localStorage) {
 | 
			
		||||
		var maybeStarred = JSON.parse(localStorage.getItem('stations/starred'))
 | 
			
		||||
		if (maybeStarred) {
 | 
			
		||||
			starred = maybeStarred
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var stationName = document.getElementById('stationName')
 | 
			
		||||
	stationName.addEventListener('input', function (e) {
 | 
			
		||||
		reloadSuggestions()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue