apply and fix ESlint

This commit is contained in:
MathMan05 2024-09-02 15:59:56 -05:00
parent f8b80b65fe
commit 19f08a6408
57 changed files with 8070 additions and 7943 deletions

View file

@ -9,7 +9,7 @@ class Voice {
source; source;
constructor(wave, freq, volume = 1) { constructor(wave, freq, volume = 1) {
this.audioCtx = new (window.AudioContext)(); this.audioCtx = new (window.AudioContext)();
this.info = { wave: wave, freq: freq }; this.info = { wave, freq };
this.playing = false; this.playing = false;
this.myArrayBuffer = this.audioCtx.createBuffer(1, this.audioCtx.sampleRate, this.audioCtx.sampleRate); this.myArrayBuffer = this.audioCtx.createBuffer(1, this.audioCtx.sampleRate, this.audioCtx.sampleRate);
this.gainNode = this.audioCtx.createGain(); this.gainNode = this.audioCtx.createGain();
@ -43,7 +43,7 @@ class Voice {
} }
} }
waveFunction() { waveFunction() {
if (typeof this.wave === 'function') { if (typeof this.wave === "function") {
return this.wave; return this.wave;
} }
switch (this.wave) { switch (this.wave) {
@ -92,9 +92,15 @@ class Voice {
case "three": { case "three": {
const voicy = new Voice("sin", 800); const voicy = new Voice("sin", 800);
voicy.play(); voicy.play();
setTimeout(_ => { voicy.freq = 1000; }, 50); setTimeout(_ => {
setTimeout(_ => { voicy.freq = 1300; }, 100); voicy.freq = 1000;
setTimeout(_ => { voicy.stop(); }, 150); }, 50);
setTimeout(_ => {
voicy.freq = 1300;
}, 100);
setTimeout(_ => {
voicy.stop();
}, 150);
break; break;
} }
case "zip": { case "zip": {
@ -102,23 +108,37 @@ class Voice {
return Math.sin(((t + 2) ** (Math.cos(t * 4))) * Math.PI * 2 * freq); return Math.sin(((t + 2) ** (Math.cos(t * 4))) * Math.PI * 2 * freq);
}, 700); }, 700);
voicy.play(); voicy.play();
setTimeout(_ => { voicy.stop(); }, 150); setTimeout(_ => {
voicy.stop();
}, 150);
break; break;
} }
case "square": { case "square": {
const voicy = new Voice("square", 600, .4); const voicy = new Voice("square", 600, 0.4);
voicy.play(); voicy.play();
setTimeout(_ => { voicy.freq = 800; }, 50); setTimeout(_ => {
setTimeout(_ => { voicy.freq = 1000; }, 100); voicy.freq = 800;
setTimeout(_ => { voicy.stop(); }, 150); }, 50);
setTimeout(_ => {
voicy.freq = 1000;
}, 100);
setTimeout(_ => {
voicy.stop();
}, 150);
break; break;
} }
case "beep": { case "beep": {
const voicy = new Voice("sin", 800); const voicy = new Voice("sin", 800);
voicy.play(); voicy.play();
setTimeout(_ => { voicy.stop(); }, 50); setTimeout(_ => {
setTimeout(_ => { voicy.play(); }, 100); voicy.stop();
setTimeout(_ => { voicy.stop(); }, 150); }, 50);
setTimeout(_ => {
voicy.play();
}, 100);
setTimeout(_ => {
voicy.stop();
}, 150);
break; break;
} }
} }
@ -127,13 +147,13 @@ class Voice {
return ["three", "zip", "square", "beep"]; return ["three", "zip", "square", "beep"];
} }
static setNotificationSound(sound) { static setNotificationSound(sound) {
let userinfos = getBulkInfo(); const userinfos = getBulkInfo();
userinfos.preferences.notisound = sound; userinfos.preferences.notisound = sound;
localStorage.setItem("userinfos", JSON.stringify(userinfos)); localStorage.setItem("userinfos", JSON.stringify(userinfos));
} }
static getNotificationSound() { static getNotificationSound() {
let userinfos = getBulkInfo(); const userinfos = getBulkInfo();
return userinfos.preferences.notisound; return userinfos.preferences.notisound;
} }
} }
export { Voice as Voice }; export { Voice };

View file

@ -58,10 +58,14 @@ class Channel {
this.contextmenu.addbutton("Delete channel", function () { this.contextmenu.addbutton("Delete channel", function () {
console.log(this); console.log(this);
this.deleteChannel(); this.deleteChannel();
}, null, function () { return this.isAdmin(); }); }, null, function () {
return this.isAdmin();
});
this.contextmenu.addbutton("Edit channel", function () { this.contextmenu.addbutton("Edit channel", function () {
this.editChannel(); this.editChannel();
}, null, function () { return this.isAdmin(); }); }, null, function () {
return this.isAdmin();
});
this.contextmenu.addbutton("Make invite", function () { this.contextmenu.addbutton("Make invite", function () {
this.createInvite(); this.createInvite();
}, null, function () { }, null, function () {
@ -148,12 +152,11 @@ class Channel {
} }
sortPerms() { sortPerms() {
this.permission_overwritesar.sort((a, b) => { this.permission_overwritesar.sort((a, b) => {
const order = this.guild.roles.findIndex(_ => _.snowflake === a[0]) - this.guild.roles.findIndex(_ => _.snowflake === b[0]); return this.guild.roles.findIndex(_ => _.snowflake === a[0]) - this.guild.roles.findIndex(_ => _.snowflake === b[0]);
return order;
}); });
} }
setUpInfiniteScroller() { setUpInfiniteScroller() {
this.infinite = new InfiniteScroller(async function (id, offset) { this.infinite = new InfiniteScroller((async (id, offset) => {
const snowflake = id; const snowflake = id;
if (offset === 1) { if (offset === 1) {
if (this.idToPrev.has(snowflake)) { if (this.idToPrev.has(snowflake)) {
@ -176,13 +179,12 @@ class Channel {
console.log("at bottom"); console.log("at bottom");
} }
} }
}.bind(this), async function (id) { }), (async (id) => {
//await new Promise(_=>{setTimeout(_,Math.random()*10)}) //await new Promise(_=>{setTimeout(_,Math.random()*10)})
const messgage = this.messages.get(id); const messgage = this.messages.get(id);
try { try {
if (messgage) { if (messgage) {
const html = messgage.buildhtml(); return messgage.buildhtml();
return html;
} }
else { else {
console.error(id + " not found"); console.error(id + " not found");
@ -191,18 +193,21 @@ class Channel {
catch (e) { catch (e) {
console.error(e); console.error(e);
} }
}.bind(this), async function (id) { return document.createElement("div");
}), (async (id) => {
const message = this.messages.get(id); const message = this.messages.get(id);
try { try {
if (message) { if (message) {
message.deleteDiv(); message.deleteDiv();
return true;
} }
} }
catch (e) { catch (e) {
console.error(e); console.error(e);
} }
finally { } finally { }
}.bind(this), this.readbottom.bind(this)); return false;
}), this.readbottom.bind(this));
} }
constructor(json, owner) { constructor(json, owner) {
if (json === -1) { if (json === -1) {
@ -227,7 +232,6 @@ class Channel {
if (thing.id === "1182819038095799904" || thing.id === "1182820803700625444") { if (thing.id === "1182819038095799904" || thing.id === "1182820803700625444") {
continue; continue;
} }
;
this.permission_overwrites.set(thing.id, new Permissions(thing.allow, thing.deny)); this.permission_overwrites.set(thing.id, new Permissions(thing.allow, thing.deny));
const permission = this.permission_overwrites.get(thing.id); const permission = this.permission_overwrites.get(thing.id);
if (permission) { if (permission) {
@ -268,7 +272,7 @@ class Channel {
if (!this.hasPermission("VIEW_CHANNEL")) { if (!this.hasPermission("VIEW_CHANNEL")) {
return false; return false;
} }
return this.lastmessageid !== this.lastreadmessageid && this.type !== 4 && !!this.lastmessageid; return this.lastmessageid !== this.lastreadmessageid && this.type !== 4 && Boolean(this.lastmessageid);
} }
hasPermission(name, member = this.guild.member) { hasPermission(name, member = this.guild.member) {
if (member.isAdmin()) { if (member.isAdmin()) {
@ -277,7 +281,7 @@ class Channel {
for (const thing of member.roles) { for (const thing of member.roles) {
const premission = this.permission_overwrites.get(thing.id); const premission = this.permission_overwrites.get(thing.id);
if (premission) { if (premission) {
let perm = premission.getPermission(name); const perm = premission.getPermission(name);
if (perm) { if (perm) {
return perm === 1; return perm === 1;
} }
@ -289,7 +293,7 @@ class Channel {
return false; return false;
} }
get canMessage() { get canMessage() {
if ((0 === this.permission_overwritesar.length) && this.hasPermission("MANAGE_CHANNELS")) { if ((this.permission_overwritesar.length === 0) && this.hasPermission("MANAGE_CHANNELS")) {
const role = this.guild.roles.find(_ => _.name === "@everyone"); const role = this.guild.roles.find(_ => _.name === "@everyone");
if (role) { if (role) {
this.addRoleToPerms(role); this.addRoleToPerms(role);
@ -298,7 +302,9 @@ class Channel {
return this.hasPermission("SEND_MESSAGES"); return this.hasPermission("SEND_MESSAGES");
} }
sortchildren() { sortchildren() {
this.children.sort((a, b) => { return a.position - b.position; }); this.children.sort((a, b) => {
return a.position - b.position;
});
} }
resolveparent(guild) { resolveparent(guild) {
const parentid = this.parent_id?.id; const parentid = this.parent_id?.id;
@ -313,7 +319,7 @@ class Channel {
} }
calculateReorder() { calculateReorder() {
let position = -1; let position = -1;
let build = []; const build = [];
for (const thing of this.children) { for (const thing of this.children) {
const thisthing = { id: thing.snowflake, position: undefined, parent_id: undefined }; const thisthing = { id: thing.snowflake, position: undefined, parent_id: undefined };
if (thing.position < position) { if (thing.position < position) {
@ -348,8 +354,13 @@ class Channel {
} }
div["all"] = this; div["all"] = this;
div.draggable = admin; div.draggable = admin;
div.addEventListener("dragstart", (e) => { Channel.dragged = [this, div]; e.stopImmediatePropagation(); }); div.addEventListener("dragstart", e => {
div.addEventListener("dragend", () => { Channel.dragged = []; }); Channel.dragged = [this, div];
e.stopImmediatePropagation();
});
div.addEventListener("dragend", () => {
Channel.dragged = [];
});
if (this.type === 4) { if (this.type === 4) {
this.sortchildren(); this.sortchildren();
const caps = document.createElement("div"); const caps = document.createElement("div");
@ -383,17 +394,19 @@ class Channel {
childrendiv.appendChild(channel.createguildHTML(admin)); childrendiv.appendChild(channel.createguildHTML(admin));
} }
childrendiv.classList.add("channels"); childrendiv.classList.add("channels");
setTimeout(_ => { childrendiv.style.height = childrendiv.scrollHeight + 'px'; }, 100); setTimeout(_ => {
childrendiv.style.height = childrendiv.scrollHeight + "px";
}, 100);
decdiv.onclick = function () { decdiv.onclick = function () {
if (childrendiv.style.height !== '0px') { if (childrendiv.style.height !== "0px") {
decoration.classList.add("hiddencat"); decoration.classList.add("hiddencat");
//childrendiv.classList.add("colapsediv"); //childrendiv.classList.add("colapsediv");
childrendiv.style.height = '0px'; childrendiv.style.height = "0px";
} }
else { else {
decoration.classList.remove("hiddencat"); decoration.classList.remove("hiddencat");
//childrendiv.classList.remove("colapsediv") //childrendiv.classList.remove("colapsediv")
childrendiv.style.height = childrendiv.scrollHeight + 'px'; childrendiv.style.height = childrendiv.scrollHeight + "px";
} }
}; };
div.appendChild(childrendiv); div.appendChild(childrendiv);
@ -479,14 +492,14 @@ class Channel {
} }
} }
coatDropDiv(div, container = false) { coatDropDiv(div, container = false) {
div.addEventListener("dragenter", (event) => { div.addEventListener("dragenter", event => {
console.log("enter"); console.log("enter");
event.preventDefault(); event.preventDefault();
}); });
div.addEventListener("dragover", (event) => { div.addEventListener("dragover", event => {
event.preventDefault(); event.preventDefault();
}); });
div.addEventListener("drop", (event) => { div.addEventListener("drop", event => {
const that = Channel.dragged[0]; const that = Channel.dragged[0];
if (!that) if (!that)
return; return;
@ -543,8 +556,8 @@ class Channel {
method: "POST", method: "POST",
headers: this.headers, headers: this.headers,
body: JSON.stringify({ body: JSON.stringify({
name: name, name,
type: type, type,
parent_id: this.snowflake, parent_id: this.snowflake,
permission_overwrites: [], permission_overwrites: [],
}) })
@ -558,22 +571,28 @@ class Channel {
const thistype = this.type; const thistype = this.type;
const full = new Dialog(["hdiv", const full = new Dialog(["hdiv",
["vdiv", ["vdiv",
["textbox", "Channel name:", this.name, function () { name = this.value; }], ["textbox", "Channel name:", this.name, function () {
["mdbox", "Channel topic:", this.topic, function () { topic = this.value; }], name = this.value;
["checkbox", "NSFW Channel", this.nsfw, function () { nsfw = this.checked; }], }],
["mdbox", "Channel topic:", this.topic, function () {
topic = this.value;
}],
["checkbox", "NSFW Channel", this.nsfw, function () {
nsfw = this.checked;
}],
["button", "", "submit", () => { ["button", "", "submit", () => {
fetch(this.info.api + "/channels/" + thisid, { fetch(this.info.api + "/channels/" + thisid, {
method: "PATCH", method: "PATCH",
headers: this.headers, headers: this.headers,
body: JSON.stringify({ body: JSON.stringify({
"name": name, name,
"type": thistype, type: thistype,
"topic": topic, topic,
"bitrate": 64000, bitrate: 64000,
"user_limit": 0, user_limit: 0,
"nsfw": nsfw, nsfw,
"flags": 0, flags: 0,
"rate_limit_per_user": 0 rate_limit_per_user: 0
}) })
}); });
console.log(full); console.log(full);
@ -683,7 +702,7 @@ class Channel {
for (let i = 0; i < 15; i++) { for (let i = 0; i < 15; i++) {
const div = document.createElement("div"); const div = document.createElement("div");
div.classList.add("loadingmessage"); div.classList.add("loadingmessage");
if (Math.random() < .5) { if (Math.random() < 0.5) {
const pfp = document.createElement("div"); const pfp = document.createElement("div");
pfp.classList.add("loadingpfp"); pfp.classList.add("loadingpfp");
const username = document.createElement("div"); const username = document.createElement("div");
@ -704,7 +723,6 @@ class Channel {
if (this.allthewayup) { if (this.allthewayup) {
return; return;
} }
;
if (this.lastreadmessageid && this.messages.has(this.lastreadmessageid)) { if (this.lastreadmessageid && this.messages.has(this.lastreadmessageid)) {
return; return;
} }
@ -715,7 +733,7 @@ class Channel {
if (response.length !== 100) { if (response.length !== 100) {
this.allthewayup = true; this.allthewayup = true;
} }
let prev = undefined; let prev;
for (const thing of response) { for (const thing of response) {
const message = new Message(thing, this); const message = new Message(thing, this);
if (prev) { if (prev) {
@ -747,7 +765,9 @@ class Channel {
} }
await fetch(this.info.api + "/channels/" + this.id + "/messages?limit=100&after=" + id, { await fetch(this.info.api + "/channels/" + this.id + "/messages?limit=100&after=" + id, {
headers: this.headers headers: this.headers
}).then((j) => { return j.json(); }).then(response => { }).then(j => {
return j.json();
}).then(response => {
let previd = id; let previd = id;
for (const i in response) { for (const i in response) {
let messager; let messager;
@ -769,7 +789,6 @@ class Channel {
} }
//out.buildmessages(); //out.buildmessages();
}); });
return;
} }
topid; topid;
async grabBefore(id) { async grabBefore(id) {
@ -778,7 +797,9 @@ class Channel {
} }
await fetch(this.info.api + "/channels/" + this.id + "/messages?before=" + id + "&limit=100", { await fetch(this.info.api + "/channels/" + this.id + "/messages?before=" + id + "&limit=100", {
headers: this.headers headers: this.headers
}).then((j) => { return j.json(); }).then((response) => { }).then(j => {
return j.json();
}).then((response) => {
if (response.length < 100) { if (response.length < 100) {
this.allthewayup = true; this.allthewayup = true;
if (response.length === 0) { if (response.length === 0) {
@ -801,7 +822,7 @@ class Channel {
this.idToPrev.set(previd, messager.id); this.idToPrev.set(previd, messager.id);
previd = messager.id; previd = messager.id;
this.messageids.set(messager.snowflake, messager); this.messageids.set(messager.snowflake, messager);
if (+i === response.length - 1 && response.length < 100) { if (Number(i) === response.length - 1 && response.length < 100) {
this.topid = previd; this.topid = previd;
} }
if (willbreak) { if (willbreak) {
@ -809,7 +830,6 @@ class Channel {
} }
} }
}); });
return;
} }
/** /**
* Please dont use this, its not implemented. * Please dont use this, its not implemented.
@ -900,7 +920,7 @@ class Channel {
while (flake && time < flaketime) { while (flake && time < flaketime) {
flake = this.idToPrev.get(flake); flake = this.idToPrev.get(flake);
if (!flake) { if (!flake) {
return undefined; return;
} }
flaketime = Number((BigInt(flake) >> 22n) + 1420070400000n); flaketime = Number((BigInt(flake) >> 22n) + 1420070400000n);
} }
@ -919,7 +939,6 @@ class Channel {
if (thing.id === "1182819038095799904" || thing.id === "1182820803700625444") { if (thing.id === "1182819038095799904" || thing.id === "1182820803700625444") {
continue; continue;
} }
;
this.permission_overwrites.set(thing.id, new Permissions(thing.allow, thing.deny)); this.permission_overwrites.set(thing.id, new Permissions(thing.allow, thing.deny));
const permisions = this.permission_overwrites.get(thing.id); const permisions = this.permission_overwrites.get(thing.id);
if (permisions) { if (permisions) {
@ -930,10 +949,10 @@ class Channel {
this.nsfw = json.nsfw; this.nsfw = json.nsfw;
} }
typingstart() { typingstart() {
if (this.typing > new Date().getTime()) { if (this.typing > Date.now()) {
return; return;
} }
this.typing = new Date().getTime() + 6000; this.typing = Date.now() + 6000;
fetch(this.info.api + "/channels/" + this.snowflake + "/typing", { fetch(this.info.api + "/channels/" + this.snowflake + "/typing", {
method: "POST", method: "POST",
headers: this.headers headers: this.headers
@ -941,11 +960,11 @@ class Channel {
} }
get notification() { get notification() {
let notinumber = this.message_notifications; let notinumber = this.message_notifications;
if (+notinumber === 3) { if (Number(notinumber) === 3) {
notinumber = null; notinumber = null;
} }
notinumber ??= this.guild.message_notifications; notinumber ??= this.guild.message_notifications;
switch (+notinumber) { switch (Number(notinumber)) {
case 0: case 0:
return "all"; return "all";
case 1: case 1:
@ -961,15 +980,14 @@ class Channel {
if (replyingto) { if (replyingto) {
replyjson = replyjson =
{ {
"guild_id": replyingto.guild.id, guild_id: replyingto.guild.id,
"channel_id": replyingto.channel.id, channel_id: replyingto.channel.id,
"message_id": replyingto.id, message_id: replyingto.id,
}; };
} }
;
if (attachments.length === 0) { if (attachments.length === 0) {
const body = { const body = {
content: content, content,
nonce: Math.floor(Math.random() * 1000000000), nonce: Math.floor(Math.random() * 1000000000),
message_reference: undefined message_reference: undefined
}; };
@ -985,21 +1003,21 @@ class Channel {
else { else {
const formData = new FormData(); const formData = new FormData();
const body = { const body = {
content: content, content,
nonce: Math.floor(Math.random() * 1000000000), nonce: Math.floor(Math.random() * 1000000000),
message_reference: undefined message_reference: undefined
}; };
if (replyjson) { if (replyjson) {
body.message_reference = replyjson; body.message_reference = replyjson;
} }
formData.append('payload_json', JSON.stringify(body)); formData.append("payload_json", JSON.stringify(body));
for (const i in attachments) { for (const i in attachments) {
formData.append("files[" + i + "]", attachments[i]); formData.append("files[" + i + "]", attachments[i]);
} }
return await fetch(this.info.api + "/channels/" + this.snowflake + "/messages", { return await fetch(this.info.api + "/channels/" + this.snowflake + "/messages", {
method: 'POST', method: "POST",
body: formData, body: formData,
headers: { "Authorization": this.headers.Authorization } headers: { Authorization: this.headers.Authorization }
}); });
} }
} }
@ -1084,7 +1102,6 @@ class Channel {
if (deep === 3) { if (deep === 3) {
return; return;
} }
;
this.notify(message, deep + 1); this.notify(message, deep + 1);
}); });
} }
@ -1115,7 +1132,7 @@ class Channel {
body: JSON.stringify({ body: JSON.stringify({
allow: permission.allow.toString(), allow: permission.allow.toString(),
deny: permission.deny.toString(), deny: permission.deny.toString(),
id: id, id,
type: 0 type: 0
}) })
}); });

View file

@ -5,7 +5,7 @@ class Contextmenu {
div; div;
static setup() { static setup() {
Contextmenu.currentmenu = ""; Contextmenu.currentmenu = "";
document.addEventListener('click', function (event) { document.addEventListener("click", event => {
if (Contextmenu.currentmenu == "") { if (Contextmenu.currentmenu == "") {
return; return;
} }
@ -50,8 +50,8 @@ class Contextmenu {
if (Contextmenu.currentmenu != "") { if (Contextmenu.currentmenu != "") {
Contextmenu.currentmenu.remove(); Contextmenu.currentmenu.remove();
} }
div.style.top = y + 'px'; div.style.top = y + "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);
console.log(div); console.log(div);
@ -59,7 +59,7 @@ class Contextmenu {
return this.div; return this.div;
} }
bindContextmenu(obj, addinfo, other) { bindContextmenu(obj, addinfo, other) {
const func = (event) => { const func = event => {
event.preventDefault(); event.preventDefault();
event.stopImmediatePropagation(); event.stopImmediatePropagation();
this.makemenu(event.clientX, event.clientY, addinfo, other); this.makemenu(event.clientX, event.clientY, addinfo, other);
@ -75,12 +75,12 @@ class Contextmenu {
console.log(box, docheight, docwidth); console.log(box, docheight, docwidth);
if (box.right > docwidth) { if (box.right > docwidth) {
console.log("test"); console.log("test");
obj.style.left = docwidth - box.width + 'px'; obj.style.left = docwidth - box.width + "px";
} }
if (box.bottom > docheight) { if (box.bottom > docheight) {
obj.style.top = docheight - box.height + 'px'; obj.style.top = docheight - box.height + "px";
} }
} }
} }
Contextmenu.setup(); Contextmenu.setup();
export { Contextmenu as Contextmenu }; export { Contextmenu };

View file

@ -58,7 +58,7 @@ class Dialog {
case "checkbox": case "checkbox":
{ {
const div = document.createElement("div"); const div = document.createElement("div");
const checkbox = document.createElement('input'); const checkbox = document.createElement("input");
div.appendChild(checkbox); div.appendChild(checkbox);
const label = document.createElement("span"); const label = document.createElement("span");
checkbox.checked = array[2]; checkbox.checked = array[2];
@ -71,7 +71,7 @@ class Dialog {
case "button": case "button":
{ {
const div = document.createElement("div"); const div = document.createElement("div");
const input = document.createElement('button'); const input = document.createElement("button");
const label = document.createElement("span"); const label = document.createElement("span");
input.textContent = array[2]; input.textContent = array[2];
label.textContent = array[1]; label.textContent = array[1];
@ -134,7 +134,7 @@ class Dialog {
case "radio": { case "radio": {
const div = document.createElement("div"); const div = document.createElement("div");
const fieldset = document.createElement("fieldset"); const fieldset = document.createElement("fieldset");
fieldset.addEventListener("change", function () { fieldset.addEventListener("change", () => {
let i = -1; let i = -1;
for (const thing of fieldset.children) { for (const thing of fieldset.children) {
i++; i++;
@ -173,9 +173,8 @@ class Dialog {
div.appendChild(fieldset); div.appendChild(fieldset);
return div; return div;
} }
case "html": { case "html":
return array[1]; return array[1];
}
case "select": { case "select": {
const div = document.createElement("div"); const div = document.createElement("div");
const label = document.createElement("label"); const label = document.createElement("label");
@ -227,7 +226,6 @@ class Dialog {
} }
default: default:
console.error("can't find element:" + array[0], " full element:" + array); console.error("can't find element:" + array[0], " full element:" + array);
return;
} }
} }
show() { show() {
@ -237,7 +235,9 @@ class Dialog {
this.background.classList.add("background"); this.background.classList.add("background");
document.body.appendChild(this.background); document.body.appendChild(this.background);
document.body.appendChild(this.html); document.body.appendChild(this.html);
this.background.onclick = _ => { this.hide(); }; this.background.onclick = _ => {
this.hide();
};
} }
hide() { hide() {
document.body.removeChild(this.background); document.body.removeChild(this.background);

View file

@ -96,7 +96,6 @@ class Group extends Channel {
this.messageids = new Map(); this.messageids = new Map();
this.permission_overwrites = new Map(); this.permission_overwrites = new Map();
this.lastmessageid = json.last_message_id; this.lastmessageid = json.last_message_id;
this.lastmessageid ??= null;
this.mentions = 0; this.mentions = 0;
this.setUpInfiniteScroller(); this.setUpInfiniteScroller();
if (this.lastmessageid) { if (this.lastmessageid) {
@ -140,8 +139,8 @@ class Group extends Channel {
const messagez = new Message(messagep.d, this); const messagez = new Message(messagep.d, this);
if (this.lastmessageid) { if (this.lastmessageid) {
this.idToNext.set(this.lastmessageid, messagez.id); this.idToNext.set(this.lastmessageid, messagez.id);
}
this.idToPrev.set(messagez.id, this.lastmessageid); this.idToPrev.set(messagez.id, this.lastmessageid);
}
this.lastmessageid = messagez.id; this.lastmessageid = messagez.id;
this.messageids.set(messagez.snowflake, messagez); this.messageids.set(messagez.snowflake, messagez);
if (messagez.author === this.localuser.user) { if (messagez.author === this.localuser.user) {

View file

@ -119,7 +119,6 @@ class Embed {
if (this.json?.timestamp) { if (this.json?.timestamp) {
const span = document.createElement("span"); const span = document.createElement("span");
span.textContent = new Date(this.json.timestamp).toLocaleString(); span.textContent = new Date(this.json.timestamp).toLocaleString();
;
footer.append(span); footer.append(span);
} }
embed.append(footer); embed.append(footer);

View file

@ -62,10 +62,8 @@ class Emoji {
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
array[i] = read8(); array[i] = read8();
} }
const decoded = new TextDecoder("utf-8").decode(array.buffer);
;
//console.log(array); //console.log(array);
return decoded; return new TextDecoder("utf-8").decode(array.buffer);
} }
const build = []; const build = [];
let cats = read16(); let cats = read16();
@ -78,7 +76,7 @@ class Emoji {
const name = readString8(); const name = readString8();
const len = read8(); const len = read8();
const skin_tone_support = len > 127; const skin_tone_support = len > 127;
const emoji = readStringNo(len - (+skin_tone_support * 128)); const emoji = readStringNo(len - (Number(skin_tone_support) * 128));
emojis.push({ emojis.push({
name, name,
skin_tone_support, skin_tone_support,
@ -102,7 +100,9 @@ class Emoji {
} }
static async emojiPicker(x, y, localuser) { static async emojiPicker(x, y, localuser) {
let res; let res;
const promise = new Promise((r) => { res = r; }); const promise = new Promise(r => {
res = r;
});
const menu = document.createElement("div"); const menu = document.createElement("div");
menu.classList.add("flextttb", "emojiPicker"); menu.classList.add("flextttb", "emojiPicker");
menu.style.top = y + "px"; menu.style.top = y + "px";

View file

@ -31,7 +31,7 @@ class File {
this.width /= scale; this.width /= scale;
this.height /= scale; this.height /= scale;
} }
if (this.content_type.startsWith('image/')) { if (this.content_type.startsWith("image/")) {
const div = document.createElement("div"); const div = document.createElement("div");
const img = document.createElement("img"); const img = document.createElement("img");
img.classList.add("messageimg"); img.classList.add("messageimg");
@ -50,7 +50,7 @@ class File {
console.log(this.width, this.height); console.log(this.width, this.height);
return div; return div;
} }
else if (this.content_type.startsWith('video/')) { else if (this.content_type.startsWith("video/")) {
const video = document.createElement("video"); const video = document.createElement("video");
const source = document.createElement("source"); const source = document.createElement("source");
source.src = src; source.src = src;
@ -63,7 +63,7 @@ class File {
} }
return video; return video;
} }
else if (this.content_type.startsWith('audio/')) { else if (this.content_type.startsWith("audio/")) {
const audio = document.createElement("audio"); const audio = document.createElement("audio");
const source = document.createElement("source"); const source = document.createElement("source");
source.src = src; source.src = src;
@ -138,8 +138,8 @@ class File {
return div; return div;
} }
static filesizehuman(fsize) { static filesizehuman(fsize) {
var i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024)); const i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024));
return +((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + ' ' + ['Bytes', 'Kilobytes', 'Megabytes', 'Gigabytes', 'Terabytes'][i]; return Number((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + " " + ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i];
} }
} }
export { File }; export { File };

View file

@ -149,7 +149,7 @@ class Guild {
method: "PATCH", method: "PATCH",
headers: this.headers, headers: this.headers,
body: JSON.stringify({ body: JSON.stringify({
"message_notifications": noti message_notifications: noti
}) })
}); });
this.message_notifications = noti; this.message_notifications = noti;
@ -202,7 +202,7 @@ class Guild {
} }
calculateReorder() { calculateReorder() {
let position = -1; let position = -1;
let build = []; const build = [];
for (const thing of this.headchannels) { for (const thing of this.headchannels) {
const thisthing = { id: thing.snowflake, position: undefined, parent_id: undefined }; const thisthing = { id: thing.snowflake, position: undefined, parent_id: undefined };
if (thing.position <= position) { if (thing.position <= position) {
@ -256,7 +256,9 @@ class Guild {
return this.owner.info; return this.owner.info;
} }
sortchannels() { sortchannels() {
this.headchannels.sort((a, b) => { return a.position - b.position; }); this.headchannels.sort((a, b) => {
return a.position - b.position;
});
} }
generateGuildIcon() { generateGuildIcon() {
const divy = document.createElement("div"); const divy = document.createElement("div");
@ -279,7 +281,7 @@ class Guild {
} }
else { else {
const div = document.createElement("div"); const div = document.createElement("div");
let build = this.properties.name.replace(/'s /g, " ").replace(/\w+/g, word => word[0]).replace(/\s/g, ""); const build = this.properties.name.replace(/'s /g, " ").replace(/\w+/g, word => word[0]).replace(/\s/g, "");
div.textContent = build; div.textContent = build;
div.classList.add("blankserver", "servericon"); div.classList.add("blankserver", "servericon");
divy.appendChild(div); divy.appendChild(div);
@ -336,7 +338,7 @@ class Guild {
headers: this.headers, headers: this.headers,
}); });
} }
unreads(html = undefined) { unreads(html) {
if (html) { if (html) {
this.html = html; this.html = html;
} }
@ -399,7 +401,7 @@ class Guild {
} }
return this.member.hasRole(r); return this.member.hasRole(r);
} }
loadChannel(ID = undefined) { loadChannel(ID) {
if (ID && this.channelids[ID]) { if (ID && this.channelids[ID]) {
this.channelids[ID].getHTML(); this.channelids[ID].getHTML();
return; return;
@ -451,7 +453,7 @@ class Guild {
["voice", "text", "announcement"], ["voice", "text", "announcement"],
function (e) { function (e) {
console.log(e); console.log(e);
category = { "text": 0, "voice": 2, "announcement": 5, "category": 4 }[e]; category = { text: 0, voice: 2, announcement: 5, category: 4 }[e];
}, },
1 1
], ],
@ -463,12 +465,12 @@ class Guild {
console.log(name, category); console.log(name, category);
func(name, category); func(name, category);
channelselect.hide(); channelselect.hide();
}.bind(this)]]); }]]);
channelselect.show(); channelselect.show();
} }
createcategory() { createcategory() {
let name = ""; let name = "";
let category = 4; const category = 4;
const channelselect = new Dialog(["vdiv", const channelselect = new Dialog(["vdiv",
["textbox", "Name of category", "", function () { ["textbox", "Name of category", "", function () {
console.log(this); console.log(this);
@ -510,7 +512,7 @@ class Guild {
fetch(this.info.api + "/guilds/" + this.snowflake + "/channels", { fetch(this.info.api + "/guilds/" + this.snowflake + "/channels", {
method: "POST", method: "POST",
headers: this.headers, headers: this.headers,
body: JSON.stringify({ name: name, type: type }) body: JSON.stringify({ name, type })
}); });
} }
async createRole(name) { async createRole(name) {
@ -518,7 +520,7 @@ class Guild {
method: "POST", method: "POST",
headers: this.headers, headers: this.headers,
body: JSON.stringify({ body: JSON.stringify({
name: name, name,
color: 0, color: 0,
permissions: "0" permissions: "0"
}) })

View file

@ -33,7 +33,7 @@ fetch("/instances.json").then(_ => _.json()).then((json) => {
if (instance.descriptionLong) { if (instance.descriptionLong) {
p.innerText = instance.descriptionLong; p.innerText = instance.descriptionLong;
} }
else { else if (instance.description) {
p.innerText = instance.description; p.innerText = instance.description;
} }
textbox.append(p); textbox.append(p);

View file

@ -6,8 +6,10 @@ import { File } from "./file.js";
(async () => { (async () => {
async function waitforload() { async function waitforload() {
let res; let res;
new Promise(r => { res = r; }); new Promise(r => {
document.addEventListener("DOMContentLoaded", function () { res = r;
});
document.addEventListener("DOMContentLoaded", () => {
res(); res();
}); });
await res; await res;
@ -15,7 +17,7 @@ import { File } from "./file.js";
await waitforload(); await waitforload();
const users = getBulkUsers(); const users = getBulkUsers();
if (!users.currentuser) { if (!users.currentuser) {
window.location.href = '/login.html'; window.location.href = "/login.html";
} }
function showAccountSwitcher() { function showAccountSwitcher() {
const table = document.createElement("div"); const table = document.createElement("div");
@ -45,7 +47,7 @@ import { File } from "./file.js";
loading.classList.remove("doneloading"); loading.classList.remove("doneloading");
loading.classList.add("loading"); loading.classList.add("loading");
thisuser = new Localuser(specialuser); thisuser = new Localuser(specialuser);
users["currentuser"] = specialuser.uid; users.currentuser = specialuser.uid;
localStorage.setItem("userinfos", JSON.stringify(users)); localStorage.setItem("userinfos", JSON.stringify(users));
thisuser.initwebsocket().then(_ => { thisuser.initwebsocket().then(_ => {
thisuser.loaduser(); thisuser.loaduser();
@ -107,16 +109,20 @@ import { File } from "./file.js";
} }
{ {
const menu = new Contextmenu("create rightclick"); //Really should go into the localuser class, but that's a later thing const menu = new Contextmenu("create rightclick"); //Really should go into the localuser class, but that's a later thing
menu.addbutton("Create channel", function () { menu.addbutton("Create channel", () => {
if (thisuser.lookingguild) { if (thisuser.lookingguild) {
thisuser.lookingguild.createchannels(); thisuser.lookingguild.createchannels();
} }
}, null, _ => { return thisuser.isAdmin(); }); }, null, _ => {
menu.addbutton("Create category", function () { return thisuser.isAdmin();
});
menu.addbutton("Create category", () => {
if (thisuser.lookingguild) { if (thisuser.lookingguild) {
thisuser.lookingguild.createcategory(); thisuser.lookingguild.createcategory();
} }
}, null, _ => { return thisuser.isAdmin(); }); }, null, _ => {
return thisuser.isAdmin();
});
menu.bindContextmenu(document.getElementById("channels"), 0, 0); menu.bindContextmenu(document.getElementById("channels"), 0, 0);
} }
const pasteimage = document.getElementById("pasteimage"); const pasteimage = document.getElementById("pasteimage");
@ -134,7 +140,7 @@ import { File } from "./file.js";
} }
else { else {
replyingto = thisuser.channelfocus.replyingto; replyingto = thisuser.channelfocus.replyingto;
let replying = replyingto; const replying = replyingto;
if (replyingto?.div) { if (replyingto?.div) {
replyingto.div.classList.remove("replying"); replyingto.div.classList.remove("replying");
} }
@ -151,7 +157,6 @@ import { File } from "./file.js";
pasteimage.removeChild(imageshtml.pop()); pasteimage.removeChild(imageshtml.pop());
} }
typebox.innerHTML = ""; typebox.innerHTML = "";
return;
} }
} }
const typebox = document.getElementById("typebox"); const typebox = document.getElementById("typebox");
@ -174,7 +179,7 @@ import { File } from "./file.js";
*/ */
const images = []; const images = [];
const imageshtml = []; const imageshtml = [];
document.addEventListener('paste', async (e) => { document.addEventListener("paste", async (e) => {
if (!e.clipboardData) if (!e.clipboardData)
return; return;
Array.from(e.clipboardData.files).forEach(async (f) => { Array.from(e.clipboardData.files).forEach(async (f) => {

View file

@ -32,7 +32,7 @@ class InfiniteScroller {
this.watchForChange(); this.watchForChange();
}); });
this.scroll.addEventListener("scroll", _ => { this.scroll.addEventListener("scroll", _ => {
if (null === this.timeout) { if (this.timeout === null) {
this.timeout = setTimeout(this.updatestuff.bind(this), 300); this.timeout = setTimeout(this.updatestuff.bind(this), 300);
} }
this.watchForChange(); this.watchForChange();
@ -71,11 +71,9 @@ class InfiniteScroller {
this.averageheight = 60; this.averageheight = 60;
} }
this.scrollTop = this.scroll.scrollTop; this.scrollTop = this.scroll.scrollTop;
if (!this.scrollBottom) { if (!this.scrollBottom && !await this.watchForChange()) {
if (!await this.watchForChange()) {
this.reachesBottom(); this.reachesBottom();
} }
}
if (!this.scrollTop) { if (!this.scrollTop) {
await this.watchForChange(); await this.watchForChange();
} }
@ -129,7 +127,6 @@ class InfiniteScroller {
this.HTMLElements.unshift([html, nextid]); this.HTMLElements.unshift([html, nextid]);
this.scrollTop += this.averageheight; this.scrollTop += this.averageheight;
} }
;
} }
if (this.scrollTop > this.maxDist) { if (this.scrollTop > this.maxDist) {
const html = this.HTMLElements.shift(); const html = this.HTMLElements.shift();
@ -176,7 +173,6 @@ class InfiniteScroller {
this.HTMLElements.push([html, nextid]); this.HTMLElements.push([html, nextid]);
this.scrollBottom += this.averageheight; this.scrollBottom += this.averageheight;
} }
;
} }
if (scrollBottom > this.maxDist) { if (scrollBottom > this.maxDist) {
const html = this.HTMLElements.pop(); const html = this.HTMLElements.pop();
@ -225,14 +221,14 @@ class InfiniteScroller {
} }
const out = await Promise.allSettled([this.watchForTop(), this.watchForBottom()]); const out = await Promise.allSettled([this.watchForTop(), this.watchForBottom()]);
const changed = (out[0].value || out[1].value); const changed = (out[0].value || out[1].value);
if (null === this.timeout && changed) { if (this.timeout === null && changed) {
this.timeout = setTimeout(this.updatestuff.bind(this), 300); this.timeout = setTimeout(this.updatestuff.bind(this), 300);
} }
if (!this.currrunning) { if (!this.currrunning) {
console.error("something really bad happened"); console.error("something really bad happened");
} }
res(!!changed); res(Boolean(changed));
return !!changed; return Boolean(changed);
} }
catch (e) { catch (e) {
console.error(e); console.error(e);

View file

@ -11,7 +11,7 @@ import { getBulkUsers, getapiurls } from "./login.js";
console.log(users.users[thing]); console.log(users.users[thing]);
} }
let urls; let urls;
if (!joinable.length) { if (!joinable.length && well) {
const out = await getapiurls(well); const out = await getapiurls(well);
if (out) { if (out) {
urls = out; urls = out;
@ -24,7 +24,7 @@ import { getBulkUsers, getapiurls } from "./login.js";
} }
} }
else { else {
throw Error("someone needs to handle the case where the servers don't exist"); throw new Error("someone needs to handle the case where the servers don't exist");
} }
} }
else { else {
@ -86,7 +86,7 @@ import { getBulkUsers, getapiurls } from "./login.js";
Authorization: thing.token Authorization: thing.token
} }
}).then(_ => { }).then(_ => {
users["currentuser"] = specialuser.uid; users.currentuser = specialuser.uid;
localStorage.setItem("userinfos", JSON.stringify(users)); localStorage.setItem("userinfos", JSON.stringify(users));
window.location.href = "/channels/" + guildinfo.id; window.location.href = "/channels/" + guildinfo.id;
}); });

View file

@ -22,13 +22,13 @@ function trimswitcher() {
for (const thing in json.users) { for (const thing in json.users) {
const user = json.users[thing]; const user = json.users[thing];
let wellknown = user.serverurls.wellknown; let wellknown = user.serverurls.wellknown;
if (wellknown[wellknown.length - 1] !== "/") { if (wellknown.at(-1) !== "/") {
wellknown += "/"; wellknown += "/";
} }
wellknown += user.username; wellknown += user.username;
if (map.has(wellknown)) { if (map.has(wellknown)) {
const otheruser = map.get(wellknown); const otheruser = map.get(wellknown);
if (otheruser[1].serverurls.wellknown[otheruser[1].serverurls.wellknown.length - 1] === "/") { if (otheruser[1].serverurls.wellknown.at(-1) === "/") {
delete json.users[otheruser[0]]; delete json.users[otheruser[0]];
map.set(wellknown, [thing, user]); map.set(wellknown, [thing, user]);
} }
@ -41,7 +41,7 @@ function trimswitcher() {
} }
} }
for (const thing in json.users) { for (const thing in json.users) {
if (thing[thing.length - 1] === "/") { if (thing.at(-1) === "/") {
const user = json.users[thing]; const user = json.users[thing];
delete json.users[thing]; delete json.users[thing];
json.users[thing.slice(0, -1)] = user; json.users[thing.slice(0, -1)] = user;
@ -73,7 +73,7 @@ function setDefaults() {
if (userinfos.accent_color === undefined) { if (userinfos.accent_color === undefined) {
userinfos.accent_color = "#242443"; userinfos.accent_color = "#242443";
} }
document.documentElement.style.setProperty('--accent-color', userinfos.accent_color); document.documentElement.style.setProperty("--accent-color", userinfos.accent_color);
if (userinfos.preferences === undefined) { if (userinfos.preferences === undefined) {
userinfos.preferences = { userinfos.preferences = {
theme: "Dark", theme: "Dark",
@ -103,11 +103,8 @@ class Specialuser {
this.serverurls.api = apistring; this.serverurls.api = apistring;
this.serverurls.cdn = new URL(json.serverurls.cdn).toString().replace(/\/$/, ""); this.serverurls.cdn = new URL(json.serverurls.cdn).toString().replace(/\/$/, "");
this.serverurls.gateway = new URL(json.serverurls.gateway).toString().replace(/\/$/, ""); this.serverurls.gateway = new URL(json.serverurls.gateway).toString().replace(/\/$/, "");
;
this.serverurls.wellknown = new URL(json.serverurls.wellknown).toString().replace(/\/$/, ""); this.serverurls.wellknown = new URL(json.serverurls.wellknown).toString().replace(/\/$/, "");
;
this.serverurls.login = new URL(json.serverurls.login).toString().replace(/\/$/, ""); this.serverurls.login = new URL(json.serverurls.login).toString().replace(/\/$/, "");
;
this.email = json.email; this.email = json.email;
this.token = json.token; this.token = json.token;
this.loggedin = json.loggedin; this.loggedin = json.loggedin;
@ -178,12 +175,12 @@ async function getapiurls(str) {
} }
} }
} }
if (str[str.length - 1] !== "/") { if (str.at(-1) !== "/") {
str += "/"; str += "/";
} }
let api; let api;
try { try {
const info = await fetch(`${str}/.well-known/spacebar`).then((x) => x.json()); const info = await fetch(`${str}/.well-known/spacebar`).then(x => x.json());
api = info.api; api = info.api;
} }
catch { catch {
@ -191,7 +188,7 @@ async function getapiurls(str) {
} }
const url = new URL(api); const url = new URL(api);
try { try {
const info = await fetch(`${api}${url.pathname.includes("api") ? "" : "api"}/policies/instance/domains`).then((x) => x.json()); const info = await fetch(`${api}${url.pathname.includes("api") ? "" : "api"}/policies/instance/domains`).then(x => x.json());
return { return {
api: info.apiEndpoint, api: info.apiEndpoint,
gateway: info.gateway, gateway: info.gateway,
@ -226,8 +223,8 @@ async function checkInstance(e) {
instanceinfo.value = instancein.value; instanceinfo.value = instancein.value;
localStorage.setItem("instanceinfo", JSON.stringify(instanceinfo)); localStorage.setItem("instanceinfo", JSON.stringify(instanceinfo));
verify.textContent = "Instance is all good"; verify.textContent = "Instance is all good";
if (checkInstance["alt"]) { if (checkInstance.alt) {
checkInstance["alt"](); checkInstance.alt();
} }
setTimeout(_ => { setTimeout(_ => {
console.log(verify.textContent); console.log(verify.textContent);
@ -238,7 +235,7 @@ async function checkInstance(e) {
verify.textContent = "Invalid Instance, try again"; verify.textContent = "Invalid Instance, try again";
} }
} }
catch (e) { catch {
console.log("catch"); console.log("catch");
verify.textContent = "Invalid Instance, try again"; verify.textContent = "Invalid Instance, try again";
} }
@ -271,10 +268,10 @@ async function login(username, password, captcha) {
const options = { const options = {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
"login": username, login: username,
"password": password, password,
"undelete": false, undelete: false,
"captcha_key": captcha captcha_key: captcha
}), }),
headers: { headers: {
"Content-type": "application/json; charset=UTF-8", "Content-type": "application/json; charset=UTF-8",
@ -283,10 +280,10 @@ async function login(username, password, captcha) {
try { try {
const info = JSON.parse(localStorage.getItem("instanceinfo")); const info = JSON.parse(localStorage.getItem("instanceinfo"));
const api = info.login + (info.login.startsWith("/") ? "/" : ""); const api = info.login + (info.login.startsWith("/") ? "/" : "");
return await fetch(api + '/auth/login', options).then(response => response.json()) return await fetch(api + "/auth/login", options).then(response => response.json())
.then((response) => { .then(response => {
console.log(response, response.message); console.log(response, response.message);
if ("Invalid Form Body" === response.message) { if (response.message === "Invalid Form Body") {
return response.errors.login._errors[0].message; return response.errors.login._errors[0].message;
console.log("test"); console.log("test");
} }
@ -306,13 +303,14 @@ async function login(username, password, captcha) {
else { else {
eval("hcaptcha.reset()"); eval("hcaptcha.reset()");
} }
return;
} }
else { else {
console.log(response); console.log(response);
if (response.ticket) { if (response.ticket) {
let onetimecode = ""; let onetimecode = "";
new Dialog(["vdiv", ["title", "2FA code:"], ["textbox", "", "", function () { onetimecode = this.value; }], ["button", "", "Submit", function () { new Dialog(["vdiv", ["title", "2FA code:"], ["textbox", "", "", function () {
onetimecode = this.value;
}], ["button", "", "Submit", function () {
fetch(api + "/auth/mfa/totp", { fetch(api + "/auth/mfa/totp", {
method: "POST", method: "POST",
headers: { headers: {
@ -336,7 +334,7 @@ async function login(username, password, captcha) {
window.location.href = redir; window.location.href = redir;
} }
else { else {
window.location.href = '/channels/@me'; window.location.href = "/channels/@me";
} }
} }
}); });
@ -352,7 +350,7 @@ async function login(username, password, captcha) {
window.location.href = redir; window.location.href = redir;
} }
else { else {
window.location.href = '/channels/@me'; window.location.href = "/channels/@me";
} }
return ""; return "";
} }
@ -360,13 +358,12 @@ async function login(username, password, captcha) {
}); });
} }
catch (error) { catch (error) {
console.error('Error:', error); console.error("Error:", error);
} }
;
} }
async function check(e) { async function check(e) {
e.preventDefault(); e.preventDefault();
let h = await login(e.srcElement[1].value, e.srcElement[2].value, e.srcElement[3].value); const h = await login(e.srcElement[1].value, e.srcElement[2].value, e.srcElement[3].value);
document.getElementById("wrong").textContent = h; document.getElementById("wrong").textContent = h;
console.log(h); console.log(h);
} }

View file

@ -28,7 +28,7 @@ class MarkDown {
return this.makeHTML().textContent; return this.makeHTML().textContent;
} }
makeHTML({ keep = this.keep, stdsize = this.stdsize } = {}) { makeHTML({ keep = this.keep, stdsize = this.stdsize } = {}) {
return this.markdown(this.txt, { keep: keep, stdsize: stdsize }); return this.markdown(this.txt, { keep, stdsize });
} }
markdown(text, { keep = false, stdsize = false } = {}) { markdown(text, { keep = false, stdsize = false } = {}) {
let txt; let txt;
@ -105,7 +105,7 @@ class MarkDown {
if (keep) { if (keep) {
element.append(keepys); element.append(keepys);
} }
element.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize })); element.appendChild(this.markdown(build, { keep, stdsize }));
span.append(element); span.append(element);
} }
finally { finally {
@ -179,7 +179,7 @@ class MarkDown {
} }
else { else {
const pre = document.createElement("pre"); const pre = document.createElement("pre");
if (build[build.length - 1] === "\n") { if (build.at(-1) === "\n") {
build = build.substring(0, build.length - 1); build = build.substring(0, build.length - 1);
} }
if (txt[i] === "\n") { if (txt[i] === "\n") {
@ -224,7 +224,7 @@ class MarkDown {
if (keep) { if (keep) {
i.append(stars); i.append(stars);
} }
i.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize })); i.appendChild(this.markdown(build, { keep, stdsize }));
if (keep) { if (keep) {
i.append(stars); i.append(stars);
} }
@ -235,7 +235,7 @@ class MarkDown {
if (keep) { if (keep) {
b.append(stars); b.append(stars);
} }
b.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize })); b.appendChild(this.markdown(build, { keep, stdsize }));
if (keep) { if (keep) {
b.append(stars); b.append(stars);
} }
@ -247,7 +247,7 @@ class MarkDown {
if (keep) { if (keep) {
b.append(stars); b.append(stars);
} }
b.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize })); b.appendChild(this.markdown(build, { keep, stdsize }));
if (keep) { if (keep) {
b.append(stars); b.append(stars);
} }
@ -290,7 +290,7 @@ class MarkDown {
if (keep) { if (keep) {
i.append(underscores); i.append(underscores);
} }
i.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize })); i.appendChild(this.markdown(build, { keep, stdsize }));
if (keep) { if (keep) {
i.append(underscores); i.append(underscores);
} }
@ -301,7 +301,7 @@ class MarkDown {
if (keep) { if (keep) {
u.append(underscores); u.append(underscores);
} }
u.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize })); u.appendChild(this.markdown(build, { keep, stdsize }));
if (keep) { if (keep) {
u.append(underscores); u.append(underscores);
} }
@ -313,7 +313,7 @@ class MarkDown {
if (keep) { if (keep) {
i.append(underscores); i.append(underscores);
} }
i.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize })); i.appendChild(this.markdown(build, { keep, stdsize }));
if (keep) { if (keep) {
i.append(underscores); i.append(underscores);
} }
@ -325,7 +325,7 @@ class MarkDown {
} }
} }
if (txt[i] === "~" && txt[i + 1] === "~") { if (txt[i] === "~" && txt[i + 1] === "~") {
let count = 2; const count = 2;
let build = []; let build = [];
let find = 0; let find = 0;
let j = i + 2; let j = i + 2;
@ -350,7 +350,7 @@ class MarkDown {
if (keep) { if (keep) {
s.append(tildes); s.append(tildes);
} }
s.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize })); s.appendChild(this.markdown(build, { keep, stdsize }));
if (keep) { if (keep) {
s.append(tildes); s.append(tildes);
} }
@ -360,7 +360,7 @@ class MarkDown {
} }
} }
if (txt[i] === "|" && txt[i + 1] === "|") { if (txt[i] === "|" && txt[i + 1] === "|") {
let count = 2; const count = 2;
let build = []; let build = [];
let find = 0; let find = 0;
let j = i + 2; let j = i + 2;
@ -385,7 +385,7 @@ class MarkDown {
if (keep) { if (keep) {
j.append(pipes); j.append(pipes);
} }
j.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize })); j.appendChild(this.markdown(build, { keep, stdsize }));
j.classList.add("spoiler"); j.classList.add("spoiler");
j.onclick = MarkDown.unspoil; j.onclick = MarkDown.unspoil;
if (keep) { if (keep) {
@ -459,7 +459,7 @@ class MarkDown {
i = j; i = j;
const isEmojiOnly = txt.join("").trim() === buildjoin.trim(); const isEmojiOnly = txt.join("").trim() === buildjoin.trim();
const owner = (this.owner instanceof Channel) ? this.owner.guild : this.owner; const owner = (this.owner instanceof Channel) ? this.owner.guild : this.owner;
const emoji = new Emoji({ name: buildjoin, id: parts[2], animated: !!parts[1] }, owner); const emoji = new Emoji({ name: buildjoin, id: parts[2], animated: Boolean(parts[1]) }, owner);
span.appendChild(emoji.getHTML(isEmojiOnly)); span.appendChild(emoji.getHTML(isEmojiOnly));
continue; continue;
} }
@ -479,7 +479,6 @@ class MarkDown {
else { else {
break; break;
} }
;
} }
else if (partsFound === 1 && txt[j] === ")") { else if (partsFound === 1 && txt[j] === ")") {
partsFound++; partsFound++;
@ -529,7 +528,7 @@ class MarkDown {
return; return;
console.log(_.clipboardData.types); console.log(_.clipboardData.types);
const data = _.clipboardData.getData("text"); const data = _.clipboardData.getData("text");
document.execCommand('insertHTML', false, data); document.execCommand("insertHTML", false, data);
_.preventDefault(); _.preventDefault();
if (!box.onkeyup) if (!box.onkeyup)
return; return;
@ -568,25 +567,25 @@ class MarkDown {
} }
//solution from https://stackoverflow.com/questions/4576694/saving-and-restoring-caret-position-for-contenteditable-div //solution from https://stackoverflow.com/questions/4576694/saving-and-restoring-caret-position-for-contenteditable-div
function saveCaretPosition(context) { function saveCaretPosition(context) {
var selection = window.getSelection(); const selection = window.getSelection();
if (!selection) if (!selection)
return; return;
var range = selection.getRangeAt(0); const range = selection.getRangeAt(0);
range.setStart(context, 0); range.setStart(context, 0);
var len = range.toString().length; const len = range.toString().length;
return function restore() { return function restore() {
if (!selection) if (!selection)
return; return;
var pos = getTextNodeAtPosition(context, len); const pos = getTextNodeAtPosition(context, len);
selection.removeAllRanges(); selection.removeAllRanges();
var range = new Range(); const range = new Range();
range.setStart(pos.node, pos.position); range.setStart(pos.node, pos.position);
selection.addRange(range); selection.addRange(range);
}; };
} }
function getTextNodeAtPosition(root, index) { function getTextNodeAtPosition(root, index) {
const NODE_TYPE = NodeFilter.SHOW_TEXT; const NODE_TYPE = NodeFilter.SHOW_TEXT;
var treeWalker = document.createTreeWalker(root, NODE_TYPE, function next(elem) { const treeWalker = document.createTreeWalker(root, NODE_TYPE, elem => {
if (!elem.textContent) if (!elem.textContent)
return 0; return 0;
if (index > elem.textContent.length) { if (index > elem.textContent.length) {
@ -595,7 +594,7 @@ function getTextNodeAtPosition(root, index) {
} }
return NodeFilter.FILTER_ACCEPT; return NodeFilter.FILTER_ACCEPT;
}); });
var c = treeWalker.nextNode(); const c = treeWalker.nextNode();
return { return {
node: c ? c : root, node: c ? c : root,
position: index position: index

View file

@ -28,7 +28,7 @@ class Member {
continue; continue;
} }
if (thing === "roles") { if (thing === "roles") {
for (const strrole of memberjson["roles"]) { for (const strrole of memberjson.roles) {
const role = SnowFlake.getSnowFlakeFromID(strrole, Role).getObject(); const role = SnowFlake.getSnowFlakeFromID(strrole, Role).getObject();
this.roles.push(role); this.roles.push(role);
} }
@ -38,7 +38,6 @@ class Member {
} }
if (this.localuser.userMap.has(this?.id)) { if (this.localuser.userMap.has(this?.id)) {
this.user = this.localuser.userMap.get(this?.id); this.user = this.localuser.userMap.get(this?.id);
return;
} }
} }
get guild() { get guild() {
@ -89,7 +88,6 @@ class Member {
const membjson = await membpromise; const membjson = await membpromise;
if (membjson === undefined) { if (membjson === undefined) {
res(undefined); res(undefined);
return undefined;
} }
else { else {
const member = new Member(membjson, guild); const member = new Member(membjson, guild);
@ -149,7 +147,6 @@ class Member {
if (!this) { if (!this) {
return; return;
} }
;
/* /*
if(this.error){ if(this.error){

View file

@ -42,7 +42,9 @@ class Message {
return this.snowflake.id; return this.snowflake.id;
} }
static setup() { static setup() {
this.del = new Promise(_ => { this.resolve = _; }); this.del = new Promise(_ => {
this.resolve = _;
});
Message.setupcmenu(); Message.setupcmenu();
} }
static setupcmenu() { static setupcmenu() {
@ -63,7 +65,7 @@ class Message {
Message.contextmenu.addbutton("Edit", function () { Message.contextmenu.addbutton("Edit", function () {
this.channel.editing = this; this.channel.editing = this;
const markdown = document.getElementById("typebox")["markdown"]; const markdown = document.getElementById("typebox")["markdown"];
markdown.txt = this.content.rawString.split(''); markdown.txt = this.content.rawString.split("");
markdown.boxupdate(document.getElementById("typebox")); markdown.boxupdate(document.getElementById("typebox"));
}, null, function () { }, null, function () {
return this.author.id === this.localuser.user.id; return this.author.id === this.localuser.user.id;
@ -199,7 +201,7 @@ class Message {
getimages() { getimages() {
const build = []; const build = [];
for (const thing of this.attachments) { for (const thing of this.attachments) {
if (thing.content_type.startsWith('image/')) { if (thing.content_type.startsWith("image/")) {
build.push(thing); build.push(thing);
} }
} }
@ -209,7 +211,7 @@ class Message {
return await fetch(this.info.api + "/channels/" + this.channel.snowflake + "/messages/" + this.id, { return await fetch(this.info.api + "/channels/" + this.channel.snowflake + "/messages/" + this.id, {
method: "PATCH", method: "PATCH",
headers: this.headers, headers: this.headers,
body: JSON.stringify({ content: content }) body: JSON.stringify({ content })
}); });
} }
delete() { delete() {
@ -266,7 +268,7 @@ class Message {
this.generateMessage(); this.generateMessage();
} }
} }
generateMessage(premessage = undefined, ignoredblock = false) { generateMessage(premessage, ignoredblock = false) {
if (!this.div) if (!this.div)
return; return;
if (!premessage) { if (!premessage) {
@ -277,21 +279,21 @@ class Message {
div.classList.add("replying"); div.classList.add("replying");
} }
div.innerHTML = ""; div.innerHTML = "";
const build = document.createElement('div'); const build = document.createElement("div");
build.classList.add("flexltr", "message"); build.classList.add("flexltr", "message");
div.classList.remove("zeroheight"); div.classList.remove("zeroheight");
if (this.author.relationshipType === 2) { if (this.author.relationshipType === 2) {
if (ignoredblock) { if (ignoredblock) {
if (premessage?.author !== this.author) { if (premessage?.author !== this.author) {
const span = document.createElement("span"); const span = document.createElement("span");
span.textContent = `You have this user blocked, click to hide these messages.`; span.textContent = "You have this user blocked, click to hide these messages.";
div.append(span); div.append(span);
span.classList.add("blocked"); span.classList.add("blocked");
span.onclick = _ => { span.onclick = _ => {
const scroll = this.channel.infinite.scrollTop; const scroll = this.channel.infinite.scrollTop;
let next = this; let next = this;
while (next?.author === this.author) { while (next?.author === this.author) {
next.generateMessage(undefined); next.generateMessage();
next = this.channel.messages.get(this.channel.idToNext.get(next.id)); next = this.channel.messages.get(this.channel.idToNext.get(next.id));
} }
if (this.channel.infinite.scroll && scroll) { if (this.channel.infinite.scroll && scroll) {
@ -375,7 +377,7 @@ class Message {
} }
div.appendChild(build); div.appendChild(build);
if ({ 0: true, 19: true }[this.type] || this.attachments.length !== 0) { if ({ 0: true, 19: true }[this.type] || this.attachments.length !== 0) {
const pfpRow = document.createElement('div'); const pfpRow = document.createElement("div");
pfpRow.classList.add("flexltr"); pfpRow.classList.add("flexltr");
let pfpparent, current; let pfpparent, current;
if (premessage != null) { if (premessage != null) {
@ -545,7 +547,7 @@ class Message {
if (thing.emoji.name === data.name) { if (thing.emoji.name === data.name) {
thing.count--; thing.count--;
if (thing.count === 0) { if (thing.count === 0) {
this.reactions.splice(+i, 1); this.reactions.splice(Number(i), 1);
this.updateReactions(); this.updateReactions();
return; return;
} }
@ -565,16 +567,16 @@ class Message {
for (const i in this.reactions) { for (const i in this.reactions) {
const reaction = this.reactions[i]; const reaction = this.reactions[i];
if ((reaction.emoji.id && reaction.emoji.id == emoji.id) || (!reaction.emoji.id && reaction.emoji.name == emoji.name)) { if ((reaction.emoji.id && reaction.emoji.id == emoji.id) || (!reaction.emoji.id && reaction.emoji.name == emoji.name)) {
this.reactions.splice(+i, 1); this.reactions.splice(Number(i), 1);
this.updateReactions(); this.updateReactions();
break; break;
} }
} }
} }
buildhtml(premessage = undefined) { buildhtml(premessage) {
if (this.div) { if (this.div) {
console.error(`HTML for ${this.snowflake} already exists, aborting`); console.error(`HTML for ${this.snowflake} already exists, aborting`);
return; return this.div;
} }
try { try {
const div = document.createElement("div"); const div = document.createElement("div");
@ -585,15 +587,16 @@ class Message {
catch (e) { catch (e) {
console.error(e); console.error(e);
} }
return this.div;
} }
} }
let now = new Date().toLocaleDateString(); const now = new Date().toLocaleDateString();
const yesterday = new Date(now); const yesterday = new Date(now);
yesterday.setDate(new Date().getDate() - 1); yesterday.setDate(new Date().getDate() - 1);
let yesterdayStr = yesterday.toLocaleDateString(); const yesterdayStr = yesterday.toLocaleDateString();
function formatTime(date) { function formatTime(date) {
const datestring = date.toLocaleDateString(); const datestring = date.toLocaleDateString();
const formatTime = (date) => date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); const formatTime = (date) => date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
if (datestring === now) { if (datestring === now) {
return `Today at ${formatTime(date)}`; return `Today at ${formatTime(date)}`;
} }

View file

@ -3,12 +3,12 @@ class Permissions {
deny; deny;
hasDeny; hasDeny;
constructor(allow, deny = "") { constructor(allow, deny = "") {
this.hasDeny = !!deny; this.hasDeny = Boolean(deny);
try { try {
this.allow = BigInt(allow); this.allow = BigInt(allow);
this.deny = BigInt(deny); this.deny = BigInt(deny);
} }
catch (e) { catch {
this.allow = 0n; this.allow = 0n;
this.deny = 0n; this.deny = 0n;
console.error(`Something really stupid happened with a permission with allow being ${allow} and deny being, ${deny}, execution will still happen, but something really stupid happened, please report if you know what caused this.`); console.error(`Something really stupid happened with a permission with allow being ${allow} and deny being, ${deny}, execution will still happen, but something really stupid happened, please report if you know what caused this.`);

View file

@ -17,9 +17,9 @@ async function registertry(e) {
await fetch(apiurl + "/auth/register", { await fetch(apiurl + "/auth/register", {
body: JSON.stringify({ body: JSON.stringify({
date_of_birth: dateofbirth, date_of_birth: dateofbirth,
email: email, email,
username: username, username,
password: password, password,
consent: elements[6].checked, consent: elements[6].checked,
captcha_key: elements[7]?.value captcha_key: elements[7]?.value
}), }),
@ -67,14 +67,14 @@ async function registertry(e) {
} }
} }
else { else {
adduser({ serverurls: JSON.parse(localStorage.getItem("instanceinfo")), email: email, token: e.token }).username = username; adduser({ serverurls: JSON.parse(localStorage.getItem("instanceinfo")), email, token: e.token }).username = username;
localStorage.setItem("token", e.token); localStorage.setItem("token", e.token);
const redir = new URLSearchParams(window.location.search).get("goback"); const redir = new URLSearchParams(window.location.search).get("goback");
if (redir) { if (redir) {
window.location.href = redir; window.location.href = redir;
} }
else { else {
window.location.href = '/channels/@me'; window.location.href = "/channels/@me";
} }
} }
}); });
@ -93,7 +93,9 @@ function error(e, message) {
} }
else { else {
element.classList.remove("suberror"); element.classList.remove("suberror");
setTimeout(_ => { element.classList.add("suberror"); }, 100); setTimeout(_ => {
element.classList.add("suberror");
}, 100);
} }
element.textContent = message; element.textContent = message;
} }

View file

@ -38,7 +38,6 @@ class Role {
if (this.color === 0) { if (this.color === 0) {
return null; return null;
} }
;
return `#${this.color.toString(16)}`; return `#${this.color.toString(16)}`;
} }
} }
@ -55,7 +54,6 @@ class PermissionToggle {
this.owner = owner; this.owner = owner;
} }
watchForChange() { } watchForChange() { }
;
generateHTML() { generateHTML() {
const div = document.createElement("div"); const div = document.createElement("div");
div.classList.add("setting"); div.classList.add("setting");
@ -80,7 +78,6 @@ class PermissionToggle {
if (state === 1) { if (state === 1) {
on.checked = true; on.checked = true;
} }
;
on.onclick = _ => { on.onclick = _ => {
this.permissions.setPermission(this.rolejson.name, 1); this.permissions.setPermission(this.rolejson.name, 1);
this.owner.changed(); this.owner.changed();
@ -92,7 +89,6 @@ class PermissionToggle {
if (state === 0) { if (state === 0) {
no.checked = true; no.checked = true;
} }
;
no.onclick = _ => { no.onclick = _ => {
this.permissions.setPermission(this.rolejson.name, 0); this.permissions.setPermission(this.rolejson.name, 0);
this.owner.changed(); this.owner.changed();
@ -105,7 +101,6 @@ class PermissionToggle {
if (state === -1) { if (state === -1) {
off.checked = true; off.checked = true;
} }
;
off.onclick = _ => { off.onclick = _ => {
this.permissions.setPermission(this.rolejson.name, -1); this.permissions.setPermission(this.rolejson.name, -1);
this.owner.changed(); this.owner.changed();

View file

@ -4,7 +4,7 @@ function deleteoldcache() {
} }
async function putInCache(request, response) { async function putInCache(request, response) {
console.log(request, response); console.log(request, response);
const cache = await caches.open('cache'); const cache = await caches.open("cache");
console.log("Grabbed"); console.log("Grabbed");
try { try {
console.log(await cache.put(request, response)); console.log(await cache.put(request, response));
@ -13,7 +13,6 @@ async function putInCache(request, response) {
console.error(error); console.error(error);
} }
} }
;
console.log("test"); console.log("test");
let lastcache; let lastcache;
self.addEventListener("activate", async (event) => { self.addEventListener("activate", async (event) => {
@ -37,7 +36,9 @@ async function checkCache() {
putInCache("/getupdates", data.clone()); putInCache("/getupdates", data.clone());
} }
checkedrecently = true; checkedrecently = true;
setTimeout(_ => { checkedrecently = false; }, 1000 * 60 * 30); setTimeout(_ => {
checkedrecently = false;
}, 1000 * 60 * 30);
}); });
} }
var checkedrecently = false; var checkedrecently = false;
@ -83,7 +84,7 @@ async function getfile(event) {
console.error(e); console.error(e);
} }
} }
self.addEventListener('fetch', (event) => { self.addEventListener("fetch", (event) => {
try { try {
event.respondWith(getfile(event)); event.respondWith(getfile(event));
} }

View file

@ -9,7 +9,7 @@ class Buttons {
this.buttons = []; this.buttons = [];
this.name = name; this.name = name;
} }
add(name, thing = undefined) { add(name, thing) {
if (!thing) { if (!thing) {
thing = new Options(name, this); thing = new Options(name, this);
} }
@ -380,7 +380,6 @@ class FileInput {
if (this.onchange) { if (this.onchange) {
this.onchange(null); this.onchange(null);
} }
;
this.value = null; this.value = null;
this.owner.changed(); this.owner.changed();
}; };
@ -424,7 +423,6 @@ class HtmlArea {
} }
} }
watchForChange() { } watchForChange() { }
;
} }
class Options { class Options {
name; name;
@ -451,7 +449,6 @@ class Options {
} }
} }
watchForChange() { } watchForChange() { }
;
addOptions(name, { ltr = false } = {}) { addOptions(name, { ltr = false } = {}) {
const options = new Options(name, this, { ltr }); const options = new Options(name, this, { ltr });
this.options.push(options); this.options.push(options);
@ -467,7 +464,7 @@ class Options {
this.generateContainter(); this.generateContainter();
} }
else { else {
throw Error("Tried to make a subOptions when the options weren't rendered"); throw new Error("Tried to make a subOptions when the options weren't rendered");
} }
return options; return options;
} }
@ -479,7 +476,7 @@ class Options {
this.generateContainter(); this.generateContainter();
} }
else { else {
throw Error("Tried to make a subForm when the options weren't rendered"); throw new Error("Tried to make a subForm when the options weren't rendered");
} }
return options; return options;
} }
@ -758,7 +755,6 @@ class Form {
watchForChange(func) { watchForChange(func) {
this.onSubmit = func; this.onSubmit = func;
} }
;
changed() { changed() {
if (this.traditionalSubmit) { if (this.traditionalSubmit) {
this.owner.changed(); this.owner.changed();
@ -819,7 +815,6 @@ class Form {
if (!(errors instanceof Object)) { if (!(errors instanceof Object)) {
return; return;
} }
;
for (const error of Object.keys(errors)) { for (const error of Object.keys(errors)) {
const elm = this.names.get(error); const elm = this.names.get(error);
if (elm) { if (elm) {
@ -858,7 +853,9 @@ class Form {
} }
else { else {
element.classList.remove("suberror"); element.classList.remove("suberror");
setTimeout(_ => { element.classList.add("suberror"); }, 100); setTimeout(_ => {
element.classList.add("suberror");
}, 100);
} }
element.textContent = message; element.textContent = message;
} }
@ -887,7 +884,9 @@ class Settings extends Buttons {
exit.textContent = "✖"; exit.textContent = "✖";
exit.classList.add("exitsettings"); exit.classList.add("exitsettings");
background.append(exit); background.append(exit);
exit.onclick = _ => { this.hide(); }; exit.onclick = _ => {
this.hide();
};
document.body.append(background); document.body.append(background);
this.html = background; this.html = background;
} }

View file

@ -72,7 +72,7 @@ class User {
}); });
this.contextmenu.addbutton("Message user", function () { this.contextmenu.addbutton("Message user", function () {
fetch(this.info.api + "/users/@me/channels", { method: "POST", fetch(this.info.api + "/users/@me/channels", { method: "POST",
body: JSON.stringify({ "recipients": [this.id] }), body: JSON.stringify({ recipients: [this.id] }),
headers: this.localuser.headers headers: this.localuser.headers
}); });
}); });
@ -97,7 +97,7 @@ class User {
}); });
this.contextmenu.addbutton("Kick member", function (member) { this.contextmenu.addbutton("Kick member", function (member) {
member.kick(); member.kick();
}, null, function (member) { }, null, member => {
if (!member) if (!member)
return false; return false;
const us = member.guild.member; const us = member.guild.member;
@ -111,7 +111,7 @@ class User {
}); });
this.contextmenu.addbutton("Ban member", function (member) { this.contextmenu.addbutton("Ban member", function (member) {
member.ban(); member.ban();
}, null, function (member) { }, null, member => {
if (!member) if (!member)
return false; return false;
const us = member.guild.member; const us = member.guild.member;
@ -192,7 +192,7 @@ class User {
} }
} }
buildpfp() { buildpfp() {
const pfp = document.createElement('img'); const pfp = document.createElement("img");
pfp.loading = "lazy"; pfp.loading = "lazy";
pfp.src = this.getpfpsrc(); pfp.src = this.getpfpsrc();
pfp.classList.add("pfp"); pfp.classList.add("pfp");
@ -419,7 +419,7 @@ class User {
} }
return div; return div;
} }
profileclick(obj, guild = undefined) { profileclick(obj, guild) {
obj.onclick = e => { obj.onclick = e => {
this.buildprofile(e.clientX, e.clientY, guild); this.buildprofile(e.clientX, e.clientY, guild);
e.stopPropagation(); e.stopPropagation();

View file

@ -45,7 +45,7 @@ for(const thing of emojilist){
} }
const out=new ArrayBuffer(i); const out=new ArrayBuffer(i);
const ar=new Uint8Array(out); const ar=new Uint8Array(out);
const br=new Uint8Array(buffer) const br=new Uint8Array(buffer);
for(const thing in ar){ for(const thing in ar){
ar[thing]=br[thing]; ar[thing]=br[thing];
} }
@ -76,10 +76,8 @@ function decodeEmojiList(buffer){
for(let i=0;i<length;i++){ for(let i=0;i<length;i++){
array[i]=read8(); array[i]=read8();
} }
const decoded=new TextDecoder("utf-8").decode(array.buffer);;
//console.log(array); //console.log(array);
return decoded; return new TextDecoder("utf-8").decode(array.buffer);
} }
const build=[]; const build=[];
let cats=read16(); let cats=read16();
@ -98,18 +96,18 @@ function decodeEmojiList(buffer){
name, name,
skin_tone_support, skin_tone_support,
emoji emoji
}) });
} }
build.push({ build.push({
name, name,
emojis emojis
}) });
} }
return build; return build;
} }
console.log(JSON.stringify(decodeEmojiList(out))); console.log(JSON.stringify(decodeEmojiList(out)));
const fs = require('fs'); const fs = require("node:fs");
fs.writeFile("./webpage/emoji.bin",new Uint8Array(out),_=>{ fs.writeFile("./webpage/emoji.bin",new Uint8Array(out),_=>{
}); });

View file

@ -10,10 +10,10 @@ const tsParser = require("@typescript-eslint/parser");
const linterOptions = { const linterOptions = {
reportUnusedDisableDirectives: "error" reportUnusedDisableDirectives: "error"
} };
const global = { const global = {
...globals.browser ...globals.browser
} };
const rules = { const rules = {
"array-callback-return": 2, "array-callback-return": 2,
@ -227,7 +227,7 @@ const rules = {
"sonarjs/prefer-while": 2, "sonarjs/prefer-while": 2,
"sonarjs/no-gratuitous-expressions": 2, "sonarjs/no-gratuitous-expressions": 2,
"sonarjs/no-duplicated-branches": 2 "sonarjs/no-duplicated-branches": 2
} };
module.exports = [ module.exports = [
{ {
@ -307,4 +307,4 @@ module.exports = [
"@html-eslint/require-img-alt": 1 "@html-eslint/require-img-alt": 1
} }
} }
] ];

View file

@ -1,8 +1,8 @@
#! /usr/bin/env node #! /usr/bin/env node
const compression = require('compression') const compression = require("compression");
const express = require('express'); const express = require("express");
const fs = require('fs'); const fs = require("node:fs");
const app = express(); const app = express();
const instances=require("./webpage/instances.json"); const instances=require("./webpage/instances.json");
const stats=require("./stats.js"); const stats=require("./stats.js");
@ -10,13 +10,13 @@ const instancenames=new Map();
for(const instance of instances){ for(const instance of instances){
instancenames.set(instance.name,instance); instancenames.set(instance.name,instance);
} }
app.use(compression()) app.use(compression());
fetch("https://raw.githubusercontent.com/spacebarchat/spacebarchat/master/instances/instances.json").then(_=>_.json()).then(json=>{ fetch("https://raw.githubusercontent.com/spacebarchat/spacebarchat/master/instances/instances.json").then(_=>_.json()).then(json=>{
for(const instance of json){ for(const instance of json){
if(!instancenames.has(instance.name)){ if(!instancenames.has(instance.name)){
instances.push(instance); instances.push(instance);
}else{ }else{
const ofinst=instancenames.get(instance.name) const ofinst=instancenames.get(instance.name);
for(const key of Object.keys(instance)){ for(const key of Object.keys(instance)){
if(!ofinst[key]){ if(!ofinst[key]){
ofinst[key]=instance[key]; ofinst[key]=instance[key];
@ -24,33 +24,32 @@ fetch("https://raw.githubusercontent.com/spacebarchat/spacebarchat/master/instan
} }
} }
} }
stats.observe(instances) stats.observe(instances);
}) });
app.use("/getupdates",(req, res) => { app.use("/getupdates",(req, res)=>{
const out=fs.statSync(`${__dirname}/webpage`); const out=fs.statSync(`${__dirname}/webpage`);
res.send(out.mtimeMs+""); res.send(out.mtimeMs+"");
}); });
let debugging=true;//Do not turn this off, the service worker is all kinds of jank as is, it'll really mess your day up if you disable this const debugging=true;//Do not turn this off, the service worker is all kinds of jank as is, it'll really mess your day up if you disable this
function isembed(str){ function isembed(str){
return str.includes("discord")||str.includes("Spacebar"); return str.includes("discord")||str.includes("Spacebar");
} }
async function getapiurls(str){ async function getapiurls(str){
if(str[str.length-1]!=="/"){ if(str.at(-1)!=="/"){
str+="/" str+="/";
} }
let api; let api;
try{ try{
const info=await fetch(`${str}/.well-known/spacebar`).then((x) => x.json()); const info=await fetch(`${str}/.well-known/spacebar`).then(x=>x.json());
api=info.api; api=info.api;
}catch{ }catch{
return false return false;
} }
const url = new URL(api); const url = new URL(api);
try{ try{
const info=await fetch(`${api}${url.pathname.includes("api") ? "" : "api"}/policies/instance/domains`).then(x=>x.json());
const info=await fetch(`${api}${url.pathname.includes("api") ? "" : "api"}/policies/instance/domains`).then((x) => x.json()); return{
return {
api: info.apiEndpoint, api: info.apiEndpoint,
gateway: info.gateway, gateway: info.gateway,
cdn: info.cdn, cdn: info.cdn,
@ -66,13 +65,13 @@ async function inviteres(req,res){
if(URL.canParse(req.query.url)){ if(URL.canParse(req.query.url)){
url=new URL(req.query.url); url=new URL(req.query.url);
}else{ }else{
const scheme = req.secure ? 'https' : 'http'; const scheme = req.secure ? "https" : "http";
const host=`${scheme}://${req.get("Host")}`; const host=`${scheme}://${req.get("Host")}`;
url=new URL(host); url=new URL(host);
} }
try{ try{
if(url.pathname.startsWith("invite")){ if(url.pathname.startsWith("invite")){
throw -1; throw-1;
} }
const code=url.pathname.split("/")[2]; const code=url.pathname.split("/")[2];
let title=""; let title="";
@ -80,7 +79,7 @@ async function inviteres(req,res){
let thumbnail=""; let thumbnail="";
const urls=await getapiurls(url.searchParams.get("instance")); const urls=await getapiurls(url.searchParams.get("instance"));
await fetch(`${urls.api}/invites/${code}`,{ await fetch(`${urls.api}/invites/${code}`,{
method:"GET" method: "GET"
}).then(_=>_.json()).then(json=>{ }).then(_=>_.json()).then(json=>{
title=json.guild.name; title=json.guild.name;
if(json.inviter){ if(json.inviter){
@ -93,8 +92,8 @@ async function inviteres(req,res){
} }
}); });
const json={ const json={
type:"link", type: "link",
version:"1.0", version: "1.0",
title, title,
thumbnail, thumbnail,
description, description,
@ -103,17 +102,17 @@ async function inviteres(req,res){
}catch(e){ }catch(e){
console.error(e); console.error(e);
const json={ const json={
type:"link", type: "link",
version:"1.0", version: "1.0",
title:"Jank Client", title: "Jank Client",
thumbnail:"/logo.webp", thumbnail: "/logo.webp",
description:"A spacebar client that has DMs, replying and more", description: "A spacebar client that has DMs, replying and more",
url:url.toString() url: url.toString()
}; };
res.send(JSON.stringify(json)); res.send(JSON.stringify(json));
} }
} }
/* /*
function htmlEnc(s) {//https://stackoverflow.com/a/11561642 function htmlEnc(s) {//https://stackoverflow.com/a/11561642
return s.replaceAll(/&/g, '&amp;') return s.replaceAll(/&/g, '&amp;')
.replaceAll(/</g, '&lt;') .replaceAll(/</g, '&lt;')
@ -143,28 +142,27 @@ async function inviteres(req,res){
return false; return false;
*/ */
app.use('/services/oembed', (req, res) => { app.use("/services/oembed", (req, res)=>{
inviteres(req, res); inviteres(req, res);
}) });
app.use("/uptime",(req,res)=>{ app.use("/uptime",(req,res)=>{
console.log(req.query.name) console.log(req.query.name);
const uptime=stats.uptime[req.query.name]; const uptime=stats.uptime[req.query.name];
console.log(req.query.name,uptime,stats.uptime) console.log(req.query.name,uptime,stats.uptime);
res.send(uptime); res.send(uptime);
}) });
app.use('/', async (req, res) => { app.use("/", async (req, res)=>{
const scheme = req.secure ? 'https' : 'http'; const scheme = req.secure ? "https" : "http";
const host=`${scheme}://${req.get("Host")}`; const host=`${scheme}://${req.get("Host")}`;
const ref=host+req.originalUrl; const ref=host+req.originalUrl;
if(host&&ref){ if(host&&ref){
const link=`${host}/services/oembed?url=${encodeURIComponent(ref)}`; const link=`${host}/services/oembed?url=${encodeURIComponent(ref)}`;
res.set("Link",`<${link}>; rel="alternate"; type="application/json+oembed"; title="Jank Client oEmbed format"`); res.set("Link",`<${link}>; rel="alternate"; type="application/json+oembed"; title="Jank Client oEmbed format"`);
}else{ }else{
console.log(req); console.log(req);
} }
if(req.path==="/"){ if(req.path==="/"){
res.sendFile(`./webpage/home.html`, {root: __dirname}); res.sendFile("./webpage/home.html", {root: __dirname});
return; return;
} }
if(debugging&&req.path.startsWith("/service.js")){ if(debugging&&req.path.startsWith("/service.js")){
@ -176,27 +174,24 @@ app.use('/', async (req, res) => {
return; return;
} }
if(req.path.startsWith("/invite/")){ if(req.path.startsWith("/invite/")){
res.sendFile(`./webpage/invite.html`, {root: __dirname}); res.sendFile("./webpage/invite.html", {root: __dirname});
return; return;
} }
if(fs.existsSync(`${__dirname}/webpage${req.path}`)) { if(fs.existsSync(`${__dirname}/webpage${req.path}`)){
res.sendFile(`./webpage${req.path}`, {root: __dirname}); res.sendFile(`./webpage${req.path}`, {root: __dirname});
}else if(req.path.endsWith(".js") && fs.existsSync(`${__dirname}/.dist${req.path}`)){ }else if(req.path.endsWith(".js") && fs.existsSync(`${__dirname}/.dist${req.path}`)){
const dir=`./.dist${req.path}`; const dir=`./.dist${req.path}`;
res.sendFile(dir, {root: __dirname}); res.sendFile(dir, {root: __dirname});
return; }else if(fs.existsSync(`${__dirname}/webpage${req.path}.html`)){
}
else if(fs.existsSync(`${__dirname}/webpage${req.path}.html`)) {
res.sendFile(`./webpage${req.path}.html`, {root: __dirname}); res.sendFile(`./webpage${req.path}.html`, {root: __dirname});
} }else{
else {
res.sendFile("./webpage/index.html", {root: __dirname}); res.sendFile("./webpage/index.html", {root: __dirname});
} }
}); });
const PORT = process.env.PORT || +process.argv[1] || 8080; const PORT = process.env.PORT || Number(process.argv[1]) || 8080;
app.listen(PORT, () => {}); app.listen(PORT, ()=>{});
console.log("this ran :P"); console.log("this ran :P");
exports.getapiurls=getapiurls; exports.getapiurls=getapiurls;

View file

@ -1,22 +1,25 @@
const index = require('./index.js'); const index = require("./index.js");
const fs=require("fs"); const fs=require("node:fs");
let uptimeObject={}; let uptimeObject={};
if(fs.existsSync("./uptime.json")){ if(fs.existsSync("./uptime.json")){
try{ try{
uptimeObject=JSON.parse(fs.readFileSync('./uptime.json', 'utf8')); uptimeObject=JSON.parse(fs.readFileSync("./uptime.json", "utf8"));
}catch{ }catch{
uptimeObject={}; uptimeObject={};
} }
} }
if(uptimeObject["undefined"]){ if(uptimeObject.undefined){
delete uptimeObject["undefined"]; delete uptimeObject.undefined;
updatejson(); updatejson();
} }
async function observe(instances){ async function observe(instances){
const active=new Set(); const active=new Set();
async function resolveinstance(instance){ async function resolveinstance(instance){
try{calcStats(instance)}catch(e){console.error(e)} try{
calcStats(instance);
}catch(e){
console.error(e);
}
let api; let api;
if(instance.urls){ if(instance.urls){
api=instance.urls.api; api=instance.urls.api;
@ -27,27 +30,28 @@ async function observe(instances){
} }
} }
if(!api||api===""){ if(!api||api===""){
setStatus(instance,false); setStatus(instance,false);
console.warn(instance.name+" does not resolve api URL"); console.warn(instance.name+" does not resolve api URL");
setTimeout(_=>{resolveinstance(instance)},1000*60*30,); setTimeout(_=>{
return resolveinstance(instance);
},1000*60*30,);
return;
} }
active.add(instance.name); active.add(instance.name);
api+=api.endsWith("/")?"":"/" api+=api.endsWith("/")?"":"/";
function check(){ function check(){
fetch(api+"ping",{method:"HEAD"}).then(_=>{ fetch(api+"ping",{method: "HEAD"}).then(_=>{
setStatus(instance,_.ok); setStatus(instance,_.ok);
}) });
} }
setTimeout( setTimeout(
_=>{ _=>{
check(); check();
setInterval(_=>{ setInterval(_=>{
check(); check();
},1000*60*30) },1000*60*30);
},Math.random()*1000*60*10 },Math.random()*1000*60*10
) );
} }
const promlist=[]; const promlist=[];
for(const instance of instances){ for(const instance of instances){
@ -61,8 +65,8 @@ async function observe(instances){
} }
} }
function calcStats(instance){ function calcStats(instance){
let obj=uptimeObject[instance.name]; const obj=uptimeObject[instance.name];
if(!obj) return; if(!obj)return;
const day=Date.now()-1000*60*60*24; const day=Date.now()-1000*60*60*24;
const week=Date.now()-1000*60*60*24*7; const week=Date.now()-1000*60*60*24*7;
let alltime=-1; let alltime=-1;
@ -119,10 +123,10 @@ function calcStats(instance){
weektime=alltime; weektime=alltime;
} }
}else{ }else{
weektime=alltime weektime=alltime;
daytime=alltime; daytime=alltime;
} }
instance.uptime={daytime,weektime,alltime} instance.uptime={daytime,weektime,alltime};
} }
/** /**
* @param {string|Object} instance * @param {string|Object} instance
@ -130,7 +134,7 @@ function calcStats(instance){
*/ */
function setStatus(instance,status){ function setStatus(instance,status){
let name=instance.name; let name=instance.name;
if(typeof instance==="string" ){ if(typeof instance==="string"){
name=instance; name=instance;
} }
@ -141,20 +145,20 @@ function setStatus(instance,status){
uptimeObject[name]=obj; uptimeObject[name]=obj;
needSetting=true; needSetting=true;
}else{ }else{
if(obj[obj.length-1].online!==status){ if(obj.at(-1).online!==status){
needSetting=true; needSetting=true;
} }
} }
if(needSetting){ if(needSetting){
obj.push({time:Date.now(),online:status}); obj.push({time: Date.now(),online: status});
updatejson(); updatejson();
} }
if(typeof instance!=="string" ){ if(typeof instance!=="string"){
calcStats(instance); calcStats(instance);
} }
} }
function updatejson(){ function updatejson(){
fs.writeFile('./uptime.json',JSON.stringify(uptimeObject),_=>{}); fs.writeFile("./uptime.json",JSON.stringify(uptimeObject),_=>{});
} }
exports.observe=observe; exports.observe=observe;
exports.uptime=uptimeObject; exports.uptime=uptimeObject;

View file

@ -1,4 +1,4 @@
import {getBulkInfo} from "./login.js"; import{getBulkInfo}from"./login.js";
class Voice{ class Voice{
audioCtx:AudioContext; audioCtx:AudioContext;
@ -10,7 +10,7 @@ class Voice{
source:AudioBufferSourceNode; source:AudioBufferSourceNode;
constructor(wave:string|Function,freq:number,volume=1){ constructor(wave:string|Function,freq:number,volume=1){
this.audioCtx = new (window.AudioContext)(); this.audioCtx = new (window.AudioContext)();
this.info={wave:wave,freq:freq} this.info={wave,freq};
this.playing=false; this.playing=false;
this.myArrayBuffer=this.audioCtx.createBuffer( this.myArrayBuffer=this.audioCtx.createBuffer(
1, 1,
@ -43,40 +43,39 @@ class Voice{
} }
updateWave():void{ updateWave():void{
const func=this.waveFunction(); const func=this.waveFunction();
for (let i = 0; i < this.buffer.length; i++) { for(let i = 0; i < this.buffer.length; i++){
this.buffer[i]=func(i/this.audioCtx.sampleRate,this.freq); this.buffer[i]=func(i/this.audioCtx.sampleRate,this.freq);
} }
} }
waveFunction():Function{ waveFunction():Function{
if(typeof this.wave === 'function'){ if(typeof this.wave === "function"){
return this.wave; return this.wave;
} }
switch(this.wave){ switch(this.wave){
case "sin": case"sin":
return (t:number,freq:number)=>{ return(t:number,freq:number)=>{
return Math.sin(t*Math.PI*2*freq); return Math.sin(t*Math.PI*2*freq);
} };
case "triangle": case"triangle":
return (t:number,freq:number)=>{ return(t:number,freq:number)=>{
return Math.abs((4*t*freq)%4-2)-1; return Math.abs((4*t*freq)%4-2)-1;
} };
case "sawtooth": case"sawtooth":
return (t:number,freq:number)=>{ return(t:number,freq:number)=>{
return ((t*freq)%1)*2-1; return((t*freq)%1)*2-1;
} };
case "square": case"square":
return (t:number,freq:number)=>{ return(t:number,freq:number)=>{
return (t*freq)%2<1?1:-1; return(t*freq)%2<1?1:-1;
} };
case "white": case"white":
return (_t:number,_freq:number)=>{ return(_t:number,_freq:number)=>{
return Math.random()*2-1; return Math.random()*2-1;
} };
case "noise": case"noise":
return (_t:number,_freq:number)=>{ return(_t:number,_freq:number)=>{
return 0; return 0;
} };
} }
return new Function(); return new Function();
} }
@ -86,7 +85,6 @@ class Voice{
} }
this.source.connect(this.gainNode); this.source.connect(this.gainNode);
this.playing=true; this.playing=true;
} }
stop():void{ stop():void{
if(this.playing){ if(this.playing){
@ -96,51 +94,71 @@ class Voice{
} }
static noises(noise:string):void{ static noises(noise:string):void{
switch(noise){ switch(noise){
case "three":{ case"three":{
const voicy=new Voice("sin",800); const voicy=new Voice("sin",800);
voicy.play(); voicy.play();
setTimeout(_=>{voicy.freq=1000},50); setTimeout(_=>{
setTimeout(_=>{voicy.freq=1300},100); voicy.freq=1000;
setTimeout(_=>{voicy.stop()},150); },50);
setTimeout(_=>{
voicy.freq=1300;
},100);
setTimeout(_=>{
voicy.stop();
},150);
break; break;
} }
case "zip":{ case"zip":{
const voicy=new Voice((t:number,freq:number)=>{ const voicy=new Voice((t:number,freq:number)=>{
return Math.sin(((t+2)**(Math.cos(t*4)))*Math.PI*2*freq); return Math.sin(((t+2)**(Math.cos(t*4)))*Math.PI*2*freq);
},700); },700);
voicy.play(); voicy.play();
setTimeout(_=>{voicy.stop()},150); setTimeout(_=>{
voicy.stop();
},150);
break; break;
} }
case "square":{ case"square":{
const voicy=new Voice("square",600,.4); const voicy=new Voice("square",600,0.4);
voicy.play() voicy.play();
setTimeout(_=>{voicy.freq=800},50); setTimeout(_=>{
setTimeout(_=>{voicy.freq=1000},100); voicy.freq=800;
setTimeout(_=>{voicy.stop()},150); },50);
setTimeout(_=>{
voicy.freq=1000;
},100);
setTimeout(_=>{
voicy.stop();
},150);
break; break;
} }
case "beep":{ case"beep":{
const voicy=new Voice("sin",800); const voicy=new Voice("sin",800);
voicy.play(); voicy.play();
setTimeout(_=>{voicy.stop()},50); setTimeout(_=>{
setTimeout(_=>{voicy.play();},100); voicy.stop();
setTimeout(_=>{voicy.stop()},150); },50);
setTimeout(_=>{
voicy.play();
},100);
setTimeout(_=>{
voicy.stop();
},150);
break; break;
} }
} }
} }
static get sounds(){ static get sounds(){
return ["three","zip","square","beep"]; return["three","zip","square","beep"];
} }
static setNotificationSound(sound:string){ static setNotificationSound(sound:string){
let userinfos=getBulkInfo(); const userinfos=getBulkInfo();
userinfos.preferences.notisound=sound; userinfos.preferences.notisound=sound;
localStorage.setItem("userinfos",JSON.stringify(userinfos)); localStorage.setItem("userinfos",JSON.stringify(userinfos));
} }
static getNotificationSound(){ static getNotificationSound(){
let userinfos=getBulkInfo(); const userinfos=getBulkInfo();
return userinfos.preferences.notisound; return userinfos.preferences.notisound;
} }
} }
export {Voice as Voice}; export{Voice};

View file

@ -1,17 +1,17 @@
"use strict" "use strict";
import { Message } from "./message.js"; import{ Message }from"./message.js";
import {Voice} from "./audio.js"; import{Voice}from"./audio.js";
import {Contextmenu} from "./contextmenu.js"; import{Contextmenu}from"./contextmenu.js";
import {Dialog} from "./dialog.js"; import{Dialog}from"./dialog.js";
import {Guild} from "./guild.js"; import{Guild}from"./guild.js";
import { Localuser } from "./localuser.js"; import{ Localuser }from"./localuser.js";
import { Permissions } from "./permissions.js"; import{ Permissions }from"./permissions.js";
import { Settings } from "./settings.js"; import{ Settings }from"./settings.js";
import { Role,RoleList } from "./role.js"; import{ Role,RoleList }from"./role.js";
import {InfiniteScroller} from "./infiniteScroller.js"; import{InfiniteScroller}from"./infiniteScroller.js";
import { SnowFlake } from "./snowflake.js"; import{ SnowFlake }from"./snowflake.js";
import { channeljson, messageCreateJson, messagejson, readyjson } from "./jsontypes.js"; import{ channeljson, messageCreateJson, messagejson, readyjson }from"./jsontypes.js";
import { MarkDown } from "./markdown.js"; import{ MarkDown }from"./markdown.js";
declare global { declare global {
interface NotificationOptions { interface NotificationOptions {
@ -31,7 +31,7 @@ class Channel{
guild_id:string; guild_id:string;
messageids:Map<SnowFlake<Message>,Message>; messageids:Map<SnowFlake<Message>,Message>;
permission_overwrites:Map<string,Permissions>; permission_overwrites:Map<string,Permissions>;
permission_overwritesar:[SnowFlake<Role>,Permissions][] permission_overwritesar:[SnowFlake<Role>,Permissions][];
topic:string; topic:string;
nsfw:boolean; nsfw:boolean;
position:number; position:number;
@ -54,12 +54,12 @@ class Channel{
} }
static setupcontextmenu(){ static setupcontextmenu(){
this.contextmenu.addbutton("Copy channel id",function(this:Channel){ this.contextmenu.addbutton("Copy channel id",function(this:Channel){
console.log(this) console.log(this);
navigator.clipboard.writeText(this.id); navigator.clipboard.writeText(this.id);
}); });
this.contextmenu.addbutton("Mark as read",function(this:Channel){ this.contextmenu.addbutton("Mark as read",function(this:Channel){
console.log(this) console.log(this);
this.readbottom(); this.readbottom();
}); });
@ -68,18 +68,22 @@ class Channel{
}); });
this.contextmenu.addbutton("Delete channel",function(this:Channel){ this.contextmenu.addbutton("Delete channel",function(this:Channel){
console.log(this) console.log(this);
this.deleteChannel(); this.deleteChannel();
},null,function(){return this.isAdmin()}); },null,function(){
return this.isAdmin();
});
this.contextmenu.addbutton("Edit channel",function(this:Channel){ this.contextmenu.addbutton("Edit channel",function(this:Channel){
this.editChannel(); this.editChannel();
},null,function(){return this.isAdmin()}); },null,function(){
return this.isAdmin();
});
this.contextmenu.addbutton("Make invite",function(this:Channel){ this.contextmenu.addbutton("Make invite",function(this:Channel){
this.createInvite(); this.createInvite();
},null,function(){ },null,function(){
return this.hasPermission("CREATE_INSTANT_INVITE")&&this.type!==4 return this.hasPermission("CREATE_INSTANT_INVITE")&&this.type!==4;
}); });
/* /*
this.contextmenu.addbutton("Test button",function(){ this.contextmenu.addbutton("Test button",function(){
@ -108,7 +112,7 @@ class Channel{
let uses=0; let uses=0;
let expires=1800; let expires=1800;
const copycontainer=document.createElement("div"); const copycontainer=document.createElement("div");
copycontainer.classList.add("copycontainer") copycontainer.classList.add("copycontainer");
const copy=document.createElement("img"); const copy=document.createElement("img");
copy.src="/icons/copy.svg"; copy.src="/icons/copy.svg";
copy.classList.add("copybutton","svgtheme"); copy.classList.add("copybutton","svgtheme");
@ -117,13 +121,13 @@ class Channel{
if(text.textContent){ if(text.textContent){
navigator.clipboard.writeText(text.textContent); navigator.clipboard.writeText(text.textContent);
} }
} };
div.append(copycontainer); div.append(copycontainer);
const update=()=>{ const update=()=>{
fetch(`${this.info.api}/channels/${this.id}/invites`,{ fetch(`${this.info.api}/channels/${this.id}/invites`,{
method:"POST", method: "POST",
headers:this.headers, headers: this.headers,
body:JSON.stringify({ body: JSON.stringify({
flags: 0, flags: 0,
target_type: null, target_type: null,
target_user_id: null, target_user_id: null,
@ -133,11 +137,11 @@ class Channel{
}) })
}).then(_=>_.json()).then(json=>{ }).then(_=>_.json()).then(json=>{
const params=new URLSearchParams(""); const params=new URLSearchParams("");
params.set("instance",this.info.wellknown) params.set("instance",this.info.wellknown);
const encoded=params.toString(); const encoded=params.toString();
text.textContent=`${location.origin}/invite/${json.code}?${encoded}` text.textContent=`${location.origin}/invite/${json.code}?${encoded}`;
}) });
} };
update(); update();
new Dialog(["vdiv", new Dialog(["vdiv",
["title","Invite people"], ["title","Invite people"],
@ -151,7 +155,7 @@ class Channel{
update(); update();
},0], },0],
["html",div] ["html",div]
]).show() ]).show();
} }
generateSettings(){ generateSettings(){
this.sortPerms(); this.sortPerms();
@ -159,17 +163,16 @@ class Channel{
const s1=settings.addButton("roles"); const s1=settings.addButton("roles");
s1.options.push(new RoleList(this.permission_overwritesar,this.guild,this.updateRolePermissions.bind(this),true)) s1.options.push(new RoleList(this.permission_overwritesar,this.guild,this.updateRolePermissions.bind(this),true));
settings.show(); settings.show();
} }
sortPerms(){ sortPerms(){
this.permission_overwritesar.sort((a,b)=>{ this.permission_overwritesar.sort((a,b)=>{
const order=this.guild.roles.findIndex(_=>_.snowflake===a[0])-this.guild.roles.findIndex(_=>_.snowflake===b[0]); return this.guild.roles.findIndex(_=>_.snowflake===a[0])-this.guild.roles.findIndex(_=>_.snowflake===b[0]);
return order; });
})
} }
setUpInfiniteScroller(){ setUpInfiniteScroller(){
this.infinite=new InfiniteScroller(async function(this:Channel,id:string,offset:number):Promise<string|undefined>{ this.infinite=new InfiniteScroller((async (id:string,offset:number):Promise<string|undefined>=>{
const snowflake=id; const snowflake=id;
if(offset===1){ if(offset===1){
if(this.idToPrev.has(snowflake)){ if(this.idToPrev.has(snowflake)){
@ -185,37 +188,40 @@ class Channel{
await this.grabAfter(id); await this.grabAfter(id);
return this.idToNext.get(snowflake); return this.idToNext.get(snowflake);
}else{ }else{
console.log("at bottom") console.log("at bottom");
} }
} }
}.bind(this), }),
async function(this:Channel,id:string){ (async (id:string):Promise<HTMLElement>=>{
//await new Promise(_=>{setTimeout(_,Math.random()*10)}) //await new Promise(_=>{setTimeout(_,Math.random()*10)})
const messgage=this.messages.get(id); const messgage=this.messages.get(id);
try{ try{
if(messgage){ if(messgage){
const html=messgage.buildhtml(); return messgage.buildhtml();
return html;
}else{ }else{
console.error(id+" not found") console.error(id+" not found");
} }
}catch(e){ }catch(e){
console.error(e); console.error(e);
} }
}.bind(this), return document.createElement("div");
async function(this:Channel,id:string){ }),
(async (id:string)=>{
const message=this.messages.get(id); const message=this.messages.get(id);
try{ try{
if(message){ if(message){
message.deleteDiv(); message.deleteDiv();
return true;
} }
}catch(e){console.error(e)}finally{} }catch(e){
}.bind(this), console.error(e);
}finally{}
return false;
}),
this.readbottom.bind(this) this.readbottom.bind(this)
); );
} }
constructor(json:channeljson|-1,owner:Guild){ constructor(json:channeljson|-1,owner:Guild){
if(json===-1){ if(json===-1){
return; return;
} }
@ -235,7 +241,9 @@ class Channel{
this.permission_overwrites=new Map(); this.permission_overwrites=new Map();
this.permission_overwritesar=[]; this.permission_overwritesar=[];
for(const thing of json.permission_overwrites){ for(const thing of json.permission_overwrites){
if(thing.id==="1182819038095799904"||thing.id==="1182820803700625444"){continue;}; if(thing.id==="1182819038095799904"||thing.id==="1182820803700625444"){
continue;
}
this.permission_overwrites.set(thing.id,new Permissions(thing.allow,thing.deny)); this.permission_overwrites.set(thing.id,new Permissions(thing.allow,thing.deny));
const permission=this.permission_overwrites.get(thing.id); const permission=this.permission_overwrites.get(thing.id);
if(permission){ if(permission){
@ -273,8 +281,10 @@ class Channel{
this.lastpin=json.last_pin_timestamp; this.lastpin=json.last_pin_timestamp;
} }
get hasunreads():boolean{ get hasunreads():boolean{
if(!this.hasPermission("VIEW_CHANNEL")){return false;} if(!this.hasPermission("VIEW_CHANNEL")){
return this.lastmessageid!==this.lastreadmessageid&&this.type!==4&&!!this.lastmessageid; return false;
}
return this.lastmessageid!==this.lastreadmessageid&&this.type!==4&&Boolean(this.lastmessageid);
} }
hasPermission(name:string,member=this.guild.member):boolean{ hasPermission(name:string,member=this.guild.member):boolean{
if(member.isAdmin()){ if(member.isAdmin()){
@ -283,7 +293,7 @@ class Channel{
for(const thing of member.roles){ for(const thing of member.roles){
const premission=this.permission_overwrites.get(thing.id); const premission=this.permission_overwrites.get(thing.id);
if(premission){ if(premission){
let perm=premission.getPermission(name); const perm=premission.getPermission(name);
if(perm){ if(perm){
return perm===1; return perm===1;
} }
@ -295,7 +305,7 @@ class Channel{
return false; return false;
} }
get canMessage():boolean{ get canMessage():boolean{
if((0===this.permission_overwritesar.length)&&this.hasPermission("MANAGE_CHANNELS")){ if((this.permission_overwritesar.length===0)&&this.hasPermission("MANAGE_CHANNELS")){
const role=this.guild.roles.find(_=>_.name==="@everyone"); const role=this.guild.roles.find(_=>_.name==="@everyone");
if(role){ if(role){
this.addRoleToPerms(role); this.addRoleToPerms(role);
@ -304,11 +314,13 @@ class Channel{
return this.hasPermission("SEND_MESSAGES"); return this.hasPermission("SEND_MESSAGES");
} }
sortchildren(){ sortchildren(){
this.children.sort((a,b)=>{return a.position-b.position}); this.children.sort((a,b)=>{
return a.position-b.position;
});
} }
resolveparent(guild:Guild){ resolveparent(guild:Guild){
const parentid=this.parent_id?.id; const parentid=this.parent_id?.id;
if(!parentid) return false; if(!parentid)return false;
this.parent=guild.channelids[parentid]; this.parent=guild.channelids[parentid];
this.parent??=null; this.parent??=null;
if(this.parent!==null){ if(this.parent!==null){
@ -318,9 +330,9 @@ class Channel{
} }
calculateReorder(){ calculateReorder(){
let position=-1; let position=-1;
let build:{id:SnowFlake<Channel>,position:number|undefined,parent_id:SnowFlake<Channel>|undefined}[]=[]; const build:{id:SnowFlake<Channel>,position:number|undefined,parent_id:SnowFlake<Channel>|undefined}[]=[];
for(const thing of this.children){ for(const thing of this.children){
const thisthing:{id:SnowFlake<Channel>,position:number|undefined,parent_id:SnowFlake<Channel>|undefined}={id:thing.snowflake,position:undefined,parent_id:undefined}; const thisthing:{id:SnowFlake<Channel>,position:number|undefined,parent_id:SnowFlake<Channel>|undefined}={id: thing.snowflake,position: undefined,parent_id: undefined};
if(thing.position<position){ if(thing.position<position){
thing.position=thisthing.position=position+1; thing.position=thisthing.position=position+1;
} }
@ -341,7 +353,7 @@ class Channel{
createguildHTML(admin=false):HTMLDivElement{ createguildHTML(admin=false):HTMLDivElement{
const div=document.createElement("div"); const div=document.createElement("div");
if(!this.hasPermission("VIEW_CHANNEL")){ if(!this.hasPermission("VIEW_CHANNEL")){
let quit=true let quit=true;
for(const thing of this.children){ for(const thing of this.children){
if(thing.hasPermission("VIEW_CHANNEL")){ if(thing.hasPermission("VIEW_CHANNEL")){
quit=false; quit=false;
@ -353,8 +365,12 @@ class Channel{
} }
div["all"]=this; div["all"]=this;
div.draggable=admin; div.draggable=admin;
div.addEventListener("dragstart",(e)=>{Channel.dragged=[this,div];e.stopImmediatePropagation()}) div.addEventListener("dragstart",e=>{
div.addEventListener("dragend",()=>{Channel.dragged=[]}) Channel.dragged=[this,div];e.stopImmediatePropagation();
});
div.addEventListener("dragend",()=>{
Channel.dragged=[];
});
if(this.type===4){ if(this.type===4){
this.sortchildren(); this.sortchildren();
const caps=document.createElement("div"); const caps=document.createElement("div");
@ -362,8 +378,8 @@ class Channel{
const decdiv=document.createElement("div"); const decdiv=document.createElement("div");
const decoration=document.createElement("img"); const decoration=document.createElement("img");
decoration.src="/icons/category.svg"; decoration.src="/icons/category.svg";
decoration.classList.add("svgtheme","colaspeicon") decoration.classList.add("svgtheme","colaspeicon");
decdiv.appendChild(decoration) decdiv.appendChild(decoration);
const myhtml=document.createElement("p2"); const myhtml=document.createElement("p2");
myhtml.textContent=this.name; myhtml.textContent=this.name;
@ -377,11 +393,11 @@ class Channel{
caps.appendChild(addchannel); caps.appendChild(addchannel);
addchannel.onclick=_=>{ addchannel.onclick=_=>{
this.guild.createchannels(this.createChannel.bind(this)); this.guild.createchannels(this.createChannel.bind(this));
} };
this.coatDropDiv(decdiv,childrendiv); this.coatDropDiv(decdiv,childrendiv);
} }
div.appendChild(caps) div.appendChild(caps);
caps.classList.add("capsflex") caps.classList.add("capsflex");
decdiv.classList.add("channeleffects"); decdiv.classList.add("channeleffects");
decdiv.classList.add("channel"); decdiv.classList.add("channel");
@ -393,18 +409,20 @@ class Channel{
childrendiv.appendChild(channel.createguildHTML(admin)); childrendiv.appendChild(channel.createguildHTML(admin));
} }
childrendiv.classList.add("channels"); childrendiv.classList.add("channels");
setTimeout(_=>{childrendiv.style.height = childrendiv.scrollHeight + 'px';},100) setTimeout(_=>{
childrendiv.style.height = childrendiv.scrollHeight + "px";
},100);
decdiv.onclick=function(){ decdiv.onclick=function(){
if(childrendiv.style.height!=='0px'){ if(childrendiv.style.height!=="0px"){
decoration.classList.add("hiddencat"); decoration.classList.add("hiddencat");
//childrendiv.classList.add("colapsediv"); //childrendiv.classList.add("colapsediv");
childrendiv.style.height = '0px'; childrendiv.style.height = "0px";
}else{ }else{
decoration.classList.remove("hiddencat"); decoration.classList.remove("hiddencat");
//childrendiv.classList.remove("colapsediv") //childrendiv.classList.remove("colapsediv")
childrendiv.style.height = childrendiv.scrollHeight + 'px'; childrendiv.style.height = childrendiv.scrollHeight + "px";
}
} }
};
div.appendChild(childrendiv); div.appendChild(childrendiv);
}else{ }else{
div.classList.add("channel"); div.classList.add("channel");
@ -412,39 +430,41 @@ class Channel{
div.classList.add("cunread"); div.classList.add("cunread");
} }
Channel.contextmenu.bindContextmenu(div,this,undefined); Channel.contextmenu.bindContextmenu(div,this,undefined);
if(admin){this.coatDropDiv(div);} if(admin){
this.coatDropDiv(div);
}
div["all"]=this; div["all"]=this;
const myhtml=document.createElement("span"); const myhtml=document.createElement("span");
myhtml.textContent=this.name; myhtml.textContent=this.name;
if(this.type===0){ if(this.type===0){
const decoration=document.createElement("img"); const decoration=document.createElement("img");
decoration.src="/icons/channel.svg"; decoration.src="/icons/channel.svg";
div.appendChild(decoration) div.appendChild(decoration);
decoration.classList.add("space","svgtheme"); decoration.classList.add("space","svgtheme");
}else if(this.type===2){// }else if(this.type===2){//
const decoration=document.createElement("img"); const decoration=document.createElement("img");
decoration.src="/icons/voice.svg"; decoration.src="/icons/voice.svg";
div.appendChild(decoration) div.appendChild(decoration);
decoration.classList.add("space","svgtheme"); decoration.classList.add("space","svgtheme");
}else if(this.type===5){// }else if(this.type===5){//
const decoration=document.createElement("img"); const decoration=document.createElement("img");
decoration.src="/icons/announce.svg"; decoration.src="/icons/announce.svg";
div.appendChild(decoration) div.appendChild(decoration);
decoration.classList.add("space","svgtheme"); decoration.classList.add("space","svgtheme");
}else{ }else{
console.log(this.type) console.log(this.type);
} }
div.appendChild(myhtml); div.appendChild(myhtml);
div.onclick=_=>{ div.onclick=_=>{
this.getHTML(); this.getHTML();
} };
} }
return div; return div;
} }
get myhtml(){ get myhtml(){
const search=(document.getElementById("channels") as HTMLDivElement).children[0].children const search=(document.getElementById("channels") as HTMLDivElement).children[0].children;
if(this.guild!==this.localuser.lookingguild){ if(this.guild!==this.localuser.lookingguild){
return null return null;
}else if(this.parent){ }else if(this.parent){
for(const thing of search){ for(const thing of search){
if(thing["all"]===this.parent){ if(thing["all"]===this.parent){
@ -469,9 +489,9 @@ class Channel{
return; return;
} }
fetch(this.info.api+"/channels/"+this.snowflake+"/messages/"+this.lastmessageid+"/ack",{ fetch(this.info.api+"/channels/"+this.snowflake+"/messages/"+this.lastmessageid+"/ack",{
method:"POST", method: "POST",
headers:this.headers, headers: this.headers,
body:JSON.stringify({}) body: JSON.stringify({})
}); });
this.lastreadmessageid=this.lastmessageid; this.lastreadmessageid=this.lastmessageid;
this.guild.unreads(); this.guild.unreads();
@ -480,18 +500,18 @@ class Channel{
} }
} }
coatDropDiv(div:HTMLDivElement,container:HTMLElement|boolean=false){ coatDropDiv(div:HTMLDivElement,container:HTMLElement|boolean=false){
div.addEventListener("dragenter", (event) => { div.addEventListener("dragenter", event=>{
console.log("enter") console.log("enter");
event.preventDefault(); event.preventDefault();
}); });
div.addEventListener("dragover", (event) => { div.addEventListener("dragover", event=>{
event.preventDefault(); event.preventDefault();
}); });
div.addEventListener("drop", (event) => { div.addEventListener("drop", event=>{
const that=Channel.dragged[0]; const that=Channel.dragged[0];
if(!that) return; if(!that)return;
event.preventDefault(); event.preventDefault();
if(container){ if(container){
that.move_id=this.snowflake; that.move_id=this.snowflake;
@ -513,7 +533,7 @@ class Channel{
if(that.parent){ if(that.parent){
const build:Channel[]=[]; const build:Channel[]=[];
for(let i=0;i<that.parent.children.length;i++){ for(let i=0;i<that.parent.children.length;i++){
build.push(that.parent.children[i]) build.push(that.parent.children[i]);
if(that.parent.children[i]===this){ if(that.parent.children[i]===this){
build.push(that); build.push(that);
} }
@ -522,7 +542,7 @@ class Channel{
}else{ }else{
const build:Channel[]=[]; const build:Channel[]=[];
for(let i=0;i<this.guild.headchannels.length;i++){ for(let i=0;i<this.guild.headchannels.length;i++){
build.push(this.guild.headchannels[i]) build.push(this.guild.headchannels[i]);
if(this.guild.headchannels[i]===this){ if(this.guild.headchannels[i]===this){
build.push(that); build.push(that);
} }
@ -533,22 +553,22 @@ class Channel{
div.after(Channel.dragged[1]); div.after(Channel.dragged[1]);
} }
} }
this.guild.calculateReorder() this.guild.calculateReorder();
}); });
return div; return div;
} }
createChannel(name:string,type:number){ createChannel(name:string,type:number){
fetch(this.info.api+"/guilds/"+this.guild.id+"/channels",{ fetch(this.info.api+"/guilds/"+this.guild.id+"/channels",{
method:"POST", method: "POST",
headers:this.headers, headers: this.headers,
body:JSON.stringify({ body: JSON.stringify({
name: name, name,
type: type, type,
parent_id: this.snowflake, parent_id: this.snowflake,
permission_overwrites:[], permission_overwrites: [],
})
}) })
});
} }
editChannel(){ editChannel(){
let name=this.name; let name=this.name;
@ -559,50 +579,54 @@ class Channel{
const full=new Dialog( const full=new Dialog(
["hdiv", ["hdiv",
["vdiv", ["vdiv",
["textbox","Channel name:",this.name,function(this:HTMLInputElement){name=this.value}], ["textbox","Channel name:",this.name,function(this:HTMLInputElement){
["mdbox","Channel topic:",this.topic,function(this:HTMLTextAreaElement){topic=this.value}], name=this.value;
["checkbox","NSFW Channel",this.nsfw,function(this:HTMLInputElement){nsfw=this.checked}], }],
["mdbox","Channel topic:",this.topic,function(this:HTMLTextAreaElement){
topic=this.value;
}],
["checkbox","NSFW Channel",this.nsfw,function(this:HTMLInputElement){
nsfw=this.checked;
}],
["button","","submit",()=>{ ["button","","submit",()=>{
fetch(this.info.api+"/channels/"+thisid,{ fetch(this.info.api+"/channels/"+thisid,{
method:"PATCH", method: "PATCH",
headers:this.headers, headers: this.headers,
body:JSON.stringify({ body: JSON.stringify({
"name": name, name,
"type": thistype, type: thistype,
"topic": topic, topic,
"bitrate": 64000, bitrate: 64000,
"user_limit": 0, user_limit: 0,
"nsfw": nsfw, nsfw,
"flags": 0, flags: 0,
"rate_limit_per_user": 0 rate_limit_per_user: 0
}) })
}) });
console.log(full) console.log(full);
full.hide(); full.hide();
}] }]
] ]
]); ]);
full.show(); full.show();
console.log(full) console.log(full);
} }
deleteChannel(){ deleteChannel(){
fetch(this.info.api+"/channels/"+this.snowflake,{ fetch(this.info.api+"/channels/"+this.snowflake,{
method:"DELETE", method: "DELETE",
headers:this.headers headers: this.headers
}) });
} }
setReplying(message:Message){ setReplying(message:Message){
if(this.replyingto?.div){ if(this.replyingto?.div){
this.replyingto.div.classList.remove("replying"); this.replyingto.div.classList.remove("replying");
} }
this.replyingto=message; this.replyingto=message;
if(!this.replyingto?.div) return; if(!this.replyingto?.div)return;
console.log(message); console.log(message);
this.replyingto.div.classList.add("replying"); this.replyingto.div.classList.add("replying");
this.makereplybox(); this.makereplybox();
} }
makereplybox(){ makereplybox(){
const replybox=document.getElementById("replybox") as HTMLElement; const replybox=document.getElementById("replybox") as HTMLElement;
@ -618,7 +642,7 @@ class Channel{
replybox.classList.add("hideReplyBox"); replybox.classList.add("hideReplyBox");
this.replyingto=null; this.replyingto=null;
replybox.innerHTML=""; replybox.innerHTML="";
} };
replybox.classList.remove("hideReplyBox"); replybox.classList.remove("hideReplyBox");
X.textContent="⦻"; X.textContent="⦻";
X.classList.add("cancelReply"); X.classList.add("cancelReply");
@ -633,7 +657,7 @@ class Channel{
if(message){ if(message){
return message; return message;
}else{ }else{
const gety=await fetch(this.info.api+"/channels/"+this.snowflake+"/messages?limit=1&around="+id,{headers:this.headers}) const gety=await fetch(this.info.api+"/channels/"+this.snowflake+"/messages?limit=1&around="+id,{headers: this.headers});
const json=await gety.json(); const json=await gety.json();
return new Message(json[0],this); return new Message(json[0],this);
} }
@ -651,7 +675,7 @@ class Channel{
this.localuser.channelfocus.myhtml.classList.remove("viewChannel"); this.localuser.channelfocus.myhtml.classList.remove("viewChannel");
} }
if(this.myhtml){ if(this.myhtml){
this.myhtml.classList.add("viewChannel") this.myhtml.classList.add("viewChannel");
} }
this.guild.prevchannel=this; this.guild.prevchannel=this;
this.localuser.channelfocus=this; this.localuser.channelfocus=this;
@ -660,10 +684,10 @@ class Channel{
this.localuser.pageTitle("#"+this.name); this.localuser.pageTitle("#"+this.name);
const channelTopic=document.getElementById("channelTopic") as HTMLSpanElement; const channelTopic=document.getElementById("channelTopic") as HTMLSpanElement;
if (this.topic) { if(this.topic){
channelTopic.innerHTML=new MarkDown(this.topic, this).makeHTML().innerHTML; channelTopic.innerHTML=new MarkDown(this.topic, this).makeHTML().innerHTML;
channelTopic.removeAttribute("hidden"); channelTopic.removeAttribute("hidden");
} else channelTopic.setAttribute("hidden",""); }else channelTopic.setAttribute("hidden","");
const loading=document.getElementById("loadingdiv") as HTMLDivElement; const loading=document.getElementById("loadingdiv") as HTMLDivElement;
Channel.regenLoadingMessages(); Channel.regenLoadingMessages();
@ -686,8 +710,8 @@ class Channel{
for(let i=0;i<15;i++){ for(let i=0;i<15;i++){
const div=document.createElement("div"); const div=document.createElement("div");
div.classList.add("loadingmessage"); div.classList.add("loadingmessage");
if(Math.random()<.5){ if(Math.random()<0.5){
const pfp=document.createElement("div") const pfp=document.createElement("div");
pfp.classList.add("loadingpfp"); pfp.classList.add("loadingpfp");
const username=document.createElement("div"); const username=document.createElement("div");
username.style.width=Math.floor(Math.random()*96*1.5+40)+"px"; username.style.width=Math.floor(Math.random()*96*1.5+40)+"px";
@ -704,9 +728,11 @@ class Channel{
} }
lastmessage:Message|undefined; lastmessage:Message|undefined;
async putmessages(){ async putmessages(){
if(this.allthewayup){return}; if(this.allthewayup){
return;
}
if(this.lastreadmessageid&&this.messages.has(this.lastreadmessageid)){ if(this.lastreadmessageid&&this.messages.has(this.lastreadmessageid)){
return return;
} }
const j=await fetch(this.info.api+"/channels/"+this.snowflake+"/messages?limit=100",{ const j=await fetch(this.info.api+"/channels/"+this.snowflake+"/messages?limit=100",{
headers: this.headers, headers: this.headers,
@ -716,7 +742,7 @@ class Channel{
if(response.length!==100){ if(response.length!==100){
this.allthewayup=true; this.allthewayup=true;
} }
let prev:Message|undefined=undefined; let prev:Message|undefined;
for(const thing of response){ for(const thing of response){
const message=new Message(thing,this); const message=new Message(thing,this);
if(prev){ if(prev){
@ -736,7 +762,7 @@ class Channel{
const build:Channel[]=[]; const build:Channel[]=[];
for(const thing of this.children){ for(const thing of this.children){
if(thing.id!==json.id){ if(thing.id!==json.id){
build.push(thing) build.push(thing);
} }
} }
this.children=build; this.children=build;
@ -746,12 +772,14 @@ class Channel{
return; return;
} }
await fetch(this.info.api+"/channels/"+this.id+"/messages?limit=100&after="+id,{ await fetch(this.info.api+"/channels/"+this.id+"/messages?limit=100&after="+id,{
headers:this.headers headers: this.headers
}).then((j)=>{return j.json()}).then(response=>{ }).then(j=>{
return j.json();
}).then(response=>{
let previd:string=id; let previd:string=id;
for(const i in response){ for(const i in response){
let messager:Message; let messager:Message;
let willbreak=false let willbreak=false;
if(!SnowFlake.hasSnowFlakeFromID(response[i].id,Message)){ if(!SnowFlake.hasSnowFlakeFromID(response[i].id,Message)){
messager=new Message(response[i],this); messager=new Message(response[i],this);
}else{ }else{
@ -767,8 +795,7 @@ class Channel{
} }
} }
//out.buildmessages(); //out.buildmessages();
}) });
return;
} }
topid:string; topid:string;
async grabBefore(id:string){ async grabBefore(id:string){
@ -777,8 +804,10 @@ class Channel{
} }
await fetch(this.info.api+"/channels/"+this.id+"/messages?before="+id+"&limit=100",{ await fetch(this.info.api+"/channels/"+this.id+"/messages?before="+id+"&limit=100",{
headers:this.headers headers: this.headers
}).then((j)=>{return j.json()}).then((response:messagejson[])=>{ }).then(j=>{
return j.json();
}).then((response:messagejson[])=>{
if(response.length<100){ if(response.length<100){
this.allthewayup=true; this.allthewayup=true;
if(response.length===0){ if(response.length===0){
@ -790,7 +819,7 @@ class Channel{
let messager:Message; let messager:Message;
let willbreak=false; let willbreak=false;
if(this.messages.has(response[i].id)){ if(this.messages.has(response[i].id)){
console.log("flaky") console.log("flaky");
messager=this.messages.get(response[i].id) as Message; messager=this.messages.get(response[i].id) as Message;
willbreak=true; willbreak=true;
}else{ }else{
@ -802,15 +831,14 @@ class Channel{
previd=messager.id; previd=messager.id;
this.messageids.set(messager.snowflake,messager); this.messageids.set(messager.snowflake,messager);
if(+i===response.length-1&&response.length<100){ if(Number(i)===response.length-1&&response.length<100){
this.topid=previd; this.topid=previd;
} }
if(willbreak){ if(willbreak){
break; break;
} }
} }
}) });
return;
} }
/** /**
* Please dont use this, its not implemented. * Please dont use this, its not implemented.
@ -818,7 +846,7 @@ class Channel{
* @todo * @todo
**/ **/
async grabArround(id:string){//currently unused and no plans to use it yet async grabArround(id:string){//currently unused and no plans to use it yet
throw new Error("please don't call this, no one has implemented it :P") throw new Error("please don't call this, no one has implemented it :P");
} }
async buildmessages(){ async buildmessages(){
/* /*
@ -831,7 +859,7 @@ class Channel{
} }
infinitefocus=false; infinitefocus=false;
private async tryfocusinfinate(){ private async tryfocusinfinate(){
if(this.infinitefocus) return; if(this.infinitefocus)return;
this.infinitefocus=true; this.infinitefocus=true;
const messages=document.getElementById("channelw") as HTMLDivElement; const messages=document.getElementById("channelw") as HTMLDivElement;
for(const thing of messages.getElementsByClassName("messagecontainer")){ for(const thing of messages.getElementsByClassName("messagecontainer")){
@ -852,7 +880,7 @@ class Channel{
if(!removetitle){ if(!removetitle){
const title=document.createElement("h2"); const title=document.createElement("h2");
title.id="removetitle"; title.id="removetitle";
title.textContent="No messages appear to be here, be the first to say something!" title.textContent="No messages appear to be here, be the first to say something!";
title.classList.add("titlespace"); title.classList.add("titlespace");
messages.append(title); messages.append(title);
} }
@ -870,7 +898,6 @@ class Channel{
loading.classList.remove("loading"); loading.classList.remove("loading");
}); });
//this.infinite.focus(id.id,false); //this.infinite.focus(id.id,false);
} }
private goBackIds(id:string,back:number,returnifnotexistant=true):string|undefined{ private goBackIds(id:string,back:number,returnifnotexistant=true):string|undefined{
while(back!==0){ while(back!==0){
@ -889,7 +916,7 @@ class Channel{
return id; return id;
} }
private findClosest(id:string|undefined){ private findClosest(id:string|undefined){
if(!this.lastmessageid||!id) return; if(!this.lastmessageid||!id)return;
let flake:string|undefined=this.lastmessageid; let flake:string|undefined=this.lastmessageid;
const time=Number((BigInt(id)>>22n)+1420070400000n); const time=Number((BigInt(id)>>22n)+1420070400000n);
let flaketime=Number((BigInt(flake)>>22n)+1420070400000n); let flaketime=Number((BigInt(flake)>>22n)+1420070400000n);
@ -897,7 +924,7 @@ class Channel{
flake=this.idToPrev.get(flake); flake=this.idToPrev.get(flake);
if(!flake){ if(!flake){
return undefined; return;
} }
flaketime=Number((BigInt(flake)>>22n)+1420070400000n); flaketime=Number((BigInt(flake)>>22n)+1420070400000n);
} }
@ -913,7 +940,9 @@ class Channel{
this.messageids=new Map(); this.messageids=new Map();
this.permission_overwrites=new Map(); this.permission_overwrites=new Map();
for(const thing of json.permission_overwrites){ for(const thing of json.permission_overwrites){
if(thing.id==="1182819038095799904"||thing.id==="1182820803700625444"){continue;}; if(thing.id==="1182819038095799904"||thing.id==="1182820803700625444"){
continue;
}
this.permission_overwrites.set(thing.id,new Permissions(thing.allow,thing.deny)); this.permission_overwrites.set(thing.id,new Permissions(thing.allow,thing.deny));
const permisions=this.permission_overwrites.get(thing.id); const permisions=this.permission_overwrites.get(thing.id);
if(permisions){ if(permisions){
@ -924,28 +953,30 @@ class Channel{
this.nsfw=json.nsfw; this.nsfw=json.nsfw;
} }
typingstart(){ typingstart(){
if(this.typing>new Date().getTime()){ if(this.typing>Date.now()){
return; return;
} }
this.typing=new Date().getTime()+6000; this.typing=Date.now()+6000;
fetch(this.info.api+"/channels/"+this.snowflake+"/typing",{ fetch(this.info.api+"/channels/"+this.snowflake+"/typing",{
method:"POST", method: "POST",
headers:this.headers headers: this.headers
}) });
} }
get notification(){ get notification(){
let notinumber:number|null=this.message_notifications; let notinumber:number|null=this.message_notifications;
if(+notinumber===3){notinumber=null;} if(Number(notinumber)===3){
notinumber=null;
}
notinumber??=this.guild.message_notifications; notinumber??=this.guild.message_notifications;
switch(+notinumber){ switch(Number(notinumber)){
case 0: case 0:
return "all"; return"all";
case 1: case 1:
return "mentions"; return"mentions";
case 2: case 2:
return "none"; return"none";
case 3: case 3:
return "default"; return"default";
} }
} }
async sendMessage(content:string,{attachments=[],embeds=[],replyingto=null}: async sendMessage(content:string,{attachments=[],embeds=[],replyingto=null}:
@ -954,48 +985,50 @@ class Channel{
if(replyingto){ if(replyingto){
replyjson= replyjson=
{ {
"guild_id":replyingto.guild.id, guild_id: replyingto.guild.id,
"channel_id": replyingto.channel.id, channel_id: replyingto.channel.id,
"message_id": replyingto.id, message_id: replyingto.id,
};
}; };
}
if(attachments.length===0){ if(attachments.length===0){
const body={ const body={
content:content, content,
nonce:Math.floor(Math.random()*1000000000), nonce: Math.floor(Math.random()*1000000000),
message_reference:undefined message_reference: undefined
}; };
if(replyjson){ if(replyjson){
body.message_reference=replyjson; body.message_reference=replyjson;
} }
return await fetch(this.info.api+"/channels/"+this.snowflake+"/messages",{ return await fetch(this.info.api+"/channels/"+this.snowflake+"/messages",{
method:"POST", method: "POST",
headers:this.headers, headers: this.headers,
body:JSON.stringify(body) body: JSON.stringify(body)
}) });
}else{ }else{
const formData = new FormData(); const formData = new FormData();
const body={ const body={
content:content, content,
nonce:Math.floor(Math.random()*1000000000), nonce: Math.floor(Math.random()*1000000000),
message_reference:undefined message_reference: undefined
} };
if(replyjson){ if(replyjson){
body.message_reference=replyjson; body.message_reference=replyjson;
} }
formData.append('payload_json', JSON.stringify(body)); formData.append("payload_json", JSON.stringify(body));
for(const i in attachments){ for(const i in attachments){
formData.append("files["+i+"]",attachments[i]); formData.append("files["+i+"]",attachments[i]);
} }
return await fetch(this.info.api+"/channels/"+this.snowflake+"/messages", { return await fetch(this.info.api+"/channels/"+this.snowflake+"/messages", {
method: 'POST', method: "POST",
body: formData, body: formData,
headers:{"Authorization":this.headers.Authorization} headers: {Authorization: this.headers.Authorization}
}); });
} }
} }
messageCreate(messagep:messageCreateJson):void{ messageCreate(messagep:messageCreateJson):void{
if(!this.hasPermission("VIEW_CHANNEL")){return} if(!this.hasPermission("VIEW_CHANNEL")){
return;
}
const messagez=new Message(messagep.d,this); const messagez=new Message(messagep.d,this);
this.lastmessage=messagez; this.lastmessage=messagez;
if(this.lastmessageid){ if(this.lastmessageid){
@ -1018,7 +1051,9 @@ class Channel{
} }
this.guild.unreads(); this.guild.unreads();
if(this===this.localuser.channelfocus){ if(this===this.localuser.channelfocus){
if(!this.infinitefocus){this.tryfocusinfinate();} if(!this.infinitefocus){
this.tryfocusinfinate();
}
this.infinite.addedBottom(); this.infinite.addedBottom();
} }
if(messagez.author===this.localuser.user){ if(messagez.author===this.localuser.user){
@ -1032,16 +1067,15 @@ class Channel{
}else if(this.notification==="mentions"&&messagez.mentionsuser(this.localuser.user)){ }else if(this.notification==="mentions"&&messagez.mentionsuser(this.localuser.user)){
this.notify(messagez); this.notify(messagez);
} }
} }
notititle(message:Message):string{ notititle(message:Message):string{
return message.author.username+" > "+this.guild.properties.name+" > "+this.name; return message.author.username+" > "+this.guild.properties.name+" > "+this.name;
} }
notify(message:Message,deep=0){ notify(message:Message,deep=0){
Voice.noises(Voice.getNotificationSound()); Voice.noises(Voice.getNotificationSound());
if (!("Notification" in window)) { if(!("Notification" in window)){
} else if (Notification.permission === "granted") { }else if(Notification.permission === "granted"){
let noticontent:string|undefined|null=message.content.textContent; let noticontent:string|undefined|null=message.content.textContent;
if(message.embeds[0]){ if(message.embeds[0]){
noticontent||=message.embeds[0].json.title; noticontent||=message.embeds[0].json.title;
@ -1058,32 +1092,34 @@ class Channel{
imgurl||=image.url; imgurl||=image.url;
} }
const notification = new Notification(this.notititle(message),{ const notification = new Notification(this.notititle(message),{
body:noticontent, body: noticontent,
icon:message.author.getpfpsrc(), icon: message.author.getpfpsrc(),
image:imgurl, image: imgurl,
}); });
notification.addEventListener("click",_=>{ notification.addEventListener("click",_=>{
window.focus(); window.focus();
this.getHTML(); this.getHTML();
}) });
} else if (Notification.permission !== "denied") { }else if(Notification.permission !== "denied"){
Notification.requestPermission().then(() => { Notification.requestPermission().then(()=>{
if(deep===3){return}; if(deep===3){
return;
}
this.notify(message,deep+1); this.notify(message,deep+1);
}); });
} }
} }
async addRoleToPerms(role:Role){ async addRoleToPerms(role:Role){
await fetch(this.info.api+"/channels/"+this.snowflake+"/permissions/"+role.snowflake,{ await fetch(this.info.api+"/channels/"+this.snowflake+"/permissions/"+role.snowflake,{
method:"PUT", method: "PUT",
headers:this.headers, headers: this.headers,
body:JSON.stringify({ body: JSON.stringify({
allow:"0", allow: "0",
deny:"0", deny: "0",
id:role.id, id: role.id,
type:0 type: 0
})
}) })
});
const perm=new Permissions("0","0"); const perm=new Permissions("0","0");
this.permission_overwrites.set(role.id,perm); this.permission_overwrites.set(role.id,perm);
this.permission_overwritesar.push([role.snowflake,perm]); this.permission_overwritesar.push([role.snowflake,perm]);
@ -1094,18 +1130,18 @@ class Channel{
permission.allow=perms.allow; permission.allow=perms.allow;
permission.deny=perms.deny; permission.deny=perms.deny;
await fetch(this.info.api+"/channels/"+this.snowflake+"/permissions/"+id,{ await fetch(this.info.api+"/channels/"+this.snowflake+"/permissions/"+id,{
method:"PUT", method: "PUT",
headers:this.headers, headers: this.headers,
body:JSON.stringify({ body: JSON.stringify({
allow:permission.allow.toString(), allow: permission.allow.toString(),
deny:permission.deny.toString(), deny: permission.deny.toString(),
id:id, id,
type:0 type: 0
})
}) })
});
} }
} }
} }
Channel.setupcontextmenu(); Channel.setupcontextmenu();
export {Channel}; export{Channel};

View file

@ -5,11 +5,11 @@ class Contextmenu<x,y>{
div:HTMLDivElement; div:HTMLDivElement;
static setup(){ static setup(){
Contextmenu.currentmenu=""; Contextmenu.currentmenu="";
document.addEventListener('click', function(event) { document.addEventListener("click", event=>{
if(Contextmenu.currentmenu==""){ if(Contextmenu.currentmenu==""){
return; return;
} }
if (!Contextmenu.currentmenu.contains(event.target)) { if(!Contextmenu.currentmenu.contains(event.target)){
Contextmenu.currentmenu.remove(); Contextmenu.currentmenu.remove();
Contextmenu.currentmenu=""; Contextmenu.currentmenu="";
} }
@ -17,15 +17,15 @@ class Contextmenu<x,y>{
} }
constructor(name:string){ constructor(name:string){
this.name=name; this.name=name;
this.buttons=[] this.buttons=[];
} }
addbutton(text:string,onclick:(this:x,arg:y,e:MouseEvent)=>void,img:null|string=null,shown:(this:x,arg:y)=>boolean=_=>true,enabled:(this:x,arg:y)=>boolean=_=>true){ addbutton(text:string,onclick:(this:x,arg:y,e:MouseEvent)=>void,img:null|string=null,shown:(this:x,arg:y)=>boolean=_=>true,enabled:(this:x,arg:y)=>boolean=_=>true){
this.buttons.push([text,onclick,img,shown,enabled,"button"]); this.buttons.push([text,onclick,img,shown,enabled,"button"]);
return {}; return{};
} }
addsubmenu(text:string,onclick:(this:x,arg:y,e:MouseEvent)=>void,img=null,shown:(this:x,arg:y)=>boolean=_=>true,enabled:(this:x,arg:y)=>boolean=_=>true){ addsubmenu(text:string,onclick:(this:x,arg:y,e:MouseEvent)=>void,img=null,shown:(this:x,arg:y)=>boolean=_=>true,enabled:(this:x,arg:y)=>boolean=_=>true){
this.buttons.push([text,onclick,img,shown,enabled,"submenu"]) this.buttons.push([text,onclick,img,shown,enabled,"submenu"]);
return {}; return{};
} }
makemenu(x:number,y:number,addinfo:any,other:y){ makemenu(x:number,y:number,addinfo:any,other:y){
const div=document.createElement("div"); const div=document.createElement("div");
@ -36,53 +36,53 @@ class Contextmenu<x,y>{
if(!thing[3].bind(addinfo)(other))continue; if(!thing[3].bind(addinfo)(other))continue;
visibleButtons++; visibleButtons++;
const intext=document.createElement("button") const intext=document.createElement("button");
intext.disabled=!thing[4].bind(addinfo)(other); intext.disabled=!thing[4].bind(addinfo)(other);
intext.classList.add("contextbutton") intext.classList.add("contextbutton");
intext.textContent=thing[0] intext.textContent=thing[0];
console.log(thing) console.log(thing);
if(thing[5]==="button"||thing[5]==="submenu"){ if(thing[5]==="button"||thing[5]==="submenu"){
intext.onclick=thing[1].bind(addinfo,other); intext.onclick=thing[1].bind(addinfo,other);
} }
div.appendChild(intext); div.appendChild(intext);
} }
if (visibleButtons == 0) return; if(visibleButtons == 0)return;
if(Contextmenu.currentmenu!=""){ if(Contextmenu.currentmenu!=""){
Contextmenu.currentmenu.remove(); Contextmenu.currentmenu.remove();
} }
div.style.top = y+'px'; div.style.top = y+"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);
console.log(div) console.log(div);
Contextmenu.currentmenu=div; Contextmenu.currentmenu=div;
return this.div; return this.div;
} }
bindContextmenu(obj:HTMLElement,addinfo:x,other:y){ bindContextmenu(obj:HTMLElement,addinfo:x,other:y){
const func=(event) => { const func=event=>{
event.preventDefault(); event.preventDefault();
event.stopImmediatePropagation(); event.stopImmediatePropagation();
this.makemenu(event.clientX,event.clientY,addinfo,other); this.makemenu(event.clientX,event.clientY,addinfo,other);
} };
obj.addEventListener("contextmenu", func); obj.addEventListener("contextmenu", func);
return func; return func;
} }
static keepOnScreen(obj:HTMLElement){ static keepOnScreen(obj:HTMLElement){
const html = document.documentElement.getBoundingClientRect(); const html = document.documentElement.getBoundingClientRect();
const docheight=html.height const docheight=html.height;
const docwidth=html.width const docwidth=html.width;
const box=obj.getBoundingClientRect(); const box=obj.getBoundingClientRect();
console.log(box,docheight,docwidth); console.log(box,docheight,docwidth);
if(box.right>docwidth){ if(box.right>docwidth){
console.log("test") console.log("test");
obj.style.left = docwidth-box.width+'px'; obj.style.left = docwidth-box.width+"px";
} }
if(box.bottom>docheight){ if(box.bottom>docheight){
obj.style.top = docheight-box.height+'px'; obj.style.top = docheight-box.height+"px";
} }
} }
} }
Contextmenu.setup(); Contextmenu.setup();
export {Contextmenu as Contextmenu} export{Contextmenu};

View file

@ -10,17 +10,16 @@ class Dialog{
this.onclose=onclose; this.onclose=onclose;
this.onopen=onopen; this.onopen=onopen;
const div=document.createElement("div"); const div=document.createElement("div");
div.appendChild(this.tohtml(layout)) div.appendChild(this.tohtml(layout));
this.html=div; this.html=div;
this.html.classList.add("centeritem"); this.html.classList.add("centeritem");
if(!(layout[0]==="img")){ if(!(layout[0]==="img")){
this.html.classList.add("nonimagecenter"); this.html.classList.add("nonimagecenter");
} }
} }
tohtml(array:any[]){ tohtml(array:any[]){
switch(array[0]){ switch(array[0]){
case "img": case"img":
const img=document.createElement("img"); const img=document.createElement("img");
img.src=array[1]; img.src=array[1];
if(array[2]!=undefined){ if(array[2]!=undefined){
@ -28,36 +27,40 @@ class Dialog{
img.width=array[2][0]; img.width=array[2][0];
img.height=array[2][1]; img.height=array[2][1];
}else if(array[2][0]=="fit"){ }else if(array[2][0]=="fit"){
img.classList.add("imgfit") img.classList.add("imgfit");
} }
} }
return img; return img;
case "hdiv": case"hdiv":
const hdiv=document.createElement("table"); const hdiv=document.createElement("table");
const tr=document.createElement("tr"); const tr=document.createElement("tr");
hdiv.appendChild(tr) hdiv.appendChild(tr);
for(const thing of array){ for(const thing of array){
if(thing==="hdiv"){continue;} if(thing==="hdiv"){
continue;
}
const td=document.createElement("td"); const td=document.createElement("td");
td.appendChild(this.tohtml(thing)); td.appendChild(this.tohtml(thing));
tr.appendChild(td); tr.appendChild(td);
} }
return hdiv; return hdiv;
case "vdiv": case"vdiv":
const vdiv=document.createElement("table"); const vdiv=document.createElement("table");
for(const thing of array){ for(const thing of array){
if(thing==="vdiv"){continue;} if(thing==="vdiv"){
continue;
}
const tr=document.createElement("tr"); const tr=document.createElement("tr");
tr.appendChild(this.tohtml(thing)); tr.appendChild(this.tohtml(thing));
vdiv.appendChild(tr); vdiv.appendChild(tr);
} }
return vdiv; return vdiv;
case "checkbox": case"checkbox":
{ {
const div=document.createElement("div"); const div=document.createElement("div");
const checkbox = document.createElement('input'); const checkbox = document.createElement("input");
div.appendChild(checkbox) div.appendChild(checkbox);
const label=document.createElement("span"); const label=document.createElement("span");
checkbox.checked=array[2]; checkbox.checked=array[2];
label.textContent=array[1]; label.textContent=array[1];
@ -66,20 +69,20 @@ class Dialog{
checkbox.type = "checkbox"; checkbox.type = "checkbox";
return div; return div;
} }
case "button": case"button":
{ {
const div=document.createElement("div"); const div=document.createElement("div");
const input = document.createElement('button'); const input = document.createElement("button");
const label=document.createElement("span"); const label=document.createElement("span");
input.textContent=array[2]; input.textContent=array[2];
label.textContent=array[1]; label.textContent=array[1];
div.appendChild(label); div.appendChild(label);
div.appendChild(input) div.appendChild(input);
input.addEventListener("click",array[3]); input.addEventListener("click",array[3]);
return div; return div;
} }
case "mdbox": case"mdbox":
{ {
const div=document.createElement("div"); const div=document.createElement("div");
const input=document.createElement("textarea"); const input=document.createElement("textarea");
@ -92,7 +95,7 @@ class Dialog{
div.appendChild(input); div.appendChild(input);
return div; return div;
} }
case "textbox": case"textbox":
{ {
const div=document.createElement("div"); const div=document.createElement("div");
const input=document.createElement("input"); const input=document.createElement("input");
@ -100,13 +103,13 @@ class Dialog{
input.type="text"; input.type="text";
const label=document.createElement("span"); const label=document.createElement("span");
label.textContent=array[1]; label.textContent=array[1];
console.log(array[3]) console.log(array[3]);
input.addEventListener("input",array[3]); input.addEventListener("input",array[3]);
div.appendChild(label); div.appendChild(label);
div.appendChild(input); div.appendChild(input);
return div; return div;
} }
case "fileupload": case"fileupload":
{ {
const div=document.createElement("div"); const div=document.createElement("div");
const input=document.createElement("input"); const input=document.createElement("input");
@ -116,24 +119,24 @@ class Dialog{
div.appendChild(label); div.appendChild(label);
div.appendChild(input); div.appendChild(input);
input.addEventListener("change",array[2]); input.addEventListener("change",array[2]);
console.log(array) console.log(array);
return div; return div;
} }
case "text":{ case"text":{
const span =document.createElement("span"); const span =document.createElement("span");
span.textContent=array[1]; span.textContent=array[1];
return span; return span;
} }
case "title":{ case"title":{
const span =document.createElement("span"); const span =document.createElement("span");
span.classList.add("title") span.classList.add("title");
span.textContent=array[1]; span.textContent=array[1];
return span; return span;
} }
case "radio":{ case"radio":{
const div=document.createElement("div"); const div=document.createElement("div");
const fieldset=document.createElement("fieldset"); const fieldset=document.createElement("fieldset");
fieldset.addEventListener("change",function(){ fieldset.addEventListener("change",()=>{
let i=-1; let i=-1;
for(const thing of fieldset.children){ for(const thing of fieldset.children){
i++; i++;
@ -153,7 +156,7 @@ class Dialog{
for(const thing of array[2]){ for(const thing of array[2]){
const div=document.createElement("div"); const div=document.createElement("div");
const input=document.createElement("input"); const input=document.createElement("input");
input.classList.add("radio") input.classList.add("radio");
input.type="radio"; input.type="radio";
input.name=array[1]; input.name=array[1];
input.value=thing; input.value=thing;
@ -168,15 +171,15 @@ class Dialog{
label.appendChild(span); label.appendChild(span);
div.appendChild(label); div.appendChild(label);
fieldset.appendChild(div); fieldset.appendChild(div);
i++ i++;
} }
div.appendChild(fieldset); div.appendChild(fieldset);
return div; return div;
} }
case "html":{ case"html":
return array[1]; return array[1];
}
case "select":{ case"select":{
const div=document.createElement("div"); const div=document.createElement("div");
const label=document.createElement("label"); const label=document.createElement("label");
const select=document.createElement("select"); const select=document.createElement("select");
@ -193,7 +196,7 @@ class Dialog{
select.addEventListener("change",array[3]); select.addEventListener("change",array[3]);
return div; return div;
} }
case "tabs":{ case"tabs":{
const table=document.createElement("table"); const table=document.createElement("table");
const tabs=document.createElement("tr"); const tabs=document.createElement("tr");
tabs.classList.add("tabbed-head"); tabs.classList.add("tabbed-head");
@ -206,7 +209,6 @@ class Dialog{
let shown; let shown;
for(const thing of array[1]){ for(const thing of array[1]){
const button=document.createElement("button"); const button=document.createElement("button");
button.textContent=thing[0]; button.textContent=thing[0];
td.appendChild(button); td.appendChild(button);
@ -225,27 +227,28 @@ class Dialog{
shown.hidden=true; shown.hidden=true;
tdcontent.hidden=false; tdcontent.hidden=false;
shown=tdcontent; shown=tdcontent;
}) });
} }
return table; return table;
} }
default: default:
console.error("can't find element:"+array[0]," full element:"+array) console.error("can't find element:"+array[0]," full element:"+array);
return;
} }
} }
show(){ show(){
this.onopen(); this.onopen();
console.log("fullscreen") console.log("fullscreen");
this.background=document.createElement("div"); this.background=document.createElement("div");
this.background.classList.add("background"); this.background.classList.add("background");
document.body.appendChild(this.background); document.body.appendChild(this.background);
document.body.appendChild(this.html); document.body.appendChild(this.html);
this.background.onclick = _=>{this.hide()}; this.background.onclick = _=>{
this.hide();
};
} }
hide(){ hide(){
document.body.removeChild(this.background); document.body.removeChild(this.background);
document.body.removeChild(this.html); document.body.removeChild(this.html);
} }
} }
export {Dialog}; export{Dialog};

View file

@ -1,12 +1,12 @@
import {Guild} from "./guild.js"; import{Guild}from"./guild.js";
import { Channel } from "./channel.js"; import{ Channel }from"./channel.js";
import { Message } from "./message.js"; import{ Message }from"./message.js";
import { Localuser } from "./localuser.js"; import{ Localuser }from"./localuser.js";
import {User} from "./user.js"; import{User}from"./user.js";
import { Member } from "./member.js"; import{ Member }from"./member.js";
import { SnowFlake } from "./snowflake.js"; import{ SnowFlake }from"./snowflake.js";
import { dirrectjson, memberjson } from "./jsontypes.js"; import{ dirrectjson, memberjson }from"./jsontypes.js";
import { Permissions } from "./permissions.js"; import{ Permissions }from"./permissions.js";
class Direct extends Guild{ class Direct extends Guild{
constructor(json:dirrectjson[],owner:Localuser){ constructor(json:dirrectjson[],owner:Localuser){
@ -14,7 +14,7 @@ class Direct extends Guild{
this.message_notifications=0; this.message_notifications=0;
this.owner=owner; this.owner=owner;
if(!this.localuser){ if(!this.localuser){
console.error("Owner was not included, please fix") console.error("Owner was not included, please fix");
} }
this.headers=this.localuser.headers; this.headers=this.localuser.headers;
this.channels=[]; this.channels=[];
@ -40,7 +40,7 @@ class Direct extends Guild{
this.printServers(); this.printServers();
} }
giveMember(_member:memberjson){ giveMember(_member:memberjson){
console.error("not a real guild, can't give member object") console.error("not a real guild, can't give member object");
} }
getRole(ID:string){ getRole(ID:string){
return null; return null;
@ -102,7 +102,6 @@ class Group extends Channel{
this.messageids=new Map(); this.messageids=new Map();
this.permission_overwrites=new Map(); this.permission_overwrites=new Map();
this.lastmessageid=json.last_message_id; this.lastmessageid=json.last_message_id;
this.lastmessageid??=null;
this.mentions=0; this.mentions=0;
this.setUpInfiniteScroller(); this.setUpInfiniteScroller();
if(this.lastmessageid){ if(this.lastmessageid){
@ -111,7 +110,7 @@ class Group extends Channel{
this.position=-Math.max(this.position,this.snowflake.getUnixTime()); this.position=-Math.max(this.position,this.snowflake.getUnixTime());
} }
createguildHTML(){ createguildHTML(){
const div=document.createElement("div") const div=document.createElement("div");
div.classList.add("channeleffects"); div.classList.add("channeleffects");
const myhtml=document.createElement("span"); const myhtml=document.createElement("span");
myhtml.textContent=this.name; myhtml.textContent=this.name;
@ -120,7 +119,7 @@ class Group extends Channel{
div["myinfo"]=this; div["myinfo"]=this;
div.onclick=_=>{ div.onclick=_=>{
this.getHTML(); this.getHTML();
} };
return div; return div;
} }
async getHTML(){ async getHTML(){
@ -146,8 +145,8 @@ class Group extends Channel{
const messagez=new Message(messagep.d,this); const messagez=new Message(messagep.d,this);
if(this.lastmessageid){ if(this.lastmessageid){
this.idToNext.set(this.lastmessageid,messagez.id); this.idToNext.set(this.lastmessageid,messagez.id);
}
this.idToPrev.set(messagez.id,this.lastmessageid); this.idToPrev.set(messagez.id,this.lastmessageid);
}
this.lastmessageid=messagez.id; this.lastmessageid=messagez.id;
this.messageids.set(messagez.snowflake,messagez); this.messageids.set(messagez.snowflake,messagez);
if(messagez.author===this.localuser.user){ if(messagez.author===this.localuser.user){
@ -186,35 +185,36 @@ class Group extends Channel{
} }
} }
if(this.hasunreads){ if(this.hasunreads){
if(current){current["noti"].textContent=this.mentions;return;} if(current){
current["noti"].textContent=this.mentions;return;
}
const div=document.createElement("div"); const div=document.createElement("div");
div.classList.add("servernoti"); div.classList.add("servernoti");
const noti=document.createElement("div"); const noti=document.createElement("div");
noti.classList.add("unread","notiunread","pinged"); noti.classList.add("unread","notiunread","pinged");
noti.textContent=""+this.mentions; noti.textContent=""+this.mentions;
div["noti"]=noti; div["noti"]=noti;
div.append(noti) div.append(noti);
const buildpfp=this.user.buildpfp(); const buildpfp=this.user.buildpfp();
div["all"]=this; div["all"]=this;
buildpfp.classList.add("mentioned"); buildpfp.classList.add("mentioned");
div.append(buildpfp) div.append(buildpfp);
sentdms.append(div); sentdms.append(div);
div.onclick=_=>{ div.onclick=_=>{
this.guild.loadGuild(); this.guild.loadGuild();
this.getHTML(); this.getHTML();
} };
}else if(current){ }else if(current){
current.remove(); current.remove();
}else{ }else{
} }
} }
isAdmin(): boolean { isAdmin(): boolean{
return false; return false;
} }
hasPermission(name: string): boolean { hasPermission(name: string): boolean{
return dmPermissions.hasPermission(name); return dmPermissions.hasPermission(name);
} }
} }
export {Direct, Group}; export{Direct, Group};

View file

@ -1,7 +1,7 @@
import {Dialog} from "./dialog.js"; import{Dialog}from"./dialog.js";
import {Message} from "./message.js"; import{Message}from"./message.js";
import {MarkDown} from "./markdown.js"; import{MarkDown}from"./markdown.js";
import { embedjson } from "./jsontypes.js"; import{ embedjson }from"./jsontypes.js";
class Embed{ class Embed{
type:string; type:string;
@ -17,13 +17,13 @@ class Embed{
} }
generateHTML(){ generateHTML(){
switch(this.type){ switch(this.type){
case "rich": case"rich":
return this.generateRich(); return this.generateRich();
case "image": case"image":
return this.generateImage(); return this.generateImage();
case "link": case"link":
return this.generateLink(); return this.generateLink();
case "article": case"article":
return this.generateArticle(); return this.generateArticle();
default: default:
console.warn(`unsupported embed type ${this.type}, please add support dev :3`,this.json); console.warn(`unsupported embed type ${this.type}, please add support dev :3`,this.json);
@ -64,9 +64,9 @@ class Embed{
const a=document.createElement("a"); const a=document.createElement("a");
a.textContent=this.json.author.name as string; a.textContent=this.json.author.name as string;
if(this.json.author.url){ if(this.json.author.url){
a.href=this.json.author.url a.href=this.json.author.url;
} }
a.classList.add("username") a.classList.add("username");
authorline.append(a); authorline.append(a);
embed.append(authorline); embed.append(authorline);
} }
@ -92,12 +92,14 @@ class Embed{
const b=document.createElement("b"); const b=document.createElement("b");
b.textContent=thing.name; b.textContent=thing.name;
div.append(b); div.append(b);
const p=document.createElement("p") const p=document.createElement("p");
p.append(new MarkDown(thing.value,this.channel).makeHTML()); p.append(new MarkDown(thing.value,this.channel).makeHTML());
p.classList.add("embedp"); p.classList.add("embedp");
div.append(p); div.append(p);
if(thing.inline){div.classList.add("inline");} if(thing.inline){
div.classList.add("inline");
}
embed.append(div); embed.append(div);
} }
} }
@ -122,8 +124,8 @@ class Embed{
footer.append(span); footer.append(span);
} }
if(this.json?.timestamp){ if(this.json?.timestamp){
const span=document.createElement("span") const span=document.createElement("span");
span.textContent=new Date(this.json.timestamp).toLocaleString();; span.textContent=new Date(this.json.timestamp).toLocaleString();
footer.append(span); footer.append(span);
} }
embed.append(footer); embed.append(footer);
@ -132,11 +134,11 @@ class Embed{
} }
generateImage(){ generateImage(){
const img=document.createElement("img"); const img=document.createElement("img");
img.classList.add("messageimg") img.classList.add("messageimg");
img.onclick=function(){ img.onclick=function(){
const full=new Dialog(["img",img.src,["fit"]]); const full=new Dialog(["img",img.src,["fit"]]);
full.show(); full.show();
} };
img.src=this.json.thumbnail.proxy_url; img.src=this.json.thumbnail.proxy_url;
if(this.json.thumbnail.width){ if(this.json.thumbnail.width){
let scale=1; let scale=1;
@ -172,7 +174,7 @@ class Embed{
img.onclick=function(){ img.onclick=function(){
const full=new Dialog(["img",img.src,["fit"]]); const full=new Dialog(["img",img.src,["fit"]]);
full.show(); full.show();
} };
img.src=this.json.thumbnail.proxy_url; img.src=this.json.thumbnail.proxy_url;
td.append(img); td.append(img);
} }
@ -186,7 +188,7 @@ class Embed{
td.append(span); td.append(span);
} }
bottomtr.append(td); bottomtr.append(td);
table.append(bottomtr) table.append(bottomtr);
return table; return table;
} }
generateArticle(){ generateArticle(){
@ -219,7 +221,7 @@ class Embed{
img.onclick=function(){ img.onclick=function(){
const full=new Dialog(["img",img.src,["fit"]]); const full=new Dialog(["img",img.src,["fit"]]);
full.show(); full.show();
} };
img.src=this.json.thumbnail.proxy_url||this.json.thumbnail.url; img.src=this.json.thumbnail.proxy_url||this.json.thumbnail.url;
div.append(img); div.append(img);
} }
@ -227,4 +229,4 @@ class Embed{
return colordiv; return colordiv;
} }
} }
export {Embed}; export{Embed};

View file

@ -1,7 +1,7 @@
import { Contextmenu } from "./contextmenu.js"; import{ Contextmenu }from"./contextmenu.js";
import { Guild } from "./guild.js"; import{ Guild }from"./guild.js";
import { emojijson } from "./jsontypes.js"; import{ emojijson }from"./jsontypes.js";
import { Localuser } from "./localuser.js"; import{ Localuser }from"./localuser.js";
class Emoji{ class Emoji{
static emojis:{ static emojis:{
@ -33,7 +33,7 @@ class Emoji{
constructor(json:{name:string,id:string,animated:boolean},owner:Guild|Localuser){ constructor(json:{name:string,id:string,animated:boolean},owner:Guild|Localuser){
this.name=json.name; this.name=json.name;
this.id=json.id; this.id=json.id;
this.animated=json.animated this.animated=json.animated;
this.owner=owner; this.owner=owner;
} }
getHTML(bigemoji:boolean=false){ getHTML(bigemoji:boolean=false){
@ -72,10 +72,8 @@ class Emoji{
for(let i=0;i<length;i++){ for(let i=0;i<length;i++){
array[i]=read8(); array[i]=read8();
} }
const decoded=new TextDecoder("utf-8").decode(array.buffer);;
//console.log(array); //console.log(array);
return decoded; return new TextDecoder("utf-8").decode(array.buffer);
} }
const build:{name:string,emojis:{name:string,emoji:string}[]}[]=[]; const build:{name:string,emojis:{name:string,emoji:string}[]}[]=[];
let cats=read16(); let cats=read16();
@ -93,33 +91,35 @@ class Emoji{
const name=readString8(); const name=readString8();
const len=read8(); const len=read8();
const skin_tone_support=len>127; const skin_tone_support=len>127;
const emoji=readStringNo(len-(+skin_tone_support*128)); const emoji=readStringNo(len-(Number(skin_tone_support)*128));
emojis.push({ emojis.push({
name, name,
skin_tone_support, skin_tone_support,
emoji emoji
}) });
} }
build.push({ build.push({
name, name,
emojis emojis
}) });
} }
this.emojis=build; this.emojis=build;
console.log(build); console.log(build);
} }
static grabEmoji(){ static grabEmoji(){
fetch("/emoji.bin").then(e=>{ fetch("/emoji.bin").then(e=>{
return e.arrayBuffer() return e.arrayBuffer();
}).then(e=>{ }).then(e=>{
Emoji.decodeEmojiList(e); Emoji.decodeEmojiList(e);
}) });
} }
static async emojiPicker(x:number,y:number, localuser:Localuser):Promise<Emoji|string>{ static async emojiPicker(x:number,y:number, localuser:Localuser):Promise<Emoji|string>{
let res:(r:Emoji|string)=>void; let res:(r:Emoji|string)=>void;
const promise:Promise<Emoji|string>=new Promise((r)=>{res=r;}) const promise:Promise<Emoji|string>=new Promise(r=>{
res=r;
});
const menu=document.createElement("div"); const menu=document.createElement("div");
menu.classList.add("flextttb", "emojiPicker") menu.classList.add("flextttb", "emojiPicker");
menu.style.top=y+"px"; menu.style.top=y+"px";
menu.style.left=x+"px"; menu.style.left=x+"px";
@ -133,53 +133,53 @@ class Emoji{
body.classList.add("emojiBody"); body.classList.add("emojiBody");
let isFirst = true; let isFirst = true;
localuser.guilds.filter(guild => guild.id != "@me" && guild.emojis.length > 0).forEach(guild => { localuser.guilds.filter(guild=>guild.id != "@me" && guild.emojis.length > 0).forEach(guild=>{
const select = document.createElement("div") const select = document.createElement("div");
select.classList.add("emojiSelect") select.classList.add("emojiSelect");
if (guild.properties.icon) { if(guild.properties.icon){
const img = document.createElement("img") const img = document.createElement("img");
img.classList.add("pfp", "servericon", "emoji-server") img.classList.add("pfp", "servericon", "emoji-server");
img.crossOrigin = "anonymous" img.crossOrigin = "anonymous";
img.src = localuser.info.cdn + "/icons/" + guild.properties.id + "/" + guild.properties.icon + ".png?size=48" img.src = localuser.info.cdn + "/icons/" + guild.properties.id + "/" + guild.properties.icon + ".png?size=48";
img.alt = "Server: " + guild.properties.name img.alt = "Server: " + guild.properties.name;
select.appendChild(img) select.appendChild(img);
} else { }else{
const div = document.createElement("span") const div = document.createElement("span");
div.textContent = guild.properties.name.replace(/'s /g, " ").replace(/\w+/g, word => word[0]).replace(/\s/g, "") div.textContent = guild.properties.name.replace(/'s /g, " ").replace(/\w+/g, word=>word[0]).replace(/\s/g, "");
select.append(div) select.append(div);
} }
selection.append(select) selection.append(select);
const clickEvent = () => { const clickEvent = ()=>{
title.textContent = guild.properties.name title.textContent = guild.properties.name;
body.innerHTML = "" body.innerHTML = "";
for (const emojit of guild.emojis) { for(const emojit of guild.emojis){
const emojiElem = document.createElement("div") const emojiElem = document.createElement("div");
emojiElem.classList.add("emojiSelect") emojiElem.classList.add("emojiSelect");
const emojiClass = new Emoji({ const emojiClass = new Emoji({
id: emojit.id as string, id: emojit.id as string,
name: emojit.name, name: emojit.name,
animated: emojit.animated as boolean animated: emojit.animated as boolean
},localuser) },localuser);
emojiElem.append(emojiClass.getHTML()) emojiElem.append(emojiClass.getHTML());
body.append(emojiElem) body.append(emojiElem);
emojiElem.addEventListener("click", () => { emojiElem.addEventListener("click", ()=>{
res(emojiClass) res(emojiClass);
Contextmenu.currentmenu.remove() Contextmenu.currentmenu.remove();
}) });
}
} }
};
select.addEventListener("click", clickEvent) select.addEventListener("click", clickEvent);
if (isFirst) { if(isFirst){
clickEvent() clickEvent();
isFirst = false isFirst = false;
} }
}) });
setTimeout(()=>{ setTimeout(()=>{
if(Contextmenu.currentmenu!=""){ if(Contextmenu.currentmenu!=""){
@ -188,7 +188,7 @@ class Emoji{
document.body.append(menu); document.body.append(menu);
Contextmenu.currentmenu=menu; Contextmenu.currentmenu=menu;
Contextmenu.keepOnScreen(menu); Contextmenu.keepOnScreen(menu);
},10) },10);
let i=0; let i=0;
@ -208,10 +208,10 @@ class Emoji{
emoji.onclick=_=>{ emoji.onclick=_=>{
res(emojit.emoji); res(emojit.emoji);
Contextmenu.currentmenu.remove(); Contextmenu.currentmenu.remove();
} };
} }
}; };
select.onclick=clickEvent select.onclick=clickEvent;
if(i===0){ if(i===0){
clickEvent(); clickEvent();
} }
@ -223,4 +223,4 @@ class Emoji{
} }
} }
Emoji.grabEmoji(); Emoji.grabEmoji();
export {Emoji}; export{Emoji};

View file

@ -1,6 +1,6 @@
import { Message } from "./message.js"; import{ Message }from"./message.js";
import { Dialog } from "./dialog.js"; import{ Dialog }from"./dialog.js";
import { filejson } from "./jsontypes.js"; import{ filejson }from"./jsontypes.js";
class File{ class File{
owner:Message|null; owner:Message|null;
@ -34,25 +34,25 @@ class File{
this.width/=scale; this.width/=scale;
this.height/=scale; this.height/=scale;
} }
if(this.content_type.startsWith('image/')){ if(this.content_type.startsWith("image/")){
const div=document.createElement("div") const div=document.createElement("div");
const img=document.createElement("img"); const img=document.createElement("img");
img.classList.add("messageimg"); img.classList.add("messageimg");
div.classList.add("messageimgdiv") div.classList.add("messageimgdiv");
img.onclick=function(){ img.onclick=function(){
const full=new Dialog(["img",img.src,["fit"]]); const full=new Dialog(["img",img.src,["fit"]]);
full.show(); full.show();
} };
img.src=src; img.src=src;
div.append(img) div.append(img);
if(this.width){ if(this.width){
div.style.width=this.width+"px"; div.style.width=this.width+"px";
div.style.height=this.height+"px"; div.style.height=this.height+"px";
} }
console.log(img); console.log(img);
console.log(this.width,this.height) console.log(this.width,this.height);
return div; return div;
}else if(this.content_type.startsWith('video/')){ }else if(this.content_type.startsWith("video/")){
const video=document.createElement("video"); const video=document.createElement("video");
const source=document.createElement("source"); const source=document.createElement("source");
source.src=src; source.src=src;
@ -64,7 +64,7 @@ class File{
video.height=this.height; video.height=this.height;
} }
return video; return video;
}else if(this.content_type.startsWith('audio/')){ }else if(this.content_type.startsWith("audio/")){
const audio=document.createElement("audio"); const audio=document.createElement("audio");
const source=document.createElement("source"); const source=document.createElement("source");
source.src=src; source.src=src;
@ -87,7 +87,7 @@ class File{
garbage.onclick=_=>{ garbage.onclick=_=>{
div.remove(); div.remove();
files.splice(files.indexOf(file),1); files.splice(files.indexOf(file),1);
} };
controls.classList.add("controls"); controls.classList.add("controls");
div.append(controls); div.append(controls);
controls.append(garbage); controls.append(garbage);
@ -95,18 +95,18 @@ class File{
} }
static initFromBlob(file:globalThis.File){ static initFromBlob(file:globalThis.File){
return new File({ return new File({
filename:file.name, filename: file.name,
size:file.size, size: file.size,
id:"null", id: "null",
content_type:file.type, content_type: file.type,
width:undefined, width: undefined,
height:undefined, height: undefined,
url:URL.createObjectURL(file), url: URL.createObjectURL(file),
proxy_url:undefined proxy_url: undefined
},null) },null);
} }
createunknown():HTMLElement{ createunknown():HTMLElement{
console.log("🗎") console.log("🗎");
const src=this.proxy_url||this.url; const src=this.proxy_url||this.url;
const div=document.createElement("table"); const div=document.createElement("table");
div.classList.add("unknownfile"); div.classList.add("unknownfile");
@ -138,8 +138,8 @@ class File{
return div; return div;
} }
static filesizehuman(fsize:number){ static filesizehuman(fsize:number){
var i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024)); const i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024));
return +((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + ' ' + ['Bytes', 'Kilobytes', 'Megabytes', 'Gigabytes', 'Terabytes'][i]; return Number((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + " " + ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i];
} }
} }
export{File} export{File};

View file

@ -1,22 +1,22 @@
import { Channel } from "./channel.js"; import{ Channel }from"./channel.js";
import { Localuser } from "./localuser.js"; import{ Localuser }from"./localuser.js";
import {Contextmenu} from "./contextmenu.js"; import{Contextmenu}from"./contextmenu.js";
import {Role,RoleList} from "./role.js"; import{Role,RoleList}from"./role.js";
import {Dialog} from "./dialog.js"; import{Dialog}from"./dialog.js";
import {Member} from "./member.js"; import{Member}from"./member.js";
import {Settings} from "./settings.js"; import{Settings}from"./settings.js";
import {Permissions} from "./permissions.js"; import{Permissions}from"./permissions.js";
import { SnowFlake } from "./snowflake.js"; import{ SnowFlake }from"./snowflake.js";
import { channeljson, guildjson, emojijson, memberjson } from "./jsontypes.js"; import{ channeljson, guildjson, emojijson, memberjson }from"./jsontypes.js";
import { User } from "./user.js"; import{ User }from"./user.js";
import { Message } from "./message.js"; import{ Message }from"./message.js";
class Guild{ class Guild{
owner:Localuser; owner:Localuser;
headers:Localuser["headers"]; headers:Localuser["headers"];
channels:Channel[]; channels:Channel[];
channelids:{[key:string]:Channel}; channelids:{[key:string]:Channel};
snowflake:SnowFlake<Guild>; snowflake:SnowFlake<Guild>;
properties properties;
roles:Role[]; roles:Role[];
roleids:Map<SnowFlake<Role>,Role>; roleids:Map<SnowFlake<Role>,Role>;
prevchannel:Channel|undefined; prevchannel:Channel|undefined;
@ -33,30 +33,30 @@ class Guild{
static contextmenu=new Contextmenu<Guild,undefined>("guild menu"); static contextmenu=new Contextmenu<Guild,undefined>("guild menu");
static setupcontextmenu(){ static setupcontextmenu(){
Guild.contextmenu.addbutton("Copy Guild id",function(this:Guild){ Guild.contextmenu.addbutton("Copy Guild id",function(this:Guild){
console.log(this) console.log(this);
navigator.clipboard.writeText(this.id); navigator.clipboard.writeText(this.id);
}); });
Guild.contextmenu.addbutton("Mark as read",function(this:Guild){ Guild.contextmenu.addbutton("Mark as read",function(this:Guild){
console.log(this) console.log(this);
this.markAsRead(); this.markAsRead();
}); });
Guild.contextmenu.addbutton("Notifications",function(this:Guild){ Guild.contextmenu.addbutton("Notifications",function(this:Guild){
console.log(this) console.log(this);
this.setnotifcation(); this.setnotifcation();
}); });
Guild.contextmenu.addbutton("Leave guild",function(this:Guild){ Guild.contextmenu.addbutton("Leave guild",function(this:Guild){
this.confirmleave(); this.confirmleave();
},null,function(_){ },null,function(_){
return this.properties.owner_id!==this.member.user.id return this.properties.owner_id!==this.member.user.id;
}); });
Guild.contextmenu.addbutton("Delete guild",function(this:Guild){ Guild.contextmenu.addbutton("Delete guild",function(this:Guild){
this.confirmDelete(); this.confirmDelete();
},null,function(_){ },null,function(_){
return this.properties.owner_id===this.member.user.id return this.properties.owner_id===this.member.user.id;
}); });
Guild.contextmenu.addbutton("Create invite",function(this:Guild){ Guild.contextmenu.addbutton("Create invite",function(this:Guild){
@ -92,9 +92,9 @@ class Guild{
return; return;
} }
if(json.stickers.length){ if(json.stickers.length){
console.log(json.stickers,":3") console.log(json.stickers,":3");
} }
this.emojis = json.emojis this.emojis = json.emojis;
this.owner=owner; this.owner=owner;
this.headers=this.owner.headers; this.headers=this.owner.headers;
this.channels=[]; this.channels=[];
@ -107,13 +107,13 @@ class Guild{
this.message_notifications=0; this.message_notifications=0;
for(const roley of json.roles){ for(const roley of json.roles){
const roleh=new Role(roley,this); const roleh=new Role(roley,this);
this.roles.push(roleh) this.roles.push(roleh);
this.roleids.set(roleh.snowflake,roleh); this.roleids.set(roleh.snowflake,roleh);
} }
if(member instanceof User){ if(member instanceof User){
Member.resolveMember(member,this).then(_=>{ Member.resolveMember(member,this).then(_=>{
if(_){ if(_){
this.member=_ this.member=_;
}else{ }else{
console.error("Member was unable to resolve"); console.error("Member was unable to resolve");
} }
@ -121,7 +121,7 @@ class Guild{
}else{ }else{
Member.new(member,this).then(_=>{ Member.new(member,this).then(_=>{
if(_){ if(_){
this.member=_ this.member=_;
} }
}); });
} }
@ -138,13 +138,12 @@ class Guild{
this.headchannels.push(thing); this.headchannels.push(thing);
} }
} }
} }
notisetting(settings){ notisetting(settings){
this.message_notifications=settings.message_notifications; this.message_notifications=settings.message_notifications;
} }
setnotifcation(){ setnotifcation(){
let noti=this.message_notifications let noti=this.message_notifications;
const notiselect=new Dialog( const notiselect=new Dialog(
["vdiv", ["vdiv",
["radio","select notifications type", ["radio","select notifications type",
@ -157,12 +156,12 @@ class Guild{
["button","","submit",_=>{ ["button","","submit",_=>{
// //
fetch(this.info.api+`/users/@me/guilds/${this.id}/settings/`,{ fetch(this.info.api+`/users/@me/guilds/${this.id}/settings/`,{
method:"PATCH", method: "PATCH",
headers:this.headers, headers: this.headers,
body:JSON.stringify({ body: JSON.stringify({
"message_notifications": noti message_notifications: noti
})
}) })
});
this.message_notifications=noti; this.message_notifications=noti;
}] }]
]); ]);
@ -198,12 +197,12 @@ class Guild{
} }
async leave(){ async leave(){
return fetch(this.info.api+"/users/@me/guilds/"+this.snowflake,{ return fetch(this.info.api+"/users/@me/guilds/"+this.snowflake,{
method:"DELETE", method: "DELETE",
headers:this.headers headers: this.headers
}) });
} }
printServers(){ printServers(){
let build="" let build="";
for(const thing of this.headchannels){ for(const thing of this.headchannels){
build+=(thing.name+":"+thing.position)+"\n"; build+=(thing.name+":"+thing.position)+"\n";
for(const thingy of thing.children){ for(const thingy of thing.children){
@ -214,9 +213,9 @@ class Guild{
} }
calculateReorder(){ calculateReorder(){
let position=-1; let position=-1;
let build:{id:SnowFlake<Channel>,position:number|undefined,parent_id:SnowFlake<Channel>|undefined}[]=[]; const build:{id:SnowFlake<Channel>,position:number|undefined,parent_id:SnowFlake<Channel>|undefined}[]=[];
for(const thing of this.headchannels){ for(const thing of this.headchannels){
const thisthing:{id:SnowFlake<Channel>,position:number|undefined,parent_id:SnowFlake<Channel>|undefined}={id:thing.snowflake,position:undefined,parent_id:undefined} const thisthing:{id:SnowFlake<Channel>,position:number|undefined,parent_id:SnowFlake<Channel>|undefined}={id: thing.snowflake,position: undefined,parent_id: undefined};
if(thing.position<=position){ if(thing.position<=position){
thing.position=(thisthing.position=position+1); thing.position=(thisthing.position=position+1);
} }
@ -231,33 +230,34 @@ class Guild{
build.push(thisthing); build.push(thisthing);
} }
if(thing.children.length>0){ if(thing.children.length>0){
const things=thing.calculateReorder() const things=thing.calculateReorder();
for(const thing of things){ for(const thing of things){
build.push(thing); build.push(thing);
} }
} }
} }
console.log(build) console.log(build);
this.printServers(); this.printServers();
if(build.length===0){return} if(build.length===0){
return;
}
const serverbug=false; const serverbug=false;
if(serverbug){ if(serverbug){
for(const thing of build){ for(const thing of build){
console.log(build,thing) console.log(build,thing);
fetch(this.info.api+"/guilds/"+this.snowflake+"/channels",{ fetch(this.info.api+"/guilds/"+this.snowflake+"/channels",{
method:"PATCH", method: "PATCH",
headers:this.headers, headers: this.headers,
body:JSON.stringify([thing]) body: JSON.stringify([thing])
}); });
} }
}else{ }else{
fetch(this.info.api+"/guilds/"+this.snowflake+"/channels",{ fetch(this.info.api+"/guilds/"+this.snowflake+"/channels",{
method:"PATCH", method: "PATCH",
headers:this.headers, headers: this.headers,
body:JSON.stringify(build) body: JSON.stringify(build)
}); });
} }
} }
get localuser(){ get localuser(){
return this.owner; return this.owner;
@ -266,7 +266,9 @@ class Guild{
return this.owner.info; return this.owner.info;
} }
sortchannels(){ sortchannels(){
this.headchannels.sort((a,b)=>{return a.position-b.position;}); this.headchannels.sort((a,b)=>{
return a.position-b.position;
});
} }
generateGuildIcon(){ generateGuildIcon(){
const divy=document.createElement("div"); const divy=document.createElement("div");
@ -280,24 +282,24 @@ class Guild{
const img=document.createElement("img"); const img=document.createElement("img");
img.classList.add("pfp","servericon"); img.classList.add("pfp","servericon");
img.src=this.info.cdn+"/icons/"+this.properties.id+"/"+this.properties.icon+".png"; img.src=this.info.cdn+"/icons/"+this.properties.id+"/"+this.properties.icon+".png";
divy.appendChild(img) divy.appendChild(img);
img.onclick=()=>{ img.onclick=()=>{
console.log(this.loadGuild) console.log(this.loadGuild);
this.loadGuild(); this.loadGuild();
this.loadChannel(); this.loadChannel();
} };
Guild.contextmenu.bindContextmenu(img,this,undefined); Guild.contextmenu.bindContextmenu(img,this,undefined);
}else{ }else{
const div=document.createElement("div"); const div=document.createElement("div");
let build=this.properties.name.replace(/'s /g, " ").replace(/\w+/g, word => word[0]).replace(/\s/g, ""); const build=this.properties.name.replace(/'s /g, " ").replace(/\w+/g, word=>word[0]).replace(/\s/g, "");
div.textContent=build; div.textContent=build;
div.classList.add("blankserver","servericon") div.classList.add("blankserver","servericon");
divy.appendChild(div) divy.appendChild(div);
div.onclick=()=>{ div.onclick=()=>{
this.loadGuild(); this.loadGuild();
this.loadChannel(); this.loadChannel();
} };
Guild.contextmenu.bindContextmenu(div,this,undefined) Guild.contextmenu.bindContextmenu(div,this,undefined);
} }
return divy; return divy;
} }
@ -314,14 +316,13 @@ class Guild{
function(this:HTMLInputElement){ function(this:HTMLInputElement){
confirmname=this.value; confirmname=this.value;
} }
] ],
,
["hdiv", ["hdiv",
["button", ["button",
"", "",
"Yes, I'm sure", "Yes, I'm sure",
_=>{ _=>{
console.log(confirmname) console.log(confirmname);
if(confirmname!==this.properties.name){ if(confirmname!==this.properties.name){
return; return;
} }
@ -344,11 +345,11 @@ class Guild{
} }
async delete(){ async delete(){
return fetch(this.info.api+"/guilds/"+this.snowflake+"/delete",{ return fetch(this.info.api+"/guilds/"+this.snowflake+"/delete",{
method:"POST", method: "POST",
headers:this.headers, headers: this.headers,
}) });
} }
unreads(html:HTMLElement|undefined=undefined){ unreads(html?:HTMLElement|undefined){
if(html){ if(html){
this.html=html; this.html=html;
}else{ }else{
@ -357,12 +358,14 @@ class Guild{
let read=true; let read=true;
for(const thing of this.channels){ for(const thing of this.channels){
if(thing.hasunreads){ if(thing.hasunreads){
console.log(thing) console.log(thing);
read=false; read=false;
break; break;
} }
} }
if(!html){return;} if(!html){
return;
}
if(read){ if(read){
html.children[0].classList.remove("notiunread"); html.children[0].classList.remove("notiunread");
}else{ }else{
@ -381,24 +384,24 @@ class Guild{
return build; return build;
} }
isAdmin(){ isAdmin(){
return this.member.isAdmin() return this.member.isAdmin();
} }
async markAsRead(){ async markAsRead(){
const build:{read_states:{channel_id:SnowFlake<Channel>,message_id:string|null,read_state_type:number}[]}={read_states:[]}; const build:{read_states:{channel_id:SnowFlake<Channel>,message_id:string|null|undefined,read_state_type:number}[]}={read_states: []};
for(const thing of this.channels){ for(const thing of this.channels){
if(thing.hasunreads){ if(thing.hasunreads){
build.read_states.push({channel_id:thing.snowflake,message_id:thing.lastmessageid,read_state_type:0}); build.read_states.push({channel_id: thing.snowflake,message_id: thing.lastmessageid,read_state_type: 0});
thing.lastreadmessageid=thing.lastmessageid; thing.lastreadmessageid=thing.lastmessageid;
if(!thing.myhtml) continue; if(!thing.myhtml)continue;
thing.myhtml.classList.remove("cunread"); thing.myhtml.classList.remove("cunread");
} }
} }
this.unreads(); this.unreads();
fetch(this.info.api+"/read-states/ack-bulk",{ fetch(this.info.api+"/read-states/ack-bulk",{
method:"POST", method: "POST",
headers:this.headers, headers: this.headers,
body:JSON.stringify(build) body: JSON.stringify(build)
}) });
} }
hasRole(r:Role|string){ hasRole(r:Role|string){
console.log("this should run"); console.log("this should run");
@ -407,20 +410,20 @@ class Guild{
} }
return this.member.hasRole(r); return this.member.hasRole(r);
} }
loadChannel(ID:string|undefined=undefined){ loadChannel(ID?:string|undefined){
if(ID&&this.channelids[ID]){ if(ID&&this.channelids[ID]){
this.channelids[ID].getHTML(); this.channelids[ID].getHTML();
return; return;
} }
if(this.prevchannel){ if(this.prevchannel){
console.log(this.prevchannel) console.log(this.prevchannel);
this.prevchannel.getHTML(); this.prevchannel.getHTML();
return; return;
} }
for(const thing of this.channels){ for(const thing of this.channels){
if(thing.children.length===0){ if(thing.children.length===0){
thing.getHTML(); thing.getHTML();
return return;
} }
} }
} }
@ -459,26 +462,26 @@ class Guild{
["radio","select channel type", ["radio","select channel type",
["voice","text","announcement"], ["voice","text","announcement"],
function(e){ function(e){
console.log(e) console.log(e);
category={"text":0,"voice":2,"announcement":5,"category":4}[e] category={text: 0,voice: 2,announcement: 5,category: 4}[e];
}, },
1 1
], ],
["textbox","Name of channel","",function(this:HTMLInputElement){ ["textbox","Name of channel","",function(this:HTMLInputElement){
console.log(this) console.log(this);
name=this.value name=this.value;
}], }],
["button","","submit",function(){ ["button","","submit",function(){
console.log(name,category) console.log(name,category);
func(name,category); func(name,category);
channelselect.hide(); channelselect.hide();
}.bind(this)] }]
]); ]);
channelselect.show(); channelselect.show();
} }
createcategory(){ createcategory(){
let name=""; let name="";
let category=4; const category=4;
const channelselect=new Dialog( const channelselect=new Dialog(
["vdiv", ["vdiv",
["textbox","Name of category","",function(this:HTMLInputElement){ ["textbox","Name of category","",function(this:HTMLInputElement){
@ -486,7 +489,7 @@ class Guild{
name=this.value; name=this.value;
}], }],
["button","","submit",()=>{ ["button","","submit",()=>{
console.log(name,category) console.log(name,category);
this.createChannel(name,category); this.createChannel(name,category);
channelselect.hide(); channelselect.hide();
}] }]
@ -522,21 +525,21 @@ class Guild{
} }
createChannel(name:string,type:number){ createChannel(name:string,type:number){
fetch(this.info.api+"/guilds/"+this.snowflake+"/channels",{ fetch(this.info.api+"/guilds/"+this.snowflake+"/channels",{
method:"POST", method: "POST",
headers:this.headers, headers: this.headers,
body:JSON.stringify({name: name, type: type}) body: JSON.stringify({name, type})
}) });
} }
async createRole(name:string){ async createRole(name:string){
const fetched=await fetch(this.info.api+"/guilds/"+this.snowflake+"roles",{ const fetched=await fetch(this.info.api+"/guilds/"+this.snowflake+"roles",{
method:"POST", method: "POST",
headers:this.headers, headers: this.headers,
body:JSON.stringify({ body: JSON.stringify({
name:name, name,
color:0, color: 0,
permissions:"0" permissions: "0"
})
}) })
});
const json=await fetched.json(); const json=await fetched.json();
const role=new Role(json,this); const role=new Role(json,this);
this.roleids.set(role.snowflake,role); this.roleids.set(role.snowflake,role);
@ -549,19 +552,19 @@ class Guild{
role.permissions.deny=perms.deny; role.permissions.deny=perms.deny;
await fetch(this.info.api+"/guilds/"+this.snowflake+"/roles/"+this.snowflake,{ await fetch(this.info.api+"/guilds/"+this.snowflake+"/roles/"+this.snowflake,{
method:"PATCH", method: "PATCH",
headers:this.headers, headers: this.headers,
body:JSON.stringify({ body: JSON.stringify({
color:role.color, color: role.color,
hoist:role.hoist, hoist: role.hoist,
icon:role.icon, icon: role.icon,
mentionable:role.mentionable, mentionable: role.mentionable,
name:role.name, name: role.name,
permissions:role.permissions.allow.toString(), permissions: role.permissions.allow.toString(),
unicode_emoji:role.unicode_emoji, unicode_emoji: role.unicode_emoji,
})
}) })
});
} }
} }
Guild.setupcontextmenu(); Guild.setupcontextmenu();
export { Guild }; export{ Guild };

View file

@ -4,12 +4,12 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jank Client</title> <title>Jank Client</title>
<meta content="Jank Client" property="og:title" /> <meta content="Jank Client" property="og:title">
<meta content="A spacebar client that has DMs, replying and more" property="og:description" /> <meta content="A spacebar client that has DMs, replying and more" property="og:description">
<meta content="/logo.webp" property="og:image" /> <meta content="/logo.webp" property="og:image">
<meta content="#4b458c" data-react-helmet="true" name="theme-color" /> <meta content="#4b458c" data-react-helmet="true" name="theme-color">
<link href="/style.css" rel="stylesheet" type="text/css" /> <link href="/style.css" rel="stylesheet">
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/> <link href="/themes.css" rel="stylesheet" id="lightcss">
</head> </head>
<body class="Dark-theme"> <body class="Dark-theme">
@ -44,5 +44,5 @@
</div> </div>
</div> </div>
</body> </body>
<script src="/home.js" type="module" ></script> <script src="/home.js" type="module"></script>
</html> </html>

View file

@ -1,4 +1,4 @@
import {mobile} from "./login.js"; import{mobile}from"./login.js";
console.log(mobile); console.log(mobile);
const serverbox=document.getElementById("instancebox") as HTMLDivElement; const serverbox=document.getElementById("instancebox") as HTMLDivElement;
@ -36,18 +36,18 @@ fetch("/instances.json").then(_=>_.json()).then((json:{name:string,description?:
const p=document.createElement("p"); const p=document.createElement("p");
if(instance.descriptionLong){ if(instance.descriptionLong){
p.innerText=instance.descriptionLong; p.innerText=instance.descriptionLong;
}else{ }else if(instance.description){
p.innerText=instance.description; p.innerText=instance.description;
} }
textbox.append(p); textbox.append(p);
} }
statbox.append(textbox) statbox.append(textbox);
} }
if(instance.uptime){ if(instance.uptime){
const stats=document.createElement("div"); const stats=document.createElement("div");
stats.classList.add("flexltr"); stats.classList.add("flexltr");
const span=document.createElement("span"); const span=document.createElement("span");
span.innerText=`Uptime: All time: ${Math.floor(instance.uptime.alltime*100)}% This week: ${Math.floor(instance.uptime.weektime*100)}% Today: ${Math.floor(instance.uptime.daytime*100)}%` span.innerText=`Uptime: All time: ${Math.floor(instance.uptime.alltime*100)}% This week: ${Math.floor(instance.uptime.weektime*100)}% Today: ${Math.floor(instance.uptime.daytime*100)}%`;
stats.append(span); stats.append(span);
statbox.append(stats); statbox.append(stats);
} }
@ -58,7 +58,7 @@ fetch("/instances.json").then(_=>_.json()).then((json:{name:string,description?:
}else{ }else{
alert("Instance is offline, can't connect"); alert("Instance is offline, can't connect");
} }
} };
serverbox.append(div); serverbox.append(div);
} }
}) });

View file

@ -4,14 +4,14 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Jank Client</title> <title>Jank Client</title>
<meta content="Jank Client" property="og:title" /> <meta content="Jank Client" property="og:title">
<meta content="A spacebar client that has DMs, replying and more" property="og:description" /> <meta content="A spacebar client that has DMs, replying and more" property="og:description">
<meta content="/logo.webp" property="og:image" /> <meta content="/logo.webp" property="og:image">
<meta content="#4b458c" data-react-helmet="true" name="theme-color" /> <meta content="#4b458c" data-react-helmet="true" name="theme-color">
<link href="/style.css" rel="stylesheet" type="text/css" /> <link href="/style.css" rel="stylesheet">
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/> <link href="/themes.css" rel="stylesheet" id="lightcss">
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json">
</head> </head>
<body class="Dark-theme"> <body class="Dark-theme">
@ -76,5 +76,5 @@
</div> </div>
</div> </div>
</div> </div>
</body> </body>
</html> </html>

View file

@ -1,14 +1,16 @@
import { Localuser } from "./localuser.js"; import{ Localuser }from"./localuser.js";
import {Contextmenu} from "./contextmenu.js"; import{Contextmenu}from"./contextmenu.js";
import {mobile, getBulkUsers,setTheme, Specialuser} from "./login.js"; import{mobile, getBulkUsers,setTheme, Specialuser}from"./login.js";
import { MarkDown } from "./markdown.js"; import{ MarkDown }from"./markdown.js";
import { Message } from "./message.js"; import{ Message }from"./message.js";
import { File } from "./file.js"; import{ File }from"./file.js";
(async()=>{ (async ()=>{
async function waitforload(){ async function waitforload(){
let res; let res;
new Promise(r=>{res=r}); new Promise(r=>{
document.addEventListener("DOMContentLoaded", function(){ res=r;
});
document.addEventListener("DOMContentLoaded", ()=>{
res(); res();
}); });
await res; await res;
@ -19,7 +21,7 @@ import { File } from "./file.js";
const users=getBulkUsers(); const users=getBulkUsers();
if(!users.currentuser){ if(!users.currentuser){
window.location.href = '/login.html'; window.location.href = "/login.html";
} }
@ -27,7 +29,7 @@ import { File } from "./file.js";
const table=document.createElement("div"); const table=document.createElement("div");
for(const thing of Object.values(users.users)){ for(const thing of Object.values(users.users)){
const specialuser=thing as Specialuser; const specialuser=thing as Specialuser;
console.log(specialuser.pfpsrc) console.log(specialuser.pfpsrc);
const userinfo=document.createElement("div"); const userinfo=document.createElement("div");
userinfo.classList.add("flexltr","switchtable"); userinfo.classList.add("flexltr","switchtable");
@ -41,8 +43,8 @@ import { File } from "./file.js";
const span=document.createElement("span"); const span=document.createElement("span");
span.textContent=specialuser.serverurls.wellknown.replace("https://","").replace("http://",""); span.textContent=specialuser.serverurls.wellknown.replace("https://","").replace("http://","");
user.append(span); user.append(span);
user.classList.add("userinfo") user.classList.add("userinfo");
span.classList.add("serverURL") span.classList.add("serverURL");
pfp.src=specialuser.pfpsrc; pfp.src=specialuser.pfpsrc;
pfp.classList.add("pfp"); pfp.classList.add("pfp");
@ -54,26 +56,25 @@ import { File } from "./file.js";
loading.classList.remove("doneloading"); loading.classList.remove("doneloading");
loading.classList.add("loading"); loading.classList.add("loading");
thisuser=new Localuser(specialuser); thisuser=new Localuser(specialuser);
users["currentuser"]=specialuser.uid; users.currentuser=specialuser.uid;
localStorage.setItem("userinfos",JSON.stringify(users)); localStorage.setItem("userinfos",JSON.stringify(users));
thisuser.initwebsocket().then(_=>{ thisuser.initwebsocket().then(_=>{
thisuser.loaduser(); thisuser.loaduser();
thisuser.init(); thisuser.init();
loading.classList.add("doneloading"); loading.classList.add("doneloading");
loading.classList.remove("loading"); loading.classList.remove("loading");
console.log("done loading") console.log("done loading");
}); });
userinfo.remove(); userinfo.remove();
}) });
} }
{ {
const td=document.createElement("div"); const td=document.createElement("div");
td.classList.add("switchtable") td.classList.add("switchtable");
td.append("Switch accounts ⇌"); td.append("Switch accounts ⇌");
td.addEventListener("click",_=>{ td.addEventListener("click",_=>{
window.location.href="/login.html"; window.location.href="/login.html";
}) });
table.append(td); table.append(td);
} }
table.classList.add("accountSwitcher"); table.classList.add("accountSwitcher");
@ -89,17 +90,17 @@ import { File } from "./file.js";
userinfo.addEventListener("click",_=>{ userinfo.addEventListener("click",_=>{
_.stopImmediatePropagation(); _.stopImmediatePropagation();
showAccountSwitcher(); showAccountSwitcher();
}) });
const switchaccounts=document.getElementById("switchaccounts") as HTMLDivElement; const switchaccounts=document.getElementById("switchaccounts") as HTMLDivElement;
switchaccounts.addEventListener("click",_=>{ switchaccounts.addEventListener("click",_=>{
_.stopImmediatePropagation(); _.stopImmediatePropagation();
showAccountSwitcher(); showAccountSwitcher();
}) });
console.log("this ran") console.log("this ran");
} }
let thisuser:Localuser; let thisuser:Localuser;
try{ try{
console.log(users.users,users.currentuser) console.log(users.users,users.currentuser);
thisuser=new Localuser(users.users[users.currentuser]); thisuser=new Localuser(users.users[users.currentuser]);
thisuser.initwebsocket().then(_=>{ thisuser.initwebsocket().then(_=>{
thisuser.loaduser(); thisuser.loaduser();
@ -107,7 +108,7 @@ import { File } from "./file.js";
const loading=document.getElementById("loading") as HTMLDivElement; const loading=document.getElementById("loading") as HTMLDivElement;
loading.classList.add("doneloading"); loading.classList.add("doneloading");
loading.classList.remove("loading"); loading.classList.remove("loading");
console.log("done loading") console.log("done loading");
}); });
}catch(e){ }catch(e){
console.error(e); console.error(e);
@ -118,25 +119,29 @@ import { File } from "./file.js";
{ {
const menu=new Contextmenu("create rightclick");//Really should go into the localuser class, but that's a later thing const menu=new Contextmenu("create rightclick");//Really should go into the localuser class, but that's a later thing
menu.addbutton("Create channel",function(){ menu.addbutton("Create channel",()=>{
if(thisuser.lookingguild){ if(thisuser.lookingguild){
thisuser.lookingguild.createchannels(); thisuser.lookingguild.createchannels();
} }
},null,_=>{return thisuser.isAdmin()}) },null,_=>{
return thisuser.isAdmin();
});
menu.addbutton("Create category",function(){ menu.addbutton("Create category",()=>{
if(thisuser.lookingguild){ if(thisuser.lookingguild){
thisuser.lookingguild.createcategory(); thisuser.lookingguild.createcategory();
} }
},null,_=>{return thisuser.isAdmin()}) },null,_=>{
menu.bindContextmenu(document.getElementById("channels") as HTMLDivElement,0,0) return thisuser.isAdmin();
});
menu.bindContextmenu(document.getElementById("channels") as HTMLDivElement,0,0);
} }
const pasteimage=document.getElementById("pasteimage") as HTMLDivElement; const pasteimage=document.getElementById("pasteimage") as HTMLDivElement;
let replyingto:Message|null=null; let replyingto:Message|null=null;
async function enter(event){ async function enter(event){
const channel=thisuser.channelfocus const channel=thisuser.channelfocus;
if(!channel||!thisuser.channelfocus) return; if(!channel||!thisuser.channelfocus)return;
channel.typingstart(); channel.typingstart();
if(event.key === "Enter"&&!event.shiftKey){ if(event.key === "Enter"&&!event.shiftKey){
event.preventDefault(); event.preventDefault();
@ -145,16 +150,16 @@ import { File } from "./file.js";
channel.editing=null; channel.editing=null;
}else{ }else{
replyingto= thisuser.channelfocus.replyingto; replyingto= thisuser.channelfocus.replyingto;
let replying=replyingto; const replying=replyingto;
if(replyingto?.div){ if(replyingto?.div){
replyingto.div.classList.remove("replying"); replyingto.div.classList.remove("replying");
} }
thisuser.channelfocus.replyingto=null; thisuser.channelfocus.replyingto=null;
channel.sendMessage(markdown.rawString,{ channel.sendMessage(markdown.rawString,{
attachments:images, attachments: images,
embeds:[], embeds: [],
replyingto:replying replyingto: replying
}) });
thisuser.channelfocus.makereplybox(); thisuser.channelfocus.makereplybox();
} }
while(images.length!=0){ while(images.length!=0){
@ -162,7 +167,6 @@ import { File } from "./file.js";
pasteimage.removeChild(imageshtml.pop() as HTMLElement); pasteimage.removeChild(imageshtml.pop() as HTMLElement);
} }
typebox.innerHTML=""; typebox.innerHTML="";
return;
} }
} }
@ -174,7 +178,7 @@ import { File } from "./file.js";
typebox.addEventListener("keydown",event=>{ typebox.addEventListener("keydown",event=>{
if(event.key === "Enter"&&!event.shiftKey) event.preventDefault(); if(event.key === "Enter"&&!event.shiftKey) event.preventDefault();
}); });
console.log(typebox) console.log(typebox);
typebox.onclick=console.log; typebox.onclick=console.log;
/* /*
@ -190,14 +194,14 @@ import { File } from "./file.js";
document.addEventListener('paste', async (e) => { document.addEventListener("paste", async e=>{
if(!e.clipboardData) return; if(!e.clipboardData)return;
Array.from(e.clipboardData.files).forEach(async (f) => { Array.from(e.clipboardData.files).forEach(async f=>{
const file=File.initFromBlob(f); const file=File.initFromBlob(f);
e.preventDefault(); e.preventDefault();
const html=file.upHTML(images,f); const html=file.upHTML(images,f);
pasteimage.appendChild(html); pasteimage.appendChild(html);
images.push(f) images.push(f);
imageshtml.push(html); imageshtml.push(html);
}); });
}); });
@ -214,12 +218,12 @@ import { File } from "./file.js";
((document.getElementById("channels") as HTMLDivElement).parentNode as HTMLElement).classList.add("collapse"); ((document.getElementById("channels") as HTMLDivElement).parentNode as HTMLElement).classList.add("collapse");
(document.getElementById("servertd") as HTMLDivElement).classList.add("collapse"); (document.getElementById("servertd") as HTMLDivElement).classList.add("collapse");
(document.getElementById("servers") as HTMLDivElement).classList.add("collapse"); (document.getElementById("servers") as HTMLDivElement).classList.add("collapse");
} };
(document.getElementById("mobileback") as HTMLDivElement).textContent="#"; (document.getElementById("mobileback") as HTMLDivElement).textContent="#";
(document.getElementById("mobileback") as HTMLDivElement).onclick=()=>{ (document.getElementById("mobileback") as HTMLDivElement).onclick=()=>{
((document.getElementById("channels") as HTMLDivElement).parentNode as HTMLElement).classList.remove("collapse"); ((document.getElementById("channels") as HTMLDivElement).parentNode as HTMLElement).classList.remove("collapse");
(document.getElementById("servertd") as HTMLDivElement).classList.remove("collapse"); (document.getElementById("servertd") as HTMLDivElement).classList.remove("collapse");
(document.getElementById("servers") as HTMLDivElement).classList.remove("collapse"); (document.getElementById("servers") as HTMLDivElement).classList.remove("collapse");
};
} }
} })();
})()

View file

@ -21,22 +21,22 @@ class InfiniteScroller{
div.classList.add("messagecontainer"); div.classList.add("messagecontainer");
//div.classList.add("flexttb") //div.classList.add("flexttb")
const scroll=document.createElement("div"); const scroll=document.createElement("div");
scroll.classList.add("flexttb","scroller") scroll.classList.add("flexttb","scroller");
div.appendChild(scroll); div.appendChild(scroll);
this.div=div; this.div=div;
//this.interval=setInterval(this.updatestuff.bind(this,true),100); //this.interval=setInterval(this.updatestuff.bind(this,true),100);
this.scroll=scroll; this.scroll=scroll;
this.div.addEventListener("scroll",_=>{ this.div.addEventListener("scroll",_=>{
if(this.scroll) this.scrollTop=this.scroll.scrollTop; if(this.scroll)this.scrollTop=this.scroll.scrollTop;
this.watchForChange() this.watchForChange();
}); });
this.scroll.addEventListener("scroll",_=>{ this.scroll.addEventListener("scroll",_=>{
if(null===this.timeout){ if(this.timeout===null){
this.timeout=setTimeout(this.updatestuff.bind(this),300); this.timeout=setTimeout(this.updatestuff.bind(this),300);
} }
this.watchForChange() this.watchForChange();
}); });
{ {
let oldheight=0; let oldheight=0;
@ -52,11 +52,11 @@ class InfiniteScroller{
} }
new ResizeObserver(this.watchForChange.bind(this)).observe(scroll); new ResizeObserver(this.watchForChange.bind(this)).observe(scroll);
await this.firstElement(initialId) await this.firstElement(initialId);
this.updatestuff(); this.updatestuff();
await this.watchForChange().then(_=>{ await this.watchForChange().then(_=>{
this.updatestuff(); this.updatestuff();
}) });
return div; return div;
} }
scrollBottom:number; scrollBottom:number;
@ -65,26 +65,24 @@ class InfiniteScroller{
averageheight:number=60; averageheight:number=60;
async updatestuff(){ async updatestuff(){
this.timeout=null; this.timeout=null;
if(!this.scroll) return; if(!this.scroll)return;
this.scrollBottom = this.scroll.scrollHeight - this.scroll.scrollTop - this.scroll.clientHeight; this.scrollBottom = this.scroll.scrollHeight - this.scroll.scrollTop - this.scroll.clientHeight;
this.averageheight=this.scroll.scrollHeight/this.HTMLElements.length; this.averageheight=this.scroll.scrollHeight/this.HTMLElements.length;
if(this.averageheight<10){ if(this.averageheight<10){
this.averageheight=60; this.averageheight=60;
} }
this.scrollTop=this.scroll.scrollTop; this.scrollTop=this.scroll.scrollTop;
if(!this.scrollBottom){ if(!this.scrollBottom && !await this.watchForChange()){
if(!await this.watchForChange()){
this.reachesBottom(); this.reachesBottom();
} }
}
if(!this.scrollTop){ if(!this.scrollTop){
await this.watchForChange() await this.watchForChange();
} }
this.needsupdate=false; this.needsupdate=false;
//this.watchForChange(); //this.watchForChange();
} }
async firstElement(id:string){ async firstElement(id:string){
if(!this.scroll) return; if(!this.scroll)return;
const html=await this.getHTMLFromID(id); const html=await this.getHTMLFromID(id);
this.scroll.appendChild(html); this.scroll.appendChild(html);
this.HTMLElements.push([html,id]); this.HTMLElements.push([html,id]);
@ -98,14 +96,14 @@ class InfiniteScroller{
} }
snapBottom(){ snapBottom(){
const scrollBottom=this.scrollBottom; const scrollBottom=this.scrollBottom;
return ()=>{ return()=>{
if(this.scroll&&scrollBottom<30){ if(this.scroll&&scrollBottom<30){
this.scroll.scrollTop=this.scroll.scrollHeight+20; this.scroll.scrollTop=this.scroll.scrollHeight+20;
} }
} };
} }
private async watchForTop(already=false,fragement=new DocumentFragment()):Promise<boolean>{ private async watchForTop(already=false,fragement=new DocumentFragment()):Promise<boolean>{
if(!this.scroll) return false; if(!this.scroll)return false;
try{ try{
let again=false; let again=false;
if(this.scrollTop<(already?this.fillDist:this.minDist)){ if(this.scrollTop<(already?this.fillDist:this.minDist)){
@ -129,11 +127,9 @@ class InfiniteScroller{
fragement.prepend(html); fragement.prepend(html);
this.HTMLElements.unshift([html,nextid]); this.HTMLElements.unshift([html,nextid]);
this.scrollTop+=this.averageheight; this.scrollTop+=this.averageheight;
}; }
} }
if(this.scrollTop>this.maxDist){ if(this.scrollTop>this.maxDist){
const html=this.HTMLElements.shift(); const html=this.HTMLElements.shift();
if(html){ if(html){
again=true; again=true;
@ -156,12 +152,11 @@ class InfiniteScroller{
} }
} }
async watchForBottom(already=false,fragement=new DocumentFragment()):Promise<boolean>{ async watchForBottom(already=false,fragement=new DocumentFragment()):Promise<boolean>{
if(!this.scroll) return false; if(!this.scroll)return false;
try{ try{
let again=false; let again=false;
const scrollBottom = this.scrollBottom; const scrollBottom = this.scrollBottom;
if(scrollBottom<(already?this.fillDist:this.minDist)){ if(scrollBottom<(already?this.fillDist:this.minDist)){
let nextid:string|undefined; let nextid:string|undefined;
const lastelm=this.HTMLElements.at(-1); const lastelm=this.HTMLElements.at(-1);
if(lastelm){ if(lastelm){
@ -175,11 +170,9 @@ class InfiniteScroller{
fragement.appendChild(html); fragement.appendChild(html);
this.HTMLElements.push([html,nextid]); this.HTMLElements.push([html,nextid]);
this.scrollBottom+=this.averageheight; this.scrollBottom+=this.averageheight;
}; }
} }
if(scrollBottom>this.maxDist){ if(scrollBottom>this.maxDist){
const html=this.HTMLElements.pop(); const html=this.HTMLElements.pop();
if(html){ if(html){
await this.destroyFromID(html[1]); await this.destroyFromID(html[1]);
@ -213,23 +206,24 @@ class InfiniteScroller{
}else{ }else{
this.watchtime=false; this.watchtime=false;
this.currrunning=true; this.currrunning=true;
} }
this.changePromise=new Promise<boolean>(async res=>{ this.changePromise=new Promise<boolean>(async res=>{
try{ try{
try{ try{
if(!this.div){res(false);return false} if(!this.div){
res(false);return false;
}
const out=await Promise.allSettled([this.watchForTop(),this.watchForBottom()]) as {value:boolean}[]; const out=await Promise.allSettled([this.watchForTop(),this.watchForBottom()]) as {value:boolean}[];
const changed=(out[0].value||out[1].value); const changed=(out[0].value||out[1].value);
if(null===this.timeout&&changed){ if(this.timeout===null&&changed){
this.timeout=setTimeout(this.updatestuff.bind(this),300); this.timeout=setTimeout(this.updatestuff.bind(this),300);
} }
if(!this.currrunning){console.error("something really bad happened")} if(!this.currrunning){
console.error("something really bad happened");
res(!!changed); }
return !!changed;
res(Boolean(changed));
return Boolean(changed);
}catch(e){ }catch(e){
console.error(e); console.error(e);
} }
@ -238,22 +232,18 @@ class InfiniteScroller{
}catch(e){ }catch(e){
throw e; throw e;
}finally{ }finally{
setTimeout(_=>{ setTimeout(_=>{
this.changePromise=undefined; this.changePromise=undefined;
this.currrunning=false; this.currrunning=false;
if(this.watchtime){ if(this.watchtime){
this.watchForChange(); this.watchForChange();
} }
},300) },300);
} }
}) });
return await this.changePromise; return await this.changePromise;
} }
async focus(id:string,flash=true){ async focus(id:string,flash=true){
let element:HTMLElement|undefined; let element:HTMLElement|undefined;
for(const thing of this.HTMLElements){ for(const thing of this.HTMLElements){
if(thing[1]===id){ if(thing[1]===id){
@ -262,15 +252,14 @@ class InfiniteScroller{
} }
console.log(id,element,this.HTMLElements.length,":3"); console.log(id,element,this.HTMLElements.length,":3");
if(element){ if(element){
if(flash){ if(flash){
element.scrollIntoView({ element.scrollIntoView({
behavior:"smooth", behavior: "smooth",
block:"center" block: "center"
}); });
await new Promise(resolve => setTimeout(resolve, 1000)); await new Promise(resolve=>setTimeout(resolve, 1000));
element.classList.remove("jumped"); element.classList.remove("jumped");
await new Promise(resolve => setTimeout(resolve, 100)); await new Promise(resolve=>setTimeout(resolve, 100));
element.classList.add("jumped"); element.classList.add("jumped");
}else{ }else{
element.scrollIntoView(); element.scrollIntoView();
@ -283,7 +272,7 @@ class InfiniteScroller{
await this.firstElement(id); await this.firstElement(id);
this.updatestuff(); this.updatestuff();
await this.watchForChange(); await this.watchForChange();
await new Promise(resolve => setTimeout(resolve, 100)); await new Promise(resolve=>setTimeout(resolve, 100));
await this.focus(id,true); await this.focus(id,true);
} }
} }
@ -302,4 +291,4 @@ class InfiniteScroller{
this.div=null; this.div=null;
} }
} }
export {InfiniteScroller}; export{InfiniteScroller};

View file

@ -1,22 +1,22 @@
<body class="Dark-theme"> <body class="Dark-theme">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jank Client</title> <title>Jank Client</title>
<meta content="Invite" property="og:title" /> <meta content="Invite" property="og:title">
<meta content="You shouldn't see this, but this is an invite URL" property="og:description" /> <meta content="You shouldn't see this, but this is an invite URL" property="og:description">
<meta content="/logo.webp" property="og:image" /> <meta content="/logo.webp" property="og:image">
<meta content="#4b458c" data-react-helmet="true" name="theme-color" /> <meta content="#4b458c" data-react-helmet="true" name="theme-color">
<link href="/style.css" rel="stylesheet" type="text/css" /> <link href="/style.css" rel="stylesheet">
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/> <link href="/themes.css" rel="stylesheet" id="lightcss">
</head> </head>
<div> <div>
<div id="invitebody"> <div id="invitebody">
<div id="inviteimg"></div> <div id="inviteimg"></div>
<h1 id="invitename">Server Name</h1> <h1 id="invitename">Server Name</h1>
<p id="invitedescription">Someone invited you to Server Name</p> <p id="invitedescription">Someone invited you to Server Name</p>
<button id="AcceptInvite">Accept Invite</button> <button id="AcceptInvite">Accept Invite</button>
</div> </div>
</div> </div>
<script type="module" src="/invite.js"></script> <script type="module" src="/invite.js"></script>
</body> </body>

View file

@ -1,41 +1,40 @@
import {getBulkUsers, Specialuser, getapiurls} from "./login.js"; import{getBulkUsers, Specialuser, getapiurls}from"./login.js";
(async()=>{ (async ()=>{
const users=getBulkUsers(); const users=getBulkUsers();
const well=new URLSearchParams(window.location.search).get("instance"); const well=new URLSearchParams(window.location.search).get("instance");
const joinable:Specialuser[]=[]; const joinable:Specialuser[]=[];
for(const thing in users.users){ for(const thing in users.users){
const user:Specialuser = users.users[thing] const user:Specialuser = users.users[thing];
if(user.serverurls.wellknown.includes(well)){ if(user.serverurls.wellknown.includes(well)){
joinable.push(user); joinable.push(user);
} }
console.log(users.users[thing]); console.log(users.users[thing]);
} }
let urls:{api:string,cdn:string}; let urls:{api:string,cdn:string};
if(!joinable.length){ if(!joinable.length&&well){
const out=await getapiurls(well); const out=await getapiurls(well);
if(out){ if(out){
urls=out; urls=out;
for(const thing in users.users){ for(const thing in users.users){
const user:Specialuser = users.users[thing] const user:Specialuser = users.users[thing];
if(user.serverurls.api.includes(out.api)){ if(user.serverurls.api.includes(out.api)){
joinable.push(user); joinable.push(user);
} }
console.log(users.users[thing]); console.log(users.users[thing]);
} }
}else{ }else{
throw Error("someone needs to handle the case where the servers don't exist") throw new Error("someone needs to handle the case where the servers don't exist");
} }
}else{ }else{
urls=joinable[0].serverurls; urls=joinable[0].serverurls;
} }
if(!joinable.length){ if(!joinable.length){
document.getElementById("AcceptInvite").textContent="Create an account to accept the invite" document.getElementById("AcceptInvite").textContent="Create an account to accept the invite";
} }
const code=window.location.pathname.split("/")[2]; const code=window.location.pathname.split("/")[2];
let guildinfo; let guildinfo;
fetch(`${urls.api}/invites/${code}`,{ fetch(`${urls.api}/invites/${code}`,{
method:"GET" method: "GET"
}).then(_=>_.json()).then(json=>{ }).then(_=>_.json()).then(json=>{
const guildjson=json.guild; const guildjson=json.guild;
guildinfo=guildjson; guildinfo=guildjson;
@ -48,19 +47,18 @@ import {getBulkUsers, Specialuser, getapiurls} from "./login.js";
img.classList.add("inviteGuild"); img.classList.add("inviteGuild");
document.getElementById("inviteimg").append(img); document.getElementById("inviteimg").append(img);
}else{ }else{
const txt=guildjson.name.replace(/'s /g, " ").replace(/\w+/g, word => word[0]).replace(/\s/g, ""); const txt=guildjson.name.replace(/'s /g, " ").replace(/\w+/g, word=>word[0]).replace(/\s/g, "");
const div=document.createElement("div"); const div=document.createElement("div");
div.textContent=txt; div.textContent=txt;
div.classList.add("inviteGuild"); div.classList.add("inviteGuild");
document.getElementById("inviteimg").append(div); document.getElementById("inviteimg").append(div);
} }
});
})
function showAccounts(){ function showAccounts(){
const table=document.createElement("dialog"); const table=document.createElement("dialog");
for(const thing of Object.values(joinable)){ for(const thing of Object.values(joinable)){
const specialuser=thing as Specialuser; const specialuser=thing as Specialuser;
console.log(specialuser.pfpsrc) console.log(specialuser.pfpsrc);
const userinfo=document.createElement("div"); const userinfo=document.createElement("div");
userinfo.classList.add("flexltr","switchtable"); userinfo.classList.add("flexltr","switchtable");
@ -74,8 +72,8 @@ import {getBulkUsers, Specialuser, getapiurls} from "./login.js";
const span=document.createElement("span"); const span=document.createElement("span");
span.textContent=specialuser.serverurls.wellknown.replace("https://","").replace("http://",""); span.textContent=specialuser.serverurls.wellknown.replace("https://","").replace("http://","");
user.append(span); user.append(span);
user.classList.add("userinfo") user.classList.add("userinfo");
span.classList.add("serverURL") span.classList.add("serverURL");
pfp.src=specialuser.pfpsrc; pfp.src=specialuser.pfpsrc;
pfp.classList.add("pfp"); pfp.classList.add("pfp");
@ -83,29 +81,29 @@ import {getBulkUsers, Specialuser, getapiurls} from "./login.js";
userinfo.addEventListener("click",_=>{ userinfo.addEventListener("click",_=>{
console.log(thing); console.log(thing);
fetch(`${urls.api}/invites/${code}`,{ fetch(`${urls.api}/invites/${code}`,{
method:"POST", method: "POST",
headers:{ headers: {
Authorization:thing.token Authorization: thing.token
} }
}).then(_=>{ }).then(_=>{
users["currentuser"]=specialuser.uid; users.currentuser=specialuser.uid;
localStorage.setItem("userinfos",JSON.stringify(users)); localStorage.setItem("userinfos",JSON.stringify(users));
window.location.href="/channels/"+guildinfo.id; window.location.href="/channels/"+guildinfo.id;
}) });
}) });
} }
{ {
const td=document.createElement("div"); const td=document.createElement("div");
td.classList.add("switchtable") td.classList.add("switchtable");
td.append("Login or create an account ⇌"); td.append("Login or create an account ⇌");
td.addEventListener("click",_=>{ td.addEventListener("click",_=>{
const l=new URLSearchParams("?") const l=new URLSearchParams("?");
l.set("goback",window.location.href); l.set("goback",window.location.href);
l.set("instance",well); l.set("instance",well);
window.location.href="/login?"+l.toString(); window.location.href="/login?"+l.toString();
}) });
if(!joinable.length){ if(!joinable.length){
const l=new URLSearchParams("?") const l=new URLSearchParams("?");
l.set("goback",window.location.href); l.set("goback",window.location.href);
l.set("instance",well); l.set("instance",well);
window.location.href="/login?"+l.toString(); window.location.href="/login?"+l.toString();

View file

@ -396,4 +396,4 @@ type memberChunk={
chunk_count: number, chunk_count: number,
not_found: string[] not_found: string[]
} }
export {readyjson,dirrectjson,channeljson,guildjson,rolesjson,userjson,memberjson,mainuserjson,messagejson,filejson,embedjson,emojijson,presencejson,wsjson,messageCreateJson,memberChunk}; export{readyjson,dirrectjson,channeljson,guildjson,rolesjson,userjson,memberjson,mainuserjson,messagejson,filejson,embedjson,emojijson,presencejson,wsjson,messageCreateJson,memberChunk};

View file

@ -1,18 +1,18 @@
<body class="Dark-theme"> <body class="Dark-theme">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jank Client</title> <title>Jank Client</title>
<meta content="Jank Client" property="og:title" /> <meta content="Jank Client" property="og:title">
<meta content="A spacebar client that has DMs, replying and more" property="og:description" /> <meta content="A spacebar client that has DMs, replying and more" property="og:description">
<meta content="/logo.webp" property="og:image" /> <meta content="/logo.webp" property="og:image">
<meta content="#4b458c" data-react-helmet="true" name="theme-color" /> <meta content="#4b458c" data-react-helmet="true" name="theme-color">
<link href="/style.css" rel="stylesheet" type="text/css" /> <link href="/style.css" rel="stylesheet">
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/> <link href="/themes.css" rel="stylesheet" id="lightcss">
</head> </head>
<div id="logindiv"> <div id="logindiv">
<h1>Login</h1><br> <h1>Login</h1><br>
<form id="form" submit="check(e)"> <form id="form" submit="check(e)">
<label for="instance"><b>Instance:</b></label><br> <label for="instance"><b>Instance:</b></label><br>
<p id="verify"></p> <p id="verify"></p>
<input type="search" list="instances" placeholder="Instance URL" name="instance" id="instancein" value="" id="instancein" required><br><br> <input type="search" list="instances" placeholder="Instance URL" name="instance" id="instancein" value="" id="instancein" required><br><br>
@ -28,9 +28,9 @@
</div> </div>
<button type="submit">Login</button> <button type="submit">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> </div>
<datalist id="instances"></datalist> <datalist id="instances"></datalist>
<script src="/login.js" type="module" ></script> <script src="/login.js" type="module"></script>
</body> </body>

View file

@ -1,4 +1,4 @@
import { Dialog } from "./dialog.js"; import{ Dialog }from"./dialog.js";
const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
@ -12,25 +12,25 @@ function setTheme(){
} }
setTheme(); setTheme();
function getBulkUsers(){ function getBulkUsers(){
const json=getBulkInfo() const json=getBulkInfo();
for(const thing in json.users){ for(const thing in json.users){
json.users[thing]=new Specialuser(json.users[thing]); json.users[thing]=new Specialuser(json.users[thing]);
} }
return json; return json;
} }
function trimswitcher(){ function trimswitcher(){
const json=getBulkInfo() const json=getBulkInfo();
const map=new Map(); const map=new Map();
for(const thing in json.users){ for(const thing in json.users){
const user=json.users[thing]; const user=json.users[thing];
let wellknown=user.serverurls.wellknown; let wellknown=user.serverurls.wellknown;
if(wellknown[wellknown.length-1]!=="/"){ if(wellknown.at(-1)!=="/"){
wellknown+="/"; wellknown+="/";
} }
wellknown+=user.username; wellknown+=user.username;
if(map.has(wellknown)){ if(map.has(wellknown)){
const otheruser=map.get(wellknown); const otheruser=map.get(wellknown);
if(otheruser[1].serverurls.wellknown[otheruser[1].serverurls.wellknown.length-1]==="/"){ if(otheruser[1].serverurls.wellknown.at(-1)==="/"){
delete json.users[otheruser[0]]; delete json.users[otheruser[0]];
map.set(wellknown,[thing,user]); map.set(wellknown,[thing,user]);
}else{ }else{
@ -41,7 +41,7 @@ function trimswitcher(){
} }
} }
for(const thing in json.users){ for(const thing in json.users){
if(thing[thing.length-1]==="/"){ if(thing.at(-1)==="/"){
const user=json.users[thing]; const user=json.users[thing];
delete json.users[thing]; delete json.users[thing];
json.users[thing.slice(0, -1)]=user; json.users[thing.slice(0, -1)]=user;
@ -58,13 +58,13 @@ function setDefaults(){
let userinfos=getBulkInfo(); let userinfos=getBulkInfo();
if(!userinfos){ if(!userinfos){
localStorage.setItem("userinfos",JSON.stringify({ localStorage.setItem("userinfos",JSON.stringify({
currentuser:null, currentuser: null,
users:{}, users: {},
preferences: preferences:
{ {
theme:"Dark", theme: "Dark",
notifications:false, notifications: false,
notisound:"three", notisound: "three",
}, },
})); }));
userinfos=getBulkInfo(); userinfos=getBulkInfo();
@ -75,18 +75,18 @@ function setDefaults(){
if(userinfos.accent_color===undefined){ if(userinfos.accent_color===undefined){
userinfos.accent_color="#242443"; userinfos.accent_color="#242443";
} }
document.documentElement.style.setProperty('--accent-color', userinfos.accent_color); document.documentElement.style.setProperty("--accent-color", userinfos.accent_color);
if(userinfos.preferences===undefined){ if(userinfos.preferences===undefined){
userinfos.preferences={ userinfos.preferences={
theme:"Dark", theme: "Dark",
notifications:false, notifications: false,
notisound:"three", notisound: "three",
} };
} }
if(userinfos.preferences&&(userinfos.preferences.notisound===undefined)){ if(userinfos.preferences&&(userinfos.preferences.notisound===undefined)){
userinfos.preferences.notisound="three"; userinfos.preferences.notisound="three";
} }
localStorage.setItem("userinfos",JSON.stringify(userinfos)) localStorage.setItem("userinfos",JSON.stringify(userinfos));
} }
setDefaults(); setDefaults();
class Specialuser{ class Specialuser{
@ -104,9 +104,9 @@ class Specialuser{
apistring=apistring.replace(/\/(v\d+\/?)?$/, "")+"/v9"; apistring=apistring.replace(/\/(v\d+\/?)?$/, "")+"/v9";
this.serverurls.api=apistring; this.serverurls.api=apistring;
this.serverurls.cdn=new URL(json.serverurls.cdn).toString().replace(/\/$/,""); this.serverurls.cdn=new URL(json.serverurls.cdn).toString().replace(/\/$/,"");
this.serverurls.gateway=new URL(json.serverurls.gateway).toString().replace(/\/$/,"");; this.serverurls.gateway=new URL(json.serverurls.gateway).toString().replace(/\/$/,"");
this.serverurls.wellknown=new URL(json.serverurls.wellknown).toString().replace(/\/$/,"");; this.serverurls.wellknown=new URL(json.serverurls.wellknown).toString().replace(/\/$/,"");
this.serverurls.login=new URL(json.serverurls.login).toString().replace(/\/$/,"");; this.serverurls.login=new URL(json.serverurls.login).toString().replace(/\/$/,"");
this.email=json.email; this.email=json.email;
this.token=json.token; this.token=json.token;
this.loggedin=json.loggedin; this.loggedin=json.loggedin;
@ -116,7 +116,7 @@ class Specialuser{
} }
} }
set pfpsrc(e){ set pfpsrc(e){
console.log("this ran fr") console.log("this ran fr");
this.json.pfpsrc=e; this.json.pfpsrc=e;
this.updateLocal(); this.updateLocal();
} }
@ -162,7 +162,7 @@ async function getapiurls(str:string):Promise<{api:string,cdn:string,gateway:str
if(val){ if(val){
str=val; str=val;
}else{ }else{
const val=stringURLsMap.get(str) const val=stringURLsMap.get(str);
if(val){ if(val){
const responce=await fetch(val.api+val.api.endsWith("/")?"":"/"+"ping"); const responce=await fetch(val.api+val.api.endsWith("/")?"":"/"+"ping");
if(responce.ok){ if(responce.ok){
@ -172,34 +172,32 @@ async function getapiurls(str:string):Promise<{api:string,cdn:string,gateway:str
val.login=val.api; val.login=val.api;
return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string}; return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string};
} }
} }
} }
} }
} }
if(str[str.length-1]!=="/"){ if(str.at(-1)!=="/"){
str+="/" str+="/";
} }
let api:string; let api:string;
try{ try{
const info=await fetch(`${str}/.well-known/spacebar`).then((x) => x.json()); const info=await fetch(`${str}/.well-known/spacebar`).then(x=>x.json());
api=info.api; api=info.api;
}catch{ }catch{
return false return false;
} }
const url = new URL(api); const url = new URL(api);
try{ try{
const info=await fetch(`${api}${url.pathname.includes("api") ? "" : "api"}/policies/instance/domains`).then(x=>x.json());
const info=await fetch(`${api}${url.pathname.includes("api") ? "" : "api"}/policies/instance/domains`).then((x) => x.json()); return{
return {
api: info.apiEndpoint, api: info.apiEndpoint,
gateway: info.gateway, gateway: info.gateway,
cdn: info.cdn, cdn: info.cdn,
wellknown: str, wellknown: str,
login:url.toString() login: url.toString()
}; };
}catch{ }catch{
const val=stringURLsMap.get(str) const val=stringURLsMap.get(str);
if(val){ if(val){
const responce=await fetch(val.api+val.api.endsWith("/")?"":"/"+"ping"); const responce=await fetch(val.api+val.api.endsWith("/")?"":"/"+"ping");
if(responce.ok){ if(responce.ok){
@ -209,12 +207,10 @@ async function getapiurls(str:string):Promise<{api:string,cdn:string,gateway:str
val.login=val.api; val.login=val.api;
return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string}; return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string};
} }
} }
} }
return false; return false;
} }
} }
async function checkInstance(e:string){ async function checkInstance(e:string){
const verify=document.getElementById("verify"); const verify=document.getElementById("verify");
@ -224,39 +220,40 @@ async function checkInstance(e:string){
if(instanceinfo){ if(instanceinfo){
instanceinfo.value=(instancein as HTMLInputElement).value; instanceinfo.value=(instancein as HTMLInputElement).value;
localStorage.setItem("instanceinfo",JSON.stringify(instanceinfo)); localStorage.setItem("instanceinfo",JSON.stringify(instanceinfo));
verify.textContent="Instance is all good" verify.textContent="Instance is all good";
if(checkInstance["alt"]){checkInstance["alt"]();} if(checkInstance.alt){
checkInstance.alt();
}
setTimeout(_=>{ setTimeout(_=>{
console.log(verify.textContent) console.log(verify.textContent);
verify.textContent=""; verify.textContent="";
},3000); },3000);
}else{ }else{
verify.textContent="Invalid Instance, try again" verify.textContent="Invalid Instance, try again";
} }
}catch(e){ }catch{
console.log("catch") console.log("catch");
verify.textContent="Invalid Instance, try again" verify.textContent="Invalid Instance, try again";
} }
} }
if(instancein){ if(instancein){
console.log(instancein) console.log(instancein);
instancein.addEventListener("keydown",e=>{ instancein.addEventListener("keydown",e=>{
const verify=document.getElementById("verify"); const verify=document.getElementById("verify");
verify.textContent="Waiting to check Instance" verify.textContent="Waiting to check Instance";
clearTimeout(timeout); clearTimeout(timeout);
timeout=setTimeout(checkInstance,1000); timeout=setTimeout(checkInstance,1000);
}); });
if(localStorage.getItem("instanceinfo")){ if(localStorage.getItem("instanceinfo")){
const json=JSON.parse(localStorage.getItem("instanceinfo")); const json=JSON.parse(localStorage.getItem("instanceinfo"));
if(json.value){ if(json.value){
(instancein as HTMLInputElement).value=json.value (instancein as HTMLInputElement).value=json.value;
}else{ }else{
(instancein as HTMLInputElement).value=json.wellknown (instancein as HTMLInputElement).value=json.wellknown;
} }
}else{ }else{
checkInstance("https://spacebar.chat/"); checkInstance("https://spacebar.chat/");
} }
} }
async function login(username:string, password:string, captcha:string){ async function login(username:string, password:string, captcha:string){
@ -265,30 +262,29 @@ async function login(username:string, password:string, captcha:string){
} }
const options={ const options={
method: "POST", method: "POST",
body:JSON.stringify({ body: JSON.stringify({
"login": username, login: username,
"password": password, password,
"undelete":false, undelete: false,
"captcha_key":captcha captcha_key: captcha
}), }),
headers: { headers: {
"Content-type": "application/json; charset=UTF-8", "Content-type": "application/json; charset=UTF-8",
}} }};
try{ try{
const info=JSON.parse(localStorage.getItem("instanceinfo")); const info=JSON.parse(localStorage.getItem("instanceinfo"));
const api=info.login+(info.login.startsWith("/")?"/":""); const api=info.login+(info.login.startsWith("/")?"/":"");
return await fetch(api+'/auth/login',options).then(response=>response.json()) return await fetch(api+"/auth/login",options).then(response=>response.json())
.then((response) => { .then(response=>{
console.log(response,response.message) console.log(response,response.message);
if("Invalid Form Body"===response.message){ if(response.message==="Invalid Form Body"){
return response.errors.login._errors[0].message; return response.errors.login._errors[0].message;
console.log("test") console.log("test");
} }
//this.serverurls||!this.email||!this.token //this.serverurls||!this.email||!this.token
console.log(response); console.log(response);
if(response.captcha_sitekey){ if(response.captcha_sitekey){
const capt=document.getElementById("h-captcha"); const capt=document.getElementById("h-captcha");
if(!capt.children.length){ if(!capt.children.length){
const capty=document.createElement("div"); const capty=document.createElement("div");
@ -302,65 +298,65 @@ async function login(username:string, password:string, captcha:string){
}else{ }else{
eval("hcaptcha.reset()"); eval("hcaptcha.reset()");
} }
return;
}else{ }else{
console.log(response); console.log(response);
if(response.ticket){ if(response.ticket){
let onetimecode=""; let onetimecode="";
new Dialog(["vdiv",["title","2FA code:"],["textbox","","",function(this:HTMLInputElement){onetimecode=this.value}],["button","","Submit",function(){ new Dialog(["vdiv",["title","2FA code:"],["textbox","","",function(this:HTMLInputElement){
onetimecode=this.value;
}],["button","","Submit",function(){
fetch(api+"/auth/mfa/totp",{ fetch(api+"/auth/mfa/totp",{
method:"POST", method: "POST",
headers:{ headers: {
"Content-Type": "application/json" "Content-Type": "application/json"
}, },
body:JSON.stringify({ body: JSON.stringify({
code:onetimecode, code: onetimecode,
ticket:response.ticket, ticket: response.ticket,
}) })
}).then(r=>r.json()).then(response=>{ }).then(r=>r.json()).then(response=>{
if(response.message){ if(response.message){
alert(response.message) alert(response.message);
}else{ }else{
console.warn(response); console.warn(response);
if(!response.token) return; if(!response.token)return;
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:username,token:response.token}).username=username; adduser({serverurls: JSON.parse(localStorage.getItem("instanceinfo")),email: username,token: response.token}).username=username;
const redir=new URLSearchParams(window.location.search).get("goback"); const redir=new URLSearchParams(window.location.search).get("goback");
if(redir){ if(redir){
window.location.href = redir; window.location.href = redir;
}else{ }else{
window.location.href = '/channels/@me'; window.location.href = "/channels/@me";
} }
} }
}) });
}]]).show(); }]]).show();
}else{ }else{
console.warn(response); console.warn(response);
if(!response.token) return; if(!response.token)return;
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:username,token:response.token}).username=username; adduser({serverurls: JSON.parse(localStorage.getItem("instanceinfo")),email: username,token: response.token}).username=username;
const redir=new URLSearchParams(window.location.search).get("goback"); const redir=new URLSearchParams(window.location.search).get("goback");
if(redir){ if(redir){
window.location.href = redir; window.location.href = redir;
}else{ }else{
window.location.href = '/channels/@me'; window.location.href = "/channels/@me";
} }
return ""; return"";
} }
} }
}) });
}catch(error){ }catch(error){
console.error('Error:', error); console.error("Error:", error);
}; }
} }
async function check(e){ async function check(e){
e.preventDefault(); e.preventDefault();
let h=await login(e.srcElement[1].value,e.srcElement[2].value,e.srcElement[3].value); const h=await login(e.srcElement[1].value,e.srcElement[2].value,e.srcElement[3].value);
document.getElementById("wrong").textContent=h; document.getElementById("wrong").textContent=h;
console.log(h); console.log(h);
} }
if(document.getElementById("form")){ if(document.getElementById("form")){
document.getElementById("form").addEventListener("submit", check); document.getElementById("form").addEventListener("submit", check);
} }
//this currently does not work, and need to be implemented better at some time. //this currently does not work, and need to be implemented better at some time.
/* /*
@ -398,9 +394,9 @@ if(switchurl){
checkInstance(""); checkInstance("");
} }
} }
export {checkInstance}; export{checkInstance};
trimswitcher(); trimswitcher();
export {mobile, getBulkUsers,getBulkInfo,setTheme,Specialuser,getapiurls,adduser} export{mobile, getBulkUsers,getBulkInfo,setTheme,Specialuser,getapiurls,adduser};
const datalist=document.getElementById("instances"); const datalist=document.getElementById("instances");
console.warn(datalist); console.warn(datalist);
@ -435,5 +431,5 @@ if(datalist){
datalist.append(option); datalist.append(option);
} }
checkInstance(""); checkInstance("");
}) });
} }

View file

@ -1,6 +1,6 @@
import { Channel } from "./channel.js"; import{ Channel }from"./channel.js";
import { Emoji } from "./emoji.js"; import{ Emoji }from"./emoji.js";
import { Localuser } from "./localuser.js"; import{ Localuser }from"./localuser.js";
class MarkDown{ class MarkDown{
@ -30,7 +30,7 @@ class MarkDown{
return this.makeHTML().textContent; return this.makeHTML().textContent;
} }
makeHTML({keep=this.keep,stdsize=this.stdsize}={}){ makeHTML({keep=this.keep,stdsize=this.stdsize}={}){
return this.markdown(this.txt,{keep:keep,stdsize:stdsize}); return this.markdown(this.txt,{keep,stdsize});
} }
markdown(text : string|string[],{keep=false,stdsize=false} = {}){ markdown(text : string|string[],{keep=false,stdsize=false} = {}){
let txt : string[]; let txt : string[];
@ -49,7 +49,6 @@ class MarkDown{
span.append(current); span.append(current);
current=document.createElement("span"); current=document.createElement("span");
} }
} }
for(let i=0;i<txt.length;i++){ for(let i=0;i<txt.length;i++){
if(txt[i]==="\n"||i===0){ if(txt[i]==="\n"||i===0){
@ -103,7 +102,7 @@ class MarkDown{
if(keep){ if(keep){
element.append(keepys); element.append(keepys);
} }
element.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize})); element.appendChild(this.markdown(build,{keep,stdsize}));
span.append(element); span.append(element);
}finally{ }finally{
i-=1; i-=1;
@ -116,7 +115,6 @@ class MarkDown{
} }
} }
if(txt[i]==="\n"){ if(txt[i]==="\n"){
if(!stdsize){ if(!stdsize){
appendcurrent(); appendcurrent();
span.append(document.createElement("br")); span.append(document.createElement("br"));
@ -175,11 +173,11 @@ class MarkDown{
span.appendChild(samp); span.appendChild(samp);
}else{ }else{
const pre=document.createElement("pre"); const pre=document.createElement("pre");
if(build[build.length-1]==="\n"){ if(build.at(-1)==="\n"){
build=build.substring(0,build.length-1); build=build.substring(0,build.length-1);
} }
if(txt[i]==="\n"){ if(txt[i]==="\n"){
i++ i++;
} }
pre.textContent=build; pre.textContent=build;
span.appendChild(pre); span.appendChild(pre);
@ -201,7 +199,6 @@ class MarkDown{
let find=0; let find=0;
let j=i+count; let j=i+count;
for(;txt[j]!==undefined&&find!==count;j++){ for(;txt[j]!==undefined&&find!==count;j++){
if(txt[j]==="*"){ if(txt[j]==="*"){
find++; find++;
}else{ }else{
@ -219,26 +216,38 @@ class MarkDown{
const stars="*".repeat(count); const stars="*".repeat(count);
if(count===1){ if(count===1){
const i=document.createElement("i"); const i=document.createElement("i");
if(keep){i.append(stars)} if(keep){
i.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize})); i.append(stars);
if(keep){i.append(stars)} }
i.appendChild(this.markdown(build,{keep,stdsize}));
if(keep){
i.append(stars);
}
span.appendChild(i); span.appendChild(i);
}else if(count===2){ }else if(count===2){
const b=document.createElement("b"); const b=document.createElement("b");
if(keep){b.append(stars)} if(keep){
b.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize})); b.append(stars);
if(keep){b.append(stars)} }
b.appendChild(this.markdown(build,{keep,stdsize}));
if(keep){
b.append(stars);
}
span.appendChild(b); span.appendChild(b);
}else{ }else{
const b=document.createElement("b"); const b=document.createElement("b");
const i=document.createElement("i"); const i=document.createElement("i");
if(keep){b.append(stars)} if(keep){
b.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize})); b.append(stars);
if(keep){b.append(stars)} }
b.appendChild(this.markdown(build,{keep,stdsize}));
if(keep){
b.append(stars);
}
i.appendChild(b); i.appendChild(b);
span.appendChild(i); span.appendChild(i);
} }
i-- i--;
continue; continue;
} }
} }
@ -255,7 +264,6 @@ class MarkDown{
let find=0; let find=0;
let j=i+count; let j=i+count;
for(;txt[j]!==undefined&&find!==count;j++){ for(;txt[j]!==undefined&&find!==count;j++){
if(txt[j]==="_"){ if(txt[j]==="_"){
find++; find++;
}else{ }else{
@ -272,23 +280,35 @@ class MarkDown{
const underscores="_".repeat(count); const underscores="_".repeat(count);
if(count===1){ if(count===1){
const i=document.createElement("i"); const i=document.createElement("i");
if(keep){i.append(underscores)} if(keep){
i.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize})); i.append(underscores);
if(keep){i.append(underscores)} }
i.appendChild(this.markdown(build,{keep,stdsize}));
if(keep){
i.append(underscores);
}
span.appendChild(i); span.appendChild(i);
}else if(count===2){ }else if(count===2){
const u=document.createElement("u"); const u=document.createElement("u");
if(keep){u.append(underscores)} if(keep){
u.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize})); u.append(underscores);
if(keep){u.append(underscores)} }
u.appendChild(this.markdown(build,{keep,stdsize}));
if(keep){
u.append(underscores);
}
span.appendChild(u); span.appendChild(u);
}else{ }else{
const u=document.createElement("u"); const u=document.createElement("u");
const i=document.createElement("i"); const i=document.createElement("i");
if(keep){i.append(underscores)} if(keep){
i.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize})); i.append(underscores);
if(keep){i.append(underscores)} }
u.appendChild(i) i.appendChild(this.markdown(build,{keep,stdsize}));
if(keep){
i.append(underscores);
}
u.appendChild(i);
span.appendChild(u); span.appendChild(u);
} }
i--; i--;
@ -297,7 +317,7 @@ class MarkDown{
} }
if(txt[i]==="~"&&txt[i+1]==="~"){ if(txt[i]==="~"&&txt[i+1]==="~"){
let count=2; const count=2;
let build:string[]=[]; let build:string[]=[];
let find=0; let find=0;
let j=i+2; let j=i+2;
@ -318,16 +338,20 @@ class MarkDown{
const tildes="~~"; const tildes="~~";
if(count===2){ if(count===2){
const s=document.createElement("s"); const s=document.createElement("s");
if(keep){s.append(tildes)} if(keep){
s.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize})); s.append(tildes);
if(keep){s.append(tildes)} }
s.appendChild(this.markdown(build,{keep,stdsize}));
if(keep){
s.append(tildes);
}
span.appendChild(s); span.appendChild(s);
} }
continue; continue;
} }
} }
if(txt[i]==="|"&&txt[i+1]==="|"){ if(txt[i]==="|"&&txt[i+1]==="|"){
let count=2; const count=2;
let build:string[]=[]; let build:string[]=[];
let find=0; let find=0;
let j=i+2; let j=i+2;
@ -348,47 +372,51 @@ class MarkDown{
const pipes="||"; const pipes="||";
if(count===2){ if(count===2){
const j=document.createElement("j"); const j=document.createElement("j");
if(keep){j.append(pipes)} if(keep){
j.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize})); j.append(pipes);
}
j.appendChild(this.markdown(build,{keep,stdsize}));
j.classList.add("spoiler"); j.classList.add("spoiler");
j.onclick=MarkDown.unspoil; j.onclick=MarkDown.unspoil;
if(keep){j.append(pipes)} if(keep){
j.append(pipes);
}
span.appendChild(j); span.appendChild(j);
} }
continue; continue;
} }
} }
if (txt[i]==="<" && txt[i + 1]==="t" && txt[i + 2]===":") { if(txt[i]==="<" && txt[i + 1]==="t" && txt[i + 2]===":"){
let found=false; let found=false;
const build=["<","t",":"]; const build=["<","t",":"];
let j = i+3; let j = i+3;
for (; txt[j] !== void 0; j++) { for(; txt[j] !== void 0; j++){
build.push(txt[j]); build.push(txt[j]);
if (txt[j]===">") { if(txt[j]===">"){
found=true; found=true;
break; break;
} }
} }
if (found) { if(found){
appendcurrent(); appendcurrent();
i=j; i=j;
const parts=build.join("").match(/^<t:([0-9]{1,16})(:([tTdDfFR]))?>$/) as RegExpMatchArray; const parts=build.join("").match(/^<t:([0-9]{1,16})(:([tTdDfFR]))?>$/) as RegExpMatchArray;
const dateInput=new Date(Number.parseInt(parts[1]) * 1000); const dateInput=new Date(Number.parseInt(parts[1]) * 1000);
let time=""; let time="";
if (Number.isNaN(dateInput.getTime())) time=build.join(""); if(Number.isNaN(dateInput.getTime())) time=build.join("");
else { else{
if (parts[3]==="d") time=dateInput.toLocaleString(void 0, {day: "2-digit", month: "2-digit", year: "numeric"}); if(parts[3]==="d") time=dateInput.toLocaleString(void 0, {day: "2-digit", month: "2-digit", year: "numeric"});
else if (parts[3]==="D") time=dateInput.toLocaleString(void 0, {day: "numeric", month: "long", year: "numeric"}); else if(parts[3]==="D") time=dateInput.toLocaleString(void 0, {day: "numeric", month: "long", year: "numeric"});
else if (!parts[3] || parts[3]==="f") time=dateInput.toLocaleString(void 0, {day: "numeric", month: "long", year: "numeric"}) + " " + else if(!parts[3] || parts[3]==="f") time=dateInput.toLocaleString(void 0, {day: "numeric", month: "long", year: "numeric"}) + " " +
dateInput.toLocaleString(void 0, {hour: "2-digit", minute: "2-digit"}); dateInput.toLocaleString(void 0, {hour: "2-digit", minute: "2-digit"});
else if (parts[3]==="F") time=dateInput.toLocaleString(void 0, {day: "numeric", month: "long", year: "numeric", weekday: "long"}) + " " + else if(parts[3]==="F") time=dateInput.toLocaleString(void 0, {day: "numeric", month: "long", year: "numeric", weekday: "long"}) + " " +
dateInput.toLocaleString(void 0, {hour: "2-digit", minute: "2-digit"}); dateInput.toLocaleString(void 0, {hour: "2-digit", minute: "2-digit"});
else if (parts[3]==="t") time=dateInput.toLocaleString(void 0, {hour: "2-digit", minute: "2-digit"}); else if(parts[3]==="t") time=dateInput.toLocaleString(void 0, {hour: "2-digit", minute: "2-digit"});
else if (parts[3]==="T") time=dateInput.toLocaleString(void 0, {hour: "2-digit", minute: "2-digit", second: "2-digit"}); else if(parts[3]==="T") time=dateInput.toLocaleString(void 0, {hour: "2-digit", minute: "2-digit", second: "2-digit"});
else if (parts[3]==="R") time=Math.round((Date.now() - (Number.parseInt(parts[1]) * 1000))/1000/60) + " minutes ago"; else if(parts[3]==="R") time=Math.round((Date.now() - (Number.parseInt(parts[1]) * 1000))/1000/60) + " minutes ago";
} }
const timeElem=document.createElement("span"); const timeElem=document.createElement("span");
@ -399,28 +427,28 @@ class MarkDown{
} }
} }
if (txt[i] === "<" && (txt[i + 1] === ":" || (txt[i + 1] === "a" && txt[i + 2] === ":"))) { if(txt[i] === "<" && (txt[i + 1] === ":" || (txt[i + 1] === "a" && txt[i + 2] === ":"))){
let found=false; let found=false;
const build = txt[i + 1] === "a" ? ["<","a",":"] : ["<",":"]; const build = txt[i + 1] === "a" ? ["<","a",":"] : ["<",":"];
let j = i+build.length; let j = i+build.length;
for (; txt[j] !== void 0; j++) { for(; txt[j] !== void 0; j++){
build.push(txt[j]); build.push(txt[j]);
if (txt[j]===">") { if(txt[j]===">"){
found=true; found=true;
break; break;
} }
} }
if (found) { if(found){
const buildjoin=build.join(""); const buildjoin=build.join("");
const parts=buildjoin.match(/^<(a)?:\w+:(\d{10,30})>$/); const parts=buildjoin.match(/^<(a)?:\w+:(\d{10,30})>$/);
if (parts && parts[2]) { if(parts && parts[2]){
appendcurrent(); appendcurrent();
i=j; i=j;
const isEmojiOnly = txt.join("").trim()===buildjoin.trim(); const isEmojiOnly = txt.join("").trim()===buildjoin.trim();
const owner=(this.owner instanceof Channel)?this.owner.guild:this.owner const owner=(this.owner instanceof Channel)?this.owner.guild:this.owner;
const emoji=new Emoji({name:buildjoin,id:parts[2],animated:!!parts[1]},owner); const emoji=new Emoji({name: buildjoin,id: parts[2],animated: Boolean(parts[1])},owner);
span.appendChild(emoji.getHTML(isEmojiOnly)); span.appendChild(emoji.getHTML(isEmojiOnly));
continue; continue;
@ -428,33 +456,33 @@ class MarkDown{
} }
} }
if (txt[i] == "[" && !keep) { if(txt[i] == "[" && !keep){
let partsFound=0; let partsFound=0;
let j=i+1; let j=i+1;
const build=["["]; const build=["["];
for (; txt[j] !== void 0; j++) { for(; txt[j] !== void 0; j++){
build.push(txt[j]); build.push(txt[j]);
if (partsFound === 0 && txt[j] === "]") { if(partsFound === 0 && txt[j] === "]"){
if (txt[j + 1] === "(" && if(txt[j + 1] === "(" &&
txt[j + 2] === "h" && txt[j + 3] === "t" && txt[j + 4] === "t" && txt[j + 5] === "p" && (txt[j + 6] === "s" || txt[j + 6] === ":") txt[j + 2] === "h" && txt[j + 3] === "t" && txt[j + 4] === "t" && txt[j + 5] === "p" && (txt[j + 6] === "s" || txt[j + 6] === ":")
) { ){
partsFound++; partsFound++;
} else { }else{
break; break;
}; }
} else if (partsFound === 1 && txt[j] === ")") { }else if(partsFound === 1 && txt[j] === ")"){
partsFound++; partsFound++;
break; break;
} }
} }
if (partsFound === 2) { if(partsFound === 2){
appendcurrent(); appendcurrent();
i=j; i=j;
const parts=build.join("").match(/^\[(.+)\]\((https?:.+?)( ('|").+('|"))?\)$/); const parts=build.join("").match(/^\[(.+)\]\((https?:.+?)( ('|").+('|"))?\)$/);
if (parts) { if(parts){
const linkElem=document.createElement("a"); const linkElem=document.createElement("a");
linkElem.href=parts[2]; linkElem.href=parts[2];
linkElem.textContent=parts[1]; linkElem.textContent=parts[1];
@ -491,37 +519,35 @@ class MarkDown{
} }
}; };
box.onpaste=_=>{ box.onpaste=_=>{
if(!_.clipboardData) return; if(!_.clipboardData)return;
console.log(_.clipboardData.types) console.log(_.clipboardData.types);
const data=_.clipboardData.getData("text"); const data=_.clipboardData.getData("text");
document.execCommand('insertHTML', false, data); document.execCommand("insertHTML", false, data);
_.preventDefault(); _.preventDefault();
if(!box.onkeyup) return; if(!box.onkeyup)return;
box.onkeyup(new KeyboardEvent("_")) box.onkeyup(new KeyboardEvent("_"));
} };
} }
boxupdate(box:HTMLElement){ boxupdate(box:HTMLElement){
const restore = saveCaretPosition(box); const restore = saveCaretPosition(box);
box.innerHTML=""; box.innerHTML="";
box.append(this.makeHTML({keep:true})) box.append(this.makeHTML({keep: true}));
if(restore){ if(restore){
restore(); restore();
} }
} }
static gatherBoxText(element:HTMLElement){ static gatherBoxText(element:HTMLElement){
if(element.tagName.toLowerCase()==="img"){ if(element.tagName.toLowerCase()==="img"){
return (element as HTMLImageElement).alt; return(element as HTMLImageElement).alt;
} }
if(element.tagName.toLowerCase()==="br"){ if(element.tagName.toLowerCase()==="br"){
return "\n"; return"\n";
} }
let build=""; let build="";
for(const thing of element.childNodes){ for(const thing of element.childNodes){
if(thing instanceof Text){ if(thing instanceof Text){
const text=thing.textContent; const text=thing.textContent;
build+=text; build+=text;
continue; continue;
@ -537,37 +563,36 @@ class MarkDown{
//solution from https://stackoverflow.com/questions/4576694/saving-and-restoring-caret-position-for-contenteditable-div //solution from https://stackoverflow.com/questions/4576694/saving-and-restoring-caret-position-for-contenteditable-div
function saveCaretPosition(context){ function saveCaretPosition(context){
var selection = window.getSelection(); const selection = window.getSelection();
if(!selection) return; if(!selection)return;
var range = selection.getRangeAt(0); const range = selection.getRangeAt(0);
range.setStart( context, 0 ); range.setStart(context, 0);
var len = range.toString().length; const len = range.toString().length;
return function restore(){ return function restore(){
if(!selection) return; if(!selection)return;
var pos = getTextNodeAtPosition(context, len); const pos = getTextNodeAtPosition(context, len);
selection.removeAllRanges(); selection.removeAllRanges();
var range = new Range(); const range = new Range();
range.setStart(pos.node ,pos.position); range.setStart(pos.node ,pos.position);
selection.addRange(range); selection.addRange(range);
};
}
} }
function getTextNodeAtPosition(root, index){ function getTextNodeAtPosition(root, index){
const NODE_TYPE = NodeFilter.SHOW_TEXT; const NODE_TYPE = NodeFilter.SHOW_TEXT;
var treeWalker = document.createTreeWalker(root, NODE_TYPE, function next(elem) { const treeWalker = document.createTreeWalker(root, NODE_TYPE, elem=>{
if(!elem.textContent) return 0; if(!elem.textContent)return 0;
if(index > elem.textContent.length){ if(index > elem.textContent.length){
index -= elem.textContent.length; index -= elem.textContent.length;
return NodeFilter.FILTER_REJECT return NodeFilter.FILTER_REJECT;
} }
return NodeFilter.FILTER_ACCEPT; return NodeFilter.FILTER_ACCEPT;
}); });
var c = treeWalker.nextNode(); const c = treeWalker.nextNode();
return { return{
node: c? c: root, node: c? c: root,
position: index position: index
}; };
} }
export {MarkDown}; export{MarkDown};

View file

@ -1,9 +1,9 @@
import {User} from "./user.js"; import{User}from"./user.js";
import {Role} from "./role.js"; import{Role}from"./role.js";
import {Guild} from "./guild.js"; import{Guild}from"./guild.js";
import { SnowFlake } from "./snowflake.js"; import{ SnowFlake }from"./snowflake.js";
import { memberjson, presencejson, userjson } from "./jsontypes.js"; import{ memberjson, presencejson, userjson }from"./jsontypes.js";
import { Dialog } from "./dialog.js"; import{ Dialog }from"./dialog.js";
class Member{ class Member{
static already={}; static already={};
@ -23,11 +23,14 @@ class Member{
} }
for(const thing of Object.keys(memberjson)){ for(const thing of Object.keys(memberjson)){
if(thing==="guild"){continue} if(thing==="guild"){
if(thing==="owner"){continue} continue;
}
if(thing==="owner"){
continue;
}
if(thing==="roles"){ if(thing==="roles"){
for(const strrole of memberjson["roles"]){ for(const strrole of memberjson.roles){
const role=SnowFlake.getSnowFlakeFromID(strrole,Role).getObject(); const role=SnowFlake.getSnowFlakeFromID(strrole,Role).getObject();
this.roles.push(role); this.roles.push(role);
} }
@ -37,10 +40,7 @@ class Member{
} }
if(this.localuser.userMap.has(this?.id)){ if(this.localuser.userMap.has(this?.id)){
this.user=this.localuser.userMap.get(this?.id) as User; this.user=this.localuser.userMap.get(this?.id) as User;
return;
} }
} }
get guild(){ get guild(){
return this.owner; return this.owner;
@ -54,18 +54,18 @@ class Member{
static async new(memberjson:memberjson,owner:Guild):Promise<Member|undefined>{ static async new(memberjson:memberjson,owner:Guild):Promise<Member|undefined>{
let user:User; let user:User;
if(owner.localuser.userMap.has(memberjson.id)){ if(owner.localuser.userMap.has(memberjson.id)){
user=owner.localuser.userMap.get(memberjson.id); user=owner.localuser.userMap.get(memberjson.id) as User;
}else if(memberjson.user){ }else if(memberjson.user){
user=new User(memberjson.user,owner.localuser); user=new User(memberjson.user,owner.localuser);
}else{ }else{
throw new Error("missing user object of this member"); throw new Error("missing user object of this member");
} }
if(user.members.has(owner)){ if(user.members.has(owner)){
let memb=user.members.get(owner) let memb=user.members.get(owner);
if(memb===undefined){ if(memb===undefined){
memb=new Member(memberjson,owner); memb=new Member(memberjson,owner);
user.members.set(owner,memb); user.members.set(owner,memb);
return memb return memb;
}else if(memb instanceof Promise){ }else if(memb instanceof Promise){
return await memb;//I should do something else, though for now this is "good enough" return await memb;//I should do something else, though for now this is "good enough"
}else{ }else{
@ -81,11 +81,10 @@ class Member{
const maybe=user.members.get(guild); const maybe=user.members.get(guild);
if(!user.members.has(guild)){ if(!user.members.has(guild)){
const membpromise=guild.localuser.resolvemember(user.id,guild.id); const membpromise=guild.localuser.resolvemember(user.id,guild.id);
const promise=new Promise<Member|undefined>( async res=>{ const promise=new Promise<Member|undefined>(async res=>{
const membjson=await membpromise; const membjson=await membpromise;
if(membjson===undefined){ if(membjson===undefined){
res(undefined); res(undefined);
return undefined;
}else{ }else{
const member=new Member(membjson,guild); const member=new Member(membjson,guild);
const map=guild.localuser.presences; const map=guild.localuser.presences;
@ -94,13 +93,13 @@ class Member{
res(member); res(member);
return member; return member;
} }
}) });
user.members.set(guild,promise); user.members.set(guild,promise);
} }
if(maybe instanceof Promise){ if(maybe instanceof Promise){
return await maybe; return await maybe;
}else{ }else{
return maybe return maybe;
} }
} }
public getPresence(presence:presencejson|undefined){ public getPresence(presence:presencejson|undefined){
@ -110,7 +109,7 @@ class Member{
* @todo * @todo
*/ */
highInfo(){ highInfo(){
fetch(this.info.api+"/users/"+this.id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+this.guild.id,{headers:this.guild.headers}) fetch(this.info.api+"/users/"+this.id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+this.guild.id,{headers: this.guild.headers});
} }
hasRole(ID:string){ hasRole(ID:string){
console.log(this.roles,ID); console.log(this.roles,ID);
@ -128,7 +127,7 @@ class Member{
return color; return color;
} }
} }
return ""; return"";
} }
isAdmin(){ isAdmin(){
for(const role of this.roles){ for(const role of this.roles){
@ -140,7 +139,9 @@ class Member{
} }
bind(html:HTMLElement){ bind(html:HTMLElement){
if(html.tagName==="SPAN"){ if(html.tagName==="SPAN"){
if(!this) {return}; if(!this){
return;
}
/* /*
if(this.error){ if(this.error){
@ -158,7 +159,7 @@ class Member{
return this.nick||this.user.username; return this.nick||this.user.username;
} }
kick(){ kick(){
let reason="" let reason="";
const menu=new Dialog(["vdiv", const menu=new Dialog(["vdiv",
["title","Kick "+this.name+" from "+this.guild.properties.name], ["title","Kick "+this.name+" from "+this.guild.properties.name],
["textbox","Reason:","",function(e:Event){ ["textbox","Reason:","",function(e:Event){
@ -173,15 +174,15 @@ class Member{
} }
kickAPI(reason:string){ kickAPI(reason:string){
const headers=structuredClone(this.guild.headers); const headers=structuredClone(this.guild.headers);
headers["x-audit-log-reason"]=reason headers["x-audit-log-reason"]=reason;
fetch(`${this.info.api}/guilds/${this.guild.id}/members/${this.id}`,{ fetch(`${this.info.api}/guilds/${this.guild.id}/members/${this.id}`,{
method:"DELETE", method: "DELETE",
headers, headers,
}) });
} }
ban(){ ban(){
let reason="" let reason="";
const menu=new Dialog(["vdiv", const menu=new Dialog(["vdiv",
["title","Ban "+this.name+" from "+this.guild.properties.name], ["title","Ban "+this.name+" from "+this.guild.properties.name],
["textbox","Reason:","",function(e:Event){ ["textbox","Reason:","",function(e:Event){
@ -196,12 +197,12 @@ class Member{
} }
banAPI(reason:string){ banAPI(reason:string){
const headers=structuredClone(this.guild.headers); const headers=structuredClone(this.guild.headers);
headers["x-audit-log-reason"]=reason headers["x-audit-log-reason"]=reason;
fetch(`${this.info.api}/guilds/${this.guild.id}/bans/${this.id}`,{ fetch(`${this.info.api}/guilds/${this.guild.id}/bans/${this.id}`,{
method:"PUT", method: "PUT",
headers headers
}) });
} }
hasPermission(name:string):boolean{ hasPermission(name:string):boolean{
if(this.isAdmin()){ if(this.isAdmin()){
@ -215,4 +216,4 @@ class Member{
return false; return false;
} }
} }
export {Member}; export{Member};

View file

@ -1,15 +1,15 @@
import {Contextmenu} from "./contextmenu.js"; import{Contextmenu}from"./contextmenu.js";
import {User} from "./user.js"; import{User}from"./user.js";
import {Member} from "./member.js"; import{Member}from"./member.js";
import {MarkDown} from "./markdown.js"; import{MarkDown}from"./markdown.js";
import {Embed} from "./embed.js"; import{Embed}from"./embed.js";
import { Channel } from "./channel.js"; import{ Channel }from"./channel.js";
import {Localuser} from "./localuser.js"; import{Localuser}from"./localuser.js";
import { Role } from "./role.js"; import{ Role }from"./role.js";
import {File} from "./file.js"; import{File}from"./file.js";
import { SnowFlake } from "./snowflake.js"; import{ SnowFlake }from"./snowflake.js";
import { memberjson, messagejson } from "./jsontypes.js"; import{ memberjson, messagejson }from"./jsontypes.js";
import {Emoji} from "./emoji.js"; import{Emoji}from"./emoji.js";
class Message{ class Message{
static contextmenu=new Contextmenu<Message,undefined>("message menu"); static contextmenu=new Contextmenu<Message,undefined>("message menu");
@ -47,7 +47,9 @@ class Message{
return this.snowflake.id; return this.snowflake.id;
} }
static setup(){ static setup(){
this.del=new Promise(_=>{this.resolve=_}); this.del=new Promise(_=>{
this.resolve=_;
});
Message.setupcmenu(); Message.setupcmenu();
} }
static setupcmenu(){ static setupcmenu(){
@ -68,17 +70,16 @@ class Message{
Message.contextmenu.addbutton("Edit",function(this:Message){ Message.contextmenu.addbutton("Edit",function(this:Message){
this.channel.editing=this; this.channel.editing=this;
const markdown=(document.getElementById("typebox") as HTMLDivElement)["markdown"] as MarkDown; const markdown=(document.getElementById("typebox") as HTMLDivElement)["markdown"] as MarkDown;
markdown.txt=this.content.rawString.split(''); markdown.txt=this.content.rawString.split("");
markdown.boxupdate(document.getElementById("typebox") as HTMLDivElement); markdown.boxupdate(document.getElementById("typebox") as HTMLDivElement);
},null,function(){ },null,function(){
return this.author.id===this.localuser.user.id return this.author.id===this.localuser.user.id;
}); });
Message.contextmenu.addbutton("Delete message",function(this:Message){ Message.contextmenu.addbutton("Delete message",function(this:Message){
this.delete(); this.delete();
},null,function(){ },null,function(){
return this.canDelete() return this.canDelete();
});
})
} }
constructor(messagejson:messagejson,owner:Channel){ constructor(messagejson:messagejson,owner:Channel){
this.owner=owner; this.owner=owner;
@ -87,14 +88,12 @@ class Message{
this.owner.messages.set(this.id,this); this.owner.messages.set(this.id,this);
} }
reactionToggle(emoji:string|Emoji){ reactionToggle(emoji:string|Emoji){
let remove = false;
let remove = false for(const thing of this.reactions){
for (const thing of this.reactions) { if(thing.emoji.name === emoji){
if (thing.emoji.name === emoji) { remove = thing.me;
remove = thing.me break;
break
} }
} }
let reactiontxt:string; let reactiontxt:string;
if(emoji instanceof Emoji){ if(emoji instanceof Emoji){
@ -105,7 +104,7 @@ class Message{
fetch(`${this.info.api}/channels/${this.channel.id}/messages/${this.id}/reactions/${reactiontxt}/@me`, { fetch(`${this.info.api}/channels/${this.channel.id}/messages/${this.id}/reactions/${reactiontxt}/@me`, {
method: remove ? "DELETE" : "PUT", method: remove ? "DELETE" : "PUT",
headers: this.headers headers: this.headers
}) });
} }
giveData(messagejson:messagejson){ giveData(messagejson:messagejson){
const func=this.channel.infinite.snapBottom(); const func=this.channel.infinite.snapBottom();
@ -130,7 +129,7 @@ class Message{
}else if(thing ==="embeds"){ }else if(thing ==="embeds"){
this.embeds=[]; this.embeds=[];
for(const thing in messagejson.embeds){ for(const thing in messagejson.embeds){
console.log(thing,messagejson.embeds) console.log(thing,messagejson.embeds);
this.embeds[thing]=new Embed(messagejson.embeds[thing],this); this.embeds[thing]=new Embed(messagejson.embeds[thing],this);
} }
continue; continue;
@ -148,10 +147,10 @@ class Message{
if(!this.member&&this.guild.id!=="@me"){ if(!this.member&&this.guild.id!=="@me"){
this.author.resolvemember(this.guild).then(_=>{ this.author.resolvemember(this.guild).then(_=>{
this.member=_; this.member=_;
}) });
} }
if(this.mentions.length||this.mention_roles.length){//currently mention_roles isn't implemented on the spacebar servers if(this.mentions.length||this.mention_roles.length){//currently mention_roles isn't implemented on the spacebar servers
console.log(this.mentions,this.mention_roles) console.log(this.mentions,this.mention_roles);
} }
if(this.mentionsuser(this.localuser.user)){ if(this.mentionsuser(this.localuser.user)){
console.log(this); console.log(this);
@ -182,12 +181,12 @@ class Message{
obj.classList.add("messagediv"); obj.classList.add("messagediv");
} }
deleteDiv(){ deleteDiv(){
if(!this.div) return; if(!this.div)return;
try{ try{
this.div.remove(); this.div.remove();
this.div=undefined; this.div=undefined;
}catch(e){ }catch(e){
console.error(e) console.error(e);
} }
} }
mentionsuser(userd:User|Member){ mentionsuser(userd:User|Member){
@ -200,7 +199,7 @@ class Message{
getimages(){ getimages(){
const build:File[]=[]; const build:File[]=[];
for(const thing of this.attachments){ for(const thing of this.attachments){
if(thing.content_type.startsWith('image/')){ if(thing.content_type.startsWith("image/")){
build.push(thing); build.push(thing);
} }
} }
@ -210,14 +209,14 @@ class Message{
return await fetch(this.info.api+"/channels/"+this.channel.snowflake+"/messages/"+this.id,{ return await fetch(this.info.api+"/channels/"+this.channel.snowflake+"/messages/"+this.id,{
method: "PATCH", method: "PATCH",
headers: this.headers, headers: this.headers,
body:JSON.stringify({content:content}) body: JSON.stringify({content})
}); });
} }
delete(){ delete(){
fetch(`${this.info.api}/channels/${this.channel.snowflake}/messages/${this.id}`,{ fetch(`${this.info.api}/channels/${this.channel.snowflake}/messages/${this.id}`,{
headers:this.headers, headers: this.headers,
method:"DELETE", method: "DELETE",
}) });
} }
deleteEvent(){ deleteEvent(){
if(this.div){ if(this.div){
@ -227,10 +226,10 @@ class Message{
const prev=this.channel.idToPrev.get(this.id); const prev=this.channel.idToPrev.get(this.id);
const next=this.channel.idToNext.get(this.id); const next=this.channel.idToNext.get(this.id);
if(prev){ if(prev){
this.channel.idToPrev.delete(this.id) this.channel.idToPrev.delete(this.id);
} }
if(next){ if(next){
this.channel.idToNext.delete(this.id) this.channel.idToNext.delete(this.id);
} }
if(prev&&next){ if(prev&&next){
this.channel.idToPrev.set(next,prev); this.channel.idToPrev.set(next,prev);
@ -265,8 +264,8 @@ class Message{
this.generateMessage(); this.generateMessage();
} }
} }
generateMessage(premessage:Message|undefined=undefined,ignoredblock=false){ generateMessage(premessage?:Message|undefined,ignoredblock=false){
if(!this.div) return; if(!this.div)return;
if(!premessage){ if(!premessage){
premessage=this.channel.messages.get(this.channel.idToPrev.get(this.id) as string); premessage=this.channel.messages.get(this.channel.idToPrev.get(this.id) as string);
} }
@ -275,38 +274,38 @@ class Message{
div.classList.add("replying"); div.classList.add("replying");
} }
div.innerHTML=""; div.innerHTML="";
const build = document.createElement('div'); const build = document.createElement("div");
build.classList.add("flexltr","message"); build.classList.add("flexltr","message");
div.classList.remove("zeroheight") div.classList.remove("zeroheight");
if(this.author.relationshipType===2){ if(this.author.relationshipType===2){
if(ignoredblock){ if(ignoredblock){
if(premessage?.author!==this.author){ if(premessage?.author!==this.author){
const span=document.createElement("span"); const span=document.createElement("span");
span.textContent=`You have this user blocked, click to hide these messages.`; span.textContent="You have this user blocked, click to hide these messages.";
div.append(span); div.append(span);
span.classList.add("blocked") span.classList.add("blocked");
span.onclick=_=>{ span.onclick=_=>{
const scroll=this.channel.infinite.scrollTop; const scroll=this.channel.infinite.scrollTop;
let next:Message|undefined=this; let next:Message|undefined=this;
while(next?.author===this.author){ while(next?.author===this.author){
next.generateMessage(undefined); next.generateMessage();
next=this.channel.messages.get(this.channel.idToNext.get(next.id) as string); next=this.channel.messages.get(this.channel.idToNext.get(next.id) as string);
} }
if(this.channel.infinite.scroll&&scroll){ if(this.channel.infinite.scroll&&scroll){
this.channel.infinite.scroll.scrollTop=scroll; this.channel.infinite.scroll.scrollTop=scroll;
} }
} };
} }
}else{ }else{
div.classList.remove("topMessage"); div.classList.remove("topMessage");
if(premessage?.author===this.author){ if(premessage?.author===this.author){
div.classList.add("zeroheight") div.classList.add("zeroheight");
premessage.blockedPropigate(); premessage.blockedPropigate();
div.appendChild(build); div.appendChild(build);
return div; return div;
}else{ }else{
build.classList.add("blocked","topMessage") build.classList.add("blocked","topMessage");
const span=document.createElement("span"); const span=document.createElement("span");
let count=1; let count=1;
let next=this.channel.messages.get(this.channel.idToNext.get(this.id) as string); let next=this.channel.messages.get(this.channel.idToNext.get(this.id) as string);
@ -323,13 +322,13 @@ class Message{
while(next?.author===this.author){ while(next?.author===this.author){
next.generateMessage(undefined,true); next.generateMessage(undefined,true);
next=this.channel.messages.get(this.channel.idToNext.get(next.id) as string); next=this.channel.messages.get(this.channel.idToNext.get(next.id) as string);
console.log("loopy") console.log("loopy");
} }
if(this.channel.infinite.scroll&&scroll){ if(this.channel.infinite.scroll&&scroll){
func(); func();
this.channel.infinite.scroll.scrollTop=scroll; this.channel.infinite.scroll.scrollTop=scroll;
} }
} };
div.appendChild(build); div.appendChild(build);
return div; return div;
} }
@ -338,7 +337,7 @@ class Message{
if(this.message_reference){ if(this.message_reference){
const replyline=document.createElement("div"); const replyline=document.createElement("div");
const line=document.createElement("hr"); const line=document.createElement("hr");
const minipfp=document.createElement("img") const minipfp=document.createElement("img");
minipfp.classList.add("replypfp"); minipfp.classList.add("replypfp");
replyline.appendChild(line); replyline.appendChild(line);
replyline.appendChild(minipfp); replyline.appendChild(minipfp);
@ -352,29 +351,29 @@ class Message{
replyline.appendChild(line2); replyline.appendChild(line2);
line2.classList.add("reply"); line2.classList.add("reply");
line.classList.add("startreply"); line.classList.add("startreply");
replyline.classList.add("replyflex") replyline.classList.add("replyflex");
this.channel.getmessage(this.message_reference.message_id).then(message=>{ this.channel.getmessage(this.message_reference.message_id).then(message=>{
if(message.author.relationshipType===2){ if(message.author.relationshipType===2){
username.textContent="Blocked user"; username.textContent="Blocked user";
return; return;
} }
const author=message.author; const author=message.author;
reply.appendChild(message.content.makeHTML({stdsize:true})); reply.appendChild(message.content.makeHTML({stdsize: true}));
minipfp.src=author.getpfpsrc() minipfp.src=author.getpfpsrc();
author.bind(minipfp); author.bind(minipfp);
username.textContent=author.username; username.textContent=author.username;
author.bind(username); author.bind(username);
}); });
reply.onclick=_=>{ reply.onclick=_=>{
this.channel.infinite.focus(this.message_reference.message_id); this.channel.infinite.focus(this.message_reference.message_id);
} };
div.appendChild(replyline); div.appendChild(replyline);
} }
div.appendChild(build); div.appendChild(build);
if({0:true,19:true}[this.type]||this.attachments.length!==0){ if({0: true,19: true}[this.type]||this.attachments.length!==0){
const pfpRow = document.createElement('div'); const pfpRow = document.createElement("div");
pfpRow.classList.add("flexltr"); pfpRow.classList.add("flexltr");
let pfpparent, current let pfpparent, current;
if(premessage!=null){ if(premessage!=null){
pfpparent??=premessage; pfpparent??=premessage;
let pfpparent2=pfpparent.all; let pfpparent2=pfpparent.all;
@ -383,7 +382,7 @@ class Message{
const newt=(new Date(this.timestamp).getTime())/1000; const newt=(new Date(this.timestamp).getTime())/1000;
current=(newt-old)>600; current=(newt-old)>600;
} }
const combine=(premessage?.author?.snowflake!=this.author.snowflake)||(current)||this.message_reference const combine=(premessage?.author?.snowflake!=this.author.snowflake)||(current)||this.message_reference;
if(combine){ if(combine){
const pfp=this.author.buildpfp(); const pfp=this.author.buildpfp();
this.author.bind(pfp,this.guild,false); this.author.bind(pfp,this.guild,false);
@ -391,68 +390,67 @@ class Message{
}else{ }else{
div["pfpparent"]=pfpparent; div["pfpparent"]=pfpparent;
} }
pfpRow.classList.add("pfprow") pfpRow.classList.add("pfprow");
build.appendChild(pfpRow); build.appendChild(pfpRow);
const text=document.createElement("div"); const text=document.createElement("div");
text.classList.add("flexttb") text.classList.add("flexttb");
const texttxt=document.createElement("div"); const texttxt=document.createElement("div");
texttxt.classList.add("commentrow","flexttb"); texttxt.classList.add("commentrow","flexttb");
text.appendChild(texttxt); text.appendChild(texttxt);
if(combine){ if(combine){
const username=document.createElement("span"); const username=document.createElement("span");
username.classList.add("username") username.classList.add("username");
this.author.bind(username,this.guild); this.author.bind(username,this.guild);
div.classList.add("topMessage"); div.classList.add("topMessage");
username.textContent=this.author.username; username.textContent=this.author.username;
const userwrap=document.createElement("div"); const userwrap=document.createElement("div");
userwrap.classList.add("flexltr"); userwrap.classList.add("flexltr");
userwrap.appendChild(username) userwrap.appendChild(username);
if(this.author.bot){ if(this.author.bot){
const username=document.createElement("span"); const username=document.createElement("span");
username.classList.add("bot") username.classList.add("bot");
username.textContent="BOT"; username.textContent="BOT";
userwrap.appendChild(username) userwrap.appendChild(username);
} }
const time=document.createElement("span"); const time=document.createElement("span");
time.textContent=" "+formatTime(new Date(this.timestamp)); time.textContent=" "+formatTime(new Date(this.timestamp));
time.classList.add("timestamp") time.classList.add("timestamp");
userwrap.appendChild(time); userwrap.appendChild(time);
texttxt.appendChild(userwrap) texttxt.appendChild(userwrap);
}else{ }else{
div.classList.remove("topMessage"); div.classList.remove("topMessage");
} }
const messaged=this.content.makeHTML(); const messaged=this.content.makeHTML();
div["txt"]=messaged; div["txt"]=messaged;
const messagedwrap=document.createElement("div"); const messagedwrap=document.createElement("div");
messagedwrap.classList.add("flexttb") messagedwrap.classList.add("flexttb");
messagedwrap.appendChild(messaged) messagedwrap.appendChild(messaged);
texttxt.appendChild(messagedwrap) texttxt.appendChild(messagedwrap);
build.appendChild(text) build.appendChild(text);
if(this.attachments.length){ if(this.attachments.length){
console.log(this.attachments) console.log(this.attachments);
const attach = document.createElement("div"); const attach = document.createElement("div");
attach.classList.add("flexltr"); attach.classList.add("flexltr");
for(const thing of this.attachments){ for(const thing of this.attachments){
attach.appendChild(thing.getHTML()) attach.appendChild(thing.getHTML());
} }
messagedwrap.appendChild(attach) messagedwrap.appendChild(attach);
} }
if(this.embeds.length){ if(this.embeds.length){
console.log(this.embeds); console.log(this.embeds);
const embeds = document.createElement("div") const embeds = document.createElement("div");
embeds.classList.add("flexltr"); embeds.classList.add("flexltr");
for(const thing of this.embeds){ for(const thing of this.embeds){
embeds.appendChild(thing.generateHTML()); embeds.appendChild(thing.generateHTML());
} }
messagedwrap.appendChild(embeds) messagedwrap.appendChild(embeds);
} }
// //
}else if(this.type===7){ }else if(this.type===7){
const text=document.createElement("div"); const text=document.createElement("div");
text.classList.add("flexttb") text.classList.add("flexttb");
const texttxt=document.createElement("div"); const texttxt=document.createElement("div");
text.appendChild(texttxt); text.appendChild(texttxt);
build.appendChild(text); build.appendChild(text);
@ -473,31 +471,30 @@ class Message{
time.textContent=" "+formatTime(new Date(this.timestamp)); time.textContent=" "+formatTime(new Date(this.timestamp));
time.classList.add("timestamp"); time.classList.add("timestamp");
texttxt.append(time); texttxt.append(time);
div.classList.add("topMessage") div.classList.add("topMessage");
} }
div["all"]=this; div["all"]=this;
const reactions=document.createElement("div"); const reactions=document.createElement("div");
reactions.classList.add("flexltr","reactiondiv"); reactions.classList.add("flexltr","reactiondiv");
this.reactdiv=new WeakRef(reactions); this.reactdiv=new WeakRef(reactions);
this.updateReactions(); this.updateReactions();
div.append(reactions) div.append(reactions);
return(div) return(div);
} }
updateReactions(){ updateReactions(){
const reactdiv=this.reactdiv.deref(); const reactdiv=this.reactdiv.deref();
if(!reactdiv) return; if(!reactdiv)return;
const func=this.channel.infinite.snapBottom(); const func=this.channel.infinite.snapBottom();
reactdiv.innerHTML=""; reactdiv.innerHTML="";
for(const thing of this.reactions){ for(const thing of this.reactions){
const reaction=document.createElement("div"); const reaction=document.createElement("div");
reaction.classList.add("reaction"); reaction.classList.add("reaction");
if(thing.me){ if(thing.me){
reaction.classList.add("meReacted") reaction.classList.add("meReacted");
} }
let emoji:HTMLElement; let emoji:HTMLElement;
if (thing.emoji.id || /\d{17,21}/.test(thing.emoji.name)) { if(thing.emoji.id || /\d{17,21}/.test(thing.emoji.name)){
if (/\d{17,21}/.test(thing.emoji.name)) thing.emoji.id=thing.emoji.name;//Should stop being a thing once the server fixes this bug if(/\d{17,21}/.test(thing.emoji.name)) thing.emoji.id=thing.emoji.name;//Should stop being a thing once the server fixes this bug
const emo=new Emoji(thing.emoji as {name:string,id:string,animated:boolean},this.guild); const emo=new Emoji(thing.emoji as {name:string,id:string,animated:boolean},this.guild);
emoji=emo.getHTML(false); emoji=emo.getHTML(false);
}else{ }else{
@ -513,7 +510,7 @@ class Message{
reaction.onclick=_=>{ reaction.onclick=_=>{
this.reactionToggle(thing.emoji.name); this.reactionToggle(thing.emoji.name);
} };
} }
func(); func();
} }
@ -529,9 +526,9 @@ class Message{
} }
} }
this.reactions.push({ this.reactions.push({
count:1, count: 1,
emoji:data, emoji: data,
me:member.id===this.localuser.user.id me: member.id===this.localuser.user.id
}); });
this.updateReactions(); this.updateReactions();
} }
@ -543,7 +540,7 @@ class Message{
if(thing.emoji.name===data.name){ if(thing.emoji.name===data.name){
thing.count--; thing.count--;
if(thing.count===0){ if(thing.count===0){
this.reactions.splice(+i,1); this.reactions.splice(Number(i),1);
this.updateReactions(); this.updateReactions();
return; return;
} }
@ -555,48 +552,50 @@ class Message{
} }
} }
} }
reactionRemoveAll() { reactionRemoveAll(){
this.reactions = []; this.reactions = [];
this.updateReactions(); this.updateReactions();
} }
reactionRemoveEmoji(emoji:Emoji) { reactionRemoveEmoji(emoji:Emoji){
for (const i in this.reactions) { for(const i in this.reactions){
const reaction = this.reactions[i]; const reaction = this.reactions[i];
if ((reaction.emoji.id && reaction.emoji.id == emoji.id) || (!reaction.emoji.id && reaction.emoji.name == emoji.name)) { if((reaction.emoji.id && reaction.emoji.id == emoji.id) || (!reaction.emoji.id && reaction.emoji.name == emoji.name)){
this.reactions.splice(+i, 1); this.reactions.splice(Number(i), 1);
this.updateReactions(); this.updateReactions();
break; break;
} }
} }
} }
buildhtml(premessage:Message|undefined=undefined){ buildhtml(premessage?:Message|undefined):HTMLElement{
if(this.div){console.error(`HTML for ${this.snowflake} already exists, aborting`);return;} if(this.div){
console.error(`HTML for ${this.snowflake} already exists, aborting`);return this.div;
}
try{ try{
const div=document.createElement("div"); const div=document.createElement("div");
this.div=div; this.div=div;
this.messageevents(div); this.messageevents(div);
return this.generateMessage(premessage); return this.generateMessage(premessage) as HTMLElement;
}catch(e){ }catch(e){
console.error(e); console.error(e);
} }
return this.div as HTMLElement;
} }
} }
let now = new Date().toLocaleDateString(); const now = new Date().toLocaleDateString();
const yesterday = new Date(now); const yesterday = new Date(now);
yesterday.setDate(new Date().getDate() - 1); yesterday.setDate(new Date().getDate() - 1);
let yesterdayStr=yesterday.toLocaleDateString(); const yesterdayStr=yesterday.toLocaleDateString();
function formatTime(date:Date) { function formatTime(date:Date){
const datestring=date.toLocaleDateString(); const datestring=date.toLocaleDateString();
const formatTime = (date:Date) => date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); const formatTime = (date:Date)=>date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
if (datestring=== now) { if(datestring=== now){
return `Today at ${formatTime(date)}`; return`Today at ${formatTime(date)}`;
} else if (datestring===yesterdayStr) { }else if(datestring===yesterdayStr){
return `Yesterday at ${formatTime(date)}`; return`Yesterday at ${formatTime(date)}`;
} else { }else{
return `${date.toLocaleDateString()} at ${formatTime(date)}`; return`${date.toLocaleDateString()} at ${formatTime(date)}`;
} }
} }
Message.setup(); Message.setup();
export { Message }; export{ Message };

View file

@ -3,14 +3,14 @@ class Permissions{
deny:bigint; deny:bigint;
readonly hasDeny:boolean; readonly hasDeny:boolean;
constructor(allow:string,deny:string=""){ constructor(allow:string,deny:string=""){
this.hasDeny=!!deny; this.hasDeny=Boolean(deny);
try{ try{
this.allow = BigInt(allow); this.allow = BigInt(allow);
this.deny = BigInt(deny); this.deny = BigInt(deny);
}catch(e){ }catch{
this.allow = 0n; this.allow = 0n;
this.deny = 0n; this.deny = 0n;
console.error(`Something really stupid happened with a permission with allow being ${allow} and deny being, ${deny}, execution will still happen, but something really stupid happened, please report if you know what caused this.`) console.error(`Something really stupid happened with a permission with allow being ${allow} and deny being, ${deny}, execution will still happen, but something really stupid happened, please report if you know what caused this.`);
} }
} }
getPermissionbit(b:number,big:bigint) : boolean{ getPermissionbit(b:number,big:bigint) : boolean{
@ -18,258 +18,258 @@ class Permissions{
} }
setPermissionbit(b:number,state:boolean,big:bigint) : bigint{ setPermissionbit(b:number,state:boolean,big:bigint) : bigint{
const bit=1n<<BigInt(b); const bit=1n<<BigInt(b);
return (big & ~bit) | (BigInt(state) << BigInt(b));//thanks to geotale for this code :3 return(big & ~bit) | (BigInt(state) << BigInt(b));//thanks to geotale for this code :3
} }
static map:{ static map:{
[key:number|string]:{"name":string,"readableName":string,"description":string}|number, [key:number|string]:{"name":string,"readableName":string,"description":string}|number,
} };
static info:{"name":string,"readableName":string,"description":string}[]; static info:{"name":string,"readableName":string,"description":string}[];
static makeMap(){ static makeMap(){
Permissions.info=[//for people in the future, do not reorder these, the creation of the map realize on the order Permissions.info=[//for people in the future, do not reorder these, the creation of the map realize on the order
{ {
name:"CREATE_INSTANT_INVITE", name: "CREATE_INSTANT_INVITE",
readableName:"Create invite", readableName: "Create invite",
description:"Allows the user to create invites for the guild" description: "Allows the user to create invites for the guild"
}, },
{ {
name:"KICK_MEMBERS", name: "KICK_MEMBERS",
readableName:"Kick members", readableName: "Kick members",
description:"Allows the user to kick members from the guild" description: "Allows the user to kick members from the guild"
}, },
{ {
name:"BAN_MEMBERS", name: "BAN_MEMBERS",
readableName:"Ban members", readableName: "Ban members",
description:"Allows the user to ban members from the guild" description: "Allows the user to ban members from the guild"
}, },
{ {
name:"ADMINISTRATOR", name: "ADMINISTRATOR",
readableName:"Administrator", readableName: "Administrator",
description:"Allows all permissions and bypasses channel permission overwrites. This is a dangerous permission!" description: "Allows all permissions and bypasses channel permission overwrites. This is a dangerous permission!"
}, },
{ {
name:"MANAGE_CHANNELS", name: "MANAGE_CHANNELS",
readableName:"Manage channels", readableName: "Manage channels",
description:"Allows the user to manage and edit channels" description: "Allows the user to manage and edit channels"
}, },
{ {
name:"MANAGE_GUILD", name: "MANAGE_GUILD",
readableName:"Manage guild", readableName: "Manage guild",
description:"Allows management and editing of the guild" description: "Allows management and editing of the guild"
}, },
{ {
name:"ADD_REACTIONS", name: "ADD_REACTIONS",
readableName:"Add reactions", readableName: "Add reactions",
description:"Allows user to add reactions to messages" description: "Allows user to add reactions to messages"
}, },
{ {
name:"VIEW_AUDIT_LOG", name: "VIEW_AUDIT_LOG",
readableName:"View audit log", readableName: "View audit log",
description:"Allows the user to view the audit log" description: "Allows the user to view the audit log"
}, },
{ {
name:"PRIORITY_SPEAKER", name: "PRIORITY_SPEAKER",
readableName:"Priority speaker", readableName: "Priority speaker",
description:"Allows for using priority speaker in a voice channel" description: "Allows for using priority speaker in a voice channel"
}, },
{ {
name:"STREAM", name: "STREAM",
readableName:"Video", readableName: "Video",
description:"Allows the user to stream" description: "Allows the user to stream"
}, },
{ {
name:"VIEW_CHANNEL", name: "VIEW_CHANNEL",
readableName:"View channels", readableName: "View channels",
description:"Allows the user to view the channel" description: "Allows the user to view the channel"
}, },
{ {
name:"SEND_MESSAGES", name: "SEND_MESSAGES",
readableName:"Send messages", readableName: "Send messages",
description:"Allows user to send messages" description: "Allows user to send messages"
}, },
{ {
name:"SEND_TTS_MESSAGES", name: "SEND_TTS_MESSAGES",
readableName:"Send text-to-speech messages", readableName: "Send text-to-speech messages",
description:"Allows the user to send text-to-speech messages" description: "Allows the user to send text-to-speech messages"
}, },
{ {
name:"MANAGE_MESSAGES", name: "MANAGE_MESSAGES",
readableName:"Manage messages", readableName: "Manage messages",
description:"Allows the user to delete messages that aren't their own" description: "Allows the user to delete messages that aren't their own"
}, },
{ {
name:"EMBED_LINKS", name: "EMBED_LINKS",
readableName:"Embed links", readableName: "Embed links",
description:"Allow links sent by this user to auto-embed" description: "Allow links sent by this user to auto-embed"
}, },
{ {
name:"ATTACH_FILES", name: "ATTACH_FILES",
readableName:"Attach files", readableName: "Attach files",
description:"Allows the user to attach files" description: "Allows the user to attach files"
}, },
{ {
name:"READ_MESSAGE_HISTORY", name: "READ_MESSAGE_HISTORY",
readableName:"Read message history", readableName: "Read message history",
description:"Allows user to read the message history" description: "Allows user to read the message history"
}, },
{ {
name:"MENTION_EVERYONE", name: "MENTION_EVERYONE",
readableName:"Mention @everyone, @here and all roles", readableName: "Mention @everyone, @here and all roles",
description:"Allows the user to mention everyone" description: "Allows the user to mention everyone"
}, },
{ {
name:"USE_EXTERNAL_EMOJIS", name: "USE_EXTERNAL_EMOJIS",
readableName:"Use external emojis", readableName: "Use external emojis",
description:"Allows the user to use external emojis" description: "Allows the user to use external emojis"
}, },
{ {
name:"VIEW_GUILD_INSIGHTS", name: "VIEW_GUILD_INSIGHTS",
readableName:"View guild insights", readableName: "View guild insights",
description:"Allows the user to see guild insights" description: "Allows the user to see guild insights"
}, },
{ {
name:"CONNECT", name: "CONNECT",
readableName:"Connect", readableName: "Connect",
description:"Allows the user to connect to a voice channel" description: "Allows the user to connect to a voice channel"
}, },
{ {
name:"SPEAK", name: "SPEAK",
readableName:"Speak", readableName: "Speak",
description:"Allows the user to speak in a voice channel" description: "Allows the user to speak in a voice channel"
}, },
{ {
name:"MUTE_MEMBERS", name: "MUTE_MEMBERS",
readableName:"Mute members", readableName: "Mute members",
description:"Allows user to mute other members" description: "Allows user to mute other members"
}, },
{ {
name:"DEAFEN_MEMBERS", name: "DEAFEN_MEMBERS",
readableName:"Deafen members", readableName: "Deafen members",
description:"Allows user to deafen other members" description: "Allows user to deafen other members"
}, },
{ {
name:"MOVE_MEMBERS", name: "MOVE_MEMBERS",
readableName:"Move members", readableName: "Move members",
description:"Allows the user to move members between voice channels" description: "Allows the user to move members between voice channels"
}, },
{ {
name:"USE_VAD", name: "USE_VAD",
readableName:"Use voice activity detection", readableName: "Use voice activity detection",
description:"Allows users to speak in a voice channel by simply talking" description: "Allows users to speak in a voice channel by simply talking"
}, },
{ {
name:"CHANGE_NICKNAME", name: "CHANGE_NICKNAME",
readableName:"Change nickname", readableName: "Change nickname",
description:"Allows the user to change their own nickname" description: "Allows the user to change their own nickname"
}, },
{ {
name:"MANAGE_NICKNAMES", name: "MANAGE_NICKNAMES",
readableName:"Manage nicknames", readableName: "Manage nicknames",
description:"Allows user to change nicknames of other members" description: "Allows user to change nicknames of other members"
}, },
{ {
name:"MANAGE_ROLES", name: "MANAGE_ROLES",
readableName:"Manage roles", readableName: "Manage roles",
description:"Allows user to edit and manage roles" description: "Allows user to edit and manage roles"
}, },
{ {
name:"MANAGE_WEBHOOKS", name: "MANAGE_WEBHOOKS",
readableName:"Manage webhooks", readableName: "Manage webhooks",
description:"Allows management and editing of webhooks" description: "Allows management and editing of webhooks"
}, },
{ {
name:"MANAGE_GUILD_EXPRESSIONS", name: "MANAGE_GUILD_EXPRESSIONS",
readableName:"Manage expressions", readableName: "Manage expressions",
description:"Allows for managing emoji, stickers, and soundboards" description: "Allows for managing emoji, stickers, and soundboards"
}, },
{ {
name:"USE_APPLICATION_COMMANDS", name: "USE_APPLICATION_COMMANDS",
readableName:"Use application commands", readableName: "Use application commands",
description:"Allows the user to use application commands" description: "Allows the user to use application commands"
}, },
{ {
name:"REQUEST_TO_SPEAK", name: "REQUEST_TO_SPEAK",
readableName:"Request to speak", readableName: "Request to speak",
description:"Allows user to request to speak in stage channel" description: "Allows user to request to speak in stage channel"
}, },
{ {
name:"MANAGE_EVENTS", name: "MANAGE_EVENTS",
readableName:"Manage events", readableName: "Manage events",
description:"Allows user to edit and manage events" description: "Allows user to edit and manage events"
}, },
{ {
name:"MANAGE_THREADS", name: "MANAGE_THREADS",
readableName:"Manage threads", readableName: "Manage threads",
description:"Allows the user to delete and archive threads and view all private threads" description: "Allows the user to delete and archive threads and view all private threads"
}, },
{ {
name:"CREATE_PUBLIC_THREADS", name: "CREATE_PUBLIC_THREADS",
readableName:"Create public threads", readableName: "Create public threads",
description:"Allows the user to create public threads" description: "Allows the user to create public threads"
}, },
{ {
name:"CREATE_PRIVATE_THREADS", name: "CREATE_PRIVATE_THREADS",
readableName:"Create private threads", readableName: "Create private threads",
description:"Allows the user to create private threads" description: "Allows the user to create private threads"
}, },
{ {
name:"USE_EXTERNAL_STICKERS", name: "USE_EXTERNAL_STICKERS",
readableName:"Use external stickers", readableName: "Use external stickers",
description:"Allows user to use external stickers" description: "Allows user to use external stickers"
}, },
{ {
name:"SEND_MESSAGES_IN_THREADS", name: "SEND_MESSAGES_IN_THREADS",
readableName:"Send messages in threads", readableName: "Send messages in threads",
description:"Allows the user to send messages in threads" description: "Allows the user to send messages in threads"
}, },
{ {
name:"USE_EMBEDDED_ACTIVITIES", name: "USE_EMBEDDED_ACTIVITIES",
readableName:"Use activities", readableName: "Use activities",
description:"Allows the user to use embedded activities" description: "Allows the user to use embedded activities"
}, },
{ {
name:"MODERATE_MEMBERS", name: "MODERATE_MEMBERS",
readableName:"Timeout members", readableName: "Timeout members",
description:"Allows the user to time out other users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels" description: "Allows the user to time out other users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels"
}, },
{ {
name:"VIEW_CREATOR_MONETIZATION_ANALYTICS", name: "VIEW_CREATOR_MONETIZATION_ANALYTICS",
readableName:"View creator monetization analytics", readableName: "View creator monetization analytics",
description:"Allows for viewing role subscription insights" description: "Allows for viewing role subscription insights"
}, },
{ {
name:"USE_SOUNDBOARD", name: "USE_SOUNDBOARD",
readableName:"Use soundboard", readableName: "Use soundboard",
description:"Allows for using soundboard in a voice channel" description: "Allows for using soundboard in a voice channel"
}, },
{ {
name:"CREATE_GUILD_EXPRESSIONS", name: "CREATE_GUILD_EXPRESSIONS",
readableName:"Create expressions", readableName: "Create expressions",
description:"Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user." description: "Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user."
}, },
{ {
name:"CREATE_EVENTS", name: "CREATE_EVENTS",
readableName:"Create events", readableName: "Create events",
description:"Allows for creating scheduled events, and editing and deleting those created by the current user." description: "Allows for creating scheduled events, and editing and deleting those created by the current user."
}, },
{ {
name:"USE_EXTERNAL_SOUNDS", name: "USE_EXTERNAL_SOUNDS",
readableName:"Use external sounds", readableName: "Use external sounds",
description:"Allows the usage of custom soundboard sounds from other servers" description: "Allows the usage of custom soundboard sounds from other servers"
}, },
{ {
name:"SEND_VOICE_MESSAGES", name: "SEND_VOICE_MESSAGES",
readableName:"Send voice messages", readableName: "Send voice messages",
description:"Allows sending voice messages" description: "Allows sending voice messages"
}, },
{ {
name:"SEND_POLLS", name: "SEND_POLLS",
readableName:"Create polls", readableName: "Create polls",
description:"Allows sending polls" description: "Allows sending polls"
}, },
{ {
name:"USE_EXTERNAL_APPS", name: "USE_EXTERNAL_APPS",
readableName:"Use external apps", readableName: "Use external apps",
description:"Allows user-installed apps to send public responses. " + description: "Allows user-installed apps to send public responses. " +
"When disabled, users will still be allowed to use their apps but the responses will be ephemeral. " + "When disabled, users will still be allowed to use their apps but the responses will be ephemeral. " +
"This only applies to apps not also installed to the server." "This only applies to apps not also installed to the server."
}, },
@ -286,20 +286,22 @@ class Permissions{
if(this.getPermissionbit(Permissions.map[name] as number,this.allow)){ if(this.getPermissionbit(Permissions.map[name] as number,this.allow)){
return 1; return 1;
}else if(this.getPermissionbit(Permissions.map[name] as number,this.deny)){ }else if(this.getPermissionbit(Permissions.map[name] as number,this.deny)){
return -1; return-1;
}else{ }else{
return 0; return 0;
} }
} }
hasPermission(name:string):boolean{ hasPermission(name:string):boolean{
if(this.deny){console.warn("This function may of been used in error, think about using getPermision instead")} if(this.deny){
if (this.getPermissionbit(Permissions.map[name] as number,this.allow)) return true; console.warn("This function may of been used in error, think about using getPermision instead");
if (name != "ADMINISTRATOR") return this.hasPermission("ADMINISTRATOR"); }
if(this.getPermissionbit(Permissions.map[name] as number,this.allow))return true;
if(name != "ADMINISTRATOR")return this.hasPermission("ADMINISTRATOR");
return false; return false;
} }
setPermission(name:string,setto:number):void{ setPermission(name:string,setto:number):void{
const bit=Permissions.map[name] as number; const bit=Permissions.map[name] as number;
if (!bit) { if(!bit){
return console.error("Tried to set permission to " + setto + " for " + name + " but it doesn't exist"); return console.error("Tried to set permission to " + setto + " for " + name + " but it doesn't exist");
} }
@ -307,11 +309,9 @@ class Permissions{
this.deny=this.setPermissionbit(bit,false,this.deny); this.deny=this.setPermissionbit(bit,false,this.deny);
this.allow=this.setPermissionbit(bit,false,this.allow); this.allow=this.setPermissionbit(bit,false,this.allow);
}else if(setto===1){ }else if(setto===1){
this.deny=this.setPermissionbit(bit,false,this.deny); this.deny=this.setPermissionbit(bit,false,this.deny);
this.allow=this.setPermissionbit(bit,true,this.allow); this.allow=this.setPermissionbit(bit,true,this.allow);
}else if(setto===-1){ }else if(setto===-1){
this.deny=this.setPermissionbit(bit,true,this.deny); this.deny=this.setPermissionbit(bit,true,this.deny);
this.allow=this.setPermissionbit(bit,false,this.allow); this.allow=this.setPermissionbit(bit,false,this.allow);
}else{ }else{
@ -320,4 +320,4 @@ class Permissions{
} }
} }
Permissions.makeMap(); Permissions.makeMap();
export {Permissions}; export{Permissions};

View file

@ -1,18 +1,18 @@
<body class="Dark-theme"> <body class="Dark-theme">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jank Client</title> <title>Jank Client</title>
<meta content="Jank Client" property="og:title" /> <meta content="Jank Client" property="og:title">
<meta content="A spacebar client that has DMs, replying and more" property="og:description" /> <meta content="A spacebar client that has DMs, replying and more" property="og:description">
<meta content="/logo.webp" property="og:image" /> <meta content="/logo.webp" property="og:image">
<meta content="#4b458c" data-react-helmet="true" name="theme-color" /> <meta content="#4b458c" data-react-helmet="true" name="theme-color">
<link href="/style.css" rel="stylesheet" type="text/css" /> <link href="/style.css" rel="stylesheet">
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/> <link href="/themes.css" rel="stylesheet" id="lightcss">
</head> </head>
<div id="logindiv"> <div id="logindiv">
<h1>Create an account</h1><br> <h1>Create an account</h1><br>
<form id="register" submit="registertry(e)"> <form id="register" submit="registertry(e)">
<div> <div>
<label for="instance"><b>Instance:</b></label><br> <label for="instance"><b>Instance:</b></label><br>
<p id="verify"></p> <p id="verify"></p>
@ -39,12 +39,12 @@
<div> <div>
<label for="date"><b>Date of birth:</b></label><br> <label for="date"><b>Date of birth:</b></label><br>
<input type="date" id="date" name="date"/> <input type="date" id="date" name="date">
</div> </div>
<div> <div>
<b id="TOSbox">I agree to the <a href="" id="TOSa">Terms of Service</a>:</b> <b id="TOSbox">I agree to the <a href="" id="TOSa">Terms of Service</a>:</b>
<input type="checkbox" id="TOS" name="TOS"/> <input type="checkbox" id="TOS" name="TOS">
</div> </div>
<p class="wrongred" id="wrong"></p> <p class="wrongred" id="wrong"></p>
@ -52,9 +52,9 @@
</div> </div>
<button type="submit" class="dontgrow">Create account</button> <button type="submit" class="dontgrow">Create account</button>
</form> </form>
<a href="/login.html" id="switch">Already have an account?</a> <a href="/login.html" id="switch">Already have an account?</a>
</div> </div>
<datalist id="instances"></datalist> <datalist id="instances"></datalist>
<script src="/register.js" type="module"></script> <script src="/register.js" type="module"></script>
</body> </body>

View file

@ -1,9 +1,8 @@
import {checkInstance, adduser} from "./login.js"; import{checkInstance, adduser}from"./login.js";
if(document.getElementById("register")){ if(document.getElementById("register")){
document.getElementById("register").addEventListener("submit", registertry); document.getElementById("register").addEventListener("submit", registertry);
} }
async function registertry(e){ async function registertry(e){
e.preventDefault(); e.preventDefault();
const elements=e.srcElement; const elements=e.srcElement;
const email=elements[1].value; const email=elements[1].value;
@ -14,21 +13,21 @@ async function registertry(e){
} }
const password=elements[3].value; const password=elements[3].value;
const dateofbirth=elements[5].value; const dateofbirth=elements[5].value;
const apiurl=new URL(JSON.parse(localStorage.getItem("instanceinfo")).api) const apiurl=new URL(JSON.parse(localStorage.getItem("instanceinfo")).api);
await fetch(apiurl+"/auth/register",{ await fetch(apiurl+"/auth/register",{
body:JSON.stringify({ body: JSON.stringify({
date_of_birth:dateofbirth, date_of_birth: dateofbirth,
email:email, email,
username:username, username,
password:password, password,
consent:elements[6].checked, consent: elements[6].checked,
captcha_key:elements[7]?.value captcha_key: elements[7]?.value
}), }),
headers:{ headers: {
"content-type": "application/json" "content-type": "application/json"
}, },
method:"POST" method: "POST"
}).then(e=>{ }).then(e=>{
e.json().then(e=>{ e.json().then(e=>{
if(e.captcha_sitekey){ if(e.captcha_sitekey){
@ -63,17 +62,17 @@ async function registertry(e){
document.getElementById("wrong").textContent=e.errors[Object.keys(e.errors)[0]]._errors[0].message; document.getElementById("wrong").textContent=e.errors[Object.keys(e.errors)[0]]._errors[0].message;
} }
}else{ }else{
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:email,token:e.token}).username=username; adduser({serverurls: JSON.parse(localStorage.getItem("instanceinfo")),email,token: e.token}).username=username;
localStorage.setItem("token",e.token); localStorage.setItem("token",e.token);
const redir=new URLSearchParams(window.location.search).get("goback"); const redir=new URLSearchParams(window.location.search).get("goback");
if(redir){ if(redir){
window.location.href = redir; window.location.href = redir;
}else{ }else{
window.location.href = '/channels/@me'; window.location.href = "/channels/@me";
} }
} }
}) });
}) });
//document.getElementById("wrong").textContent=h; //document.getElementById("wrong").textContent=h;
// console.log(h); // console.log(h);
} }
@ -87,13 +86,15 @@ function error(e:HTMLFormElement,message:string){
element=div; element=div;
}else{ }else{
element.classList.remove("suberror"); element.classList.remove("suberror");
setTimeout(_=>{element.classList.add("suberror")},100); setTimeout(_=>{
element.classList.add("suberror");
},100);
} }
element.textContent=message; element.textContent=message;
} }
let TOSa=document.getElementById("TOSa"); let TOSa=document.getElementById("TOSa");
async function tosLogic(){ async function tosLogic(){
const apiurl=new URL(JSON.parse(localStorage.getItem("instanceinfo")).api) const apiurl=new URL(JSON.parse(localStorage.getItem("instanceinfo")).api);
const tosPage=(await (await fetch(apiurl.toString()+"/ping")).json()).instance.tosPage; const tosPage=(await (await fetch(apiurl.toString()+"/ping")).json()).instance.tosPage;
if(tosPage){ if(tosPage){
document.getElementById("TOSbox").innerHTML="I agree to the <a href=\"\" id=\"TOSa\">Terms of Service</a>:"; document.getElementById("TOSbox").innerHTML="I agree to the <a href=\"\" id=\"TOSa\">Terms of Service</a>:";

View file

@ -1,9 +1,9 @@
import {Permissions} from "./permissions.js"; import{Permissions}from"./permissions.js";
import {Localuser} from "./localuser.js"; import{Localuser}from"./localuser.js";
import {Guild} from "./guild.js"; import{Guild}from"./guild.js";
import { SnowFlake } from "./snowflake.js"; import{ SnowFlake }from"./snowflake.js";
import { rolesjson } from "./jsontypes.js"; import{ rolesjson }from"./jsontypes.js";
class Role{ class Role{
permissions:Permissions; permissions:Permissions;
owner:Guild; owner:Guild;
@ -39,12 +39,14 @@ class Role{
return this.guild.localuser; return this.guild.localuser;
} }
getColor():string|null{ getColor():string|null{
if(this.color===0){return null}; if(this.color===0){
return `#${this.color.toString(16)}`; return null;
}
return`#${this.color.toString(16)}`;
} }
} }
export {Role}; export{Role};
import {Options} from "./settings.js"; import{Options}from"./settings.js";
class PermissionToggle implements OptionsElement<number>{ class PermissionToggle implements OptionsElement<number>{
readonly rolejson:{name:string,readableName:string,description:string}; readonly rolejson:{name:string,readableName:string,description:string};
permissions:Permissions; permissions:Permissions;
@ -55,7 +57,7 @@ class PermissionToggle implements OptionsElement<number>{
this.permissions=permissions; this.permissions=permissions;
this.owner=owner; this.owner=owner;
} }
watchForChange(){}; watchForChange(){}
generateHTML():HTMLElement{ generateHTML():HTMLElement{
const div=document.createElement("div"); const div=document.createElement("div");
div.classList.add("setting"); div.classList.add("setting");
@ -80,31 +82,37 @@ class PermissionToggle implements OptionsElement<number>{
on.type="radio"; on.type="radio";
on.name=this.rolejson.name; on.name=this.rolejson.name;
div.append(on); div.append(on);
if(state===1){on.checked=true;}; if(state===1){
on.checked=true;
}
on.onclick=_=>{ on.onclick=_=>{
this.permissions.setPermission(this.rolejson.name,1); this.permissions.setPermission(this.rolejson.name,1);
this.owner.changed(); this.owner.changed();
} };
const no=document.createElement("input"); const no=document.createElement("input");
no.type="radio"; no.type="radio";
no.name=this.rolejson.name; no.name=this.rolejson.name;
div.append(no); div.append(no);
if(state===0){no.checked=true;}; if(state===0){
no.checked=true;
}
no.onclick=_=>{ no.onclick=_=>{
this.permissions.setPermission(this.rolejson.name,0); this.permissions.setPermission(this.rolejson.name,0);
this.owner.changed(); this.owner.changed();
} };
if(this.permissions.hasDeny){ if(this.permissions.hasDeny){
const off=document.createElement("input"); const off=document.createElement("input");
off.type="radio"; off.type="radio";
off.name=this.rolejson.name; off.name=this.rolejson.name;
div.append(off); div.append(off);
if(state===-1){off.checked=true;}; if(state===-1){
off.checked=true;
}
off.onclick=_=>{ off.onclick=_=>{
this.permissions.setPermission(this.rolejson.name,-1); this.permissions.setPermission(this.rolejson.name,-1);
this.owner.changed(); this.owner.changed();
} };
} }
return div; return div;
} }
@ -112,7 +120,7 @@ class PermissionToggle implements OptionsElement<number>{
} }
} }
import { OptionsElement,Buttons } from "./settings.js"; import{ OptionsElement,Buttons }from"./settings.js";
class RoleList extends Buttons{ class RoleList extends Buttons{
readonly permissions:[SnowFlake<Role>,Permissions][]; readonly permissions:[SnowFlake<Role>,Permissions][];
permission:Permissions; permission:Permissions;
@ -139,7 +147,7 @@ class RoleList extends Buttons{
} }
for(const i of permissions){ for(const i of permissions){
console.log(i); console.log(i);
this.buttons.push([i[0].getObject().name,i[0].id])// this.buttons.push([i[0].getObject().name,i[0].id]);//
} }
this.options=options; this.options=options;
} }
@ -159,4 +167,4 @@ class RoleList extends Buttons{
this.onchange(this.curid,this.permission); this.onchange(this.curid,this.permission);
} }
} }
export {RoleList} export{RoleList};

View file

@ -1,25 +1,25 @@
function deleteoldcache(){ function deleteoldcache(){
caches.delete("cache"); caches.delete("cache");
console.log("this ran :P") console.log("this ran :P");
} }
async function putInCache(request, response){ async function putInCache(request, response){
console.log(request,response); console.log(request,response);
const cache = await caches.open('cache'); const cache = await caches.open("cache");
console.log("Grabbed") console.log("Grabbed");
try{ try{
console.log(await cache.put(request, response)); console.log(await cache.put(request, response));
}catch(error){ }catch(error){
console.error(error); console.error(error);
} }
}; }
console.log("test"); console.log("test");
let lastcache let lastcache;
self.addEventListener("activate", async (event) => { self.addEventListener("activate", async event=>{
console.log("test2"); console.log("test2");
checkCache(); checkCache();
}) });
async function checkCache(){ async function checkCache(){
if(checkedrecently){ if(checkedrecently){
return; return;
@ -31,14 +31,16 @@ async function checkCache(){
console.log(lastcache); console.log(lastcache);
fetch("/getupdates").then(async data=>{ fetch("/getupdates").then(async data=>{
const text=await data.clone().text(); const text=await data.clone().text();
console.log(text,lastcache) console.log(text,lastcache);
if(lastcache!==text){ if(lastcache!==text){
deleteoldcache(); deleteoldcache();
putInCache("/getupdates",data.clone()); putInCache("/getupdates",data.clone());
} }
checkedrecently=true; checkedrecently=true;
setTimeout(_=>{checkedrecently=false},1000*60*30); setTimeout(_=>{
}) checkedrecently=false;
},1000*60*30);
});
} }
var checkedrecently=false; var checkedrecently=false;
function samedomain(url){ function samedomain(url){
@ -58,15 +60,15 @@ async function getfile(event){
} }
const responseFromCache = await caches.match(event.request.url); const responseFromCache = await caches.match(event.request.url);
console.log(responseFromCache,caches); console.log(responseFromCache,caches);
if (responseFromCache) { if(responseFromCache){
console.log("cache hit") console.log("cache hit");
return responseFromCache; return responseFromCache;
} }
if(isindexhtml(event.request.url)){ if(isindexhtml(event.request.url)){
console.log("is index.html") console.log("is index.html");
const responseFromCache = await caches.match("/index.html"); const responseFromCache = await caches.match("/index.html");
if (responseFromCache) { if(responseFromCache){
console.log("cache hit") console.log("cache hit");
return responseFromCache; return responseFromCache;
} }
const responseFromNetwork = await fetch("/index.html"); const responseFromNetwork = await fetch("/index.html");
@ -78,10 +80,14 @@ async function getfile(event){
await putInCache(event.request.clone(),responseFromNetwork.clone()); await putInCache(event.request.clone(),responseFromNetwork.clone());
try{ try{
return responseFromNetwork; return responseFromNetwork;
}catch(e){console.error(e)} }catch(e){
console.error(e);
}
} }
self.addEventListener('fetch', (event:any) => { self.addEventListener("fetch", (event:any)=>{
try{ try{
event.respondWith(getfile(event)); event.respondWith(getfile(event));
}catch(e){console.error(e)} }catch(e){
}) console.error(e);
}
});

View file

@ -16,8 +16,10 @@ class Buttons implements OptionsElement<unknown>{
this.buttons=[]; this.buttons=[];
this.name=name; this.name=name;
} }
add(name:string,thing:Options|undefined=undefined){ add(name:string,thing?:Options|undefined){
if(!thing){thing=new Options(name,this)} if(!thing){
thing=new Options(name,this);
}
this.buttons.push([name,thing]); this.buttons.push([name,thing]);
return thing; return thing;
} }
@ -39,7 +41,7 @@ class Buttons implements OptionsElement<unknown>{
if(this.warndiv){ if(this.warndiv){
this.warndiv.remove(); this.warndiv.remove();
} }
} };
buttonTable.append(button); buttonTable.append(button);
} }
this.generateHTMLArea(this.buttons[0][1],htmlarea); this.generateHTMLArea(this.buttons[0][1],htmlarea);
@ -123,7 +125,7 @@ class TextInput implements OptionsElement<string>{
class SettingsText implements OptionsElement<void>{ class SettingsText implements OptionsElement<void>{
readonly onSubmit:(str:string)=>void; readonly onSubmit:(str:string)=>void;
value:void; value:void;
readonly text:string readonly text:string;
constructor(text:string){ constructor(text:string){
this.text=text; this.text=text;
} }
@ -138,7 +140,7 @@ class SettingsText implements OptionsElement<void>{
class SettingsTitle implements OptionsElement<void>{ class SettingsTitle implements OptionsElement<void>{
readonly onSubmit:(str:string)=>void; readonly onSubmit:(str:string)=>void;
value:void; value:void;
readonly text:string readonly text:string;
constructor(text:string){ constructor(text:string){
this.text=text; this.text=text;
} }
@ -274,7 +276,7 @@ class SelectInput implements OptionsElement<number>{
readonly onSubmit:(str:number)=>void; readonly onSubmit:(str:number)=>void;
options:string[]; options:string[];
index:number; index:number;
select:WeakRef<HTMLSelectElement> select:WeakRef<HTMLSelectElement>;
get value(){ get value(){
return this.index; return this.index;
} }
@ -325,7 +327,7 @@ class MDInput implements OptionsElement<string>{
readonly owner:Options; readonly owner:Options;
readonly onSubmit:(str:string)=>void; readonly onSubmit:(str:string)=>void;
value:string; value:string;
input:WeakRef<HTMLTextAreaElement> input:WeakRef<HTMLTextAreaElement>;
constructor(label:string,onSubmit:(str:string)=>void,owner:Options,{initText=""}={}){ constructor(label:string,onSubmit:(str:string)=>void,owner:Options,{initText=""}={}){
this.label=label; this.label=label;
this.value=initText; this.value=initText;
@ -366,7 +368,7 @@ class FileInput implements OptionsElement<FileList|null>{
readonly label:string; readonly label:string;
readonly owner:Options; readonly owner:Options;
readonly onSubmit:(str:FileList|null)=>void; readonly onSubmit:(str:FileList|null)=>void;
input:WeakRef<HTMLInputElement> input:WeakRef<HTMLInputElement>;
value:FileList|null; value:FileList|null;
clear:boolean; clear:boolean;
constructor(label:string,onSubmit:(str:FileList)=>void,owner:Options,{clear=false}={}){ constructor(label:string,onSubmit:(str:FileList)=>void,owner:Options,{clear=false}={}){
@ -389,10 +391,12 @@ class FileInput implements OptionsElement<FileList|null>{
const button=document.createElement("button"); const button=document.createElement("button");
button.textContent="Clear"; button.textContent="Clear";
button.onclick=_=>{ button.onclick=_=>{
if(this.onchange){this.onchange(null)}; if(this.onchange){
this.onchange(null);
}
this.value=null; this.value=null;
this.owner.changed(); this.owner.changed();
} };
div.append(button); div.append(button);
} }
return div; return div;
@ -425,14 +429,14 @@ class HtmlArea implements OptionsElement<void>{
this.submit=submit; this.submit=submit;
this.html=html; this.html=html;
} }
generateHTML(): HTMLElement { generateHTML(): HTMLElement{
if(this.html instanceof Function){ if(this.html instanceof Function){
return this.html(); return this.html();
}else{ }else{
return this.html; return this.html;
} }
} }
watchForChange(){}; watchForChange(){}
} }
class Options implements OptionsElement<void>{ class Options implements OptionsElement<void>{
name:string; name:string;
@ -458,7 +462,7 @@ class Options implements OptionsElement<void>{
container.innerHTML=""; container.innerHTML="";
} }
} }
watchForChange(){}; watchForChange(){}
addOptions(name:string,{ltr=false}={}){ addOptions(name:string,{ltr=false}={}){
const options=new Options(name,this,{ltr}); const options=new Options(name,this,{ltr});
this.options.push(options); this.options.push(options);
@ -473,7 +477,7 @@ class Options implements OptionsElement<void>{
if(container){ if(container){
this.generateContainter(); this.generateContainter();
}else{ }else{
throw Error("Tried to make a subOptions when the options weren't rendered"); throw new Error("Tried to make a subOptions when the options weren't rendered");
} }
return options; return options;
} }
@ -484,7 +488,7 @@ class Options implements OptionsElement<void>{
if(container){ if(container){
this.generateContainter(); this.generateContainter();
}else{ }else{
throw Error("Tried to make a subForm when the options weren't rendered"); throw new Error("Tried to make a subForm when the options weren't rendered");
} }
return options; return options;
} }
@ -557,7 +561,7 @@ class Options implements OptionsElement<void>{
if(container){ if(container){
const div=document.createElement("div"); const div=document.createElement("div");
if(!(elm instanceof Options)){ if(!(elm instanceof Options)){
div.classList.add("optionElement") div.classList.add("optionElement");
} }
const html=elm.generateHTML(); const html=elm.generateHTML();
div.append(html); div.append(html);
@ -595,8 +599,8 @@ class Options implements OptionsElement<void>{
name.classList.add("clickable"); name.classList.add("clickable");
name.onclick=()=>{ name.onclick=()=>{
this.returnFromSub(); this.returnFromSub();
} };
title.append(name," > ",this.subOptions.name) title.append(name," > ",this.subOptions.name);
} }
}else{ }else{
for(const thing of this.options){ for(const thing of this.options){
@ -611,7 +615,6 @@ class Options implements OptionsElement<void>{
}else if(title){ }else if(title){
title.classList.remove("settingstitle"); title.classList.remove("settingstitle");
} }
}else{ }else{
console.warn("tried to generate container, but it did not exist"); console.warn("tried to generate container, but it did not exist");
} }
@ -639,7 +642,7 @@ class Options implements OptionsElement<void>{
} }
div.remove(); div.remove();
this.submit(); this.submit();
} };
} }
} }
submit(){ submit(){
@ -658,7 +661,7 @@ class FormError extends Error{
this.elem=elem; this.elem=elem;
} }
} }
export {FormError}; export{FormError};
class Form implements OptionsElement<object>{ class Form implements OptionsElement<object>{
name:string; name:string;
readonly options:Options; readonly options:Options;
@ -753,16 +756,16 @@ class Form implements OptionsElement<object>{
const button=document.createElement("button"); const button=document.createElement("button");
button.onclick=_=>{ button.onclick=_=>{
this.submit(); this.submit();
} };
button.textContent=this.submitText; button.textContent=this.submitText;
div.append(button) div.append(button);
} }
return div; return div;
} }
onSubmit:((arg1:object)=>void); onSubmit:((arg1:object)=>void);
watchForChange(func:(arg1:object)=>void){ watchForChange(func:(arg1:object)=>void){
this.onSubmit=func; this.onSubmit=func;
}; }
changed(){ changed(){
if(this.traditionalSubmit){ if(this.traditionalSubmit){
this.owner.changed(); this.owner.changed();
@ -792,7 +795,7 @@ class Form implements OptionsElement<object>{
} }
} }
for(const thing of this.names.keys()){ for(const thing of this.names.keys()){
if(thing==="") continue; if(thing==="")continue;
const input=this.names.get(thing) as OptionsElement<any>; const input=this.names.get(thing) as OptionsElement<any>;
if(input instanceof SelectInput){ if(input instanceof SelectInput){
build[thing]=input.options[input.value]; build[thing]=input.options[input.value];
@ -802,27 +805,29 @@ class Form implements OptionsElement<object>{
} }
if(this.fetchURL!==""){ if(this.fetchURL!==""){
fetch(this.fetchURL,{ fetch(this.fetchURL,{
method:this.method, method: this.method,
body:JSON.stringify(build), body: JSON.stringify(build),
headers:this.headers headers: this.headers
}).then(_=>_.json()).then(json=>{ }).then(_=>_.json()).then(json=>{
if(json.errors&&this.errors(json.errors)) return; if(json.errors&&this.errors(json.errors))return;
this.onSubmit(json); this.onSubmit(json);
}) });
}else{ }else{
this.onSubmit(build); this.onSubmit(build);
} }
console.warn("needs to be implemented") console.warn("needs to be implemented");
} }
errors(errors:{code:number,message:string,errors:{[key:string]:{_errors:{message:string,code:string}}}}){ errors(errors:{code:number,message:string,errors:{[key:string]:{_errors:{message:string,code:string}}}}){
if(!(errors instanceof Object)){return}; if(!(errors instanceof Object)){
return;
}
for(const error of Object.keys(errors)){ for(const error of Object.keys(errors)){
const elm=this.names.get(error); const elm=this.names.get(error);
if(elm){ if(elm){
const ref=this.options.html.get(elm); const ref=this.options.html.get(elm);
if(ref&&ref.deref()){ if(ref&&ref.deref()){
const html=ref.deref() as HTMLDivElement; const html=ref.deref() as HTMLDivElement;
this.makeError(html,errors[error]._errors[0].message) this.makeError(html,errors[error]._errors[0].message);
return true; return true;
} }
} }
@ -840,7 +845,7 @@ class Form implements OptionsElement<object>{
} }
} }
}else{ }else{
console.warn(formElm+" is not a valid form property") console.warn(formElm+" is not a valid form property");
} }
} }
makeError(e:HTMLDivElement,message:string){ makeError(e:HTMLDivElement,message:string){
@ -852,7 +857,9 @@ class Form implements OptionsElement<object>{
element=div; element=div;
}else{ }else{
element.classList.remove("suberror"); element.classList.remove("suberror");
setTimeout(_=>{element.classList.add("suberror")},100); setTimeout(_=>{
element.classList.add("suberror");
},100);
} }
element.textContent=message; element.textContent=message;
} }
@ -875,7 +882,7 @@ class Settings extends Buttons{
const title=document.createElement("h2"); const title=document.createElement("h2");
title.textContent=this.name; title.textContent=this.name;
title.classList.add("settingstitle") title.classList.add("settingstitle");
background.append(title); background.append(title);
background.append(this.generateHTML()); background.append(this.generateHTML());
@ -886,7 +893,9 @@ class Settings extends Buttons{
exit.textContent="✖"; exit.textContent="✖";
exit.classList.add("exitsettings"); exit.classList.add("exitsettings");
background.append(exit); background.append(exit);
exit.onclick=_=>{this.hide();}; exit.onclick=_=>{
this.hide();
};
document.body.append(background); document.body.append(background);
this.html=background; this.html=background;
} }
@ -898,5 +907,5 @@ class Settings extends Buttons{
} }
} }
export {Settings,OptionsElement,Buttons,Options} export{Settings,OptionsElement,Buttons,Options};

View file

@ -81,7 +81,7 @@ class SnowFlake<x extends WeakKey>{
try{ try{
return Number((BigInt(this.id)>>22n)+1420070400000n); return Number((BigInt(this.id)>>22n)+1420070400000n);
}catch{ }catch{
console.error(`The ID is corrupted, it's ${this.id} when it should be some number.`) console.error(`The ID is corrupted, it's ${this.id} when it should be some number.`);
return 0; return 0;
} }
} }
@ -92,4 +92,4 @@ class SnowFlake<x extends WeakKey>{
return this.obj; return this.obj;
} }
} }
export {SnowFlake}; export{SnowFlake};

View file

@ -1,11 +1,11 @@
//const usercache={}; //const usercache={};
import {Member} from "./member.js"; import{Member}from"./member.js";
import {MarkDown} from "./markdown.js"; import{MarkDown}from"./markdown.js";
import {Contextmenu} from "./contextmenu.js"; import{Contextmenu}from"./contextmenu.js";
import {Localuser} from "./localuser.js"; import{Localuser}from"./localuser.js";
import {Guild} from "./guild.js"; import{Guild}from"./guild.js";
import { SnowFlake } from "./snowflake.js"; import{ SnowFlake }from"./snowflake.js";
import { presencejson, userjson } from "./jsontypes.js"; import{ presencejson, userjson }from"./jsontypes.js";
class User{ class User{
owner:Localuser; owner:Localuser;
@ -31,21 +31,21 @@ class User{
private status:string; private status:string;
clone(){ clone(){
return new User({ return new User({
username:this.username, username: this.username,
id:this.id+"#clone", id: this.id+"#clone",
public_flags:this.public_flags, public_flags: this.public_flags,
discriminator:this.discriminator, discriminator: this.discriminator,
avatar:this.avatar, avatar: this.avatar,
accent_color:this.accent_color, accent_color: this.accent_color,
banner:this.banner, banner: this.banner,
bio:this.bio.rawString, bio: this.bio.rawString,
premium_since:this.premium_since, premium_since: this.premium_since,
premium_type:this.premium_type, premium_type: this.premium_type,
bot:this.bot, bot: this.bot,
theme_colors:this.theme_colors, theme_colors: this.theme_colors,
pronouns:this.pronouns, pronouns: this.pronouns,
badge_ids:this.badge_ids badge_ids: this.badge_ids
},this.owner) },this.owner);
} }
public getPresence(presence:presencejson|undefined){ public getPresence(presence:presencejson|undefined){
if(presence){ if(presence){
@ -61,7 +61,7 @@ class User{
if(this.status){ if(this.status){
return this.status; return this.status;
}else{ }else{
return "offline"; return"offline";
} }
} }
get id(){ get id(){
@ -74,35 +74,35 @@ class User{
}); });
this.contextmenu.addbutton("Message user",function(this:User){ this.contextmenu.addbutton("Message user",function(this:User){
fetch(this.info.api+"/users/@me/channels", fetch(this.info.api+"/users/@me/channels",
{method:"POST", {method: "POST",
body:JSON.stringify({"recipients":[this.id]}), body: JSON.stringify({recipients: [this.id]}),
headers: this.localuser.headers headers: this.localuser.headers
}); });
}); });
this.contextmenu.addbutton("Block user",function(this:User){ this.contextmenu.addbutton("Block user",function(this:User){
this.block(); this.block();
},null,function(){ },null,function(){
return this.relationshipType!==2 return this.relationshipType!==2;
}); });
this.contextmenu.addbutton("Unblock user",function(this:User){ this.contextmenu.addbutton("Unblock user",function(this:User){
this.unblock(); this.unblock();
},null,function(){ },null,function(){
return this.relationshipType===2 return this.relationshipType===2;
}); });
this.contextmenu.addbutton("Friend request",function(this:User){ this.contextmenu.addbutton("Friend request",function(this:User){
fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{ fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{
method:"PUT", method: "PUT",
headers:this.owner.headers, headers: this.owner.headers,
body:JSON.stringify({ body: JSON.stringify({
type:1 type: 1
})
}) })
}); });
});
this.contextmenu.addbutton("Kick member",function(this:User,member:Member){ this.contextmenu.addbutton("Kick member",function(this:User,member:Member){
member.kick(); member.kick();
},null,function(member){ },null,member=>{
if(!member) return false; if(!member)return false;
const us=member.guild.member; const us=member.guild.member;
if(member.id===us.id){ if(member.id===us.id){
return false; return false;
@ -110,12 +110,12 @@ class User{
if(member.id===member.guild.properties.owner_id){ if(member.id===member.guild.properties.owner_id){
return false; return false;
} }
return (us.hasPermission("KICK_MEMBERS"))||false; return(us.hasPermission("KICK_MEMBERS"))||false;
}); });
this.contextmenu.addbutton("Ban member",function(this:User,member:Member){ this.contextmenu.addbutton("Ban member",function(this:User,member:Member){
member.ban(); member.ban();
},null,function(member){ },null,member=>{
if(!member) return false; if(!member)return false;
const us=member.guild.member; const us=member.guild.member;
if(member.id===us.id){ if(member.id===us.id){
return false; return false;
@ -123,14 +123,14 @@ class User{
if(member.id===member.guild.properties.owner_id){ if(member.id===member.guild.properties.owner_id){
return false; return false;
} }
return (us.hasPermission("BAN_MEMBERS"))||false; return(us.hasPermission("BAN_MEMBERS"))||false;
}); });
} }
static checkuser(user:User|userjson,owner:Localuser):User{ static checkuser(user:User|userjson,owner:Localuser):User{
if(owner.userMap.has(user.id)){ if(owner.userMap.has(user.id)){
return owner.userMap.get(user.id) as User; return owner.userMap.get(user.id) as User;
}else{ }else{
const tempuser=new User(user as userjson,owner,true) const tempuser=new User(user as userjson,owner,true);
owner.userMap.set(user.id,tempuser); owner.userMap.set(user.id,tempuser);
return tempuser; return tempuser;
} }
@ -143,7 +143,9 @@ class User{
} }
constructor(userjson:userjson,owner:Localuser,dontclone=false){ constructor(userjson:userjson,owner:Localuser,dontclone=false){
this.owner=owner; this.owner=owner;
if(!owner){console.error("missing localuser")} if(!owner){
console.error("missing localuser");
}
if(dontclone){ if(dontclone){
for(const thing of Object.keys(userjson)){ for(const thing of Object.keys(userjson)){
if(thing==="bio"){ if(thing==="bio"){
@ -166,17 +168,16 @@ class User{
} }
async getUserProfile(){ async getUserProfile(){
return (await fetch(`${this.info.api}/users/${this.id.replace("#clone","")}/profile?with_mutual_guilds=true&with_mutual_friends=true`,{ return(await fetch(`${this.info.api}/users/${this.id.replace("#clone","")}/profile?with_mutual_guilds=true&with_mutual_friends=true`,{
headers:this.localuser.headers headers: this.localuser.headers
})).json() })).json();
} }
resolving:false|Promise<any>=false; resolving:false|Promise<any>=false;
async getBadge(id:string){ async getBadge(id:string){
if(this.localuser.badges.has(id)){ if(this.localuser.badges.has(id)){
return this.localuser.badges.get(id); return this.localuser.badges.get(id);
}else{ }else{
if(this.resolving) if(this.resolving){
{
await this.resolving; await this.resolving;
return this.localuser.badges.get(id); return this.localuser.badges.get(id);
} }
@ -192,7 +193,7 @@ class User{
} }
} }
buildpfp(){ buildpfp(){
const pfp=document.createElement('img'); const pfp=document.createElement("img");
pfp.loading="lazy"; pfp.loading="lazy";
pfp.src=this.getpfpsrc(); pfp.src=this.getpfpsrc();
pfp.classList.add("pfp"); pfp.classList.add("pfp");
@ -208,10 +209,10 @@ class User{
const status=document.createElement("div"); const status=document.createElement("div");
status.classList.add("statusDiv"); status.classList.add("statusDiv");
switch(await this.getStatus()){ switch(await this.getStatus()){
case "offline": case"offline":
status.classList.add("offlinestatus"); status.classList.add("offlinestatus");
break; break;
case "online": case"online":
default: default:
status.classList.add("onlinestatus"); status.classList.add("onlinestatus");
break; break;
@ -222,7 +223,7 @@ class User{
} }
userupdate(json:userjson){ userupdate(json:userjson){
if(json.avatar!==this.avatar){ if(json.avatar!==this.avatar){
console.log console.log;
this.changepfp(json.avatar); this.changepfp(json.avatar);
} }
} }
@ -241,7 +242,7 @@ class User{
_.bind(html); _.bind(html);
} }
}).catch(_=>{ }).catch(_=>{
console.log(_) console.log(_);
}); });
} }
if(guild){ if(guild){
@ -252,7 +253,7 @@ class User{
} }
static async resolve(id:string,localuser:Localuser){ static async resolve(id:string,localuser:Localuser){
const json=await fetch(localuser.info.api.toString()+"/users/"+id+"/profile", const json=await fetch(localuser.info.api.toString()+"/users/"+id+"/profile",
{headers:localuser.headers} {headers: localuser.headers}
).then(_=>_.json()); ).then(_=>_.json());
return new User(json,localuser); return new User(json,localuser);
} }
@ -260,19 +261,19 @@ class User{
this.avatar=update; this.avatar=update;
this.hypotheticalpfp=false; this.hypotheticalpfp=false;
const src=this.getpfpsrc(); const src=this.getpfpsrc();
console.log(src) console.log(src);
for(const thing of document.getElementsByClassName("userid:"+this.id)){ for(const thing of document.getElementsByClassName("userid:"+this.id)){
(thing as HTMLImageElement).src=src; (thing as HTMLImageElement).src=src;
} }
} }
block(){ block(){
fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{ fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{
method:"PUT", method: "PUT",
headers:this.owner.headers, headers: this.owner.headers,
body:JSON.stringify({ body: JSON.stringify({
type:2 type: 2
})
}) })
});
this.relationshipType=2; this.relationshipType=2;
const channel=this.localuser.channelfocus; const channel=this.localuser.channelfocus;
if(channel){ if(channel){
@ -283,9 +284,9 @@ class User{
} }
unblock(){ unblock(){
fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{ fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{
method:"DELETE", method: "DELETE",
headers:this.owner.headers, headers: this.owner.headers,
}) });
this.relationshipType=0; this.relationshipType=0;
const channel=this.localuser.channelfocus; const channel=this.localuser.channelfocus;
if(channel){ if(channel){
@ -306,7 +307,7 @@ class User{
} }
} }
createjankpromises(){ createjankpromises(){
new Promise(_=>{}) new Promise(_=>{});
} }
async buildprofile(x:number,y:number,guild:Guild|null=null){ async buildprofile(x:number,y:number,guild:Guild|null=null){
if(Contextmenu.currentmenu!=""){ if(Contextmenu.currentmenu!=""){
@ -322,7 +323,7 @@ class User{
div.style.setProperty("--accent_color","transparent"); div.style.setProperty("--accent_color","transparent");
} }
if(this.banner){ if(this.banner){
const banner=document.createElement("img") const banner=document.createElement("img");
let src:string; let src:string;
if(!this.hypotheticalbanner){ if(!this.hypotheticalbanner){
src=this.info.cdn+"/avatars/"+this.id.replace("#clone","")+"/"+this.banner+".png"; src=this.info.cdn+"/avatars/"+this.id.replace("#clone","")+"/"+this.banner+".png";
@ -345,12 +346,12 @@ class User{
const badgediv=document.createElement("div"); const badgediv=document.createElement("div");
badgediv.classList.add("badges"); badgediv.classList.add("badges");
(async ()=>{ (async ()=>{
if(!this.badge_ids) return; if(!this.badge_ids)return;
for(const id of this.badge_ids){ for(const id of this.badge_ids){
const badgejson=await this.getBadge(id); const badgejson=await this.getBadge(id);
if(badgejson){ if(badgejson){
const badge=document.createElement(badgejson.link?"a":"div"); const badge=document.createElement(badgejson.link?"a":"div");
badge.classList.add("badge") badge.classList.add("badge");
const img=document.createElement("img"); const img=document.createElement("img");
img.src=badgejson.icon; img.src=badgejson.icon;
badge.append(img); badge.append(img);
@ -363,7 +364,7 @@ class User{
badgediv.append(badge); badgediv.append(badge);
} }
} }
})() })();
{ {
const pfp=await this.buildstatuspfp(); const pfp=await this.buildstatuspfp();
div.appendChild(pfp); div.appendChild(pfp);
@ -379,12 +380,12 @@ class User{
const discrimatorhtml=document.createElement("h3"); const discrimatorhtml=document.createElement("h3");
discrimatorhtml.classList.add("tag"); discrimatorhtml.classList.add("tag");
discrimatorhtml.textContent=this.username+"#"+this.discriminator; discrimatorhtml.textContent=this.username+"#"+this.discriminator;
userbody.appendChild(discrimatorhtml) userbody.appendChild(discrimatorhtml);
const pronounshtml=document.createElement("p"); const pronounshtml=document.createElement("p");
pronounshtml.textContent=this.pronouns; pronounshtml.textContent=this.pronouns;
pronounshtml.classList.add("pronouns"); pronounshtml.classList.add("pronouns");
userbody.appendChild(pronounshtml) userbody.appendChild(pronounshtml);
const rule=document.createElement("hr"); const rule=document.createElement("hr");
userbody.appendChild(rule); userbody.appendChild(rule);
@ -392,7 +393,7 @@ class User{
userbody.appendChild(biohtml); userbody.appendChild(biohtml);
if(guild){ if(guild){
Member.resolveMember(this,guild).then(member=>{ Member.resolveMember(this,guild).then(member=>{
if(!member) return; if(!member)return;
const roles=document.createElement("div"); const roles=document.createElement("div");
roles.classList.add("rolesbox"); roles.classList.add("rolesbox");
for(const role of member.roles){ for(const role of member.roles){
@ -400,7 +401,7 @@ class User{
div.classList.add("rolediv"); div.classList.add("rolediv");
const color=document.createElement("div"); const color=document.createElement("div");
div.append(color); div.append(color);
color.style.setProperty("--role-color","#"+role.color.toString(16).padStart(6,"0")) color.style.setProperty("--role-color","#"+role.color.toString(16).padStart(6,"0"));
color.classList.add("colorrolediv"); color.classList.add("colorrolediv");
const span=document.createElement("span"); const span=document.createElement("span");
div.append(span); div.append(span);
@ -415,17 +416,17 @@ class User{
if(x!==-1){ if(x!==-1){
Contextmenu.currentmenu=div; Contextmenu.currentmenu=div;
document.body.appendChild(div) document.body.appendChild(div);
Contextmenu.keepOnScreen(div); Contextmenu.keepOnScreen(div);
} }
return div; return div;
} }
profileclick(obj:HTMLElement,guild:Guild|undefined=undefined){ profileclick(obj:HTMLElement,guild?:Guild|undefined){
obj.onclick=e=>{ obj.onclick=e=>{
this.buildprofile(e.clientX,e.clientY,guild); this.buildprofile(e.clientX,e.clientY,guild);
e.stopPropagation(); e.stopPropagation();
} };
} }
} }
User.setUpContextMenu(); User.setUpContextMenu();
export {User}; export{User};