Various improvements and checks

This commit is contained in:
MathMan05 2024-08-20 14:17:54 -05:00
parent a2abc91a2a
commit 1608d00beb
30 changed files with 541 additions and 360 deletions

View file

@ -39,6 +39,7 @@ class Channel {
infinite; infinite;
idToPrev = new Map(); idToPrev = new Map();
idToNext = new Map(); idToNext = new Map();
messages = new Map();
get id() { get id() {
return this.snowflake.id; return this.snowflake.id;
} }
@ -167,7 +168,7 @@ class Channel {
if (this.idToNext.has(snowflake)) { if (this.idToNext.has(snowflake)) {
return this.idToNext.get(snowflake)?.id; return this.idToNext.get(snowflake)?.id;
} }
else if (this.lastmessage.id !== id) { else if (this.lastmessage?.id !== id) {
await this.grabAfter(id); await this.grabAfter(id);
return this.idToNext.get(snowflake)?.id; return this.idToNext.get(snowflake)?.id;
} }
@ -177,19 +178,11 @@ class Channel {
} }
}.bind(this), async function (id) { }.bind(this), async function (id) {
//await new Promise(_=>{setTimeout(_,Math.random()*10)}) //await new Promise(_=>{setTimeout(_,Math.random()*10)})
const snowflake = SnowFlake.getSnowFlakeFromID(id, Message); const messgage = this.messages.get(id);
if (!snowflake.getObject()) {
//await this.grabArround(id);
console.error("Uh...");
}
try { try {
const prev = this.idToPrev.get(snowflake); if (messgage) {
if (prev) { const html = messgage.buildhtml();
const messgage = this.messageids.get(prev); return html;
if (messgage) {
const html = snowflake.getObject().buildhtml(messgage);
return html;
}
} }
} }
catch (e) { catch (e) {
@ -595,10 +588,12 @@ class Channel {
}); });
} }
setReplying(message) { setReplying(message) {
if (this.replyingto) { 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;
console.log(message); console.log(message);
this.replyingto.div.classList.add("replying"); this.replyingto.div.classList.add("replying");
this.makereplybox(); this.makereplybox();
@ -611,7 +606,7 @@ class Channel {
span.textContent = "Replying to " + this.replyingto.author.username; span.textContent = "Replying to " + this.replyingto.author.username;
const X = document.createElement("button"); const X = document.createElement("button");
X.onclick = _ => { X.onclick = _ => {
if (this.replyingto) { if (this.replyingto?.div) {
this.replyingto.div.classList.remove("replying"); this.replyingto.div.classList.remove("replying");
} }
replybox.classList.add("hideReplyBox"); replybox.classList.add("hideReplyBox");
@ -744,8 +739,7 @@ class Channel {
this.children = build; this.children = build;
} }
async grabAfter(id) { async grabAfter(id) {
console.log(id, this.lastmessage.id); if (id === this.lastmessage?.id) {
if (id === this.lastmessage.id) {
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, {
@ -1025,8 +1019,8 @@ class Channel {
console.log(this.lastmessageid, messagez.snowflake, ":3"); console.log(this.lastmessageid, messagez.snowflake, ":3");
if (this.lastmessageid) { if (this.lastmessageid) {
this.idToNext.set(this.lastmessageid, messagez.snowflake); this.idToNext.set(this.lastmessageid, messagez.snowflake);
this.idToPrev.set(messagez.snowflake, this.lastmessageid);
} }
this.idToPrev.set(messagez.snowflake, this.lastmessageid);
this.lastmessageid = messagez.snowflake; this.lastmessageid = messagez.snowflake;
this.messageids.set(messagez.snowflake, messagez); this.messageids.set(messagez.snowflake, messagez);
if (messagez.author === this.localuser.user) { if (messagez.author === this.localuser.user) {
@ -1078,7 +1072,9 @@ class Channel {
const images = message.getimages(); const images = message.getimages();
if (images.length) { if (images.length) {
const image = images[0]; const image = images[0];
imgurl ||= image.proxy_url; if (image.proxy_url) {
imgurl ||= image.proxy_url;
}
imgurl ||= image.url; imgurl ||= image.url;
} }
const notification = new Notification(this.notititle(message), { const notification = new Notification(this.notititle(message), {

View file

@ -35,12 +35,6 @@ class Direct extends Guild {
this.calculateReorder(); this.calculateReorder();
this.printServers(); this.printServers();
} }
sortchannels() {
this.headchannels.sort((a, b) => {
const result = (a.lastmessageid.getUnixTime() - b.lastmessageid.getUnixTime());
return Number(-result);
});
}
giveMember(_member) { giveMember(_member) {
console.error("not a real guild, can't give member object"); console.error("not a real guild, can't give member object");
} }
@ -105,7 +99,10 @@ class Group extends Channel {
this.lastmessageid ??= null; this.lastmessageid ??= null;
this.mentions = 0; this.mentions = 0;
this.setUpInfiniteScroller(); this.setUpInfiniteScroller();
this.position = Math.max(this.lastmessageid.getUnixTime(), this.snowflake.getUnixTime()); if (this.lastmessageid) {
this.position = this.lastmessageid.getUnixTime();
}
this.position = -Math.max(this.position, this.snowflake.getUnixTime());
} }
createguildHTML() { createguildHTML() {
const div = document.createElement("div"); const div = document.createElement("div");
@ -134,14 +131,16 @@ class Group extends Channel {
return; return;
} }
this.buildmessages(); this.buildmessages();
history.pushState(null, null, "/channels/" + this.guild_id + "/" + this.snowflake); history.pushState(null, "", "/channels/" + this.guild_id + "/" + this.id);
document.getElementById("channelname").textContent = "@" + this.name; document.getElementById("channelname").textContent = "@" + this.name;
document.getElementById("channelTopic").setAttribute("hidden", ""); document.getElementById("channelTopic").setAttribute("hidden", "");
document.getElementById("typebox").contentEditable = "" + true; document.getElementById("typebox").contentEditable = "" + true;
} }
messageCreate(messagep) { messageCreate(messagep) {
const messagez = new Message(messagep.d, this); const messagez = new Message(messagep.d, this);
this.idToNext.set(this.lastmessageid, messagez.snowflake); if (this.lastmessageid) {
this.idToNext.set(this.lastmessageid, messagez.snowflake);
}
this.idToPrev.set(messagez.snowflake, this.lastmessageid); this.idToPrev.set(messagez.snowflake, this.lastmessageid);
this.lastmessageid = messagez.snowflake; this.lastmessageid = messagez.snowflake;
this.messageids.set(messagez.snowflake, messagez); this.messageids.set(messagez.snowflake, messagez);
@ -161,7 +160,7 @@ class Group extends Channel {
if (messagez.author === this.localuser.user) { if (messagez.author === this.localuser.user) {
return; return;
} }
if (this.localuser.lookingguild.prevchannel === this && document.hasFocus()) { if (this.localuser.lookingguild?.prevchannel === this && document.hasFocus()) {
return; return;
} }
if (this.notification === "all") { if (this.notification === "all") {
@ -175,7 +174,7 @@ class Group extends Channel {
return message.author.username; return message.author.username;
} }
unreads() { unreads() {
const sentdms = document.getElementById("sentdms"); const sentdms = document.getElementById("sentdms"); //Need to change sometime
let current = null; let current = null;
for (const thing of sentdms.children) { for (const thing of sentdms.children) {
if (thing["all"] === this) { if (thing["all"] === this) {
@ -184,7 +183,7 @@ class Group extends Channel {
} }
if (this.hasunreads) { if (this.hasunreads) {
if (current) { if (current) {
current.noti.textContent = this.mentions; current["noti"].textContent = this.mentions;
return; return;
} }
const div = document.createElement("div"); const div = document.createElement("div");

View file

@ -65,13 +65,15 @@ class Embed {
authorline.append(a); authorline.append(a);
embed.append(authorline); embed.append(authorline);
} }
const title = document.createElement("a"); if (this.json.title) {
title.append(new MarkDown(this.json.title, this.channel).makeHTML()); const title = document.createElement("a");
if (this.json.url) { title.append(new MarkDown(this.json.title, this.channel).makeHTML());
title.href = this.json.url; if (this.json.url) {
title.href = this.json.url;
}
title.classList.add("embedtitle");
embed.append(title);
} }
title.classList.add("embedtitle");
embed.append(title);
if (this.json.description) { if (this.json.description) {
const p = document.createElement("p"); const p = document.createElement("p");
p.append(new MarkDown(this.json.description, this.channel).makeHTML()); p.append(new MarkDown(this.json.description, this.channel).makeHTML());
@ -150,7 +152,7 @@ class Embed {
table.classList.add("embed", "linkembed"); table.classList.add("embed", "linkembed");
const trtop = document.createElement("tr"); const trtop = document.createElement("tr");
table.append(trtop); table.append(trtop);
{ if (this.json.url && this.json.title) {
const td = document.createElement("td"); const td = document.createElement("td");
const a = document.createElement("a"); const a = document.createElement("a");
a.href = this.json.url; a.href = this.json.url;
@ -174,9 +176,11 @@ class Embed {
} }
const bottomtr = document.createElement("tr"); const bottomtr = document.createElement("tr");
const td = document.createElement("td"); const td = document.createElement("td");
const span = document.createElement("span"); if (this.json.description) {
span.textContent = this.json.description; const span = document.createElement("span");
td.append(span); span.textContent = this.json.description;
td.append(span);
}
bottomtr.append(td); bottomtr.append(td);
table.append(bottomtr); table.append(bottomtr);
return table; return table;
@ -194,12 +198,16 @@ class Embed {
div.append(provider); div.append(provider);
} }
const a = document.createElement("a"); const a = document.createElement("a");
a.href = this.json.url; if (this.json.url && this.json.url) {
a.textContent = this.json.title; a.href = this.json.url;
div.append(a); a.textContent = this.json.url;
const description = document.createElement("p"); div.append(a);
description.textContent = this.json.description; }
div.append(description); if (this.json.description) {
const description = document.createElement("p");
description.textContent = this.json.description;
div.append(description);
}
if (this.json.thumbnail) { if (this.json.thumbnail) {
const img = document.createElement("img"); const img = document.createElement("img");
img.classList.add("bigembedimg"); img.classList.add("bigembedimg");

View file

@ -13,7 +13,7 @@ class Emoji {
} }
get localuser() { get localuser() {
if (this.owner instanceof Guild) { if (this.owner instanceof Guild) {
return this.guild.localuser; return this.owner.localuser;
} }
else { else {
return this.owner; return this.owner;

View file

@ -23,7 +23,7 @@ class File {
} }
getHTML(temp = false) { getHTML(temp = false) {
const src = this.proxy_url || this.url; const src = this.proxy_url || this.url;
if (this.width) { if (this.width && this.height) {
let scale = 1; let scale = 1;
const max = 96 * 3; const max = 96 * 3;
scale = Math.max(scale, this.width / max); scale = Math.max(scale, this.width / max);
@ -57,7 +57,7 @@ class File {
video.append(source); video.append(source);
source.type = this.content_type; source.type = this.content_type;
video.controls = !temp; video.controls = !temp;
if (this.width) { if (this.width && this.height) {
video.width = this.width; video.width = this.width;
video.height = this.height; video.height = this.height;
} }
@ -97,7 +97,7 @@ class 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,

View file

@ -97,10 +97,21 @@ class Guild {
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(_ => this.member = _); Member.resolveMember(member, this).then(_ => {
if (_) {
this.member = _;
}
else {
console.error("Member was unable to resolve");
}
});
} }
else { else {
Member.new(member, this).then(_ => this.member = _); Member.new(member, this).then(_ => {
if (_) {
this.member = _;
}
});
} }
for (const thing of json.channels) { for (const thing of json.channels) {
const temp = new Channel(thing, this); const temp = new Channel(thing, this);
@ -199,11 +210,10 @@ class Guild {
if (thing.move_id && thing.move_id !== thing.parent_id) { if (thing.move_id && thing.move_id !== thing.parent_id) {
thing.parent_id = thing.move_id; thing.parent_id = thing.move_id;
thisthing.parent_id = thing.parent_id; thisthing.parent_id = thing.parent_id;
thing.move_id = undefined; thing.move_id = null;
} }
if (thisthing.position || thisthing.parent_id) { if (thisthing.position || thisthing.parent_id) {
build.push(thisthing); build.push(thisthing);
console.log(this.channelids[thisthing.parent_id]);
} }
if (thing.children.length > 0) { if (thing.children.length > 0) {
const things = thing.calculateReorder(); const things = thing.calculateReorder();
@ -369,6 +379,8 @@ class Guild {
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;
thing.myhtml.classList.remove("cunread"); thing.myhtml.classList.remove("cunread");
} }
} }

View file

@ -38,16 +38,17 @@ function showAccountSwitcher() {
userinfo.addEventListener("click", _ => { userinfo.addEventListener("click", _ => {
thisuser.unload(); thisuser.unload();
thisuser.swapped = true; thisuser.swapped = true;
document.getElementById("loading").classList.remove("doneloading"); const loading = document.getElementById("loading");
document.getElementById("loading").classList.add("loading"); loading.classList.remove("doneloading");
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();
document.getElementById("loading").classList.add("doneloading"); loading.classList.add("doneloading");
document.getElementById("loading").classList.remove("loading"); loading.classList.remove("loading");
console.log("done loading"); console.log("done loading");
}); });
userinfo.remove(); userinfo.remove();
@ -90,8 +91,9 @@ try {
thisuser.initwebsocket().then(_ => { thisuser.initwebsocket().then(_ => {
thisuser.loaduser(); thisuser.loaduser();
thisuser.init(); thisuser.init();
document.getElementById("loading").classList.add("doneloading"); const loading = document.getElementById("loading");
document.getElementById("loading").classList.remove("loading"); loading.classList.add("doneloading");
loading.classList.remove("loading");
console.log("done loading"); console.log("done loading");
}); });
} }
@ -103,10 +105,14 @@ catch (e) {
{ {
const menu = new Contextmenu("create rightclick"); const menu = new Contextmenu("create rightclick");
menu.addbutton("Create channel", function () { menu.addbutton("Create channel", function () {
thisuser.lookingguild.createchannels(); if (thisuser.lookingguild) {
thisuser.lookingguild.createchannels();
}
}, null, _ => { return thisuser.isAdmin(); }); }, null, _ => { return thisuser.isAdmin(); });
menu.addbutton("Create category", function () { menu.addbutton("Create category", function () {
thisuser.lookingguild.createcategory(); if (thisuser.lookingguild) {
thisuser.lookingguild.createcategory();
}
}, null, _ => { return thisuser.isAdmin(); }); }, null, _ => { return thisuser.isAdmin(); });
menu.bind(document.getElementById("channels")); menu.bind(document.getElementById("channels"));
} }
@ -114,6 +120,8 @@ const pasteimage = document.getElementById("pasteimage");
let replyingto = null; let replyingto = null;
async function enter(event) { async function enter(event) {
const channel = thisuser.channelfocus; const channel = thisuser.channelfocus;
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();
@ -124,13 +132,14 @@ async function enter(event) {
else { else {
replyingto = thisuser.channelfocus.replyingto; replyingto = thisuser.channelfocus.replyingto;
let replying = replyingto; let replying = replyingto;
if (replyingto) { 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,
replyingto: replying, embeds: [],
replyingto: replying
}); });
thisuser.channelfocus.makereplybox(); thisuser.channelfocus.makereplybox();
} }
@ -165,6 +174,8 @@ const imageshtml = [];
import { File } from "./file.js"; import { File } from "./file.js";
import { MarkDown } from "./markdown.js"; import { MarkDown } from "./markdown.js";
document.addEventListener('paste', async (e) => { document.addEventListener('paste', async (e) => {
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();
@ -180,13 +191,13 @@ function userSettings() {
} }
document.getElementById("settings").onclick = userSettings; document.getElementById("settings").onclick = userSettings;
if (mobile) { if (mobile) {
document.getElementById("channelw").onclick = function () { document.getElementById("channelw").onclick = () => {
document.getElementById("channels").parentNode.classList.add("collapse"); document.getElementById("channels").parentNode.classList.add("collapse");
document.getElementById("servertd").classList.add("collapse"); document.getElementById("servertd").classList.add("collapse");
document.getElementById("servers").classList.add("collapse"); document.getElementById("servers").classList.add("collapse");
}; };
document.getElementById("mobileback").textContent = "#"; document.getElementById("mobileback").textContent = "#";
document.getElementById("mobileback").onclick = function () { document.getElementById("mobileback").onclick = () => {
document.getElementById("channels").parentNode.classList.remove("collapse"); document.getElementById("channels").parentNode.classList.remove("collapse");
document.getElementById("servertd").classList.remove("collapse"); document.getElementById("servertd").classList.remove("collapse");
document.getElementById("servers").classList.remove("collapse"); document.getElementById("servers").classList.remove("collapse");

View file

@ -50,6 +50,8 @@ class InfiniteScroller {
scrollTop; scrollTop;
needsupdate = true; needsupdate = true;
async updatestuff() { async updatestuff() {
if (!this.scroll)
return;
this.timeout = null; this.timeout = null;
this.scrollBottom = this.scroll.scrollHeight - this.scroll.scrollTop - this.scroll.clientHeight; this.scrollBottom = this.scroll.scrollHeight - this.scroll.scrollTop - this.scroll.clientHeight;
this.scrollTop = this.scroll.scrollTop; this.scrollTop = this.scroll.scrollTop;
@ -65,6 +67,8 @@ class InfiniteScroller {
//this.watchForChange(); //this.watchForChange();
} }
async firstElement(id) { async firstElement(id) {
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]);
@ -85,14 +89,20 @@ class InfiniteScroller {
}; };
} }
async watchForTop() { async watchForTop() {
if (!this.scroll)
return false;
let again = false; let again = false;
if (this.scrollTop === 0) { if (this.scrollTop === 0) {
this.scrollTop = 1; this.scrollTop = 1;
this.scroll.scrollTop = 1; this.scroll.scrollTop = 1;
} }
if (this.scrollTop < this.minDist) { if (this.scrollTop < this.minDist) {
const previd = this.HTMLElements.at(0)[1]; let nextid;
const nextid = await this.getIDFromOffset(previd, 1); const firstelm = this.HTMLElements.at(0);
if (firstelm) {
const previd = firstelm[1];
nextid = await this.getIDFromOffset(previd, 1);
}
if (!nextid) { if (!nextid) {
} }
else { else {
@ -110,10 +120,12 @@ class InfiniteScroller {
; ;
} }
if (this.scrollTop > this.maxDist) { if (this.scrollTop > this.maxDist) {
again = true;
const html = this.HTMLElements.shift(); const html = this.HTMLElements.shift();
await this.destroyFromID(html[1]); if (html) {
this.scrollTop -= 60; again = true;
await this.destroyFromID(html[1]);
this.scrollTop -= 60;
}
} }
if (again) { if (again) {
await this.watchForTop(); await this.watchForTop();
@ -121,11 +133,17 @@ class InfiniteScroller {
return again; return again;
} }
async watchForBottom() { async watchForBottom() {
if (!this.scroll)
return false;
let again = false; let again = false;
const scrollBottom = this.scrollBottom; const scrollBottom = this.scrollBottom;
if (scrollBottom < this.minDist) { if (scrollBottom < this.minDist) {
const previd = this.HTMLElements.at(-1)[1]; let nextid;
const nextid = await this.getIDFromOffset(previd, -1); const lastelm = this.HTMLElements.at(-1);
if (lastelm) {
const previd = lastelm[1];
nextid = await this.getIDFromOffset(previd, -1);
}
if (!nextid) { if (!nextid) {
} }
else { else {
@ -141,10 +159,12 @@ class InfiniteScroller {
; ;
} }
if (scrollBottom > this.maxDist) { if (scrollBottom > this.maxDist) {
again = true;
const html = this.HTMLElements.pop(); const html = this.HTMLElements.pop();
await this.destroyFromID(html[1]); if (html) {
this.scrollBottom -= 60; await this.destroyFromID(html[1]);
this.scrollBottom -= 60;
again = true;
}
} }
if (again) { if (again) {
await this.watchForBottom(); await this.watchForBottom();
@ -154,14 +174,14 @@ class InfiniteScroller {
async watchForChange() { async watchForChange() {
try { try {
if (this.currrunning) { if (this.currrunning) {
return; return false;
} }
else { else {
this.currrunning = true; this.currrunning = true;
} }
if (!this.div) { if (!this.div) {
this.currrunning = false; this.currrunning = false;
return; return false;
} }
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);
@ -177,6 +197,7 @@ class InfiniteScroller {
catch (e) { catch (e) {
console.error(e); console.error(e);
} }
return false;
} }
async focus(id, flash = true) { async focus(id, flash = true) {
let element; let element;
@ -217,7 +238,9 @@ class InfiniteScroller {
await this.destroyFromID(thing[1]); await this.destroyFromID(thing[1]);
} }
this.HTMLElements = []; this.HTMLElements = [];
clearTimeout(this.timeout); if (this.timeout) {
clearTimeout(this.timeout);
}
if (this.div) { if (this.div) {
this.div.remove(); this.div.remove();
} }

View file

@ -691,6 +691,8 @@ class Localuser {
if (!guild) if (!guild)
return; return;
const memb = await Member.new(typing.d.member, guild); const memb = await Member.new(typing.d.member, guild);
if (!memb)
return;
if (memb.id === this.user.id) { if (memb.id === this.user.id) {
console.log("you is typing"); console.log("you is typing");
return; return;
@ -834,7 +836,7 @@ class Localuser {
}); });
const bclear = settingsLeft.addButtonInput("Clear banner", "Clear", () => { const bclear = settingsLeft.addButtonInput("Clear banner", "Clear", () => {
bfile = null; bfile = null;
hypouser.banner = null; hypouser.banner = undefined;
settingsLeft.changed(); settingsLeft.changed();
regen(); regen();
}); });

View file

@ -56,7 +56,7 @@ class MarkDown {
if (first) { if (first) {
i--; i--;
} }
let element = null; let element;
let keepys = ""; let keepys = "";
if (txt[i + 1] === "#") { if (txt[i + 1] === "#") {
console.log("test"); console.log("test");
@ -97,17 +97,23 @@ class MarkDown {
for (; txt[i] !== "\n" && txt[i] !== undefined; i++) { for (; txt[i] !== "\n" && txt[i] !== undefined; i++) {
build.push(txt[i]); build.push(txt[i]);
} }
if (stdsize) { try {
element = document.createElement("span"); if (stdsize) {
element = document.createElement("span");
}
else
continue;
if (keep) {
element.append(keepys);
}
element.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
span.append(element);
} }
if (keep) { finally {
element.append(keepys); i -= 1;
console.log(txt[i]);
continue;
} }
element.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
span.append(element);
i -= 1;
console.log(txt[i]);
continue;
} }
if (first) { if (first) {
i++; i++;
@ -483,18 +489,24 @@ class MarkDown {
} }
}; };
box.onpaste = _ => { box.onpaste = _ => {
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;
box.onkeyup(new KeyboardEvent("_")); box.onkeyup(new KeyboardEvent("_"));
}; };
} }
boxupdate(box) { boxupdate(box) {
var restore = saveCaretPosition(box); const restore = saveCaretPosition(box);
box.innerHTML = ""; box.innerHTML = "";
box.append(this.makeHTML({ keep: true })); box.append(this.makeHTML({ keep: true }));
restore(); if (restore) {
restore();
}
} }
static gatherBoxText(element) { static gatherBoxText(element) {
if (element.tagName.toLowerCase() === "img") { if (element.tagName.toLowerCase() === "img") {
@ -521,10 +533,14 @@ 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(); var selection = window.getSelection();
if (!selection)
return;
var range = selection.getRangeAt(0); var range = selection.getRangeAt(0);
range.setStart(context, 0); range.setStart(context, 0);
var len = range.toString().length; var len = range.toString().length;
return function restore() { return function restore() {
if (!selection)
return;
var pos = getTextNodeAtPosition(context, len); var pos = getTextNodeAtPosition(context, len);
selection.removeAllRanges(); selection.removeAllRanges();
var range = new Range(); var range = new Range();
@ -535,6 +551,8 @@ function saveCaretPosition(context) {
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) { var treeWalker = document.createTreeWalker(root, NODE_TYPE, function next(elem) {
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;

View file

@ -25,9 +25,12 @@ class Member {
if (User.userids[memberjson.id]) { if (User.userids[memberjson.id]) {
this.user = User.userids[memberjson.id]; this.user = User.userids[memberjson.id];
} }
else { else if (memberjson.user) {
this.user = new User(memberjson.user, owner.localuser); this.user = new User(memberjson.user, owner.localuser);
} }
else {
throw new Error("Missing user object of this member");
}
this.owner = owner; this.owner = owner;
for (const thing of Object.keys(memberjson)) { for (const thing of Object.keys(memberjson)) {
if (thing === "guild") { if (thing === "guild") {
@ -64,9 +67,12 @@ class Member {
if (User.userids[memberjson.id]) { if (User.userids[memberjson.id]) {
user = User.userids[memberjson.id]; user = User.userids[memberjson.id];
} }
else { else if (memberjson.user) {
user = new User(memberjson.user, owner.localuser); user = new User(memberjson.user, owner.localuser);
} }
else {
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) {
@ -91,22 +97,22 @@ 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);
let res; const promise = new Promise(async (res) => {
const promise = new Promise(r => { res = r; }); const membjson = await membpromise;
if (membjson === undefined) {
res(undefined);
return undefined;
}
else {
const member = new Member(membjson, guild);
const map = guild.localuser.presences;
member.getPresence(map.get(member.id));
map.delete(member.id);
res(member);
return member;
}
});
user.members.set(guild, promise); user.members.set(guild, promise);
const membjson = await membpromise;
if (membjson === undefined) {
res(undefined);
return undefined;
}
else {
const member = new Member(membjson, guild);
const map = guild.localuser.presences;
member.getPresence(map.get(member.id));
map.delete(member.id);
res(member);
return member;
}
} }
if (maybe instanceof Promise) { if (maybe instanceof Promise) {
return await maybe; return await maybe;

View file

@ -45,12 +45,6 @@ class Message {
this.del = new Promise(_ => { this.resolve = _; }); this.del = new Promise(_ => { this.resolve = _; });
Message.setupcmenu(); Message.setupcmenu();
} }
static async wipeChanel() {
this.resolve();
document.getElementById("messages").innerHTML = "";
await Promise.allSettled([this.resolve]);
this.del = new Promise(_ => { this.resolve = _; });
}
static setupcmenu() { static setupcmenu() {
Message.contextmenu.addbutton("Copy raw text", function () { Message.contextmenu.addbutton("Copy raw text", function () {
navigator.clipboard.writeText(this.content.rawString); navigator.clipboard.writeText(this.content.rawString);
@ -69,7 +63,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, _ => { return _.author.id === _.localuser.user.id; }); }, null, _ => { return _.author.id === _.localuser.user.id; });
@ -81,6 +75,7 @@ class Message {
this.owner = owner; this.owner = owner;
this.headers = this.owner.headers; this.headers = this.owner.headers;
this.giveData(messagejson); this.giveData(messagejson);
this.owner.messages.set(this.id, this);
} }
reactionToggle(emoji) { reactionToggle(emoji) {
let remove = false; let remove = false;
@ -121,7 +116,9 @@ class Message {
continue; continue;
} }
else if (thing === "member") { else if (thing === "member") {
Member.new(messagejson.member, this.guild).then(_ => { this.member = _; }); Member.new(messagejson.member, this.guild).then(_ => {
this.member = _;
});
continue; continue;
} }
else if (thing === "embeds") { else if (thing === "embeds") {
@ -182,7 +179,7 @@ class Message {
return; return;
try { try {
this.div.remove(); this.div.remove();
this.div = null; this.div = undefined;
} }
catch (e) { catch (e) {
console.error(e); console.error(e);
@ -221,23 +218,37 @@ class Message {
deleteEvent() { deleteEvent() {
if (this.div) { if (this.div) {
this.div.innerHTML = ""; this.div.innerHTML = "";
this.div = null; this.div = undefined;
} }
const prev = this.channel.idToPrev.get(this.snowflake); const prev = this.channel.idToPrev.get(this.snowflake);
const next = this.channel.idToNext.get(this.snowflake); const next = this.channel.idToNext.get(this.snowflake);
this.channel.idToNext.set(prev, next); if (prev) {
this.channel.idToPrev.set(next, prev); this.channel.idToPrev.delete(this.snowflake);
}
if (next) {
this.channel.idToNext.delete(this.snowflake);
}
if (prev && next) {
this.channel.idToPrev.set(next, prev);
this.channel.idToNext.set(prev, next);
}
this.channel.messageids.delete(this.snowflake); this.channel.messageids.delete(this.snowflake);
const regen = prev.getObject(); if (prev && prev.getObject()) {
if (regen) { prev.getObject().generateMessage();
regen.generateMessage();
} }
if (this.channel.lastmessage === this) { if (this.channel.lastmessage === this) {
this.channel.lastmessage = prev.getObject(); if (prev) {
this.channel.lastmessage = prev.getObject();
}
else {
this.channel.lastmessage = undefined;
}
} }
} }
reactdiv; reactdiv;
generateMessage(premessage = null) { generateMessage(premessage = undefined) {
if (!this.div)
return;
if (!premessage) { if (!premessage) {
premessage = this.channel.idToPrev.get(this.snowflake)?.getObject(); premessage = this.channel.idToPrev.get(this.snowflake)?.getObject();
} }
@ -467,13 +478,12 @@ class Message {
} }
} }
} }
buildhtml(premessage) { buildhtml(premessage = undefined) {
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;
} }
try { try {
//premessage??=messages.lastChild;
const div = document.createElement("div"); const div = document.createElement("div");
this.div = div; this.div = div;
this.messageevents(div); this.messageevents(div);

View file

@ -33,7 +33,7 @@ class SnowFlake {
} }
/** /**
* Just to clarify bc TS, it returns a SnowFlake\<type> which is what you entered with the type parameter * Just to clarify bc TS, it returns a SnowFlake\<type> which is what you entered with the type parameter
* * @deprecated
**/ **/
static getSnowFlakeFromID(id, type) { static getSnowFlakeFromID(id, type) {
if (!SnowFlake.SnowFlakes.get(type)) { if (!SnowFlake.SnowFlakes.get(type)) {
@ -56,6 +56,11 @@ class SnowFlake {
return snowflake; return snowflake;
} }
} }
/**
* @deprecated
*
*
*/
static hasSnowFlakeFromID(id, type) { static hasSnowFlakeFromID(id, type) {
if (!SnowFlake.SnowFlakes.get(type)) { if (!SnowFlake.SnowFlakes.get(type)) {
return false; return false;

View file

@ -191,12 +191,19 @@ class User {
html.after(error); html.after(error);
return; return;
} }
_.bind(html); if (_) {
_.bind(html);
}
}).catch(_ => { }).catch(_ => {
console.log(_); console.log(_);
}); });
} }
this.profileclick(html, guild); if (guild) {
this.profileclick(html, guild);
}
else {
this.profileclick(html);
}
User.contextmenu.bind(html, this); User.contextmenu.bind(html, this);
} }
static async resolve(id, localuser) { static async resolve(id, localuser) {
@ -269,18 +276,20 @@ class User {
return; 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);
const badge = document.createElement(badgejson.link ? "a" : "div"); if (badgejson) {
badge.classList.add("badge"); const badge = document.createElement(badgejson.link ? "a" : "div");
const img = document.createElement("img"); badge.classList.add("badge");
img.src = badgejson.icon; const img = document.createElement("img");
badge.append(img); img.src = badgejson.icon;
const span = document.createElement("span"); badge.append(img);
span.textContent = badgejson.description; const span = document.createElement("span");
badge.append(span); span.textContent = badgejson.description;
if (badge instanceof HTMLAnchorElement) { badge.append(span);
badge.href = badgejson.link; if (badge instanceof HTMLAnchorElement) {
badge.href = badgejson.link;
}
badgediv.append(badge);
} }
badgediv.append(badge);
} }
})(); })();
{ {
@ -337,7 +346,7 @@ class User {
} }
return div; return div;
} }
profileclick(obj, guild) { profileclick(obj, 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();

View file

@ -19,7 +19,7 @@ declare global {
} }
} }
class Channel{ class Channel{
editing:Message; editing:Message|null;
type:number; type:number;
owner:Guild; owner:Guild;
headers:Localuser["headers"]; headers:Localuser["headers"];
@ -46,8 +46,9 @@ class Channel{
static contextmenu=new Contextmenu("channel menu"); static contextmenu=new Contextmenu("channel menu");
replyingto:Message|null; replyingto:Message|null;
infinite:InfiniteScroller; infinite:InfiniteScroller;
idToPrev:Map<SnowFlake<Message>,SnowFlake<Message>|null>=new Map(); idToPrev:Map<SnowFlake<Message>,SnowFlake<Message>>=new Map();
idToNext:Map<SnowFlake<Message>,SnowFlake<Message>|null>=new Map(); idToNext:Map<SnowFlake<Message>,SnowFlake<Message>>=new Map();
messages:Map<string,Message>=new Map();
get id(){ get id(){
return this.snowflake.id; return this.snowflake.id;
} }
@ -180,7 +181,7 @@ class Channel{
}else{ }else{
if(this.idToNext.has(snowflake)){ if(this.idToNext.has(snowflake)){
return this.idToNext.get(snowflake)?.id; return this.idToNext.get(snowflake)?.id;
}else if(this.lastmessage.id!==id){ }else if(this.lastmessage?.id!==id){
await this.grabAfter(id); await this.grabAfter(id);
return this.idToNext.get(snowflake)?.id; return this.idToNext.get(snowflake)?.id;
}else{ }else{
@ -190,21 +191,12 @@ class Channel{
}.bind(this), }.bind(this),
async function(this:Channel,id:string){ async function(this:Channel,id:string){
//await new Promise(_=>{setTimeout(_,Math.random()*10)}) //await new Promise(_=>{setTimeout(_,Math.random()*10)})
const snowflake=SnowFlake.getSnowFlakeFromID(id,Message); const messgage=this.messages.get(id);
if(!snowflake.getObject()){
//await this.grabArround(id);
console.error("Uh...")
}
try{ try{
const prev=this.idToPrev.get(snowflake); if(messgage){
if(prev){ const html=messgage.buildhtml();
const messgage=this.messageids.get(prev); return html;
if(messgage){
const html=snowflake.getObject().buildhtml(messgage);
return html;
}
} }
}catch(e){ }catch(e){
console.error(e); console.error(e);
} }
@ -600,13 +592,15 @@ class Channel{
}) })
} }
setReplying(message:Message){ setReplying(message:Message){
if(this.replyingto){
this.replyingto.div.classList.remove("replying"); if(this.replyingto?.div){
} this.replyingto.div.classList.remove("replying");
this.replyingto=message; }
console.log(message); this.replyingto=message;
this.replyingto.div.classList.add("replying"); if(!this.replyingto?.div) return;
this.makereplybox(); console.log(message);
this.replyingto.div.classList.add("replying");
this.makereplybox();
} }
makereplybox(){ makereplybox(){
@ -617,7 +611,7 @@ class Channel{
span.textContent="Replying to "+this.replyingto.author.username; span.textContent="Replying to "+this.replyingto.author.username;
const X=document.createElement("button"); const X=document.createElement("button");
X.onclick=_=>{ X.onclick=_=>{
if(this.replyingto){ if(this.replyingto?.div){
this.replyingto.div.classList.remove("replying"); this.replyingto.div.classList.remove("replying");
} }
replybox.classList.add("hideReplyBox"); replybox.classList.add("hideReplyBox");
@ -707,7 +701,7 @@ class Channel{
loading.append(div); loading.append(div);
} }
} }
lastmessage:Message; lastmessage:Message|undefined;
async putmessages(){ async putmessages(){
if(this.allthewayup){return}; if(this.allthewayup){return};
if(this.lastreadmessageid&&this.lastreadmessageid.getObject()){ if(this.lastreadmessageid&&this.lastreadmessageid.getObject()){
@ -746,8 +740,7 @@ class Channel{
this.children=build; this.children=build;
} }
async grabAfter(id:string){ async grabAfter(id:string){
console.log(id,this.lastmessage.id) if(id===this.lastmessage?.id){
if(id===this.lastmessage.id){
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,{
@ -960,7 +953,7 @@ class Channel{
} }
} }
async sendMessage(content:string,{attachments=[],embeds=[],replyingto=null}: async sendMessage(content:string,{attachments=[],embeds=[],replyingto=null}:
{attachments,embeds,replyingto:Message|null}){ {attachments:Blob[],embeds,replyingto:Message|null}){
let replyjson:any; let replyjson:any;
if(replyingto){ if(replyingto){
replyjson= replyjson=
@ -1012,8 +1005,9 @@ class Channel{
console.log(this.lastmessageid,messagez.snowflake,":3"); console.log(this.lastmessageid,messagez.snowflake,":3");
if(this.lastmessageid){ if(this.lastmessageid){
this.idToNext.set(this.lastmessageid,messagez.snowflake); this.idToNext.set(this.lastmessageid,messagez.snowflake);
this.idToPrev.set(messagez.snowflake,this.lastmessageid);
} }
this.idToPrev.set(messagez.snowflake,this.lastmessageid);
this.lastmessageid=messagez.snowflake; this.lastmessageid=messagez.snowflake;
this.messageids.set(messagez.snowflake,messagez); this.messageids.set(messagez.snowflake,messagez);
@ -1063,7 +1057,9 @@ class Channel{
const images=message.getimages(); const images=message.getimages();
if(images.length){ if(images.length){
const image = images[0]; const image = images[0];
imgurl||=image.proxy_url; if(image.proxy_url){
imgurl||=image.proxy_url;
}
imgurl||=image.url; imgurl||=image.url;
} }
const notification = new Notification(this.notititle(message),{ const notification = new Notification(this.notititle(message),{

View file

@ -39,12 +39,6 @@ class Direct extends Guild{
this.calculateReorder(); this.calculateReorder();
this.printServers(); this.printServers();
} }
sortchannels(){
this.headchannels.sort((a,b)=>{
const result=(a.lastmessageid.getUnixTime()-b.lastmessageid.getUnixTime());
return Number(-result);
});
}
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")
} }
@ -111,7 +105,10 @@ class Group extends Channel{
this.lastmessageid??=null; this.lastmessageid??=null;
this.mentions=0; this.mentions=0;
this.setUpInfiniteScroller(); this.setUpInfiniteScroller();
this.position=Math.max(this.lastmessageid.getUnixTime(),this.snowflake.getUnixTime()); if(this.lastmessageid){
this.position=this.lastmessageid.getUnixTime()
}
this.position=-Math.max(this.position,this.snowflake.getUnixTime());
} }
createguildHTML(){ createguildHTML(){
const div=document.createElement("div") const div=document.createElement("div")
@ -140,14 +137,16 @@ class Group extends Channel{
return; return;
} }
this.buildmessages(); this.buildmessages();
history.pushState(null, null,"/channels/"+this.guild_id+"/"+this.snowflake); history.pushState(null, "","/channels/"+this.guild_id+"/"+this.id);
document.getElementById("channelname").textContent="@"+this.name; (document.getElementById("channelname") as HTMLElement).textContent="@"+this.name;
document.getElementById("channelTopic").setAttribute("hidden",""); (document.getElementById("channelTopic") as HTMLElement).setAttribute("hidden","");
document.getElementById("typebox").contentEditable=""+true; (document.getElementById("typebox") as HTMLDivElement).contentEditable=""+true;
} }
messageCreate(messagep){ messageCreate(messagep){
const messagez=new Message(messagep.d,this); const messagez=new Message(messagep.d,this);
this.idToNext.set(this.lastmessageid,messagez.snowflake); if(this.lastmessageid){
this.idToNext.set(this.lastmessageid,messagez.snowflake);
}
this.idToPrev.set(messagez.snowflake,this.lastmessageid); this.idToPrev.set(messagez.snowflake,this.lastmessageid);
this.lastmessageid=messagez.snowflake; this.lastmessageid=messagez.snowflake;
this.messageids.set(messagez.snowflake,messagez); this.messageids.set(messagez.snowflake,messagez);
@ -166,7 +165,7 @@ class Group extends Channel{
if(messagez.author===this.localuser.user){ if(messagez.author===this.localuser.user){
return; return;
} }
if(this.localuser.lookingguild.prevchannel===this&&document.hasFocus()){ if(this.localuser.lookingguild?.prevchannel===this&&document.hasFocus()){
return; return;
} }
if(this.notification==="all"){ if(this.notification==="all"){
@ -179,15 +178,15 @@ class Group extends Channel{
return message.author.username; return message.author.username;
} }
unreads(){ unreads(){
const sentdms=document.getElementById("sentdms"); const sentdms=document.getElementById("sentdms") as HTMLDivElement;//Need to change sometime
let current=null; let current:HTMLElement|null=null;
for(const thing of sentdms.children){ for(const thing of sentdms.children){
if(thing["all"]===this){ if(thing["all"]===this){
current=thing; current=thing as HTMLElement;
} }
} }
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");

View file

@ -62,7 +62,7 @@ class Embed{
authorline.append(img); authorline.append(img);
} }
const a=document.createElement("a"); const a=document.createElement("a");
a.textContent=this.json.author.name 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
} }
@ -70,14 +70,15 @@ class Embed{
authorline.append(a); authorline.append(a);
embed.append(authorline); embed.append(authorline);
} }
const title=document.createElement("a"); if(this.json.title){
title.append(new MarkDown(this.json.title,this.channel).makeHTML()); const title=document.createElement("a");
if(this.json.url){ title.append(new MarkDown(this.json.title,this.channel).makeHTML());
title.href=this.json.url; if(this.json.url){
title.href=this.json.url;
}
title.classList.add("embedtitle");
embed.append(title);
} }
title.classList.add("embedtitle");
embed.append(title);
if(this.json.description){ if(this.json.description){
const p=document.createElement("p"); const p=document.createElement("p");
p.append(new MarkDown(this.json.description,this.channel).makeHTML()); p.append(new MarkDown(this.json.description,this.channel).makeHTML());
@ -155,7 +156,7 @@ class Embed{
table.classList.add("embed","linkembed"); table.classList.add("embed","linkembed");
const trtop=document.createElement("tr"); const trtop=document.createElement("tr");
table.append(trtop); table.append(trtop);
{ if(this.json.url&&this.json.title){
const td=document.createElement("td"); const td=document.createElement("td");
const a=document.createElement("a"); const a=document.createElement("a");
a.href=this.json.url; a.href=this.json.url;
@ -179,9 +180,11 @@ class Embed{
} }
const bottomtr=document.createElement("tr"); const bottomtr=document.createElement("tr");
const td=document.createElement("td"); const td=document.createElement("td");
const span=document.createElement("span"); if(this.json.description){
span.textContent=this.json.description; const span=document.createElement("span");
td.append(span); span.textContent=this.json.description;
td.append(span);
}
bottomtr.append(td); bottomtr.append(td);
table.append(bottomtr) table.append(bottomtr)
return table; return table;
@ -200,14 +203,16 @@ class Embed{
div.append(provider); div.append(provider);
} }
const a=document.createElement("a"); const a=document.createElement("a");
a.href=this.json.url; if(this.json.url&&this.json.url){
a.textContent=this.json.title; a.href=this.json.url;
div.append(a); a.textContent=this.json.url;
div.append(a);
const description=document.createElement("p"); }
description.textContent=this.json.description; if(this.json.description){
div.append(description); const description=document.createElement("p");
description.textContent=this.json.description;
div.append(description);
}
if(this.json.thumbnail){ if(this.json.thumbnail){
const img=document.createElement("img"); const img=document.createElement("img");
img.classList.add("bigembedimg"); img.classList.add("bigembedimg");

View file

@ -1,5 +1,6 @@
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 { Localuser } from "./localuser.js"; import { Localuser } from "./localuser.js";
class Emoji{ class Emoji{
@ -21,7 +22,7 @@ class Emoji{
} }
get localuser(){ get localuser(){
if(this.owner instanceof Guild){ if(this.owner instanceof Guild){
return this.guild.localuser; return this.owner.localuser;
}else{ }else{
return this.owner; return this.owner;
} }
@ -81,7 +82,11 @@ class Emoji{
for(;cats!==0;cats--){ for(;cats!==0;cats--){
const name=readString16(); const name=readString16();
const emojis=[]; const emojis:{
name:string,
skin_tone_support:boolean,
emoji:string
}[]=[];
let emojinumber=read16(); let emojinumber=read16();
for(;emojinumber!==0;emojinumber--){ for(;emojinumber!==0;emojinumber--){
//console.log(emojis); //console.log(emojis);

View file

@ -3,16 +3,16 @@ import { Dialog } from "./dialog.js";
import { filejson } from "./jsontypes.js"; import { filejson } from "./jsontypes.js";
class File{ class File{
owner:Message; owner:Message|null;
id:string; id:string;
filename:string; filename:string;
content_type:string; content_type:string;
width:number; width:number|undefined;
height:number; height:number|undefined;
proxy_url:string; proxy_url:string|undefined;
url:string; url:string;
size:number; size:number;
constructor(fileJSON:filejson,owner:Message){ constructor(fileJSON:filejson,owner:Message|null){
this.owner=owner; this.owner=owner;
this.id=fileJSON.id; this.id=fileJSON.id;
this.filename=fileJSON.filename; this.filename=fileJSON.filename;
@ -26,7 +26,7 @@ class File{
} }
getHTML(temp:boolean=false):HTMLElement{ getHTML(temp:boolean=false):HTMLElement{
const src=this.proxy_url||this.url; const src=this.proxy_url||this.url;
if(this.width){ if(this.width&&this.height){
let scale=1; let scale=1;
const max=96*3; const max=96*3;
scale=Math.max(scale,this.width/max); scale=Math.max(scale,this.width/max);
@ -59,7 +59,7 @@ class File{
video.append(source); video.append(source);
source.type=this.content_type; source.type=this.content_type;
video.controls=!temp; video.controls=!temp;
if(this.width){ if(this.width&&this.height){
video.width=this.width; video.width=this.width;
video.height=this.height; video.height=this.height;
} }
@ -97,7 +97,7 @@ class 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,

View file

@ -9,6 +9,7 @@ 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";
class Guild{ class Guild{
owner:Localuser; owner:Localuser;
headers:Localuser["headers"]; headers:Localuser["headers"];
@ -106,9 +107,19 @@ class Guild{
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(_=>this.member=_); Member.resolveMember(member,this).then(_=>{
if(_){
this.member=_
}else{
console.error("Member was unable to resolve");
}
});
}else{ }else{
Member.new(member,this).then(_=>this.member=_); Member.new(member,this).then(_=>{
if(_){
this.member=_
}
});
} }
for(const thing of json.channels){ for(const thing of json.channels){
@ -200,9 +211,9 @@ class Guild{
} }
calculateReorder(){ calculateReorder(){
let position=-1; let position=-1;
let build=[]; let 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: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);
} }
@ -211,11 +222,10 @@ class Guild{
if(thing.move_id&&thing.move_id!==thing.parent_id){ if(thing.move_id&&thing.move_id!==thing.parent_id){
thing.parent_id=thing.move_id; thing.parent_id=thing.move_id;
thisthing.parent_id=thing.parent_id; thisthing.parent_id=thing.parent_id;
thing.move_id=undefined; thing.move_id=null;
} }
if(thisthing.position||thisthing.parent_id){ if(thisthing.position||thisthing.parent_id){
build.push(thisthing); build.push(thisthing);
console.log(this.channelids[thisthing.parent_id]);
} }
if(thing.children.length>0){ if(thing.children.length>0){
const things=thing.calculateReorder() const things=thing.calculateReorder()
@ -373,11 +383,12 @@ class Guild{
return this.member.isAdmin() return this.member.isAdmin()
} }
async markAsRead(){ async markAsRead(){
const build={read_states:[]}; const build:{read_states:{channel_id:SnowFlake<Channel>,message_id:SnowFlake<Message>|null,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;
thing.myhtml.classList.remove("cunread"); thing.myhtml.classList.remove("cunread");
} }
} }
@ -395,7 +406,7 @@ class Guild{
} }
return this.member.hasRole(r); return this.member.hasRole(r);
} }
loadChannel(ID:string=undefined){ loadChannel(ID:string|undefined=undefined){
if(ID&&this.channelids[ID]){ if(ID&&this.channelids[ID]){
this.channelids[ID].getHTML(); this.channelids[ID].getHTML();
return; return;

View file

@ -47,16 +47,17 @@ function showAccountSwitcher(){
userinfo.addEventListener("click",_=>{ userinfo.addEventListener("click",_=>{
thisuser.unload(); thisuser.unload();
thisuser.swapped=true; thisuser.swapped=true;
document.getElementById("loading").classList.remove("doneloading"); const loading=document.getElementById("loading") as HTMLDivElement;
document.getElementById("loading").classList.add("loading"); loading.classList.remove("doneloading");
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();
document.getElementById("loading").classList.add("doneloading"); loading.classList.add("doneloading");
document.getElementById("loading").classList.remove("loading"); loading.classList.remove("loading");
console.log("done loading") console.log("done loading")
}); });
@ -81,12 +82,12 @@ function showAccountSwitcher(){
document.body.append(table); document.body.append(table);
} }
{ {
const userinfo=document.getElementById("userinfo"); const userinfo=document.getElementById("userinfo") as HTMLDivElement;
userinfo.addEventListener("click",_=>{ userinfo.addEventListener("click",_=>{
_.stopImmediatePropagation(); _.stopImmediatePropagation();
showAccountSwitcher(); showAccountSwitcher();
}) })
const switchaccounts=document.getElementById("switchaccounts"); const switchaccounts=document.getElementById("switchaccounts") as HTMLDivElement;
switchaccounts.addEventListener("click",_=>{ switchaccounts.addEventListener("click",_=>{
_.stopImmediatePropagation(); _.stopImmediatePropagation();
showAccountSwitcher(); showAccountSwitcher();
@ -100,13 +101,14 @@ try{
thisuser.initwebsocket().then(_=>{ thisuser.initwebsocket().then(_=>{
thisuser.loaduser(); thisuser.loaduser();
thisuser.init(); thisuser.init();
document.getElementById("loading").classList.add("doneloading"); const loading=document.getElementById("loading") as HTMLDivElement;
document.getElementById("loading").classList.remove("loading"); loading.classList.add("doneloading");
loading.classList.remove("loading");
console.log("done loading") console.log("done loading")
}); });
}catch(e){ }catch(e){
console.error(e); console.error(e);
document.getElementById("load-desc").textContent="Account unable to start"; (document.getElementById("load-desc") as HTMLSpanElement).textContent="Account unable to start";
thisuser=new Localuser(-1); thisuser=new Localuser(-1);
} }
@ -114,19 +116,24 @@ try{
{ {
const menu=new Contextmenu("create rightclick"); const menu=new Contextmenu("create rightclick");
menu.addbutton("Create channel",function(){ menu.addbutton("Create channel",function(){
thisuser.lookingguild.createchannels(); if(thisuser.lookingguild){
thisuser.lookingguild.createchannels();
}
},null,_=>{return thisuser.isAdmin()}) },null,_=>{return thisuser.isAdmin()})
menu.addbutton("Create category",function(){ menu.addbutton("Create category",function(){
thisuser.lookingguild.createcategory(); if(thisuser.lookingguild){
thisuser.lookingguild.createcategory();
}
},null,_=>{return thisuser.isAdmin()}) },null,_=>{return thisuser.isAdmin()})
menu.bind(document.getElementById("channels")) menu.bind(document.getElementById("channels") as HTMLDivElement)
} }
const pasteimage=document.getElementById("pasteimage"); const pasteimage=document.getElementById("pasteimage") as HTMLDivElement;
let replyingto=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;
channel.typingstart(); channel.typingstart();
if(event.key === "Enter"&&!event.shiftKey){ if(event.key === "Enter"&&!event.shiftKey){
event.preventDefault(); event.preventDefault();
@ -136,19 +143,20 @@ async function enter(event){
}else{ }else{
replyingto= thisuser.channelfocus.replyingto; replyingto= thisuser.channelfocus.replyingto;
let replying=replyingto; let replying=replyingto;
if(replyingto){ 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,
replyingto:replying, embeds:[],
replyingto:replying
}) })
thisuser.channelfocus.makereplybox(); thisuser.channelfocus.makereplybox();
} }
while(images.length!=0){ while(images.length!=0){
images.pop(); images.pop();
pasteimage.removeChild(imageshtml.pop()); pasteimage.removeChild(imageshtml.pop() as HTMLElement);
} }
typebox.innerHTML=""; typebox.innerHTML="";
return; return;
@ -175,11 +183,13 @@ function getguildinfo(){
*/ */
const images:Blob[]=[]; const images:Blob[]=[];
const imageshtml=[]; const imageshtml:HTMLElement[]=[];
import { File } from "./file.js"; import { File } from "./file.js";
import { MarkDown } from "./markdown.js"; import { MarkDown } from "./markdown.js";
import { Message } from "./message.js";
document.addEventListener('paste', async (e) => { document.addEventListener('paste', async (e) => {
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();
@ -195,19 +205,19 @@ setTheme();
function userSettings(){ function userSettings(){
thisuser.showusersettings(); thisuser.showusersettings();
} }
document.getElementById("settings").onclick=userSettings; (document.getElementById("settings") as HTMLImageElement).onclick=userSettings;
if(mobile){ if(mobile){
document.getElementById("channelw").onclick=function(){ (document.getElementById("channelw") as HTMLDivElement).onclick=()=>{
(document.getElementById("channels").parentNode as HTMLElement).classList.add("collapse"); ((document.getElementById("channels") as HTMLDivElement).parentNode as HTMLElement).classList.add("collapse");
document.getElementById("servertd").classList.add("collapse"); (document.getElementById("servertd") as HTMLDivElement).classList.add("collapse");
document.getElementById("servers").classList.add("collapse"); (document.getElementById("servers") as HTMLDivElement).classList.add("collapse");
} }
document.getElementById("mobileback").textContent="#"; (document.getElementById("mobileback") as HTMLDivElement).textContent="#";
document.getElementById("mobileback").onclick=function(){ (document.getElementById("mobileback") as HTMLDivElement).onclick=()=>{
(document.getElementById("channels").parentNode as HTMLElement).classList.remove("collapse"); ((document.getElementById("channels") as HTMLDivElement).parentNode as HTMLElement).classList.remove("collapse");
document.getElementById("servertd").classList.remove("collapse"); (document.getElementById("servertd") as HTMLDivElement).classList.remove("collapse");
document.getElementById("servers").classList.remove("collapse"); (document.getElementById("servers") as HTMLDivElement).classList.remove("collapse");
} }
} }

View file

@ -1,20 +1,20 @@
class InfiniteScroller{ class InfiniteScroller{
readonly getIDFromOffset:(ID:string,offset:number)=>Promise<string>; readonly getIDFromOffset:(ID:string,offset:number)=>Promise<string|undefined>;
readonly getHTMLFromID:(ID:string)=>Promise<HTMLElement>; readonly getHTMLFromID:(ID:string)=>Promise<HTMLElement>;
readonly destroyFromID:(ID:string)=>Promise<boolean>; readonly destroyFromID:(ID:string)=>Promise<boolean>;
readonly reachesBottom:()=>void; readonly reachesBottom:()=>void;
private readonly minDist=3000; private readonly minDist=3000;
private readonly maxDist=8000; private readonly maxDist=8000;
HTMLElements:[HTMLElement,string][]=[]; HTMLElements:[HTMLElement,string][]=[];
div:HTMLDivElement; div:HTMLDivElement|null;
scroll:HTMLDivElement; scroll:HTMLDivElement|null;
constructor(getIDFromOffset:InfiniteScroller["getIDFromOffset"],getHTMLFromID:InfiniteScroller["getHTMLFromID"],destroyFromID:InfiniteScroller["destroyFromID"],reachesBottom:InfiniteScroller["reachesBottom"]=()=>{}){ constructor(getIDFromOffset:InfiniteScroller["getIDFromOffset"],getHTMLFromID:InfiniteScroller["getHTMLFromID"],destroyFromID:InfiniteScroller["destroyFromID"],reachesBottom:InfiniteScroller["reachesBottom"]=()=>{}){
this.getIDFromOffset=getIDFromOffset; this.getIDFromOffset=getIDFromOffset;
this.getHTMLFromID=getHTMLFromID; this.getHTMLFromID=getHTMLFromID;
this.destroyFromID=destroyFromID; this.destroyFromID=destroyFromID;
this.reachesBottom=reachesBottom; this.reachesBottom=reachesBottom;
} }
timeout:NodeJS.Timeout; timeout:NodeJS.Timeout|null;
async getDiv(initialId:string,bottom=true):Promise<HTMLDivElement>{ async getDiv(initialId:string,bottom=true):Promise<HTMLDivElement>{
const div=document.createElement("div"); const div=document.createElement("div");
div.classList.add("messagecontainer"); div.classList.add("messagecontainer");
@ -52,6 +52,7 @@ class InfiniteScroller{
scrollTop:number; scrollTop:number;
needsupdate=true; needsupdate=true;
async updatestuff(){ async updatestuff(){
if(!this.scroll) return;
this.timeout=null; this.timeout=null;
this.scrollBottom = this.scroll.scrollHeight - this.scroll.scrollTop - this.scroll.clientHeight; this.scrollBottom = this.scroll.scrollHeight - this.scroll.scrollTop - this.scroll.clientHeight;
this.scrollTop=this.scroll.scrollTop; this.scrollTop=this.scroll.scrollTop;
@ -67,6 +68,7 @@ class InfiniteScroller{
//this.watchForChange(); //this.watchForChange();
} }
async firstElement(id:string){ async firstElement(id:string){
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]);
@ -87,14 +89,21 @@ class InfiniteScroller{
} }
} }
private async watchForTop():Promise<boolean>{ private async watchForTop():Promise<boolean>{
if(!this.scroll) return false;
let again=false; let again=false;
if(this.scrollTop===0){ if(this.scrollTop===0){
this.scrollTop=1; this.scrollTop=1;
this.scroll.scrollTop=1; this.scroll.scrollTop=1;
} }
if(this.scrollTop<this.minDist){ if(this.scrollTop<this.minDist){
const previd=this.HTMLElements.at(0)[1]; let nextid:string|undefined;
const nextid=await this.getIDFromOffset(previd,1); const firstelm=this.HTMLElements.at(0);
if(firstelm){
const previd=firstelm[1];
nextid=await this.getIDFromOffset(previd,1);
}
if(!nextid){ if(!nextid){
}else{ }else{
@ -112,10 +121,13 @@ class InfiniteScroller{
} }
if(this.scrollTop>this.maxDist){ if(this.scrollTop>this.maxDist){
again=true;
const html=this.HTMLElements.shift(); const html=this.HTMLElements.shift();
await this.destroyFromID(html[1]); if(html){
this.scrollTop-=60; again=true;
await this.destroyFromID(html[1]);
this.scrollTop-=60;
}
} }
if(again){ if(again){
await this.watchForTop(); await this.watchForTop();
@ -123,13 +135,17 @@ class InfiniteScroller{
return again; return again;
} }
async watchForBottom():Promise<boolean>{ async watchForBottom():Promise<boolean>{
if(!this.scroll) return false;
let again=false; let again=false;
const scrollBottom = this.scrollBottom; const scrollBottom = this.scrollBottom;
if(scrollBottom<this.minDist){ if(scrollBottom<this.minDist){
let nextid:string|undefined;
const previd=this.HTMLElements.at(-1)[1]; const lastelm=this.HTMLElements.at(-1);
const nextid=await this.getIDFromOffset(previd,-1); if(lastelm){
const previd=lastelm[1];
nextid=await this.getIDFromOffset(previd,-1);
}
if(!nextid){ if(!nextid){
}else{ }else{
again=true; again=true;
@ -144,10 +160,13 @@ class InfiniteScroller{
} }
if(scrollBottom>this.maxDist){ if(scrollBottom>this.maxDist){
again=true;
const html=this.HTMLElements.pop(); const html=this.HTMLElements.pop();
await this.destroyFromID(html[1]); if(html){
this.scrollBottom-=60; await this.destroyFromID(html[1]);
this.scrollBottom-=60;
again=true;
}
} }
if(again){ if(again){
await this.watchForBottom(); await this.watchForBottom();
@ -158,11 +177,11 @@ class InfiniteScroller{
try{ try{
if(this.currrunning){ if(this.currrunning){
return; return false;
}else{ }else{
this.currrunning=true; this.currrunning=true;
} }
if(!this.div){this.currrunning=false;return} if(!this.div){this.currrunning=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(null===this.timeout&&changed){
@ -174,9 +193,10 @@ class InfiniteScroller{
}catch(e){ }catch(e){
console.error(e); console.error(e);
} }
return false;
} }
async focus(id:string,flash=true){ async focus(id:string,flash=true){
let element:HTMLElement; let element:HTMLElement|undefined;
for(const thing of this.HTMLElements){ for(const thing of this.HTMLElements){
if(thing[1]===id){ if(thing[1]===id){
element=thing[0]; element=thing[0];
@ -213,7 +233,9 @@ class InfiniteScroller{
await this.destroyFromID(thing[1]); await this.destroyFromID(thing[1]);
} }
this.HTMLElements=[]; this.HTMLElements=[];
clearTimeout(this.timeout); if(this.timeout){
clearTimeout(this.timeout);
}
if(this.div){ if(this.div){
this.div.remove(); this.div.remove();
} }

View file

@ -130,7 +130,7 @@ type userjson={
public_flags: number, public_flags: number,
avatar: string, avatar: string,
accent_color: number, accent_color: number,
banner: string, banner?: string,
bio: string, bio: string,
bot: boolean, bot: boolean,
premium_since: string, premium_since: string,
@ -157,10 +157,10 @@ type memberjson= {
last_message_id?: boolean//What??? last_message_id?: boolean//What???
} }
type emojijson={ type emojijson={
name:string, name:string,
id?:string, id?:string,
animated?:boolean animated?:boolean
} }
type guildjson={ type guildjson={
application_command_counts: {[key:string]:number}, application_command_counts: {[key:string]:number},
@ -290,8 +290,8 @@ type filejson={
id:string, id:string,
filename:string, filename:string,
content_type:string, content_type:string,
width:number, width?:number,
height:number, height?:number,
proxy_url:string|undefined, proxy_url:string|undefined,
url:string, url:string,
size:number size:number

View file

@ -365,7 +365,7 @@ class Localuser{
const guild=SnowFlake.getSnowFlakeFromID(temp.d.guild_id,Guild).getObject(); const guild=SnowFlake.getSnowFlakeFromID(temp.d.guild_id,Guild).getObject();
let thing:Member|{id:string}; let thing:Member|{id:string};
if(temp.d.member){ if(temp.d.member){
thing=await Member.new(temp.d.member,guild); thing=await Member.new(temp.d.member,guild) as Member;
}else{ }else{
thing={id:temp.d.user_id} thing={id:temp.d.user_id}
} }
@ -701,6 +701,7 @@ class Localuser{
const guild=this.guildids.get(typing.d.guild_id); const guild=this.guildids.get(typing.d.guild_id);
if(!guild) return; if(!guild) return;
const memb=await Member.new(typing.d.member,guild); const memb=await Member.new(typing.d.member,guild);
if(!memb) return;
if(memb.id===this.user.id){ if(memb.id===this.user.id){
console.log("you is typing") console.log("you is typing")
return; return;
@ -844,7 +845,7 @@ class Localuser{
}); });
const bclear=settingsLeft.addButtonInput("Clear banner","Clear",()=>{ const bclear=settingsLeft.addButtonInput("Clear banner","Clear",()=>{
bfile=null; bfile=null;
hypouser.banner = null; hypouser.banner = undefined;
settingsLeft.changed(); settingsLeft.changed();
regen(); regen();
}) })

View file

@ -57,7 +57,7 @@ class MarkDown{
if(first){ if(first){
i--; i--;
} }
let element=null; let element:HTMLElement;
let keepys=""; let keepys="";
if(txt[i+1]==="#"){ if(txt[i+1]==="#"){
@ -92,21 +92,24 @@ class MarkDown{
if(!first&&!stdsize){ if(!first&&!stdsize){
span.appendChild(document.createElement("br")); span.appendChild(document.createElement("br"));
} }
const build=[]; const build:string[]=[];
for(;txt[i]!=="\n"&&txt[i]!==undefined;i++){ for(;txt[i]!=="\n"&&txt[i]!==undefined;i++){
build.push(txt[i]); build.push(txt[i]);
} }
if(stdsize){ try{
element=document.createElement("span"); if(stdsize){
element=document.createElement("span");
}else continue;
if(keep){
element.append(keepys);
}
element.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
span.append(element);
}finally{
i-=1;
console.log(txt[i]);
continue;
} }
if(keep){
element.append(keepys);
}
element.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
span.append(element);
i-=1;
console.log(txt[i]);
continue;
} }
if(first){ if(first){
i++; i++;
@ -194,7 +197,7 @@ class MarkDown{
count++; count++;
} }
} }
let build=[]; let build:string[]=[];
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++){
@ -248,7 +251,7 @@ class MarkDown{
count++; count++;
} }
} }
let build=[]; let build:string[]=[];
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++){
@ -295,7 +298,7 @@ class MarkDown{
if(txt[i]==="~"&&txt[i+1]==="~"){ if(txt[i]==="~"&&txt[i+1]==="~"){
let count=2; let count=2;
let build=[]; let build:string[]=[];
let find=0; let find=0;
let j=i+2; let j=i+2;
for(;txt[j]!==undefined&&find!==count;j++){ for(;txt[j]!==undefined&&find!==count;j++){
@ -325,7 +328,7 @@ class MarkDown{
} }
if(txt[i]==="|"&&txt[i+1]==="|"){ if(txt[i]==="|"&&txt[i+1]==="|"){
let count=2; let count=2;
let build=[]; let build:string[]=[];
let find=0; let find=0;
let j=i+2; let j=i+2;
for(;txt[j]!==undefined&&find!==count;j++){ for(;txt[j]!==undefined&&find!==count;j++){
@ -372,8 +375,7 @@ class MarkDown{
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]))?>$/);
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("");
@ -449,19 +451,23 @@ class MarkDown{
} }
}; };
box.onpaste=_=>{ box.onpaste=_=>{
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;
box.onkeyup(new KeyboardEvent("_")) box.onkeyup(new KeyboardEvent("_"))
} }
} }
boxupdate(box:HTMLElement){ boxupdate(box:HTMLElement){
var restore = saveCaretPosition(box); const restore = saveCaretPosition(box);
box.innerHTML=""; box.innerHTML="";
box.append(this.makeHTML({keep:true})) box.append(this.makeHTML({keep:true}))
restore(); if(restore){
restore();
}
} }
static gatherBoxText(element:HTMLElement){ static gatherBoxText(element:HTMLElement){
if(element.tagName.toLowerCase()==="img"){ if(element.tagName.toLowerCase()==="img"){
@ -492,11 +498,13 @@ 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(); var selection = window.getSelection();
if(!selection) return;
var range = selection.getRangeAt(0); var range = selection.getRangeAt(0);
range.setStart( context, 0 ); range.setStart( context, 0 );
var len = range.toString().length; var len = range.toString().length;
return function restore(){ return function restore(){
if(!selection) return;
var pos = getTextNodeAtPosition(context, len); var pos = getTextNodeAtPosition(context, len);
selection.removeAllRanges(); selection.removeAllRanges();
var range = new Range(); var range = new Range();
@ -509,6 +517,7 @@ function saveCaretPosition(context){
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) { var treeWalker = document.createTreeWalker(root, NODE_TYPE, function next(elem) {
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

View file

@ -28,8 +28,10 @@ class Member{
private constructor(memberjson:memberjson,owner:Guild){ private constructor(memberjson:memberjson,owner:Guild){
if(User.userids[memberjson.id]){ if(User.userids[memberjson.id]){
this.user=User.userids[memberjson.id]; this.user=User.userids[memberjson.id];
}else{ }else if(memberjson.user){
this.user=new User(memberjson.user,owner.localuser); this.user=new User(memberjson.user,owner.localuser);
}else{
throw new Error("Missing user object of this member");
} }
this.owner=owner; this.owner=owner;
for(const thing of Object.keys(memberjson)){ for(const thing of Object.keys(memberjson)){
@ -60,12 +62,14 @@ class Member{
get info(){ get info(){
return this.owner.info; return this.owner.info;
} }
static async new(memberjson:memberjson,owner:Guild):Promise<Member>{ static async new(memberjson:memberjson,owner:Guild):Promise<Member|undefined>{
let user:User; let user:User;
if(User.userids[memberjson.id]){ if(User.userids[memberjson.id]){
user=User.userids[memberjson.id]; user=User.userids[memberjson.id];
}else{ }else if(memberjson.user){
user=new User(memberjson.user,owner.localuser); user=new User(memberjson.user,owner.localuser);
}else{
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)
@ -88,9 +92,7 @@ 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);
let res:Function; const promise=new Promise<Member|undefined>( async res=>{
const promise=new Promise<Member|undefined>(r=>{res=r})
user.members.set(guild,promise);
const membjson=await membpromise; const membjson=await membpromise;
if(membjson===undefined){ if(membjson===undefined){
res(undefined); res(undefined);
@ -103,6 +105,8 @@ class Member{
res(member); res(member);
return member; return member;
} }
})
user.members.set(guild,promise);
} }
if(maybe instanceof Promise){ if(maybe instanceof Promise){
return await maybe; return await maybe;
@ -110,7 +114,7 @@ class Member{
return maybe return maybe
} }
} }
public getPresence(presence:presencejson|null){ public getPresence(presence:presencejson|undefined){
this.user.getPresence(presence); this.user.getPresence(presence);
} }
/** /**

View file

@ -8,7 +8,7 @@ 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 { messagejson } from "./jsontypes.js"; import { memberjson, messagejson } from "./jsontypes.js";
import {Emoji} from "./emoji.js"; import {Emoji} from "./emoji.js";
class Message{ class Message{
@ -40,8 +40,8 @@ class Message{
return this.weakdiv?.deref(); return this.weakdiv?.deref();
} }
//*/ //*/
div:HTMLDivElement; div:HTMLDivElement|undefined;
member:Member; member:Member|undefined;
reactions:messagejson["reactions"]; reactions:messagejson["reactions"];
get id(){ get id(){
return this.snowflake.id; return this.snowflake.id;
@ -50,12 +50,6 @@ class Message{
this.del=new Promise(_=>{this.resolve=_}); this.del=new Promise(_=>{this.resolve=_});
Message.setupcmenu(); Message.setupcmenu();
} }
static async wipeChanel(){
this.resolve();
document.getElementById("messages").innerHTML="";
await Promise.allSettled([this.resolve]);
this.del=new Promise(_=>{this.resolve=_})
}
static setupcmenu(){ static setupcmenu(){
Message.contextmenu.addbutton("Copy raw text",function(this:Message){ Message.contextmenu.addbutton("Copy raw text",function(this:Message){
navigator.clipboard.writeText(this.content.rawString); navigator.clipboard.writeText(this.content.rawString);
@ -74,9 +68,9 @@ 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"))["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")); markdown.boxupdate(document.getElementById("typebox") as HTMLDivElement);
},null,_=>{return _.author.id===_.localuser.user.id}); },null,_=>{return _.author.id===_.localuser.user.id});
Message.contextmenu.addbutton("Delete message",function(this:Message){ Message.contextmenu.addbutton("Delete message",function(this:Message){
this.delete(); this.delete();
@ -86,7 +80,7 @@ class Message{
this.owner=owner; this.owner=owner;
this.headers=this.owner.headers; this.headers=this.owner.headers;
this.giveData(messagejson); this.giveData(messagejson);
this.owner.messages.set(this.id,this);
} }
reactionToggle(emoji:string|Emoji){ reactionToggle(emoji:string|Emoji){
@ -125,7 +119,9 @@ class Message{
this.snowflake=new SnowFlake(messagejson.id,this); this.snowflake=new SnowFlake(messagejson.id,this);
continue; continue;
}else if(thing==="member"){ }else if(thing==="member"){
Member.new(messagejson.member,this.guild).then(_=>{this.member=_}); Member.new(messagejson.member as memberjson,this.guild).then(_=>{
this.member=_ as Member;
});
continue; continue;
}else if(thing ==="embeds"){ }else if(thing ==="embeds"){
this.embeds=[]; this.embeds=[];
@ -185,7 +181,7 @@ class Message{
if(!this.div) return; if(!this.div) return;
try{ try{
this.div.remove(); this.div.remove();
this.div=null; this.div=undefined;
}catch(e){ }catch(e){
console.error(e) console.error(e)
} }
@ -222,23 +218,35 @@ class Message{
deleteEvent(){ deleteEvent(){
if(this.div){ if(this.div){
this.div.innerHTML=""; this.div.innerHTML="";
this.div=null; this.div=undefined;
}
const prev=this.channel.idToPrev.get(this.snowflake) as SnowFlake<Message> | null;
const next=this.channel.idToNext.get(this.snowflake) as SnowFlake<Message> | null;
if(prev){
this.channel.idToPrev.delete(this.snowflake)
}
if(next){
this.channel.idToNext.delete(this.snowflake)
}
if(prev&&next){
this.channel.idToPrev.set(next,prev);
this.channel.idToNext.set(prev,next);
} }
const prev=this.channel.idToPrev.get(this.snowflake);
const next=this.channel.idToNext.get(this.snowflake);
this.channel.idToNext.set(prev,next);
this.channel.idToPrev.set(next,prev);
this.channel.messageids.delete(this.snowflake); this.channel.messageids.delete(this.snowflake);
const regen=prev.getObject(); if(prev&&prev.getObject()){
if(regen){ prev.getObject().generateMessage();
regen.generateMessage();
} }
if(this.channel.lastmessage===this){ if(this.channel.lastmessage===this){
this.channel.lastmessage=prev.getObject(); if(prev){
this.channel.lastmessage=prev.getObject();
}else{
this.channel.lastmessage=undefined;
}
} }
} }
reactdiv:WeakRef<HTMLDivElement>; reactdiv:WeakRef<HTMLDivElement>;
generateMessage(premessage:Message=null){ generateMessage(premessage:Message|undefined=undefined){
if(!this.div) return;
if(!premessage){ if(!premessage){
premessage=this.channel.idToPrev.get(this.snowflake)?.getObject(); premessage=this.channel.idToPrev.get(this.snowflake)?.getObject();
} }
@ -469,13 +477,11 @@ class Message{
} }
} }
} }
buildhtml(premessage:Message){ buildhtml(premessage:Message|undefined=undefined){
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;}
try{ try{
//premessage??=messages.lastChild;
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);
}catch(e){ }catch(e){

View file

@ -38,7 +38,7 @@ class Role{
get localuser():Localuser{ get localuser():Localuser{
return this.guild.localuser; return this.guild.localuser;
} }
getColor():string{ getColor():string|null{
if(this.color===0){return null}; if(this.color===0){return null};
return `#${this.color.toString(16)}`; return `#${this.color.toString(16)}`;
} }

View file

@ -32,7 +32,7 @@ class SnowFlake<x extends WeakKey>{
} }
/** /**
* Just to clarify bc TS, it returns a SnowFlake\<type> which is what you entered with the type parameter * Just to clarify bc TS, it returns a SnowFlake\<type> which is what you entered with the type parameter
* * @deprecated
**/ **/
static getSnowFlakeFromID<T extends {}>(id:string,type: abstract new(...args: never) => T): SnowFlake<T>{ static getSnowFlakeFromID<T extends {}>(id:string,type: abstract new(...args: never) => T): SnowFlake<T>{
if(!SnowFlake.SnowFlakes.get(type)){ if(!SnowFlake.SnowFlakes.get(type)){
@ -56,6 +56,11 @@ class SnowFlake<x extends WeakKey>{
return snowflake; return snowflake;
} }
} }
/**
* @deprecated
*
*
*/
static hasSnowFlakeFromID(id:string,type:any){ static hasSnowFlakeFromID(id:string,type:any){
if(!SnowFlake.SnowFlakes.get(type)){ if(!SnowFlake.SnowFlakes.get(type)){
return false; return false;

View file

@ -20,7 +20,7 @@ class User{
bot:boolean; bot:boolean;
public_flags: number; public_flags: number;
accent_color: number; accent_color: number;
banner: string|null|undefined; banner: string|undefined;
hypotheticalbanner:boolean; hypotheticalbanner:boolean;
premium_since: string; premium_since: string;
premium_type: number; premium_type: number;
@ -46,7 +46,7 @@ class User{
badge_ids:this.badge_ids badge_ids:this.badge_ids
},this.owner) },this.owner)
} }
public getPresence(presence:presencejson|null){ public getPresence(presence:presencejson|undefined){
if(presence){ if(presence){
this.setstatus(presence.status); this.setstatus(presence.status);
}else{ }else{
@ -183,7 +183,7 @@ class User{
this.changepfp(json.avatar); this.changepfp(json.avatar);
} }
} }
bind(html:HTMLElement,guild:Guild=null,error=true){ bind(html:HTMLElement,guild:Guild|null=null,error=true){
if(guild&&guild.id!=="@me"){ if(guild&&guild.id!=="@me"){
Member.resolveMember(this,guild).then(_=>{ Member.resolveMember(this,guild).then(_=>{
if(_===undefined&&error){ if(_===undefined&&error){
@ -193,12 +193,19 @@ class User{
html.after(error); html.after(error);
return; return;
} }
_.bind(html); if(_){
_.bind(html);
}
}).catch(_=>{ }).catch(_=>{
console.log(_) console.log(_)
}); });
} }
this.profileclick(html,guild); if(guild){
this.profileclick(html,guild);
}else{
this.profileclick(html);
}
User.contextmenu.bind(html,this); User.contextmenu.bind(html,this);
} }
static async resolve(id:string,localuser:Localuser){ static async resolve(id:string,localuser:Localuser){
@ -230,7 +237,7 @@ class User{
createjankpromises(){ createjankpromises(){
new Promise(_=>{}) new Promise(_=>{})
} }
async buildprofile(x:number,y:number,guild:Guild=null){ async buildprofile(x:number,y:number,guild:Guild|null=null){
if(Contextmenu.currentmenu!=""){ if(Contextmenu.currentmenu!=""){
Contextmenu.currentmenu.remove(); Contextmenu.currentmenu.remove();
} }
@ -271,18 +278,20 @@ class User{
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);
const badge=document.createElement(badgejson.link?"a":"div"); if(badgejson){
badge.classList.add("badge") const badge=document.createElement(badgejson.link?"a":"div");
const img=document.createElement("img"); badge.classList.add("badge")
img.src=badgejson.icon; const img=document.createElement("img");
badge.append(img); img.src=badgejson.icon;
const span=document.createElement("span"); badge.append(img);
span.textContent=badgejson.description; const span=document.createElement("span");
badge.append(span); span.textContent=badgejson.description;
if(badge instanceof HTMLAnchorElement){ badge.append(span);
badge.href=badgejson.link; if(badge instanceof HTMLAnchorElement){
badge.href=badgejson.link;
}
badgediv.append(badge);
} }
badgediv.append(badge);
} }
})() })()
{ {
@ -341,7 +350,7 @@ class User{
} }
return div; return div;
} }
profileclick(obj:HTMLElement,guild:Guild){ profileclick(obj:HTMLElement,guild:Guild|undefined=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();