Merge branch 'main' into svg-masks
This commit is contained in:
commit
ebf4c5aa6e
60 changed files with 9653 additions and 9426 deletions
304
webpage/audio.ts
304
webpage/audio.ts
|
@ -1,146 +1,164 @@
|
|||
import {getBulkInfo} from "./login.js";
|
||||
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(
|
||||
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():string|Function{
|
||||
return this.info.wave;
|
||||
}
|
||||
get freq():number{
|
||||
return this.info.freq;
|
||||
}
|
||||
set wave(wave:string|Function){
|
||||
this.info.wave=wave;
|
||||
this.updateWave();
|
||||
}
|
||||
set freq(freq:number){
|
||||
this.info.freq=freq;
|
||||
this.updateWave();
|
||||
}
|
||||
updateWave():void{
|
||||
const func=this.waveFunction();
|
||||
for (let i = 0; i < this.buffer.length; i++) {
|
||||
this.buffer[i]=func(i/this.audioCtx.sampleRate,this.freq);
|
||||
}
|
||||
|
||||
}
|
||||
waveFunction():Function{
|
||||
if(typeof this.wave === 'function'){
|
||||
return this.wave;
|
||||
}
|
||||
switch(this.wave){
|
||||
case "sin":
|
||||
return (t:number,freq:number)=>{
|
||||
return Math.sin(t*Math.PI*2*freq);
|
||||
}
|
||||
case "triangle":
|
||||
return (t:number,freq:number)=>{
|
||||
return Math.abs((4*t*freq)%4-2)-1;
|
||||
}
|
||||
case "sawtooth":
|
||||
return (t:number,freq:number)=>{
|
||||
return ((t*freq)%1)*2-1;
|
||||
}
|
||||
case "square":
|
||||
return (t:number,freq:number)=>{
|
||||
return (t*freq)%2<1?1:-1;
|
||||
}
|
||||
case "white":
|
||||
return (_t:number,_freq:number)=>{
|
||||
return Math.random()*2-1;
|
||||
}
|
||||
case "noise":
|
||||
return (_t:number,_freq:number)=>{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return new Function();
|
||||
}
|
||||
play():void{
|
||||
if(this.playing){
|
||||
return;
|
||||
}
|
||||
this.source.connect(this.gainNode);
|
||||
this.playing=true;
|
||||
|
||||
}
|
||||
stop():void{
|
||||
if(this.playing){
|
||||
this.source.disconnect();
|
||||
this.playing=false;
|
||||
}
|
||||
}
|
||||
static noises(noise:string):void{
|
||||
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:number,freq:number)=>{
|
||||
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:string){
|
||||
let userinfos=getBulkInfo();
|
||||
userinfos.preferences.notisound=sound;
|
||||
localStorage.setItem("userinfos",JSON.stringify(userinfos));
|
||||
}
|
||||
static getNotificationSound(){
|
||||
let userinfos=getBulkInfo();
|
||||
return userinfos.preferences.notisound;
|
||||
}
|
||||
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,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():string|Function{
|
||||
return this.info.wave;
|
||||
}
|
||||
get freq():number{
|
||||
return this.info.freq;
|
||||
}
|
||||
set wave(wave:string|Function){
|
||||
this.info.wave=wave;
|
||||
this.updateWave();
|
||||
}
|
||||
set freq(freq:number){
|
||||
this.info.freq=freq;
|
||||
this.updateWave();
|
||||
}
|
||||
updateWave():void{
|
||||
const func=this.waveFunction();
|
||||
for(let i = 0; i < this.buffer.length; i++){
|
||||
this.buffer[i]=func(i/this.audioCtx.sampleRate,this.freq);
|
||||
}
|
||||
}
|
||||
waveFunction():Function{
|
||||
if(typeof this.wave === "function"){
|
||||
return this.wave;
|
||||
}
|
||||
switch(this.wave){
|
||||
case"sin":
|
||||
return(t:number,freq:number)=>{
|
||||
return Math.sin(t*Math.PI*2*freq);
|
||||
};
|
||||
case"triangle":
|
||||
return(t:number,freq:number)=>{
|
||||
return Math.abs((4*t*freq)%4-2)-1;
|
||||
};
|
||||
case"sawtooth":
|
||||
return(t:number,freq:number)=>{
|
||||
return((t*freq)%1)*2-1;
|
||||
};
|
||||
case"square":
|
||||
return(t:number,freq:number)=>{
|
||||
return(t*freq)%2<1?1:-1;
|
||||
};
|
||||
case"white":
|
||||
return(_t:number,_freq:number)=>{
|
||||
return Math.random()*2-1;
|
||||
};
|
||||
case"noise":
|
||||
return(_t:number,_freq:number)=>{
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
return new Function();
|
||||
}
|
||||
play():void{
|
||||
if(this.playing){
|
||||
return;
|
||||
}
|
||||
this.source.connect(this.gainNode);
|
||||
this.playing=true;
|
||||
}
|
||||
stop():void{
|
||||
if(this.playing){
|
||||
this.source.disconnect();
|
||||
this.playing=false;
|
||||
}
|
||||
}
|
||||
static noises(noise:string):void{
|
||||
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:number,freq:number)=>{
|
||||
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,0.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:string){
|
||||
const userinfos=getBulkInfo();
|
||||
userinfos.preferences.notisound=sound;
|
||||
localStorage.setItem("userinfos",JSON.stringify(userinfos));
|
||||
}
|
||||
static getNotificationSound(){
|
||||
const userinfos=getBulkInfo();
|
||||
return userinfos.preferences.notisound;
|
||||
}
|
||||
}
|
||||
export {Voice as Voice};
|
||||
export{Voice};
|
||||
|
|
2119
webpage/channel.ts
2119
webpage/channel.ts
File diff suppressed because it is too large
Load diff
|
@ -1,82 +1,88 @@
|
|||
class Contextmenu<x,y>{
|
||||
static currentmenu;
|
||||
name:string;
|
||||
buttons:[string,(this:x,arg:y,e:MouseEvent)=>void,string|null,(this:x,arg:y)=>boolean,(this:x,arg:y)=>boolean,string][];
|
||||
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:(this:x,arg:y,e:MouseEvent)=>void,img:null|string=null,shown:(this:x,arg:y)=>boolean=_=>true,enabled:(this:x,arg:y)=>boolean=_=>true){
|
||||
this.buttons.push([text,onclick,img,shown,enabled,"button"]);
|
||||
return {};
|
||||
}
|
||||
addsubmenu(text:string,onclick:(this:x,arg:y,e:MouseEvent)=>void,img=null,shown:(this:x,arg:y)=>boolean=_=>true,enabled:(this:x,arg:y)=>boolean=_=>true){
|
||||
this.buttons.push([text,onclick,img,shown,enabled,"submenu"])
|
||||
return {};
|
||||
}
|
||||
makemenu(x:number,y:number,addinfo:any,other:y){
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("contextmenu","flexttb");
|
||||
for(const thing of this.buttons){
|
||||
if(!thing[3].bind(addinfo)(other)){continue;}
|
||||
const intext=document.createElement("button")
|
||||
intext.disabled=!thing[4].bind(addinfo)(other);
|
||||
intext.classList.add("contextbutton")
|
||||
intext.textContent=thing[0]
|
||||
console.log(thing)
|
||||
if(thing[5]==="button"||thing[5]==="submenu"){
|
||||
intext.onclick=thing[1].bind(addinfo,other);
|
||||
}
|
||||
static currentmenu;
|
||||
name:string;
|
||||
buttons:[string,(this:x,arg:y,e:MouseEvent)=>void,string|null,(this:x,arg:y)=>boolean,(this:x,arg:y)=>boolean,string][];
|
||||
div:HTMLDivElement;
|
||||
static setup(){
|
||||
Contextmenu.currentmenu="";
|
||||
document.addEventListener("click", 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:(this:x,arg:y,e:MouseEvent)=>void,img:null|string=null,shown:(this:x,arg:y)=>boolean=_=>true,enabled:(this:x,arg:y)=>boolean=_=>true){
|
||||
this.buttons.push([text,onclick,img,shown,enabled,"button"]);
|
||||
return{};
|
||||
}
|
||||
addsubmenu(text:string,onclick:(this:x,arg:y,e:MouseEvent)=>void,img=null,shown:(this:x,arg:y)=>boolean=_=>true,enabled:(this:x,arg:y)=>boolean=_=>true){
|
||||
this.buttons.push([text,onclick,img,shown,enabled,"submenu"]);
|
||||
return{};
|
||||
}
|
||||
makemenu(x:number,y:number,addinfo:any,other:y){
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("contextmenu","flexttb");
|
||||
|
||||
div.appendChild(intext);
|
||||
}
|
||||
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;
|
||||
}
|
||||
bindContextmenu(obj:HTMLElement,addinfo:x,other:y){
|
||||
const func=(event) => {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.makemenu(event.clientX,event.clientY,addinfo,other);
|
||||
}
|
||||
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';
|
||||
}
|
||||
}
|
||||
let visibleButtons=0;
|
||||
for(const thing of this.buttons){
|
||||
if(!thing[3].bind(addinfo)(other))continue;
|
||||
visibleButtons++;
|
||||
|
||||
const intext=document.createElement("button");
|
||||
intext.disabled=!thing[4].bind(addinfo)(other);
|
||||
intext.classList.add("contextbutton");
|
||||
intext.textContent=thing[0];
|
||||
console.log(thing);
|
||||
if(thing[5]==="button"||thing[5]==="submenu"){
|
||||
intext.onclick=thing[1].bind(addinfo,other);
|
||||
}
|
||||
|
||||
div.appendChild(intext);
|
||||
}
|
||||
if(visibleButtons == 0)return;
|
||||
|
||||
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;
|
||||
}
|
||||
bindContextmenu(obj:HTMLElement,addinfo:x,other:y){
|
||||
const func=event=>{
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
this.makemenu(event.clientX,event.clientY,addinfo,other);
|
||||
};
|
||||
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}
|
||||
export{Contextmenu};
|
||||
|
|
|
@ -1,251 +1,254 @@
|
|||
|
||||
class Dialog{
|
||||
layout;
|
||||
onclose: Function;
|
||||
onopen: Function;
|
||||
html:HTMLDivElement;
|
||||
background: HTMLDivElement;
|
||||
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")){
|
||||
layout;
|
||||
onclose: Function;
|
||||
onopen: Function;
|
||||
html:HTMLDivElement;
|
||||
background: HTMLDivElement;
|
||||
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:any[]){
|
||||
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);
|
||||
|
||||
this.html.classList.add("nonimagecenter");
|
||||
}
|
||||
}
|
||||
tohtml(array:any[]){
|
||||
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.checked=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");
|
||||
|
||||
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.checked=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",()=>{
|
||||
let i=-1;
|
||||
for(const thing of fieldset.children){
|
||||
i++;
|
||||
if(i===0){
|
||||
continue;
|
||||
}
|
||||
const checkbox = thing.children[0].children[0] as HTMLInputElement;
|
||||
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");
|
||||
|
||||
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] as HTMLInputElement;
|
||||
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];
|
||||
|
||||
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");
|
||||
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);
|
||||
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);
|
||||
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 = _=>{this.hide()};
|
||||
}
|
||||
hide(){
|
||||
document.body.removeChild(this.background);
|
||||
document.body.removeChild(this.html);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 = _=>{
|
||||
this.hide();
|
||||
};
|
||||
}
|
||||
hide(){
|
||||
document.body.removeChild(this.background);
|
||||
document.body.removeChild(this.html);
|
||||
}
|
||||
}
|
||||
export {Dialog};
|
||||
export{Dialog};
|
||||
|
|
|
@ -1,61 +1,61 @@
|
|||
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";
|
||||
import { SnowFlake } from "./snowflake.js";
|
||||
import { dirrectjson, memberjson } from "./jsontypes.js";
|
||||
import { Permissions } from "./permissions.js";
|
||||
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";
|
||||
import{ SnowFlake }from"./snowflake.js";
|
||||
import{ dirrectjson, memberjson }from"./jsontypes.js";
|
||||
import{ Permissions }from"./permissions.js";
|
||||
|
||||
class Direct extends Guild{
|
||||
constructor(json:dirrectjson[],owner:Localuser){
|
||||
super(-1,owner,null);
|
||||
this.message_notifications=0;
|
||||
this.owner=owner;
|
||||
if(!this.localuser){
|
||||
console.error("Owner was not included, please fix")
|
||||
}
|
||||
this.headers=this.localuser.headers;
|
||||
this.channels=[];
|
||||
this.channelids={};
|
||||
this.snowflake=new SnowFlake("@me",this);
|
||||
this.properties={};
|
||||
this.roles=[];
|
||||
this.roleids=new Map();
|
||||
this.prevchannel=undefined;
|
||||
this.properties.name="Direct 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();
|
||||
}
|
||||
giveMember(_member:memberjson){
|
||||
console.error("not a real guild, can't give member object")
|
||||
}
|
||||
getRole(ID:string){
|
||||
return null;
|
||||
}
|
||||
hasRole(r:string){
|
||||
return false;
|
||||
}
|
||||
isAdmin(){
|
||||
return false;
|
||||
}
|
||||
unreaddms(){
|
||||
for(const thing of this.channels){
|
||||
(thing as Group).unreads();
|
||||
}
|
||||
}
|
||||
constructor(json:dirrectjson[],owner:Localuser){
|
||||
super(-1,owner,null);
|
||||
this.message_notifications=0;
|
||||
this.owner=owner;
|
||||
if(!this.localuser){
|
||||
console.error("Owner was not included, please fix");
|
||||
}
|
||||
this.headers=this.localuser.headers;
|
||||
this.channels=[];
|
||||
this.channelids={};
|
||||
this.snowflake=new SnowFlake("@me",this);
|
||||
this.properties={};
|
||||
this.roles=[];
|
||||
this.roleids=new Map();
|
||||
this.prevchannel=undefined;
|
||||
this.properties.name="Direct 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();
|
||||
}
|
||||
giveMember(_member:memberjson){
|
||||
console.error("not a real guild, can't give member object");
|
||||
}
|
||||
getRole(ID:string){
|
||||
return null;
|
||||
}
|
||||
hasRole(r:string){
|
||||
return false;
|
||||
}
|
||||
isAdmin(){
|
||||
return false;
|
||||
}
|
||||
unreaddms(){
|
||||
for(const thing of this.channels){
|
||||
(thing as Group).unreads();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const dmPermissions = new Permissions("0");
|
||||
|
@ -82,139 +82,139 @@ dmPermissions.setPermission("STREAM",1);
|
|||
dmPermissions.setPermission("USE_VAD",1);
|
||||
|
||||
class Group extends Channel{
|
||||
user:User;
|
||||
constructor(json:dirrectjson,owner:Direct){
|
||||
super(-1,owner);
|
||||
this.owner=owner;
|
||||
this.headers=this.guild.headers;
|
||||
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.snowflake=new SnowFlake(json.id,this);
|
||||
this.parent_id=null;
|
||||
this.parent=null;
|
||||
this.children=[];
|
||||
this.guild_id="@me";
|
||||
this.messageids=new Map();
|
||||
this.permission_overwrites=new Map();
|
||||
this.lastmessageid=json.last_message_id;
|
||||
this.lastmessageid??=null;
|
||||
this.mentions=0;
|
||||
this.setUpInfiniteScroller();
|
||||
if(this.lastmessageid){
|
||||
this.position=Number((BigInt(this.lastmessageid)>>22n)+1420070400000n);
|
||||
}
|
||||
this.position=-Math.max(this.position,this.snowflake.getUnixTime());
|
||||
}
|
||||
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(){
|
||||
const id=++Channel.genid;
|
||||
if(this.guild!==this.localuser.lookingguild){
|
||||
this.guild.loadGuild();
|
||||
}
|
||||
this.guild.prevchannel=this;
|
||||
this.localuser.channelfocus=this;
|
||||
const prom=this.infinite.delete();
|
||||
await this.putmessages();
|
||||
await prom;
|
||||
if(id!==Channel.genid){
|
||||
return;
|
||||
}
|
||||
this.buildmessages();
|
||||
history.pushState(null, "","/channels/"+this.guild_id+"/"+this.id);
|
||||
this.localuser.pageTitle("@"+this.name);
|
||||
(document.getElementById("channelTopic") as HTMLElement).setAttribute("hidden","");
|
||||
(document.getElementById("typebox") as HTMLDivElement).contentEditable=""+true;
|
||||
}
|
||||
messageCreate(messagep){
|
||||
const messagez=new Message(messagep.d,this);
|
||||
if(this.lastmessageid){
|
||||
this.idToNext.set(this.lastmessageid,messagez.id);
|
||||
}
|
||||
this.idToPrev.set(messagez.id,this.lastmessageid);
|
||||
this.lastmessageid=messagez.id;
|
||||
this.messageids.set(messagez.snowflake,messagez);
|
||||
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.unreads();
|
||||
this.infinite.addedBottom();
|
||||
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;
|
||||
}
|
||||
unreads(){
|
||||
const sentdms=document.getElementById("sentdms") as HTMLDivElement;//Need to change sometime
|
||||
let current:HTMLElement|null=null;
|
||||
for(const thing of sentdms.children){
|
||||
if(thing["all"]===this){
|
||||
current=thing as HTMLElement;
|
||||
}
|
||||
}
|
||||
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;
|
||||
div["noti"]=noti;
|
||||
div.append(noti)
|
||||
const buildpfp=this.user.buildpfp();
|
||||
div["all"]=this;
|
||||
buildpfp.classList.add("mentioned");
|
||||
div.append(buildpfp)
|
||||
sentdms.append(div);
|
||||
div.onclick=_=>{
|
||||
this.guild.loadGuild();
|
||||
this.getHTML();
|
||||
}
|
||||
}else if(current){
|
||||
user:User;
|
||||
constructor(json:dirrectjson,owner:Direct){
|
||||
super(-1,owner);
|
||||
this.owner=owner;
|
||||
this.headers=this.guild.headers;
|
||||
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.snowflake=new SnowFlake(json.id,this);
|
||||
this.parent_id=null;
|
||||
this.parent=null;
|
||||
this.children=[];
|
||||
this.guild_id="@me";
|
||||
this.messageids=new Map();
|
||||
this.permission_overwrites=new Map();
|
||||
this.lastmessageid=json.last_message_id;
|
||||
this.mentions=0;
|
||||
this.setUpInfiniteScroller();
|
||||
if(this.lastmessageid){
|
||||
this.position=Number((BigInt(this.lastmessageid)>>22n)+1420070400000n);
|
||||
}
|
||||
this.position=-Math.max(this.position,this.snowflake.getUnixTime());
|
||||
}
|
||||
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(){
|
||||
const id=++Channel.genid;
|
||||
if(this.guild!==this.localuser.lookingguild){
|
||||
this.guild.loadGuild();
|
||||
}
|
||||
this.guild.prevchannel=this;
|
||||
this.localuser.channelfocus=this;
|
||||
const prom=this.infinite.delete();
|
||||
await this.putmessages();
|
||||
await prom;
|
||||
if(id!==Channel.genid){
|
||||
return;
|
||||
}
|
||||
this.buildmessages();
|
||||
history.pushState(null, "","/channels/"+this.guild_id+"/"+this.id);
|
||||
this.localuser.pageTitle("@"+this.name);
|
||||
(document.getElementById("channelTopic") as HTMLElement).setAttribute("hidden","");
|
||||
(document.getElementById("typebox") as HTMLDivElement).contentEditable=""+true;
|
||||
}
|
||||
messageCreate(messagep){
|
||||
const messagez=new Message(messagep.d,this);
|
||||
if(this.lastmessageid){
|
||||
this.idToNext.set(this.lastmessageid,messagez.id);
|
||||
this.idToPrev.set(messagez.id,this.lastmessageid);
|
||||
}
|
||||
this.lastmessageid=messagez.id;
|
||||
this.messageids.set(messagez.snowflake,messagez);
|
||||
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.unreads();
|
||||
this.infinite.addedBottom();
|
||||
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;
|
||||
}
|
||||
unreads(){
|
||||
const sentdms=document.getElementById("sentdms") as HTMLDivElement;//Need to change sometime
|
||||
let current:HTMLElement|null=null;
|
||||
for(const thing of sentdms.children){
|
||||
if(thing["all"]===this){
|
||||
current=thing as HTMLElement;
|
||||
}
|
||||
}
|
||||
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;
|
||||
div["noti"]=noti;
|
||||
div.append(noti);
|
||||
const buildpfp=this.user.buildpfp();
|
||||
div["all"]=this;
|
||||
buildpfp.classList.add("mentioned");
|
||||
div.append(buildpfp);
|
||||
sentdms.append(div);
|
||||
div.onclick=_=>{
|
||||
this.guild.loadGuild();
|
||||
this.getHTML();
|
||||
};
|
||||
}else if(current){
|
||||
current.remove();
|
||||
}else{
|
||||
|
||||
current.remove();
|
||||
}else{
|
||||
|
||||
}
|
||||
}
|
||||
isAdmin(): boolean {
|
||||
return false;
|
||||
}
|
||||
hasPermission(name: string): boolean {
|
||||
return dmPermissions.hasPermission(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
isAdmin(): boolean{
|
||||
return false;
|
||||
}
|
||||
hasPermission(name: string): boolean{
|
||||
return dmPermissions.hasPermission(name);
|
||||
}
|
||||
}
|
||||
export {Direct, Group};
|
||||
export{Direct, Group};
|
||||
|
|
446
webpage/embed.ts
446
webpage/embed.ts
|
@ -1,230 +1,232 @@
|
|||
import {Dialog} from "./dialog.js";
|
||||
import {Message} from "./message.js";
|
||||
import {MarkDown} from "./markdown.js";
|
||||
import { embedjson } from "./jsontypes.js";
|
||||
import{Dialog}from"./dialog.js";
|
||||
import{Message}from"./message.js";
|
||||
import{MarkDown}from"./markdown.js";
|
||||
import{ embedjson }from"./jsontypes.js";
|
||||
|
||||
class Embed{
|
||||
type:string;
|
||||
owner:Message;
|
||||
json:embedjson;
|
||||
constructor(json:embedjson, owner:Message){
|
||||
this.type=this.getType(json);
|
||||
this.owner=owner;
|
||||
this.json=json;
|
||||
}
|
||||
getType(json:embedjson){
|
||||
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
|
||||
}
|
||||
}
|
||||
get message(){
|
||||
return this.owner;
|
||||
}
|
||||
get channel(){
|
||||
return this.message.channel;
|
||||
}
|
||||
get guild(){
|
||||
return this.channel.guild;
|
||||
}
|
||||
get localuser(){
|
||||
return this.guild.localuser;
|
||||
}
|
||||
generateRich(){
|
||||
const div=document.createElement("div");
|
||||
if(this.json.color){
|
||||
div.style.backgroundColor="#"+this.json.color.toString(16);
|
||||
}
|
||||
div.classList.add("embed-color");
|
||||
type:string;
|
||||
owner:Message;
|
||||
json:embedjson;
|
||||
constructor(json:embedjson, owner:Message){
|
||||
this.type=this.getType(json);
|
||||
this.owner=owner;
|
||||
this.json=json;
|
||||
}
|
||||
getType(json:embedjson){
|
||||
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
|
||||
}
|
||||
}
|
||||
get message(){
|
||||
return this.owner;
|
||||
}
|
||||
get channel(){
|
||||
return this.message.channel;
|
||||
}
|
||||
get guild(){
|
||||
return this.channel.guild;
|
||||
}
|
||||
get localuser(){
|
||||
return this.guild.localuser;
|
||||
}
|
||||
generateRich(){
|
||||
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);
|
||||
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.textContent=this.json.author.name as string;
|
||||
if(this.json.author.url){
|
||||
a.href=this.json.author.url
|
||||
}
|
||||
a.classList.add("username")
|
||||
authorline.append(a);
|
||||
embed.append(authorline);
|
||||
}
|
||||
if(this.json.title){
|
||||
const title=document.createElement("a");
|
||||
title.append(new MarkDown(this.json.title,this.channel).makeHTML());
|
||||
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.append(new MarkDown(this.json.description,this.channel).makeHTML());
|
||||
embed.append(p);
|
||||
}
|
||||
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.textContent=this.json.author.name as string;
|
||||
if(this.json.author.url){
|
||||
a.href=this.json.author.url;
|
||||
}
|
||||
a.classList.add("username");
|
||||
authorline.append(a);
|
||||
embed.append(authorline);
|
||||
}
|
||||
if(this.json.title){
|
||||
const title=document.createElement("a");
|
||||
title.append(new MarkDown(this.json.title,this.channel).makeHTML());
|
||||
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.append(new MarkDown(this.json.description,this.channel).makeHTML());
|
||||
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);
|
||||
const p=document.createElement("p")
|
||||
p.append(new MarkDown(thing.value,this.channel).makeHTML());
|
||||
p.classList.add("embedp");
|
||||
div.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);
|
||||
const p=document.createElement("p");
|
||||
p.append(new MarkDown(thing.value,this.channel).makeHTML());
|
||||
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 Dialog(["img",img.src,["fit"]]);
|
||||
full.show();
|
||||
}
|
||||
img.src=this.json.thumbnail.proxy_url;
|
||||
if(this.json.thumbnail.width){
|
||||
let scale=1;
|
||||
const max=96*3;
|
||||
scale=Math.max(scale,this.json.thumbnail.width/max);
|
||||
scale=Math.max(scale,this.json.thumbnail.height/max);
|
||||
this.json.thumbnail.width/=scale;
|
||||
this.json.thumbnail.height/=scale;
|
||||
}
|
||||
img.style.width=this.json.thumbnail.width+"px";
|
||||
img.style.height=this.json.thumbnail.height+"px";
|
||||
console.log(this.json,"Image fix");
|
||||
return img;
|
||||
}
|
||||
generateLink(){
|
||||
const table=document.createElement("table");
|
||||
table.classList.add("embed","linkembed");
|
||||
const trtop=document.createElement("tr");
|
||||
table.append(trtop);
|
||||
if(this.json.url&&this.json.title){
|
||||
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 Dialog(["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");
|
||||
if(this.json.description){
|
||||
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");
|
||||
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 Dialog(["img",img.src,["fit"]]);
|
||||
full.show();
|
||||
};
|
||||
img.src=this.json.thumbnail.proxy_url;
|
||||
if(this.json.thumbnail.width){
|
||||
let scale=1;
|
||||
const max=96*3;
|
||||
scale=Math.max(scale,this.json.thumbnail.width/max);
|
||||
scale=Math.max(scale,this.json.thumbnail.height/max);
|
||||
this.json.thumbnail.width/=scale;
|
||||
this.json.thumbnail.height/=scale;
|
||||
}
|
||||
img.style.width=this.json.thumbnail.width+"px";
|
||||
img.style.height=this.json.thumbnail.height+"px";
|
||||
console.log(this.json,"Image fix");
|
||||
return img;
|
||||
}
|
||||
generateLink(){
|
||||
const table=document.createElement("table");
|
||||
table.classList.add("embed","linkembed");
|
||||
const trtop=document.createElement("tr");
|
||||
table.append(trtop);
|
||||
if(this.json.url&&this.json.title){
|
||||
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 Dialog(["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");
|
||||
if(this.json.description){
|
||||
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 provider=document.createElement("p");
|
||||
provider.classList.add("provider");
|
||||
provider.textContent=this.json.provider.name;
|
||||
div.append(provider);
|
||||
}
|
||||
const a=document.createElement("a");
|
||||
if(this.json.url&&this.json.url){
|
||||
a.href=this.json.url;
|
||||
a.textContent=this.json.url;
|
||||
div.append(a);
|
||||
}
|
||||
if(this.json.description){
|
||||
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 Dialog(["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;
|
||||
}
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("embed");
|
||||
if(this.json.provider){
|
||||
const provider=document.createElement("p");
|
||||
provider.classList.add("provider");
|
||||
provider.textContent=this.json.provider.name;
|
||||
div.append(provider);
|
||||
}
|
||||
const a=document.createElement("a");
|
||||
if(this.json.url&&this.json.url){
|
||||
a.href=this.json.url;
|
||||
a.textContent=this.json.url;
|
||||
div.append(a);
|
||||
}
|
||||
if(this.json.description){
|
||||
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 Dialog(["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};
|
||||
export{Embed};
|
||||
|
|
396
webpage/emoji.ts
396
webpage/emoji.ts
|
@ -1,226 +1,226 @@
|
|||
import { Contextmenu } from "./contextmenu.js";
|
||||
import { Guild } from "./guild.js";
|
||||
import { emojijson } from "./jsontypes.js";
|
||||
import { Localuser } from "./localuser.js";
|
||||
import{ Contextmenu }from"./contextmenu.js";
|
||||
import{ Guild }from"./guild.js";
|
||||
import{ emojijson }from"./jsontypes.js";
|
||||
import{ Localuser }from"./localuser.js";
|
||||
|
||||
class Emoji{
|
||||
static emojis:{
|
||||
static emojis:{
|
||||
name:string,
|
||||
emojis:{
|
||||
name:string,
|
||||
emoji:string,
|
||||
}[]
|
||||
}[];
|
||||
name:string;
|
||||
id:string;
|
||||
animated:boolean;
|
||||
owner:Guild|Localuser;
|
||||
get guild(){
|
||||
if(this.owner instanceof Guild){
|
||||
return this.owner;
|
||||
}
|
||||
}
|
||||
get localuser(){
|
||||
if(this.owner instanceof Guild){
|
||||
return this.owner.localuser;
|
||||
}else{
|
||||
return this.owner;
|
||||
}
|
||||
}
|
||||
get info(){
|
||||
return this.owner.info;
|
||||
}
|
||||
constructor(json:{name:string,id:string,animated:boolean},owner:Guild|Localuser){
|
||||
this.name=json.name;
|
||||
this.id=json.id;
|
||||
this.animated=json.animated
|
||||
this.owner=owner;
|
||||
}
|
||||
getHTML(bigemoji:boolean=false){
|
||||
const emojiElem=document.createElement("img");
|
||||
emojiElem.classList.add("md-emoji");
|
||||
emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji");
|
||||
emojiElem.crossOrigin="anonymous";
|
||||
emojiElem.src=this.info.cdn + "/emojis/" + this.id + "." + (this.animated ? "gif" : "png") + "?size=32";
|
||||
name:string;
|
||||
id:string;
|
||||
animated:boolean;
|
||||
owner:Guild|Localuser;
|
||||
get guild(){
|
||||
if(this.owner instanceof Guild){
|
||||
return this.owner;
|
||||
}
|
||||
}
|
||||
get localuser(){
|
||||
if(this.owner instanceof Guild){
|
||||
return this.owner.localuser;
|
||||
}else{
|
||||
return this.owner;
|
||||
}
|
||||
}
|
||||
get info(){
|
||||
return this.owner.info;
|
||||
}
|
||||
constructor(json:{name:string,id:string,animated:boolean},owner:Guild|Localuser){
|
||||
this.name=json.name;
|
||||
this.id=json.id;
|
||||
this.animated=json.animated;
|
||||
this.owner=owner;
|
||||
}
|
||||
getHTML(bigemoji:boolean=false){
|
||||
const emojiElem=document.createElement("img");
|
||||
emojiElem.classList.add("md-emoji");
|
||||
emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji");
|
||||
emojiElem.crossOrigin="anonymous";
|
||||
emojiElem.src=this.info.cdn + "/emojis/" + this.id + "." + (this.animated ? "gif" : "png") + "?size=32";
|
||||
|
||||
emojiElem.alt=this.name;
|
||||
emojiElem.loading="lazy";
|
||||
return emojiElem;
|
||||
}
|
||||
static decodeEmojiList(buffer:ArrayBuffer){
|
||||
const view = new DataView(buffer, 0);
|
||||
let i=0;
|
||||
function read16(){
|
||||
const int=view.getUint16(i);
|
||||
i+=2;
|
||||
return int;
|
||||
}
|
||||
function read8(){
|
||||
const int=view.getUint8(i);
|
||||
i+=1;
|
||||
return int;
|
||||
}
|
||||
function readString8(){
|
||||
return readStringNo(read8());
|
||||
}
|
||||
function readString16(){
|
||||
return readStringNo(read16());
|
||||
}
|
||||
function readStringNo(length:number){
|
||||
const array=new Uint8Array(length);
|
||||
emojiElem.alt=this.name;
|
||||
emojiElem.loading="lazy";
|
||||
return emojiElem;
|
||||
}
|
||||
static decodeEmojiList(buffer:ArrayBuffer){
|
||||
const view = new DataView(buffer, 0);
|
||||
let i=0;
|
||||
function read16(){
|
||||
const int=view.getUint16(i);
|
||||
i+=2;
|
||||
return int;
|
||||
}
|
||||
function read8(){
|
||||
const int=view.getUint8(i);
|
||||
i+=1;
|
||||
return int;
|
||||
}
|
||||
function readString8(){
|
||||
return readStringNo(read8());
|
||||
}
|
||||
function readString16(){
|
||||
return readStringNo(read16());
|
||||
}
|
||||
function readStringNo(length:number){
|
||||
const array=new Uint8Array(length);
|
||||
|
||||
for(let i=0;i<length;i++){
|
||||
array[i]=read8();
|
||||
}
|
||||
const decoded=new TextDecoder("utf-8").decode(array.buffer);;
|
||||
for(let i=0;i<length;i++){
|
||||
array[i]=read8();
|
||||
}
|
||||
//console.log(array);
|
||||
return new TextDecoder("utf-8").decode(array.buffer);
|
||||
}
|
||||
const build:{name:string,emojis:{name:string,emoji:string}[]}[]=[];
|
||||
let cats=read16();
|
||||
|
||||
//console.log(array);
|
||||
return decoded;
|
||||
}
|
||||
const build:{name:string,emojis:{name:string,emoji:string}[]}[]=[];
|
||||
let cats=read16();
|
||||
|
||||
for(;cats!==0;cats--){
|
||||
const name=readString16();
|
||||
const emojis:{
|
||||
for(;cats!==0;cats--){
|
||||
const name=readString16();
|
||||
const emojis:{
|
||||
name:string,
|
||||
skin_tone_support:boolean,
|
||||
emoji:string
|
||||
}[]=[];
|
||||
let emojinumber=read16();
|
||||
for(;emojinumber!==0;emojinumber--){
|
||||
//console.log(emojis);
|
||||
const name=readString8();
|
||||
const len=read8();
|
||||
const skin_tone_support=len>127;
|
||||
const emoji=readStringNo(len-(+skin_tone_support*128));
|
||||
emojis.push({
|
||||
name,
|
||||
skin_tone_support,
|
||||
emoji
|
||||
})
|
||||
}
|
||||
build.push({
|
||||
name,
|
||||
emojis
|
||||
})
|
||||
}
|
||||
this.emojis=build;
|
||||
console.log(build);
|
||||
}
|
||||
static grabEmoji(){
|
||||
fetch("/emoji.bin").then(e=>{
|
||||
return e.arrayBuffer()
|
||||
}).then(e=>{
|
||||
Emoji.decodeEmojiList(e);
|
||||
})
|
||||
}
|
||||
static async emojiPicker(x:number,y:number, localuser:Localuser):Promise<Emoji|string>{
|
||||
let res:(r:Emoji|string)=>void;
|
||||
const promise:Promise<Emoji|string>=new Promise((r)=>{res=r;})
|
||||
const menu=document.createElement("div");
|
||||
menu.classList.add("flextttb", "emojiPicker")
|
||||
menu.style.top=y+"px";
|
||||
menu.style.left=x+"px";
|
||||
let emojinumber=read16();
|
||||
for(;emojinumber!==0;emojinumber--){
|
||||
//console.log(emojis);
|
||||
const name=readString8();
|
||||
const len=read8();
|
||||
const skin_tone_support=len>127;
|
||||
const emoji=readStringNo(len-(Number(skin_tone_support)*128));
|
||||
emojis.push({
|
||||
name,
|
||||
skin_tone_support,
|
||||
emoji
|
||||
});
|
||||
}
|
||||
build.push({
|
||||
name,
|
||||
emojis
|
||||
});
|
||||
}
|
||||
this.emojis=build;
|
||||
console.log(build);
|
||||
}
|
||||
static grabEmoji(){
|
||||
fetch("/emoji.bin").then(e=>{
|
||||
return e.arrayBuffer();
|
||||
}).then(e=>{
|
||||
Emoji.decodeEmojiList(e);
|
||||
});
|
||||
}
|
||||
static async emojiPicker(x:number,y:number, localuser:Localuser):Promise<Emoji|string>{
|
||||
let res:(r:Emoji|string)=>void;
|
||||
const promise:Promise<Emoji|string>=new Promise(r=>{
|
||||
res=r;
|
||||
});
|
||||
const menu=document.createElement("div");
|
||||
menu.classList.add("flextttb", "emojiPicker");
|
||||
menu.style.top=y+"px";
|
||||
menu.style.left=x+"px";
|
||||
|
||||
const title=document.createElement("h2");
|
||||
title.textContent=Emoji.emojis[0].name;
|
||||
title.classList.add("emojiTitle");
|
||||
menu.append(title);
|
||||
const selection=document.createElement("div");
|
||||
selection.classList.add("flexltr","dontshrink","emojirow");
|
||||
const body=document.createElement("div");
|
||||
body.classList.add("emojiBody");
|
||||
const title=document.createElement("h2");
|
||||
title.textContent=Emoji.emojis[0].name;
|
||||
title.classList.add("emojiTitle");
|
||||
menu.append(title);
|
||||
const selection=document.createElement("div");
|
||||
selection.classList.add("flexltr","dontshrink","emojirow");
|
||||
const body=document.createElement("div");
|
||||
body.classList.add("emojiBody");
|
||||
|
||||
let isFirst = true;
|
||||
localuser.guilds.filter(guild => guild.id != "@me" && guild.emojis.length > 0).forEach(guild => {
|
||||
const select = document.createElement("div")
|
||||
select.classList.add("emojiSelect")
|
||||
let isFirst = true;
|
||||
localuser.guilds.filter(guild=>guild.id != "@me" && guild.emojis.length > 0).forEach(guild=>{
|
||||
const select = document.createElement("div");
|
||||
select.classList.add("emojiSelect");
|
||||
|
||||
if (guild.properties.icon) {
|
||||
const img = document.createElement("img")
|
||||
img.classList.add("pfp", "servericon", "emoji-server")
|
||||
img.crossOrigin = "anonymous"
|
||||
img.src = localuser.info.cdn + "/icons/" + guild.properties.id + "/" + guild.properties.icon + ".png?size=48"
|
||||
img.alt = "Server: " + guild.properties.name
|
||||
select.appendChild(img)
|
||||
} else {
|
||||
const div = document.createElement("span")
|
||||
div.textContent = guild.properties.name.replace(/'s /g, " ").replace(/\w+/g, word => word[0]).replace(/\s/g, "")
|
||||
select.append(div)
|
||||
}
|
||||
if(guild.properties.icon){
|
||||
const img = document.createElement("img");
|
||||
img.classList.add("pfp", "servericon", "emoji-server");
|
||||
img.crossOrigin = "anonymous";
|
||||
img.src = localuser.info.cdn + "/icons/" + guild.properties.id + "/" + guild.properties.icon + ".png?size=48";
|
||||
img.alt = "Server: " + guild.properties.name;
|
||||
select.appendChild(img);
|
||||
}else{
|
||||
const div = document.createElement("span");
|
||||
div.textContent = guild.properties.name.replace(/'s /g, " ").replace(/\w+/g, word=>word[0]).replace(/\s/g, "");
|
||||
select.append(div);
|
||||
}
|
||||
|
||||
selection.append(select)
|
||||
selection.append(select);
|
||||
|
||||
const clickEvent = () => {
|
||||
title.textContent = guild.properties.name
|
||||
body.innerHTML = ""
|
||||
for (const emojit of guild.emojis) {
|
||||
const emojiElem = document.createElement("div")
|
||||
emojiElem.classList.add("emojiSelect")
|
||||
const clickEvent = ()=>{
|
||||
title.textContent = guild.properties.name;
|
||||
body.innerHTML = "";
|
||||
for(const emojit of guild.emojis){
|
||||
const emojiElem = document.createElement("div");
|
||||
emojiElem.classList.add("emojiSelect");
|
||||
|
||||
const emojiClass = new Emoji({
|
||||
id: emojit.id as string,
|
||||
name: emojit.name,
|
||||
animated: emojit.animated as boolean
|
||||
},localuser)
|
||||
emojiElem.append(emojiClass.getHTML())
|
||||
body.append(emojiElem)
|
||||
const emojiClass = new Emoji({
|
||||
id: emojit.id as string,
|
||||
name: emojit.name,
|
||||
animated: emojit.animated as boolean
|
||||
},localuser);
|
||||
emojiElem.append(emojiClass.getHTML());
|
||||
body.append(emojiElem);
|
||||
|
||||
emojiElem.addEventListener("click", () => {
|
||||
res(emojiClass)
|
||||
Contextmenu.currentmenu.remove()
|
||||
})
|
||||
}
|
||||
}
|
||||
emojiElem.addEventListener("click", ()=>{
|
||||
res(emojiClass);
|
||||
Contextmenu.currentmenu.remove();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
select.addEventListener("click", clickEvent)
|
||||
if (isFirst) {
|
||||
clickEvent()
|
||||
isFirst = false
|
||||
}
|
||||
})
|
||||
select.addEventListener("click", clickEvent);
|
||||
if(isFirst){
|
||||
clickEvent();
|
||||
isFirst = false;
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(()=>{
|
||||
if(Contextmenu.currentmenu!=""){
|
||||
Contextmenu.currentmenu.remove();
|
||||
}
|
||||
document.body.append(menu);
|
||||
Contextmenu.currentmenu=menu;
|
||||
Contextmenu.keepOnScreen(menu);
|
||||
},10)
|
||||
setTimeout(()=>{
|
||||
if(Contextmenu.currentmenu!=""){
|
||||
Contextmenu.currentmenu.remove();
|
||||
}
|
||||
document.body.append(menu);
|
||||
Contextmenu.currentmenu=menu;
|
||||
Contextmenu.keepOnScreen(menu);
|
||||
},10);
|
||||
|
||||
|
||||
let i=0;
|
||||
for(const thing of Emoji.emojis){
|
||||
const select=document.createElement("div");
|
||||
select.textContent=thing.emojis[0].emoji;
|
||||
select.classList.add("emojiSelect");
|
||||
selection.append(select);
|
||||
const clickEvent=()=>{
|
||||
title.textContent=thing.name;
|
||||
body.innerHTML="";
|
||||
for(const emojit of thing.emojis){
|
||||
const emoji=document.createElement("div");
|
||||
emoji.classList.add("emojiSelect");
|
||||
emoji.textContent=emojit.emoji;
|
||||
body.append(emoji);
|
||||
emoji.onclick=_=>{
|
||||
res(emojit.emoji);
|
||||
Contextmenu.currentmenu.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
select.onclick=clickEvent
|
||||
if(i===0){
|
||||
clickEvent();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
menu.append(selection);
|
||||
menu.append(body);
|
||||
return promise;
|
||||
}
|
||||
let i=0;
|
||||
for(const thing of Emoji.emojis){
|
||||
const select=document.createElement("div");
|
||||
select.textContent=thing.emojis[0].emoji;
|
||||
select.classList.add("emojiSelect");
|
||||
selection.append(select);
|
||||
const clickEvent=()=>{
|
||||
title.textContent=thing.name;
|
||||
body.innerHTML="";
|
||||
for(const emojit of thing.emojis){
|
||||
const emoji=document.createElement("div");
|
||||
emoji.classList.add("emojiSelect");
|
||||
emoji.textContent=emojit.emoji;
|
||||
body.append(emoji);
|
||||
emoji.onclick=_=>{
|
||||
res(emojit.emoji);
|
||||
Contextmenu.currentmenu.remove();
|
||||
};
|
||||
}
|
||||
};
|
||||
select.onclick=clickEvent;
|
||||
if(i===0){
|
||||
clickEvent();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
menu.append(selection);
|
||||
menu.append(body);
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
Emoji.grabEmoji();
|
||||
export {Emoji};
|
||||
export{Emoji};
|
||||
|
|
282
webpage/file.ts
282
webpage/file.ts
|
@ -1,145 +1,145 @@
|
|||
import { Message } from "./message.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
import { filejson } from "./jsontypes.js";
|
||||
import{ Message }from"./message.js";
|
||||
import{ Dialog }from"./dialog.js";
|
||||
import{ filejson }from"./jsontypes.js";
|
||||
|
||||
class File{
|
||||
owner:Message|null;
|
||||
id:string;
|
||||
filename:string;
|
||||
content_type:string;
|
||||
width:number|undefined;
|
||||
height:number|undefined;
|
||||
proxy_url:string|undefined;
|
||||
url:string;
|
||||
size:number;
|
||||
constructor(fileJSON:filejson,owner:Message|null){
|
||||
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.width&&this.height){
|
||||
let scale=1;
|
||||
const max=96*3;
|
||||
scale=Math.max(scale,this.width/max);
|
||||
scale=Math.max(scale,this.height/max);
|
||||
this.width/=scale;
|
||||
this.height/=scale;
|
||||
}
|
||||
if(this.content_type.startsWith('image/')){
|
||||
const div=document.createElement("div")
|
||||
const img=document.createElement("img");
|
||||
img.classList.add("messageimg");
|
||||
div.classList.add("messageimgdiv")
|
||||
img.onclick=function(){
|
||||
const full=new Dialog(["img",img.src,["fit"]]);
|
||||
full.show();
|
||||
}
|
||||
img.src=src;
|
||||
div.append(img)
|
||||
if(this.width){
|
||||
div.style.width=this.width+"px";
|
||||
div.style.height=this.height+"px";
|
||||
}
|
||||
console.log(img);
|
||||
console.log(this.width,this.height)
|
||||
return div;
|
||||
}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;
|
||||
if(this.width&&this.height){
|
||||
video.width=this.width;
|
||||
video.height=this.height;
|
||||
}
|
||||
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;
|
||||
}
|
||||
owner:Message|null;
|
||||
id:string;
|
||||
filename:string;
|
||||
content_type:string;
|
||||
width:number|undefined;
|
||||
height:number|undefined;
|
||||
proxy_url:string|undefined;
|
||||
url:string;
|
||||
size:number;
|
||||
constructor(fileJSON:filejson,owner:Message|null){
|
||||
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.width&&this.height){
|
||||
let scale=1;
|
||||
const max=96*3;
|
||||
scale=Math.max(scale,this.width/max);
|
||||
scale=Math.max(scale,this.height/max);
|
||||
this.width/=scale;
|
||||
this.height/=scale;
|
||||
}
|
||||
if(this.content_type.startsWith("image/")){
|
||||
const div=document.createElement("div");
|
||||
const img=document.createElement("img");
|
||||
img.classList.add("messageimg");
|
||||
div.classList.add("messageimgdiv");
|
||||
img.onclick=function(){
|
||||
const full=new Dialog(["img",img.src,["fit"]]);
|
||||
full.show();
|
||||
};
|
||||
img.src=src;
|
||||
div.append(img);
|
||||
if(this.width){
|
||||
div.style.width=this.width+"px";
|
||||
div.style.height=this.height+"px";
|
||||
}
|
||||
console.log(img);
|
||||
console.log(this.width,this.height);
|
||||
return div;
|
||||
}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;
|
||||
if(this.width&&this.height){
|
||||
video.width=this.width;
|
||||
video.height=this.height;
|
||||
}
|
||||
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];
|
||||
}
|
||||
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){
|
||||
const i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024));
|
||||
return Number((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + " " + ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i];
|
||||
}
|
||||
}
|
||||
export{File}
|
||||
export{File};
|
||||
|
|
1057
webpage/guild.ts
1057
webpage/guild.ts
File diff suppressed because it is too large
Load diff
|
@ -1,48 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Jank Client</title>
|
||||
<meta content="Jank Client" property="og:title" />
|
||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description" />
|
||||
<meta content="/logo.webp" property="og:image" />
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||
<link href="/style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/>
|
||||
</head>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Jank Client</title>
|
||||
<meta content="Jank Client" property="og:title">
|
||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description">
|
||||
<meta content="/logo.webp" property="og:image">
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
||||
<link href="/style.css" rel="stylesheet">
|
||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
||||
</head>
|
||||
|
||||
<body class="Dark-theme">
|
||||
<div id="titleDiv">
|
||||
<img src="/logo.svg" width="40">
|
||||
<h1 id="pageTitle">Jank Client</h1>
|
||||
<a href="https://sb-jankclient.vanillaminigames.net/invite/USgYJo?instance=https%3A%2F%2Fspacebar.chat" class="TitleButtons"><h1>Spacebar Guild</h1></a>
|
||||
<a href="https://github.com/MathMan05/JankClient" class="TitleButtons"><h1>Github</h1></a>
|
||||
</div>
|
||||
<div class="flexttb">
|
||||
<body class="Dark-theme">
|
||||
<div id="titleDiv">
|
||||
<img src="/logo.svg" width="40">
|
||||
<h1 id="pageTitle">Jank Client</h1>
|
||||
<a href="https://sb-jankclient.vanillaminigames.net/invite/USgYJo?instance=https%3A%2F%2Fspacebar.chat" class="TitleButtons"><h1>Spacebar Guild</h1></a>
|
||||
<a href="https://github.com/MathMan05/JankClient" class="TitleButtons"><h1>Github</h1></a>
|
||||
</div>
|
||||
<div class="flexttb">
|
||||
|
||||
<div class="flexttb pagehead"><h1>Welcome to Jank Client</h1></div>
|
||||
<div class="pagebox">
|
||||
<p>Jank Client is a spacebar compatible client seeking to be as good as it can be with many features including:</p>
|
||||
<ul>
|
||||
<li>Direct Messaging</li>
|
||||
<li>Reactions support</li>
|
||||
<li>Invites</li>
|
||||
<li>Account switching</li>
|
||||
<li>User settings</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pagebox">
|
||||
<h2>Spacebar compatible Instances:</h2>
|
||||
<div id="instancebox">
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagebox">
|
||||
<h2>Contribute to Jank Client</h2>
|
||||
<p>We always appreciate some help, wether that be in the form of bug reports, or code, or even just pointing out some typos.</p><br>
|
||||
<div class="flexttb pagehead"><h1>Welcome to Jank Client</h1></div>
|
||||
<div class="pagebox">
|
||||
<p>Jank Client is a spacebar compatible client seeking to be as good as it can be with many features including:</p>
|
||||
<ul>
|
||||
<li>Direct Messaging</li>
|
||||
<li>Reactions support</li>
|
||||
<li>Invites</li>
|
||||
<li>Account switching</li>
|
||||
<li>User settings</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pagebox">
|
||||
<h2>Spacebar compatible Instances:</h2>
|
||||
<div id="instancebox">
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagebox">
|
||||
<h2>Contribute to Jank Client</h2>
|
||||
<p>We always appreciate some help, wether that be in the form of bug reports, or code, or even just pointing out some typos.</p><br>
|
||||
</a><a href="https://github.com/MathMan05/JankClient" class="TitleButtons"><h1>Github</h1></a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="/home.js" type="module" ></script>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="/home.js" type="module"></script>
|
||||
</html>
|
||||
|
|
114
webpage/home.ts
114
webpage/home.ts
|
@ -1,64 +1,64 @@
|
|||
import {mobile} from "./login.js";
|
||||
import{mobile}from"./login.js";
|
||||
console.log(mobile);
|
||||
const serverbox=document.getElementById("instancebox") as HTMLDivElement;
|
||||
|
||||
fetch("/instances.json").then(_=>_.json()).then((json:{name:string,description?:string,descriptionLong?:string,image?:string,url?:string,display?:boolean,online?:boolean,
|
||||
uptime:{alltime:number,daytime:number,weektime:number},
|
||||
urls:{wellknown:string,api:string,cdn:string,gateway:string,login?:string}}[])=>{
|
||||
console.warn(json);
|
||||
for(const instance of json){
|
||||
if(instance.display===false){
|
||||
continue;
|
||||
}
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("flexltr","instance");
|
||||
if(instance.image){
|
||||
const img=document.createElement("img");
|
||||
img.src=instance.image;
|
||||
div.append(img);
|
||||
}
|
||||
const statbox=document.createElement("div");
|
||||
statbox.classList.add("flexttb");
|
||||
console.warn(json);
|
||||
for(const instance of json){
|
||||
if(instance.display===false){
|
||||
continue;
|
||||
}
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("flexltr","instance");
|
||||
if(instance.image){
|
||||
const img=document.createElement("img");
|
||||
img.src=instance.image;
|
||||
div.append(img);
|
||||
}
|
||||
const statbox=document.createElement("div");
|
||||
statbox.classList.add("flexttb");
|
||||
|
||||
{
|
||||
const textbox=document.createElement("div");
|
||||
textbox.classList.add("flexttb","instatancetextbox");
|
||||
const title=document.createElement("h2");
|
||||
title.innerText=instance.name;
|
||||
if(instance.online!==undefined){
|
||||
const status=document.createElement("span");
|
||||
status.innerText=instance.online?"Online":"Offline";
|
||||
status.classList.add("instanceStatus");
|
||||
title.append(status);
|
||||
}
|
||||
textbox.append(title);
|
||||
if(instance.description||instance.descriptionLong){
|
||||
const p=document.createElement("p");
|
||||
if(instance.descriptionLong){
|
||||
p.innerText=instance.descriptionLong;
|
||||
}else{
|
||||
p.innerText=instance.description;
|
||||
}
|
||||
textbox.append(p);
|
||||
}
|
||||
statbox.append(textbox)
|
||||
}
|
||||
if(instance.uptime){
|
||||
const stats=document.createElement("div");
|
||||
stats.classList.add("flexltr");
|
||||
const span=document.createElement("span");
|
||||
span.innerText=`Uptime: All time: ${Math.floor(instance.uptime.alltime*100)}% This week: ${Math.floor(instance.uptime.weektime*100)}% Today: ${Math.floor(instance.uptime.daytime*100)}%`
|
||||
stats.append(span);
|
||||
statbox.append(stats);
|
||||
}
|
||||
div.append(statbox);
|
||||
div.onclick=_=>{
|
||||
if(instance.online){
|
||||
window.location.href="/register.html?instance="+encodeURI(instance.name);
|
||||
}else{
|
||||
alert("Instance is offline, can't connect");
|
||||
}
|
||||
}
|
||||
serverbox.append(div);
|
||||
}
|
||||
})
|
||||
{
|
||||
const textbox=document.createElement("div");
|
||||
textbox.classList.add("flexttb","instatancetextbox");
|
||||
const title=document.createElement("h2");
|
||||
title.innerText=instance.name;
|
||||
if(instance.online!==undefined){
|
||||
const status=document.createElement("span");
|
||||
status.innerText=instance.online?"Online":"Offline";
|
||||
status.classList.add("instanceStatus");
|
||||
title.append(status);
|
||||
}
|
||||
textbox.append(title);
|
||||
if(instance.description||instance.descriptionLong){
|
||||
const p=document.createElement("p");
|
||||
if(instance.descriptionLong){
|
||||
p.innerText=instance.descriptionLong;
|
||||
}else if(instance.description){
|
||||
p.innerText=instance.description;
|
||||
}
|
||||
textbox.append(p);
|
||||
}
|
||||
statbox.append(textbox);
|
||||
}
|
||||
if(instance.uptime){
|
||||
const stats=document.createElement("div");
|
||||
stats.classList.add("flexltr");
|
||||
const span=document.createElement("span");
|
||||
span.innerText=`Uptime: All time: ${Math.floor(instance.uptime.alltime*100)}% This week: ${Math.floor(instance.uptime.weektime*100)}% Today: ${Math.floor(instance.uptime.daytime*100)}%`;
|
||||
stats.append(span);
|
||||
statbox.append(stats);
|
||||
}
|
||||
div.append(statbox);
|
||||
div.onclick=_=>{
|
||||
if(instance.online){
|
||||
window.location.href="/register.html?instance="+encodeURI(instance.name);
|
||||
}else{
|
||||
alert("Instance is offline, can't connect");
|
||||
}
|
||||
};
|
||||
serverbox.append(div);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,80 +1,80 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>Jank Client</title>
|
||||
<meta content="Jank Client" property="og:title" />
|
||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description" />
|
||||
<meta content="/logo.webp" property="og:image" />
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||
<link href="/style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>Jank Client</title>
|
||||
<meta content="Jank Client" property="og:title">
|
||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description">
|
||||
<meta content="/logo.webp" property="og:image">
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
||||
<link href="/style.css" rel="stylesheet">
|
||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
||||
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
</head>
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
</head>
|
||||
|
||||
<body class="Dark-theme">
|
||||
<script src="/index.js" type="module"></script>
|
||||
<body class="Dark-theme">
|
||||
<script src="/index.js" type="module"></script>
|
||||
|
||||
<div id="loading" class="loading">
|
||||
<div id="centerdiv">
|
||||
<img src="/logo.svg" style="width:3in;height:3in;">
|
||||
<h1>Jank Client is loading</h1>
|
||||
<h2 id="load-desc">This shouldn't take long</h2>
|
||||
<h1 id="switchaccounts">Switch Accounts</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flexltr" id="page">
|
||||
<div id="neunence">
|
||||
<div id="servers"></div>
|
||||
</div>
|
||||
<div class="flexttb channelflex">
|
||||
<div class="servertd" id="servertd">
|
||||
<h2 id="serverName">Server Name</h2>
|
||||
</div>
|
||||
<div id="channels"></div>
|
||||
<div class="flexltr" id="userdock">
|
||||
<div class="flexltr" id="userinfo">
|
||||
<img id="userpfp" class="pfp">
|
||||
<div id="loading" class="loading">
|
||||
<div id="centerdiv">
|
||||
<img src="/logo.svg" style="width:3in;height:3in;">
|
||||
<h1>Jank Client is loading</h1>
|
||||
<h2 id="load-desc">This shouldn't take long</h2>
|
||||
<h1 id="switchaccounts">Switch Accounts</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flexltr" id="page">
|
||||
<div id="neunence">
|
||||
<div id="servers"></div>
|
||||
</div>
|
||||
<div class="flexttb channelflex">
|
||||
<div class="servertd" id="servertd">
|
||||
<h2 id="serverName">Server Name</h2>
|
||||
</div>
|
||||
<div id="channels"></div>
|
||||
<div class="flexltr" id="userdock">
|
||||
<div class="flexltr" id="userinfo">
|
||||
<img id="userpfp" class="pfp">
|
||||
|
||||
<div class="userflex">
|
||||
<p id="username">USERNAME</p>
|
||||
<p id="status">STATUS</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="userflex">
|
||||
<p id="username">USERNAME</p>
|
||||
<p id="status">STATUS</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="user-actions">
|
||||
<span id="settings" class="svgtheme svg-settings"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flexttb messageflex">
|
||||
<div class="servertd channelnamediv">
|
||||
<span id="mobileback" hidden></span>
|
||||
<span id="channelname">Channel name</span>
|
||||
<span id="channelTopic" hidden>Channel topic</span>
|
||||
</div>
|
||||
<div id="channelw">
|
||||
<div id="loadingdiv">
|
||||
</div>
|
||||
</div>
|
||||
<div id="pasteimage"></div>
|
||||
<div id="replybox" class="hideReplyBox"></div>
|
||||
<div id="typediv">
|
||||
<div id="realbox">
|
||||
<div id="typebox" contentEditable="true"></div>
|
||||
</div>
|
||||
<div id="typing" class="hidden">
|
||||
<p id="typingtext">typing</p>
|
||||
<div class="loading-indicator">
|
||||
<div class="dot"></div>
|
||||
<div class="dot"></div>
|
||||
<div class="dot"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<div id="user-actions">
|
||||
<img id="settings" class="svgtheme" src="/icons/settings.svg"></img>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flexttb messageflex">
|
||||
<div class="servertd channelnamediv">
|
||||
<span id="mobileback" hidden></span>
|
||||
<span id="channelname">Channel name</span>
|
||||
<span id="channelTopic" hidden>Channel topic</span>
|
||||
</div>
|
||||
<div id="channelw">
|
||||
<div id="loadingdiv">
|
||||
</div>
|
||||
</div>
|
||||
<div id="pasteimage"></div>
|
||||
<div id="replybox" class="hideReplyBox"></div>
|
||||
<div id="typediv">
|
||||
<div id="realbox">
|
||||
<div id="typebox" contentEditable="true"></div>
|
||||
</div>
|
||||
<div id="typing" class="hidden">
|
||||
<p id="typingtext">typing</p>
|
||||
<div class="loading-indicator">
|
||||
<div class="dot"></div>
|
||||
<div class="dot"></div>
|
||||
<div class="dot"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
400
webpage/index.ts
400
webpage/index.ts
|
@ -1,183 +1,187 @@
|
|||
import { Localuser } from "./localuser.js";
|
||||
import {Contextmenu} from "./contextmenu.js";
|
||||
import {mobile, getBulkUsers,setTheme, Specialuser} from "./login.js";
|
||||
import { MarkDown } from "./markdown.js";
|
||||
import { Message } from "./message.js";
|
||||
import { File } from "./file.js";
|
||||
(async()=>{
|
||||
async function waitforload(){
|
||||
let res;
|
||||
new Promise(r=>{res=r});
|
||||
document.addEventListener("DOMContentLoaded", function(){
|
||||
res();
|
||||
});
|
||||
await res;
|
||||
}
|
||||
await waitforload();
|
||||
import{ Localuser }from"./localuser.js";
|
||||
import{Contextmenu}from"./contextmenu.js";
|
||||
import{mobile, getBulkUsers,setTheme, Specialuser}from"./login.js";
|
||||
import{ MarkDown }from"./markdown.js";
|
||||
import{ Message }from"./message.js";
|
||||
import{ File }from"./file.js";
|
||||
(async ()=>{
|
||||
async function waitforload(){
|
||||
let res;
|
||||
new Promise(r=>{
|
||||
res=r;
|
||||
});
|
||||
document.addEventListener("DOMContentLoaded", ()=>{
|
||||
res();
|
||||
});
|
||||
await res;
|
||||
}
|
||||
await waitforload();
|
||||
|
||||
|
||||
|
||||
const users=getBulkUsers();
|
||||
if(!users.currentuser){
|
||||
window.location.href = '/login.html';
|
||||
}
|
||||
const users=getBulkUsers();
|
||||
if(!users.currentuser){
|
||||
window.location.href = "/login.html";
|
||||
}
|
||||
|
||||
|
||||
function showAccountSwitcher(){
|
||||
const table=document.createElement("div");
|
||||
for(const thing of Object.values(users.users)){
|
||||
const specialuser=thing as Specialuser;
|
||||
console.log(specialuser.pfpsrc)
|
||||
function showAccountSwitcher(){
|
||||
const table=document.createElement("div");
|
||||
for(const thing of Object.values(users.users)){
|
||||
const specialuser=thing as Specialuser;
|
||||
console.log(specialuser.pfpsrc);
|
||||
|
||||
const userinfo=document.createElement("div");
|
||||
userinfo.classList.add("flexltr","switchtable");
|
||||
const pfp=document.createElement("img");
|
||||
userinfo.append(pfp);
|
||||
const userinfo=document.createElement("div");
|
||||
userinfo.classList.add("flexltr","switchtable");
|
||||
const pfp=document.createElement("img");
|
||||
userinfo.append(pfp);
|
||||
|
||||
const user=document.createElement("div");
|
||||
userinfo.append(user);
|
||||
user.append(specialuser.username);
|
||||
user.append(document.createElement("br"));
|
||||
const span=document.createElement("span");
|
||||
span.textContent=specialuser.serverurls.wellknown.replace("https://","").replace("http://","");
|
||||
user.append(span);
|
||||
user.classList.add("userinfo")
|
||||
span.classList.add("serverURL")
|
||||
const user=document.createElement("div");
|
||||
userinfo.append(user);
|
||||
user.append(specialuser.username);
|
||||
user.append(document.createElement("br"));
|
||||
const span=document.createElement("span");
|
||||
span.textContent=specialuser.serverurls.wellknown.replace("https://","").replace("http://","");
|
||||
user.append(span);
|
||||
user.classList.add("userinfo");
|
||||
span.classList.add("serverURL");
|
||||
|
||||
pfp.src=specialuser.pfpsrc;
|
||||
pfp.classList.add("pfp");
|
||||
table.append(userinfo);
|
||||
userinfo.addEventListener("click",_=>{
|
||||
thisuser.unload();
|
||||
thisuser.swapped=true;
|
||||
const loading=document.getElementById("loading") as HTMLDivElement;
|
||||
loading.classList.remove("doneloading");
|
||||
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();
|
||||
loading.classList.add("doneloading");
|
||||
loading.classList.remove("loading");
|
||||
console.log("done loading")
|
||||
|
||||
});
|
||||
userinfo.remove();
|
||||
})
|
||||
}
|
||||
{
|
||||
const td=document.createElement("div");
|
||||
td.classList.add("switchtable")
|
||||
td.append("Switch accounts ⇌");
|
||||
td.addEventListener("click",_=>{
|
||||
window.location.href="/login.html";
|
||||
})
|
||||
table.append(td);
|
||||
}
|
||||
table.classList.add("accountSwitcher");
|
||||
if(Contextmenu.currentmenu!=""){
|
||||
Contextmenu.currentmenu.remove();
|
||||
}
|
||||
Contextmenu.currentmenu=table;
|
||||
console.log(table);
|
||||
document.body.append(table);
|
||||
}
|
||||
{
|
||||
const userinfo=document.getElementById("userinfo") as HTMLDivElement;
|
||||
userinfo.addEventListener("click",_=>{
|
||||
_.stopImmediatePropagation();
|
||||
showAccountSwitcher();
|
||||
})
|
||||
const switchaccounts=document.getElementById("switchaccounts") as HTMLDivElement;
|
||||
switchaccounts.addEventListener("click",_=>{
|
||||
_.stopImmediatePropagation();
|
||||
showAccountSwitcher();
|
||||
})
|
||||
console.log("this ran")
|
||||
}
|
||||
let thisuser:Localuser;
|
||||
try{
|
||||
console.log(users.users,users.currentuser)
|
||||
thisuser=new Localuser(users.users[users.currentuser]);
|
||||
thisuser.initwebsocket().then(_=>{
|
||||
thisuser.loaduser();
|
||||
thisuser.init();
|
||||
const loading=document.getElementById("loading") as HTMLDivElement;
|
||||
loading.classList.add("doneloading");
|
||||
loading.classList.remove("loading");
|
||||
console.log("done loading")
|
||||
});
|
||||
}catch(e){
|
||||
console.error(e);
|
||||
(document.getElementById("load-desc") as HTMLSpanElement).textContent="Account unable to start";
|
||||
thisuser=new Localuser(-1);
|
||||
}
|
||||
pfp.src=specialuser.pfpsrc;
|
||||
pfp.classList.add("pfp");
|
||||
table.append(userinfo);
|
||||
userinfo.addEventListener("click",_=>{
|
||||
thisuser.unload();
|
||||
thisuser.swapped=true;
|
||||
const loading=document.getElementById("loading") as HTMLDivElement;
|
||||
loading.classList.remove("doneloading");
|
||||
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();
|
||||
loading.classList.add("doneloading");
|
||||
loading.classList.remove("loading");
|
||||
console.log("done loading");
|
||||
});
|
||||
userinfo.remove();
|
||||
});
|
||||
}
|
||||
{
|
||||
const td=document.createElement("div");
|
||||
td.classList.add("switchtable");
|
||||
td.append("Switch accounts ⇌");
|
||||
td.addEventListener("click",_=>{
|
||||
window.location.href="/login.html";
|
||||
});
|
||||
table.append(td);
|
||||
}
|
||||
table.classList.add("accountSwitcher");
|
||||
if(Contextmenu.currentmenu!=""){
|
||||
Contextmenu.currentmenu.remove();
|
||||
}
|
||||
Contextmenu.currentmenu=table;
|
||||
console.log(table);
|
||||
document.body.append(table);
|
||||
}
|
||||
{
|
||||
const userinfo=document.getElementById("userinfo") as HTMLDivElement;
|
||||
userinfo.addEventListener("click",_=>{
|
||||
_.stopImmediatePropagation();
|
||||
showAccountSwitcher();
|
||||
});
|
||||
const switchaccounts=document.getElementById("switchaccounts") as HTMLDivElement;
|
||||
switchaccounts.addEventListener("click",_=>{
|
||||
_.stopImmediatePropagation();
|
||||
showAccountSwitcher();
|
||||
});
|
||||
console.log("this ran");
|
||||
}
|
||||
let thisuser:Localuser;
|
||||
try{
|
||||
console.log(users.users,users.currentuser);
|
||||
thisuser=new Localuser(users.users[users.currentuser]);
|
||||
thisuser.initwebsocket().then(_=>{
|
||||
thisuser.loaduser();
|
||||
thisuser.init();
|
||||
const loading=document.getElementById("loading") as HTMLDivElement;
|
||||
loading.classList.add("doneloading");
|
||||
loading.classList.remove("loading");
|
||||
console.log("done loading");
|
||||
});
|
||||
}catch(e){
|
||||
console.error(e);
|
||||
(document.getElementById("load-desc") as HTMLSpanElement).textContent="Account unable to start";
|
||||
thisuser=new Localuser(-1);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
const menu=new Contextmenu("create rightclick");//Really should go into the localuser class, but that's a later thing
|
||||
menu.addbutton("Create channel",function(){
|
||||
if(thisuser.lookingguild){
|
||||
thisuser.lookingguild.createchannels();
|
||||
}
|
||||
},null,_=>{return thisuser.isAdmin()})
|
||||
{
|
||||
const menu=new Contextmenu("create rightclick");//Really should go into the localuser class, but that's a later thing
|
||||
menu.addbutton("Create channel",()=>{
|
||||
if(thisuser.lookingguild){
|
||||
thisuser.lookingguild.createchannels();
|
||||
}
|
||||
},null,_=>{
|
||||
return thisuser.isAdmin();
|
||||
});
|
||||
|
||||
menu.addbutton("Create category",function(){
|
||||
if(thisuser.lookingguild){
|
||||
thisuser.lookingguild.createcategory();
|
||||
}
|
||||
},null,_=>{return thisuser.isAdmin()})
|
||||
menu.bindContextmenu(document.getElementById("channels") as HTMLDivElement,0,0)
|
||||
}
|
||||
menu.addbutton("Create category",()=>{
|
||||
if(thisuser.lookingguild){
|
||||
thisuser.lookingguild.createcategory();
|
||||
}
|
||||
},null,_=>{
|
||||
return thisuser.isAdmin();
|
||||
});
|
||||
menu.bindContextmenu(document.getElementById("channels") as HTMLDivElement,0,0);
|
||||
}
|
||||
|
||||
const pasteimage=document.getElementById("pasteimage") as HTMLDivElement;
|
||||
let replyingto:Message|null=null;
|
||||
async function enter(event){
|
||||
const channel=thisuser.channelfocus
|
||||
if(!channel||!thisuser.channelfocus) return;
|
||||
channel.typingstart();
|
||||
if(event.key === "Enter"&&!event.shiftKey){
|
||||
event.preventDefault();
|
||||
if(channel.editing){
|
||||
channel.editing.edit(markdown.rawString);
|
||||
channel.editing=null;
|
||||
}else{
|
||||
replyingto= thisuser.channelfocus.replyingto;
|
||||
let replying=replyingto;
|
||||
if(replyingto?.div){
|
||||
replyingto.div.classList.remove("replying");
|
||||
}
|
||||
thisuser.channelfocus.replyingto=null;
|
||||
channel.sendMessage(markdown.rawString,{
|
||||
attachments:images,
|
||||
embeds:[],
|
||||
replyingto:replying
|
||||
})
|
||||
thisuser.channelfocus.makereplybox();
|
||||
}
|
||||
while(images.length!=0){
|
||||
images.pop();
|
||||
pasteimage.removeChild(imageshtml.pop() as HTMLElement);
|
||||
}
|
||||
typebox.innerHTML="";
|
||||
return;
|
||||
}
|
||||
}
|
||||
const pasteimage=document.getElementById("pasteimage") as HTMLDivElement;
|
||||
let replyingto:Message|null=null;
|
||||
async function enter(event){
|
||||
const channel=thisuser.channelfocus;
|
||||
if(!channel||!thisuser.channelfocus)return;
|
||||
channel.typingstart();
|
||||
if(event.key === "Enter"&&!event.shiftKey){
|
||||
event.preventDefault();
|
||||
if(channel.editing){
|
||||
channel.editing.edit(markdown.rawString);
|
||||
channel.editing=null;
|
||||
}else{
|
||||
replyingto= thisuser.channelfocus.replyingto;
|
||||
const replying=replyingto;
|
||||
if(replyingto?.div){
|
||||
replyingto.div.classList.remove("replying");
|
||||
}
|
||||
thisuser.channelfocus.replyingto=null;
|
||||
channel.sendMessage(markdown.rawString,{
|
||||
attachments: images,
|
||||
embeds: [],
|
||||
replyingto: replying
|
||||
});
|
||||
thisuser.channelfocus.makereplybox();
|
||||
}
|
||||
while(images.length!=0){
|
||||
images.pop();
|
||||
pasteimage.removeChild(imageshtml.pop() as HTMLElement);
|
||||
}
|
||||
typebox.innerHTML="";
|
||||
}
|
||||
}
|
||||
|
||||
const typebox=document.getElementById("typebox") as HTMLDivElement;
|
||||
const markdown=new MarkDown("",thisuser);
|
||||
markdown.giveBox(typebox);
|
||||
typebox["markdown"]=markdown;
|
||||
typebox.addEventListener("keyup",enter);
|
||||
typebox.addEventListener("keydown",event=>{
|
||||
if(event.key === "Enter"&&!event.shiftKey) event.preventDefault();
|
||||
});
|
||||
console.log(typebox)
|
||||
typebox.onclick=console.log;
|
||||
const typebox=document.getElementById("typebox") as HTMLDivElement;
|
||||
const markdown=new MarkDown("",thisuser);
|
||||
markdown.giveBox(typebox);
|
||||
typebox["markdown"]=markdown;
|
||||
typebox.addEventListener("keyup",enter);
|
||||
typebox.addEventListener("keydown",event=>{
|
||||
if(event.key === "Enter"&&!event.shiftKey) event.preventDefault();
|
||||
});
|
||||
console.log(typebox);
|
||||
typebox.onclick=console.log;
|
||||
|
||||
/*
|
||||
/*
|
||||
function getguildinfo(){
|
||||
const path=window.location.pathname.split("/");
|
||||
const channel=path[3];
|
||||
|
@ -185,41 +189,41 @@ import { File } from "./file.js";
|
|||
}
|
||||
*/
|
||||
|
||||
const images:Blob[]=[];
|
||||
const imageshtml:HTMLElement[]=[];
|
||||
const images:Blob[]=[];
|
||||
const imageshtml:HTMLElement[]=[];
|
||||
|
||||
|
||||
|
||||
document.addEventListener('paste', async (e) => {
|
||||
if(!e.clipboardData) return;
|
||||
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);
|
||||
});
|
||||
});
|
||||
document.addEventListener("paste", async e=>{
|
||||
if(!e.clipboardData)return;
|
||||
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();
|
||||
setTheme();
|
||||
|
||||
function userSettings(){
|
||||
thisuser.showusersettings();
|
||||
}
|
||||
(document.getElementById("settings") as HTMLImageElement).onclick=userSettings;
|
||||
function userSettings(){
|
||||
thisuser.showusersettings();
|
||||
}
|
||||
(document.getElementById("settings") as HTMLImageElement).onclick=userSettings;
|
||||
|
||||
if(mobile){
|
||||
(document.getElementById("channelw") as HTMLDivElement).onclick=()=>{
|
||||
((document.getElementById("channels") as HTMLDivElement).parentNode as HTMLElement).classList.add("collapse");
|
||||
(document.getElementById("servertd") as HTMLDivElement).classList.add("collapse");
|
||||
(document.getElementById("servers") as HTMLDivElement).classList.add("collapse");
|
||||
}
|
||||
(document.getElementById("mobileback") as HTMLDivElement).textContent="#";
|
||||
(document.getElementById("mobileback") as HTMLDivElement).onclick=()=>{
|
||||
((document.getElementById("channels") as HTMLDivElement).parentNode as HTMLElement).classList.remove("collapse");
|
||||
(document.getElementById("servertd") as HTMLDivElement).classList.remove("collapse");
|
||||
(document.getElementById("servers") as HTMLDivElement).classList.remove("collapse");
|
||||
}
|
||||
}
|
||||
})()
|
||||
if(mobile){
|
||||
(document.getElementById("channelw") as HTMLDivElement).onclick=()=>{
|
||||
((document.getElementById("channels") as HTMLDivElement).parentNode as HTMLElement).classList.add("collapse");
|
||||
(document.getElementById("servertd") as HTMLDivElement).classList.add("collapse");
|
||||
(document.getElementById("servers") as HTMLDivElement).classList.add("collapse");
|
||||
};
|
||||
(document.getElementById("mobileback") as HTMLDivElement).textContent="#";
|
||||
(document.getElementById("mobileback") as HTMLDivElement).onclick=()=>{
|
||||
((document.getElementById("channels") as HTMLDivElement).parentNode as HTMLElement).classList.remove("collapse");
|
||||
(document.getElementById("servertd") as HTMLDivElement).classList.remove("collapse");
|
||||
(document.getElementById("servers") as HTMLDivElement).classList.remove("collapse");
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -1,305 +1,294 @@
|
|||
class InfiniteScroller{
|
||||
readonly getIDFromOffset:(ID:string,offset:number)=>Promise<string|undefined>;
|
||||
readonly getHTMLFromID:(ID:string)=>Promise<HTMLElement>;
|
||||
readonly destroyFromID:(ID:string)=>Promise<boolean>;
|
||||
readonly reachesBottom:()=>void;
|
||||
private readonly minDist=2000;
|
||||
private readonly fillDist=3000;
|
||||
private readonly maxDist=6000;
|
||||
HTMLElements:[HTMLElement,string][]=[];
|
||||
div:HTMLDivElement|null;
|
||||
scroll:HTMLDivElement|null;
|
||||
constructor(getIDFromOffset:InfiniteScroller["getIDFromOffset"],getHTMLFromID:InfiniteScroller["getHTMLFromID"],destroyFromID:InfiniteScroller["destroyFromID"],reachesBottom:InfiniteScroller["reachesBottom"]=()=>{}){
|
||||
this.getIDFromOffset=getIDFromOffset;
|
||||
this.getHTMLFromID=getHTMLFromID;
|
||||
this.destroyFromID=destroyFromID;
|
||||
this.reachesBottom=reachesBottom;
|
||||
}
|
||||
timeout:NodeJS.Timeout|null;
|
||||
async getDiv(initialId:string,bottom=true):Promise<HTMLDivElement>{
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("messagecontainer");
|
||||
//div.classList.add("flexttb")
|
||||
const scroll=document.createElement("div");
|
||||
scroll.classList.add("flexttb","scroller")
|
||||
div.appendChild(scroll);
|
||||
this.div=div;
|
||||
//this.interval=setInterval(this.updatestuff.bind(this,true),100);
|
||||
readonly getIDFromOffset:(ID:string,offset:number)=>Promise<string|undefined>;
|
||||
readonly getHTMLFromID:(ID:string)=>Promise<HTMLElement>;
|
||||
readonly destroyFromID:(ID:string)=>Promise<boolean>;
|
||||
readonly reachesBottom:()=>void;
|
||||
private readonly minDist=2000;
|
||||
private readonly fillDist=3000;
|
||||
private readonly maxDist=6000;
|
||||
HTMLElements:[HTMLElement,string][]=[];
|
||||
div:HTMLDivElement|null;
|
||||
scroll:HTMLDivElement|null;
|
||||
constructor(getIDFromOffset:InfiniteScroller["getIDFromOffset"],getHTMLFromID:InfiniteScroller["getHTMLFromID"],destroyFromID:InfiniteScroller["destroyFromID"],reachesBottom:InfiniteScroller["reachesBottom"]=()=>{}){
|
||||
this.getIDFromOffset=getIDFromOffset;
|
||||
this.getHTMLFromID=getHTMLFromID;
|
||||
this.destroyFromID=destroyFromID;
|
||||
this.reachesBottom=reachesBottom;
|
||||
}
|
||||
timeout:NodeJS.Timeout|null;
|
||||
async getDiv(initialId:string,bottom=true):Promise<HTMLDivElement>{
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("messagecontainer");
|
||||
//div.classList.add("flexttb")
|
||||
const scroll=document.createElement("div");
|
||||
scroll.classList.add("flexttb","scroller");
|
||||
div.appendChild(scroll);
|
||||
this.div=div;
|
||||
//this.interval=setInterval(this.updatestuff.bind(this,true),100);
|
||||
|
||||
this.scroll=scroll;
|
||||
this.div.addEventListener("scroll",_=>{
|
||||
if(this.scroll) this.scrollTop=this.scroll.scrollTop;
|
||||
this.watchForChange()
|
||||
});
|
||||
this.scroll.addEventListener("scroll",_=>{
|
||||
if(null===this.timeout){
|
||||
this.timeout=setTimeout(this.updatestuff.bind(this),300);
|
||||
}
|
||||
this.scroll=scroll;
|
||||
this.div.addEventListener("scroll",_=>{
|
||||
if(this.scroll)this.scrollTop=this.scroll.scrollTop;
|
||||
this.watchForChange();
|
||||
});
|
||||
this.scroll.addEventListener("scroll",_=>{
|
||||
if(this.timeout===null){
|
||||
this.timeout=setTimeout(this.updatestuff.bind(this),300);
|
||||
}
|
||||
|
||||
this.watchForChange()
|
||||
});
|
||||
{
|
||||
let oldheight=0;
|
||||
new ResizeObserver(_=>{
|
||||
this.updatestuff();
|
||||
const change=oldheight-div.offsetHeight;
|
||||
if(change>0&&this.scroll){
|
||||
this.scroll.scrollTop+=change;
|
||||
}
|
||||
oldheight=div.offsetHeight;
|
||||
this.watchForChange();
|
||||
}).observe(div);
|
||||
}
|
||||
new ResizeObserver(this.watchForChange.bind(this)).observe(scroll);
|
||||
this.watchForChange();
|
||||
});
|
||||
{
|
||||
let oldheight=0;
|
||||
new ResizeObserver(_=>{
|
||||
this.updatestuff();
|
||||
const change=oldheight-div.offsetHeight;
|
||||
if(change>0&&this.scroll){
|
||||
this.scroll.scrollTop+=change;
|
||||
}
|
||||
oldheight=div.offsetHeight;
|
||||
this.watchForChange();
|
||||
}).observe(div);
|
||||
}
|
||||
new ResizeObserver(this.watchForChange.bind(this)).observe(scroll);
|
||||
|
||||
await this.firstElement(initialId)
|
||||
this.updatestuff();
|
||||
await this.watchForChange().then(_=>{
|
||||
this.updatestuff();
|
||||
})
|
||||
return div;
|
||||
}
|
||||
scrollBottom:number;
|
||||
scrollTop:number;
|
||||
needsupdate=true;
|
||||
averageheight:number=60;
|
||||
async updatestuff(){
|
||||
this.timeout=null;
|
||||
if(!this.scroll) return;
|
||||
this.scrollBottom = this.scroll.scrollHeight - this.scroll.scrollTop - this.scroll.clientHeight;
|
||||
this.averageheight=this.scroll.scrollHeight/this.HTMLElements.length;
|
||||
if(this.averageheight<10){
|
||||
this.averageheight=60;
|
||||
}
|
||||
this.scrollTop=this.scroll.scrollTop;
|
||||
if(!this.scrollBottom){
|
||||
if(!await this.watchForChange()){
|
||||
this.reachesBottom();
|
||||
}
|
||||
}
|
||||
if(!this.scrollTop){
|
||||
await this.watchForChange()
|
||||
}
|
||||
this.needsupdate=false;
|
||||
//this.watchForChange();
|
||||
}
|
||||
async firstElement(id:string){
|
||||
if(!this.scroll) return;
|
||||
const html=await this.getHTMLFromID(id);
|
||||
this.scroll.appendChild(html);
|
||||
this.HTMLElements.push([html,id]);
|
||||
}
|
||||
currrunning:boolean=false;
|
||||
async addedBottom(){
|
||||
this.updatestuff();
|
||||
const func=this.snapBottom();
|
||||
await this.watchForChange();
|
||||
func();
|
||||
}
|
||||
snapBottom(){
|
||||
const scrollBottom=this.scrollBottom;
|
||||
return ()=>{
|
||||
if(this.scroll&&scrollBottom<30){
|
||||
this.scroll.scrollTop=this.scroll.scrollHeight+20;
|
||||
}
|
||||
}
|
||||
}
|
||||
private async watchForTop(already=false,fragement=new DocumentFragment()):Promise<boolean>{
|
||||
if(!this.scroll) return false;
|
||||
try{
|
||||
let again=false;
|
||||
if(this.scrollTop<(already?this.fillDist:this.minDist)){
|
||||
let nextid:string|undefined;
|
||||
const firstelm=this.HTMLElements.at(0);
|
||||
if(firstelm){
|
||||
const previd=firstelm[1];
|
||||
nextid=await this.getIDFromOffset(previd,1);
|
||||
}
|
||||
await this.firstElement(initialId);
|
||||
this.updatestuff();
|
||||
await this.watchForChange().then(_=>{
|
||||
this.updatestuff();
|
||||
});
|
||||
return div;
|
||||
}
|
||||
scrollBottom:number;
|
||||
scrollTop:number;
|
||||
needsupdate=true;
|
||||
averageheight:number=60;
|
||||
async updatestuff(){
|
||||
this.timeout=null;
|
||||
if(!this.scroll)return;
|
||||
this.scrollBottom = this.scroll.scrollHeight - this.scroll.scrollTop - this.scroll.clientHeight;
|
||||
this.averageheight=this.scroll.scrollHeight/this.HTMLElements.length;
|
||||
if(this.averageheight<10){
|
||||
this.averageheight=60;
|
||||
}
|
||||
this.scrollTop=this.scroll.scrollTop;
|
||||
if(!this.scrollBottom && !await this.watchForChange()){
|
||||
this.reachesBottom();
|
||||
}
|
||||
if(!this.scrollTop){
|
||||
await this.watchForChange();
|
||||
}
|
||||
this.needsupdate=false;
|
||||
//this.watchForChange();
|
||||
}
|
||||
async firstElement(id:string){
|
||||
if(!this.scroll)return;
|
||||
const html=await this.getHTMLFromID(id);
|
||||
this.scroll.appendChild(html);
|
||||
this.HTMLElements.push([html,id]);
|
||||
}
|
||||
currrunning:boolean=false;
|
||||
async addedBottom(){
|
||||
this.updatestuff();
|
||||
const func=this.snapBottom();
|
||||
await this.watchForChange();
|
||||
func();
|
||||
}
|
||||
snapBottom(){
|
||||
const scrollBottom=this.scrollBottom;
|
||||
return()=>{
|
||||
if(this.scroll&&scrollBottom<30){
|
||||
this.scroll.scrollTop=this.scroll.scrollHeight+20;
|
||||
}
|
||||
};
|
||||
}
|
||||
private async watchForTop(already=false,fragement=new DocumentFragment()):Promise<boolean>{
|
||||
if(!this.scroll)return false;
|
||||
try{
|
||||
let again=false;
|
||||
if(this.scrollTop<(already?this.fillDist:this.minDist)){
|
||||
let nextid:string|undefined;
|
||||
const firstelm=this.HTMLElements.at(0);
|
||||
if(firstelm){
|
||||
const previd=firstelm[1];
|
||||
nextid=await this.getIDFromOffset(previd,1);
|
||||
}
|
||||
|
||||
|
||||
if(!nextid){
|
||||
if(!nextid){
|
||||
|
||||
}else{
|
||||
const html=await this.getHTMLFromID(nextid);
|
||||
if(!html){
|
||||
this.destroyFromID(nextid);
|
||||
return false;
|
||||
}
|
||||
again=true;
|
||||
fragement.prepend(html);
|
||||
this.HTMLElements.unshift([html,nextid]);
|
||||
this.scrollTop+=this.averageheight;
|
||||
};
|
||||
}
|
||||
if(this.scrollTop>this.maxDist){
|
||||
}else{
|
||||
const html=await this.getHTMLFromID(nextid);
|
||||
if(!html){
|
||||
this.destroyFromID(nextid);
|
||||
return false;
|
||||
}
|
||||
again=true;
|
||||
fragement.prepend(html);
|
||||
this.HTMLElements.unshift([html,nextid]);
|
||||
this.scrollTop+=this.averageheight;
|
||||
}
|
||||
}
|
||||
if(this.scrollTop>this.maxDist){
|
||||
const html=this.HTMLElements.shift();
|
||||
if(html){
|
||||
again=true;
|
||||
await this.destroyFromID(html[1]);
|
||||
this.scrollTop-=this.averageheight;
|
||||
}
|
||||
}
|
||||
if(again){
|
||||
await this.watchForTop(true,fragement);
|
||||
}
|
||||
return again;
|
||||
}finally{
|
||||
if(!already){
|
||||
if(this.scroll.scrollTop===0){
|
||||
this.scrollTop=1;
|
||||
this.scroll.scrollTop=10;
|
||||
}
|
||||
this.scroll.prepend(fragement,fragement);
|
||||
}
|
||||
}
|
||||
}
|
||||
async watchForBottom(already=false,fragement=new DocumentFragment()):Promise<boolean>{
|
||||
if(!this.scroll)return false;
|
||||
try{
|
||||
let again=false;
|
||||
const scrollBottom = this.scrollBottom;
|
||||
if(scrollBottom<(already?this.fillDist:this.minDist)){
|
||||
let nextid:string|undefined;
|
||||
const lastelm=this.HTMLElements.at(-1);
|
||||
if(lastelm){
|
||||
const previd=lastelm[1];
|
||||
nextid=await this.getIDFromOffset(previd,-1);
|
||||
}
|
||||
if(!nextid){
|
||||
}else{
|
||||
again=true;
|
||||
const html=await this.getHTMLFromID(nextid);
|
||||
fragement.appendChild(html);
|
||||
this.HTMLElements.push([html,nextid]);
|
||||
this.scrollBottom+=this.averageheight;
|
||||
}
|
||||
}
|
||||
if(scrollBottom>this.maxDist){
|
||||
const html=this.HTMLElements.pop();
|
||||
if(html){
|
||||
await this.destroyFromID(html[1]);
|
||||
this.scrollBottom-=this.averageheight;
|
||||
again=true;
|
||||
}
|
||||
}
|
||||
if(again){
|
||||
await this.watchForBottom(true,fragement);
|
||||
}
|
||||
return again;
|
||||
}finally{
|
||||
if(!already){
|
||||
this.scroll.append(fragement);
|
||||
if(this.scrollBottom<30){
|
||||
this.scroll.scrollTop=this.scroll.scrollHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
watchtime:boolean=false;
|
||||
changePromise:Promise<boolean>|undefined;
|
||||
async watchForChange():Promise<boolean>{
|
||||
if(this.currrunning){
|
||||
this.watchtime=true;
|
||||
if(this.changePromise){
|
||||
return await this.changePromise;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
this.watchtime=false;
|
||||
this.currrunning=true;
|
||||
}
|
||||
this.changePromise=new Promise<boolean>(async res=>{
|
||||
try{
|
||||
try{
|
||||
if(!this.div){
|
||||
res(false);return false;
|
||||
}
|
||||
const out=await Promise.allSettled([this.watchForTop(),this.watchForBottom()]) as {value:boolean}[];
|
||||
const changed=(out[0].value||out[1].value);
|
||||
if(this.timeout===null&&changed){
|
||||
this.timeout=setTimeout(this.updatestuff.bind(this),300);
|
||||
}
|
||||
if(!this.currrunning){
|
||||
console.error("something really bad happened");
|
||||
}
|
||||
|
||||
|
||||
const html=this.HTMLElements.shift();
|
||||
if(html){
|
||||
again=true;
|
||||
await this.destroyFromID(html[1]);
|
||||
this.scrollTop-=this.averageheight;
|
||||
}
|
||||
}
|
||||
if(again){
|
||||
await this.watchForTop(true,fragement);
|
||||
}
|
||||
return again;
|
||||
}finally{
|
||||
if(!already){
|
||||
if(this.scroll.scrollTop===0){
|
||||
this.scrollTop=1;
|
||||
this.scroll.scrollTop=10;
|
||||
}
|
||||
this.scroll.prepend(fragement,fragement);
|
||||
}
|
||||
}
|
||||
}
|
||||
async watchForBottom(already=false,fragement=new DocumentFragment()):Promise<boolean>{
|
||||
if(!this.scroll) return false;
|
||||
try{
|
||||
let again=false;
|
||||
const scrollBottom = this.scrollBottom;
|
||||
if(scrollBottom<(already?this.fillDist:this.minDist)){
|
||||
|
||||
let nextid:string|undefined;
|
||||
const lastelm=this.HTMLElements.at(-1);
|
||||
if(lastelm){
|
||||
const previd=lastelm[1];
|
||||
nextid=await this.getIDFromOffset(previd,-1);
|
||||
}
|
||||
if(!nextid){
|
||||
}else{
|
||||
again=true;
|
||||
const html=await this.getHTMLFromID(nextid);
|
||||
fragement.appendChild(html);
|
||||
this.HTMLElements.push([html,nextid]);
|
||||
this.scrollBottom+=this.averageheight;
|
||||
};
|
||||
}
|
||||
if(scrollBottom>this.maxDist){
|
||||
|
||||
|
||||
const html=this.HTMLElements.pop();
|
||||
if(html){
|
||||
await this.destroyFromID(html[1]);
|
||||
this.scrollBottom-=this.averageheight;
|
||||
again=true;
|
||||
}
|
||||
}
|
||||
if(again){
|
||||
await this.watchForBottom(true,fragement);
|
||||
}
|
||||
return again;
|
||||
}finally{
|
||||
if(!already){
|
||||
this.scroll.append(fragement);
|
||||
if(this.scrollBottom<30){
|
||||
this.scroll.scrollTop=this.scroll.scrollHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
watchtime:boolean=false;
|
||||
changePromise:Promise<boolean>|undefined;
|
||||
async watchForChange():Promise<boolean>{
|
||||
if(this.currrunning){
|
||||
this.watchtime=true;
|
||||
if(this.changePromise){
|
||||
return await this.changePromise;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
this.watchtime=false;
|
||||
this.currrunning=true;
|
||||
|
||||
}
|
||||
this.changePromise=new Promise<boolean>(async res=>{
|
||||
try{
|
||||
|
||||
try{
|
||||
if(!this.div){res(false);return false}
|
||||
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);
|
||||
}
|
||||
if(!this.currrunning){console.error("something really bad happened")}
|
||||
|
||||
res(!!changed);
|
||||
return !!changed;
|
||||
|
||||
}catch(e){
|
||||
console.error(e);
|
||||
}
|
||||
res(false);
|
||||
return false;
|
||||
}catch(e){
|
||||
throw e;
|
||||
}finally{
|
||||
|
||||
|
||||
setTimeout(_=>{
|
||||
this.changePromise=undefined;
|
||||
this.currrunning=false;
|
||||
if(this.watchtime){
|
||||
this.watchForChange();
|
||||
}
|
||||
},300)
|
||||
|
||||
}
|
||||
})
|
||||
return await this.changePromise;
|
||||
}
|
||||
async focus(id:string,flash=true){
|
||||
|
||||
let element:HTMLElement|undefined;
|
||||
for(const thing of this.HTMLElements){
|
||||
if(thing[1]===id){
|
||||
element=thing[0];
|
||||
}
|
||||
}
|
||||
console.log(id,element,this.HTMLElements.length,":3");
|
||||
if(element){
|
||||
|
||||
if(flash){
|
||||
element.scrollIntoView({
|
||||
behavior:"smooth",
|
||||
block:"center"
|
||||
});
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
element.classList.remove("jumped");
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
element.classList.add("jumped");
|
||||
}else{
|
||||
element.scrollIntoView();
|
||||
}
|
||||
}else{
|
||||
for(const thing of this.HTMLElements){
|
||||
await this.destroyFromID(thing[1]);
|
||||
}
|
||||
this.HTMLElements=[];
|
||||
await this.firstElement(id);
|
||||
this.updatestuff();
|
||||
await this.watchForChange();
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
await this.focus(id,true);
|
||||
}
|
||||
}
|
||||
async delete():Promise<void>{
|
||||
for(const thing of this.HTMLElements){
|
||||
await this.destroyFromID(thing[1]);
|
||||
}
|
||||
this.HTMLElements=[];
|
||||
if(this.timeout){
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
if(this.div){
|
||||
this.div.remove();
|
||||
}
|
||||
this.scroll=null;
|
||||
this.div=null;
|
||||
}
|
||||
res(Boolean(changed));
|
||||
return Boolean(changed);
|
||||
}catch(e){
|
||||
console.error(e);
|
||||
}
|
||||
res(false);
|
||||
return false;
|
||||
}catch(e){
|
||||
throw e;
|
||||
}finally{
|
||||
setTimeout(_=>{
|
||||
this.changePromise=undefined;
|
||||
this.currrunning=false;
|
||||
if(this.watchtime){
|
||||
this.watchForChange();
|
||||
}
|
||||
},300);
|
||||
}
|
||||
});
|
||||
return await this.changePromise;
|
||||
}
|
||||
async focus(id:string,flash=true){
|
||||
let element:HTMLElement|undefined;
|
||||
for(const thing of this.HTMLElements){
|
||||
if(thing[1]===id){
|
||||
element=thing[0];
|
||||
}
|
||||
}
|
||||
console.log(id,element,this.HTMLElements.length,":3");
|
||||
if(element){
|
||||
if(flash){
|
||||
element.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "center"
|
||||
});
|
||||
await new Promise(resolve=>setTimeout(resolve, 1000));
|
||||
element.classList.remove("jumped");
|
||||
await new Promise(resolve=>setTimeout(resolve, 100));
|
||||
element.classList.add("jumped");
|
||||
}else{
|
||||
element.scrollIntoView();
|
||||
}
|
||||
}else{
|
||||
for(const thing of this.HTMLElements){
|
||||
await this.destroyFromID(thing[1]);
|
||||
}
|
||||
this.HTMLElements=[];
|
||||
await this.firstElement(id);
|
||||
this.updatestuff();
|
||||
await this.watchForChange();
|
||||
await new Promise(resolve=>setTimeout(resolve, 100));
|
||||
await this.focus(id,true);
|
||||
}
|
||||
}
|
||||
async delete():Promise<void>{
|
||||
for(const thing of this.HTMLElements){
|
||||
await this.destroyFromID(thing[1]);
|
||||
}
|
||||
this.HTMLElements=[];
|
||||
if(this.timeout){
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
if(this.div){
|
||||
this.div.remove();
|
||||
}
|
||||
this.scroll=null;
|
||||
this.div=null;
|
||||
}
|
||||
}
|
||||
export {InfiniteScroller};
|
||||
export{InfiniteScroller};
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
<body class="Dark-theme">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Jank Client</title>
|
||||
<meta content="Invite" property="og:title" />
|
||||
<meta content="You shouldn't see this, but this is an invite URL" property="og:description" />
|
||||
<meta content="/logo.webp" property="og:image" />
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||
<link href="/style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/>
|
||||
</head>
|
||||
<div>
|
||||
<div id="invitebody">
|
||||
<div id="inviteimg"></div>
|
||||
<h1 id="invitename">Server Name</h1>
|
||||
<p id="invitedescription">Someone invited you to Server Name</p>
|
||||
<button id="AcceptInvite">Accept Invite</button>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/invite.js"></script>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Jank Client</title>
|
||||
<meta content="Invite" property="og:title">
|
||||
<meta content="You shouldn't see this, but this is an invite URL" property="og:description">
|
||||
<meta content="/logo.webp" property="og:image">
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
||||
<link href="/style.css" rel="stylesheet">
|
||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
||||
</head>
|
||||
<div>
|
||||
<div id="invitebody">
|
||||
<div id="inviteimg"></div>
|
||||
<h1 id="invitename">Server Name</h1>
|
||||
<p id="invitedescription">Someone invited you to Server Name</p>
|
||||
<button id="AcceptInvite">Accept Invite</button>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/invite.js"></script>
|
||||
</body>
|
||||
|
|
|
@ -1,120 +1,118 @@
|
|||
import {getBulkUsers, Specialuser, getapiurls} from "./login.js";
|
||||
(async()=>{
|
||||
const users=getBulkUsers();
|
||||
const well=new URLSearchParams(window.location.search).get("instance");
|
||||
const joinable:Specialuser[]=[];
|
||||
for(const thing in users.users){
|
||||
const user:Specialuser = users.users[thing]
|
||||
if(user.serverurls.wellknown.includes(well)){
|
||||
joinable.push(user);
|
||||
}
|
||||
console.log(users.users[thing]);
|
||||
}
|
||||
let urls:{api:string,cdn:string};
|
||||
if(!joinable.length){
|
||||
const out=await getapiurls(well);
|
||||
if(out){
|
||||
urls=out;
|
||||
for(const thing in users.users){
|
||||
const user:Specialuser = users.users[thing]
|
||||
if(user.serverurls.api.includes(out.api)){
|
||||
joinable.push(user);
|
||||
}
|
||||
console.log(users.users[thing]);
|
||||
}
|
||||
}else{
|
||||
throw Error("someone needs to handle the case where the servers don't exist")
|
||||
}
|
||||
|
||||
}else{
|
||||
urls=joinable[0].serverurls;
|
||||
}
|
||||
if(!joinable.length){
|
||||
document.getElementById("AcceptInvite").textContent="Create an account to accept the invite"
|
||||
}
|
||||
const code=window.location.pathname.split("/")[2];
|
||||
let guildinfo;
|
||||
fetch(`${urls.api}/invites/${code}`,{
|
||||
method:"GET"
|
||||
}).then(_=>_.json()).then(json=>{
|
||||
const guildjson=json.guild;
|
||||
guildinfo=guildjson;
|
||||
document.getElementById("invitename").textContent=guildjson.name;
|
||||
document.getElementById("invitedescription").textContent=
|
||||
import{getBulkUsers, Specialuser, getapiurls}from"./login.js";
|
||||
(async ()=>{
|
||||
const users=getBulkUsers();
|
||||
const well=new URLSearchParams(window.location.search).get("instance");
|
||||
const joinable:Specialuser[]=[];
|
||||
for(const thing in users.users){
|
||||
const user:Specialuser = users.users[thing];
|
||||
if(user.serverurls.wellknown.includes(well)){
|
||||
joinable.push(user);
|
||||
}
|
||||
console.log(users.users[thing]);
|
||||
}
|
||||
let urls:{api:string,cdn:string};
|
||||
if(!joinable.length&&well){
|
||||
const out=await getapiurls(well);
|
||||
if(out){
|
||||
urls=out;
|
||||
for(const thing in users.users){
|
||||
const user:Specialuser = users.users[thing];
|
||||
if(user.serverurls.api.includes(out.api)){
|
||||
joinable.push(user);
|
||||
}
|
||||
console.log(users.users[thing]);
|
||||
}
|
||||
}else{
|
||||
throw new Error("someone needs to handle the case where the servers don't exist");
|
||||
}
|
||||
}else{
|
||||
urls=joinable[0].serverurls;
|
||||
}
|
||||
if(!joinable.length){
|
||||
document.getElementById("AcceptInvite").textContent="Create an account to accept the invite";
|
||||
}
|
||||
const code=window.location.pathname.split("/")[2];
|
||||
let guildinfo;
|
||||
fetch(`${urls.api}/invites/${code}`,{
|
||||
method: "GET"
|
||||
}).then(_=>_.json()).then(json=>{
|
||||
const guildjson=json.guild;
|
||||
guildinfo=guildjson;
|
||||
document.getElementById("invitename").textContent=guildjson.name;
|
||||
document.getElementById("invitedescription").textContent=
|
||||
`${json.inviter.username} invited you to join ${guildjson.name}`;
|
||||
if(guildjson.icon){
|
||||
const img=document.createElement("img");
|
||||
img.src=`${urls.cdn}/icons/${guildjson.id}/${guildjson.icon}.png`;
|
||||
img.classList.add("inviteGuild");
|
||||
document.getElementById("inviteimg").append(img);
|
||||
}else{
|
||||
const txt=guildjson.name.replace(/'s /g, " ").replace(/\w+/g, word => word[0]).replace(/\s/g, "");
|
||||
const div=document.createElement("div");
|
||||
div.textContent=txt;
|
||||
div.classList.add("inviteGuild");
|
||||
document.getElementById("inviteimg").append(div);
|
||||
}
|
||||
if(guildjson.icon){
|
||||
const img=document.createElement("img");
|
||||
img.src=`${urls.cdn}/icons/${guildjson.id}/${guildjson.icon}.png`;
|
||||
img.classList.add("inviteGuild");
|
||||
document.getElementById("inviteimg").append(img);
|
||||
}else{
|
||||
const txt=guildjson.name.replace(/'s /g, " ").replace(/\w+/g, word=>word[0]).replace(/\s/g, "");
|
||||
const div=document.createElement("div");
|
||||
div.textContent=txt;
|
||||
div.classList.add("inviteGuild");
|
||||
document.getElementById("inviteimg").append(div);
|
||||
}
|
||||
});
|
||||
function showAccounts(){
|
||||
const table=document.createElement("dialog");
|
||||
for(const thing of Object.values(joinable)){
|
||||
const specialuser=thing as Specialuser;
|
||||
console.log(specialuser.pfpsrc);
|
||||
|
||||
})
|
||||
function showAccounts(){
|
||||
const table=document.createElement("dialog");
|
||||
for(const thing of Object.values(joinable)){
|
||||
const specialuser=thing as Specialuser;
|
||||
console.log(specialuser.pfpsrc)
|
||||
const userinfo=document.createElement("div");
|
||||
userinfo.classList.add("flexltr","switchtable");
|
||||
const pfp=document.createElement("img");
|
||||
userinfo.append(pfp);
|
||||
|
||||
const userinfo=document.createElement("div");
|
||||
userinfo.classList.add("flexltr","switchtable");
|
||||
const pfp=document.createElement("img");
|
||||
userinfo.append(pfp);
|
||||
const user=document.createElement("div");
|
||||
userinfo.append(user);
|
||||
user.append(specialuser.username);
|
||||
user.append(document.createElement("br"));
|
||||
const span=document.createElement("span");
|
||||
span.textContent=specialuser.serverurls.wellknown.replace("https://","").replace("http://","");
|
||||
user.append(span);
|
||||
user.classList.add("userinfo");
|
||||
span.classList.add("serverURL");
|
||||
|
||||
const user=document.createElement("div");
|
||||
userinfo.append(user);
|
||||
user.append(specialuser.username);
|
||||
user.append(document.createElement("br"));
|
||||
const span=document.createElement("span");
|
||||
span.textContent=specialuser.serverurls.wellknown.replace("https://","").replace("http://","");
|
||||
user.append(span);
|
||||
user.classList.add("userinfo")
|
||||
span.classList.add("serverURL")
|
||||
|
||||
pfp.src=specialuser.pfpsrc;
|
||||
pfp.classList.add("pfp");
|
||||
table.append(userinfo);
|
||||
userinfo.addEventListener("click",_=>{
|
||||
console.log(thing);
|
||||
fetch(`${urls.api}/invites/${code}`,{
|
||||
method:"POST",
|
||||
headers:{
|
||||
Authorization:thing.token
|
||||
}
|
||||
}).then(_=>{
|
||||
users["currentuser"]=specialuser.uid;
|
||||
localStorage.setItem("userinfos",JSON.stringify(users));
|
||||
window.location.href="/channels/"+guildinfo.id;
|
||||
})
|
||||
})
|
||||
}
|
||||
{
|
||||
const td=document.createElement("div");
|
||||
td.classList.add("switchtable")
|
||||
td.append("Login or create an account ⇌");
|
||||
td.addEventListener("click",_=>{
|
||||
const l=new URLSearchParams("?")
|
||||
l.set("goback",window.location.href);
|
||||
l.set("instance",well);
|
||||
window.location.href="/login?"+l.toString();
|
||||
})
|
||||
if(!joinable.length){
|
||||
const l=new URLSearchParams("?")
|
||||
l.set("goback",window.location.href);
|
||||
l.set("instance",well);
|
||||
window.location.href="/login?"+l.toString();
|
||||
}
|
||||
table.append(td);
|
||||
}
|
||||
table.classList.add("accountSwitcher");
|
||||
console.log(table);
|
||||
document.body.append(table);
|
||||
}
|
||||
document.getElementById("AcceptInvite").addEventListener("click",showAccounts);
|
||||
pfp.src=specialuser.pfpsrc;
|
||||
pfp.classList.add("pfp");
|
||||
table.append(userinfo);
|
||||
userinfo.addEventListener("click",_=>{
|
||||
console.log(thing);
|
||||
fetch(`${urls.api}/invites/${code}`,{
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: thing.token
|
||||
}
|
||||
}).then(_=>{
|
||||
users.currentuser=specialuser.uid;
|
||||
localStorage.setItem("userinfos",JSON.stringify(users));
|
||||
window.location.href="/channels/"+guildinfo.id;
|
||||
});
|
||||
});
|
||||
}
|
||||
{
|
||||
const td=document.createElement("div");
|
||||
td.classList.add("switchtable");
|
||||
td.append("Login or create an account ⇌");
|
||||
td.addEventListener("click",_=>{
|
||||
const l=new URLSearchParams("?");
|
||||
l.set("goback",window.location.href);
|
||||
l.set("instance",well);
|
||||
window.location.href="/login?"+l.toString();
|
||||
});
|
||||
if(!joinable.length){
|
||||
const l=new URLSearchParams("?");
|
||||
l.set("goback",window.location.href);
|
||||
l.set("instance",well);
|
||||
window.location.href="/login?"+l.toString();
|
||||
}
|
||||
table.append(td);
|
||||
}
|
||||
table.classList.add("accountSwitcher");
|
||||
console.log(table);
|
||||
document.body.append(table);
|
||||
}
|
||||
document.getElementById("AcceptInvite").addEventListener("click",showAccounts);
|
||||
})();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
type readyjson={
|
||||
op:number;
|
||||
t:string;
|
||||
op:0;
|
||||
t:"READY";
|
||||
s:number;
|
||||
d:{
|
||||
v:number;
|
||||
|
@ -341,4 +341,59 @@ type presencejson={
|
|||
afk: boolean,
|
||||
user?:userjson,
|
||||
}
|
||||
export {readyjson,dirrectjson,channeljson,guildjson,rolesjson,userjson,memberjson,mainuserjson,messagejson,filejson,embedjson,emojijson,presencejson};
|
||||
type messageCreateJson={
|
||||
op:0,
|
||||
d:{
|
||||
guild_id?:string,
|
||||
channel_id?:string,
|
||||
}&messagejson,
|
||||
s:number,
|
||||
t:"MESSAGE_CREATE"
|
||||
}
|
||||
type wsjson={
|
||||
op:0,
|
||||
d:any,
|
||||
s:number,
|
||||
t:"TYPING_START"|"USER_UPDATE"|"CHANNEL_UPDATE"|"CHANNEL_CREATE"|"CHANNEL_DELETE"|"GUILD_DELETE"|"GUILD_CREATE"|"MESSAGE_REACTION_ADD"|"MESSAGE_REACTION_REMOVE"|"MESSAGE_REACTION_REMOVE_ALL"|"MESSAGE_REACTION_REMOVE_EMOJI"
|
||||
}|{
|
||||
op:0,
|
||||
t:"GUILD_MEMBERS_CHUNK",
|
||||
d:memberChunk
|
||||
}|{
|
||||
op:0,
|
||||
d:{
|
||||
id:string,
|
||||
guild_id?:string,
|
||||
channel_id:string
|
||||
},
|
||||
s:number,
|
||||
t:"MESSAGE_DELETE"
|
||||
}|{
|
||||
op:0,
|
||||
d:{
|
||||
guild_id?:string,
|
||||
channel_id:string
|
||||
}&messagejson,
|
||||
s:number,
|
||||
t:"MESSAGE_UPDATE"
|
||||
}|messageCreateJson|readyjson|{
|
||||
op:11,
|
||||
s:undefined,
|
||||
d:{}
|
||||
}|{
|
||||
op:10,
|
||||
s:undefined,
|
||||
d:{
|
||||
heartbeat_interval:number
|
||||
}
|
||||
}
|
||||
type memberChunk={
|
||||
guild_id: string,
|
||||
nonce: string,
|
||||
members: memberjson[],
|
||||
presences: presencejson[],
|
||||
chunk_index: number,
|
||||
chunk_count: number,
|
||||
not_found: string[]
|
||||
}
|
||||
export{readyjson,dirrectjson,channeljson,guildjson,rolesjson,userjson,memberjson,mainuserjson,messagejson,filejson,embedjson,emojijson,presencejson,wsjson,messageCreateJson,memberChunk};
|
||||
|
|
2873
webpage/localuser.ts
2873
webpage/localuser.ts
File diff suppressed because it is too large
Load diff
|
@ -1,36 +1,36 @@
|
|||
<body class="Dark-theme">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Jank Client</title>
|
||||
<meta content="Jank Client" property="og:title" />
|
||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description" />
|
||||
<meta content="/logo.webp" property="og:image" />
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||
<link href="/style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/>
|
||||
</head>
|
||||
<div id="logindiv">
|
||||
<h1>Login</h1><br>
|
||||
<form id="form" submit="check(e)">
|
||||
<label for="instance"><b>Instance:</b></label><br>
|
||||
<p id="verify"></p>
|
||||
<input type="search" list="instances" placeholder="Instance URL" name="instance" id="instancein" value="" id="instancein" required><br><br>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Jank Client</title>
|
||||
<meta content="Jank Client" property="og:title">
|
||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description">
|
||||
<meta content="/logo.webp" property="og:image">
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
||||
<link href="/style.css" rel="stylesheet">
|
||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
||||
</head>
|
||||
<div id="logindiv">
|
||||
<h1>Login</h1><br>
|
||||
<form id="form" submit="check(e)">
|
||||
<label for="instance"><b>Instance:</b></label><br>
|
||||
<p id="verify"></p>
|
||||
<input type="search" list="instances" placeholder="Instance URL" name="instance" id="instancein" value="" id="instancein" required><br><br>
|
||||
|
||||
<label for="uname"><b>Email:</b></label><br>
|
||||
<input type="text" placeholder="Enter email address" name="uname" id="uname" required><br><br>
|
||||
<label for="uname"><b>Email:</b></label><br>
|
||||
<input type="text" placeholder="Enter email address" name="uname" id="uname" required><br><br>
|
||||
|
||||
<label for="psw"><b>Password:</b></label><br>
|
||||
<input type="password" placeholder="Enter Password" name="psw" id="psw" required><br><br><br><br>
|
||||
<p class="wrongred" id="wrong"></p>
|
||||
<label for="psw"><b>Password:</b></label><br>
|
||||
<input type="password" placeholder="Enter Password" name="psw" id="psw" required><br><br><br><br>
|
||||
<p class="wrongred" id="wrong"></p>
|
||||
|
||||
<div id="h-captcha">
|
||||
<div id="h-captcha">
|
||||
|
||||
</div>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
<a href="/register.html" id="switch">Don't have an account?</a>
|
||||
</div>
|
||||
<datalist id="instances"></datalist>
|
||||
<script src="/login.js" type="module" ></script>
|
||||
</div>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
<a href="/register.html" id="switch">Don't have an account?</a>
|
||||
</div>
|
||||
<datalist id="instances"></datalist>
|
||||
<script src="/login.js" type="module"></script>
|
||||
</body>
|
||||
|
|
718
webpage/login.ts
718
webpage/login.ts
|
@ -1,366 +1,362 @@
|
|||
import { Dialog } from "./dialog.js";
|
||||
import{ Dialog }from"./dialog.js";
|
||||
|
||||
const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||
|
||||
function setTheme(){
|
||||
let name=localStorage.getItem("theme");
|
||||
if(!name){
|
||||
localStorage.setItem("theme","Dark");
|
||||
name="Dark";
|
||||
}
|
||||
document.body.className=name+"-theme";
|
||||
let name=localStorage.getItem("theme");
|
||||
if(!name){
|
||||
localStorage.setItem("theme","Dark");
|
||||
name="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;
|
||||
const json=getBulkInfo();
|
||||
for(const thing in json.users){
|
||||
json.users[thing]=new Specialuser(json.users[thing]);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
function trimswitcher(){
|
||||
const json=getBulkInfo()
|
||||
const map=new Map();
|
||||
for(const thing in json.users){
|
||||
const user=json.users[thing];
|
||||
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);
|
||||
const json=getBulkInfo();
|
||||
const map=new Map();
|
||||
for(const thing in json.users){
|
||||
const user=json.users[thing];
|
||||
let wellknown=user.serverurls.wellknown;
|
||||
if(wellknown.at(-1)!=="/"){
|
||||
wellknown+="/";
|
||||
}
|
||||
wellknown+=user.username;
|
||||
if(map.has(wellknown)){
|
||||
const otheruser=map.get(wellknown);
|
||||
if(otheruser[1].serverurls.wellknown.at(-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.at(-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"));
|
||||
return JSON.parse(localStorage.getItem("userinfos"));
|
||||
}
|
||||
function setDefaults(){
|
||||
let userinfos=getBulkInfo();
|
||||
if(!userinfos){
|
||||
localStorage.setItem("userinfos",JSON.stringify({
|
||||
currentuser:null,
|
||||
users:{},
|
||||
preferences:
|
||||
let userinfos=getBulkInfo();
|
||||
if(!userinfos){
|
||||
localStorage.setItem("userinfos",JSON.stringify({
|
||||
currentuser: null,
|
||||
users: {},
|
||||
preferences:
|
||||
{
|
||||
theme:"Dark",
|
||||
notifications:false,
|
||||
notisound:"three",
|
||||
theme: "Dark",
|
||||
notifications: false,
|
||||
notisound: "three",
|
||||
},
|
||||
}));
|
||||
userinfos=getBulkInfo();
|
||||
}
|
||||
if(userinfos.users===undefined){
|
||||
userinfos.users={};
|
||||
}
|
||||
if(userinfos.accent_color===undefined){
|
||||
userinfos.accent_color="#242443";
|
||||
}
|
||||
document.documentElement.style.setProperty('--accent-color', userinfos.accent_color);
|
||||
if(userinfos.preferences===undefined){
|
||||
userinfos.preferences={
|
||||
theme:"Dark",
|
||||
notifications:false,
|
||||
notisound:"three",
|
||||
}
|
||||
}
|
||||
if(userinfos.preferences&&(userinfos.preferences.notisound===undefined)){
|
||||
userinfos.preferences.notisound="three";
|
||||
}
|
||||
localStorage.setItem("userinfos",JSON.stringify(userinfos))
|
||||
}));
|
||||
userinfos=getBulkInfo();
|
||||
}
|
||||
if(userinfos.users===undefined){
|
||||
userinfos.users={};
|
||||
}
|
||||
if(userinfos.accent_color===undefined){
|
||||
userinfos.accent_color="#242443";
|
||||
}
|
||||
document.documentElement.style.setProperty("--accent-color", userinfos.accent_color);
|
||||
if(userinfos.preferences===undefined){
|
||||
userinfos.preferences={
|
||||
theme: "Dark",
|
||||
notifications: false,
|
||||
notisound: "three",
|
||||
};
|
||||
}
|
||||
if(userinfos.preferences&&(userinfos.preferences.notisound===undefined)){
|
||||
userinfos.preferences.notisound="three";
|
||||
}
|
||||
localStorage.setItem("userinfos",JSON.stringify(userinfos));
|
||||
}
|
||||
setDefaults();
|
||||
class Specialuser{
|
||||
serverurls:{api:string,cdn:string,gateway:string,wellknown:string,login:string};
|
||||
email:string;
|
||||
token:string;
|
||||
loggedin;
|
||||
json;
|
||||
constructor(json){
|
||||
if(json instanceof Specialuser){
|
||||
console.error("specialuser can't construct from another specialuser");
|
||||
}
|
||||
this.serverurls=json.serverurls;
|
||||
let apistring=new URL(json.serverurls.api).toString();
|
||||
apistring=apistring.replace(/\/(v\d+\/?)?$/, "")+"/v9";
|
||||
this.serverurls.api=apistring;
|
||||
this.serverurls.cdn=new URL(json.serverurls.cdn).toString().replace(/\/$/,"");
|
||||
this.serverurls.gateway=new URL(json.serverurls.gateway).toString().replace(/\/$/,"");;
|
||||
this.serverurls.wellknown=new URL(json.serverurls.wellknown).toString().replace(/\/$/,"");;
|
||||
this.serverurls.login=new URL(json.serverurls.login).toString().replace(/\/$/,"");;
|
||||
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));
|
||||
}
|
||||
serverurls:{api:string,cdn:string,gateway:string,wellknown:string,login:string};
|
||||
email:string;
|
||||
token:string;
|
||||
loggedin;
|
||||
json;
|
||||
constructor(json){
|
||||
if(json instanceof Specialuser){
|
||||
console.error("specialuser can't construct from another specialuser");
|
||||
}
|
||||
this.serverurls=json.serverurls;
|
||||
let apistring=new URL(json.serverurls.api).toString();
|
||||
apistring=apistring.replace(/\/(v\d+\/?)?$/, "")+"/v9";
|
||||
this.serverurls.api=apistring;
|
||||
this.serverurls.cdn=new URL(json.serverurls.cdn).toString().replace(/\/$/,"");
|
||||
this.serverurls.gateway=new URL(json.serverurls.gateway).toString().replace(/\/$/,"");
|
||||
this.serverurls.wellknown=new URL(json.serverurls.wellknown).toString().replace(/\/$/,"");
|
||||
this.serverurls.login=new URL(json.serverurls.login).toString().replace(/\/$/,"");
|
||||
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));
|
||||
return user;
|
||||
user=new Specialuser(user);
|
||||
const info=getBulkInfo();
|
||||
info.users[user.uid]=user;
|
||||
info.currentuser=user.uid;
|
||||
localStorage.setItem("userinfos",JSON.stringify(info));
|
||||
return user;
|
||||
}
|
||||
const instancein=document.getElementById("instancein") as HTMLInputElement;
|
||||
const instancein=document.getElementById("instancein") as HTMLInputElement;
|
||||
let timeout;
|
||||
let instanceinfo;
|
||||
const stringURLMap=new Map<string,string>();
|
||||
|
||||
const stringURLsMap=new Map<string,{wellknown:string,api:string,cdn:string,gateway:string,login?:string}>();
|
||||
async function getapiurls(str:string):Promise<{api:string,cdn:string,gateway:string,wellknown:string,login:string}|false>{
|
||||
if(!URL.canParse(str)){
|
||||
const val=stringURLMap.get(str);
|
||||
if(val){
|
||||
str=val;
|
||||
}else{
|
||||
const val=stringURLsMap.get(str)
|
||||
if(val){
|
||||
const responce=await fetch(val.api+val.api.endsWith("/")?"":"/"+"ping");
|
||||
if(responce.ok){
|
||||
if(val.login){
|
||||
return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string};
|
||||
}else{
|
||||
val.login=val.api;
|
||||
return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(str[str.length-1]!=="/"){
|
||||
str+="/"
|
||||
}
|
||||
let api:string;
|
||||
try{
|
||||
const info=await fetch(`${str}/.well-known/spacebar`).then((x) => x.json());
|
||||
api=info.api;
|
||||
}catch{
|
||||
return false
|
||||
}
|
||||
const url = new URL(api);
|
||||
try{
|
||||
|
||||
const info=await fetch(`${api}${url.pathname.includes("api") ? "" : "api"}/policies/instance/domains`).then((x) => x.json());
|
||||
return {
|
||||
api: info.apiEndpoint,
|
||||
gateway: info.gateway,
|
||||
cdn: info.cdn,
|
||||
wellknown: str,
|
||||
login:url.toString()
|
||||
};
|
||||
}catch{
|
||||
const val=stringURLsMap.get(str)
|
||||
if(val){
|
||||
const responce=await fetch(val.api+val.api.endsWith("/")?"":"/"+"ping");
|
||||
if(responce.ok){
|
||||
if(val.login){
|
||||
return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string};
|
||||
}else{
|
||||
val.login=val.api;
|
||||
return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!URL.canParse(str)){
|
||||
const val=stringURLMap.get(str);
|
||||
if(val){
|
||||
str=val;
|
||||
}else{
|
||||
const val=stringURLsMap.get(str);
|
||||
if(val){
|
||||
const responce=await fetch(val.api+val.api.endsWith("/")?"":"/"+"ping");
|
||||
if(responce.ok){
|
||||
if(val.login){
|
||||
return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string};
|
||||
}else{
|
||||
val.login=val.api;
|
||||
return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(str.at(-1)!=="/"){
|
||||
str+="/";
|
||||
}
|
||||
let api:string;
|
||||
try{
|
||||
const info=await fetch(`${str}/.well-known/spacebar`).then(x=>x.json());
|
||||
api=info.api;
|
||||
}catch{
|
||||
return false;
|
||||
}
|
||||
const url = new URL(api);
|
||||
try{
|
||||
const info=await fetch(`${api}${url.pathname.includes("api") ? "" : "api"}/policies/instance/domains`).then(x=>x.json());
|
||||
return{
|
||||
api: info.apiEndpoint,
|
||||
gateway: info.gateway,
|
||||
cdn: info.cdn,
|
||||
wellknown: str,
|
||||
login: url.toString()
|
||||
};
|
||||
}catch{
|
||||
const val=stringURLsMap.get(str);
|
||||
if(val){
|
||||
const responce=await fetch(val.api+val.api.endsWith("/")?"":"/"+"ping");
|
||||
if(responce.ok){
|
||||
if(val.login){
|
||||
return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string};
|
||||
}else{
|
||||
val.login=val.api;
|
||||
return val as {wellknown:string,api:string,cdn:string,gateway:string,login:string};
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
async function checkInstance(e:string){
|
||||
const verify=document.getElementById("verify");
|
||||
try{
|
||||
verify.textContent="Checking Instance";
|
||||
const instanceinfo=await getapiurls((instancein as HTMLInputElement).value) as {wellknown:string,api:string,cdn:string,gateway:string,login:string, value:string};
|
||||
if(instanceinfo){
|
||||
instanceinfo.value=(instancein as HTMLInputElement).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);
|
||||
}else{
|
||||
verify.textContent="Invalid Instance, try again"
|
||||
}
|
||||
}catch(e){
|
||||
console.log("catch")
|
||||
verify.textContent="Invalid Instance, try again"
|
||||
}
|
||||
const verify=document.getElementById("verify");
|
||||
try{
|
||||
verify.textContent="Checking Instance";
|
||||
const instanceinfo=await getapiurls((instancein as HTMLInputElement).value) as {wellknown:string,api:string,cdn:string,gateway:string,login:string, value:string};
|
||||
if(instanceinfo){
|
||||
instanceinfo.value=(instancein as HTMLInputElement).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);
|
||||
}else{
|
||||
verify.textContent="Invalid Instance, try again";
|
||||
}
|
||||
}catch{
|
||||
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")){
|
||||
const json=JSON.parse(localStorage.getItem("instanceinfo"));
|
||||
if(json.value){
|
||||
(instancein as HTMLInputElement).value=json.value
|
||||
}else{
|
||||
(instancein as HTMLInputElement).value=json.wellknown
|
||||
}
|
||||
}else{
|
||||
checkInstance("https://spacebar.chat/");
|
||||
}
|
||||
|
||||
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")){
|
||||
const json=JSON.parse(localStorage.getItem("instanceinfo"));
|
||||
if(json.value){
|
||||
(instancein as HTMLInputElement).value=json.value;
|
||||
}else{
|
||||
(instancein as HTMLInputElement).value=json.wellknown;
|
||||
}
|
||||
}else{
|
||||
checkInstance("https://spacebar.chat/");
|
||||
}
|
||||
}
|
||||
|
||||
async function login(username:string, password:string, captcha:string){
|
||||
if(captcha===""){
|
||||
captcha=undefined;
|
||||
}
|
||||
const options={
|
||||
method: "POST",
|
||||
body:JSON.stringify({
|
||||
"login": username,
|
||||
"password": password,
|
||||
"undelete":false,
|
||||
"captcha_key":captcha
|
||||
}),
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8",
|
||||
}}
|
||||
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())
|
||||
.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
|
||||
console.log(response);
|
||||
if(captcha===""){
|
||||
captcha=undefined;
|
||||
}
|
||||
const options={
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
login: username,
|
||||
password,
|
||||
undelete: false,
|
||||
captcha_key: captcha
|
||||
}),
|
||||
headers: {
|
||||
"Content-type": "application/json; charset=UTF-8",
|
||||
}};
|
||||
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())
|
||||
.then(response=>{
|
||||
console.log(response,response.message);
|
||||
if(response.message==="Invalid Form Body"){
|
||||
return response.errors.login._errors[0].message;
|
||||
console.log("test");
|
||||
}
|
||||
//this.serverurls||!this.email||!this.token
|
||||
console.log(response);
|
||||
|
||||
if(response.captcha_sitekey){
|
||||
if(response.captcha_sitekey){
|
||||
const capt=document.getElementById("h-captcha");
|
||||
if(!capt.children.length){
|
||||
const capty=document.createElement("div");
|
||||
capty.classList.add("h-captcha");
|
||||
|
||||
const capt=document.getElementById("h-captcha");
|
||||
if(!capt.children.length){
|
||||
const capty=document.createElement("div");
|
||||
capty.classList.add("h-captcha");
|
||||
|
||||
capty.setAttribute("data-sitekey", response.captcha_sitekey);
|
||||
const script=document.createElement("script");
|
||||
script.src="https://js.hcaptcha.com/1/api.js";
|
||||
capt.append(script);
|
||||
capt.append(capty);
|
||||
}else{
|
||||
eval("hcaptcha.reset()");
|
||||
}
|
||||
return;
|
||||
}else{
|
||||
console.log(response);
|
||||
if(response.ticket){
|
||||
let onetimecode="";
|
||||
new Dialog(["vdiv",["title","2FA code:"],["textbox","","",function(this:HTMLInputElement){onetimecode=this.value}],["button","","Submit",function(){
|
||||
fetch(api+"/auth/mfa/totp",{
|
||||
method:"POST",
|
||||
headers:{
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body:JSON.stringify({
|
||||
code:onetimecode,
|
||||
ticket:response.ticket,
|
||||
})
|
||||
}).then(r=>r.json()).then(response=>{
|
||||
if(response.message){
|
||||
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){
|
||||
window.location.href = redir;
|
||||
}else{
|
||||
window.location.href = '/channels/@me';
|
||||
}
|
||||
}
|
||||
})
|
||||
}]]).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){
|
||||
window.location.href = redir;
|
||||
}else{
|
||||
window.location.href = '/channels/@me';
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
})
|
||||
}catch(error){
|
||||
console.error('Error:', error);
|
||||
};
|
||||
capty.setAttribute("data-sitekey", response.captcha_sitekey);
|
||||
const script=document.createElement("script");
|
||||
script.src="https://js.hcaptcha.com/1/api.js";
|
||||
capt.append(script);
|
||||
capt.append(capty);
|
||||
}else{
|
||||
eval("hcaptcha.reset()");
|
||||
}
|
||||
}else{
|
||||
console.log(response);
|
||||
if(response.ticket){
|
||||
let onetimecode="";
|
||||
new Dialog(["vdiv",["title","2FA code:"],["textbox","","",function(this:HTMLInputElement){
|
||||
onetimecode=this.value;
|
||||
}],["button","","Submit",function(){
|
||||
fetch(api+"/auth/mfa/totp",{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
code: onetimecode,
|
||||
ticket: response.ticket,
|
||||
})
|
||||
}).then(r=>r.json()).then(response=>{
|
||||
if(response.message){
|
||||
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){
|
||||
window.location.href = redir;
|
||||
}else{
|
||||
window.location.href = "/channels/@me";
|
||||
}
|
||||
}
|
||||
});
|
||||
}]]).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){
|
||||
window.location.href = redir;
|
||||
}else{
|
||||
window.location.href = "/channels/@me";
|
||||
}
|
||||
return"";
|
||||
}
|
||||
}
|
||||
});
|
||||
}catch(error){
|
||||
console.error("Error:", error);
|
||||
}
|
||||
}
|
||||
|
||||
async function check(e){
|
||||
|
||||
e.preventDefault();
|
||||
let h=await login(e.srcElement[1].value,e.srcElement[2].value,e.srcElement[3].value);
|
||||
document.getElementById("wrong").textContent=h;
|
||||
console.log(h);
|
||||
e.preventDefault();
|
||||
const h=await login(e.srcElement[1].value,e.srcElement[2].value,e.srcElement[3].value);
|
||||
document.getElementById("wrong").textContent=h;
|
||||
console.log(h);
|
||||
}
|
||||
if(document.getElementById("form")){
|
||||
document.getElementById("form").addEventListener("submit", check);
|
||||
document.getElementById("form").addEventListener("submit", check);
|
||||
}
|
||||
//this currently does not work, and need to be implemented better at some time.
|
||||
/*
|
||||
|
@ -390,50 +386,50 @@ if ("serviceWorker" in navigator){
|
|||
*/
|
||||
const switchurl=document.getElementById("switch") as HTMLAreaElement;
|
||||
if(switchurl){
|
||||
switchurl.href+=window.location.search;
|
||||
const instance=new URLSearchParams(window.location.search).get("instance");
|
||||
console.log(instance);
|
||||
if(instance){
|
||||
instancein.value=instance;
|
||||
checkInstance("");
|
||||
}
|
||||
switchurl.href+=window.location.search;
|
||||
const instance=new URLSearchParams(window.location.search).get("instance");
|
||||
console.log(instance);
|
||||
if(instance){
|
||||
instancein.value=instance;
|
||||
checkInstance("");
|
||||
}
|
||||
}
|
||||
export {checkInstance};
|
||||
export{checkInstance};
|
||||
trimswitcher();
|
||||
export {mobile, getBulkUsers,getBulkInfo,setTheme,Specialuser,getapiurls,adduser}
|
||||
export{mobile, getBulkUsers,getBulkInfo,setTheme,Specialuser,getapiurls,adduser};
|
||||
|
||||
const datalist=document.getElementById("instances");
|
||||
console.warn(datalist);
|
||||
if(datalist){
|
||||
fetch("/instances.json").then(_=>_.json()).then((json:{name:string,online:boolean,description?:string,src?:string,url?:string,display?:boolean,urls:{wellknown:string,api:string,cdn:string,gateway:string,login?:string}}[])=>{
|
||||
console.warn(json);
|
||||
if(instancein&&instancein.value===""){
|
||||
instancein.value=json[0].name;
|
||||
}
|
||||
for(const instance of json){
|
||||
if(instance.display===false){
|
||||
continue;
|
||||
}
|
||||
const option=document.createElement("option");
|
||||
option.disabled=!instance.online;
|
||||
option.value=instance.name;
|
||||
if(instance.url){
|
||||
stringURLMap.set(option.value,instance.url);
|
||||
if(instance.urls){
|
||||
stringURLsMap.set(instance.url,instance.urls);
|
||||
}
|
||||
}else if(instance.urls){
|
||||
stringURLsMap.set(option.value,instance.urls);
|
||||
}else{
|
||||
option.disabled=true;
|
||||
}
|
||||
if(instance.description){
|
||||
option.label=instance.description;
|
||||
}else{
|
||||
option.label=instance.name;
|
||||
}
|
||||
datalist.append(option);
|
||||
}
|
||||
checkInstance("");
|
||||
})
|
||||
fetch("/instances.json").then(_=>_.json()).then((json:{name:string,online:boolean,description?:string,src?:string,url?:string,display?:boolean,urls:{wellknown:string,api:string,cdn:string,gateway:string,login?:string}}[])=>{
|
||||
console.warn(json);
|
||||
if(instancein&&instancein.value===""){
|
||||
instancein.value=json[0].name;
|
||||
}
|
||||
for(const instance of json){
|
||||
if(instance.display===false){
|
||||
continue;
|
||||
}
|
||||
const option=document.createElement("option");
|
||||
option.disabled=!instance.online;
|
||||
option.value=instance.name;
|
||||
if(instance.url){
|
||||
stringURLMap.set(option.value,instance.url);
|
||||
if(instance.urls){
|
||||
stringURLsMap.set(instance.url,instance.urls);
|
||||
}
|
||||
}else if(instance.urls){
|
||||
stringURLsMap.set(option.value,instance.urls);
|
||||
}else{
|
||||
option.disabled=true;
|
||||
}
|
||||
if(instance.description){
|
||||
option.label=instance.description;
|
||||
}else{
|
||||
option.label=instance.name;
|
||||
}
|
||||
datalist.append(option);
|
||||
}
|
||||
checkInstance("");
|
||||
});
|
||||
}
|
||||
|
|
1099
webpage/markdown.ts
1099
webpage/markdown.ts
File diff suppressed because it is too large
Load diff
|
@ -1,218 +1,219 @@
|
|||
import {User} from "./user.js";
|
||||
import {Role} from "./role.js";
|
||||
import {Guild} from "./guild.js";
|
||||
import { SnowFlake } from "./snowflake.js";
|
||||
import { memberjson, presencejson, userjson } from "./jsontypes.js";
|
||||
import { Dialog } from "./dialog.js";
|
||||
import{User}from"./user.js";
|
||||
import{Role}from"./role.js";
|
||||
import{Guild}from"./guild.js";
|
||||
import{ SnowFlake }from"./snowflake.js";
|
||||
import{ memberjson, presencejson, userjson }from"./jsontypes.js";
|
||||
import{ Dialog }from"./dialog.js";
|
||||
|
||||
class Member{
|
||||
static already={};
|
||||
owner:Guild;
|
||||
user:User;
|
||||
roles:Role[]=[];
|
||||
id:string;
|
||||
nick:string;
|
||||
private constructor(memberjson:memberjson,owner:Guild){
|
||||
this.owner=owner;
|
||||
if(this.localuser.userMap.has(memberjson.id)){
|
||||
this.user=this.localuser.userMap.get(memberjson.id) as User;
|
||||
}else if(memberjson.user){
|
||||
this.user=new User(memberjson.user,owner.localuser);
|
||||
}else{
|
||||
throw new Error("Missing user object of this member");
|
||||
}
|
||||
static already={};
|
||||
owner:Guild;
|
||||
user:User;
|
||||
roles:Role[]=[];
|
||||
id:string;
|
||||
nick:string;
|
||||
private constructor(memberjson:memberjson,owner:Guild){
|
||||
this.owner=owner;
|
||||
if(this.localuser.userMap.has(memberjson.id)){
|
||||
this.user=this.localuser.userMap.get(memberjson.id) as User;
|
||||
}else if(memberjson.user){
|
||||
this.user=new User(memberjson.user,owner.localuser);
|
||||
}else{
|
||||
throw new Error("Missing user object of this member");
|
||||
}
|
||||
|
||||
for(const thing of Object.keys(memberjson)){
|
||||
if(thing==="guild"){continue}
|
||||
if(thing==="owner"){continue}
|
||||
if(thing==="roles"){
|
||||
for(const strrole of memberjson["roles"]){
|
||||
|
||||
const role=SnowFlake.getSnowFlakeFromID(strrole,Role).getObject();
|
||||
this.roles.push(role);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
this[thing]=memberjson[thing];
|
||||
}
|
||||
if(this.localuser.userMap.has(this?.id)){
|
||||
this.user=this.localuser.userMap.get(this?.id) as User;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
get guild(){
|
||||
return this.owner;
|
||||
}
|
||||
get localuser(){
|
||||
return this.guild.localuser;
|
||||
}
|
||||
get info(){
|
||||
return this.owner.info;
|
||||
}
|
||||
static async new(memberjson:memberjson,owner:Guild):Promise<Member|undefined>{
|
||||
let user:User;
|
||||
if(owner.localuser.userMap.has(memberjson.id)){
|
||||
user=owner.localuser.userMap.get(memberjson.id);
|
||||
}else if(memberjson.user){
|
||||
user=new User(memberjson.user,owner.localuser);
|
||||
}else{
|
||||
throw new Error("missing user object of this member");
|
||||
}
|
||||
if(user.members.has(owner)){
|
||||
let memb=user.members.get(owner)
|
||||
if(memb===undefined){
|
||||
memb=new Member(memberjson,owner);
|
||||
user.members.set(owner,memb);
|
||||
return memb
|
||||
}else if(memb instanceof Promise){
|
||||
return await memb;//I should do something else, though for now this is "good enough"
|
||||
}else{
|
||||
return memb;
|
||||
}
|
||||
}else{
|
||||
const memb=new Member(memberjson,owner);
|
||||
user.members.set(owner,memb);
|
||||
return memb;
|
||||
}
|
||||
}
|
||||
static async resolveMember(user:User,guild:Guild):Promise<Member|undefined>{
|
||||
const maybe=user.members.get(guild);
|
||||
if(!user.members.has(guild)){
|
||||
const membpromise=guild.localuser.resolvemember(user.id,guild.id);
|
||||
const promise=new Promise<Member|undefined>( async res=>{
|
||||
const membjson=await membpromise;
|
||||
if(membjson===undefined){
|
||||
res(undefined);
|
||||
return undefined;
|
||||
}else{
|
||||
const member=new Member(membjson,guild);
|
||||
const map=guild.localuser.presences;
|
||||
member.getPresence(map.get(member.id));
|
||||
map.delete(member.id);
|
||||
res(member);
|
||||
return member;
|
||||
}
|
||||
})
|
||||
user.members.set(guild,promise);
|
||||
}
|
||||
if(maybe instanceof Promise){
|
||||
return await maybe;
|
||||
}else{
|
||||
return maybe
|
||||
}
|
||||
}
|
||||
public getPresence(presence:presencejson|undefined){
|
||||
this.user.getPresence(presence);
|
||||
}
|
||||
/**
|
||||
for(const thing of Object.keys(memberjson)){
|
||||
if(thing==="guild"){
|
||||
continue;
|
||||
}
|
||||
if(thing==="owner"){
|
||||
continue;
|
||||
}
|
||||
if(thing==="roles"){
|
||||
for(const strrole of memberjson.roles){
|
||||
const role=SnowFlake.getSnowFlakeFromID(strrole,Role).getObject();
|
||||
this.roles.push(role);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
this[thing]=memberjson[thing];
|
||||
}
|
||||
if(this.localuser.userMap.has(this?.id)){
|
||||
this.user=this.localuser.userMap.get(this?.id) as User;
|
||||
}
|
||||
}
|
||||
get guild(){
|
||||
return this.owner;
|
||||
}
|
||||
get localuser(){
|
||||
return this.guild.localuser;
|
||||
}
|
||||
get info(){
|
||||
return this.owner.info;
|
||||
}
|
||||
static async new(memberjson:memberjson,owner:Guild):Promise<Member|undefined>{
|
||||
let user:User;
|
||||
if(owner.localuser.userMap.has(memberjson.id)){
|
||||
user=owner.localuser.userMap.get(memberjson.id) as User;
|
||||
}else if(memberjson.user){
|
||||
user=new User(memberjson.user,owner.localuser);
|
||||
}else{
|
||||
throw new Error("missing user object of this member");
|
||||
}
|
||||
if(user.members.has(owner)){
|
||||
let memb=user.members.get(owner);
|
||||
if(memb===undefined){
|
||||
memb=new Member(memberjson,owner);
|
||||
user.members.set(owner,memb);
|
||||
return memb;
|
||||
}else if(memb instanceof Promise){
|
||||
return await memb;//I should do something else, though for now this is "good enough"
|
||||
}else{
|
||||
return memb;
|
||||
}
|
||||
}else{
|
||||
const memb=new Member(memberjson,owner);
|
||||
user.members.set(owner,memb);
|
||||
return memb;
|
||||
}
|
||||
}
|
||||
static async resolveMember(user:User,guild:Guild):Promise<Member|undefined>{
|
||||
const maybe=user.members.get(guild);
|
||||
if(!user.members.has(guild)){
|
||||
const membpromise=guild.localuser.resolvemember(user.id,guild.id);
|
||||
const promise=new Promise<Member|undefined>(async res=>{
|
||||
const membjson=await membpromise;
|
||||
if(membjson===undefined){
|
||||
res(undefined);
|
||||
}else{
|
||||
const member=new Member(membjson,guild);
|
||||
const map=guild.localuser.presences;
|
||||
member.getPresence(map.get(member.id));
|
||||
map.delete(member.id);
|
||||
res(member);
|
||||
return member;
|
||||
}
|
||||
});
|
||||
user.members.set(guild,promise);
|
||||
}
|
||||
if(maybe instanceof Promise){
|
||||
return await maybe;
|
||||
}else{
|
||||
return maybe;
|
||||
}
|
||||
}
|
||||
public getPresence(presence:presencejson|undefined){
|
||||
this.user.getPresence(presence);
|
||||
}
|
||||
/**
|
||||
* @todo
|
||||
*/
|
||||
highInfo(){
|
||||
fetch(this.info.api+"/users/"+this.id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+this.guild.id,{headers:this.guild.headers})
|
||||
}
|
||||
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.getPermission("ADMINISTRATOR")){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return this.guild.properties.owner_id===this.user.id;
|
||||
}
|
||||
bind(html:HTMLElement){
|
||||
if(html.tagName==="SPAN"){
|
||||
if(!this) {return};
|
||||
/*
|
||||
highInfo(){
|
||||
fetch(this.info.api+"/users/"+this.id+"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id="+this.guild.id,{headers: this.guild.headers});
|
||||
}
|
||||
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.getPermission("ADMINISTRATOR")){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return this.guild.properties.owner_id===this.user.id;
|
||||
}
|
||||
bind(html:HTMLElement){
|
||||
if(html.tagName==="SPAN"){
|
||||
if(!this){
|
||||
return;
|
||||
}
|
||||
/*
|
||||
if(this.error){
|
||||
|
||||
}
|
||||
*/
|
||||
html.style.color=this.getColor();
|
||||
}
|
||||
html.style.color=this.getColor();
|
||||
}
|
||||
|
||||
//this.profileclick(html);
|
||||
}
|
||||
profileclick(html:HTMLElement){
|
||||
//to be implemented
|
||||
}
|
||||
get name(){
|
||||
return this.nick||this.user.username;
|
||||
}
|
||||
kick(){
|
||||
let reason=""
|
||||
const menu=new Dialog(["vdiv",
|
||||
["title","Kick "+this.name+" from "+this.guild.properties.name],
|
||||
["textbox","Reason:","",function(e:Event){
|
||||
reason=(e.target as HTMLInputElement).value;
|
||||
}],
|
||||
["button","","submit",()=>{
|
||||
this.kickAPI(reason);
|
||||
menu.hide();
|
||||
}]
|
||||
]);
|
||||
menu.show();
|
||||
}
|
||||
kickAPI(reason:string){
|
||||
const headers=structuredClone(this.guild.headers);
|
||||
headers["x-audit-log-reason"]=reason
|
||||
fetch(`${this.info.api}/guilds/${this.guild.id}/members/${this.id}`,{
|
||||
method:"DELETE",
|
||||
headers,
|
||||
//this.profileclick(html);
|
||||
}
|
||||
profileclick(html:HTMLElement){
|
||||
//to be implemented
|
||||
}
|
||||
get name(){
|
||||
return this.nick||this.user.username;
|
||||
}
|
||||
kick(){
|
||||
let reason="";
|
||||
const menu=new Dialog(["vdiv",
|
||||
["title","Kick "+this.name+" from "+this.guild.properties.name],
|
||||
["textbox","Reason:","",function(e:Event){
|
||||
reason=(e.target as HTMLInputElement).value;
|
||||
}],
|
||||
["button","","submit",()=>{
|
||||
this.kickAPI(reason);
|
||||
menu.hide();
|
||||
}]
|
||||
]);
|
||||
menu.show();
|
||||
}
|
||||
kickAPI(reason:string){
|
||||
const headers=structuredClone(this.guild.headers);
|
||||
headers["x-audit-log-reason"]=reason;
|
||||
fetch(`${this.info.api}/guilds/${this.guild.id}/members/${this.id}`,{
|
||||
method: "DELETE",
|
||||
headers,
|
||||
|
||||
})
|
||||
}
|
||||
ban(){
|
||||
let reason=""
|
||||
const menu=new Dialog(["vdiv",
|
||||
["title","Ban "+this.name+" from "+this.guild.properties.name],
|
||||
["textbox","Reason:","",function(e:Event){
|
||||
reason=(e.target as HTMLInputElement).value;
|
||||
}],
|
||||
["button","","submit",()=>{
|
||||
this.banAPI(reason);
|
||||
menu.hide();
|
||||
}]
|
||||
]);
|
||||
menu.show();
|
||||
}
|
||||
banAPI(reason:string){
|
||||
const headers=structuredClone(this.guild.headers);
|
||||
headers["x-audit-log-reason"]=reason
|
||||
fetch(`${this.info.api}/guilds/${this.guild.id}/bans/${this.id}`,{
|
||||
method:"PUT",
|
||||
headers
|
||||
});
|
||||
}
|
||||
ban(){
|
||||
let reason="";
|
||||
const menu=new Dialog(["vdiv",
|
||||
["title","Ban "+this.name+" from "+this.guild.properties.name],
|
||||
["textbox","Reason:","",function(e:Event){
|
||||
reason=(e.target as HTMLInputElement).value;
|
||||
}],
|
||||
["button","","submit",()=>{
|
||||
this.banAPI(reason);
|
||||
menu.hide();
|
||||
}]
|
||||
]);
|
||||
menu.show();
|
||||
}
|
||||
banAPI(reason:string){
|
||||
const headers=structuredClone(this.guild.headers);
|
||||
headers["x-audit-log-reason"]=reason;
|
||||
fetch(`${this.info.api}/guilds/${this.guild.id}/bans/${this.id}`,{
|
||||
method: "PUT",
|
||||
headers
|
||||
|
||||
})
|
||||
}
|
||||
hasPermission(name:string):boolean{
|
||||
if(this.isAdmin()){
|
||||
return true;
|
||||
}
|
||||
for(const thing of this.roles){
|
||||
if(thing.permissions.getPermission(name)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
hasPermission(name:string):boolean{
|
||||
if(this.isAdmin()){
|
||||
return true;
|
||||
}
|
||||
for(const thing of this.roles){
|
||||
if(thing.permissions.getPermission(name)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export {Member};
|
||||
export{Member};
|
||||
|
|
1149
webpage/message.ts
1149
webpage/message.ts
File diff suppressed because it is too large
Load diff
|
@ -1,323 +1,323 @@
|
|||
class Permissions{
|
||||
allow:bigint;
|
||||
deny:bigint;
|
||||
readonly hasDeny:boolean;
|
||||
constructor(allow:string,deny:string=""){
|
||||
this.hasDeny=!!deny;
|
||||
try{
|
||||
this.allow = BigInt(allow);
|
||||
this.deny = BigInt(deny);
|
||||
}catch(e){
|
||||
this.allow = 0n;
|
||||
this.deny = 0n;
|
||||
console.error(`Something really stupid happened with a permission with allow being ${allow} and deny being, ${deny}, execution will still happen, but something really stupid happened, please report if you know what caused this.`)
|
||||
}
|
||||
}
|
||||
getPermissionbit(b:number,big:bigint) : boolean{
|
||||
return Boolean((big>>BigInt(b))&1n);
|
||||
}
|
||||
setPermissionbit(b:number,state:boolean,big:bigint) : bigint{
|
||||
const bit=1n<<BigInt(b);
|
||||
return (big & ~bit) | (BigInt(state) << BigInt(b));//thanks to geotale for this code :3
|
||||
}
|
||||
static map:{
|
||||
allow:bigint;
|
||||
deny:bigint;
|
||||
readonly hasDeny:boolean;
|
||||
constructor(allow:string,deny:string=""){
|
||||
this.hasDeny=Boolean(deny);
|
||||
try{
|
||||
this.allow = BigInt(allow);
|
||||
this.deny = BigInt(deny);
|
||||
}catch{
|
||||
this.allow = 0n;
|
||||
this.deny = 0n;
|
||||
console.error(`Something really stupid happened with a permission with allow being ${allow} and deny being, ${deny}, execution will still happen, but something really stupid happened, please report if you know what caused this.`);
|
||||
}
|
||||
}
|
||||
getPermissionbit(b:number,big:bigint) : boolean{
|
||||
return Boolean((big>>BigInt(b))&1n);
|
||||
}
|
||||
setPermissionbit(b:number,state:boolean,big:bigint) : bigint{
|
||||
const bit=1n<<BigInt(b);
|
||||
return(big & ~bit) | (BigInt(state) << BigInt(b));//thanks to geotale for this code :3
|
||||
}
|
||||
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
|
||||
{
|
||||
name:"CREATE_INSTANT_INVITE",
|
||||
readableName:"Create 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. This is a dangerous permission!"
|
||||
},
|
||||
{
|
||||
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:"Video",
|
||||
description:"Allows the user to stream"
|
||||
},
|
||||
{
|
||||
name:"VIEW_CHANNEL",
|
||||
readableName:"View channels",
|
||||
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:"Manage 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, @here and all roles",
|
||||
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 users to speak in a voice channel by simply talking"
|
||||
},
|
||||
{
|
||||
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 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 activities",
|
||||
description:"Allows the user to use embedded activities"
|
||||
},
|
||||
{
|
||||
name:"MODERATE_MEMBERS",
|
||||
readableName:"Timeout 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"
|
||||
},
|
||||
{
|
||||
name:"VIEW_CREATOR_MONETIZATION_ANALYTICS",
|
||||
readableName:"View creator monetization analytics",
|
||||
description:"Allows for viewing role subscription insights"
|
||||
},
|
||||
{
|
||||
name:"USE_SOUNDBOARD",
|
||||
readableName:"Use soundboard",
|
||||
description:"Allows for using soundboard in a voice channel"
|
||||
},
|
||||
{
|
||||
name:"CREATE_GUILD_EXPRESSIONS",
|
||||
readableName:"Create expressions",
|
||||
description:"Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user."
|
||||
},
|
||||
{
|
||||
name:"CREATE_EVENTS",
|
||||
readableName:"Create events",
|
||||
description:"Allows for creating scheduled events, and editing and deleting those created by the current user."
|
||||
},
|
||||
{
|
||||
name:"USE_EXTERNAL_SOUNDS",
|
||||
readableName:"Use external sounds",
|
||||
description:"Allows the usage of custom soundboard sounds from other servers"
|
||||
},
|
||||
{
|
||||
name:"SEND_VOICE_MESSAGES",
|
||||
readableName:"Send voice messages",
|
||||
description:"Allows sending voice messages"
|
||||
},
|
||||
{
|
||||
name:"SEND_POLLS",
|
||||
readableName:"Create polls",
|
||||
description:"Allows sending polls"
|
||||
},
|
||||
{
|
||||
name:"USE_EXTERNAL_APPS",
|
||||
readableName:"Use external apps",
|
||||
description:"Allows user-installed apps to send public responses. " +
|
||||
};
|
||||
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
|
||||
{
|
||||
name: "CREATE_INSTANT_INVITE",
|
||||
readableName: "Create 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. This is a dangerous permission!"
|
||||
},
|
||||
{
|
||||
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: "Video",
|
||||
description: "Allows the user to stream"
|
||||
},
|
||||
{
|
||||
name: "VIEW_CHANNEL",
|
||||
readableName: "View channels",
|
||||
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: "Manage 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, @here and all roles",
|
||||
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 users to speak in a voice channel by simply talking"
|
||||
},
|
||||
{
|
||||
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 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 activities",
|
||||
description: "Allows the user to use embedded activities"
|
||||
},
|
||||
{
|
||||
name: "MODERATE_MEMBERS",
|
||||
readableName: "Timeout 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"
|
||||
},
|
||||
{
|
||||
name: "VIEW_CREATOR_MONETIZATION_ANALYTICS",
|
||||
readableName: "View creator monetization analytics",
|
||||
description: "Allows for viewing role subscription insights"
|
||||
},
|
||||
{
|
||||
name: "USE_SOUNDBOARD",
|
||||
readableName: "Use soundboard",
|
||||
description: "Allows for using soundboard in a voice channel"
|
||||
},
|
||||
{
|
||||
name: "CREATE_GUILD_EXPRESSIONS",
|
||||
readableName: "Create expressions",
|
||||
description: "Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user."
|
||||
},
|
||||
{
|
||||
name: "CREATE_EVENTS",
|
||||
readableName: "Create events",
|
||||
description: "Allows for creating scheduled events, and editing and deleting those created by the current user."
|
||||
},
|
||||
{
|
||||
name: "USE_EXTERNAL_SOUNDS",
|
||||
readableName: "Use external sounds",
|
||||
description: "Allows the usage of custom soundboard sounds from other servers"
|
||||
},
|
||||
{
|
||||
name: "SEND_VOICE_MESSAGES",
|
||||
readableName: "Send voice messages",
|
||||
description: "Allows sending voice messages"
|
||||
},
|
||||
{
|
||||
name: "SEND_POLLS",
|
||||
readableName: "Create polls",
|
||||
description: "Allows sending polls"
|
||||
},
|
||||
{
|
||||
name: "USE_EXTERNAL_APPS",
|
||||
readableName: "Use external apps",
|
||||
description: "Allows user-installed apps to send public responses. " +
|
||||
"When disabled, users will still be allowed to use their apps but the responses will be ephemeral. " +
|
||||
"This only applies to apps not also installed to the server."
|
||||
},
|
||||
];
|
||||
Permissions.map={};
|
||||
let i=0;
|
||||
for(const thing of Permissions.info){
|
||||
Permissions.map[i]=thing;
|
||||
Permissions.map[thing.name]=i;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
getPermission(name:string):number{
|
||||
if(this.getPermissionbit(Permissions.map[name] as number,this.allow)){
|
||||
return 1;
|
||||
}else if(this.getPermissionbit(Permissions.map[name] as number,this.deny)){
|
||||
return -1;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
hasPermission(name:string):boolean{
|
||||
if(this.deny){console.warn("This function may of been used in error, think about using getPermision instead")}
|
||||
if (this.getPermissionbit(Permissions.map[name] as number,this.allow)) return true;
|
||||
if (name != "ADMINISTRATOR") return this.hasPermission("ADMINISTRATOR");
|
||||
return false;
|
||||
}
|
||||
setPermission(name:string,setto:number):void{
|
||||
const bit=Permissions.map[name] as number;
|
||||
if (!bit) {
|
||||
return console.error("Tried to set permission to " + setto + " for " + name + " but it doesn't exist");
|
||||
}
|
||||
},
|
||||
];
|
||||
Permissions.map={};
|
||||
let i=0;
|
||||
for(const thing of Permissions.info){
|
||||
Permissions.map[i]=thing;
|
||||
Permissions.map[thing.name]=i;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
getPermission(name:string):number{
|
||||
if(this.getPermissionbit(Permissions.map[name] as number,this.allow)){
|
||||
return 1;
|
||||
}else if(this.getPermissionbit(Permissions.map[name] as number,this.deny)){
|
||||
return-1;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
hasPermission(name:string):boolean{
|
||||
if(this.deny){
|
||||
console.warn("This function may of been used in error, think about using getPermision instead");
|
||||
}
|
||||
if(this.getPermissionbit(Permissions.map[name] as number,this.allow))return true;
|
||||
if(name != "ADMINISTRATOR")return this.hasPermission("ADMINISTRATOR");
|
||||
return false;
|
||||
}
|
||||
setPermission(name:string,setto:number):void{
|
||||
const bit=Permissions.map[name] as number;
|
||||
if(!bit){
|
||||
return console.error("Tried to set permission to " + setto + " for " + name + " but it doesn't exist");
|
||||
}
|
||||
|
||||
if(setto===0){
|
||||
this.deny=this.setPermissionbit(bit,false,this.deny);
|
||||
this.allow=this.setPermissionbit(bit,false,this.allow);
|
||||
}else if(setto===1){
|
||||
|
||||
this.deny=this.setPermissionbit(bit,false,this.deny);
|
||||
this.allow=this.setPermissionbit(bit,true,this.allow);
|
||||
}else if(setto===-1){
|
||||
|
||||
this.deny=this.setPermissionbit(bit,true,this.deny);
|
||||
this.allow=this.setPermissionbit(bit,false,this.allow);
|
||||
}else{
|
||||
console.error("invalid number entered:"+setto);
|
||||
}
|
||||
}
|
||||
if(setto===0){
|
||||
this.deny=this.setPermissionbit(bit,false,this.deny);
|
||||
this.allow=this.setPermissionbit(bit,false,this.allow);
|
||||
}else if(setto===1){
|
||||
this.deny=this.setPermissionbit(bit,false,this.deny);
|
||||
this.allow=this.setPermissionbit(bit,true,this.allow);
|
||||
}else if(setto===-1){
|
||||
this.deny=this.setPermissionbit(bit,true,this.deny);
|
||||
this.allow=this.setPermissionbit(bit,false,this.allow);
|
||||
}else{
|
||||
console.error("invalid number entered:"+setto);
|
||||
}
|
||||
}
|
||||
}
|
||||
Permissions.makeMap();
|
||||
export {Permissions};
|
||||
export{Permissions};
|
||||
|
|
|
@ -1,60 +1,60 @@
|
|||
<body class="Dark-theme">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Jank Client</title>
|
||||
<meta content="Jank Client" property="og:title" />
|
||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description" />
|
||||
<meta content="/logo.webp" property="og:image" />
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||
<link href="/style.css" rel="stylesheet" type="text/css" />
|
||||
<link href="/themes.css" rel="stylesheet" type="text/css" id="lightcss"/>
|
||||
</head>
|
||||
<div id="logindiv">
|
||||
<h1>Create an account</h1><br>
|
||||
<form id="register" submit="registertry(e)">
|
||||
<div>
|
||||
<label for="instance"><b>Instance:</b></label><br>
|
||||
<p id="verify"></p>
|
||||
<input type="search" list="instances" placeholder="Instance URL" id="instancein" name="instance" value="" id="instancein" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="uname"><b>Email:</b></label><br>
|
||||
<input type="text" placeholder="Enter Email" name="uname" id="uname" required>
|
||||
</div>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Jank Client</title>
|
||||
<meta content="Jank Client" property="og:title">
|
||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description">
|
||||
<meta content="/logo.webp" property="og:image">
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
||||
<link href="/style.css" rel="stylesheet">
|
||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
||||
</head>
|
||||
<div id="logindiv">
|
||||
<h1>Create an account</h1><br>
|
||||
<form id="register" submit="registertry(e)">
|
||||
<div>
|
||||
<label for="instance"><b>Instance:</b></label><br>
|
||||
<p id="verify"></p>
|
||||
<input type="search" list="instances" placeholder="Instance URL" id="instancein" name="instance" value="" id="instancein" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="uname"><b>Email:</b></label><br>
|
||||
<input type="text" placeholder="Enter Email" name="uname" id="uname" required>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="uname"><b>Username:</b></label><br>
|
||||
<input type="text" placeholder="Enter Username" name="username" id="username" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="psw"><b>Password:</b></label><br>
|
||||
<input type="password" placeholder="Enter Password" name="psw" id="psw" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="uname"><b>Username:</b></label><br>
|
||||
<input type="text" placeholder="Enter Username" name="username" id="username" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="psw"><b>Password:</b></label><br>
|
||||
<input type="password" placeholder="Enter Password" name="psw" id="psw" required>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="psw2"><b>Enter password again:</b></label><br>
|
||||
<input type="password" placeholder="Enter Password Again" name="psw2" id="psw2" required>
|
||||
</div>
|
||||
<div>
|
||||
<label for="psw2"><b>Enter password again:</b></label><br>
|
||||
<input type="password" placeholder="Enter Password Again" name="psw2" id="psw2" required>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="date"><b>Date of birth:</b></label><br>
|
||||
<input type="date" id="date" name="date"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="date"><b>Date of birth:</b></label><br>
|
||||
<input type="date" id="date" name="date">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<b id="TOSbox">I agree to the <a href="" id="TOSa">Terms of Service</a>:</b>
|
||||
<input type="checkbox" id="TOS" name="TOS"/>
|
||||
</div>
|
||||
<div>
|
||||
<b id="TOSbox">I agree to the <a href="" id="TOSa">Terms of Service</a>:</b>
|
||||
<input type="checkbox" id="TOS" name="TOS">
|
||||
</div>
|
||||
|
||||
<p class="wrongred" id="wrong"></p>
|
||||
<div id="h-captcha">
|
||||
<p class="wrongred" id="wrong"></p>
|
||||
<div id="h-captcha">
|
||||
|
||||
</div>
|
||||
<button type="submit" class="dontgrow">Create account</button>
|
||||
</form>
|
||||
<a href="/login.html" id="switch">Already have an account?</a>
|
||||
</div>
|
||||
<datalist id="instances"></datalist>
|
||||
<script src="/register.js" type="module"></script>
|
||||
</div>
|
||||
<button type="submit" class="dontgrow">Create account</button>
|
||||
</form>
|
||||
<a href="/login.html" id="switch">Already have an account?</a>
|
||||
</div>
|
||||
<datalist id="instances"></datalist>
|
||||
<script src="/register.js" type="module"></script>
|
||||
</body>
|
||||
|
|
|
@ -1,109 +1,110 @@
|
|||
import {checkInstance, adduser} from "./login.js";
|
||||
import{checkInstance, adduser}from"./login.js";
|
||||
if(document.getElementById("register")){
|
||||
document.getElementById("register").addEventListener("submit", registertry);
|
||||
document.getElementById("register").addEventListener("submit", registertry);
|
||||
}
|
||||
async function registertry(e){
|
||||
e.preventDefault();
|
||||
const elements=e.srcElement;
|
||||
const email=elements[1].value;
|
||||
const username=elements[2].value;
|
||||
if(elements[3].value!==elements[4].value){
|
||||
document.getElementById("wrong").textContent="Passwords don't match";
|
||||
return;
|
||||
}
|
||||
const password=elements[3].value;
|
||||
const dateofbirth=elements[5].value;
|
||||
const apiurl=new URL(JSON.parse(localStorage.getItem("instanceinfo")).api);
|
||||
|
||||
e.preventDefault();
|
||||
const elements=e.srcElement;
|
||||
const email=elements[1].value;
|
||||
const username=elements[2].value;
|
||||
if(elements[3].value!==elements[4].value){
|
||||
document.getElementById("wrong").textContent="Passwords don't match";
|
||||
return;
|
||||
}
|
||||
const password=elements[3].value;
|
||||
const dateofbirth=elements[5].value;
|
||||
const apiurl=new URL(JSON.parse(localStorage.getItem("instanceinfo")).api)
|
||||
await fetch(apiurl+"/auth/register",{
|
||||
body: JSON.stringify({
|
||||
date_of_birth: dateofbirth,
|
||||
email,
|
||||
username,
|
||||
password,
|
||||
consent: elements[6].checked,
|
||||
captcha_key: elements[7]?.value
|
||||
}),
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
method: "POST"
|
||||
}).then(e=>{
|
||||
e.json().then(e=>{
|
||||
if(e.captcha_sitekey){
|
||||
const capt=document.getElementById("h-captcha");
|
||||
if(!capt.children.length){
|
||||
const capty=document.createElement("div");
|
||||
capty.classList.add("h-captcha");
|
||||
|
||||
await fetch(apiurl+"/auth/register",{
|
||||
body:JSON.stringify({
|
||||
date_of_birth:dateofbirth,
|
||||
email:email,
|
||||
username:username,
|
||||
password:password,
|
||||
consent:elements[6].checked,
|
||||
captcha_key:elements[7]?.value
|
||||
}),
|
||||
headers:{
|
||||
"content-type": "application/json"
|
||||
},
|
||||
method:"POST"
|
||||
}).then(e=>{
|
||||
e.json().then(e=>{
|
||||
if(e.captcha_sitekey){
|
||||
const capt=document.getElementById("h-captcha");
|
||||
if(!capt.children.length){
|
||||
const capty=document.createElement("div");
|
||||
capty.classList.add("h-captcha");
|
||||
|
||||
capty.setAttribute("data-sitekey", e.captcha_sitekey);
|
||||
const script=document.createElement("script");
|
||||
script.src="https://js.hcaptcha.com/1/api.js";
|
||||
capt.append(script);
|
||||
capt.append(capty);
|
||||
}else{
|
||||
eval("hcaptcha.reset()");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!e.token){
|
||||
console.log(e);
|
||||
if(e.errors.consent){
|
||||
error(elements[6],e.errors.consent._errors[0].message);
|
||||
}else if(e.errors.password){
|
||||
error(elements[3],"Password: "+e.errors.password._errors[0].message);
|
||||
}else if(e.errors.username){
|
||||
error(elements[2],"Username: "+e.errors.username._errors[0].message);
|
||||
}else if(e.errors.email){
|
||||
error(elements[1],"Email: "+e.errors.email._errors[0].message);
|
||||
}else if(e.errors.date_of_birth){
|
||||
error(elements[5],"Date of Birth: "+e.errors.date_of_birth._errors[0].message);
|
||||
}else{
|
||||
document.getElementById("wrong").textContent=e.errors[Object.keys(e.errors)[0]]._errors[0].message;
|
||||
}
|
||||
}else{
|
||||
adduser({serverurls:JSON.parse(localStorage.getItem("instanceinfo")),email:email,token:e.token}).username=username;
|
||||
localStorage.setItem("token",e.token);
|
||||
const redir=new URLSearchParams(window.location.search).get("goback");
|
||||
if(redir){
|
||||
window.location.href = redir;
|
||||
}else{
|
||||
window.location.href = '/channels/@me';
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
//document.getElementById("wrong").textContent=h;
|
||||
// console.log(h);
|
||||
capty.setAttribute("data-sitekey", e.captcha_sitekey);
|
||||
const script=document.createElement("script");
|
||||
script.src="https://js.hcaptcha.com/1/api.js";
|
||||
capt.append(script);
|
||||
capt.append(capty);
|
||||
}else{
|
||||
eval("hcaptcha.reset()");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!e.token){
|
||||
console.log(e);
|
||||
if(e.errors.consent){
|
||||
error(elements[6],e.errors.consent._errors[0].message);
|
||||
}else if(e.errors.password){
|
||||
error(elements[3],"Password: "+e.errors.password._errors[0].message);
|
||||
}else if(e.errors.username){
|
||||
error(elements[2],"Username: "+e.errors.username._errors[0].message);
|
||||
}else if(e.errors.email){
|
||||
error(elements[1],"Email: "+e.errors.email._errors[0].message);
|
||||
}else if(e.errors.date_of_birth){
|
||||
error(elements[5],"Date of Birth: "+e.errors.date_of_birth._errors[0].message);
|
||||
}else{
|
||||
document.getElementById("wrong").textContent=e.errors[Object.keys(e.errors)[0]]._errors[0].message;
|
||||
}
|
||||
}else{
|
||||
adduser({serverurls: JSON.parse(localStorage.getItem("instanceinfo")),email,token: e.token}).username=username;
|
||||
localStorage.setItem("token",e.token);
|
||||
const redir=new URLSearchParams(window.location.search).get("goback");
|
||||
if(redir){
|
||||
window.location.href = redir;
|
||||
}else{
|
||||
window.location.href = "/channels/@me";
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
//document.getElementById("wrong").textContent=h;
|
||||
// console.log(h);
|
||||
}
|
||||
function error(e:HTMLFormElement,message:string){
|
||||
const p=e.parentElement;
|
||||
let element=p.getElementsByClassName("suberror")[0] as HTMLElement;
|
||||
if(!element){
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("suberror","suberrora");
|
||||
p.append(div);
|
||||
element=div;
|
||||
}else{
|
||||
element.classList.remove("suberror");
|
||||
setTimeout(_=>{element.classList.add("suberror")},100);
|
||||
}
|
||||
element.textContent=message;
|
||||
const p=e.parentElement;
|
||||
let element=p.getElementsByClassName("suberror")[0] as HTMLElement;
|
||||
if(!element){
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("suberror","suberrora");
|
||||
p.append(div);
|
||||
element=div;
|
||||
}else{
|
||||
element.classList.remove("suberror");
|
||||
setTimeout(_=>{
|
||||
element.classList.add("suberror");
|
||||
},100);
|
||||
}
|
||||
element.textContent=message;
|
||||
}
|
||||
let TOSa=document.getElementById("TOSa");
|
||||
async function tosLogic(){
|
||||
const apiurl=new URL(JSON.parse(localStorage.getItem("instanceinfo")).api)
|
||||
const tosPage=(await (await fetch(apiurl.toString()+"/ping")).json()).instance.tosPage;
|
||||
if(tosPage){
|
||||
document.getElementById("TOSbox").innerHTML="I agree to the <a href=\"\" id=\"TOSa\">Terms of Service</a>:";
|
||||
TOSa=document.getElementById("TOSa");
|
||||
(TOSa as HTMLAnchorElement).href=tosPage;
|
||||
}else{
|
||||
document.getElementById("TOSbox").textContent="This instance has no Terms of Service, accept ToS anyways:";
|
||||
TOSa=null;
|
||||
}
|
||||
console.log(tosPage);
|
||||
const apiurl=new URL(JSON.parse(localStorage.getItem("instanceinfo")).api);
|
||||
const tosPage=(await (await fetch(apiurl.toString()+"/ping")).json()).instance.tosPage;
|
||||
if(tosPage){
|
||||
document.getElementById("TOSbox").innerHTML="I agree to the <a href=\"\" id=\"TOSa\">Terms of Service</a>:";
|
||||
TOSa=document.getElementById("TOSa");
|
||||
(TOSa as HTMLAnchorElement).href=tosPage;
|
||||
}else{
|
||||
document.getElementById("TOSbox").textContent="This instance has no Terms of Service, accept ToS anyways:";
|
||||
TOSa=null;
|
||||
}
|
||||
console.log(tosPage);
|
||||
}
|
||||
tosLogic();
|
||||
|
||||
|
|
308
webpage/role.ts
308
webpage/role.ts
|
@ -1,162 +1,170 @@
|
|||
|
||||
import {Permissions} from "./permissions.js";
|
||||
import {Localuser} from "./localuser.js";
|
||||
import {Guild} from "./guild.js";
|
||||
import { SnowFlake } from "./snowflake.js";
|
||||
import { rolesjson } from "./jsontypes.js";
|
||||
import{Permissions}from"./permissions.js";
|
||||
import{Localuser}from"./localuser.js";
|
||||
import{Guild}from"./guild.js";
|
||||
import{ SnowFlake }from"./snowflake.js";
|
||||
import{ rolesjson }from"./jsontypes.js";
|
||||
class Role{
|
||||
permissions:Permissions;
|
||||
owner:Guild;
|
||||
color:number;
|
||||
readonly snowflake:SnowFlake<Role>;
|
||||
name:string;
|
||||
info:Guild["info"];
|
||||
hoist:boolean;
|
||||
icon:string;
|
||||
mentionable:boolean;
|
||||
unicode_emoji:string;
|
||||
headers:Guild["headers"];
|
||||
get id(){
|
||||
return this.snowflake.id;
|
||||
}
|
||||
constructor(json:rolesjson, owner:Guild){
|
||||
this.headers=owner.headers;
|
||||
this.info=owner.info;
|
||||
for(const thing of Object.keys(json)){
|
||||
if(thing==="id"){
|
||||
this.snowflake=new SnowFlake(json.id,this);
|
||||
continue;
|
||||
}
|
||||
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|null{
|
||||
if(this.color===0){return null};
|
||||
return `#${this.color.toString(16)}`;
|
||||
}
|
||||
permissions:Permissions;
|
||||
owner:Guild;
|
||||
color:number;
|
||||
readonly snowflake:SnowFlake<Role>;
|
||||
name:string;
|
||||
info:Guild["info"];
|
||||
hoist:boolean;
|
||||
icon:string;
|
||||
mentionable:boolean;
|
||||
unicode_emoji:string;
|
||||
headers:Guild["headers"];
|
||||
get id(){
|
||||
return this.snowflake.id;
|
||||
}
|
||||
constructor(json:rolesjson, owner:Guild){
|
||||
this.headers=owner.headers;
|
||||
this.info=owner.info;
|
||||
for(const thing of Object.keys(json)){
|
||||
if(thing==="id"){
|
||||
this.snowflake=new SnowFlake(json.id,this);
|
||||
continue;
|
||||
}
|
||||
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|null{
|
||||
if(this.color===0){
|
||||
return null;
|
||||
}
|
||||
return`#${this.color.toString(16)}`;
|
||||
}
|
||||
}
|
||||
export {Role};
|
||||
import {Options} from "./settings.js";
|
||||
export{Role};
|
||||
import{Options}from"./settings.js";
|
||||
class PermissionToggle implements OptionsElement<number>{
|
||||
readonly rolejson:{name:string,readableName:string,description:string};
|
||||
permissions:Permissions;
|
||||
owner:Options;
|
||||
value:number;
|
||||
constructor(roleJSON:PermissionToggle["rolejson"],permissions:Permissions,owner:Options){
|
||||
this.rolejson=roleJSON;
|
||||
this.permissions=permissions;
|
||||
this.owner=owner;
|
||||
}
|
||||
watchForChange(){};
|
||||
generateHTML():HTMLElement{
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("setting");
|
||||
const name=document.createElement("span");
|
||||
name.textContent=this.rolejson.readableName;
|
||||
name.classList.add("settingsname");
|
||||
div.append(name);
|
||||
readonly rolejson:{name:string,readableName:string,description:string};
|
||||
permissions:Permissions;
|
||||
owner:Options;
|
||||
value:number;
|
||||
constructor(roleJSON:PermissionToggle["rolejson"],permissions:Permissions,owner:Options){
|
||||
this.rolejson=roleJSON;
|
||||
this.permissions=permissions;
|
||||
this.owner=owner;
|
||||
}
|
||||
watchForChange(){}
|
||||
generateHTML():HTMLElement{
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("setting");
|
||||
const name=document.createElement("span");
|
||||
name.textContent=this.rolejson.readableName;
|
||||
name.classList.add("settingsname");
|
||||
div.append(name);
|
||||
|
||||
|
||||
div.append(this.generateCheckbox());
|
||||
const p=document.createElement("p");
|
||||
p.textContent=this.rolejson.description;
|
||||
div.appendChild(p);
|
||||
return div;
|
||||
}
|
||||
generateCheckbox():HTMLElement{
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("tritoggle");
|
||||
const state=this.permissions.getPermission(this.rolejson.name);
|
||||
div.append(this.generateCheckbox());
|
||||
const p=document.createElement("p");
|
||||
p.textContent=this.rolejson.description;
|
||||
div.appendChild(p);
|
||||
return div;
|
||||
}
|
||||
generateCheckbox():HTMLElement{
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("tritoggle");
|
||||
const state=this.permissions.getPermission(this.rolejson.name);
|
||||
|
||||
const on=document.createElement("input");
|
||||
on.type="radio";
|
||||
on.name=this.rolejson.name;
|
||||
div.append(on);
|
||||
if(state===1){on.checked=true;};
|
||||
on.onclick=_=>{
|
||||
this.permissions.setPermission(this.rolejson.name,1);
|
||||
this.owner.changed();
|
||||
}
|
||||
const on=document.createElement("input");
|
||||
on.type="radio";
|
||||
on.name=this.rolejson.name;
|
||||
div.append(on);
|
||||
if(state===1){
|
||||
on.checked=true;
|
||||
}
|
||||
on.onclick=_=>{
|
||||
this.permissions.setPermission(this.rolejson.name,1);
|
||||
this.owner.changed();
|
||||
};
|
||||
|
||||
const no=document.createElement("input");
|
||||
no.type="radio";
|
||||
no.name=this.rolejson.name;
|
||||
div.append(no);
|
||||
if(state===0){no.checked=true;};
|
||||
no.onclick=_=>{
|
||||
this.permissions.setPermission(this.rolejson.name,0);
|
||||
this.owner.changed();
|
||||
}
|
||||
if(this.permissions.hasDeny){
|
||||
const off=document.createElement("input");
|
||||
off.type="radio";
|
||||
off.name=this.rolejson.name;
|
||||
div.append(off);
|
||||
if(state===-1){off.checked=true;};
|
||||
off.onclick=_=>{
|
||||
this.permissions.setPermission(this.rolejson.name,-1);
|
||||
this.owner.changed();
|
||||
}
|
||||
}
|
||||
return div;
|
||||
}
|
||||
submit(){
|
||||
const no=document.createElement("input");
|
||||
no.type="radio";
|
||||
no.name=this.rolejson.name;
|
||||
div.append(no);
|
||||
if(state===0){
|
||||
no.checked=true;
|
||||
}
|
||||
no.onclick=_=>{
|
||||
this.permissions.setPermission(this.rolejson.name,0);
|
||||
this.owner.changed();
|
||||
};
|
||||
if(this.permissions.hasDeny){
|
||||
const off=document.createElement("input");
|
||||
off.type="radio";
|
||||
off.name=this.rolejson.name;
|
||||
div.append(off);
|
||||
if(state===-1){
|
||||
off.checked=true;
|
||||
}
|
||||
off.onclick=_=>{
|
||||
this.permissions.setPermission(this.rolejson.name,-1);
|
||||
this.owner.changed();
|
||||
};
|
||||
}
|
||||
return div;
|
||||
}
|
||||
submit(){
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
import { OptionsElement,Buttons } from "./settings.js";
|
||||
import{ OptionsElement,Buttons }from"./settings.js";
|
||||
class RoleList extends Buttons{
|
||||
readonly permissions:[SnowFlake<Role>,Permissions][];
|
||||
permission:Permissions;
|
||||
readonly guild:Guild;
|
||||
readonly channel:boolean;
|
||||
readonly declare buttons:[string,string][];
|
||||
readonly options:Options;
|
||||
onchange:Function;
|
||||
curid:string;
|
||||
constructor(permissions:[SnowFlake<Role>,Permissions][],guild:Guild,onchange:Function,channel=false){
|
||||
super("Roles");
|
||||
this.guild=guild;
|
||||
this.permissions=permissions;
|
||||
this.channel=channel;
|
||||
this.onchange=onchange;
|
||||
const options=new Options("",this);
|
||||
if(channel){
|
||||
this.permission=new Permissions("0","0");
|
||||
}else{
|
||||
this.permission=new Permissions("0");
|
||||
}
|
||||
for(const thing of Permissions.info){
|
||||
options.options.push(new PermissionToggle(thing,this.permission,options));
|
||||
}
|
||||
for(const i of permissions){
|
||||
console.log(i);
|
||||
this.buttons.push([i[0].getObject().name,i[0].id])//
|
||||
}
|
||||
this.options=options;
|
||||
}
|
||||
handleString(str:string):HTMLElement{
|
||||
this.curid=str;
|
||||
const arr=this.permissions.find(_=>_[0].id===str);
|
||||
if(arr){
|
||||
const perm=arr[1];
|
||||
this.permission.deny=perm.deny;
|
||||
this.permission.allow=perm.allow;
|
||||
this.options.name=SnowFlake.getSnowFlakeFromID(str,Role).getObject().name;
|
||||
this.options.haschanged=false;
|
||||
}
|
||||
return this.options.generateHTML();
|
||||
}
|
||||
save(){
|
||||
this.onchange(this.curid,this.permission);
|
||||
}
|
||||
readonly permissions:[SnowFlake<Role>,Permissions][];
|
||||
permission:Permissions;
|
||||
readonly guild:Guild;
|
||||
readonly channel:boolean;
|
||||
readonly declare buttons:[string,string][];
|
||||
readonly options:Options;
|
||||
onchange:Function;
|
||||
curid:string;
|
||||
constructor(permissions:[SnowFlake<Role>,Permissions][],guild:Guild,onchange:Function,channel=false){
|
||||
super("Roles");
|
||||
this.guild=guild;
|
||||
this.permissions=permissions;
|
||||
this.channel=channel;
|
||||
this.onchange=onchange;
|
||||
const options=new Options("",this);
|
||||
if(channel){
|
||||
this.permission=new Permissions("0","0");
|
||||
}else{
|
||||
this.permission=new Permissions("0");
|
||||
}
|
||||
for(const thing of Permissions.info){
|
||||
options.options.push(new PermissionToggle(thing,this.permission,options));
|
||||
}
|
||||
for(const i of permissions){
|
||||
console.log(i);
|
||||
this.buttons.push([i[0].getObject().name,i[0].id]);//
|
||||
}
|
||||
this.options=options;
|
||||
}
|
||||
handleString(str:string):HTMLElement{
|
||||
this.curid=str;
|
||||
const arr=this.permissions.find(_=>_[0].id===str);
|
||||
if(arr){
|
||||
const perm=arr[1];
|
||||
this.permission.deny=perm.deny;
|
||||
this.permission.allow=perm.allow;
|
||||
this.options.name=SnowFlake.getSnowFlakeFromID(str,Role).getObject().name;
|
||||
this.options.haschanged=false;
|
||||
}
|
||||
return this.options.generateHTML();
|
||||
}
|
||||
save(){
|
||||
this.onchange(this.curid,this.permission);
|
||||
}
|
||||
}
|
||||
export {RoleList}
|
||||
export{RoleList};
|
||||
|
|
|
@ -1,87 +1,93 @@
|
|||
function deleteoldcache(){
|
||||
caches.delete("cache");
|
||||
console.log("this ran :P")
|
||||
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(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();
|
||||
})
|
||||
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);
|
||||
})
|
||||
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;
|
||||
return new URL(url).origin===self.origin;
|
||||
}
|
||||
function isindexhtml(url){
|
||||
console.log(url);
|
||||
if(new URL(url).pathname.startsWith("/channels")){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
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)}
|
||||
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:any) => {
|
||||
try{
|
||||
event.respondWith(getfile(event));
|
||||
}catch(e){console.error(e)}
|
||||
})
|
||||
self.addEventListener("fetch", (event:any)=>{
|
||||
try{
|
||||
event.respondWith(getfile(event));
|
||||
}catch(e){
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
|
1697
webpage/settings.ts
1697
webpage/settings.ts
File diff suppressed because it is too large
Load diff
|
@ -1,95 +1,95 @@
|
|||
class SnowFlake<x extends WeakKey>{
|
||||
public readonly id:string;
|
||||
private static SnowFlakes:Map<any,Map<string,WeakRef<SnowFlake<any>>>>=new Map();
|
||||
private static readonly FinalizationRegistry=new FinalizationRegistry((a:[string,WeakKey])=>{
|
||||
SnowFlake.SnowFlakes.get(a[1]).delete(a[0]);
|
||||
});
|
||||
private obj:x;
|
||||
constructor(id:string,obj:x){
|
||||
if(!obj){
|
||||
this.id=id;
|
||||
return;
|
||||
}
|
||||
if(!SnowFlake.SnowFlakes.get(obj.constructor)){
|
||||
SnowFlake.SnowFlakes.set(obj.constructor,new Map());
|
||||
}
|
||||
if(SnowFlake.SnowFlakes.get(obj.constructor).get(id)){
|
||||
const snowflake=SnowFlake.SnowFlakes.get(obj.constructor).get(id).deref();
|
||||
if(snowflake){
|
||||
snowflake.obj=obj;
|
||||
return snowflake;
|
||||
}else{
|
||||
SnowFlake.SnowFlakes.get(obj.constructor).delete(id);
|
||||
}
|
||||
}
|
||||
this.id=id;
|
||||
SnowFlake.SnowFlakes.get(obj.constructor).set(id,new WeakRef(this));
|
||||
SnowFlake.FinalizationRegistry.register(this,[id,obj.constructor]);
|
||||
this.obj=obj;
|
||||
}
|
||||
static clear(){//this is kinda a temp solution, it should be fixed, though its not that easy to do so
|
||||
this.SnowFlakes=new Map();
|
||||
}
|
||||
/**
|
||||
public readonly id:string;
|
||||
private static SnowFlakes:Map<any,Map<string,WeakRef<SnowFlake<any>>>>=new Map();
|
||||
private static readonly FinalizationRegistry=new FinalizationRegistry((a:[string,WeakKey])=>{
|
||||
SnowFlake.SnowFlakes.get(a[1]).delete(a[0]);
|
||||
});
|
||||
private obj:x;
|
||||
constructor(id:string,obj:x){
|
||||
if(!obj){
|
||||
this.id=id;
|
||||
return;
|
||||
}
|
||||
if(!SnowFlake.SnowFlakes.get(obj.constructor)){
|
||||
SnowFlake.SnowFlakes.set(obj.constructor,new Map());
|
||||
}
|
||||
if(SnowFlake.SnowFlakes.get(obj.constructor).get(id)){
|
||||
const snowflake=SnowFlake.SnowFlakes.get(obj.constructor).get(id).deref();
|
||||
if(snowflake){
|
||||
snowflake.obj=obj;
|
||||
return snowflake;
|
||||
}else{
|
||||
SnowFlake.SnowFlakes.get(obj.constructor).delete(id);
|
||||
}
|
||||
}
|
||||
this.id=id;
|
||||
SnowFlake.SnowFlakes.get(obj.constructor).set(id,new WeakRef(this));
|
||||
SnowFlake.FinalizationRegistry.register(this,[id,obj.constructor]);
|
||||
this.obj=obj;
|
||||
}
|
||||
static clear(){//this is kinda a temp solution, it should be fixed, though its not that easy to do so
|
||||
this.SnowFlakes=new Map();
|
||||
}
|
||||
/**
|
||||
* Just to clarify bc TS, it returns a SnowFlake\<type> which is what you entered with the type parameter
|
||||
* @deprecated
|
||||
**/
|
||||
static getSnowFlakeFromID<T extends {}>(id:string,type: abstract new(...args: never) => T): SnowFlake<T>{
|
||||
if(!SnowFlake.SnowFlakes.get(type)){
|
||||
SnowFlake.SnowFlakes.set(type,new Map());
|
||||
}
|
||||
const snowflake=SnowFlake.SnowFlakes.get(type).get(id);
|
||||
if(snowflake){
|
||||
const obj=snowflake.deref();
|
||||
if(obj){
|
||||
return obj;
|
||||
}else{
|
||||
SnowFlake.SnowFlakes.get(type).delete(id);
|
||||
}
|
||||
}
|
||||
{
|
||||
const snowflake=new SnowFlake(id,undefined);
|
||||
static getSnowFlakeFromID<T extends {}>(id:string,type: abstract new(...args: never) => T): SnowFlake<T>{
|
||||
if(!SnowFlake.SnowFlakes.get(type)){
|
||||
SnowFlake.SnowFlakes.set(type,new Map());
|
||||
}
|
||||
const snowflake=SnowFlake.SnowFlakes.get(type).get(id);
|
||||
if(snowflake){
|
||||
const obj=snowflake.deref();
|
||||
if(obj){
|
||||
return obj;
|
||||
}else{
|
||||
SnowFlake.SnowFlakes.get(type).delete(id);
|
||||
}
|
||||
}
|
||||
{
|
||||
const snowflake=new SnowFlake(id,undefined);
|
||||
|
||||
SnowFlake.SnowFlakes.get(type).set(id,new WeakRef(snowflake));
|
||||
SnowFlake.FinalizationRegistry.register(this,[id,type]);
|
||||
SnowFlake.SnowFlakes.get(type).set(id,new WeakRef(snowflake));
|
||||
SnowFlake.FinalizationRegistry.register(this,[id,type]);
|
||||
|
||||
return snowflake;
|
||||
}
|
||||
}
|
||||
/**
|
||||
return snowflake;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
*
|
||||
*/
|
||||
static hasSnowFlakeFromID(id:string,type:any){
|
||||
if(!SnowFlake.SnowFlakes.get(type)){
|
||||
return false;
|
||||
}
|
||||
const flake=SnowFlake.SnowFlakes.get(type).get(id);
|
||||
if(flake){
|
||||
const flake2=flake.deref()?.getObject();
|
||||
if(flake2){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
getUnixTime():number{
|
||||
try{
|
||||
return Number((BigInt(this.id)>>22n)+1420070400000n);
|
||||
}catch{
|
||||
console.error(`The ID is corrupted, it's ${this.id} when it should be some number.`)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
toString(){
|
||||
return this.id;
|
||||
}
|
||||
getObject():x{
|
||||
return this.obj;
|
||||
}
|
||||
static hasSnowFlakeFromID(id:string,type:any){
|
||||
if(!SnowFlake.SnowFlakes.get(type)){
|
||||
return false;
|
||||
}
|
||||
const flake=SnowFlake.SnowFlakes.get(type).get(id);
|
||||
if(flake){
|
||||
const flake2=flake.deref()?.getObject();
|
||||
if(flake2){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
getUnixTime():number{
|
||||
try{
|
||||
return Number((BigInt(this.id)>>22n)+1420070400000n);
|
||||
}catch{
|
||||
console.error(`The ID is corrupted, it's ${this.id} when it should be some number.`);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
toString(){
|
||||
return this.id;
|
||||
}
|
||||
getObject():x{
|
||||
return this.obj;
|
||||
}
|
||||
}
|
||||
export {SnowFlake};
|
||||
export{SnowFlake};
|
||||
|
|
835
webpage/user.ts
835
webpage/user.ts
|
@ -1,431 +1,432 @@
|
|||
//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";
|
||||
import { SnowFlake } from "./snowflake.js";
|
||||
import { presencejson, userjson } from "./jsontypes.js";
|
||||
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";
|
||||
import{ SnowFlake }from"./snowflake.js";
|
||||
import{ presencejson, userjson }from"./jsontypes.js";
|
||||
|
||||
class User{
|
||||
owner:Localuser;
|
||||
hypotheticalpfp:boolean;
|
||||
snowflake:SnowFlake<User>;
|
||||
avatar:string|null;
|
||||
username:string;
|
||||
nickname:string|null=null;
|
||||
relationshipType:0|1|2|3|4=0;
|
||||
bio:MarkDown;
|
||||
discriminator:string;
|
||||
pronouns:string;
|
||||
bot:boolean;
|
||||
public_flags: number;
|
||||
accent_color: number;
|
||||
banner: string|undefined;
|
||||
hypotheticalbanner:boolean;
|
||||
premium_since: string;
|
||||
premium_type: number;
|
||||
theme_colors: string;
|
||||
badge_ids: string[];
|
||||
members: WeakMap<Guild, Member|undefined|Promise<Member|undefined>>=new WeakMap();
|
||||
private status:string;
|
||||
clone(){
|
||||
return new User({
|
||||
username:this.username,
|
||||
id:this.id+"#clone",
|
||||
public_flags:this.public_flags,
|
||||
discriminator:this.discriminator,
|
||||
avatar:this.avatar,
|
||||
accent_color:this.accent_color,
|
||||
banner:this.banner,
|
||||
bio:this.bio.rawString,
|
||||
premium_since:this.premium_since,
|
||||
premium_type:this.premium_type,
|
||||
bot:this.bot,
|
||||
theme_colors:this.theme_colors,
|
||||
pronouns:this.pronouns,
|
||||
badge_ids:this.badge_ids
|
||||
},this.owner)
|
||||
}
|
||||
public getPresence(presence:presencejson|undefined){
|
||||
if(presence){
|
||||
this.setstatus(presence.status);
|
||||
}else{
|
||||
this.setstatus("offline");
|
||||
}
|
||||
}
|
||||
setstatus(status:string){
|
||||
this.status=status;
|
||||
}
|
||||
async getStatus(){
|
||||
if(this.status){
|
||||
return this.status;
|
||||
}else{
|
||||
return "offline";
|
||||
}
|
||||
}
|
||||
get id(){
|
||||
return this.snowflake.id;
|
||||
}
|
||||
static contextmenu=new Contextmenu<User,Member|undefined>("User Menu");
|
||||
static setUpContextMenu(){
|
||||
this.contextmenu.addbutton("Copy user id",function(this:User){
|
||||
navigator.clipboard.writeText(this.id);
|
||||
});
|
||||
this.contextmenu.addbutton("Message user",function(this:User){
|
||||
fetch(this.info.api+"/users/@me/channels",
|
||||
{method:"POST",
|
||||
body:JSON.stringify({"recipients":[this.id]}),
|
||||
headers: this.localuser.headers
|
||||
});
|
||||
});
|
||||
this.contextmenu.addbutton("Block user",function(this:User){
|
||||
this.block();
|
||||
},null,function(){
|
||||
return this.relationshipType!==2
|
||||
});
|
||||
owner:Localuser;
|
||||
hypotheticalpfp:boolean;
|
||||
snowflake:SnowFlake<User>;
|
||||
avatar:string|null;
|
||||
username:string;
|
||||
nickname:string|null=null;
|
||||
relationshipType:0|1|2|3|4=0;
|
||||
bio:MarkDown;
|
||||
discriminator:string;
|
||||
pronouns:string;
|
||||
bot:boolean;
|
||||
public_flags: number;
|
||||
accent_color: number;
|
||||
banner: string|undefined;
|
||||
hypotheticalbanner:boolean;
|
||||
premium_since: string;
|
||||
premium_type: number;
|
||||
theme_colors: string;
|
||||
badge_ids: string[];
|
||||
members: WeakMap<Guild, Member|undefined|Promise<Member|undefined>>=new WeakMap();
|
||||
private status:string;
|
||||
clone(){
|
||||
return new User({
|
||||
username: this.username,
|
||||
id: this.id+"#clone",
|
||||
public_flags: this.public_flags,
|
||||
discriminator: this.discriminator,
|
||||
avatar: this.avatar,
|
||||
accent_color: this.accent_color,
|
||||
banner: this.banner,
|
||||
bio: this.bio.rawString,
|
||||
premium_since: this.premium_since,
|
||||
premium_type: this.premium_type,
|
||||
bot: this.bot,
|
||||
theme_colors: this.theme_colors,
|
||||
pronouns: this.pronouns,
|
||||
badge_ids: this.badge_ids
|
||||
},this.owner);
|
||||
}
|
||||
public getPresence(presence:presencejson|undefined){
|
||||
if(presence){
|
||||
this.setstatus(presence.status);
|
||||
}else{
|
||||
this.setstatus("offline");
|
||||
}
|
||||
}
|
||||
setstatus(status:string){
|
||||
this.status=status;
|
||||
}
|
||||
async getStatus(){
|
||||
if(this.status){
|
||||
return this.status;
|
||||
}else{
|
||||
return"offline";
|
||||
}
|
||||
}
|
||||
get id(){
|
||||
return this.snowflake.id;
|
||||
}
|
||||
static contextmenu=new Contextmenu<User,Member|undefined>("User Menu");
|
||||
static setUpContextMenu(){
|
||||
this.contextmenu.addbutton("Copy user id",function(this:User){
|
||||
navigator.clipboard.writeText(this.id);
|
||||
});
|
||||
this.contextmenu.addbutton("Message user",function(this:User){
|
||||
fetch(this.info.api+"/users/@me/channels",
|
||||
{method: "POST",
|
||||
body: JSON.stringify({recipients: [this.id]}),
|
||||
headers: this.localuser.headers
|
||||
});
|
||||
});
|
||||
this.contextmenu.addbutton("Block user",function(this:User){
|
||||
this.block();
|
||||
},null,function(){
|
||||
return this.relationshipType!==2;
|
||||
});
|
||||
|
||||
this.contextmenu.addbutton("Unblock user",function(this:User){
|
||||
this.unblock();
|
||||
},null,function(){
|
||||
return this.relationshipType===2
|
||||
});
|
||||
this.contextmenu.addbutton("Friend request",function(this:User){
|
||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{
|
||||
method:"PUT",
|
||||
headers:this.owner.headers,
|
||||
body:JSON.stringify({
|
||||
type:1
|
||||
})
|
||||
})
|
||||
});
|
||||
this.contextmenu.addbutton("Kick member",function(this:User,member:Member){
|
||||
member.kick();
|
||||
},null,function(member){
|
||||
if(!member) return false;
|
||||
const us=member.guild.member;
|
||||
if(member.id===us.id){
|
||||
return false;
|
||||
}
|
||||
if(member.id===member.guild.properties.owner_id){
|
||||
return false;
|
||||
}
|
||||
return (us.hasPermission("KICK_MEMBERS"))||false;
|
||||
});
|
||||
this.contextmenu.addbutton("Ban member",function(this:User,member:Member){
|
||||
member.ban();
|
||||
},null,function(member){
|
||||
if(!member) return false;
|
||||
const us=member.guild.member;
|
||||
if(member.id===us.id){
|
||||
return false;
|
||||
}
|
||||
if(member.id===member.guild.properties.owner_id){
|
||||
return false;
|
||||
}
|
||||
return (us.hasPermission("BAN_MEMBERS"))||false;
|
||||
});
|
||||
}
|
||||
static checkuser(user:User|userjson,owner:Localuser):User{
|
||||
if(owner.userMap.has(user.id)){
|
||||
return owner.userMap.get(user.id) as User;
|
||||
}else{
|
||||
const tempuser=new User(user as userjson,owner,true)
|
||||
owner.userMap.set(user.id,tempuser);
|
||||
return tempuser;
|
||||
}
|
||||
}
|
||||
get info(){
|
||||
return this.owner.info;
|
||||
}
|
||||
get localuser(){
|
||||
return this.owner;
|
||||
}
|
||||
constructor(userjson:userjson,owner:Localuser,dontclone=false){
|
||||
this.owner=owner;
|
||||
if(!owner){console.error("missing localuser")}
|
||||
if(dontclone){
|
||||
for(const thing of Object.keys(userjson)){
|
||||
if(thing==="bio"){
|
||||
this.bio=new MarkDown(userjson[thing],this.localuser);
|
||||
continue;
|
||||
}
|
||||
if(thing === "id"){
|
||||
this.snowflake=new SnowFlake(userjson[thing],this);
|
||||
continue;
|
||||
}
|
||||
this[thing]=userjson[thing];
|
||||
}
|
||||
this.hypotheticalpfp=false;
|
||||
}else{
|
||||
return User.checkuser(userjson,owner);
|
||||
}
|
||||
}
|
||||
async resolvemember(guild:Guild){
|
||||
return await Member.resolveMember(this,guild);
|
||||
}
|
||||
this.contextmenu.addbutton("Unblock user",function(this:User){
|
||||
this.unblock();
|
||||
},null,function(){
|
||||
return this.relationshipType===2;
|
||||
});
|
||||
this.contextmenu.addbutton("Friend request",function(this:User){
|
||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{
|
||||
method: "PUT",
|
||||
headers: this.owner.headers,
|
||||
body: JSON.stringify({
|
||||
type: 1
|
||||
})
|
||||
});
|
||||
});
|
||||
this.contextmenu.addbutton("Kick member",function(this:User,member:Member){
|
||||
member.kick();
|
||||
},null,member=>{
|
||||
if(!member)return false;
|
||||
const us=member.guild.member;
|
||||
if(member.id===us.id){
|
||||
return false;
|
||||
}
|
||||
if(member.id===member.guild.properties.owner_id){
|
||||
return false;
|
||||
}
|
||||
return(us.hasPermission("KICK_MEMBERS"))||false;
|
||||
});
|
||||
this.contextmenu.addbutton("Ban member",function(this:User,member:Member){
|
||||
member.ban();
|
||||
},null,member=>{
|
||||
if(!member)return false;
|
||||
const us=member.guild.member;
|
||||
if(member.id===us.id){
|
||||
return false;
|
||||
}
|
||||
if(member.id===member.guild.properties.owner_id){
|
||||
return false;
|
||||
}
|
||||
return(us.hasPermission("BAN_MEMBERS"))||false;
|
||||
});
|
||||
}
|
||||
static checkuser(user:User|userjson,owner:Localuser):User{
|
||||
if(owner.userMap.has(user.id)){
|
||||
return owner.userMap.get(user.id) as User;
|
||||
}else{
|
||||
const tempuser=new User(user as userjson,owner,true);
|
||||
owner.userMap.set(user.id,tempuser);
|
||||
return tempuser;
|
||||
}
|
||||
}
|
||||
get info(){
|
||||
return this.owner.info;
|
||||
}
|
||||
get localuser(){
|
||||
return this.owner;
|
||||
}
|
||||
constructor(userjson:userjson,owner:Localuser,dontclone=false){
|
||||
this.owner=owner;
|
||||
if(!owner){
|
||||
console.error("missing localuser");
|
||||
}
|
||||
if(dontclone){
|
||||
for(const thing of Object.keys(userjson)){
|
||||
if(thing==="bio"){
|
||||
this.bio=new MarkDown(userjson[thing],this.localuser);
|
||||
continue;
|
||||
}
|
||||
if(thing === "id"){
|
||||
this.snowflake=new SnowFlake(userjson[thing],this);
|
||||
continue;
|
||||
}
|
||||
this[thing]=userjson[thing];
|
||||
}
|
||||
this.hypotheticalpfp=false;
|
||||
}else{
|
||||
return User.checkuser(userjson,owner);
|
||||
}
|
||||
}
|
||||
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){
|
||||
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);
|
||||
}
|
||||
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){
|
||||
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.loading="lazy";
|
||||
pfp.src=this.getpfpsrc();
|
||||
pfp.classList.add("pfp");
|
||||
pfp.classList.add("userid:"+this.id);
|
||||
return pfp;
|
||||
}
|
||||
async buildstatuspfp(){
|
||||
const div=document.createElement("div");
|
||||
div.style.position="relative";
|
||||
const pfp=this.buildpfp();
|
||||
div.append(pfp);
|
||||
{
|
||||
const status=document.createElement("div");
|
||||
status.classList.add("statusDiv");
|
||||
switch(await this.getStatus()){
|
||||
case "offline":
|
||||
status.classList.add("offlinestatus");
|
||||
break;
|
||||
case "online":
|
||||
default:
|
||||
status.classList.add("onlinestatus");
|
||||
break;
|
||||
}
|
||||
div.append(status);
|
||||
}
|
||||
return div;
|
||||
}
|
||||
userupdate(json:userjson){
|
||||
if(json.avatar!==this.avatar){
|
||||
console.log
|
||||
this.changepfp(json.avatar);
|
||||
}
|
||||
}
|
||||
bind(html:HTMLElement,guild:Guild|null=null,error=true){
|
||||
if(guild&&guild.id!=="@me"){
|
||||
Member.resolveMember(this,guild).then(_=>{
|
||||
User.contextmenu.bindContextmenu(html,this,_);
|
||||
if(_===undefined&&error){
|
||||
const error=document.createElement("span");
|
||||
error.textContent="!";
|
||||
error.classList.add("membererror");
|
||||
html.after(error);
|
||||
return;
|
||||
}
|
||||
if(_){
|
||||
_.bind(html);
|
||||
}
|
||||
}).catch(_=>{
|
||||
console.log(_)
|
||||
});
|
||||
}
|
||||
if(guild){
|
||||
this.profileclick(html,guild);
|
||||
}else{
|
||||
this.profileclick(html);
|
||||
}
|
||||
}
|
||||
static async resolve(id:string,localuser:Localuser){
|
||||
const json=await fetch(localuser.info.api.toString()+"/users/"+id+"/profile",
|
||||
{headers:localuser.headers}
|
||||
).then(_=>_.json());
|
||||
return new User(json,localuser);
|
||||
}
|
||||
changepfp(update:string|null){
|
||||
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;
|
||||
}
|
||||
}
|
||||
block(){
|
||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{
|
||||
method:"PUT",
|
||||
headers:this.owner.headers,
|
||||
body:JSON.stringify({
|
||||
type:2
|
||||
})
|
||||
})
|
||||
this.relationshipType=2;
|
||||
const channel=this.localuser.channelfocus;
|
||||
if(channel){
|
||||
for(const thing of channel.messages){
|
||||
thing[1].generateMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
unblock(){
|
||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{
|
||||
method:"DELETE",
|
||||
headers:this.owner.headers,
|
||||
})
|
||||
this.relationshipType=0;
|
||||
const channel=this.localuser.channelfocus;
|
||||
if(channel){
|
||||
for(const thing of channel.messages){
|
||||
thing[1].generateMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
getpfpsrc(){
|
||||
if(this.hypotheticalpfp&&this.avatar){
|
||||
return this.avatar;
|
||||
}
|
||||
if(this.avatar!=null){
|
||||
return this.info.cdn+"/avatars/"+this.id.replace("#clone","")+"/"+this.avatar+".png";
|
||||
}else{
|
||||
const int=new Number((BigInt(this.id.replace("#clone","")) >> 22n) % 6n);
|
||||
return this.info.cdn+`/embed/avatars/${int}.png`;
|
||||
}
|
||||
}
|
||||
createjankpromises(){
|
||||
new Promise(_=>{})
|
||||
}
|
||||
async buildprofile(x:number,y:number,guild:Guild|null=null){
|
||||
if(Contextmenu.currentmenu!=""){
|
||||
Contextmenu.currentmenu.remove();
|
||||
}
|
||||
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.loading="lazy";
|
||||
pfp.src=this.getpfpsrc();
|
||||
pfp.classList.add("pfp");
|
||||
pfp.classList.add("userid:"+this.id);
|
||||
return pfp;
|
||||
}
|
||||
async buildstatuspfp(){
|
||||
const div=document.createElement("div");
|
||||
div.style.position="relative";
|
||||
const pfp=this.buildpfp();
|
||||
div.append(pfp);
|
||||
{
|
||||
const status=document.createElement("div");
|
||||
status.classList.add("statusDiv");
|
||||
switch(await this.getStatus()){
|
||||
case"offline":
|
||||
status.classList.add("offlinestatus");
|
||||
break;
|
||||
case"online":
|
||||
default:
|
||||
status.classList.add("onlinestatus");
|
||||
break;
|
||||
}
|
||||
div.append(status);
|
||||
}
|
||||
return div;
|
||||
}
|
||||
userupdate(json:userjson){
|
||||
if(json.avatar!==this.avatar){
|
||||
console.log;
|
||||
this.changepfp(json.avatar);
|
||||
}
|
||||
}
|
||||
bind(html:HTMLElement,guild:Guild|null=null,error=true){
|
||||
if(guild&&guild.id!=="@me"){
|
||||
Member.resolveMember(this,guild).then(_=>{
|
||||
User.contextmenu.bindContextmenu(html,this,_);
|
||||
if(_===undefined&&error){
|
||||
const error=document.createElement("span");
|
||||
error.textContent="!";
|
||||
error.classList.add("membererror");
|
||||
html.after(error);
|
||||
return;
|
||||
}
|
||||
if(_){
|
||||
_.bind(html);
|
||||
}
|
||||
}).catch(_=>{
|
||||
console.log(_);
|
||||
});
|
||||
}
|
||||
if(guild){
|
||||
this.profileclick(html,guild);
|
||||
}else{
|
||||
this.profileclick(html);
|
||||
}
|
||||
}
|
||||
static async resolve(id:string,localuser:Localuser){
|
||||
const json=await fetch(localuser.info.api.toString()+"/users/"+id+"/profile",
|
||||
{headers: localuser.headers}
|
||||
).then(_=>_.json());
|
||||
return new User(json,localuser);
|
||||
}
|
||||
changepfp(update:string|null){
|
||||
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;
|
||||
}
|
||||
}
|
||||
block(){
|
||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{
|
||||
method: "PUT",
|
||||
headers: this.owner.headers,
|
||||
body: JSON.stringify({
|
||||
type: 2
|
||||
})
|
||||
});
|
||||
this.relationshipType=2;
|
||||
const channel=this.localuser.channelfocus;
|
||||
if(channel){
|
||||
for(const thing of channel.messages){
|
||||
thing[1].generateMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
unblock(){
|
||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`,{
|
||||
method: "DELETE",
|
||||
headers: this.owner.headers,
|
||||
});
|
||||
this.relationshipType=0;
|
||||
const channel=this.localuser.channelfocus;
|
||||
if(channel){
|
||||
for(const thing of channel.messages){
|
||||
thing[1].generateMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
getpfpsrc(){
|
||||
if(this.hypotheticalpfp&&this.avatar){
|
||||
return this.avatar;
|
||||
}
|
||||
if(this.avatar!=null){
|
||||
return this.info.cdn+"/avatars/"+this.id.replace("#clone","")+"/"+this.avatar+".png";
|
||||
}else{
|
||||
const int=new Number((BigInt(this.id.replace("#clone","")) >> 22n) % 6n);
|
||||
return this.info.cdn+`/embed/avatars/${int}.png`;
|
||||
}
|
||||
}
|
||||
createjankpromises(){
|
||||
new Promise(_=>{});
|
||||
}
|
||||
async buildprofile(x:number,y:number,guild:Guild|null=null){
|
||||
if(Contextmenu.currentmenu!=""){
|
||||
Contextmenu.currentmenu.remove();
|
||||
}
|
||||
|
||||
|
||||
const div=document.createElement("div");
|
||||
const div=document.createElement("div");
|
||||
|
||||
if(this.accent_color){
|
||||
div.style.setProperty("--accent_color","#"+this.accent_color.toString(16).padStart(6,"0"));
|
||||
}else{
|
||||
div.style.setProperty("--accent_color","transparent");
|
||||
}
|
||||
if(this.banner){
|
||||
const banner=document.createElement("img")
|
||||
let src:string;
|
||||
if(!this.hypotheticalbanner){
|
||||
src=this.info.cdn+"/avatars/"+this.id.replace("#clone","")+"/"+this.banner+".png";
|
||||
}else{
|
||||
src=this.banner;
|
||||
}
|
||||
console.log(src,this.banner);
|
||||
banner.src=src;
|
||||
banner.classList.add("banner");
|
||||
div.append(banner);
|
||||
}
|
||||
if(x!==-1){
|
||||
div.style.left=x+"px";
|
||||
div.style.top=y+"px";
|
||||
div.classList.add("profile","flexttb");
|
||||
}else{
|
||||
this.setstatus("online");
|
||||
div.classList.add("hypoprofile","flexttb");
|
||||
}
|
||||
const badgediv=document.createElement("div");
|
||||
badgediv.classList.add("badges");
|
||||
(async ()=>{
|
||||
if(!this.badge_ids) return;
|
||||
for(const id of this.badge_ids){
|
||||
const badgejson=await this.getBadge(id);
|
||||
if(badgejson){
|
||||
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);
|
||||
}
|
||||
{
|
||||
const userbody=document.createElement("div");
|
||||
userbody.classList.add("infosection");
|
||||
div.appendChild(userbody);
|
||||
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;
|
||||
userbody.appendChild(discrimatorhtml)
|
||||
if(this.accent_color){
|
||||
div.style.setProperty("--accent_color","#"+this.accent_color.toString(16).padStart(6,"0"));
|
||||
}else{
|
||||
div.style.setProperty("--accent_color","transparent");
|
||||
}
|
||||
if(this.banner){
|
||||
const banner=document.createElement("img");
|
||||
let src:string;
|
||||
if(!this.hypotheticalbanner){
|
||||
src=this.info.cdn+"/avatars/"+this.id.replace("#clone","")+"/"+this.banner+".png";
|
||||
}else{
|
||||
src=this.banner;
|
||||
}
|
||||
console.log(src,this.banner);
|
||||
banner.src=src;
|
||||
banner.classList.add("banner");
|
||||
div.append(banner);
|
||||
}
|
||||
if(x!==-1){
|
||||
div.style.left=x+"px";
|
||||
div.style.top=y+"px";
|
||||
div.classList.add("profile","flexttb");
|
||||
}else{
|
||||
this.setstatus("online");
|
||||
div.classList.add("hypoprofile","flexttb");
|
||||
}
|
||||
const badgediv=document.createElement("div");
|
||||
badgediv.classList.add("badges");
|
||||
(async ()=>{
|
||||
if(!this.badge_ids)return;
|
||||
for(const id of this.badge_ids){
|
||||
const badgejson=await this.getBadge(id);
|
||||
if(badgejson){
|
||||
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);
|
||||
}
|
||||
{
|
||||
const userbody=document.createElement("div");
|
||||
userbody.classList.add("infosection");
|
||||
div.appendChild(userbody);
|
||||
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;
|
||||
userbody.appendChild(discrimatorhtml);
|
||||
|
||||
const pronounshtml=document.createElement("p");
|
||||
pronounshtml.textContent=this.pronouns;
|
||||
pronounshtml.classList.add("pronouns");
|
||||
userbody.appendChild(pronounshtml)
|
||||
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=this.bio.makeHTML();
|
||||
userbody.appendChild(biohtml);
|
||||
if(guild){
|
||||
Member.resolveMember(this,guild).then(member=>{
|
||||
if(!member) return;
|
||||
const roles=document.createElement("div");
|
||||
roles.classList.add("rolesbox");
|
||||
for(const role of member.roles){
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("rolediv");
|
||||
const color=document.createElement("div");
|
||||
div.append(color);
|
||||
color.style.setProperty("--role-color","#"+role.color.toString(16).padStart(6,"0"))
|
||||
color.classList.add("colorrolediv");
|
||||
const span=document.createElement("span");
|
||||
div.append(span);
|
||||
span.textContent=role.name;
|
||||
roles.append(div);
|
||||
}
|
||||
userbody.append(roles);
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log(div);
|
||||
const rule=document.createElement("hr");
|
||||
userbody.appendChild(rule);
|
||||
const biohtml=this.bio.makeHTML();
|
||||
userbody.appendChild(biohtml);
|
||||
if(guild){
|
||||
Member.resolveMember(this,guild).then(member=>{
|
||||
if(!member)return;
|
||||
const roles=document.createElement("div");
|
||||
roles.classList.add("rolesbox");
|
||||
for(const role of member.roles){
|
||||
const div=document.createElement("div");
|
||||
div.classList.add("rolediv");
|
||||
const color=document.createElement("div");
|
||||
div.append(color);
|
||||
color.style.setProperty("--role-color","#"+role.color.toString(16).padStart(6,"0"));
|
||||
color.classList.add("colorrolediv");
|
||||
const span=document.createElement("span");
|
||||
div.append(span);
|
||||
span.textContent=role.name;
|
||||
roles.append(div);
|
||||
}
|
||||
userbody.append(roles);
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log(div);
|
||||
|
||||
if(x!==-1){
|
||||
Contextmenu.currentmenu=div;
|
||||
document.body.appendChild(div)
|
||||
Contextmenu.keepOnScreen(div);
|
||||
}
|
||||
return div;
|
||||
}
|
||||
profileclick(obj:HTMLElement,guild:Guild|undefined=undefined){
|
||||
obj.onclick=e=>{
|
||||
this.buildprofile(e.clientX,e.clientY,guild);
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
if(x!==-1){
|
||||
Contextmenu.currentmenu=div;
|
||||
document.body.appendChild(div);
|
||||
Contextmenu.keepOnScreen(div);
|
||||
}
|
||||
return div;
|
||||
}
|
||||
profileclick(obj:HTMLElement,guild?:Guild|undefined){
|
||||
obj.onclick=e=>{
|
||||
this.buildprofile(e.clientX,e.clientY,guild);
|
||||
e.stopPropagation();
|
||||
};
|
||||
}
|
||||
}
|
||||
User.setUpContextMenu();
|
||||
export {User};
|
||||
export{User};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue