Merge pull request #17 from MathMan05/TypeScript-Port

Type script port, I think it's ready
This commit is contained in:
MathMan05 2024-06-29 11:20:42 -05:00 committed by GitHub
commit eb5dc55003
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 7415 additions and 1011 deletions

138
.dist/audio.js Normal file
View file

@ -0,0 +1,138 @@
import { getBulkInfo } from "./login.js";
class Voice {
audioCtx;
info;
playing;
myArrayBuffer;
gainNode;
buffer;
source;
constructor(wave, freq, volume = 1) {
this.audioCtx = new (window.AudioContext)();
this.info = { wave: wave, freq: freq };
this.playing = false;
this.myArrayBuffer = this.audioCtx.createBuffer(1, this.audioCtx.sampleRate, this.audioCtx.sampleRate);
this.gainNode = this.audioCtx.createGain();
this.gainNode.gain.value = volume;
this.gainNode.connect(this.audioCtx.destination);
this.buffer = this.myArrayBuffer.getChannelData(0);
this.source = this.audioCtx.createBufferSource();
this.source.buffer = this.myArrayBuffer;
this.source.loop = true;
this.source.start();
this.updateWave();
}
get wave() {
return this.info.wave;
}
get freq() {
return this.info.freq;
}
set wave(wave) {
this.info.wave = wave;
this.updateWave();
}
set freq(freq) {
this.info.freq = freq;
this.updateWave();
}
updateWave() {
const func = this.waveFucnion();
for (let i = 0; i < this.buffer.length; i++) {
this.buffer[i] = func(i / this.audioCtx.sampleRate, this.freq);
}
}
waveFucnion() {
if (typeof this.wave === 'function') {
return this.wave;
}
switch (this.wave) {
case "sin":
return (t, freq) => {
return Math.sin(t * Math.PI * 2 * freq);
};
case "triangle":
return (t, freq) => {
return Math.abs((4 * t * freq) % 4 - 2) - 1;
};
case "sawtooth":
return (t, freq) => {
return ((t * freq) % 1) * 2 - 1;
};
case "square":
return (t, freq) => {
return (t * freq) % 2 < 1 ? 1 : -1;
};
case "white":
return (_t, _freq) => {
return Math.random() * 2 - 1;
};
case "noise":
return (_t, _freq) => {
return 0;
};
}
}
play() {
if (this.playing) {
return;
}
this.source.connect(this.gainNode);
this.playing = true;
}
stop() {
if (this.playing) {
this.source.disconnect();
this.playing = false;
}
}
static noises(noise) {
switch (noise) {
case "three": {
const voicy = new Voice("sin", 800);
voicy.play();
setTimeout(_ => { voicy.freq = 1000; }, 50);
setTimeout(_ => { voicy.freq = 1300; }, 100);
setTimeout(_ => { voicy.stop(); }, 150);
break;
}
case "zip": {
const voicy = new Voice((t, freq) => {
return Math.sin(((t + 2) ** (Math.cos(t * 4))) * Math.PI * 2 * freq);
}, 700);
voicy.play();
setTimeout(_ => { voicy.stop(); }, 150);
break;
}
case "square": {
const voicy = new Voice("square", 600, .4);
voicy.play();
setTimeout(_ => { voicy.freq = 800; }, 50);
setTimeout(_ => { voicy.freq = 1000; }, 100);
setTimeout(_ => { voicy.stop(); }, 150);
break;
}
case "beep": {
const voicy = new Voice("sin", 800);
voicy.play();
setTimeout(_ => { voicy.stop(); }, 50);
setTimeout(_ => { voicy.play(); }, 100);
setTimeout(_ => { voicy.stop(); }, 150);
break;
}
}
}
static get sounds() {
return ["three", "zip", "square", "beep"];
}
static setNotificationSound(sound) {
let userinfos = getBulkInfo();
userinfos.preferances.notisound = sound;
localStorage.setItem("userinfos", JSON.stringify(userinfos));
}
static getNotificationSound() {
let userinfos = getBulkInfo();
return userinfos.preferances.notisound;
}
}
export { Voice as Voice };

726
.dist/channel.js Normal file
View file

@ -0,0 +1,726 @@
"use strict";
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";
class Channel {
editing;
type;
owner;
headers;
messages;
name;
id;
parent_id;
parrent;
children;
guild_id;
messageids;
permission_overwrites;
topic;
nsfw;
position;
lastreadmessageid;
lastmessageid;
mentions;
lastpin;
move_id;
typing;
message_notifications;
allthewayup;
static contextmenu = new Contextmenu("channel menu");
replyingto;
static setupcontextmenu() {
Channel.contextmenu.addbutton("Copy channel id", function () {
console.log(this);
navigator.clipboard.writeText(this.id);
});
Channel.contextmenu.addbutton("Mark as read", function () {
console.log(this);
this.readbottom();
});
Channel.contextmenu.addbutton("Delete channel", function () {
console.log(this);
this.deleteChannel();
}, null, _ => { console.log(_); return _.isAdmin(); });
Channel.contextmenu.addbutton("Edit channel", function () {
this.editChannel(this);
}, null, _ => { return _.isAdmin(); });
}
constructor(JSON, owner) {
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;
this.parrent = null;
this.children = [];
this.guild_id = JSON.guild_id;
this.messageids = {};
this.permission_overwrites = {};
for (const thing of JSON.permission_overwrites) {
this.permission_overwrites[thing.id] = new Permissions(thing.allow, thing.deny);
}
this.topic = JSON.topic;
this.nsfw = JSON.nsfw;
this.position = JSON.position;
this.lastreadmessageid = null;
this.lastmessageid = JSON.last_message_id;
}
isAdmin() {
return this.guild.isAdmin();
}
get guild() {
return this.owner;
}
get localuser() {
return this.guild.localuser;
}
get info() {
return this.owner.info;
}
readStateInfo(json) {
this.lastreadmessageid = json.last_message_id;
this.mentions = json.mention_count;
this.mentions ??= 0;
this.lastpin = json.last_pin_timestamp;
}
get hasunreads() {
if (!this.hasPermission("VIEW_CHANNEL")) {
return false;
}
return this.lastmessageid !== this.lastreadmessageid && this.type !== 4;
}
hasPermission(name, member = this.guild.member) {
if (member.isAdmin()) {
return true;
}
for (const thing of member.roles) {
if (this.permission_overwrites[thing.id]) {
let perm = this.permission_overwrites[thing.id].getPermision(name);
if (perm) {
return perm === 1;
}
}
if (thing.permissions.getPermision(name)) {
return true;
}
}
return false;
}
get canMessage() {
return this.hasPermission("SEND_MESSAGES");
}
sortchildren() {
this.children.sort((a, b) => { return a.position - b.position; });
}
resolveparent(guild) {
this.parrent = guild.channelids[this.parent_id];
this.parrent ??= null;
if (this.parrent !== null) {
this.parrent.children.push(this);
}
return this.parrent === null;
}
calculateReorder() {
let position = -1;
let build = [];
for (const thing of this.children) {
const thisthing = { id: thing.id, position: undefined, parent_id: undefined };
if (thing.position < position) {
thing.position = thisthing.position = position + 1;
}
position = thing.position;
if (thing.move_id && thing.move_id !== thing.parent_id) {
thing.parent_id = thing.move_id;
thisthing.parent_id = thing.parent_id;
thing.move_id = undefined;
console.log(this.guild.channelids[thisthing.parent_id]);
}
if (thisthing.position || thisthing.parent_id) {
build.push(thisthing);
}
}
return build;
}
static dragged = [];
createguildHTML(admin = false) {
const div = document.createElement("div");
if (!this.hasPermission("VIEW_CHANNEL")) {
let quit = true;
for (const thing of this.children) {
if (thing.hasPermission("VIEW_CHANNEL")) {
quit = false;
}
}
if (quit) {
return div;
}
}
div["all"] = this;
div.draggable = admin;
div.addEventListener("dragstart", (e) => { Channel.dragged = [this, div]; e.stopImmediatePropagation(); });
div.addEventListener("dragend", () => { Channel.dragged = []; });
if (this.type === 4) {
this.sortchildren();
const caps = document.createElement("div");
const decdiv = document.createElement("div");
const decoration = document.createElement("b");
decoration.textContent = "▼";
decdiv.appendChild(decoration);
const myhtml = document.createElement("p2");
myhtml.textContent = this.name;
decdiv.appendChild(myhtml);
caps.appendChild(decdiv);
const childrendiv = document.createElement("div");
if (admin) {
const addchannel = document.createElement("span");
addchannel.textContent = "+";
addchannel.classList.add("addchannel");
caps.appendChild(addchannel);
addchannel.onclick = function () {
this.guild.createchannels(this.createChannel.bind(this));
}.bind(this);
this.coatDropDiv(decdiv, childrendiv);
}
div.appendChild(caps);
caps.classList.add("capsflex");
decdiv.classList.add("channeleffects");
decdiv.classList.add("channel");
Channel.contextmenu.bind(decdiv, this);
decdiv["all"] = this;
for (const channel of this.children) {
childrendiv.appendChild(channel.createguildHTML(admin));
}
childrendiv.classList.add("channels");
setTimeout(_ => { childrendiv.style.height = childrendiv.scrollHeight + 'px'; }, 100);
decdiv.onclick = function () {
if (decoration.textContent === "▼") { //
decoration.textContent = "▲";
//childrendiv.classList.add("colapsediv");
childrendiv.style.height = '0px';
}
else {
decoration.textContent = "▼";
//childrendiv.classList.remove("colapsediv")
childrendiv.style.height = childrendiv.scrollHeight + 'px';
}
};
div.appendChild(childrendiv);
}
else {
div.classList.add("channel");
if (this.hasunreads) {
div.classList.add("cunread");
}
Channel.contextmenu.bind(div, this);
if (admin) {
this.coatDropDiv(div);
}
div["all"] = this;
const myhtml = document.createElement("span");
myhtml.textContent = this.name;
if (this.type === 0) {
const decoration = document.createElement("b");
decoration.textContent = "#";
div.appendChild(decoration);
decoration.classList.add("space");
}
else if (this.type === 2) { //
const decoration = document.createElement("b");
decoration.textContent = "🕪";
div.appendChild(decoration);
decoration.classList.add("spacee");
}
else if (this.type === 5) { //
const decoration = document.createElement("b");
decoration.textContent = "📣";
div.appendChild(decoration);
decoration.classList.add("spacee");
}
else {
console.log(this.type);
}
div.appendChild(myhtml);
div.onclick = _ => {
this.getHTML();
};
}
return div;
}
get myhtml() {
const search = document.getElementById("channels").children[0].children;
if (this.guild !== this.localuser.lookingguild) {
return null;
}
else if (this.parrent) {
for (const thing of search) {
if (thing["all"] === this.parrent) {
for (const thing2 of thing.children[1].children) {
if (thing2["all"] === this) {
return thing2;
}
}
}
}
}
else {
for (const thing of search) {
if (thing["all"] === this) {
return thing;
}
}
}
return null;
}
readbottom() {
if (!this.hasunreads) {
return;
}
fetch(this.info.api.toString() + "/v9/channels/" + this.id + "/messages/" + this.lastmessageid + "/ack", {
method: "POST",
headers: this.headers,
body: JSON.stringify({})
});
this.lastreadmessageid = this.lastmessageid;
this.guild.unreads();
if (this.myhtml !== null) {
this.myhtml.classList.remove("cunread");
}
}
coatDropDiv(div, container = false) {
div.addEventListener("dragenter", (event) => {
console.log("enter");
event.preventDefault();
});
div.addEventListener("dragover", (event) => {
event.preventDefault();
});
div.addEventListener("drop", (event) => {
const that = Channel.dragged[0];
event.preventDefault();
if (container) {
that.move_id = this.id;
if (that.parrent) {
that.parrent.children.splice(that.parrent.children.indexOf(that), 1);
}
that.parrent = this;
container.prepend(Channel.dragged[1]);
this.children.unshift(that);
}
else {
console.log(this, Channel.dragged);
that.move_id = this.parent_id;
if (that.parrent) {
that.parrent.children.splice(that.parrent.children.indexOf(that), 1);
}
else {
this.guild.headchannels.splice(this.guild.headchannels.indexOf(that), 1);
}
that.parrent = this.parrent;
if (that.parrent) {
const build = [];
for (let i = 0; i < that.parrent.children.length; i++) {
build.push(that.parrent.children[i]);
if (that.parrent.children[i] === this) {
build.push(that);
}
}
that.parrent.children = build;
}
else {
const build = [];
for (let i = 0; i < this.guild.headchannels.length; i++) {
build.push(this.guild.headchannels[i]);
if (this.guild.headchannels[i] === this) {
build.push(that);
}
}
this.guild.headchannels = build;
}
div.after(Channel.dragged[1]);
}
this.guild.calculateReorder();
});
return div;
}
createChannel(name, type) {
fetch(this.info.api.toString() + "/guilds/" + this.guild.id + "/channels", {
method: "Post",
headers: this.headers,
body: JSON.stringify({
name: name,
type: type,
parent_id: this.id,
permission_overwrites: [],
})
});
}
editChannel() {
let name = this.name;
let topic = this.topic;
let nsfw = this.nsfw;
const thisid = this.id;
const thistype = this.type;
const full = new Fullscreen(["hdiv",
["vdiv",
["textbox", "Channel name:", this.name, function () { name = this.value; }],
["mdbox", "Channel topic:", this.topic, function () { topic = this.value; }],
["checkbox", "NSFW Channel", this.nsfw, function () { nsfw = this.checked; }],
["button", "", "submit", function () {
fetch(this.info.api.toString() + "/v9/channels/" + thisid, {
method: "PATCH",
headers: this.headers,
body: JSON.stringify({
"name": name,
"type": thistype,
"topic": topic,
"bitrate": 64000,
"user_limit": 0,
"nsfw": nsfw,
"flags": 0,
"rate_limit_per_user": 0
})
});
console.log(full);
full.hide();
}]
]
]);
full.show();
console.log(full);
}
deleteChannel() {
fetch(this.info.api.toString() + "/v9/channels/" + this.id, {
method: "DELETE",
headers: this.headers
});
}
setReplying(message) {
if (this.replyingto) {
this.replyingto.div.classList.remove("replying");
}
this.replyingto = message;
console.log(message);
this.replyingto.div.classList.add("replying");
this.makereplybox();
}
makereplybox() {
const replybox = document.getElementById("replybox");
if (this.replyingto) {
replybox.innerHTML = "";
const span = document.createElement("span");
span.textContent = "Replying to " + this.replyingto.author.username;
const X = document.createElement("button");
X.onclick = _ => {
this.replyingto.div.classList.remove("replying");
replybox.classList.add("hideReplyBox");
this.replyingto = null;
replybox.innerHTML = "";
};
replybox.classList.remove("hideReplyBox");
X.textContent = "⦻";
X.classList.add("cancelReply");
replybox.append(span);
replybox.append(X);
}
else {
replybox.classList.add("hideReplyBox");
}
}
async getmessage(id) {
if (this.messageids[id]) {
return this.messageids[id];
}
else {
const gety = await fetch(this.info.api.toString() + "/v9/channels/" + this.id + "/messages?limit=1&around=" + id, { headers: this.headers });
const json = await gety.json();
return new Message(json[0], this);
}
}
async getHTML() {
if (this.guild !== this.localuser.lookingguild) {
this.guild.loadGuild();
}
if (this.localuser.channelfocus && this.localuser.channelfocus.myhtml) {
this.localuser.channelfocus.myhtml.classList.remove("viewChannel");
}
this.myhtml.classList.add("viewChannel");
this.guild.prevchannel = this;
this.localuser.channelfocus = this;
const prom = Message.wipeChanel();
await this.putmessages();
await prom;
this.makereplybox();
this.buildmessages();
history.pushState(null, null, "/channels/" + this.guild_id + "/" + this.id);
document.getElementById("channelname").textContent = "#" + this.name;
console.log(this);
document.getElementById("typebox").disabled = !this.canMessage;
}
async putmessages() {
if (this.messages.length >= 100 || this.allthewayup) {
return;
}
;
const j = await fetch(this.info.api.toString() + "/channels/" + this.id + "/messages?limit=100", {
method: 'GET',
headers: this.headers,
});
const responce = await j.json();
if (responce.length !== 100) {
this.allthewayup = true;
}
for (const thing of responce) {
const messager = new Message(thing, this);
if (this.messageids[messager.id] === undefined) {
this.messageids[messager.id] = messager;
this.messages.push(messager);
}
}
}
delChannel(JSON) {
const build = [];
for (const thing of this.children) {
if (thing.id !== JSON.id) {
build.push(thing);
}
}
this.children = build;
}
async grabmoremessages() {
if (this.messages.length === 0 || 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", {
method: "GET",
headers: this.headers
}).then((j) => { return j.json(); }).then(responce => {
//messages.innerHTML = '';
//responce.reverse()
let next;
if (responce.length === 0) {
out.allthewayup = true;
}
for (const i in responce) {
let messager;
if (!next) {
messager = new Message(responce[i], this);
}
else {
messager = next;
}
if (responce[+i + 1] !== undefined) {
next = new Message(responce[+i + 1], this);
}
else {
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);
}
else {
console.log("How???");
}
}
//out.buildmessages();
});
return;
}
buildmessage(message, next) {
const built = message.buildhtml(next);
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);
}
document.getElementById("messagecontainer").scrollTop = document.getElementById("messagecontainer").scrollHeight;
}
updateChannel(JSON) {
this.type = JSON.type;
this.name = JSON.name;
this.parent_id = JSON.parent_id;
this.parrent = null;
this.children = [];
this.guild_id = JSON.guild_id;
this.messageids = {};
this.permission_overwrites = JSON.permission_overwrites;
this.topic = JSON.topic;
this.nsfw = JSON.nsfw;
}
typingstart() {
if (this.typing > new Date().getTime()) {
return;
}
this.typing = new Date().getTime() + 6000;
fetch(this.info.api.toString() + "/channels/" + this.id + "/typing", {
method: "POST",
headers: this.headers
});
}
get notification() {
let notinumber = this.message_notifications;
if (+notinumber === 3) {
notinumber = null;
}
notinumber ??= this.guild.message_notifications;
switch (+notinumber) {
case 0:
return "all";
case 1:
return "mentions";
case 2:
return "none";
case 3:
return "default";
}
}
async sendMessage(content, { attachments = [], embeds = [], replyingto = null }) {
let replyjson;
if (replyingto) {
replyjson =
{
"guild_id": replyingto.guild.id,
"channel_id": replyingto.channel.id,
"message_id": replyingto.id,
};
}
;
if (attachments.length === 0) {
const body = {
content: content,
nonce: Math.floor(Math.random() * 1000000000),
message_reference: undefined
};
if (replyjson) {
body.message_reference = replyjson;
}
console.log(body);
return await fetch(this.info.api.toString() + "/channels/" + this.id + "/messages", {
method: "POST",
headers: this.headers,
body: JSON.stringify(body)
});
}
else {
const formData = new FormData();
const body = {
content: content,
nonce: Math.floor(Math.random() * 1000000000),
message_reference: undefined
};
if (replyjson) {
body.message_reference = replyjson;
}
formData.append('payload_json', JSON.stringify(body));
for (const i in attachments) {
console.log(attachments[i]);
formData.append("files[" + i + "]", attachments[i]);
}
return await fetch(this.info.api.toString() + "/channels/" + this.id + "/messages", {
method: 'POST',
body: formData,
headers: { "Authorization": this.headers.Authorization }
});
}
}
messageCreate(messagep) {
if (!this.hasPermission("VIEW_CHANNEL")) {
return;
}
const messagez = new Message(messagep.d, this);
this.lastmessageid = messagez.id;
if (messagez.author === this.localuser.user) {
this.lastreadmessageid = messagez.id;
if (this.myhtml) {
this.myhtml.classList.remove("cunread");
}
}
else {
if (this.myhtml) {
this.myhtml.classList.add("cunread");
}
}
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;
}
if (messagez.author === this.localuser.user) {
return;
}
if (this.localuser.lookingguild.prevchannel === this && document.hasFocus()) {
return;
}
if (this.notification === "all") {
this.notify(messagez);
}
else if (this.notification === "mentions" && messagez.mentionsuser(this.localuser.user)) {
this.notify(messagez);
}
}
notititle(message) {
return message.author.username + " > " + this.guild.properties.name + " > " + this.name;
}
notify(message, deep = 0) {
Voice.noises(Voice.getNotificationSound());
if (!("Notification" in window)) {
}
else if (Notification.permission === "granted") {
let noticontent = markdown(message.content).textContent;
if (message.embeds[0]) {
noticontent ||= message.embeds[0].json.title;
noticontent ||= markdown(message.embeds[0].json.description).textContent;
}
noticontent ||= "Blank Message";
let imgurl = null;
const images = message.getimages();
if (images.length) {
const image = images[0];
imgurl ||= image.proxy_url;
imgurl ||= image.url;
}
const notification = new Notification(this.notititle(message), {
body: noticontent,
icon: message.author.getpfpsrc(),
image: imgurl,
});
notification.addEventListener("click", _ => {
window.focus();
this.getHTML();
});
}
else if (Notification.permission !== "denied") {
Notification.requestPermission().then(() => {
if (deep === 3) {
return;
}
;
this.notify(message, deep + 1);
});
}
}
}
Channel.setupcontextmenu();
export { Channel };

80
.dist/contextmenu.js Normal file
View file

@ -0,0 +1,80 @@
class Contextmenu {
static currentmenu;
name;
buttons;
div;
static setup() {
Contextmenu.currentmenu = "";
document.addEventListener('click', function (event) {
if (Contextmenu.currentmenu == "") {
return;
}
if (!Contextmenu.currentmenu.contains(event.target)) {
Contextmenu.currentmenu.remove();
Contextmenu.currentmenu = "";
}
});
}
constructor(name) {
this.name = name;
this.buttons = [];
}
addbutton(text, onclick, img = null, shown = _ => true, enabled = _ => true) {
this.buttons.push([text, onclick, img, shown, enabled]);
return {};
}
makemenu(x, y, addinfo, obj) {
const div = document.createElement("table");
div.classList.add("contextmenu");
for (const thing of this.buttons) {
if (!thing[3](addinfo)) {
continue;
}
const textb = document.createElement("tr");
const intext = document.createElement("button");
intext.disabled = !thing[4]();
textb["button"] = intext;
intext.classList.add("contextbutton");
intext.textContent = thing[0];
textb.appendChild(intext);
console.log(thing);
intext.onclick = thing[1].bind(addinfo, obj);
div.appendChild(textb);
}
if (Contextmenu.currentmenu != "") {
Contextmenu.currentmenu.remove();
}
div.style.top = y + 'px';
div.style.left = x + 'px';
document.body.appendChild(div);
Contextmenu.keepOnScreen(div);
console.log(div);
Contextmenu.currentmenu = div;
return this.div;
}
bind(obj, addinfo = undefined) {
const func = (event) => {
event.preventDefault();
event.stopImmediatePropagation();
this.makemenu(event.clientX, event.clientY, addinfo, obj);
};
obj.addEventListener("contextmenu", func);
return func;
}
static keepOnScreen(obj) {
const html = document.documentElement.getBoundingClientRect();
const docheight = html.height;
const docwidth = html.width;
const box = obj.getBoundingClientRect();
console.log(box, docheight, docwidth);
if (box.right > docwidth) {
console.log("test");
obj.style.left = docwidth - box.width + 'px';
}
if (box.bottom > docheight) {
obj.style.top = docheight - box.height + 'px';
}
}
}
Contextmenu.setup();
export { Contextmenu as Contextmenu };

202
.dist/direct.js Normal file
View file

@ -0,0 +1,202 @@
import { Guild } from "./guild.js";
import { Channel } from "./channel.js";
import { Message } from "./message.js";
import { User } from "./user.js";
class Direct extends Guild {
constructor(JSON, owner) {
super(-1, owner, null);
this.message_notifications = 0;
console.log(JSON);
this.owner = owner;
if (!this.localuser) {
console.error("Owner was not included, please fix");
}
this.headers = this.localuser.headers;
this.channels = [];
this.channelids = {};
this.id = "@me";
this.properties = {};
this.roles = [];
this.roleids = {};
this.prevchannel = undefined;
this.properties.name = "Dirrect Messages";
for (const thing of JSON) {
const temp = new Group(thing, this);
this.channels.push(temp);
this.channelids[temp.id] = temp;
}
this.headchannels = this.channels;
}
createChannelpac(JSON) {
const thischannel = new Group(JSON, this);
this.channelids[JSON.id] = thischannel;
this.channels.push(thischannel);
this.calculateReorder();
this.printServers();
}
sortchannels() {
this.headchannels.sort((a, b) => {
const result = (BigInt(a.lastmessageid) - BigInt(b.lastmessageid));
return Number(-result);
});
}
giveMember(member) {
console.error("not a real guild, can't give member object");
}
getRole(ID) {
return null;
}
hasRole(r) {
return false;
}
isAdmin() {
return false;
}
unreaddms() {
for (const thing of this.channels) {
thing.unreads();
}
}
}
class Group extends Channel {
user;
constructor(JSON, owner) {
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);
}
else {
this.user = this.localuser.user;
}
this.name ??= this.localuser.user.username;
this.id = JSON.id;
this.parent_id = null;
this.parrent = null;
this.children = [];
this.guild_id = "@me";
this.messageids = {};
this.permission_overwrites = {};
this.lastmessageid = JSON.last_message_id;
this.lastmessageid ??= "0";
this.mentions = 0;
}
createguildHTML() {
const div = document.createElement("div");
div.classList.add("channeleffects");
const myhtml = document.createElement("span");
myhtml.textContent = this.name;
div.appendChild(this.user.buildpfp());
div.appendChild(myhtml);
div["myinfo"] = this;
div.onclick = _ => {
this.getHTML();
};
return div;
}
async getHTML() {
if (this.guild !== this.localuser.lookingguild) {
this.guild.loadGuild();
}
const prom = Message.wipeChanel();
this.guild.prevchannel = this;
this.localuser.channelfocus = this;
await this.putmessages();
await prom;
this.buildmessages();
history.pushState(null, null, "/channels/" + this.guild_id + "/" + this.id);
document.getElementById("channelname").textContent = "@" + this.name;
}
messageCreate(messagep) {
const messagez = new Message(messagep.d, this);
this.lastmessageid = messagez.id;
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;
}
}
}
this.unreads();
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)) {
this.notify(messagez);
}
}
notititle(message) {
return message.author.username;
}
unreads() {
const sentdms = document.getElementById("sentdms");
let current = null;
for (const thing of sentdms.children) {
if (thing["all"] === this) {
current = thing;
}
}
if (this.hasunreads) {
if (current) {
current.noti.textContent = this.mentions;
return;
}
const div = document.createElement("div");
div.classList.add("servernoti");
const noti = document.createElement("div");
noti.classList.add("unread", "notiunread", "pinged");
noti.textContent = "" + this.mentions;
console.log(this.mentions);
div["noti"] = noti;
div.append(noti);
const buildpfp = this.user.buildpfp();
div["all"] = this;
buildpfp.classList.add("mentioned");
console.log(this);
div.append(buildpfp);
sentdms.append(div);
div.onclick = function () {
this["noti"].guild.loadGuild();
this["noti"].getHTML();
};
}
else if (current) {
current.remove();
}
else {
}
}
isAdmin() {
return false;
}
hasPermission(name, member) {
return true;
}
}
export { Direct, Group };

