friend and more update
This commit is contained in:
parent
e24afe2abe
commit
2502d8f977
13 changed files with 491 additions and 79 deletions
|
@ -40,6 +40,7 @@ jsc: {
|
||||||
|
|
||||||
gulp.task('watch', function () {
|
gulp.task('watch', function () {
|
||||||
gulp.watch('./src', gulp.series("default"));
|
gulp.watch('./src', gulp.series("default"));
|
||||||
|
gulp.watch('./translations', gulp.series("default"));
|
||||||
}, {debounceDelay: 10});
|
}, {debounceDelay: 10});
|
||||||
|
|
||||||
// Clean task to delete the dist directory
|
// Clean task to delete the dist directory
|
||||||
|
|
|
@ -842,6 +842,10 @@ class Channel extends SnowFlake{
|
||||||
if(this.voice&&localStorage.getItem("Voice enabled")){
|
if(this.voice&&localStorage.getItem("Voice enabled")){
|
||||||
this.localuser.joinVoice(this);
|
this.localuser.joinVoice(this);
|
||||||
}
|
}
|
||||||
|
(document.getElementById("typebox") as HTMLDivElement).contentEditable =""+this.canMessage;
|
||||||
|
(document.getElementById("upload") as HTMLElement).style.visibility=this.canMessage?"visible":"hidden";
|
||||||
|
(document.getElementById("typediv") as HTMLElement).style.visibility="visible";
|
||||||
|
(document.getElementById("typebox") as HTMLDivElement).focus();
|
||||||
await this.putmessages();
|
await this.putmessages();
|
||||||
await prom;
|
await prom;
|
||||||
if(id !== Channel.genid){
|
if(id !== Channel.genid){
|
||||||
|
@ -851,10 +855,7 @@ class Channel extends SnowFlake{
|
||||||
|
|
||||||
await this.buildmessages();
|
await this.buildmessages();
|
||||||
//loading.classList.remove("loading");
|
//loading.classList.remove("loading");
|
||||||
(document.getElementById("typebox") as HTMLDivElement).contentEditable =""+this.canMessage;
|
|
||||||
(document.getElementById("upload") as HTMLElement).style.visibility=this.canMessage?"visible":"hidden";
|
|
||||||
(document.getElementById("typediv") as HTMLElement).style.visibility="visible";
|
|
||||||
(document.getElementById("typebox") as HTMLDivElement).focus();
|
|
||||||
}
|
}
|
||||||
typingmap: Map<Member, number> = new Map();
|
typingmap: Map<Member, number> = new Map();
|
||||||
async typingStart(typing: startTypingjson): Promise<void>{
|
async typingStart(typing: startTypingjson): Promise<void>{
|
||||||
|
@ -938,6 +939,7 @@ class Channel extends SnowFlake{
|
||||||
}
|
}
|
||||||
lastmessage: Message | undefined;
|
lastmessage: Message | undefined;
|
||||||
async putmessages(){
|
async putmessages(){
|
||||||
|
//TODO swap out with the WS op code
|
||||||
if(this.allthewayup){
|
if(this.allthewayup){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,11 @@ import{ Permissions }from"./permissions.js";
|
||||||
import{ SnowFlake }from"./snowflake.js";
|
import{ SnowFlake }from"./snowflake.js";
|
||||||
import{ Contextmenu }from"./contextmenu.js";
|
import{ Contextmenu }from"./contextmenu.js";
|
||||||
import { I18n } from "./i18n.js";
|
import { I18n } from "./i18n.js";
|
||||||
|
import { Float, FormError } from "./settings.js";
|
||||||
|
|
||||||
class Direct extends Guild{
|
class Direct extends Guild{
|
||||||
declare channelids: { [key: string]: Group };
|
declare channelids: { [key: string]: Group };
|
||||||
|
channels: Group[];
|
||||||
getUnixTime(): number{
|
getUnixTime(): number{
|
||||||
throw new Error("Do not call this for Direct, it does not make sense");
|
throw new Error("Do not call this for Direct, it does not make sense");
|
||||||
}
|
}
|
||||||
|
@ -26,7 +28,7 @@ class Direct extends Guild{
|
||||||
this.roles = [];
|
this.roles = [];
|
||||||
this.roleids = new Map();
|
this.roleids = new Map();
|
||||||
this.prevchannel = undefined;
|
this.prevchannel = undefined;
|
||||||
this.properties.name = "Direct Messages";
|
this.properties.name = I18n.getTranslation("DMs.name");
|
||||||
for(const thing of json){
|
for(const thing of json){
|
||||||
const temp = new Group(thing, this);
|
const temp = new Group(thing, this);
|
||||||
this.channels.push(temp);
|
this.channels.push(temp);
|
||||||
|
@ -60,7 +62,7 @@ class Direct extends Guild{
|
||||||
icon.classList.add("svgicon","svg-friends","space");
|
icon.classList.add("svgicon","svg-friends","space");
|
||||||
freindDiv.append(icon);
|
freindDiv.append(icon);
|
||||||
|
|
||||||
freindDiv.append("Friends");
|
freindDiv.append(I18n.getTranslation("friends.friends"));
|
||||||
ddiv.append(freindDiv);
|
ddiv.append(freindDiv);
|
||||||
freindDiv.onclick=()=>{
|
freindDiv.onclick=()=>{
|
||||||
this.loadChannel(null);
|
this.loadChannel(null);
|
||||||
|
@ -69,6 +71,217 @@ class Direct extends Guild{
|
||||||
ddiv.append(build);
|
ddiv.append(build);
|
||||||
return ddiv;
|
return ddiv;
|
||||||
}
|
}
|
||||||
|
noChannel(addstate:boolean){
|
||||||
|
if(addstate){
|
||||||
|
history.pushState([this.id,undefined], "", "/channels/" + this.id);
|
||||||
|
}
|
||||||
|
this.localuser.pageTitle(I18n.getTranslation("friends.friendlist"));
|
||||||
|
const channelTopic = document.getElementById("channelTopic") as HTMLSpanElement;
|
||||||
|
channelTopic.removeAttribute("hidden");
|
||||||
|
channelTopic.textContent="";
|
||||||
|
|
||||||
|
const loading = document.getElementById("loadingdiv") as HTMLDivElement;
|
||||||
|
loading.classList.remove("loading");
|
||||||
|
this.localuser.getSidePannel();
|
||||||
|
|
||||||
|
const messages = document.getElementById("channelw") as HTMLDivElement;
|
||||||
|
for(const thing of Array.from(messages.getElementsByClassName("messagecontainer"))){
|
||||||
|
thing.remove();
|
||||||
|
}
|
||||||
|
const container=document.createElement("div");
|
||||||
|
container.classList.add("messagecontainer","flexttb","friendcontainer")
|
||||||
|
|
||||||
|
messages.append(container);
|
||||||
|
const checkVoid=()=>{
|
||||||
|
if(this.localuser.channelfocus!==undefined||this.localuser.lookingguild!==this){
|
||||||
|
this.localuser.relationshipsUpdate=()=>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function genuserstrip(user:User,icons:HTMLElement):HTMLElement{
|
||||||
|
const div=document.createElement("div");
|
||||||
|
div.classList.add("flexltr","liststyle");
|
||||||
|
user.bind(div);
|
||||||
|
div.append(user.buildpfp());
|
||||||
|
|
||||||
|
const userinfos=document.createElement("div");
|
||||||
|
userinfos.classList.add("flexttb");
|
||||||
|
const username=document.createElement("span");
|
||||||
|
username.textContent=user.name;
|
||||||
|
userinfos.append(username,user.getStatus());
|
||||||
|
div.append(userinfos);
|
||||||
|
User.contextmenu.bindContextmenu(div,user,undefined);
|
||||||
|
userinfos.style.flexGrow="1";
|
||||||
|
|
||||||
|
div.append(icons);
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//TODO update on users coming online
|
||||||
|
const online=document.createElement("button");
|
||||||
|
online.textContent=I18n.getTranslation("friends.online");
|
||||||
|
channelTopic.append(online);
|
||||||
|
const genOnline=()=>{
|
||||||
|
this.localuser.relationshipsUpdate=genOnline;
|
||||||
|
checkVoid();
|
||||||
|
container.innerHTML="";
|
||||||
|
container.append(I18n.getTranslation("friends.online:"));
|
||||||
|
for(const user of this.localuser.inrelation){
|
||||||
|
if(user.relationshipType===1&&user.online){
|
||||||
|
const buttonc=document.createElement("div");
|
||||||
|
const button1=document.createElement("span");
|
||||||
|
button1.classList.add("svg-frmessage","svgicon");
|
||||||
|
buttonc.append(button1);
|
||||||
|
buttonc.classList.add("friendlyButton");
|
||||||
|
buttonc.onclick=(e)=>{
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
user.opendm();
|
||||||
|
}
|
||||||
|
container.append(genuserstrip(user,buttonc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
online.onclick=genOnline;
|
||||||
|
genOnline();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const all=document.createElement("button");
|
||||||
|
all.textContent=I18n.getTranslation("friends.all");
|
||||||
|
const genAll=()=>{
|
||||||
|
this.localuser.relationshipsUpdate=genAll;
|
||||||
|
checkVoid();
|
||||||
|
container.innerHTML="";
|
||||||
|
container.append(I18n.getTranslation("friends.all:"));
|
||||||
|
for(const user of this.localuser.inrelation){
|
||||||
|
if(user.relationshipType===1){
|
||||||
|
const buttonc=document.createElement("div");
|
||||||
|
const button1=document.createElement("span");
|
||||||
|
button1.classList.add("svg-frmessage","svgicon");
|
||||||
|
buttonc.append(button1);
|
||||||
|
buttonc.classList.add("friendlyButton");
|
||||||
|
buttonc.onclick=(e)=>{
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
user.opendm();
|
||||||
|
}
|
||||||
|
container.append(genuserstrip(user,buttonc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all.onclick=genAll;
|
||||||
|
channelTopic.append(all);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const pending=document.createElement("button");
|
||||||
|
pending.textContent=I18n.getTranslation("friends.pending");
|
||||||
|
const genPending=()=>{
|
||||||
|
this.localuser.relationshipsUpdate=genPending;
|
||||||
|
checkVoid();
|
||||||
|
container.innerHTML="";
|
||||||
|
container.append(I18n.getTranslation("friends.pending:"));
|
||||||
|
for(const user of this.localuser.inrelation){
|
||||||
|
if(user.relationshipType===3||user.relationshipType===4){
|
||||||
|
const buttons=document.createElement("div");
|
||||||
|
buttons.classList.add("flexltr");
|
||||||
|
const buttonc=document.createElement("div");
|
||||||
|
const button1=document.createElement("span");
|
||||||
|
button1.classList.add("svgicon","svg-x");
|
||||||
|
if(user.relationshipType===3){
|
||||||
|
const buttonc=document.createElement("div");
|
||||||
|
const button2=document.createElement("span");
|
||||||
|
button2.classList.add("svgicon","svg-x");
|
||||||
|
button2.classList.add("svg-addfriend");
|
||||||
|
buttonc.append(button2);
|
||||||
|
buttonc.classList.add("friendlyButton");
|
||||||
|
buttonc.append(button2);
|
||||||
|
buttons.append(buttonc);
|
||||||
|
buttonc.onclick=(e)=>{
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
user.changeRelationship(1);
|
||||||
|
outerDiv.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buttonc.append(button1);
|
||||||
|
buttonc.classList.add("friendlyButton");
|
||||||
|
buttonc.onclick=(e)=>{
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
user.changeRelationship(0);
|
||||||
|
outerDiv.remove();
|
||||||
|
}
|
||||||
|
buttons.append(buttonc);
|
||||||
|
const outerDiv=genuserstrip(user,buttons);
|
||||||
|
container.append(outerDiv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pending.onclick=genPending;
|
||||||
|
channelTopic.append(pending);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const blocked=document.createElement("button");
|
||||||
|
blocked.textContent=I18n.getTranslation("friends.blocked");
|
||||||
|
|
||||||
|
const genBlocked=()=>{
|
||||||
|
this.localuser.relationshipsUpdate=genBlocked;
|
||||||
|
checkVoid();
|
||||||
|
container.innerHTML="";
|
||||||
|
container.append(I18n.getTranslation("friends.blockedusers"));
|
||||||
|
for(const user of this.localuser.inrelation){
|
||||||
|
if(user.relationshipType===2){
|
||||||
|
const buttonc=document.createElement("div");
|
||||||
|
const button1=document.createElement("span");
|
||||||
|
button1.classList.add("svg-x","svgicon");
|
||||||
|
buttonc.append(button1);
|
||||||
|
buttonc.classList.add("friendlyButton");
|
||||||
|
buttonc.onclick=(e)=>{
|
||||||
|
user.changeRelationship(0);
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
outerDiv.remove();
|
||||||
|
}
|
||||||
|
const outerDiv=genuserstrip(user,buttonc);
|
||||||
|
container.append(outerDiv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blocked.onclick=genBlocked;
|
||||||
|
channelTopic.append(blocked);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const add=document.createElement("button");
|
||||||
|
add.textContent=I18n.getTranslation("friends.addfriend");
|
||||||
|
add.onclick=()=>{
|
||||||
|
this.localuser.relationshipsUpdate=()=>{};
|
||||||
|
container.innerHTML="";
|
||||||
|
const float=new Float("");
|
||||||
|
const options=float.options;
|
||||||
|
const form=options.addForm("",(e:any)=>{
|
||||||
|
console.log(e);
|
||||||
|
if(e.code===404){
|
||||||
|
throw new FormError(text,I18n.getTranslation("friends.notfound"));
|
||||||
|
}else if(e.code===400){
|
||||||
|
throw new FormError(text,e.message.split("Error: ")[1]);
|
||||||
|
}else{
|
||||||
|
const box=text.input.deref();
|
||||||
|
if(!box)return;
|
||||||
|
box.value="";
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
method:"POST",
|
||||||
|
fetchURL:this.info.api+"/users/@me/relationships",
|
||||||
|
headers:this.headers
|
||||||
|
});
|
||||||
|
const text=form.addTextInput(I18n.getTranslation("friends.addfriendpromt"),"username");
|
||||||
|
form.addPreprocessor((obj:any)=>{
|
||||||
|
const [username,discriminator]=obj.username.split("#");
|
||||||
|
obj.username=username;
|
||||||
|
obj.discriminator=discriminator;
|
||||||
|
if(!discriminator){
|
||||||
|
throw new FormError(text,I18n.getTranslation("friends.discnotfound"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
container.append(float.generateHTML());
|
||||||
|
}
|
||||||
|
channelTopic.append(add);
|
||||||
|
}
|
||||||
|
}
|
||||||
giveMember(_member: memberjson){
|
giveMember(_member: memberjson){
|
||||||
console.error("not a real guild, can't give member object");
|
console.error("not a real guild, can't give member object");
|
||||||
}
|
}
|
||||||
|
@ -143,15 +356,15 @@ class Group extends Channel{
|
||||||
this.user = this.localuser.user;
|
this.user = this.localuser.user;
|
||||||
}
|
}
|
||||||
this.name ??= this.localuser.user.username;
|
this.name ??= this.localuser.user.username;
|
||||||
this.parent_id!;
|
this.parent_id!;
|
||||||
this.parent!;
|
this.parent!;
|
||||||
this.children = [];
|
this.children = [];
|
||||||
this.guild_id = "@me";
|
this.guild_id = "@me";
|
||||||
this.permission_overwrites = new Map();
|
this.permission_overwrites = new Map();
|
||||||
this.lastmessageid = json.last_message_id;
|
this.lastmessageid = json.last_message_id;
|
||||||
this.mentions = 0;
|
this.mentions = 0;
|
||||||
this.setUpInfiniteScroller();
|
this.setUpInfiniteScroller();
|
||||||
this.updatePosition();
|
this.updatePosition();
|
||||||
}
|
}
|
||||||
updatePosition(){
|
updatePosition(){
|
||||||
if(this.lastmessageid){
|
if(this.lastmessageid){
|
||||||
|
@ -202,6 +415,10 @@ class Group extends Channel{
|
||||||
|
|
||||||
loading.classList.add("loading");
|
loading.classList.add("loading");
|
||||||
this.rendertyping();
|
this.rendertyping();
|
||||||
|
(document.getElementById("typebox") as HTMLDivElement).contentEditable ="" + true;
|
||||||
|
(document.getElementById("upload") as HTMLElement).style.visibility="visible";
|
||||||
|
(document.getElementById("typediv") as HTMLElement).style.visibility="visible";
|
||||||
|
(document.getElementById("typebox") as HTMLDivElement).focus();
|
||||||
await this.putmessages();
|
await this.putmessages();
|
||||||
await prom;
|
await prom;
|
||||||
this.localuser.getSidePannel();
|
this.localuser.getSidePannel();
|
||||||
|
@ -209,10 +426,7 @@ class Group extends Channel{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.buildmessages();
|
this.buildmessages();
|
||||||
(document.getElementById("typebox") as HTMLDivElement).contentEditable ="" + true;
|
|
||||||
(document.getElementById("upload") as HTMLElement).style.visibility="visible";
|
|
||||||
(document.getElementById("typediv") as HTMLElement).style.visibility="visible";
|
|
||||||
(document.getElementById("typebox") as HTMLDivElement).focus();
|
|
||||||
}
|
}
|
||||||
messageCreate(messagep: { d: messagejson }){
|
messageCreate(messagep: { d: messagejson }){
|
||||||
const messagez = new Message(messagep.d, this);
|
const messagez = new Message(messagep.d, this);
|
||||||
|
|
|
@ -626,7 +626,7 @@ class Guild extends SnowFlake{
|
||||||
if(addstate){
|
if(addstate){
|
||||||
history.pushState([this.id,undefined], "", "/channels/" + this.id);
|
history.pushState([this.id,undefined], "", "/channels/" + this.id);
|
||||||
}
|
}
|
||||||
this.localuser.pageTitle("Weird spot");
|
this.localuser.pageTitle(I18n.getTranslation("guild.emptytitle"));
|
||||||
const channelTopic = document.getElementById("channelTopic") as HTMLSpanElement;
|
const channelTopic = document.getElementById("channelTopic") as HTMLSpanElement;
|
||||||
channelTopic.setAttribute("hidden", "");
|
channelTopic.setAttribute("hidden", "");
|
||||||
|
|
||||||
|
@ -640,7 +640,7 @@ class Guild extends SnowFlake{
|
||||||
}
|
}
|
||||||
const h1=document.createElement("h1");
|
const h1=document.createElement("h1");
|
||||||
h1.classList.add("messagecontainer")
|
h1.classList.add("messagecontainer")
|
||||||
h1.textContent="You're in a weird spot, this guild has no channels";
|
h1.textContent=I18n.getTranslation("guild.emptytext");
|
||||||
messages.append(h1);
|
messages.append(h1);
|
||||||
}
|
}
|
||||||
loadGuild(){
|
loadGuild(){
|
||||||
|
|
1
src/webpage/icons/addfriend.svg
Normal file
1
src/webpage/icons/addfriend.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180"><g fill="red"><circle cx="71" cy="31.3" r="27.5"/><path d="M72.2 62.1A48.2 48.2 0 0 0 23.5 110l-.6 70h96.5l.3-32a13.5 13.5 0 0 1-12-13.2v-10.2H97.4A13.5 13.5 0 0 1 84 111.1a13.5 13.5 0 0 1 13.5-13.5h10.1V87.5a13.5 13.5 0 0 1 2.1-7 48.2 48.2 0 0 0-37.5-18.4z" overflow="visible"/><path stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width="15" d="M121.1 87.5v47.3m23.7-23.7H97.5"/></g></svg>
|
After Width: | Height: | Size: 472 B |
1
src/webpage/icons/frmessage.svg
Normal file
1
src/webpage/icons/frmessage.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180"><g fill="red"><circle cx="97.7" cy="97.7" r="82.3"/><path d="M0 180h90v-80Z"/></g></svg>
|
After Width: | Height: | Size: 150 B |
|
@ -59,7 +59,7 @@
|
||||||
<span class="svgicon svg-category"></span>
|
<span class="svgicon svg-category"></span>
|
||||||
</label>
|
</label>
|
||||||
<input type="checkbox" id="maintoggle">
|
<input type="checkbox" id="maintoggle">
|
||||||
<span class="flexltr">
|
<span class="flexltr" style="align-items: center;">
|
||||||
<span id="channelname">Channel name</span>
|
<span id="channelname">Channel name</span>
|
||||||
<span id="channelTopic" class="ellipsis" hidden>Channel topic</span>
|
<span id="channelTopic" class="ellipsis" hidden>Channel topic</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -505,7 +505,25 @@ roleCreate | {
|
||||||
op:9,
|
op:9,
|
||||||
d:boolean,
|
d:boolean,
|
||||||
s:number
|
s:number
|
||||||
}|memberlistupdatejson|voiceupdate|voiceserverupdate;
|
}|memberlistupdatejson|voiceupdate|voiceserverupdate|{
|
||||||
|
op: 0,
|
||||||
|
t: "RELATIONSHIP_ADD",
|
||||||
|
d: {
|
||||||
|
id: string,
|
||||||
|
type: 0|1|2|3|4|5|6,
|
||||||
|
user: userjson
|
||||||
|
},
|
||||||
|
s: number
|
||||||
|
}|{
|
||||||
|
op: 0,
|
||||||
|
t: "RELATIONSHIP_REMOVE",
|
||||||
|
d: {
|
||||||
|
id: string,
|
||||||
|
type: number,
|
||||||
|
nickname: null
|
||||||
|
},
|
||||||
|
s: number
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
type memberChunk = {
|
type memberChunk = {
|
||||||
|
|
|
@ -124,12 +124,14 @@ class Localuser{
|
||||||
const user = new User(thing.user, this);
|
const user = new User(thing.user, this);
|
||||||
user.nickname = thing.nickname;
|
user.nickname = thing.nickname;
|
||||||
user.relationshipType = thing.type;
|
user.relationshipType = thing.type;
|
||||||
|
this.inrelation.add(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pingEndpoint();
|
this.pingEndpoint();
|
||||||
this.userinfo.updateLocal();
|
this.userinfo.updateLocal();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
inrelation=new Set<User>();
|
||||||
outoffocus(): void{
|
outoffocus(): void{
|
||||||
const servers = document.getElementById("servers") as HTMLDivElement;
|
const servers = document.getElementById("servers") as HTMLDivElement;
|
||||||
servers.innerHTML = "";
|
servers.innerHTML = "";
|
||||||
|
@ -365,6 +367,7 @@ class Localuser{
|
||||||
});
|
});
|
||||||
await promise;
|
await promise;
|
||||||
}
|
}
|
||||||
|
relationshipsUpdate=()=>{};
|
||||||
async handleEvent(temp: wsjson){
|
async handleEvent(temp: wsjson){
|
||||||
console.debug(temp);
|
console.debug(temp);
|
||||||
if(temp.s)this.lastSequence = temp.s;
|
if(temp.s)this.lastSequence = temp.s;
|
||||||
|
@ -539,6 +542,23 @@ class Localuser{
|
||||||
guild.memberupdate(temp.d)
|
guild.memberupdate(temp.d)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
case "RELATIONSHIP_ADD":{
|
||||||
|
const user = new User(temp.d.user, this);
|
||||||
|
user.nickname = null;
|
||||||
|
user.relationshipType = temp.d.type;
|
||||||
|
this.inrelation.add(user);
|
||||||
|
this.relationshipsUpdate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "RELATIONSHIP_REMOVE":{
|
||||||
|
const user = this.userMap.get(temp.d.id);
|
||||||
|
if(!user) return;
|
||||||
|
user.nickname = null;
|
||||||
|
user.relationshipType = 0;
|
||||||
|
this.inrelation.delete(user);
|
||||||
|
this.relationshipsUpdate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default :{
|
default :{
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
console.warn("Unhandled case "+temp.t,temp);
|
console.warn("Unhandled case "+temp.t,temp);
|
||||||
|
|
|
@ -516,11 +516,27 @@ class HtmlArea implements OptionsElement<void>{
|
||||||
}
|
}
|
||||||
watchForChange(){}
|
watchForChange(){}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This is a simple wrapper class for Options to make it happy so it can be used outside of Settings.
|
||||||
|
*/
|
||||||
|
class Float{
|
||||||
|
options:Options;
|
||||||
|
/**
|
||||||
|
* This is a simple wrapper class for Options to make it happy so it can be used outside of Settings.
|
||||||
|
*/
|
||||||
|
constructor(name:string, options={ ltr:false, noSubmit:false}){
|
||||||
|
this.options=new Options(name,this,options)
|
||||||
|
}
|
||||||
|
changed=()=>{};
|
||||||
|
generateHTML(){
|
||||||
|
return this.options.generateHTML();
|
||||||
|
}
|
||||||
|
}
|
||||||
class Options implements OptionsElement<void>{
|
class Options implements OptionsElement<void>{
|
||||||
name: string;
|
name: string;
|
||||||
haschanged = false;
|
haschanged = false;
|
||||||
readonly options: OptionsElement<any>[];
|
readonly options: OptionsElement<any>[];
|
||||||
readonly owner: Buttons | Options | Form;
|
readonly owner: Buttons | Options | Form | Float;
|
||||||
readonly ltr: boolean;
|
readonly ltr: boolean;
|
||||||
value!: void;
|
value!: void;
|
||||||
readonly html: WeakMap<OptionsElement<any>, WeakRef<HTMLDivElement>> = new WeakMap();
|
readonly html: WeakMap<OptionsElement<any>, WeakRef<HTMLDivElement>> = new WeakMap();
|
||||||
|
@ -530,7 +546,7 @@ class Options implements OptionsElement<void>{
|
||||||
);
|
);
|
||||||
constructor(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
owner: Buttons | Options | Form,
|
owner: Buttons | Options | Form | Float,
|
||||||
{ ltr = false, noSubmit=false} = {}
|
{ ltr = false, noSubmit=false} = {}
|
||||||
){
|
){
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -1145,38 +1161,84 @@ class Form implements OptionsElement<object>{
|
||||||
}
|
}
|
||||||
console.log("middle2");
|
console.log("middle2");
|
||||||
await Promise.allSettled(promises);
|
await Promise.allSettled(promises);
|
||||||
this.preprocessor(build);
|
try{
|
||||||
|
this.preprocessor(build);
|
||||||
|
}catch(e){
|
||||||
|
if(e instanceof FormError){
|
||||||
|
const elm = this.options.html.get(e.elem);
|
||||||
|
if(elm){
|
||||||
|
const html = elm.deref();
|
||||||
|
if(html){
|
||||||
|
this.makeError(html, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(this.fetchURL !== ""){
|
if(this.fetchURL !== ""){
|
||||||
fetch(this.fetchURL, {
|
fetch(this.fetchURL, {
|
||||||
method: this.method,
|
method: this.method,
|
||||||
body: JSON.stringify(build),
|
body: JSON.stringify(build),
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
})
|
})
|
||||||
.then(_=>_.json())
|
.then(_=>{
|
||||||
|
return _.text()
|
||||||
|
}).then(_=>{
|
||||||
|
if(_==="") return {};
|
||||||
|
return JSON.parse(_)
|
||||||
|
})
|
||||||
.then(json=>{
|
.then(json=>{
|
||||||
if(json.errors && this.errors(json.errors))return;
|
if(json.errors){
|
||||||
this.onSubmit(json);
|
if(this.errors(json)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
this.onSubmit(json);
|
||||||
|
}catch(e){
|
||||||
|
console.error(e);
|
||||||
|
if(e instanceof FormError){
|
||||||
|
const elm = this.options.html.get(e.elem);
|
||||||
|
if(elm){
|
||||||
|
const html = elm.deref();
|
||||||
|
if(html){
|
||||||
|
this.makeError(html, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
this.onSubmit(build);
|
try{
|
||||||
|
this.onSubmit(build);
|
||||||
|
}catch(e){
|
||||||
|
if(e instanceof FormError){
|
||||||
|
const elm = this.options.html.get(e.elem);
|
||||||
|
if(elm){
|
||||||
|
const html = elm.deref();
|
||||||
|
if(html){
|
||||||
|
this.makeError(html, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
console.warn("needs to be implemented");
|
console.warn("needs to be implemented");
|
||||||
}
|
}
|
||||||
errors(errors: {
|
errors(errors: {code: number; message: string; errors: { [key: string]: { _errors: { message: string; code: string }[] } }}){
|
||||||
code: number;
|
|
||||||
message: string;
|
|
||||||
errors: { [key: string]: { _errors: { message: string; code: string } } };
|
|
||||||
}){
|
|
||||||
if(!(errors instanceof Object)){
|
if(!(errors instanceof Object)){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(const error of Object.keys(errors)){
|
for(const error of Object.keys(errors.errors)){
|
||||||
const elm = this.names.get(error);
|
const elm = this.names.get(error);
|
||||||
if(elm){
|
if(elm){
|
||||||
const ref = this.options.html.get(elm);
|
const ref = this.options.html.get(elm);
|
||||||
if(ref && ref.deref()){
|
if(ref && ref.deref()){
|
||||||
const html = ref.deref() as HTMLDivElement;
|
const html = ref.deref() as HTMLDivElement;
|
||||||
this.makeError(html, errors.errors[error]._errors.message);
|
const errorMessage=errors.errors[error]._errors[0].message;
|
||||||
|
this.makeError(html, errorMessage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1253,4 +1315,4 @@ class Settings extends Buttons{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export{ Settings, OptionsElement, Buttons, Options,Form };
|
export{ Settings, OptionsElement, Buttons, Options,Form,Float };
|
||||||
|
|
|
@ -256,9 +256,15 @@ textarea {
|
||||||
}
|
}
|
||||||
.svg-friends{
|
.svg-friends{
|
||||||
mask: url(/icons/friends.svg);
|
mask: url(/icons/friends.svg);
|
||||||
width: 24px !important;!i;!;
|
width: 24px !important;
|
||||||
height: 24px !important;!i;!;
|
height: 24px !important;
|
||||||
margin-right: 0 !important;!i;!;
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
.svg-frmessage{
|
||||||
|
mask: url(/icons/frmessage.svg);
|
||||||
|
}
|
||||||
|
.svg-addfriend{
|
||||||
|
mask: url(/icons/addfriend.svg);
|
||||||
}
|
}
|
||||||
.svgicon {
|
.svgicon {
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -833,6 +839,9 @@ span.instanceStatus {
|
||||||
margin: auto 0 0 8px;
|
margin: auto 0 0 8px;
|
||||||
font-size: .9em;
|
font-size: .9em;
|
||||||
color: var(--primary-text-soft);
|
color: var(--primary-text-soft);
|
||||||
|
button{
|
||||||
|
margin-right:.05in;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#channelTopic[hidden] {
|
#channelTopic[hidden] {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -2045,7 +2054,18 @@ fieldset input[type="radio"] {
|
||||||
margin: 6px 12px;
|
margin: 6px 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.friendcontainer{
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding: .2in;
|
||||||
|
>div{
|
||||||
|
background:#00000030;
|
||||||
|
margin-bottom:.1in;
|
||||||
|
padding:.06in .1in;
|
||||||
|
border-radius:.1in;
|
||||||
|
border: solid 1px var(--black);
|
||||||
|
}
|
||||||
|
}
|
||||||
.fixedsearch{
|
.fixedsearch{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: var(--primary-bg);
|
background: var(--primary-bg);
|
||||||
|
@ -2064,6 +2084,35 @@ fieldset input[type="radio"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
.suberror{
|
||||||
|
animation: goout 6s forwards;
|
||||||
|
}
|
||||||
|
.suberrora{
|
||||||
|
background:var(--channel-hover);
|
||||||
|
border-radius:.1in;
|
||||||
|
position:absolute;
|
||||||
|
border:solid var(--primary-text) .02in;
|
||||||
|
color:color-mix(in hsl,var(--yellow),var(--red));
|
||||||
|
font-weight:bold;
|
||||||
|
opacity:0;
|
||||||
|
cursor:default;
|
||||||
|
/* height: .4in; */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
padding: .075in;
|
||||||
|
box-sizing: border-box;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
@keyframes goout {
|
||||||
|
0%,100%{
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
5%,90%{
|
||||||
|
opacity:1;
|
||||||
|
}
|
||||||
|
}
|
||||||
.friendsbutton{
|
.friendsbutton{
|
||||||
transition: background-color .2s;
|
transition: background-color .2s;
|
||||||
background-color: #00000050;
|
background-color: #00000050;
|
||||||
|
@ -2072,3 +2121,16 @@ fieldset input[type="radio"] {
|
||||||
.bigemoji{
|
.bigemoji{
|
||||||
width:.6in;
|
width:.6in;
|
||||||
}
|
}
|
||||||
|
.friendlyButton{
|
||||||
|
padding: .07in;
|
||||||
|
background: #00000045;
|
||||||
|
transition:background .2s;
|
||||||
|
border-radius: 1in;
|
||||||
|
border: solid 1px var(--black);
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin: 0 .05in;
|
||||||
|
}
|
||||||
|
.friendlyButton:hover{
|
||||||
|
background:black;
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import{ presencejson, userjson }from"./jsontypes.js";
|
||||||
import { Role } from "./role.js";
|
import { Role } from "./role.js";
|
||||||
import { Search } from "./search.js";
|
import { Search } from "./search.js";
|
||||||
import { I18n } from "./i18n.js";
|
import { I18n } from "./i18n.js";
|
||||||
|
import { Direct } from "./direct.js";
|
||||||
|
|
||||||
class User extends SnowFlake{
|
class User extends SnowFlake{
|
||||||
owner: Localuser;
|
owner: Localuser;
|
||||||
|
@ -15,7 +16,7 @@ class User extends SnowFlake{
|
||||||
avatar!: string | null;
|
avatar!: string | null;
|
||||||
username!: string;
|
username!: string;
|
||||||
nickname: string | null = null;
|
nickname: string | null = null;
|
||||||
relationshipType: 0 | 1 | 2 | 3 | 4 = 0;
|
relationshipType: 0 | 1 | 2 | 3 | 4 | 5 | 6 = 0;
|
||||||
bio!: MarkDown;
|
bio!: MarkDown;
|
||||||
discriminator!: string;
|
discriminator!: string;
|
||||||
pronouns!: string;
|
pronouns!: string;
|
||||||
|
@ -85,31 +86,59 @@ class User extends SnowFlake{
|
||||||
this.setstatus("offline");
|
this.setstatus("offline");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
get online(){
|
||||||
|
return (this.status)&&(this.status!="offline");
|
||||||
|
}
|
||||||
setstatus(status: string): void{
|
setstatus(status: string): void{
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStatus(): Promise<string>{
|
getStatus(): string{
|
||||||
return this.status || "offline";
|
return this.status || "offline";
|
||||||
}
|
}
|
||||||
|
|
||||||
static contextmenu = new Contextmenu<User, Member | undefined>("User Menu");
|
static contextmenu = new Contextmenu<User, Member | undefined>("User Menu");
|
||||||
|
async opendm(){
|
||||||
|
for(const dm of (this.localuser.guildids.get("@me") as Direct).channels){
|
||||||
|
if(dm.user.id===this.id){
|
||||||
|
this.localuser.goToChannel(dm.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await fetch(this.info.api + "/users/@me/channels", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ recipients: [this.id] }),
|
||||||
|
headers: this.localuser.headers,
|
||||||
|
})
|
||||||
|
.then(res=>res.json())
|
||||||
|
.then(json=>{
|
||||||
|
this.localuser.goToChannel(json.id);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
async changeRelationship(type:0|1|2|3|4|5){
|
||||||
|
if(type!==0){
|
||||||
|
await fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: this.owner.headers,
|
||||||
|
body: JSON.stringify({
|
||||||
|
type,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
await fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: this.owner.headers
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.relationshipType=type;
|
||||||
|
}
|
||||||
static setUpContextMenu(): void{
|
static setUpContextMenu(): void{
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("user.copyId"), function(this: User){
|
this.contextmenu.addbutton(()=>I18n.getTranslation("user.copyId"), function(this: User){
|
||||||
navigator.clipboard.writeText(this.id);
|
navigator.clipboard.writeText(this.id);
|
||||||
});
|
});
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("user.message"), function(this: User){
|
this.contextmenu.addbutton(()=>I18n.getTranslation("user.message"), function(this: User){
|
||||||
fetch(this.info.api + "/users/@me/channels", {
|
this.opendm();
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({ recipients: [this.id] }),
|
|
||||||
headers: this.localuser.headers,
|
|
||||||
})
|
|
||||||
.then(res=>res.json())
|
|
||||||
.then(json=>{
|
|
||||||
this.localuser.goToChannel(json.id);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
()=>I18n.getTranslation("user.block"),
|
()=>I18n.getTranslation("user.block"),
|
||||||
|
@ -133,13 +162,7 @@ class User extends SnowFlake{
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("user.friendReq"), function(this: User){
|
this.contextmenu.addbutton(()=>I18n.getTranslation("user.friendReq"), function(this: User){
|
||||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
this.changeRelationship(1);
|
||||||
method: "PUT",
|
|
||||||
headers: this.owner.headers,
|
|
||||||
body: JSON.stringify({
|
|
||||||
type: 1,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
()=>I18n.getTranslation("user.kick"),
|
()=>I18n.getTranslation("user.kick"),
|
||||||
|
@ -370,15 +393,8 @@ class User extends SnowFlake{
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
block(): void{
|
async block(){
|
||||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
await this.changeRelationship(2);
|
||||||
method: "PUT",
|
|
||||||
headers: this.owner.headers,
|
|
||||||
body: JSON.stringify({
|
|
||||||
type: 2,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
this.relationshipType = 2;
|
|
||||||
const channel = this.localuser.channelfocus;
|
const channel = this.localuser.channelfocus;
|
||||||
if(channel){
|
if(channel){
|
||||||
for(const message of channel.messages){
|
for(const message of channel.messages){
|
||||||
|
@ -387,12 +403,8 @@ class User extends SnowFlake{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unblock(): void{
|
async unblock(){
|
||||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
await this.changeRelationship(0);
|
||||||
method: "DELETE",
|
|
||||||
headers: this.owner.headers,
|
|
||||||
});
|
|
||||||
this.relationshipType = 0;
|
|
||||||
const channel = this.localuser.channelfocus;
|
const channel = this.localuser.channelfocus;
|
||||||
if(channel){
|
if(channel){
|
||||||
for(const message of channel.messages){
|
for(const message of channel.messages){
|
||||||
|
|
|
@ -229,7 +229,9 @@
|
||||||
"noDelete":"Nevermind",
|
"noDelete":"Nevermind",
|
||||||
"create":"Create guild",
|
"create":"Create guild",
|
||||||
"loadingDiscovery":"Loading...",
|
"loadingDiscovery":"Loading...",
|
||||||
"disoveryTitle":"Guild discovery ($1) {{PLURAL:$1|entry|entries}}"
|
"disoveryTitle":"Guild discovery ($1) {{PLURAL:$1|entry|entries}}",
|
||||||
|
"emptytitle":"Weird spot",
|
||||||
|
"emptytext":"You're in a weird spot, this guild has no channels"
|
||||||
},
|
},
|
||||||
"role":{
|
"role":{
|
||||||
"displaySettings":"Display settings",
|
"displaySettings":"Display settings",
|
||||||
|
@ -345,11 +347,28 @@
|
||||||
"joinUsing":"Join using invite",
|
"joinUsing":"Join using invite",
|
||||||
"inviteLinkCode":"Invite Link/Code"
|
"inviteLinkCode":"Invite Link/Code"
|
||||||
},
|
},
|
||||||
|
"friends":{
|
||||||
|
"blocked":"Blocked",
|
||||||
|
"blockedusers":"Blocked Users:",
|
||||||
|
"addfriend":"Add Friend",
|
||||||
|
"addfriendpromt":"Add friends by username:",
|
||||||
|
"notfound":"User not found",
|
||||||
|
"discnotfound":"Discriminator not found",
|
||||||
|
"pending":"Pending",
|
||||||
|
"pending:":"Pending friend requests:",
|
||||||
|
"all":"All",
|
||||||
|
"all:":"All friends:",
|
||||||
|
"online":"Online",
|
||||||
|
"online:":"Online friends:",
|
||||||
|
"friendlist":"Friend List",
|
||||||
|
"friends":"Friends"
|
||||||
|
},
|
||||||
"replyingTo":"Replying to $1",
|
"replyingTo":"Replying to $1",
|
||||||
"DMs":{
|
"DMs":{
|
||||||
"copyId":"Copy DM id",
|
"copyId":"Copy DM id",
|
||||||
"markRead":"Mark as read",
|
"markRead":"Mark as read",
|
||||||
"close":"Close DM"
|
"close":"Close DM",
|
||||||
|
"name":"Dirrect Messages"
|
||||||
},
|
},
|
||||||
"user":{
|
"user":{
|
||||||
"copyId":"Copy user ID",
|
"copyId":"Copy user ID",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue