oeffisearch/client/js/searchView.js
2020-02-07 14:09:42 +01:00

410 lines
14 KiB
JavaScript

'use strict';
import { showDiv, hideDiv, ElementById, padZeros, isValidDate } from './helpers.js';
import { getCache, addCache, parseName, saveDataStorage, clearDataStorage, ConsoleLog, t, loadDS100 } from './app_functions.js';
import { dataStorage } from './app.js';
import { get } from './api.js';
import { go } from './router.js';
import { html, render } from './lit-html.js';
import { showAlertModal, showModal, showLoader, hideLoader} from './overlays.js';
let currDate = new Date();
let fromValue = '';
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 suggestionsCache = {
from: {},
to: {},
};
const searchTemplate = (journeysHistory) => html`
<div id="searchView">
<div class="inputs">
<input type="text" id="from" value="${fromValue}" placeholder="${t('from')}" autocomplete="off" @keyup=${loadSuggestions} @focus=${startTyping} @blur=${stopTyping} @keypress=${onKeypress}>
<div class="suggestions" id="fromsuggestions"></div>
<input type="text" id="to" value="${toValue}" placeholder="${t('to')}" autocomplete="off" @keyup=${loadSuggestions} @focus=${startTyping} @blur=${stopTyping} @keypress=${onKeypress}>
<div class="suggestions" id="tosuggestions"></div>
<div id="datetime">
<div id="deparr">
<label class="switch">
<input type="checkbox" id="isarr" ?checked=${isArrValue}>
<span class="slider"></span>
</label>
</div>
<input type="date" id="date" placeholder="${t('date')} (YYYY-MM-DD)" pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}" value="${dateValue}">
<input type="time" id="time" placeholder="${t('time')} (HH:MM" pattern="[0-9]{2}:[0-9]{2}" value="${timeValue}">
</div>
</div>
<div class="row">
<div class="product_selector">
<input type="checkbox" id="national">
<label for="national" title="${t('longdistancetrain')}">&nbsp;</label>
<input type="checkbox" id="regional">
<label for="regional" title="${t('regionaltrain')}">&nbsp;</label>
<input type="checkbox" id="suburban">
<label for="suburban" title="${t('suburbantrain')}">&nbsp;</label>
<input type="checkbox" id="subway">
<label for="subway" title="${t('subway')}">&nbsp;</label>
<input type="checkbox" id="tram">
<label for="tram" title="${t('tram')}">&nbsp;</label>
<input type="checkbox" id="bus">
<label for="bus" title="${t('bus')}">&nbsp;</label>
<input type="checkbox" id="ferry">
<label for="ferry" title="${t('ferry')}">&nbsp;</label>
<input type="checkbox" id="taxi">
<label for="taxi" title="${t('taxi')}">&nbsp;</label>
</div>
<div class="button swap" id="swap" title="${t('swap')}" @click=${swapFromTo}></div>
<a class="button settings" title="${t('settings')}" @click=${showSettings}></a>
<div class="button search" tabindex="0" id="search" title="${t('search')}" @click=${search}></div>
</div>
${journeysHistory.length ? html`
${journeysHistoryTemplate(journeysHistory)}
` : ''}
</div>
`;
const journeysHistoryTemplate = (journeysHistory) => html`
<div id="journeysHistory">
<table>
<thead>
<tr><th>${t('from')}</th><th>${t('to')}</th><th>${t('options')}</th></tr>
</thead>
<tbody id="journeysHistoryTable">
${journeysHistory.map(element => html`
<tr class="fromHistory" @click=${() => setFromHistory(journeysHistory.length - 1 - journeysHistory.indexOf(element))}" title="${t('setfromto')}">
<td>${parseName(element.fromPoint)}</td>
<td>${parseName(element.toPoint)}</td>
<td>
<a class="departures" href="#/${element.reqId}" title="${t('journeyoverview')}"></a>
${element.journeyId === '' ? '' : html`
<a class="directions" href="#/${element.reqId}/${element.journeyId}" title="${t('lastjourney')}"></a>
`}
</td>
</tr>
`)}
</tbody>
</table>
</div>
`;
export const searchView = () => {
const journeysHistory = getCache('journeysHistory').slice().reverse();
render(searchTemplate(journeysHistory), ElementById('content'));
ElementById('from').focus();
for (let product in dataStorage.settings.products) {
if (ElementById(product) !== null) {
ElementById(product).checked = dataStorage.settings.products[product];
}
};
};
export const search = async (requestId) => {
const provider = dataStorage.settings.provider;
let products = readProductSelection();
const accessibility = dataStorage.settings.accessibility;
let isDep = !ElementById('isarr').checked;
let date = ElementById('date').value;
let time = ElementById('time').value;
let timestamp = '';
let from = '';
let to = '';
currDate = new Date();
fromValue = ElementById('from').value;
toValue = ElementById('to').value;
dateValue = ElementById('date').value;
timeValue = ElementById('time').value;
isArrValue = ElementById('isarr').checked;
if (date !== '') {
if (!isValidDate(date)) {
showAlertModal('Ungültiges Datum!');
return;
}
} else {
date = 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)) {
showAlertModal('Ungültige Zeitangabe!');
return;
}
} else {
time = padZeros(currDate.getHours())+':'+padZeros(currDate.getMinutes());
}
if (ElementById('from').value == "" | ElementById('to').value == "") {
showAlertModal("Abfahrts - und Ankunftsbahnhof müssen ausgefüllt werden.");
return;
}
if (Object.entries(suggestionsCache.from).length !== 0) {
from = suggestionsCache.from;
} else {
let suggestions = await get("/suggestions", {"query": ElementById('from').value, "results": 1}, true);
if (!suggestions[0]) {
showAlertModal("Abfahrtsbahnof ungültig");
return;
}
from = suggestions[0]
}
if (Object.entries(suggestionsCache.to).length !== 0) {
to = suggestionsCache.to;
} else {
let suggestions = await get("/suggestions", {"query": ElementById('to').value, "results": 1}, true);
if (!suggestions[0]) {
showAlertModal("Ankunftsbahnhof ungültig");
return;
}
to = suggestions[0]
}
dataStorage.settings.products = products;
saveDataStorage();
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);
ConsoleLog(timestamp+'///'+date+' '+time+':00');
let params = {
"fromPoint": from,
"toPoint": to,
"accessibility": accessibility,
"products": products
}
if (!isDep) {
params.arrival = timestamp
} else {
params.departure = timestamp
}
const data = await get("/journeys", {"params":params});
addCache('journeys', data);
go('/' + data.reqId);
};
const suggestionsTemplate = (suggestions, inputId) => html`
<div class="suggestionsbox" @mouseover=${mouseOverSuggestions} @mouseout=${stopMouseOverSuggestions}>
${suggestions.map(element => html`
<p class="suggestion" @click=${() => setSuggestion(encodeURI(JSON.stringify(element)), inputId)}>${parseName(element)}</p>
`)}
</div>
`;
const loadSuggestions = async (e, input) => {
const val = e.target.value;
suggestionsCache[e.target.id] = {};
const suggestions = val ? await get("/suggestions", {"query": val}, true) : [];
const suggestionsEl = ElementById(e.target.id+'suggestions');
render(suggestionsTemplate(suggestions, e.target.id), suggestionsEl);
};
export const setSuggestion = (data, inputId) => {
if (typeof data === 'string') {
data = JSON.parse(decodeURI(data));
}
suggestionsCache[inputId] = data;
ElementById(inputId).value = parseName(data);
if (inputId === 'from') {
ElementById('fromsuggestions').classList.remove('mouseover');
ElementById('to').focus();
} else if (inputId === 'to') {
ElementById('tosuggestions').classList.remove('mouseover');
ElementById('to').blur();
}
};
export const swapFromTo = () => {
suggestionsCache.from = [suggestionsCache.to, suggestionsCache.to = suggestionsCache.from][0];
let from = ElementById('from');
let to = ElementById('to');
from.value = [to.value, to.value = from.value][0];
};
export const setFromHistory = (id) => {
const cache = getCache('journeysHistory');
if (cache[id] !== undefined){
setSuggestion(cache[id].fromPoint, 'from');
setSuggestion(cache[id].toPoint, 'to');
}
};
export const readProductSelection = () => {
var products = {
"nationalExp": false,
"national": false,
"regionalExp": false,
"regional": false,
"suburban": false,
"bus": false,
"ferry": false,
"subway": false,
"tram": false,
"taxi": false
}
if (ElementById('national').checked !== false) {
products.nationalExp = true;
products.national = true;
}
if (ElementById('regional').checked !== false) {
products.regionalExp = true;
products.regional = true;
}
if (ElementById('suburban').checked !== false) {
products.suburban = true;
}
if (ElementById('subway').checked !== false) {
products.subway = true;
}
if (ElementById('tram').checked !== false) {
products.tram = true;
}
if (ElementById('bus').checked !== false) {
products.bus = true;
}
if (ElementById('ferry').checked !== false) {
products.ferry = true;
}
if (ElementById('taxi').checked !== false) {
products.taxi = true;
}
return products;
};
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 !== '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 !== 'tosuggestions') el = el.parentElement;
el.classList.remove('mouseover');
};
const onKeypress = (e) => {
if (e.which == 13 || e.keyCode == 13) { // enter
document.querySelector(`#${e.target.id}suggestions>.suggestionsbox>:first-child`).click();
if (e.target.id === 'to') ElementById('search').click();
return false;
}
return true;
};
const showSettings = () => {
showModal(t('settings'), settingsTemplate())
};
const settingsTemplate = () => html`
<b>${t('datasource')}:</b><br>
<label><input type="radio" name="provider" ?checked=${dataStorage.settings.provider === "DB"} value="DB"> DB</label><br>
<label><input type="radio" disabled="disabled" name="provider" ?checked=${dataStorage.settings.provider === "SH"} value="SH"> NAH.SH</label><br>
<label><input type="radio" disabled="disabled" name="provider" ?checked=${dataStorage.settings.provider === "BVG"} value="BVG"> BVG</label><br>
<br>
<b>${t('accessibility')}:</b><br>
<label><input type="radio" name="accessibility" ?checked=${dataStorage.settings.accessibility === "none"} value="none"> ${t('access_none')}</label><br>
<label><input type="radio" name="accessibility" ?checked=${dataStorage.settings.accessibility === "partial"} value="partial"> ${t('access_partial')}</label><br>
<label><input type="radio" name="accessibility" ?checked=${dataStorage.settings.accessibility === "complete"} value="complete"> ${t('access_full')}</label><br>
<br>
<b>${t('etc')}:</b><br>
<label><input type="checkbox" ?checked=${dataStorage.settings.showRIL100Names} id="ril100"> ${t('showds100')}</label><br>
<label><input type="checkbox" ?checked=${dataStorage.settings.writeDebugLog} id="debug-messages"> ${t('showdebug')}</label><br>
<label><input type="checkbox" ?checked=${dataStorage.settings.enableCanvas} id="enable-canvas"> ${t('graphical')} <b>BETA</b></label><br>
<label><input type="checkbox" ?checked=${dataStorage.settings.fancyCanvas} id="fancy-canvas"> ${t('fancy')}<label><br>
<br>
<b>${t('language')}:</b><br>
<label><input type="radio" name="language" ?checked=${dataStorage.settings.language === "de"} value="de"> ${t('de')}</label><br>
<label><input type="radio" name="language" ?checked=${dataStorage.settings.language === "en"} value="en"> ${t('en')}</label><br>
<button class="btn" id="save" @click=${saveSettings}><span>${t('save')}</span></button>
<button class="btn red" id="clear" @click=${clearDataStorage}><span>${t('clearstorage')}</span></button>
<button class="btn orange" id="rebuild-cache" @click=${rebuildCache}><span>${t('update')}</span></button>
`;
const rebuildCache = () => {
ConsoleLog('sw update');
registration.update();
location.reload();
};
const saveSettings = async () => {
const provider = document.querySelector('input[name="provider"]:checked').value;
const accessibility = document.querySelector('input[name="accessibility"]:checked').value;
const language = document.querySelector('input[name="language"]:checked').value;
const show_ril100 = ElementById('ril100').checked;
const write_debug = ElementById('debug-messages').checked;
const enable_canvas = ElementById('enable-canvas').checked;
const fancy_canvas = ElementById('fancy-canvas').checked;
if (provider !== dataStorage.settings.provider) {
dataStorage.journeysHistory = [];
}
dataStorage.settings.provider = provider;
dataStorage.settings.accessibility = accessibility;
dataStorage.settings.showRIL100Names = show_ril100;
dataStorage.settings.writeDebugLog = write_debug;
dataStorage.settings.enableCanvas = enable_canvas;
dataStorage.settings.fancyCanvas = fancy_canvas;
dataStorage.settings.language = language;
saveDataStorage();
if (show_ril100) await loadDS100();
searchView();
hideDiv('overlay');
};