195
.dist/embed.js Normal file
View file

@ -0,0 +1,195 @@
import { Fullscreen } from "./fullscreen.js";
class Embed {
type;
owner;
json;
constructor(json, owner) {
this.type = this.getType(json);
this.owner = owner;
this.json = json;
}
getType(json) {
return json.type || "rich";
}
generateHTML() {
switch (this.type) {
case "rich":
return this.generateRich();
case "image":
return this.generateImage();
case "link":
return this.generateLink();
case "article":
return this.generateArticle();
default:
console.warn(`unsupported embed type ${this.type}, please add support dev :3`, this.json);
return document.createElement("div"); //prevent errors by giving blank div
}
}
generateRich() {
console.log(this.json);
const div = document.createElement("div");
if (this.json.color) {
div.style.backgroundColor = "#" + this.json.color.toString(16);
}
div.classList.add("embed-color");
const embed = document.createElement("div");
embed.classList.add("embed");
div.append(embed);
if (this.json.author) {
const authorline = document.createElement("div");
if (this.json.author.icon_url) {
const img = document.createElement("img");
img.classList.add("embedimg");
img.src = this.json.author.icon_url;
authorline.append(img);
}
const a = document.createElement("a");
a.innerText = this.json.author.name;
if (this.json.author.url) {
a.href = this.json.author.url;
}
a.classList.add("username");
authorline.append(a);
embed.append(authorline);
}
const title = document.createElement("a");
title.textContent = this.json.title;
if (this.json.url) {
title.href = this.json.url;
}
title.classList.add("embedtitle");
embed.append(title);
if (this.json.description) {
const p = document.createElement("p");
p.textContent = this.json.description;
embed.append(p);
}
embed.append(document.createElement("br"));
if (this.json.fields) {
for (const thing of this.json.fields) {
const div = document.createElement("div");
const b = document.createElement("b");
b.textContent = thing.name;
div.append(b);
let p;
p = document.createElement("p");
p.textContent = thing.value;
p.classList.add("embedp");
div.append(p);
if (thing.inline) {
div.classList.add("inline");
}
embed.append(div);
}
}
if (this.json.footer || this.json.timestamp) {
const footer = document.createElement("div");
if (this.json?.footer?.icon_url) {
const img = document.createElement("img");
img.src = this.json.footer.icon_url;
img.classList.add("embedicon");
footer.append(img);
}
if (this.json?.footer?.text) {
const span = document.createElement("span");
span.textContent = this.json.footer.text;
span.classList.add("spaceright");
footer.append(span);
}
if (this.json?.footer && this.json?.timestamp) {
const span = document.createElement("span");
span.textContent = "•";
span.classList.add("spaceright");
footer.append(span);
}
if (this.json?.timestamp) {
const span = document.createElement("span");
span.textContent = new Date(this.json.timestamp).toLocaleString();
;
footer.append(span);
}
embed.append(footer);
}
return div;
}
generateImage() {
const img = document.createElement("img");
img.classList.add("messageimg");
img.onclick = function () {
const full = new Fullscreen(["img", img.src, ["fit"]]);
full.show();
};
img.src = this.json.thumbnail.proxy_url;
return img;
}
generateLink() {
const table = document.createElement("table");
table.classList.add("embed", "linkembed");
const trtop = document.createElement("tr");
table.append(trtop);
{
const td = document.createElement("td");
const a = document.createElement("a");
a.href = this.json.url;
a.textContent = this.json.title;
td.append(a);
trtop.append(td);
}
{
const td = document.createElement("td");
const img = document.createElement("img");
if (this.json.thumbnail) {
img.classList.add("embedimg");
img.onclick = function () {
const full = new Fullscreen(["img", img.src, ["fit"]]);
full.show();
};
img.src = this.json.thumbnail.proxy_url;
td.append(img);
}
trtop.append(td);
}
const bottomtr = document.createElement("tr");
const td = document.createElement("td");
const span = document.createElement("span");
span.textContent = this.json.description;
td.append(span);
bottomtr.append(td);
table.append(bottomtr);
return table;
}
generateArticle() {
const colordiv = document.createElement("div");
colordiv.style.backgroundColor = "#000000";
colordiv.classList.add("embed-color");
const div = document.createElement("div");
div.classList.add("embed");
if (this.json.provider) {
const providor = document.createElement("p");
providor.classList.add("provider");
providor.textContent = this.json.provider.name;
div.append(providor);
}
const a = document.createElement("a");
a.href = this.json.url;
a.textContent = this.json.title;
div.append(a);
const description = document.createElement("p");
description.textContent = this.json.description;
div.append(description);
if (this.json.thumbnail) {
const img = document.createElement("img");
img.classList.add("bigembedimg");
img.onclick = function () {
const full = new Fullscreen(["img", img.src, ["fit"]]);
full.show();
};
img.src = this.json.thumbnail.proxy_url || this.json.thumbnail.url;
div.append(img);
}
colordiv.append(div);
return colordiv;
}
}
export { Embed };

127
.dist/file.js Normal file
View file

@ -0,0 +1,127 @@
import { Fullscreen } from "./fullscreen.js";
class File {
owner;
id;
filename;
content_type;
width;
height;
proxy_url;
url;
size;
constructor(fileJSON, owner) {
console.log(fileJSON);
this.owner = owner;
this.id = fileJSON.id;
this.filename = fileJSON.filename;
this.content_type = fileJSON.content_type;
this.width = fileJSON.width;
this.height = fileJSON.height;
this.url = fileJSON.url;
this.proxy_url = fileJSON.proxy_url;
this.content_type = fileJSON.content_type;
this.size = fileJSON.size;
}
getHTML(temp = false) {
const src = this.proxy_url || this.url;
if (this.content_type.startsWith('image/')) {
const img = document.createElement("img");
img.classList.add("messageimg");
img.onclick = function () {
const full = new Fullscreen(["img", img.src, ["fit"]]);
full.show();
};
img.src = src;
img.height = this.height;
img.width = this.width;
return img;
}
else if (this.content_type.startsWith('video/')) {
const video = document.createElement("video");
const source = document.createElement("source");
source.src = src;
video.append(source);
source.type = this.content_type;
video.controls = !temp;
return video;
}
else if (this.content_type.startsWith('audio/')) {
const audio = document.createElement("audio");
const source = document.createElement("source");
source.src = src;
audio.append(source);
source.type = this.content_type;
audio.controls = !temp;
return audio;
}
else {
return this.createunknown();
}
}
upHTML(files, file) {
const div = document.createElement("div");
const contained = this.getHTML(true);
div.classList.add("containedFile");
div.append(contained);
const controls = document.createElement("div");
const garbage = document.createElement("button");
garbage.textContent = "🗑";
garbage.onclick = _ => {
div.remove();
files.splice(files.indexOf(file), 1);
};
controls.classList.add("controls");
div.append(controls);
controls.append(garbage);
return div;
}
static initFromBlob(file) {
return new File({
filename: file.name,
size: file.size,
id: null,
content_type: file.type,
width: undefined,
height: undefined,
url: URL.createObjectURL(file),
proxy_url: undefined
}, null);
}
createunknown() {
console.log("🗎");
const src = this.proxy_url || this.url;
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");
if (src) {
const a = document.createElement("a");
a.href = src;
a.textContent = this.filename;
nametd.append(a);
}
else {
nametd.textContent = this.filename;
}
nametd.classList.add("filename");
nametr.append(nametd);
const sizetr = document.createElement("tr");
const size = document.createElement("td");
sizetr.append(size);
size.textContent = "Size:" + File.filesizehuman(this.size);
size.classList.add("filesize");
div.appendChild(sizetr);
return div;
}
static 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];
}
}
export { File };

247
.dist/fullscreen.js Normal file
View file

@ -0,0 +1,247 @@
export { Fullscreen };
class Fullscreen {
layout;
onclose;
onopen;
html;
background;
constructor(layout, onclose = _ => { }, onopen = _ => { }) {
this.layout = layout;
this.onclose = onclose;
this.onopen = onopen;
const div = document.createElement("div");
div.appendChild(this.tohtml(layout));
this.html = div;
this.html.classList.add("centeritem");
if (!(layout[0] === "img")) {
this.html.classList.add("nonimagecenter");
}
}
tohtml(array) {
switch (array[0]) {
case "img":
const img = document.createElement("img");
img.src = array[1];
if (array[2] != undefined) {
if (array[2].length == 2) {
img.width = array[2][0];
img.height = array[2][1];
}
else if (array[2][0] == "fit") {
img.classList.add("imgfit");
}
}
return img;
case "hdiv":
const hdiv = document.createElement("table");
const tr = document.createElement("tr");
hdiv.appendChild(tr);
for (const thing of array) {
if (thing === "hdiv") {
continue;
}
const td = document.createElement("td");
td.appendChild(this.tohtml(thing));
tr.appendChild(td);
}
return hdiv;
case "vdiv":
const vdiv = document.createElement("table");
for (const thing of array) {
if (thing === "vdiv") {
continue;
}
const tr = document.createElement("tr");
tr.appendChild(this.tohtml(thing));
vdiv.appendChild(tr);
}
return vdiv;
case "checkbox":
{
const div = document.createElement("div");
const checkbox = document.createElement('input');
div.appendChild(checkbox);
const label = document.createElement("span");
checkbox.value = array[2];
label.textContent = array[1];
div.appendChild(label);
checkbox.addEventListener("change", array[3]);
checkbox.type = "checkbox";
return div;
}
case "button":
{
const div = document.createElement("div");
const input = document.createElement('button');
const label = document.createElement("span");
input.textContent = array[2];
label.textContent = array[1];
div.appendChild(label);
div.appendChild(input);
input.addEventListener("click", array[3]);
return div;
}
case "mdbox":
{
const div = document.createElement("div");
const input = document.createElement("textarea");
input.value = array[2];
const label = document.createElement("span");
label.textContent = array[1];
input.addEventListener("input", array[3]);
div.appendChild(label);
div.appendChild(document.createElement("br"));
div.appendChild(input);
return div;
}
case "textbox":
{
const div = document.createElement("div");
const input = document.createElement("input");
input.value = array[2];
input.type = "text";
const label = document.createElement("span");
label.textContent = array[1];
console.log(array[3]);
input.addEventListener("input", array[3]);
div.appendChild(label);
div.appendChild(input);
return div;
}
case "fileupload":
{
const div = document.createElement("div");
const input = document.createElement("input");
input.type = "file";
const label = document.createElement("span");
label.textContent = array[1];
div.appendChild(label);
div.appendChild(input);
input.addEventListener("change", array[2]);
console.log(array);
return div;
}
case "text": {
const span = document.createElement("span");
span.textContent = array[1];
return span;
}
case "title": {
const span = document.createElement("span");
span.classList.add("title");
span.textContent = array[1];
return span;
}
case "radio": {
const div = document.createElement("div");
const fieldset = document.createElement("fieldset");
fieldset.addEventListener("change", function () {
let i = -1;
for (const thing of fieldset.children) {
i++;
if (i === 0) {
continue;
}
const checkbox = thing.children[0].children[0];
if (checkbox.checked) {
array[3](checkbox.value);
}
}
});
const legend = document.createElement("legend");
legend.textContent = array[1];
fieldset.appendChild(legend);
let i = 0;
for (const thing of array[2]) {
const div = document.createElement("div");
const input = document.createElement("input");
input.classList.add("radio");
input.type = "radio";
input.name = array[1];
input.value = thing;
if (i === array[4]) {
input.checked = true;
}
const label = document.createElement("label");
label.appendChild(input);
const span = document.createElement("span");
span.textContent = thing;
label.appendChild(span);
div.appendChild(label);
fieldset.appendChild(div);
i++;
}
div.appendChild(fieldset);
return div;
}
case "html": {
return array[1];
}
case "select": {
const div = document.createElement("div");
const label = document.createElement("label");
const select = document.createElement("select");
label.textContent = array[1];
div.append(label);
div.appendChild(select);
for (const thing of array[2]) {
const option = document.createElement("option");
option.textContent = thing;
select.appendChild(option);
}
select.selectedIndex = array[4];
select.addEventListener("change", array[3]);
return div;
}
case "tabs": {
const table = document.createElement("table");
const tabs = document.createElement("tr");
tabs.classList.add("tabbed-head");
table.appendChild(tabs);
const td = document.createElement("td");
tabs.appendChild(td);
const content = document.createElement("tr");
content.classList.add("tabbed-content");
table.appendChild(content);
let shown;
for (const thing of array[1]) {
const button = document.createElement("button");
button.textContent = thing[0];
td.appendChild(button);
const tdcontent = document.createElement("td");
tdcontent.colSpan = array[1].length;
tdcontent.appendChild(this.tohtml(thing[1]));
content.appendChild(tdcontent);
if (!shown) {
shown = tdcontent;
}
else {
tdcontent.hidden = true;
}
button.addEventListener("click", _ => {
shown.hidden = true;
tdcontent.hidden = false;
shown = tdcontent;
});
}
return table;
}
default:
console.error("can't find element:" + array[0], " full element:" + array);
return;
}
}
show() {
this.onopen();
console.log("fullscreen");
this.background = document.createElement("div");
this.background.classList.add("background");
document.body.appendChild(this.background);
document.body.appendChild(this.html);
this.background.onclick = function () { this.hide(); }.bind(this);
}
hide() {
document.body.removeChild(this.background);
document.body.removeChild(this.html);
}
}

486
.dist/guild.js Normal file
View file

@ -0,0 +1,486 @@
import { Channel } from "./channel.js";
import { Contextmenu } from "./contextmenu.js";
import { Role } from "./role.js";
import { Fullscreen } from "./fullscreen.js";
import { Member } from "./member.js";
class Guild {
owner;
headers;
channels;
channelids;
id;
properties;
roles;
roleids;
prevchannel;
message_notifications;
headchannels;
position;
parent_id;
member;
html;
static contextmenu = new Contextmenu("guild menu");
static setupcontextmenu() {
Guild.contextmenu.addbutton("Copy Guild id", function () {
console.log(this);
navigator.clipboard.writeText(this.id);
});
Guild.contextmenu.addbutton("Mark as read", function () {
console.log(this);
this.markAsRead();
});
Guild.contextmenu.addbutton("Notifications", function () {
console.log(this);
this.setnotifcation();
});
Guild.contextmenu.addbutton("Leave guild", function () {
this.confirmleave();
}, null, function (_) { return _.properties.owner_id !== _.member.user.id; });
Guild.contextmenu.addbutton("Delete guild", function () {
this.confirmDelete();
}, null, function (_) { return _.properties.owner_id === _.member.user.id; });
Guild.contextmenu.addbutton("Create invite", function () {
console.log(this);
}, null, _ => true, _ => false);
/* -----things left for later-----
guild.contextmenu.addbutton("Leave Guild",function(){
console.log(this)
this.deleteChannel();
},null,_=>{return thisuser.isAdmin()})
guild.contextmenu.addbutton("Mute Guild",function(){
editchannelf(this);
},null,_=>{return thisuser.isAdmin()})
*/
}
constructor(JSON, owner, member) {
if (JSON === -1) {
return;
}
this.owner = owner;
this.headers = this.owner.headers;
this.channels = [];
this.channelids = {};
this.id = JSON.id;
this.properties = JSON.properties;
this.roles = [];
this.roleids = {};
this.prevchannel = undefined;
this.message_notifications = 0;
for (const roley of JSON.roles) {
const roleh = new Role(roley, this);
this.roles.push(roleh);
this.roleids[roleh.id] = roleh;
}
Member.resolve(member, this).then(_ => this.member = _);
for (const thing of JSON.channels) {
const temp = new Channel(thing, this);
this.channels.push(temp);
this.channelids[temp.id] = temp;
}
this.headchannels = [];
for (const thing of this.channels) {
if (thing.resolveparent(this)) {
this.headchannels.push(thing);
}
}
}
notisetting(settings) {
this.message_notifications = settings.message_notifications;
}
setnotifcation() {
let noti = this.message_notifications;
const notiselect = new Fullscreen(["vdiv",
["radio", "select notifications type",
["all", "only mentions", "none"],
function (e) {
noti = ["all", "only mentions", "none"].indexOf(e);
},
noti
],
["button", "", "submit", _ => {
fetch(this.info.api.toString() + "/v9/users/@me/guilds/settings", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify({
"guilds": {
[this.id]: {
"message_notifications": noti
}
}
})
});
this.message_notifications = noti;
}]
]);
notiselect.show();
}
confirmleave() {
const full = new Fullscreen([
"vdiv",
["title",
"Are you sure you want to leave?"
],
["hdiv",
["button",
"",
"Yes, I'm sure",
_ => {
this.leave().then(_ => {
full.hide();
});
}
],
["button",
"",
"Nevermind",
_ => {
full.hide();
}
]
]
]);
full.show();
}
async leave() {
return fetch(this.info.api.toString() + "/users/@me/guilds/" + this.id, {
method: "DELETE",
headers: this.headers
});
}
printServers() {
let build = "";
for (const thing of this.headchannels) {
build += (thing.name + ":" + thing.position) + "\n";
for (const thingy of thing.children) {
build += (" " + thingy.name + ":" + thingy.position) + "\n";
}
}
console.log(build);
}
calculateReorder() {
let position = -1;
let build = [];
for (const thing of this.headchannels) {
const thisthing = { id: thing.id, position: undefined, parent_id: undefined };
if (thing.position <= position) {
thing.position = (thisthing.position = position + 1);
}
position = thing.position;
console.log(position);
if (thing.move_id && thing.move_id !== thing.parent_id) {
thing.parent_id = thing.move_id;
thisthing.parent_id = thing.parent_id;
thing.move_id = undefined;
}
if (thisthing.position || thisthing.parent_id) {
build.push(thisthing);
console.log(this.channelids[thisthing.parent_id]);
}
if (thing.children.length > 0) {
const things = thing.calculateReorder();
for (const thing of things) {
build.push(thing);
}
}
}
console.log(build);
this.printServers();
if (build.length === 0) {
return;
}
const serverbug = false;
if (serverbug) {
for (const thing of build) {
console.log(build, thing);
fetch(this.info.api.toString() + "/v9/guilds/" + this.id + "/channels", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify([thing])
});
}
}
else {
fetch(this.info.api.toString() + "/v9/guilds/" + this.id + "/channels", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify(build)
});
}
}
get localuser() {
return this.owner;
}
get info() {
return this.owner.info;
}
sortchannels() {
this.headchannels.sort((a, b) => { return a.position - b.position; });
}
generateGuildIcon() {
const divy = document.createElement("div");
divy.classList.add("servernoti");
const noti = document.createElement("div");
noti.classList.add("unread");
divy.append(noti);
this.localuser.guildhtml[this.id] = divy;
if (this.properties.icon != null) {
const img = document.createElement("img");
img.classList.add("pfp", "servericon");
img.src = this.info.cdn.toString() + "icons/" + this.properties.id + "/" + this.properties.icon + ".png";
divy.appendChild(img);
img.onclick = () => {
console.log(this.loadGuild);
this.loadGuild();
this.loadChannel();
};
Guild.contextmenu.bind(img, this);
}
else {
const div = document.createElement("div");
let build = "";
for (const char of this.properties.name.split(" ")) {
build += char[0];
}
div.textContent = build;
div.classList.add("blankserver", "servericon");
divy.appendChild(div);
div.onclick = () => {
this.loadGuild();
this.loadChannel();
};
Guild.contextmenu.bind(div, this);
}
return divy;
}
confirmDelete() {
let confirmname = "";
const full = new Fullscreen([
"vdiv",
["title",
"Are you sure you want to delete " + this.properties.name + "?"
],
["textbox",
"Name of server:",
"",
function () {
confirmname = this.value;
}
],
["hdiv",
["button",
"",
"Yes, I'm sure",
_ => {
console.log(confirmname);
if (confirmname !== this.properties.name) {
return;
}
this.delete().then(_ => {
full.hide();
});
}
],
["button",
"",
"Nevermind",
_ => {
full.hide();
}
]
]
]);
full.show();
}
async delete() {
return fetch(this.info.api.toString() + "/guilds/" + this.id + "/delete", {
method: "POST",
headers: this.headers,
});
}
unreads(html = undefined) {
if (html) {
this.html = html;
}
else {
html = this.html;
}
let read = true;
for (const thing of this.channels) {
if (thing.hasunreads) {
console.log(thing);
read = false;
break;
}
}
if (!html) {
return;
}
if (read) {
html.children[0].classList.remove("notiunread");
}
else {
html.children[0].classList.add("notiunread");
}
}
getHTML() {
//this.printServers();
this.sortchannels();
this.printServers();
const build = document.createElement("div");
for (const thing of this.headchannels) {
build.appendChild(thing.createguildHTML(this.isAdmin()));
}
return build;
}
isAdmin() {
return this.member.isAdmin();
}
async markAsRead() {
const build = { read_states: [] };
for (const thing of this.channels) {
if (thing.hasunreads) {
build.read_states.push({ channel_id: thing.id, message_id: thing.lastmessageid, read_state_type: 0 });
thing.lastreadmessageid = thing.lastmessageid;
thing.myhtml.classList.remove("cunread");
}
}
this.unreads();
fetch(this.info.api.toString() + "/v9/read-states/ack-bulk", {
method: "POST",
headers: this.headers,
body: JSON.stringify(build)
});
}
getRole(ID) {
if (!this.roleids[ID]) {
console.error(`role id ${ID} does not exist`, this.roleids);
}
return this.roleids[ID];
}
hasRole(r) {
console.log("this should run");
if ((typeof r) !== (typeof "")) {
r = r.id;
}
return this.member.hasRole(r);
}
loadChannel(ID = undefined) {
if (ID && this.channelids[ID]) {
this.channelids[ID].getHTML();
return;
}
if (this.prevchannel) {
console.log(this.prevchannel);
this.prevchannel.getHTML();
return;
}
for (const thing of this.channels) {
if (thing.children.length === 0) {
thing.getHTML();
return;
}
}
}
loadGuild() {
this.localuser.loadGuild(this.id);
}
updateChannel(JSON) {
this.channelids[JSON.id].updateChannel(JSON);
this.headchannels = [];
for (const thing of this.channels) {
thing.children = [];
}
for (const thing of this.channels) {
if (thing.resolveparent(this)) {
this.headchannels.push(thing);
}
}
this.printServers();
}
createChannelpac(JSON) {
const thischannel = new Channel(JSON, this);
this.channelids[JSON.id] = thischannel;
this.channels.push(thischannel);
thischannel.resolveparent(this);
if (!thischannel.parrent) {
this.headchannels.push(thischannel);
}
this.calculateReorder();
this.printServers();
}
createchannels(func = this.createChannel) {
let name = "";
let category = 0;
const channelselect = new Fullscreen(["vdiv",
["radio", "select channel type",
["voice", "text", "announcement"],
function (e) {
console.log(e);
category = { "text": 0, "voice": 2, "announcement": 5, "category": 4 }[e];
},
1
],
["textbox", "Name of channel", "", function () {
console.log(this);
name = this.value;
}],
["button", "", "submit", function () {
console.log(name, category);
func(name, category);
channelselect.hide();
}.bind(this)]
]);
channelselect.show();
}
createcategory() {
let name = "";
let category = 4;
const channelselect = new Fullscreen(["vdiv",
["textbox", "Name of category", "", function () {
console.log(this);
name = this.value;
}],
["button", "", "submit", function () {
console.log(name, category);
this.createChannel(name, category);
channelselect.hide();
}]
]);
channelselect.show();
}
delChannel(JSON) {
const channel = this.channelids[JSON.id];
delete this.channelids[JSON.id];
this.channels.splice(this.channels.indexOf(channel), 1);
const indexy = this.headchannels.indexOf(channel);
if (indexy !== -1) {
this.headchannels.splice(indexy, 1);
}
/*
const build=[];
for(const thing of this.channels){
console.log(thing.id);
if(thing!==channel){
build.push(thing)
}else{
console.log("fail");
if(thing.parrent){
thing.parrent.delChannel(JSON);
}
}
}
this.channels=build;
*/
this.printServers();
}
createChannel(name, type) {
fetch(this.info.api.toString() + "/guilds/" + this.id + "/channels", {
method: "Post",
headers: this.headers,
body: JSON.stringify({ name: name, type: type })
});
}
}
Guild.setupcontextmenu();
export { Guild };

278
.dist/index.js Normal file
View file

@ -0,0 +1,278 @@
import { Localuser } from "./localuser.js";
import { Contextmenu } from "./contextmenu.js";
import { mobile, getBulkUsers, setTheme } from "./login.js";
async function waitforload() {
let res;
new Promise(r => { res = r; });
document.addEventListener("DOMContentLoaded", function () {
res();
});
await res;
}
await waitforload();
function setDynamicHeight() {
var servertdHeight = document.getElementById('servertd').offsetHeight + document.getElementById('typediv').offsetHeight + document.getElementById('pasteimage').offsetHeight;
document.documentElement.style.setProperty('--servertd-height', servertdHeight + 'px');
}
const resizeObserver = new ResizeObserver(() => {
setDynamicHeight();
});
resizeObserver.observe(document.getElementById('servertd'));
resizeObserver.observe(document.getElementById('replybox'));
resizeObserver.observe(document.getElementById('pasteimage'));
setDynamicHeight();
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();
thisuser.init();
document.getElementById("loading").classList.add("doneloading");
document.getElementById("loading").classList.remove("loading");
console.log("done loading");
});
{
const userinfo = document.getElementById("userinfo");
const userdock = document.getElementById("userdock");
userinfo.addEventListener("click", function (event) {
const table = document.createElement("table");
for (const thing of Object.values(users.users)) {
const specialuser = thing;
console.log(specialuser.pfpsrc);
const tr = document.createElement("tr");
const td = document.createElement("td");
const userinfo = document.createElement("table");
userinfo.classList.add("switchtable");
const row = document.createElement("tr");
userinfo.append(row);
const pfpcell = document.createElement("td");
row.append(pfpcell);
const pfp = document.createElement("img");
pfpcell.append(pfp);
const usertd = document.createElement("td");
row.append(usertd);
const user = document.createElement("div");
usertd.append(user);
user.append(specialuser.username);
user.append(document.createElement("br"));
const span = document.createElement("span");
span.textContent = specialuser.serverurls.wellknown.hostname;
user.append(span);
span.classList.add("serverURL");
pfp.src = specialuser.pfpsrc;
pfp.classList.add("pfp");
td.append(userinfo);
tr.append(td);
table.append(tr);
tr.addEventListener("click", _ => {
thisuser.unload();
document.getElementById("loading").classList.remove("doneloading");
document.getElementById("loading").classList.add("loading");
thisuser = new Localuser(specialuser);
users["currentuser"] = specialuser.uid;
localStorage.setItem("userinfos", JSON.stringify(users));
thisuser.initwebsocket().then(_ => {
thisuser.loaduser();
thisuser.init();
document.getElementById("loading").classList.add("doneloading");
document.getElementById("loading").classList.remove("loading");
console.log("done loading");
});
});
}
{
const tr = document.createElement("tr");
const td = document.createElement("td");
tr.append(td);
td.append("Switch accounts ⇌");
td.addEventListener("click", _ => {
window.location.href = "/login.html";
});
table.append(tr);
}
table.classList.add("accountSwitcher");
if (Contextmenu.currentmenu != "") {
Contextmenu.currentmenu.remove();
}
Contextmenu.currentmenu = table;
console.log(table);
userdock.append(table);
event.stopImmediatePropagation();
});
}
{
const menu = new Contextmenu("create rightclick");
menu.addbutton("Create channel", function () {
thisuser.lookingguild.createchannels();
}, null, _ => { return thisuser.isAdmin(); });
menu.addbutton("Create category", function () {
thisuser.lookingguild.createcategory();
}, 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) {
const channel = thisuser.channelfocus;
channel.typingstart();
if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault();
if (channel.editing) {
channel.editing.edit((typebox).value);
channel.editing = null;
}
else {
replyingto = thisuser.channelfocus.replyingto;
let replying = replyingto;
if (replyingto) {
replyingto.div.classList.remove("replying");
}
thisuser.channelfocus.replyingto = null;
channel.sendMessage(typebox.value, {
attachments: images,
replyingto: replying,
});
thisuser.channelfocus.makereplybox();
}
while (images.length != 0) {
images.pop();
pasteimage.removeChild(imageshtml.pop());
}
typebox.value = "";
return;
}
}
const typebox = document.getElementById("typebox");
typebox.addEventListener("keyup", enter);
typebox.addEventListener("keydown", event => {
if (event.key === "Enter" && !event.shiftKey)
event.preventDefault();
});
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];
this.ws.send(JSON.stringify({ op: 14, d: { guild_id: path[2], channels: { [channel]: [[0, 99]] } } }));
}
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) => {
const file = File.initFromBlob(f);
e.preventDefault();
const html = file.upHTML(images, f);
pasteimage.appendChild(html);
images.push(f);
imageshtml.push(html);
});
});
setTheme();
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");
document.getElementById("servertd").classList.add("collapse");
document.getElementById("servers").classList.add("collapse");
};
document.getElementById("mobileback").textContent = "#";
document.getElementById("mobileback").onclick = function () {
document.getElementById("channels").parentNode.classList.remove("collapse");
document.getElementById("servertd").classList.remove("collapse");
document.getElementById("servers").classList.remove("collapse");
};
}
/*
{
const messages=document.getElementById("messages");
let height=messages.clientHeight;
//
const resizeObserver=new ResizeObserver(()=>{
console.log(messages.scrollTop,messages.clientHeight-height-messages.scrollHeight);
messages.scrollTop-=height-messages.scrollHeight;
console.log(messages.scrollTop)
//if(shouldsnap){
// document.getElementById("messagecontainer").scrollTop = document.getElementById("messagecontainer").scrollHeight;
//}
height=messages.scrollHeight;
})
resizeObserver.observe(messages)
}
*/

