get rid of the dialog class/improved notifications
This commit is contained in:
parent
258fba7b8c
commit
d4d5da9da4
15 changed files with 500 additions and 785 deletions
|
@ -2,11 +2,10 @@
|
|||
import{ Message }from"./message.js";
|
||||
import{ AVoice }from"./audio.js";
|
||||
import{ Contextmenu }from"./contextmenu.js";
|
||||
import{ Dialog }from"./dialog.js";
|
||||
import{ Guild }from"./guild.js";
|
||||
import{ Localuser }from"./localuser.js";
|
||||
import{ Permissions }from"./permissions.js";
|
||||
import{ Settings }from"./settings.js";
|
||||
import{ BDialog, Settings }from"./settings.js";
|
||||
import{ Role, RoleList }from"./role.js";
|
||||
import{ InfiniteScroller }from"./infiniteScroller.js";
|
||||
import{ SnowFlake }from"./snowflake.js";
|
||||
|
@ -43,7 +42,7 @@ class Channel extends SnowFlake{
|
|||
lastpin!: string;
|
||||
move_id?: string;
|
||||
typing!: number;
|
||||
message_notifications!: number;
|
||||
message_notifications:number=3;
|
||||
allthewayup!: boolean;
|
||||
static contextmenu = new Contextmenu<Channel, undefined>("channel menu");
|
||||
replyingto!: Message | null;
|
||||
|
@ -53,6 +52,14 @@ class Channel extends SnowFlake{
|
|||
messages: Map<string, Message> = new Map();
|
||||
voice?:Voice;
|
||||
bitrate:number=128000;
|
||||
|
||||
muted:boolean=false;
|
||||
mute_config= {selected_time_window: -1,end_time: 0}
|
||||
handleUserOverrides(settings:{message_notifications: number,muted: boolean,mute_config: {selected_time_window: number,end_time: number},channel_id: string}){
|
||||
this.message_notifications=settings.message_notifications;
|
||||
this.muted=settings.muted;
|
||||
this.mute_config=settings.mute_config;
|
||||
}
|
||||
static setupcontextmenu(){
|
||||
this.contextmenu.addbutton(()=>I18n.getTranslation("channel.copyId"), function(this: Channel){
|
||||
navigator.clipboard.writeText(this.id);
|
||||
|
@ -76,6 +83,12 @@ class Channel extends SnowFlake{
|
|||
return this.isAdmin();
|
||||
}
|
||||
);
|
||||
this.contextmenu.addbutton(
|
||||
()=>I18n.getTranslation("guild.notifications"),
|
||||
function(){
|
||||
this.setnotifcation();
|
||||
}
|
||||
)
|
||||
|
||||
this.contextmenu.addbutton(
|
||||
()=>I18n.getTranslation("channel.makeInvite"),
|
||||
|
@ -129,50 +142,21 @@ class Channel extends SnowFlake{
|
|||
});
|
||||
};
|
||||
update();
|
||||
new Dialog([
|
||||
"vdiv",
|
||||
["title", I18n.getTranslation("inviteOptions.title")],
|
||||
["text", `to #${this.name} in ${this.guild.properties.name}`],
|
||||
[
|
||||
"select",
|
||||
"Expire after:",
|
||||
[
|
||||
I18n.getTranslation("inviteOptions.30m"),
|
||||
I18n.getTranslation("inviteOptions.1h"),
|
||||
I18n.getTranslation("inviteOptions.6h"),
|
||||
I18n.getTranslation("inviteOptions.12h"),
|
||||
I18n.getTranslation("inviteOptions.1d"),
|
||||
I18n.getTranslation("inviteOptions.7d"),
|
||||
I18n.getTranslation("inviteOptions.30d"),
|
||||
I18n.getTranslation("inviteOptions.never"),
|
||||
],
|
||||
function(e: Event){
|
||||
expires = [1800, 3600, 21600, 43200, 86400, 604800, 2592000, 0,][(e.srcElement as HTMLSelectElement).selectedIndex];
|
||||
const inviteOptions=new BDialog("",{noSubmit:true});
|
||||
inviteOptions.options.addTitle(I18n.getTranslation("inviteOptions.title"));
|
||||
inviteOptions.options.addText(I18n.getTranslation("invite.subtext",this.name,this.guild.properties.name));
|
||||
|
||||
update();
|
||||
},
|
||||
0,
|
||||
],
|
||||
[
|
||||
"select",
|
||||
"Max uses:",
|
||||
[
|
||||
I18n.getTranslation("inviteOptions.noLimit"),
|
||||
I18n.getTranslation("inviteOptions.limit","1"),
|
||||
I18n.getTranslation("inviteOptions.limit","5"),
|
||||
I18n.getTranslation("inviteOptions.limit","10"),
|
||||
I18n.getTranslation("inviteOptions.limit","25"),
|
||||
I18n.getTranslation("inviteOptions.limit","50"),
|
||||
I18n.getTranslation("inviteOptions.limit","100"),
|
||||
],
|
||||
function(e: Event){
|
||||
uses = [0, 1, 5, 10, 25, 50, 100][(e.srcElement as HTMLSelectElement).selectedIndex];
|
||||
update();
|
||||
},
|
||||
0,
|
||||
],
|
||||
["html", div],
|
||||
]).show();
|
||||
inviteOptions.options.addSelect(I18n.getTranslation("invite.expireAfter"),()=>{},
|
||||
["30m","1h","6h","12h","1d","7d","30d","never"].map((e)=>I18n.getTranslation("inviteOptions."+e))
|
||||
).onchange=(e)=>{expires=[1800, 3600, 21600, 43200, 86400, 604800, 2592000, 0][e];update()};
|
||||
|
||||
const timeOptions=["1","5","10","25","50","100"].map((e)=>I18n.getTranslation("inviteOptions.limit",e))
|
||||
timeOptions.unshift(I18n.getTranslation("inviteOptions.noLimit"))
|
||||
inviteOptions.options.addSelect(I18n.getTranslation("invite.expireAfter"),()=>{},timeOptions)
|
||||
.onchange=(e)=>{uses=[0, 1, 5, 10, 25, 50, 100][e];update()};
|
||||
|
||||
inviteOptions.options.addHTMLArea(div);
|
||||
inviteOptions.show();
|
||||
}
|
||||
generateSettings(){
|
||||
this.sortPerms();
|
||||
|
@ -938,6 +922,81 @@ class Channel extends SnowFlake{
|
|||
}
|
||||
}
|
||||
lastmessage: Message | undefined;
|
||||
setnotifcation(){
|
||||
const defualt=I18n.getTranslation("guild."+["all", "onlyMentions", "none","default"][this.guild.message_notifications])
|
||||
const options=["all", "onlyMentions", "none","default"].map(e=>I18n.getTranslation("guild."+e,defualt));
|
||||
const notiselect=new BDialog("");
|
||||
const form=notiselect.options.addForm("",(_,sent:any)=>{
|
||||
notiselect.hide();
|
||||
console.log(sent);
|
||||
this.message_notifications = sent.channel_overrides[this.id].message_notifications;
|
||||
},{
|
||||
fetchURL:`${this.info.api}/users/@me/guilds/${this.guild.id}/settings/`,
|
||||
method:"PATCH",
|
||||
headers:this.headers
|
||||
});
|
||||
form.addSelect(I18n.getTranslation("guild.selectnoti"),"message_notifications",options,{
|
||||
radio:true,
|
||||
defaultIndex:this.message_notifications
|
||||
},[0,1,2,3]);
|
||||
|
||||
form.addPreprocessor((e:any)=>{
|
||||
const message_notifications=e.message_notifications;
|
||||
delete e.message_notifications;
|
||||
e.channel_overrides={
|
||||
[this.id]:{
|
||||
message_notifications,
|
||||
muted:this.muted,
|
||||
mute_config:this.mute_config,
|
||||
channel_id:this.id
|
||||
}
|
||||
}
|
||||
})
|
||||
/*
|
||||
let noti = this.message_notifications;
|
||||
const defualt=I18n.getTranslation("guild."+["all", "onlyMentions", "none","default"][this.guild.message_notifications])
|
||||
const options=["all", "onlyMentions", "none","default"].map(e=>I18n.getTranslation("guild."+e,defualt))
|
||||
const notiselect = new Dialog([
|
||||
"vdiv",
|
||||
[
|
||||
"radio",
|
||||
I18n.getTranslation("guild.selectnoti"),
|
||||
options,
|
||||
function(e: string){
|
||||
noti = options.indexOf(e);
|
||||
},
|
||||
noti,
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
"submit",
|
||||
(_: any)=>{
|
||||
//
|
||||
fetch(this.info.api + `/users/@me/guilds/${this.guild.id}/settings/`, {
|
||||
method: "PATCH",
|
||||
headers: this.headers,
|
||||
body: JSON.stringify({
|
||||
channel_overrides:{
|
||||
[this.id]:{
|
||||
message_notifications: noti,
|
||||
muted:false,
|
||||
mute_config:{
|
||||
selected_time_window:0,
|
||||
end_time:0
|
||||
},
|
||||
channel_id:this.id
|
||||
}
|
||||
}
|
||||
}),
|
||||
}).then(()=>notiselect.hide());
|
||||
this.message_notifications = noti;
|
||||
},
|
||||
],
|
||||
]);
|
||||
*/
|
||||
notiselect.show();
|
||||
}
|
||||
async putmessages(){
|
||||
//TODO swap out with the WS op code
|
||||
if(this.allthewayup){
|
||||
|
@ -1229,16 +1288,17 @@ class Channel extends SnowFlake{
|
|||
notinumber = null;
|
||||
}
|
||||
notinumber ??= this.guild.message_notifications;
|
||||
console.warn("info:",notinumber);
|
||||
switch(Number(notinumber)){
|
||||
case 0:
|
||||
return"all";
|
||||
case 1:
|
||||
return"mentions";
|
||||
case 2:
|
||||
return"none";
|
||||
case 3:
|
||||
default:
|
||||
return"default";
|
||||
case 0:
|
||||
return"all";
|
||||
case 1:
|
||||
return"mentions";
|
||||
case 2:
|
||||
return"none";
|
||||
case 3:
|
||||
default:
|
||||
return"default";
|
||||
}
|
||||
}
|
||||
async sendMessage(
|
||||
|
|
|
@ -1,273 +0,0 @@
|
|||
type dialogjson =
|
||||
| ["hdiv", ...dialogjson[]]
|
||||
| ["vdiv", ...dialogjson[]]
|
||||
| ["img", string, [number, number] | undefined | ["fit"]]
|
||||
| ["checkbox", string, boolean, (this: HTMLInputElement, e: Event) => unknown]
|
||||
| ["button", string, string, (this: HTMLButtonElement, e: Event) => unknown]
|
||||
| ["mdbox", string, string, (this: HTMLTextAreaElement, e: Event) => unknown]
|
||||
| ["textbox", string, string, (this: HTMLInputElement, e: Event) => unknown]
|
||||
| ["fileupload", string, (this: HTMLInputElement, e: Event) => unknown]
|
||||
| ["text", string]
|
||||
| ["title", string]
|
||||
| ["radio", string, string[], (this: unknown, e: string) => unknown, number]
|
||||
| ["html", HTMLElement]
|
||||
| ["select", string, string[], (this: HTMLSelectElement, e: Event) => unknown, number]
|
||||
| ["tabs", [string, dialogjson][]];
|
||||
class Dialog{
|
||||
layout: dialogjson;
|
||||
onclose: Function;
|
||||
onopen: Function;
|
||||
html: HTMLDivElement;
|
||||
background!: HTMLDivElement;
|
||||
constructor(
|
||||
layout: dialogjson,
|
||||
onclose = (_: any)=>{},
|
||||
onopen = (_: any)=>{}
|
||||
){
|
||||
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: dialogjson): HTMLElement{
|
||||
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("div");
|
||||
hdiv.classList.add("flexltr");
|
||||
|
||||
for(const thing of array){
|
||||
if(thing === "hdiv"){
|
||||
continue;
|
||||
}
|
||||
hdiv.appendChild(this.tohtml(thing));
|
||||
}
|
||||
return hdiv;
|
||||
case"vdiv":
|
||||
const vdiv = document.createElement("div");
|
||||
vdiv.classList.add("flexttb");
|
||||
for(const thing of array){
|
||||
if(thing === "vdiv"){
|
||||
continue;
|
||||
}
|
||||
vdiv.appendChild(this.tohtml(thing));
|
||||
}
|
||||
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 Array.from(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];
|
||||
|
||||
case"select": {
|
||||
const div = document.createElement("div");
|
||||
const label = document.createElement("label");
|
||||
const selectSpan = document.createElement("span");
|
||||
selectSpan.classList.add("selectspan");
|
||||
const select = document.createElement("select");
|
||||
const selectArrow = document.createElement("span");
|
||||
selectArrow.classList.add("svgicon","svg-category","selectarrow");
|
||||
|
||||
label.textContent = array[1];
|
||||
selectSpan.append(select);
|
||||
selectSpan.append(selectArrow);
|
||||
div.append(label);
|
||||
div.appendChild(selectSpan);
|
||||
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("div");
|
||||
table.classList.add("flexttb");
|
||||
const tabs = document.createElement("div");
|
||||
tabs.classList.add("flexltr");
|
||||
tabs.classList.add("tabbed-head");
|
||||
table.appendChild(tabs);
|
||||
const content = document.createElement("div");
|
||||
content.classList.add("tabbed-content");
|
||||
table.appendChild(content);
|
||||
|
||||
let shown: HTMLElement | undefined;
|
||||
for(const thing of array[1]){
|
||||
const button = document.createElement("button");
|
||||
button.textContent = thing[0];
|
||||
tabs.appendChild(button);
|
||||
|
||||
const html = this.tohtml(thing[1]);
|
||||
content.append(html);
|
||||
if(!shown){
|
||||
shown = html;
|
||||
}else{
|
||||
html.style.display = "none";
|
||||
}
|
||||
button.addEventListener("click", _=>{
|
||||
if(shown){
|
||||
shown.style.display = "none";
|
||||
}
|
||||
html.style.display = "";
|
||||
shown = html;
|
||||
});
|
||||
}
|
||||
return table;
|
||||
}
|
||||
default:
|
||||
console.error(
|
||||
"can't find element:" + array[0],
|
||||
" full element:",
|
||||
array
|
||||
);
|
||||
return document.createElement("span");
|
||||
}
|
||||
}
|
||||
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 };
|
37
src/webpage/disimg.ts
Normal file
37
src/webpage/disimg.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
class ImagesDisplay{
|
||||
images:string[];
|
||||
index=0;
|
||||
constructor(srcs:string[],index=0){
|
||||
this.images=srcs;
|
||||
this.index=index;
|
||||
}
|
||||
weakbg=new WeakRef<HTMLElement>(document.createElement("div"));
|
||||
get background():HTMLElement|undefined{
|
||||
return this.weakbg.deref();
|
||||
}
|
||||
set background(e:HTMLElement){
|
||||
this.weakbg=new WeakRef(e);
|
||||
}
|
||||
makeHTML():HTMLElement{
|
||||
//TODO this should be able to display more than one image at a time lol
|
||||
const image= document.createElement("img");
|
||||
image.src=this.images[this.index];
|
||||
image.classList.add("imgfit","centeritem");
|
||||
return image;
|
||||
}
|
||||
show(){
|
||||
this.background = document.createElement("div");
|
||||
this.background.classList.add("background");
|
||||
this.background.appendChild(this.makeHTML());
|
||||
this.background.onclick = _=>{
|
||||
this.hide();
|
||||
};
|
||||
document.body.append(this.background);
|
||||
}
|
||||
hide(){
|
||||
if(this.background){
|
||||
this.background.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
export{ImagesDisplay}
|
|
@ -1,10 +1,10 @@
|
|||
import{ Dialog }from"./dialog.js";
|
||||
import{ Message }from"./message.js";
|
||||
import{ MarkDown }from"./markdown.js";
|
||||
import{ embedjson, invitejson }from"./jsontypes.js";
|
||||
import{ getapiurls, getInstances }from"./login.js";
|
||||
import{ Guild }from"./guild.js";
|
||||
import { I18n } from "./i18n.js";
|
||||
import { ImagesDisplay } from "./disimg.js";
|
||||
|
||||
class Embed{
|
||||
type: string;
|
||||
|
@ -178,7 +178,7 @@ Url.pathname.split("/")[Url.pathname.split("/").length - 1];
|
|||
const img = document.createElement("img");
|
||||
img.classList.add("messageimg");
|
||||
img.onclick = function(){
|
||||
const full = new Dialog(["img", img.src, ["fit"]]);
|
||||
const full = new ImagesDisplay([img.src]);
|
||||
full.show();
|
||||
};
|
||||
img.src = this.json.thumbnail.proxy_url;
|
||||
|
@ -214,7 +214,7 @@ Url.pathname.split("/")[Url.pathname.split("/").length - 1];
|
|||
if(this.json.thumbnail){
|
||||
img.classList.add("embedimg");
|
||||
img.onclick = function(){
|
||||
const full = new Dialog(["img", img.src, ["fit"]]);
|
||||
const full = new ImagesDisplay([img.src]);
|
||||
full.show();
|
||||
};
|
||||
img.src = this.json.thumbnail.proxy_url;
|
||||
|
@ -392,7 +392,7 @@ guild as invitejson["guild"] & { info: { cdn: string } }
|
|||
};
|
||||
}else{
|
||||
img.onclick = async ()=>{
|
||||
const full = new Dialog(["img", img.src, ["fit"]]);
|
||||
const full = new ImagesDisplay([img.src]);
|
||||
full.show();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import{ Message }from"./message.js";
|
||||
import{ Dialog }from"./dialog.js";
|
||||
import{ filejson }from"./jsontypes.js";
|
||||
import { ImagesDisplay } from "./disimg.js";
|
||||
|
||||
class File{
|
||||
owner: Message | null;
|
||||
|
@ -40,7 +40,7 @@ class File{
|
|||
img.classList.add("messageimg");
|
||||
div.classList.add("messageimgdiv");
|
||||
img.onclick = function(){
|
||||
const full = new Dialog(["img", img.src, ["fit"]]);
|
||||
const full = new ImagesDisplay([img.src]);
|
||||
full.show();
|
||||
};
|
||||
img.src = src;
|
||||
|
|
|
@ -2,9 +2,8 @@ import{ Channel }from"./channel.js";
|
|||
import{ Localuser }from"./localuser.js";
|
||||
import{ Contextmenu }from"./contextmenu.js";
|
||||
import{ Role, RoleList }from"./role.js";
|
||||
import{ Dialog }from"./dialog.js";
|
||||
import{ Member }from"./member.js";
|
||||
import{ Settings }from"./settings.js";
|
||||
import{ BDialog, Settings }from"./settings.js";
|
||||
import{ Permissions }from"./permissions.js";
|
||||
import{ SnowFlake }from"./snowflake.js";
|
||||
import{channeljson,guildjson,emojijson,memberjson,invitejson,rolesjson,}from"./jsontypes.js";
|
||||
|
@ -238,7 +237,7 @@ class Guild extends SnowFlake{
|
|||
this.localuser.perminfo.guilds[this.id] = e;
|
||||
}
|
||||
notisetting(settings: {
|
||||
channel_overrides?: unknown[];
|
||||
channel_overrides: {message_notifications: number,muted: boolean,mute_config: {selected_time_window: number,end_time: number},channel_id: string}[];
|
||||
message_notifications: any;
|
||||
flags?: number;
|
||||
hide_muted_channels?: boolean;
|
||||
|
@ -253,66 +252,42 @@ class Guild extends SnowFlake{
|
|||
guild_id?: string;
|
||||
}){
|
||||
this.message_notifications = settings.message_notifications;
|
||||
for(const override of settings.channel_overrides){
|
||||
const channel=this.localuser.channelids.get(override.channel_id);
|
||||
if(!channel) continue;
|
||||
channel.handleUserOverrides(override);
|
||||
}
|
||||
}
|
||||
setnotifcation(){
|
||||
let noti = this.message_notifications;
|
||||
const options=["all", "onlyMentions", "none"].map(e=>I18n.getTranslation("guild."+e))
|
||||
const notiselect = new Dialog([
|
||||
"vdiv",
|
||||
[
|
||||
"radio",
|
||||
I18n.getTranslation("guild.selectnoti"),
|
||||
options,
|
||||
function(e: string){
|
||||
noti = options.indexOf(e);
|
||||
},
|
||||
noti,
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
"submit",
|
||||
(_: any)=>{
|
||||
//
|
||||
fetch(this.info.api + `/users/@me/guilds/${this.id}/settings/`, {
|
||||
method: "PATCH",
|
||||
headers: this.headers,
|
||||
body: JSON.stringify({
|
||||
message_notifications: noti,
|
||||
}),
|
||||
});
|
||||
this.message_notifications = noti;
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
const options=["all", "onlyMentions", "none"].map(e=>I18n.getTranslation("guild."+e));
|
||||
const notiselect=new BDialog("");
|
||||
const form=notiselect.options.addForm("",(_,sent:any)=>{
|
||||
notiselect.hide();
|
||||
this.message_notifications = sent.message_notifications;
|
||||
},{
|
||||
fetchURL:`${this.info.api}/users/@me/guilds/${this.id}/settings/`,
|
||||
method:"PATCH",
|
||||
headers:this.headers
|
||||
});
|
||||
form.addSelect(I18n.getTranslation("guild.selectnoti"),"message_notifications",options,{
|
||||
radio:true,
|
||||
defaultIndex:this.message_notifications
|
||||
},[0,1,2]);
|
||||
notiselect.show();
|
||||
}
|
||||
confirmleave(){
|
||||
const full = new Dialog([
|
||||
"vdiv",
|
||||
["title", I18n.getTranslation("guild.confirmLeave")],
|
||||
[
|
||||
"hdiv",
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("guild.yesLeave"),
|
||||
(_: any)=>{
|
||||
this.leave().then(_=>{
|
||||
full.hide();
|
||||
});
|
||||
},
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("guild.noLeave"),
|
||||
(_: any)=>{
|
||||
full.hide();
|
||||
},
|
||||
],
|
||||
],
|
||||
]);
|
||||
const full = new BDialog("");
|
||||
full.options.addTitle(I18n.getTranslation("guild.confirmLeave"))
|
||||
const options=full.options.addOptions("",{ltr:true});
|
||||
options.addButtonInput("",I18n.getTranslation("guild.yesLeave"),()=>{
|
||||
this.leave().then(_=>{
|
||||
full.hide();
|
||||
});
|
||||
});
|
||||
options.addButtonInput("",I18n.getTranslation("guild.noLeave"),()=>{
|
||||
full.hide();
|
||||
});
|
||||
full.show();
|
||||
}
|
||||
async leave(){
|
||||
|
@ -458,46 +433,26 @@ class Guild extends SnowFlake{
|
|||
}
|
||||
confirmDelete(){
|
||||
let confirmname = "";
|
||||
const full = new Dialog([
|
||||
"vdiv",
|
||||
[
|
||||
"title",
|
||||
I18n.getTranslation("guild.confirmDelete",this.properties.name)
|
||||
],
|
||||
[
|
||||
"textbox",
|
||||
I18n.getTranslation("guild.serverName"),
|
||||
"",
|
||||
function(this: HTMLInputElement){
|
||||
confirmname = this.value;
|
||||
},
|
||||
],
|
||||
[
|
||||
"hdiv",
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("guild.yesDelete"),
|
||||
(_: any)=>{
|
||||
console.log(confirmname);
|
||||
if(confirmname !== this.properties.name){
|
||||
return;
|
||||
}
|
||||
this.delete().then(_=>{
|
||||
full.hide();
|
||||
});
|
||||
},
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("guild.noDelete"),
|
||||
(_: any)=>{
|
||||
full.hide();
|
||||
},
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
const full = new BDialog("");
|
||||
full.options.addTitle(I18n.getTranslation("guild.confirmDelete",this.properties.name));
|
||||
full.options.addTextInput(I18n.getTranslation("guild.serverName"),()=>{}).onchange=(e)=>confirmname=e;
|
||||
|
||||
const options=full.options.addOptions("",{ltr:true});
|
||||
options.addButtonInput("",I18n.getTranslation("guild.yesDelete"),()=>{
|
||||
if(confirmname !== this.properties.name){
|
||||
//TODO maybe some sort of form error? idk
|
||||
alert("names don't match");
|
||||
return;
|
||||
}
|
||||
this.delete().then(_=>{
|
||||
full.hide();
|
||||
});
|
||||
});
|
||||
|
||||
options.addButtonInput("",I18n.getTranslation("guild.noDelete"),()=>{
|
||||
full.hide();
|
||||
});
|
||||
full.show();
|
||||
}
|
||||
async delete(){
|
||||
|
@ -677,67 +632,27 @@ class Guild extends SnowFlake{
|
|||
return thischannel;
|
||||
}
|
||||
createchannels(func = this.createChannel){
|
||||
let name = "";
|
||||
let category = 0;
|
||||
const options=["voice", "text", "announcement"].map(e=>I18n.getTranslation("channel."+e));
|
||||
const numbers=[2,0,5]
|
||||
const channelselect = new Dialog([
|
||||
"vdiv",
|
||||
[
|
||||
"radio",
|
||||
I18n.getTranslation("channel.selectType"),
|
||||
options,
|
||||
function(radio: string){
|
||||
console.log(radio);
|
||||
category = numbers[options.indexOf(radio)] || 0;
|
||||
},
|
||||
1,
|
||||
],
|
||||
[
|
||||
"textbox",
|
||||
I18n.getTranslation("channel.selectName"),
|
||||
"",
|
||||
function(this: HTMLInputElement){
|
||||
name = this.value;
|
||||
},
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("submit"),
|
||||
()=>{
|
||||
console.log(name, category);
|
||||
func.bind(this)(name, category);
|
||||
channelselect.hide();
|
||||
},
|
||||
],
|
||||
]);
|
||||
const options=["text", "announcement","voice"].map(e=>I18n.getTranslation("channel."+e));
|
||||
|
||||
const channelselect=new BDialog("");
|
||||
const form=channelselect.options.addForm("",(e:any)=>{
|
||||
func(e.name,e.type);
|
||||
channelselect.hide();
|
||||
});
|
||||
|
||||
form.addSelect(I18n.getTranslation("channel.selectType"),"type",options,{radio:true},[0,5,2]);
|
||||
form.addTextInput(I18n.getTranslation("channel.selectName"),"name");
|
||||
channelselect.show();
|
||||
}
|
||||
createcategory(){
|
||||
let name = "";
|
||||
const category = 4;
|
||||
const channelselect = new Dialog([
|
||||
"vdiv",
|
||||
[
|
||||
"textbox",
|
||||
I18n.getTranslation("channel.selectCatName"),
|
||||
"",
|
||||
function(this: HTMLInputElement){
|
||||
name = this.value;
|
||||
},
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("submit"),
|
||||
function(this:Guild){
|
||||
console.log(name, category);
|
||||
this.createChannel(name, category);
|
||||
channelselect.hide();
|
||||
}.bind(this),
|
||||
],
|
||||
]);
|
||||
const channelselect=new BDialog("");
|
||||
const options=channelselect.options;
|
||||
const form=options.addForm("",(e:any)=>{
|
||||
this.createChannel(e.name, category);
|
||||
channelselect.hide();
|
||||
});
|
||||
form.addTextInput(I18n.getTranslation("channel.selectCatName"),"name");
|
||||
channelselect.show();
|
||||
}
|
||||
delChannel(json: channeljson){
|
||||
|
|
|
@ -63,7 +63,7 @@ type readyjson = {
|
|||
};
|
||||
user_guild_settings: {
|
||||
entries: {
|
||||
channel_overrides: unknown[]; //will have to find example
|
||||
channel_overrides: {message_notifications: number,muted: boolean,mute_config: {selected_time_window: number,end_time: number},channel_id: string}[];
|
||||
message_notifications: number;
|
||||
flags: number;
|
||||
hide_muted_channels: boolean;
|
||||
|
@ -523,6 +523,11 @@ roleCreate | {
|
|||
nickname: null
|
||||
},
|
||||
s: number
|
||||
}|{
|
||||
op: 0,
|
||||
t: "PRESENCE_UPDATE",
|
||||
d: presencejson,
|
||||
s:number
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -3,11 +3,10 @@ import{ Channel }from"./channel.js";
|
|||
import{ Direct }from"./direct.js";
|
||||
import{ AVoice }from"./audio.js";
|
||||
import{ User }from"./user.js";
|
||||
import{ Dialog }from"./dialog.js";
|
||||
import{ getapiurls, getBulkInfo, setTheme, Specialuser, SW }from"./login.js";
|
||||
import{channeljson,guildjson,mainuserjson,memberjson,memberlistupdatejson,messageCreateJson,presencejson,readyjson,startTypingjson,wsjson,}from"./jsontypes.js";
|
||||
import{ Member }from"./member.js";
|
||||
import{ Form, FormError, Options, Settings }from"./settings.js";
|
||||
import{ BDialog, Form, FormError, Options, Settings }from"./settings.js";
|
||||
import{ getTextNodeAtPosition, MarkDown }from"./markdown.js";
|
||||
import { Bot } from "./bot.js";
|
||||
import { Role } from "./role.js";
|
||||
|
@ -26,8 +25,6 @@ class Localuser{
|
|||
initialized!: boolean;
|
||||
info!: Specialuser["serverurls"];
|
||||
headers!: { "Content-type": string; Authorization: string };
|
||||
userConnections!: Dialog;
|
||||
devPortal!: Dialog;
|
||||
ready!: readyjson;
|
||||
guilds!: Guild[];
|
||||
guildids: Map<string, Guild> = new Map();
|
||||
|
@ -559,6 +556,12 @@ class Localuser{
|
|||
this.relationshipsUpdate();
|
||||
break;
|
||||
}
|
||||
case "PRESENCE_UPDATE":{
|
||||
if(temp.d.user){
|
||||
this.presences.set(temp.d.user.id, temp.d);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default :{
|
||||
//@ts-ignore
|
||||
console.warn("Unhandled case "+temp.t,temp);
|
||||
|
@ -888,99 +891,44 @@ class Localuser{
|
|||
this.unreads();
|
||||
}
|
||||
createGuild(){
|
||||
let inviteurl = "";
|
||||
const error = document.createElement("span");
|
||||
const fields: { name: string; icon: string | null } = {
|
||||
name: "",
|
||||
icon: null,
|
||||
};
|
||||
const full = new Dialog([
|
||||
"tabs",
|
||||
[
|
||||
[
|
||||
I18n.getTranslation("invite.joinUsing"),
|
||||
[
|
||||
"vdiv",
|
||||
[
|
||||
"textbox",
|
||||
I18n.getTranslation("invite.inviteLinkCode"),
|
||||
"",
|
||||
function(this: HTMLInputElement){
|
||||
inviteurl = this.value;
|
||||
},
|
||||
],
|
||||
["html", error],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("submit"),
|
||||
(_: any)=>{
|
||||
let parsed = "";
|
||||
if(inviteurl.includes("/")){
|
||||
parsed =
|
||||
inviteurl.split("/")[inviteurl.split("/").length - 1];
|
||||
}else{
|
||||
parsed = inviteurl;
|
||||
}
|
||||
fetch(this.info.api + "/invites/" + parsed, {
|
||||
method: "POST",
|
||||
headers: this.headers,
|
||||
})
|
||||
.then(r=>r.json())
|
||||
.then(_=>{
|
||||
if(_.message){
|
||||
error.textContent = _.message;
|
||||
}
|
||||
});
|
||||
},
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
I18n.getTranslation("guild.create"),
|
||||
[
|
||||
"vdiv",
|
||||
["title", I18n.getTranslation("guild.create")],
|
||||
[
|
||||
"fileupload",
|
||||
I18n.getTranslation("guild.icon:"),
|
||||
function(event: Event){
|
||||
const target = event.target as HTMLInputElement;
|
||||
if(!target.files)return;
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(target.files[0]);
|
||||
reader.onload = ()=>{
|
||||
fields.icon = reader.result as string;
|
||||
};
|
||||
},
|
||||
],
|
||||
[
|
||||
"textbox",
|
||||
I18n.getTranslation("guild.name:"),
|
||||
"",
|
||||
function(this: HTMLInputElement, event: Event){
|
||||
const target = event.target as HTMLInputElement;
|
||||
fields.name = target.value;
|
||||
},
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("submit"),
|
||||
()=>{
|
||||
this.makeGuild(fields).then(_=>{
|
||||
if(_.message){
|
||||
alert(_.errors.name._errors[0].message);
|
||||
}else{
|
||||
full.hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
const full=new BDialog("");
|
||||
const buttons=full.options.addButtons("",{top:true});
|
||||
const viacode=buttons.add(I18n.getTranslation("invite.joinUsing"));
|
||||
{
|
||||
const form=viacode.addForm("",async (e: any)=>{
|
||||
let parsed = "";
|
||||
if(e.code.includes("/")){
|
||||
parsed = e.code.split("/")[e.code.split("/").length - 1];
|
||||
}else{
|
||||
parsed = e.code;
|
||||
}
|
||||
const json=await (await fetch(this.info.api + "/invites/" + parsed, {
|
||||
method: "POST",
|
||||
headers: this.headers,
|
||||
})).json()
|
||||
if(json.message){
|
||||
throw new FormError(text,json.message);
|
||||
}
|
||||
full.hide();
|
||||
});
|
||||
const text=form.addTextInput(I18n.getTranslation("invite.inviteLinkCode"),"code");
|
||||
}
|
||||
const guildcreate=buttons.add(I18n.getTranslation("guild.create"));
|
||||
{
|
||||
const form=guildcreate.addForm("",(fields:any)=>{
|
||||
this.makeGuild(fields).then(_=>{
|
||||
if(_.message){
|
||||
alert(_.errors.name._errors[0].message);
|
||||
}else{
|
||||
full.hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
form.addFileInput(I18n.getTranslation("guild.icon:"),"icon",{files:"one"});
|
||||
form.addTextInput(I18n.getTranslation("guild.name:"),"name",{required:true});
|
||||
|
||||
}
|
||||
full.show();
|
||||
}
|
||||
async makeGuild(fields: { name: string; icon: string | null }){
|
||||
|
@ -996,7 +944,8 @@ class Localuser{
|
|||
const content = document.createElement("div");
|
||||
content.classList.add("flexttb","guildy");
|
||||
content.textContent = I18n.getTranslation("guild.loadingDiscovery");
|
||||
const full = new Dialog(["html", content]);
|
||||
const full = new BDialog("");
|
||||
full.options.addHTMLArea(content);
|
||||
full.show();
|
||||
|
||||
const res = await fetch(this.info.api + "/discoverable-guilds?limit=50", {
|
||||
|
@ -2147,15 +2096,12 @@ class Localuser{
|
|||
headers: this.headers,
|
||||
});
|
||||
const json = await res.json();
|
||||
|
||||
const dialog = new Dialog([
|
||||
"vdiv",
|
||||
["title", I18n.getTranslation("instanceStats.name",this.instancePing.name) ],
|
||||
["text", I18n.getTranslation("instanceStats.users",json.counts.user)],
|
||||
["text", I18n.getTranslation("instanceStats.servers",json.counts.guild)],
|
||||
["text", I18n.getTranslation("instanceStats.messages",json.counts.message)],
|
||||
["text", I18n.getTranslation("instanceStats.members",json.counts.members)],
|
||||
]);
|
||||
const dialog = new BDialog("");
|
||||
dialog.options.addTitle(I18n.getTranslation("instanceStats.name",this.instancePing.name));
|
||||
dialog.options.addText(I18n.getTranslation("instanceStats.users",json.counts.user));
|
||||
dialog.options.addText(I18n.getTranslation("instanceStats.servers",json.counts.guild));
|
||||
dialog.options.addText(I18n.getTranslation("instanceStats.messages",json.counts.message));
|
||||
dialog.options.addText(I18n.getTranslation("instanceStats.members",json.counts.members));
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import{ Dialog }from"./dialog.js";
|
||||
import { I18n } from "./i18n.js";
|
||||
import { BDialog, FormError } from "./settings.js";
|
||||
|
||||
const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||
const iOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
||||
|
@ -511,65 +511,43 @@ async function login(username: string, password: string, captcha: string){
|
|||
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);
|
||||
capt!.append(script);
|
||||
capt!.append(capty);
|
||||
}
|
||||
}else{
|
||||
console.log(response);
|
||||
if(response.ticket){
|
||||
let onetimecode = "";
|
||||
new Dialog([
|
||||
"vdiv",
|
||||
["title", I18n.getTranslation("2faCode")],
|
||||
[
|
||||
"textbox",
|
||||
"",
|
||||
"",
|
||||
function(this: HTMLInputElement){
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
onetimecode = this.value;
|
||||
},
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("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(res=>{
|
||||
if(res.message){
|
||||
alert(res.message);
|
||||
}else{
|
||||
console.warn(res);
|
||||
if(!res.token)return;
|
||||
adduser({
|
||||
serverurls: JSON.parse(localStorage.getItem("instanceinfo") as string),
|
||||
email: username,
|
||||
token: res.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();
|
||||
const better=new BDialog("");
|
||||
const form=better.options.addForm("",(res:any)=>{
|
||||
if(res.message){
|
||||
throw new FormError(ti,res.message);
|
||||
}else{
|
||||
console.warn(res);
|
||||
if(!res.token)return;
|
||||
adduser({
|
||||
serverurls: JSON.parse(localStorage.getItem("instanceinfo") as string),
|
||||
email: username,
|
||||
token: res.token,
|
||||
}).username = username;
|
||||
const redir = new URLSearchParams(
|
||||
window.location.search
|
||||
).get("goback");
|
||||
if(redir){
|
||||
window.location.href = redir;
|
||||
}else{
|
||||
window.location.href = "/channels/@me";
|
||||
}
|
||||
}
|
||||
},{
|
||||
fetchURL:api + "/auth/mfa/totp",
|
||||
method:"POST",
|
||||
headers:{
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
});
|
||||
form.addTitle(I18n.getTranslation("2faCode"));
|
||||
const ti=form.addTextInput("","code");
|
||||
better.show()
|
||||
}else{
|
||||
console.warn(response);
|
||||
if(!response.token)return;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import{ Channel }from"./channel.js";
|
||||
import{ Dialog }from"./dialog.js";
|
||||
import{ Emoji }from"./emoji.js";
|
||||
import{ Guild }from"./guild.js";
|
||||
import { I18n } from "./i18n.js";
|
||||
import{ Localuser }from"./localuser.js";
|
||||
import{ Member }from"./member.js";
|
||||
import { BDialog } from "./settings.js";
|
||||
|
||||
class MarkDown{
|
||||
txt: string[];
|
||||
|
@ -781,37 +781,20 @@ txt[j + 1] === undefined)
|
|||
if(this.trustedDomains.has(Url.host)){
|
||||
open();
|
||||
}else{
|
||||
const full: Dialog = new Dialog([
|
||||
"vdiv",
|
||||
["title", I18n.getTranslation("leaving")],
|
||||
[
|
||||
"text",
|
||||
I18n.getTranslation("goingToURL",Url.host)
|
||||
],
|
||||
[
|
||||
"hdiv",
|
||||
["button", "", I18n.getTranslation("nevermind"), (_: any)=>full.hide()],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("goThere"),
|
||||
(_: any)=>{
|
||||
open();
|
||||
full.hide();
|
||||
},
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("goThereTrust"),
|
||||
(_: any)=>{
|
||||
open();
|
||||
full.hide();
|
||||
this.trustedDomains.add(Url.host);
|
||||
},
|
||||
],
|
||||
],
|
||||
]);
|
||||
const full=new BDialog("");
|
||||
full.options.addTitle(I18n.getTranslation("leaving"));
|
||||
full.options.addText(I18n.getTranslation("goingToURL",Url.host));
|
||||
const options=full.options.addOptions("",{ltr:true});
|
||||
options.addButtonInput("",I18n.getTranslation("nevermind"),()=>full.hide());
|
||||
options.addButtonInput("",I18n.getTranslation("goThere"),()=>{
|
||||
open();
|
||||
full.hide();
|
||||
});
|
||||
options.addButtonInput("",I18n.getTranslation("goThereTrust"),()=>{
|
||||
open();
|
||||
full.hide();
|
||||
this.trustedDomains.add(Url.host);
|
||||
});
|
||||
full.show();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,8 +3,8 @@ import{ Role }from"./role.js";
|
|||
import{ Guild }from"./guild.js";
|
||||
import{ SnowFlake }from"./snowflake.js";
|
||||
import{ memberjson, presencejson }from"./jsontypes.js";
|
||||
import{ Dialog }from"./dialog.js";
|
||||
import { I18n } from "./i18n.js";
|
||||
import { BDialog } from "./settings.js";
|
||||
|
||||
class Member extends SnowFlake{
|
||||
static already = {};
|
||||
|
@ -229,28 +229,13 @@ class Member extends SnowFlake{
|
|||
return this.nick || this.user.username;
|
||||
}
|
||||
kick(){
|
||||
let reason = "";
|
||||
const menu = new Dialog([
|
||||
"vdiv",
|
||||
["title", I18n.getTranslation("member.kick",this.name,this.guild.properties.name)],
|
||||
[
|
||||
"textbox",
|
||||
I18n.getTranslation("member.reason:"),
|
||||
"",
|
||||
function(e: Event){
|
||||
reason = (e.target as HTMLInputElement).value;
|
||||
},
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("submit"),
|
||||
()=>{
|
||||
this.kickAPI(reason);
|
||||
menu.hide();
|
||||
},
|
||||
],
|
||||
]);
|
||||
const menu = new BDialog("");
|
||||
const form=menu.options.addForm("",((e:any)=>{
|
||||
this.kickAPI(e.reason);
|
||||
menu.hide();
|
||||
}));
|
||||
form.addTitle(I18n.getTranslation("member.kick",this.name,this.guild.properties.name));
|
||||
form.addTextInput(I18n.getTranslation("member.reason:"),"reason");
|
||||
menu.show();
|
||||
}
|
||||
kickAPI(reason: string){
|
||||
|
@ -262,28 +247,13 @@ class Member extends SnowFlake{
|
|||
});
|
||||
}
|
||||
ban(){
|
||||
let reason = "";
|
||||
const menu = new Dialog([
|
||||
"vdiv",
|
||||
["title", I18n.getTranslation("member.ban",this.name,this.guild.properties.name)],
|
||||
[
|
||||
"textbox",
|
||||
I18n.getTranslation("member.reason:",this.name,this.guild.properties.name),
|
||||
"",
|
||||
function(e: Event){
|
||||
reason = (e.target as HTMLInputElement).value;
|
||||
},
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("submit",this.name,this.guild.properties.name),
|
||||
()=>{
|
||||
this.banAPI(reason);
|
||||
menu.hide();
|
||||
},
|
||||
],
|
||||
]);
|
||||
const menu = new BDialog("");
|
||||
const form=menu.options.addForm("",((e:any)=>{
|
||||
this.banAPI(e.reason);
|
||||
menu.hide();
|
||||
}));
|
||||
form.addTitle(I18n.getTranslation("member.ban",this.name,this.guild.properties.name));
|
||||
form.addTextInput(I18n.getTranslation("member.reason:"),"reason");
|
||||
menu.show();
|
||||
}
|
||||
addRole(role:Role){
|
||||
|
|
|
@ -10,10 +10,10 @@ import{ File }from"./file.js";
|
|||
import{ SnowFlake }from"./snowflake.js";
|
||||
import{ memberjson, messagejson }from"./jsontypes.js";
|
||||
import{ Emoji }from"./emoji.js";
|
||||
import{ Dialog }from"./dialog.js";
|
||||
import{ mobile }from"./login.js";
|
||||
import { I18n } from "./i18n.js";
|
||||
import { Hover } from "./hover.js";
|
||||
import { BDialog } from "./settings.js";
|
||||
|
||||
class Message extends SnowFlake{
|
||||
static contextmenu = new Contextmenu<Message, undefined>("message menu");
|
||||
|
@ -87,7 +87,7 @@ class Message extends SnowFlake{
|
|||
Message.contextmenu.addbutton(
|
||||
()=>I18n.getTranslation("message.delete"),
|
||||
function(this: Message){
|
||||
this.delete();
|
||||
this.confirmDelete();
|
||||
},
|
||||
null,
|
||||
function(){
|
||||
|
@ -674,31 +674,7 @@ class Message extends SnowFlake{
|
|||
this.delete();
|
||||
return;
|
||||
}
|
||||
const diaolog = new Dialog([
|
||||
"vdiv",
|
||||
["title", I18n.getTranslation("deleteConfirm")],
|
||||
[
|
||||
"hdiv",
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("yes"),
|
||||
()=>{
|
||||
this.delete();
|
||||
diaolog.hide();
|
||||
},
|
||||
],
|
||||
[
|
||||
"button",
|
||||
"",
|
||||
I18n.getTranslation("no"),
|
||||
()=>{
|
||||
diaolog.hide();
|
||||
},
|
||||
],
|
||||
]
|
||||
]);
|
||||
diaolog.show();
|
||||
this.confirmDelete();
|
||||
};
|
||||
}
|
||||
if(buttons.childNodes.length !== 0){
|
||||
|
@ -714,6 +690,19 @@ class Message extends SnowFlake{
|
|||
};
|
||||
}
|
||||
}
|
||||
confirmDelete(){
|
||||
const diaolog=new BDialog("");
|
||||
diaolog.options.addTitle(I18n.getTranslation("deleteConfirm"));
|
||||
const options=diaolog.options.addOptions("",{ltr:true});
|
||||
options.addButtonInput("",I18n.getTranslation("yes"),()=>{
|
||||
this.delete();
|
||||
diaolog.hide();
|
||||
});
|
||||
options.addButtonInput("",I18n.getTranslation("no"),()=>{
|
||||
diaolog.hide();
|
||||
})
|
||||
diaolog.show();
|
||||
}
|
||||
updateReactions(){
|
||||
const reactdiv = this.reactdiv.deref();
|
||||
if(!reactdiv)return;
|
||||
|
|
|
@ -14,7 +14,9 @@ class Buttons implements OptionsElement<unknown>{
|
|||
buttonList!: HTMLDivElement;
|
||||
warndiv!: HTMLElement;
|
||||
value: unknown;
|
||||
constructor(name: string){
|
||||
top=false;
|
||||
constructor(name: string,{top=false}={}){
|
||||
this.top=top;
|
||||
this.buttons = [];
|
||||
this.name = name;
|
||||
}
|
||||
|
@ -28,7 +30,7 @@ class Buttons implements OptionsElement<unknown>{
|
|||
generateHTML(){
|
||||
const buttonList = document.createElement("div");
|
||||
buttonList.classList.add("Buttons");
|
||||
buttonList.classList.add("flexltr");
|
||||
buttonList.classList.add(this.top?"flexttb":"flexltr");
|
||||
this.buttonList = buttonList;
|
||||
const htmlarea = document.createElement("div");
|
||||
htmlarea.classList.add("flexgrow");
|
||||
|
@ -43,6 +45,9 @@ class Buttons implements OptionsElement<unknown>{
|
|||
generateButtons(optionsArea:HTMLElement){
|
||||
const buttonTable = document.createElement("div");
|
||||
buttonTable.classList.add("settingbuttons");
|
||||
if(this.top){
|
||||
buttonTable.classList.add("flexltr");
|
||||
}
|
||||
for(const thing of this.buttons){
|
||||
const button = document.createElement("button");
|
||||
button.classList.add("SettingsButton");
|
||||
|
@ -328,6 +333,7 @@ class SelectInput implements OptionsElement<number>{
|
|||
options: string[];
|
||||
index: number;
|
||||
select!: WeakRef<HTMLSelectElement>;
|
||||
radio:boolean;
|
||||
get value(){
|
||||
return this.index;
|
||||
}
|
||||
|
@ -336,15 +342,61 @@ class SelectInput implements OptionsElement<number>{
|
|||
onSubmit: (str: number) => void,
|
||||
options: string[],
|
||||
owner: Options,
|
||||
{ defaultIndex = 0 } = {}
|
||||
{ defaultIndex = 0,radio=false } = {}
|
||||
){
|
||||
this.label = label;
|
||||
this.index = defaultIndex;
|
||||
this.owner = owner;
|
||||
this.onSubmit = onSubmit;
|
||||
this.options = options;
|
||||
this.radio=radio;
|
||||
}
|
||||
generateHTML(): HTMLDivElement{
|
||||
if(this.radio){
|
||||
const map=new WeakMap<HTMLInputElement,number>();
|
||||
const div = document.createElement("div");
|
||||
const fieldset = document.createElement("fieldset");
|
||||
fieldset.addEventListener("change", ()=>{
|
||||
let i = -1;
|
||||
for(const thing of Array.from(fieldset.children)){
|
||||
i++;
|
||||
if(i === 0){
|
||||
continue;
|
||||
}
|
||||
const checkbox = thing.children[0].children[0] as HTMLInputElement;
|
||||
if(checkbox.checked){
|
||||
this.onChange(map.get(checkbox));
|
||||
}
|
||||
}
|
||||
});
|
||||
const legend = document.createElement("legend");
|
||||
legend.textContent = this.label;
|
||||
fieldset.appendChild(legend);
|
||||
let i = 0;
|
||||
for(const thing of this.options){
|
||||
const div = document.createElement("div");
|
||||
const input = document.createElement("input");
|
||||
input.classList.add("radio");
|
||||
input.type = "radio";
|
||||
input.name = this.label;
|
||||
input.value = thing;
|
||||
map.set(input,i);
|
||||
if(i === this.index){
|
||||
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;
|
||||
}
|
||||
const div = document.createElement("div");
|
||||
const span = document.createElement("span");
|
||||
span.textContent = this.label;
|
||||
|
@ -353,7 +405,7 @@ class SelectInput implements OptionsElement<number>{
|
|||
selectSpan.classList.add("selectspan");
|
||||
const select = document.createElement("select");
|
||||
|
||||
select.onchange = this.onChange.bind(this);
|
||||
select.onchange = this.onChange.bind(this,-1);
|
||||
for(const thing of this.options){
|
||||
const option = document.createElement("option");
|
||||
option.textContent = thing;
|
||||
|
@ -368,8 +420,13 @@ class SelectInput implements OptionsElement<number>{
|
|||
div.append(selectSpan);
|
||||
return div;
|
||||
}
|
||||
private onChange(){
|
||||
private onChange(index=-1){
|
||||
this.owner.changed();
|
||||
if(index!==-1){
|
||||
this.onchange(index);
|
||||
this.index = index;
|
||||
return;
|
||||
}
|
||||
const select = this.select.deref();
|
||||
if(select){
|
||||
const value = select.selectedIndex;
|
||||
|
@ -524,7 +581,7 @@ class Float{
|
|||
/**
|
||||
* 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}){
|
||||
constructor(name:string, options={ ltr:false, noSubmit:true}){
|
||||
this.options=new Options(name,this,options)
|
||||
}
|
||||
changed=()=>{};
|
||||
|
@ -532,6 +589,38 @@ class Float{
|
|||
return this.options.generateHTML();
|
||||
}
|
||||
}
|
||||
class BDialog{
|
||||
float:Float;
|
||||
get options(){
|
||||
return this.float.options;
|
||||
}
|
||||
background=new WeakRef(document.createElement("div"));
|
||||
constructor(name:string, { ltr=false, noSubmit=true}={}){
|
||||
this.float=new Float(name,{ltr,noSubmit});
|
||||
}
|
||||
show(){
|
||||
const background = document.createElement("div");
|
||||
background.classList.add("background");
|
||||
const center=this.float.generateHTML();
|
||||
center.classList.add("centeritem","nonimagecenter");
|
||||
center.classList.remove("titlediv");
|
||||
background.append(center);
|
||||
center.onclick=e=>{
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
document.body.append(background);
|
||||
this.background=new WeakRef(background);
|
||||
background.onclick = _=>{
|
||||
background.remove();
|
||||
};
|
||||
}
|
||||
hide(){
|
||||
const background=this.background.deref();
|
||||
if(!background) return;
|
||||
background.remove();
|
||||
}
|
||||
}
|
||||
export{BDialog};
|
||||
class Options implements OptionsElement<void>{
|
||||
name: string;
|
||||
haschanged = false;
|
||||
|
@ -571,6 +660,12 @@ class Options implements OptionsElement<void>{
|
|||
this.generate(options);
|
||||
return options;
|
||||
}
|
||||
addButtons(name: string, { top = false } = {}){
|
||||
const buttons = new Buttons(name, { top });
|
||||
this.options.push(buttons);
|
||||
this.generate(buttons);
|
||||
return buttons;
|
||||
}
|
||||
subOptions: Options | Form | undefined;
|
||||
genTop(){
|
||||
const container = this.container.deref();
|
||||
|
@ -596,7 +691,7 @@ class Options implements OptionsElement<void>{
|
|||
}
|
||||
addSubForm(
|
||||
name: string,
|
||||
onSubmit: (arg1: object) => void,
|
||||
onSubmit: (arg1: object,sent:object) => void,
|
||||
{
|
||||
ltr = false,
|
||||
submitText = "Submit",
|
||||
|
@ -626,10 +721,10 @@ class Options implements OptionsElement<void>{
|
|||
label: string,
|
||||
onSubmit: (str: number) => void,
|
||||
selections: string[],
|
||||
{ defaultIndex = 0 } = {}
|
||||
{ defaultIndex = 0,radio=false } = {}
|
||||
){
|
||||
const select = new SelectInput(label, onSubmit, selections, this, {
|
||||
defaultIndex,
|
||||
defaultIndex,radio
|
||||
});
|
||||
this.options.push(select);
|
||||
this.generate(select);
|
||||
|
@ -717,7 +812,7 @@ class Options implements OptionsElement<void>{
|
|||
}
|
||||
addForm(
|
||||
name: string,
|
||||
onSubmit: (arg1: object) => void,
|
||||
onSubmit: (arg1: object,sent:object) => void,
|
||||
{
|
||||
ltr = false,
|
||||
submitText = "Submit",
|
||||
|
@ -901,7 +996,7 @@ class Form implements OptionsElement<object>{
|
|||
constructor(
|
||||
name: string,
|
||||
owner: Options,
|
||||
onSubmit: (arg1: object) => void,
|
||||
onSubmit: (arg1: object,sent:object) => void,
|
||||
{
|
||||
ltr = false,
|
||||
submitText = I18n.getTranslation("submit"),
|
||||
|
@ -934,7 +1029,7 @@ class Form implements OptionsElement<object>{
|
|||
}
|
||||
addSubForm(
|
||||
name: string,
|
||||
onSubmit: (arg1: object) => void,
|
||||
onSubmit: (arg1: object,sent:object) => void,
|
||||
{
|
||||
ltr = false,
|
||||
submitText = I18n.getTranslation("submit"),
|
||||
|
@ -956,16 +1051,16 @@ class Form implements OptionsElement<object>{
|
|||
(this.button.deref() as HTMLElement).hidden=false;
|
||||
}
|
||||
}
|
||||
selectMap=new WeakMap<SelectInput,string[]>();
|
||||
selectMap=new WeakMap<SelectInput,(number|string)[]>();
|
||||
addSelect(
|
||||
label: string,
|
||||
formName: string,
|
||||
selections: string[],
|
||||
{ defaultIndex = 0, required = false}={},
|
||||
correct:string[]=selections
|
||||
{ defaultIndex = 0, required = false,radio=false}={},
|
||||
correct:(string|number)[]=selections
|
||||
){
|
||||
const select = this.options.addSelect(label, _=>{}, selections, {
|
||||
defaultIndex,
|
||||
defaultIndex,radio
|
||||
});
|
||||
this.selectMap.set(select,correct);
|
||||
this.names.set(formName, select);
|
||||
|
@ -1084,7 +1179,7 @@ class Form implements OptionsElement<object>{
|
|||
}
|
||||
return div;
|
||||
}
|
||||
onSubmit: (arg1: object) => void;
|
||||
onSubmit: ((arg1: object,sent:object) => void )|((arg1: object,sent:object) => Promise<void> );
|
||||
watchForChange(func: (arg1: object) => void){
|
||||
this.onSubmit = func;
|
||||
}
|
||||
|
@ -1187,14 +1282,14 @@ class Form implements OptionsElement<object>{
|
|||
if(_==="") return {};
|
||||
return JSON.parse(_)
|
||||
})
|
||||
.then(json=>{
|
||||
.then(async json=>{
|
||||
if(json.errors){
|
||||
if(this.errors(json)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
try{
|
||||
this.onSubmit(json);
|
||||
await this.onSubmit(json,build);
|
||||
}catch(e){
|
||||
console.error(e);
|
||||
if(e instanceof FormError){
|
||||
|
@ -1211,7 +1306,7 @@ class Form implements OptionsElement<object>{
|
|||
});
|
||||
}else{
|
||||
try{
|
||||
this.onSubmit(build);
|
||||
await this.onSubmit(build,build);
|
||||
}catch(e){
|
||||
if(e instanceof FormError){
|
||||
const elm = this.options.html.get(e.elem);
|
||||
|
|
|
@ -1614,12 +1614,12 @@ img.bigembedimg {
|
|||
gap: 8px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.nonimagecenter .flexttb, .nonimagecenter .flexltr {
|
||||
.nonimagecenter & .flexttb, .nonimagecenter & .flexltr {
|
||||
flex: 1;
|
||||
gap: 8px;
|
||||
}
|
||||
.nonimagecenter > .flexttb, .nonimagecenter > .flexltr {
|
||||
padding: 16px;
|
||||
padding: 16px !important;
|
||||
background: var(--primary-bg);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
@ -1758,6 +1758,12 @@ fieldset input[type="radio"] {
|
|||
.Buttons {
|
||||
flex: 1;
|
||||
}
|
||||
.settingbuttons.flexltr{
|
||||
width: 100%;
|
||||
.SettingsButton{
|
||||
width:auto;
|
||||
}
|
||||
}
|
||||
.settingbuttons {
|
||||
flex: none;
|
||||
width: 192px;
|
||||
|
@ -1800,7 +1806,8 @@ fieldset input[type="radio"] {
|
|||
}
|
||||
.optionElement, .FormSettings > button {
|
||||
margin: 16px 16px 0 16px;
|
||||
word-break: break-word;
|
||||
/* word-break: break-word; */
|
||||
overflow: hidden;
|
||||
}
|
||||
.optionElement:has(.optionElement) {
|
||||
margin: 0;
|
||||
|
@ -1915,7 +1922,7 @@ fieldset input[type="radio"] {
|
|||
height: calc(100svh - 50px);
|
||||
}
|
||||
.flexspace {
|
||||
flex-direction: column;
|
||||
/*flex-direction: column;*/
|
||||
}
|
||||
.optionElement input[type="text"],
|
||||
.optionElement textarea,
|
||||
|
|
|
@ -152,7 +152,7 @@
|
|||
"nsfw:":"NSFW:",
|
||||
"selectType":"Select channel type",
|
||||
"selectName":"Name of channel",
|
||||
"selectCatName":"Name of channel",
|
||||
"selectCatName":"Name of category",
|
||||
"createChannel":"Create channel",
|
||||
"createCatagory":"Create category"
|
||||
},
|
||||
|
@ -219,7 +219,7 @@
|
|||
"selectnoti":"Select notifications type",
|
||||
"all":"all",
|
||||
"onlyMentions":"only mentions",
|
||||
"none":"node",
|
||||
"none":"none",
|
||||
"confirmLeave":"Are you sure you want to leave?",
|
||||
"yesLeave":"Yes, I'm sure",
|
||||
"noLeave":"Nevermind",
|
||||
|
@ -231,7 +231,8 @@
|
|||
"loadingDiscovery":"Loading...",
|
||||
"disoveryTitle":"Guild discovery ($1) {{PLURAL:$1|entry|entries}}",
|
||||
"emptytitle":"Weird spot",
|
||||
"emptytext":"You're in a weird spot, this guild has no channels"
|
||||
"emptytext":"You're in a weird spot, this guild has no channels",
|
||||
"default":"Default ($1)"
|
||||
},
|
||||
"role":{
|
||||
"displaySettings":"Display settings",
|
||||
|
@ -345,7 +346,9 @@
|
|||
"longInvitedBy":"$1 invited you to join $2",
|
||||
"loginOrCreateAccount":"Login or create an account ⇌",
|
||||
"joinUsing":"Join using invite",
|
||||
"inviteLinkCode":"Invite Link/Code"
|
||||
"inviteLinkCode":"Invite Link/Code",
|
||||
"subtext":"to $1 in $2",
|
||||
"expireAfter":"Expire after:"
|
||||
},
|
||||
"friends":{
|
||||
"blocked":"Blocked",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue