ctucx.git: trainsearch

web based trip-planner, fork of https://cyberchaos.dev/yuka/trainsearch

commit e2e8fbd5e1885abc65e136bb4df64500b9259ef2
parent 22ca1f5132a13a494f45f8ea507a28e38deb05c4
Author: Yureka <yuka@yuka.dev>
Date: Wed, 18 Aug 2021 18:16:22 +0200

format
16 files changed, 220 insertions(+), 219 deletions(-)
M
client/.eslintrc.json
|
3
++-
M
client/src/api.js
|
14
+++++++-------
M
client/src/app_functions.js
|
52
++++++++++++++++++++++++++--------------------------
M
client/src/canvas.js
|
66
+++++++++++++++++++++++++++++++++---------------------------------
M
client/src/dataStorage.js
|
16
++++++++--------
M
client/src/helpers.js
|
20
++++++++++----------
M
client/src/journeyView.js
|
22
+++++++++++-----------
M
client/src/journeysView.js
|
38
+++++++++++++++++++-------------------
M
client/src/languages.js
|
2
+-
M
client/src/main.js
|
4
++--
M
client/src/map.js
|
6
+++---
M
client/src/router.js
|
2
+-
M
client/src/searchView.js
|
150
++++++++++++++++++++++++++++++++++++++++----------------------------------------
M
client/src/settings.js
|
24
++++++++++++------------
M
client/src/settingsView.js
|
12
++++++------
M
server/index.js
|
8
++++----
diff --git a/client/.eslintrc.json b/client/.eslintrc.json
@@ -12,6 +12,7 @@
 		"semi": "error",
 		"quotes": [ "error", "single" ],
 		"indent": [ "error", "tab" ],
-		"prefer-const": "error"
+		"prefer-const": "error",
+		"no-multi-spaces": "error"
 	}
 }