575
.dist/localuser.js Normal file
View file

@ -0,0 +1,575 @@
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";
class Localuser {
packets;
token;
userinfo;
serverurls;
initialized;
info;
headers;
usersettings;
ready;
guilds;
guildids;
user;
status;
channelfocus;
lookingguild;
guildhtml;
ws;
typing;
wsinterval;
constructor(userinfo) {
this.packets = 1;
this.token = userinfo.token;
this.userinfo = userinfo;
this.serverurls = this.userinfo.serverurls;
this.initialized = false;
this.info = this.serverurls;
this.headers = { "Content-type": "application/json; charset=UTF-8", Authorization: this.userinfo.token };
}
gottenReady(ready) {
this.usersettings = null;
this.initialized = true;
this.ready = ready;
this.guilds = [];
this.guildids = {};
this.user = new User(ready.d.user, this);
this.userinfo.username = this.user.username;
this.userinfo.pfpsrc = this.user.getpfpsrc();
this.status = this.ready.d.user_settings.status;
this.channelfocus = null;
this.lookingguild = null;
this.guildhtml = {};
const members = {};
for (const thing of ready.d.merged_members) {
members[thing[0].guild_id] = thing[0];
}
for (const thing of ready.d.guilds) {
const temp = new Guild(thing, this, members[thing.id]);
this.guilds.push(temp);
this.guildids[temp.id] = temp;
}
{
const temp = new Direct(ready.d.private_channels, this);
this.guilds.push(temp);
this.guildids[temp.id] = temp;
}
console.log(ready.d.user_guild_settings.entries);
for (const thing of ready.d.user_guild_settings.entries) {
this.guildids[thing.guild_id].notisetting(thing);
}
for (const thing of ready.d.read_state.entries) {
const channel = this.resolveChannelFromID(thing.id);
if (!channel) {
continue;
}
const guild = channel.guild;
if (guild === undefined) {
continue;
}
const guildid = guild.id;
this.guildids[guildid].channelids[thing.channel_id].readStateInfo(thing);
}
this.typing = [];
}
outoffocus() {
document.getElementById("servers").textContent = "";
document.getElementById("channels").textContent = "";
document.getElementById("messages").textContent = "";
this.lookingguild = null;
this.channelfocus = null;
}
unload() {
this.initialized = false;
clearInterval(this.wsinterval);
this.outoffocus();
this.guilds = [];
this.guildids = {};
this.ws.close(4000);
}
async initwebsocket() {
let returny = null;
const promise = new Promise((res) => { returny = res; });
this.ws = new WebSocket(this.serverurls.gateway.toString());
this.ws.addEventListener('open', (event) => {
console.log('WebSocket connected');
this.ws.send(JSON.stringify({
"op": 2,
"d": {
"token": this.token,
"capabilities": 16381,
"properties": {
"browser": "Jank Client",
"client_build_number": 0,
"release_channel": "Custom",
"browser_user_agent": navigator.userAgent
},
"compress": false,
"presence": {
"status": "online",
"since": new Date().getTime(),
"activities": [],
"afk": false
}
}
}));
});
this.ws.addEventListener('message', (event) => {
try {
const temp = JSON.parse(event.data);
console.log(temp);
if (temp.op == 0) {
switch (temp.t) {
case "MESSAGE_CREATE":
if (this.initialized) {
this.messageCreate(temp);
}
break;
case "MESSAGE_DELETE":
console.log(temp.d);
this.guildids[temp.d.guild_id].channelids[temp.d.channel_id].messageids[temp.d.id].deleteEvent();
break;
case "READY":
this.gottenReady(temp);
this.genusersettings();
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;
}
}
break;
case "TYPING_START":
if (this.initialized) {
this.typeingStart(temp);
}
break;
case "USER_UPDATE":
if (this.initialized) {
const users = User.userids[temp.d.id];
console.log(users, temp.d.id);
if (users) {
users.userupdate(temp.d);
}
}
break;
case "CHANNEL_UPDATE":
if (this.initialized) {
this.updateChannel(temp.d);
}
break;
case "CHANNEL_CREATE":
if (this.initialized) {
this.createChannel(temp.d);
}
break;
case "CHANNEL_DELETE":
if (this.initialized) {
this.delChannel(temp.d);
}
break;
case "GUILD_DELETE":
{
const guildy = this.guildids[temp.d.id];
delete this.guildids[temp.d.id];
this.guilds.splice(this.guilds.indexOf(guildy), 1);
guildy.html.remove();
break;
}
case "GUILD_CREATE":
{
const guildy = new Guild(temp.d, this, this.user);
this.guilds.push(guildy);
this.guildids[guildy.id] = guildy;
document.getElementById("servers").insertBefore(guildy.generateGuildIcon(), document.getElementById("bottomseperator"));
}
}
}
else if (temp.op === 10) {
console.log("heartbeat down");
this.wsinterval = setInterval(_ => {
this.ws.send(JSON.stringify({ op: 1, d: this.packets }));
}, temp.d.heartbeat_interval);
this.packets = 1;
}
else if (temp.op != 11) {
this.packets++;
}
}
catch (error) {
console.error(error);
}
});
this.ws.addEventListener('close', (event) => {
clearInterval(this.wsinterval);
console.log('WebSocket closed');
console.warn(event);
if (event.code !== 4000) {
this.unload();
document.getElementById("loading").classList.remove("doneloading");
document.getElementById("loading").classList.add("loading");
this.initwebsocket().then(_ => {
this.loaduser();
this.init();
document.getElementById("loading").classList.add("doneloading");
document.getElementById("loading").classList.remove("loading");
console.log("done loading");
});
}
});
await promise;
return;
}
resolveChannelFromID(ID) {
let resolve = this.guilds.find(guild => guild.channelids[ID]);
if (resolve) {
return resolve.channelids[ID];
}
return undefined;
}
updateChannel(JSON) {
this.guildids[JSON.guild_id].updateChannel(JSON);
if (JSON.guild_id === this.lookingguild.id) {
this.loadGuild(JSON.guild_id);
}
}
createChannel(JSON) {
JSON.guild_id ??= "@me";
this.guildids[JSON.guild_id].createChannelpac(JSON);
if (JSON.guild_id === this.lookingguild.id) {
this.loadGuild(JSON.guild_id);
}
}
delChannel(JSON) {
JSON.guild_id ??= "@me";
this.guildids[JSON.guild_id].delChannel(JSON);
if (JSON.guild_id === this.lookingguild.id) {
this.loadGuild(JSON.guild_id);
}
}
init() {
const location = window.location.href.split("/");
this.buildservers();
if (location[3] === "channels") {
const guild = this.loadGuild(location[4]);
guild.loadChannel(location[5]);
this.channelfocus = guild.channelids[location[5]];
}
}
loaduser() {
document.getElementById("username").textContent = this.user.username;
document.getElementById("userpfp").src = this.user.getpfpsrc();
document.getElementById("status").textContent = this.status;
}
isAdmin() {
return this.lookingguild.isAdmin();
}
loadGuild(id) {
let guild = this.guildids[id];
if (!guild) {
guild = this.guildids["@me"];
}
if (this.lookingguild) {
this.lookingguild.html.classList.remove("serveropen");
}
if (guild.html) {
guild.html.classList.add("serveropen");
}
this.lookingguild = guild;
document.getElementById("serverName").textContent = guild.properties.name;
//console.log(this.guildids,id)
document.getElementById("channels").innerHTML = "";
document.getElementById("channels").appendChild(guild.getHTML());
return guild;
}
buildservers() {
const serverlist = document.getElementById("servers"); //
const outdiv = document.createElement("div");
const div = document.createElement("div");
div.textContent = "⌂";
div.classList.add("home", "servericon");
div["all"] = this.guildids["@me"];
this.guildids["@me"].html = outdiv;
const unread = document.createElement("div");
unread.classList.add("unread");
outdiv.append(unread);
outdiv.appendChild(div);
outdiv.classList.add("servernoti");
serverlist.append(outdiv);
div.onclick = function () {
this["all"].loadGuild();
this["all"].loadChannel();
};
const sentdms = document.createElement("div");
sentdms.classList.add("sentdms");
serverlist.append(sentdms);
sentdms.id = "sentdms";
const br = document.createElement("hr");
br.classList.add("lightbr");
serverlist.appendChild(br);
for (const thing of this.guilds) {
if (thing instanceof Direct) {
thing.unreaddms();
continue;
}
const divy = thing.generateGuildIcon();
serverlist.append(divy);
}
{
const br = document.createElement("hr");
br.classList.add("lightbr");
serverlist.appendChild(br);
br.id = "bottomseperator";
const div = document.createElement("div");
div.textContent = "+";
div.classList.add("addserver", "servericon");
serverlist.appendChild(div);
div.onclick = _ => {
console.log("clicked :3");
this.createGuild();
};
}
this.unreads();
}
createGuild() {
let inviteurl = "";
const error = document.createElement("span");
const full = new Fullscreen(["tabs", [
["Join using invite", [
"vdiv",
["textbox",
"Invite Link/Code",
"",
function () {
console.log(this);
inviteurl = this.value;
}
],
["html", error],
["button",
"",
"Submit",
_ => {
let parsed = "";
if (inviteurl.includes("/")) {
parsed = inviteurl.split("/")[inviteurl.split("/").length - 1];
}
else {
parsed = inviteurl;
}
fetch(this.info.api.toString() + "/v9/invites/" + parsed, {
method: "POST",
headers: this.headers,
}).then(r => r.json()).then(_ => {
console.log(_);
if (_.message) {
error.textContent = _.message;
}
});
}
]
]],
["Create Server", [
"text", "Not currently implemented, sorry"
]]
]]);
full.show();
}
messageCreate(messagep) {
messagep.d.guild_id ??= "@me";
this.guildids[messagep.d.guild_id].channelids[messagep.d.channel_id].messageCreate(messagep);
this.unreads();
}
unreads() {
console.log(this.guildhtml);
for (const thing of this.guilds) {
if (thing.id === "@me") {
continue;
}
thing.unreads(this.guildhtml[thing.id]);
}
}
typeingStart(typing) {
if (this.channelfocus.id === typing.d.channel_id) {
const memb = typing.d.member;
let name;
if (memb.id === this.user.id) {
console.log("you is typing");
return;
}
console.log("user is typing and you should see it");
if (memb.nick) {
name = memb.nick;
}
else {
name = memb.user.username;
}
let already = false;
for (const thing of this.typing) {
if (thing[0] === name) {
thing[1] = new Date().getTime();
already = true;
break;
}
}
if (!already) {
this.typing.push([name, new Date().getTime()]);
}
setTimeout(this.rendertyping.bind(this), 10000);
this.rendertyping();
}
}
updatepfp(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
console.log(this.headers);
reader.onload = () => {
fetch(this.info.api.toString() + "/v9/users/@me", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify({
avatar: reader.result,
})
});
console.log(reader.result);
};
}
updatepronouns(pronouns) {
fetch(this.info.api.toString() + "/v9/users/@me/profile", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify({
pronouns: pronouns,
})
});
}
updatebio(bio) {
fetch(this.info.api.toString() + "/v9/users/@me/profile", {
method: "PATCH",
headers: this.headers,
body: JSON.stringify({
bio: bio,
})
});
}
rendertyping() {
const typingtext = document.getElementById("typing");
let build = "";
const array2 = [];
let showing = false;
let i = 0;
for (const thing of this.typing) {
i++;
if (thing[1] > new Date().getTime() - 5000) {
build += thing[0];
array2.push(thing);
showing = true;
if (i !== this.typing.length) {
build += ",";
}
}
}
if (i > 1) {
build += " are typing";
}
else {
build += " is typing";
}
console.log(typingtext.classList);
if (showing) {
typingtext.classList.remove("hidden");
document.getElementById("typingtext").textContent = build;
}
else {
typingtext.classList.add("hidden");
}
}
genusersettings() {
const hypothetcialprofie = document.createElement("div");
let file = null;
let newprouns = null;
let newbio = null;
let hypouser = new User(this.user, this, true);
function regen() {
hypothetcialprofie.textContent = "";
const hypoprofile = hypouser.buildprofile(-1, -1);
hypothetcialprofie.appendChild(hypoprofile);
}
regen();
this.usersettings = new Fullscreen(["hdiv",
["vdiv",
["fileupload", "upload pfp:", function (e) {
console.log(this.files[0]);
file = this.files[0];
const blob = URL.createObjectURL(this.files[0]);
hypouser.avatar = blob;
hypouser.hypotheticalpfp = true;
regen();
}],
["textbox", "Pronouns:", this.user.pronouns, function (e) {
console.log(this.value);
hypouser.pronouns = this.value;
newprouns = this.value;
regen();
}],
["mdbox", "Bio:", this.user.bio, function (e) {
console.log(this.value);
hypouser.bio = this.value;
newbio = this.value;
regen();
}],
["button", "update user content:", "submit", function () {
if (file !== null) {
this.updatepfp(file);
}
if (newprouns !== null) {
this.updatepronouns(newprouns);
}
if (newbio !== null) {
this.updatebio(newbio);
}
}],
["select", "Theme:", ["Dark", "Light", "WHITE"], e => {
localStorage.setItem("theme", ["Dark", "Light", "WHITE"][e.target.selectedIndex]);
setTheme();
}, ["Dark", "Light", "WHITE"].indexOf(localStorage.getItem("theme"))],
["select", "Notification sound:", Voice.sounds, e => {
Voice.setNotificationSound(Voice.sounds[e.target.selectedIndex]);
Voice.noises(Voice.sounds[e.target.selectedIndex]);
}, Voice.sounds.indexOf(Voice.getNotificationSound())]
],
["vdiv",
["html", hypothetcialprofie]
]
], _ => { }, function () {
console.log(this);
hypouser = new User(this.user, this);
regen();
file = null;
newprouns = null;
newbio = null;
}.bind(this));
}
}
export { Localuser };

237
.dist/login.js Normal file
View file

@ -0,0 +1,237 @@
const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
export { mobile, getBulkUsers, getBulkInfo, setTheme, Specialuser };
function setTheme() {
const name = localStorage.getItem("theme");
if (!name) {
document.body.className = "Dark-theme";
localStorage.setItem("theme", "Dark");
}
document.body.className = name + "-theme";
}
setTheme();
function getBulkUsers() {
const json = getBulkInfo();
for (const thing in json.users) {
json.users[thing] = new Specialuser(json.users[thing]);
}
return json;
}
function getBulkInfo() {
return JSON.parse(localStorage.getItem("userinfos"));
}
function setDefaults() {
let userinfos = getBulkInfo();
if (!userinfos) {
localStorage.setItem("userinfos", JSON.stringify({
currentuser: null,
users: {},
preferances: {
theme: "Dark",
notifcations: false,
notisound: "three",
},
}));
}
if (userinfos.users === undefined) {
userinfos.users = {};
}
if (userinfos.preferances === undefined) {
userinfos.preferances = {
theme: "Dark",
notifcations: false,
notisound: "three",
};
}
if (userinfos.preferances && (userinfos.preferances.notisound === undefined)) {
userinfos.preferances.notisound = "three";
}
localStorage.setItem("userinfos", JSON.stringify(userinfos));
}
setDefaults();
class Specialuser {
serverurls;
email;
token;
loggedin;
json;
constructor(json) {
if (json instanceof Specialuser) {
console.error("specialuser can't construct from another specialuser");
}
this.serverurls = json.serverurls;
this.serverurls.api = new URL(this.serverurls.api);
this.serverurls.cdn = new URL(this.serverurls.cdn);
this.serverurls.gateway = new URL(this.serverurls.gateway);
this.serverurls.wellknown = new URL(this.serverurls.wellknown);
this.email = json.email;
this.token = json.token;
this.loggedin = json.loggedin;
this.json = json;
if (!this.serverurls || !this.email || !this.token) {
console.error("There are fundamentally missing pieces of info missing from this user");
}
}
set pfpsrc(e) {
console.log("this ran fr");
this.json.pfpsrc = e;
this.updateLocal();
}
get pfpsrc() {
return this.json.pfpsrc;
}
set username(e) {
this.json.username = e;
this.updateLocal();
}
get username() {
return this.json.username;
}
get uid() {
return this.email + this.serverurls.wellknown;
}
toJSON() {
return this.json;
}
updateLocal() {
const info = getBulkInfo();
info.users[this.uid] = this.toJSON();
localStorage.setItem("userinfos", JSON.stringify(info));
}
}
function adduser(user) {
user = new Specialuser(user);
const info = getBulkInfo();
info.users[user.uid] = user;
info.currentuser = user.uid;
localStorage.setItem("userinfos", JSON.stringify(info));
}
const instancein = document.getElementById("instancein");
let timeout;
let instanceinfo;
async function checkInstance(e) {
const verify = document.getElementById("verify");
;
try {
verify.textContent = "Checking Instance";
const instanceinfo = await setInstance(instancein.value);
localStorage.setItem("instanceinfo", JSON.stringify(instanceinfo));
verify.textContent = "Instance is all good";
if (checkInstance["alt"]) {
checkInstance["alt"]();
}
setTimeout(_ => {
console.log(verify.textContent);
verify.textContent = "";
}, 3000);
}
catch (e) {
console.log("catch");
verify.textContent = "Invalid Instance, try again";
}
}
if (instancein) {
console.log(instancein);
instancein.addEventListener("keydown", e => {
const verify = document.getElementById("verify");
verify.textContent = "Waiting to check Instance";
clearTimeout(timeout);
timeout = setTimeout(checkInstance, 1000);
});
if (localStorage.getItem("instanceinfo")) {
instancein.value = JSON.parse(localStorage.getItem("instanceinfo")).wellknown;
}
else {
checkInstance("https://spacebar.chat/");
}
}
async function login(username, password) {
const options = {
method: "POST",
body: JSON.stringify({
"login": username,
"password": password,
"undelete": false
}),
headers: {
"Content-type": "application/json; charset=UTF-8",
}
};
try {
const info = JSON.parse(localStorage.getItem("instanceinfo"));
const url = new URL(info.login);
return await fetch(url.origin + '/api/auth/login', options).then(responce => responce.json())
.then((response) => {
console.log(response, response.message);
if ("Invalid Form Body" === response.message) {
return response.errors.login._errors[0].message;
console.log("test");
}
//this.serverurls||!this.email||!this.token
adduser({ serverurls: JSON.parse(localStorage.getItem("instanceinfo")), email: username, token: response.token });
window.location.href = '/channels/@me';
return response.token;
});
}
catch (error) {
console.error('Error:', error);
}
;
}
async function setInstance(url) {
url = new URL(url);
async function attempt(aurl) {
const info = await fetch(`${aurl.toString()}${aurl.pathname.includes("api") ? "" : "api"}/policies/instance/domains`)
.then((x) => x.json());
return {
api: info.apiEndpoint,
gateway: info.gateway,
cdn: info.cdn,
wellknown: url,
login: aurl.toString()
};
}
try {
return await attempt(url);
}
catch (e) {
}
const wellKnown = await fetch(`${url.origin}/.well-known/spacebar`)
.then((x) => x.json())
.then((x) => new URL(x.api));
return await attempt(wellKnown);
}
async function check(e) {
e.preventDefault();
let h = await login(e.srcElement[1].value, e.srcElement[2].value);
document.getElementById("wrong").textContent = h;
console.log(h);
}
if (document.getElementById("form")) {
document.getElementById("form").addEventListener("submit", check);
}
//Service workers :3
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/service.js", {
scope: "/",
}).then((registration) => {
let serviceWorker;
if (registration.installing) {
serviceWorker = registration.installing;
console.log("installing");
}
else if (registration.waiting) {
serviceWorker = registration.waiting;
console.log("waiting");
}
else if (registration.active) {
serviceWorker = registration.active;
console.log("active");
}
if (serviceWorker) {
console.log(serviceWorker.state);
serviceWorker.addEventListener("statechange", (e) => {
console.log(e.target.state);
});
}
});
}

362
.dist/markdown.js Normal file
View file

@ -0,0 +1,362 @@
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");
}
}
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 + 2] === " ") {
element = document.createElement("h1");
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"));
}
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(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 (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 underscores = "~~";
if (count === 2) {
const s = document.createElement("s");
if (keep) {
s.append(underscores);
}
s.appendChild(markdown(build, { keep: keep, stdsize: stdsize }));
if (keep) {
s.append(underscores);
}
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 underscores = "||";
if (count === 2) {
const j = document.createElement("j");
if (keep) {
j.append(underscores);
}
j.appendChild(markdown(build, { keep: keep, stdsize: stdsize }));
j.classList.add("spoiler");
j.onclick = markdown.unspoil;
if (keep) {
j.append(underscores);
}
span.appendChild(j);
}
continue;
}
}
current.textContent += txt[i];
}
appendcurrent();
return span;
}
markdown.unspoil = function (e) {
//console.log("undone")
e.target.classList.remove("spoiler");
e.target.classList.add("unspoiled");
};

119
.dist/member.js Normal file
View file

@ -0,0 +1,119 @@
import { User } from "./user.js";
import { Guild } from "./guild.js";
class Member {
static already = {};
owner;
user;
roles;
error;
constructor(memberjson, owner, error = false) {
this.error = error;
this.owner = owner;
let membery = memberjson;
this.roles = [];
if (!error) {
if (memberjson.guild_member) {
membery = memberjson.guild_member;
this.user = memberjson.user;
}
}
for (const thing of Object.keys(membery)) {
if (thing === "guild") {
continue;
}
if (thing === "owner") {
continue;
}
if (thing === "roles") {
for (const strrole of membery["roles"]) {
const role = this.guild.getRole(strrole);
this.roles.push(role);
}
continue;
}
this[thing] = membery[thing];
}
if (error) {
this.user = memberjson;
}
else {
this.user = new User(this.user, owner.localuser);
}
}
get guild() {
return this.owner;
}
get localuser() {
return this.guild.localuser;
}
get info() {
return this.owner.info;
}
static async resolve(unkown, guild) {
if (!(guild instanceof Guild)) {
console.error(guild);
}
let user;
if (unkown instanceof User) {
user = unkown;
}
else {
return new Member(unkown, guild);
}
if (guild.id === "@me") {
return null;
}
if (!Member.already[guild.id]) {
Member.already[guild.id] = {};
}
else if (Member.already[guild.id][user.id]) {
const memb = Member.already[guild.id][user.id];
if (memb instanceof Promise) {
return await memb;
}
return memb;
}
const promoise = fetch(guild.info.api.toString() + "/v9/users/" + user.id + "/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" + guild.id, { headers: guild.headers }).then(_ => _.json()).then(json => {
const memb = new Member(json, guild);
Member.already[guild.id][user.id] = memb;
console.log("resolved");
return memb;
});
Member.already[guild.id][user.id] = promoise;
try {
return await promoise;
}
catch (_) {
const memb = new Member(user, guild, true);
Member.already[guild.id][user.id] = memb;
return memb;
}
}
hasRole(ID) {
console.log(this.roles, ID);
for (const thing of this.roles) {
if (thing.id === ID) {
return true;
}
}
return false;
}
getColor() {
for (const thing of this.roles) {
const color = thing.getColor();
if (color) {
return color;
}
}
return "";
}
isAdmin() {
for (const role of this.roles) {
if (role.permissions.getPermision("ADMINISTRATOR")) {
return true;
}
}
return this.guild.properties.owner_id === this.user.id;
}
}
export { Member };

384
.dist/message.js Normal file
View file

