235 lines
7.0 KiB
JavaScript
235 lines
7.0 KiB
JavaScript
"use strict";
|
|
|
|
import * as USIMP from "./usimp.js";
|
|
|
|
export class App {
|
|
account;
|
|
defaultLocation;
|
|
main;
|
|
windows;
|
|
session;
|
|
|
|
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.main = document.getElementsByTagName("main")[0];
|
|
this.windows = document.getElementById("windows");
|
|
|
|
window.addEventListener("hashchange", event => {
|
|
this.handleUrl(event.newURL);
|
|
});
|
|
|
|
this.handleUrl(document.URL);
|
|
}
|
|
|
|
setHash(hash) {
|
|
const url = new URL(document.URL);
|
|
url.hash = hash;
|
|
location.href = url.toString();
|
|
}
|
|
|
|
handleUrl(url) {
|
|
this.handleHash(new URL(url).hash);
|
|
}
|
|
|
|
handleHash(hash) {
|
|
if (hash[0] === '#') hash = hash.substr(1);
|
|
|
|
const defaultCase = () => {
|
|
history.replaceState(null, null, `#${this.defaultLocation}`);
|
|
this.handleHash(this.defaultLocation);
|
|
}
|
|
|
|
switch (hash) {
|
|
case "/":
|
|
if (!this.session) {
|
|
return defaultCase();
|
|
}
|
|
this.hideWindows();
|
|
this.showMain();
|
|
this.removeAllWindows();
|
|
this.setupMain();
|
|
break;
|
|
case "/welcome":
|
|
this.hideMain();
|
|
this.showWindows();
|
|
this.removeAllWindows();
|
|
this.addWelcomeWindow();
|
|
break;
|
|
case "/login":
|
|
if (this.session) {
|
|
return defaultCase();
|
|
}
|
|
this.hideMain();
|
|
this.showWindows();
|
|
this.removeAllWindows();
|
|
this.addLoginWindow();
|
|
break;
|
|
default:
|
|
console.warn(`Invalid url hash #${hash}`);
|
|
return defaultCase();
|
|
}
|
|
|
|
//this.setHash(hash);
|
|
}
|
|
|
|
async login(accountName, domainName, password) {
|
|
let domain;
|
|
try {
|
|
domain = await USIMP.Domain.fromName(domainName);
|
|
} catch (error) {
|
|
if (error instanceof DOMException) {
|
|
throw Error("Connection timed out");
|
|
} else {
|
|
throw Error("Invalid USIMP domain");
|
|
}
|
|
}
|
|
|
|
const session = new USIMP.Session(domain);
|
|
const rtt = await session.chooseDomainServer();
|
|
console.log(rtt);
|
|
|
|
const response = await session.authenticate(accountName, password);
|
|
if (response.status === "success") {
|
|
this.session = session;
|
|
this.defaultLocation = "/";
|
|
this.setHash("/");
|
|
} else {
|
|
throw Error(response.message);
|
|
}
|
|
}
|
|
|
|
hideMain() {
|
|
this.main.style.visibility = "hidden";
|
|
}
|
|
|
|
showMain() {
|
|
this.main.style.visibility = "visible";
|
|
}
|
|
|
|
hideWindows() {
|
|
this.windows.style.visibility = "hidden";
|
|
}
|
|
|
|
showWindows() {
|
|
this.windows.style.visibility = "visible";
|
|
}
|
|
|
|
removeAllWindows() {
|
|
while (this.windows.lastChild) this.windows.removeChild(this.windows.lastChild);
|
|
}
|
|
|
|
addWelcomeWindow() {
|
|
const win = document.createElement("div");
|
|
win.classList.add("window-welcome");
|
|
|
|
win.innerHTML = `
|
|
<h1>Welcome to Locutus!</h1>
|
|
<a href="#/login" class="button">Login</a>`;
|
|
|
|
this.windows.appendChild(win);
|
|
}
|
|
|
|
addMessage(message) {
|
|
const msg = document.createElement("div");
|
|
msg.classList.add("message");
|
|
|
|
msg.innerText = message;
|
|
|
|
const chat = this.main.getElementsByClassName("chat-history")[0];
|
|
chat.appendChild(msg);
|
|
chat.scrollTop = chat.scrollHeight;
|
|
}
|
|
|
|
addLoginWindow() {
|
|
const win = document.createElement("div");
|
|
win.classList.add("window-login");
|
|
|
|
win.innerHTML = `
|
|
<h1>Login to USIMP Account</h1>
|
|
<form>
|
|
<input name="account" placeholder="Account name" type="text" required/>
|
|
<input name="domain" placeholder="Domain" type="text" pattern="([a-zA-Z0-9_-]+\\.)+[a-zA-Z]{2,}" required/>
|
|
<input name="password" placeholder="Password" type="password" required/>
|
|
<button type="submit">Login</button>
|
|
</form>`;
|
|
|
|
win.getElementsByTagName("form")[0].addEventListener("submit", async (event) => {
|
|
event.preventDefault();
|
|
const form = event.target;
|
|
for (const e of form) {
|
|
e.disabled = true;
|
|
e.removeAttribute("invalid");
|
|
}
|
|
|
|
for (const d of form.getElementsByTagName("div")) {
|
|
form.removeChild(d);
|
|
}
|
|
|
|
function formError(msg) {
|
|
const div = document.createElement("div");
|
|
div.classList.add("error");
|
|
div.innerText = msg;
|
|
form.appendChild(div);
|
|
}
|
|
|
|
try {
|
|
await this.login(form.account.value, form.domain.value, form.password.value);
|
|
} catch (error) {
|
|
if (error.toString() === "Error: unable to authenticate") {
|
|
document.getElementsByName("account")[0].setAttribute("invalid", "invalid");
|
|
} else {
|
|
document.getElementsByName("domain")[0].setAttribute("invalid", "invalid");
|
|
}
|
|
formError(error.toString());
|
|
} finally {
|
|
for (const e of form) e.disabled = false;
|
|
}
|
|
});
|
|
|
|
this.windows.appendChild(win);
|
|
|
|
document.getElementsByName("domain")[0].addEventListener("input", (event) => {
|
|
event.target.removeAttribute("invalid");
|
|
});
|
|
|
|
document.getElementsByName("account")[0].addEventListener("input", (event) => {
|
|
event.target.removeAttribute("invalid");
|
|
});
|
|
|
|
document.getElementsByName("account")[0].focus();
|
|
}
|
|
|
|
setupMain() {
|
|
this.main.innerHTML = `
|
|
<div class="chat">
|
|
<div class="chat-history"></div>
|
|
<div class="chat-input-wrapper">
|
|
<input name="message" type="text" autocomplete="off"/>
|
|
</div>
|
|
</div>`;
|
|
|
|
const input = document.getElementsByName("message")[0];
|
|
input.addEventListener("keyup", (event) => {
|
|
if (event.key === "Enter" && input.value.length > 0) {
|
|
this.session.sendEvent("60nc0XXDIYUh6QzX4p0rMpCdzDmxghZLZk8dLuQh628", {
|
|
message: input.value,
|
|
});
|
|
this.addMessage(input.value);
|
|
input.value = "";
|
|
}
|
|
});
|
|
|
|
this.session.subscribe(response => {
|
|
this.addMessage(response.data.event.data.message);
|
|
});
|
|
}
|
|
}
|