605 lines
21 KiB
HTML
605 lines
21 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<!--
|
|
IDEAS:
|
|
- Achievements (i.e. "take a train which is delayed by at least 60 minutes" xd)
|
|
- Bonus bei Verspätung, Gesamtverspätung sammeln
|
|
- Show a map in the end (no need for world map, just use coordinates on flat black rectangle)
|
|
-->
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="color-scheme" content="light dark">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>🚉 bahnreise</title>
|
|
<style>
|
|
* {
|
|
margin: 0px;
|
|
border-width: 0px;
|
|
padding: 0px;
|
|
max-width: 100%;
|
|
}
|
|
|
|
body {
|
|
background: light-dark(#ECE, #000);
|
|
}
|
|
|
|
.DraggingTop {
|
|
z-index: 15;
|
|
}
|
|
|
|
#Header {
|
|
z-index: 5;
|
|
position: sticky;
|
|
top: 0px;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
background: light-dark(#FC8888, #421414);
|
|
width: 100%;
|
|
border-bottom-style: solid;
|
|
padding-top: 0.2em;
|
|
padding-bottom: 0.2em;
|
|
border-bottom-width: 0.4em;
|
|
margin-bottom: 0.2em;
|
|
border-bottom-color: light-dark(#ECEA, #000A);
|
|
}
|
|
#HeaderLeft, #HeaderRight {
|
|
display: inline-block;
|
|
flex: 1;
|
|
text-wrap-mode: nowrap;
|
|
cursor: default;
|
|
user-select: none;
|
|
}
|
|
#HeaderLeft {
|
|
left: 0px;
|
|
}
|
|
#HeaderRight {
|
|
right: 0px;
|
|
}
|
|
#StationCurrent, #StationDestination {
|
|
position: relative;
|
|
user-select: none;
|
|
}
|
|
|
|
#Welcome, #InGame {
|
|
max-width: min(90%, 50em);
|
|
margin: 0 auto;
|
|
}
|
|
#TransportModeSelection {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: space-evenly;
|
|
cursor: default;
|
|
}
|
|
.TransportModeIcon {
|
|
font-size: xx-large;
|
|
text-wrap-mode: nowrap;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
transition: opacity 0.3s;
|
|
}
|
|
#StartGameButton {
|
|
border-style: solid;
|
|
padding: 2px;
|
|
border-width: 2px;
|
|
border-radius: 4px;
|
|
border-color: #0000;
|
|
cursor: pointer;
|
|
background: light-dark(#FC6C6C, #541818);
|
|
opacity: 1;
|
|
}
|
|
#StartGameButton:hover {
|
|
transition: filter 2s ease-out;
|
|
filter: hue-rotate(-270deg);
|
|
border-color: light-dark(#0004, #FFF3);
|
|
}
|
|
#StartGameButton:disabled {
|
|
filter: none;
|
|
border-color: #0000;
|
|
cursor: default;
|
|
}
|
|
#StartGameButton:active {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
input[type="text"] {
|
|
margin: 2px;
|
|
padding: 2px;
|
|
border-width: 2px;
|
|
border-radius: 4px;
|
|
border-style: solid;
|
|
border-color: light-dark(#4006, #FCC6);
|
|
background: inherit;
|
|
}
|
|
.StationSearchResult {
|
|
margin-top: 4px;
|
|
margin-bottom: 4px;
|
|
position: relative;
|
|
user-select: none;
|
|
}
|
|
|
|
#InGame {
|
|
display: none;
|
|
position: relative;
|
|
}
|
|
#FocusedDeparturePanel {
|
|
position: fixed;
|
|
top: 2.5em;
|
|
bottom: 0.5em;
|
|
right: max(5%, calc(50% - 25em));
|
|
padding-right: 0.5em;
|
|
padding-left: 0.5em;
|
|
left: 100%;
|
|
transition: left 0.3s ease-in-out;
|
|
border: 1px solid light-dark(#0004, #FFF2);
|
|
background: light-dark(#DBD, #080808);
|
|
overflow: scroll;
|
|
}
|
|
#FocusedDeparturePanelStops {
|
|
padding-left: 1em;
|
|
min-height: 100%;
|
|
}
|
|
#FocusedDeparturePanelCloseClickable {
|
|
display: none;
|
|
position: fixed;
|
|
inset: 0px;
|
|
}
|
|
|
|
.DetailedViewPastStop {
|
|
opacity: 0.8;
|
|
font-size: x-small;
|
|
cursor: default;
|
|
}
|
|
.DetailedViewCurrentStop {
|
|
opacity: 0.8;
|
|
font-size: small;
|
|
text-decoration: underline;
|
|
cursor: default;
|
|
}
|
|
.DetailedViewFutureStop {
|
|
opacity: 0.8;
|
|
transition: opacity 0.15s;
|
|
cursor: pointer;
|
|
}
|
|
.DetailedViewFutureStop:hover {
|
|
opacity: 1;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div id="Header">
|
|
<span id="HeaderLeft">⊙ <span id="StationCurrent"></span><pre style="display:inline;"> </pre></span>
|
|
<span id="HeaderRight">➤ <span id="StationDestination"></span></span>
|
|
</div>
|
|
|
|
<div id="Welcome">
|
|
<div id="TransportModeHeader">I like traveling by...</div>
|
|
<div id="TransportModeSelection">
|
|
<span id="TransportModeBus" class="TransportModeIcon" title="Bus"> 🚌 </span>
|
|
<span id="TransportModeTram" class="TransportModeIcon" title="Tram & Metro"> 🚊 </span>
|
|
<span id="TransportModeS" class="TransportModeIcon" title="Light Rail / S-Bahn"> 🚈 </span>
|
|
<span id="TransportModeRE" class="TransportModeIcon" title="Regional Train (RB/RE)"> 🚆 </span>
|
|
<span id="TransportModeICE" class="TransportModeIcon" title="High-Speed Rail (IC/ICE)"> 🚄 </span>
|
|
</div>
|
|
<br>
|
|
<div id="StartGameSection">
|
|
<button id="StartGameButton">Begin Journey</button>
|
|
</div>
|
|
<br>
|
|
<div id="StationSearch">
|
|
<input id="StationSearchInput" type="text">
|
|
<div id="StationSearchResults"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="InGame">
|
|
<div id="DeparturesList"></div>
|
|
<div id="FocusedDeparturePanelCloseClickable"></div>
|
|
<div id="FocusedDeparturePanel">
|
|
<div id="FocusedDeparturePanelHead"></div>
|
|
<ul id="FocusedDeparturePanelStops"></ul>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
|
|
// === Utilities ===
|
|
|
|
function runInit(func) {
|
|
func();
|
|
return func;
|
|
}
|
|
|
|
// === Game State ===
|
|
|
|
var isInGame = false;
|
|
|
|
var transportModesInteger = 0b00011;
|
|
var transportModeBus = true;
|
|
var transportModeTram = true;
|
|
var transportModeS = false;
|
|
var transportModeRE = false;
|
|
var transportModeICE = false;
|
|
|
|
var stationCurrent = null;
|
|
var stationDestination = null;
|
|
|
|
// === Dragging ===
|
|
|
|
var draggingElement = null;
|
|
var draggingStartPos = null;
|
|
var draggingEndCallback = null;
|
|
var draggableElements = new Array();
|
|
|
|
function draggingEnable(elem, onUp) {
|
|
// NOTE: Assumes the element has `position: relative;`
|
|
draggableElements.push(elem);
|
|
elem.style.cursor = "grab";
|
|
elem.addEventListener("mousedown", (e) => {
|
|
if (isInGame) return;
|
|
if (e.button != 0) return;
|
|
draggingEndCallback = onUp;
|
|
draggingOnDown(e.clientX, e.clientY, elem);
|
|
});
|
|
elem.addEventListener("touchstart", (e) => {
|
|
if (isInGame) return;
|
|
if (e.touches.length == 1) {
|
|
draggingEndCallback = onUp;
|
|
draggingOnDown(e.touches[0].clientX, e.touches[0].clientY, elem);
|
|
} else {
|
|
draggingCancel();
|
|
}
|
|
});
|
|
}
|
|
|
|
document.addEventListener("mousemove", (e) => {
|
|
draggingOnMove(e.clientX, e.clientY);
|
|
});
|
|
document.addEventListener("mouseup", (e) => {
|
|
draggingOnUp(e.clientX, e.clientY);
|
|
});
|
|
document.addEventListener("touchmove", (e) => {
|
|
if (e.touches.length == 1) {
|
|
draggingOnMove(e.touches[0].clientX, e.touches[0].clientY);
|
|
} else {
|
|
draggingCancel();
|
|
}
|
|
});
|
|
document.addEventListener("touchend", (e) => {
|
|
if (e.changedTouches.length == 1) {
|
|
draggingOnUp(e.changedTouches[0].clientX, e.changedTouches[0].clientY);
|
|
}
|
|
});
|
|
document.addEventListener("touchcancel", (e) => {
|
|
draggingCancel();
|
|
});
|
|
function draggingOnDown(x, y, e) {
|
|
if (isInGame) return;
|
|
if (draggingElement !== null) return;
|
|
draggingElement = e;
|
|
draggingElement.classList.add("DraggingTop");
|
|
draggingStartPos = [x, y];
|
|
}
|
|
function draggingOnMove(x, y) {
|
|
if (isInGame) return;
|
|
if (draggingElement === null) return;
|
|
let dx = x - draggingStartPos[0];
|
|
let dy = y - draggingStartPos[1];
|
|
draggingElement.style.top = dy + "px";
|
|
draggingElement.style.left = dx + "px";
|
|
}
|
|
function draggingOnUp(x, y) {
|
|
if (draggingElement === null) return;
|
|
draggingElement.classList.remove("DraggingTop");
|
|
if (!isInGame) {
|
|
if (draggingEndCallback) draggingEndCallback(x, y);
|
|
}
|
|
draggingCancel();
|
|
}
|
|
function draggingCancel() {
|
|
draggingElement.style.removeProperty("top");
|
|
draggingElement.style.removeProperty("left");
|
|
draggingElement = null;
|
|
}
|
|
|
|
// === Header ===
|
|
|
|
const domHeaderLeft = document.getElementById("HeaderLeft");
|
|
const domHeaderRight = document.getElementById("HeaderRight");
|
|
const domStationCurrent = document.getElementById("StationCurrent");
|
|
const domStationDestination = document.getElementById("StationDestination");
|
|
|
|
function setHeaderTexts() {
|
|
domStationCurrent.innerText = stationCurrent ? stationCurrent.name : "";
|
|
domStationDestination.innerText = stationDestination ? stationDestination.name : "";
|
|
}
|
|
setHeaderTexts();
|
|
|
|
var chooseRandomStationsTimeoutId = null;
|
|
async function chooseRandomStations() {
|
|
if (chooseRandomStationsTimeoutId) clearTimeout(chooseRandomStationsTimeoutId);
|
|
chooseRandomStationsTimeoutId = setTimeout(async () => {
|
|
let response = await fetch("./random_stations/" + encodeURIComponent(transportModesInteger) + "/2/");
|
|
if (!response.ok) return;
|
|
let randomStations = await response.json();
|
|
if (randomStations.length >= 2) {
|
|
stationCurrent = { name: randomStations[0][0], evaNumber: randomStations[0][1] };
|
|
stationDestination = { name: randomStations[1][0], evaNumber: randomStations[1][1] };
|
|
setHeaderTexts();
|
|
}
|
|
chooseRandomStationsTimeoutId = null;
|
|
}, 100);
|
|
}
|
|
|
|
draggingEnable(domStationCurrent, (x, y) => {
|
|
let target = domHeaderRight.getBoundingClientRect();
|
|
if (target.left <= x && x <= target.right && target.top <= y && y <= target.bottom) {
|
|
let temp = stationDestination;
|
|
stationDestination = stationCurrent;
|
|
stationCurrent = temp;
|
|
setHeaderTexts();
|
|
}
|
|
});
|
|
draggingEnable(domStationDestination, (x, y) => {
|
|
let target = domHeaderLeft.getBoundingClientRect();
|
|
if (target.left <= x && x <= target.right && target.top <= y && y <= target.bottom) {
|
|
let temp = stationDestination;
|
|
stationDestination = stationCurrent;
|
|
stationCurrent = temp;
|
|
setHeaderTexts();
|
|
}
|
|
});
|
|
|
|
// === Transport Mode Selection ===
|
|
|
|
const domTransportModeBus = document.getElementById("TransportModeBus");
|
|
const domTransportModeTram = document.getElementById("TransportModeTram");
|
|
const domTransportModeS = document.getElementById("TransportModeS");
|
|
const domTransportModeRE = document.getElementById("TransportModeRE");
|
|
const domTransportModeICE = document.getElementById("TransportModeICE");
|
|
|
|
const TRANSPORT_MODE_ICON_BUS = "🚌";
|
|
const TRANSPORT_MODE_ICON_TRAM = "🚊";
|
|
const TRANSPORT_MODE_ICON_S = "🚈";
|
|
const TRANSPORT_MODE_ICON_RE = "🚆";
|
|
const TRANSPORT_MODE_ICON_ICE = "🚄";
|
|
const TRANSPORT_MODE_TEXT_BUS = domTransportModeBus.title;
|
|
const TRANSPORT_MODE_TEXT_TRAM = domTransportModeTram.title;
|
|
const TRANSPORT_MODE_TEXT_S = domTransportModeS.title;
|
|
const TRANSPORT_MODE_TEXT_RE = domTransportModeRE.title;
|
|
const TRANSPORT_MODE_TEXT_ICE = domTransportModeICE.title;
|
|
|
|
domTransportModeBus.addEventListener("click", runInit((e) => {
|
|
if (e) e.preventDefault(); transportModeBus ^= true; transportModesInteger ^= 1;
|
|
domTransportModeBus.style.opacity = transportModeBus ? 1 : 0.5;
|
|
if (!transportModeBus || transportModesInteger == 1) chooseRandomStations();
|
|
}));
|
|
domTransportModeTram.addEventListener("click", runInit((e) => {
|
|
if (e) e.preventDefault(); transportModeTram ^= true; transportModesInteger ^= 2;
|
|
domTransportModeTram.style.opacity = transportModeTram ? 1 : 0.5;
|
|
if (!transportModeTram || transportModesInteger == 2) chooseRandomStations();
|
|
}));
|
|
domTransportModeS.addEventListener("click", runInit((e) => {
|
|
if (e) e.preventDefault(); transportModeS ^= true; transportModesInteger ^= 4;
|
|
domTransportModeS.style.opacity = transportModeS ? 1 : 0.5;
|
|
if (!transportModeS || transportModesInteger == 4) chooseRandomStations();
|
|
}));
|
|
domTransportModeRE.addEventListener("click", runInit((e) => {
|
|
if (e) e.preventDefault(); transportModeRE ^= true; transportModesInteger ^= 8;
|
|
domTransportModeRE.style.opacity = transportModeRE ? 1 : 0.5;
|
|
if (!transportModeRE || transportModesInteger == 8) chooseRandomStations();
|
|
}));
|
|
domTransportModeICE.addEventListener("click", runInit((e) => {
|
|
if (e) e.preventDefault(); transportModeICE ^= true; transportModesInteger ^= 16;
|
|
domTransportModeICE.style.opacity = transportModeICE ? 1 : 0.5;
|
|
if (!transportModeICE || transportModesInteger == 16) chooseRandomStations();
|
|
}));
|
|
|
|
// === Station Search ===
|
|
|
|
const domStationSearchInput = document.getElementById("StationSearchInput");
|
|
const domStationSearchResults = document.getElementById("StationSearchResults");
|
|
|
|
const stationSearchTimeoutDuration = 500;
|
|
var stationSearchTimeoutId = null;
|
|
var stationSearchPrevious = null;
|
|
|
|
const stationSearchInputChanged = () => {
|
|
let query = domStationSearchInput.value;
|
|
if (stationSearchPrevious === query) return;
|
|
stationSearchPrevious = query;
|
|
if (stationSearchTimeoutId !== null) clearTimeout(stationSearchTimeoutId);
|
|
stationSearchTimeoutId = (query && query.length > 1) ? setTimeout(async () => {
|
|
let response = await fetch("./query_stations/" + encodeURIComponent(query) + "/");
|
|
if (!response.ok) {
|
|
let error = await response.text();
|
|
console.warn("Station Search: Got error " + response.status + " from server: " + error);
|
|
} else {
|
|
let result = await response.json();
|
|
domStationSearchResults.replaceChildren();
|
|
for (const [stationName, stationEvaNum, transportModesInteger] of result) {
|
|
let searchResultElem = document.createElement("div");
|
|
let searchResultTransportModesElem = document.createElement("small");
|
|
searchResultTransportModesElem.style.cursor = "default";
|
|
for (const [i, char, text] of [[1, TRANSPORT_MODE_ICON_BUS, TRANSPORT_MODE_TEXT_BUS], [2, TRANSPORT_MODE_ICON_TRAM, TRANSPORT_MODE_TEXT_TRAM], [4, TRANSPORT_MODE_ICON_S, TRANSPORT_MODE_TEXT_S], [8, TRANSPORT_MODE_ICON_RE, TRANSPORT_MODE_TEXT_RE], [16, TRANSPORT_MODE_ICON_ICE, TRANSPORT_MODE_TEXT_ICE]]) {
|
|
if ((transportModesInteger & i) != 0) {
|
|
let transportModeElem = document.createElement("span");
|
|
transportModeElem.innerText = char;
|
|
transportModeElem.title = text;
|
|
searchResultTransportModesElem.append(transportModeElem);
|
|
}
|
|
}
|
|
let searchResultNameElem = document.createElement("span");
|
|
searchResultNameElem.innerText = stationName;
|
|
searchResultElem.append(searchResultTransportModesElem, searchResultNameElem);
|
|
searchResultElem.classList.add("StationSearchResult");
|
|
draggingEnable(searchResultElem, (x, y) => {
|
|
let right = domHeaderRight.getBoundingClientRect();
|
|
let left = domHeaderLeft.getBoundingClientRect();
|
|
if (left.left <= x && x <= left.right && left.top <= y && y <= left.bottom) {
|
|
stationCurrent = { name: stationName, evaNumber: stationEvaNum };
|
|
setHeaderTexts();
|
|
}
|
|
if (right.left <= x && x <= right.right && right.top <= y && y <= right.bottom) {
|
|
stationDestination = { name: stationName, evaNumber: stationEvaNum };
|
|
setHeaderTexts();
|
|
}
|
|
});
|
|
domStationSearchResults.appendChild(searchResultElem);
|
|
}
|
|
}
|
|
}, stationSearchTimeoutDuration) : (() => { domStationSearchResults.replaceChildren(); return null; })();
|
|
;
|
|
};
|
|
domStationSearchInput.addEventListener("change", stationSearchInputChanged);
|
|
domStationSearchInput.addEventListener("input", stationSearchInputChanged);
|
|
|
|
// === Loading (Network) ===
|
|
|
|
chooseRandomStations();
|
|
|
|
// === InGame ===
|
|
|
|
const domStartGameButton = document.getElementById("StartGameButton");
|
|
const domWelcome = document.getElementById("Welcome");
|
|
const domInGame = document.getElementById("InGame");
|
|
const domDeparturesList = document.getElementById("DeparturesList");
|
|
const domFocusedDeparturePanel = document.getElementById("FocusedDeparturePanel");
|
|
const domFocusedDeparturePanelHead = document.getElementById("FocusedDeparturePanelHead");
|
|
const domFocusedDeparturePanelStops = document.getElementById("FocusedDeparturePanelStops");
|
|
const domFocusedDeparturePanelCloseClickable = document.getElementById("FocusedDeparturePanelCloseClickable");
|
|
function hideFocusDeparturePanel() {
|
|
domFocusedDeparturePanel.style.left = "100%";
|
|
domFocusedDeparturePanelCloseClickable.style.display = "none";
|
|
}
|
|
domFocusedDeparturePanelCloseClickable.addEventListener("click", hideFocusDeparturePanel);
|
|
|
|
async function goInGame() {
|
|
isInGame = true;
|
|
// make server get all eva numbers of the destination station
|
|
let testDestinationDepartures = await (await fetch("./query_departures/" + encodeURIComponent(transportModesInteger) + "/" + encodeURIComponent(stationDestination.evaNumber) + "/")).json();
|
|
if (testDestinationDepartures[1].length < 10) {
|
|
if (!window.confirm("Warning: Low activity (" + testDestinationDepartures[1].length + ") at the specified destination. It may not be possible to win.")) {
|
|
isInGame = false;
|
|
return;
|
|
}
|
|
}
|
|
stationDestination.relatedEvaNumbers = testDestinationDepartures[0];
|
|
for (const elem of draggableElements) elem.style.cursor = "default";
|
|
draggableElements = new Array();
|
|
domWelcome.style.display = "none";
|
|
domInGame.style.display = "block";
|
|
reloadDepartures();
|
|
}
|
|
|
|
domStartGameButton.onclick = () => goInGame();
|
|
|
|
async function reloadDepartures() {
|
|
domDeparturesList.replaceChildren();
|
|
hideFocusDeparturePanel();
|
|
if (stationDestination.evaNumber === stationCurrent.evaNumber || (stationDestination.relatedEvaNumbers && stationDestination.relatedEvaNumbers.includes(stationCurrent.evaNumber))) {
|
|
endGameWin();
|
|
return;
|
|
}
|
|
let response = await fetch("./query_departures/" + encodeURIComponent(transportModesInteger) + "/" + encodeURIComponent(stationCurrent.evaNumber) + "/");
|
|
if (!response.ok) {
|
|
let error = await response.text();
|
|
console.warn("Query Departures: Got error " + response.status + " from server: " + error);
|
|
} else {
|
|
let [stationRelatedEvaNumbers, result] = await response.json();
|
|
for (let relatedEvaNumber of stationRelatedEvaNumbers) {
|
|
if (stationDestination.evaNumber === relatedEvaNumber || (stationDestination.relatedEvaNumbers && stationDestination.relatedEvaNumbers.includes(relatedEvaNumber))) {
|
|
endGameWin();
|
|
return;
|
|
}
|
|
}
|
|
for (const [route, stopEvaNumber, stops, routeId] of result) {
|
|
if (stops.length > 0) {
|
|
let departureElem = document.createElement("div");
|
|
let departureElemHead = document.createElement("div");
|
|
departureElemHead.style.marginTop = "0.5em";
|
|
departureElemHead.innerText = route + " ➟ " + stops[stops.length-1];
|
|
let departureElemDetails = document.createElement("small");
|
|
departureElemDetails.style.display = "flex";
|
|
departureElemDetails.style.flexWrap = "wrap";
|
|
let firstStop = true;
|
|
for (const stop of stops.slice(0, stops.length-1)) {
|
|
if (firstStop && stop == stationCurrent.name) continue;
|
|
let departureStopElem = document.createElement("span");
|
|
departureStopElem.style.whiteSpace = "pre";
|
|
departureStopElem.innerText = (firstStop ? "" : " ➞ ") + stop;
|
|
departureElemDetails.append(departureStopElem);
|
|
firstStop = false;
|
|
}
|
|
let departureElemSelect = document.createElement("div");
|
|
departureElemSelect.style.overflow = "hidden";
|
|
departureElemSelect.style.height = "0vh";
|
|
departureElemSelect.style.transition = "height 0.25s ease-in-out";
|
|
departureElem.append(departureElemHead, departureElemDetails, departureElemSelect);
|
|
departureElem.style.cursor = "pointer";
|
|
let resultCache = [null];
|
|
departureElem.addEventListener("click", async () => {
|
|
domFocusedDeparturePanelHead.replaceChildren();
|
|
domFocusedDeparturePanelStops.replaceChildren();
|
|
domFocusedDeparturePanelCloseClickable.style.display = "block";
|
|
domFocusedDeparturePanel.style.left = "max(calc(5% + 5em), calc(50% - 22.5em))";
|
|
let headElem = document.createElement("b");
|
|
headElem.innerText = route;
|
|
let headSmallerElem = document.createElement("span");
|
|
headSmallerElem.style.whiteSpace = "pre";
|
|
headSmallerElem.innerText = " ➟ " + stops[stops.length-1];
|
|
domFocusedDeparturePanelHead.append(headElem, headSmallerElem);
|
|
if (resultCache[0] === null) {
|
|
let response = await fetch("./query_route/" + encodeURIComponent(routeId) + "/");
|
|
if (!response.ok) {
|
|
let error = await response.text();
|
|
console.warn("Query Route: Got error " + response.status + " from server: " + error);
|
|
return;
|
|
} else {
|
|
resultCache[0] = await response.json();
|
|
}
|
|
}
|
|
let result = resultCache[0];
|
|
let canceled = result[1];
|
|
let foundCurrent = true;
|
|
for (const [stop, evaNumber] of result[0]) {
|
|
if (evaNumber === stopEvaNumber) foundCurrent = false;
|
|
}
|
|
for (const [stop, evaNumber] of result[0]) {
|
|
let stopElem = document.createElement("li");
|
|
stopElem.innerText = stop;
|
|
stopElem.style.wordWrap = "nowrap";
|
|
if (!foundCurrent) {
|
|
if (evaNumber === stopEvaNumber) {
|
|
foundCurrent = true;
|
|
stopElem.classList.add("DetailedViewCurrentStop");
|
|
} else {
|
|
stopElem.classList.add("DetailedViewPastStop");
|
|
}
|
|
} else {
|
|
stopElem.classList.add("DetailedViewFutureStop");
|
|
stopElem.addEventListener("click", async () => {
|
|
stationCurrent = { name: stop, evaNumber: evaNumber };
|
|
setHeaderTexts();
|
|
await reloadDepartures();
|
|
});
|
|
}
|
|
domFocusedDeparturePanelStops.append(stopElem);
|
|
}
|
|
});
|
|
domDeparturesList.append(departureElem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function endGameWin() {
|
|
// TODO: obv
|
|
alert("You won! Unfortunately, i haven't made a screen for that yet...");
|
|
location.reload();
|
|
}
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|