commit aaf74e860006b10359634644961c518ee4070d94
parent 1ccd8603fe332643371f4d49cd987e2e8c7d3609
Author: Katja (ctucx) <git@ctu.cx>
Date: Sun, 20 Apr 2025 19:07:58 +0200
parent 1ccd8603fe332643371f4d49cd987e2e8c7d3609
Author: Katja (ctucx) <git@ctu.cx>
Date: Sun, 20 Apr 2025 19:07:58 +0200
improve state handling
8 files changed, 124 insertions(+), 103 deletions(-)
diff --git a/src/baseView.js b/src/baseView.js @@ -36,26 +36,34 @@ export class BaseView extends LitElement { connectedCallback () { super.connectedCallback(); + window.addEventListener('online', this.connectionHandler); window.addEventListener('offline', this.connectionHandler); } disconnectedCallback () { super.disconnectedCallback(); + window.removeEventListener('online', this.connectionHandler); window.removeEventListener('offline', this.connectionHandler); } + updated () { + if (isDevServer) console.info('BaseView(overlayState):', this.overlayState); + } + connectionHandler = event => { this.isOffline = event.type === 'offline'; }; showLoaderOverlay = () => this.showOverlay('loader'); showDialogOverlay = (title, body) => this.showOverlay('dialog', body, title); showAlertOverlay = text => this.showOverlay('alert', text); showSelectOverlay = items => this.showOverlay('select', items); + hideOverlay = () => { this.overlayState.visible = false; this.requestUpdate(); }; + showOverlay = (type, content, title) => { this.overlayState = { type, content, title, @@ -71,7 +79,7 @@ export class BaseView extends LitElement { } }; - render () { + render = () => { let overlayContent; if (this.overlayState.visible) { @@ -105,5 +113,6 @@ export class BaseView extends LitElement { this.renderView(), !this.overlayState.visible ? nothing : html`<div class="overlay flex-center" @click=${this.overlayHandler}>${overlayContent}</div>` ]; - } + }; + }
diff --git a/src/departuresView.js b/src/departuresView.js @@ -32,28 +32,24 @@ class DeparturesView extends BaseView { this.viewState = null; } - 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 willUpdate (previous) { + if (previous.has('stopId')) this.viewState = null; - async updated (previous) { - super.updated(previous); + if (!this.viewState) await this.updateViewState(); + } + + updated (previous) { + super.updated(); - if (isDevServer) console.info('updated(): ', previous); + if (isDevServer) console.info('DeparturesView(updated):', previous); - if (previous.has('isOffline') && this.viewState === null) await this.updateViewState(); + setThemeColor(queryBackgroundColor(this.renderRoot, 'header')); } updateViewState = async () => { @@ -76,7 +72,7 @@ class DeparturesView extends BaseView { departures }; - if (isDevServer) console.info('viewState:', this.viewState); + if (isDevServer) console.info('DeparturesView(viewState):', this.viewState); } catch(e) { this.showAlertOverlay(e.toString()); console.error(e); @@ -144,6 +140,7 @@ class DeparturesView extends BaseView { ` ) ]; + } customElements.define('departures-view', DeparturesView);
diff --git a/src/journeyView.js b/src/journeyView.js @@ -37,13 +37,8 @@ class JourneyView extends BaseView { this.settingsState = settings.getState(); } - async connectedCallback () { + connectedCallback () { super.connectedCallback(); - await sleep(100); - - setThemeColor(queryBackgroundColor(this.renderRoot, 'header')); - - await this.updateViewState(); this._unsubscribeSettingsState = settings.subscribe(state => { this.settingsState = state; @@ -61,6 +56,20 @@ class JourneyView extends BaseView { } } + async willUpdate (previous) { + if (previous.has('refreshToken')) this.viewState = null; + + if (!this.viewState) await this.updateViewState(); + } + + updated (previous) { + super.updated(); + + if (isDevServer) console.info('JourneyView(updated):', previous); + + setThemeColor(queryBackgroundColor(this.renderRoot, 'header')); + } + renderView = () => [ html` <div class="header-container"> @@ -173,7 +182,7 @@ class JourneyView extends BaseView { </div> `; } - } + }; updateViewState = async viewState => { this.isUpdating = true; @@ -246,13 +255,13 @@ class JourneyView extends BaseView { } } - if (isDevServer) console.info('viewState:', this.viewState); + if (isDevServer) console.info('JourneyView(viewState):', this.viewState); } catch(e) { this.showAlertOverlay(e.toString()); console.error(e); } this.isUpdating = false; - } + }; refreshJourney = async () => { if (this.isOffline !== false) return; @@ -267,7 +276,7 @@ class JourneyView extends BaseView { console.error(e); } this.isUpdating = false; - } + }; moreModal = async () => { const options = [ @@ -288,7 +297,7 @@ class JourneyView extends BaseView { await navigator.clipboard.writeText(window.location); this.showAlertOverlay('URL has been copied to clipboard.'); } - } + }; ticketsAction = async () => { try { @@ -367,6 +376,7 @@ class JourneyView extends BaseView { window.location = URL.createObjectURL(file); }; + } customElements.define('journey-view', JourneyView);
diff --git a/src/journeysCanvas.js b/src/journeysCanvas.js @@ -71,8 +71,7 @@ export class JourneysCanvas extends BaseView { } updated (previous) { - super.updated(previous); - if (isDevServer) console.info('canvasState: ', this.canvasState); + if (isDevServer) console.info('JourneysCanvas(canvasState):', this.canvasState); } resetCanvasPosition = () => { @@ -82,6 +81,8 @@ export class JourneysCanvas extends BaseView { getCanvas = () => html`<canvas @mousedown=${this.mouseDownHandler} @touchstart=${this.mouseDownHandler} ${ref(this.canvasRef)}></canvas>`; connectCanvas = () => { + this.resizeHandler(); + if (!this.canvasState.handlersConnected) { window.addEventListener('mouseup', this.mouseUpHandler); window.addEventListener('touchend', this.mouseUpHandler); @@ -91,7 +92,6 @@ export class JourneysCanvas extends BaseView { window.addEventListener('zoom', this.resizeHandler); this.canvasState.handlersConnected = true; } - this.resizeHandler(); }; disconnectCanvas = () => { @@ -107,7 +107,7 @@ export class JourneysCanvas extends BaseView { resizeHandler = () => { const canvasElement = this.canvasRef.value; - if (canvasElement === undefined) return true; + if (!canvasElement) return true; const canvasContext = canvasElement.getContext('2d'); @@ -222,6 +222,7 @@ export class JourneysCanvas extends BaseView { if (this.isOffline !== false) return; if (!['db', 'rmv'].includes(this.viewState.profile)) return; + if (isDevServer) console.info('JourneysCanvas(getCoachSequences): fetch start'); this.isUpdating = true; for (const journey of this.viewState.journeys) { for (const leg of journey.legs) { @@ -236,6 +237,7 @@ export class JourneysCanvas extends BaseView { } } this.isUpdating = false; + if (isDevServer) console.info('JourneysCanvas(getCoachSequences): fetch end'); }; getTrainTypeTexts = leg => { @@ -250,7 +252,7 @@ export class JourneysCanvas extends BaseView { renderCanvas = () => { const canvasElement = this.canvasRef.value; - if (canvasElement === undefined) return true; + if (!canvasElement) return true; const canvasContext = canvasElement.getContext('2d');
diff --git a/src/journeysView.js b/src/journeysView.js @@ -37,13 +37,9 @@ export class JourneysView extends JourneysCanvas { this.settingsState = settings.getState(); } - async connectedCallback() { + connectedCallback () { super.connectedCallback(); - await sleep(100); - setThemeColor(queryBackgroundColor(this.renderRoot, 'header')); - - if (this.viewState === null) await this.updateViewState(); if (this.mode === 'canvas') this.connectCanvas(); this._unsubscribeSettingsState = settings.subscribe(state => { @@ -64,31 +60,36 @@ export class JourneysView extends JourneysCanvas { } } - async updated (previous) { - await super.updated(previous); - if (isDevServer) console.info('updated(): ', previous); + async willUpdate (previous) { + if (previous.has('slug')) this.viewState = null; - if (previous.has('mode') && this.settingsState.journeysViewMode !== this.mode) this.settingsState.setJourneysViewMode(this.mode); + if (previous.has('mode')) { + if (previous.get('mode') === 'canvas' && this.mode !== 'canvas') this.disconnectCanvas(); + if (this.settingsState.journeysViewMode !== this.mode) this.settingsState.setJourneysViewMode(this.mode); + } - if (previous.has('slug')) { + if (!this.viewState) { this.resetCanvasPosition(); await this.updateViewState(); } - if (previous.has('mode')) { - if (this.mode === 'canvas') this.connectCanvas(); - if (previous.get('mode') === 'canvas' && this.mode !== 'canvas') this.disconnectCanvas(); - } - if (this.mode === 'canvas') { this.connectCanvas(); - if (previous.has('viewState') && this.viewState !== null) { - this.renderCanvas(); - if (previous.get('viewState') !== undefined) await this.getCoachSequences(); + + if (previous.has('viewState') && this.viewState) { + if (previous.get('viewState') !== null) await this.getCoachSequences(); } } } + updated (previous) { + super.updated(); + + if (isDevServer) console.info('JourneysView(updated):', previous); + + setThemeColor(queryBackgroundColor(this.renderRoot, 'header')); + } + renderView = () => [ html` <div class="header-container"> @@ -110,7 +111,8 @@ export class JourneysView extends JourneysCanvas { </a> </div> </div> - <a class="icon-reload ${classMap({ spinning: this.isUpdating, invisible: this.isOffline })}" title=${t("refresh")} @click=${this.refreshJourneys}></a> + <a class="icon-reload ${classMap({ spinning: this.isUpdating, invisible: this.isOffline })}" tabindex=0 title=${t("refresh")} + @keydown=${this.keyClickHandler} @click=${this.refreshJourneys}></a> </header> </div> `, @@ -123,7 +125,8 @@ export class JourneysView extends JourneysCanvas { <div class="container"> ${when( this.viewState.earlierRef, - () => html`<a class="arrowButton icon-arrow flipped flex-center" title="${t('earlier')}" @click=${() => this.moreJourneys('earlier')}></a>` + () => html`<div tabindex=0 class="arrowButton icon-arrow flipped flex-center" title="${t('earlier')}" + @keydown=${this.keyClickHandler} @click=${() => this.moreJourneys('earlier')}></a>` )} <div class="table" style="grid-template-columns: repeat(${this.settingsState.showPrices && this.viewState.profile === 'db' ? '6' : '5'}, 1fr) .3fr"> @@ -144,7 +147,8 @@ export class JourneysView extends JourneysCanvas { ${when( this.viewState.laterRef, - () => html`<a class="arrowButton icon-arrow flex-center" title="${t('later')}" @click=${() => this.moreJourneys('later')}></a>` + () => html`<a tabindex=0 class="arrowButton icon-arrow flex-center" title="${t('later')}" + @keydown=${this.keyClickHandler} @click=${() => this.moreJourneys('later')}></a>` )} </div> <footer-component></footer-component> @@ -159,7 +163,7 @@ export class JourneysView extends JourneysCanvas { return html` <a class="row" href="#/j/${this.viewState.profile}/${journey.refreshToken}"> - <span class=${!journey.cancelled ? nothing : 'cancelled'}>${timeTemplate(firstLeg, 'departure')}</span> + <span class=${classMap({ cancelled: journey.cancelled })}>${timeTemplate(firstLeg, 'departure')}</span> ${when( !journey.cancelled, () => html`<span>${timeTemplate(lastLeg, 'arrival')}</span>`, @@ -178,7 +182,7 @@ export class JourneysView extends JourneysCanvas { <span><i class="icon-arrow" style="transform:rotate(-90deg)"></i></span> </a> `; - } + }; updateViewState = async () => { try { @@ -221,12 +225,12 @@ export class JourneysView extends JourneysCanvas { }); this.viewState = viewState; - if (isDevServer) console.info('viewState: ', this.viewState); + if (isDevServer) console.info('JourneysView(viewState):', this.viewState); } catch(e) { this.showAlertOverlay(e.toString()); console.error(e); } - } + }; refreshJourneys = async () => { if (this.isOffline || this.isUpdating) return; @@ -242,7 +246,7 @@ export class JourneysView extends JourneysCanvas { this.showAlertOverlay(e.toString()); console.error(e); } - } + }; moreJourneys = async mode => { if (this.isOffline) { @@ -263,7 +267,8 @@ export class JourneysView extends JourneysCanvas { console.error(e); } this.hideOverlay(); - } + }; + } customElements.define('journeys-view', JourneysView);
diff --git a/src/searchView.js b/src/searchView.js @@ -66,11 +66,8 @@ class SearchView extends BaseView { }; } - async connectedCallback() { + async connectedCallback () { super.connectedCallback(); - await sleep(100); - - setThemeColor(queryBackgroundColor(document, 'body')); this.history = (await db.getHistory(this.settingsState.profile)).slice().reverse(); @@ -92,18 +89,21 @@ class SearchView extends BaseView { } } - async updated (previous) { - super.updated(previous); - - if (isDevServer) console.info('updated():', previous); - + async willUpdate (previous) { if ( previous.has('settingsState') && previous.get('settingsState') !== undefined && previous.get('settingsState').profile !== this.settingsState.profile ) await this.profileChangeHandler(); + } - if (isDevServer) console.info('settingsState:', this.settingsState); + updated (previous) { + super.updated(); + + if (isDevServer) console.info('SearchView(updated):', previous); + if (isDevServer) console.info('SearchView(settingsState):', this.settingsState); + + setThemeColor(queryBackgroundColor(document, 'body')); } renderView = () => { @@ -225,17 +225,17 @@ class SearchView extends BaseView { <footer-component></footer-component> </div> `; - } + }; swapFromTo = () => { this.location.from = [this.location.to, this.location.to = this.location.from][0]; this.requestUpdate(); - } + }; resetDate = () => { this.date = new CustomDate(); this.requestUpdate(); - } + }; showSettings = () => this.showDialogOverlay('settings', html`<settings-view></settings-view>`); toggleHistory = () => this.showHistory = !this.showHistory; @@ -256,7 +256,7 @@ class SearchView extends BaseView { } this.showSelectOverlay(options); - } + }; setFromHistory = async id => { const entry = await db.getHistoryEntry(id); @@ -271,7 +271,7 @@ class SearchView extends BaseView { }); this.requestUpdate(); - } + }; iconForProduct = id => { const productIcons = { @@ -309,7 +309,7 @@ class SearchView extends BaseView { }; return productIcons[id] || `icon-${id}`; - } + }; focusNextElement = currentElementId => { switch (currentElementId) { @@ -327,7 +327,7 @@ class SearchView extends BaseView { this.renderRoot.querySelector('[type=submit]').focus(); break; } - } + }; setSuggestion = (name, num, pointerType) => { this.location[name].value = formatPoint(this.location[name].suggestions[num]); @@ -335,7 +335,7 @@ class SearchView extends BaseView { this.location[name].suggestionsVisible = false; this.requestUpdate(); if (pointerType !== '') this.focusNextElement(name); - } + }; profileChangeHandler = async () => { [ 'from', 'via','to' ].forEach(name => { @@ -349,7 +349,7 @@ class SearchView extends BaseView { }); this.history = (await db.getHistory(this.settingsState.profile)).slice().reverse(); - } + }; submitHandler = async event => { event.preventDefault(); @@ -420,17 +420,17 @@ class SearchView extends BaseView { this.showAlertOverlay(e.toString()); console.error(e); } - } + }; - mouseOverHandler (name) { this.location[name].suggestionsFocused = true; } - mouseOutHandler (name) { this.location[name].suggestionsFocused = false; } + mouseOverHandler = name => { this.location[name].suggestionsFocused = true; }; + mouseOutHandler = name => { this.location[name].suggestionsFocused = false; }; focusHandler = event => { const name = event.target.name; this.location[name].suggestionsVisible = true; this.requestUpdate(); - } + }; blurHandler = event => { const name = event.target.name; @@ -439,7 +439,7 @@ class SearchView extends BaseView { this.location[name].suggestionsVisible = false; this.requestUpdate(); } - } + }; keyupHandler = event => { const name = event.target.name; @@ -497,7 +497,7 @@ class SearchView extends BaseView { } this.requestUpdate(); - } + }; inputHandler = async event => { const name = event.target.name; @@ -521,7 +521,7 @@ class SearchView extends BaseView { this.requestUpdate(); }; - } + }; changeHandler = event => { const name = event.target.name; @@ -534,7 +534,8 @@ class SearchView extends BaseView { if (name === 'time') this.date.setTime(value); this.requestUpdate(); - } + }; + } customElements.define('search-view', SearchView);
diff --git a/src/settingsView.js b/src/settingsView.js @@ -23,6 +23,7 @@ class SettingsView extends BaseView { constructor () { super(); + this.viewState = settings.getState(); } @@ -44,7 +45,6 @@ class SettingsView extends BaseView { } } - render = () => [ html` <div class="flex-row">
diff --git a/src/tripView.js b/src/tripView.js @@ -31,16 +31,7 @@ class TripView extends BaseView { constructor () { super(); - this.viewState = null; - } - - async connectedCallback () { - super.connectedCallback(); - await sleep(100); - - setThemeColor(queryBackgroundColor(this.renderRoot, 'header')); - - if (!this.isOffline) await this.updateViewState(); + this.viewState = null; } disconnectedCallback () { @@ -49,13 +40,18 @@ class TripView extends BaseView { this.viewState = null; } + async willUpdate (previous) { + if (previous.has('stopId')) this.viewState = null; - async updated (previous) { - super.updated(previous); + if (!this.viewState) await this.updateViewState(); + } + + updated (previous) { + super.updated(); - if (isDevServer) console.info('updated(): ', previous); + if (isDevServer) console.info('TripView(updated): ', previous); - if (previous.has('isOffline') && this.viewState === null) await this.updateViewState(); + setThemeColor(queryBackgroundColor(this.renderRoot, 'header')); } updateViewState = async () => { @@ -93,13 +89,13 @@ class TripView extends BaseView { this.requestUpdate(); } - if (isDevServer) console.info('viewState: ',this.viewState); + if (isDevServer) console.info('TripView(viewState): ',this.viewState); } catch(e) { this.showAlertOverlay(e.toString()); console.error(e); } this.isUpdating = false; - } + }; renderView = () => [ html` @@ -212,6 +208,7 @@ class TripView extends BaseView { ` ) ]; + } customElements.define('trip-view', TripView);