-
-
-
+
-
-
-
- About
-
- ⎋ Interlanguage links
- allow wikis to tell users where to find translations of articles.
- Without the
- ⎋ interlanguage extension,
- each translation is responsible for maintaining its own outgoing links.
- As the number of translations grows, the network of links becomes more complex, and the
- number of errors grows.
-
- The Interlanguage Checker traverses the network of interlanguage links starting from a
- given article and shows you that network in a table.
- If there are missing or incorrect links, you can quickly spot them and fix
- them.
-
- To use the tool, you should enter the link to the
- ⎋ API of the wiki you want to
- check.
- For Wikimedia wikis, this is https://<example.org>/w/api.php
.
- For Fandom wikis, this is https://<wiki>.fandom.com/api.php
.
-
- If the application refuses to connect to the API and you are certain the URL is correct,
- make sure that you allow scripts to be executed from the API you have entered by checking the
- configuration of your tracking blockers.
- These external scripts are necessary to provide support to older wikis that rely on
- ⎋ JSONP requests to interact with the
- API.
-
- If you need help, have a question, or found a bug, please
- ⎋ open an issue
- or ⎋ leave a talk message.
-
-
-
-
-
+
+
+
+ About
+
+
+ Interlanguage links
+ allow wikis to tell users where to find translations of articles.
+ Without the
+
+ interlanguage extension,
+ each translation is responsible for maintaining its own outgoing links.
+ As the number of translations grows, the network of links becomes more complex, and the
+ number of errors grows.
+
+
+ The Interlanguage Checker traverses the network of interlanguage links starting from a
+ given article and shows you that network in a table.
+ If there are missing or incorrect links, you can quickly spot them and fix them.
+
+
+ To use the tool, you should enter the link to the
+ API of the wiki you want
+ to check.
+ For Wikimedia wikis, this is https://<example.org>/w/api.php
.
+ For Fandom wikis, this is https://<wiki>.fandom.com/api.php
.
+
+
+ If the application refuses to connect to the API and you are certain the URL is correct,
+ make sure that you allow scripts to be executed from the API you have entered by checking the
+ configuration of your tracking blockers.
+ These external scripts are necessary to provide support to older wikis that rely on
+ JSONP requests to interact with
+ the API.
+
+
+ If you need help, have a question, or found a bug, please
+
+ open an issue
+ or
+
+ leave a talk message.
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
-
-
+
diff --git a/src/main/js/DOM.ts b/src/main/js/DOM.ts
deleted file mode 100644
index c07ef3e..0000000
--- a/src/main/js/DOM.ts
+++ /dev/null
@@ -1,471 +0,0 @@
-// @ts-ignore
-const {stringToHtml} = window.fwdekker;
-import {InterlangNetwork, LinkVerdict, Page, PageVerdict} from "./MediaWiki";
-
-
-/**
- * An input that can be validated.
- */
-export class ValidatableInput {
- /**
- * The validatable input.
- */
- readonly input: HTMLInputElement;
- /**
- * Returns an empty string if the given input string is valid, and a string explaining why it is invalid otherwise.
- *
- * @private
- */
- private readonly isValid: (input: string) => string;
-
-
- /**
- * Constructs a new validatable input.
- *
- * @param input the input that is validatable
- * @param isValid returns an empty string if the given input string is valid, and a string explaining why it is is
- * invalid otherwise
- */
- constructor(input: HTMLInputElement, isValid: ((input: string) => string)) {
- this.input = input;
- this.isValid = isValid;
- }
-
-
- /**
- * Returns the value of the underlying input element.
- *
- * @return the value of the underlying input element
- */
- getValue(): string {
- return this.input.value;
- }
-
- /**
- * Sets the value of the underlying input element.
- *
- * @param value the value to set
- */
- setValue(value: string): void {
- this.input.value = value;
- }
-
- /**
- * Validates the input.
- *
- * @return an empty string if the input string is valid, and a string explaining why it is is invalid otherwise
- */
- validate(): string {
- const validity = this.isValid(this.input.value);
-
- if (validity.length === 0) this.showSuccess();
- else this.showError();
-
- return validity;
- }
-
- /**
- * Marks the input as neither valid nor invalid.
- */
- showBlank(): void {
- this.input.dataset["entered"] = "false";
- this.input.setCustomValidity("");
- }
-
- /**
- * Marks the input as invalid and moves focus to it.
- */
- showError(): void {
- this.input.dataset["entered"] = "true";
- this.input.setCustomValidity("Incorrect");
- this.input.focus();
- }
-
- /**
- * Marks the input as valid.
- */
- showSuccess(): void {
- this.input.dataset["entered"] = "true";
- this.input.setCustomValidity("");
- }
-}
-
-/**
- * The types of error that can be displayed by an `ErrorHandler`.
- */
-export type ErrorLevel = "warning" | "error" | null;
-
-/**
- * Interacts with the DOM to delegate errors to the user.
- */
-export class ErrorHandler {
- /**
- * The outer div that wraps around all displayed errors.
- *
- * @private
- */
- private readonly outerDiv: HTMLDivElement;
-
-
- /**
- * Constructs a new error handler, inserting relevant new elements into the DOM.
- *
- * @param parent the element to insert elements into
- */
- constructor(parent: HTMLElement) {
- this.outerDiv = document.createElement("div");
- this.outerDiv.classList.add("errorOuter", "hidden");
- parent.appendChild(this.outerDiv);
- }
-
-
- /**
- * Handles the displaying of the given error.
- *
- * @param level the level of message to display, determines the style of the text
- * @param message the message to display
- * @return this `ErrorHandler`
- */
- handle(level: ErrorLevel, message: string): ErrorHandler {
- this.outerDiv.classList.remove("hidden");
-
- const errorInner = document.createElement("div");
- errorInner.classList.add("errorInner");
- if (level !== null) errorInner.classList.add(level);
- errorInner.innerText = message;
- this.outerDiv.appendChild(errorInner);
-
- return this;
- }
-
- /**
- * Clears all errors from the DOM.
- *
- * @return this `ErrorHandler`
- */
- clear(): ErrorHandler {
- this.outerDiv.classList.add("hidden");
- this.outerDiv.innerHTML = "";
-
- return this;
- }
-}
-
-/**
- * The types of message that can be displayed by a `MessageHandler`.
- */
-export type MessageLevel = "complete" | "progress" | "warning" | "error" | "neutral" | null;
-
-/**
- * Interacts with the DOM to delegate messages to the user.
- */
-export class MessageHandler {
- /**
- * The outer div, wrapping around all of the handler's elements.
- *
- * @private
- */
- private readonly outerDiv: HTMLDivElement;
- /**
- * The inner div, wrapping around the icon, spacing, and current message.
- *
- * @private
- */
- private readonly innerDiv: HTMLDivElement;
- /**
- * A loading icon, optionally displayed before the current message.
- *
- * @private
- */
- private readonly loadingIcon: HTMLElement;
- /**
- * Spacing between the loading icon and the current message.
- *
- * @private
- */
- private readonly spacing: HTMLSpanElement;
- /**
- * The span containing the current message.
- *
- * @private
- */
- private readonly textSpan: HTMLSpanElement;
-
- /**
- * The callback to be executed whenever a message is handler by this handler.
- *
- * @private
- */
- private callback: ((level: MessageLevel, message: string) => void) | undefined;
- /**
- * The currently displayed message level.
- *
- * @private
- */
- private currentLevel: MessageLevel | undefined;
-
-
- /**
- * Constructs a new `MessageHandler`, inserting relevant new elements into the DOM to interact with.
- *
- * @param parent the element to insert elements into
- */
- constructor(parent: HTMLElement) {
- this.outerDiv = document.createElement("div");
- this.outerDiv.classList.add("messageOuter", "hidden");
- parent.appendChild(this.outerDiv);
-
- this.innerDiv = document.createElement("div");
- this.innerDiv.classList.add("messageInner");
- this.outerDiv.appendChild(this.innerDiv);
-
- this.loadingIcon = document.createElement("i");
- this.loadingIcon.classList.add("fa", "fa-spinner", "fa-spin");
- this.innerDiv.appendChild(this.loadingIcon);
-
- this.spacing = document.createElement("span");
- this.spacing.innerHTML = " ";
- this.innerDiv.appendChild(this.spacing);
-
- this.textSpan = document.createElement("span");
- this.innerDiv.appendChild(this.textSpan);
-
- this.callback = undefined;
- this.currentLevel = undefined;
- }
-
-
- /**
- * Handles the displaying of the given message.
- *
- * If no message is given, the current message and the loading icon are hidden. To display an empty message next to
- * the loading icon, give an empty string.
- *
- * @param level the level of message to display, or `null` if the entire message handler should be hidden
- * @param message the message to display
- * @return this `MessageHandler`
- */
- handle(level: MessageLevel, message: string): MessageHandler {
- this.displayLevel(level);
- if (level === undefined) return this; // No need to handle the rest
-
- if (this.callback !== undefined) this.callback(level, message);
- this.textSpan.innerHTML = message;
- return this;
- }
-
- /**
- * Clears the message handler's contents and hides it.
- *
- * @return this `MessageHandler`
- */
- clear(): MessageHandler {
- return this.handle(null, "");
- }
-
- /**
- * Sets the callback to be executed whenever a message is handler by this handler.
- *
- * @param callback the function to execute whenever a message is handled
- * @return this `MessageHandler`
- */
- setCallback(callback: ((level: MessageLevel, message: string) => void)): MessageHandler {
- this.callback = callback;
-
- return this;
- }
-
-
- /**
- * Changes the appearance of the message handler to that of the given level.
- *
- * @param level the level to change appearance to
- * @return this `MessageHandler`
- * @private
- */
- private displayLevel(level: MessageLevel): MessageHandler {
- if (level === this.currentLevel) return this;
- this.currentLevel = level;
-
- this.outerDiv.classList.remove("hidden");
- this.innerDiv.classList.remove("success", "warning", "error");
-
- switch (level) {
- case "complete":
- this.innerDiv.classList.add("success");
- this.toggleLoadingIcon(false);
- break;
- case "progress":
- this.toggleLoadingIcon(true);
- break;
- case "warning":
- this.innerDiv.classList.add("warning");
- this.toggleLoadingIcon(false);
- break;
- case "error":
- this.innerDiv.classList.add("error");
- this.toggleLoadingIcon(false);
- break;
- case "neutral":
- this.toggleLoadingIcon(false);
- break;
- default:
- this.outerDiv.classList.add("hidden");
- break;
- }
-
- return this;
- }
-
- /**
- * Turns the loading icon on or off.
- *
- * @param state `true` if and only if the loading icon should be on
- * @return this `MessageHandler`
- * @private
- */
- private toggleLoadingIcon(state: boolean): MessageHandler {
- if (state) {
- this.loadingIcon.classList.remove("hidden");
- this.spacing.classList.remove("hidden");
- } else {
- this.loadingIcon.classList.add("hidden");
- this.spacing.classList.add("hidden");
- }
-
- return this;
- }
-}
-
-/**
- * A network of interlanguage links.
- */
-export class InterlangTable {
- /**
- * Generates an icon element with the given title and additional classes.
- *
- * @param icon the name of the icon to display, or `null` if an empty span should be returned
- * @param title the title of the icon, used for the `title` attribute
- * @param classes the additional classes to apply to the icon
- * @return an icon element with the given title and additional classes
- * @private
- */
- private static createIcon(icon: string | null, title: string, classes: string[]): string {
- if (icon === null) return `
`;
-
- return `
`;
- }
-
- /**
- * Returns an appropriate label for the given page.
- *
- * The label contains a link to the page and a few buttons to help the user interact with that page. The label's
- * appearance and contents depend both on the properties of the page (e.g. whether it exists and whether it's a
- * redirect page) and on the other pages in this network (e.g. whether it's the only page in its language).
- *
- * @param pages a list of all pages
- * @param page the page to generate a label of
- * @return an appropriate label with icons for the given page
- * @private
- */
- private generateLabel(pages: Page[], page: Page): string {
- const labelText = pages.some(it => it.link.lang === page.link.lang && !it.link.equals(page.link))
- ? page.link.toString()
- : page.link.lang;
-
- return "" +
- `
` +
- /**/`${labelText}` +
- /**/` ` +
- /**/`` +
- /**/` ` +
- /**/`` +
- ``;
- }
-
- /**
- * Generates the head of the table generated by `#toTable`.
- *
- * @param network the network to generate the head for
- * @return the head of the table generated by `#toTable`
- * @private
- */
- private generateTableHead(network: InterlangNetwork): string {
- return "" +
- `
` +
- /**/`` +
- /****/` | ` +
- /****/`Source | ` +
- /****/`Destination | ` +
- /**/`
` +
- /**/`${network.pages.map(page => `${this.generateLabel(network.pages, page)} | `)}
` +
- ``;
- }
-
- /**
- * Generates the body of the table generated by `#toTable`.
- *
- * @param network the network to generate the body for
- * @return the body of the table generated by `#toTable`
- * @private
- */
- private generateTableBody(network: InterlangNetwork): string {
- const rows = network.pages.map(srcPage => {
- const {self: selfVerdict, links: linkVerdicts} = network.getPageVerdict(srcPage);
-
- const icons = selfVerdict
- .map(state => {
- const props = PageVerdict.props[state];
- return InterlangTable.createIcon(props.icon, props.message, props.style);
- })
- .map(it => `${it}
`);
- const label = this.generateLabel(network.pages, srcPage);
- const cells = network.pages.map(dstPage => {
- const linkState = linkVerdicts.get(dstPage.link)!;
- const props = LinkVerdict.props[linkState];
- return InterlangTable.createIcon(props.icon, props.message, props.style);
- });
-
- return "" +
- `
` +
- /**/`${icons} | ` +
- /**/`${label} | ` +
- /**/cells.map(it => `${it} | `) +
- `
`;
- });
-
- return `
${rows}`;
- }
-
- /**
- * Renders the the table describing the interlanguage network.
- *
- * @param id the ID to assign to the table element
- * @param network the network of pages to render
- * @return the generated table
- */
- render(id: string, network: InterlangNetwork): HTMLElement {
- const table = stringToHtml(
- `
` +
- /**/this.generateTableHead(network) +
- /**/this.generateTableBody(network) +
- `
`,
- "table"
- ) as HTMLElement;
-
- // Add event handlers
- table.querySelectorAll(".copyIcon").forEach(icon => {
- if (!(icon instanceof HTMLElement)) return;
-
- icon.addEventListener("click", () => {
- // noinspection JSIgnoredPromiseFromCall
- navigator.clipboard.writeText(`[[${icon.dataset.clipboarddata}]]`);
-
- icon.classList.replace("fa-clipboard", "fa-check");
- setTimeout(() => icon.classList.replace("fa-check", "fa-clipboard"), 1000);
- });
- });
-
- return table;
- }
-}
diff --git a/src/main/js/InterlangTable.ts b/src/main/js/InterlangTable.ts
new file mode 100644
index 0000000..562d43b
--- /dev/null
+++ b/src/main/js/InterlangTable.ts
@@ -0,0 +1,136 @@
+const {stringToHtml} = (window as any).fwdekker;
+import {InterlangNetwork, LinkVerdict, Page, PageVerdict} from "./MediaWiki";
+
+
+/**
+ * A network of interlanguage links.
+ */
+export class InterlangTable {
+ /**
+ * Generates an icon element with the given title and additional classes.
+ *
+ * @param icon the name of the icon to display, or `null` if an empty span should be returned
+ * @param title the title of the icon, used for the `title` attribute
+ * @param classes the additional classes to apply to the icon
+ * @return an icon element with the given title and additional classes
+ * @private
+ */
+ private static createIcon(icon: string | null, title: string, classes: string[]): string {
+ if (icon === null) return `
`;
+
+ return `
`;
+ }
+
+ /**
+ * Returns an appropriate label for the given page.
+ *
+ * The label contains a link to the page and a few buttons to help the user interact with that page. The label's
+ * appearance and contents depend both on the properties of the page (e.g. whether it exists and whether it's a
+ * redirect page) and on the other pages in this network (e.g. whether it's the only page in its language).
+ *
+ * @param pages a list of all pages
+ * @param page the page to generate a label of
+ * @return an appropriate label with icons for the given page
+ * @private
+ */
+ private generateLabel(pages: Page[], page: Page): string {
+ const labelText = pages.some(it => it.link.lang === page.link.lang && !it.link.equals(page.link))
+ ? page.link.toString()
+ : page.link.lang;
+
+ return "" +
+ `
` +
+ /**/`${labelText}` +
+ /**/` ` +
+ /**/`` +
+ /**/` ` +
+ /**/`` +
+ ``;
+ }
+
+ /**
+ * Generates the head of the table generated by `#toTable`.
+ *
+ * @param network the network to generate the head for
+ * @return the head of the table generated by `#toTable`
+ * @private
+ */
+ private generateTableHead(network: InterlangNetwork): string {
+ return "" +
+ `
` +
+ /**/`` +
+ /****/` | ` +
+ /****/`Source | ` +
+ /****/`Destination | ` +
+ /**/`
` +
+ /**/`${network.pages.map(page => `${this.generateLabel(network.pages, page)} | `)}
` +
+ ``;
+ }
+
+ /**
+ * Generates the body of the table generated by `#toTable`.
+ *
+ * @param network the network to generate the body for
+ * @return the body of the table generated by `#toTable`
+ * @private
+ */
+ private generateTableBody(network: InterlangNetwork): string {
+ const rows = network.pages.map(srcPage => {
+ const {self: selfVerdict, links: linkVerdicts} = network.getPageVerdict(srcPage);
+
+ const icons = selfVerdict
+ .map(state => {
+ const props = PageVerdict.props[state];
+ return InterlangTable.createIcon(props.icon, props.message, props.style);
+ })
+ .map(it => `${it}
`);
+ const label = this.generateLabel(network.pages, srcPage);
+ const cells = network.pages.map(dstPage => {
+ const linkState = linkVerdicts.get(dstPage.link)!;
+ const props = LinkVerdict.props[linkState];
+ return InterlangTable.createIcon(props.icon, props.message, props.style);
+ });
+
+ return "" +
+ `
` +
+ /**/`${icons} | ` +
+ /**/`${label} | ` +
+ /**/cells.map(it => `${it} | `) +
+ `
`;
+ });
+
+ return `
${rows}`;
+ }
+
+ /**
+ * Renders the table describing the interlanguage network.
+ *
+ * @param id the ID to assign to the table element
+ * @param network the network of pages to render
+ * @return the generated table
+ */
+ render(id: string, network: InterlangNetwork): HTMLElement {
+ const table = stringToHtml(
+ `
` +
+ /**/this.generateTableHead(network) +
+ /**/this.generateTableBody(network) +
+ `
`,
+ "table"
+ ) as HTMLElement;
+
+ // Add event handlers
+ table.querySelectorAll(".copy-icon").forEach(icon => {
+ if (!(icon instanceof HTMLElement)) return;
+
+ icon.addEventListener("click", () => {
+ // noinspection JSIgnoredPromiseFromCall
+ navigator.clipboard.writeText(`[[${icon.dataset.clipboarddata}]]`);
+
+ icon.classList.replace("fa-clipboard", "fa-check");
+ setTimeout(() => icon.classList.replace("fa-check", "fa-clipboard"), 1000);
+ });
+ });
+
+ return table;
+ }
+}
diff --git a/src/main/js/Main.ts b/src/main/js/Main.ts
index 785bba4..8e8a30b 100644
--- a/src/main/js/Main.ts
+++ b/src/main/js/Main.ts
@@ -1,28 +1,16 @@
-// @ts-ignore
-const {$, doAfterLoad, footer, header, nav} = window.fwdekker;
-import {ErrorHandler, InterlangTable, MessageHandler, ValidatableInput} from "./DOM";
+const {$, doAfterLoad} = (window as any).fwdekker;
+const {
+ clearFormValidity, showInputInvalid, showMessageBusy, showMessageError, showMessageInfo, showMessageType
+} = (window as any).fwdekker.validation;
+
+import {InterlangTable} from "./InterlangTable";
import {discoverNetwork, InterlangNetwork, MediaWiki, MediaWikiManager, NetworkVerdict} from "./MediaWiki";
// Contains global functions for debugging
-// @ts-ignore
-window.ilc = {};
+(window as any).ilc = {};
-// Set up template
-doAfterLoad(() => {
- $("#nav").appendChild(nav("/Tools/Interlanguage Checker/"));
- $("#header").appendChild(header({
- title: "Interlanguage Checker",
- description: "Check the consistency of MediaWiki interlanguage links in a simple overview"
- }));
- $("#footer").appendChild(footer({
- vcsURL: "https://git.fwdekker.com/tools/interlanguage-checker/",
- version: "v%%VERSION_NUMBER%%"
- }));
- $("main").classList.remove("hidden");
-});
-
// Handle "About" toggle
doAfterLoad(() => {
const about = $("#about");
@@ -31,138 +19,109 @@ doAfterLoad(() => {
about.addEventListener("toggle", () => localStorage.setItem(key, "" + !!about.open));
const storedState = localStorage.getItem(key);
- if (storedState === null) about.open = true;
- else about.open = storedState === "true";
+ about.open = storedState === null || storedState === "true";
});
// Handle input
doAfterLoad(async () => {
- const urlInput = new ValidatableInput($("#url"), (value) => {
- if (value.trim() === "")
- return "API URL must not be empty.";
-
- try {
- new URL(value); // Throws exception if invalid
- return "";
- } catch (error) {
- try {
- // noinspection HttpUrlsUsage
- const url = `http://${value}`;
- new URL(url); // Throws exception if invalid
- $("#url").value = url;
- return "";
- } catch {
- if (!(error instanceof Error))
- throw Error(`Error while processing connection error:\n${error}`);
-
- return error.message;
- }
- }
- });
- const articleInput = new ValidatableInput($("#article"), (value) => {
- return value.trim() === "" ? "Article must not be empty" : "";
- });
- const checkButton = $("#check");
-
- const errorHandler = new ErrorHandler($("#errors"));
- const messageHandler = new MessageHandler($("#messages"))
- .setCallback((level, message) => {
- if (level === "error") console.error(message);
- });
-
+ const form = $("#inputs");
+ const urlInput = $("#url");
+ const articleInput = $("#article");
+ // Form submission
let previousUrl: string | undefined;
let mwm: MediaWikiManager | undefined;
const submit = async () => {
- localStorage.setItem("/tools/interlanguage-checker//api-url", urlInput.getValue());
+ localStorage.setItem("/tools/interlanguage-checker//api-url", urlInput.value);
// Clean up
- urlInput.showBlank();
- articleInput.showBlank();
- errorHandler.clear();
- messageHandler.clear();
-
- const oldTable = $("#networkTable");
- if (oldTable !== null)
- oldTable.parentNode.removeChild(oldTable);
+ clearFormValidity(form);
+ $("#network-table")?.remove();
// Validate
- const urlValidity = urlInput.validate();
- if (urlValidity !== "") return messageHandler.handle("error", urlValidity);
+ const urlValue = urlInput.value;
+ const articleValue = articleInput.value;
- const articleValidity = articleInput.validate();
- if (articleValidity !== "") return messageHandler.handle("error", articleValidity);
+ if (urlValue.trim() === "")
+ return showInputInvalid(urlInput, "Enter the API URL.");
+
+ try {
+ new URL(urlValue); // Throws exception if invalid
+ } catch (error) {
+ try {
+ const url = `http://${urlValue}`;
+ new URL(url); // Throws exception if invalid
+ $("#url").value = url;
+ return "";
+ } catch {
+ return showInputInvalid(urlInput, (error as Error).message);
+ }
+ }
+
+ if (articleValue.trim() === "")
+ return showInputInvalid(articleInput, "Enter the name of the article to check.");
// Initialize
- if (urlInput.getValue() !== previousUrl) {
- messageHandler.handle("progress", `Initializing
${urlInput.getValue()}
`);
+ if (urlValue !== previousUrl) {
+ showMessageBusy(form, `Initializing
${urlValue}
`);
try {
- const mw = await new MediaWiki(urlInput.getValue()).init();
+ const mw = await new MediaWiki(urlValue).init();
mwm = await new MediaWikiManager().init(mw);
} catch (error) {
- if (!(error instanceof Error))
- throw Error(`Error while processing initialization error:\n${error}`);
-
- messageHandler.handle("error", error.message);
- return;
+ return showMessageError(form, (error as Error).message);
}
- previousUrl = urlInput.getValue();
+ previousUrl = urlValue;
}
// Discover
discoverNetwork(
mwm!,
- articleInput.getValue(),
- (level, message) => errorHandler.handle(level, message),
- it => messageHandler.handle("progress", it)
+ articleInput.value,
+ (type, message) => showMessageType(form, message, type),
+ it => showMessageType(form, it, "busy")
)
.then(it => new InterlangNetwork(it.pages, it.redirects))
.then(network => {
- messageHandler.handle("progress", "Creating table");
+ showMessageType(form, "Creating table", "busy");
- const form = $("#networkTableForm");
- form.textContent = "";
- form.appendChild((new InterlangTable()).render("networkTable", network));
+ const tableForm = $("#network-table-form");
+ tableForm.textContent = "";
+ tableForm.appendChild((new InterlangTable()).render("network-table", network));
const props = NetworkVerdict.props[network.getNetworkVerdict()];
- messageHandler.handle(props.style, props.message);
+ showMessageType(form, props.message, props.type);
})
- .catch(error => messageHandler.handle("error", error));
+ .catch(error => showMessageError(form, error));
};
-
- urlInput.input.addEventListener("keypress", (event) => {
- if (event.key.toLowerCase() === "enter") submit();
+ form.addEventListener("submit", (event: SubmitEvent) => {
+ event.preventDefault();
+ submit();
});
- articleInput.input.addEventListener("keypress", (event) => {
- if (event.key.toLowerCase() === "enter") submit();
- });
- checkButton.addEventListener("click", () => submit());
- urlInput.input.focus() // Default focus
+ urlInput.focus(); // Default focus
// Read inputs from cookies
const apiUrl = localStorage.getItem("/tools/interlanguage-checker//api-url");
if (apiUrl !== null && apiUrl.trim() !== "") {
- urlInput.setValue(apiUrl);
- articleInput.input.focus();
+ urlInput.value = apiUrl;
+ articleInput.focus();
}
// Read inputs from URL
const currentParams = new URLSearchParams(window.location.search);
if (currentParams.has("api")) {
- urlInput.setValue(currentParams.get("api")!);
- articleInput.input.focus();
+ urlInput.value = currentParams.get("api")!;
+ articleInput.focus();
}
- if (currentParams.has("article")) articleInput.setValue(currentParams.get("article")!);
+ if (currentParams.has("article")) articleInput.value = currentParams.get("article")!;
if (currentParams.has("api") && currentParams.has("article")) await submit();
// Set global debug function
- // @ts-ignore
- window.ilc.getCurrentInputAsUrl = () =>
+ (window as any).ilc.getCurrentInputAsUrl = () =>
location.href.split("?")[0] +
- `?api=${encodeURI(urlInput.getValue())}` +
- `&article=${encodeURI(articleInput.getValue())}`;
+ `?api=${encodeURI(urlInput.value)}` +
+ `&article=${encodeURI(articleInput.value)}`;
});
diff --git a/src/main/js/MediaWiki.ts b/src/main/js/MediaWiki.ts
index 79e06d1..fcfb915 100644
--- a/src/main/js/MediaWiki.ts
+++ b/src/main/js/MediaWiki.ts
@@ -1,4 +1,3 @@
-import {MessageLevel} from "./DOM";
import {couldNotConnectMessage, mergeMaps, mergeSets} from "./Shared";
@@ -621,7 +620,7 @@ export class MediaWikiManager {
export const discoverNetwork = async function(
mwm: MediaWikiManager,
title: string,
- errorCb: (level: "error" | "warning" | null, message: string) => void,
+ errorCb: (type: "error" | "warning" | null, message: string) => void,
progressCb: (message: string) => void
): Promise<{ pages: Page[], redirects: Redirect[] }> {
const pages = [];
@@ -630,7 +629,7 @@ export const discoverNetwork = async function(
const history: InterlangLink[] = [];
const queue: InterlangLink[] = [new InterlangLink(mwm.baseLang, title)];
while (queue.length > 0) {
- progressCb("Checking
" + queue[queue.length - 1] + "
");
+ progressCb("Checking
" + queue[queue.length - 1] + "
.");
let next = queue.pop()!;
if (history.some(it => it.equals(next)))
@@ -644,7 +643,10 @@ export const discoverNetwork = async function(
if (history.length === 1)
throw new Error(couldNotConnectMessage);
else {
- errorCb("warning", `Could not connect to the wiki for language '${next.lang}'. Maybe the wiki no longer exists?`);
+ errorCb(
+ "warning",
+ `Could not connect to the wiki for language '${next.lang}'. Maybe the wiki no longer exists?`
+ );
continue;
}
}
@@ -765,17 +767,19 @@ export namespace NetworkVerdict {
export const props = {
"perfect": {
message: "A perfect network! 🙂",
- style: "complete" as MessageLevel
+ type: "success"
},
"flawed": {
- message: "The network is complete but flawed 😕
" +
+ message:
+ "The network is complete but flawed 😕
" +
"Hover over an icon in the left column for more information.",
- style: "warning" as MessageLevel
+ type: "warning"
},
"broken": {
- message: "The network is broken 😞
" +
+ message:
+ "The network is broken 😞
" +
"Hover over an icon in the left column for more information.",
- style: "warning" as MessageLevel
+ type: "warning"
},
};
diff --git a/src/main/js/Shared.ts b/src/main/js/Shared.ts
index 0eab05e..0b8bda8 100644
--- a/src/main/js/Shared.ts
+++ b/src/main/js/Shared.ts
@@ -2,7 +2,7 @@
* The message that is displayed when the application fails to connect to the API.
*/
export const couldNotConnectMessage: string =
- "Could not to connect to API. Is the URL correct? Are you using a script blocker? " +
+ "Could not connect to API. Is the URL correct? Are you using a script blocker? " +
"See the
About section for more information.";
/**