diff --git a/.dist/channel.js b/.dist/channel.js index ac24437..3efee21 100644 --- a/.dist/channel.js +++ b/.dist/channel.js @@ -3,16 +3,15 @@ import { Message } from "./message.js"; import { Voice } from "./audio.js"; import { Contextmenu } from "./contextmenu.js"; import { Fullscreen } from "./fullscreen.js"; -import { markdown } from "./markdown.js"; import { Permissions } from "./permissions.js"; import { Settings, RoleList } from "./settings.js"; +import { InfiniteScroller } from "./infiniteScroller.js"; Settings; class Channel { editing; type; owner; headers; - messages; name; id; parent_id; @@ -35,6 +34,9 @@ class Channel { allthewayup; static contextmenu = new Contextmenu("channel menu"); replyingto; + infinite; + idToPrev = {}; + idToNext = {}; static setupcontextmenu() { this.contextmenu.addbutton("Copy channel id", function () { console.log(this); @@ -68,6 +70,33 @@ class Channel { 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) { if (JSON === -1) { return; @@ -76,7 +105,6 @@ class Channel { this.type = JSON.type; this.owner = owner; this.headers = this.owner.headers; - this.messages = []; this.name = JSON.name; this.id = JSON.id; this.parent_id = JSON.parent_id; @@ -100,6 +128,7 @@ class Channel { this.position = JSON.position; this.lastreadmessageid = null; this.lastmessageid = JSON.last_message_id; + this.setUpInfiniteScroller(); } isAdmin() { return this.guild.isAdmin(); @@ -487,7 +516,7 @@ class Channel { this.myhtml.classList.add("viewChannel"); this.guild.prevchannel = this; this.localuser.channelfocus = this; - const prom = Message.wipeChanel(); + const prom = this.infinite.delete(); await this.putmessages(); await prom; if (id !== Channel.genid) { @@ -501,7 +530,7 @@ class Channel { document.getElementById("typebox").disabled = !this.canMessage; } async putmessages() { - if (this.messages.length >= 100 || this.allthewayup) { + if (this.allthewayup) { return; } ; @@ -512,11 +541,16 @@ class Channel { if (response.length !== 100) { this.allthewayup = true; } + let prev = undefined; for (const thing of response) { - const messager = new Message(thing, this); - if (this.messageids[messager.id] === undefined) { - this.messageids[messager.id] = messager; - this.messages.push(messager); + const message = new Message(thing, this); + if (prev) { + this.idToNext[message.id] = prev.id; + 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; } - async grabmoremessages() { - if (this.messages.length === 0 || this.allthewayup) { + async grabmoremessages(id) { + if (this.allthewayup) { 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 }).then((j) => { return j.json(); }).then(response => { - //messages.innerHTML = ''; - //response.reverse() let next; if (response.length === 0) { - out.allthewayup = true; + this.allthewayup = true; } + let previd = id; for (const i in response) { let messager; if (!next) { @@ -558,10 +590,11 @@ class Channel { next = undefined; console.log("ohno", +i + 1); } - if (out.messageids[messager.id] == undefined) { - out.messageids[messager.id] = messager; - out.buildmessage(messager, next); - out.messages.push(messager); + if (this.messageids[messager.id] === undefined) { + this.idToNext[messager.id] = previd; + this.idToPrev[previd] = messager.id; + previd = messager.id; + this.messageids[messager.id] = messager; } else { console.log("How???"); @@ -576,30 +609,9 @@ class Channel { document.getElementById("messages").prepend(built); } buildmessages() { - for (const i in this.messages) { - const prev = this.messages[(+i) + 1]; - const built = this.messages[i].buildhtml(prev); - 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; + const messages = document.getElementById("channelw"); + messages.innerHTML = ""; + messages.append(this.infinite.getDiv(this.lastmessageid)); } updateChannel(JSON) { this.type = JSON.type; @@ -694,7 +706,10 @@ class Channel { return; } const messagez = new Message(messagep.d, this); + this.idToNext[this.lastmessageid] = messagez.id; + this.idToPrev[messagez.id] = this.lastmessageid; this.lastmessageid = messagez.id; + this.messageids[messagez.id] = messagez; if (messagez.author === this.localuser.user) { this.lastreadmessageid = messagez.id; if (this.myhtml) { @@ -707,16 +722,7 @@ class Channel { } } this.guild.unreads(); - this.messages.unshift(messagez); - 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; - } + this.infinite.addedBottom(); if (messagez.author === this.localuser.user) { return; } @@ -738,10 +744,10 @@ class Channel { if (!("Notification" in window)) { } else if (Notification.permission === "granted") { - let noticontent = markdown(message.content).textContent; + let noticontent = message.content.textContent; if (message.embeds[0]) { noticontent ||= message.embeds[0].json.title; - noticontent ||= markdown(message.embeds[0].json.description).textContent; + noticontent ||= message.content.textContent; } noticontent ||= "Blank Message"; let imgurl = null; diff --git a/.dist/direct.js b/.dist/direct.js index a39d928..e8a9620 100644 --- a/.dist/direct.js +++ b/.dist/direct.js @@ -64,7 +64,6 @@ class Group extends Channel { super(-1, owner); this.owner = owner; this.headers = this.guild.headers; - this.messages = []; this.name = JSON.recipients[0]?.username; if (JSON.recipients[0]) { 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 ??= "0"; this.mentions = 0; + this.setUpInfiniteScroller(); } createguildHTML() { const div = document.createElement("div"); @@ -102,9 +102,9 @@ class Group extends Channel { if (this.guild !== this.localuser.lookingguild) { this.guild.loadGuild(); } - const prom = Message.wipeChanel(); this.guild.prevchannel = this; this.localuser.channelfocus = this; + const prom = this.infinite.delete(); await this.putmessages(); await prom; if (id !== Channel.genid) { @@ -116,38 +116,29 @@ class Group extends Channel { } messageCreate(messagep) { const messagez = new Message(messagep.d, this); + this.idToNext[this.lastmessageid] = messagez.id; + this.idToPrev[messagez.id] = this.lastmessageid; this.lastmessageid = messagez.id; + this.messageids[messagez.id] = messagez; if (messagez.author === this.localuser.user) { this.lastreadmessageid = messagez.id; + if (this.myhtml) { + this.myhtml.classList.remove("cunread"); + } } - this.messages.unshift(messagez); - 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; - } - 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; - } + else { + if (this.myhtml) { + this.myhtml.classList.add("cunread"); } } this.unreads(); + this.infinite.addedBottom(); if (messagez.author === this.localuser.user) { return; } if (this.localuser.lookingguild.prevchannel === this && document.hasFocus()) { return; } - console.log(this.notification); if (this.notification === "all") { this.notify(messagez); } @@ -185,9 +176,9 @@ class Group extends Channel { console.log(this); div.append(buildpfp); sentdms.append(div); - div.onclick = function () { - this["noti"].guild.loadGuild(); - this["noti"].getHTML(); + div.onclick = _ => { + this.guild.loadGuild(); + this.getHTML(); }; } else if (current) { diff --git a/.dist/embed.js b/.dist/embed.js index 172bdd3..e617bdb 100644 --- a/.dist/embed.js +++ b/.dist/embed.js @@ -1,4 +1,5 @@ import { Fullscreen } from "./fullscreen.js"; +import { MarkDown } from "./markdown.js"; class Embed { type; owner; @@ -26,6 +27,18 @@ class Embed { 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() { console.log(this.json); const div = document.createElement("div"); @@ -45,7 +58,7 @@ class Embed { authorline.append(img); } const a = document.createElement("a"); - a.innerText = this.json.author.name; + a.textContent = this.json.author.name; if (this.json.author.url) { a.href = this.json.author.url; } @@ -54,7 +67,7 @@ class Embed { embed.append(authorline); } const title = document.createElement("a"); - title.textContent = this.json.title; + title.append(new MarkDown(this.json.title, this.localuser).makeHTML()); if (this.json.url) { title.href = this.json.url; } @@ -62,7 +75,7 @@ class Embed { embed.append(title); if (this.json.description) { 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(document.createElement("br")); @@ -72,9 +85,8 @@ class Embed { const b = document.createElement("b"); b.textContent = thing.name; div.append(b); - let p; - p = document.createElement("p"); - p.textContent = thing.value; + const p = document.createElement("p"); + p.append(new MarkDown(thing.value, this.channel).makeHTML()); p.classList.add("embedp"); div.append(p); if (thing.inline) { diff --git a/.dist/file.js b/.dist/file.js index 2484889..90979c1 100644 --- a/.dist/file.js +++ b/.dist/file.js @@ -32,8 +32,10 @@ class File { full.show(); }; img.src = src; - img.height = this.height; - img.width = this.width; + if (this.width) { + img.height = this.height; + img.width = this.width; + } console.log(this.width, this.height); return img; } diff --git a/.dist/fullscreen.js b/.dist/fullscreen.js index 3d271b0..44d790c 100644 --- a/.dist/fullscreen.js +++ b/.dist/fullscreen.js @@ -62,7 +62,7 @@ class Fullscreen { const checkbox = document.createElement('input'); div.appendChild(checkbox); const label = document.createElement("span"); - checkbox.value = array[2]; + checkbox.checked = array[2]; label.textContent = array[1]; div.appendChild(label); checkbox.addEventListener("change", array[3]); diff --git a/.dist/index.js b/.dist/index.js index 02331b2..7421acd 100644 --- a/.dist/index.js +++ b/.dist/index.js @@ -14,9 +14,6 @@ const users = getBulkUsers(); if (!users.currentuser) { 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]); thisuser.initwebsocket().then(_ => { thisuser.loaduser(); @@ -104,7 +101,6 @@ thisuser.initwebsocket().then(_ => { }, null, _ => { return thisuser.isAdmin(); }); menu.bind(document.getElementById("channels")); } -function editchannelf(channel) { channel.editChannel(); } const pasteimage = document.getElementById("pasteimage"); let replyingto = null; async function enter(event) { @@ -145,9 +141,6 @@ typebox.addEventListener("keydown", event => { }); console.log(typebox); typebox.onclick = console.log; -let serverz = 0; -let serverid = []; -let cchanel = 0; function getguildinfo() { const path = window.location.pathname.split("/"); const channel = path[3]; @@ -155,49 +148,6 @@ function getguildinfo() { } const images = []; 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"; document.addEventListener('paste', async (e) => { Array.from(e.clipboardData.files).forEach(async (f) => { @@ -214,27 +164,6 @@ function userSettings() { thisuser.usersettings.show(); } 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) { document.getElementById("channelw").onclick = function () { document.getElementById("channels").parentNode.classList.add("collapse"); @@ -248,20 +177,3 @@ if (mobile) { 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) -} -*/ diff --git a/.dist/infiniteScroller.js b/.dist/infiniteScroller.js new file mode 100644 index 0000000..ec34c33 --- /dev/null +++ b/.dist/infiniteScroller.js @@ -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 }; diff --git a/.dist/localuser.js b/.dist/localuser.js index b7c9d94..d650a46 100644 --- a/.dist/localuser.js +++ b/.dist/localuser.js @@ -2,7 +2,6 @@ import { Guild } from "./guild.js"; import { Direct } from "./direct.js"; import { Voice } from "./audio.js"; import { User } from "./user.js"; -import { markdown } from "./markdown.js"; import { Fullscreen } from "./fullscreen.js"; import { setTheme } from "./login.js"; const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]); @@ -85,7 +84,7 @@ class Localuser { outoffocus() { document.getElementById("servers").textContent = ""; document.getElementById("channels").textContent = ""; - document.getElementById("messages").textContent = ""; + this.channelfocus.infinite.delete(); this.lookingguild = null; this.channelfocus = null; } @@ -145,23 +144,8 @@ class Localuser { returny(); break; case "MESSAGE_UPDATE": - if (this.initialized) { - if (this.channelfocus.id === temp.d.channel_id) { - 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; - } - } + const message = this.resolveChannelFromID(temp.d.channel_id).messageids[temp.d.id]; + message.giveData(temp.d); break; case "TYPING_START": if (this.initialized) { @@ -522,7 +506,7 @@ class Localuser { reader.readAsDataURL(file); console.log(this.headers); reader.onload = () => { - fetch(this.info.api.toString() + "/v9/users/@me", { + fetch(this.info.api.toString() + "/users/@me", { method: "PATCH", headers: this.headers, body: JSON.stringify({ @@ -533,7 +517,7 @@ class Localuser { }; } updatepronouns(pronouns) { - fetch(this.info.api.toString() + "/v9/users/@me/profile", { + fetch(this.info.api.toString() + "/users/@me/profile", { method: "PATCH", headers: this.headers, body: JSON.stringify({ @@ -616,7 +600,7 @@ class Localuser { newbio = this.value; regen(); }], - ["button", "update user content:", "submit", function () { + ["button", "update user content:", "submit", () => { if (file !== null) { this.updatepfp(file); } diff --git a/.dist/markdown.js b/.dist/markdown.js index 2521580..c98a848 100644 --- a/.dist/markdown.js +++ b/.dist/markdown.js @@ -1,411 +1,474 @@ -export { markdown }; -function markdown(text, { keep = false, stdsize = false } = {}) { - let txt; - if ((typeof txt) === "string") { - txt = text.split(""); - } - else { - txt = text; - } - const span = document.createElement("span"); - let current = document.createElement("span"); - function appendcurrent() { - if (current.innerHTML !== "") { - span.append(current); - current = document.createElement("span"); +export { MarkDown }; +class MarkDown { + txt; + keep; + stdsize; + owner; + info; + constructor(text, owner, { keep = false, stdsize = false } = {}) { + if ((typeof text) === (typeof "")) { + this.txt = text.split(""); } + 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++) { - if (txt[i] === "\n" || i === 0) { - const first = i === 0; - if (first) { - i--; + get rawString() { + return this.txt.concat(""); + } + get textContent() { + 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 = ""; - 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; + } + for (let i = 0; i < txt.length; i++) { + if (txt[i] === "\n" || i === 0) { + const first = i === 0; + if (first) { + i--; + } + let element = null; + 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] === " ") { - 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] === " ") { - element = document.createElement("h1"); - keepys = "# "; + else if (txt[i + 1] === ">" && txt[i + 2] === " ") { + element = document.createElement("div"); + const line = document.createElement("div"); + line.classList.add("quoteline"); + element.append(line); + element.classList.add("quote"); + keepys = "> "; i += 3; } - } - else if (txt[i + 1] === ">" && txt[i + 2] === " ") { - element = document.createElement("div"); - const line = document.createElement("div"); - line.classList.add("quoteline"); - element.append(line); - element.classList.add("quote"); - keepys = "> "; - i += 3; - } - if (keepys) { - appendcurrent(); - if (!first && !stdsize) { - span.appendChild(document.createElement("br")); + if (keepys) { + appendcurrent(); + if (!first && !stdsize) { + span.appendChild(document.createElement("br")); + } + const build = []; + for (; txt[i] !== "\n" && txt[i] !== undefined; i++) { + build.push(txt[i]); + } + if (stdsize) { + element = document.createElement("span"); + } + if (keep) { + element.append(keepys); + } + element.appendChild(this.markdown(build, { keep: keep, stdsize: stdsize })); + span.append(element); + i--; + continue; } - const build = []; - for (; txt[i] !== "\n" && txt[i] !== undefined; i++) { - build.push(txt[i]); + 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) { - element = document.createElement("span"); + console.log(build); + build = build.replaceAll("\n", ""); + console.log(build, JSON.stringify(build)); } - if (keep) { - 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) { + if (find === count) { + appendcurrent(); + i = j; + if (keep) { build += "`".repeat(find); - find = 0; } - if (init && count === 3) { - if (txt[j] === " " || txt[j] === "\n") { - init = false; + 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) { - 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(/^$/); + 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; } - 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; - } + current.textContent += txt[i]; } - 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(/^$/); - 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; + } + static unspoil(e) { + e.target.classList.remove("spoiler"); + e.target.classList.add("unspoiled"); } - appendcurrent(); - return span; } -markdown.unspoil = function (e) { - //console.log("undone") - e.target.classList.remove("spoiler"); - e.target.classList.add("unspoiled"); -}; diff --git a/.dist/message.js b/.dist/message.js index f6f43b3..6dcaafb 100644 --- a/.dist/message.js +++ b/.dist/message.js @@ -1,7 +1,7 @@ import { Contextmenu } from "./contextmenu.js"; import { User } from "./user.js"; import { Member } from "./member.js"; -import { markdown } from "./markdown.js"; +import { MarkDown } from "./markdown.js"; import { Embed } from "./embed.js"; import { File } from "./file.js"; class Message { @@ -33,7 +33,7 @@ class Message { } static setupcmenu() { Message.contextmenu.addbutton("Copy raw text", function () { - navigator.clipboard.writeText(this.content); + navigator.clipboard.writeText(this.content.rawString); }); Message.contextmenu.addbutton("Reply", function (div) { this.channel.setReplying(this); @@ -52,6 +52,9 @@ class Message { constructor(messagejson, owner) { this.owner = owner; this.headers = this.owner.headers; + this.giveData(messagejson); + } + giveData(messagejson) { for (const thing of Object.keys(messagejson)) { if (thing === "attachments") { this.attachments = []; @@ -60,6 +63,10 @@ class Message { } continue; } + else if (thing === "content") { + this.content = new MarkDown(messagejson[thing], this.channel); + continue; + } this[thing] = messagejson[thing]; } for (const thing in this.embeds) { @@ -76,6 +83,9 @@ class Message { if (this.mentionsuser(this.localuser.user)) { console.log(this); } + if (this.div) { + this.generateMessage(); + } } canDelete() { return this.channel.hasPermission("MANAGE_MESSAGES") || this.author.id === this.localuser.user.id; @@ -92,11 +102,12 @@ class Message { get info() { return this.owner.info; } - messageevents(obj) { + messageevents(obj, del = Message.del) { const func = Message.contextmenu.bind(obj, this); this.div = obj; - Message.del.then(_ => { + del.then(_ => { obj.removeEventListener("click", func); + this.div.remove(); this.div = null; }); obj.classList.add("messagediv"); @@ -136,17 +147,19 @@ class Message { this.div.innerHTML = ""; this.div = null; } - const index = this.channel.messages.indexOf(this); - this.channel.messages.splice(this.channel.messages.indexOf(this), 1); + const prev = this.channel.idToPrev[this.id]; + const next = this.channel.idToNext[this.id]; + this.channel.idToNext[prev] = next; + this.channel.idToPrev[next] = prev; delete this.channel.messageids[this.id]; - const regen = this.channel.messages[index - 1]; + const regen = this.channel.messageids[prev]; if (regen) { regen.generateMessage(); } } generateMessage(premessage = null) { 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; if (this === this.channel.replyingto) { @@ -195,7 +208,7 @@ class Message { replyline.classList.add("replyflex"); this.channel.getmessage(this.message_reference.message_id).then(message => { const author = message.author; - reply.appendChild(markdown(message.content, { stdsize: true })); + reply.appendChild(message.content.makeHTML({ stdsize: true })); minipfp.src = author.getpfpsrc(); author.bind(minipfp); username.textContent = author.username; @@ -203,7 +216,6 @@ class Message { }); div.appendChild(replyline); } - this.messageevents(div); build.classList.add("message"); div.appendChild(build); if ({ 0: true, 19: true }[this.type] || this.attachments.length !== 0) { @@ -258,7 +270,7 @@ class Message { else { div.classList.remove("topMessage"); } - const messaged = markdown(this.content); + const messaged = this.content.makeHTML(); div["txt"] = messaged; const messagedwrap = document.createElement("div"); messagedwrap.classList.add("flexttb"); @@ -304,14 +316,15 @@ class Message { div["all"] = this; return (div); } - buildhtml(premessage) { + buildhtml(premessage, del = Message.del) { if (this.div) { - console.error(`HTML for ${this} already exists, aborting`); + console.error(`HTML for ${this.id} already exists, aborting`); return; } //premessage??=messages.lastChild; const div = document.createElement("div"); this.div = div; + this.messageevents(div, del); return this.generateMessage(premessage); } } diff --git a/.dist/register.js b/.dist/register.js index 8db00d0..5478eaa 100644 --- a/.dist/register.js +++ b/.dist/register.js @@ -57,4 +57,4 @@ async function tosLogic() { console.log(tosPage); } tosLogic(); -checkInstance.alt = tosLogic; +checkInstance["alt"] = tosLogic; diff --git a/.dist/settings.js b/.dist/settings.js index 08ce7bd..18d032a 100644 --- a/.dist/settings.js +++ b/.dist/settings.js @@ -80,7 +80,7 @@ class PermissionToggle { div.append(name); div.append(this.generateCheckbox()); const p = document.createElement("p"); - p.innerText = this.rolejson.description; + p.textContent = this.rolejson.description; div.appendChild(p); return div; } diff --git a/.dist/user.js b/.dist/user.js index 2323d78..401b8a9 100644 --- a/.dist/user.js +++ b/.dist/user.js @@ -1,6 +1,6 @@ //const usercache={}; import { Member } from "./member.js"; -import { markdown } from "./markdown.js"; +import { MarkDown } from "./markdown.js"; import { Contextmenu } from "./contextmenu.js"; class User { static userids = {}; @@ -48,6 +48,10 @@ class User { } if (dontclone) { for (const thing of Object.keys(userjson)) { + if (thing === "bio") { + this.bio = new MarkDown(userjson[thing], this.localuser); + continue; + } this[thing] = userjson[thing]; } this.hypotheticalpfp = false; @@ -146,7 +150,7 @@ class User { userbody.appendChild(pronounshtml); const rule = document.createElement("hr"); userbody.appendChild(rule); - const biohtml = markdown(this.bio); + const biohtml = this.bio.makeHTML(); userbody.appendChild(biohtml); } console.log(div); diff --git a/Archive.tar.gz b/Archive.tar.gz deleted file mode 100644 index ac47266..0000000 Binary files a/Archive.tar.gz and /dev/null differ diff --git a/README.md b/README.md index 527b2c8..039af32 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # 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 `node index.js` diff --git a/webpage/channel.ts b/webpage/channel.ts index fdc76a0..1f1eca6 100644 --- a/webpage/channel.ts +++ b/webpage/channel.ts @@ -3,12 +3,13 @@ import { Message } from "./message.js"; import {Voice} from "./audio.js"; import {Contextmenu} from "./contextmenu.js"; import {Fullscreen} from "./fullscreen.js"; -import {markdown} from "./markdown.js"; +import {MarkDown} from "./markdown.js"; import {Guild} from "./guild.js"; import { Localuser } from "./localuser.js"; import { Permissions } from "./permissions.js"; import { Settings, RoleList } from "./settings.js"; import { Role } from "./role.js"; +import {InfiniteScroller} from "./infiniteScroller.js" Settings; declare global { interface NotificationOptions { @@ -20,7 +21,6 @@ class Channel{ type:number; owner:Guild; headers:Localuser["headers"]; - messages:Message[]; name:string; id:string; parent_id:string; @@ -43,6 +43,9 @@ class Channel{ allthewayup:boolean; static contextmenu=new Contextmenu("channel menu"); replyingto:Message; + infinite:InfiniteScroller; + idToPrev:{[key:string]:string}={}; + idToNext:{[key:string]:string}={}; static setupcontextmenu(){ this.contextmenu.addbutton("Copy channel id",function(){ console.log(this) @@ -82,16 +85,45 @@ class Channel{ 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; + 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){ if(JSON===-1){ return; } + this.editing; this.type=JSON.type; this.owner=owner; this.headers=this.owner.headers; - this.messages=[]; this.name=JSON.name; this.id=JSON.id; this.parent_id=JSON.parent_id; @@ -113,6 +145,7 @@ class Channel{ this.position=JSON.position; this.lastreadmessageid=null; this.lastmessageid=JSON.last_message_id; + this.setUpInfiniteScroller(); } isAdmin(){ return this.guild.isAdmin(); @@ -495,7 +528,7 @@ class Channel{ this.myhtml.classList.add("viewChannel") this.guild.prevchannel=this; this.localuser.channelfocus=this; - const prom=Message.wipeChanel(); + const prom=this.infinite.delete(); await this.putmessages(); await prom; if(id!==Channel.genid){ @@ -509,7 +542,7 @@ class Channel{ (document.getElementById("typebox") as HTMLInputElement).disabled=!this.canMessage; } 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",{ headers: this.headers, }) @@ -517,11 +550,16 @@ class Channel{ if(response.length!==100){ this.allthewayup=true; } + let prev=undefined; for(const thing of response){ - const messager=new Message(thing,this) - if(this.messageids[messager.id]===undefined){ - this.messageids[messager.id]=messager; - this.messages.push(messager); + const message=new Message(thing,this); + if(prev){ + this.idToNext[message.id]=prev.id; + 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; } - async grabmoremessages(){ - if(this.messages.length===0||this.allthewayup){ + async grabmoremessages(id:string){ + if(this.allthewayup){ 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 }).then((j)=>{return j.json()}).then(response=>{ - //messages.innerHTML = ''; - //response.reverse() let next:Message; if(response.length===0){ - out.allthewayup=true; + this.allthewayup=true; } + let previd=id; for(const i in response){ let messager:Message; if(!next){ - messager=new Message(response[i],this) + messager=new Message(response[i],this); }else{ messager=next; } @@ -560,12 +596,13 @@ class Channel{ next=new Message(response[+i+1],this); }else{ next=undefined; - console.log("ohno",+i+1) + console.log("ohno",+i+1); } - if(out.messageids[messager.id]==undefined){ - out.messageids[messager.id]=messager; - out.buildmessage(messager,next); - out.messages.push(messager); + if(this.messageids[messager.id]===undefined){ + this.idToNext[messager.id]=previd; + this.idToPrev[previd]=messager.id; + previd=messager.id; + this.messageids[messager.id]=messager; }else{ console.log("How???") } @@ -579,37 +616,9 @@ class Channel{ document.getElementById("messages").prepend(built); } buildmessages(){ - for(const i in this.messages){ - const prev=this.messages[(+i)+1]; - const built=this.messages[i].buildhtml(prev); - 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; - + const messages=document.getElementById("channelw"); + messages.innerHTML=""; + messages.append(this.infinite.getDiv(this.lastmessageid)); } updateChannel(JSON){ this.type=JSON.type; @@ -698,7 +707,10 @@ class Channel{ messageCreate(messagep:any):void{ if(!this.hasPermission("VIEW_CHANNEL")){return} const messagez=new Message(messagep.d,this); + this.idToNext[this.lastmessageid]=messagez.id; + this.idToPrev[messagez.id]=this.lastmessageid; this.lastmessageid=messagez.id; + this.messageids[messagez.id]=messagez; if(messagez.author===this.localuser.user){ this.lastreadmessageid=messagez.id; if(this.myhtml){ @@ -710,16 +722,7 @@ class Channel{ } } this.guild.unreads(); - this.messages.unshift(messagez); - 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; - } + this.infinite.addedBottom(); if(messagez.author===this.localuser.user){ return; } @@ -731,6 +734,7 @@ class Channel{ }else if(this.notification==="mentions"&&messagez.mentionsuser(this.localuser.user)){ this.notify(messagez); } + } notititle(message:Message):string{ return message.author.username+" > "+this.guild.properties.name+" > "+this.name; @@ -740,10 +744,10 @@ class Channel{ if (!("Notification" in window)) { } else if (Notification.permission === "granted") { - let noticontent=markdown(message.content).textContent; + let noticontent=message.content.textContent; if(message.embeds[0]){ noticontent||=message.embeds[0].json.title; - noticontent||=markdown(message.embeds[0].json.description).textContent; + noticontent||=message.content.textContent; } noticontent||="Blank Message"; let imgurl=null; diff --git a/webpage/direct.ts b/webpage/direct.ts index cf8a9de..3d4ad35 100644 --- a/webpage/direct.ts +++ b/webpage/direct.ts @@ -67,7 +67,6 @@ class Group extends Channel{ super(-1,owner); this.owner=owner; this.headers=this.guild.headers; - this.messages=[]; this.name=JSON.recipients[0]?.username; if(JSON.recipients[0]){ 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??="0"; this.mentions=0; + this.setUpInfiniteScroller(); } createguildHTML(){ const div=document.createElement("div") @@ -104,9 +104,9 @@ class Group extends Channel{ if(this.guild!==this.localuser.lookingguild){ this.guild.loadGuild(); } - const prom=Message.wipeChanel(); this.guild.prevchannel=this; this.localuser.channelfocus=this; + const prom=this.infinite.delete(); await this.putmessages(); await prom; if(id!==Channel.genid){ @@ -118,38 +118,28 @@ class Group extends Channel{ } messageCreate(messagep){ const messagez=new Message(messagep.d,this); + this.idToNext[this.lastmessageid]=messagez.id; + this.idToPrev[messagez.id]=this.lastmessageid; this.lastmessageid=messagez.id; + this.messageids[messagez.id]=messagez; if(messagez.author===this.localuser.user){ this.lastreadmessageid=messagez.id; - } - this.messages.unshift(messagez); - 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; - } - 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; - } + if(this.myhtml){ + this.myhtml.classList.remove("cunread"); + } + }else{ + if(this.myhtml){ + this.myhtml.classList.add("cunread"); } } this.unreads(); + this.infinite.addedBottom(); if(messagez.author===this.localuser.user){ return; } if(this.localuser.lookingguild.prevchannel===this&&document.hasFocus()){ return; } - console.log(this.notification); if(this.notification==="all"){ this.notify(messagez); }else if(this.notification==="mentions"&&messagez.mentionsuser(this.localuser.user)){ @@ -183,9 +173,9 @@ class Group extends Channel{ console.log(this); div.append(buildpfp) sentdms.append(div); - div.onclick=function(){ - this["noti"].guild.loadGuild(); - this["noti"].getHTML(); + div.onclick=_=>{ + this.guild.loadGuild(); + this.getHTML(); } }else if(current){ diff --git a/webpage/embed.ts b/webpage/embed.ts index a9c1494..ac5d60e 100644 --- a/webpage/embed.ts +++ b/webpage/embed.ts @@ -1,6 +1,6 @@ import {Fullscreen} from "./fullscreen.js"; import {Message} from "./message.js"; -import {markdown} from "./markdown.js"; +import {MarkDown} from "./markdown.js"; class Embed{ type:string; @@ -29,6 +29,18 @@ class Embed{ 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(){ console.log(this.json) const div=document.createElement("div"); @@ -59,7 +71,7 @@ class Embed{ embed.append(authorline); } 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){ title.href=this.json.url; } @@ -68,7 +80,7 @@ class Embed{ if(this.json.description){ const p=document.createElement("p"); - p.append(markdown(this.json.description)); + p.append(new MarkDown(this.json.description,this.channel).makeHTML()); embed.append(p); } @@ -80,7 +92,7 @@ class Embed{ b.textContent=thing.name; div.append(b); const p=document.createElement("p") - p.append(markdown(thing.value)); + p.append(new MarkDown(thing.value,this.channel).makeHTML()); p.classList.add("embedp"); div.append(p); diff --git a/webpage/file.ts b/webpage/file.ts index b055f7f..d71d384 100644 --- a/webpage/file.ts +++ b/webpage/file.ts @@ -34,8 +34,10 @@ class File{ full.show(); } img.src=src; - img.height=this.height; - img.width=this.width; + if(this.width){ + img.height=this.height; + img.width=this.width; + } console.log(this.width,this.height) return img; }else if(this.content_type.startsWith('video/')){ diff --git a/webpage/index.ts b/webpage/index.ts index 3c21fa6..b3db4ee 100644 --- a/webpage/index.ts +++ b/webpage/index.ts @@ -3,7 +3,7 @@ import {Contextmenu} from "./contextmenu.js"; import {mobile, getBulkUsers,setTheme, Specialuser} from "./login.js"; async function waitforload(){ - let res + let res; new Promise(r=>{res=r}); document.addEventListener("DOMContentLoaded", function(){ res(); @@ -18,9 +18,6 @@ const users=getBulkUsers(); if(!users.currentuser){ 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]); thisuser.initwebsocket().then(_=>{ @@ -117,11 +114,6 @@ thisuser.initwebsocket().then(_=>{ menu.bind(document.getElementById("channels")) } - -function editchannelf(channel){channel.editChannel();} - - - const pasteimage=document.getElementById("pasteimage"); let replyingto=null; async function enter(event){ @@ -163,17 +155,6 @@ console.log(typebox) typebox.onclick=console.log; - - -let serverz=0; -let serverid=[]; - - - - -let cchanel=0; - - function getguildinfo(){ const path=window.location.pathname.split("/"); const channel=path[3]; @@ -183,50 +164,7 @@ function getguildinfo(){ const images:Blob[]=[]; 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"; document.addEventListener('paste', async (e) => { Array.from(e.clipboardData.files).forEach(async (f) => { @@ -245,17 +183,6 @@ function userSettings(){ thisuser.usersettings.show(); } 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; document.getElementById("messagecontainer").addEventListener("scroll",(e)=>{ const messagecontainer=document.getElementById("messagecontainer") @@ -289,20 +216,3 @@ if(mobile){ 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) -} -*/ diff --git a/webpage/infiniteScroller.ts b/webpage/infiniteScroller.ts new file mode 100644 index 0000000..6b3be1b --- /dev/null +++ b/webpage/infiniteScroller.ts @@ -0,0 +1,148 @@ +class InfiniteScroller{ + readonly getIDFromOffset:(ID:string,offset:number)=>Promise; + readonly getHTMLFromID:(ID:string)=>HTMLElement; + readonly destroyFromID:(ID:string)=>Promise; + 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{ + 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.scrollTopthis.maxDist){ + + again=true; + const html=this.HTMLElements.shift(); + await this.destroyFromID(html[1]); + this.scrollTop-=60; + } + const scrollBottom = this.scrollBottom; + if(scrollBottomthis.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{ + 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}; diff --git a/webpage/localuser.ts b/webpage/localuser.ts index 87cf0c5..40f38ae 100644 --- a/webpage/localuser.ts +++ b/webpage/localuser.ts @@ -4,7 +4,7 @@ import {Direct} from "./direct.js"; import {Voice} from "./audio.js"; import {User} from "./user.js"; import {Member} from "./member.js"; -import {markdown} from "./markdown.js"; +import {MarkDown} from "./markdown.js"; import {Fullscreen} from "./fullscreen.js"; import {setTheme, Specialuser} from "./login.js"; @@ -93,7 +93,7 @@ class Localuser{ outoffocus():void{ document.getElementById("servers").textContent=""; document.getElementById("channels").textContent=""; - document.getElementById("messages").textContent=""; + this.channelfocus.infinite.delete(); this.lookingguild=null; this.channelfocus=null; } @@ -156,22 +156,8 @@ class Localuser{ returny(); break; case "MESSAGE_UPDATE": - if(this.initialized){ - if(this.channelfocus.id===temp.d.channel_id){ - 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; - } - } + const message=this.resolveChannelFromID(temp.d.channel_id).messageids[temp.d.id]; + message.giveData(temp.d); break; case "TYPING_START": if(this.initialized){ @@ -547,7 +533,7 @@ class Localuser{ reader.readAsDataURL(file); console.log(this.headers); reader.onload = ()=>{ - fetch(this.info.api.toString()+"/v9/users/@me",{ + fetch(this.info.api.toString()+"/users/@me",{ method:"PATCH", headers:this.headers, body:JSON.stringify({ @@ -559,7 +545,7 @@ class Localuser{ } updatepronouns(pronouns:string):void{ - fetch(this.info.api.toString()+"/v9/users/@me/profile",{ + fetch(this.info.api.toString()+"/users/@me/profile",{ method:"PATCH", headers:this.headers, body:JSON.stringify({ @@ -642,7 +628,7 @@ class Localuser{ newbio=this.value; regen(); }], - ["button","update user content:","submit",function(){ + ["button","update user content:","submit",()=>{ if(file!==null){ this.updatepfp(file); } diff --git a/webpage/markdown.ts b/webpage/markdown.ts index 5c912e4..8896749 100644 --- a/webpage/markdown.ts +++ b/webpage/markdown.ts @@ -1,409 +1,444 @@ -export {markdown}; -function markdown(text : string|string[],{keep=false,stdsize=false} = {}){ - let txt : string[]; - if((typeof txt)==="string"){ - txt=(text as string).split(""); - }else{ - txt=(text as string[]); - } - const span=document.createElement("span"); - let current=document.createElement("span"); - function appendcurrent(){ - if(current.innerHTML!==""){ - span.append(current); - current=document.createElement("span"); +import { Channel } from "./channel"; +import { Localuser } from "./localuser"; + +export {MarkDown}; +class MarkDown{ + txt : string[]; + keep:boolean; + stdsize:boolean; + owner:Localuser|Channel; + info:Localuser["info"]; + constructor(text : string|string[],owner:MarkDown["owner"],{keep=false,stdsize=false} = {}){ + if((typeof text)===(typeof "")){ + this.txt=(text as string).split(""); + }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[i+2]===" "){ + element=document.createElement("div"); + const line=document.createElement("div"); + line.classList.add("quoteline"); + element.append(line); + element.classList.add("quote"); + keepys="> "; i+=3; } - }else if(txt[i+1]===">"&&txt[i+2]===" "){ - element=document.createElement("div"); - const line=document.createElement("div"); - line.classList.add("quoteline"); - element.append(line); - element.classList.add("quote"); - keepys="> "; - i+=3; - } - if(keepys){ - appendcurrent(); - if(!first&&!stdsize){ - span.appendChild(document.createElement("br")); + if(keepys){ + appendcurrent(); + if(!first&&!stdsize){ + span.appendChild(document.createElement("br")); + } + const build=[]; + for(;txt[i]!=="\n"&&txt[i]!==undefined;i++){ + build.push(txt[i]); + } + if(stdsize){ + element=document.createElement("span"); + } + if(keep){ + element.append(keepys); + } + element.appendChild(this.markdown(build,{keep:keep,stdsize:stdsize})); + span.append(element); + i--; + continue; } - const build=[]; - for(;txt[i]!=="\n"&&txt[i]!==undefined;i++){ - build.push(txt[i]); + 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){ - element=document.createElement("span"); + console.log(build); + build=build.replaceAll("\n",""); + console.log(build,JSON.stringify(build)); } - if(keep){ - 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(/^$/); - 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]) { + if(find===count){ appendcurrent(); i=j; - - const isEmojiOnly = txt.join("").trim()===build.join("").trim(); - - const emojiElem=document.createElement("img"); - emojiElem.classList.add("md-emoji"); - emojiElem.width=isEmojiOnly ? 48 : 22; - emojiElem.height=isEmojiOnly ? 48 : 22; - emojiElem.crossOrigin="anonymous"; - emojiElem.src=this.info.cdn.toString() + "/emojis/" + parts[2] + "." + (parts[1] ? "gif" : "png") + "?size=32"; - emojiElem.alt=""; - emojiElem.loading="lazy"; - span.appendChild(emojiElem); - + 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(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(/^$/); + 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]; } - - current.textContent+=txt[i]; + appendcurrent(); + 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") } diff --git a/webpage/message.ts b/webpage/message.ts index 9a7f02b..a16ac7b 100644 --- a/webpage/message.ts +++ b/webpage/message.ts @@ -1,9 +1,8 @@ import {Contextmenu} from "./contextmenu.js"; import {User} from "./user.js"; import {Member} from "./member.js"; -import {markdown} from "./markdown.js"; +import {MarkDown} from "./markdown.js"; import {Embed} from "./embed.js"; -import {Fullscreen} from "./fullscreen.js"; import { Channel } from "./channel.js"; import {Localuser} from "./localuser.js"; import { Role } from "./role.js"; @@ -22,7 +21,7 @@ class Message{ message_reference; type:number; timestamp:number; - content:string; + content:MarkDown; static del:Promise; static resolve:Function; div:HTMLDivElement; @@ -38,7 +37,7 @@ class Message{ } static setupcmenu(){ 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){ this.channel.setReplying(this); @@ -57,6 +56,10 @@ class Message{ constructor(messagejson,owner:Channel){ this.owner=owner; this.headers=this.owner.headers; + this.giveData(messagejson); + + } + giveData(messagejson){ for(const thing of Object.keys(messagejson)){ if(thing==="attachments"){ this.attachments=[]; @@ -64,6 +67,9 @@ class Message{ this.attachments.push(new File(thing,this)); } continue; + }else if(thing==="content"){ + this.content=new MarkDown(messagejson[thing],this.channel); + continue; } this[thing]=messagejson[thing]; } @@ -81,6 +87,9 @@ class Message{ if(this.mentionsuser(this.localuser.user)){ console.log(this); } + if(this.div){ + this.generateMessage(); + } } canDelete(){ return this.channel.hasPermission("MANAGE_MESSAGES")||this.author.id===this.localuser.user.id; @@ -97,11 +106,12 @@ class Message{ get info(){ return this.owner.info; } - messageevents(obj:HTMLDivElement){ + messageevents(obj:HTMLDivElement,del=Message.del){ const func=Message.contextmenu.bind(obj,this); this.div=obj; - Message.del.then(_=>{ + del.then(_=>{ obj.removeEventListener("click",func); + this.div.remove(); this.div=null; }) obj.classList.add("messagediv"); @@ -140,17 +150,19 @@ class Message{ this.div.innerHTML=""; this.div=null; } - const index=this.channel.messages.indexOf(this); - this.channel.messages.splice(this.channel.messages.indexOf(this),1); + const prev=this.channel.idToPrev[this.id]; + const next=this.channel.idToNext[this.id]; + this.channel.idToNext[prev]=next; + this.channel.idToPrev[next]=prev; delete this.channel.messageids[this.id]; - const regen=this.channel.messages[index-1] + const regen=this.channel.messageids[prev] if(regen){ regen.generateMessage(); } } generateMessage(premessage:Message=null){ 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; if(this===this.channel.replyingto){ @@ -201,7 +213,7 @@ class Message{ replyline.classList.add("replyflex") this.channel.getmessage(this.message_reference.message_id).then(message=>{ const author=message.author; - reply.appendChild(markdown(message.content,{stdsize:true})); + reply.appendChild(message.content.makeHTML({stdsize:true})); minipfp.src=author.getpfpsrc() author.bind(minipfp); username.textContent=author.username; @@ -209,8 +221,6 @@ class Message{ }); div.appendChild(replyline); } - - this.messageevents(div); build.classList.add("message"); div.appendChild(build); if({0:true,19:true}[this.type]||this.attachments.length!==0){ @@ -264,7 +274,7 @@ class Message{ }else{ div.classList.remove("topMessage"); } - const messaged=markdown(this.content); + const messaged=this.content.makeHTML(); div["txt"]=messaged; const messagedwrap=document.createElement("div"); messagedwrap.classList.add("flexttb") @@ -313,11 +323,13 @@ class Message{ div["all"]=this; return(div) } - buildhtml(premessage:Message){ - if(this.div){console.error(`HTML for ${this} already exists, aborting`);return;} + buildhtml(premessage:Message,del:Promise=Message.del){ + if(this.div){console.error(`HTML for ${this.id} already exists, aborting`);return;} //premessage??=messages.lastChild; const div=document.createElement("div"); this.div=div; + + this.messageevents(div,del); return this.generateMessage(premessage); } } diff --git a/webpage/register.ts b/webpage/register.ts index afc0d17..4a72f0d 100644 --- a/webpage/register.ts +++ b/webpage/register.ts @@ -58,4 +58,4 @@ async function tosLogic(){ } tosLogic(); -checkInstance.alt=tosLogic; +checkInstance["alt"]=tosLogic; diff --git a/webpage/style.css b/webpage/style.css index 0888267..1300f70 100644 --- a/webpage/style.css +++ b/webpage/style.css @@ -74,6 +74,8 @@ th { flex-wrap: nowrap; flex-direction: column; max-height: 20in; + flex-shrink: 0; + width: 100%; } pre { background-color: var(--code-bg); @@ -215,6 +217,8 @@ img { vertical-align: middle; max-width: 3in; max-height: 3in; + width: auto; + height: auto; } #page { @@ -242,8 +246,8 @@ img { font-weight: normal; } -#messagecontainer { - overflow-y: auto; +.messagecontainer { + overflow-y: hidden; display: flex; max-width: 100%; flex-shrink: 1; @@ -547,18 +551,18 @@ p { grid-column: 2; } .replytext pre { - padding: 0 .05in; + /* padding: 0 .05in; */ color: var(--reply-text); - overflow: hidden; + /* overflow: hidden; */ white-space: nowrap; text-overflow: ellipsis; max-width: fit-content; /* display: block; */ /* flex-grow: 1; */ flex: 1 1 auto; - width: fit-content; + /* width: fit-content; */ min-width: 0; - /* display: inline-block !important; */ + display: inline-block !important; width: 25vw; grid-column: 2; } @@ -723,7 +727,7 @@ textarea { } .servernamediv { - /* width: 100%; */ + width: 99%; /* max-width: 100%; */ } @@ -1167,6 +1171,7 @@ span { /* margin-bottom: 1in; */ /* padding-bottom: .1in; */ align-items: flex-start; + width: 100%; } .settingbuttons{ padding-top:.075in; @@ -1346,7 +1351,7 @@ span { overflow: hidden; flex-wrap: wrap; width: 100%; - flex-direction: row; + flex-direction: column; max-height:100in; } @@ -1366,3 +1371,15 @@ span { background-color: var(--embed-fallback); cursor: not-allowed; } + +.sizeupdown{ + height:4in; +} +.bigemoji{ + width:48px; + height:48px; +} +.smallemoji{ + width:22px; + height:22px; +} diff --git a/webpage/user.ts b/webpage/user.ts index dadf121..d62433b 100644 --- a/webpage/user.ts +++ b/webpage/user.ts @@ -1,6 +1,6 @@ //const usercache={}; import {Member} from "./member.js"; -import {markdown} from "./markdown.js"; +import {MarkDown} from "./markdown.js"; import {Contextmenu} from "./contextmenu.js"; import {Localuser} from "./localuser.js"; import {Guild} from "./guild.js"; @@ -12,7 +12,7 @@ class User{ id:string; avatar:string; username:string; - bio:string; + bio:MarkDown; discriminator:string; pronouns:string; bot:boolean; @@ -49,6 +49,10 @@ class User{ if(!owner){console.error("missing localuser")} if(dontclone){ for(const thing of Object.keys(userjson)){ + if(thing==="bio"){ + this.bio=new MarkDown(userjson[thing],this.localuser); + continue; + } this[thing]=userjson[thing]; } this.hypotheticalpfp=false; @@ -152,7 +156,7 @@ class User{ const rule=document.createElement("hr"); userbody.appendChild(rule); - const biohtml=markdown(this.bio); + const biohtml=this.bio.makeHTML(); userbody.appendChild(biohtml); } console.log(div);