@ -0,0 +1,384 @@
import { Contextmenu } from "./contextmenu.js";
import { User } from "./user.js";
import { Member } from "./member.js";
import { markdown } from "./markdown.js";
import { Embed } from "./embed.js";
import { File } from "./file.js";
class Message {
static contextmenu = new Contextmenu("message menu");
owner;
headers;
embeds;
author;
mentions;
mention_roles;
attachments; //probably should be its own class tbh, should be Attachments[]
id;
message_reference;
type;
timestamp;
content;
static del;
static resolve;
div;
static setup() {
this.del = new Promise(_ => { this.resolve = _; });
Message.setupcmenu();
}
static async wipeChanel() {
this.resolve();
document.getElementById("messages").innerHTML = "";
await Promise.allSettled([this.resolve]);
this.del = new Promise(_ => { this.resolve = _; });
}
static setupcmenu() {
Message.contextmenu.addbutton("Copy raw text", function () {
navigator.clipboard.writeText(this.content);
});
Message.contextmenu.addbutton("Reply", function (div) {
this.channel.setReplying(this);
});
Message.contextmenu.addbutton("Copy message id", function () {
navigator.clipboard.writeText(this.id);
});
Message.contextmenu.addbutton("Copy user id", function () {
navigator.clipboard.writeText(this.author.id);
});
Message.contextmenu.addbutton("Message user", function () {
fetch(this.info.api.toString() + "/v9/users/@me/channels", { method: "POST",
body: JSON.stringify({ "recipients": [this.author.id] }),
headers: this.headers
});
});
Message.contextmenu.addbutton("Edit", function () {
this.channel.editing = this;
document.getElementById("typebox").value = this.content;
}, null, _ => { return _.author.id === _.localuser.user.id; });
Message.contextmenu.addbutton("Delete message", function () {
this.delete();
}, null, _ => { return _.canDelete(); });
}
constructor(messagejson, owner) {
this.owner = owner;
this.headers = this.owner.headers;
for (const thing of Object.keys(messagejson)) {
if (thing === "attachments") {
this.attachments = [];
for (const thing of messagejson.attachments) {
this.attachments.push(new File(thing, this));
}
continue;
}
this[thing] = messagejson[thing];
}
for (const thing in this.embeds) {
console.log(thing, this.embeds);
this.embeds[thing] = new Embed(this.embeds[thing], this);
}
this.author = new User(this.author, this.localuser);
for (const thing in this.mentions) {
this.mentions[thing] = new User(this.mentions[thing], this.localuser);
}
if (this.mentions.length || this.mention_roles.length) { //currently mention_roles isn't implemented on the spacebar servers
console.log(this.mentions, this.mention_roles);
}
if (this.mentionsuser(this.localuser.user)) {
console.log(this);
}
}
canDelete() {
return this.channel.hasPermission("MANAGE_MESSAGES") || this.author.id === this.localuser.user.id;
}
get channel() {
return this.owner;
}
get guild() {
return this.owner.guild;
}
get localuser() {
return this.owner.localuser;
}
get info() {
return this.owner.info;
}
messageevents(obj) {
const func = Message.contextmenu.bind(obj, this);
this.div = obj;
Message.del.then(_ => {
obj.removeEventListener("click", func);
this.div = null;
});
obj.classList.add("messagediv");
}
mentionsuser(userd) {
if (userd instanceof User) {
return this.mentions.includes(userd);
}
else if (userd instanceof Member) {
return this.mentions.includes(userd.user);
}
}
getimages() {
const build = [];
for (const thing of this.attachments) {
if (thing.content_type.startsWith('image/')) {
build.push(thing);
}
}
return build;
}
async edit(content) {
return await fetch(this.info.api.toString() + "/channels/" + this.channel.id + "/messages/" + this.id, {
method: "PATCH",
headers: this.headers,
body: JSON.stringify({ content: content })
});
}
delete() {
fetch(`${this.info.api.toString()}/channels/${this.channel.id}/messages/${this.id}`, {
headers: this.headers,
method: "DELETE",
});
}
deleteEvent() {
if (this.div) {
this.div.innerHTML = "";
this.div = null;
}
const index = this.channel.messages.indexOf(this);
this.channel.messages.splice(this.channel.messages.indexOf(this), 1);
delete this.channel.messageids[this.id];
const regen = this.channel.messages[index - 1];
if (regen) {
regen.generateMessage();
}
}
generateMessage(premessage = null) {
if (!premessage) {
premessage = this.channel.messages[this.channel.messages.indexOf(this) + 1];
}
const div = this.div;
if (this === this.channel.replyingto) {
div.classList.add("replying");
}
div.innerHTML = "";
const build = document.createElement('table');
if (this.message_reference) {
const replyline = document.createElement("div");
const line = document.createElement("hr");
const minipfp = document.createElement("img");
minipfp.classList.add("replypfp");
replyline.appendChild(line);
replyline.appendChild(minipfp);
const username = document.createElement("span");
replyline.appendChild(username);
const reply = document.createElement("div");
username.classList.add("username");
Member.resolve(this.author, this.guild).then(_ => {
if (!_) {
return;
}
;
console.log(_.error);
if (_.error) {
username.textContent += "Error";
alert("Should've gotten here");
const error = document.createElement("span");
error.textContent = "!";
error.classList.add("membererror");
username.after(error);
return;
}
username.style.color = _.getColor();
}).catch(_ => {
console.log(_);
});
reply.classList.add("replytext");
replyline.appendChild(reply);
const line2 = document.createElement("hr");
replyline.appendChild(line2);
line2.classList.add("reply");
line.classList.add("startreply");
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 }));
minipfp.src = author.getpfpsrc();
author.profileclick(minipfp);
username.textContent = author.username;
author.profileclick(username);
});
div.appendChild(replyline);
}
this.messageevents(div);
build.classList.add("message");
div.appendChild(build);
if ({ 0: true, 19: true }[this.type] || this.attachments.length !== 0) {
const pfpRow = document.createElement('th');
let pfpparent, current;
if (premessage != null) {
pfpparent ??= premessage;
let pfpparent2 = pfpparent.all;
pfpparent2 ??= pfpparent;
const old = (new Date(pfpparent2.timestamp).getTime()) / 1000;
const newt = (new Date(this.timestamp).getTime()) / 1000;
current = (newt - old) > 600;
}
const combine = (premessage?.author?.id != this.author.id) || (current) || this.message_reference;
if (combine) {
const pfp = this.author.buildpfp();
this.author.profileclick(pfp);
pfpRow.appendChild(pfp);
}
else {
div["pfpparent"] = pfpparent;
}
pfpRow.classList.add("pfprow");
build.appendChild(pfpRow);
const text = document.createElement("th");
const texttxt = document.createElement("table");
texttxt.classList.add("commentrow");
text.appendChild(texttxt);
if (combine) {
const username = document.createElement("span");
username.classList.add("username");
this.author.profileclick(username);
Member.resolve(this.author, this.guild).then(_ => {
if (!_) {
return;
}
;
if (_.error) {
const error = document.createElement("span");
error.textContent = "!";
error.classList.add("membererror");
username.after(error);
return;
}
username.style.color = _.getColor();
});
username.textContent = this.author.username;
const userwrap = document.createElement("tr");
userwrap.appendChild(username);
if (this.author.bot) {
const username = document.createElement("span");
username.classList.add("bot");
username.textContent = "BOT";
userwrap.appendChild(username);
}
const time = document.createElement("span");
time.textContent = " " + formatTime(new Date(this.timestamp));
time.classList.add("timestamp");
userwrap.appendChild(time);
texttxt.appendChild(userwrap);
}
const messaged = markdown(this.content);
div["txt"] = messaged;
const messagedwrap = document.createElement("tr");
messagedwrap.appendChild(messaged);
texttxt.appendChild(messagedwrap);
build.appendChild(text);
if (this.attachments.length) {
console.log(this.attachments);
const attatch = document.createElement("tr");
for (const thing of this.attachments) {
attatch.appendChild(thing.getHTML());
}
messagedwrap.appendChild(attatch);
}
if (this.embeds.length) {
const embeds = document.createElement("tr");
for (const thing of this.embeds) {
embeds.appendChild(thing.generateHTML());
}
messagedwrap.appendChild(embeds);
}
//
}
else if (this.type === 7) {
const text = document.createElement("th");
const texttxt = document.createElement("table");
text.appendChild(texttxt);
build.appendChild(text);
const messaged = document.createElement("p");
div["txt"] = messaged;
messaged.textContent = "welcome: " + this.author.username;
const messagedwrap = document.createElement("tr");
messagedwrap.appendChild(messaged);
const time = document.createElement("span");
time.textContent = " " + formatTime(new Date(this.timestamp));
time.classList.add("timestamp");
messagedwrap.append(time);
texttxt.appendChild(messagedwrap);
}
div["all"] = this;
return (div);
}
buildhtml(premessage) {
if (this.div) {
console.error(`HTML for ${this} already exists, aborting`);
return;
}
//premessage??=messages.lastChild;
const div = document.createElement("div");
this.div = div;
return this.generateMessage(premessage);
}
createunknown(fname, fsize, src) {
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");
if (src) {
const a = document.createElement("a");
a.href = src;
a.textContent = fname;
nametd.append(a);
}
else {
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:" + this.filesizehuman(fsize);
size.classList.add("filesize");
div.appendChild(sizetr);
return div;
}
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 formatTime(date) {
const now = new Date();
const sameDay = date.getDate() === now.getDate() &&
date.getMonth() === now.getMonth() &&
date.getFullYear() === now.getFullYear();
const yesterday = new Date(now);
yesterday.setDate(now.getDate() - 1);
const isYesterday = date.getDate() === yesterday.getDate() &&
date.getMonth() === yesterday.getMonth() &&
date.getFullYear() === yesterday.getFullYear();
const formatTime = date => date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
if (sameDay) {
return `Today at ${formatTime(date)}`;
}
else if (isYesterday) {
return `Yesterday at ${formatTime(date)}`;
}
else {
return `${date.toLocaleDateString()} at ${formatTime(date)}`;
}
}
Message.setup();
export { Message };

246
.dist/permissions.js Normal file
View file

@ -0,0 +1,246 @@
export { Permissions };
class Permissions {
allow;
deny;
constructor(allow, deny = "") {
this.allow = BigInt(allow);
this.deny = BigInt(deny);
}
getPermisionbit(b, big) {
return Boolean((big >> BigInt(b)) & 1n);
}
setPermisionbit(b, state, big) {
const bit = 1n << BigInt(b);
return (big & ~bit) | (BigInt(state) << BigInt(b)); //thanks to geotale for this code :3
}
static map;
static info;
static makeMap() {
Permissions.info = [
{
name: "CREATE_INSTANT_INVITE",
readableName: "Create instance invite",
description: "Allows the user to create invites for the guild"
},
{
name: "KICK_MEMBERS",
readableName: "Kick members",
description: "Allows the user to kick members from the guild"
},
{
name: "BAN_MEMBERS",
readableName: "Ban members",
description: "Allows the user to ban members from the guild"
},
{
name: "ADMINISTRATOR",
readableName: "Administrator",
description: "Allows all permissions and bypasses channel permission overwrites"
},
{
name: "MANAGE_CHANNELS",
readableName: "Manage channels",
description: "Allows the user to manage and edit channels"
},
{
name: "MANAGE_GUILD",
readableName: "Manage guild",
description: "Allows management and editing of the guild"
},
{
name: "ADD_REACTIONS",
readableName: "Add reactions",
description: "Allows user to add reactions to messages"
},
{
name: "VIEW_AUDIT_LOG",
readableName: "View audit log",
description: "Allows the user to view the audit log"
},
{
name: "PRIORITY_SPEAKER",
readableName: "Priority speaker",
description: "Allows for using priority speaker in a voice channel"
},
{
name: "STREAM",
readableName: "Stream",
description: "Allows the user to stream"
},
{
name: "VIEW_CHANNEL",
readableName: "View channel",
description: "Allows the user to view the channel"
},
{
name: "SEND_MESSAGES",
readableName: "Send Messages",
description: "Allows user to send messages"
},
{
name: "SEND_TTS_MESSAGES",
readableName: "Send text-to-speech messages",
description: "Allows the user to send text-to-speech messages"
},
{
name: "MANAGE_MESSAGES",
readableName: "Manager messages",
description: "Allows the user to delete messages that aren't their own"
},
{
name: "EMBED_LINKS",
readableName: "Embed links",
description: "Allow links sent by this user to auto-embed"
},
{
name: "ATTACH_FILES",
readableName: "Attach files",
description: "Allows the user to attach files"
},
{
name: "READ_MESSAGE_HISTORY",
readableName: "Read message history",
description: "Allows user to read the message history"
},
{
name: "MENTION_EVERYONE",
readableName: "Mention everyone",
description: "Allows the user to mention everyone"
},
{
name: "USE_EXTERNAL_EMOJIS",
readableName: "Use external emojis",
description: "Allows the user to use external emojis"
},
{
name: "VIEW_GUILD_INSIGHTS",
readableName: "View guild insights",
description: "Allows the user to see guild insights"
},
{
name: "CONNECT",
readableName: "Connect",
description: "Allows the user to connect to a voice channel"
},
{
name: "SPEAK",
readableName: "Speak",
description: "Allows the user to speak in a voice channel"
},
{
name: "MUTE_MEMBERS",
readableName: "Mute members",
description: "Allows user to mute other members"
},
{
name: "DEAFEN_MEMBERS",
readableName: "Deafen members",
description: "Allows user to deafen other members"
},
{
name: "MOVE_MEMBERS",
readableName: "Move members",
description: "Allows the user to move members between voice channels"
},
{
name: "USE_VAD",
readableName: "use voice-activity-detection",
description: "Allows user to use voice-activity-detection"
},
{
name: "CHANGE_NICKNAME",
readableName: "Change nickname",
description: "Allows the user to change their own nickname"
},
{
name: "MANAGE_NICKNAMES",
readableName: "Manage nicknames",
description: "Allows user to change nicknames of other members"
},
{
name: "MANAGE_ROLES",
readableName: "Manage roles",
description: "Allows user to edit and manage roles"
},
{
name: "MANAGE_WEBHOOKS",
readableName: "Manage webhooks",
description: "Allows management and editing of webhooks"
},
{
name: "MANAGE_GUILD_EXPRESSIONS",
readableName: "Manage guild expressions",
description: "Allows for managing emoji, stickers, and soundboards"
},
{
name: "USE_APPLICATION_COMMANDS",
readableName: "Use application commands",
description: "Allows the user to use application commands"
},
{
name: "REQUEST_TO_SPEAK",
readableName: "Request to speak",
description: "Allows user to request to speak in stage channel"
},
{
name: "MANAGE_EVENTS",
readableName: "Manage events",
description: "Allows user to edit and manage events"
},
{
name: "MANAGE_THREADS",
readableName: "Manage threads",
description: "Allows the user to delete and archive threads and view all private threads"
},
{
name: "CREATE_PUBLIC_THREADS",
readableName: "Create public threads",
description: "Allows the user to create public threads"
},
{
name: "CREATE_PRIVATE_THREADS",
readableName: "Create private threads",
description: "Allows the user to create private threads"
},
{
name: "USE_EXTERNAL_STICKERS",
readableName: "Use external stickers",
description: "Allows user to use external stickers"
},
{
name: "SEND_MESSAGES_IN_THREADS",
readableName: "Send messages in threads",
description: "Allows the user to send messages in threads"
},
{
name: "USE_EMBEDDED_ACTIVITIES",
readableName: "Use embedded activities",
description: "Allows the user to use embedded activities"
},
{
name: "MODERATE_MEMBERS",
readableName: "Moderate members",
description: "Allows the user to time out other users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels"
},
];
Permissions.map = {};
let i = 0;
for (const thing of Permissions.info) {
Permissions.map[i] = thing;
Permissions.map[thing.name] = i;
i++;
}
}
getPermision(name) {
if (this.getPermisionbit(Permissions.map[name], this.allow)) {
return 1;
}
else if (this.getPermisionbit(Permissions.map[name], this.deny)) {
return -1;
}
else {
return 0;
}
}
}
Permissions.makeMap();

28
.dist/role.js Normal file
View file

@ -0,0 +1,28 @@
export { Role };
import { Permissions } from "./permissions.js";
class Role {
permissions;
owner;
color;
id;
constructor(JSON, owner) {
for (const thing of Object.keys(JSON)) {
this[thing] = JSON[thing];
}
this.permissions = new Permissions(JSON.permissions);
this.owner = owner;
}
get guild() {
return this.owner;
}
get localuser() {
return this.guild.localuser;
}
getColor() {
if (this.color === 0) {
return null;
}
;
return `#${this.color.toString(16)}`;
}
}

93
.dist/service.js Normal file
View file

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

140
.dist/user.js Normal file
View file

@ -0,0 +1,140 @@
//const usercache={};
import { Member } from "./member.js";
import { markdown } from "./markdown.js";
import { Contextmenu } from "./contextmenu.js";
class User {
static userids = {};
owner;
hypotheticalpfp;
id;
avatar;
username;
bio;
discriminator;
pronouns;
bot;
static checkuser(userjson, owner) {
if (User.userids[userjson.id]) {
return User.userids[userjson.id];
}
else {
const tempuser = new User(userjson, owner, true);
User.userids[userjson.id] = tempuser;
return tempuser;
}
}
get info() {
return this.owner.info;
}
get localuser() {
return this.owner;
}
constructor(userjson, owner, dontclone = false) {
this.owner = owner;
if (!owner) {
console.error("missing localuser");
}
if (dontclone) {
for (const thing of Object.keys(userjson)) {
this[thing] = userjson[thing];
}
this.hypotheticalpfp = false;
}
else {
return User.checkuser(userjson, owner);
}
}
async resolvemember(guild) {
await Member.resolve(this, guild);
}
buildpfp() {
const pfp = document.createElement('img');
pfp.src = this.getpfpsrc();
pfp.classList.add("pfp");
pfp.classList.add("userid:" + this.id);
return pfp;
}
userupdate(json) {
if (json.avatar !== this.avatar) {
console.log;
this.changepfp(json.avatar);
}
}
changepfp(update) {
this.avatar = update;
this.hypotheticalpfp = false;
const src = this.getpfpsrc();
console.log(src);
for (const thing of document.getElementsByClassName("userid:" + this.id)) {
thing.src = src;
}
}
getpfpsrc() {
if (this.hypotheticalpfp) {
return this.avatar;
}
if (this.avatar != null) {
return this.info.cdn.toString() + "avatars/" + this.id + "/" + this.avatar + ".png";
}
else {
return this.info.cdn.toString() + "embed/avatars/3.png";
}
}
createjankpromises() {
new Promise(_ => { });
}
buildprofile(x, y) {
if (Contextmenu.currentmenu != "") {
Contextmenu.currentmenu.remove();
}
const div = document.createElement("table");
if (x !== -1) {
div.style.left = x + "px";
div.style.top = y + "px";
div.classList.add("profile");
}
else {
div.classList.add("hypoprofile");
}
{
const pfp = this.buildpfp();
const pfprow = document.createElement("tr");
div.appendChild(pfprow);
pfprow.appendChild(pfp);
}
{
const userbody = document.createElement("tr");
userbody.classList.add("infosection");
div.appendChild(userbody);
const usernamehtml = document.createElement("h2");
usernamehtml.textContent = this.username;
userbody.appendChild(usernamehtml);
const discrimatorhtml = document.createElement("h3");
discrimatorhtml.classList.add("tag");
discrimatorhtml.textContent = this.username + "#" + this.discriminator;
userbody.appendChild(discrimatorhtml);
const pronounshtml = document.createElement("p");
pronounshtml.textContent = this.pronouns;
pronounshtml.classList.add("pronouns");
userbody.appendChild(pronounshtml);
const rule = document.createElement("hr");
userbody.appendChild(rule);
const biohtml = markdown(this.bio);
userbody.appendChild(biohtml);
}
console.log(div);
if (x !== -1) {
Contextmenu.currentmenu = div;
document.body.appendChild(div);
Contextmenu.keepOnScreen(div);
}
return div;
}
profileclick(obj) {
obj.onclick = e => {
this.buildprofile(e.clientX, e.clientY);
e.stopPropagation();
};
}
}
export { User };

BIN
Archive.tar.gz Normal file

Binary file not shown.

View file

@ -4,6 +4,13 @@ const express = require('express');
const fs = require('fs');
const app = express();
const tsNode = require('ts-node');
tsNode.register({
transpileOnly: true,
files: true
});
app.use("/getupdates",(req, res) => {
const out=fs.statSync(`${__dirname}/webpage`);
res.send(out.mtimeMs+"");
@ -16,6 +23,10 @@ app.use('/', (req, res) => {
}
if(fs.existsSync(`${__dirname}/webpage${req.path}`)) {
res.sendFile(`./webpage${req.path}`, {root: __dirname});
}else if(req.path.endsWith(".js") && fs.existsSync(`${__dirname}/.dist${req.path}`)){
const dir=`./.dist${req.path}`;
res.sendFile(dir, {root: __dirname});
return;
}
else if(fs.existsSync(`${__dirname}/webpage${req.path}.html`)) {
res.sendFile(`./webpage${req.path}.html`, {root: __dirname});

985
package-lock.json generated Normal file
View file

@ -0,0 +1,985 @@
{
"name": "jankclient",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "jankclient",
"version": "0.1.0",
"license": "GPL-3.0",
"dependencies": {
"express": "latest"
},
"devDependencies": {
"ts-node": "^10.9.2"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@tsconfig/node10": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "20.14.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.8.tgz",
"integrity": "sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"license": "MIT",
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/acorn": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz",
"integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.3.3",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz",
"integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.11.0"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true,
"license": "MIT"
},
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
},
"node_modules/body-parser": {
"version": "1.20.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.11.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/call-bind": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"license": "MIT",
"dependencies": {
"safe-buffer": "5.2.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT"
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true,
"license": "MIT"
},
"node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"license": "MIT",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"license": "MIT"
},
"node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/es-define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.4"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/express": {
"version": "4.19.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.2",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.6.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.2.0",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.7",
"qs": "6.11.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.18.0",
"serve-static": "1.15.0",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/finalhandler": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"statuses": "2.0.1",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-intrinsic": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3",
"hasown": "^2.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.1.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-proto": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"license": "MIT",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true,
"license": "ISC"
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
"license": "MIT"
},
"node_modules/methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"license": "MIT",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/object-inspect": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
"license": "MIT"
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"license": "MIT",
"dependencies": {
"forwarded": "0.2.0",
"ipaddr.js": "1.9.1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.0.4"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/raw-body": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/send/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/serve-static": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
"license": "MIT",
"dependencies": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.18.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
"node_modules/side-channel": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.4",
"object-inspect": "^1.13.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"license": "MIT",
"engines": {
"node": ">=0.6"
}
},
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"license": "MIT",
"dependencies": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/typescript": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz",
"integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true,
"license": "MIT",
"peer": true
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
"license": "MIT",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true,
"license": "MIT"
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
}
}
}

View file

@ -9,7 +9,10 @@
"keywords": [],
"author": "MathMan05",
"license": "GPL-3.0",
"dependencies":{
"express":"latest"
"dependencies": {
"express": "latest"
},
"devDependencies": {
"ts-node": "^10.9.2"
}
}

16
tsconfig.json Normal file
View file

@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es2022",
"moduleResolution": "Bundler",
"module":"es2022",
"strict": false,
"esModuleInterop": true,
"outDir": "./.dist"
},
"include": [
"./webpage/*.ts"
],
"exclude": [
"node_modules"
]
}

View file

