Merge branch 'main' of https://github.com/DEVTomatoCake/JankClient into jank/channel-topic
This commit is contained in:
commit
4b745ded3f
25 changed files with 383 additions and 94 deletions
|
@ -58,7 +58,7 @@ class Channel {
|
|||
this.deleteChannel();
|
||||
}, null, _ => { console.log(_); return _.isAdmin(); });
|
||||
this.contextmenu.addbutton("Edit channel", function () {
|
||||
this.editChannel(this);
|
||||
this.editChannel();
|
||||
}, null, _ => { return _.isAdmin(); });
|
||||
this.contextmenu.addbutton("Make invite", function () {
|
||||
this.createInvite();
|
||||
|
@ -189,7 +189,9 @@ class Channel {
|
|||
}.bind(this), async function (id) {
|
||||
const message = SnowFlake.getSnowFlakeFromID(id, Message).getObject();
|
||||
try {
|
||||
message.deleteDiv();
|
||||
if (message) {
|
||||
message.deleteDiv();
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
|
@ -344,9 +346,9 @@ class Channel {
|
|||
addchannel.textContent = "+";
|
||||
addchannel.classList.add("addchannel");
|
||||
caps.appendChild(addchannel);
|
||||
addchannel.onclick = function () {
|
||||
addchannel.onclick = _ => {
|
||||
this.guild.createchannels(this.createChannel.bind(this));
|
||||
}.bind(this);
|
||||
};
|
||||
this.coatDropDiv(decdiv, childrendiv);
|
||||
}
|
||||
div.appendChild(caps);
|
||||
|
@ -550,8 +552,7 @@ class Channel {
|
|||
});
|
||||
console.log(full);
|
||||
full.hide();
|
||||
}]
|
||||
]
|
||||
}]]
|
||||
]);
|
||||
full.show();
|
||||
console.log(full);
|
||||
|
@ -798,6 +799,9 @@ class Channel {
|
|||
return;
|
||||
this.infinitefocus = true;
|
||||
const messages = document.getElementById("channelw");
|
||||
for (const thing of messages.getElementsByClassName("messagecontainer")) {
|
||||
thing.remove();
|
||||
}
|
||||
const loading = document.getElementById("loadingdiv");
|
||||
const removetitle = document.getElementById("removetitle");
|
||||
//messages.innerHTML="";
|
||||
|
|
|
@ -238,7 +238,7 @@ class Dialog {
|
|||
this.background.classList.add("background");
|
||||
document.body.appendChild(this.background);
|
||||
document.body.appendChild(this.html);
|
||||
this.background.onclick = function () { this.hide(); }.bind(this);
|
||||
this.background.onclick = _ => { this.hide(); };
|
||||
}
|
||||
hide() {
|
||||
document.body.removeChild(this.background);
|
||||
|
|
|
@ -105,6 +105,7 @@ class Group extends Channel {
|
|||
this.lastmessageid ??= new SnowFlake("0", undefined);
|
||||
this.mentions = 0;
|
||||
this.setUpInfiniteScroller();
|
||||
this.position = Math.max(this.lastmessageid.getUnixTime(), this.snowflake.getUnixTime());
|
||||
}
|
||||
createguildHTML() {
|
||||
const div = document.createElement("div");
|
||||
|
|
|
@ -77,6 +77,9 @@ class Guild {
|
|||
if (json === -1) {
|
||||
return;
|
||||
}
|
||||
if (json.stickers.length) {
|
||||
console.log(json.stickers, ":3");
|
||||
}
|
||||
this.emojis = json.emojis;
|
||||
this.owner = owner;
|
||||
this.headers = this.owner.headers;
|
||||
|
@ -125,15 +128,12 @@ class Guild {
|
|||
noti
|
||||
],
|
||||
["button", "", "submit", _ => {
|
||||
fetch(this.info.api + "/users/@me/guilds/settings", {
|
||||
//
|
||||
fetch(this.info.api + `/users/@me/guilds/${this.id}/settings/`, {
|
||||
method: "PATCH",
|
||||
headers: this.headers,
|
||||
body: JSON.stringify({
|
||||
"guilds": {
|
||||
[this.id]: {
|
||||
"message_notifications": noti
|
||||
}
|
||||
}
|
||||
"message_notifications": noti
|
||||
})
|
||||
});
|
||||
this.message_notifications = noti;
|
||||
|
@ -446,8 +446,7 @@ class Guild {
|
|||
console.log(name, category);
|
||||
func(name, category);
|
||||
channelselect.hide();
|
||||
}.bind(this)]
|
||||
]);
|
||||
}.bind(this)]]);
|
||||
channelselect.show();
|
||||
}
|
||||
createcategory() {
|
||||
|
@ -458,12 +457,11 @@ class Guild {
|
|||
console.log(this);
|
||||
name = this.value;
|
||||
}],
|
||||
["button", "", "submit", function () {
|
||||
["button", "", "submit", () => {
|
||||
console.log(name, category);
|
||||
this.createChannel(name, category);
|
||||
channelselect.hide();
|
||||
}]
|
||||
]);
|
||||
}]]);
|
||||
channelselect.show();
|
||||
}
|
||||
delChannel(json) {
|
||||
|
|
|
@ -85,6 +85,7 @@ function showAccountSwitcher() {
|
|||
}
|
||||
let thisuser;
|
||||
try {
|
||||
console.log(users.users, users.currentuser);
|
||||
thisuser = new Localuser(users.users[users.currentuser]);
|
||||
thisuser.initwebsocket().then(_ => {
|
||||
thisuser.loaduser();
|
||||
|
@ -94,7 +95,8 @@ try {
|
|||
console.log("done loading");
|
||||
});
|
||||
}
|
||||
catch {
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
document.getElementById("load-desc").textContent = "Account unable to start";
|
||||
thisuser = new Localuser(-1);
|
||||
}
|
||||
|
@ -151,11 +153,13 @@ typebox.addEventListener("keydown", event => {
|
|||
});
|
||||
console.log(typebox);
|
||||
typebox.onclick = console.log;
|
||||
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]] } } }));
|
||||
/*
|
||||
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 = [];
|
||||
import { File } from "./file.js";
|
||||
|
|
|
@ -164,7 +164,7 @@ class InfiniteScroller {
|
|||
return;
|
||||
}
|
||||
const out = await Promise.allSettled([this.watchForTop(), this.watchForBottom()]);
|
||||
const changed = (out[0] || out[1]);
|
||||
const changed = (out[0].value || out[1].value);
|
||||
if (null === this.timeout && changed) {
|
||||
this.timeout = setTimeout(this.updatestuff.bind(this), 300);
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ class InfiniteScroller {
|
|||
await this.destroyFromID(thing[1]);
|
||||
}
|
||||
this.HTMLElements = [];
|
||||
clearInterval(this.timeout);
|
||||
clearTimeout(this.timeout);
|
||||
if (this.div) {
|
||||
this.div.remove();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Direct } from "./direct.js";
|
|||
import { Voice } from "./audio.js";
|
||||
import { User } from "./user.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
import { getBulkInfo, setTheme } from "./login.js";
|
||||
import { getapiurls, getBulkInfo, setTheme } from "./login.js";
|
||||
import { SnowFlake } from "./snowflake.js";
|
||||
import { Message } from "./message.js";
|
||||
import { Member } from "./member.js";
|
||||
|
@ -11,6 +11,7 @@ import { Settings } from "./settings.js";
|
|||
import { MarkDown } from "./markdown.js";
|
||||
const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]);
|
||||
class Localuser {
|
||||
badges = new Map();
|
||||
lastSequence = null;
|
||||
token;
|
||||
userinfo;
|
||||
|
@ -205,7 +206,7 @@ class Localuser {
|
|||
res();
|
||||
}
|
||||
});
|
||||
this.ws.addEventListener("close", event => {
|
||||
this.ws.addEventListener("close", async (event) => {
|
||||
this.ws = undefined;
|
||||
console.log("WebSocket closed with code " + event.code);
|
||||
this.unload();
|
||||
|
@ -221,6 +222,41 @@ class Localuser {
|
|||
this.errorBackoff++;
|
||||
this.connectionSucceed = 0;
|
||||
document.getElementById("load-desc").innerHTML = "Unable to connect to the Spacebar server, retrying in <b>" + Math.round(0.2 + (this.errorBackoff * 2.8)) + "</b> seconds...";
|
||||
switch (this.errorBackoff) { //try to recover from bad domain
|
||||
case 3:
|
||||
const newurls = await getapiurls(this.info.wellknown);
|
||||
if (newurls) {
|
||||
this.info = newurls;
|
||||
this.serverurls = newurls;
|
||||
this.userinfo.json.serverurls = this.info;
|
||||
this.userinfo.updateLocal();
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
const newurls = await getapiurls(new URL(this.info.wellknown).origin);
|
||||
if (newurls) {
|
||||
this.info = newurls;
|
||||
this.serverurls = newurls;
|
||||
this.userinfo.json.serverurls = this.info;
|
||||
this.userinfo.updateLocal();
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
const breakappart = new URL(this.info.wellknown).origin.split(".");
|
||||
const url = "https://" + breakappart[breakappart.length - 2] + "." + breakappart[breakappart.length - 1];
|
||||
const newurls = await getapiurls(url);
|
||||
if (newurls) {
|
||||
this.info = newurls;
|
||||
this.serverurls = newurls;
|
||||
this.userinfo.json.serverurls = this.info;
|
||||
this.userinfo.updateLocal();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (this.swapped)
|
||||
return;
|
||||
|
@ -618,7 +654,7 @@ class Localuser {
|
|||
}
|
||||
async typingStart(typing) {
|
||||
if (this.channelfocus.id === typing.d.channel_id) {
|
||||
const guild = SnowFlake.getSnowFlakeFromID(typing.d.guild_id, Guild).getObject();
|
||||
const guild = this.guildids.get(typing.d.guild_id);
|
||||
const memb = await Member.new(typing.d.member, guild);
|
||||
if (memb.id === this.user.id) {
|
||||
console.log("you is typing");
|
||||
|
@ -881,8 +917,7 @@ class Localuser {
|
|||
this.mfa_enabled = true;
|
||||
}
|
||||
});
|
||||
}]
|
||||
]);
|
||||
}]]);
|
||||
console.log("here :3");
|
||||
addmodel.show();
|
||||
});
|
||||
|
|
|
@ -17,6 +17,41 @@ function getBulkUsers() {
|
|||
}
|
||||
return json;
|
||||
}
|
||||
function trimswitcher() {
|
||||
const json = getBulkInfo();
|
||||
const map = new Map();
|
||||
for (const thing in json.users) {
|
||||
const user = json.users[thing];
|
||||
console.log(user, json.users);
|
||||
let wellknown = user.serverurls.wellknown;
|
||||
if (wellknown[wellknown.length - 1] !== "/") {
|
||||
wellknown += "/";
|
||||
}
|
||||
wellknown += user.username;
|
||||
if (map.has(wellknown)) {
|
||||
const otheruser = map.get(wellknown);
|
||||
if (otheruser[1].serverurls.wellknown[otheruser[1].serverurls.wellknown.length - 1] === "/") {
|
||||
delete json.users[otheruser[0]];
|
||||
map.set(wellknown, [thing, user]);
|
||||
}
|
||||
else {
|
||||
delete json.users[thing];
|
||||
}
|
||||
}
|
||||
else {
|
||||
map.set(wellknown, [thing, user]);
|
||||
}
|
||||
}
|
||||
for (const thing in json.users) {
|
||||
if (thing[thing.length - 1] === "/") {
|
||||
const user = json.users[thing];
|
||||
delete json.users[thing];
|
||||
json.users[thing.slice(0, -1)] = user;
|
||||
}
|
||||
}
|
||||
localStorage.setItem("userinfos", JSON.stringify(json));
|
||||
console.log(json);
|
||||
}
|
||||
function getBulkInfo() {
|
||||
return JSON.parse(localStorage.getItem("userinfos"));
|
||||
}
|
||||
|
@ -141,6 +176,7 @@ async function getapiurls(str) {
|
|||
gateway: info.gateway,
|
||||
cdn: info.cdn,
|
||||
wellknown: str,
|
||||
login: url.toString()
|
||||
};
|
||||
}
|
||||
catch {
|
||||
|
@ -201,7 +237,7 @@ async function login(username, password, captcha) {
|
|||
try {
|
||||
const info = JSON.parse(localStorage.getItem("instanceinfo"));
|
||||
const api = info.login + (info.login.startsWith("/") ? "/" : "");
|
||||
return await fetch(api + 'auth/login', options).then(response => response.json())
|
||||
return await fetch(api + '/auth/login', options).then(response => response.json())
|
||||
.then((response) => {
|
||||
console.log(response, response.message);
|
||||
if ("Invalid Form Body" === response.message) {
|
||||
|
@ -246,6 +282,8 @@ async function login(username, password, captcha) {
|
|||
}
|
||||
else {
|
||||
console.warn(response);
|
||||
if (!response.token)
|
||||
return;
|
||||
adduser({ serverurls: JSON.parse(localStorage.getItem("instanceinfo")), email: username, token: response.token }).username = username;
|
||||
const redir = new URLSearchParams(window.location.search).get("goback");
|
||||
if (redir) {
|
||||
|
@ -260,6 +298,8 @@ async function login(username, password, captcha) {
|
|||
}
|
||||
else {
|
||||
console.warn(response);
|
||||
if (!response.token)
|
||||
return;
|
||||
adduser({ serverurls: JSON.parse(localStorage.getItem("instanceinfo")), email: username, token: response.token }).username = username;
|
||||
const redir = new URLSearchParams(window.location.search).get("goback");
|
||||
if (redir) {
|
||||
|
@ -347,3 +387,4 @@ if (switchurl) {
|
|||
}
|
||||
}
|
||||
export { checkInstance };
|
||||
trimswitcher();
|
||||
|
|
|
@ -17,7 +17,7 @@ class Member {
|
|||
this.contextmenu.addbutton("Message user", function () {
|
||||
fetch(this.info.api + "/users/@me/channels", { method: "POST",
|
||||
body: JSON.stringify({ "recipients": [this.id] }),
|
||||
headers: this.headers
|
||||
headers: this.localuser.headers
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ class Message {
|
|||
Message.contextmenu.addbutton("Edit", function () {
|
||||
this.channel.editing = this;
|
||||
const markdown = (document.getElementById("typebox"))["markdown"];
|
||||
markdown.txt = this.content.rawString;
|
||||
markdown.txt = this.content.rawString.split('');
|
||||
markdown.boxupdate(document.getElementById("typebox"));
|
||||
}, null, _ => { return _.author.id === _.localuser.user.id; });
|
||||
Message.contextmenu.addbutton("Delete message", function () {
|
||||
|
|
|
@ -121,6 +121,32 @@ class User {
|
|||
async resolvemember(guild) {
|
||||
return await Member.resolveMember(this, guild);
|
||||
}
|
||||
async getUserProfile() {
|
||||
return (await fetch(`${this.info.api}/users/${this.id.replace("#clone", "")}/profile?with_mutual_guilds=true&with_mutual_friends=true`, {
|
||||
headers: this.localuser.headers
|
||||
})).json();
|
||||
}
|
||||
resolving = false;
|
||||
async getBadge(id) {
|
||||
console.log(id, ":3");
|
||||
if (this.localuser.badges.has(id)) {
|
||||
return this.localuser.badges.get(id);
|
||||
}
|
||||
else {
|
||||
if (this.resolving) {
|
||||
await this.resolving;
|
||||
return this.localuser.badges.get(id);
|
||||
}
|
||||
const prom = await this.getUserProfile();
|
||||
this.resolving = prom;
|
||||
const badges = prom.badges;
|
||||
this.resolving = false;
|
||||
for (const thing of badges) {
|
||||
this.localuser.badges.set(thing.id, thing);
|
||||
}
|
||||
return this.localuser.badges.get(id);
|
||||
}
|
||||
}
|
||||
buildpfp() {
|
||||
const pfp = document.createElement('img');
|
||||
pfp.src = this.getpfpsrc();
|
||||
|
@ -235,6 +261,28 @@ class User {
|
|||
this.setstatus("online");
|
||||
div.classList.add("hypoprofile", "flexttb");
|
||||
}
|
||||
const badgediv = document.createElement("div");
|
||||
badgediv.classList.add("badges");
|
||||
(async () => {
|
||||
console.log(this.badge_ids, ":3");
|
||||
if (!this.badge_ids)
|
||||
return;
|
||||
for (const id of this.badge_ids) {
|
||||
const badgejson = await this.getBadge(id);
|
||||
const badge = document.createElement(badgejson.link ? "a" : "div");
|
||||
badge.classList.add("badge");
|
||||
const img = document.createElement("img");
|
||||
img.src = badgejson.icon;
|
||||
badge.append(img);
|
||||
const span = document.createElement("span");
|
||||
span.textContent = badgejson.description;
|
||||
badge.append(span);
|
||||
if (badge instanceof HTMLAnchorElement) {
|
||||
badge.href = badgejson.link;
|
||||
}
|
||||
badgediv.append(badge);
|
||||
}
|
||||
})();
|
||||
{
|
||||
const pfp = await this.buildstatuspfp();
|
||||
div.appendChild(pfp);
|
||||
|
@ -246,6 +294,7 @@ class User {
|
|||
const usernamehtml = document.createElement("h2");
|
||||
usernamehtml.textContent = this.username;
|
||||
userbody.appendChild(usernamehtml);
|
||||
userbody.appendChild(badgediv);
|
||||
const discrimatorhtml = document.createElement("h3");
|
||||
discrimatorhtml.classList.add("tag");
|
||||
discrimatorhtml.textContent = this.username + "#" + this.discriminator;
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
"strict": false,
|
||||
"esModuleInterop": true,
|
||||
"outDir": "./.dist",
|
||||
"removeComments": false
|
||||
"removeComments": false,
|
||||
"noImplicitThis":true
|
||||
},
|
||||
"include": [
|
||||
"./webpage/*.ts"
|
||||
|
|
|
@ -52,30 +52,30 @@ class Channel{
|
|||
return this.snowflake.id;
|
||||
}
|
||||
static setupcontextmenu(){
|
||||
this.contextmenu.addbutton("Copy channel id",function(){
|
||||
this.contextmenu.addbutton("Copy channel id",function(this:Channel){
|
||||
console.log(this)
|
||||
navigator.clipboard.writeText(this.id);
|
||||
});
|
||||
|
||||
this.contextmenu.addbutton("Mark as read",function(){
|
||||
this.contextmenu.addbutton("Mark as read",function(this:Channel){
|
||||
console.log(this)
|
||||
this.readbottom();
|
||||
});
|
||||
|
||||
this.contextmenu.addbutton("Settings[temp]",function(){
|
||||
this.contextmenu.addbutton("Settings[temp]",function(this:Channel){
|
||||
this.generateSettings();
|
||||
});
|
||||
|
||||
this.contextmenu.addbutton("Delete channel",function(){
|
||||
this.contextmenu.addbutton("Delete channel",function(this:Channel){
|
||||
console.log(this)
|
||||
this.deleteChannel();
|
||||
},null,_=>{console.log(_);return _.isAdmin()});
|
||||
|
||||
this.contextmenu.addbutton("Edit channel",function(){
|
||||
this.editChannel(this);
|
||||
this.contextmenu.addbutton("Edit channel",function(this:Channel){
|
||||
this.editChannel();
|
||||
},null,_=>{return _.isAdmin()});
|
||||
|
||||
this.contextmenu.addbutton("Make invite",function(){
|
||||
this.contextmenu.addbutton("Make invite",function(this:Channel){
|
||||
this.createInvite();
|
||||
},null,(_:Channel)=>{
|
||||
return _.hasPermission("CREATE_INSTANT_INVITE")&&_.type!==4
|
||||
|
@ -203,7 +203,9 @@ class Channel{
|
|||
async function(this:Channel,id:string){
|
||||
const message=SnowFlake.getSnowFlakeFromID(id,Message).getObject();
|
||||
try{
|
||||
message.deleteDiv();
|
||||
if(message){
|
||||
message.deleteDiv();
|
||||
}
|
||||
}catch(e){console.error(e)}finally{}
|
||||
}.bind(this),
|
||||
this.readbottom.bind(this)
|
||||
|
@ -355,9 +357,9 @@ class Channel{
|
|||
addchannel.textContent="+";
|
||||
addchannel.classList.add("addchannel");
|
||||
caps.appendChild(addchannel);
|
||||
addchannel.onclick=function(){
|
||||
addchannel.onclick=_=>{
|
||||
this.guild.createchannels(this.createChannel.bind(this));
|
||||
}.bind(this);
|
||||
}
|
||||
this.coatDropDiv(decdiv,childrendiv);
|
||||
}
|
||||
div.appendChild(caps)
|
||||
|
@ -536,9 +538,9 @@ class Channel{
|
|||
const full=new Dialog(
|
||||
["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}],
|
||||
["textbox","Channel name:",this.name,function(this:HTMLInputElement){name=this.value}],
|
||||
["mdbox","Channel topic:",this.topic,function(this:HTMLTextAreaElement){topic=this.value}],
|
||||
["checkbox","NSFW Channel",this.nsfw,function(this:HTMLInputElement){nsfw=this.checked}],
|
||||
["button","","submit",()=>{
|
||||
fetch(this.info.api+"/channels/"+thisid,{
|
||||
method:"PATCH",
|
||||
|
@ -809,6 +811,9 @@ class Channel{
|
|||
if(this.infinitefocus) return;
|
||||
this.infinitefocus=true;
|
||||
const messages=document.getElementById("channelw");
|
||||
for(const thing of messages.getElementsByClassName("messagecontainer")){
|
||||
thing.remove();
|
||||
}
|
||||
const loading=document.getElementById("loadingdiv");
|
||||
const removetitle=document.getElementById("removetitle");
|
||||
//messages.innerHTML="";
|
||||
|
|
|
@ -241,7 +241,7 @@ class Dialog{
|
|||
this.background.classList.add("background");
|
||||
document.body.appendChild(this.background);
|
||||
document.body.appendChild(this.html);
|
||||
this.background.onclick = function(){this.hide();}.bind(this);
|
||||
this.background.onclick = _=>{this.hide()};
|
||||
}
|
||||
hide(){
|
||||
document.body.removeChild(this.background);
|
||||
|
|
|
@ -111,6 +111,7 @@ class Group extends Channel{
|
|||
this.lastmessageid??=new SnowFlake("0",undefined);
|
||||
this.mentions=0;
|
||||
this.setUpInfiniteScroller();
|
||||
this.position=Math.max(this.lastmessageid.getUnixTime(),this.snowflake.getUnixTime());
|
||||
}
|
||||
createguildHTML(){
|
||||
const div=document.createElement("div")
|
||||
|
|
|
@ -31,33 +31,33 @@ class Guild{
|
|||
}
|
||||
static contextmenu=new Contextmenu("guild menu");
|
||||
static setupcontextmenu(){
|
||||
Guild.contextmenu.addbutton("Copy Guild id",function(){
|
||||
Guild.contextmenu.addbutton("Copy Guild id",function(this:Guild){
|
||||
console.log(this)
|
||||
navigator.clipboard.writeText(this.id);
|
||||
});
|
||||
|
||||
Guild.contextmenu.addbutton("Mark as read",function(){
|
||||
Guild.contextmenu.addbutton("Mark as read",function(this:Guild){
|
||||
console.log(this)
|
||||
this.markAsRead();
|
||||
});
|
||||
|
||||
Guild.contextmenu.addbutton("Notifications",function(){
|
||||
Guild.contextmenu.addbutton("Notifications",function(this:Guild){
|
||||
console.log(this)
|
||||
this.setnotifcation();
|
||||
});
|
||||
|
||||
Guild.contextmenu.addbutton("Leave guild",function(){
|
||||
Guild.contextmenu.addbutton("Leave guild",function(this:Guild){
|
||||
this.confirmleave();
|
||||
},null,function(_){return _.properties.owner_id!==_.member.user.id});
|
||||
|
||||
Guild.contextmenu.addbutton("Delete guild",function(){
|
||||
Guild.contextmenu.addbutton("Delete guild",function(this:Guild){
|
||||
this.confirmDelete();
|
||||
},null,function(_){return _.properties.owner_id===_.member.user.id});
|
||||
|
||||
Guild.contextmenu.addbutton("Create invite",function(){
|
||||
Guild.contextmenu.addbutton("Create invite",function(this:Guild){
|
||||
console.log(this);
|
||||
},null,_=>true,_=>false);
|
||||
Guild.contextmenu.addbutton("Settings[temp]",function(){
|
||||
Guild.contextmenu.addbutton("Settings[temp]",function(this:Guild){
|
||||
this.generateSettings();
|
||||
});
|
||||
/* -----things left for later-----
|
||||
|
@ -86,6 +86,9 @@ class Guild{
|
|||
if(json===-1){
|
||||
return;
|
||||
}
|
||||
if(json.stickers.length){
|
||||
console.log(json.stickers,":3")
|
||||
}
|
||||
this.emojis = json.emojis
|
||||
this.owner=owner;
|
||||
this.headers=this.owner.headers;
|
||||
|
@ -136,15 +139,12 @@ class Guild{
|
|||
noti
|
||||
],
|
||||
["button","","submit",_=>{
|
||||
fetch(this.info.api+"/users/@me/guilds/settings",{
|
||||
//
|
||||
fetch(this.info.api+`/users/@me/guilds/${this.id}/settings/`,{
|
||||
method:"PATCH",
|
||||
headers:this.headers,
|
||||
body:JSON.stringify({
|
||||
"guilds":{
|
||||
[this.id]:{
|
||||
"message_notifications": noti
|
||||
}
|
||||
}
|
||||
"message_notifications": noti
|
||||
})
|
||||
})
|
||||
this.message_notifications=noti;
|
||||
|
@ -296,7 +296,7 @@ class Guild{
|
|||
["textbox",
|
||||
"Name of server:",
|
||||
"",
|
||||
function(){
|
||||
function(this:HTMLInputElement){
|
||||
confirmname=this.value;
|
||||
}
|
||||
]
|
||||
|
@ -447,7 +447,7 @@ class Guild{
|
|||
},
|
||||
1
|
||||
],
|
||||
["textbox","Name of channel","",function(){
|
||||
["textbox","Name of channel","",function(this:HTMLInputElement){
|
||||
console.log(this)
|
||||
name=this.value
|
||||
}],
|
||||
|
@ -464,11 +464,11 @@ class Guild{
|
|||
let category=4;
|
||||
const channelselect=new Dialog(
|
||||
["vdiv",
|
||||
["textbox","Name of category","",function(){
|
||||
["textbox","Name of category","",function(this:HTMLInputElement){
|
||||
console.log(this);
|
||||
name=this.value;
|
||||
}],
|
||||
["button","","submit",function(){
|
||||
["button","","submit",()=>{
|
||||
console.log(name,category)
|
||||
this.createChannel(name,category);
|
||||
channelselect.hide();
|
||||
|
|
|
@ -95,6 +95,7 @@ function showAccountSwitcher(){
|
|||
}
|
||||
let thisuser:Localuser;
|
||||
try{
|
||||
console.log(users.users,users.currentuser)
|
||||
thisuser=new Localuser(users.users[users.currentuser]);
|
||||
thisuser.initwebsocket().then(_=>{
|
||||
thisuser.loaduser();
|
||||
|
@ -103,7 +104,8 @@ try{
|
|||
document.getElementById("loading").classList.remove("loading");
|
||||
console.log("done loading")
|
||||
});
|
||||
}catch{
|
||||
}catch(e){
|
||||
console.error(e);
|
||||
document.getElementById("load-desc").textContent="Account unable to start";
|
||||
thisuser=new Localuser(-1);
|
||||
}
|
||||
|
@ -164,13 +166,13 @@ typebox.addEventListener("keydown",event=>{
|
|||
console.log(typebox)
|
||||
typebox.onclick=console.log;
|
||||
|
||||
|
||||
/*
|
||||
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:Blob[]=[];
|
||||
const imageshtml=[];
|
||||
|
|
|
@ -163,8 +163,8 @@ class InfiniteScroller{
|
|||
this.currrunning=true;
|
||||
}
|
||||
if(!this.div){this.currrunning=false;return}
|
||||
const out=await Promise.allSettled([this.watchForTop(),this.watchForBottom()])
|
||||
const changed=(out[0]||out[1]);
|
||||
const out=await Promise.allSettled([this.watchForTop(),this.watchForBottom()]) as {value:boolean}[];
|
||||
const changed=(out[0].value||out[1].value);
|
||||
if(null===this.timeout&&changed){
|
||||
this.timeout=setTimeout(this.updatestuff.bind(this),300);
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ class InfiniteScroller{
|
|||
await this.destroyFromID(thing[1]);
|
||||
}
|
||||
this.HTMLElements=[];
|
||||
clearInterval(this.timeout);
|
||||
clearTimeout(this.timeout);
|
||||
if(this.div){
|
||||
this.div.remove();
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ type userjson={
|
|||
premium_type: number,
|
||||
theme_colors: string,
|
||||
pronouns: string,
|
||||
badge_ids: string,
|
||||
badge_ids: string[],
|
||||
}
|
||||
type memberjson= {
|
||||
index?:number,
|
||||
|
|
|
@ -4,7 +4,7 @@ import {Direct} from "./direct.js";
|
|||
import {Voice} from "./audio.js";
|
||||
import {User} from "./user.js";
|
||||
import {Dialog} from "./dialog.js";
|
||||
import {getBulkInfo, setTheme, Specialuser} from "./login.js";
|
||||
import {getapiurls, getBulkInfo, setTheme, Specialuser} from "./login.js";
|
||||
import { SnowFlake } from "./snowflake.js";
|
||||
import { Message } from "./message.js";
|
||||
import { channeljson, guildjson, memberjson, presencejson, readyjson } from "./jsontypes.js";
|
||||
|
@ -15,6 +15,7 @@ import { MarkDown } from "./markdown.js";
|
|||
const wsCodesRetry=new Set([4000,4003,4005,4007,4008,4009]);
|
||||
|
||||
class Localuser{
|
||||
badges:Map<string,{id:string,description:string,icon:string,link:string}>=new Map();
|
||||
lastSequence:number|null=null;
|
||||
token:string;
|
||||
userinfo:Specialuser;
|
||||
|
@ -214,7 +215,7 @@ class Localuser{
|
|||
}
|
||||
});
|
||||
|
||||
this.ws.addEventListener("close", event => {
|
||||
this.ws.addEventListener("close",async event => {
|
||||
this.ws=undefined;
|
||||
console.log("WebSocket closed with code " + event.code);
|
||||
|
||||
|
@ -230,7 +231,43 @@ class Localuser{
|
|||
this.connectionSucceed=0;
|
||||
|
||||
document.getElementById("load-desc").innerHTML="Unable to connect to the Spacebar server, retrying in <b>" + Math.round(0.2 + (this.errorBackoff*2.8)) + "</b> seconds...";
|
||||
switch(this.errorBackoff){//try to recover from bad domain
|
||||
case 3:
|
||||
const newurls=await getapiurls(this.info.wellknown);
|
||||
if(newurls){
|
||||
this.info=newurls;
|
||||
this.serverurls=newurls;
|
||||
this.userinfo.json.serverurls=this.info;
|
||||
this.userinfo.updateLocal();
|
||||
break
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
const newurls=await getapiurls(new URL(this.info.wellknown).origin);
|
||||
if(newurls){
|
||||
this.info=newurls;
|
||||
this.serverurls=newurls;
|
||||
this.userinfo.json.serverurls=this.info;
|
||||
this.userinfo.updateLocal();
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
const breakappart=new URL(this.info.wellknown).origin.split(".");
|
||||
const url="https://"+breakappart[breakappart.length-2]+"."+breakappart[breakappart.length-1]
|
||||
const newurls=await getapiurls(url);
|
||||
if(newurls){
|
||||
this.info=newurls;
|
||||
this.serverurls=newurls;
|
||||
this.userinfo.json.serverurls=this.info;
|
||||
this.userinfo.updateLocal();
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
if(this.swapped) return;
|
||||
document.getElementById("load-desc").textContent="Retrying...";
|
||||
|
@ -497,7 +534,7 @@ class Localuser{
|
|||
["textbox",
|
||||
"Invite Link/Code",
|
||||
"",
|
||||
function(){
|
||||
function(this:HTMLInputElement){
|
||||
inviteurl=this.value;
|
||||
}
|
||||
],
|
||||
|
@ -635,7 +672,8 @@ class Localuser{
|
|||
}
|
||||
async typingStart(typing):Promise<void>{
|
||||
if(this.channelfocus.id===typing.d.channel_id){
|
||||
const guild=SnowFlake.getSnowFlakeFromID(typing.d.guild_id,Guild).getObject()
|
||||
|
||||
const guild=this.guildids.get(typing.d.guild_id);
|
||||
const memb=await Member.new(typing.d.member,guild);
|
||||
if(memb.id===this.user.id){
|
||||
console.log("you is typing")
|
||||
|
@ -878,8 +916,8 @@ class Localuser{
|
|||
["title","2FA set up"],
|
||||
["text","Copy this secret into your totp(time-based one time password) app"],
|
||||
["text",`Your secret is: ${secret} and it's 6 digits, with a 30 second token period`],
|
||||
["textbox","Account password:","",function(){password=this.value}],
|
||||
["textbox","Code:","",function(){code=this.value}],
|
||||
["textbox","Account password:","",function(this:HTMLInputElement){password=this.value}],
|
||||
["textbox","Code:","",function(this:HTMLInputElement){code=this.value}],
|
||||
["button","","Submit",()=>{
|
||||
fetch(this.info.api+"/users/@me/mfa/totp/enable/",{
|
||||
method:"POST",
|
||||
|
|
|
@ -18,6 +18,39 @@ function getBulkUsers(){
|
|||
}
|
||||
return json;
|
||||
}
|
||||
function trimswitcher(){
|
||||
const json=getBulkInfo()
|
||||
const map=new Map();
|
||||
for(const thing in json.users){
|
||||
const user=json.users[thing];
|
||||
console.log(user,json.users);
|
||||
let wellknown=user.serverurls.wellknown;
|
||||
if(wellknown[wellknown.length-1]!=="/"){
|
||||
wellknown+="/";
|
||||
}
|
||||
wellknown+=user.username;
|
||||
if(map.has(wellknown)){
|
||||
const otheruser=map.get(wellknown);
|
||||
if(otheruser[1].serverurls.wellknown[otheruser[1].serverurls.wellknown.length-1]==="/"){
|
||||
delete json.users[otheruser[0]];
|
||||
map.set(wellknown,[thing,user]);
|
||||
}else{
|
||||
delete json.users[thing];
|
||||
}
|
||||
}else{
|
||||
map.set(wellknown,[thing,user]);
|
||||
}
|
||||
}
|
||||
for(const thing in json.users){
|
||||
if(thing[thing.length-1]==="/"){
|
||||
const user=json.users[thing];
|
||||
delete json.users[thing];
|
||||
json.users[thing.slice(0, -1)]=user;
|
||||
}
|
||||
}
|
||||
localStorage.setItem("userinfos",JSON.stringify(json));
|
||||
console.log(json);
|
||||
}
|
||||
|
||||
function getBulkInfo(){
|
||||
return JSON.parse(localStorage.getItem("userinfos"));
|
||||
|
@ -121,7 +154,7 @@ function adduser(user){
|
|||
const instancein=document.getElementById("instancein") as HTMLInputElement;
|
||||
let timeout;
|
||||
let instanceinfo;
|
||||
async function getapiurls(str:string):Promise<{api:string,cdn:string,gateway:string,wellknown:string}|false>{
|
||||
async function getapiurls(str:string):Promise<{api:string,cdn:string,gateway:string,wellknown:string,login:string}|false>{
|
||||
if(str[str.length-1]!=="/"){
|
||||
str+="/"
|
||||
}
|
||||
|
@ -141,6 +174,7 @@ async function getapiurls(str:string):Promise<{api:string,cdn:string,gateway:str
|
|||
gateway: info.gateway,
|
||||
cdn: info.cdn,
|
||||
wellknown: str,
|
||||
login:url.toString()
|
||||
};
|
||||
}catch{
|
||||
return false;
|
||||
|
@ -199,7 +233,7 @@ async function login(username:string, password:string, captcha:string){
|
|||
try{
|
||||
const info=JSON.parse(localStorage.getItem("instanceinfo"));
|
||||
const api=info.login+(info.login.startsWith("/")?"/":"");
|
||||
return await fetch(api+'auth/login',options).then(response=>response.json())
|
||||
return await fetch(api+'/auth/login',options).then(response=>response.json())
|
||||
.then((response) => {
|
||||
console.log(response,response.message)
|
||||
if("Invalid Form Body"===response.message){
|
||||
|
@ -229,7 +263,7 @@ async function login(username:string, password:string, captcha:string){
|
|||
console.log(response);
|
||||
if(response.ticket){
|
||||
let onetimecode="";
|
||||
new Dialog(["vdiv",["title","2FA code:"],["textbox","","",function(){onetimecode=this.value}],["button","","Submit",function(){
|
||||
new Dialog(["vdiv",["title","2FA code:"],["textbox","","",function(this:HTMLInputElement){onetimecode=this.value}],["button","","Submit",function(){
|
||||
fetch(api+"/auth/mfa/totp",{
|
||||
method:"POST",
|
||||
headers:{
|
||||
|
@ -244,6 +278,7 @@ async function login(username:string, password:string, captcha:string){
|
|||
alert(response.message)
|
||||
}else{
|
||||
console.warn(response);
|
||||
if(!response.token) return;
|
||||
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:username,token:response.token}).username=username;
|
||||
const redir=new URLSearchParams(window.location.search).get("goback");
|
||||
if(redir){
|
||||
|
@ -256,6 +291,7 @@ async function login(username:string, password:string, captcha:string){
|
|||
}]]).show();
|
||||
}else{
|
||||
console.warn(response);
|
||||
if(!response.token) return;
|
||||
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:username,token:response.token}).username=username;
|
||||
const redir=new URLSearchParams(window.location.search).get("goback");
|
||||
if(redir){
|
||||
|
@ -343,3 +379,4 @@ if(switchurl){
|
|||
}
|
||||
}
|
||||
export {checkInstance};
|
||||
trimswitcher();
|
||||
|
|
|
@ -14,14 +14,14 @@ class Member{
|
|||
nick:string;
|
||||
static contextmenu:Contextmenu=new Contextmenu("User Menu");
|
||||
static setUpContextMenu(){
|
||||
this.contextmenu.addbutton("Copy user id",function(){
|
||||
this.contextmenu.addbutton("Copy user id",function(this:Member){
|
||||
navigator.clipboard.writeText(this.id);
|
||||
});
|
||||
this.contextmenu.addbutton("Message user",function(){
|
||||
this.contextmenu.addbutton("Message user",function(this:Member){
|
||||
fetch(this.info.api+"/users/@me/channels",
|
||||
{method:"POST",
|
||||
body:JSON.stringify({"recipients":[this.id]}),
|
||||
headers: this.headers
|
||||
headers: this.localuser.headers
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -57,13 +57,13 @@ class Message{
|
|||
this.del=new Promise(_=>{this.resolve=_})
|
||||
}
|
||||
static setupcmenu(){
|
||||
Message.contextmenu.addbutton("Copy raw text",function(){
|
||||
Message.contextmenu.addbutton("Copy raw text",function(this:Message){
|
||||
navigator.clipboard.writeText(this.content.rawString);
|
||||
});
|
||||
Message.contextmenu.addbutton("Reply",function(this:Message,div:HTMLDivElement){
|
||||
this.channel.setReplying(this);
|
||||
});
|
||||
Message.contextmenu.addbutton("Copy message id",function(){
|
||||
Message.contextmenu.addbutton("Copy message id",function(this:Message){
|
||||
navigator.clipboard.writeText(this.id);
|
||||
});
|
||||
Message.contextmenu.addsubmenu("Add reaction",function(this:Message,e){
|
||||
|
@ -72,13 +72,13 @@ class Message{
|
|||
this.reactionToggle(_);
|
||||
});
|
||||
});
|
||||
Message.contextmenu.addbutton("Edit",function(){
|
||||
Message.contextmenu.addbutton("Edit",function(this:Message){
|
||||
this.channel.editing=this;
|
||||
const markdown=(document.getElementById("typebox"))["markdown"] as MarkDown;
|
||||
markdown.txt=this.content.rawString;
|
||||
markdown.txt=this.content.rawString.split('');
|
||||
markdown.boxupdate(document.getElementById("typebox"));
|
||||
},null,_=>{return _.author.id===_.localuser.user.id});
|
||||
Message.contextmenu.addbutton("Delete message",function(){
|
||||
Message.contextmenu.addbutton("Delete message",function(this:Message){
|
||||
this.delete();
|
||||
},null,_=>{return _.canDelete()})
|
||||
}
|
||||
|
|
|
@ -1782,7 +1782,7 @@ form div{
|
|||
justify-content: center;
|
||||
padding: .5in .2in;
|
||||
gap: .1in;
|
||||
width: 5.in;
|
||||
width: 5in;
|
||||
}
|
||||
#AcceptInvite{
|
||||
padding: .1in .2in;
|
||||
|
@ -1929,3 +1929,28 @@ form div{
|
|||
#channelTopic {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.badge{
|
||||
display:flex;
|
||||
color:white;
|
||||
width:fit-content;
|
||||
img{
|
||||
width: .1in;
|
||||
height: .1in;
|
||||
}
|
||||
background: var(--profile-bg);
|
||||
padding: .04in;
|
||||
border-radius: .07in;
|
||||
font-size: .12in;
|
||||
align-items: center;
|
||||
border: solid .01in var(--black);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.badges{
|
||||
width:fit-content;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class User{
|
|||
premium_since: string;
|
||||
premium_type: number;
|
||||
theme_colors: string;
|
||||
badge_ids: string;
|
||||
badge_ids: string[];
|
||||
members: WeakMap<Guild, Member|undefined|Promise<Member|undefined>>=new WeakMap();
|
||||
private status:string;
|
||||
clone(){
|
||||
|
@ -71,7 +71,7 @@ class User{
|
|||
this.contextmenu.addbutton("Copy user id",function(this:User){
|
||||
navigator.clipboard.writeText(this.id);
|
||||
});
|
||||
this.contextmenu.addbutton("Message user",function(){
|
||||
this.contextmenu.addbutton("Message user",function(this:User){
|
||||
fetch(this.info.api+"/users/@me/channels",
|
||||
{method:"POST",
|
||||
body:JSON.stringify({"recipients":[this.id]}),
|
||||
|
@ -121,6 +121,34 @@ class User{
|
|||
async resolvemember(guild:Guild){
|
||||
return await Member.resolveMember(this,guild);
|
||||
}
|
||||
|
||||
async getUserProfile(){
|
||||
return (await fetch(`${this.info.api}/users/${this.id.replace("#clone","")}/profile?with_mutual_guilds=true&with_mutual_friends=true`,{
|
||||
headers:this.localuser.headers
|
||||
})).json()
|
||||
}
|
||||
resolving:false|Promise<any>=false;
|
||||
async getBadge(id:string){
|
||||
console.log(id,":3")
|
||||
if(this.localuser.badges.has(id)){
|
||||
return this.localuser.badges.get(id);
|
||||
}else{
|
||||
if(this.resolving)
|
||||
{
|
||||
await this.resolving;
|
||||
return this.localuser.badges.get(id);
|
||||
}
|
||||
|
||||
const prom=await this.getUserProfile();
|
||||
this.resolving=prom;
|
||||
const badges=prom.badges;
|
||||
this.resolving=false;
|
||||
for(const thing of badges){
|
||||
this.localuser.badges.set(thing.id,thing);
|
||||
}
|
||||
return this.localuser.badges.get(id);
|
||||
}
|
||||
}
|
||||
buildpfp(){
|
||||
const pfp=document.createElement('img');
|
||||
pfp.src=this.getpfpsrc();
|
||||
|
@ -236,7 +264,27 @@ class User{
|
|||
this.setstatus("online");
|
||||
div.classList.add("hypoprofile","flexttb");
|
||||
}
|
||||
|
||||
const badgediv=document.createElement("div");
|
||||
badgediv.classList.add("badges");
|
||||
(async ()=>{
|
||||
console.log(this.badge_ids,":3")
|
||||
if(!this.badge_ids) return;
|
||||
for(const id of this.badge_ids){
|
||||
const badgejson=await this.getBadge(id);
|
||||
const badge=document.createElement(badgejson.link?"a":"div");
|
||||
badge.classList.add("badge")
|
||||
const img=document.createElement("img");
|
||||
img.src=badgejson.icon;
|
||||
badge.append(img);
|
||||
const span=document.createElement("span");
|
||||
span.textContent=badgejson.description;
|
||||
badge.append(span);
|
||||
if(badge instanceof HTMLAnchorElement){
|
||||
badge.href=badgejson.link;
|
||||
}
|
||||
badgediv.append(badge);
|
||||
}
|
||||
})()
|
||||
{
|
||||
const pfp=await this.buildstatuspfp();
|
||||
div.appendChild(pfp);
|
||||
|
@ -248,7 +296,7 @@ class User{
|
|||
const usernamehtml=document.createElement("h2");
|
||||
usernamehtml.textContent=this.username;
|
||||
userbody.appendChild(usernamehtml);
|
||||
|
||||
userbody.appendChild(badgediv);
|
||||
const discrimatorhtml=document.createElement("h3");
|
||||
discrimatorhtml.classList.add("tag");
|
||||
discrimatorhtml.textContent=this.username+"#"+this.discriminator;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue