diff --git a/.gitignore b/.gitignore index 9f11b75..5c6b34c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea/ +www/res/scripts/* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fb21cbd --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +.DEFAULT_GOAL := build + +OUT=www/res/scripts + +${OUT}/locutus.js ${OUT}/usimp.js: src/locutus.ts src/usimp.ts + tsc + +build: ${OUT}/locutus.js ${OUT}/usimp.js + perl -i -pE 's/(\?v=[0-9]+\.[0-9]+\.[0-9]+\+)([0-9]+)/($$1).($$2+1)/eg' www/index.html + +clean: + rm -rf "${OUT}" diff --git a/www/res/js/modules/locutus.js b/src/locutus.ts similarity index 67% rename from www/res/js/modules/locutus.js rename to src/locutus.ts index bf7e893..9d33442 100644 --- a/www/res/js/modules/locutus.js +++ b/src/locutus.ts @@ -1,26 +1,26 @@ "use strict"; -import * as USIMP from "./usimp.js"; +import * as USIMP from "./usimp"; export class App { - account; - defaultLocation; - main; - windows; - session; + account: USIMP.Account | null; + defaultLocation: string; + main: HTMLElement; + windows: HTMLElement; + session: USIMP.Session | null; constructor() { - if (localStorage.session === undefined) { - this.defaultLocation = '/welcome'; - this.account = null; - } else { - const session = JSON.parse(localStorage.session); - this.defaultLocation = '/'; - this.account = session.account; - } + this.defaultLocation = '/welcome'; + this.account = null; + this.session = null; - this.main = document.getElementsByTagName("main")[0]; - this.windows = document.getElementById("windows"); + const main = document.getElementsByTagName("main")[0]; + if (!main) throw Error("Element
not found"); + this.main = main; + + const windows = document.getElementById("windows"); + if (!windows) throw Error("Element #windows not found"); + this.windows = windows; window.addEventListener("hashchange", event => { this.handleUrl(event.newURL); @@ -29,21 +29,21 @@ export class App { this.handleUrl(document.URL); } - setHash(hash) { + setHash(hash: string) { const url = new URL(document.URL); url.hash = hash; location.href = url.toString(); } - handleUrl(url) { + handleUrl(url: string) { this.handleHash(new URL(url).hash); } - handleHash(hash) { + handleHash(hash: string) { if (hash[0] === '#') hash = hash.substr(1); const defaultCase = () => { - history.replaceState(null, null, `#${this.defaultLocation}`); + history.replaceState(null, document.title, `#${this.defaultLocation}`); this.handleHash(this.defaultLocation); } @@ -78,7 +78,7 @@ export class App { } } - async login(accountName, domainName, password) { + async login(accountName: string, domainName: string, password: string) { let domain; try { domain = await USIMP.Domain.fromName(domainName); @@ -135,13 +135,15 @@ export class App { this.windows.appendChild(win); } - addMessage(message) { + addMessage(message: string) { const msg = document.createElement("div"); msg.classList.add("message"); msg.innerText = message; const chat = this.main.getElementsByClassName("chat-history")[0]; + if (!chat) throw Error("Element .chat-history not found"); + chat.appendChild(msg); chat.scrollTop = chat.scrollHeight; } @@ -159,26 +161,33 @@ export class App { `; - win.getElementsByTagName("form")[0].addEventListener("submit", async event => { + const form = win.getElementsByTagName("form")[0]; + if (!form) throw Error("Element
not found"); + + form.addEventListener("submit", async event => { event.preventDefault(); - const form = event.target; - for (const e of form) { + + for (const e of form.getElementsByTagName("button")) e.disabled = false; + for (const e of form.getElementsByTagName("input")) { e.disabled = true; e.removeAttribute("invalid"); } try { try { - await this.login(form.account.value, form.domain.value, form.password.value); + await this.login(form['account'].value, form['domain'].value, form['password'].value); } finally { for (const d of form.getElementsByTagName("div")) form.removeChild(d); - for (const e of form) e.disabled = false; + for (const e of form.getElementsByTagName("input")) e.disabled = false; + for (const e of form.getElementsByTagName("button")) e.disabled = false; } } catch (error) { if (error.toString() === "Error: unable to authenticate") { - document.getElementsByName("account")[0].setAttribute("invalid", "invalid"); + const account = document.getElementsByName("account")[0]; + if (account) account.setAttribute("invalid", "invalid"); } else { - document.getElementsByName("domain")[0].setAttribute("invalid", "invalid"); + const domain = document.getElementsByName("domain")[0]; + if (domain) domain.setAttribute("invalid", "invalid"); } const div = document.createElement("div"); @@ -190,18 +199,26 @@ export class App { this.windows.appendChild(win); - document.getElementsByName("domain")[0].addEventListener("input", (event) => { - event.target.removeAttribute("invalid"); + const domain = document.getElementsByName("domain")[0]; + if (!domain) throw Error("Element name=domain not found"); + + domain.addEventListener("input", (event) => { + domain.removeAttribute("invalid"); }); - document.getElementsByName("account")[0].addEventListener("input", (event) => { - event.target.removeAttribute("invalid"); + const account = document.getElementsByName("account")[0]; + if (!account) throw Error("Element name=account not found"); + + account.addEventListener("input", (event) => { + account.removeAttribute("invalid"); }); - document.getElementsByName("account")[0].focus(); + account.focus(); } setupMain() { + if (!this.session) throw Error("Invalid state"); + this.main.innerHTML = `
@@ -210,9 +227,13 @@ export class App {
`; - const input = document.getElementsByName("message")[0]; + const input = document.getElementsByTagName("input")[0]; + if (!input) throw Error("Element not found"); + input.addEventListener("keyup", async event => { if (event.key === "Enter" && input.value.length > 0) { + if (!this.session) throw Error("No session found"); + this.addMessage(input.value); const val = input.value; input.value = ""; diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..a07ad01 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,11 @@ +"use strict"; + +import * as Locutus from "./locutus"; + +window.addEventListener("DOMContentLoaded", () => { + // Remove