commit e72c4f2fc34ab7e56603340c395ad14d79b7bf03
parent 8bde1ff49f98fd2f6c886902b5f4d63f30aaa26a
Author: Katja (ctucx) <git@ctu.cx>
Date: Mon, 21 Apr 2025 15:10:14 +0200
parent 8bde1ff49f98fd2f6c886902b5f4d63f30aaa26a
Author: Katja (ctucx) <git@ctu.cx>
Date: Mon, 21 Apr 2025 15:10:14 +0200
improve error handling, dont access `window` in `willUpdate` phase
5 files changed, 68 insertions(+), 31 deletions(-)
diff --git a/src/baseView.js b/src/baseView.js @@ -1,4 +1,5 @@ import { LitElement, html, nothing } from 'lit'; +import { when } from 'lit/directives/when.js'; import { choose } from 'lit/directives/choose.js'; import { t } from './translate.js'; @@ -27,16 +28,17 @@ export class BaseView extends LitElement { this.isUpdating = false; this.overlayState = { - type: 'plain', - visible: false, - content: null, - title: null, + type: 'plain', + visible: false, + content: null, }; } connectedCallback () { super.connectedCallback(); + this.hideOverlay(); + window.addEventListener('online', this.connectionHandler); window.addEventListener('offline', this.connectionHandler); } @@ -54,24 +56,27 @@ export class BaseView extends LitElement { 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); + showLoaderOverlay = () => this.showOverlay('loader'); + showDialogOverlay = (title, body) => this.showOverlay('dialog', { title, body }); + showAlertOverlay = (message, callback) => this.showOverlay('alert', { message, callback }); + showSelectOverlay = items => this.showOverlay('select', items); hideOverlay = () => { - this.overlayState.visible = false; - this.requestUpdate(); + this.overlayState = { + type: 'plain', + visible: false, + content: null, + }; }; - showOverlay = (type, content, title) => { + showOverlay = (type, content) => { this.overlayState = { - type, content, title, + type, content, visible: true, } }; - overlayHandler = event => event.target === event.currentTarget && this.overlayState.type !== 'loader' ? this.hideOverlay() : true; + overlayHandler = event => event.target === event.currentTarget && ![ 'loader', 'alert' ].includes(this.overlayState.type) ? this.hideOverlay() : true; keyClickHandler = event => { if ([ 'Enter', 'Space' ].includes(event.code)) { event.preventDefault(); @@ -89,10 +94,10 @@ export class BaseView extends LitElement { [ 'dialog', () => html` <div class="modal dialog"> <div class="header flex-row"> - <h4>${t(this.overlayState.title)}</h4> + <h4>${t(this.overlayState.content.title)}</h4> <div class="icon-close" title="${t('close')}" @click=${this.hideOverlay}></div> </div> - <div class="body">${this.overlayState.content}</div> + <div class="body">${this.overlayState.content.body}</div> </div> ` ], [ 'select', () => html` @@ -103,7 +108,12 @@ export class BaseView extends LitElement { ` ], [ 'alert', () => html` <div class="modal alert" style="overflow:auto"> - ${this.overlayState.content}<br><button class="color" style="float:right" @click=${this.hideOverlay}>OK</button> + ${this.overlayState.content.message}<br><button class="color" style="float:right" + @click=${when( + !this.overlayState.content.callback, + () => this.hideOverlay, + () => this.overlayState.content.callback + )}>OK</button> </div> ` ], ]); @@ -111,7 +121,10 @@ export class BaseView extends LitElement { return [ this.renderView(), - !this.overlayState.visible ? nothing : html`<div class="overlay flex-center" @click=${this.overlayHandler}>${overlayContent}</div>` + when( + this.overlayState.visible, + () => html`<div class="overlay flex-center" @click=${this.overlayHandler}>${overlayContent}</div>` + ) ]; };
diff --git a/src/departuresView.js b/src/departuresView.js @@ -41,7 +41,7 @@ class DeparturesView extends BaseView { async willUpdate (previous) { if (previous.has('stopId')) this.viewState = null; - if (!this.viewState) await this.updateViewState(); + if (!this.viewState && !this.overlayState.visible) await this.updateViewState(); } updated (previous) { @@ -74,7 +74,12 @@ class DeparturesView extends BaseView { if (isDevServer) console.info('DeparturesView(viewState):', this.viewState); } catch(e) { - this.showAlertOverlay(e.toString()); + this.showAlertOverlay( + e.toString(), + () => { + window.location = '#/'; + } + ); console.error(e); } this.isUpdating = false;
diff --git a/src/journeyView.js b/src/journeyView.js @@ -59,7 +59,7 @@ class JourneyView extends BaseView { async willUpdate (previous) { if (previous.has('refreshToken')) this.viewState = null; - if (!this.viewState) await this.updateViewState(); + if (!this.viewState && !this.overlayState.visible) await this.updateViewState(); } updated (previous) { @@ -257,7 +257,12 @@ class JourneyView extends BaseView { if (isDevServer) console.info('JourneyView(viewState):', this.viewState); } catch(e) { - this.showAlertOverlay(e.toString()); + this.showAlertOverlay( + e.toString(), + () => { + window.location = '#/'; + } + ); console.error(e); } this.isUpdating = false;
diff --git a/src/journeysView.js b/src/journeysView.js @@ -61,17 +61,17 @@ export class JourneysView extends JourneysCanvas { } async willUpdate (previous) { - if (previous.has('slug')) this.viewState = null; + if (previous.has('slug')) { + this.resetCanvasPosition(); + this.viewState = null; + } 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 (!this.viewState) { - this.resetCanvasPosition(); - await this.updateViewState(); - } + if (!this.viewState && !this.overlayState.visible) await this.updateViewState(); if (this.mode === 'canvas') { this.connectCanvas(); @@ -189,8 +189,12 @@ export class JourneysView extends JourneysCanvas { let viewState = await getJourneys(this.slug); if (!viewState) { - this.showAlertOverlay(html`journeys overview id invalid. <br>journeys overview links can not be shared across devices.`); - window.location = '#/'; + this.showAlertOverlay( + html`journeys overview id invalid. <br>journeys overview links can not be shared across devices.`, + () => { + window.location = '#/'; + } + ); return; } @@ -227,7 +231,12 @@ export class JourneysView extends JourneysCanvas { this.viewState = viewState; if (isDevServer) console.info('JourneysView(viewState):', this.viewState); } catch(e) { - this.showAlertOverlay(e.toString()); + this.showAlertOverlay( + e.toString(), + () => { + window.location = '#/'; + } + ); console.error(e); } };
diff --git a/src/tripView.js b/src/tripView.js @@ -43,7 +43,7 @@ class TripView extends BaseView { async willUpdate (previous) { if (previous.has('stopId')) this.viewState = null; - if (!this.viewState) await this.updateViewState(); + if (!this.viewState && !this.overlayState.visible) await this.updateViewState(); } updated (previous) { @@ -91,7 +91,12 @@ class TripView extends BaseView { if (isDevServer) console.info('TripView(viewState): ',this.viewState); } catch(e) { - this.showAlertOverlay(e.toString()); + this.showAlertOverlay( + e.toString(), + () => { + window.location = '#/'; + } + ); console.error(e); } this.isUpdating = false;