@ -1,6 +1,15 @@
class voice{
constructor(wave,freq,volume=1){
this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
import {getBulkInfo} from "./login.js";
class Voice{
audioCtx:AudioContext;
info:{wave:string|Function,freq:number};
playing:boolean;
myArrayBuffer:AudioBuffer;
gainNode:GainNode;
buffer:Float32Array;
source:AudioBufferSourceNode;
constructor(wave:string|Function,freq:number,volume=1){
this.audioCtx = new (window.AudioContext)();
this.info={wave:wave,freq:freq}
this.playing=false;
this.myArrayBuffer=this.audioCtx.createBuffer(
@ -16,61 +25,61 @@ class voice{
this.source.buffer = this.myArrayBuffer;
this.source.loop=true;
this.source.start();
this.updateWave(freq);
this.updateWave();
}
get wave(){
get wave():string|Function{
return this.info.wave;
}
get freq(){
get freq():number{
return this.info.freq;
}
set wave(wave){
set wave(wave:string|Function){
this.info.wave=wave;
this.updateWave()
this.updateWave();
}
set freq(freq){
set freq(freq:number){
this.info.freq=freq;
this.updateWave()
this.updateWave();
}
updateWave(){
updateWave():void{
const func=this.waveFucnion();
for (let i = 0; i < this.buffer.length; i++) {
this.buffer[i]=func(i/this.audioCtx.sampleRate,this.freq);
}
}
waveFucnion(){
waveFucnion():Function{
if(typeof this.wave === 'function'){
return this.wave;
}
switch(this.wave){
case "sin":
return (t,freq)=>{
return (t:number,freq:number)=>{
return Math.sin(t*Math.PI*2*freq);
}
case "triangle":
return (t,freq)=>{
return (t:number,freq:number)=>{
return Math.abs((4*t*freq)%4-2)-1;
}
case "sawtooth":
return (t,freq)=>{
return (t:number,freq:number)=>{
return ((t*freq)%1)*2-1;
}
case "square":
return (t,freq)=>{
return (t:number,freq:number)=>{
return (t*freq)%2<1?1:-1;
}
case "white":
return (t,freq)=>{
return (_t:number,_freq:number)=>{
return Math.random()*2-1;
}
case "noise":
return (t,freq)=>{
return (_t:number,_freq:number)=>{
return 0;
}
}
}
play(){
play():void{
if(this.playing){
return;
}
@ -78,16 +87,16 @@ class voice{
this.playing=true;
}
stop(){
stop():void{
if(this.playing){
this.source.disconnect();
this.playing=false;
}
}
static noises(noise){
static noises(noise:string):void{
switch(noise){
case "three":{
const voicy=new voice("sin",800);
const voicy=new Voice("sin",800);
voicy.play();
setTimeout(_=>{voicy.freq=1000},50);
setTimeout(_=>{voicy.freq=1300},100);
@ -95,7 +104,7 @@ class voice{
break;
}
case "zip":{
const voicy=new voice((t,freq)=>{
const voicy=new Voice((t:number,freq:number)=>{
return Math.sin(((t+2)**(Math.cos(t*4)))*Math.PI*2*freq);
},700);
voicy.play();
@ -103,7 +112,7 @@ class voice{
break;
}
case "square":{
const voicy=new voice("square",600,.4);
const voicy=new Voice("square",600,.4);
voicy.play()
setTimeout(_=>{voicy.freq=800},50);
setTimeout(_=>{voicy.freq=1000},100);
@ -111,7 +120,7 @@ class voice{
break;
}
case "beep":{
const voicy=new voice("sin",800);
const voicy=new Voice("sin",800);
voicy.play();
setTimeout(_=>{voicy.stop()},50);
setTimeout(_=>{voicy.play();},100);
@ -123,7 +132,7 @@ class voice{
static get sounds(){
return ["three","zip","square","beep"];
}
static setNotificationSound(sound){
static setNotificationSound(sound:string){
let userinfos=getBulkInfo();
userinfos.preferances.notisound=sound;
localStorage.setItem("userinfos",JSON.stringify(userinfos));
@ -133,3 +142,4 @@ class voice{
return userinfos.preferances.notisound;
}
}
export {Voice as Voice};

View file

@ -1,31 +1,71 @@
"use strict"
class channel{
static contextmenu=new contextmenu("channel menu");
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 {Guild} from "./guild.js";
import { Localuser } from "./localuser.js";
import { Permissions } from "./permissions.js";
declare global {
interface NotificationOptions {
image?: string
}
}
class Channel{
editing:Message;
type:number;
owner:Guild;
headers:Localuser["headers"];
messages:Message[];
name:string;
id:string;
parent_id:string;
parrent:Channel;
children:Channel[];
guild_id:string;
messageids:{[key : string]:Message};
permission_overwrites:{[key:string]:Permissions};
topic:string;
nsfw:boolean;
position:number;
lastreadmessageid:string;
lastmessageid:string;
mentions:number;
lastpin:string;
move_id:string;
typing:number;
message_notifications:number;
allthewayup:boolean;
static contextmenu=new Contextmenu("channel menu");
replyingto:Message;
static setupcontextmenu(){
channel.contextmenu.addbutton("Copy channel id",function(){
Channel.contextmenu.addbutton("Copy channel id",function(){
console.log(this)
navigator.clipboard.writeText(this.id);
});
channel.contextmenu.addbutton("Mark as read",function(){
Channel.contextmenu.addbutton("Mark as read",function(){
console.log(this)
this.readbottom();
});
channel.contextmenu.addbutton("Delete channel",function(){
Channel.contextmenu.addbutton("Delete channel",function(){
console.log(this)
this.deleteChannel();
},null,_=>{console.log(_);return _.isAdmin()});
channel.contextmenu.addbutton("Edit channel",function(){
editchannelf(this);
Channel.contextmenu.addbutton("Edit channel",function(){
this.editChannel(this);
},null,_=>{return _.isAdmin()});
}
constructor(JSON,owner){
constructor(JSON,owner:Guild){
if(JSON===-1){
return;
}
this.editing;
this.type=JSON.type;
this.owner=owner;
this.headers=this.owner.headers;
@ -37,7 +77,10 @@ class channel{
this.children=[];
this.guild_id=JSON.guild_id;
this.messageids={};
this.permission_overwrites=JSON.permission_overwrites;
this.permission_overwrites={};
for(const thing of JSON.permission_overwrites){
this.permission_overwrites[thing.id]=new Permissions(thing.allow,thing.deny);
}
this.topic=JSON.topic;
this.nsfw=JSON.nsfw;
this.position=JSON.position;
@ -53,27 +96,43 @@ class channel{
get localuser(){
return this.guild.localuser;
}
get info(){
return this.owner.info;
}
readStateInfo(json){
this.lastreadmessageid=json.last_message_id;
this.mentions=json.mention_count;
this.mentions??=0;
this.lastpin=json.last_pin_timestamp;
}
get hasunreads(){
get hasunreads():boolean{
if(!this.hasPermission("VIEW_CHANNEL")){return false;}
return this.lastmessageid!==this.lastreadmessageid&&this.type!==4;
}
get canMessage(){
for(const thing of this.permission_overwrites){
if(this.guild.hasRole(thing.id)&&thing.deny&(1<<11)){
return false;
hasPermission(name:string,member=this.guild.member):boolean{
if(member.isAdmin()){
return true;
}
for(const thing of member.roles){
if(this.permission_overwrites[thing.id]){
let perm=this.permission_overwrites[thing.id].getPermision(name);
if(perm){
return perm===1;
}
}
if(thing.permissions.getPermision(name)){
return true;
}
}
return true;
return false;
}
get canMessage():boolean{
return this.hasPermission("SEND_MESSAGES");
}
sortchildren(){
this.children.sort((a,b)=>{return a.position-b.position});
}
resolveparent(guild){
resolveparent(guild:Guild){
this.parrent=guild.channelids[this.parent_id];
this.parrent??=null;
if(this.parrent!==null){
@ -85,7 +144,7 @@ class channel{
let position=-1;
let build=[];
for(const thing of this.children){
const thisthing={id:thing.id}
const thisthing={id:thing.id,position:undefined,parent_id:undefined};
if(thing.position<position){
thing.position=thisthing.position=position+1;
}
@ -103,12 +162,23 @@ class channel{
return build;
}
static dragged=[];
createguildHTML(admin=false){
createguildHTML(admin=false):HTMLDivElement{
const div=document.createElement("div");
div.all=this;
if(!this.hasPermission("VIEW_CHANNEL")){
let quit=true
for(const thing of this.children){
if(thing.hasPermission("VIEW_CHANNEL")){
quit=false;
}
}
if(quit){
return div;
}
}
div["all"]=this;
div.draggable=admin;
div.addEventListener("dragstart",(e)=>{channel.dragged=[this,div];e.stopImmediatePropagation()})
div.addEventListener("dragend",()=>{channel.dragged=[]})
div.addEventListener("dragstart",(e)=>{Channel.dragged=[this,div];e.stopImmediatePropagation()})
div.addEventListener("dragend",()=>{Channel.dragged=[]})
if(this.type===4){
this.sortchildren();
const caps=document.createElement("div");
@ -129,17 +199,17 @@ class channel{
addchannel.classList.add("addchannel");
caps.appendChild(addchannel);
addchannel.onclick=function(){
createchannels(this.createChannel.bind(this));
this.guild.createchannels(this.createChannel.bind(this));
}.bind(this);
this.coatDropDiv(decdiv,this,childrendiv);
this.coatDropDiv(decdiv,childrendiv);
}
div.appendChild(caps)
caps.classList.add("capsflex")
decdiv.classList.add("channeleffects");
decdiv.classList.add("channel");
channel.contextmenu.bind(decdiv,this);
decdiv.all=this;
Channel.contextmenu.bind(decdiv,this);
decdiv["all"]=this;
for(const channel of this.children){
@ -164,9 +234,9 @@ class channel{
if(this.hasunreads){
div.classList.add("cunread");
}
channel.contextmenu.bind(div,this);
if(admin){this.coatDropDiv(div,this);}
div.all=this;
Channel.contextmenu.bind(div,this);
if(admin){this.coatDropDiv(div);}
div["all"]=this;
const myhtml=document.createElement("span");
myhtml.textContent=this.name;
if(this.type===0){
@ -188,9 +258,8 @@ class channel{
console.log(this.type)
}
div.appendChild(myhtml);
div.myinfo=this;
div.onclick=function(){
this.myinfo.getHTML();
div.onclick=_=>{
this.getHTML();
}
}
return div;
@ -201,9 +270,9 @@ class channel{
return null
}else if(this.parrent){
for(const thing of search){
if(thing.all===this.parrent){
if(thing["all"]===this.parrent){
for(const thing2 of thing.children[1].children){
if(thing2.all===this){
if(thing2["all"]===this){
return thing2;
}
}
@ -211,7 +280,7 @@ class channel{
}
}else{
for(const thing of search){
if(thing.all===this){
if(thing["all"]===this){
return thing;
}
}
@ -222,7 +291,7 @@ class channel{
if(!this.hasunreads){
return;
}
fetch(info.api.toString()+"/v9/channels/"+this.id+"/messages/"+this.lastmessageid+"/ack",{
fetch(this.info.api.toString()+"/v9/channels/"+this.id+"/messages/"+this.lastmessageid+"/ack",{
method:"POST",
headers:this.headers,
body:JSON.stringify({})
@ -233,7 +302,7 @@ class channel{
this.myhtml.classList.remove("cunread");
}
}
coatDropDiv(div,that,container=false){
coatDropDiv(div:HTMLDivElement,container:HTMLElement|boolean=false){
div.addEventListener("dragenter", (event) => {
console.log("enter")
event.preventDefault();
@ -244,7 +313,7 @@ class channel{
});
div.addEventListener("drop", (event) => {
const that=channel.dragged[0];
const that=Channel.dragged[0];
event.preventDefault();
if(container){
that.move_id=this.id;
@ -252,10 +321,10 @@ class channel{
that.parrent.children.splice(that.parrent.children.indexOf(that),1);
}
that.parrent=this;
container.prepend(channel.dragged[1]);
(container as HTMLElement).prepend(Channel.dragged[1]);
this.children.unshift(that);
}else{
console.log(this,channel.dragged);
console.log(this,Channel.dragged);
that.move_id=this.parent_id;
if(that.parrent){
that.parrent.children.splice(that.parrent.children.indexOf(that),1);
@ -282,15 +351,15 @@ class channel{
}
this.guild.headchannels=build;
}
div.after(channel.dragged[1]);
div.after(Channel.dragged[1]);
}
this.guild.calculateReorder()
});
return div;
}
createChannel(name,type){
fetch(info.api.toString()+"/guilds/"+this.guild.id+"/channels",{
createChannel(name:string,type:number){
fetch(this.info.api.toString()+"/guilds/"+this.guild.id+"/channels",{
method:"Post",
headers:this.headers,
body:JSON.stringify({
@ -307,14 +376,14 @@ class channel{
let nsfw=this.nsfw;
const thisid=this.id;
const thistype=this.type;
const full=new fullscreen(
const full=new Fullscreen(
["hdiv",
["vdiv",
["textbox","Channel name:",this.name,function(){name=this.value}],
["mdbox","Channel topic:",this.topic,function(){topic=this.value}],
["checkbox","NSFW Channel",this.nsfw,function(){nsfw=this.checked}],
["button","","submit",function(){
fetch(info.api.toString()+"/v9/channels/"+thisid,{
fetch(this.info.api.toString()+"/v9/channels/"+thisid,{
method:"PATCH",
headers:this.headers,
body:JSON.stringify({
@ -338,39 +407,89 @@ class channel{
console.log(full)
}
deleteChannel(){
fetch(info.api.toString()+"/v9/channels/"+this.id,{
fetch(this.info.api.toString()+"/v9/channels/"+this.id,{
method:"DELETE",
headers:this.headers
})
}
getHTML(){
setReplying(message:Message){
if(this.replyingto){
this.replyingto.div.classList.remove("replying");
}
this.replyingto=message;
console.log(message);
this.replyingto.div.classList.add("replying");
this.makereplybox();
}
makereplybox(){
const replybox=document.getElementById("replybox");
if(this.replyingto){
replybox.innerHTML="";
const span=document.createElement("span");
span.textContent="Replying to "+this.replyingto.author.username;
const X=document.createElement("button");
X.onclick=_=>{
this.replyingto.div.classList.remove("replying");
replybox.classList.add("hideReplyBox");
this.replyingto=null;
replybox.innerHTML="";
}
replybox.classList.remove("hideReplyBox");
X.textContent="⦻";
X.classList.add("cancelReply");
replybox.append(span);
replybox.append(X);
}else{
replybox.classList.add("hideReplyBox");
}
}
async getmessage(id:string):Promise<Message>{
if(this.messageids[id]){
return this.messageids[id];
}else{
const gety=await fetch(this.info.api.toString()+"/v9/channels/"+this.id+"/messages?limit=1&around="+id,{headers:this.headers})
const json=await gety.json();
return new Message(json[0],this);
}
}
async getHTML(){
if(this.guild!==this.localuser.lookingguild){
this.guild.loadGuild();
}
if(this.localuser.channelfocus&&this.localuser.channelfocus.myhtml){
this.localuser.channelfocus.myhtml.classList.remove("viewChannel");
}
this.myhtml.classList.add("viewChannel")
this.guild.prevchannel=this;
this.localuser.channelfocus=this;
this.putmessages();
const prom=Message.wipeChanel();
await this.putmessages();
await prom;
this.makereplybox();
this.buildmessages();
history.pushState(null, null,"/channels/"+this.guild_id+"/"+this.id);
document.getElementById("channelname").textContent="#"+this.name;
console.log(this);
(document.getElementById("typebox") as HTMLInputElement).disabled=!this.canMessage;
}
putmessages(){
const out=this;
fetch(info.api.toString()+"/channels/"+this.id+"/messages?limit=100",{
async putmessages(){
if(this.messages.length>=100||this.allthewayup){return};
const j=await fetch(this.info.api.toString()+"/channels/"+this.id+"/messages?limit=100",{
method: 'GET',
headers: this.headers,
}).then((j)=>{return j.json()}).then(responce=>{
messages.innerHTML = '';
//responce.reverse()
messagelist=[];
for(const thing of responce){
const messager=new cmessage(thing,this)
if(out.messageids[messager.id]==undefined){
out.messageids[messager.id]=messager;
out.messages.push(messager);
}
}
out.buildmessages();
})
const responce=await j.json();
if(responce.length!==100){
this.allthewayup=true;
}
for(const thing of responce){
const messager=new Message(thing,this)
if(this.messageids[messager.id]===undefined){
this.messageids[messager.id]=messager;
this.messages.push(messager);
}
}
}
delChannel(JSON){
const build=[];
@ -387,25 +506,25 @@ class channel{
}
const out=this;
await fetch(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="+this.messages[this.messages.length-1].id+"&limit=100",{
method:"GET",
headers:this.headers
}).then((j)=>{return j.json()}).then(responce=>{
//messages.innerHTML = '';
//responce.reverse()
let next
let next:Message;
if(responce.length===0){
out.allthewayup=true;
}
for(const i in responce){
let messager
let messager:Message;
if(!next){
messager=new cmessage(responce[i],this)
messager=new Message(responce[i],this)
}else{
messager=next;
}
if(responce[+i+1]!==undefined){
next=new cmessage(responce[+i+1],this);
next=new Message(responce[+i+1],this);
}else{
next=undefined;
console.log("ohno",+i+1)
@ -422,15 +541,15 @@ class channel{
})
return;
}
buildmessage(message,next){
buildmessage(message:Message,next:Message){
const built=message.buildhtml(next);
messages.prepend(built);
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);
messages.prepend(built);
document.getElementById("messages").prepend(built);
}
document.getElementById("messagecontainer").scrollTop = document.getElementById("messagecontainer").scrollHeight;
@ -452,7 +571,7 @@ class channel{
return;
}
this.typing=new Date().getTime()+6000;
fetch(info.api.toString()+"/channels/"+this.id+"/typing",{
fetch(this.info.api.toString()+"/channels/"+this.id+"/typing",{
method:"POST",
headers:this.headers
})
@ -472,8 +591,8 @@ class channel{
return "default";
}
}
async sendMessage(content,{attachments=[],embeds=[],replyingto=false}){
let replyjson=false;
async sendMessage(content:string,{attachments=[],embeds=[],replyingto=null}){
let replyjson:any;
if(replyingto){
replyjson=
{
@ -481,17 +600,18 @@ class channel{
"channel_id": replyingto.channel.id,
"message_id": replyingto.id,
};
}
};
if(attachments.length===0){
const body={
content:content,
nonce:Math.floor(Math.random()*1000000000)
nonce:Math.floor(Math.random()*1000000000),
message_reference:undefined
};
if(replyjson){
body.message_reference=replyjson;
}
console.log(body)
return await fetch(info.api.toString()+"/channels/"+this.id+"/messages",{
return await fetch(this.info.api.toString()+"/channels/"+this.id+"/messages",{
method:"POST",
headers:this.headers,
body:JSON.stringify(body)
@ -501,6 +621,7 @@ class channel{
const body={
content:content,
nonce:Math.floor(Math.random()*1000000000),
message_reference:undefined
}
if(replyjson){
body.message_reference=replyjson;
@ -510,15 +631,16 @@ class channel{
console.log(attachments[i])
formData.append("files["+i+"]",attachments[i]);
}
return await fetch(info.api.toString()+"/channels/"+this.id+"/messages", {
return await fetch(this.info.api.toString()+"/channels/"+this.id+"/messages", {
method: 'POST',
body: formData,
headers:{"Authorization":this.headers.Authorization}
});
}
}
messageCreate(messagep,focus){
const messagez=new cmessage(messagep.d,this);
messageCreate(messagep:any):void{
if(!this.hasPermission("VIEW_CHANNEL")){return}
const messagez=new Message(messagep.d,this);
this.lastmessageid=messagez.id;
if(messagez.author===this.localuser.user){
this.lastreadmessageid=messagez.id;
@ -536,7 +658,7 @@ class channel{
this.messageids[messagez.id]=messagez;
if(this.localuser.lookingguild.prevchannel===this){
var shouldScroll=scrolly.scrollTop+scrolly.clientHeight>scrolly.scrollHeight-20;
messages.appendChild(messagez.buildhtml(this.messages[1]));
document.getElementById("messages").appendChild(messagez.buildhtml(this.messages[1]));
}
if(shouldScroll){
scrolly.scrollTop = scrolly.scrollHeight;
@ -553,11 +675,11 @@ class channel{
this.notify(messagez);
}
}
notititle(message){
notititle(message:Message):string{
return message.author.username+" > "+this.guild.properties.name+" > "+this.name;
}
notify(message,deep=0){
voice.noises(voice.getNotificationSound());
notify(message:Message,deep=0){
Voice.noises(Voice.getNotificationSound());
if (!("Notification" in window)) {
} else if (Notification.permission === "granted") {
@ -584,11 +706,12 @@ class channel{
this.getHTML();
})
} else if (Notification.permission !== "denied") {
Notification.requestPermission().then((permission) => {
Notification.requestPermission().then(() => {
if(deep===3){return};
this.notify(message,deep+1);
});
}
}
}
channel.setupcontextmenu();
Channel.setupcontextmenu();
export {Channel};

View file

@ -1,44 +0,0 @@
class contextmenu{
constructor(name){
this.name=name;
this.buttons=[]
}
addbutton(text,onclick,img=null,shown=_=>true,enabled=_=>true){
this.buttons.push([text,onclick,img,shown,enabled])
return {};
}
makemenu(x,y,addinfo,obj){
const div=document.createElement("table");
div.classList.add("contextmenu");
for(const thing of this.buttons){
if(!thing[3](addinfo)){continue;}
const textb=document.createElement("tr");
const intext=document.createElement("button")
intext.disabled=!thing[4]();
textb.button=intext;
intext.classList.add("contextbutton")
intext.textContent=thing[0]
textb.appendChild(intext)
console.log(thing)
intext.onclick=thing[1].bind(addinfo,obj);
div.appendChild(textb);
}
if(currentmenu!=""){
currentmenu.remove();
}
div.style.top = y+'px';
div.style.left = x+'px';
document.body.appendChild(div);
console.log(div)
currentmenu=div;
return this.div;
}
bind(obj,addinfo){
obj.addEventListener("contextmenu", (event) => {
event.preventDefault();
event.stopImmediatePropagation();
this.makemenu(event.clientX,event.clientY,addinfo,obj)
});
}
}

78
webpage/contextmenu.ts Normal file
View file

@ -0,0 +1,78 @@
class Contextmenu{
static currentmenu;
name:string;
buttons:[string,Function,string,Function,Function][];
div:HTMLDivElement;
static setup(){
Contextmenu.currentmenu="";
document.addEventListener('click', function(event) {
if(Contextmenu.currentmenu==""){
return;
}
if (!Contextmenu.currentmenu.contains(event.target)) {
Contextmenu.currentmenu.remove();
Contextmenu.currentmenu="";
}
});
}
constructor(name:string){
this.name=name;
this.buttons=[]
}
addbutton(text:string,onclick:Function,img=null,shown=_=>true,enabled=_=>true){
this.buttons.push([text,onclick,img,shown,enabled])
return {};
}
makemenu(x:number,y:number,addinfo:any,obj:HTMLElement){
const div=document.createElement("table");
div.classList.add("contextmenu");
for(const thing of this.buttons){
if(!thing[3](addinfo)){continue;}
const textb=document.createElement("tr");
const intext=document.createElement("button")
intext.disabled=!thing[4]();
textb["button"]=intext;
intext.classList.add("contextbutton")
intext.textContent=thing[0]
textb.appendChild(intext)
console.log(thing)
intext.onclick=thing[1].bind(addinfo,obj);
div.appendChild(textb);
}
if(Contextmenu.currentmenu!=""){
Contextmenu.currentmenu.remove();
}
div.style.top = y+'px';
div.style.left = x+'px';
document.body.appendChild(div);
Contextmenu.keepOnScreen(div);
console.log(div)
Contextmenu.currentmenu=div;
return this.div;
}
bind(obj:HTMLElement,addinfo:any=undefined){
const func=(event) => {
event.preventDefault();
event.stopImmediatePropagation();
this.makemenu(event.clientX,event.clientY,addinfo,obj)
}
obj.addEventListener("contextmenu", func);
return func;
}
static keepOnScreen(obj:HTMLElement){
const html = document.documentElement.getBoundingClientRect();
const docheight=html.height
const docwidth=html.width
const box=obj.getBoundingClientRect();
console.log(box,docheight,docwidth);
if(box.right>docwidth){
console.log("test")
obj.style.left = docwidth-box.width+'px';
}
if(box.bottom>docheight){
obj.style.top = docheight-box.height+'px';
}
}
}
Contextmenu.setup();
export {Contextmenu as Contextmenu}

View file

@ -1,6 +1,13 @@
class direct extends guild{
constructor(JSON,owner){
super(-1);
import {Guild} from "./guild.js";
import { Channel } from "./channel.js";
import { Message } from "./message.js";
import { Localuser } from "./localuser.js";
import {User} from "./user.js";
import { Member } from "./member.js";
class Direct extends Guild{
constructor(JSON,owner:Localuser){
super(-1,owner,null);
this.message_notifications=0;
console.log(JSON);
this.owner=owner;
@ -17,14 +24,14 @@ class direct extends guild{
this.prevchannel=undefined;
this.properties.name="Dirrect Messages";
for(const thing of JSON){
const temp=new group(thing,this);
const temp=new Group(thing,this);
this.channels.push(temp);
this.channelids[temp.id]=temp;
}
this.headchannels=this.channels;
}
createChannelpac(JSON){
const thischannel=new group(JSON,this);
const thischannel=new Group(JSON,this);
this.channelids[JSON.id]=thischannel;
this.channels.push(thischannel);
this.calculateReorder();
@ -50,19 +57,20 @@ class direct extends guild{
}
unreaddms(){
for(const thing of this.channels){
thing.unreads();
(thing as Group).unreads();
}
}
}
class group extends channel{
constructor(JSON,owner){
super(-1);
class Group extends Channel{
user:User;
constructor(JSON,owner:Direct){
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.user=new User(JSON.recipients[0],this.localuser);
}else{
this.user=this.localuser.user;
}
@ -73,9 +81,9 @@ class group extends channel{
this.children=[];
this.guild_id="@me";
this.messageids={};
this.permission_overwrites=[];
this.permission_overwrites={};
this.lastmessageid=JSON.last_message_id;
this.lastmessageid??=0;
this.lastmessageid??="0";
this.mentions=0;
}
createguildHTML(){
@ -85,21 +93,27 @@ class group extends channel{
myhtml.textContent=this.name;
div.appendChild(this.user.buildpfp());
div.appendChild(myhtml);
div.myinfo=this;
div.onclick=function(){
this.myinfo.getHTML();
div["myinfo"]=this;
div.onclick=_=>{
this.getHTML();
}
return div;
}
getHTML(){
async getHTML(){
if(this.guild!==this.localuser.lookingguild){
this.guild.loadGuild();
}
const prom=Message.wipeChanel();
this.guild.prevchannel=this;
this.localuser.channelfocus=this;
this.putmessages();
await this.putmessages();
await prom;
this.buildmessages();
history.pushState(null, null,"/channels/"+this.guild_id+"/"+this.id);
document.getElementById("channelname").textContent="@"+this.name;
}
messageCreate(messagep,focus){
const messagez=new cmessage(messagep.d,this);
messageCreate(messagep){
const messagez=new Message(messagep.d,this);
this.lastmessageid=messagez.id;
if(messagez.author===this.localuser.user){
this.lastreadmessageid=messagez.id;
@ -109,7 +123,7 @@ class group extends channel{
this.messageids[messagez.id]=messagez;
if(this.localuser.lookingguild.prevchannel===this){
var shouldScroll=scrolly.scrollTop+scrolly.clientHeight>scrolly.scrollHeight-20;
messages.appendChild(messagez.buildhtml(this.messages[1]));
document.getElementById("messages").appendChild(messagez.buildhtml(this.messages[1]));
}
if(shouldScroll){
scrolly.scrollTop = scrolly.scrollHeight;
@ -118,12 +132,10 @@ class group extends channel{
if(this.localuser.lookingguild===this.guild){
const channellist=document.getElementById("channels").children[0]
for(const thing of channellist.children){
if(thing.myinfo===this){
if(thing["myinfo"]===this){
channellist.prepend(thing);
console.log(thing.myinfo);
break;
}
console.log(thing.myinfo,this,thing.myinfo===this);
}
}
this.unreads();
@ -147,8 +159,7 @@ class group extends channel{
const sentdms=document.getElementById("sentdms");
let current=null;
for(const thing of sentdms.children){
console.log(thing.all)
if(thing.all===this){
if(thing["all"]===this){
current=thing;
}
}
@ -158,19 +169,19 @@ class group extends channel{
div.classList.add("servernoti");
const noti=document.createElement("div");
noti.classList.add("unread","notiunread","pinged");
noti.textContent=this.mentions;
noti.textContent=""+this.mentions;
console.log(this.mentions)
div.noti=noti;
div["noti"]=noti;
div.append(noti)
const buildpfp=this.user.buildpfp();
div.all=this;
div["all"]=this;
buildpfp.classList.add("mentioned");
console.log(this);
div.append(buildpfp)
sentdms.append(div);
div.onclick=function(){
this.all.guild.loadGuild();
this.all.getHTML();
this["noti"].guild.loadGuild();
this["noti"].getHTML();
}
}else if(current){
@ -179,4 +190,11 @@ class group extends channel{
}
}
isAdmin(): boolean {
return false;
}
hasPermission(name: string, member?: Member): boolean {
return true;
}
}
export {Direct, Group};

View file

@ -1,6 +1,10 @@
class embed{
constructor(json, owner){
import {Fullscreen} from "./fullscreen.js";
import {Message} from "./message.js";
class Embed{
type:string;
owner:Message;
json;
constructor(json, owner:Message){
this.type=this.getType(json);
this.owner=owner;
this.json=json;
@ -116,7 +120,7 @@ class embed{
const img=document.createElement("img");
img.classList.add("messageimg")
img.onclick=function(){
const full=new fullscreen(["img",img.src,["fit"]]);
const full=new Fullscreen(["img",img.src,["fit"]]);
full.show();
}
img.src=this.json.thumbnail.proxy_url;
@ -141,7 +145,7 @@ class embed{
if(this.json.thumbnail){
img.classList.add("embedimg");
img.onclick=function(){
const full=new fullscreen(["img",img.src,["fit"]]);
const full=new Fullscreen(["img",img.src,["fit"]]);
full.show();
}
img.src=this.json.thumbnail.proxy_url;
@ -180,17 +184,18 @@ class embed{
description.textContent=this.json.description;
div.append(description);
{
if(this.json.thumbnail){
const img=document.createElement("img");
img.classList.add("bigembedimg");
img.onclick=function(){
const full=new fullscreen(["img",img.src,["fit"]]);
const full=new Fullscreen(["img",img.src,["fit"]]);
full.show();
}
img.src=this.json.thumbnail.proxy_url;
img.src=this.json.thumbnail.proxy_url||this.json.thumbnail.url;
div.append(img);
}
colordiv.append(div);
return colordiv;
}
}
export {Embed};

BIN
webpage/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

126
webpage/file.ts Normal file
View file

@ -0,0 +1,126 @@
import { Message } from "./message.js";
import { Fullscreen } from "./fullscreen.js";
type filejson= {id:string,filename:string,content_type:string,width:number,height:number,proxy_url:string|undefined,url:string,size:number};
class File{
owner:Message;
id:string;
filename:string;
content_type:string;
width:number;
height:number;
proxy_url:string;
url:string;
size:number;
constructor(fileJSON:filejson,owner:Message){
console.log(fileJSON);
this.owner=owner;
this.id=fileJSON.id;
this.filename=fileJSON.filename;
this.content_type=fileJSON.content_type;
this.width=fileJSON.width;
this.height=fileJSON.height;
this.url=fileJSON.url;
this.proxy_url=fileJSON.proxy_url;
this.content_type=fileJSON.content_type;
this.size=fileJSON.size;
}
getHTML(temp:boolean=false):HTMLElement{
const src=this.proxy_url||this.url;
if(this.content_type.startsWith('image/')){
const img=document.createElement("img");
img.classList.add("messageimg");
img.onclick=function(){
const full=new Fullscreen(["img",img.src,["fit"]]);
full.show();
}
img.src=src;
img.height=this.height;
img.width=this.width;
return img;
}else if(this.content_type.startsWith('video/')){
const video=document.createElement("video");
const source=document.createElement("source");
source.src=src;
video.append(source);
source.type=this.content_type;
video.controls=!temp;
return video;
}else if(this.content_type.startsWith('audio/')){
const audio=document.createElement("audio");
const source=document.createElement("source");
source.src=src;
audio.append(source);
source.type=this.content_type;
audio.controls=!temp;
return audio;
}else{
return this.createunknown();
}
}
upHTML(files:Blob[],file:globalThis.File):HTMLElement{
const div=document.createElement("div");
const contained=this.getHTML(true);
div.classList.add("containedFile");
div.append(contained);
const controls=document.createElement("div");
const garbage=document.createElement("button");
garbage.textContent="🗑";
garbage.onclick=_=>{
div.remove();
files.splice(files.indexOf(file),1);
}
controls.classList.add("controls");
div.append(controls);
controls.append(garbage);
return div;
}
static initFromBlob(file:globalThis.File){
return new File({
filename:file.name,
size:file.size,
id:null,
content_type:file.type,
width:undefined,
height:undefined,
url:URL.createObjectURL(file),
proxy_url:undefined
},null)
}
createunknown():HTMLElement{
console.log("🗎")
const src=this.proxy_url||this.url;
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");
if(src){
const a=document.createElement("a");
a.href=src;
a.textContent=this.filename;
nametd.append(a);
}else{
nametd.textContent=this.filename;
}
nametd.classList.add("filename");
nametr.append(nametd);
const sizetr=document.createElement("tr");
const size=document.createElement("td");
sizetr.append(size);
size.textContent="Size:"+File.filesizehuman(this.size);
size.classList.add("filesize");
div.appendChild(sizetr);
return div;
}
static filesizehuman(fsize:number){
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];
}
}
export{File}

View file

@ -1,4 +1,10 @@
class fullscreen{
export {Fullscreen};
class Fullscreen{
layout;
onclose: Function;
onopen: Function;
html:HTMLDivElement;
background: HTMLDivElement;
constructor(layout,onclose=_=>{},onopen=_=>{}){
this.layout=layout;
this.onclose=onclose;
@ -134,8 +140,9 @@ class fullscreen{
if(i===0){
continue;
}
if(thing.children[0].children[0].checked){
array[3](thing.children[0].children[0].value);
const checkbox = thing.children[0].children[0] as HTMLInputElement;
if(checkbox.checked){
array[3](checkbox.value);
}
}
});

View file

@ -1,30 +1,52 @@
class guild{
static contextmenu=new contextmenu("guild menu");
import { Channel } from "./channel.js";
import { Localuser } from "./localuser.js";
import {Contextmenu} from "./contextmenu.js";
import {Role} from "./role.js";
import {Fullscreen} from "./fullscreen.js";
import {Member} from "./member.js";
class Guild{
owner:Localuser;
headers:Localuser["headers"];
channels:Channel[];
channelids:{[key:string]:Channel};
id:string;
properties
roles:Role[];
roleids:{[key:string]:Role};
prevchannel:Channel;
message_notifications:number;
headchannels:Channel[];
position:number;
parent_id:string;
member:Member;
html:HTMLElement;
static contextmenu=new Contextmenu("guild menu");
static setupcontextmenu(){
guild.contextmenu.addbutton("Copy Guild id",function(){
Guild.contextmenu.addbutton("Copy Guild id",function(){
console.log(this)
navigator.clipboard.writeText(this.id);
});
guild.contextmenu.addbutton("Mark as read",function(){
Guild.contextmenu.addbutton("Mark as read",function(){
console.log(this)
this.markAsRead();
});
guild.contextmenu.addbutton("Notifications",function(){
Guild.contextmenu.addbutton("Notifications",function(){
console.log(this)
this.setnotifcation();
});
guild.contextmenu.addbutton("Leave guild",function(){
Guild.contextmenu.addbutton("Leave guild",function(){
this.confirmleave();
},null,function(_){return _.properties.owner_id!==_.member.user.id});
guild.contextmenu.addbutton("Delete guild",function(){
Guild.contextmenu.addbutton("Delete guild",function(){
this.confirmDelete();
},null,function(_){return _.properties.owner_id===_.member.user.id});
guild.contextmenu.addbutton("Create invite",function(){
Guild.contextmenu.addbutton("Create invite",function(){
console.log(this);
},null,_=>true,_=>false);
/* -----things left for later-----
@ -38,16 +60,13 @@ class guild{
},null,_=>{return thisuser.isAdmin()})
*/
}
constructor(JSON,owner){
constructor(JSON,owner:Localuser,member){
if(JSON===-1){
return;
}
this.owner=owner;
this.headers=this.owner.headers;
if(!this.owner){
console.error("localuser was not included, please fix")
}
this.channels=[];
this.channelids={};
this.id=JSON.id;
@ -57,12 +76,13 @@ class guild{
this.prevchannel=undefined;
this.message_notifications=0;
for(const roley of JSON.roles){
const roleh=new role(roley);
const roleh=new Role(roley,this);
this.roles.push(roleh)
this.roleids[roleh.id]=roleh;
}
Member.resolve(member,this).then(_=>this.member=_);
for(const thing of JSON.channels){
const temp=new channel(thing,this);
const temp=new Channel(thing,this);
this.channels.push(temp);
this.channelids[temp.id]=temp;
}
@ -78,7 +98,7 @@ class guild{
}
setnotifcation(){
let noti=this.message_notifications
const notiselect=new fullscreen(
const notiselect=new Fullscreen(
["vdiv",
["radio","select notifications type",
["all","only mentions","none"],
@ -88,7 +108,7 @@ class guild{
noti
],
["button","","submit",_=>{
fetch(info.api.toString()+"/v9/users/@me/guilds/settings",{
fetch(this.info.api.toString()+"/v9/users/@me/guilds/settings",{
method:"PATCH",
headers:this.headers,
body:JSON.stringify({
@ -105,7 +125,7 @@ class guild{
notiselect.show();
}
confirmleave(){
const full= new fullscreen([
const full= new Fullscreen([
"vdiv",
["title",
"Are you sure you want to leave?"
@ -133,7 +153,7 @@ class guild{
full.show();
}
async leave(){
return fetch(info.api.toString()+"/users/@me/guilds/"+this.id,{
return fetch(this.info.api.toString()+"/users/@me/guilds/"+this.id,{
method:"DELETE",
headers:this.headers
})
@ -152,7 +172,7 @@ class guild{
let position=-1;
let build=[];
for(const thing of this.headchannels){
const thisthing={id:thing.id}
const thisthing={id:thing.id,position:undefined,parent_id:undefined}
if(thing.position<=position){
thing.position=(thisthing.position=position+1);
}
@ -181,14 +201,14 @@ class guild{
if(serverbug){
for(const thing of build){
console.log(build,thing)
fetch(info.api.toString()+"/v9/guilds/"+this.id+"/channels",{
fetch(this.info.api.toString()+"/v9/guilds/"+this.id+"/channels",{
method:"PATCH",
headers:this.headers,
body:JSON.stringify([thing])
});
}
}else{
fetch(info.api.toString()+"/v9/guilds/"+this.id+"/channels",{
fetch(this.info.api.toString()+"/v9/guilds/"+this.id+"/channels",{
method:"PATCH",
headers:this.headers,
body:JSON.stringify(build)
@ -199,9 +219,8 @@ class guild{
get localuser(){
return this.owner;
}
loadChannel(id){
this.localuser.channelfocus=this.channelids[id];
this.channelids[id].getHTML();
get info(){
return this.owner.info;
}
sortchannels(){
this.headchannels.sort((a,b)=>{return a.position-b.position;});
@ -217,14 +236,14 @@ class guild{
if(this.properties.icon!=null){
const img=document.createElement("img");
img.classList.add("pfp","servericon");
img.src=info.cdn.toString()+"icons/"+this.properties.id+"/"+this.properties.icon+".png";
img.src=this.info.cdn.toString()+"icons/"+this.properties.id+"/"+this.properties.icon+".png";
divy.appendChild(img)
img.onclick=()=>{
console.log(this.loadGuild)
this.loadGuild();
this.loadChannel();
}
guild.contextmenu.bind(img,this);
Guild.contextmenu.bind(img,this);
}else{
const div=document.createElement("div");
let build="";
@ -238,13 +257,13 @@ class guild{
this.loadGuild();
this.loadChannel();
}
guild.contextmenu.bind(div,this)
Guild.contextmenu.bind(div,this)
}
return divy;
}
confirmDelete(){
let confirmname="";
const full= new fullscreen([
const full= new Fullscreen([
"vdiv",
["title",
"Are you sure you want to delete "+this.properties.name+"?"
@ -284,12 +303,12 @@ class guild{
full.show();
}
async delete(){
return fetch(info.api.toString()+"/guilds/"+this.id+"/delete",{
return fetch(this.info.api.toString()+"/guilds/"+this.id+"/delete",{
method:"POST",
headers:this.headers,
})
}
unreads(html){
unreads(html=undefined){
if(html){
this.html=html;
}else{
@ -333,34 +352,24 @@ class guild{
}
}
this.unreads();
fetch(info.api.toString()+"/v9/read-states/ack-bulk",{
fetch(this.info.api.toString()+"/v9/read-states/ack-bulk",{
method:"POST",
headers:this.headers,
body:JSON.stringify(build)
})
}
fillMember(member){
const realroles=[];
for(const thing of member.roles){
realroles.push(this.getRole(thing));
}
member.roles=realroles;
return member;
}
giveMember(member){
this.fillMember(member);
this.member=member;
}
getRole(ID){
getRole(ID:string):Role{
if(!this.roleids[ID]){console.error(`role id ${ID} does not exist`,this.roleids)}
return this.roleids[ID];
}
hasRole(r){
hasRole(r:Role|string){
console.log("this should run");
if((typeof r)!==(typeof "")){
r=r.id;
r=(r as Role).id;
}
return this.member.hasRole(r);
return this.member.hasRole(r as string);
}
loadChannel(ID){
loadChannel(ID:string=undefined){
if(ID&&this.channelids[ID]){
this.channelids[ID].getHTML();
return;
@ -394,7 +403,7 @@ class guild{
this.printServers();
}
createChannelpac(JSON){
const thischannel=new channel(JSON,this);
const thischannel=new Channel(JSON,this);
this.channelids[JSON.id]=thischannel;
this.channels.push(thischannel);
thischannel.resolveparent(this);
@ -404,26 +413,82 @@ class guild{
this.calculateReorder();
this.printServers();
}
createchannels(func=this.createChannel){
let name="";
let category=0;
const channelselect=new Fullscreen(
["vdiv",
["radio","select channel type",
["voice","text","announcement"],
function(e){
console.log(e)
category={"text":0,"voice":2,"announcement":5,"category":4}[e]
},
1
],
["textbox","Name of channel","",function(){
console.log(this)
name=this.value
}],
["button","","submit",function(){
console.log(name,category)
func(name,category);
channelselect.hide();
}.bind(this)]
]);
channelselect.show();
}
createcategory(){
let name="";
let category=4;
const channelselect=new Fullscreen(
["vdiv",
["textbox","Name of category","",function(){
console.log(this);
name=this.value;
}],
["button","","submit",function(){
console.log(name,category)
this.createChannel(name,category);
channelselect.hide();
}]
]);
channelselect.show();
}
delChannel(JSON){
const channel=this.channelids[JSON.id];
delete this.channelids[JSON.id];
this.channels.splice(this.channels.indexOf(channel),1);
const indexy=this.headchannels.indexOf(channel);
if(indexy!==-1){
this.headchannels.splice(indexy,1);
}
/*
const build=[];
for(const thing of this.channels){
if(thing.id!==JSON.id){
console.log(thing.id);
if(thing!==channel){
build.push(thing)
}else{
console.log("fail");
if(thing.parrent){
thing.parrent.delChannel(JSON);
}
}
}
this.channels=build;
*/
this.printServers();
}
createChannel(name,type){
fetch(info.api.toString()+"/guilds/"+this.id+"/channels",{
createChannel(name:string,type:number){
fetch(this.info.api.toString()+"/guilds/"+this.id+"/channels",{
method:"Post",
headers:this.headers,
body:JSON.stringify({name: name, type: type})
})
}
}
guild.setupcontextmenu();
Guild.setupcontextmenu();
export { Guild };

View file

@ -10,21 +10,7 @@
</head>
<body class="Dark-theme">
<script src="/login.js"></script>
<script src="/contextmenu.js"></script>
<script src="/member.js"></script>
<script src="/user.js"></script>
<script src="/embed.js"></script>
<script src="/message.js"></script>
<script src="/channel.js"></script>
<script src="/permissions.js"></script>
<script src="/role.js"></script>
<script src="/guild.js"></script>
<script src="/direct.js"></script>
<script src="/localuser.js"></script>
<script src="/markdown.js"></script>
<script src="/fullscreen.js"></script>
<script src="/audio.js"></script>
<script src="/index.js" type="module"></script>
<div id="loading" class="loading"><div id="centerdiv"><img src="/bitmap.svg" width="1in" height="1in"><h1>Jank Client is loading</h1><h2>This shouldn't take long</h2></div></div>
<table id="page" cellspacing="0" cellpadding="0">
@ -58,7 +44,7 @@
</td>
</tr></table></td>
<td>
<h2 id="settings" onclick="userSettings()"></h2>
<h2 id="settings"></h2>
</td>
</tr>
</table>
@ -71,6 +57,7 @@
</div>
<div id="pasteimage"></div>
<div id="typediv">
<div id="replybox" class="hideReplyBox"></div>
<textarea id="typebox"></textarea>
<div id="typing" class="hidden">
<p id="typingtext">typing</p>
@ -86,6 +73,5 @@
</td>
</tr>
</table>
<script src="/index.js"></script>
</body>
</html>

View file

@ -1,12 +1,25 @@
import { Localuser } from "./localuser.js";
import {Contextmenu} from "./contextmenu.js";
import {mobile, getBulkUsers,setTheme, Specialuser} from "./login.js";
async function waitforload(){
let res
new Promise(r=>{res=r});
document.addEventListener("DOMContentLoaded", function(){
res();
});
await res;
}
await waitforload();
function setDynamicHeight() {
var servertdHeight = document.getElementById('servertd').offsetHeight+document.getElementById('typebox').offsetHeight+document.getElementById('pasteimage').offsetHeight;
var servertdHeight = document.getElementById('servertd').offsetHeight+document.getElementById('typediv').offsetHeight+document.getElementById('pasteimage').offsetHeight;
document.documentElement.style.setProperty('--servertd-height', servertdHeight + 'px');
}
const resizeObserver = new ResizeObserver(() => {
setDynamicHeight();
});
resizeObserver.observe(document.getElementById('servertd'));
resizeObserver.observe(document.getElementById('typebox'));
resizeObserver.observe(document.getElementById('replybox'));
resizeObserver.observe(document.getElementById('pasteimage'));
setDynamicHeight();
@ -18,7 +31,7 @@ var info=users.users[users.currentuser].serverurls;
let token=users.users[users.currentuser].token;
let READY;
let thisuser=new localuser(users.users[users.currentuser]);
let thisuser=new Localuser(users.users[users.currentuser]);
thisuser.initwebsocket().then(_=>{
thisuser.loaduser();
thisuser.init();
@ -32,7 +45,8 @@ thisuser.initwebsocket().then(_=>{
userinfo.addEventListener("click",function(event){
const table=document.createElement("table");
for(const thing of Object.values(users.users)){
console.log(thing.pfpsrc)
const specialuser=thing as Specialuser;
console.log(specialuser.pfpsrc)
const tr=document.createElement("tr");
const td=document.createElement("td");
@ -49,14 +63,14 @@ thisuser.initwebsocket().then(_=>{
row.append(usertd);
const user=document.createElement("div");
usertd.append(user);
user.append(thing.username);
user.append(specialuser.username);
user.append(document.createElement("br"));
const span=document.createElement("span");
span.textContent=thing.serverurls.wellknown.hostname;
span.textContent=specialuser.serverurls.wellknown.hostname;
user.append(span);
span.classList.add("serverURL")
pfp.src=thing.pfpsrc;
pfp.src=specialuser.pfpsrc;
pfp.classList.add("pfp");
td.append(userinfo)
@ -66,9 +80,8 @@ thisuser.initwebsocket().then(_=>{
thisuser.unload();
document.getElementById("loading").classList.remove("doneloading");
document.getElementById("loading").classList.add("loading");
thisuser=new localuser(thing);
window.info =thing.serverurls;
users.currentuser=thing.uid;
thisuser=new Localuser(specialuser);
users["currentuser"]=specialuser.uid;
localStorage.setItem("userinfos",JSON.stringify(users));
thisuser.initwebsocket().then(_=>{
thisuser.loaduser();
@ -91,181 +104,55 @@ thisuser.initwebsocket().then(_=>{
table.append(tr);
}
table.classList.add("accountSwitcher");
if(currentmenu!=""){
currentmenu.remove();
if(Contextmenu.currentmenu!=""){
Contextmenu.currentmenu.remove();
}
currentmenu=table;
Contextmenu.currentmenu=table;
console.log(table);
userdock.append(table);
event.stopImmediatePropagation();
})
}
var currentmenu="";
document.addEventListener('click', function(event) {
if(currentmenu==""){
return;
}
if (!currentmenu.contains(event.target)) {
currentmenu.remove();
currentmenu="";
}
});
let replyingto=null;
{
const menu=new contextmenu("create rightclick");
const menu=new Contextmenu("create rightclick");
menu.addbutton("Create channel",function(){
createchannels(thisuser.lookingguild.createChannel.bind(thisuser.lookingguild));
thisuser.lookingguild.createchannels();
},null,_=>{return thisuser.isAdmin()})
menu.addbutton("Create category",function(){
createcategory(thisuser.lookingguild.createChannel.bind(thisuser.lookingguild));
thisuser.lookingguild.createcategory();
},null,_=>{return thisuser.isAdmin()})
menu.bind(document.getElementById("channels"))
}
function createchannels(fincall){
let name="";
let category=0;
console.log(fincall);
channelselect=new fullscreen(
["vdiv",
["radio","select channel type",
["voice","text","announcement"],
function(e){
console.log(e)
category={"text":0,"voice":2,"announcement":5,"category":4}[e]
},
1
],
["textbox","Name of channel","",function(){
console.log(this)
name=this.value
}],
["button","","submit",function(){
console.log(name,category)
fincall(name,category);
channelselect.hide();
}]
]);
channelselect.show();
}
function createcategory(fincall){
let name="";
let category=4;
console.log(fincall);
channelselect=new fullscreen(
["vdiv",
["textbox","Name of category","",function(){
console.log(this)
name=this.value
}],
["button","","submit",function(){
console.log(name,category)
fincall(name,category);
channelselect.hide();
}]
]);
channelselect.show();
}
function editchannelf(channel){channel.editChannel();}
let messagelist=[];
function buildprofile(x,y,user,type="author"){
if(currentmenu!=""){
currentmenu.remove();
}
let nickname, username, discriminator, bio, bot, pronouns, id, avatar
if(type=="author"){
console.log(user)
username=nickname=user.username;
bio=user.bio;
id=user.id;
discriminator=user.discriminator;
pronouns=user.pronouns;
bot=user.bot;
avatar=user.avatar;
}
const div=document.createElement("table");
if(x!==-1){
div.style.left=x+"px";
div.style.top=y+"px";
div.classList.add("profile");
}else{
div.classList.add("hypoprofile");
}
{
const pfp=user.buildpfp();
const pfprow=document.createElement("tr");
div.appendChild(pfprow);
pfprow.appendChild(pfp);
}
{
const userbody=document.createElement("tr");
userbody.classList.add("infosection");
div.appendChild(userbody);
const usernamehtml=document.createElement("h2");
usernamehtml.textContent=nickname;
userbody.appendChild(usernamehtml);
const discrimatorhtml=document.createElement("h3");
discrimatorhtml.classList.add("tag");
discrimatorhtml.textContent=username+"#"+discriminator;
userbody.appendChild(discrimatorhtml)
const pronounshtml=document.createElement("p");
pronounshtml.textContent=pronouns;
pronounshtml.classList.add("pronouns");
userbody.appendChild(pronounshtml)
const rule=document.createElement("hr");
userbody.appendChild(rule);
const biohtml=markdown(bio);
userbody.appendChild(biohtml);
}
console.log(div);
if(x!==-1){
currentmenu=div;
document.body.appendChild(div)
}
return div
}
function profileclick(obj,author){
obj.onclick=function(e){
console.log(e.clientX,e.clientY,author);
buildprofile(e.clientX,e.clientY,author);
e.stopPropagation();
}
}
var editing=false;
const typebox=document.getElementById("typebox")
typebox.addEventListener("keyup",enter);
typebox.addEventListener("keydown",event=>{
if(event.key === "Enter"&&!event.shiftKey) event.preventDefault();
});
console.log(typebox)
typebox.onclick=console.log;
const pasteimage=document.getElementById("pasteimage");
let replyingto=null;
async function enter(event){
thisuser.channelfocus.typingstart();
const channel=thisuser.channelfocus
channel.typingstart();
if(event.key === "Enter"&&!event.shiftKey){
event.preventDefault();
if(editing){
editing.edit(typebox.value);
editing=false;
if(channel.editing){
channel.editing.edit((typebox).value);
channel.editing=null;
}else{
let replying=replyingto?.all;
replyingto= thisuser.channelfocus.replyingto;
let replying=replyingto;
if(replyingto){
replyingto.classList.remove("replying");
replyingto.div.classList.remove("replying");
}
replyingto=false;
thisuser.channelfocus.sendMessage(typebox.value,{
thisuser.channelfocus.replyingto=null;
channel.sendMessage(typebox.value,{
attachments:images,
replyingto:replying,
})
thisuser.channelfocus.makereplybox();
}
while(images.length!=0){
images.pop();
@ -276,7 +163,17 @@ async function enter(event){
}
}
let packets=1;
const typebox=document.getElementById("typebox") as HTMLInputElement;
typebox.addEventListener("keyup",enter);
typebox.addEventListener("keydown",event=>{
if(event.key === "Enter"&&!event.shiftKey) event.preventDefault();
});
console.log(typebox)
typebox.onclick=console.log;
let serverz=0;
let serverid=[];
@ -289,13 +186,13 @@ let cchanel=0;
function getguildinfo(){
const path=window.location.pathname.split("/");
const channel=path[3];
ws.send(JSON.stringify({op: 14, d: {guild_id: path[2], channels: {[channel]: [[0, 99]]}}}));
this.ws.send(JSON.stringify({op: 14, d: {guild_id: path[2], channels: {[channel]: [[0, 99]]}}}));
}
const images=[];
const images:Blob[]=[];
const imageshtml=[];
function createunknown(fname,fsize,src){
function createunknown(fname,fsize){
const div=document.createElement("table");
div.classList.add("unknownfile");
const nametr=document.createElement("tr");
@ -304,14 +201,9 @@ function createunknown(fname,fsize,src){
nametr.append(fileicon);
fileicon.append("🗎");
fileicon.classList.add("fileicon");
fileicon.rowSpan="2";
fileicon.rowSpan=2;
const nametd=document.createElement("td");
if(src){
const a=document.createElement("a");
a.href=src;
a.textContent=fname;
nametd.append(a);
}else{
{
nametd.textContent=fname;
}
@ -344,17 +236,16 @@ function filetohtml(file){
return createunknownfile(file);
}
}
import { File } from "./file.js";
document.addEventListener('paste', async (e) => {
Array.from(e.clipboardData.files).forEach(async (file) => {
e.preventDefault();
const html=filetohtml(file);
pasteimage.appendChild(html);
const blob = URL.createObjectURL(file);
images.push(file)
imageshtml.push(html);
console.log(file.type)
});
Array.from(e.clipboardData.files).forEach(async (f) => {
const file=File.initFromBlob(f);
e.preventDefault();
const html=file.upHTML(images,f);
pasteimage.appendChild(html);
images.push(f)
imageshtml.push(html);
});
});
setTheme();
@ -362,6 +253,7 @@ setTheme();
function userSettings(){
thisuser.usersettings.show();
}
document.getElementById("settings").onclick=userSettings;
let triggered=false;
document.getElementById("messagecontainer").addEventListener("scroll",(e)=>{
const messagecontainer=document.getElementById("messagecontainer")
@ -384,13 +276,13 @@ document.getElementById("messagecontainer").addEventListener("scroll",(e)=>{
})
if(mobile){
document.getElementById("channelw").onclick=function(){
document.getElementById("channels").parentNode.classList.add("collapse");
(document.getElementById("channels").parentNode as HTMLElement).classList.add("collapse");
document.getElementById("servertd").classList.add("collapse");
document.getElementById("servers").classList.add("collapse");
}
document.getElementById("mobileback").textContent="#";
document.getElementById("mobileback").onclick=function(){
document.getElementById("channels").parentNode.classList.remove("collapse");
(document.getElementById("channels").parentNode as HTMLElement).classList.remove("collapse");
document.getElementById("servertd").classList.remove("collapse");
document.getElementById("servers").classList.remove("collapse");
}

View file

@ -1,45 +1,80 @@
class localuser{
constructor(userinfo){
import {Guild} from "./guild.js";
import {Channel} from "./channel.js";
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 {Fullscreen} from "./fullscreen.js";
import {setTheme, Specialuser} from "./login.js";
class Localuser{
packets:number;
token:string;
userinfo:Specialuser;
serverurls;
initialized:boolean;
info;
headers:{"Content-type":string,Authorization:string};
usersettings:Fullscreen;
ready;
guilds:Guild[];
guildids:{ [key: string]: Guild };
user:User;
status:string;
channelfocus:Channel;
lookingguild:Guild;
guildhtml:Record<string, HTMLDivElement>;
ws:WebSocket;
typing:[string,number][];
wsinterval:NodeJS.Timeout;
constructor(userinfo:Specialuser){
this.packets=1;
this.token=userinfo.token;
this.userinfo=userinfo;
this.serverurls=this.userinfo.serverurls;
this.initialized=false;
this.info=this.serverurls;
this.headers={"Content-type": "application/json; charset=UTF-8",Authorization:this.userinfo.token};
}
gottenReady(ready){
gottenReady(ready):void{
this.usersettings=null;
this.initialized=true;
this.ready=ready;
this.guilds=[];
this.guildids={};
this.user=new user(ready.d.user);
this.user=new User(ready.d.user,this);
this.userinfo.username=this.user.username;
this.userinfo.pfpsrc=this.user.getpfpsrc();
this.status=this.ready.d.user_settings.status;
this.channelfocus=null;
this.lookingguild=null;
this.guildhtml={};
const members={};
for(const thing of ready.d.merged_members){
members[thing[0].guild_id]=thing[0];
}
for(const thing of ready.d.guilds){
const temp=new guild(thing,this);
const temp=new Guild(thing,this,members[thing.id]);
this.guilds.push(temp);
this.guildids[temp.id]=temp;
}
{
const temp=new direct(ready.d.private_channels,this);
const temp=new Direct(ready.d.private_channels,this);
this.guilds.push(temp);
this.guildids[temp.id]=temp;
}
console.log(ready.d.user_guild_settings.entries)
console.log(ready.d.user_guild_settings.entries);
for(const thing of ready.d.user_guild_settings.entries){
this.guildids[thing.guild_id].notisetting(thing);
}
for(const thing of ready.d.merged_members){
const guild=this.guildids[thing[0].guild_id]
const temp=new member(thing[0],guild);
guild.giveMember(temp);
}
for(const thing of ready.d.read_state.entries){
const guild=this.resolveGuildidFromChannelID(thing.id)
const channel=this.resolveChannelFromID(thing.id);
if(!channel){continue;}
const guild=channel.guild;
if(guild===undefined){
continue
}
@ -48,14 +83,14 @@ class localuser{
}
this.typing=[];
}
outoffocus(){
outoffocus():void{
document.getElementById("servers").textContent="";
document.getElementById("channels").textContent="";
document.getElementById("messages").textContent="";
this.lookingguild=null;
this.channelfocus=null;
}
unload(){
unload():void{
this.initialized=false;
clearInterval(this.wsinterval);
this.outoffocus();
@ -63,7 +98,7 @@ class localuser{
this.guildids={};
this.ws.close(4000)
}
async initwebsocket(){
async initwebsocket():Promise<void>{
let returny=null
const promise=new Promise((res)=>{returny=res});
this.ws = new WebSocket(this.serverurls.gateway.toString());
@ -104,24 +139,31 @@ class localuser{
this.messageCreate(temp);
}
break;
case "MESSAGE_DELETE":
console.log(temp.d);
this.guildids[temp.d.guild_id].channelids[temp.d.channel_id].messageids[temp.d.id].deleteEvent();
break;
case "READY":
this.gottenReady(temp);
READY=temp;
this.genusersettings();
returny();
break;
case "MESSAGE_UPDATE":
if(this.initialized){
if(window.location.pathname.split("/")[3]==temp.d.channel_id){
if(this.channelfocus.id===temp.d.channel_id){
const find=temp.d.id;
const messagelist=document.getElementById("messages").children;
for(const message of messagelist){
if(message.all.id===find){
message.all.content=temp.d.content;
message.txt.innerHTML=markdown(temp.d.content).innerHTML;
const all = message["all"];
if(all.id===find){
all.content=temp.d.content;
message["txt"].innerHTML=markdown(temp.d.content).innerHTML;
break;
}
}
}
}else{
this.resolveChannelFromID(temp.d.channel_id).messages.find(e=>e.id===temp.d.channel_id).content=temp.d.content;
}
}
break;
case "TYPING_START":
@ -131,7 +173,7 @@ class localuser{
break;
case "USER_UPDATE":
if(this.initialized){
const users=user.userids[temp.d.id];
const users=User.userids[temp.d.id];
console.log(users,temp.d.id)
if(users){
users.userupdate(temp.d);
@ -163,7 +205,7 @@ class localuser{
}
case "GUILD_CREATE":
{
const guildy=new guild(temp.d,this);
const guildy=new Guild(temp.d,this,this.user);
this.guilds.push(guildy);
this.guildids[guildy.id]=guildy;
document.getElementById("servers").insertBefore(guildy.generateGuildIcon(),document.getElementById("bottomseperator"));
@ -173,11 +215,11 @@ class localuser{
}else if(temp.op===10){
console.log("heartbeat down")
this.wsinterval=setInterval(_=>{
this.ws.send(JSON.stringify({op:1,d:packets}))
this.ws.send(JSON.stringify({op:1,d:this.packets}))
},temp.d.heartbeat_interval)
packets=1;
this.packets=1;
}else if(temp.op!=11){
packets++
this.packets++
}
}catch(error){
console.error(error)
@ -189,13 +231,13 @@ class localuser{
clearInterval(this.wsinterval);
console.log('WebSocket closed');
console.warn(event);
if(event.code!==4000&&thisuser===this){
if(event.code!==4000){
this.unload();
document.getElementById("loading").classList.remove("doneloading");
document.getElementById("loading").classList.add("loading");
this.initwebsocket().then(_=>{
thisuser.loaduser();
thisuser.init();
this.loaduser();
this.init();
document.getElementById("loading").classList.add("doneloading");
document.getElementById("loading").classList.remove("loading");
console.log("done loading")
@ -205,53 +247,63 @@ class localuser{
await promise;
return;
}
resolveGuildidFromChannelID(ID){
let resolve=this.guilds.find(guild => guild.channelids[ID])
resolve??=undefined;
return resolve;
resolveChannelFromID(ID:string):Channel{
let resolve=this.guilds.find(guild => guild.channelids[ID]);
if(resolve){
return resolve.channelids[ID];
}
return undefined;
}
updateChannel(JSON){
updateChannel(JSON):void{
this.guildids[JSON.guild_id].updateChannel(JSON);
if(JSON.guild_id===this.lookingguild.id){
this.loadGuild(JSON.guild_id);
}
}
createChannel(JSON){
createChannel(JSON):void{
JSON.guild_id??="@me";
this.guildids[JSON.guild_id].createChannelpac(JSON);
if(JSON.guild_id===this.lookingguild.id){
this.loadGuild(JSON.guild_id);
}
}
delChannel(JSON){
delChannel(JSON):void{
JSON.guild_id??="@me";
this.guildids[JSON.guild_id].delChannel(JSON);
if(JSON.guild_id===this.lookingguild.id){
this.loadGuild(JSON.guild_id);
}
}
init(){
init():void{
const location=window.location.href.split("/");
this.buildservers();
if(location[3]==="channels"){
const guild=this.loadGuild(location[4]);
guild.loadChannel(location[5]);
this.channelfocus=guild.channelids[location[5]];
}
this.buildservers();
}
loaduser(){
document.getElementById("username").textContent=this.user.username
document.getElementById("userpfp").src=this.user.getpfpsrc()
loaduser():void{
document.getElementById("username").textContent=this.user.username;
(document.getElementById("userpfp") as HTMLImageElement).src=this.user.getpfpsrc();
document.getElementById("status").textContent=this.status;
}
isAdmin(){
isAdmin():boolean{
return this.lookingguild.isAdmin();
}
loadGuild(id){
loadGuild(id:string):Guild{
let guild=this.guildids[id];
if(!guild){
guild=this.guildids["@me"];
}
if(this.lookingguild){
this.lookingguild.html.classList.remove("serveropen");
}
if(guild.html){
guild.html.classList.add("serveropen")
}
this.lookingguild=guild;
document.getElementById("serverName").textContent=guild.properties.name;
//console.log(this.guildids,id)
@ -259,17 +311,25 @@ class localuser{
document.getElementById("channels").appendChild(guild.getHTML());
return guild;
}
buildservers(){
buildservers():void{
const serverlist=document.getElementById("servers");//
const outdiv=document.createElement("div");
const div=document.createElement("div");
div.textContent="⌂";
div.classList.add("home","servericon")
div.all=this.guildids["@me"];
serverlist.appendChild(div)
div["all"]=this.guildids["@me"];
this.guildids["@me"].html=outdiv;
const unread=document.createElement("div");
unread.classList.add("unread");
outdiv.append(unread);
outdiv.appendChild(div);
outdiv.classList.add("servernoti")
serverlist.append(outdiv);
div.onclick=function(){
this.all.loadGuild();
this.all.loadChannel();
this["all"].loadGuild();
this["all"].loadChannel();
}
const sentdms=document.createElement("div");
sentdms.classList.add("sentdms");
@ -280,8 +340,8 @@ class localuser{
br.classList.add("lightbr");
serverlist.appendChild(br)
for(const thing of this.guilds){
if(thing instanceof direct){
thing.unreaddms();
if(thing instanceof Direct){
(thing as Direct).unreaddms();
continue;
}
const divy=thing.generateGuildIcon();
@ -309,7 +369,7 @@ class localuser{
let inviteurl="";
const error=document.createElement("span");
const full=new fullscreen(["tabs",[
const full=new Fullscreen(["tabs",[
["Join using invite",[
"vdiv",
["textbox",
@ -332,7 +392,7 @@ class localuser{
}else{
parsed=inviteurl;
}
fetch(info.api.toString()+"/v9/invites/"+parsed,{
fetch(this.info.api.toString()+"/v9/invites/"+parsed,{
method:"POST",
headers:this.headers,
}).then(r=>r.json()).then(_=>{
@ -351,19 +411,19 @@ class localuser{
]])
full.show();
}
messageCreate(messagep){
messageCreate(messagep):void{
messagep.d.guild_id??="@me";
this.guildids[messagep.d.guild_id].channelids[messagep.d.channel_id].messageCreate(messagep,this.channelfocus.id===messagep.d.channel_id);
this.guildids[messagep.d.guild_id].channelids[messagep.d.channel_id].messageCreate(messagep);
this.unreads();
}
unreads(){
unreads():void{
console.log(this.guildhtml)
for(const thing of this.guilds){
if(thing.id==="@me"){continue;}
thing.unreads(this.guildhtml[thing.id]);
}
}
typeingStart(typing){
typeingStart(typing):void{
if(this.channelfocus.id===typing.d.channel_id){
const memb=typing.d.member;
let name;
@ -392,12 +452,12 @@ class localuser{
this.rendertyping();
}
}
updatepfp(file){
updatepfp(file:Blob):void{
var reader = new FileReader();
reader.readAsDataURL(file);
console.log(this.headers);
reader.onload = ()=>{
fetch(info.api.toString()+"/v9/users/@me",{
fetch(this.info.api.toString()+"/v9/users/@me",{
method:"PATCH",
headers:this.headers,
body:JSON.stringify({
@ -408,8 +468,8 @@ class localuser{
};
}
updatepronouns(pronouns){
fetch(info.api.toString()+"/v9/users/@me/profile",{
updatepronouns(pronouns:string):void{
fetch(this.info.api.toString()+"/v9/users/@me/profile",{
method:"PATCH",
headers:this.headers,
body:JSON.stringify({
@ -417,8 +477,8 @@ class localuser{
})
});
}
updatebio(bio){
fetch(info.api.toString()+"/v9/users/@me/profile",{
updatebio(bio:string):void{
fetch(this.info.api.toString()+"/v9/users/@me/profile",{
method:"PATCH",
headers:this.headers,
body:JSON.stringify({
@ -426,7 +486,7 @@ class localuser{
})
});
}
rendertyping(){
rendertyping():void{
const typingtext=document.getElementById("typing")
let build="";
const array2=[];
@ -456,20 +516,20 @@ class localuser{
typingtext.classList.add("hidden");
}
}
genusersettings(){
genusersettings():void{
const hypothetcialprofie=document.createElement("div");
let file=null;
let newprouns=null;
let newbio=null;
let hypouser=new user(thisuser.user,true);
let hypouser=new User(this.user,this,true);
function regen(){
hypothetcialprofie.textContent="";
const hypoprofile=buildprofile(-1,-1,hypouser);
const hypoprofile=hypouser.buildprofile(-1,-1);
hypothetcialprofie.appendChild(hypoprofile)
}
regen();
this.usersettings=new fullscreen(
this.usersettings=new Fullscreen(
["hdiv",
["vdiv",
["fileupload","upload pfp:",function(e){
@ -480,13 +540,13 @@ class localuser{
hypouser.hypotheticalpfp=true;
regen();
}],
["textbox","Pronouns:",thisuser.user.pronouns,function(e){
["textbox","Pronouns:",this.user.pronouns,function(e){
console.log(this.value);
hypouser.pronouns=this.value;
newprouns=this.value;
regen();
}],
["mdbox","Bio:",thisuser.user.bio,function(e){
["mdbox","Bio:",this.user.bio,function(e){
console.log(this.value);
hypouser.bio=this.value;
newbio=this.value;
@ -494,33 +554,35 @@ class localuser{
}],
["button","update user content:","submit",function(){
if(file!==null){
thisuser.updatepfp(file);
this.updatepfp(file);
}
if(newprouns!==null){
thisuser.updatepronouns(newprouns);
this.updatepronouns(newprouns);
}
if(newbio!==null){
thisuser.updatebio(newbio);
this.updatebio(newbio);
}
}],
["select","Theme:",["Dark","Light","WHITE"],e=>{
localStorage.setItem("theme",["Dark","Light","WHITE"][e.target.selectedIndex]);
setTheme();
},["Dark","Light","WHITE"].indexOf(localStorage.getItem("theme"))],
["select","Notification sound:",voice.sounds,e=>{
voice.setNotificationSound(voice.sounds[e.target.selectedIndex]);
voice.noises(voice.sounds[e.target.selectedIndex]);
},voice.sounds.indexOf(voice.getNotificationSound())]
["select","Notification sound:",Voice.sounds,e=>{
Voice.setNotificationSound(Voice.sounds[e.target.selectedIndex]);
Voice.noises(Voice.sounds[e.target.selectedIndex]);
},Voice.sounds.indexOf(Voice.getNotificationSound())]
],
["vdiv",
["html",hypothetcialprofie]
]
],_=>{},function(){
hypouser=new user(thisuser.user);
console.log(this);
hypouser=new User(this.user,this);
regen();
file=null;
newprouns=null;
newbio=null;
})
}.bind(this))
}
}
export {Localuser};

View file

@ -22,5 +22,5 @@
</form>
<a href="/register.html">Don't have an account?</a>
</div>
<script src="/login.js"></script>
<script src="/login.js" type="module"></script>
</body>

View file

@ -1,4 +1,5 @@
const mobile=isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
export {mobile, getBulkUsers,getBulkInfo,setTheme,Specialuser}
function setTheme(){
const name=localStorage.getItem("theme");
if(!name){
@ -11,7 +12,7 @@ setTheme();
function getBulkUsers(){
const json=getBulkInfo()
for(const thing in json.users){
json.users[thing]=new specialuser(json.users[thing]);
json.users[thing]=new Specialuser(json.users[thing]);
}
return json;
}
@ -48,9 +49,14 @@ function setDefaults(){
localStorage.setItem("userinfos",JSON.stringify(userinfos));
}
setDefaults();
class specialuser{
class Specialuser{
serverurls;
email:string;
token:string;
loggedin;
json;
constructor(json){
if(json instanceof specialuser){
if(json instanceof Specialuser){
console.error("specialuser can't construct from another specialuser");
}
this.serverurls=json.serverurls;
@ -94,21 +100,23 @@ class specialuser{
}
}
function adduser(user){
user=new specialuser(user);
user=new Specialuser(user);
const info=getBulkInfo();
info.users[user.uid]=user;
info.currentuser=user.uid;
localStorage.setItem("userinfos",JSON.stringify(info));
}
const instancein=document.getElementById("instancein");
let timeout=0;
let timeout;
let instanceinfo;
async function checkInstance(e){
const verify=document.getElementById("verify");;
try{
verify.textContent="Checking Instance";
instanceinfo=await setInstance(instancein.value);
const instanceinfo=await setInstance((instancein as HTMLInputElement).value);
localStorage.setItem("instanceinfo",JSON.stringify(instanceinfo));
verify.textContent="Instance is all good"
if(checkInstance.alt){checkInstance.alt();}
if(checkInstance["alt"]){checkInstance["alt"]();}
setTimeout(_=>{
console.log(verify.textContent)
verify.textContent="";
@ -128,7 +136,7 @@ if(instancein){
timeout=setTimeout(checkInstance,1000);
});
if(localStorage.getItem("instanceinfo")){
instancein.value=JSON.parse(localStorage.getItem("instanceinfo")).wellknown
(instancein as HTMLInputElement).value=JSON.parse(localStorage.getItem("instanceinfo")).wellknown
}else{
checkInstance("https://spacebar.chat/");
}
@ -148,7 +156,7 @@ async function login(username, password){
}}
try{
const info=JSON.parse(localStorage.getItem("instanceinfo"));
url=new URL(info.login);
const url=new URL(info.login);
return await fetch(url.origin+'/api/auth/login',options).then(responce=>responce.json())
.then((response) => {
console.log(response,response.message)

View file

@ -1,7 +1,10 @@
"use strict";
function markdown(txt,keep=false){
if((typeof txt)===(typeof "")){
return markdown(txt.split(""),keep);
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");
@ -19,7 +22,7 @@ function markdown(txt,keep=false){
i--;
}
let element=null;
let keepys=false;
let keepys="";
if(txt[i+1]==="#"){
console.log("test");
@ -50,17 +53,20 @@ function markdown(txt,keep=false){
}
if(keepys){
appendcurrent();
if(!first){
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(markdown(build,keep));
element.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
span.append(element);
i--;
continue;
@ -70,8 +76,11 @@ function markdown(txt,keep=false){
}
}
if(txt[i]==="\n"){
appendcurrent();
span.append(document.createElement("br"));
if(!stdsize){
appendcurrent();
span.append(document.createElement("br"));
}
continue;
}
if(txt[i]==="`"){
@ -115,7 +124,7 @@ function markdown(txt,keep=false){
if(keep){
build+="`".repeat(find);
}
if(count!==3){
if(count!==3&&!stdsize){
const samp=document.createElement("samp");
samp.textContent=build;
span.appendChild(samp);
@ -151,7 +160,7 @@ function markdown(txt,keep=false){
if(txt[j]==="*"){
find++;
}else{
build+=txt[j];
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("*"));
find=0;
@ -166,20 +175,20 @@ function markdown(txt,keep=false){
if(count===1){
const i=document.createElement("i");
if(keep){i.append(stars)}
i.appendChild(markdown(build,keep));
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));
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));
b.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){b.append(stars)}
i.appendChild(b);
span.appendChild(i);
@ -205,7 +214,7 @@ function markdown(txt,keep=false){
if(txt[j]==="_"){
find++;
}else{
build+=txt[j];
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("_"));
find=0;
@ -219,20 +228,20 @@ function markdown(txt,keep=false){
if(count===1){
const i=document.createElement("i");
if(keep){i.append(underscores)}
i.appendChild(markdown(build,keep));
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));
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));
i.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){i.append(underscores)}
u.appendChild(i)
span.appendChild(u);
@ -251,7 +260,7 @@ function markdown(txt,keep=false){
if(txt[j]==="~"){
find++;
}else{
build+=txt[j];
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("~"));
find=0;
@ -265,7 +274,7 @@ function markdown(txt,keep=false){
if(count===2){
const s=document.createElement("s");
if(keep){s.append(underscores)}
s.appendChild(markdown(build,keep));
s.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
if(keep){s.append(underscores)}
span.appendChild(s);
}
@ -281,7 +290,7 @@ function markdown(txt,keep=false){
if(txt[j]==="|"){
find++;
}else{
build+=txt[j];
build.push(txt[j]);
if(find!==0){
build=build.concat(new Array(find).fill("~"));
find=0;
@ -295,7 +304,7 @@ function markdown(txt,keep=false){
if(count===2){
const j=document.createElement("j");
if(keep){j.append(underscores)}
j.appendChild(markdown(build,keep));
j.appendChild(markdown(build,{keep:keep,stdsize:stdsize}));
j.classList.add("spoiler");
j.onclick=markdown.unspoil;
if(keep){j.append(underscores)}
@ -309,8 +318,9 @@ function markdown(txt,keep=false){
appendcurrent();
return span;
}
markdown.unspoil=function(e){
markdown.unspoil=function(e:any) : void{
//console.log("undone")
e.target.classList.remove("spoiler")
e.target.classList.add("unspoiled")
}

View file

@ -1,64 +0,0 @@
class member{
static already={};
constructor(memberjson,owner){
if(!owner){console.error("Guild not included in the creation of a member object")}
this.owner=owner;
let membery=memberjson;
if(memberjson.guild_member){
membery=memberjson.guild_member;
this.user=memberjson.user;
}
for(const thing of Object.keys(membery)){
if(thing==="guild"){continue}
this[thing]=membery[thing];
}
this.user=new user(this.user);
}
get guild(){
return this.owner;
}
get localuser(){
return this.guild.localuser;
}
static async resolve(user,guild){
if(!member.already[guild.id]){
member.already[guild.id]={};
}else if(member.already[guild.id][user.id]){
const memb=member.already[guild.id][user.id]
if(memb instanceof Promise){
return await memb;
}
return memb;
}
const promoise= fetch(info.api.toString()+"/v9/users/"+user.id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+guild.id,{headers:guild.headers}).then(_=>_.json()).then(json=>{
const memb=new member(json,guild);
member.already[guild.id][user.id]=memb;
guild.fillMember(memb);
console.log("resolved")
return memb
});
member.already[guild.id][user.id]=promoise;
return await promoise;
}
hasRole(ID){
for(const thing of this.roles){
if(thing.id===ID){
return true;
}
}
return false;
}
getColor(){
for(const thing of this.roles){
const color=thing.getColor();
if(color){
return color;
}
}
return "";
}
isAdmin(){
return this.guild.properties.owner_id===this.user.id;
}
}

111
webpage/member.ts Normal file
View file

@ -0,0 +1,111 @@
import {User} from "./user.js";
import {Role} from "./role.js";
import {Guild} from "./guild.js";
class Member{
static already={};
owner:Guild;
user:User;
roles:Role[];
error:boolean;
constructor(memberjson,owner:Guild,error=false){
this.error=error;
this.owner=owner;
let membery=memberjson;
this.roles=[];
if(!error){
if(memberjson.guild_member){
membery=memberjson.guild_member;
this.user=memberjson.user;
}
}
for(const thing of Object.keys(membery)){
if(thing==="guild"){continue}
if(thing==="owner"){continue}
if(thing==="roles"){
for(const strrole of membery["roles"]){
const role=this.guild.getRole(strrole);
this.roles.push(role);
}
continue;
}
this[thing]=membery[thing];
}
if(error){
this.user=memberjson as User;
}else{
this.user=new User(this.user,owner.localuser);
}
}
get guild(){
return this.owner;
}
get localuser(){
return this.guild.localuser;
}
get info(){
return this.owner.info;
}
static async resolve(unkown:User|object,guild:Guild):Promise<Member>{
if(!(guild instanceof Guild)){
console.error(guild)
}
let user:User;
if(unkown instanceof User){
user=unkown as User;
}else{
return new Member(unkown,guild);
}
if(guild.id==="@me"){return null}
if(!Member.already[guild.id]){
Member.already[guild.id]={};
}else if(Member.already[guild.id][user.id]){
const memb=Member.already[guild.id][user.id]
if(memb instanceof Promise){
return await memb;
}
return memb;
}
const promoise= fetch(guild.info.api.toString()+"/v9/users/"+user.id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+guild.id,{headers:guild.headers}).then(_=>_.json()).then(json=>{
const memb=new Member(json,guild);
Member.already[guild.id][user.id]=memb;
console.log("resolved")
return memb
})
Member.already[guild.id][user.id]=promoise;
try{
return await promoise
}catch(_){
const memb=new Member(user,guild,true);
Member.already[guild.id][user.id]=memb;
return memb;
}
}
hasRole(ID:string){
console.log(this.roles,ID);
for(const thing of this.roles){
if(thing.id===ID){
return true;
}
}
return false;
}
getColor(){
for(const thing of this.roles){
const color=thing.getColor();
if(color){
return color;
}
}
return "";
}
isAdmin(){
for(const role of this.roles){
if(role.permissions.getPermision("ADMINISTRATOR")){
return true;
}
}
return this.guild.properties.owner_id===this.user.id;
}
}
export {Member};

View file

@ -1,271 +0,0 @@
class cmessage{
static contextmenu=new contextmenu("message menu");
static setupcmenu(){
cmessage.contextmenu.addbutton("Copy raw text",function(){
navigator.clipboard.writeText(this.content);
});
cmessage.contextmenu.addbutton("Reply",function(div){
if(replyingto){
replyingto.classList.remove("replying");
}
replyingto=div;
console.log(div);
replyingto.classList.add("replying");
});
cmessage.contextmenu.addbutton("Copy message id",function(){
navigator.clipboard.writeText(this.id);
});
cmessage.contextmenu.addbutton("Copy user id",function(){
navigator.clipboard.writeText(this.author.id);
});
cmessage.contextmenu.addbutton("Message user",function(){
fetch(info.api.toString()+"/v9/users/@me/channels",
{method:"POST",
body:JSON.stringify({"recipients":[this.author.id]}),
headers: {"Content-type": "application/json; charset=UTF-8",Authorization:token}
});
})
cmessage.contextmenu.addbutton("Edit",function(){
editing=this;
document.getElementById("typebox").value=this.content;
},null,_=>{return _.author.id==READY.d.user.id});
}
constructor(messagejson,owner){
this.owner=owner;
this.headers=this.owner.headers;
for(const thing of Object.keys(messagejson)){
this[thing]=messagejson[thing];
}
for(const thing in this.embeds){
console.log(thing,this.embeds)
this.embeds[thing]=new embed(this.embeds[thing],this);
}
this.author=new user(this.author);
for(const thing in this.mentions){
this.mentions[thing]=new user(this.mentions[thing]);
}
if(this.mentions.length||this.mention_roles.length){//currently mention_roles isn't implemented on the spacebar servers
console.log(this.mentions,this.mention_roles)
}
if(this.mentionsuser(this.localuser.user)){
console.log(this);
}
}
get channel(){
return this.owner;
}
get guild(){
return this.owner.guild;
}
get localuser(){
return this.owner.localuser;
}
messageevents(obj){
cmessage.contextmenu.bind(obj,this)
obj.classList.add("messagediv")
}
mentionsuser(userd){
if(userd instanceof user){
return this.mentions.includes(userd);
}else if(userd instanceof member){
return this.mentions.includes(userd.user);
}
}
getimages(){
const build=[];
for(const thing of this.attachments){
if(thing.content_type.startsWith('image/')){
build.push(thing);
}
}
return build;
}
async edit(content){
return await fetch(info.api.toString()+"/channels/"+this.channel.id+"/messages/"+this.id,{
method: "PATCH",
headers: this.headers,
body:JSON.stringify({content:content})
});
}
buildhtml(premessage){
//premessage??=messages.lastChild;
const build = document.createElement('table');
const div=document.createElement("div");
if(this.message_reference){
const replyline=document.createElement("div");
const line=document.createElement("hr");
const minipfp=document.createElement("img")
minipfp.classList.add("replypfp");
replyline.appendChild(line);
replyline.appendChild(minipfp);
const username=document.createElement("span");
replyline.appendChild(username);
const reply=document.createElement("div");
username.classList.add("username");
member.resolve(this.author,this.guild).then(_=>{
username.style.color=_.getColor();
});
reply.classList.add("replytext");
replyline.appendChild(reply);
const line2=document.createElement("hr");
replyline.appendChild(line2);
line2.classList.add("reply");
line.classList.add("startreply");
replyline.classList.add("replyflex")
fetch(info.api.toString()+"/v9/channels/"+this.message_reference.channel_id+"/messages?limit=1&around="+this.message_reference.message_id,{headers:this.headers}).then(responce=>responce.json()).then(responce=>{
const author=new user(responce[0].author);
reply.appendChild(markdown(responce[0].content));
minipfp.src=author.getpfpsrc()
profileclick(minipfp,author)
username.textContent=author.username;
profileclick(username,author)
});
div.appendChild(replyline);
}
this.messageevents(div);
messagelist.push(div)
build.classList.add("message");
div.appendChild(build);
if({0:true,19:true}[this.type]||this.attachments.length!==0){
const pfpRow = document.createElement('th');
let pfpparent, current
if(premessage!=null){
pfpparent=premessage.pfpparent;
pfpparent??=premessage;
let pfpparent2=pfpparent.all;
pfpparent2??=pfpparent;
const old=(new Date(pfpparent2.timestamp).getTime())/1000;
const newt=(new Date(this.timestamp).getTime())/1000;
current=(newt-old)>600;
}
const combine=(premessage?.userid!=this.author.id&premessage?.author?.id!=this.author.id)||(current)||this.message_reference
if(combine){
const pfp=this.author.buildpfp();
profileclick(pfp,this.author);
pfpRow.appendChild(pfp);
}else{
div.pfpparent=pfpparent;
}
pfpRow.classList.add("pfprow")
build.appendChild(pfpRow);
const text=document.createElement("th");
const texttxt=document.createElement("table");
texttxt.classList.add("commentrow")
text.appendChild(texttxt);
if(combine){
const username=document.createElement("span");
username.classList.add("username")
profileclick(username,this.author);
member.resolve(this.author,this.guild).then(_=>{
username.style.color=_.getColor();
})
username.textContent=this.author.username;
const userwrap=document.createElement("tr")
userwrap.appendChild(username)
if(this.author.bot){
const username=document.createElement("span");
username.classList.add("bot")
username.textContent="BOT";
userwrap.appendChild(username)
}
const time=document.createElement("span");
time.textContent=" "+formatTime(new Date(this.timestamp));
time.classList.add("timestamp")
userwrap.appendChild(time);
texttxt.appendChild(userwrap)
}
const messaged=markdown(this.content);
div.txt=messaged;
const messagedwrap=document.createElement("tr")
messagedwrap.appendChild(messaged)
texttxt.appendChild(messagedwrap)
build.appendChild(text)
if(this.attachments.length){
const attatch = document.createElement("tr")
for(const thing of this.attachments){
const array=thing.url.split("/");array.shift();array.shift();array.shift();
const src=info.cdn.toString()+array.join("/");
if(thing.content_type.startsWith('image/')){
const img=document.createElement("img");
img.classList.add("messageimg")
img.onclick=function(){
const full=new fullscreen(["img",img.src,["fit"]]);
full.show();
}
img.src=src;
attatch.appendChild(img)
}else{
attatch.appendChild(createunknown(thing.filename,thing.size,src))
}
}
messagedwrap.appendChild(attatch)
}
if(this.embeds.length){
const embeds = document.createElement("tr")
for(const thing of this.embeds){
embeds.appendChild(thing.generateHTML());
}
messagedwrap.appendChild(embeds)
}
//
}else if(this.type===7){
const text=document.createElement("th");
const texttxt=document.createElement("table");
text.appendChild(texttxt);
build.appendChild(text)
const messaged=document.createElement("p");
div.txt=messaged;
messaged.textContent="welcome: "+this.author.username;
const messagedwrap=document.createElement("tr")
messagedwrap.appendChild(messaged);
const time=document.createElement("span");
time.textContent=" "+formatTime(new Date(this.timestamp));
time.classList.add("timestamp");
messagedwrap.append(time);
texttxt.appendChild(messagedwrap)
}
div.userid=this.author.id;
div.all=this;
return(div)
}
}
function formatTime(date) {
const now = new Date();
const sameDay = date.getDate() === now.getDate() &&
date.getMonth() === now.getMonth() &&
date.getFullYear() === now.getFullYear();
const yesterday = new Date(now);
yesterday.setDate(now.getDate() - 1);
const isYesterday = date.getDate() === yesterday.getDate() &&
date.getMonth() === yesterday.getMonth() &&
date.getFullYear() === yesterday.getFullYear();
const formatTime = date => date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
if (sameDay) {
return `Today at ${formatTime(date)}`;
} else if (isYesterday) {
return `Yesterday at ${formatTime(date)}`;
} else {
return `${date.toLocaleDateString()} at ${formatTime(date)}`;
}
}
cmessage.setupcmenu();

394
webpage/message.ts Normal file
View file

@ -0,0 +1,394 @@
import {Contextmenu} from "./contextmenu.js";
import {User} from "./user.js";
import {Member} from "./member.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";
import {File} from "./file.js";
class Message{
static contextmenu=new Contextmenu("message menu");
owner:Channel;
headers:Localuser["headers"];
embeds:Embed[];
author:User;
mentions:User[];
mention_roles:Role[];
attachments:File[];//probably should be its own class tbh, should be Attachments[]
id:string;
message_reference;
type:number;
timestamp:number;
content:string;
static del:Promise<void>;
static resolve:Function;
div:HTMLDivElement;
static setup(){
this.del=new Promise(_=>{this.resolve=_});
Message.setupcmenu();
}
static async wipeChanel(){
this.resolve();
document.getElementById("messages").innerHTML="";
await Promise.allSettled([this.resolve]);
this.del=new Promise(_=>{this.resolve=_})
}
static setupcmenu(){
Message.contextmenu.addbutton("Copy raw text",function(){
navigator.clipboard.writeText(this.content);
});
Message.contextmenu.addbutton("Reply",function(this:Message,div:HTMLDivElement){
this.channel.setReplying(this);
});
Message.contextmenu.addbutton("Copy message id",function(){
navigator.clipboard.writeText(this.id);
});
Message.contextmenu.addbutton("Copy user id",function(){
navigator.clipboard.writeText(this.author.id);
});
Message.contextmenu.addbutton("Message user",function(){
fetch(this.info.api.toString()+"/v9/users/@me/channels",
{method:"POST",
body:JSON.stringify({"recipients":[this.author.id]}),
headers: this.headers
});
})
Message.contextmenu.addbutton("Edit",function(){
this.channel.editing=this;
(document.getElementById("typebox") as HTMLInputElement).value=this.content;
},null,_=>{return _.author.id===_.localuser.user.id});
Message.contextmenu.addbutton("Delete message",function(){
this.delete();
},null,_=>{return _.canDelete()})
}
constructor(messagejson,owner:Channel){
this.owner=owner;
this.headers=this.owner.headers;
for(const thing of Object.keys(messagejson)){
if(thing==="attachments"){
this.attachments=[];
for(const thing of messagejson.attachments){
this.attachments.push(new File(thing,this));
}
continue;
}
this[thing]=messagejson[thing];
}
for(const thing in this.embeds){
console.log(thing,this.embeds)
this.embeds[thing]=new Embed(this.embeds[thing],this);
}
this.author=new User(this.author,this.localuser);
for(const thing in this.mentions){
this.mentions[thing]=new User(this.mentions[thing],this.localuser);
}
if(this.mentions.length||this.mention_roles.length){//currently mention_roles isn't implemented on the spacebar servers
console.log(this.mentions,this.mention_roles)
}
if(this.mentionsuser(this.localuser.user)){
console.log(this);
}
}
canDelete(){
return this.channel.hasPermission("MANAGE_MESSAGES")||this.author.id===this.localuser.user.id;
}
get channel(){
return this.owner;
}
get guild(){
return this.owner.guild;
}
get localuser(){
return this.owner.localuser;
}
get info(){
return this.owner.info;
}
messageevents(obj:HTMLDivElement){
const func=Message.contextmenu.bind(obj,this);
this.div=obj;
Message.del.then(_=>{
obj.removeEventListener("click",func);
this.div=null;
})
obj.classList.add("messagediv");
}
mentionsuser(userd:User|Member){
if(userd instanceof User){
return this.mentions.includes(userd);
}else if(userd instanceof Member){
return this.mentions.includes(userd.user);
}
}
getimages(){
const build=[];
for(const thing of this.attachments){
if(thing.content_type.startsWith('image/')){
build.push(thing);
}
}
return build;
}
async edit(content){
return await fetch(this.info.api.toString()+"/channels/"+this.channel.id+"/messages/"+this.id,{
method: "PATCH",
headers: this.headers,
body:JSON.stringify({content:content})
});
}
delete(){
fetch(`${this.info.api.toString()}/channels/${this.channel.id}/messages/${this.id}`,{
headers:this.headers,
method:"DELETE",
})
}
deleteEvent(){
if(this.div){
this.div.innerHTML="";
this.div=null;
}
const index=this.channel.messages.indexOf(this);
this.channel.messages.splice(this.channel.messages.indexOf(this),1);
delete this.channel.messageids[this.id];
const regen=this.channel.messages[index-1]
if(regen){
regen.generateMessage();
}
}
generateMessage(premessage:Message=null){
if(!premessage){
premessage=this.channel.messages[this.channel.messages.indexOf(this)+1];
}
const div=this.div;
if(this===this.channel.replyingto){
div.classList.add("replying");
}
div.innerHTML="";
const build = document.createElement('table');
if(this.message_reference){
const replyline=document.createElement("div");
const line=document.createElement("hr");
const minipfp=document.createElement("img")
minipfp.classList.add("replypfp");
replyline.appendChild(line);
replyline.appendChild(minipfp);
const username=document.createElement("span");
replyline.appendChild(username);
const reply=document.createElement("div");
username.classList.add("username");
Member.resolve(this.author,this.guild).then(_=>{
if(!_) {return};
console.log(_.error);
if(_.error){
username.textContent+="Error";
alert("Should've gotten here")
const error=document.createElement("span");
error.textContent="!";
error.classList.add("membererror");
username.after(error);
return;
}
username.style.color=_.getColor();
}).catch(_=>{
console.log(_)
});
reply.classList.add("replytext");
replyline.appendChild(reply);
const line2=document.createElement("hr");
replyline.appendChild(line2);
line2.classList.add("reply");
line.classList.add("startreply");
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}));
minipfp.src=author.getpfpsrc()
author.profileclick(minipfp)
username.textContent=author.username;
author.profileclick(username)
});
div.appendChild(replyline);
}
this.messageevents(div);
build.classList.add("message");
div.appendChild(build);
if({0:true,19:true}[this.type]||this.attachments.length!==0){
const pfpRow = document.createElement('th');
let pfpparent, current
if(premessage!=null){
pfpparent??=premessage;
let pfpparent2=pfpparent.all;
pfpparent2??=pfpparent;
const old=(new Date(pfpparent2.timestamp).getTime())/1000;
const newt=(new Date(this.timestamp).getTime())/1000;
current=(newt-old)>600;
}
const combine=(premessage?.author?.id!=this.author.id)||(current)||this.message_reference
if(combine){
const pfp=this.author.buildpfp();
this.author.profileclick(pfp);
pfpRow.appendChild(pfp);
}else{
div["pfpparent"]=pfpparent;
}
pfpRow.classList.add("pfprow")
build.appendChild(pfpRow);
const text=document.createElement("th");
const texttxt=document.createElement("table");
texttxt.classList.add("commentrow")
text.appendChild(texttxt);
if(combine){
const username=document.createElement("span");
username.classList.add("username")
this.author.profileclick(username);
Member.resolve(this.author,this.guild).then(_=>{
if(!_) {return};
if(_.error){
const error=document.createElement("span");
error.textContent="!";
error.classList.add("membererror");
username.after(error);
return;
}
username.style.color=_.getColor();
})
username.textContent=this.author.username;
const userwrap=document.createElement("tr")
userwrap.appendChild(username)
if(this.author.bot){
const username=document.createElement("span");
username.classList.add("bot")
username.textContent="BOT";
userwrap.appendChild(username)
}
const time=document.createElement("span");
time.textContent=" "+formatTime(new Date(this.timestamp));
time.classList.add("timestamp")
userwrap.appendChild(time);
texttxt.appendChild(userwrap)
}
const messaged=markdown(this.content);
div["txt"]=messaged;
const messagedwrap=document.createElement("tr")
messagedwrap.appendChild(messaged)
texttxt.appendChild(messagedwrap)
build.appendChild(text)
if(this.attachments.length){
console.log(this.attachments)
const attatch = document.createElement("tr")
for(const thing of this.attachments){
attatch.appendChild(thing.getHTML())
}
messagedwrap.appendChild(attatch)
}
if(this.embeds.length){
const embeds = document.createElement("tr")
for(const thing of this.embeds){
embeds.appendChild(thing.generateHTML());
}
messagedwrap.appendChild(embeds)
}
//
}else if(this.type===7){
const text=document.createElement("th");
const texttxt=document.createElement("table");
text.appendChild(texttxt);
build.appendChild(text)
const messaged=document.createElement("p");
div["txt"]=messaged;
messaged.textContent="welcome: "+this.author.username;
const messagedwrap=document.createElement("tr")
messagedwrap.appendChild(messaged);
const time=document.createElement("span");
time.textContent=" "+formatTime(new Date(this.timestamp));
time.classList.add("timestamp");
messagedwrap.append(time);
texttxt.appendChild(messagedwrap)
}
div["all"]=this;
return(div)
}
buildhtml(premessage:Message){
if(this.div){console.error(`HTML for ${this} already exists, aborting`);return;}
//premessage??=messages.lastChild;
const div=document.createElement("div");
this.div=div;
return this.generateMessage(premessage);
}
createunknown(fname,fsize,src){
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");
if(src){
const a=document.createElement("a");
a.href=src;
a.textContent=fname;
nametd.append(a);
}else{
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:"+this.filesizehuman(fsize);
size.classList.add("filesize");
div.appendChild(sizetr)
return div;
}
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 formatTime(date) {
const now = new Date();
const sameDay = date.getDate() === now.getDate() &&
date.getMonth() === now.getMonth() &&
date.getFullYear() === now.getFullYear();
const yesterday = new Date(now);
yesterday.setDate(now.getDate() - 1);
const isYesterday = date.getDate() === yesterday.getDate() &&
date.getMonth() === yesterday.getMonth() &&
date.getFullYear() === yesterday.getFullYear();
const formatTime = date => date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
if (sameDay) {
return `Today at ${formatTime(date)}`;
} else if (isYesterday) {
return `Yesterday at ${formatTime(date)}`;
} else {
return `${date.toLocaleDateString()} at ${formatTime(date)}`;
}
}
Message.setup();
export { Message };

View file

@ -1,18 +1,24 @@
class permissions{
constructor(b){
this.permissions=BigInt(b);
export {Permissions};
class Permissions{
allow:bigint;
deny:bigint;
constructor(allow:string,deny:string=""){
this.allow=BigInt(allow);
this.deny=BigInt(deny);
}
getPermisionbit(b){
return Boolean((this.permissions>>BigInt(b))&1n);
getPermisionbit(b:number,big:bigint) : boolean{
return Boolean((big>>BigInt(b))&1n);
}
setPermisionbit(b,state){
setPermisionbit(b:number,state:boolean,big:bigint) : bigint{
const bit=1n<<BigInt(b);
this.permissions=(this.permissions & ~bit) | (BigInt(state) << BigInt(b));//thanks to geotale for this code :3
return (big & ~bit) | (BigInt(state) << BigInt(b));//thanks to geotale for this code :3
}
static map
static info
static map:{
[key:number|string]:{"name":string,"readableName":string,"description":string}|number,
}
static info:{"name":string,"readableName":string,"description":string}[];
static makeMap(){
permissions.info=[//for people in the future, do not reorder these, the creation of the map realize on the order
Permissions.info=[//for people in the future, do not reorder these, the creation of the map realize on the order
{
name:"CREATE_INSTANT_INVITE",
readableName:"Create instance invite",
@ -219,16 +225,22 @@ class permissions{
description:"Allows the user to time out other users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels"
},
];
permissions.map={};
Permissions.map={};
let i=0;
for(const thing of permissions.info){
permissions.map[i]=thing;
permissions.map[thing.name]=i;
for(const thing of Permissions.info){
Permissions.map[i]=thing;
Permissions.map[thing.name]=i;
i++;
}
}
getPermision(name){
return this.getPermisionbit(permissions.map[name]);
getPermision(name:string):number{
if(this.getPermisionbit(Permissions.map[name] as number,this.allow)){
return 1;
}else if(this.getPermisionbit(Permissions.map[name] as number,this.deny)){
return -1;
}else{
return 0;
}
}
}
permissions.makeMap();
Permissions.makeMap();

View file

@ -1,20 +0,0 @@
class role{
constructor(JSON, owner){
for(const thing of Object.keys(JSON)){
this[thing]=JSON[thing];
}
this.permissions=new permissions(JSON.permissions);
this.owner=owner;
}
get guild(){
return this.owner;
}
get localuser(){
return this.guild.localuser;
}
getColor(){
if(this.color===0){return null};
return `#${this.color.toString(16)}`;
}
}

28
webpage/role.ts Normal file
View file

@ -0,0 +1,28 @@
export {Role};
import {Permissions} from "./permissions.js";
import {Localuser} from "./localuser.js";
import {Guild} from "./guild.js";
class Role{
permissions:Permissions;
owner:Guild;
color:number;
id:string;
constructor(JSON, owner:Guild){
for(const thing of Object.keys(JSON)){
this[thing]=JSON[thing];
}
this.permissions=new Permissions(JSON.permissions);
this.owner=owner;
}
get guild():Guild{
return this.owner;
}
get localuser():Localuser{
return this.guild.localuser;
}
getColor():string{
if(this.color===0){return null};
return `#${this.color.toString(16)}`;
}
}

View file

@ -24,13 +24,13 @@ async function checkCache(){
if(checkedrecently){
return;
}
promise=await caches.match("/getupdates");
const promise=await caches.match("/getupdates");
if(promise){
lastcache= await promise.text();
}
console.log(lastcache);
fetch("/getupdates").then(async data=>{
text=await data.clone().text();
const text=await data.clone().text();
console.log(text,lastcache)
if(lastcache!==text){
deleteoldcache();
@ -80,8 +80,8 @@ async function getfile(event){
return responseFromNetwork;
}catch(e){console.error(e)}
}
self.addEventListener('fetch', (event) => {
self.addEventListener('fetch', (event:any) => {
try{
event.respondWith(getfile(event));
event.respondWith(getfile(event));
}catch(e){console.error(e)}
})

View file

@ -8,6 +8,10 @@ body {
margin: 0;
padding: 0;
}
video{
max-width: 3in;
max-height: 4in;
}
.collapse{
width:0px !important;
overflow: hidden;
@ -57,7 +61,12 @@ th {
.messagediv:hover {
background-color: var(--message-bg-hover);
}
.messagediv{
overflow: hidden;
max-width:100%;
/* width: 9%; */
/* display: inline-block; */
}
pre {
background-color: var(--code-bg);
width: 100%;
@ -138,7 +147,7 @@ h2 {
.pfp {
border-radius: 50%;
width: .5in;
width: 0.5in;
height: .5in;
user-select: none;
cursor: pointer;
@ -147,11 +156,14 @@ h2 {
.servericon {
transition: border-radius .2s;
position: relative;
margin: .0in 0in 0.03in 0;
}
.servericon:hover {
border-radius: 30%;
}
.serveropen .servericon{
border-radius: 30%;
}
.contextbutton:hover {
background-color: var(--primary-bg);
}
@ -172,6 +184,7 @@ h2 {
vertical-align: top;
height: 100dvh;
overflow-x: hidden;
padding: 0.02in .05in 0.0in .05in;
}
#servers::-webkit-scrollbar {
@ -225,10 +238,11 @@ img {
height: 100%;
width: 100%;
display: inline-block;
max-width: 100%;
}
#messages {
width: 100%;
max-width: 100%;
}
p {
@ -390,6 +404,7 @@ p {
/* Move down out of view */
opacity: 0;
/* Fade out */
display: none;
}
@keyframes fade {
@ -448,15 +463,25 @@ p {
}
.replyflex {
overflow: hidden;
display: flex;
align-items: center;
max-width: 100%;
flex-direction: row;
/* width: 00; */
flex-wrap: nowrap;
justify-content: space-between;
}
.reply {
display: inline-block;
display: inline;
vertical-align: middle;
flex-grow: 1;
border-color: var(--reply-border);
/* flex: 1; */
min-width: 0px;
/* max-width: 0px; */
/* grid-column-end: 1; */
}
.startreply {
@ -477,8 +502,20 @@ p {
}
.replytext {
padding: .05in;
padding: 0 .05in;
color: var(--reply-text);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: fit-content;
/* display: block; */
/* flex-grow: 1; */
flex: 1 1 auto;
width: fit-content;
min-width: 0;
/* display: inline-block !important; */
width: 25vw;
grid-column: 2;
}
::-webkit-scrollbar {
@ -528,8 +565,12 @@ textarea {
.channel {
user-select: none;
cursor: pointer;
transition: font-weight .1s;
}
.viewChannel{
font-weight:900;
background: color-mix(in srgb, var(--channel-hover) 60%, transparent)
}
#servername {
margin-top: .1in;
margin-bottom: .1in;
@ -599,9 +640,12 @@ textarea {
#settings {
cursor: pointer;
user-select: none;
border-radius: .1in;
border-radius: .3in;
transition: background 1s;
text-align: center;
font-size: .25in;
width: .3in;
height: .3in;
}
#settings:hover {
@ -762,6 +806,9 @@ input[type="checkbox"] {
span {
word-wrap: break-word;
word-break: break-word;
/* overflow: clip; */
/* width: 2in; */
/* max-width: 100%; */
}
#loading {
@ -811,17 +858,24 @@ span {
background-color: var(--primary-text);
height: .075in;
width: .075in;
transition: transform .2s, background .2s, height .2s, width .2s;
transform: translate(-.20in, .2in);
transition: transform .2s, background .2s, height .3s, width .2s;
transform: translate(-.14in, .2in);
z-index: 10;
border-radius: 50%;
border-radius: .2in;
border: solid;
border-width: .02in;
border-color: var(--black);
}
.servernoti:hover .unread{
transform: translate(-.1in, 0.15in);
height:.2in;
}
.serveropen .unread{
transform: translate(-.1in, 0.1in) !important;
height:.3in !important;
}
.notiunread {
transform: translate(0, .2in);
transform: translate(-.1in, .2in);
}
.pinged {
@ -975,3 +1029,57 @@ span {
.spaceright{
margin-right:.1in;
}
.membererror{
display:inline-block;
background:#656500;
height:.15in;
width:.15in;
border-radius:.1in;
text-align:center;
border:solid black .03in;
margin-left:.025in;
}
.replyflex span{
/* display: inline-block; */
text-overflow:ellipsis;
overflow: hidden;
max-width: 100%;
}
.controls{
position:absolute;
top:0px;
right:0px;
}
.containedFile{
position:relative !important;
width: fit-content;
box-shadow:.02in .02in .05in black;
}
#replybox{
display:flex;
background:var(--reply-bg);
height:.25in;
transition: height .2s, padding .2s;
border-radius:.1in .1in 0 0;
padding-left:.05in;
justify-content: space-between;
flex-direction: row;
align-items: flex-end;
padding-top: .05in;
}
#replybox span{
align-self:stretch;
}
.cancelReply{
align-self:flex-start;
color:red;
margin-right: .1in;
height: .25in;
width: .25in;
text-align: center;
padding: 0in;
}
#replybox.hideReplyBox{
height: 0in;
padding: 0in;
}

View file

@ -1,61 +0,0 @@
//const usercache={};
class user{
static userids={};
static checkuser(userjson){
if(user.userids[userjson.id]){
return user.userids[userjson.id];
}else{
const tempuser=new user(userjson,true)
user.userids[userjson.id]=tempuser;
return tempuser;
}
}
constructor(userjson,dontclone=false){
if(dontclone){
for(const thing of Object.keys(userjson)){
this[thing]=userjson[thing];
}
this.hypotheticalpfp=false;
}else{
return user.checkuser(userjson);
}
}
async resolvemember(guild){
await member.resolve(this,guild);
}
buildpfp(){
const pfp=document.createElement('img');
pfp.src=this.getpfpsrc(this.id,this.avatar);
pfp.classList.add("pfp");
pfp.classList.add("userid:"+this.id);
return pfp;
}
userupdate(json){
if(json.avatar!==this.avatar){
console.log
this.changepfp(json.avatar);
}
}
changepfp(update){
this.avatar=update;
this.hypotheticalpfp=false;
const src=this.getpfpsrc();
console.log(src)
for(thing of document.getElementsByClassName("userid:"+this.id)){
thing.src=src;
}
}
getpfpsrc(){
if(this.hypotheticalpfp){
return this.avatar;
}
if(this.avatar!=null){
return info.cdn.toString()+"avatars/"+this.id+"/"+this.avatar+".png";
}else{
return info.cdn.toString()+"embed/avatars/3.png";
}
}
createjankpromises(){
new Promise(_=>{})
}
}

143
webpage/user.ts Normal file
View file

@ -0,0 +1,143 @@
//const usercache={};
import {Member} from "./member.js";
import {markdown} from "./markdown.js";
import {Contextmenu} from "./contextmenu.js";
import {Localuser} from "./localuser.js";
import {Guild} from "./guild.js";
class User{
static userids={};
owner:Localuser;
hypotheticalpfp:boolean;
id:string;
avatar:string;
username:string;
bio:string;
discriminator:string;
pronouns:string;
bot:boolean;
static checkuser(userjson,owner:Localuser){
if(User.userids[userjson.id]){
return User.userids[userjson.id];
}else{
const tempuser=new User(userjson,owner,true)
User.userids[userjson.id]=tempuser;
return tempuser;
}
}
get info(){
return this.owner.info;
}
get localuser(){
return this.owner;
}
constructor(userjson,owner:Localuser,dontclone=false){
this.owner=owner;
if(!owner){console.error("missing localuser")}
if(dontclone){
for(const thing of Object.keys(userjson)){
this[thing]=userjson[thing];
}
this.hypotheticalpfp=false;
}else{
return User.checkuser(userjson,owner);
}
}
async resolvemember(guild:Guild){
await Member.resolve(this,guild);
}
buildpfp(){
const pfp=document.createElement('img');
pfp.src=this.getpfpsrc();
pfp.classList.add("pfp");
pfp.classList.add("userid:"+this.id);
return pfp;
}
userupdate(json){
if(json.avatar!==this.avatar){
console.log
this.changepfp(json.avatar);
}
}
changepfp(update:string){
this.avatar=update;
this.hypotheticalpfp=false;
const src=this.getpfpsrc();
console.log(src)
for(const thing of document.getElementsByClassName("userid:"+this.id)){
(thing as HTMLImageElement).src=src;
}
}
getpfpsrc(){
if(this.hypotheticalpfp){
return this.avatar;
}
if(this.avatar!=null){
return this.info.cdn.toString()+"avatars/"+this.id+"/"+this.avatar+".png";
}else{
return this.info.cdn.toString()+"embed/avatars/3.png";
}
}
createjankpromises(){
new Promise(_=>{})
}
buildprofile(x:number,y:number){
if(Contextmenu.currentmenu!=""){
Contextmenu.currentmenu.remove();
}
const div=document.createElement("table");
if(x!==-1){
div.style.left=x+"px";
div.style.top=y+"px";
div.classList.add("profile");
}else{
div.classList.add("hypoprofile");
}
{
const pfp=this.buildpfp();
const pfprow=document.createElement("tr");
div.appendChild(pfprow);
pfprow.appendChild(pfp);
}
{
const userbody=document.createElement("tr");
userbody.classList.add("infosection");
div.appendChild(userbody);
const usernamehtml=document.createElement("h2");
usernamehtml.textContent=this.username;
userbody.appendChild(usernamehtml);
const discrimatorhtml=document.createElement("h3");
discrimatorhtml.classList.add("tag");
discrimatorhtml.textContent=this.username+"#"+this.discriminator;
userbody.appendChild(discrimatorhtml)
const pronounshtml=document.createElement("p");
pronounshtml.textContent=this.pronouns;
pronounshtml.classList.add("pronouns");
userbody.appendChild(pronounshtml)
const rule=document.createElement("hr");
userbody.appendChild(rule);
const biohtml=markdown(this.bio);
userbody.appendChild(biohtml);
}
console.log(div);
if(x!==-1){
Contextmenu.currentmenu=div;
document.body.appendChild(div)
Contextmenu.keepOnScreen(div);
}
return div;
}
profileclick(obj:HTMLElement){
obj.onclick=e=>{
this.buildprofile(e.clientX,e.clientY);
e.stopPropagation();
}
}
}
export {User};