account recovery and inital status stuff
This commit is contained in:
parent
4b087cb98b
commit
acbce08e49
11 changed files with 370 additions and 92 deletions
|
@ -169,7 +169,11 @@ class Contextmenu<x, y> {
|
||||||
if (Contextmenu.currentmenu !== "") {
|
if (Contextmenu.currentmenu !== "") {
|
||||||
Contextmenu.currentmenu.remove();
|
Contextmenu.currentmenu.remove();
|
||||||
}
|
}
|
||||||
div.style.top = y + "px";
|
if (y > 0) {
|
||||||
|
div.style.top = y + "px";
|
||||||
|
} else {
|
||||||
|
div.style.bottom = y * -1 + "px";
|
||||||
|
}
|
||||||
div.style.left = x + "px";
|
div.style.left = x + "px";
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
Contextmenu.keepOnScreen(div);
|
Contextmenu.keepOnScreen(div);
|
||||||
|
|
|
@ -8,8 +8,8 @@ import {File} from "./file.js";
|
||||||
import {I18n} from "./i18n.js";
|
import {I18n} from "./i18n.js";
|
||||||
(async () => {
|
(async () => {
|
||||||
await I18n.done;
|
await I18n.done;
|
||||||
const users = getBulkUsers();
|
|
||||||
if (!users.currentuser) {
|
if (!Localuser.users.currentuser) {
|
||||||
window.location.href = "/login.html";
|
window.location.href = "/login.html";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -26,94 +26,27 @@ import {I18n} from "./i18n.js";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
I18n;
|
I18n;
|
||||||
function showAccountSwitcher(): void {
|
|
||||||
const table = document.createElement("div");
|
|
||||||
table.classList.add("flexttb", "accountSwitcher");
|
|
||||||
|
|
||||||
for (const user of Object.values(users.users)) {
|
|
||||||
const specialUser = user as Specialuser;
|
|
||||||
const userInfo = document.createElement("div");
|
|
||||||
userInfo.classList.add("flexltr", "switchtable");
|
|
||||||
|
|
||||||
const pfp = document.createElement("img");
|
|
||||||
pfp.src = specialUser.pfpsrc;
|
|
||||||
pfp.classList.add("pfp");
|
|
||||||
userInfo.append(pfp);
|
|
||||||
|
|
||||||
const userDiv = document.createElement("div");
|
|
||||||
userDiv.classList.add("userinfo");
|
|
||||||
userDiv.textContent = specialUser.username;
|
|
||||||
userDiv.append(document.createElement("br"));
|
|
||||||
|
|
||||||
const span = document.createElement("span");
|
|
||||||
span.textContent = specialUser.serverurls.wellknown
|
|
||||||
.replace("https://", "")
|
|
||||||
.replace("http://", "");
|
|
||||||
span.classList.add("serverURL");
|
|
||||||
userDiv.append(span);
|
|
||||||
|
|
||||||
userInfo.append(userDiv);
|
|
||||||
table.append(userInfo);
|
|
||||||
|
|
||||||
userInfo.addEventListener("click", () => {
|
|
||||||
thisUser.unload();
|
|
||||||
thisUser.swapped = true;
|
|
||||||
const loading = document.getElementById("loading") as HTMLDivElement;
|
|
||||||
loading.classList.remove("doneloading");
|
|
||||||
loading.classList.add("loading");
|
|
||||||
|
|
||||||
thisUser = new Localuser(specialUser);
|
|
||||||
users.currentuser = specialUser.uid;
|
|
||||||
sessionStorage.setItem("currentuser", specialUser.uid);
|
|
||||||
localStorage.setItem("userinfos", JSON.stringify(users));
|
|
||||||
|
|
||||||
thisUser.initwebsocket().then(() => {
|
|
||||||
thisUser.loaduser();
|
|
||||||
thisUser.init();
|
|
||||||
loading.classList.add("doneloading");
|
|
||||||
loading.classList.remove("loading");
|
|
||||||
console.log("done loading");
|
|
||||||
});
|
|
||||||
|
|
||||||
userInfo.remove();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const switchAccountDiv = document.createElement("div");
|
|
||||||
switchAccountDiv.classList.add("switchtable");
|
|
||||||
switchAccountDiv.textContent = I18n.getTranslation("switchAccounts");
|
|
||||||
switchAccountDiv.addEventListener("click", () => {
|
|
||||||
window.location.href = "/login.html";
|
|
||||||
});
|
|
||||||
table.append(switchAccountDiv);
|
|
||||||
|
|
||||||
if (Contextmenu.currentmenu) {
|
|
||||||
Contextmenu.currentmenu.remove();
|
|
||||||
}
|
|
||||||
Contextmenu.currentmenu = table;
|
|
||||||
document.body.append(table);
|
|
||||||
}
|
|
||||||
|
|
||||||
const userInfoElement = document.getElementById("userinfo") as HTMLDivElement;
|
const userInfoElement = document.getElementById("userinfo") as HTMLDivElement;
|
||||||
userInfoElement.addEventListener("click", (event) => {
|
userInfoElement.addEventListener("click", (event) => {
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
showAccountSwitcher();
|
const rect = userInfoElement.getBoundingClientRect();
|
||||||
|
Localuser.userMenu.makemenu(rect.x, rect.top - 10 - window.innerHeight, thisUser);
|
||||||
});
|
});
|
||||||
|
|
||||||
const switchAccountsElement = document.getElementById("switchaccounts") as HTMLDivElement;
|
const switchAccountsElement = document.getElementById("switchaccounts") as HTMLDivElement;
|
||||||
switchAccountsElement.addEventListener("click", (event) => {
|
switchAccountsElement.addEventListener("click", (event) => {
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
showAccountSwitcher();
|
Localuser.showAccountSwitcher(thisUser);
|
||||||
});
|
});
|
||||||
|
|
||||||
let thisUser: Localuser;
|
let thisUser: Localuser;
|
||||||
try {
|
try {
|
||||||
const current = sessionStorage.getItem("currentuser") || users.currentuser;
|
const current = sessionStorage.getItem("currentuser") || Localuser.users.currentuser;
|
||||||
console.log(users.users, current);
|
if (!Localuser.users.users[current]) {
|
||||||
if (!users.users[current]) {
|
|
||||||
window.location.href = "/login";
|
window.location.href = "/login";
|
||||||
}
|
}
|
||||||
thisUser = new Localuser(users.users[current]);
|
thisUser = new Localuser(Localuser.users.users[current]);
|
||||||
thisUser.initwebsocket().then(() => {
|
thisUser.initwebsocket().then(() => {
|
||||||
thisUser.loaduser();
|
thisUser.loaduser();
|
||||||
thisUser.init();
|
thisUser.init();
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {Channel} from "./channel.js";
|
||||||
import {Direct} from "./direct.js";
|
import {Direct} from "./direct.js";
|
||||||
import {AVoice} from "./audio/voice.js";
|
import {AVoice} from "./audio/voice.js";
|
||||||
import {User} from "./user.js";
|
import {User} from "./user.js";
|
||||||
import {getapiurls, SW} from "./utils/utils.js";
|
import {getapiurls, getBulkUsers, SW} from "./utils/utils.js";
|
||||||
import {getBulkInfo, setTheme, Specialuser} from "./utils/utils.js";
|
import {getBulkInfo, setTheme, Specialuser} from "./utils/utils.js";
|
||||||
import {
|
import {
|
||||||
channeljson,
|
channeljson,
|
||||||
|
@ -30,6 +30,7 @@ import {Play} from "./audio/play.js";
|
||||||
import {Message} from "./message.js";
|
import {Message} from "./message.js";
|
||||||
import {badgeArr} from "./Dbadges.js";
|
import {badgeArr} from "./Dbadges.js";
|
||||||
import {Rights} from "./rights.js";
|
import {Rights} from "./rights.js";
|
||||||
|
import {Contextmenu} from "./contextmenu.js";
|
||||||
|
|
||||||
const wsCodesRetry = new Set([4000, 4001, 4002, 4003, 4005, 4007, 4008, 4009]);
|
const wsCodesRetry = new Set([4000, 4001, 4002, 4003, 4005, 4007, 4008, 4009]);
|
||||||
|
|
||||||
|
@ -75,6 +76,146 @@ class Localuser {
|
||||||
set perminfo(e) {
|
set perminfo(e) {
|
||||||
this.userinfo.localuserStore = e;
|
this.userinfo.localuserStore = e;
|
||||||
}
|
}
|
||||||
|
static users = getBulkUsers();
|
||||||
|
static showAccountSwitcher(thisUser: Localuser): void {
|
||||||
|
const table = document.createElement("div");
|
||||||
|
table.classList.add("flexttb", "accountSwitcher");
|
||||||
|
|
||||||
|
for (const user of Object.values(this.users.users)) {
|
||||||
|
const specialUser = user as Specialuser;
|
||||||
|
const userInfo = document.createElement("div");
|
||||||
|
userInfo.classList.add("flexltr", "switchtable");
|
||||||
|
|
||||||
|
const pfp = document.createElement("img");
|
||||||
|
pfp.src = specialUser.pfpsrc;
|
||||||
|
pfp.classList.add("pfp");
|
||||||
|
userInfo.append(pfp);
|
||||||
|
|
||||||
|
const userDiv = document.createElement("div");
|
||||||
|
userDiv.classList.add("userinfo");
|
||||||
|
userDiv.textContent = specialUser.username;
|
||||||
|
userDiv.append(document.createElement("br"));
|
||||||
|
|
||||||
|
const span = document.createElement("span");
|
||||||
|
span.textContent = specialUser.serverurls.wellknown
|
||||||
|
.replace("https://", "")
|
||||||
|
.replace("http://", "");
|
||||||
|
span.classList.add("serverURL");
|
||||||
|
userDiv.append(span);
|
||||||
|
|
||||||
|
userInfo.append(userDiv);
|
||||||
|
table.append(userInfo);
|
||||||
|
|
||||||
|
userInfo.addEventListener("click", () => {
|
||||||
|
thisUser.unload();
|
||||||
|
thisUser.swapped = true;
|
||||||
|
const loading = document.getElementById("loading") as HTMLDivElement;
|
||||||
|
loading.classList.remove("doneloading");
|
||||||
|
loading.classList.add("loading");
|
||||||
|
|
||||||
|
thisUser = new Localuser(specialUser);
|
||||||
|
Localuser.users.currentuser = specialUser.uid;
|
||||||
|
sessionStorage.setItem("currentuser", specialUser.uid);
|
||||||
|
localStorage.setItem("userinfos", JSON.stringify(Localuser.users));
|
||||||
|
|
||||||
|
thisUser.initwebsocket().then(() => {
|
||||||
|
thisUser.loaduser();
|
||||||
|
thisUser.init();
|
||||||
|
loading.classList.add("doneloading");
|
||||||
|
loading.classList.remove("loading");
|
||||||
|
console.log("done loading");
|
||||||
|
});
|
||||||
|
|
||||||
|
userInfo.remove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const switchAccountDiv = document.createElement("div");
|
||||||
|
switchAccountDiv.classList.add("switchtable");
|
||||||
|
switchAccountDiv.textContent = I18n.getTranslation("switchAccounts");
|
||||||
|
switchAccountDiv.addEventListener("click", () => {
|
||||||
|
window.location.href = "/login.html";
|
||||||
|
});
|
||||||
|
table.append(switchAccountDiv);
|
||||||
|
|
||||||
|
if (Contextmenu.currentmenu) {
|
||||||
|
Contextmenu.currentmenu.remove();
|
||||||
|
}
|
||||||
|
Contextmenu.currentmenu = table;
|
||||||
|
document.body.append(table);
|
||||||
|
}
|
||||||
|
static userMenu = this.generateUserMenu();
|
||||||
|
static generateUserMenu() {
|
||||||
|
const menu = new Contextmenu<Localuser, void>("");
|
||||||
|
menu.addButton(
|
||||||
|
() => I18n.localuser.addStatus(),
|
||||||
|
function () {
|
||||||
|
const d = new Dialog(I18n.localuser.status());
|
||||||
|
const opt = d.float.options.addForm(
|
||||||
|
"",
|
||||||
|
() => {
|
||||||
|
const status = cust.value;
|
||||||
|
sessionStorage.setItem("cstatus", JSON.stringify({text: status}));
|
||||||
|
//this.user.setstatus(status);
|
||||||
|
d.hide();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fetchURL: this.info.api + "/users/@me/settings",
|
||||||
|
method: "PATCH",
|
||||||
|
headers: this.headers,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
opt.addText(I18n.localuser.customStatusWarn());
|
||||||
|
opt.addPreprocessor((obj) => {
|
||||||
|
if ("custom_status" in obj) {
|
||||||
|
obj.custom_status = {text: obj.custom_status};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const cust = opt.addTextInput(I18n.localuser.status(), "custom_status", {});
|
||||||
|
d.show();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
menu.addButton(
|
||||||
|
() => I18n.localuser.status(),
|
||||||
|
function () {
|
||||||
|
const d = new Dialog(I18n.localuser.status());
|
||||||
|
const opt = d.float.options;
|
||||||
|
const selection = ["online", "invisible", "dnd", "idle"] as const;
|
||||||
|
opt.addText(I18n.localuser.statusWarn());
|
||||||
|
const smap = selection.map((_) => I18n.user[_]());
|
||||||
|
let index = selection.indexOf(
|
||||||
|
sessionStorage.getItem("status") as "online" | "invisible" | "dnd" | "idle",
|
||||||
|
);
|
||||||
|
if (index === -1) {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
opt
|
||||||
|
.addSelect("", () => {}, smap, {
|
||||||
|
defaultIndex: index,
|
||||||
|
})
|
||||||
|
.watchForChange(async (i) => {
|
||||||
|
const status = selection[i];
|
||||||
|
await fetch(this.info.api + "/users/@me/settings", {
|
||||||
|
body: JSON.stringify({
|
||||||
|
status,
|
||||||
|
}),
|
||||||
|
headers: this.headers,
|
||||||
|
method: "PATCH",
|
||||||
|
});
|
||||||
|
sessionStorage.setItem("status", status);
|
||||||
|
this.user.setstatus(status);
|
||||||
|
});
|
||||||
|
d.show();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
menu.addButton(
|
||||||
|
() => I18n.switchAccounts(),
|
||||||
|
function () {
|
||||||
|
Localuser.showAccountSwitcher(this);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
constructor(userinfo: Specialuser | -1) {
|
constructor(userinfo: Specialuser | -1) {
|
||||||
Play.playURL("/audio/sounds.jasf").then((_) => {
|
Play.playURL("/audio/sounds.jasf").then((_) => {
|
||||||
this.play = _;
|
this.play = _;
|
||||||
|
@ -104,7 +245,7 @@ class Localuser {
|
||||||
this.guilds = [];
|
this.guilds = [];
|
||||||
this.guildids = new Map();
|
this.guildids = new Map();
|
||||||
this.user = new User(ready.d.user, this);
|
this.user = new User(ready.d.user, this);
|
||||||
this.user.setstatus("online");
|
this.user.setstatus(sessionStorage.getItem("status") || "online");
|
||||||
this.resume_gateway_url = ready.d.resume_gateway_url;
|
this.resume_gateway_url = ready.d.resume_gateway_url;
|
||||||
this.session_id = ready.d.session_id;
|
this.session_id = ready.d.session_id;
|
||||||
|
|
||||||
|
@ -240,7 +381,7 @@ class Localuser {
|
||||||
},
|
},
|
||||||
compress: Boolean(DecompressionStream),
|
compress: Boolean(DecompressionStream),
|
||||||
presence: {
|
presence: {
|
||||||
status: "online",
|
status: sessionStorage.getItem("status") || "online",
|
||||||
since: null, //new Date().getTime()
|
since: null, //new Date().getTime()
|
||||||
activities: [],
|
activities: [],
|
||||||
afk: false,
|
afk: false,
|
||||||
|
@ -756,13 +897,13 @@ class Localuser {
|
||||||
for (const [role, list] of elms) {
|
for (const [role, list] of elms) {
|
||||||
members.forEach((member) => {
|
members.forEach((member) => {
|
||||||
if (role === "offline") {
|
if (role === "offline") {
|
||||||
if (member.user.getStatus() === "offline") {
|
if (member.user.getStatus() === "offline" || member.user.getStatus() === "invisible") {
|
||||||
list.push(member);
|
list.push(member);
|
||||||
members.delete(member);
|
members.delete(member);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (member.user.getStatus() === "offline") {
|
if (member.user.getStatus() === "offline" || member.user.getStatus() === "invisible") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (role !== "online" && member.hasRole(role.id)) {
|
if (role !== "online" && member.hasRole(role.id)) {
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
<button type="submit" id="loginButton">Login</button>
|
<button type="submit" id="loginButton">Login</button>
|
||||||
</form>
|
</form>
|
||||||
<a href="/register.html" id="switch">Don't have an account?</a>
|
<a href="/register.html" id="switch">Don't have an account?</a>
|
||||||
|
<div id="recover"></div>
|
||||||
</div>
|
</div>
|
||||||
<datalist id="instances"></datalist>
|
<datalist id="instances"></datalist>
|
||||||
<script src="/login.js" type="module"></script>
|
<script src="/login.js" type="module"></script>
|
||||||
|
|
|
@ -2,9 +2,35 @@ import {getBulkInfo, Specialuser} from "./utils/utils.js";
|
||||||
import {I18n} from "./i18n.js";
|
import {I18n} from "./i18n.js";
|
||||||
import {Dialog, FormError} from "./settings.js";
|
import {Dialog, FormError} from "./settings.js";
|
||||||
import {checkInstance} from "./utils/utils.js";
|
import {checkInstance} from "./utils/utils.js";
|
||||||
|
function generateRecArea() {
|
||||||
|
const recover = document.getElementById("recover");
|
||||||
|
if (!recover) return;
|
||||||
|
const can = localStorage.getItem("canRecover");
|
||||||
|
if (can) {
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.textContent = I18n.login.recover();
|
||||||
|
a.href = "/reset";
|
||||||
|
recover.append(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkInstance.alt = async (e) => {
|
||||||
|
const recover = document.getElementById("recover");
|
||||||
|
if (!recover) return;
|
||||||
|
recover.innerHTML = "";
|
||||||
|
try {
|
||||||
|
const json = (await (await fetch(e.api + "/policies/instance/config")).json()) as {
|
||||||
|
can_recover_account: boolean;
|
||||||
|
};
|
||||||
|
if (!json || !json.can_recover_account) throw Error("can't recover account");
|
||||||
|
localStorage.setItem("canRecover", "true");
|
||||||
|
generateRecArea();
|
||||||
|
} catch {
|
||||||
|
localStorage.removeItem("canRecover");
|
||||||
|
generateRecArea();
|
||||||
|
}
|
||||||
|
};
|
||||||
await I18n.done;
|
await I18n.done;
|
||||||
|
generateRecArea();
|
||||||
(async () => {
|
(async () => {
|
||||||
await I18n.done;
|
await I18n.done;
|
||||||
const instanceField = document.getElementById("instanceField");
|
const instanceField = document.getElementById("instanceField");
|
||||||
|
|
119
src/webpage/recover.ts
Normal file
119
src/webpage/recover.ts
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
import {I18n} from "./i18n.js";
|
||||||
|
import {adduser} from "./login.js";
|
||||||
|
import {Dialog, FormError} from "./settings.js";
|
||||||
|
await I18n.done;
|
||||||
|
const info = JSON.parse(localStorage.getItem("instanceinfo") as string);
|
||||||
|
|
||||||
|
function makeMenu2(email: string | void) {
|
||||||
|
const d2 = new Dialog(I18n.login.recovery());
|
||||||
|
const headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
};
|
||||||
|
const opt = d2.float.options.addForm(
|
||||||
|
"",
|
||||||
|
async (obj) => {
|
||||||
|
const serverurls = JSON.parse(localStorage.getItem("instanceinfo") as string);
|
||||||
|
|
||||||
|
if ("token" in obj && typeof obj.token === "string") {
|
||||||
|
if (email === undefined) {
|
||||||
|
const user = await (
|
||||||
|
await fetch(serverurls.api + "/users/@me", {
|
||||||
|
headers: {
|
||||||
|
Authorization: obj.token,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).json();
|
||||||
|
if ("email" in user && typeof user.email === "string") {
|
||||||
|
email = user.email;
|
||||||
|
} else {
|
||||||
|
throw new Error("stupid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const username = email;
|
||||||
|
adduser({
|
||||||
|
serverurls,
|
||||||
|
email: username,
|
||||||
|
token: obj.token,
|
||||||
|
}).username = username;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fetchURL: info.api + "/auth/reset",
|
||||||
|
method: "POST",
|
||||||
|
headers,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (email !== undefined) {
|
||||||
|
opt.addTextInput(I18n.login.pasteInfo(), "token");
|
||||||
|
}
|
||||||
|
opt.addTextInput(I18n.login.newPassword(), "password", {password: true});
|
||||||
|
const p2 = opt.addTextInput(I18n.login.enterPAgain(), "password2", {password: true});
|
||||||
|
opt.addPreprocessor((e) => {
|
||||||
|
const obj = e as unknown as {password: string; password2?: string; token?: string};
|
||||||
|
const token = obj.token || window.location.href;
|
||||||
|
if (URL.canParse(token)) {
|
||||||
|
obj.token = new URLSearchParams(token.split("#")[1]).get("token") as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.password !== obj.password2) {
|
||||||
|
throw new FormError(p2, I18n.localuser.PasswordsNoMatch());
|
||||||
|
}
|
||||||
|
delete obj.password2;
|
||||||
|
});
|
||||||
|
d2.show(false);
|
||||||
|
}
|
||||||
|
function makeMenu1() {
|
||||||
|
const d = new Dialog(I18n.login.recovery());
|
||||||
|
let area: HTMLElement | undefined = undefined;
|
||||||
|
const opt = d.float.options.addForm(
|
||||||
|
"",
|
||||||
|
(e) => {
|
||||||
|
if (Object.keys(e).length === 0) {
|
||||||
|
d.hide();
|
||||||
|
makeMenu2(email.value);
|
||||||
|
} else if ("captcha_sitekey" in e && typeof e.captcha_sitekey === "string") {
|
||||||
|
if (area) {
|
||||||
|
eval("hcaptcha.reset()");
|
||||||
|
} else {
|
||||||
|
area = document.createElement("div");
|
||||||
|
opt.addHTMLArea(area);
|
||||||
|
const capty = document.createElement("div");
|
||||||
|
capty.classList.add("h-captcha");
|
||||||
|
|
||||||
|
capty.setAttribute("data-sitekey", e.captcha_sitekey);
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = "https://js.hcaptcha.com/1/api.js";
|
||||||
|
area.append(script);
|
||||||
|
area.append(capty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fetchURL: info.api + "/auth/forgot",
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const email = opt.addTextInput(I18n.htmlPages.emailField(), "login");
|
||||||
|
opt.addPreprocessor((e) => {
|
||||||
|
if (area) {
|
||||||
|
try {
|
||||||
|
//@ts-expect-error
|
||||||
|
e.captcha_key = area.children[1].children[1].value;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
d.show(false);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
window.location.href.split("#").length == 2 &&
|
||||||
|
new URLSearchParams(window.location.href.split("#")[1]).has("token")
|
||||||
|
) {
|
||||||
|
makeMenu2();
|
||||||
|
} else {
|
||||||
|
makeMenu1();
|
||||||
|
}
|
27
src/webpage/reset.html
Normal file
27
src/webpage/reset.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Jank Client</title>
|
||||||
|
<meta content="Jank Client" property="og:title" />
|
||||||
|
<meta content="A spacebar client that has DMs, replying and more" property="og:description" />
|
||||||
|
<meta content="/logo.webp" property="og:image" />
|
||||||
|
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||||
|
<link href="/style.css" rel="stylesheet" />
|
||||||
|
<link href="/themes.css" rel="stylesheet" id="lightcss" />
|
||||||
|
<style>
|
||||||
|
body.no-theme {
|
||||||
|
background: #16191b;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
body.no-theme {
|
||||||
|
background: #9397bd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="no-theme">
|
||||||
|
<script src="/recover.js" type="module"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -351,7 +351,7 @@ class SelectInput implements OptionsElement<number> {
|
||||||
readonly label: string;
|
readonly label: string;
|
||||||
readonly owner: Options;
|
readonly owner: Options;
|
||||||
readonly onSubmit: (str: number) => void;
|
readonly onSubmit: (str: number) => void;
|
||||||
options: string[];
|
options: readonly string[];
|
||||||
index: number;
|
index: number;
|
||||||
select!: WeakRef<HTMLSelectElement>;
|
select!: WeakRef<HTMLSelectElement>;
|
||||||
radio: boolean;
|
radio: boolean;
|
||||||
|
@ -361,7 +361,7 @@ class SelectInput implements OptionsElement<number> {
|
||||||
constructor(
|
constructor(
|
||||||
label: string,
|
label: string,
|
||||||
onSubmit: (str: number) => void,
|
onSubmit: (str: number) => void,
|
||||||
options: string[],
|
options: readonly string[],
|
||||||
owner: Options,
|
owner: Options,
|
||||||
{defaultIndex = 0, radio = false} = {},
|
{defaultIndex = 0, radio = false} = {},
|
||||||
) {
|
) {
|
||||||
|
@ -619,7 +619,7 @@ class Dialog {
|
||||||
constructor(name: string, {ltr = false, noSubmit = true} = {}) {
|
constructor(name: string, {ltr = false, noSubmit = true} = {}) {
|
||||||
this.float = new Float(name, {ltr, noSubmit});
|
this.float = new Float(name, {ltr, noSubmit});
|
||||||
}
|
}
|
||||||
show() {
|
show(hideOnClick = true) {
|
||||||
const background = document.createElement("div");
|
const background = document.createElement("div");
|
||||||
background.classList.add("background");
|
background.classList.add("background");
|
||||||
const center = this.float.generateHTML();
|
const center = this.float.generateHTML();
|
||||||
|
@ -632,7 +632,9 @@ class Dialog {
|
||||||
document.body.append(background);
|
document.body.append(background);
|
||||||
this.background = new WeakRef(background);
|
this.background = new WeakRef(background);
|
||||||
background.onclick = (_) => {
|
background.onclick = (_) => {
|
||||||
background.remove();
|
if (hideOnClick) {
|
||||||
|
background.remove();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
hide() {
|
hide() {
|
||||||
|
@ -738,7 +740,7 @@ class Options implements OptionsElement<void> {
|
||||||
addSelect(
|
addSelect(
|
||||||
label: string,
|
label: string,
|
||||||
onSubmit: (str: number) => void,
|
onSubmit: (str: number) => void,
|
||||||
selections: string[],
|
selections: readonly string[],
|
||||||
{defaultIndex = 0, radio = false} = {},
|
{defaultIndex = 0, radio = false} = {},
|
||||||
) {
|
) {
|
||||||
const select = new SelectInput(label, onSubmit, selections, this, {
|
const select = new SelectInput(label, onSubmit, selections, this, {
|
||||||
|
|
|
@ -124,6 +124,9 @@ class User extends SnowFlake {
|
||||||
return this.status && this.status != "offline";
|
return this.status && this.status != "offline";
|
||||||
}
|
}
|
||||||
setstatus(status: string): void {
|
setstatus(status: string): void {
|
||||||
|
if (this.id === this.localuser.user.id) {
|
||||||
|
console.warn(status);
|
||||||
|
}
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,6 +485,7 @@ class User extends SnowFlake {
|
||||||
status.classList.add("statusDiv");
|
status.classList.add("statusDiv");
|
||||||
switch (await this.getStatus()) {
|
switch (await this.getStatus()) {
|
||||||
case "offline":
|
case "offline":
|
||||||
|
case "invisible":
|
||||||
status.classList.add("offlinestatus");
|
status.classList.add("offlinestatus");
|
||||||
break;
|
break;
|
||||||
case "online":
|
case "online":
|
||||||
|
|
|
@ -614,7 +614,7 @@ const checkInstance = Object.assign(
|
||||||
verify!.textContent = I18n.getTranslation("login.allGood");
|
verify!.textContent = I18n.getTranslation("login.allGood");
|
||||||
loginButton.disabled = false;
|
loginButton.disabled = false;
|
||||||
if (checkInstance.alt) {
|
if (checkInstance.alt) {
|
||||||
checkInstance.alt();
|
checkInstance.alt(instanceinfo);
|
||||||
}
|
}
|
||||||
setTimeout((_: any) => {
|
setTimeout((_: any) => {
|
||||||
console.log(verify!.textContent);
|
console.log(verify!.textContent);
|
||||||
|
@ -630,7 +630,16 @@ const checkInstance = Object.assign(
|
||||||
loginButton.disabled = true;
|
loginButton.disabled = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{} as {alt?: Function},
|
{} as {
|
||||||
|
alt?: (e: {
|
||||||
|
wellknown: string;
|
||||||
|
api: string;
|
||||||
|
cdn: string;
|
||||||
|
gateway: string;
|
||||||
|
login: string;
|
||||||
|
value: string;
|
||||||
|
}) => void;
|
||||||
|
},
|
||||||
);
|
);
|
||||||
export {checkInstance};
|
export {checkInstance};
|
||||||
export function getInstances() {
|
export function getInstances() {
|
||||||
|
|
|
@ -295,6 +295,10 @@
|
||||||
"save": "Save changes"
|
"save": "Save changes"
|
||||||
},
|
},
|
||||||
"localuser": {
|
"localuser": {
|
||||||
|
"addStatus": "Add status",
|
||||||
|
"status": "Status",
|
||||||
|
"statusWarn": "Spacebar has bugs with this feature and will only update after a refresh, and will often not respect it",
|
||||||
|
"customStatusWarn": "Spacebar does not support custom status being displayed at this time so while it'll accept the status, it will not do anything with it",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"userSettings": "User Settings",
|
"userSettings": "User Settings",
|
||||||
"themesAndSounds": "Themes & Sounds",
|
"themesAndSounds": "Themes & Sounds",
|
||||||
|
@ -331,7 +335,7 @@
|
||||||
"changePassword": "Change password",
|
"changePassword": "Change password",
|
||||||
"oldPassword:": "Old password:",
|
"oldPassword:": "Old password:",
|
||||||
"newPassword:": "New password:",
|
"newPassword:": "New password:",
|
||||||
"PasswordsNoMatch": "Password don't match",
|
"PasswordsNoMatch": "Passwords don't match",
|
||||||
"disableConnection": "This connection has been disabled server-side",
|
"disableConnection": "This connection has been disabled server-side",
|
||||||
"devPortal": "Developer Portal",
|
"devPortal": "Developer Portal",
|
||||||
"createApp": "Create application",
|
"createApp": "Create application",
|
||||||
|
@ -455,6 +459,9 @@
|
||||||
"copyId": "Copy user ID",
|
"copyId": "Copy user ID",
|
||||||
"online": "Online",
|
"online": "Online",
|
||||||
"offline": "Offline",
|
"offline": "Offline",
|
||||||
|
"invisible": "Invisible",
|
||||||
|
"dnd": "Do Not Disturb",
|
||||||
|
"idle": "Idle",
|
||||||
"message": "Message user",
|
"message": "Message user",
|
||||||
"block": "Block user",
|
"block": "Block user",
|
||||||
"unblock": "Unblock user",
|
"unblock": "Unblock user",
|
||||||
|
@ -471,7 +478,12 @@
|
||||||
"checking": "Checking Instance",
|
"checking": "Checking Instance",
|
||||||
"allGood": "All good",
|
"allGood": "All good",
|
||||||
"invalid": "Invalid Instance, try again",
|
"invalid": "Invalid Instance, try again",
|
||||||
"waiting": "Waiting to check Instance"
|
"waiting": "Waiting to check Instance",
|
||||||
|
"recover": "Forgot password?",
|
||||||
|
"pasteInfo": "Paste the recovery URL here:",
|
||||||
|
"newPassword": "New password:",
|
||||||
|
"enterPAgain": "Enter new password again:",
|
||||||
|
"recovery": "Forgotten password"
|
||||||
},
|
},
|
||||||
"member": {
|
"member": {
|
||||||
"kick": "Kick $1 from $2",
|
"kick": "Kick $1 from $2",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue