Merge branch 'main' of https://github.com/DEVTomatoCake/JankClient into jank/connection-list-dev-portal

This commit is contained in:
TomatoCake
2024-07-21 10:57:33 +02:00
27 changed files with 1482 additions and 1229 deletions

View File

@@ -3,16 +3,15 @@ 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 { Fullscreen } from "./fullscreen.js"; import { Fullscreen } from "./fullscreen.js";
import { markdown } from "./markdown.js";
import { Permissions } from "./permissions.js"; import { Permissions } from "./permissions.js";
import { Settings, RoleList } from "./settings.js"; import { Settings, RoleList } from "./settings.js";
import { InfiniteScroller } from "./infiniteScroller.js";
Settings; Settings;
class Channel { class Channel {
editing; editing;
type; type;
owner; owner;
headers; headers;
messages;
name; name;
id; id;
parent_id; parent_id;
@@ -35,6 +34,9 @@ class Channel {
allthewayup; allthewayup;
static contextmenu = new Contextmenu("channel menu"); static contextmenu = new Contextmenu("channel menu");
replyingto; replyingto;
infinite;
idToPrev = {};
idToNext = {};
static setupcontextmenu() { static setupcontextmenu() {
this.contextmenu.addbutton("Copy channel id", function () { this.contextmenu.addbutton("Copy channel id", function () {
console.log(this); console.log(this);
@@ -68,6 +70,33 @@ class Channel {
return order; return order;
}); });
} }
setUpInfiniteScroller() {
const ids = {};
this.infinite = new InfiniteScroller(async function (id, offset) {
if (offset === 1) {
if (this.idToPrev[id]) {
return this.idToPrev[id];
}
else {
await this.grabmoremessages(id);
return this.idToPrev[id];
}
}
else {
return this.idToNext[id];
}
}.bind(this), function (id) {
let res;
const promise = new Promise(_ => { res = _; });
const html = this.messageids[id].buildhtml(this.messageids[this.idToPrev[id]], promise);
ids[id] = res;
return html;
}.bind(this), async function (id) {
ids[id]();
delete ids[id];
return true;
}.bind(this), this.readbottom.bind(this));
}
constructor(JSON, owner) { constructor(JSON, owner) {
if (JSON === -1) { if (JSON === -1) {
return; return;
@@ -76,7 +105,6 @@ class Channel {
this.type = JSON.type; this.type = JSON.type;
this.owner = owner; this.owner = owner;
this.headers = this.owner.headers; this.headers = this.owner.headers;
this.messages = [];
this.name = JSON.name; this.name = JSON.name;
this.id = JSON.id; this.id = JSON.id;
this.parent_id = JSON.parent_id; this.parent_id = JSON.parent_id;
@@ -100,6 +128,7 @@ class Channel {
this.position = JSON.position; this.position = JSON.position;
this.lastreadmessageid = null; this.lastreadmessageid = null;
this.lastmessageid = JSON.last_message_id; this.lastmessageid = JSON.last_message_id;
this.setUpInfiniteScroller();
} }
isAdmin() { isAdmin() {
return this.guild.isAdmin(); return this.guild.isAdmin();
@@ -487,7 +516,7 @@ class Channel {
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;
const prom = Message.wipeChanel(); const prom = this.infinite.delete();
await this.putmessages(); await this.putmessages();
await prom; await prom;
if (id !== Channel.genid) { if (id !== Channel.genid) {
@@ -501,7 +530,7 @@ class Channel {
document.getElementById("typebox").disabled = !this.canMessage; document.getElementById("typebox").disabled = !this.canMessage;
} }
async putmessages() { async putmessages() {
if (this.messages.length >= 100 || this.allthewayup) { if (this.allthewayup) {
return; return;
} }
; ;
@@ -512,11 +541,16 @@ class Channel {
if (response.length !== 100) { if (response.length !== 100) {
this.allthewayup = true; this.allthewayup = true;
} }
let prev = undefined;
for (const thing of response) { for (const thing of response) {
const messager = new Message(thing, this); const message = new Message(thing, this);
if (this.messageids[messager.id] === undefined) { if (prev) {
this.messageids[messager.id] = messager; this.idToNext[message.id] = prev.id;
this.messages.push(messager); this.idToPrev[prev.id] = message.id;
}
prev = message;
if (this.messageids[message.id] === undefined) {
this.messageids[message.id] = message;
} }
} }
} }
@@ -529,20 +563,18 @@ class Channel {
} }
this.children = build; this.children = build;
} }
async grabmoremessages() { async grabmoremessages(id) {
if (this.messages.length === 0 || this.allthewayup) { if (this.allthewayup) {
return; return;
} }
const out = this; await fetch(this.info.api.toString() + "/channels/" + this.id + "/messages?before=" + id + "&limit=100", {
await fetch(this.info.api.toString() + "/channels/" + this.id + "/messages?before=" + this.messages[this.messages.length - 1].id + "&limit=100", {
headers: this.headers headers: this.headers
}).then((j) => { return j.json(); }).then(response => { }).then((j) => { return j.json(); }).then(response => {
//messages.innerHTML = '';
//response.reverse()
let next; let next;
if (response.length === 0) { if (response.length === 0) {
out.allthewayup = true; this.allthewayup = true;
} }
let previd = id;
for (const i in response) { for (const i in response) {
let messager; let messager;
if (!next) { if (!next) {
@@ -558,10 +590,11 @@ class Channel {
next = undefined; next = undefined;
console.log("ohno", +i + 1); console.log("ohno", +i + 1);
} }
if (out.messageids[messager.id] == undefined) { if (this.messageids[messager.id] === undefined) {
out.messageids[messager.id] = messager; this.idToNext[messager.id] = previd;
out.buildmessage(messager, next); this.idToPrev[previd] = messager.id;
out.messages.push(messager); previd = messager.id;
this.messageids[messager.id] = messager;
} }
else { else {
console.log("How???"); console.log("How???");
@@ -576,30 +609,9 @@ class Channel {
document.getElementById("messages").prepend(built); document.getElementById("messages").prepend(built);
} }
buildmessages() { buildmessages() {
for (const i in this.messages) { const messages = document.getElementById("channelw");
const prev = this.messages[(+i) + 1]; messages.innerHTML = "";
const built = this.messages[i].buildhtml(prev); messages.append(this.infinite.getDiv(this.lastmessageid));
document.getElementById("messages").prepend(built);
if (prev) {
const prevDate = new Date(prev.timestamp);
const currentDate = new Date(this.messages[i].timestamp);
if (prevDate.toLocaleDateString() != currentDate.toLocaleDateString()) {
const dateContainer = document.createElement("div");
dateContainer.classList.add("replyflex");
const line = document.createElement("hr");
line.classList.add("reply");
dateContainer.appendChild(line);
const date = document.createElement("span");
date.textContent = currentDate.toLocaleDateString(undefined, { weekday: "long", year: "numeric", month: "long", day: "numeric" });
dateContainer.appendChild(date);
const line2 = document.createElement("hr");
line2.classList.add("reply");
dateContainer.appendChild(line2);
document.getElementById("messages").prepend(dateContainer);
}
}
}
document.getElementById("messagecontainer").scrollTop = document.getElementById("messagecontainer").scrollHeight;
} }
updateChannel(JSON) { updateChannel(JSON) {
this.type = JSON.type; this.type = JSON.type;
@@ -694,7 +706,10 @@ class Channel {
return; return;
} }
const messagez = new Message(messagep.d, this); const messagez = new Message(messagep.d, this);
this.idToNext[this.lastmessageid] = messagez.id;
this.idToPrev[messagez.id] = this.lastmessageid;
this.lastmessageid = messagez.id; this.lastmessageid = messagez.id;
this.messageids[messagez.id] = messagez;
if (messagez.author === this.localuser.user) { if (messagez.author === this.localuser.user) {
this.lastreadmessageid = messagez.id; this.lastreadmessageid = messagez.id;
if (this.myhtml) { if (this.myhtml) {
@@ -707,16 +722,7 @@ class Channel {
} }
} }
this.guild.unreads(); this.guild.unreads();
this.messages.unshift(messagez); this.infinite.addedBottom();
const scrolly = document.getElementById("messagecontainer");
this.messageids[messagez.id] = messagez;
if (this.localuser.lookingguild.prevchannel === this) {
var shouldScroll = scrolly.scrollTop + scrolly.clientHeight > scrolly.scrollHeight - 20;
document.getElementById("messages").appendChild(messagez.buildhtml(this.messages[1]));
}
if (shouldScroll) {
scrolly.scrollTop = scrolly.scrollHeight;
}
if (messagez.author === this.localuser.user) { if (messagez.author === this.localuser.user) {
return; return;
} }
@@ -738,10 +744,10 @@ class Channel {
if (!("Notification" in window)) { if (!("Notification" in window)) {
} }
else if (Notification.permission === "granted") { else if (Notification.permission === "granted") {
let noticontent = markdown(message.content).textContent; let noticontent = message.content.textContent;
if (message.embeds[0]) { if (message.embeds[0]) {
noticontent ||= message.embeds[0].json.title; noticontent ||= message.embeds[0].json.title;
noticontent ||= markdown(message.embeds[0].json.description).textContent; noticontent ||= message.content.textContent;
} }
noticontent ||= "Blank Message"; noticontent ||= "Blank Message";
let imgurl = null; let imgurl = null;

View File

@@ -64,7 +64,6 @@ class Group extends Channel {
super(-1, owner); super(-1, owner);
this.owner = owner; this.owner = owner;
this.headers = this.guild.headers; this.headers = this.guild.headers;
this.messages = [];
this.name = JSON.recipients[0]?.username; this.name = JSON.recipients[0]?.username;
if (JSON.recipients[0]) { if (JSON.recipients[0]) {
this.user = new User(JSON.recipients[0], this.localuser); this.user = new User(JSON.recipients[0], this.localuser);
@@ -83,6 +82,7 @@ class Group extends Channel {
this.lastmessageid = JSON.last_message_id; this.lastmessageid = JSON.last_message_id;
this.lastmessageid ??= "0"; this.lastmessageid ??= "0";
this.mentions = 0; this.mentions = 0;
this.setUpInfiniteScroller();
} }
createguildHTML() { createguildHTML() {
const div = document.createElement("div"); const div = document.createElement("div");
@@ -102,9 +102,9 @@ class Group extends Channel {
if (this.guild !== this.localuser.lookingguild) { if (this.guild !== this.localuser.lookingguild) {
this.guild.loadGuild(); this.guild.loadGuild();
} }
const prom = Message.wipeChanel();
this.guild.prevchannel = this; this.guild.prevchannel = this;
this.localuser.channelfocus = this; this.localuser.channelfocus = this;
const prom = this.infinite.delete();
await this.putmessages(); await this.putmessages();
await prom; await prom;
if (id !== Channel.genid) { if (id !== Channel.genid) {
@@ -116,38 +116,29 @@ class Group extends Channel {
} }
messageCreate(messagep) { messageCreate(messagep) {
const messagez = new Message(messagep.d, this); const messagez = new Message(messagep.d, this);
this.idToNext[this.lastmessageid] = messagez.id;
this.idToPrev[messagez.id] = this.lastmessageid;
this.lastmessageid = messagez.id; this.lastmessageid = messagez.id;
this.messageids[messagez.id] = messagez;
if (messagez.author === this.localuser.user) { if (messagez.author === this.localuser.user) {
this.lastreadmessageid = messagez.id; this.lastreadmessageid = messagez.id;
if (this.myhtml) {
this.myhtml.classList.remove("cunread");
}
} }
this.messages.unshift(messagez); else {
const scrolly = document.getElementById("messagecontainer"); if (this.myhtml) {
this.messageids[messagez.id] = messagez; this.myhtml.classList.add("cunread");
if (this.localuser.lookingguild.prevchannel === this) {
var shouldScroll = scrolly.scrollTop + scrolly.clientHeight > scrolly.scrollHeight - 20;
document.getElementById("messages").appendChild(messagez.buildhtml(this.messages[1]));
}
if (shouldScroll) {
scrolly.scrollTop = scrolly.scrollHeight;
}
console.log(document.getElementById("channels").children);
if (this.localuser.lookingguild === this.guild) {
const channellist = document.getElementById("channels").children[0];
for (const thing of channellist.children) {
if (thing["myinfo"] === this) {
channellist.prepend(thing);
break;
}
} }
} }
this.unreads(); this.unreads();
this.infinite.addedBottom();
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;
} }
console.log(this.notification);
if (this.notification === "all") { if (this.notification === "all") {
this.notify(messagez); this.notify(messagez);
} }
@@ -185,9 +176,9 @@ class Group extends Channel {
console.log(this); console.log(this);
div.append(buildpfp); div.append(buildpfp);
sentdms.append(div); sentdms.append(div);
div.onclick = function () { div.onclick = _ => {
this["noti"].guild.loadGuild(); this.guild.loadGuild();
this["noti"].getHTML(); this.getHTML();
}; };
} }
else if (current) { else if (current) {

View File

@@ -1,4 +1,5 @@
import { Fullscreen } from "./fullscreen.js"; import { Fullscreen } from "./fullscreen.js";
import { MarkDown } from "./markdown.js";
class Embed { class Embed {
type; type;
owner; owner;
@@ -26,6 +27,18 @@ class Embed {
return document.createElement("div"); //prevent errors by giving blank div return document.createElement("div"); //prevent errors by giving blank div
} }
} }
get message() {
return this.owner;
}
get channel() {
return this.message.channel;
}
get guild() {
return this.channel.guild;
}
get localuser() {
return this.guild.localuser;
}
generateRich() { generateRich() {
console.log(this.json); console.log(this.json);
const div = document.createElement("div"); const div = document.createElement("div");
@@ -45,7 +58,7 @@ class Embed {
authorline.append(img); authorline.append(img);
} }
const a = document.createElement("a"); const a = document.createElement("a");
a.innerText = this.json.author.name; a.textContent = this.json.author.name;
if (this.json.author.url) { if (this.json.author.url) {
a.href = this.json.author.url; a.href = this.json.author.url;
} }
@@ -54,7 +67,7 @@ class Embed {
embed.append(authorline); embed.append(authorline);
} }
const title = document.createElement("a"); const title = document.createElement("a");
title.textContent = this.json.title; title.append(new MarkDown(this.json.title, this.localuser).makeHTML());
if (this.json.url) { if (this.json.url) {
title.href = this.json.url; title.href = this.json.url;
} }
@@ -62,7 +75,7 @@ class Embed {
embed.append(title); embed.append(title);
if (this.json.description) { if (this.json.description) {
const p = document.createElement("p"); const p = document.createElement("p");
p.textContent = this.json.description; p.append(new MarkDown(this.json.description, this.channel).makeHTML());
embed.append(p); embed.append(p);
} }
embed.append(document.createElement("br")); embed.append(document.createElement("br"));
@@ -72,9 +85,8 @@ 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);
let p; const p = document.createElement("p");
p = document.createElement("p"); p.append(new MarkDown(thing.value, this.channel).makeHTML());
p.textContent = thing.value;
p.classList.add("embedp"); p.classList.add("embedp");
div.append(p); div.append(p);
if (thing.inline) { if (thing.inline) {

View File

@@ -32,8 +32,10 @@ class File {
full.show(); full.show();
}; };
img.src = src; img.src = src;
img.height = this.height; if (this.width) {
img.width = this.width; img.height = this.height;
img.width = this.width;
}
console.log(this.width, this.height); console.log(this.width, this.height);
return img; return img;
} }

View File

@@ -62,7 +62,7 @@ class Fullscreen {
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.value = array[2]; checkbox.checked = array[2];
label.textContent = array[1]; label.textContent = array[1];
div.appendChild(label); div.appendChild(label);
checkbox.addEventListener("change", array[3]); checkbox.addEventListener("change", array[3]);

View File

@@ -14,9 +14,6 @@ const users = getBulkUsers();
if (!users.currentuser) { if (!users.currentuser) {
window.location.href = '/login.html'; window.location.href = '/login.html';
} }
var info = users.users[users.currentuser].serverurls;
let token = users.users[users.currentuser].token;
let READY;
let thisuser = new Localuser(users.users[users.currentuser]); let thisuser = new Localuser(users.users[users.currentuser]);
thisuser.initwebsocket().then(_ => { thisuser.initwebsocket().then(_ => {
thisuser.loaduser(); thisuser.loaduser();
@@ -104,7 +101,6 @@ thisuser.initwebsocket().then(_ => {
}, null, _ => { return thisuser.isAdmin(); }); }, null, _ => { return thisuser.isAdmin(); });
menu.bind(document.getElementById("channels")); menu.bind(document.getElementById("channels"));
} }
function editchannelf(channel) { channel.editChannel(); }
const pasteimage = document.getElementById("pasteimage"); const pasteimage = document.getElementById("pasteimage");
let replyingto = null; let replyingto = null;
async function enter(event) { async function enter(event) {
@@ -145,9 +141,6 @@ typebox.addEventListener("keydown", event => {
}); });
console.log(typebox); console.log(typebox);
typebox.onclick = console.log; typebox.onclick = console.log;
let serverz = 0;
let serverid = [];
let cchanel = 0;
function getguildinfo() { function getguildinfo() {
const path = window.location.pathname.split("/"); const path = window.location.pathname.split("/");
const channel = path[3]; const channel = path[3];
@@ -155,49 +148,6 @@ function getguildinfo() {
} }
const images = []; const images = [];
const imageshtml = []; const imageshtml = [];
function createunknown(fname, fsize) {
const div = document.createElement("table");
div.classList.add("unknownfile");
const nametr = document.createElement("tr");
div.append(nametr);
const fileicon = document.createElement("td");
nametr.append(fileicon);
fileicon.append("🗎");
fileicon.classList.add("fileicon");
fileicon.rowSpan = 2;
const nametd = document.createElement("td");
{
nametd.textContent = fname;
}
nametd.classList.add("filename");
nametr.append(nametd);
const sizetr = document.createElement("tr");
const size = document.createElement("td");
sizetr.append(size);
size.textContent = "Size:" + filesizehuman(fsize);
size.classList.add("filesize");
div.appendChild(sizetr);
return div;
}
function filesizehuman(fsize) {
var 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];
}
function createunknownfile(file) {
return createunknown(file.name, file.size);
}
function filetohtml(file) {
if (file.type.startsWith('image/')) {
const img = document.createElement('img');
const blob = URL.createObjectURL(file);
img.src = blob;
return img;
}
else {
console.log(file.name);
return createunknownfile(file);
}
}
import { File } from "./file.js"; import { File } from "./file.js";
document.addEventListener('paste', async (e) => { document.addEventListener('paste', async (e) => {
Array.from(e.clipboardData.files).forEach(async (f) => { Array.from(e.clipboardData.files).forEach(async (f) => {
@@ -214,27 +164,6 @@ function userSettings() {
thisuser.usersettings.show(); thisuser.usersettings.show();
} }
document.getElementById("settings").onclick = userSettings; document.getElementById("settings").onclick = userSettings;
let triggered = false;
document.getElementById("messagecontainer").addEventListener("scroll", (e) => {
const messagecontainer = document.getElementById("messagecontainer");
if (messagecontainer.scrollTop < 2000) {
if (!triggered) {
thisuser.lookingguild.prevchannel.grabmoremessages().then(() => {
triggered = false;
if (messagecontainer.scrollTop === 0) {
messagecontainer.scrollTop = 1;
}
});
}
triggered = true;
}
else {
if (Math.abs(messagecontainer.scrollHeight - messagecontainer.scrollTop - messagecontainer.clientHeight) < 3) {
thisuser.lookingguild.prevchannel.readbottom();
}
}
//
});
if (mobile) { if (mobile) {
document.getElementById("channelw").onclick = function () { document.getElementById("channelw").onclick = function () {
document.getElementById("channels").parentNode.classList.add("collapse"); document.getElementById("channels").parentNode.classList.add("collapse");
@@ -248,20 +177,3 @@ if (mobile) {
document.getElementById("servers").classList.remove("collapse"); document.getElementById("servers").classList.remove("collapse");
}; };
} }
/*
{
const messages=document.getElementById("messages");
let height=messages.clientHeight;
//
const resizeObserver=new ResizeObserver(()=>{
console.log(messages.scrollTop,messages.clientHeight-height-messages.scrollHeight);
messages.scrollTop-=height-messages.scrollHeight;
console.log(messages.scrollTop)
//if(shouldsnap){
// document.getElementById("messagecontainer").scrollTop = document.getElementById("messagecontainer").scrollHeight;
//}
height=messages.scrollHeight;
})
resizeObserver.observe(messages)
}
*/

146
.dist/infiniteScroller.js Normal file
View File

@@ -0,0 +1,146 @@
class InfiniteScroller {
getIDFromOffset;
getHTMLFromID;
destroyFromID;
reachesBottom;
minDist = 3000;
maxDist = 8000;
HTMLElements = [];
div;
scroll;
constructor(getIDFromOffset, getHTMLFromID, destroyFromID, reachesBottom = () => { }) {
this.getIDFromOffset = getIDFromOffset;
this.getHTMLFromID = getHTMLFromID;
this.destroyFromID = destroyFromID;
this.reachesBottom = reachesBottom;
}
interval;
getDiv(initialId, bottom = true) {
const div = document.createElement("div");
div.classList.add("messagecontainer");
//div.classList.add("flexttb")
const scroll = document.createElement("div");
scroll.classList.add("flexttb", "scroller");
div.append(scroll);
this.div = div;
this.interval = setInterval(this.updatestuff.bind(this), 100);
this.scroll = scroll;
this.scroll.addEventListener("scroll", this.watchForChange.bind(this));
new ResizeObserver(this.watchForChange.bind(this)).observe(div);
new ResizeObserver(this.watchForChange.bind(this)).observe(scroll);
this.firstElement(initialId);
this.updatestuff();
this.watchForChange().then(_ => {
this.scroll.scrollTop = this.scroll.scrollHeight;
});
return div;
}
scrollBottom;
scrollTop;
updatestuff() {
this.scrollBottom = this.scroll.scrollHeight - this.scroll.scrollTop - this.scroll.clientHeight;
this.scrollTop = this.scroll.scrollTop;
if (this.scrollBottom) {
this.reachesBottom();
}
//this.watchForChange();
}
firstElement(id) {
const html = this.getHTMLFromID(id);
this.scroll.append(html);
this.HTMLElements.push([html, id]);
}
currrunning = false;
async addedBottom() {
this.updatestuff();
const scrollBottom = this.scrollBottom;
await this.watchForChange();
if (scrollBottom < 30) {
this.scroll.scrollTop = this.scroll.scrollHeight;
}
}
async watchForChange() {
if (this.currrunning) {
return;
}
else {
this.currrunning = true;
}
let again = false;
if (!this.div) {
this.currrunning = false;
return;
}
/*
if(this.scrollTop===0){
this.scrollTop=10;
}
*/
if (this.scrollTop === 0) {
this.scrollTop = 1;
this.scroll.scrollTop = 1;
}
if (this.scrollTop < this.minDist) {
const previd = this.HTMLElements.at(0)[1];
const nextid = await this.getIDFromOffset(previd, 1);
if (!nextid) {
}
else {
again = true;
const html = this.getHTMLFromID(nextid);
this.scroll.prepend(html);
this.HTMLElements.unshift([html, nextid]);
this.scrollTop += 60;
}
;
}
if (this.scrollTop > this.maxDist) {
again = true;
const html = this.HTMLElements.shift();
await this.destroyFromID(html[1]);
this.scrollTop -= 60;
}
const scrollBottom = this.scrollBottom;
if (scrollBottom < this.minDist) {
const previd = this.HTMLElements.at(-1)[1];
const nextid = await this.getIDFromOffset(previd, -1);
if (!nextid) {
}
else {
again = true;
const html = this.getHTMLFromID(nextid);
this.scroll.append(html);
this.HTMLElements.push([html, nextid]);
this.scrollBottom += 60;
if (scrollBottom < 30) {
this.scroll.scrollTop = this.scroll.scrollHeight;
}
}
;
}
if (scrollBottom > this.maxDist) {
again = true;
const html = this.HTMLElements.pop();
await this.destroyFromID(html[1]);
this.scrollBottom -= 60;
}
this.currrunning = false;
if (again) {
await this.watchForChange();
}
this.currrunning = false;
}
async delete() {
for (const thing of this.HTMLElements) {
await this.destroyFromID(thing[1]);
}
this.HTMLElements = [];
clearInterval(this.interval);
if (this.div) {
this.div.remove();
}
this.scroll = null;
this.div = null;
}
}
export { InfiniteScroller };

View File

@@ -2,7 +2,6 @@ import { Guild } from "./guild.js";
import { Direct } from "./direct.js"; import { Direct } from "./direct.js";
import { Voice } from "./audio.js"; import { Voice } from "./audio.js";
import { User } from "./user.js"; import { User } from "./user.js";
import { markdown } from "./markdown.js";
import { Fullscreen } from "./fullscreen.js"; import { Fullscreen } from "./fullscreen.js";
import { setTheme } from "./login.js"; import { setTheme } from "./login.js";
const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]); const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]);
@@ -85,7 +84,7 @@ class Localuser {
outoffocus() { outoffocus() {
document.getElementById("servers").textContent = ""; document.getElementById("servers").textContent = "";
document.getElementById("channels").textContent = ""; document.getElementById("channels").textContent = "";
document.getElementById("messages").textContent = ""; this.channelfocus.infinite.delete();
this.lookingguild = null; this.lookingguild = null;
this.channelfocus = null; this.channelfocus = null;
} }
@@ -145,23 +144,8 @@ class Localuser {
returny(); returny();
break; break;
case "MESSAGE_UPDATE": case "MESSAGE_UPDATE":
if (this.initialized) { const message = this.resolveChannelFromID(temp.d.channel_id).messageids[temp.d.id];
if (this.channelfocus.id === temp.d.channel_id) { message.giveData(temp.d);
const find = temp.d.id;
const messagelist = document.getElementById("messages").children;
for (const message of messagelist) {
const all = message["all"];
if (all.id === find) {
all.content = temp.d.content;
message["txt"].innerHTML = markdown(temp.d.content).innerHTML;
break;
}
}
}
else {
this.resolveChannelFromID(temp.d.channel_id).messages.find(e => e.id === temp.d.channel_id).content = temp.d.content;
}
}
break; break;
case "TYPING_START": case "TYPING_START":
if (this.initialized) { if (this.initialized) {
@@ -522,7 +506,7 @@ class Localuser {
reader.readAsDataURL(file); reader.readAsDataURL(file);
console.log(this.headers); console.log(this.headers);
reader.onload = () => { reader.onload = () => {
fetch(this.info.api.toString() + "/v9/users/@me", { fetch(this.info.api.toString() + "/users/@me", {
method: "PATCH", method: "PATCH",
headers: this.headers, headers: this.headers,
body: JSON.stringify({ body: JSON.stringify({
@@ -533,7 +517,7 @@ class Localuser {
}; };
} }
updatepronouns(pronouns) { updatepronouns(pronouns) {
fetch(this.info.api.toString() + "/v9/users/@me/profile", { fetch(this.info.api.toString() + "/users/@me/profile", {
method: "PATCH", method: "PATCH",
headers: this.headers, headers: this.headers,
body: JSON.stringify({ body: JSON.stringify({
@@ -616,7 +600,7 @@ class Localuser {
newbio = this.value; newbio = this.value;
regen(); regen();
}], }],
["button", "update user content:", "submit", function () { ["button", "update user content:", "submit", () => {
if (file !== null) { if (file !== null) {
this.updatepfp(file); this.updatepfp(file);
} }

View File

@@ -1,411 +1,474 @@
export { markdown }; export { MarkDown };
function markdown(text, { keep = false, stdsize = false } = {}) { class MarkDown {
let txt; txt;
if ((typeof txt) === "string") { keep;
txt = text.split(""); stdsize;
} owner;
else { info;
txt = text; constructor(text, owner, { keep = false, stdsize = false } = {}) {
} if ((typeof text) === (typeof "")) {
const span = document.createElement("span"); this.txt = text.split("");
let current = document.createElement("span");
function appendcurrent() {
if (current.innerHTML !== "") {
span.append(current);
current = document.createElement("span");
} }
else {
this.txt = text;
}
if (this.txt === undefined) {
this.txt = [];
}
this.info = owner.info;
this.keep = keep;
this.owner = owner;
this.stdsize = stdsize;
} }
for (let i = 0; i < txt.length; i++) { get rawString() {
if (txt[i] === "\n" || i === 0) { return this.txt.concat("");
const first = i === 0; }
if (first) { get textContent() {
i--; return this.makeHTML().textContent;
}
makeHTML({ keep = this.keep, stdsize = this.stdsize } = {}) {
return this.markdown(this.txt, { keep: keep, stdsize: stdsize });
}
markdown(text, { keep = false, stdsize = false } = {}) {
let txt;
if ((typeof text) === (typeof "")) {
txt = text.split("");
}
else {
txt = text;
}
if (txt === undefined) {
txt = [];
}
const span = document.createElement("span");
let current = document.createElement("span");
function appendcurrent() {
if (current.innerHTML !== "") {
span.append(current);
current = document.createElement("span");
} }
let element = null; }
let keepys = ""; for (let i = 0; i < txt.length; i++) {
if (txt[i + 1] === "#") { if (txt[i] === "\n" || i === 0) {
console.log("test"); const first = i === 0;
if (txt[i + 2] === "#") { if (first) {
if (txt[i + 3] === "#" && txt[i + 4] === " ") { i--;
element = document.createElement("h3"); }
keepys = "### "; let element = null;
i += 5; let keepys = "";
if (txt[i + 1] === "#") {
console.log("test");
if (txt[i + 2] === "#") {
if (txt[i + 3] === "#" && txt[i + 4] === " ") {
element = document.createElement("h3");
keepys = "### ";
i += 5;
}
else if (txt[i + 3] === " ") {
element = document.createElement("h2");
element.classList.add("h2md");
keepys = "## ";
i += 4;
}
} }
else if (txt[i + 3] === " ") { else if (txt[i + 2] === " ") {
element = document.createElement("h2"); element = document.createElement("h1");
element.classList.add("h2md"); keepys = "# ";
keepys = "## "; i += 3;
i += 4;
} }
} }
else if (txt[i + 2] === " ") { else if (txt[i + 1] === ">" && txt[i + 2] === " ") {
element = document.createElement("h1"); element = document.createElement("div");
keepys = "# "; const line = document.createElement("div");
line.classList.add("quoteline");
element.append(line);
element.classList.add("quote");
keepys = "> ";
i += 3; i += 3;
} }
} if (keepys) {
else if (txt[i + 1] === ">" && txt[i + 2] === " ") { appendcurrent();
element = document.createElement("div"); if (!first && !stdsize) {
const line = document.createElement("div"); span.appendChild(document.createElement("br"));
line.classList.add("quoteline"); }
element.append(line); const build = [];
element.classList.add("quote"); for (; txt[i] !== "\n" && txt[i] !== undefined; i++) {
keepys = "> "; build.push(txt[i]);
i += 3; }
} if (stdsize) {
if (keepys) { element = document.createElement("span");
appendcurrent(); }
if (!first && !stdsize) { if (keep) {
span.appendChild(document.createElement("br")); element.append(keepys);
}
element.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
span.append(element);
i--;
continue;
} }
const build = []; if (first) {
for (; txt[i] !== "\n" && txt[i] !== undefined; i++) { i++;
build.push(txt[i]); }
}
if (txt[i] === "\n") {
if (!stdsize) {
appendcurrent();
span.append(document.createElement("br"));
}
continue;
}
if (txt[i] === "`") {
let count = 1;
if (txt[i + 1] === "`") {
count++;
if (txt[i + 2] === "`") {
count++;
}
}
let build = "";
if (keep) {
build += "`".repeat(count);
}
let find = 0;
let j = i + count;
let init = true;
for (; txt[j] !== undefined && (txt[j] !== "\n" || count === 3) && find !== count; j++) {
if (txt[j] === "`") {
find++;
}
else {
if (find !== 0) {
build += "`".repeat(find);
find = 0;
}
if (init && count === 3) {
if (txt[j] === " " || txt[j] === "\n") {
init = false;
}
if (keep) {
build += txt[j];
}
continue;
}
build += txt[j];
}
} }
if (stdsize) { if (stdsize) {
element = document.createElement("span"); console.log(build);
build = build.replaceAll("\n", "");
console.log(build, JSON.stringify(build));
} }
if (keep) { if (find === count) {
element.append(keepys); appendcurrent();
} i = j;
element.appendChild(markdown(build, { keep: keep, stdsize: stdsize })); if (keep) {
span.append(element);
i--;
continue;
}
if (first) {
i++;
}
}
if (txt[i] === "\n") {
if (!stdsize) {
appendcurrent();
span.append(document.createElement("br"));
}
continue;
}
if (txt[i] === "`") {
let count = 1;
if (txt[i + 1] === "`") {
count++;
if (txt[i + 2] === "`") {
count++;
}
}
let build = "";
if (keep) {
build += "`".repeat(count);
}
let find = 0;
let j = i + count;
let init = true;
for (; txt[j] !== undefined && (txt[j] !== "\n" || count === 3) && find !== count; j++) {
if (txt[j] === "`") {
find++;
}
else {
if (find !== 0) {
build += "`".repeat(find); build += "`".repeat(find);
find = 0;
} }
if (init && count === 3) { if (count !== 3 && !stdsize) {
if (txt[j] === " " || txt[j] === "\n") { const samp = document.createElement("samp");
init = false; samp.textContent = build;
span.appendChild(samp);
}
else {
const pre = document.createElement("pre");
if (build[build.length - 1] === "\n") {
build = build.substring(0, build.length - 1);
} }
if (txt[i] === "\n") {
i++;
}
pre.textContent = build;
span.appendChild(pre);
}
i--;
continue;
}
}
if (txt[i] === "*") {
let count = 1;
if (txt[i + 1] === "*") {
count++;
if (txt[i + 2] === "*") {
count++;
}
}
let build = [];
let find = 0;
let j = i + count;
for (; txt[j] !== undefined && find !== count; j++) {
if (txt[j] === "*") {
find++;
}
else {
build.push(txt[j]);
if (find !== 0) {
build = build.concat(new Array(find).fill("*"));
find = 0;
}
}
}
if (find === count && (count != 1 || txt[i + 1] !== " ")) {
appendcurrent();
i = j;
const stars = "*".repeat(count);
if (count === 1) {
const i = document.createElement("i");
if (keep) { if (keep) {
build += txt[j]; i.append(stars);
} }
i.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
i.append(stars);
}
span.appendChild(i);
}
else if (count === 2) {
const b = document.createElement("b");
if (keep) {
b.append(stars);
}
b.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
b.append(stars);
}
span.appendChild(b);
}
else {
const b = document.createElement("b");
const i = document.createElement("i");
if (keep) {
b.append(stars);
}
b.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
b.append(stars);
}
i.appendChild(b);
span.appendChild(i);
}
i--;
continue;
}
}
if (txt[i] === "_") {
let count = 1;
if (txt[i + 1] === "_") {
count++;
if (txt[i + 2] === "_") {
count++;
}
}
let build = [];
let find = 0;
let j = i + count;
for (; txt[j] !== undefined && find !== count; j++) {
if (txt[j] === "_") {
find++;
}
else {
build.push(txt[j]);
if (find !== 0) {
build = build.concat(new Array(find).fill("_"));
find = 0;
}
}
}
if (find === count && (count != 1 || (txt[j + 1] === " " || txt[j + 1] === "\n" || txt[j + 1] === undefined))) {
appendcurrent();
i = j;
const underscores = "_".repeat(count);
if (count === 1) {
const i = document.createElement("i");
if (keep) {
i.append(underscores);
}
i.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
i.append(underscores);
}
span.appendChild(i);
}
else if (count === 2) {
const u = document.createElement("u");
if (keep) {
u.append(underscores);
}
u.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
u.append(underscores);
}
span.appendChild(u);
}
else {
const u = document.createElement("u");
const i = document.createElement("i");
if (keep) {
i.append(underscores);
}
i.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
i.append(underscores);
}
u.appendChild(i);
span.appendChild(u);
}
i--;
continue;
}
}
if (txt[i] === "~" && txt[i + 1] === "~") {
let count = 2;
let build = [];
let find = 0;
let j = i + 2;
for (; txt[j] !== undefined && find !== count; j++) {
if (txt[j] === "~") {
find++;
}
else {
build.push(txt[j]);
if (find !== 0) {
build = build.concat(new Array(find).fill("~"));
find = 0;
}
}
}
if (find === count) {
appendcurrent();
i = j;
const tildes = "~~";
if (count === 2) {
const s = document.createElement("s");
if (keep) {
s.append(tildes);
}
s.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
s.append(tildes);
}
span.appendChild(s);
}
continue;
}
}
if (txt[i] === "|" && txt[i + 1] === "|") {
let count = 2;
let build = [];
let find = 0;
let j = i + 2;
for (; txt[j] !== undefined && find !== count; j++) {
if (txt[j] === "|") {
find++;
}
else {
build.push(txt[j]);
if (find !== 0) {
build = build.concat(new Array(find).fill("~"));
find = 0;
}
}
}
if (find === count) {
appendcurrent();
i = j;
const pipes = "||";
if (count === 2) {
const j = document.createElement("j");
if (keep) {
j.append(pipes);
}
j.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize }));
j.classList.add("spoiler");
j.onclick = MarkDown.unspoil;
if (keep) {
j.append(pipes);
}
span.appendChild(j);
}
continue;
}
}
if (txt[i] === "<" && txt[i + 1] === "t" && txt[i + 2] === ":") {
let found = false;
const build = ["<", "t", ":"];
let j = i + 3;
for (; txt[j] !== void 0; j++) {
build.push(txt[j]);
if (txt[j] === ">") {
found = true;
break;
}
}
if (found) {
appendcurrent();
i = j;
const parts = build.join("").match(/^<t:([0-9]{1,16})(:([tTdDfFR]))?>$/);
const dateInput = new Date(Number.parseInt(parts[1]) * 1000);
let time = "";
if (Number.isNaN(dateInput.getTime()))
time = build.join("");
else {
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] || parts[3] === "f")
time = dateInput.toLocaleString(void 0, { day: "numeric", month: "long", year: "numeric" }) + " " +
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" }) + " " +
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] === "R")
time = Math.round((Date.now() - (Number.parseInt(parts[1]) * 1000)) / 1000 / 60) + " minutes ago";
}
const timeElem = document.createElement("span");
timeElem.classList.add("markdown-timestamp");
timeElem.textContent = time;
span.appendChild(timeElem);
continue;
}
}
if (txt[i] === "<" && (txt[i + 1] === ":" || (txt[i + 1] === "a" && txt[i + 2] === ":"))) {
let found = false;
const build = txt[i + 1] === "a" ? ["<", "a", ":"] : ["<", ":"];
let j = i + build.length;
for (; txt[j] !== void 0; j++) {
build.push(txt[j]);
if (txt[j] === ">") {
found = true;
break;
}
}
if (found) {
const buildjoin = build.join("");
const parts = buildjoin.match(/^<(a)?:\w+:(\d{10,30})>$/);
if (parts && parts[2]) {
appendcurrent();
i = j;
const isEmojiOnly = txt.join("").trim() === buildjoin.trim();
const emojiElem = document.createElement("img");
emojiElem.classList.add("md-emoji");
emojiElem.classList.add(isEmojiOnly ? "bigemoji" : "smallemoji");
emojiElem.crossOrigin = "anonymous";
emojiElem.src = this.info.cdn.toString() + "emojis/" + parts[2] + "." + (parts[1] ? "gif" : "png") + "?size=32";
emojiElem.alt = buildjoin;
emojiElem.loading = "lazy";
span.appendChild(emojiElem);
continue; continue;
} }
build += txt[j];
} }
} }
if (stdsize) { current.textContent += txt[i];
console.log(build);
build = build.replaceAll("\n", "");
console.log(build, JSON.stringify(build));
}
if (find === count) {
appendcurrent();
i = j;
if (keep) {
build += "`".repeat(find);
}
if (count !== 3 && !stdsize) {
const samp = document.createElement("samp");
samp.textContent = build;
span.appendChild(samp);
}
else {
const pre = document.createElement("pre");
if (build[build.length - 1] === "\n") {
build = build.substring(0, build.length - 1);
}
if (txt[i] === "\n") {
i++;
}
pre.textContent = build;
span.appendChild(pre);
}
i--;
continue;
}
} }
if (txt[i] === "*") { appendcurrent();
let count = 1; return span;
if (txt[i + 1] === "*") { }
count++; static unspoil(e) {
if (txt[i + 2] === "*") { e.target.classList.remove("spoiler");
count++; e.target.classList.add("unspoiled");
}
}
let build = [];
let find = 0;
let j = i + count;
for (; txt[j] !== undefined && find !== count; j++) {
if (txt[j] === "*") {
find++;
}
else {
build.push(txt[j]);
if (find !== 0) {
build = build.concat(new Array(find).fill("*"));
find = 0;
}
}
}
if (find === count && (count != 1 || txt[i + 1] !== " ")) {
appendcurrent();
i = j;
const stars = "*".repeat(count);
if (count === 1) {
const i = document.createElement("i");
if (keep) {
i.append(stars);
}
i.appendChild(markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
i.append(stars);
}
span.appendChild(i);
}
else if (count === 2) {
const b = document.createElement("b");
if (keep) {
b.append(stars);
}
b.appendChild(markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
b.append(stars);
}
span.appendChild(b);
}
else {
const b = document.createElement("b");
const i = document.createElement("i");
if (keep) {
b.append(stars);
}
b.appendChild(markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
b.append(stars);
}
i.appendChild(b);
span.appendChild(i);
}
i--;
continue;
}
}
if (txt[i] === "_") {
let count = 1;
if (txt[i + 1] === "_") {
count++;
if (txt[i + 2] === "_") {
count++;
}
}
let build = [];
let find = 0;
let j = i + count;
for (; txt[j] !== undefined && find !== count; j++) {
if (txt[j] === "_") {
find++;
}
else {
build.push(txt[j]);
if (find !== 0) {
build = build.concat(new Array(find).fill("_"));
find = 0;
}
}
}
if (find === count && (count != 1 || (txt[j + 1] === " " || txt[j + 1] === "\n" || txt[j + 1] === undefined))) {
appendcurrent();
i = j;
const underscores = "_".repeat(count);
if (count === 1) {
const i = document.createElement("i");
if (keep) {
i.append(underscores);
}
i.appendChild(markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
i.append(underscores);
}
span.appendChild(i);
}
else if (count === 2) {
const u = document.createElement("u");
if (keep) {
u.append(underscores);
}
u.appendChild(markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
u.append(underscores);
}
span.appendChild(u);
}
else {
const u = document.createElement("u");
const i = document.createElement("i");
if (keep) {
i.append(underscores);
}
i.appendChild(markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
i.append(underscores);
}
u.appendChild(i);
span.appendChild(u);
}
i--;
continue;
}
}
if (txt[i] === "~" && txt[i + 1] === "~") {
let count = 2;
let build = [];
let find = 0;
let j = i + 2;
for (; txt[j] !== undefined && find !== count; j++) {
if (txt[j] === "~") {
find++;
}
else {
build.push(txt[j]);
if (find !== 0) {
build = build.concat(new Array(find).fill("~"));
find = 0;
}
}
}
if (find === count) {
appendcurrent();
i = j;
const tildes = "~~";
if (count === 2) {
const s = document.createElement("s");
if (keep) {
s.append(tildes);
}
s.appendChild(markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
s.append(tildes);
}
span.appendChild(s);
}
continue;
}
}
if (txt[i] === "|" && txt[i + 1] === "|") {
let count = 2;
let build = [];
let find = 0;
let j = i + 2;
for (; txt[j] !== undefined && find !== count; j++) {
if (txt[j] === "|") {
find++;
}
else {
build.push(txt[j]);
if (find !== 0) {
build = build.concat(new Array(find).fill("~"));
find = 0;
}
}
}
if (find === count) {
appendcurrent();
i = j;
const pipes = "||";
if (count === 2) {
const j = document.createElement("j");
if (keep) {
j.append(pipes);
}
j.appendChild(markdown(build, { keep: keep, stdsize: stdsize }));
j.classList.add("spoiler");
j.onclick = markdown.unspoil;
if (keep) {
j.append(pipes);
}
span.appendChild(j);
}
continue;
}
}
if (txt[i] === "<" && txt[i + 1] === "t" && txt[i + 2] === ":") {
let found = false;
const build = ["<", "t", ":"];
let j = i + 3;
for (; txt[j] !== void 0; j++) {
build.push(txt[j]);
if (txt[j] === ">") {
found = true;
break;
}
}
if (found) {
appendcurrent();
i = j;
const parts = build.join("").match(/^<t:([0-9]{1,16})(:([tTdDfFR]))?>$/);
const dateInput = new Date(Number.parseInt(parts[1]) * 1000);
let time = "";
if (Number.isNaN(dateInput.getTime()))
time = build.join("");
else {
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] || parts[3] === "f")
time = dateInput.toLocaleString(void 0, { day: "numeric", month: "long", year: "numeric" }) + " " +
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" }) + " " +
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] === "R")
time = Math.round((Date.now() - (Number.parseInt(parts[1]) * 1000)) / 1000 / 60) + " minutes ago";
}
const timeElem = document.createElement("span");
timeElem.classList.add("markdown-timestamp");
timeElem.textContent = time;
span.appendChild(timeElem);
continue;
}
}
current.textContent += txt[i];
} }
appendcurrent();
return span;
} }
markdown.unspoil = function (e) {
//console.log("undone")
e.target.classList.remove("spoiler");
e.target.classList.add("unspoiled");
};

View File

@@ -1,7 +1,7 @@
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 { File } from "./file.js"; import { File } from "./file.js";
class Message { class Message {
@@ -33,7 +33,7 @@ class Message {
} }
static setupcmenu() { static setupcmenu() {
Message.contextmenu.addbutton("Copy raw text", function () { Message.contextmenu.addbutton("Copy raw text", function () {
navigator.clipboard.writeText(this.content); navigator.clipboard.writeText(this.content.rawString);
}); });
Message.contextmenu.addbutton("Reply", function (div) { Message.contextmenu.addbutton("Reply", function (div) {
this.channel.setReplying(this); this.channel.setReplying(this);
@@ -52,6 +52,9 @@ class Message {
constructor(messagejson, owner) { constructor(messagejson, owner) {
this.owner = owner; this.owner = owner;
this.headers = this.owner.headers; this.headers = this.owner.headers;
this.giveData(messagejson);
}
giveData(messagejson) {
for (const thing of Object.keys(messagejson)) { for (const thing of Object.keys(messagejson)) {
if (thing === "attachments") { if (thing === "attachments") {
this.attachments = []; this.attachments = [];
@@ -60,6 +63,10 @@ class Message {
} }
continue; continue;
} }
else if (thing === "content") {
this.content = new MarkDown(messagejson[thing], this.channel);
continue;
}
this[thing] = messagejson[thing]; this[thing] = messagejson[thing];
} }
for (const thing in this.embeds) { for (const thing in this.embeds) {
@@ -76,6 +83,9 @@ class Message {
if (this.mentionsuser(this.localuser.user)) { if (this.mentionsuser(this.localuser.user)) {
console.log(this); console.log(this);
} }
if (this.div) {
this.generateMessage();
}
} }
canDelete() { canDelete() {
return this.channel.hasPermission("MANAGE_MESSAGES") || this.author.id === this.localuser.user.id; return this.channel.hasPermission("MANAGE_MESSAGES") || this.author.id === this.localuser.user.id;
@@ -92,11 +102,12 @@ class Message {
get info() { get info() {
return this.owner.info; return this.owner.info;
} }
messageevents(obj) { messageevents(obj, del = Message.del) {
const func = Message.contextmenu.bind(obj, this); const func = Message.contextmenu.bind(obj, this);
this.div = obj; this.div = obj;
Message.del.then(_ => { del.then(_ => {
obj.removeEventListener("click", func); obj.removeEventListener("click", func);
this.div.remove();
this.div = null; this.div = null;
}); });
obj.classList.add("messagediv"); obj.classList.add("messagediv");
@@ -136,17 +147,19 @@ class Message {
this.div.innerHTML = ""; this.div.innerHTML = "";
this.div = null; this.div = null;
} }
const index = this.channel.messages.indexOf(this); const prev = this.channel.idToPrev[this.id];
this.channel.messages.splice(this.channel.messages.indexOf(this), 1); const next = this.channel.idToNext[this.id];
this.channel.idToNext[prev] = next;
this.channel.idToPrev[next] = prev;
delete this.channel.messageids[this.id]; delete this.channel.messageids[this.id];
const regen = this.channel.messages[index - 1]; const regen = this.channel.messageids[prev];
if (regen) { if (regen) {
regen.generateMessage(); regen.generateMessage();
} }
} }
generateMessage(premessage = null) { generateMessage(premessage = null) {
if (!premessage) { if (!premessage) {
premessage = this.channel.messages[this.channel.messages.indexOf(this) + 1]; premessage = this.channel.messageids[this.channel.idToNext[this.id]];
} }
const div = this.div; const div = this.div;
if (this === this.channel.replyingto) { if (this === this.channel.replyingto) {
@@ -195,7 +208,7 @@ class Message {
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 => {
const author = message.author; const author = message.author;
reply.appendChild(markdown(message.content, { 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;
@@ -203,7 +216,6 @@ class Message {
}); });
div.appendChild(replyline); div.appendChild(replyline);
} }
this.messageevents(div);
build.classList.add("message"); build.classList.add("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) {
@@ -258,7 +270,7 @@ class Message {
else { else {
div.classList.remove("topMessage"); div.classList.remove("topMessage");
} }
const messaged = markdown(this.content); 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");
@@ -304,14 +316,15 @@ class Message {
div["all"] = this; div["all"] = this;
return (div); return (div);
} }
buildhtml(premessage) { buildhtml(premessage, del = Message.del) {
if (this.div) { if (this.div) {
console.error(`HTML for ${this} already exists, aborting`); console.error(`HTML for ${this.id} already exists, aborting`);
return; return;
} }
//premessage??=messages.lastChild; //premessage??=messages.lastChild;
const div = document.createElement("div"); const div = document.createElement("div");
this.div = div; this.div = div;
this.messageevents(div, del);
return this.generateMessage(premessage); return this.generateMessage(premessage);
} }
} }

View File

@@ -57,4 +57,4 @@ async function tosLogic() {
console.log(tosPage); console.log(tosPage);
} }
tosLogic(); tosLogic();
checkInstance.alt = tosLogic; checkInstance["alt"] = tosLogic;

View File

@@ -80,7 +80,7 @@ class PermissionToggle {
div.append(name); div.append(name);
div.append(this.generateCheckbox()); div.append(this.generateCheckbox());
const p = document.createElement("p"); const p = document.createElement("p");
p.innerText = this.rolejson.description; p.textContent = this.rolejson.description;
div.appendChild(p); div.appendChild(p);
return div; return div;
} }

View File

@@ -1,6 +1,6 @@
//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";
class User { class User {
static userids = {}; static userids = {};
@@ -48,6 +48,10 @@ class User {
} }
if (dontclone) { if (dontclone) {
for (const thing of Object.keys(userjson)) { for (const thing of Object.keys(userjson)) {
if (thing === "bio") {
this.bio = new MarkDown(userjson[thing], this.localuser);
continue;
}
this[thing] = userjson[thing]; this[thing] = userjson[thing];
} }
this.hypotheticalpfp = false; this.hypotheticalpfp = false;
@@ -146,7 +150,7 @@ class User {
userbody.appendChild(pronounshtml); userbody.appendChild(pronounshtml);
const rule = document.createElement("hr"); const rule = document.createElement("hr");
userbody.appendChild(rule); userbody.appendChild(rule);
const biohtml = markdown(this.bio); const biohtml = this.bio.makeHTML();
userbody.appendChild(biohtml); userbody.appendChild(biohtml);
} }
console.log(div); console.log(div);

Binary file not shown.

View File

@@ -1,5 +1,5 @@
# Jank Client # Jank Client
Jank Client is a [Spacebar](https://spacebar.chat) Client written in JS, HTML, and CSS. Jank Client is a [Spacebar](https://spacebar.chat) Client written in TS, HTML, and CSS.
To run it, clone the repo and do `npm install express`, then either To run it, clone the repo and do `npm install express`, then either
`node index.js` `node index.js`

View File

@@ -3,12 +3,13 @@ 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 {Fullscreen} from "./fullscreen.js"; import {Fullscreen} from "./fullscreen.js";
import {markdown} from "./markdown.js"; import {MarkDown} from "./markdown.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, RoleList } from "./settings.js"; import { Settings, RoleList } from "./settings.js";
import { Role } from "./role.js"; import { Role } from "./role.js";
import {InfiniteScroller} from "./infiniteScroller.js"
Settings; Settings;
declare global { declare global {
interface NotificationOptions { interface NotificationOptions {
@@ -20,7 +21,6 @@ class Channel{
type:number; type:number;
owner:Guild; owner:Guild;
headers:Localuser["headers"]; headers:Localuser["headers"];
messages:Message[];
name:string; name:string;
id:string; id:string;
parent_id:string; parent_id:string;
@@ -43,6 +43,9 @@ class Channel{
allthewayup:boolean; allthewayup:boolean;
static contextmenu=new Contextmenu("channel menu"); static contextmenu=new Contextmenu("channel menu");
replyingto:Message; replyingto:Message;
infinite:InfiniteScroller;
idToPrev:{[key:string]:string}={};
idToNext:{[key:string]:string}={};
static setupcontextmenu(){ static setupcontextmenu(){
this.contextmenu.addbutton("Copy channel id",function(){ this.contextmenu.addbutton("Copy channel id",function(){
console.log(this) console.log(this)
@@ -82,16 +85,45 @@ class Channel{
return order; return order;
}) })
} }
setUpInfiniteScroller(){
const ids:{[key:string]:Function}={};
this.infinite=new InfiniteScroller(async function(id:string,offset:number){
if(offset===1){
if(this.idToPrev[id]){
return this.idToPrev[id];
}else{
await this.grabmoremessages(id);
return this.idToPrev[id];
}
}else{
return this.idToNext[id];
}
}.bind(this),
function(this:Channel,id:string){
let res:Function;
const promise=new Promise(_=>{res=_;}) as Promise<void>;
const html=this.messageids[id].buildhtml(this.messageids[this.idToPrev[id]],promise);
ids[id]=res;
return html;
}.bind(this),
async function(id:string){
ids[id]();
delete ids[id];
return true;
}.bind(this),
this.readbottom.bind(this)
);
}
constructor(JSON,owner:Guild){ constructor(JSON,owner:Guild){
if(JSON===-1){ if(JSON===-1){
return; return;
} }
this.editing; this.editing;
this.type=JSON.type; this.type=JSON.type;
this.owner=owner; this.owner=owner;
this.headers=this.owner.headers; this.headers=this.owner.headers;
this.messages=[];
this.name=JSON.name; this.name=JSON.name;
this.id=JSON.id; this.id=JSON.id;
this.parent_id=JSON.parent_id; this.parent_id=JSON.parent_id;
@@ -113,6 +145,7 @@ class Channel{
this.position=JSON.position; this.position=JSON.position;
this.lastreadmessageid=null; this.lastreadmessageid=null;
this.lastmessageid=JSON.last_message_id; this.lastmessageid=JSON.last_message_id;
this.setUpInfiniteScroller();
} }
isAdmin(){ isAdmin(){
return this.guild.isAdmin(); return this.guild.isAdmin();
@@ -495,7 +528,7 @@ class Channel{
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;
const prom=Message.wipeChanel(); const prom=this.infinite.delete();
await this.putmessages(); await this.putmessages();
await prom; await prom;
if(id!==Channel.genid){ if(id!==Channel.genid){
@@ -509,7 +542,7 @@ class Channel{
(document.getElementById("typebox") as HTMLInputElement).disabled=!this.canMessage; (document.getElementById("typebox") as HTMLInputElement).disabled=!this.canMessage;
} }
async putmessages(){ async putmessages(){
if(this.messages.length>=100||this.allthewayup){return}; if(this.allthewayup){return};
const j=await fetch(this.info.api.toString()+"/channels/"+this.id+"/messages?limit=100",{ const j=await fetch(this.info.api.toString()+"/channels/"+this.id+"/messages?limit=100",{
headers: this.headers, headers: this.headers,
}) })
@@ -517,11 +550,16 @@ class Channel{
if(response.length!==100){ if(response.length!==100){
this.allthewayup=true; this.allthewayup=true;
} }
let prev=undefined;
for(const thing of response){ for(const thing of response){
const messager=new Message(thing,this) const message=new Message(thing,this);
if(this.messageids[messager.id]===undefined){ if(prev){
this.messageids[messager.id]=messager; this.idToNext[message.id]=prev.id;
this.messages.push(messager); this.idToPrev[prev.id]=message.id;
}
prev=message;
if(this.messageids[message.id]===undefined){
this.messageids[message.id]=message;
} }
} }
} }
@@ -534,25 +572,23 @@ class Channel{
} }
this.children=build; this.children=build;
} }
async grabmoremessages(){ async grabmoremessages(id:string){
if(this.messages.length===0||this.allthewayup){ if(this.allthewayup){
return; return;
} }
const out=this;
await fetch(this.info.api.toString()+"/channels/"+this.id+"/messages?before="+this.messages[this.messages.length-1].id+"&limit=100",{ await fetch(this.info.api.toString()+"/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=>{
//messages.innerHTML = '';
//response.reverse()
let next:Message; let next:Message;
if(response.length===0){ if(response.length===0){
out.allthewayup=true; this.allthewayup=true;
} }
let previd=id;
for(const i in response){ for(const i in response){
let messager:Message; let messager:Message;
if(!next){ if(!next){
messager=new Message(response[i],this) messager=new Message(response[i],this);
}else{ }else{
messager=next; messager=next;
} }
@@ -560,12 +596,13 @@ class Channel{
next=new Message(response[+i+1],this); next=new Message(response[+i+1],this);
}else{ }else{
next=undefined; next=undefined;
console.log("ohno",+i+1) console.log("ohno",+i+1);
} }
if(out.messageids[messager.id]==undefined){ if(this.messageids[messager.id]===undefined){
out.messageids[messager.id]=messager; this.idToNext[messager.id]=previd;
out.buildmessage(messager,next); this.idToPrev[previd]=messager.id;
out.messages.push(messager); previd=messager.id;
this.messageids[messager.id]=messager;
}else{ }else{
console.log("How???") console.log("How???")
} }
@@ -579,37 +616,9 @@ class Channel{
document.getElementById("messages").prepend(built); document.getElementById("messages").prepend(built);
} }
buildmessages(){ buildmessages(){
for(const i in this.messages){ const messages=document.getElementById("channelw");
const prev=this.messages[(+i)+1]; messages.innerHTML="";
const built=this.messages[i].buildhtml(prev); messages.append(this.infinite.getDiv(this.lastmessageid));
document.getElementById("messages").prepend(built);
if (prev) {
const prevDate=new Date(prev.timestamp);
const currentDate=new Date(this.messages[i].timestamp);
if (prevDate.toLocaleDateString() != currentDate.toLocaleDateString()) {
const dateContainer=document.createElement("div");
dateContainer.classList.add("replyflex");
const line=document.createElement("hr");
line.classList.add("reply");
dateContainer.appendChild(line);
const date=document.createElement("span");
date.textContent=currentDate.toLocaleDateString(undefined, { weekday: "long", year: "numeric", month: "long", day: "numeric" });
dateContainer.appendChild(date);
const line2=document.createElement("hr");
line2.classList.add("reply");
dateContainer.appendChild(line2);
document.getElementById("messages").prepend(dateContainer);
}
}
}
document.getElementById("messagecontainer").scrollTop = document.getElementById("messagecontainer").scrollHeight;
} }
updateChannel(JSON){ updateChannel(JSON){
this.type=JSON.type; this.type=JSON.type;
@@ -698,7 +707,10 @@ class Channel{
messageCreate(messagep:any):void{ messageCreate(messagep:any):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.idToNext[this.lastmessageid]=messagez.id;
this.idToPrev[messagez.id]=this.lastmessageid;
this.lastmessageid=messagez.id; this.lastmessageid=messagez.id;
this.messageids[messagez.id]=messagez;
if(messagez.author===this.localuser.user){ if(messagez.author===this.localuser.user){
this.lastreadmessageid=messagez.id; this.lastreadmessageid=messagez.id;
if(this.myhtml){ if(this.myhtml){
@@ -710,16 +722,7 @@ class Channel{
} }
} }
this.guild.unreads(); this.guild.unreads();
this.messages.unshift(messagez); this.infinite.addedBottom();
const scrolly=document.getElementById("messagecontainer");
this.messageids[messagez.id]=messagez;
if(this.localuser.lookingguild.prevchannel===this){
var shouldScroll=scrolly.scrollTop+scrolly.clientHeight>scrolly.scrollHeight-20;
document.getElementById("messages").appendChild(messagez.buildhtml(this.messages[1]));
}
if(shouldScroll){
scrolly.scrollTop = scrolly.scrollHeight;
}
if(messagez.author===this.localuser.user){ if(messagez.author===this.localuser.user){
return; return;
} }
@@ -731,6 +734,7 @@ 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;
@@ -740,10 +744,10 @@ class Channel{
if (!("Notification" in window)) { if (!("Notification" in window)) {
} else if (Notification.permission === "granted") { } else if (Notification.permission === "granted") {
let noticontent=markdown(message.content).textContent; let noticontent=message.content.textContent;
if(message.embeds[0]){ if(message.embeds[0]){
noticontent||=message.embeds[0].json.title; noticontent||=message.embeds[0].json.title;
noticontent||=markdown(message.embeds[0].json.description).textContent; noticontent||=message.content.textContent;
} }
noticontent||="Blank Message"; noticontent||="Blank Message";
let imgurl=null; let imgurl=null;

View File

@@ -67,7 +67,6 @@ class Group extends Channel{
super(-1,owner); super(-1,owner);
this.owner=owner; this.owner=owner;
this.headers=this.guild.headers; this.headers=this.guild.headers;
this.messages=[];
this.name=JSON.recipients[0]?.username; this.name=JSON.recipients[0]?.username;
if(JSON.recipients[0]){ if(JSON.recipients[0]){
this.user=new User(JSON.recipients[0],this.localuser); this.user=new User(JSON.recipients[0],this.localuser);
@@ -85,6 +84,7 @@ class Group extends Channel{
this.lastmessageid=JSON.last_message_id; this.lastmessageid=JSON.last_message_id;
this.lastmessageid??="0"; this.lastmessageid??="0";
this.mentions=0; this.mentions=0;
this.setUpInfiniteScroller();
} }
createguildHTML(){ createguildHTML(){
const div=document.createElement("div") const div=document.createElement("div")
@@ -104,9 +104,9 @@ class Group extends Channel{
if(this.guild!==this.localuser.lookingguild){ if(this.guild!==this.localuser.lookingguild){
this.guild.loadGuild(); this.guild.loadGuild();
} }
const prom=Message.wipeChanel();
this.guild.prevchannel=this; this.guild.prevchannel=this;
this.localuser.channelfocus=this; this.localuser.channelfocus=this;
const prom=this.infinite.delete();
await this.putmessages(); await this.putmessages();
await prom; await prom;
if(id!==Channel.genid){ if(id!==Channel.genid){
@@ -118,38 +118,28 @@ class Group extends Channel{
} }
messageCreate(messagep){ messageCreate(messagep){
const messagez=new Message(messagep.d,this); const messagez=new Message(messagep.d,this);
this.idToNext[this.lastmessageid]=messagez.id;
this.idToPrev[messagez.id]=this.lastmessageid;
this.lastmessageid=messagez.id; this.lastmessageid=messagez.id;
this.messageids[messagez.id]=messagez;
if(messagez.author===this.localuser.user){ if(messagez.author===this.localuser.user){
this.lastreadmessageid=messagez.id; this.lastreadmessageid=messagez.id;
} if(this.myhtml){
this.messages.unshift(messagez); this.myhtml.classList.remove("cunread");
const scrolly=document.getElementById("messagecontainer"); }
this.messageids[messagez.id]=messagez; }else{
if(this.localuser.lookingguild.prevchannel===this){ if(this.myhtml){
var shouldScroll=scrolly.scrollTop+scrolly.clientHeight>scrolly.scrollHeight-20; this.myhtml.classList.add("cunread");
document.getElementById("messages").appendChild(messagez.buildhtml(this.messages[1]));
}
if(shouldScroll){
scrolly.scrollTop = scrolly.scrollHeight;
}
console.log(document.getElementById("channels").children)
if(this.localuser.lookingguild===this.guild){
const channellist=document.getElementById("channels").children[0]
for(const thing of channellist.children){
if(thing["myinfo"]===this){
channellist.prepend(thing);
break;
}
} }
} }
this.unreads(); this.unreads();
this.infinite.addedBottom();
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;
} }
console.log(this.notification);
if(this.notification==="all"){ if(this.notification==="all"){
this.notify(messagez); this.notify(messagez);
}else if(this.notification==="mentions"&&messagez.mentionsuser(this.localuser.user)){ }else if(this.notification==="mentions"&&messagez.mentionsuser(this.localuser.user)){
@@ -183,9 +173,9 @@ class Group extends Channel{
console.log(this); console.log(this);
div.append(buildpfp) div.append(buildpfp)
sentdms.append(div); sentdms.append(div);
div.onclick=function(){ div.onclick=_=>{
this["noti"].guild.loadGuild(); this.guild.loadGuild();
this["noti"].getHTML(); this.getHTML();
} }
}else if(current){ }else if(current){

View File

@@ -1,6 +1,6 @@
import {Fullscreen} from "./fullscreen.js"; import {Fullscreen} from "./fullscreen.js";
import {Message} from "./message.js"; import {Message} from "./message.js";
import {markdown} from "./markdown.js"; import {MarkDown} from "./markdown.js";
class Embed{ class Embed{
type:string; type:string;
@@ -29,6 +29,18 @@ class Embed{
return document.createElement("div");//prevent errors by giving blank div return document.createElement("div");//prevent errors by giving blank div
} }
} }
get message(){
return this.owner;
}
get channel(){
return this.message.channel;
}
get guild(){
return this.channel.guild;
}
get localuser(){
return this.guild.localuser;
}
generateRich(){ generateRich(){
console.log(this.json) console.log(this.json)
const div=document.createElement("div"); const div=document.createElement("div");
@@ -59,7 +71,7 @@ class Embed{
embed.append(authorline); embed.append(authorline);
} }
const title=document.createElement("a"); const title=document.createElement("a");
title.append(markdown(this.json.title)); title.append(new MarkDown(this.json.title,this.localuser).makeHTML());
if(this.json.url){ if(this.json.url){
title.href=this.json.url; title.href=this.json.url;
} }
@@ -68,7 +80,7 @@ class Embed{
if(this.json.description){ if(this.json.description){
const p=document.createElement("p"); const p=document.createElement("p");
p.append(markdown(this.json.description)); p.append(new MarkDown(this.json.description,this.channel).makeHTML());
embed.append(p); embed.append(p);
} }
@@ -80,7 +92,7 @@ class Embed{
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(markdown(thing.value)); p.append(new MarkDown(thing.value,this.channel).makeHTML());
p.classList.add("embedp"); p.classList.add("embedp");
div.append(p); div.append(p);

View File

@@ -34,8 +34,10 @@ class File{
full.show(); full.show();
} }
img.src=src; img.src=src;
img.height=this.height; if(this.width){
img.width=this.width; img.height=this.height;
img.width=this.width;
}
console.log(this.width,this.height) console.log(this.width,this.height)
return img; return img;
}else if(this.content_type.startsWith('video/')){ }else if(this.content_type.startsWith('video/')){

View File

@@ -3,7 +3,7 @@ import {Contextmenu} from "./contextmenu.js";
import {mobile, getBulkUsers,setTheme, Specialuser} from "./login.js"; import {mobile, getBulkUsers,setTheme, Specialuser} from "./login.js";
async function waitforload(){ async function waitforload(){
let res let res;
new Promise(r=>{res=r}); new Promise(r=>{res=r});
document.addEventListener("DOMContentLoaded", function(){ document.addEventListener("DOMContentLoaded", function(){
res(); res();
@@ -18,9 +18,6 @@ const users=getBulkUsers();
if(!users.currentuser){ if(!users.currentuser){
window.location.href = '/login.html'; window.location.href = '/login.html';
} }
var info=users.users[users.currentuser].serverurls;
let token=users.users[users.currentuser].token;
let READY;
let thisuser=new Localuser(users.users[users.currentuser]); let thisuser=new Localuser(users.users[users.currentuser]);
thisuser.initwebsocket().then(_=>{ thisuser.initwebsocket().then(_=>{
@@ -117,11 +114,6 @@ thisuser.initwebsocket().then(_=>{
menu.bind(document.getElementById("channels")) menu.bind(document.getElementById("channels"))
} }
function editchannelf(channel){channel.editChannel();}
const pasteimage=document.getElementById("pasteimage"); const pasteimage=document.getElementById("pasteimage");
let replyingto=null; let replyingto=null;
async function enter(event){ async function enter(event){
@@ -163,17 +155,6 @@ console.log(typebox)
typebox.onclick=console.log; typebox.onclick=console.log;
let serverz=0;
let serverid=[];
let cchanel=0;
function getguildinfo(){ function getguildinfo(){
const path=window.location.pathname.split("/"); const path=window.location.pathname.split("/");
const channel=path[3]; const channel=path[3];
@@ -183,50 +164,7 @@ function getguildinfo(){
const images:Blob[]=[]; const images:Blob[]=[];
const imageshtml=[]; const imageshtml=[];
function createunknown(fname,fsize){
const div=document.createElement("table");
div.classList.add("unknownfile");
const nametr=document.createElement("tr");
div.append(nametr);
const fileicon=document.createElement("td");
nametr.append(fileicon);
fileicon.append("🗎");
fileicon.classList.add("fileicon");
fileicon.rowSpan=2;
const nametd=document.createElement("td");
{
nametd.textContent=fname;
}
nametd.classList.add("filename");
nametr.append(nametd);
const sizetr=document.createElement("tr");
const size=document.createElement("td");
sizetr.append(size);
size.textContent="Size:"+filesizehuman(fsize);
size.classList.add("filesize");
div.appendChild(sizetr)
return div;
}
function filesizehuman(fsize){
var 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];
}
function createunknownfile(file){
return createunknown(file.name,file.size)
}
function filetohtml(file){
if (file.type.startsWith('image/')) {
const img = document.createElement('img');
const blob = URL.createObjectURL(file);
img.src = blob;
return img;
}else{
console.log(file.name);
return createunknownfile(file);
}
}
import { File } from "./file.js"; import { File } from "./file.js";
document.addEventListener('paste', async (e) => { document.addEventListener('paste', async (e) => {
Array.from(e.clipboardData.files).forEach(async (f) => { Array.from(e.clipboardData.files).forEach(async (f) => {
@@ -245,17 +183,6 @@ function userSettings(){
thisuser.usersettings.show(); thisuser.usersettings.show();
} }
document.getElementById("settings").onclick=userSettings; document.getElementById("settings").onclick=userSettings;
function userConnections(){
thisuser.userConnections.show();
}
document.getElementById("connections").onclick=userConnections;
function devPortal(){
thisuser.devPortal.show();
}
document.getElementById("dev-portal").onclick=devPortal;
let triggered=false; let triggered=false;
document.getElementById("messagecontainer").addEventListener("scroll",(e)=>{ document.getElementById("messagecontainer").addEventListener("scroll",(e)=>{
const messagecontainer=document.getElementById("messagecontainer") const messagecontainer=document.getElementById("messagecontainer")
@@ -289,20 +216,3 @@ if(mobile){
document.getElementById("servers").classList.remove("collapse"); document.getElementById("servers").classList.remove("collapse");
} }
} }
/*
{
const messages=document.getElementById("messages");
let height=messages.clientHeight;
//
const resizeObserver=new ResizeObserver(()=>{
console.log(messages.scrollTop,messages.clientHeight-height-messages.scrollHeight);
messages.scrollTop-=height-messages.scrollHeight;
console.log(messages.scrollTop)
//if(shouldsnap){
// document.getElementById("messagecontainer").scrollTop = document.getElementById("messagecontainer").scrollHeight;
//}
height=messages.scrollHeight;
})
resizeObserver.observe(messages)
}
*/

148
webpage/infiniteScroller.ts Normal file
View File

@@ -0,0 +1,148 @@
class InfiniteScroller{
readonly getIDFromOffset:(ID:string,offset:number)=>Promise<string>;
readonly getHTMLFromID:(ID:string)=>HTMLElement;
readonly destroyFromID:(ID:string)=>Promise<boolean>;
readonly reachesBottom:()=>void;
private readonly minDist=3000;
private readonly maxDist=8000;
HTMLElements:[HTMLElement,string][]=[];
div:HTMLDivElement;
scroll:HTMLDivElement;
constructor(getIDFromOffset:InfiniteScroller["getIDFromOffset"],getHTMLFromID:InfiniteScroller["getHTMLFromID"],destroyFromID:InfiniteScroller["destroyFromID"],reachesBottom:InfiniteScroller["reachesBottom"]=()=>{}){
this.getIDFromOffset=getIDFromOffset;
this.getHTMLFromID=getHTMLFromID;
this.destroyFromID=destroyFromID;
this.reachesBottom=reachesBottom;
}
interval:NodeJS.Timeout;
getDiv(initialId:string,bottom=true):HTMLDivElement{
const div=document.createElement("div");
div.classList.add("messagecontainer");
//div.classList.add("flexttb")
const scroll=document.createElement("div");
scroll.classList.add("flexttb","scroller")
div.append(scroll);
this.div=div;
this.interval=setInterval(this.updatestuff.bind(this),100);
this.scroll=scroll;
this.scroll.addEventListener("scroll",this.watchForChange.bind(this));
new ResizeObserver(this.watchForChange.bind(this)).observe(div);
new ResizeObserver(this.watchForChange.bind(this)).observe(scroll);
this.firstElement(initialId);
this.updatestuff();
this.watchForChange().then(_=>{
this.scroll.scrollTop=this.scroll.scrollHeight;
})
return div;
}
scrollBottom:number;
scrollTop:number;
updatestuff(){
this.scrollBottom = this.scroll.scrollHeight - this.scroll.scrollTop - this.scroll.clientHeight;
this.scrollTop=this.scroll.scrollTop;
if(this.scrollBottom){
this.reachesBottom();
}
//this.watchForChange();
}
firstElement(id:string){
const html=this.getHTMLFromID(id);
this.scroll.append(html);
this.HTMLElements.push([html,id]);
}
currrunning:boolean=false;
async addedBottom(){
this.updatestuff();
const scrollBottom=this.scrollBottom;
await this.watchForChange();
if(scrollBottom<30){
this.scroll.scrollTop=this.scroll.scrollHeight;
}
}
async watchForChange():Promise<void>{
if(this.currrunning){
return;
}else{
this.currrunning=true;
}
let again=false;
if(!this.div){this.currrunning=false;return}
/*
if(this.scrollTop===0){
this.scrollTop=10;
}
*/
if(this.scrollTop===0){
this.scrollTop=1;
this.scroll.scrollTop=1;
}
if(this.scrollTop<this.minDist){
const previd=this.HTMLElements.at(0)[1];
const nextid=await this.getIDFromOffset(previd,1);
if(!nextid){
}else{
again=true;
const html=this.getHTMLFromID(nextid);
this.scroll.prepend(html);
this.HTMLElements.unshift([html,nextid]);
this.scrollTop+=60;
};
}
if(this.scrollTop>this.maxDist){
again=true;
const html=this.HTMLElements.shift();
await this.destroyFromID(html[1]);
this.scrollTop-=60;
}
const scrollBottom = this.scrollBottom;
if(scrollBottom<this.minDist){
const previd=this.HTMLElements.at(-1)[1];
const nextid=await this.getIDFromOffset(previd,-1);
if(!nextid){
}else{
again=true;
const html=this.getHTMLFromID(nextid);
this.scroll.append(html);
this.HTMLElements.push([html,nextid]);
this.scrollBottom+=60;
if(scrollBottom<30){
this.scroll.scrollTop=this.scroll.scrollHeight;
}
};
}
if(scrollBottom>this.maxDist){
again=true;
const html=this.HTMLElements.pop();
await this.destroyFromID(html[1]);
this.scrollBottom-=60;
}
this.currrunning=false;
if(again){
await this.watchForChange();
}
this.currrunning=false;
}
async delete():Promise<void>{
for(const thing of this.HTMLElements){
await this.destroyFromID(thing[1]);
}
this.HTMLElements=[];
clearInterval(this.interval);
if(this.div){
this.div.remove();
}
this.scroll=null;
this.div=null;
}
}
export {InfiniteScroller};

View File

@@ -4,7 +4,7 @@ import {Direct} from "./direct.js";
import {Voice} from "./audio.js"; import {Voice} from "./audio.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 {Fullscreen} from "./fullscreen.js"; import {Fullscreen} from "./fullscreen.js";
import {setTheme, Specialuser} from "./login.js"; import {setTheme, Specialuser} from "./login.js";
@@ -93,7 +93,7 @@ class Localuser{
outoffocus():void{ outoffocus():void{
document.getElementById("servers").textContent=""; document.getElementById("servers").textContent="";
document.getElementById("channels").textContent=""; document.getElementById("channels").textContent="";
document.getElementById("messages").textContent=""; this.channelfocus.infinite.delete();
this.lookingguild=null; this.lookingguild=null;
this.channelfocus=null; this.channelfocus=null;
} }
@@ -156,22 +156,8 @@ class Localuser{
returny(); returny();
break; break;
case "MESSAGE_UPDATE": case "MESSAGE_UPDATE":
if(this.initialized){ const message=this.resolveChannelFromID(temp.d.channel_id).messageids[temp.d.id];
if(this.channelfocus.id===temp.d.channel_id){ message.giveData(temp.d);
const find=temp.d.id;
const messagelist=document.getElementById("messages").children;
for(const message of messagelist){
const all = message["all"];
if(all.id===find){
all.content=temp.d.content;
message["txt"].innerHTML=markdown(temp.d.content).innerHTML;
break;
}
}
}else{
this.resolveChannelFromID(temp.d.channel_id).messages.find(e=>e.id===temp.d.channel_id).content=temp.d.content;
}
}
break; break;
case "TYPING_START": case "TYPING_START":
if(this.initialized){ if(this.initialized){
@@ -547,7 +533,7 @@ class Localuser{
reader.readAsDataURL(file); reader.readAsDataURL(file);
console.log(this.headers); console.log(this.headers);
reader.onload = ()=>{ reader.onload = ()=>{
fetch(this.info.api.toString()+"/v9/users/@me",{ fetch(this.info.api.toString()+"/users/@me",{
method:"PATCH", method:"PATCH",
headers:this.headers, headers:this.headers,
body:JSON.stringify({ body:JSON.stringify({
@@ -559,7 +545,7 @@ class Localuser{
} }
updatepronouns(pronouns:string):void{ updatepronouns(pronouns:string):void{
fetch(this.info.api.toString()+"/v9/users/@me/profile",{ fetch(this.info.api.toString()+"/users/@me/profile",{
method:"PATCH", method:"PATCH",
headers:this.headers, headers:this.headers,
body:JSON.stringify({ body:JSON.stringify({
@@ -642,7 +628,7 @@ class Localuser{
newbio=this.value; newbio=this.value;
regen(); regen();
}], }],
["button","update user content:","submit",function(){ ["button","update user content:","submit",()=>{
if(file!==null){ if(file!==null){
this.updatepfp(file); this.updatepfp(file);
} }

View File

@@ -1,409 +1,444 @@
export {markdown}; import { Channel } from "./channel";
function markdown(text : string|string[],{keep=false,stdsize=false} = {}){ import { Localuser } from "./localuser";
let txt : string[];
if((typeof txt)==="string"){ export {MarkDown};
txt=(text as string).split(""); class MarkDown{
}else{ txt : string[];
txt=(text as string[]); keep:boolean;
} stdsize:boolean;
const span=document.createElement("span"); owner:Localuser|Channel;
let current=document.createElement("span"); info:Localuser["info"];
function appendcurrent(){ constructor(text : string|string[],owner:MarkDown["owner"],{keep=false,stdsize=false} = {}){
if(current.innerHTML!==""){ if((typeof text)===(typeof "")){
span.append(current); this.txt=(text as string).split("");
current=document.createElement("span"); }else{
this.txt=(text as string[]);
} }
if(this.txt===undefined){
this.txt=[];
}
this.info=owner.info;
this.keep=keep;
this.owner=owner;
this.stdsize=stdsize;
} }
for(let i=0;i<txt.length;i++){ get rawString(){
if(txt[i]==="\n"||i===0){ return this.txt.concat("");
const first=i===0; }
if(first){ get textContent(){
i--; return this.makeHTML().textContent;
}
makeHTML({keep=this.keep,stdsize=this.stdsize}={}){
return this.markdown(this.txt,{keep:keep,stdsize:stdsize});
}
markdown(text : string|string[],{keep=false,stdsize=false} = {}){
let txt : string[];
if((typeof text)===(typeof "")){
txt=(text as string).split("");
}else{
txt=(text as string[]);
}
if(txt===undefined){
txt=[];
}
const span=document.createElement("span");
let current=document.createElement("span");
function appendcurrent(){
if(current.innerHTML!==""){
span.append(current);
current=document.createElement("span");
} }
let element=null;
let keepys="";
if(txt[i+1]==="#"){ }
console.log("test"); for(let i=0;i<txt.length;i++){
if(txt[i+2]==="#"){ if(txt[i]==="\n"||i===0){
if(txt[i+3]==="#"&&txt[i+4]===" "){ const first=i===0;
element=document.createElement("h3"); if(first){
keepys="### "; i--;
i+=5; }
}else if(txt[i+3]===" "){ let element=null;
element=document.createElement("h2"); let keepys="";
element.classList.add("h2md");
keepys="## "; if(txt[i+1]==="#"){
i+=4; console.log("test");
if(txt[i+2]==="#"){
if(txt[i+3]==="#"&&txt[i+4]===" "){
element=document.createElement("h3");
keepys="### ";
i+=5;
}else if(txt[i+3]===" "){
element=document.createElement("h2");
element.classList.add("h2md");
keepys="## ";
i+=4;
}
}else if(txt[i+2]===" "){
element=document.createElement("h1");
keepys="# ";
i+=3;
} }
}else if(txt[i+2]===" "){ }else if(txt[i+1]===">"&&txt[i+2]===" "){
element=document.createElement("h1"); element=document.createElement("div");
keepys="# "; const line=document.createElement("div");
line.classList.add("quoteline");
element.append(line);
element.classList.add("quote");
keepys="> ";
i+=3; i+=3;
} }
}else if(txt[i+1]===">"&&txt[i+2]===" "){ if(keepys){
element=document.createElement("div"); appendcurrent();
const line=document.createElement("div"); if(!first&&!stdsize){
line.classList.add("quoteline"); span.appendChild(document.createElement("br"));
element.append(line); }
element.classList.add("quote"); const build=[];
keepys="> "; for(;txt[i]!=="\n"&&txt[i]!==undefined;i++){
i+=3; build.push(txt[i]);
} }
if(keepys){ if(stdsize){
appendcurrent(); element=document.createElement("span");
if(!first&&!stdsize){ }
span.appendChild(document.createElement("br")); if(keep){
element.append(keepys);
}
element.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
span.append(element);
i--;
continue;
} }
const build=[]; if(first){
for(;txt[i]!=="\n"&&txt[i]!==undefined;i++){ i++;
build.push(txt[i]); }
}
if(txt[i]==="\n"){
if(!stdsize){
appendcurrent();
span.append(document.createElement("br"));
}
continue;
}
if(txt[i]==="`"){
let count=1;
if(txt[i+1]==="`"){
count++;
if(txt[i+2]==="`"){
count++;
}
}
let build="";
if(keep){
build+="`".repeat(count);
}
let find=0;
let j=i+count;
let init=true;
for(;txt[j]!==undefined&&(txt[j]!=="\n"||count===3)&&find!==count;j++){
if(txt[j]==="`"){
find++;
}else{
if(find!==0){
build+="`".repeat(find);
find=0;
}
if(init&&count===3){
if(txt[j]===" "||txt[j]==="\n"){
init=false;
}
if(keep){
build+=txt[j];
}
continue;
}
build+=txt[j];
}
} }
if(stdsize){ if(stdsize){
element=document.createElement("span"); console.log(build);
build=build.replaceAll("\n","");
console.log(build,JSON.stringify(build));
} }
if(keep){ if(find===count){
element.append(keepys);
}
element.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
span.append(element);
i--;
continue;
}
if(first){
i++;
}
}
if(txt[i]==="\n"){
if(!stdsize){
appendcurrent();
span.append(document.createElement("br"));
}
continue;
}
if(txt[i]==="`"){
let count=1;
if(txt[i+1]==="`"){
count++;
if(txt[i+2]==="`"){
count++;
}
}
let build="";
if(keep){
build+="`".repeat(count);
}
let find=0;
let j=i+count;
let init=true;
for(;txt[j]!==undefined&&(txt[j]!=="\n"||count===3)&&find!==count;j++){
if(txt[j]==="`"){
find++;
}else{
if(find!==0){
build+="`".repeat(find);
find=0;
}
if(init&&count===3){
if(txt[j]===" "||txt[j]==="\n"){
init=false;
}
if(keep){
build+=txt[j];
}
continue;
}
build+=txt[j];
}
}
if(stdsize){
console.log(build);
build=build.replaceAll("\n","");
console.log(build,JSON.stringify(build));
}
if(find===count){
appendcurrent();
i=j;
if(keep){
build+="`".repeat(find);
}
if(count!==3&&!stdsize){
const samp=document.createElement("samp");
samp.textContent=build;
span.appendChild(samp);
}else{
const pre=document.createElement("pre");
if(build[build.length-1]==="\n"){
build=build.substring(0,build.length-1);
}
if(txt[i]==="\n"){
i++
}
pre.textContent=build;
span.appendChild(pre);
}
i--;
continue;
}
}
if(txt[i]==="*"){
let count=1;
if(txt[i+1]==="*"){
count++;
if(txt[i+2]==="*"){
count++;
}
}
let build=[];
let find=0;
let j=i+count;
for(;txt[j]!==undefined&&find!==count;j++){
if(txt[j]==="*"){
find++;
}else{
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("*"));
find=0;
}
}
}
if(find===count&&(count!=1||txt[i+1]!==" ")){
appendcurrent();
i=j;
const stars="*".repeat(count);
if(count===1){
const i=document.createElement("i");
if(keep){i.append(stars)}
i.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){i.append(stars)}
span.appendChild(i);
}else if(count===2){
const b=document.createElement("b");
if(keep){b.append(stars)}
b.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){b.append(stars)}
span.appendChild(b);
}else{
const b=document.createElement("b");
const i=document.createElement("i");
if(keep){b.append(stars)}
b.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){b.append(stars)}
i.appendChild(b);
span.appendChild(i);
}
i--
continue;
}
}
if(txt[i]==="_"){
let count=1;
if(txt[i+1]==="_"){
count++;
if(txt[i+2]==="_"){
count++;
}
}
let build=[];
let find=0;
let j=i+count;
for(;txt[j]!==undefined&&find!==count;j++){
if(txt[j]==="_"){
find++;
}else{
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("_"));
find=0;
}
}
}
if(find===count&&(count!=1||(txt[j+1]===" "||txt[j+1]==="\n"||txt[j+1]===undefined))){
appendcurrent();
i=j;
const underscores="_".repeat(count);
if(count===1){
const i=document.createElement("i");
if(keep){i.append(underscores)}
i.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){i.append(underscores)}
span.appendChild(i);
}else if(count===2){
const u=document.createElement("u");
if(keep){u.append(underscores)}
u.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){u.append(underscores)}
span.appendChild(u);
}else{
const u=document.createElement("u");
const i=document.createElement("i");
if(keep){i.append(underscores)}
i.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){i.append(underscores)}
u.appendChild(i)
span.appendChild(u);
}
i--;
continue;
}
}
if(txt[i]==="~"&&txt[i+1]==="~"){
let count=2;
let build=[];
let find=0;
let j=i+2;
for(;txt[j]!==undefined&&find!==count;j++){
if(txt[j]==="~"){
find++;
}else{
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("~"));
find=0;
}
}
}
if(find===count){
appendcurrent();
i=j;
const tildes="~~";
if(count===2){
const s=document.createElement("s");
if(keep){s.append(tildes)}
s.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){s.append(tildes)}
span.appendChild(s);
}
continue;
}
}
if(txt[i]==="|"&&txt[i+1]==="|"){
let count=2;
let build=[];
let find=0;
let j=i+2;
for(;txt[j]!==undefined&&find!==count;j++){
if(txt[j]==="|"){
find++;
}else{
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("~"));
find=0;
}
}
}
if(find===count){
appendcurrent();
i=j;
const pipes="||";
if(count===2){
const j=document.createElement("j");
if(keep){j.append(pipes)}
j.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
j.classList.add("spoiler");
j.onclick=markdown.unspoil;
if(keep){j.append(pipes)}
span.appendChild(j);
}
continue;
}
}
if (txt[i]==="<" && txt[i + 1]==="t" && txt[i + 2]===":") {
let found=false;
const build=["<","t",":"];
let j = i+3;
for (; txt[j] !== void 0; j++) {
build.push(txt[j]);
if (txt[j]===">") {
found=true;
break;
}
}
if (found) {
appendcurrent();
i=j;
const parts=build.join("").match(/^<t:([0-9]{1,16})(:([tTdDfFR]))?>$/);
const dateInput=new Date(Number.parseInt(parts[1]) * 1000);
let time="";
if (Number.isNaN(dateInput.getTime())) time=build.join("");
else {
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] || parts[3]==="f") time=dateInput.toLocaleString(void 0, {day: "numeric", month: "long", year: "numeric"}) + " " +
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"}) + " " +
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]==="R") time=Math.round((Date.now() - (Number.parseInt(parts[1]) * 1000))/1000/60) + " minutes ago";
}
const timeElem=document.createElement("span");
timeElem.classList.add("markdown-timestamp");
timeElem.textContent=time;
span.appendChild(timeElem);
continue;
}
}
if (txt[i] === "<" && (txt[i + 1] === ":" || (txt[i + 1] === "a" && txt[i + 2] === ":"))) {
let found=false;
const build = txt[i + 1] === "a" ? ["<","a",":"] : ["<",":"];
let j = i+build.length;
for (; txt[j] !== void 0; j++) {
build.push(txt[j]);
if (txt[j]===">") {
found=true;
break;
}
}
if (found) {
const parts=build.join("").match(/^<(a)?:\w+:(\d{10,30})>$/);
if (parts && parts[2]) {
appendcurrent(); appendcurrent();
i=j; i=j;
if(keep){
const isEmojiOnly = txt.join("").trim()===build.join("").trim(); build+="`".repeat(find);
}
const emojiElem=document.createElement("img"); if(count!==3&&!stdsize){
emojiElem.classList.add("md-emoji"); const samp=document.createElement("samp");
emojiElem.width=isEmojiOnly ? 48 : 22; samp.textContent=build;
emojiElem.height=isEmojiOnly ? 48 : 22; span.appendChild(samp);
emojiElem.crossOrigin="anonymous"; }else{
emojiElem.src=this.info.cdn.toString() + "/emojis/" + parts[2] + "." + (parts[1] ? "gif" : "png") + "?size=32"; const pre=document.createElement("pre");
emojiElem.alt=""; if(build[build.length-1]==="\n"){
emojiElem.loading="lazy"; build=build.substring(0,build.length-1);
span.appendChild(emojiElem); }
if(txt[i]==="\n"){
i++
}
pre.textContent=build;
span.appendChild(pre);
}
i--;
continue; continue;
} }
} }
if(txt[i]==="*"){
let count=1;
if(txt[i+1]==="*"){
count++;
if(txt[i+2]==="*"){
count++;
}
}
let build=[];
let find=0;
let j=i+count;
for(;txt[j]!==undefined&&find!==count;j++){
if(txt[j]==="*"){
find++;
}else{
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("*"));
find=0;
}
}
}
if(find===count&&(count!=1||txt[i+1]!==" ")){
appendcurrent();
i=j;
const stars="*".repeat(count);
if(count===1){
const i=document.createElement("i");
if(keep){i.append(stars)}
i.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){i.append(stars)}
span.appendChild(i);
}else if(count===2){
const b=document.createElement("b");
if(keep){b.append(stars)}
b.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){b.append(stars)}
span.appendChild(b);
}else{
const b=document.createElement("b");
const i=document.createElement("i");
if(keep){b.append(stars)}
b.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){b.append(stars)}
i.appendChild(b);
span.appendChild(i);
}
i--
continue;
}
}
if(txt[i]==="_"){
let count=1;
if(txt[i+1]==="_"){
count++;
if(txt[i+2]==="_"){
count++;
}
}
let build=[];
let find=0;
let j=i+count;
for(;txt[j]!==undefined&&find!==count;j++){
if(txt[j]==="_"){
find++;
}else{
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("_"));
find=0;
}
}
}
if(find===count&&(count!=1||(txt[j+1]===" "||txt[j+1]==="\n"||txt[j+1]===undefined))){
appendcurrent();
i=j;
const underscores="_".repeat(count);
if(count===1){
const i=document.createElement("i");
if(keep){i.append(underscores)}
i.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){i.append(underscores)}
span.appendChild(i);
}else if(count===2){
const u=document.createElement("u");
if(keep){u.append(underscores)}
u.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){u.append(underscores)}
span.appendChild(u);
}else{
const u=document.createElement("u");
const i=document.createElement("i");
if(keep){i.append(underscores)}
i.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){i.append(underscores)}
u.appendChild(i)
span.appendChild(u);
}
i--;
continue;
}
}
if(txt[i]==="~"&&txt[i+1]==="~"){
let count=2;
let build=[];
let find=0;
let j=i+2;
for(;txt[j]!==undefined&&find!==count;j++){
if(txt[j]==="~"){
find++;
}else{
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("~"));
find=0;
}
}
}
if(find===count){
appendcurrent();
i=j;
const tildes="~~";
if(count===2){
const s=document.createElement("s");
if(keep){s.append(tildes)}
s.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){s.append(tildes)}
span.appendChild(s);
}
continue;
}
}
if(txt[i]==="|"&&txt[i+1]==="|"){
let count=2;
let build=[];
let find=0;
let j=i+2;
for(;txt[j]!==undefined&&find!==count;j++){
if(txt[j]==="|"){
find++;
}else{
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("~"));
find=0;
}
}
}
if(find===count){
appendcurrent();
i=j;
const pipes="||";
if(count===2){
const j=document.createElement("j");
if(keep){j.append(pipes)}
j.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize}));
j.classList.add("spoiler");
j.onclick=MarkDown.unspoil;
if(keep){j.append(pipes)}
span.appendChild(j);
}
continue;
}
}
if (txt[i]==="<" && txt[i + 1]==="t" && txt[i + 2]===":") {
let found=false;
const build=["<","t",":"];
let j = i+3;
for (; txt[j] !== void 0; j++) {
build.push(txt[j]);
if (txt[j]===">") {
found=true;
break;
}
}
if (found) {
appendcurrent();
i=j;
const parts=build.join("").match(/^<t:([0-9]{1,16})(:([tTdDfFR]))?>$/);
const dateInput=new Date(Number.parseInt(parts[1]) * 1000);
let time="";
if (Number.isNaN(dateInput.getTime())) time=build.join("");
else {
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] || parts[3]==="f") time=dateInput.toLocaleString(void 0, {day: "numeric", month: "long", year: "numeric"}) + " " +
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"}) + " " +
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]==="R") time=Math.round((Date.now() - (Number.parseInt(parts[1]) * 1000))/1000/60) + " minutes ago";
}
const timeElem=document.createElement("span");
timeElem.classList.add("markdown-timestamp");
timeElem.textContent=time;
span.appendChild(timeElem);
continue;
}
}
if (txt[i] === "<" && (txt[i + 1] === ":" || (txt[i + 1] === "a" && txt[i + 2] === ":"))) {
let found=false;
const build = txt[i + 1] === "a" ? ["<","a",":"] : ["<",":"];
let j = i+build.length;
for (; txt[j] !== void 0; j++) {
build.push(txt[j]);
if (txt[j]===">") {
found=true;
break;
}
}
if (found) {
const buildjoin=build.join("");
const parts=buildjoin.match(/^<(a)?:\w+:(\d{10,30})>$/);
if (parts && parts[2]) {
appendcurrent();
i=j;
const isEmojiOnly = txt.join("").trim()===buildjoin.trim();
const emojiElem=document.createElement("img");
emojiElem.classList.add("md-emoji");
emojiElem.classList.add(isEmojiOnly ? "bigemoji" : "smallemoji");
emojiElem.crossOrigin="anonymous";
emojiElem.src=this.info.cdn.toString() + "emojis/" + parts[2] + "." + (parts[1] ? "gif" : "png") + "?size=32";
emojiElem.alt=buildjoin;
emojiElem.loading="lazy";
span.appendChild(emojiElem);
continue;
}
}
}
current.textContent+=txt[i];
} }
appendcurrent();
current.textContent+=txt[i]; return span;
}
static unspoil(e:any) : void{
e.target.classList.remove("spoiler")
e.target.classList.add("unspoiled")
} }
appendcurrent();
return span;
}
markdown.unspoil=function(e:any) : void{
//console.log("undone")
e.target.classList.remove("spoiler")
e.target.classList.add("unspoiled")
} }

View File

@@ -1,9 +1,8 @@
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 {Fullscreen} from "./fullscreen.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";
@@ -22,7 +21,7 @@ class Message{
message_reference; message_reference;
type:number; type:number;
timestamp:number; timestamp:number;
content:string; content:MarkDown;
static del:Promise<void>; static del:Promise<void>;
static resolve:Function; static resolve:Function;
div:HTMLDivElement; div:HTMLDivElement;
@@ -38,7 +37,7 @@ class Message{
} }
static setupcmenu(){ static setupcmenu(){
Message.contextmenu.addbutton("Copy raw text",function(){ Message.contextmenu.addbutton("Copy raw text",function(){
navigator.clipboard.writeText(this.content); navigator.clipboard.writeText(this.content.rawString);
}); });
Message.contextmenu.addbutton("Reply",function(this:Message,div:HTMLDivElement){ Message.contextmenu.addbutton("Reply",function(this:Message,div:HTMLDivElement){
this.channel.setReplying(this); this.channel.setReplying(this);
@@ -57,6 +56,10 @@ class Message{
constructor(messagejson,owner:Channel){ constructor(messagejson,owner:Channel){
this.owner=owner; this.owner=owner;
this.headers=this.owner.headers; this.headers=this.owner.headers;
this.giveData(messagejson);
}
giveData(messagejson){
for(const thing of Object.keys(messagejson)){ for(const thing of Object.keys(messagejson)){
if(thing==="attachments"){ if(thing==="attachments"){
this.attachments=[]; this.attachments=[];
@@ -64,6 +67,9 @@ class Message{
this.attachments.push(new File(thing,this)); this.attachments.push(new File(thing,this));
} }
continue; continue;
}else if(thing==="content"){
this.content=new MarkDown(messagejson[thing],this.channel);
continue;
} }
this[thing]=messagejson[thing]; this[thing]=messagejson[thing];
} }
@@ -81,6 +87,9 @@ class Message{
if(this.mentionsuser(this.localuser.user)){ if(this.mentionsuser(this.localuser.user)){
console.log(this); console.log(this);
} }
if(this.div){
this.generateMessage();
}
} }
canDelete(){ canDelete(){
return this.channel.hasPermission("MANAGE_MESSAGES")||this.author.id===this.localuser.user.id; return this.channel.hasPermission("MANAGE_MESSAGES")||this.author.id===this.localuser.user.id;
@@ -97,11 +106,12 @@ class Message{
get info(){ get info(){
return this.owner.info; return this.owner.info;
} }
messageevents(obj:HTMLDivElement){ messageevents(obj:HTMLDivElement,del=Message.del){
const func=Message.contextmenu.bind(obj,this); const func=Message.contextmenu.bind(obj,this);
this.div=obj; this.div=obj;
Message.del.then(_=>{ del.then(_=>{
obj.removeEventListener("click",func); obj.removeEventListener("click",func);
this.div.remove();
this.div=null; this.div=null;
}) })
obj.classList.add("messagediv"); obj.classList.add("messagediv");
@@ -140,17 +150,19 @@ class Message{
this.div.innerHTML=""; this.div.innerHTML="";
this.div=null; this.div=null;
} }
const index=this.channel.messages.indexOf(this); const prev=this.channel.idToPrev[this.id];
this.channel.messages.splice(this.channel.messages.indexOf(this),1); const next=this.channel.idToNext[this.id];
this.channel.idToNext[prev]=next;
this.channel.idToPrev[next]=prev;
delete this.channel.messageids[this.id]; delete this.channel.messageids[this.id];
const regen=this.channel.messages[index-1] const regen=this.channel.messageids[prev]
if(regen){ if(regen){
regen.generateMessage(); regen.generateMessage();
} }
} }
generateMessage(premessage:Message=null){ generateMessage(premessage:Message=null){
if(!premessage){ if(!premessage){
premessage=this.channel.messages[this.channel.messages.indexOf(this)+1]; premessage=this.channel.messageids[this.channel.idToNext[this.id]];
} }
const div=this.div; const div=this.div;
if(this===this.channel.replyingto){ if(this===this.channel.replyingto){
@@ -201,7 +213,7 @@ class Message{
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=>{
const author=message.author; const author=message.author;
reply.appendChild(markdown(message.content,{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;
@@ -209,8 +221,6 @@ class Message{
}); });
div.appendChild(replyline); div.appendChild(replyline);
} }
this.messageevents(div);
build.classList.add("message"); build.classList.add("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){
@@ -264,7 +274,7 @@ class Message{
}else{ }else{
div.classList.remove("topMessage"); div.classList.remove("topMessage");
} }
const messaged=markdown(this.content); 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")
@@ -313,11 +323,13 @@ class Message{
div["all"]=this; div["all"]=this;
return(div) return(div)
} }
buildhtml(premessage:Message){ buildhtml(premessage:Message,del:Promise<void>=Message.del){
if(this.div){console.error(`HTML for ${this} already exists, aborting`);return;} if(this.div){console.error(`HTML for ${this.id} already exists, aborting`);return;}
//premessage??=messages.lastChild; //premessage??=messages.lastChild;
const div=document.createElement("div"); const div=document.createElement("div");
this.div=div; this.div=div;
this.messageevents(div,del);
return this.generateMessage(premessage); return this.generateMessage(premessage);
} }
} }

View File

@@ -58,4 +58,4 @@ async function tosLogic(){
} }
tosLogic(); tosLogic();
checkInstance.alt=tosLogic; checkInstance["alt"]=tosLogic;

View File

@@ -74,6 +74,8 @@ th {
flex-wrap: nowrap; flex-wrap: nowrap;
flex-direction: column; flex-direction: column;
max-height: 20in; max-height: 20in;
flex-shrink: 0;
width: 100%;
} }
pre { pre {
background-color: var(--code-bg); background-color: var(--code-bg);
@@ -215,6 +217,8 @@ img {
vertical-align: middle; vertical-align: middle;
max-width: 3in; max-width: 3in;
max-height: 3in; max-height: 3in;
width: auto;
height: auto;
} }
#page { #page {
@@ -242,8 +246,8 @@ img {
font-weight: normal; font-weight: normal;
} }
#messagecontainer { .messagecontainer {
overflow-y: auto; overflow-y: hidden;
display: flex; display: flex;
max-width: 100%; max-width: 100%;
flex-shrink: 1; flex-shrink: 1;
@@ -547,18 +551,18 @@ p {
grid-column: 2; grid-column: 2;
} }
.replytext pre { .replytext pre {
padding: 0 .05in; /* padding: 0 .05in; */
color: var(--reply-text); color: var(--reply-text);
overflow: hidden; /* overflow: hidden; */
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
max-width: fit-content; max-width: fit-content;
/* display: block; */ /* display: block; */
/* flex-grow: 1; */ /* flex-grow: 1; */
flex: 1 1 auto; flex: 1 1 auto;
width: fit-content; /* width: fit-content; */
min-width: 0; min-width: 0;
/* display: inline-block !important; */ display: inline-block !important;
width: 25vw; width: 25vw;
grid-column: 2; grid-column: 2;
} }
@@ -723,7 +727,7 @@ textarea {
} }
.servernamediv { .servernamediv {
/* width: 100%; */ width: 99%;
/* max-width: 100%; */ /* max-width: 100%; */
} }
@@ -1167,6 +1171,7 @@ span {
/* margin-bottom: 1in; */ /* margin-bottom: 1in; */
/* padding-bottom: .1in; */ /* padding-bottom: .1in; */
align-items: flex-start; align-items: flex-start;
width: 100%;
} }
.settingbuttons{ .settingbuttons{
padding-top:.075in; padding-top:.075in;
@@ -1346,7 +1351,7 @@ span {
overflow: hidden; overflow: hidden;
flex-wrap: wrap; flex-wrap: wrap;
width: 100%; width: 100%;
flex-direction: row; flex-direction: column;
max-height:100in; max-height:100in;
} }
@@ -1366,3 +1371,15 @@ span {
background-color: var(--embed-fallback); background-color: var(--embed-fallback);
cursor: not-allowed; cursor: not-allowed;
} }
.sizeupdown{
height:4in;
}
.bigemoji{
width:48px;
height:48px;
}
.smallemoji{
width:22px;
height:22px;
}

View File

@@ -1,6 +1,6 @@
//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";
@@ -12,7 +12,7 @@ class User{
id:string; id:string;
avatar:string; avatar:string;
username:string; username:string;
bio:string; bio:MarkDown;
discriminator:string; discriminator:string;
pronouns:string; pronouns:string;
bot:boolean; bot:boolean;
@@ -49,6 +49,10 @@ class User{
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"){
this.bio=new MarkDown(userjson[thing],this.localuser);
continue;
}
this[thing]=userjson[thing]; this[thing]=userjson[thing];
} }
this.hypotheticalpfp=false; this.hypotheticalpfp=false;
@@ -152,7 +156,7 @@ class User{
const rule=document.createElement("hr"); const rule=document.createElement("hr");
userbody.appendChild(rule); userbody.appendChild(rule);
const biohtml=markdown(this.bio); const biohtml=this.bio.makeHTML();
userbody.appendChild(biohtml); userbody.appendChild(biohtml);
} }
console.log(div); console.log(div);