ctucx.git: trainsearch

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

commit 792344d73052d3b927e58e97607e49ee9797ef5d
parent 524765015a611484d4d5a6bcc109969289b9a14a
Author: Katja (ctucx) <git@ctu.cx>
Date: Thu, 23 Jan 2025 17:22:50 +0100

searchView.js: refactor logic
1 file changed, 125 insertions(+), 129 deletions(-)
M
src/searchView.js
|
254
+++++++++++++++++++++++++++++++++++++++----------------------------------------
diff --git a/src/searchView.js b/src/searchView.js
@@ -1,6 +1,6 @@
-import { ElementById, padZeros, isValidDate } from './helpers.js';
+import { ElementById, hideElement, showElement, elementHidden, flipElement, unflipElement, padZeros, isValidDate } from './helpers.js';
 import { db } from './dataStorage.js';
-import { t, loadDS100, getJourneys, newJourneys, ds100Reverse } from './app_functions.js';
+import { t, getJourneys, newJourneys, ds100Reverse } from './app_functions.js';
 import { formatName, formatFromTo } from './formatters.js';
 import { modifySettings, settings } from './settings.js';
 import { go } from './router.js';

@@ -15,18 +15,18 @@ 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 isArrival  = false;
+let dateValue  = currDate.getFullYear() + '-' + padZeros(currDate.getMonth()+1) + '-' + padZeros(currDate.getDate());;
+let timeValue  = padZeros(currDate.getHours()) + ':' + padZeros(currDate.getMinutes());
 
 const productIcons = {
 	// DB
 	"nationalExpress": "icon-ice",
-	"national": "icon-ic",
+	"national":        "icon-ic",
 	"regionalExpress": "icon-dzug",
 
 	// vbb, bvg

@@ -34,11 +34,11 @@ const productIcons = {
 
 	// nahsh
 	"interregional": "icon-dzug",
-	"onCall": "icon-taxi",
+	"onCall":        "icon-taxi",
 
 	// SNCB
 	"intercity-p": "icon-ic",
-	"s-train": "icon-suburban",
+	"s-train":     "icon-suburban",
 
 	// RMV
 	"express-train":       "icon-ice",

@@ -91,9 +91,9 @@ const searchTemplate = (journeysHistory) => html`
 
 			<div class="row">
 				<div class="selector">
-					<input type="radio" id="departure" name="deparr" ?checked=${!isArrValue}>
+					<input type="radio" id="departure" name="deparr" ?checked=${!isArrival}>
 					<label for="departure">${t('departure')}</label>
-					<input type="radio" id="arrival" name="deparr" ?checked=${isArrValue}>
+					<input type="radio" id="arrival" name="deparr" ?checked=${isArrival}>
 					<label for="arrival">${t('arrival')}</label>
 				</div>
 

@@ -171,15 +171,14 @@ const journeysHistoryTemplate = (journeysHistory) => html`
 	</div>
 `;
 
-const journeysHistoryAction = (journeysHistory, element) => {
-	showSelectModal([
-		{'label': t('setfromto'),       'action': () => { setFromHistory(journeysHistory.length - 1 - journeysHistory.indexOf(element)); hideOverlay(); }},
-		{'label': t('journeyoverview'), 'action': () => { go('/'+element.slug+'/'+settings.journeysViewMode); hideOverlay(); }}
-	]);
-};
+const journeysHistoryAction = (journeysHistory, element) => showSelectModal([
+	{'label': t('setfromto'),       'action': () => { setFromHistory(journeysHistory.length - 1 - journeysHistory.indexOf(element)); hideOverlay(); }},
+	{'label': t('journeyoverview'), 'action': () => { go('/'+element.slug+'/'+settings.journeysViewMode); hideOverlay(); }}
+]);
 
 export const searchView = async () => {
 	const journeysHistory = (await db.getJourneysHistory()).slice().reverse();	
+
 	render(searchTemplate(journeysHistory), ElementById('content'));
 
 	if (viaValue !== '') toggleVia('show');

@@ -187,57 +186,67 @@ export const searchView = async () => {
 	ElementById('from').focus();
 
 	for (const [product, enabled] of Object.entries(settings.products)) {
-		const el = ElementById(product);
-		if (!el) continue;
-		ElementById(product).checked = enabled;
+		const element = ElementById(product);
+		if (!element) continue;
+
+		element.checked = enabled;
 	}
 };
 
 export const search = async (requestId) => {
 	await modifySettings(settings => {
-		settings.products = readProductSelection(settings);
+		settings.products      = readProductSelection(settings);
 		settings.accessibility = document.querySelector('input[name="accessibility"]:checked').value;
 		return settings;
 	});
 
-	const isDep = ElementById('departure').checked;
-	let date = ElementById('date').value;
-	let time = ElementById('time').value;
+	let responseData;
 	let timestamp = '';
 	let from = '';
-	let via = '';
-	let to = '';
+	let via  = '';
+	let to   = '';
 
-	currDate = new Date();
+	currDate  = new Date();
 	fromValue = ElementById('from').value;
-	viaValue = ElementById('via').value;
-	toValue = ElementById('to').value;
+	viaValue  = ElementById('via').value;
+	toValue   = ElementById('to').value;
 	dateValue = ElementById('date').value;
 	timeValue = ElementById('time').value;
-	isArrValue = ElementById('arrival').checked;
+	isArrival = ElementById('arrival').checked;
 
 
-	if (fromValue === '') { showAlertModal('From can\'t be empty!'); return; }
-	if (toValue   === '') { showAlertModal('To can\'t be empty!');   return; }
+	if (fromValue === '' || toValue   === '') {
+		showAlertModal('At least From and To need to be filled!');
+		return false;
+	}
 
-	if (date !== '') {
-		if (!isValidDate(date)) {
+	// date
+	if (dateValue !== '') {
+		if (!isValidDate(dateValue)) {
 			showAlertModal('Invalid date');
-			return;
+			return false;
 		}
 	} else {
-		date = currDate.getFullYear()+'-'+padZeros(currDate.getMonth()+1)+'-'+padZeros(currDate.getDate());
+		dateValue = currDate.getFullYear()+'-'+padZeros(currDate.getMonth()+1)+'-'+padZeros(currDate.getDate());
 	}
 
-	if (time !== '') {
-		if (!new RegExp('([0-1][0-9]|2[0-3]):([0-5][0-9])').test(time)) {
+
+	// time
+	if (timeValue !== '') {
+		if (!new RegExp('([0-1][0-9]|2[0-3]):([0-5][0-9])').test(timeValue)) {
 			showAlertModal('Invalid time');
-			return;
+			return false;
 		}
 	} else {
-		time = padZeros(currDate.getHours())+':'+padZeros(currDate.getMinutes());
+		timeValue = padZeros(currDate.getHours())+':'+padZeros(currDate.getMinutes());
 	}
 
+	const split_date = dateValue.split('-');
+	const split_time = timeValue.split(':');
+
+	timestamp = Math.round(new Date(split_date[0], split_date[1]-1, split_date[2], split_time[0], split_time[1]).getTime()/1000);
+
+	// from
 	if (Object.entries(suggestions.from).length !== 0) {
 		from = suggestions.from;
 	} else {

@@ -245,13 +254,14 @@ export const search = async (requestId) => {
 
 		if (!data[0]) {
 			showAlertModal('Invalid From');
-			return;
+			return false;
 		}
 
 		from = data[0];
 	}
 
-	if (ElementById('via').value == '') {
+	// via
+	if (viaValue == '') {
 		via = null;
 	} else if (Object.entries(suggestions.via).length !== 0) {
 		via = suggestions.via;

@@ -260,12 +270,13 @@ export const search = async (requestId) => {
 
 		if (!data[0]) {
 			showAlertModal('Invalid Via');
-			return;
+			return false;
 		}
 
 		via = data[0];
 	}
 
+	// to
 	if (Object.entries(suggestions.to).length !== 0) {
 		to = suggestions.to;
 	} else {

@@ -273,16 +284,12 @@ export const search = async (requestId) => {
 
 		if (!data[0]) {
 			showAlertModal('Invalid To');
-			return;
+			return false;
 		}
 
 		to = data[0];
 	}
 
-	const split_date = date.split('-');
-	const split_time = time.split(':');
-
-	timestamp = Math.round(new Date(split_date[0], split_date[1]-1, split_date[2], split_time[0], split_time[1]).getTime()/1000);
 
 	const params = {
 		from,

@@ -294,49 +301,54 @@ export const search = async (requestId) => {
 
 	if (via) params.via = via;
 
-	if (isDep)
+	if (!isArrival) {
 		params.departure = timestamp * 1000;
-	else
+	} else {
 		params.arrival = timestamp * 1000;
+	}
 
-	let data;
 	showLoader();
+
 	try {
-		data = await newJourneys(params);
+		responseData = await newJourneys(params);
 	} catch(e) {
 		showAlertModal(e.toString());
 		throw e;
 	}
+
 	hideOverlay();
-	go(`/${data.slug}/${settings.journeysViewMode}`);
+
+	go(`/${responseData.slug}/${settings.journeysViewMode}`);
 	return false;
 };
 
 const suggestionsTemplate = (data, inputId) => html`
-	<div class="box" @mouseover=${mouseOverSuggestions} @mouseout=${stopMouseOverSuggestions}>
+	<div @mouseover=${mouseOverSuggestions} @mouseout=${stopMouseOverSuggestions}>
 		${data.map(element => html`
 			<p class="suggestion" @click=${() => setSuggestion(encodeURI(JSON.stringify(element)), inputId)}>${formatName(element)}</p>
 		`)}
 	</div>
 `;
 
-const loadSuggestions = async (e, input) => {
-	const val = e.target.value;
+const loadSuggestions = async (e) => {
+	const value = e.target.value;
+
 	suggestions[e.target.id] = {};
 
-	const results = val ? await Promise.all([
+	const results = value ? await Promise.all([
 		(async () => {
-			const ds100Result = await ds100Reverse(val);
+			const ds100Result = await ds100Reverse(value);
 			if (ds100Result !== null) {
 				return await client.locations(ds100Result, {'results': 1});
 			}
 			return [];
 		}) (),
-		client.locations(val, {'results': 10})
+		client.locations(value, {'results': 10})
 	]) : [[], []];
+
 	const data = results[0].concat(results[1]);
-	const suggestionsEl = ElementById(e.target.id+'Suggestions');
-	render(suggestionsTemplate(data, e.target.id), suggestionsEl);
+
+	render(suggestionsTemplate(data, e.target.id), ElementById(e.target.id+'Suggestions'));
 };
 
 export const setSuggestion = (data, inputId) => {

@@ -344,14 +356,14 @@ export const setSuggestion = (data, inputId) => {
 		data = JSON.parse(decodeURI(data));
 	}
 
-	suggestions[inputId] = data;
 	ElementById(inputId).value = formatName(data);
+	suggestions[inputId]       = data;
 
 	if (inputId === 'from') {
 		ElementById('fromSuggestions').classList.remove('mouseover');
 		ElementById('to').focus();
 
-		if (!ElementById('via').classList.contains('hidden')) {
+		if (!elementHidden(ElementById('via'))) {
 			ElementById('via').focus();
 		}
 	} else if (inputId === 'via') {

@@ -367,20 +379,12 @@ export const toggleHistory = () => {
 	const historyElement = ElementById('history');
 	const buttonElement  = ElementById('historyButton');
 
-	const show = () => {
-		buttonElement.classList.add('flipped');
-		historyElement.classList.remove('hidden');
-	};
-
-	const hide = () => {
-		buttonElement.classList.remove('flipped');
-		historyElement.classList.add('hidden');
-	};
-
-	if (!historyElement.classList.contains('hidden')) {
-		hide();
+	if (!elementHidden(historyElement)) {
+		unflipElement(buttonElement);
+		hideElement(historyElement);
 	} else {
-		show();
+		flipElement(buttonElement);
+		showElement(historyElement);
 	}
 }
 

@@ -388,25 +392,13 @@ export const toggleVia = ( mode ) => {
 	const rowElement    = ElementById('viaRow');
 	const buttonElement = ElementById('viaButton');
 
-	const show = () => {
-		buttonElement.classList.add('flipped');
-		rowElement.classList.remove('hidden');
-	}
-
-	const hide = () => {
-		buttonElement.classList.remove('flipped');
-		rowElement.classList.add('hidden');
-		ElementById('via').value = '';
-	}
-
-	if (mode === 'show') {
-		show();
-	} else if (mode === 'hide') {
-		hide();
-	} else if (rowElement.classList.contains('hidden')) {
-		show();
+	if (mode === 'show' || elementHidden(rowElement)) {
+		flipElement(buttonElement);
+		showElement(rowElement);
 	} else {
-		hide();
+		unflipElement(buttonElement);
+		hideElement(rowElement);
+		ElementById('via').value = '';
 	}
 }
 

@@ -414,7 +406,7 @@ export const swapFromTo = () => {
 	suggestions.from = [suggestions.to, suggestions.to = suggestions.from][0];
 
 	const from = ElementById('from');
-	const to = ElementById('to');
+	const to   = ElementById('to');
 
 	from.value = [to.value, to.value = from.value][0];
 };

@@ -435,93 +427,94 @@ export const setFromHistory = async id => {
 
 export const readProductSelection = settings => {
 	const productsMap = {};
+
 	for (const prod of client.profile.products) {
 		productsMap[prod.id] = ElementById(prod.id).checked;
 	}
+
 	return productsMap;
 };
 
+const stopTyping  = (e) => ElementById(e.target.id+'Suggestions').classList.remove('typing');
 const startTyping = (e) => {
 	ElementById(e.target.id+'Suggestions').classList.add('typing');
+
 	if (e.target.id == 'from') ElementById('toSuggestions').classList.remove('mouseover');
 	if (e.target.id == 'to') ElementById('fromSuggestions').classList.remove('mouseover');
 };
 
-const stopTyping = (e) => {
-	ElementById(e.target.id+'Suggestions').classList.remove('typing');
-};
 
 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;
+
 	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;
+
 	el.classList.remove('mouseover');
 };
 
 const onKeyup = (e) => {
-	const which = e.which || e.keyCode;
+	const keyCode = e.which || e.keyCode;
 
 	const forbiddeKeys = [13, 38, 40];
 
-	if (!forbiddeKeys.includes(which)) {
-		loadSuggestions(e, e.target.id);
+	if (!forbiddeKeys.includes(keyCode)) {
+		loadSuggestions(e);
 	}
 };
 
 
 const onKeydown = (e) => {
-	const which = e.which || e.keyCode;
+	const keyCode = e.which || e.keyCode;
 
-	if (which == 13) { // enter
+	if (keyCode == 13) { // enter
 		if (!ElementById('selected')) {
-			document.querySelector(`#${e.target.id}Suggestions>.box>:first-child`).click();
+			document.querySelector(`#${e.target.id}Suggestions>div>:first-child`).click();
 			if (e.target.id === 'to') ElementById('go').click();
 		} else {
-			const elem = ElementById('selected');
-			elem.id = '';
-			elem.click();
+			const element = ElementById('selected');
+			element.id = '';
+			element.click();
 		}
 		return false;
 	}
 
