commit 7b45770da6e2074391ba68377c35120d20f11f77
parent 43f3f3b3a91367eebc813ae8e221394ac61d37a8
Author: Katja (ctucx) <git@ctu.cx>
Date: Thu, 17 Apr 2025 20:58:40 +0200
parent 43f3f3b3a91367eebc813ae8e221394ac61d37a8
Author: Katja (ctucx) <git@ctu.cx>
Date: Thu, 17 Apr 2025 20:58:40 +0200
cleanup
16 files changed, 354 insertions(+), 412 deletions(-)
M
|
124
++++++++++++++++++++++++++++++++++++++++---------------------------------------
M
|
101
+++++++++++++++++++++++++++++++++++--------------------------------------------
M
|
89
++++++++++++++++++++++++++++++++++++++-----------------------------------------
M
|
99
+++++++++++++++++++++++++++++++++++++------------------------------------------
diff --git a/ds100.py b/ds100.py @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 -import json -import re - -spaces = re.compile(" +") - -# json list of station info, probably from hafas or something -with open("stations.json") as f: - data = json.load(f) - -fiddle = dict() - -for station in data: - ds100 = spaces.sub(" ", station["ds100"]) - if station["name"] in fiddle: - fiddle[station["name"]]["ds100"].add(ds100) - fiddle[station["name"]]["eva"] = min( - int(station["eva"]), fiddle[station["name"]]["eva"] - ) - else: - fiddle[station["name"]] = { - "ds100": {ds100}, - "eva": int(station["eva"]), - } - -output = dict() - -for name, station in fiddle.items(): - if station["eva"] < 8000000 or station["eva"] > 8100000 or station["ds100"] == "": - # print(station["eva"], name) - continue - - output[station["eva"]] = station["ds100"] - -for id, codes in output.items(): - output[id] = ", ".join(codes) - -print("export const ds100 = ", end="") -print(json.dumps(output, indent=2, ensure_ascii=False, sort_keys=True))
diff --git a/src/app_functions.js b/src/app_functions.js @@ -24,7 +24,7 @@ const loyaltyCardsReverse = { 'Symbol(General-Abonnement)': 'GENERALABONNEMENT', }; -export const loyaltyCardToString = loyaltyCard => +export const loyaltyCardToString = loyaltyCard => loyaltyCardsReverse[loyaltyCard.type.toString()] !== 'NONE' ? `${loyaltyCardsReverse[loyaltyCard.type.toString()]}-${loyaltyCard.discount}-${loyaltyCard.class}` : 'NONE'; @@ -83,7 +83,7 @@ export const processLeg = leg => { export const getFromPoint = journeys => journeys[0].legs[0].origin; export const getToPoint = journeys => journeys[0].legs[journeys[0].legs.length-1].destination; - export const newJourneys = async params => { +export const newJourneys = async params => { const { from, to, ...moreOpts } = params; let data; @@ -149,7 +149,7 @@ export const getJourneys = async slug => { export const getMoreJourneys = async (slug, mode) => { const saved = await db.getJourneysOverview(slug); - const params = { ...journeySettings(), ...saved.params }; + const params = { ...saved.params, ...journeySettings() }; if (typeof params.loyaltyCard === 'string') params.loyaltyCard = loyaltyCardFromString(params.loyaltyCard); @@ -166,7 +166,9 @@ export const getMoreJourneys = async (slug, mode) => { ...newData, }; - for (const journey of newData.journeys) journey.refreshToken = hafasToTrainsearch(journey.refreshToken); + newData.journeys.forEach(journey => { + journey.refreshToken = hafasToTrainsearch(journey.refreshToken); + }); if (mode === 'earlier') { res.journeys = newData.journeys.concat(existingJourneys);
diff --git a/src/baseView.js b/src/baseView.js @@ -1,21 +1,17 @@ import { LitElement, html, nothing } from 'lit'; import { t } from './languages.js'; -import { baseStyles, helperStyles, flexboxStyles, overlaysStyles, buttonInputStyles, iconStyles } from './styles.js'; +import { baseStyles, flexboxStyles, overlaysStyles, buttonInputStyles, iconStyles } from './styles.js'; export class BaseView extends LitElement { static properties = { - isOffline: { state: true }, - isUpdating: { state: true }, - overlayType: { state: true }, - overlayTitle: { state: true }, - overlayVisible: { state: true }, - overlayContent: { state: true }, + isOffline: { state: true }, + isUpdating: { state: true }, + overlayState: { state: true }, }; static styles = [ baseStyles, - helperStyles, flexboxStyles, overlaysStyles, buttonInputStyles, @@ -28,19 +24,21 @@ export class BaseView extends LitElement { this.isOffline = !navigator.onLine; this.isUpdating = false; - this.overlayType = 'plain'; - this.overlayVisible = false; - this.overlayContent = null; - this.overlayTitle = null; + this.overlayState = { + type: 'plain', + visible: false, + content: null, + title: null, + }; } - connectedCallback() { + connectedCallback () { super.connectedCallback(); window.addEventListener('online', this.connectionHandler); window.addEventListener('offline', this.connectionHandler); } - disconnectedCallback() { + disconnectedCallback () { super.disconnectedCallback(); window.removeEventListener('online', this.connectionHandler); window.removeEventListener('offline', this.connectionHandler); @@ -52,21 +50,24 @@ export class BaseView extends LitElement { showDialogOverlay = (title, body) => this.showOverlay('dialog', body, title); showAlertOverlay = text => this.showOverlay('alert', text); showSelectOverlay = items => this.showOverlay('select', items); - hideOverlay = () => { this.overlayVisible = false; } - showOverlay = (type, content, title) => { - this.overlayType = type; - this.overlayContent = content; - this.overlayTitle = title; - this.overlayVisible = true; - } + hideOverlay = () => { + this.overlayState.visible = false; + this.requestUpdate(); + }; + showOverlay = (type, content, title) => { + this.overlayState = { + type, content, title, + visible: true, + } + }; - overlayHandler = event => event.target === event.currentTarget && this.overlayType !== 'loader' ? this.hideOverlay() : true; + overlayHandler = event => event.target === event.currentTarget && this.overlayState.type !== 'loader' ? this.hideOverlay() : true; render () { let overlayContent; - if (this.overlayVisible) { - switch (this.overlayType) { + if (this.overlayState.visible) { + switch (this.overlayState.type) { case 'loader': overlayContent = html`<div class="spinner"></div>`; break; @@ -74,37 +75,37 @@ export class BaseView extends LitElement { overlayContent = html` <div class="modal dialog"> <div class="header flex-row"> - <h4>${t(this.overlayTitle)}</h4> + <h4>${t(this.overlayState.title)}</h4> <div class="icon-close" title="${t('close')}" @click=${this.hideOverlay}></div> </div> - <div class="body">${this.overlayContent}</div> + <div class="body">${this.overlayState.content}</div> </div> `; break; case 'select': overlayContent = html` <div class="modal select flex-column"> - ${this.overlayContent.map(item => html`<a class="button color" @click=${item.action}>${t(item.label)}</a>`)} - <a class="button color" @click=${() => { this.hideOverlay();}}>Close</a> + ${this.overlayState.content.map(item => html`<a class="button color" @click=${item.action}>${t(item.label)}</a>`)} + <a class="button color" @click=${this.hideOverlay}>${t('close')}</a> </div> `; break; case 'alert': overlayContent = html` <div class="modal alert" style="overflow:auto"> - ${this.overlayContent}<br><button class="color" style="float:right" @click=${this.hideOverlay}>OK</button> + ${this.overlayState.content}<br><button class="color" style="float:right" @click=${this.hideOverlay}>OK</button> </div> `; break; default: - overlayContent = this.overlayContent; + overlayContent = this.overlayState.content; break; } } return [ - this.renderContent(), - !this.overlayVisible ? nothing : html`<div class="overlay" @click=${this.overlayHandler}>${overlayContent}</div>` + this.renderView(), + !this.overlayState.visible ? nothing : html`<div class="overlay" @click=${this.overlayHandler}>${overlayContent}</div>` ]; } }
diff --git a/src/departuresView.js b/src/departuresView.js @@ -7,7 +7,7 @@ import { processLeg } from './app_functions.js'; import { getHafasClient } from './hafasClient.js'; import { t } from './languages.js'; -import { baseStyles, helperStyles, flexboxStyles, iconStyles, headerStyles, cardStyles, departuresViewStyles } from './styles.js'; +import { headerStyles, cardStyles, departuresViewStyles } from './styles.js'; class DeparturesView extends BaseView { static styles = [ @@ -24,83 +24,85 @@ class DeparturesView extends BaseView { viewState: { state: true }, }; - constructor(...args) { - super(...args); + constructor () { + super(); this.viewState = null; } - async connectedCallback() { + async connectedCallback () { super.connectedCallback(); await sleep(100); setThemeColor(queryBackgroundColor(this.renderRoot, 'header')); + + if (!this.isOffline) await this.updateViewState(); + } + + disconnectedCallback () { + super.disconnectedCallback(); + + this.viewState = null; } - async updated(previous) { + + async updated (previous) { super.updated(previous); if (isDevServer) console.info('updated(): ', previous); - if (previous.has('stopId')) { - this.viewState = null; - if (!this.isOffline) await this.updateViewState(); - } - if (previous.has('isOffline') && this.viewState === null) await this.updateViewState(); } - renderContent () { - return [ - html` - <div class="header-container"> - <header> - <a class="icon-back ${history.length !== 1 ? '': 'invisible'}" title="${t('back')}" @click=${() => history.back()}></a> - <div class="container"> - <h3>Departures from ${this.viewState !== null ? this.viewState.name : '...'}</h3> - </div> - <a class="icon-reload ${!this.isUpdating ? '' : 'spinning'} ${!this.isOffline ? '' : 'invisible'}" title="${t("reload")}" @click=${this.updateViewState}></a> - </header> - </div> - `, - - this.viewState !== null ? html` - <div class="container"> - <div class="card"> - <table> - <thead> - <tr> - <th>Time</th> - <th class="station"></th> - <th>${t('platform')}</th> - </tr> - </thead> - <tbody> - ${(this.viewState.departures || []).map(departure => html` - <tr @click=${() => window.location = `#/t/${this.profile}/${departure.tripId}`}> - <td class="${departure.cancelled ? 'cancelled' : nothing}"> - <span>${timeTemplate(departure)}</span> - </td> - <td class="${departure.cancelled ? 'cancelled' : nothing}"> - <span>${departure.line.name}${departure.direction ? html` → ${departure.direction}` : nothing}</span> - </td> - ${departure.cancelled ? html` - <td><span class="cancelled-text">${t('cancelled-ride')}</span></td> - ` : html` - <td>${platformTemplate(departure)}</td> - `} - </tr> - `)} - </tbody> - </table> + renderView = () => [ + html` + <div class="header-container"> + <header> + <a class="icon-back ${history.length !== 1 ? '': 'invisible'}" title="${t('back')}" @click=${() => history.back()}></a> + <div class="container"> + <h3>Departures from ${this.viewState !== null ? this.viewState.name : '...'}</h3> </div> + <a class="icon-reload ${!this.isUpdating ? '' : 'spinning'} ${!this.isOffline ? '' : 'invisible'}" title="${t("reload")}" @click=${this.updateViewState}></a> + </header> + </div> + `, + + this.viewState !== null ? html` + <div class="container"> + <div class="card"> + <table> + <thead> + <tr> + <th>Time</th> + <th class="station"></th> + <th>${t('platform')}</th> + </tr> + </thead> + <tbody> + ${(this.viewState.departures || []).map(departure => html` + <tr @click=${() => window.location = `#/t/${this.profile}/${departure.tripId}`}> + <td class="${departure.cancelled ? 'cancelled' : nothing}"> + <span>${timeTemplate(departure)}</span> + </td> + <td class="${departure.cancelled ? 'cancelled' : nothing}"> + <span>${departure.line.name}${departure.direction ? html` → ${departure.direction}` : nothing}</span> + </td> + ${departure.cancelled ? html` + <td><span class="cancelled-text">${t('cancelled-ride')}</span></td> + ` : html` + <td>${platformTemplate(departure)}</td> + `} + </tr> + `)} + </tbody> + </table> </div> - <footer-component></footer-component> - ` : !this.isOffline ? - html`<div class="spinner"></div>` - : html`<div class="offline"></div>` - ]; - } + </div> + <footer-component></footer-component> + ` : !this.isOffline ? + html`<div class="spinner"></div>` + : html`<div class="offline"></div>` + ]; updateViewState = async () => { if (this.isOffline !== false) return; @@ -110,7 +112,7 @@ class DeparturesView extends BaseView { const when = this.when; const client = await getHafasClient(this.profile); - const [ {departures}, stopInfo ] = await Promise.all([ + const [ { departures }, stopInfo ] = await Promise.all([ client.departures(this.stopId, { when }), client.stop(this.stopId), ]); @@ -122,7 +124,7 @@ class DeparturesView extends BaseView { departures }; - if (isDevServer) console.info('viewState: ', this.viewState); + if (isDevServer) console.info('viewState:', this.viewState); } catch(e) { this.showAlertOverlay(e.toString()); console.error(e);
diff --git a/src/footerComponent.js b/src/footerComponent.js @@ -1,11 +1,10 @@ import { LitElement, html } from 'lit'; -import { baseStyles, helperStyles, footerStyles } from './styles.js'; +import { baseStyles, footerStyles } from './styles.js'; class FooterElement extends LitElement { static styles = [ baseStyles, - helperStyles, footerStyles, ];
diff --git a/src/journeyView.js b/src/journeyView.js @@ -11,7 +11,7 @@ import { remarksModal, platformTemplate, stopTemplate, timeTemplate } from './te import { formatPoint, formatDuration, formatPrice, formatTrainTypes, formatLineAdditionalName, formatLineDisplayName } from './formatters.js'; import { cachedCoachSequence } from './coach-sequence/index.js'; -import { baseStyles, helperStyles, flexboxStyles, headerStyles, iconStyles, cardStyles, journeyViewStyles } from './styles.js'; +import { headerStyles, cardStyles, journeyViewStyles } from './styles.js'; class JourneyView extends BaseView { static styles = [ @@ -28,8 +28,8 @@ class JourneyView extends BaseView { settingsState: { state: true }, }; - constructor (...args) { - super(...args); + constructor () { + super(); this.viewState = null; this.settingsState = settings.getState(); @@ -41,7 +41,7 @@ class JourneyView extends BaseView { setThemeColor(queryBackgroundColor(this.renderRoot, 'header')); - if (this.viewState === null) await this.updateViewState(); + await this.updateViewState(); this._unsubscribeSettingsState = settings.subscribe(state => { this.settingsState = state; @@ -59,46 +59,36 @@ class JourneyView extends BaseView { } } - async updated (previous) { - super.updated(previous); - - if (isDevServer) console.info('updated(): ', previous); - - if (previous.has('refreshToken')) { - this.viewState = null; - await this.updateViewState(); - } - } - - renderContent () { - return html` - <div class="header-container"> - <header> - <a id="back" class="icon-back ${history.length !== 1 ? '': 'invisible'}" title="${t('back')}" @click=${() => history.back()}></a> - <div class="container"> - <a class="icon-reload ${this.isUpdating ? 'spinning' : ''} ${!this.isOffline ? '' : 'invisible'}" title="${t("reload")}" @click=${this.refreshJourney}></a> - ${this.viewState !== null ? html` - <h3>${formatPoint(this.viewState.legs[0].origin)} → ${formatPoint(this.viewState.legs[this.viewState.legs.length - 1].destination)}</h3> - <p><b>${t('duration')}: ${formatDuration(this.viewState.duration)} | ${t('changes')}: ${this.viewState.changes-1} | ${t('date')}: ${this.viewState.legs[0].plannedDeparture.formatDate()}${this.settingsState.showPrices && this.viewState.price ? html` | ${t('price')}: <td><span>${formatPrice(this.viewState.price)}</span></td>` : nothing}</b></p> - ` : html` - <h3>... → ...</h3> - <p><b>${t('duration')}: ... | ${t('changes')}: ... | ${t('date')}: ...</b></p> - `} - </div> - <a class="icon-dots" title="${t("more")}" @click=${this.moreModal}></a> - </header> - </div> - - ${this.viewState !== null ? html` - <div class="container journeyView"> - ${this.viewState.legs.map(leg => this.legTemplate(leg))} - </div> - <footer-component></footer-component> - ` : html`<div class="spinner"></div>`} - `; - } + renderView = () => [ + html` + <div class="header-container"> + <header> + <a id="back" class="icon-back ${history.length !== 1 ? '': 'invisible'}" title="${t('back')}" @click=${() => history.back()}></a> + <div class="container"> + <a class="icon-reload ${this.isUpdating ? 'spinning' : ''} ${!this.isOffline ? '' : 'invisible'}" title="${t("reload")}" @click=${this.refreshJourney}></a> + ${this.viewState !== null ? html` + <h3>${formatPoint(this.viewState.legs[0].origin)} → ${formatPoint(this.viewState.legs[this.viewState.legs.length - 1].destination)}</h3> + <p><b>${t('duration')}: ${formatDuration(this.viewState.duration)} | ${t('changes')}: ${this.viewState.changes-1} | ${t('date')}: ${this.viewState.legs[0].plannedDeparture.formatDate()}${this.settingsState.showPrices && this.viewState.price ? html` | ${t('price')}: <td><span>${formatPrice(this.viewState.price)}</span></td>` : nothing}</b></p> + ` : html` + <h3>... → ...</h3> + <p><b>${t('duration')}: ... | ${t('changes')}: ... | ${t('date')}: ...</b></p> + `} + </div> + <a class="icon-dots" title="${t("more")}" @click=${this.moreModal}></a> + </header> + </div> + `, + this.viewState !== null ? html` + <div class="container journeyView"> + ${this.viewState.legs.map(leg => this.legTemplate(leg))} + </div> + <footer-component></footer-component> + ` : html` + <div class="spinner"></div> + `, + ]; - legTemplate (leg) { + legTemplate = leg => { if (leg.walking) { return html`<p class="walk">${t(leg.distance === null ? 'walkinfo' : 'walkinfo_meters', formatPoint(leg.destination), leg.distance)}</p>`; } else if (leg.transfer) { @@ -152,7 +142,7 @@ class JourneyView extends BaseView { } } - async updateViewState (viewState ) { + updateViewState = async viewState => { this.isUpdating = true; try { if (viewState === undefined) viewState = await getJourney(this.profile, this.refreshToken); @@ -166,9 +156,8 @@ class JourneyView extends BaseView { await db.updateHistoryEntry(overviewObject.historyEntryId, historyObject); } - - viewState.changes = 0; - viewState.duration = null; + viewState.changes = 0; + viewState.duration = null; if (viewState.legs[viewState.legs.length - 1].arrival && viewState.legs[0].departure) viewState.duration = viewState.legs[viewState.legs.length - 1].arrival - viewState.legs[0].departure; @@ -212,7 +201,7 @@ class JourneyView extends BaseView { this.viewState = viewState; //fetch train types after setting the viewState - if (!this.isOffline !== false) { + if (!this.isOffline) { for (const leg of this.viewState.legs) { if (leg.line && leg.line.name) { const [category, number] = leg.line.name.split(' '); @@ -224,7 +213,7 @@ class JourneyView extends BaseView { } } - if (isDevServer) console.info('viewState: ', this.viewState); + if (isDevServer) console.info('viewState:', this.viewState); } catch(e) { this.showAlertOverlay(e.toString()); console.error(e); @@ -232,7 +221,7 @@ class JourneyView extends BaseView { this.isUpdating = false; } - async refreshJourney () { + refreshJourney = async () => { if (this.isOffline !== false) return; if (this.isUpdating !== false) return false; @@ -247,19 +236,19 @@ class JourneyView extends BaseView { this.isUpdating = false; } - async moreModal () { + moreModal = async () => { const options = [ { 'label': !navigator.canShare ? 'copyURL' : 'shareURL', 'action': async () => await this.shareAction() }, ]; if (isDevServer) options.push({ 'label': 'addCalendar', 'action': async () => await this.calendarAction() }); - if (this.profile === 'db') options.push({ 'label': 'tickets', 'action': async () => await this.showTicketsModal() }); + if (this.profile === 'db') options.push({ 'label': 'tickets', 'action': async () => await this.ticketsAction() }); this.showSelectOverlay(options); }; - async shareAction () { + shareAction = async () => { try { await navigator.share({ url: window.location }); } catch (error) { @@ -268,11 +257,11 @@ class JourneyView extends BaseView { } } - async showTicketsModal () { + ticketsAction = async () => { try { this.showLoaderOverlay(); - if (this.isOffline !== false) await this.refreshJourney(); + if (!this.isOffline) await this.refreshJourney(); if (this.viewState.tickets === undefined) { await this.showAlertOverlay('No ticket data available'); @@ -314,7 +303,7 @@ class JourneyView extends BaseView { } }; - async calendarAction () { + calendarAction = async () => { let events = []; this.viewState.legs.forEach(leg => {
diff --git a/src/journeysCanvas.js b/src/journeysCanvas.js @@ -47,8 +47,8 @@ export class JourneysCanvas extends BaseView { } }; - constructor (...args) { - super(...args); + constructor () { + super(); this.canvasElement = null; this.canvasContext = null;
diff --git a/src/journeysView.js b/src/journeysView.js @@ -7,14 +7,13 @@ import { timeTemplate } from './templates.js'; import { settings } from './settings.js'; import { t } from './languages.js'; -import { baseStyles, helperStyles, flexboxStyles, buttonInputStyles, iconStyles, headerStyles, cardStyles, journeysViewStyles } from './styles.js'; +import { headerStyles, cardStyles, journeysViewStyles } from './styles.js'; import { JourneysCanvas } from './journeysCanvas.js'; export class JourneysView extends JourneysCanvas { static styles = [ super.styles, - baseStyles, headerStyles, cardStyles, journeysViewStyles @@ -27,8 +26,8 @@ export class JourneysView extends JourneysCanvas { settingsState: { state: true }, }; - constructor (...args) { - super(...args); + constructor () { + super(); this.viewState = null; this.settingsState = settings.getState(); @@ -62,6 +61,7 @@ export class JourneysView extends JourneysCanvas { } async updated (previous) { + await super.updated(previous); if (isDevServer) console.info('updated(): ', previous); if (previous.has('mode') && this.settingsState.journeysViewMode !== this.mode) this.settingsState.setJourneysViewMode(this.mode); @@ -83,42 +83,40 @@ export class JourneysView extends JourneysCanvas { await this.getCoachSequences(); } } - - await super.updated(previous); } - renderContent () { - return html` - <div class="header-container"> - <header> - <a id="back" class="icon-back" title="${t('back')}" href="#/"></a> - <div class="container flex-row"> - <div> - <h3>${t('from')}: ${this.viewState !== null ? formatPoint(getFromPoint(this.viewState.journeys)) : '...'}</h3> - <h3>${t('to')}: ${this.viewState !== null ? formatPoint(getToPoint(this.viewState.journeys)) : '...'}</h3> - </div> - <div class="mode-changers flex-row"> - <a href="#/${this.slug}/table" class="${this.settingsState.journeysViewMode === 'table' ? 'active' : ''}"> - <div class="icon-table"></div> - <span>${t('table-view')}</span> - </a> - <a href="#/${this.slug}/canvas" class="${this.settingsState.journeysViewMode === 'canvas' ? 'active' : ''}"> - <div class="icon-canvas"></div> - <span>${t('canvas-view')}</span> - </a> - </div> + renderView = () => [ + html` + <div class="header-container"> + <header> + <a id="back" class="icon-back" title="${t('back')}" href="#/"></a> + <div class="container flex-row"> + <div> + <h3>${t('from')}: ${this.viewState !== null ? formatPoint(getFromPoint(this.viewState.journeys)) : '...'}</h3> + <h3>${t('to')}: ${this.viewState !== null ? formatPoint(getToPoint(this.viewState.journeys)) : '...'}</h3> </div> - <a class="icon-reload ${this.isUpdating ? 'spinning' : ''} ${!this.isOffline ? '' : 'invisible'}" title="${t("reload")}" @click=${this.refreshJourneys}></a> - </header> - </div> - - ${this.viewState !== null ? html` - ${this.settingsState.journeysViewMode === 'canvas' ? this.getCanvas() : nothing} - ${this.settingsState.journeysViewMode === 'table' ? html` - <div class="container journeysView"> - ${this.viewState.earlierRef ? html` + <div class="mode-changers flex-row"> + <a href="#/${this.slug}/table" class="${this.settingsState.journeysViewMode === 'table' ? 'active' : ''}"> + <div class="icon-table"></div> + <span>${t('table-view')}</span> + </a> + <a href="#/${this.slug}/canvas" class="${this.settingsState.journeysViewMode === 'canvas' ? 'active' : ''}"> + <div class="icon-canvas"></div> + <span>${t('canvas-view')}</span> + </a> + </div> + </div> + <a class="icon-reload ${this.isUpdating ? 'spinning' : ''} ${!this.isOffline ? '' : 'invisible'}" title="${t("reload")}" @click=${this.refreshJourneys}></a> + </header> + </div> + `, + + this.viewState !== null ? [ + this.settingsState.journeysViewMode === 'canvas' ? this.getCanvas() : nothing, + this.settingsState.journeysViewMode === 'table' ? html` + <div class="container"> + ${!this.viewState.earlierRef ? nothing : html` <a class="arrowButton icon-arrow2 flipped flex-center" title="${t('label_earlier')}" @click=${() => this.moreJourneys('earlier')}></a> - ` : nothing} <div class="card"> <table> @@ -139,17 +137,16 @@ export class JourneysView extends JourneysCanvas { </table> </div> - ${this.viewState.laterRef ? html` + ${!this.viewState.laterRef ? nothing : html` <a class="arrowButton icon-arrow2 flex-center" title="${t('label_later')}" @click=${() => this.moreJourneys('later')}></a> - ` : nothing} + `} </div> <footer-component></footer-component> - ` : nothing} - ` : html`<div class="spinner"></div>`} - `; - } + ` : nothing + ] : html`<div class="spinner"></div>` + ]; - journeyTemplate (journey) { + journeyTemplate = journey => { const firstLeg = journey.legs[0]; const lastLeg = journey.legs[journey.legs.length - 1]; @@ -172,7 +169,7 @@ export class JourneysView extends JourneysCanvas { `; } - async updateViewState () { + updateViewState = async () => { try { let viewState = await getJourneys(this.slug); @@ -223,7 +220,7 @@ export class JourneysView extends JourneysCanvas { } } - async refreshJourneys () { + refreshJourneys = async () => { if (this.isOffline !== false) return; if (this.isUpdating !== false) return false; @@ -240,7 +237,7 @@ export class JourneysView extends JourneysCanvas { } } - async moreJourneys (mode) { + moreJourneys = async mode => { if (this.isOffline !== false) { this.showAlertOverlay(t('offline')); return;
diff --git a/src/main.js b/src/main.js @@ -5,7 +5,7 @@ import { initDataStorage } from './dataStorage.js'; import { initHafasClient } from './hafasClient.js'; import { initSettingsState, settingsState } from './settings.js' -import { baseStyles, helperStyles } from './styles.js'; +import { baseStyles } from './styles.js'; import './searchView.js'; import './journeysView.js'; @@ -23,28 +23,24 @@ class Oeffisearch extends LitElement { routes = [ { pattern: /^\/$/, - render: () => html`<search-view></search-view>` - }, - { + render: param => html`<search-view></search-view>` + }, { pattern: /^\/([a-zA-Z0-9]+)\/([a-z]+)$/, render: param => html`<journeys-view slug="${param[0]}" mode="${param[1]}"></journeys-view>` - }, - { + }, { pattern: /^\/j\/([a-z]+)\/(.+)$/, render: param => html`<journey-view profile="${param[0]}" refreshToken="${param[1]}"></journey-view>` - }, - { + }, { pattern: /^\/t\/([a-z]+)\/(.+)$/, render: param => html`<trip-view profile="${param[0]}" refreshToken="${param[1]}"></trip-view>` - }, - { + }, { pattern: /^\/d\/([a-z]+)\/([^/]+)(\/[0-9]+)?$/, render: param => html`<departures-view profile="${param[0]}" stopId="${param[1]}" when="${param[2]}"></departures-view>` } ]; - constructor (...args) { - super(...args); + constructor () { + super(); this.outlet = html``; if (!window.location.hash.length) window.location = '#/'; }
diff --git a/src/searchView.js b/src/searchView.js @@ -9,7 +9,7 @@ import { formatPoint } from './formatters.js'; import { newJourneys } from './app_functions.js'; import { CustomDate, sleep, queryBackgroundColor, setThemeColor } from './helpers.js'; -import { baseStyles, helperStyles, flexboxStyles, buttonInputStyles, iconStyles, searchViewStyles } from './styles.js'; +import { searchViewStyles } from './styles.js'; import { settings } from './settings.js'; class SearchView extends BaseView { @@ -29,8 +29,8 @@ class SearchView extends BaseView { searchViewStyles ]; - constructor (...args) { - super(...args); + constructor () { + super(); this.settingsState = settings.getState(); this.date = new CustomDate(); @@ -66,16 +66,19 @@ class SearchView extends BaseView { async connectedCallback() { super.connectedCallback(); - await sleep(200); + await sleep(100); setThemeColor(queryBackgroundColor(document, 'body')); - await this.updateHistoryState(); + this.history = (await db.getHistory(this.settingsState.profile)).slice().reverse(); this._unsubscribeSettingsState = settings.subscribe(state => { this.settingsState = state; this.performUpdate(); }); + + await sleep(500); + this.renderRoot.querySelector('input[name=from]').focus(); } disconnectedCallback () { @@ -90,9 +93,7 @@ class SearchView extends BaseView { async updated (previous) { super.updated(previous); - if (isDevServer) console.info('updated(): ', previous); - - if (previous.has('history') && previous.get('history') === undefined) await this.updateHistoryState() + if (isDevServer) console.info('updated():', previous); if ( previous.has('settingsState') && @@ -100,15 +101,10 @@ class SearchView extends BaseView { previous.get('settingsState').profile !== this.settingsState.profile ) await this.profileChangeHandler(); - if (isDevServer) console.info('settingsState: ', this.settingsState); - } - - async firstUpdated () { - await sleep(500); - this.renderRoot.querySelector('input[name=from]').focus(); + if (isDevServer) console.info('settingsState:', this.settingsState); } - renderContent () { + renderView = () => { return html` <div class="container"> <div class="title flex-center"><h1>${APP_NAME}</h1></div> @@ -175,7 +171,7 @@ class SearchView extends BaseView { </div> <div class="selector rectangular"> - <input type="checkbox" id="noTransfers" name="noTransfers" @change=${this.changeHandler} .checked=${this.noTransfers}> + <input type="checkbox" id="noTransfers" name="noTransfers" @change=${this.changeHandler} .checked=${this.noTransfers}> <label class="icon-seat" for="noTransfers" title="${t('titleNoTransfers')}"></label> </div> @@ -223,10 +219,8 @@ class SearchView extends BaseView { this.requestUpdate(); } - showSettings = () => this.showDialogOverlay('settings', html`<settings-view></settings-view>`); - - updateHistoryState = async () => this.history = (await db.getHistory(this.settingsState.profile)).slice().reverse(); - toggleHistory = () => this.showHistory = !this.showHistory; + showSettings = () => this.showDialogOverlay('settings', html`<settings-view></settings-view>`); + toggleHistory = () => this.showHistory = !this.showHistory; journeysHistoryAction = num => { const element = this.history[num]; @@ -292,6 +286,32 @@ class SearchView extends BaseView { return productIcons[id] || `icon-${id}`; } + focusNextElement = currentElementId => { + switch (currentElementId) { + case 'from': + this.renderRoot.querySelector('input[name=to]').focus(); + + if (this.settingsState.showVia) this.renderRoot.querySelector('input[name=via]').focus(); + break; + + case 'via': + this.renderRoot.querySelector('input[name=to]').focus(); + break; + + case 'to': + this.renderRoot.querySelector('[type=submit]').focus(); + break; + } + } + + setSuggestion = (name, num, pointerType) => { + this.location[name].value = formatPoint(this.location[name].suggestions[num]); + this.location[name].suggestionSelected = this.location[name].suggestions[num]; + this.location[name].suggestionsVisible = false; + this.requestUpdate(); + if (pointerType !== '') this.focusNextElement(name); + } + profileChangeHandler = async () => { [ 'from', 'via','to' ].forEach(name => { this.location[name] = { @@ -362,7 +382,7 @@ class SearchView extends BaseView { params.walkingSpeed = this.settingsState.walkingSpeed; } - if (isDevServer) console.info('submitHandler(): ',params); + if (isDevServer) console.info('submitHandler():',params); this.showLoaderOverlay(); @@ -398,32 +418,6 @@ class SearchView extends BaseView { } } - focusNextElement = currentElementId => { - switch (currentElementId) { - case 'from': - this.renderRoot.querySelector('input[name=to]').focus(); - - if (this.settingsState.showVia) this.renderRoot.querySelector('input[name=via]').focus(); - break; - - case 'via': - this.renderRoot.querySelector('input[name=to]').focus(); - break; - - case 'to': - this.renderRoot.querySelector('[type=submit]').focus(); - break; - } - } - - setSuggestion = (name, num, pointerType) => { - this.location[name].value = formatPoint(this.location[name].suggestions[num]); - this.location[name].suggestionSelected = this.location[name].suggestions[num]; - this.location[name].suggestionsVisible = false; - this.requestUpdate(); - if (pointerType !== '') this.focusNextElement(name); - } - keyupHandler = event => { const name = event.target.name; const value = event.target.value; @@ -508,12 +502,11 @@ class SearchView extends BaseView { const name = event.target.name; const value = event.target.value; - if (name === 'accessibility') this.settingsState.setAccessibility(value); - if (name === 'noTransfers') this.noTransfers = !this.noTransfers; - if (name === 'isArrival') this.isArrival = !this.isArrival; - if (name === 'dateTime') this.date.setDateTime(value); - if (name === 'date') this.date.setDate(value); - if (name === 'time') this.date.setTime(value); + if (name === 'noTransfers') this.noTransfers = !this.noTransfers; + if (name === 'isArrival') this.isArrival = !this.isArrival; + if (name === 'dateTime') this.date.setDateTime(value); + if (name === 'date') this.date.setDate(value); + if (name === 'time') this.date.setTime(value); this.requestUpdate(); }
diff --git a/src/settingsView.js b/src/settingsView.js @@ -7,7 +7,7 @@ import { settings } from './settings.js'; import { initHafasClient, profiles } from './hafasClient.js'; import { clearDataStorage } from './dataStorage.js'; -import { baseStyles, helperStyles, flexboxStyles, buttonInputStyles, settingsViewStyles } from './styles.js'; +import { settingsViewStyles } from './styles.js'; class SettingsView extends BaseView { static styles = [ @@ -19,8 +19,8 @@ class SettingsView extends BaseView { viewState: { state: true }, }; - constructor (...args) { - super(...args); + constructor () { + super(); this.viewState = settings.getState(); }
diff --git a/src/styles.js b/src/styles.js @@ -1,5 +1,4 @@ import baseStyles from './styles/base.css' assert { type: 'css' }; -import helperStyles from './styles/helpers.css' assert { type: 'css' }; import flexboxStyles from './styles/flexbox.css' assert { type: 'css' }; import buttonInputStyles from './styles/buttonInput.css' assert { type: 'css' }; import headerStyles from './styles/header.css' assert { type: 'css' };
diff --git a/src/styles/base.css b/src/styles/base.css @@ -35,6 +35,23 @@ a { } +.invisible { + visibility: hidden !important; +} + +.hidden { + display: none !important; +} + +.flipped { + transform-origin: center center; + transform: rotate(180deg); +} + +.center { + margin: auto; +} + .spinner { margin: calc(50vh - 120px) auto; border: 5px solid rgba(255, 255, 255, .4);
diff --git a/src/styles/helpers.css b/src/styles/helpers.css @@ -1,16 +0,0 @@ -.invisible { - visibility: hidden !important; -} - -.hidden { - display: none !important; -} - -.flipped { - transform-origin: center center; - transform: rotate(180deg); -} - -.center { - margin: auto; -}
diff --git a/src/templates.js b/src/templates.js @@ -5,14 +5,14 @@ import { settingsState } from './settings.js'; import { getDS100byIBNR } from './ds100.js'; import { CustomDate } from './helpers.js'; -export const remarksModal = (element, remarks) => element.showDialogOverlay('remarks', [].concat( +export const remarksModal = (element, remarks) => element.showDialogOverlay('remarks', [ remarks.map(remark => html` <div class="flex-row"> <span class="icon-${remark.type}"></span> <span>${unsafeHTML(remark.text)}</span> </div> `), - [ html`<style>${css` + html`<style>${css` .flex-row { align-items: center; flex-wrap: nowrap; @@ -28,8 +28,8 @@ export const remarksModal = (element, remarks) => element.showDialogOverlay('rem align-self: start; padding-right: .3em; } - `}</style>`] -)); + `}</style>` +]); export const stopTemplate = (profile, stop) => { let stopName = stop.name; @@ -41,7 +41,7 @@ export const stopTemplate = (profile, stop) => { return html`<a class="flex-center" href="#/d/${profile}/${stop.id}">${stopName}</a>`; } -export const platformTemplate = (data) => { +export const platformTemplate = data => { if (data.departurePlatform) { if (data.departurePlatform != data.plannedDeparturePlatform) { return html`<b>${data.departurePlatform}</b>`;
diff --git a/src/tripView.js b/src/tripView.js @@ -9,7 +9,7 @@ import { formatDuration, formatLineAdditionalName, formatLineDisplayName, format import { getHafasClient } from './hafasClient.js'; import { t } from './languages.js'; -import { baseStyles, helperStyles, flexboxStyles, iconStyles, headerStyles, cardStyles, journeyViewStyles } from './styles.js'; +import { headerStyles, cardStyles, journeyViewStyles } from './styles.js'; class TripView extends BaseView { static styles = [ @@ -25,8 +25,8 @@ class TripView extends BaseView { viewState: { state: true }, }; - constructor (...args) { - super(...args); + constructor () { + super(); this.viewState = null; } @@ -36,96 +36,98 @@ class TripView extends BaseView { await sleep(100); setThemeColor(queryBackgroundColor(this.renderRoot, 'header')); + + if (!this.isOffline) await this.updateViewState(); + } + + disconnectedCallback () { + super.disconnectedCallback(); + + this.viewState = null; } + async updated (previous) { super.updated(previous); if (isDevServer) console.info('updated(): ', previous); - if (previous.has('refreshToken')) { - this.viewState = null; - if (!this.isOffline) await this.updateViewState(); - } - if (previous.has('isOffline') && this.viewState === null) await this.updateViewState(); } - renderContent () { - return [ - html` - <div class="header-container"> - <header> - <a id="back" class="icon-back ${history.length !== 1 ? '': 'invisible'}" title="${t('back')}" @click=${() => history.back()}></a> - <div class="container"> - ${this.viewState !== null ? - html`<h3>Trip of ${formatLineDisplayName(this.viewState.trip.line)} to ${this.viewState.trip.direction}</h3>` - : html`<h3>Trip of ...</h3> - `} - </div> - <a class="icon-reload ${this.isUpdating ? 'spinning' : ''} ${!this.isOffline ? '' : 'invisible'}" title="${t("reload")}" @click=${this.updateViewState}></a> - </header> - </div> - `, - - this.viewState !== null ? html` - <div class="container"> - <div class="card"> - <table> - <thead> - <tr> - <td colspan="4"> - <div class="center"> - ${this.viewState.trip.bahnExpertUrl ? html` - <a href="${this.viewState.trip.bahnExpertUrl}">${formatLineDisplayName(this.viewState.trip.line)}${this.viewState.trip.direction ? html` → ${this.viewState.trip.direction}` : ''}</a> - ` : html ` - ${formatLineDisplayName(this.viewState.trip.line)}${this.viewState.trip.direction ? html` → ${this.viewState.trip.direction}` : ''} - `} - ${this.viewState.trip.cancelled ? html`<b class="cancelled-text">${t('cancelled-ride')}</b>` : ''} - ${this.viewState.trip.remarks.length !== 0 ? html` - <a class="link ${this.viewState.trip.remarksIcon}" @click=${() => remarksModal(this, this.viewState.trip.remarks)}></a> - ` : nothing} - </div> - </td> - </tr> - <tr> - <td colspan="4"> - <div class="train-details flex-center"> - ${formatLineAdditionalName(this.viewState.trip.line) ? html`<div>Trip: ${formatLineAdditionalName(this.viewState.trip.line)}</div>` : nothing} - ${this.viewState.trip.line.trainType ? html`<div>Train type: ${this.viewState.trip.line.trainType}</div>` : nothing} - <div class="${!this.viewState.trip.cancelled ? nothing : 'cancelled'}"> - ${t('duration')}: ${formatDuration(this.viewState.trip.arrival - (this.viewState.trip.departure ? this.viewState.trip.departure : this.viewState.trip.plannedDeparture))} ${this.viewState.trip.departure ? '' : ('(' + t('planned') + ')')} - </div> - ${this.viewState.trip.loadFactor ? html`<div>${t("load-"+this.viewState.trip.loadFactor)}</div>` : nothing} + renderView = () => [ + html` + <div class="header-container"> + <header> + <a id="back" class="icon-back ${history.length !== 1 ? '': 'invisible'}" title="${t('back')}" @click=${() => history.back()}></a> + <div class="container"> + ${this.viewState !== null ? + html`<h3>Trip of ${formatLineDisplayName(this.viewState.trip.line)} to ${this.viewState.trip.direction}</h3>` + : html`<h3>Trip of ...</h3> + `} + </div> + <a class="icon-reload ${this.isUpdating ? 'spinning' : ''} ${!this.isOffline ? '' : 'invisible'}" title="${t("reload")}" @click=${this.updateViewState}></a> + </header> + </div> + `, + + this.viewState !== null ? html` + <div class="container"> + <div class="card"> + <table> + <thead> + <tr> + <td colspan="4"> + <div class="center"> + ${this.viewState.trip.bahnExpertUrl ? html` + <a href="${this.viewState.trip.bahnExpertUrl}">${formatLineDisplayName(this.viewState.trip.line)}${this.viewState.trip.direction ? html` → ${this.viewState.trip.direction}` : ''}</a> + ` : html ` + ${formatLineDisplayName(this.viewState.trip.line)}${this.viewState.trip.direction ? html` → ${this.viewState.trip.direction}` : ''} + `} + ${this.viewState.trip.cancelled ? html`<b class="cancelled-text">${t('cancelled-ride')}</b>` : ''} + ${this.viewState.trip.remarks.length !== 0 ? html` + <a class="link ${this.viewState.trip.remarksIcon}" @click=${() => remarksModal(this, this.viewState.trip.remarks)}></a> + ` : nothing} + </div> + </td> + </tr> + <tr> + <td colspan="4"> + <div class="train-details flex-center"> + ${formatLineAdditionalName(this.viewState.trip.line) ? html`<div>Trip: ${formatLineAdditionalName(this.viewState.trip.line)}</div>` : nothing} + ${this.viewState.trip.line.trainType ? html`<div>Train type: ${this.viewState.trip.line.trainType}</div>` : nothing} + <div class="${!this.viewState.trip.cancelled ? nothing : 'cancelled'}"> + ${t('duration')}: ${formatDuration(this.viewState.trip.arrival - (this.viewState.trip.departure ? this.viewState.trip.departure : this.viewState.trip.plannedDeparture))} ${this.viewState.trip.departure ? '' : ('(' + t('planned') + ')')} </div> - </td> - </tr> - <tr> - <th>${t('arrival')}</th> - <th>${t('departure')}</th> - <th class="station">${t('station')}</th> - <th>${t('platform')}</th> + ${this.viewState.trip.loadFactor ? html`<div>${t("load-"+this.viewState.trip.loadFactor)}</div>` : nothing} + </div> + </td> + </tr> + <tr> + <th>${t('arrival')}</th> + <th>${t('departure')}</th> + <th class="station">${t('station')}</th> + <th>${t('platform')}</th> + </tr> + </thead> + <tbody> + ${(this.viewState.trip.stopovers || []).map(stop => html` + <tr class="${stop.cancelled ? 'cancelled' : ''}"> + <td>${timeTemplate(stop, 'arrival')}</td> + <td>${timeTemplate(stop, 'departure')}</td> + <td>${stopTemplate(this.profile, stop.stop)}</td> + <td>${platformTemplate(stop)}</td> </tr> - </thead> - <tbody> - ${(this.viewState.trip.stopovers || []).map(stop => html` - <tr class="${stop.cancelled ? 'cancelled' : ''}"> - <td>${timeTemplate(stop, 'arrival')}</td> - <td>${timeTemplate(stop, 'departure')}</td> - <td>${stopTemplate(this.profile, stop.stop)}</td> - <td>${platformTemplate(stop)}</td> - </tr> - `)} - </tbody> - </table> - </div> + `)} + </tbody> + </table> </div> - <footer-component></footer-component> - ` : !this.isOffline ? - html`<div class="spinner"></div>` - : html`<div class="offline"></div>` - ]; - } + </div> + <footer-component></footer-component> + ` : !this.isOffline ? + html`<div class="spinner"></div>` + : html`<div class="offline"></div>` + ]; updateViewState = async () => { if (this.isOffline !== false) return;