diff --git a/client/src/api.js b/client/src/api.js
@@ -9,23 +9,23 @@ export const request = async (endpoint, params, method, noLoader) => {
 	let data;
 	const urlparams = [];
 	const addParams = (thing, prefix) => {
-		if (typeof thing === "object") {
-			for (let [key, val] of Object.entries(thing))
+		if (typeof thing === 'object') {
+			for (const [key, val] of Object.entries(thing))
 				addParams(val, prefix.concat([encodeURIComponent(key)]));
 		} else {
-			urlparams.push(`${prefix.join(".")}=${encodeURIComponent(thing)}`);
+			urlparams.push(`${prefix.join('.')}=${encodeURIComponent(thing)}`);
 		}
 	};
 	addParams(params, []);
 
-	const url = `${api_base}${endpoint}?${urlparams.join("&")}`;
+	const url = `${api_base}${endpoint}?${urlparams.join('&')}`;
 	try {
 		data = await fetch(url, {method})
 			.then(resp => resp.json());
 	} catch(e) {
 		data = {
 			error: true,
-			msg: "Failed to fetch. Please check your network connection.",
+			msg: 'Failed to fetch. Please check your network connection.',
 		};
 	}
 	if (!noLoader) hideOverlay();

@@ -39,9 +39,9 @@ export const request = async (endpoint, params, method, noLoader) => {
 };
 
 export const get = (endpoint, params, noLoader) => {
-	return request(endpoint, params, "GET", noLoader);
+	return request(endpoint, params, 'GET', noLoader);
 };
 
 export const post = async (endpoint, params, noLoader) => {
-	return request(endpoint, params, "POST", noLoader);
+	return request(endpoint, params, 'POST', noLoader);
 };
diff --git a/client/src/app_functions.js b/client/src/app_functions.js
@@ -30,13 +30,13 @@ const addJourneys = async data => {
 	//	dataStorage.journeysHistory[dataStorage.journeysHistory.length-1].slug = data.slug;										
 	//	dataStorage.journeysHistory[dataStorage.journeysHistory.length-1].journeyId = '';
 	//} else {
-		await addHistoryEntry({
-			fromPoint: getFrom(data.journeys),
-			//viaPoint: data.params.via,
-			toPoint: getTo(data.journeys),
-			slug: data.slug,
-			journeyId: ''
-		});
+	await addHistoryEntry({
+		fromPoint: getFrom(data.journeys),
+		//viaPoint: data.params.via,
+		toPoint: getTo(data.journeys),
+		slug: data.slug,
+		journeyId: ''
+	});
 	//}
 };
 

@@ -50,13 +50,13 @@ const mkParams = () => {
 };
 
 const processData = data => {
-	for (let journey of data.journeys) {
-		for (let leg of journey.legs) {
+	for (const journey of data.journeys) {
+		for (const leg of journey.legs) {
 			if (leg.plannedDeparture) leg.plannedDeparture = new Date(leg.plannedDeparture);
 			if (leg.plannedArrival) leg.plannedArrival = new Date(leg.plannedArrival);
 			if (leg.departure) leg.departure = new Date(leg.departure);
 			if (leg.arrival) leg.arrival = new Date(leg.arrival);
-			for (let stopover of (leg.stopovers || [])) {
+			for (const stopover of (leg.stopovers || [])) {
 				if (stopover.plannedDeparture) stopover.plannedDeparture = new Date(stopover.plannedDeparture);
 				if (stopover.plannedArrival) stopover.plannedArrival = new Date(stopover.plannedArrival);
 				if (stopover.departure) stopover.departure = new Date(stopover.departure);

@@ -65,7 +65,7 @@ const processData = data => {
 		}
 	}
 	return data;
-}
+};
 
 export const getJourneys = async slug => {
 	if (!slug) return;

@@ -79,7 +79,7 @@ export const getJourneys = async slug => {
 	return processData(data);
 };
 
-export const getMoreJourneys  = async (slug, mode, hideLoader) => {
+export const getMoreJourneys = async (slug, mode, hideLoader) => {
 	const data = await post(`savedJourneys/${slug}/${mode}`, mkParams(), hideLoader);
 	await addJourneys(data);
 	return processData(data);

@@ -91,8 +91,8 @@ export const refreshJourneys = async (reqId, hideLoader) => {
 	return processData(data);
 };
 
-export const newJourneys  = async (params, hideLoader) => {
-	const data = await post(`savedJourneys`, { ...mkParams(), ...params }, hideLoader);
+export const newJourneys = async (params, hideLoader) => {
+	const data = await post('savedJourneys', { ...mkParams(), ...params }, hideLoader);
 	await addJourneys(data);
 	return processData(data);
 };

@@ -102,24 +102,24 @@ export const t = (key, ...params) => {
 	if (!translation) return key;
 
 	while (params.length >= 1)
-		translation = translation.replace("{}", params.shift());
+		translation = translation.replace('{}', params.shift());
 
 	return translation;
-}
+};
 
 export const parseName = (point) => {
 	let nameHTML = '';
 
-	if (point.type == "stop") {
+	if (point.type == 'stop') {
 		nameHTML += point.name+ds100Names(point.id);
-	} else if (point.type == "location") {
+	} else if (point.type == 'location') {
 		if (point.name) {
 			nameHTML += point.name;
 		} else if (point.address) {
 			nameHTML += point.address;
 		}
 	} else {
-		return "";
+		return '';
 	}
 
 	return nameHTML;

@@ -129,9 +129,9 @@ export const ds100Names = (id) => {
 	if (!settings.showRIL100Names) return '';
 	if (!ds100[Number(id)]) return '';
 	return '('+ds100[Number(id)]+')';
-}
+};
 
-export const ConsoleLog  = (data) => {
+export const ConsoleLog = (data) => {
 	if (settings.writeDebugLog) {
 		console.log(data);
 	}

@@ -143,14 +143,14 @@ export const loadDS100 = async () => {
 };
 
 export const timeTemplate = (data, mode) => {
-	let delay = 0;
+	const delay = 0;
 
-	const time = data[mode] || data["planned"+mode.replace(/^\w/, c => c.toUpperCase())];
-	if (!time) return "-";
+	const time = data[mode] || data['planned'+mode.replace(/^\w/, c => c.toUpperCase())];
+	if (!time) return '-';
 
 	return html`
-		${data[mode+"Delay"] > 0 ? html`
-			${formatDateTime(time)} <b>(+${Math.round(data[mode+"Delay"] / 60)})</b>
+		${data[mode+'Delay'] > 0 ? html`
+			${formatDateTime(time)} <b>(+${Math.round(data[mode+'Delay'] / 60)})</b>
 		` : html`
 			${formatDateTime(time)}
 		`}
diff --git a/client/src/canvas.js b/client/src/canvas.js
@@ -3,19 +3,19 @@ import { go } from './router.js';
 import { padZeros } from './helpers.js';
 
 const formatTime = (date) => {
-	return `${padZeros(date.getHours())}:${padZeros(date.getMinutes())}`
+	return `${padZeros(date.getHours())}:${padZeros(date.getMinutes())}`;
 };
 
-const textFor = (leg) => leg.line && leg.line.name || "";
+const textFor = (leg) => leg.line && leg.line.name || '';
 const typeTextFor = (leg) => {
-	let res = "(" + leg.line.trainType + ")";
+	let res = '(' + leg.line.trainType + ')';
 	while (res.length < 12) {
-		res = " " + res + " ";
+		res = ' ' + res + ' ';
 	}
 	return res;
 };
 const colorFor = (leg, type) => {
-	let product = leg.line && leg.line.product || "walk";
+	const product = leg.line && leg.line.product || 'walk';
 	return colors[type][product] || colors[type].default;
 };
 

@@ -79,7 +79,7 @@ const addTextToCache = (text, color, fixedHeight) => {
 	const ctx = canvas.getContext('2d');
 	ctx.shadowColor = '#00000080';
 
-	let height, width
+	let height, width;
 	if (fixedHeight) {
 		height = 15;
 		ctx.font = `${height}px sans-serif`;

@@ -107,17 +107,17 @@ const updateTextCache = () => {
 	textCache.length = 0;
 	textCacheWidth = rectWidth;
 	textCacheDpr = dpr;
-	for (let journey of canvasState.journeys) {
-		for (let leg of journey.legs) {
-			addTextToCache(textFor(leg), colorFor(leg, "text"));
-			if (leg.line && leg.line.trainType) addTextToCache(typeTextFor(leg), "#555");
+	for (const journey of canvasState.journeys) {
+		for (const leg of journey.legs) {
+			addTextToCache(textFor(leg), colorFor(leg, 'text'));
+			if (leg.line && leg.line.trainType) addTextToCache(typeTextFor(leg), '#555');
 
-			let times = [];
+			const times = [];
 
 			if (journey.legs.indexOf(leg) == journey.legs.length - 1) times.push(leg.arrival || leg.plannedArrival);
 			if (journey.legs.indexOf(leg) == 0) times.push(leg.departure || leg.plannedDeparture);
-			for (let time of times) {
-				addTextToCache(formatTime(time), "#fff", 15);
+			for (const time of times) {
+				addTextToCache(formatTime(time), '#fff', 15);
 			}
 		}
 	}

@@ -129,17 +129,17 @@ const renderJourneys = () => {
 	ctx.clearRect(0, 0, canvas.width / dpr, canvas.height / dpr);
 	let x = canvasState.offsetX - canvasState.indexOffset * rectWidthWithPadding, y;
 
-	let firstVisibleJourney = Math.max(0, Math.floor((-x + padding) / rectWidthWithPadding));
-	let numVisibleJourneys = Math.ceil(canvas.width / dpr / rectWidthWithPadding);
-	let visibleJourneys = canvasState.journeys.slice(firstVisibleJourney, firstVisibleJourney + numVisibleJourneys);
+	const firstVisibleJourney = Math.max(0, Math.floor((-x + padding) / rectWidthWithPadding));
+	const numVisibleJourneys = Math.ceil(canvas.width / dpr / rectWidthWithPadding);
+	const visibleJourneys = canvasState.journeys.slice(firstVisibleJourney, firstVisibleJourney + numVisibleJourneys);
 
 	if (!visibleJourneys.length) return;
 
 	const targetFirstDeparture = Number(visibleJourneys[0].legs[0].plannedDeparture);
 	const targetLastArrival = Math.max.apply(Math,
 		visibleJourneys.map(journey => journey.legs[journey.legs.length-1].plannedArrival)
-		.concat(visibleJourneys.map(journey => journey.legs[journey.legs.length-1].arrival)
-	));
+			.concat(visibleJourneys.map(journey => journey.legs[journey.legs.length-1].arrival)
+			));
 
 	const now = new Date();
 	const factor = Math.min(.3, (now - lastAnimationUpdate) / 20);

@@ -175,7 +175,7 @@ const renderJourneys = () => {
 	ctx.font = `${(window.innerWidth / dpr) > 600 ? 20 : 15}px sans-serif`;
 	ctx.fillStyle = '#aaa';
 	while (time < lastArrival) {
-		let y = (time - firstDeparture) * scaleFactor + 32;
+		const y = (time - firstDeparture) * scaleFactor + 32;
 		ctx.fillText(formatTime(time), (window.innerWidth / dpr) > 600 ? 30 : 10, y);
 		ctx.fillRect(0, y, canvas.width / dpr, 1);
 		time = new Date(Number(time) + 3600000);//Math.floor(120/scaleFactor));

@@ -200,9 +200,9 @@ const renderJourneys = () => {
 	ctx.strokeStyle = '#00000020';
 	ctx.stroke();
 
-	for (let journey of canvasState.journeys) {
+	for (const journey of canvasState.journeys) {
 		journey.legs.reverse();
-		for (let leg of journey.legs) {
+		for (const leg of journey.legs) {
 			if (Math.abs(leg.departureDelay) > 60 || Math.abs(leg.arrivalDelay) > 60) {
 				const duration = (leg.plannedArrival - leg.plannedDeparture) * scaleFactor;
 

@@ -219,8 +219,8 @@ const renderJourneys = () => {
 
 	x = canvasState.offsetX - canvasState.indexOffset * rectWidthWithPadding;
 
-	for (let journey of canvasState.journeys) {
-		for (let leg of journey.legs) {
+	for (const journey of canvasState.journeys) {
+		for (const leg of journey.legs) {
 			const duration = ((leg.arrival || leg.plannedArrival) - (leg.departure || leg.plannedDeparture)) * scaleFactor;
 
 			y = ((leg.departure || leg.plannedDeparture) - firstDeparture) * scaleFactor + 32;

@@ -232,7 +232,7 @@ const renderJourneys = () => {
 				ctx.fillStyle = '#777';
 				ctx.fillRect(x + rectWidth / 2 - rectWidth / 10, y, rectWidth / 5, duration);
 			} else {
-				ctx.fillStyle = colorFor(leg, "fill");
+				ctx.fillStyle = colorFor(leg, 'fill');
 				ctx.fillRect(x, y, rectWidth, duration);
 			}
 			ctx.shadowBlur = 0;

@@ -244,7 +244,7 @@ const renderJourneys = () => {
 				ctx.scale(dpr, dpr);
 			}
 			if (leg.line && leg.line.trainType) {
-				let preRenderedTypeText = textCache[typeTextFor(leg)];
+				const preRenderedTypeText = textCache[typeTextFor(leg)];
 				if ((preRenderedTypeText.height / dpr + preRenderedText.height / dpr) < duration - 5) {
 					ctx.scale(1 / dpr, 1 / dpr);
 					ctx.drawImage(preRenderedTypeText, dpr * (x + 5), Math.floor(dpr * (y + duration / 2 + preRenderedText.height / 2 + 10) - preRenderedTypeText.height / 2.3));

@@ -265,10 +265,10 @@ const renderJourneys = () => {
 			/* draw journey start and end time */
 			let time;
 			// note: leg order is reversed at this point in time
-			let times = [];
+			const times = [];
 			if (journey.legs.indexOf(leg) == journey.legs.length - 1) times.push([leg.departure || leg.plannedDeparture, y - 9.5]);
 			if (journey.legs.indexOf(leg) == 0) times.push([leg.arrival || leg.plannedArrival, y + duration + 7.5]);
-			for (let [time, y] of times) {
+			for (const [time, y] of times) {
 				preRenderedText = textCache[formatTime(time)];
 				ctx.scale(1 / dpr, 1 / dpr);
 				ctx.drawImage(preRenderedText, Math.ceil(dpr * (x + ((rectWidth - preRenderedText.width/dpr)) / 2)), dpr * (y - 7.5));

@@ -321,17 +321,17 @@ const resizeHandler = () => {
 };
 
 const mouseUpHandler = (evt) => {
-	let x = evt.x || evt.changedTouches[0].pageX;
+	const x = evt.x || evt.changedTouches[0].pageX;
 	if (canvasState.dragging && canvasState.isClick) {
-		let num = Math.floor((x - canvasState.offsetX + 2 * padding) / rectWidthWithPadding);
+		const num = Math.floor((x - canvasState.offsetX + 2 * padding) / rectWidthWithPadding);
 		if (num >= 0) {
 			if (num < canvasState.journeys.length) {
 				go(`/${canvasState.slug}/${num - canvasState.indexOffset}`);
 			} else {
-				moreJourneys(canvasState.slug, "later");
+				moreJourneys(canvasState.slug, 'later');
 			}
 		} else {
-			moreJourneys(canvasState.slug, "earlier");
+			moreJourneys(canvasState.slug, 'earlier');
 		}
 	}
 

@@ -340,7 +340,7 @@ const mouseUpHandler = (evt) => {
 };
 
 const mouseDownHandler = (evt) => {
-	let x = evt.x || evt.changedTouches[0].pageX;
+	const x = evt.x || evt.changedTouches[0].pageX;
 	canvasState.dragStartMouse = x;
 	canvasState.dragStartOffset = canvasState.offsetX;
 	canvasState.dragging = true;

@@ -350,7 +350,7 @@ const mouseDownHandler = (evt) => {
 const mouseMoveHandler = (evt) => {
 	if (canvasState.dragging) {
 		evt.preventDefault();
-		let x = evt.x || evt.changedTouches[0].pageX;
+		const x = evt.x || evt.changedTouches[0].pageX;
 		canvasState.offsetX = canvasState.dragStartOffset - (canvasState.dragStartMouse - x);
 		if (Math.abs(canvasState.dragStartMouse - x) > 20) canvasState.isClick = false;
 		renderJourneys();
diff --git a/client/src/dataStorage.js b/client/src/dataStorage.js
@@ -10,14 +10,14 @@ export const initDataStorage = async () => {
 		upgrade: (db, oldVersion, newVersion, transaction) => {
 			console.log(`upgrading database from ${oldVersion} to ${newVersion}`);
 			switch (oldVersion) {
-				case 0:
-					if (!db.objectStoreNames.contains('journeys'))
-						db.createObjectStore('journeys', {keyPath: 'slug'});
-					if (!db.objectStoreNames.contains('journeysHistory'))
-						db.createObjectStore('journeysHistory', {autoIncrement: true});
-					if (!db.objectStoreNames.contains('settings'))
-						db.createObjectStore('settings');
-				case 1:
+			case 0:
+				if (!db.objectStoreNames.contains('journeys'))
+					db.createObjectStore('journeys', {keyPath: 'slug'});
+				if (!db.objectStoreNames.contains('journeysHistory'))
+					db.createObjectStore('journeysHistory', {autoIncrement: true});
+				if (!db.objectStoreNames.contains('settings'))
+					db.createObjectStore('settings');
+			case 1:
 					//... add migrations for 1->2 here
 			}
 		},
diff --git a/client/src/helpers.js b/client/src/helpers.js
@@ -34,17 +34,17 @@ export const isValidDate = (date) => {
 export const formatDateTime = (date, format) => {
 	if (format != null) {
 		switch (format) {
-			case 'full':
-				return padZeros(date.getHours()) + ':' + padZeros(date.getMinutes()) + ', ' + date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear();
-				break;
+		case 'full':
+			return padZeros(date.getHours()) + ':' + padZeros(date.getMinutes()) + ', ' + date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear();
+			break;
 
-			case 'date':
-				return date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear();
-				break;
+		case 'date':
+			return date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear();
+			break;
 
-			default:
-				return false;
-				break;
+		default:
+			return false;
+			break;
 		}
 
 	}

@@ -69,7 +69,7 @@ export const formatDuration = (duration) => {
 };
 
 export const formatFromTo = obj => {
-	if (obj.type === "stop")
+	if (obj.type === 'stop')
 		return obj.id;
 	else if (obj.address)
 		return {
diff --git a/client/src/journeyView.js b/client/src/journeyView.js
@@ -20,7 +20,7 @@ const remarksModalTemplate = (type, remarks) => html`
 `;
 
 const getAdditionalName = (line) => {
-	const splitName = line.name.split(" ");
+	const splitName = line.name.split(' ');
 	if (splitName.length === 2 && line.fahrtNr && line.fahrtNr != splitName[1])
 		return `${splitName[0]} ${line.fahrtNr}`;
 	else

@@ -29,13 +29,13 @@ const getAdditionalName = (line) => {
 
 const travelynxTemplate = (element) => {
 	if (settings.travelynx && element.line && element.line.mode === 'train') {
-		let trainName = getAdditionalName(element.line) || element.line.name;
+		const trainName = getAdditionalName(element.line) || element.line.name;
 
 		return html`
 			<a class="link icon-travelynx" href="https://travelynx.de/s/${element.origin.id}?train=${encodeURIComponent(trainName)}"></a>
 		`;
 	}
-}
+};
 
 const showRemarksModal = (type, remarks) => {
 	showModal(t('remarks'), remarksModalTemplate(type, remarks));

@@ -47,13 +47,13 @@ const remarksTemplate = ([type, remarks]) => !!remarks.length ? html`
 const legTemplate = leg => {
 	const allRemarks = leg.remarks || [];
 	const remarks = {
-		"status": allRemarks.filter(r => r.type === 'status'),
-		"hint": allRemarks.filter(r => r.type === 'hint'),
-		"other": allRemarks.filter(r => r.type !== 'status' && r.type !== 'hint'),
+		'status': allRemarks.filter(r => r.type === 'status'),
+		'hint': allRemarks.filter(r => r.type === 'hint'),
+		'other': allRemarks.filter(r => r.type !== 'status' && r.type !== 'hint'),
 	};
 
 	let marudorUrl = null;
-	if (leg.line && (leg.line.product == "nationalExpress" || leg.line.product == "national" || leg.line.product == "regionalExp" || leg.line.product == "regional")) {
+	if (leg.line && (leg.line.product == 'nationalExpress' || leg.line.product == 'national' || leg.line.product == 'regionalExp' || leg.line.product == 'regional')) {
 		marudorUrl = 'https://marudor.de/details/' + encodeURIComponent(getAdditionalName(leg.line) || leg.line.name) + '/' + Number(leg.plannedDeparture);
 	}
 

@@ -109,8 +109,8 @@ const legTemplate = leg => {
 				<tbody>
 					${(leg.stopovers || []).map(stop => html`
 						<tr class="stop ${stop.cancelled ? 'cancelled' : ''}">
-							<td><span>${timeTemplate(stop, "arrival")}</span></td>
-							<td><span>${timeTemplate(stop, "departure")}</span></td>
+							<td><span>${timeTemplate(stop, 'arrival')}</span></td>
+							<td><span>${timeTemplate(stop, 'departure')}</span></td>
 							<td><span>${stop.stop.name} ${ds100Names(stop.stop.id)}</span></td>
 							<td><span>${stopPlatformTemplate(stop)}</span></td>
 						</tr>

@@ -128,7 +128,7 @@ const journeyTemplate = (data, requestId, journeyId) => {
 	const legs = [];
 	let changes = 0;
 	let lastArrival;
-	for (let leg of data.legs) {
+	for (const leg of data.legs) {
 		if (!leg.walking && !leg.transfer) {
 
 			// add change

@@ -188,7 +188,7 @@ const stopPlatformTemplate = (data) => {
 			return data.plannedArrivalPlatform;
 		}
 	} else {
-		return '-'
+		return '-';
 	}
 };
 
diff --git a/client/src/journeysView.js b/client/src/journeysView.js
@@ -40,11 +40,11 @@ const journeysTemplate = (data) => html`
 			<div id="journeysCanvas">
 				<canvas id="canvas"></canvas>
 			</div>
-		` : ""}
+		` : ''}
 		${settings.journeysViewMode === 'map' ? html`
 			<div id="journeysMap">
 			</div>
-		` : ""}
+		` : ''}
 		${settings.journeysViewMode === 'table' ? html`
 			<a class="loadMore icon-arrow2 flipped" title="${t('label_earlier')}" @click=${() => moreJourneys(data.slug, 'earlier')}"></a>
 

@@ -67,30 +67,30 @@ const journeysTemplate = (data) => html`
 			</table>
 			</div>
 
-			<a class="loadMore icon-arrow2" title="${t('label_later')}" @click=${() => moreJourneys(data.slug, "later")}></a>
-		` : ""}
+			<a class="loadMore icon-arrow2" title="${t('label_later')}" @click=${() => moreJourneys(data.slug, 'later')}></a>
+		` : ''}
 	</div>
 `;
 
 const journeyOverviewTemplate = (entry, slug, key) => {
-	let firstLeg = entry.legs[0];
-	let lastLeg = entry.legs[entry.legs.length - 1];
+	const firstLeg = entry.legs[0];
+	const lastLeg = entry.legs[entry.legs.length - 1];
 	let changes = 0;
-	let products = {};
-	let productsString = "";
-	let changesDuration = 0;
+	const products = {};
+	let productsString = '';
+	const changesDuration = 0;
 	let cancelled = false;
 
-	let duration = Number(lastLeg.arrival || lastLeg.plannedArrival) - Number(firstLeg.departure || firstLeg.plannedDeparture);
+	const duration = Number(lastLeg.arrival || lastLeg.plannedArrival) - Number(firstLeg.departure || firstLeg.plannedDeparture);
 
-	for (let leg of entry.legs) {
+	for (const leg of entry.legs) {
 		if (leg.cancelled) cancelled = true;
 		if (leg.isWalking || leg.isTransfer) continue;
 
 		changes = changes+1;
 
 		if (leg.line) {
-			const productName = leg.line.name.split(" ")[0];
+			const productName = leg.line.name.split(' ')[0];
 			if (!products[productName]) products[productName] = [];
 		}
 		//if (leg.line && leg.line.trainTypeShort) products[leg.line.productName].push(leg.line.trainTypeShort);

@@ -98,28 +98,28 @@ const journeyOverviewTemplate = (entry, slug, key) => {
 
 	productsString = Object.entries(products).map(([prod, types]) => {
 		if (types.length >= 2) {
-			prod += " (" + types.join(", ") + ")";
+			prod += ' (' + types.join(', ') + ')';
 		} else if (types.length) {
-			prod += " " + types[0];
+			prod += ' ' + types[0];
 		}
 		return prod;
-	}).join(", ");
+	}).join(', ');
 
 	return html`
 	<tr @click=${() => go('/'+slug + '/' + key)}">
-		<td class="${cancelled ? "cancelled" : ""}"><span>${timeTemplate(firstLeg, 'departure')}</span></td>
+		<td class="${cancelled ? 'cancelled' : ''}"><span>${timeTemplate(firstLeg, 'departure')}</span></td>
 		${cancelled ? html`
 			<td><span class="cancelled-text">${t('cancelled-ride')}</span></td>
 		` : html`
 			<td><span>${timeTemplate(lastLeg, 'arrival')}</span></td>
 		`}
-		<td class="${cancelled ? "cancelled" : ""}" title="${changesDuration > 0 ? 'including '+formatDuration(changesDuration)+' transfer durations' : ''}"><span>${formatDuration(duration)}</span></td>
+		<td class="${cancelled ? 'cancelled' : ''}" title="${changesDuration > 0 ? 'including '+formatDuration(changesDuration)+' transfer durations' : ''}"><span>${formatDuration(duration)}</span></td>
 		<td><span>${changes-1}</span></td>
 		<td><span>${productsString}</span></td>
 		${settings.showPrices ? html`<td><span>${formatPrice(entry.price)}</span></td>` : ''}
 		<td><a class="details-button icon-arrow3"></a></td>
 	</tr>`;
-}
+};
 
 const formatPrice = price => {
 	if (!price) return '-';

@@ -156,7 +156,7 @@ const changeMode = (mode) => {
 	};
 };
 
-export const moreJourneys  = async (slug, mode) => {
+export const moreJourneys = async (slug, mode) => {
 	await getMoreJourneys(slug, mode);
 	journeysView([slug], true);
 };
diff --git a/client/src/languages.js b/client/src/languages.js
@@ -112,4 +112,4 @@ export const languages = {
 		'via':               'Via',
 		'walkinfo':          'Walk to {} (apprx. {} meters)'
 	}
-}
+};
diff --git a/client/src/main.js b/client/src/main.js
@@ -15,10 +15,10 @@ import { showDiv, hideDiv, ElementById } from './helpers.js';
 	route(/^\/([a-zA-Z0-9]+)$/, journeysView);
 	route(/^\/([a-zA-Z0-9]+)\/([-0-9]+)$/, journeyView);
 
-	hideDiv('overlay')
+	hideDiv('overlay');
 	if (!window.location.hash.length) go('/');
 	start();
-}) ()
+}) ();
 
 //const sw = navigator.serviceWorker;
 //export let registration;
diff --git a/client/src/map.js b/client/src/map.js
@@ -24,7 +24,7 @@ const map = new Map({
 	layers: [
 		new TileLayer({
 			source: new XYZSource({
-				url: "https://cartodb-basemaps-{a-d}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
+				url: 'https://cartodb-basemaps-{a-d}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png',
 			}),
 		}),
 		vectorLayer,

@@ -41,7 +41,7 @@ export const setupMap = (data, isUpdate) => {
 		features: [],
 	};
 
-	for (let journey of data.journeys) {
+	for (const journey of data.journeys) {
 		const i = data.journeys.indexOf(journey) / data.journeys.length;
 		const color = `hsl(${i * 360}, 50%, 50%)`;
 		const style = new Style({

@@ -50,7 +50,7 @@ export const setupMap = (data, isUpdate) => {
 				width: 5,
 			}),
 		});
-		for (let leg of journey.legs) {
+		for (const leg of journey.legs) {
 			if (!leg.polyline) continue;
 			geojson.features.push({
 				type: 'Feature',
diff --git a/client/src/router.js b/client/src/router.js
@@ -13,7 +13,7 @@ export const go = (dest) => {
 
 export const start = () => {
 	const dest = window.location.hash.slice(1);
-	for (let route of routes) {
+	for (const route of routes) {
 		const match = route.pattern.exec(dest);
 		if (!match) continue;
 		return route.handler(match.slice(1));
diff --git a/client/src/searchView.js b/client/src/searchView.js
@@ -13,13 +13,13 @@ const suggestions = {
 	to: {},
 };
 
-let currDate             = new Date();
-let fromValue            = '';
-let viaValue             = '';
-let toValue              = '';
-let isArrValue           = false;
-let dateValue            = currDate.getFullYear()+'-'+padZeros(currDate.getMonth()+1)+'-'+padZeros(currDate.getDate());;
-let timeValue            = padZeros(currDate.getHours())+':'+padZeros(currDate.getMinutes());
+let currDate = new Date();
+let fromValue = '';
+let viaValue = '';
+let toValue = '';
+let isArrValue = false;
+let dateValue = currDate.getFullYear()+'-'+padZeros(currDate.getMonth()+1)+'-'+padZeros(currDate.getDate());;
+let timeValue = padZeros(currDate.getHours())+':'+padZeros(currDate.getMinutes());
 
 const searchTemplate = (journeysHistory) => html`
 	<div id="searchView" class="center">

@@ -100,13 +100,13 @@ const searchTemplate = (journeysHistory) => html`
 
 				<span class="hidden">{{LABEL_ACCESSIBILITY}}:</span>
 				<div class="selector">
-					<input type="radio" id="accessibilityNone" name="accessibility" value="none" ?checked=${settings.accessibility === "none"}>
+					<input type="radio" id="accessibilityNone" name="accessibility" value="none" ?checked=${settings.accessibility === 'none'}>
 					<label class="icon-walk-fast" for="accessibilityNone" title="{{LABEL_ACCESSIBILITY_NONE}}">{{LABEL_ACCESSIBILITY_NONE}}<br></label>
 
-					<input type="radio" id="accessibilityPartial" name="accessibility" value="partial" ?checked=${settings.accessibility === "partial"}>
+					<input type="radio" id="accessibilityPartial" name="accessibility" value="partial" ?checked=${settings.accessibility === 'partial'}>
 					<label class="icon-walk" for="accessibilityPartial" title="{{LABEL_ACCESSIBILITY_PARTIAL}}">{{LABEL_ACCESSIBILITY_PARTIAL}}<br></label>
 
-					<input type="radio" id="accessibilityComplete" name="accessibility" value="complete" ?checked=${settings.accessibility === "complete"}>
+					<input type="radio" id="accessibilityComplete" name="accessibility" value="complete" ?checked=${settings.accessibility === 'complete'}>
 					<label class="icon-weelchair" for="accessibilityComplete" title="{{LABEL_ACCESSIBILITY_FULL}}">{{LABEL_ACCESSIBILITY_FULL}}<br></label>
 				</div>
 

@@ -135,7 +135,7 @@ const searchTemplate = (journeysHistory) => html`
 const journeysHistoryTemplate = (journeysHistory) => html`
 	<div class="history">
 		${journeysHistory.map(element => html`
-		<div class="row history" @click=${() => {journeysHistoryAction(journeysHistory, element)}}">
+		<div class="row history" @click=${() => {journeysHistoryAction(journeysHistory, element);}}">
 			<div class="history from">
 				<small>${t('from')}:</small><br>
 				${parseName(element.fromPoint)}

@@ -158,10 +158,10 @@ const journeysHistoryTemplate = (journeysHistory) => html`
 const journeysHistoryAction = (journeysHistory, element) => {
 	ConsoleLog(element);
 	showSelectModal(html`
-		<a @click=${() => {setFromHistory(journeysHistory.length - 1 - journeysHistory.indexOf(element));hideOverlay()}}>${t('setfromto')}</a>
-		<a @click=${() => {go("/"+element.slug);hideOverlay();}}>${t('journeyoverview')}</a>
+		<a @click=${() => {setFromHistory(journeysHistory.length - 1 - journeysHistory.indexOf(element));hideOverlay();}}>${t('setfromto')}</a>
+		<a @click=${() => {go('/'+element.slug);hideOverlay();}}>${t('journeyoverview')}</a>
 		${element.journeyId === '' ? '' : html`
-			<a @click=${() => {go("/"+element.slug+"/"+element.journeyId);hideOverlay();}}>${t('lastjourney')}</a>
+			<a @click=${() => {go('/'+element.slug+'/'+element.journeyId);hideOverlay();}}>${t('lastjourney')}</a>
 		`}
 	`);
 };

@@ -172,8 +172,8 @@ export const searchView = async () => {
 
 	ElementById('from').focus();
 
-	for (let [product, enabled] of Object.entries(settings.products)) {
-		let el = ElementById(product);
+	for (const [product, enabled] of Object.entries(settings.products)) {
+		const el = ElementById(product);
 		if (!el) continue;
 		ElementById(product).checked = enabled;
 	}

@@ -186,21 +186,21 @@ export const search = async (requestId) => {
 		return settings;
 	});
 
-	const provider      = settings.provider;
-	let   isDep         = !ElementById('isarr').checked;
-	let   date          = ElementById('date').value;
-	let   time          = ElementById('time').value;
-	let   timestamp     = '';
-	let   from          = '';
-	let   via           = '';
-	let   to            = '';
-
-	currDate   = new Date();
-	fromValue  = ElementById('from').value;
-	viaValue   = ElementById('via').value;
-	toValue    = ElementById('to').value;
-	dateValue  = ElementById('date').value;
-	timeValue  = ElementById('time').value;
+	const provider = settings.provider;
+	const isDep = !ElementById('isarr').checked;
+	let date = ElementById('date').value;
+	let time = ElementById('time').value;
+	let timestamp = '';
+	let from = '';
+	let via = '';
+	let to = '';
+
+	currDate = new Date();
+	fromValue = ElementById('from').value;
+	viaValue = ElementById('via').value;
+	toValue = ElementById('to').value;
+	dateValue = ElementById('date').value;
+	timeValue = ElementById('time').value;
 	isArrValue = ElementById('isarr').checked;
 
 	if (date !== '') {

@@ -224,42 +224,42 @@ export const search = async (requestId) => {
 	if (Object.entries(suggestions.from).length !== 0) {
 		from = suggestions.from;
 	} else {
-		let data = await get("locations",  {"query": fromValue, "results": 1}, true);
+		const data = await get('locations', {'query': fromValue, 'results': 1}, true);
 
 		if (!data[0]) {
-    		showAlertModal("Invalid From");
+    		showAlertModal('Invalid From');
 			return;
   		}
 
-		from = data[0]
+		from = data[0];
 	}
 
-	if (ElementById('via').value == "") {
+	if (ElementById('via').value == '') {
 		via = null;
 	} else if (Object.entries(suggestions.via).length !== 0) {
 		via = suggestions.via;
 	} else {
-		let data = await get("locations",  {"query": viaValue, "results": 1}, true);
+		const data = await get('locations', {'query': viaValue, 'results': 1}, true);
 
 		if (!data[0]) {
-			showAlertModal("Invalid Via");
+			showAlertModal('Invalid Via');
 			return;
 		}
 
-		via = data[0]
+		via = data[0];
 	}
 
 	if (Object.entries(suggestions.to).length !== 0) {
 		to = suggestions.to;
 	} else {
-		let data = await get("locations",  {"query": toValue, "results": 1}, true);
+		const data = await get('locations', {'query': toValue, 'results': 1}, true);
 
 		if (!data[0]) {
-			showAlertModal("Invalid To");
+			showAlertModal('Invalid To');
 			return;
   		}
 
-		to = data[0]
+		to = data[0];
 	}
 
 	const split_date = date.split('-');

@@ -269,7 +269,7 @@ export const search = async (requestId) => {
 
 	ConsoleLog(timestamp+'///'+date+' '+time+':00');
 
-	let params = {
+	const params = {
 		from: formatFromTo(from),
 		to: formatFromTo(to),
 		results: 6,

@@ -300,12 +300,12 @@ const suggestionsTemplate = (data, inputId) => html`
 const loadSuggestions = async (e, input) => {
 	const val = e.target.value;
 	suggestions[e.target.id] = {};
-	const data = val ? await get("locations",  {"query": val, "results": 10}, true) : [];
+	const data = val ? await get('locations', {'query': val, 'results': 10}, true) : [];
 	const suggestionsEl = ElementById(e.target.id+'Suggestions');
 	render(suggestionsTemplate(data, e.target.id), suggestionsEl);
 };
 
-export const setSuggestion  = (data, inputId) => {
+export const setSuggestion = (data, inputId) => {
 	if (typeof data === 'string') {
 		data = JSON.parse(decodeURI(data));
 	}

@@ -325,11 +325,11 @@ export const setSuggestion  = (data, inputId) => {
 	}
 };
 
-export const swapFromTo  = () => {
+export const swapFromTo = () => {
 	suggestions.from = [suggestions.to, suggestions.to = suggestions.from][0];
 
-	let from = ElementById('from');
-	let to   = ElementById('to');
+	const from = ElementById('from');
+	const to = ElementById('to');
 
 	from.value = [to.value, to.value = from.value][0];
 };

@@ -341,19 +341,19 @@ export const setFromHistory = async id => {
 	setSuggestion(entry.toPoint, 'to');
 };
 
-export const readProductSelection  = settings => {
+export const readProductSelection = settings => {
 	const splitExp = settings.advancedSelection;
 	return {
-		"nationalExpress": splitExp ? ElementById('nationalExpress').checked : ElementById('national').checked,
-		"national":        ElementById('national').checked,
-		"regionalExp":     splitExp ? ElementById('regionalExp').checked : ElementById('regional').checked,
-		"regional":        ElementById('regional').checked,
-		"suburban":        ElementById('suburban').checked,
-		"bus":             ElementById('bus').checked,
-		"ferry":           ElementById('ferry').checked,
-		"subway":          ElementById('subway').checked,
-		"tram":            ElementById('tram').checked,
-		"taxi":            ElementById('taxi').checked
+		'nationalExpress': splitExp ? ElementById('nationalExpress').checked : ElementById('national').checked,
+		'national':        ElementById('national').checked,
+		'regionalExp':     splitExp ? ElementById('regionalExp').checked : ElementById('regional').checked,
+		'regional':        ElementById('regional').checked,
+		'suburban':        ElementById('suburban').checked,
+		'bus':             ElementById('bus').checked,
+		'ferry':           ElementById('ferry').checked,
+		'subway':          ElementById('subway').checked,
+		'tram':            ElementById('tram').checked,
+		'taxi':            ElementById('taxi').checked
 	};
 };
 

@@ -368,23 +368,23 @@ const stopTyping = (e) => {
 };
 
 const mouseOverSuggestions = (e) => {
-  let el = e.target;
-  let i = 0;
-  while (i++ < 10 && el.id !== 'fromSuggestions' && el.id !== 'viaSuggestions' && el.id !== 'toSuggestions') el = el.parentElement;
+	let el = e.target;
+	let i = 0;
+	while (i++ < 10 && el.id !== 'fromSuggestions' && el.id !== 'viaSuggestions' && el.id !== 'toSuggestions') el = el.parentElement;
 	el.classList.add('mouseover');
 };
 
 const stopMouseOverSuggestions = (e) => {
-  let el = e.target;
-  let i = 0;
-  while (i++ < 10 && el.id !== 'fromSuggestions' && el.id !== 'viaSuggestions'&& el.id !== 'toSuggestions') el = el.parentElement;
+	let el = e.target;
+	let i = 0;
+	while (i++ < 10 && el.id !== 'fromSuggestions' && el.id !== 'viaSuggestions'&& el.id !== 'toSuggestions') el = el.parentElement;
 	el.classList.remove('mouseover');
 };
 
 const onKeyup = (e) => {
-	let which = e.which || e.keyCode;
+	const which = e.which || e.keyCode;
 
-	let forbiddeKeys = [13, 38, 40];
+	const forbiddeKeys = [13, 38, 40];
 
 	if (!forbiddeKeys.includes(which)) {
 		loadSuggestions(e, e.target.id);

@@ -393,14 +393,14 @@ const onKeyup = (e) => {
 
 
 const onKeydown = (e) => {
-	let which = e.which || e.keyCode;
+	const which = e.which || e.keyCode;
 
 	if (which == 13) { // enter
 		if (!ElementById('selected')) {
 			document.querySelector(`#${e.target.id}Suggestions>.suggestionsbox>:first-child`).click();
 			if (e.target.id === 'to') ElementById('go').click();
 		} else {
-			let elem = ElementById('selected')
+			const elem = ElementById('selected');
 			elem.id = '';
 			elem.click();
 		}

@@ -411,7 +411,7 @@ const onKeydown = (e) => {
 		if (!ElementById('selected')) {
 			document.querySelector(`#${e.target.id}Suggestions>.suggestionsbox>:first-child`).id = 'selected';
 		} else {
-			let currElem = ElementById('selected');
+			const currElem = ElementById('selected');
 			let nextElem = currElem.nextElementSibling;
 
 			if (nextElem == null) {

@@ -429,7 +429,7 @@ const onKeydown = (e) => {
 		if (!ElementById('selected')) {
 			document.querySelector(`#${e.target.id}Suggestions>.suggestionsbox>:first-child`).id = 'selected';
 		} else {
-			let currElem = ElementById('selected');
+			const currElem = ElementById('selected');
 			let prevElem = currElem.previousElementSibling;
 
 			if (prevElem == null) {

@@ -447,9 +447,9 @@ const onKeydown = (e) => {
 };
 
 const onKeypressSubmit = (e) => {
-  if (e.which == 13 || e.keyCode == 13) { // enter
-    ElementById('go').click();
-    return false;
-  }
-  return true;
+	if (e.which == 13 || e.keyCode == 13) { // enter
+		ElementById('go').click();
+		return false;
+	}
+	return true;
 };
diff --git a/client/src/settings.js b/client/src/settings.js
@@ -9,16 +9,16 @@ const getDefaultLanguage = () => {
 const defaultSettings = {
 	provider: 'DB',
 	products: {
-		"nationalExpress": true,
-		"national": true,
-		"regionalExp": true,
-		"regional": true,
-		"suburban": true,
-		"bus": true,
-		"ferry": true,
-		"subway": true,
-		"tram": true,
-		"taxi": true
+		'nationalExpress': true,
+		'national': true,
+		'regionalExp': true,
+		'regional': true,
+		'suburban': true,
+		'bus': true,
+		'ferry': true,
+		'subway': true,
+		'tram': true,
+		'taxi': true
 	},
 	accessibility: 'none',
 	advancedSelection: false,

@@ -41,7 +41,7 @@ export const subscribeSettings = cb => {
 
 export const initSettings = async () => {
 	settings = (await db.get('settings', 'settings')) || defaultSettings;
-	for (let cb of subscribers) await cb();
+	for (const cb of subscribers) await cb();
 };
 
 export const modifySettings = async callback => {

@@ -51,5 +51,5 @@ export const modifySettings = async callback => {
 	await tx.done;
 	Object.freeze(newSettings);
 	settings = newSettings;
-	for (let cb of subscribers) await cb();
+	for (const cb of subscribers) await cb();
 };
diff --git a/client/src/settingsView.js b/client/src/settingsView.js
@@ -7,7 +7,7 @@ import { html, render } from 'lit-html';
 import { searchView } from './searchView.js';
 
 export const showSettings = async () => {
-	showModal(t('settings'), settingsTemplate())
+	showModal(t('settings'), settingsTemplate());
 };
 
 const settingsTemplate = () => html`

@@ -19,8 +19,8 @@ const settingsTemplate = () => html`
 		<label><input type="checkbox" ?checked=${settings.advancedSelection} id="advancedSelection">ADVANCED® selection of trains</label><br>
 		<br>
 		<b>${t('language')}:</b><br>
-		<label><input type="radio" name="language" ?checked=${settings.language === "en"} value="en"> ${t('en')}</label><br>
-		<label><input type="radio" name="language" ?checked=${settings.language === "de"} value="de"> ${t('de')}</label><br>
+		<label><input type="radio" name="language" ?checked=${settings.language === 'en'} value="en"> ${t('en')}</label><br>
+		<label><input type="radio" name="language" ?checked=${settings.language === 'de'} value="de"> ${t('de')}</label><br>
 		<br>
 		<b>Experimental Features:</b><br>
 		<label><input type="checkbox" ?checked=${settings.showMap} id="feature-map"> Show geographic map</label><br>

@@ -40,12 +40,12 @@ const rebuildCache = () => {
 };
 
 const newAll = () => {
-	ElementById('clear').innerText = "New All";
+	ElementById('clear').innerText = 'New All';
 };
 
-const saveSettings  = async () => {
+const saveSettings = async () => {
 	let clearJourneys = false;
-	let clearJourneysHistory = false;
+	const clearJourneysHistory = false;
 	await modifySettings(settings => {
 		settings.showRIL100Names = ElementById('ril100').checked;
 		settings.writeDebugLog = ElementById('debug-messages').checked;
diff --git a/server/index.js b/server/index.js
@@ -96,19 +96,19 @@ const postJourneysRoute = createServer({
 	...hafas,
 	journeys: postJourneys,
 	profile,
-}, serverConfig, () => {}).routes["/journeys"];
+}, serverConfig, () => {}).routes['/journeys'];
 
 const getJourneysRoute = createServer({
 	...hafas,
 	refreshJourney: getJourneys,
 	profile,
-}, serverConfig, () => {}).routes["/journeys/:ref"];
+}, serverConfig, () => {}).routes['/journeys/:ref'];
 
 const postMoreJourneysRoute = mode => createServer({
 	...hafas,
 	refreshJourney: createMoreJourneys(mode),
 	profile,
-}, serverConfig, () => {}).routes["/journeys/:ref"];
+}, serverConfig, () => {}).routes['/journeys/:ref'];
 
 const server = createServer(hafas, serverConfig, (api) => {
 	api.post('/savedJourneys', postJourneysRoute);

@@ -126,4 +126,4 @@ const server = createServer(hafas, serverConfig, (api) => {
 		else
 			console.log('listening on port ' + port);
 	});
-}) ()
+}) ();