Merge branch 'main' of https://github.com/DEVTomatoCake/JankClient into jank/channel-topic

This commit is contained in:
TomatoCake 2024-08-20 15:54:02 +02:00
commit 4b745ded3f
25 changed files with 383 additions and 94 deletions

View file

@ -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="";

View file

@ -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);

View file

@ -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");

View file

@ -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) {

View file

@ -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";

View file

@ -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();
}

View file

@ -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();
});

View file

@ -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();

View file

@ -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
});
});
}

View file

@ -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 () {

View file

@ -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;

View file

@ -6,7 +6,8 @@
"strict": false,
"esModuleInterop": true,
"outDir": "./.dist",
"removeComments": false
"removeComments": false,
"noImplicitThis":true
},
"include": [
"./webpage/*.ts"

View file

@ -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="";

View file

@ -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);

View file

@ -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")

View file

@ -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();

View file

@ -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=[];

View file

@ -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();
}

View file

@ -137,7 +137,7 @@ type userjson={
premium_type: number,
theme_colors: string,
pronouns: string,
badge_ids: string,
badge_ids: string[],
}
type memberjson= {
index?:number,

View file

@ -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",

View file

@ -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();

View file

@ -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
});
});
}

View file

@ -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()})
}

View file

@ -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;
}

View file

@ -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;