-	if (which == 40) { // keyup
+	if (keyCode == 40) { // keyup
 		if (!ElementById('selected')) {
-			document.querySelector(`#${e.target.id}Suggestions>.box>:first-child`).id = 'selected';
+			document.querySelector(`#${e.target.id}Suggestions>div>:first-child`).id = 'selected';
 		} else {
-			const currElem = ElementById('selected');
-			let nextElem = currElem.nextElementSibling;
+			const currentElement = ElementById('selected');
+			let   nextElement    = currentElement.nextElementSibling;
 
-			if (nextElem == null) {
-				nextElem = document.querySelector(`#${e.target.id}Suggestions>.box>:first-child`).id = 'selected';
-			}
+			if (nextElement == null) nextElement = document.querySelector(`#${e.target.id}Suggestions>div>:first-child`);
 
-			currElem.id = '';
-			nextElem.id = 'selected';
+			currentElement.id = '';
+			nextElement.id    = 'selected';
 		}
 
 		return false;
 	}
 
-	if (which == 38) { // keydown
+	if (keyCode == 38) { // keydown
 		if (!ElementById('selected')) {
-			document.querySelector(`#${e.target.id}Suggestions>.box>:first-child`).id = 'selected';
+			document.querySelector(`#${e.target.id}Suggestions>div>:first-child`).id = 'selected';
 		} else {
-			const currElem = ElementById('selected');
-			let prevElem = currElem.previousElementSibling;
+			const currentElement  = ElementById('selected');
+			let   previousElement = currentElement.previousElementSibling;
 
-			if (prevElem == null) {
-				prevElem = document.querySelector(`#${e.target.id}Suggestions>.box>:last-child`).id = 'selected';
-			}
+			if (previousElement == null) previousElement = document.querySelector(`#${e.target.id}Suggestions>div>:last-child`);
 
-			currElem.id = '';
-			prevElem.id = 'selected';
+			currentElement.id  = '';
+			previousElement.id = 'selected';
 		}
 
 		return false;

@@ -531,9 +524,12 @@ const onKeydown = (e) => {
 };
 
 const onKeypressSubmit = (e) => {
-	if (e.which == 13 || e.keyCode == 13) { // enter
+	const keyCode = e.which || e.keyCode;
+
+	if (keyCode == 13) { // enter
 		ElementById('go').click();
 		return false;
 	}
+
 	return true;
 };