diff --git a/src/main/css/main.css b/src/main/css/main.css index 3733e76..51defe2 100644 --- a/src/main/css/main.css +++ b/src/main/css/main.css @@ -99,12 +99,12 @@ summary { /*** * Messages, errors, etc. **/ -#messages { +#errors, #messages { width: 100%; text-align: center; } -.messageInner { +.errorInner, .messageInner { display: inline-block; } diff --git a/src/main/index.html b/src/main/index.html index 967d970..5b5787f 100644 --- a/src/main/index.html +++ b/src/main/index.html @@ -102,6 +102,7 @@

+

diff --git a/src/main/js/DOM.js b/src/main/js/DOM.js index e2a1755..cab5b2b 100644 --- a/src/main/js/DOM.js +++ b/src/main/js/DOM.js @@ -80,6 +80,55 @@ export class ValidatableInput { } } +/** + * Interacts with the DOM to delegate errors to the user. + */ +export class ErrorHandler { + /** + * Constructs a new `ErrorHandler`, inserting relevant new elements into the DOM to interact with. + * + * @param parent {HTMLElement} the element to insert elements into + * @param [id] {string} the id of the div containing the errors + */ + constructor(parent, id) { + this._mainDiv = document.createElement("div"); + this._mainDiv.classList.add("hidden"); + this._mainDiv.classList.add("errorInner"); + parent.appendChild(this._mainDiv); + } + + + /** + * Handles the displaying of the given error. + * + * @param [level] {"warning"|"error"|null} the level of message to display, determines the style of the text + * @param [message] {*} the message to display + * @returns {ErrorHandler} this `ErrorHandler` + */ + handle(level, message) { + this._mainDiv.classList.remove("hidden"); + + const errorSpan = document.createElement("p"); + errorSpan.innerText = message; + if (level !== null) errorSpan.classList.add(level); + this._mainDiv.appendChild(errorSpan); + + return this; + } + + /** + * Clears all errors from the DOM. + * + * @returns {ErrorHandler} this `ErrorHandler` + */ + clear() { + this._mainDiv.classList.add("hidden"); + this._mainDiv.innerHTML = ""; + + return this; + } +} + /** * Interacts with the DOM to delegate messages to the user. */ @@ -90,7 +139,7 @@ export class MessageHandler { * @param parent {HTMLElement} the element to insert elements into * @param [id] {string} the id of the div containing the message */ - constructor(parent, id) { + constructor(parent) { this._mainDiv = document.createElement("div"); this._mainDiv.classList.add("hidden"); this._mainDiv.classList.add("messageInner"); @@ -105,8 +154,6 @@ export class MessageHandler { this._mainDiv.appendChild(this._spacing); this._textSpan = document.createElement("span"); - if (id !== undefined) - this._textSpan.id = id; this._mainDiv.appendChild(this._textSpan); this._currentLevel = undefined; diff --git a/src/main/js/Main.js b/src/main/js/Main.js index 34192af..1197c00 100644 --- a/src/main/js/Main.js +++ b/src/main/js/Main.js @@ -1,6 +1,6 @@ // noinspection JSUnresolvedVariable const {$, doAfterLoad, footer, header, nav} = window.fwdekker; -import {InterlangTable, MessageHandler, ValidatableInput} from "./DOM"; +import {ErrorHandler, InterlangTable, MessageHandler, ValidatableInput} from "./DOM"; import {discoverNetwork, InterlangNetwork, MediaWiki, MediaWikiManager} from "./MediaWiki"; @@ -60,6 +60,7 @@ doAfterLoad(async () => { }); const checkButton = $("#check"); + const errorHandler = new ErrorHandler($("#errors")); const messageHandler = new MessageHandler($("#messages")) .setCallback((level, message) => { if (level === "error") console.error(message); @@ -75,6 +76,7 @@ doAfterLoad(async () => { // Clean up urlInput.showBlank(); articleInput.showBlank(); + errorHandler.clear(); messageHandler.clear(); const oldTable = $("#networkTable"); @@ -104,7 +106,12 @@ doAfterLoad(async () => { } // Discover - discoverNetwork(mwm, articleInput.getValue(), it => messageHandler.handle("progress", it)) + discoverNetwork( + mwm, + articleInput.getValue(), + (level, message) => errorHandler.handle(level, message), + it => messageHandler.handle("progress", it) + ) .then(it => new InterlangNetwork(it.pages, it.redirects)) .then(network => { messageHandler.handle("progress", "Creating table"); diff --git a/src/main/js/MediaWiki.js b/src/main/js/MediaWiki.js index 1659726..33502f2 100644 --- a/src/main/js/MediaWiki.js +++ b/src/main/js/MediaWiki.js @@ -353,7 +353,10 @@ export class MediaWiki { const url = this.origin + this.apiPath + "?format=json&origin=*&" + new URLSearchParams(params).toString(); console.debug(`Requesting from ${this.origin}${this.apiPath} with params`, params, "at", url); return fetch(url) - .then(it => it.json()) + .then(response => { + if (!response.ok) throw new Error(couldNotConnectMessage); + return response.json(); + }) .catch(() => { throw new Error(couldNotConnectMessage); }); @@ -560,12 +563,13 @@ export class MediaWikiManager { * * @param mwm {MediaWikiManager} the manager to use for caching and resolving pages * @param title {string} the title of the page to start traversing at + * @param [errorCb] {function("error"|"warning"|null, *): void} a function handling errors and warnings * @param [progressCb] {function(*): void} a function handling progress updates * @returns network {Object} the discovered network * @returns network.pages {Page[]} the pages in the network * @returns network.redirects {Redirect[]} the redirects in the network */ -export const discoverNetwork = async function (mwm, title, progressCb) { +export const discoverNetwork = async function(mwm, title, errorCb, progressCb) { const pages = []; const redirects = []; @@ -585,8 +589,10 @@ export const discoverNetwork = async function (mwm, title, progressCb) { pages.push(new Page(mwm.getArticlePath(next), next, [], false)); if (history.length === 1) throw new Error(couldNotConnectMessage); - else + else { + errorCb("warning", `Could not connect to the wiki for '${next.lang}'. Maybe the wiki no longer exists?`); continue; + } } next = nextMw.normalize(next);