formatting updates
This commit is contained in:
@@ -19,6 +19,12 @@
|
|||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"rimraf": "^6.0.1"
|
"rimraf": "^6.0.1"
|
||||||
},
|
},
|
||||||
|
"prettier":{
|
||||||
|
"useTabs":true,
|
||||||
|
"printWidth":100,
|
||||||
|
"semi":true,
|
||||||
|
"bracketSpacing":false
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.10.0",
|
"@eslint/js": "^9.10.0",
|
||||||
"@html-eslint/eslint-plugin": "^0.25.0",
|
"@html-eslint/eslint-plugin": "^0.25.0",
|
||||||
|
|||||||
56
src/index.ts
56
src/index.ts
@@ -22,31 +22,33 @@ interface Instance {
|
|||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
type instace = {
|
type instace = {
|
||||||
name:string,
|
name: string;
|
||||||
description?:string,
|
description?: string;
|
||||||
descriptionLong?:string,
|
descriptionLong?: string;
|
||||||
image?:string,
|
image?: string;
|
||||||
url?:string,
|
url?: string;
|
||||||
language:string,
|
language: string;
|
||||||
country:string,
|
country: string;
|
||||||
display:boolean,
|
display: boolean;
|
||||||
urls?: {
|
urls?: {
|
||||||
wellknown:string,
|
wellknown: string;
|
||||||
api:string,
|
api: string;
|
||||||
cdn:string,
|
cdn: string;
|
||||||
gateway:string,
|
gateway: string;
|
||||||
login?:string
|
login?: string;
|
||||||
},
|
};
|
||||||
contactInfo?: {
|
contactInfo?: {
|
||||||
discord?:string,
|
discord?: string;
|
||||||
github?:string,
|
github?: string;
|
||||||
email?:string,
|
email?: string;
|
||||||
spacebar?:string,
|
spacebar?: string;
|
||||||
matrix?:string,
|
matrix?: string;
|
||||||
mastodon?:string
|
mastodon?: string;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
const instances=JSON.parse(readFileSync(process.env.JANK_INSTANCES_PATH||(__dirname+"/webpage/instances.json")).toString()) as instace[];
|
const instances = JSON.parse(
|
||||||
|
readFileSync(process.env.JANK_INSTANCES_PATH || __dirname + "/webpage/instances.json").toString(),
|
||||||
|
) as instace[];
|
||||||
|
|
||||||
const instanceNames = new Map<string, Instance>();
|
const instanceNames = new Map<string, Instance>();
|
||||||
|
|
||||||
@@ -58,7 +60,9 @@ app.use(compression());
|
|||||||
|
|
||||||
async function updateInstances(): Promise<void> {
|
async function updateInstances(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("https://raw.githubusercontent.com/spacebarchat/spacebarchat/master/instances/instances.json");
|
const response = await fetch(
|
||||||
|
"https://raw.githubusercontent.com/spacebarchat/spacebarchat/master/instances/instances.json",
|
||||||
|
);
|
||||||
const json = (await response.json()) as Instance[];
|
const json = (await response.json()) as Instance[];
|
||||||
for (const instance of json) {
|
for (const instance of json) {
|
||||||
if (instanceNames.has(instance.name)) {
|
if (instanceNames.has(instance.name)) {
|
||||||
@@ -110,7 +114,7 @@ app.use("/", async (req: Request, res: Response)=>{
|
|||||||
const link = `${host}/services/oembed?url=${encodeURIComponent(ref)}`;
|
const link = `${host}/services/oembed?url=${encodeURIComponent(ref)}`;
|
||||||
res.set(
|
res.set(
|
||||||
"Link",
|
"Link",
|
||||||
`<${link}>; rel="alternate"; type="application/json+oembed"; title="Jank Client oEmbed format"`
|
`<${link}>; rel="alternate"; type="application/json+oembed"; title="Jank Client oEmbed format"`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +170,7 @@ app.use("/", async (req: Request, res: Response)=>{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.set('trust proxy', (ip:string) => ip.startsWith("127."));
|
app.set("trust proxy", (ip: string) => ip.startsWith("127."));
|
||||||
|
|
||||||
const PORT = process.env.PORT || Number(process.argv[2]) || 8080;
|
const PORT = process.env.PORT || Number(process.argv[2]) || 8080;
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
|
|||||||
34
src/stats.ts
34
src/stats.ts
@@ -52,11 +52,11 @@ function saveUptimeObject(): void{
|
|||||||
fs.writeFile(
|
fs.writeFile(
|
||||||
process.env.JANK_UPTIME_JSON_PATH || path.join(__dirname, "..", "uptime.json"),
|
process.env.JANK_UPTIME_JSON_PATH || path.join(__dirname, "..", "uptime.json"),
|
||||||
JSON.stringify(data),
|
JSON.stringify(data),
|
||||||
error=>{
|
(error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Error saving uptime.json:", error);
|
console.error("Error saving uptime.json:", error);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}, 5000); // Batch updates every 5 seconds
|
}, 5000); // Batch updates every 5 seconds
|
||||||
}
|
}
|
||||||
@@ -72,16 +72,12 @@ removeUndefinedKey();
|
|||||||
|
|
||||||
export async function observe(instances: Instance[]): Promise<void> {
|
export async function observe(instances: Instance[]): Promise<void> {
|
||||||
const activeInstances = new Set<string>();
|
const activeInstances = new Set<string>();
|
||||||
const instancePromises = instances.map(instance=>resolveInstance(instance, activeInstances)
|
const instancePromises = instances.map((instance) => resolveInstance(instance, activeInstances));
|
||||||
);
|
|
||||||
await Promise.allSettled(instancePromises);
|
await Promise.allSettled(instancePromises);
|
||||||
updateInactiveInstances(activeInstances);
|
updateInactiveInstances(activeInstances);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveInstance(
|
async function resolveInstance(instance: Instance, activeInstances: Set<string>): Promise<void> {
|
||||||
instance: Instance,
|
|
||||||
activeInstances: Set<string>
|
|
||||||
): Promise<void>{
|
|
||||||
try {
|
try {
|
||||||
calcStats(instance);
|
calcStats(instance);
|
||||||
const api = await getApiUrl(instance);
|
const api = await getApiUrl(instance);
|
||||||
@@ -123,11 +119,7 @@ function scheduleHealthCheck(instance: Instance, api: string): void{
|
|||||||
}, initialDelay);
|
}, initialDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkHealth(
|
async function checkHealth(instance: Instance, api: string, tries = 0): Promise<void> {
|
||||||
instance: Instance,
|
|
||||||
api: string,
|
|
||||||
tries = 0
|
|
||||||
): Promise<void>{
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${api}/ping`, {method: "HEAD"});
|
const response = await fetch(`${api}/ping`, {method: "HEAD"});
|
||||||
console.log(`Checking health for ${instance.name}: ${response.status}`);
|
console.log(`Checking health for ${instance.name}: ${response.status}`);
|
||||||
@@ -146,11 +138,7 @@ async function checkHealth(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function retryHealthCheck(
|
function retryHealthCheck(instance: Instance, api: string, tries: number): void {
|
||||||
instance: Instance,
|
|
||||||
api: string,
|
|
||||||
tries: number
|
|
||||||
): void{
|
|
||||||
setTimeout(() => checkHealth(instance, api, tries + 1), 30000);
|
setTimeout(() => checkHealth(instance, api, tries + 1), 30000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,13 +186,7 @@ function calcStats(instance: Instance): void{
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance.online = online;
|
instance.online = online;
|
||||||
instance.uptime = calculateUptimeStats(
|
instance.uptime = calculateUptimeStats(totalTimePassed, alltime, daytime, weektime, online);
|
||||||
totalTimePassed,
|
|
||||||
alltime,
|
|
||||||
daytime,
|
|
||||||
weektime,
|
|
||||||
online
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateUptimeStats(
|
function calculateUptimeStats(
|
||||||
@@ -212,7 +194,7 @@ function calculateUptimeStats(
|
|||||||
alltime: number,
|
alltime: number,
|
||||||
daytime: number,
|
daytime: number,
|
||||||
weektime: number,
|
weektime: number,
|
||||||
online: boolean
|
online: boolean,
|
||||||
): {daytime: number; weektime: number; alltime: number} {
|
): {daytime: number; weektime: number; alltime: number} {
|
||||||
const dayInMs = 1000 * 60 * 60 * 24;
|
const dayInMs = 1000 * 60 * 60 * 24;
|
||||||
const weekInMs = dayInMs * 7;
|
const weekInMs = dayInMs * 7;
|
||||||
|
|||||||
10
src/utils.ts
10
src/utils.ts
@@ -24,12 +24,12 @@ export async function getApiUrls(url: string): Promise<ApiUrls | null>{
|
|||||||
url += "/";
|
url += "/";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const info: ApiUrls = await fetch(`${url}.well-known/spacebar`).then(res=>res.json());
|
const info: ApiUrls = await fetch(`${url}.well-known/spacebar`).then((res) => res.json());
|
||||||
const api = info.api;
|
const api = info.api;
|
||||||
const apiUrl = new URL(api);
|
const apiUrl = new URL(api);
|
||||||
const policies: any = await fetch(
|
const policies: any = await fetch(
|
||||||
`${api}${apiUrl.pathname.includes("api") ? "" : "api"}/policies/instance/domains`
|
`${api}${apiUrl.pathname.includes("api") ? "" : "api"}/policies/instance/domains`,
|
||||||
).then(res=>res.json());
|
).then((res) => res.json());
|
||||||
return {
|
return {
|
||||||
api: policies.apiEndpoint,
|
api: policies.apiEndpoint,
|
||||||
gateway: policies.gateway,
|
gateway: policies.gateway,
|
||||||
@@ -68,7 +68,9 @@ export async function inviteResponse(req: Request, res: Response): Promise<void>
|
|||||||
throw new Error("Failed to get API URLs");
|
throw new Error("Failed to get API URLs");
|
||||||
}
|
}
|
||||||
|
|
||||||
const invite = await fetch(`${urls.api}/invites/${code}`).then(json=>json.json() as Promise<Invite>);
|
const invite = await fetch(`${urls.api}/invites/${code}`).then(
|
||||||
|
(json) => json.json() as Promise<Invite>,
|
||||||
|
);
|
||||||
const title = invite.guild.name;
|
const title = invite.guild.name;
|
||||||
const description = invite.inviter
|
const description = invite.inviter
|
||||||
? `${invite.inviter.username} has invited you to ${invite.guild.name}${invite.guild.description ? `\n${invite.guild.description}` : ""}`
|
? `${invite.inviter.username} has invited you to ${invite.guild.name}${invite.guild.description ? `\n${invite.guild.description}` : ""}`
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export class Audio{
|
|||||||
static parse(read: BinRead, trackarr: Track[]): Audio {
|
static parse(read: BinRead, trackarr: Track[]): Audio {
|
||||||
const name = read.readString8();
|
const name = read.readString8();
|
||||||
const length = read.read16();
|
const length = read.read16();
|
||||||
const tracks:(Track|number)[]=[]
|
const tracks: (Track | number)[] = [];
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
let index = read.read16();
|
let index = read.read16();
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
@@ -20,7 +20,7 @@ export class Audio{
|
|||||||
tracks.push(trackarr[index - 1]);
|
tracks.push(trackarr[index - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Audio(name,tracks)
|
return new Audio(name, tracks);
|
||||||
}
|
}
|
||||||
async play() {
|
async play() {
|
||||||
for (const thing of this.tracks) {
|
for (const thing of this.tracks) {
|
||||||
|
|||||||
@@ -1,26 +1,39 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jank Audio</title>
|
<title>Jank Audio</title>
|
||||||
<meta content="Jank Sound" property="og:title">
|
<meta content="Jank Sound" property="og:title" />
|
||||||
<meta content="A sound editor for jank clients sound format .jasf" property="og:description">
|
<meta content="A sound editor for jank clients sound format .jasf" property="og:description" />
|
||||||
<meta content="/logo.webp" property="og:image">
|
<meta content="/logo.webp" property="og:image" />
|
||||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||||
<link href="/style.css" rel="stylesheet">
|
<link href="/style.css" rel="stylesheet" />
|
||||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
<link href="/themes.css" rel="stylesheet" id="lightcss" />
|
||||||
<style>body.no-theme{background:#16191b;}@media(prefers-color-scheme:light){body.no-theme{background:#9397bd;}}</style>
|
<style>
|
||||||
|
body.no-theme {
|
||||||
|
background: #16191b;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
body.no-theme {
|
||||||
|
background: #9397bd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="no-theme" style="overflow-y: scroll;">
|
<body class="no-theme" style="overflow-y: scroll">
|
||||||
<h1>This will eventually be something</h1>
|
<h1>This will eventually be something</h1>
|
||||||
<p>I want to let the sound system of jank not be so hard coded, but I still need to work on everything a bit before that can happen. Thanks for your patience.</p>
|
<p>
|
||||||
|
I want to let the sound system of jank not be so hard coded, but I still need to work on
|
||||||
|
everything a bit before that can happen. Thanks for your patience.
|
||||||
|
</p>
|
||||||
<h3>why does this tool need to exist?</h3>
|
<h3>why does this tool need to exist?</h3>
|
||||||
<p>For size reasons jank does not use normal sound files, so I need to make this whole format to be more adaptable</p>
|
<p>
|
||||||
|
For size reasons jank does not use normal sound files, so I need to make this whole format to
|
||||||
|
be more adaptable
|
||||||
|
</p>
|
||||||
<button id="download">Download the sounds</button>
|
<button id="download">Download the sounds</button>
|
||||||
</body>
|
</body>
|
||||||
<script src="/audio/page.js" type="module"></script>
|
<script src="/audio/page.js" type="module"></script>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -19,25 +19,28 @@ w.write32Float(150);
|
|||||||
//return Math.sin(((t + 2) ** Math.cos(t * 4)) * Math.PI * 2 * freq);
|
//return Math.sin(((t + 2) ** Math.cos(t * 4)) * Math.PI * 2 * freq);
|
||||||
//Math.sin((((t+2)**Math.cos((t*4)))*((Math.PI*2)*f)))
|
//Math.sin((((t+2)**Math.cos((t*4)))*((Math.PI*2)*f)))
|
||||||
w.write8(4); //sin
|
w.write8(4); //sin
|
||||||
w.write8(5)//times
|
w.write8(5); //times
|
||||||
{
|
{
|
||||||
w.write8(9); //Power
|
w.write8(9); //Power
|
||||||
|
|
||||||
{
|
{
|
||||||
w.write8(6); //adding
|
w.write8(6); //adding
|
||||||
w.write8(1); //t
|
w.write8(1); //t
|
||||||
w.write8(0);w.write32Float(2);//2
|
w.write8(0);
|
||||||
|
w.write32Float(2); //2
|
||||||
}
|
}
|
||||||
w.write8(13); //cos
|
w.write8(13); //cos
|
||||||
w.write8(5); // times
|
w.write8(5); // times
|
||||||
w.write8(1); //t
|
w.write8(1); //t
|
||||||
w.write8(0);w.write32Float(4);//4
|
w.write8(0);
|
||||||
|
w.write32Float(4); //4
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
w.write8(5)//times
|
w.write8(5); //times
|
||||||
w.write8(5)//times
|
w.write8(5); //times
|
||||||
w.write8(3); //PI
|
w.write8(3); //PI
|
||||||
w.write8(0);w.write32Float(2);//2
|
w.write8(0);
|
||||||
|
w.write32Float(2); //2
|
||||||
w.write8(2); //freq
|
w.write8(2); //freq
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,13 +48,13 @@ w.write16(4);//3 tracks
|
|||||||
|
|
||||||
w.write16(1); //zip
|
w.write16(1); //zip
|
||||||
w.write8(4);
|
w.write8(4);
|
||||||
w.write32Float(1)
|
w.write32Float(1);
|
||||||
w.write32Float(700)
|
w.write32Float(700);
|
||||||
|
|
||||||
w.write16(3); //beep
|
w.write16(3); //beep
|
||||||
{
|
{
|
||||||
w.write8(1);
|
w.write8(1);
|
||||||
w.write32Float(1)
|
w.write32Float(1);
|
||||||
w.write32Float(700);
|
w.write32Float(700);
|
||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ w.write16(3);//beep
|
|||||||
w.write32Float(100);
|
w.write32Float(100);
|
||||||
|
|
||||||
w.write8(1);
|
w.write8(1);
|
||||||
w.write32Float(1)
|
w.write32Float(1);
|
||||||
w.write32Float(700);
|
w.write32Float(700);
|
||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
}
|
}
|
||||||
@@ -67,7 +70,7 @@ w.write16(3);//beep
|
|||||||
w.write16(5); //three
|
w.write16(5); //three
|
||||||
{
|
{
|
||||||
w.write8(1);
|
w.write8(1);
|
||||||
w.write32Float(1)
|
w.write32Float(1);
|
||||||
w.write32Float(800);
|
w.write32Float(800);
|
||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
|
|
||||||
@@ -75,7 +78,7 @@ w.write16(5);//three
|
|||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
|
|
||||||
w.write8(1);
|
w.write8(1);
|
||||||
w.write32Float(1)
|
w.write32Float(1);
|
||||||
w.write32Float(1000);
|
w.write32Float(1000);
|
||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
|
|
||||||
@@ -83,7 +86,7 @@ w.write16(5);//three
|
|||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
|
|
||||||
w.write8(1);
|
w.write8(1);
|
||||||
w.write32Float(1)
|
w.write32Float(1);
|
||||||
w.write32Float(1300);
|
w.write32Float(1300);
|
||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
}
|
}
|
||||||
@@ -91,7 +94,7 @@ w.write16(5);//three
|
|||||||
w.write16(5); //square
|
w.write16(5); //square
|
||||||
{
|
{
|
||||||
w.write8(3);
|
w.write8(3);
|
||||||
w.write32Float(1)
|
w.write32Float(1);
|
||||||
w.write32Float(600);
|
w.write32Float(600);
|
||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
|
|
||||||
@@ -99,7 +102,7 @@ w.write16(5);//square
|
|||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
|
|
||||||
w.write8(3);
|
w.write8(3);
|
||||||
w.write32Float(1)
|
w.write32Float(1);
|
||||||
w.write32Float(800);
|
w.write32Float(800);
|
||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
|
|
||||||
@@ -107,7 +110,7 @@ w.write16(5);//square
|
|||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
|
|
||||||
w.write8(3);
|
w.write8(3);
|
||||||
w.write32Float(1)
|
w.write32Float(1);
|
||||||
w.write32Float(1000);
|
w.write32Float(1000);
|
||||||
w.write32Float(50);
|
w.write32Float(50);
|
||||||
}
|
}
|
||||||
@@ -147,11 +150,11 @@ if(download){
|
|||||||
download.onclick = () => {
|
download.onclick = () => {
|
||||||
const blob = new Blob([buff], {type: "binary"});
|
const blob = new Blob([buff], {type: "binary"});
|
||||||
const downloadUrl = URL.createObjectURL(blob);
|
const downloadUrl = URL.createObjectURL(blob);
|
||||||
const a = document.createElement('a');
|
const a = document.createElement("a");
|
||||||
a.href = downloadUrl;
|
a.href = downloadUrl;
|
||||||
a.download = "sounds.jasf";
|
a.download = "sounds.jasf";
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
a.click();
|
a.click();
|
||||||
URL.revokeObjectURL(downloadUrl);
|
URL.revokeObjectURL(downloadUrl);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { Track } from "./track.js";
|
|||||||
import {AVoice} from "./voice.js";
|
import {AVoice} from "./voice.js";
|
||||||
import {Audio} from "./audio.js";
|
import {Audio} from "./audio.js";
|
||||||
export class Play {
|
export class Play {
|
||||||
voices:[AVoice,string][]
|
voices: [AVoice, string][];
|
||||||
tracks:Track[]
|
tracks: Track[];
|
||||||
audios: Map<string, Audio>;
|
audios: Map<string, Audio>;
|
||||||
constructor(voices: [AVoice, string][], tracks: Track[], audios: Map<string, Audio>) {
|
constructor(voices: [AVoice, string][], tracks: Track[], audios: Map<string, Audio>) {
|
||||||
this.voices = voices;
|
this.voices = voices;
|
||||||
@@ -35,7 +35,7 @@ export class Play{
|
|||||||
const audioArr = new Map<string, Audio>();
|
const audioArr = new Map<string, Audio>();
|
||||||
for (let i = 0; i < audios; i++) {
|
for (let i = 0; i < audios; i++) {
|
||||||
const a = Audio.parse(read, trackArr);
|
const a = Audio.parse(read, trackArr);
|
||||||
audioArr.set(a.name,a)
|
audioArr.set(a.name, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Play(voiceArr, trackArr, audioArr);
|
return new Play(voiceArr, trackArr, audioArr);
|
||||||
|
|||||||
@@ -24,13 +24,12 @@ export class Track{
|
|||||||
if (!play[index]) throw new Error("voice not found");
|
if (!play[index]) throw new Error("voice not found");
|
||||||
const [voice] = play[index];
|
const [voice] = play[index];
|
||||||
let temp: AVoice;
|
let temp: AVoice;
|
||||||
if((voice.info.wave instanceof Function)){
|
if (voice.info.wave instanceof Function) {
|
||||||
temp = voice.clone(read.readFloat32(), read.readFloat32());
|
temp = voice.clone(read.readFloat32(), read.readFloat32());
|
||||||
} else {
|
} else {
|
||||||
temp = voice.clone(read.readFloat32(), read.readFloat32(), read.readFloat32());
|
temp = voice.clone(read.readFloat32(), read.readFloat32(), read.readFloat32());
|
||||||
}
|
}
|
||||||
play2.push(temp);
|
play2.push(temp);
|
||||||
|
|
||||||
}
|
}
|
||||||
return new Track(play2);
|
return new Track(play2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ class AVoice{
|
|||||||
this.playing = false;
|
this.playing = false;
|
||||||
this.myArrayBuffer = this.audioCtx.createBuffer(
|
this.myArrayBuffer = this.audioCtx.createBuffer(
|
||||||
1,
|
1,
|
||||||
this.audioCtx.sampleRate*length/1000,
|
(this.audioCtx.sampleRate * length) / 1000,
|
||||||
this.audioCtx.sampleRate
|
this.audioCtx.sampleRate,
|
||||||
);
|
);
|
||||||
this.gainNode = this.audioCtx.createGain();
|
this.gainNode = this.audioCtx.createGain();
|
||||||
this.gainNode.gain.value = volume;
|
this.gainNode.gain.value = volume;
|
||||||
@@ -104,13 +104,13 @@ class AVoice{
|
|||||||
case "three": {
|
case "three": {
|
||||||
const voicy = new AVoice("sin", 800);
|
const voicy = new AVoice("sin", 800);
|
||||||
voicy.play();
|
voicy.play();
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.freq = 1000;
|
voicy.freq = 1000;
|
||||||
}, 50);
|
}, 50);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.freq = 1300;
|
voicy.freq = 1300;
|
||||||
}, 100);
|
}, 100);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.stop();
|
voicy.stop();
|
||||||
}, 150);
|
}, 150);
|
||||||
break;
|
break;
|
||||||
@@ -120,7 +120,7 @@ class AVoice{
|
|||||||
return Math.sin((t + 2) ** Math.cos(t * 4) * Math.PI * 2 * freq);
|
return Math.sin((t + 2) ** Math.cos(t * 4) * Math.PI * 2 * freq);
|
||||||
}, 700);
|
}, 700);
|
||||||
voicy.play();
|
voicy.play();
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.stop();
|
voicy.stop();
|
||||||
}, 150);
|
}, 150);
|
||||||
break;
|
break;
|
||||||
@@ -128,13 +128,13 @@ class AVoice{
|
|||||||
case "square": {
|
case "square": {
|
||||||
const voicy = new AVoice("square", 600, 0.4);
|
const voicy = new AVoice("square", 600, 0.4);
|
||||||
voicy.play();
|
voicy.play();
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.freq = 800;
|
voicy.freq = 800;
|
||||||
}, 50);
|
}, 50);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.freq = 1000;
|
voicy.freq = 1000;
|
||||||
}, 100);
|
}, 100);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.stop();
|
voicy.stop();
|
||||||
}, 150);
|
}, 150);
|
||||||
break;
|
break;
|
||||||
@@ -142,45 +142,45 @@ class AVoice{
|
|||||||
case "beep": {
|
case "beep": {
|
||||||
const voicy = new AVoice("sin", 800);
|
const voicy = new AVoice("sin", 800);
|
||||||
voicy.play();
|
voicy.play();
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.stop();
|
voicy.stop();
|
||||||
}, 50);
|
}, 50);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.play();
|
voicy.play();
|
||||||
}, 100);
|
}, 100);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.stop();
|
voicy.stop();
|
||||||
}, 150);
|
}, 150);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "join": {
|
case "join": {
|
||||||
const voicy = new AVoice("triangle", 600,.1);
|
const voicy = new AVoice("triangle", 600, 0.1);
|
||||||
voicy.play();
|
voicy.play();
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.freq = 800;
|
voicy.freq = 800;
|
||||||
}, 75);
|
}, 75);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.freq = 1000;
|
voicy.freq = 1000;
|
||||||
}, 150);
|
}, 150);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.stop();
|
voicy.stop();
|
||||||
}, 200);
|
}, 200);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "leave": {
|
case "leave": {
|
||||||
const voicy = new AVoice("triangle", 850,.5);
|
const voicy = new AVoice("triangle", 850, 0.5);
|
||||||
voicy.play();
|
voicy.play();
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.freq = 700;
|
voicy.freq = 700;
|
||||||
}, 100);
|
}, 100);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.stop();
|
voicy.stop();
|
||||||
voicy.freq = 400;
|
voicy.freq = 400;
|
||||||
}, 180);
|
}, 180);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.play();
|
voicy.play();
|
||||||
}, 200);
|
}, 200);
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
voicy.stop();
|
voicy.stop();
|
||||||
}, 250);
|
}, 250);
|
||||||
break;
|
break;
|
||||||
@@ -193,14 +193,14 @@ class AVoice{
|
|||||||
static getVoice(read: BinRead): [AVoice, string] {
|
static getVoice(read: BinRead): [AVoice, string] {
|
||||||
const name = read.readString8();
|
const name = read.readString8();
|
||||||
let length = read.readFloat32();
|
let length = read.readFloat32();
|
||||||
let special:Function|string
|
let special: Function | string;
|
||||||
if (length !== 0) {
|
if (length !== 0) {
|
||||||
special = this.parseExpression(read);
|
special = this.parseExpression(read);
|
||||||
} else {
|
} else {
|
||||||
special = name;
|
special = name;
|
||||||
length = 1;
|
length = 1;
|
||||||
}
|
}
|
||||||
return [new AVoice(special,0,0,length),name]
|
return [new AVoice(special, 0, 0, length), name];
|
||||||
}
|
}
|
||||||
static parseExpression(read: BinRead): Function {
|
static parseExpression(read: BinRead): Function {
|
||||||
return new Function("t", "f", `return ${this.PEHelper(read)};`);
|
return new Function("t", "f", `return ${this.PEHelper(read)};`);
|
||||||
@@ -215,7 +215,7 @@ class AVoice{
|
|||||||
case 2:
|
case 2:
|
||||||
return "f";
|
return "f";
|
||||||
case 3:
|
case 3:
|
||||||
return `Math.PI`
|
return `Math.PI`;
|
||||||
case 4:
|
case 4:
|
||||||
return `Math.sin(${this.PEHelper(read)})`;
|
return `Math.sin(${this.PEHelper(read)})`;
|
||||||
case 5:
|
case 5:
|
||||||
@@ -238,7 +238,6 @@ class AVoice{
|
|||||||
return `Math.cos(${this.PEHelper(read)})`;
|
return `Math.cos(${this.PEHelper(read)})`;
|
||||||
default:
|
default:
|
||||||
throw new Error("unexpected case found!");
|
throw new Error("unexpected case found!");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,14 @@ import{ Dialog, Float, Settings }from"./settings.js";
|
|||||||
import {Role, RoleList} from "./role.js";
|
import {Role, RoleList} from "./role.js";
|
||||||
import {InfiniteScroller} from "./infiniteScroller.js";
|
import {InfiniteScroller} from "./infiniteScroller.js";
|
||||||
import {SnowFlake} from "./snowflake.js";
|
import {SnowFlake} from "./snowflake.js";
|
||||||
import{channeljson,embedjson,messageCreateJson,messagejson,readyjson,startTypingjson}from"./jsontypes.js";
|
import {
|
||||||
|
channeljson,
|
||||||
|
embedjson,
|
||||||
|
messageCreateJson,
|
||||||
|
messagejson,
|
||||||
|
readyjson,
|
||||||
|
startTypingjson,
|
||||||
|
} from "./jsontypes.js";
|
||||||
import {MarkDown} from "./markdown.js";
|
import {MarkDown} from "./markdown.js";
|
||||||
import {Member} from "./member.js";
|
import {Member} from "./member.js";
|
||||||
import {Voice} from "./voice.js";
|
import {Voice} from "./voice.js";
|
||||||
@@ -54,26 +61,42 @@ class Channel extends SnowFlake{
|
|||||||
bitrate: number = 128000;
|
bitrate: number = 128000;
|
||||||
|
|
||||||
muted: boolean = false;
|
muted: boolean = false;
|
||||||
mute_config= {selected_time_window: -1,end_time: 0}
|
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}){
|
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.message_notifications = settings.message_notifications;
|
||||||
this.muted = settings.muted;
|
this.muted = settings.muted;
|
||||||
this.mute_config = settings.mute_config;
|
this.mute_config = settings.mute_config;
|
||||||
}
|
}
|
||||||
static setupcontextmenu() {
|
static setupcontextmenu() {
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("channel.copyId"), function(this: Channel){
|
this.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("channel.copyId"),
|
||||||
|
function (this: Channel) {
|
||||||
navigator.clipboard.writeText(this.id);
|
navigator.clipboard.writeText(this.id);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("channel.markRead"), function(this: Channel){
|
this.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("channel.markRead"),
|
||||||
|
function (this: Channel) {
|
||||||
this.readbottom();
|
this.readbottom();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("channel.settings"), function(this: Channel){
|
this.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("channel.settings"),
|
||||||
|
function (this: Channel) {
|
||||||
this.generateSettings();
|
this.generateSettings();
|
||||||
},null,function(){
|
},
|
||||||
|
null,
|
||||||
|
function () {
|
||||||
return this.hasPermission("MANAGE_CHANNELS");
|
return this.hasPermission("MANAGE_CHANNELS");
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("channel.delete"),
|
() => I18n.getTranslation("channel.delete"),
|
||||||
@@ -83,14 +106,14 @@ class Channel extends SnowFlake{
|
|||||||
null,
|
null,
|
||||||
function () {
|
function () {
|
||||||
return this.isAdmin();
|
return this.isAdmin();
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("guild.notifications"),
|
() => I18n.getTranslation("guild.notifications"),
|
||||||
function () {
|
function () {
|
||||||
this.setnotifcation();
|
this.setnotifcation();
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("channel.makeInvite"),
|
() => I18n.getTranslation("channel.makeInvite"),
|
||||||
@@ -100,7 +123,7 @@ class Channel extends SnowFlake{
|
|||||||
null,
|
null,
|
||||||
function () {
|
function () {
|
||||||
return this.hasPermission("CREATE_INSTANT_INVITE") && this.type !== 4;
|
return this.hasPermission("CREATE_INSTANT_INVITE") && this.type !== 4;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
createInvite() {
|
createInvite() {
|
||||||
@@ -116,7 +139,7 @@ class Channel extends SnowFlake{
|
|||||||
const copy = document.createElement("span");
|
const copy = document.createElement("span");
|
||||||
copy.classList.add("copybutton", "svgicon", "svg-copy");
|
copy.classList.add("copybutton", "svgicon", "svg-copy");
|
||||||
copycontainer.append(copy);
|
copycontainer.append(copy);
|
||||||
copycontainer.onclick = _=>{
|
copycontainer.onclick = (_) => {
|
||||||
if (text.textContent) {
|
if (text.textContent) {
|
||||||
navigator.clipboard.writeText(text.textContent);
|
navigator.clipboard.writeText(text.textContent);
|
||||||
}
|
}
|
||||||
@@ -135,8 +158,8 @@ class Channel extends SnowFlake{
|
|||||||
temporary: uses !== 0,
|
temporary: uses !== 0,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.then(_=>_.json())
|
.then((_) => _.json())
|
||||||
.then(json=>{
|
.then((json) => {
|
||||||
const params = new URLSearchParams("");
|
const params = new URLSearchParams("");
|
||||||
params.set("instance", this.info.wellknown);
|
params.set("instance", this.info.wellknown);
|
||||||
const encoded = params.toString();
|
const encoded = params.toString();
|
||||||
@@ -146,16 +169,33 @@ class Channel extends SnowFlake{
|
|||||||
update();
|
update();
|
||||||
const inviteOptions = new Dialog("", {noSubmit: true});
|
const inviteOptions = new Dialog("", {noSubmit: true});
|
||||||
inviteOptions.options.addTitle(I18n.getTranslation("inviteOptions.title"));
|
inviteOptions.options.addTitle(I18n.getTranslation("inviteOptions.title"));
|
||||||
inviteOptions.options.addText(I18n.getTranslation("invite.subtext",this.name,this.guild.properties.name));
|
inviteOptions.options.addText(
|
||||||
|
I18n.getTranslation("invite.subtext", this.name, this.guild.properties.name),
|
||||||
|
);
|
||||||
|
|
||||||
inviteOptions.options.addSelect(I18n.getTranslation("invite.expireAfter"),()=>{},
|
inviteOptions.options.addSelect(
|
||||||
["30m","1h","6h","12h","1d","7d","30d","never"].map((e)=>I18n.getTranslation("inviteOptions."+e))
|
I18n.getTranslation("invite.expireAfter"),
|
||||||
).onchange=(e)=>{expires=[1800, 3600, 21600, 43200, 86400, 604800, 2592000, 0][e];update()};
|
() => {},
|
||||||
|
["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))
|
const timeOptions = ["1", "5", "10", "25", "50", "100"].map((e) =>
|
||||||
timeOptions.unshift(I18n.getTranslation("inviteOptions.noLimit"))
|
I18n.getTranslation("inviteOptions.limit", e),
|
||||||
inviteOptions.options.addSelect(I18n.getTranslation("invite.expireAfter"),()=>{},timeOptions)
|
);
|
||||||
.onchange=(e)=>{uses=[0, 1, 5, 10, 25, 50, 100][e];update()};
|
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.options.addHTMLArea(div);
|
||||||
inviteOptions.show();
|
inviteOptions.show();
|
||||||
@@ -170,19 +210,32 @@ class Channel extends SnowFlake{
|
|||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
});
|
});
|
||||||
form.addTextInput(I18n.getTranslation("channel.name:"),"name",{initText:this.name});
|
form.addTextInput(I18n.getTranslation("channel.name:"), "name", {
|
||||||
form.addMDInput(I18n.getTranslation("channel.topic:"),"topic",{initText:this.topic});
|
initText: this.name,
|
||||||
form.addCheckboxInput(I18n.getTranslation("channel.nsfw:"),"nsfw",{initState:this.nsfw});
|
});
|
||||||
|
form.addMDInput(I18n.getTranslation("channel.topic:"), "topic", {
|
||||||
|
initText: this.topic,
|
||||||
|
});
|
||||||
|
form.addCheckboxInput(I18n.getTranslation("channel.nsfw:"), "nsfw", {
|
||||||
|
initState: this.nsfw,
|
||||||
|
});
|
||||||
if (this.type !== 4) {
|
if (this.type !== 4) {
|
||||||
const options = ["voice", "text", "announcement"];
|
const options = ["voice", "text", "announcement"];
|
||||||
form.addSelect("Type:","type",options.map(e=>I18n.getTranslation("channel."+e)),{
|
form.addSelect(
|
||||||
defaultIndex:options.indexOf({0:"text", 2:"voice", 5:"announcement", 4:"category" }[this.type] as string)
|
"Type:",
|
||||||
},options);
|
"type",
|
||||||
|
options.map((e) => I18n.getTranslation("channel." + e)),
|
||||||
|
{
|
||||||
|
defaultIndex: options.indexOf(
|
||||||
|
{0: "text", 2: "voice", 5: "announcement", 4: "category"}[this.type] as string,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
options,
|
||||||
|
);
|
||||||
form.addPreprocessor((obj: any) => {
|
form.addPreprocessor((obj: any) => {
|
||||||
obj.type={text: 0, voice: 2, announcement: 5, category: 4 }[obj.type as string]
|
obj.type = {text: 0, voice: 2, announcement: 5, category: 4}[obj.type as string];
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
const s1 = settings.addButton("Permissions");
|
const s1 = settings.addButton("Permissions");
|
||||||
s1.options.push(
|
s1.options.push(
|
||||||
@@ -190,17 +243,14 @@ class Channel extends SnowFlake{
|
|||||||
this.permission_overwritesar,
|
this.permission_overwritesar,
|
||||||
this.guild,
|
this.guild,
|
||||||
this.updateRolePermissions.bind(this),
|
this.updateRolePermissions.bind(this),
|
||||||
this
|
this,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
settings.show();
|
settings.show();
|
||||||
}
|
}
|
||||||
sortPerms() {
|
sortPerms() {
|
||||||
this.permission_overwritesar.sort((a, b) => {
|
this.permission_overwritesar.sort((a, b) => {
|
||||||
return(
|
return this.guild.roles.indexOf(a[0]) - this.guild.roles.indexOf(b[0]);
|
||||||
this.guild.roles.indexOf(a[0]) -
|
|
||||||
this.guild.roles.indexOf(b[0])
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setUpInfiniteScroller() {
|
setUpInfiniteScroller() {
|
||||||
@@ -220,7 +270,6 @@ class Channel extends SnowFlake{
|
|||||||
await this.grabAfter(id);
|
await this.grabAfter(id);
|
||||||
return this.idToNext.get(id);
|
return this.idToNext.get(id);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -252,14 +301,10 @@ class Channel extends SnowFlake{
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
this.readbottom.bind(this)
|
this.readbottom.bind(this),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
constructor(
|
constructor(json: channeljson | -1, owner: Guild, id: string = json === -1 ? "" : json.id) {
|
||||||
json: channeljson | -1,
|
|
||||||
owner: Guild,
|
|
||||||
id: string = json === -1 ? "" : json.id
|
|
||||||
){
|
|
||||||
super(id);
|
super(id);
|
||||||
if (json === -1) {
|
if (json === -1) {
|
||||||
return;
|
return;
|
||||||
@@ -283,10 +328,7 @@ class Channel extends SnowFlake{
|
|||||||
}
|
}
|
||||||
if (!this.permission_overwrites.has(thing.id)) {
|
if (!this.permission_overwrites.has(thing.id)) {
|
||||||
//either a bug in the server requires this, or the API is cursed
|
//either a bug in the server requires this, or the API is cursed
|
||||||
this.permission_overwrites.set(
|
this.permission_overwrites.set(thing.id, new Permissions(thing.allow, thing.deny));
|
||||||
thing.id,
|
|
||||||
new Permissions(thing.allow, thing.deny)
|
|
||||||
);
|
|
||||||
const permission = this.permission_overwrites.get(thing.id);
|
const permission = this.permission_overwrites.get(thing.id);
|
||||||
if (permission) {
|
if (permission) {
|
||||||
const role = this.guild.roleids.get(thing.id);
|
const role = this.guild.roleids.get(thing.id);
|
||||||
@@ -309,7 +351,9 @@ class Channel extends SnowFlake{
|
|||||||
this.setUpInfiniteScroller();
|
this.setUpInfiniteScroller();
|
||||||
this.perminfo ??= {};
|
this.perminfo ??= {};
|
||||||
if (this.type === 2 && this.localuser.voiceFactory) {
|
if (this.type === 2 && this.localuser.voiceFactory) {
|
||||||
this.voice=this.localuser.voiceFactory.makeVoice(this.guild.id,this.id,{bitrate:this.bitrate});
|
this.voice = this.localuser.voiceFactory.makeVoice(this.guild.id, this.id, {
|
||||||
|
bitrate: this.bitrate,
|
||||||
|
});
|
||||||
this.setUpVoice();
|
this.setUpVoice();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,7 +400,7 @@ class Channel extends SnowFlake{
|
|||||||
const roles = new Set(member.roles);
|
const roles = new Set(member.roles);
|
||||||
const everyone = this.guild.roles[this.guild.roles.length - 1];
|
const everyone = this.guild.roles[this.guild.roles.length - 1];
|
||||||
if (!member.user.bot || true) {
|
if (!member.user.bot || true) {
|
||||||
roles.add(everyone)
|
roles.add(everyone);
|
||||||
}
|
}
|
||||||
for (const thing of roles) {
|
for (const thing of roles) {
|
||||||
const premission = this.permission_overwrites.get(thing.id);
|
const premission = this.permission_overwrites.get(thing.id);
|
||||||
@@ -374,7 +418,7 @@ class Channel extends SnowFlake{
|
|||||||
}
|
}
|
||||||
get canMessage(): boolean {
|
get canMessage(): boolean {
|
||||||
if (this.permission_overwritesar.length === 0 && this.hasPermission("MANAGE_CHANNELS")) {
|
if (this.permission_overwritesar.length === 0 && this.hasPermission("MANAGE_CHANNELS")) {
|
||||||
const role = this.guild.roles.find(_=>_.name === "@everyone");
|
const role = this.guild.roles.find((_) => _.name === "@everyone");
|
||||||
if (role) {
|
if (role) {
|
||||||
this.addRoleToPerms(role);
|
this.addRoleToPerms(role);
|
||||||
}
|
}
|
||||||
@@ -449,7 +493,7 @@ class Channel extends SnowFlake{
|
|||||||
// @ts-ignore I dont wanna deal with this
|
// @ts-ignore I dont wanna deal with this
|
||||||
div.all = this;
|
div.all = this;
|
||||||
div.draggable = admin;
|
div.draggable = admin;
|
||||||
div.addEventListener("dragstart", e=>{
|
div.addEventListener("dragstart", (e) => {
|
||||||
Channel.dragged = [this, div];
|
Channel.dragged = [this, div];
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
});
|
});
|
||||||
@@ -475,7 +519,7 @@ class Channel extends SnowFlake{
|
|||||||
const addchannel = document.createElement("span");
|
const addchannel = document.createElement("span");
|
||||||
addchannel.classList.add("addchannel", "svgicon", "svg-plus");
|
addchannel.classList.add("addchannel", "svgicon", "svg-plus");
|
||||||
caps.appendChild(addchannel);
|
caps.appendChild(addchannel);
|
||||||
addchannel.onclick = _=>{
|
addchannel.onclick = (_) => {
|
||||||
this.guild.createchannels(this.createChannel.bind(this));
|
this.guild.createchannels(this.createChannel.bind(this));
|
||||||
};
|
};
|
||||||
this.coatDropDiv(decdiv, childrendiv);
|
this.coatDropDiv(decdiv, childrendiv);
|
||||||
@@ -544,12 +588,16 @@ class Channel extends SnowFlake{
|
|||||||
//
|
//
|
||||||
const decoration = document.createElement("span");
|
const decoration = document.createElement("span");
|
||||||
button.appendChild(decoration);
|
button.appendChild(decoration);
|
||||||
decoration.classList.add("space", "svgicon", this.nsfw?"svg-announcensfw":"svg-announce");
|
decoration.classList.add(
|
||||||
|
"space",
|
||||||
|
"svgicon",
|
||||||
|
this.nsfw ? "svg-announcensfw" : "svg-announce",
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log(this.type);
|
console.log(this.type);
|
||||||
}
|
}
|
||||||
button.appendChild(myhtml);
|
button.appendChild(myhtml);
|
||||||
button.onclick = _=>{
|
button.onclick = (_) => {
|
||||||
this.getHTML();
|
this.getHTML();
|
||||||
const toggle = document.getElementById("maintoggle") as HTMLInputElement;
|
const toggle = document.getElementById("maintoggle") as HTMLInputElement;
|
||||||
toggle.checked = true;
|
toggle.checked = true;
|
||||||
@@ -572,7 +620,7 @@ class Channel extends SnowFlake{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mainarea.style.left = x + "px";
|
mainarea.style.left = x + "px";
|
||||||
mainarea.style.transition="left 0s"
|
mainarea.style.transition = "left 0s";
|
||||||
}
|
}
|
||||||
async setUpVoice() {
|
async setUpVoice() {
|
||||||
if (!this.voice) return;
|
if (!this.voice) return;
|
||||||
@@ -585,20 +633,27 @@ class Channel extends SnowFlake{
|
|||||||
if (this.voice === this.localuser.currentVoice) {
|
if (this.voice === this.localuser.currentVoice) {
|
||||||
AVoice.noises("join");
|
AVoice.noises("join");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
async updateVoiceUsers() {
|
async updateVoiceUsers() {
|
||||||
const voiceUsers = this.voiceUsers.deref();
|
const voiceUsers = this.voiceUsers.deref();
|
||||||
if (!voiceUsers || !this.voice) return;
|
if (!voiceUsers || !this.voice) return;
|
||||||
console.warn(this.voice.userids)
|
console.warn(this.voice.userids);
|
||||||
|
|
||||||
const html=(await Promise.all(this.voice.userids.entries().toArray().map(async _=>{
|
const html = (
|
||||||
|
await Promise.all(
|
||||||
|
this.voice.userids
|
||||||
|
.entries()
|
||||||
|
.toArray()
|
||||||
|
.map(async (_) => {
|
||||||
const user = await User.resolve(_[0], this.localuser);
|
const user = await User.resolve(_[0], this.localuser);
|
||||||
console.log(user);
|
console.log(user);
|
||||||
const member = await Member.resolveMember(user, this.guild);
|
const member = await Member.resolveMember(user, this.guild);
|
||||||
const array=[member,_[1]] as [Member, typeof _[1]];
|
const array = [member, _[1]] as [Member, (typeof _)[1]];
|
||||||
return array;
|
return array;
|
||||||
}))).flatMap(([member,_obj])=>{
|
}),
|
||||||
|
)
|
||||||
|
).flatMap(([member, _obj]) => {
|
||||||
if (!member) {
|
if (!member) {
|
||||||
console.warn("This is weird, member doesn't exist :P");
|
console.warn("This is weird, member doesn't exist :P");
|
||||||
return [];
|
return [];
|
||||||
@@ -627,30 +682,27 @@ class Channel extends SnowFlake{
|
|||||||
this.guild.unreads();
|
this.guild.unreads();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fetch(
|
fetch(this.info.api + "/channels/" + this.id + "/messages/" + this.lastmessageid + "/ack", {
|
||||||
this.info.api +"/channels/" + this.id + "/messages/" + this.lastmessageid + "/ack",
|
|
||||||
{
|
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
body: JSON.stringify({}),
|
body: JSON.stringify({}),
|
||||||
}
|
});
|
||||||
);
|
|
||||||
this.lastreadmessageid = this.lastmessageid;
|
this.lastreadmessageid = this.lastmessageid;
|
||||||
this.guild.unreads();
|
this.guild.unreads();
|
||||||
this.unreads();
|
this.unreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
coatDropDiv(div: HTMLDivElement, container: HTMLElement | boolean = false) {
|
coatDropDiv(div: HTMLDivElement, container: HTMLElement | boolean = false) {
|
||||||
div.addEventListener("dragenter", event=>{
|
div.addEventListener("dragenter", (event) => {
|
||||||
console.log("enter");
|
console.log("enter");
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
div.addEventListener("dragover", event=>{
|
div.addEventListener("dragover", (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
div.addEventListener("drop", event=>{
|
div.addEventListener("drop", (event) => {
|
||||||
const that = Channel.dragged[0];
|
const that = Channel.dragged[0];
|
||||||
if (!that) return;
|
if (!that) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -660,9 +712,7 @@ class Channel extends SnowFlake{
|
|||||||
that.parent.children.splice(that.parent.children.indexOf(that), 1);
|
that.parent.children.splice(that.parent.children.indexOf(that), 1);
|
||||||
}
|
}
|
||||||
that.parent = this;
|
that.parent = this;
|
||||||
(container as HTMLElement).prepend(
|
(container as HTMLElement).prepend(Channel.dragged[1] as HTMLDivElement);
|
||||||
Channel.dragged[1] as HTMLDivElement
|
|
||||||
);
|
|
||||||
this.children.unshift(that);
|
this.children.unshift(that);
|
||||||
} else {
|
} else {
|
||||||
console.log(this, Channel.dragged);
|
console.log(this, Channel.dragged);
|
||||||
@@ -670,10 +720,7 @@ class Channel extends SnowFlake{
|
|||||||
if (that.parent) {
|
if (that.parent) {
|
||||||
that.parent.children.splice(that.parent.children.indexOf(that), 1);
|
that.parent.children.splice(that.parent.children.indexOf(that), 1);
|
||||||
} else {
|
} else {
|
||||||
this.guild.headchannels.splice(
|
this.guild.headchannels.splice(this.guild.headchannels.indexOf(that), 1);
|
||||||
this.guild.headchannels.indexOf(that),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
that.parent = this.parent;
|
that.parent = this.parent;
|
||||||
if (that.parent) {
|
if (that.parent) {
|
||||||
@@ -742,7 +789,7 @@ class Channel extends SnowFlake{
|
|||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = I18n.getTranslation("replyingTo", this.replyingto.author.username);
|
span.textContent = I18n.getTranslation("replyingTo", this.replyingto.author.username);
|
||||||
const X = document.createElement("button");
|
const X = document.createElement("button");
|
||||||
X.onclick = _=>{
|
X.onclick = (_) => {
|
||||||
if (this.replyingto?.div) {
|
if (this.replyingto?.div) {
|
||||||
this.replyingto.div.classList.remove("replying");
|
this.replyingto.div.classList.remove("replying");
|
||||||
}
|
}
|
||||||
@@ -768,7 +815,7 @@ class Channel extends SnowFlake{
|
|||||||
} else {
|
} else {
|
||||||
const gety = await fetch(
|
const gety = await fetch(
|
||||||
this.info.api + "/channels/" + this.id + "/messages?limit=1&around=" + id,
|
this.info.api + "/channels/" + this.id + "/messages?limit=1&around=" + id,
|
||||||
{ headers: this.headers }
|
{headers: this.headers},
|
||||||
);
|
);
|
||||||
const json = await gety.json();
|
const json = await gety.json();
|
||||||
if (json.length === 0) {
|
if (json.length === 0) {
|
||||||
@@ -778,10 +825,10 @@ class Channel extends SnowFlake{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async focus(id: string) {
|
async focus(id: string) {
|
||||||
console.time()
|
console.time();
|
||||||
console.log(await this.getmessage(id));
|
console.log(await this.getmessage(id));
|
||||||
await this.getHTML();
|
await this.getHTML();
|
||||||
console.timeEnd()
|
console.timeEnd();
|
||||||
console.warn(id);
|
console.warn(id);
|
||||||
this.infinite.focus(id);
|
this.infinite.focus(id);
|
||||||
}
|
}
|
||||||
@@ -800,9 +847,7 @@ class Channel extends SnowFlake{
|
|||||||
(document.getElementById("upload") as HTMLElement).style.visibility = "hidden";
|
(document.getElementById("upload") as HTMLElement).style.visibility = "hidden";
|
||||||
(document.getElementById("typediv") as HTMLElement).style.visibility = "hidden";
|
(document.getElementById("typediv") as HTMLElement).style.visibility = "hidden";
|
||||||
const messages = document.getElementById("channelw") as HTMLDivElement;
|
const messages = document.getElementById("channelw") as HTMLDivElement;
|
||||||
const messageContainers = Array.from(
|
const messageContainers = Array.from(messages.getElementsByClassName("messagecontainer"));
|
||||||
messages.getElementsByClassName("messagecontainer")
|
|
||||||
);
|
|
||||||
for (const thing of messageContainers) {
|
for (const thing of messageContainers) {
|
||||||
thing.remove();
|
thing.remove();
|
||||||
}
|
}
|
||||||
@@ -828,17 +873,15 @@ class Channel extends SnowFlake{
|
|||||||
});
|
});
|
||||||
buttons.addButtonInput("", "No", () => {
|
buttons.addButtonInput("", "No", () => {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
options.addTitle("You are not allowed in this channel.");
|
options.addTitle("You are not allowed in this channel.");
|
||||||
}
|
}
|
||||||
const html = float.generateHTML();
|
const html = float.generateHTML();
|
||||||
html.classList.add("messagecontainer")
|
html.classList.add("messagecontainer");
|
||||||
messages.append(html);
|
messages.append(html);
|
||||||
|
|
||||||
}
|
}
|
||||||
async getHTML(addstate = true) {
|
async getHTML(addstate = true) {
|
||||||
|
|
||||||
if (addstate) {
|
if (addstate) {
|
||||||
history.pushState([this.guild_id, this.id], "", "/channels/" + this.guild_id + "/" + this.id);
|
history.pushState([this.guild_id, this.id], "", "/channels/" + this.guild_id + "/" + this.id);
|
||||||
}
|
}
|
||||||
@@ -846,10 +889,7 @@ class Channel extends SnowFlake{
|
|||||||
const channelTopic = document.getElementById("channelTopic") as HTMLSpanElement;
|
const channelTopic = document.getElementById("channelTopic") as HTMLSpanElement;
|
||||||
if (this.topic) {
|
if (this.topic) {
|
||||||
channelTopic.innerHTML = "";
|
channelTopic.innerHTML = "";
|
||||||
channelTopic.append(new MarkDown(
|
channelTopic.append(new MarkDown(this.topic, this).makeHTML());
|
||||||
this.topic,
|
|
||||||
this
|
|
||||||
).makeHTML());
|
|
||||||
channelTopic.removeAttribute("hidden");
|
channelTopic.removeAttribute("hidden");
|
||||||
} else channelTopic.setAttribute("hidden", "");
|
} else channelTopic.setAttribute("hidden", "");
|
||||||
if (this.guild !== this.localuser.lookingguild) {
|
if (this.guild !== this.localuser.lookingguild) {
|
||||||
@@ -869,8 +909,11 @@ class Channel extends SnowFlake{
|
|||||||
this.guild.perminfo.prevchannel = this.id;
|
this.guild.perminfo.prevchannel = this.id;
|
||||||
this.localuser.userinfo.updateLocal();
|
this.localuser.userinfo.updateLocal();
|
||||||
this.localuser.channelfocus = this;
|
this.localuser.channelfocus = this;
|
||||||
//@ts-ignore another hack
|
|
||||||
if(this.nsfw&&(!this.perminfo.nsfwOk||!this.localuser.user.nsfw_allowed)){
|
if (
|
||||||
|
this.nsfw && //@ts-ignore another hack
|
||||||
|
(!this.perminfo.nsfwOk || !this.localuser.user.nsfw_allowed)
|
||||||
|
) {
|
||||||
this.nsfwPannel();
|
this.nsfwPannel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -886,7 +929,9 @@ class Channel extends SnowFlake{
|
|||||||
this.localuser.joinVoice(this);
|
this.localuser.joinVoice(this);
|
||||||
}
|
}
|
||||||
(document.getElementById("typebox") as HTMLDivElement).contentEditable = "" + this.canMessage;
|
(document.getElementById("typebox") as HTMLDivElement).contentEditable = "" + this.canMessage;
|
||||||
(document.getElementById("upload") as HTMLElement).style.visibility=this.canMessage?"visible":"hidden";
|
(document.getElementById("upload") as HTMLElement).style.visibility = this.canMessage
|
||||||
|
? "visible"
|
||||||
|
: "hidden";
|
||||||
(document.getElementById("typediv") as HTMLElement).style.visibility = "visible";
|
(document.getElementById("typediv") as HTMLElement).style.visibility = "visible";
|
||||||
(document.getElementById("typebox") as HTMLDivElement).focus();
|
(document.getElementById("typebox") as HTMLDivElement).focus();
|
||||||
await this.putmessages();
|
await this.putmessages();
|
||||||
@@ -898,7 +943,6 @@ class Channel extends SnowFlake{
|
|||||||
|
|
||||||
await this.buildmessages();
|
await this.buildmessages();
|
||||||
//loading.classList.remove("loading");
|
//loading.classList.remove("loading");
|
||||||
|
|
||||||
}
|
}
|
||||||
typingmap: Map<Member, number> = new Map();
|
typingmap: Map<Member, number> = new Map();
|
||||||
async typingStart(typing: startTypingjson): Promise<void> {
|
async typingStart(typing: startTypingjson): Promise<void> {
|
||||||
@@ -915,7 +959,7 @@ class Channel extends SnowFlake{
|
|||||||
}
|
}
|
||||||
similar(str: string) {
|
similar(str: string) {
|
||||||
if (this.type === 4) return -1;
|
if (this.type === 4) return -1;
|
||||||
const strl=Math.max(str.length,1)
|
const strl = Math.max(str.length, 1);
|
||||||
if (this.name.includes(str)) {
|
if (this.name.includes(str)) {
|
||||||
return strl / this.name.length;
|
return strl / this.name.length;
|
||||||
} else if (this.name.toLowerCase().includes(str.toLowerCase())) {
|
} else if (this.name.toLowerCase().includes(str.toLowerCase())) {
|
||||||
@@ -949,9 +993,7 @@ class Channel extends SnowFlake{
|
|||||||
if (this.localuser.channelfocus === this) {
|
if (this.localuser.channelfocus === this) {
|
||||||
if (showing) {
|
if (showing) {
|
||||||
typingtext.classList.remove("hidden");
|
typingtext.classList.remove("hidden");
|
||||||
const typingtext2 = document.getElementById(
|
const typingtext2 = document.getElementById("typingtext") as HTMLDivElement;
|
||||||
"typingtext"
|
|
||||||
) as HTMLDivElement;
|
|
||||||
typingtext2.textContent = build;
|
typingtext2.textContent = build;
|
||||||
} else {
|
} else {
|
||||||
typingtext.classList.add("hidden");
|
typingtext.classList.add("hidden");
|
||||||
@@ -982,22 +1024,36 @@ class Channel extends SnowFlake{
|
|||||||
}
|
}
|
||||||
lastmessage: Message | undefined;
|
lastmessage: Message | undefined;
|
||||||
setnotifcation() {
|
setnotifcation() {
|
||||||
const defualt=I18n.getTranslation("guild."+["all", "onlyMentions", "none","default"][this.guild.message_notifications])
|
const defualt = I18n.getTranslation(
|
||||||
const options=["all", "onlyMentions", "none","default"].map(e=>I18n.getTranslation("guild."+e,defualt));
|
"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("");
|
const notiselect = new Dialog("");
|
||||||
const form=notiselect.options.addForm("",(_,sent:any)=>{
|
const form = notiselect.options.addForm(
|
||||||
|
"",
|
||||||
|
(_, sent: any) => {
|
||||||
notiselect.hide();
|
notiselect.hide();
|
||||||
console.log(sent);
|
console.log(sent);
|
||||||
this.message_notifications = sent.channel_overrides[this.id].message_notifications;
|
this.message_notifications = sent.channel_overrides[this.id].message_notifications;
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
fetchURL: `${this.info.api}/users/@me/guilds/${this.guild.id}/settings/`,
|
fetchURL: `${this.info.api}/users/@me/guilds/${this.guild.id}/settings/`,
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers:this.headers
|
headers: this.headers,
|
||||||
});
|
},
|
||||||
form.addSelect(I18n.getTranslation("guild.selectnoti"),"message_notifications",options,{
|
);
|
||||||
|
form.addSelect(
|
||||||
|
I18n.getTranslation("guild.selectnoti"),
|
||||||
|
"message_notifications",
|
||||||
|
options,
|
||||||
|
{
|
||||||
radio: true,
|
radio: true,
|
||||||
defaultIndex:this.message_notifications
|
defaultIndex: this.message_notifications,
|
||||||
},[0,1,2,3]);
|
},
|
||||||
|
[0, 1, 2, 3],
|
||||||
|
);
|
||||||
|
|
||||||
form.addPreprocessor((e: any) => {
|
form.addPreprocessor((e: any) => {
|
||||||
const message_notifications = e.message_notifications;
|
const message_notifications = e.message_notifications;
|
||||||
@@ -1007,10 +1063,10 @@ class Channel extends SnowFlake{
|
|||||||
message_notifications,
|
message_notifications,
|
||||||
muted: this.muted,
|
muted: this.muted,
|
||||||
mute_config: this.mute_config,
|
mute_config: this.mute_config,
|
||||||
channel_id:this.id
|
channel_id: this.id,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
/*
|
/*
|
||||||
let noti = this.message_notifications;
|
let noti = this.message_notifications;
|
||||||
const defualt=I18n.getTranslation("guild."+["all", "onlyMentions", "none","default"][this.guild.message_notifications])
|
const defualt=I18n.getTranslation("guild."+["all", "onlyMentions", "none","default"][this.guild.message_notifications])
|
||||||
@@ -1064,12 +1120,9 @@ class Channel extends SnowFlake{
|
|||||||
if (this.lastreadmessageid && this.messages.has(this.lastreadmessageid)) {
|
if (this.lastreadmessageid && this.messages.has(this.lastreadmessageid)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const j = await fetch(
|
const j = await fetch(this.info.api + "/channels/" + this.id + "/messages?limit=100", {
|
||||||
this.info.api + "/channels/" + this.id + "/messages?limit=100",
|
|
||||||
{
|
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const response = await j.json();
|
const response = await j.json();
|
||||||
if (response.length !== 100) {
|
if (response.length !== 100) {
|
||||||
@@ -1101,15 +1154,13 @@ class Channel extends SnowFlake{
|
|||||||
if (id === this.lastmessage?.id) {
|
if (id === this.lastmessage?.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await fetch(
|
await fetch(this.info.api + "/channels/" + this.id + "/messages?limit=100&after=" + id, {
|
||||||
this.info.api + "/channels/" +this.id +"/messages?limit=100&after=" +id,{
|
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
}
|
})
|
||||||
)
|
.then((j) => {
|
||||||
.then(j=>{
|
|
||||||
return j.json();
|
return j.json();
|
||||||
})
|
})
|
||||||
.then(response=>{
|
.then((response) => {
|
||||||
let previd: string = id;
|
let previd: string = id;
|
||||||
for (const i in response) {
|
for (const i in response) {
|
||||||
let messager: Message;
|
let messager: Message;
|
||||||
@@ -1136,13 +1187,10 @@ class Channel extends SnowFlake{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await fetch(
|
await fetch(this.info.api + "/channels/" + this.id + "/messages?before=" + id + "&limit=100", {
|
||||||
this.info.api + "/channels/" + this.id +"/messages?before=" + id + "&limit=100",
|
|
||||||
{
|
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
}
|
})
|
||||||
)
|
.then((j) => {
|
||||||
.then(j=>{
|
|
||||||
return j.json();
|
return j.json();
|
||||||
})
|
})
|
||||||
.then((response: messagejson[]) => {
|
.then((response: messagejson[]) => {
|
||||||
@@ -1195,9 +1243,7 @@ class Channel extends SnowFlake{
|
|||||||
if (this.infinitefocus) return;
|
if (this.infinitefocus) return;
|
||||||
this.infinitefocus = true;
|
this.infinitefocus = true;
|
||||||
const messages = document.getElementById("channelw") as HTMLDivElement;
|
const messages = document.getElementById("channelw") as HTMLDivElement;
|
||||||
const messageContainers = Array.from(
|
const messageContainers = Array.from(messages.getElementsByClassName("messagecontainer"));
|
||||||
messages.getElementsByClassName("messagecontainer")
|
|
||||||
);
|
|
||||||
for (const thing of messageContainers) {
|
for (const thing of messageContainers) {
|
||||||
thing.remove();
|
thing.remove();
|
||||||
}
|
}
|
||||||
@@ -1208,7 +1254,6 @@ class Channel extends SnowFlake{
|
|||||||
if (this.lastreadmessageid && this.messages.has(this.lastreadmessageid)) {
|
if (this.lastreadmessageid && this.messages.has(this.lastreadmessageid)) {
|
||||||
id = this.lastreadmessageid;
|
id = this.lastreadmessageid;
|
||||||
} else if (this.lastreadmessageid && (id = this.findClosest(this.lastreadmessageid))) {
|
} else if (this.lastreadmessageid && (id = this.findClosest(this.lastreadmessageid))) {
|
||||||
|
|
||||||
} else if (this.lastmessageid && this.messages.has(this.lastmessageid)) {
|
} else if (this.lastmessageid && this.messages.has(this.lastmessageid)) {
|
||||||
id = this.goBackIds(this.lastmessageid, 50);
|
id = this.goBackIds(this.lastmessageid, 50);
|
||||||
}
|
}
|
||||||
@@ -1236,18 +1281,14 @@ class Channel extends SnowFlake{
|
|||||||
}
|
}
|
||||||
messages.append(await this.infinite.getDiv(id));
|
messages.append(await this.infinite.getDiv(id));
|
||||||
this.infinite.updatestuff();
|
this.infinite.updatestuff();
|
||||||
this.infinite.watchForChange().then(async _=>{
|
this.infinite.watchForChange().then(async (_) => {
|
||||||
//await new Promise(resolve => setTimeout(resolve, 0));
|
//await new Promise(resolve => setTimeout(resolve, 0));
|
||||||
this.infinite.focus(id, false); //if someone could figure out how to make this work correctly without this, that's be great :P
|
this.infinite.focus(id, false); //if someone could figure out how to make this work correctly without this, that's be great :P
|
||||||
loading.classList.remove("loading");
|
loading.classList.remove("loading");
|
||||||
});
|
});
|
||||||
//this.infinite.focus(id.id,false);
|
//this.infinite.focus(id.id,false);
|
||||||
}
|
}
|
||||||
private goBackIds(
|
private goBackIds(id: string, back: number, returnifnotexistant = true): string | undefined {
|
||||||
id: string,
|
|
||||||
back: number,
|
|
||||||
returnifnotexistant = true
|
|
||||||
): string | undefined{
|
|
||||||
while (back !== 0) {
|
while (back !== 0) {
|
||||||
const nextid = this.idToPrev.get(id);
|
const nextid = this.idToPrev.get(id);
|
||||||
if (nextid) {
|
if (nextid) {
|
||||||
@@ -1299,10 +1340,7 @@ class Channel extends SnowFlake{
|
|||||||
if (thing.id === "1182819038095799904" || thing.id === "1182820803700625444") {
|
if (thing.id === "1182819038095799904" || thing.id === "1182820803700625444") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
this.permission_overwrites.set(
|
this.permission_overwrites.set(thing.id, new Permissions(thing.allow, thing.deny));
|
||||||
thing.id,
|
|
||||||
new Permissions(thing.allow, thing.deny)
|
|
||||||
);
|
|
||||||
const permisions = this.permission_overwrites.get(thing.id);
|
const permisions = this.permission_overwrites.get(thing.id);
|
||||||
if (permisions) {
|
if (permisions) {
|
||||||
const role = this.guild.roleids.get(thing.id);
|
const role = this.guild.roleids.get(thing.id);
|
||||||
@@ -1316,7 +1354,7 @@ class Channel extends SnowFlake{
|
|||||||
for (const thing of nchange) {
|
for (const thing of nchange) {
|
||||||
const role = this.guild.roleids.get(thing);
|
const role = this.guild.roleids.get(thing);
|
||||||
if (role) {
|
if (role) {
|
||||||
this.croleUpdate(role,new Permissions("0"),false)
|
this.croleUpdate(role, new Permissions("0"), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const thing of pchange) {
|
for (const thing of pchange) {
|
||||||
@@ -1365,7 +1403,7 @@ class Channel extends SnowFlake{
|
|||||||
{
|
{
|
||||||
attachments = [],
|
attachments = [],
|
||||||
replyingto = null,
|
replyingto = null,
|
||||||
}: { attachments: Blob[]; embeds: embedjson; replyingto: Message | null }
|
}: {attachments: Blob[]; embeds: embedjson; replyingto: Message | null},
|
||||||
) {
|
) {
|
||||||
let replyjson: any;
|
let replyjson: any;
|
||||||
if (replyingto) {
|
if (replyingto) {
|
||||||
@@ -1420,7 +1458,7 @@ class Channel extends SnowFlake{
|
|||||||
this.myhtml.classList.add("cunread");
|
this.myhtml.classList.add("cunread");
|
||||||
}
|
}
|
||||||
if (this.mentions !== 0) {
|
if (this.mentions !== 0) {
|
||||||
this.myhtml?.classList.add("mentioned")
|
this.myhtml?.classList.add("mentioned");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1453,23 +1491,17 @@ class Channel extends SnowFlake{
|
|||||||
if (messagez.author === this.localuser.user) {
|
if (messagez.author === this.localuser.user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(
|
if (this.localuser.lookingguild?.prevchannel === this && document.hasFocus()) {
|
||||||
this.localuser.lookingguild?.prevchannel === this && document.hasFocus()
|
|
||||||
){
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.notification === "all") {
|
if (this.notification === "all") {
|
||||||
this.notify(messagez);
|
this.notify(messagez);
|
||||||
}else if(
|
} else if (this.notification === "mentions" && messagez.mentionsuser(this.localuser.user)) {
|
||||||
this.notification === "mentions" && messagez.mentionsuser(this.localuser.user)
|
|
||||||
){
|
|
||||||
this.notify(messagez);
|
this.notify(messagez);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notititle(message: Message): string {
|
notititle(message: Message): string {
|
||||||
return(
|
return message.author.username + " > " + this.guild.properties.name + " > " + this.name;
|
||||||
message.author.username + " > " + this.guild.properties.name + " > " + this.name
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
notify(message: Message, deep = 0) {
|
notify(message: Message, deep = 0) {
|
||||||
if (this.localuser.play) {
|
if (this.localuser.play) {
|
||||||
@@ -1500,7 +1532,7 @@ class Channel extends SnowFlake{
|
|||||||
icon: message.author.getpfpsrc(this.guild),
|
icon: message.author.getpfpsrc(this.guild),
|
||||||
image: imgurl,
|
image: imgurl,
|
||||||
});
|
});
|
||||||
notification.addEventListener("click", _=>{
|
notification.addEventListener("click", (_) => {
|
||||||
window.focus();
|
window.focus();
|
||||||
this.getHTML();
|
this.getHTML();
|
||||||
});
|
});
|
||||||
@@ -1514,9 +1546,7 @@ class Channel extends SnowFlake{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async addRoleToPerms(role: Role) {
|
async addRoleToPerms(role: Role) {
|
||||||
await fetch(
|
await fetch(this.info.api + "/channels/" + this.id + "/permissions/" + role.id, {
|
||||||
this.info.api + "/channels/" + this.id + "/permissions/" + role.id,
|
|
||||||
{
|
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -1525,8 +1555,7 @@ class Channel extends SnowFlake{
|
|||||||
id: role.id,
|
id: role.id,
|
||||||
type: 0,
|
type: 0,
|
||||||
}),
|
}),
|
||||||
}
|
});
|
||||||
);
|
|
||||||
const perm = new Permissions("0", "0");
|
const perm = new Permissions("0", "0");
|
||||||
this.permission_overwrites.set(role.id, perm);
|
this.permission_overwrites.set(role.id, perm);
|
||||||
this.permission_overwritesar.push([role, perm]);
|
this.permission_overwritesar.push([role, perm]);
|
||||||
@@ -1539,9 +1568,7 @@ class Channel extends SnowFlake{
|
|||||||
} else {
|
} else {
|
||||||
//this.permission_overwrites.set(id,perms);
|
//this.permission_overwrites.set(id,perms);
|
||||||
}
|
}
|
||||||
await fetch(
|
await fetch(this.info.api + "/channels/" + this.id + "/permissions/" + id, {
|
||||||
this.info.api + "/channels/" + this.id + "/permissions/" + id,
|
|
||||||
{
|
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -1550,11 +1577,8 @@ class Channel extends SnowFlake{
|
|||||||
id,
|
id,
|
||||||
type: 0,
|
type: 0,
|
||||||
}),
|
}),
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Channel.setupcontextmenu();
|
Channel.setupcontextmenu();
|
||||||
export {Channel};
|
export {Channel};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ class Contextmenu<x, y>{
|
|||||||
string | null,
|
string | null,
|
||||||
(this: x, arg: y) => boolean,
|
(this: x, arg: y) => boolean,
|
||||||
(this: x, arg: y) => boolean,
|
(this: x, arg: y) => boolean,
|
||||||
string
|
string,
|
||||||
][];
|
][];
|
||||||
div!: HTMLDivElement;
|
div!: HTMLDivElement;
|
||||||
static setup() {
|
static setup() {
|
||||||
Contextmenu.currentmenu = "";
|
Contextmenu.currentmenu = "";
|
||||||
document.addEventListener("click", event=>{
|
document.addEventListener("click", (event) => {
|
||||||
if (Contextmenu.currentmenu === "") {
|
if (Contextmenu.currentmenu === "") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -31,8 +31,8 @@ class Contextmenu<x, y>{
|
|||||||
text: string | (() => string),
|
text: string | (() => string),
|
||||||
onclick: (this: x, arg: y, e: MouseEvent) => void,
|
onclick: (this: x, arg: y, e: MouseEvent) => void,
|
||||||
img: null | string = null,
|
img: null | string = null,
|
||||||
shown: (this: x, arg: y) => boolean = _=>true,
|
shown: (this: x, arg: y) => boolean = (_) => true,
|
||||||
enabled: (this: x, arg: y) => boolean = _=>true
|
enabled: (this: x, arg: y) => boolean = (_) => true,
|
||||||
) {
|
) {
|
||||||
this.buttons.push([text, onclick, img, shown, enabled, "button"]);
|
this.buttons.push([text, onclick, img, shown, enabled, "button"]);
|
||||||
return {};
|
return {};
|
||||||
@@ -41,8 +41,8 @@ class Contextmenu<x, y>{
|
|||||||
text: string | (() => string),
|
text: string | (() => string),
|
||||||
onclick: (this: x, arg: y, e: MouseEvent) => void,
|
onclick: (this: x, arg: y, e: MouseEvent) => void,
|
||||||
img = null,
|
img = null,
|
||||||
shown: (this: x, arg: y) => boolean = _=>true,
|
shown: (this: x, arg: y) => boolean = (_) => true,
|
||||||
enabled: (this: x, arg: y) => boolean = _=>true
|
enabled: (this: x, arg: y) => boolean = (_) => true,
|
||||||
) {
|
) {
|
||||||
this.buttons.push([text, onclick, img, shown, enabled, "submenu"]);
|
this.buttons.push([text, onclick, img, shown, enabled, "submenu"]);
|
||||||
return {};
|
return {};
|
||||||
@@ -68,7 +68,7 @@ class Contextmenu<x, y>{
|
|||||||
if (thing[5] === "button" || thing[5] === "submenu") {
|
if (thing[5] === "button" || thing[5] === "submenu") {
|
||||||
intext.onclick = (e) => {
|
intext.onclick = (e) => {
|
||||||
div.remove();
|
div.remove();
|
||||||
thing[1].call(addinfo, other,e)
|
thing[1].call(addinfo, other, e);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,13 @@ class Contextmenu<x, y>{
|
|||||||
Contextmenu.currentmenu = div;
|
Contextmenu.currentmenu = div;
|
||||||
return this.div;
|
return this.div;
|
||||||
}
|
}
|
||||||
bindContextmenu(obj: HTMLElement, addinfo: x, other: y,touchDrag:(x:number,y:number)=>unknown=()=>{},touchEnd:(x:number,y:number)=>unknown=()=>{}){
|
bindContextmenu(
|
||||||
|
obj: HTMLElement,
|
||||||
|
addinfo: x,
|
||||||
|
other: y,
|
||||||
|
touchDrag: (x: number, y: number) => unknown = () => {},
|
||||||
|
touchEnd: (x: number, y: number) => unknown = () => {},
|
||||||
|
) {
|
||||||
const func = (event: MouseEvent) => {
|
const func = (event: MouseEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
@@ -98,7 +104,9 @@ class Contextmenu<x, y>{
|
|||||||
let hold: NodeJS.Timeout | undefined;
|
let hold: NodeJS.Timeout | undefined;
|
||||||
let x!: number;
|
let x!: number;
|
||||||
let y!: number;
|
let y!: number;
|
||||||
obj.addEventListener("touchstart",(event: TouchEvent)=>{
|
obj.addEventListener(
|
||||||
|
"touchstart",
|
||||||
|
(event: TouchEvent) => {
|
||||||
x = event.touches[0].pageX;
|
x = event.touches[0].pageX;
|
||||||
y = event.touches[0].pageY;
|
y = event.touches[0].pageY;
|
||||||
if (event.touches.length > 1) {
|
if (event.touches.length > 1) {
|
||||||
@@ -112,9 +120,11 @@ class Contextmenu<x, y>{
|
|||||||
if (lastx ** 2 + lasty ** 2 > 10 ** 2) return;
|
if (lastx ** 2 + lasty ** 2 > 10 ** 2) return;
|
||||||
this.makemenu(event.touches[0].clientX, event.touches[0].clientY, addinfo, other);
|
this.makemenu(event.touches[0].clientX, event.touches[0].clientY, addinfo, other);
|
||||||
console.log(obj);
|
console.log(obj);
|
||||||
},500)
|
}, 500);
|
||||||
}
|
}
|
||||||
},{passive: false});
|
},
|
||||||
|
{passive: false},
|
||||||
|
);
|
||||||
let lastx = 0;
|
let lastx = 0;
|
||||||
let lasty = 0;
|
let lasty = 0;
|
||||||
obj.addEventListener("touchend", () => {
|
obj.addEventListener("touchend", () => {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class Direct extends Guild{
|
|||||||
ddiv.append(freindDiv);
|
ddiv.append(freindDiv);
|
||||||
freindDiv.onclick = () => {
|
freindDiv.onclick = () => {
|
||||||
this.loadChannel(null);
|
this.loadChannel(null);
|
||||||
}
|
};
|
||||||
|
|
||||||
ddiv.append(build);
|
ddiv.append(build);
|
||||||
return ddiv;
|
return ddiv;
|
||||||
@@ -90,14 +90,14 @@ class Direct extends Guild{
|
|||||||
thing.remove();
|
thing.remove();
|
||||||
}
|
}
|
||||||
const container = document.createElement("div");
|
const container = document.createElement("div");
|
||||||
container.classList.add("messagecontainer","flexttb","friendcontainer")
|
container.classList.add("messagecontainer", "flexttb", "friendcontainer");
|
||||||
|
|
||||||
messages.append(container);
|
messages.append(container);
|
||||||
const checkVoid = () => {
|
const checkVoid = () => {
|
||||||
if (this.localuser.channelfocus !== undefined || this.localuser.lookingguild !== this) {
|
if (this.localuser.channelfocus !== undefined || this.localuser.lookingguild !== this) {
|
||||||
this.localuser.relationshipsUpdate = () => {};
|
this.localuser.relationshipsUpdate = () => {};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
function genuserstrip(user: User, icons: HTMLElement): HTMLElement {
|
function genuserstrip(user: User, icons: HTMLElement): HTMLElement {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("flexltr", "liststyle");
|
div.classList.add("flexltr", "liststyle");
|
||||||
@@ -136,11 +136,11 @@ class Direct extends Guild{
|
|||||||
buttonc.onclick = (e) => {
|
buttonc.onclick = (e) => {
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
user.opendm();
|
user.opendm();
|
||||||
}
|
};
|
||||||
container.append(genuserstrip(user, buttonc));
|
container.append(genuserstrip(user, buttonc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
online.onclick = genOnline;
|
online.onclick = genOnline;
|
||||||
genOnline();
|
genOnline();
|
||||||
}
|
}
|
||||||
@@ -162,11 +162,11 @@ class Direct extends Guild{
|
|||||||
buttonc.onclick = (e) => {
|
buttonc.onclick = (e) => {
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
user.opendm();
|
user.opendm();
|
||||||
}
|
};
|
||||||
container.append(genuserstrip(user, buttonc));
|
container.append(genuserstrip(user, buttonc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
all.onclick = genAll;
|
all.onclick = genAll;
|
||||||
channelTopic.append(all);
|
channelTopic.append(all);
|
||||||
}
|
}
|
||||||
@@ -198,7 +198,7 @@ class Direct extends Guild{
|
|||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
user.changeRelationship(1);
|
user.changeRelationship(1);
|
||||||
outerDiv.remove();
|
outerDiv.remove();
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
buttonc.append(button1);
|
buttonc.append(button1);
|
||||||
buttonc.classList.add("friendlyButton");
|
buttonc.classList.add("friendlyButton");
|
||||||
@@ -206,13 +206,13 @@ class Direct extends Guild{
|
|||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
user.changeRelationship(0);
|
user.changeRelationship(0);
|
||||||
outerDiv.remove();
|
outerDiv.remove();
|
||||||
}
|
};
|
||||||
buttons.append(buttonc);
|
buttons.append(buttonc);
|
||||||
const outerDiv = genuserstrip(user, buttons);
|
const outerDiv = genuserstrip(user, buttons);
|
||||||
container.append(outerDiv);
|
container.append(outerDiv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
pending.onclick = genPending;
|
pending.onclick = genPending;
|
||||||
channelTopic.append(pending);
|
channelTopic.append(pending);
|
||||||
}
|
}
|
||||||
@@ -236,12 +236,12 @@ class Direct extends Guild{
|
|||||||
user.changeRelationship(0);
|
user.changeRelationship(0);
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
outerDiv.remove();
|
outerDiv.remove();
|
||||||
}
|
};
|
||||||
const outerDiv = genuserstrip(user, buttonc);
|
const outerDiv = genuserstrip(user, buttonc);
|
||||||
container.append(outerDiv);
|
container.append(outerDiv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
blocked.onclick = genBlocked;
|
blocked.onclick = genBlocked;
|
||||||
channelTopic.append(blocked);
|
channelTopic.append(blocked);
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,9 @@ class Direct extends Guild{
|
|||||||
container.innerHTML = "";
|
container.innerHTML = "";
|
||||||
const float = new Float("");
|
const float = new Float("");
|
||||||
const options = float.options;
|
const options = float.options;
|
||||||
const form=options.addForm("",(e:any)=>{
|
const form = options.addForm(
|
||||||
|
"",
|
||||||
|
(e: any) => {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
if (e.code === 404) {
|
if (e.code === 404) {
|
||||||
throw new FormError(text, I18n.getTranslation("friends.notfound"));
|
throw new FormError(text, I18n.getTranslation("friends.notfound"));
|
||||||
@@ -264,11 +266,13 @@ class Direct extends Guild{
|
|||||||
if (!box) return;
|
if (!box) return;
|
||||||
box.value = "";
|
box.value = "";
|
||||||
}
|
}
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
fetchURL: this.info.api + "/users/@me/relationships",
|
fetchURL: this.info.api + "/users/@me/relationships",
|
||||||
headers:this.headers
|
headers: this.headers,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
const text = form.addTextInput(I18n.getTranslation("friends.addfriendpromt"), "username");
|
const text = form.addTextInput(I18n.getTranslation("friends.addfriendpromt"), "username");
|
||||||
form.addPreprocessor((obj: any) => {
|
form.addPreprocessor((obj: any) => {
|
||||||
const [username, discriminator] = obj.username.split("#");
|
const [username, discriminator] = obj.username.split("#");
|
||||||
@@ -279,7 +283,7 @@ class Direct extends Guild{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
container.append(float.generateHTML());
|
container.append(float.generateHTML());
|
||||||
}
|
};
|
||||||
channelTopic.append(add);
|
channelTopic.append(add);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,21 +343,33 @@ class Group extends Channel{
|
|||||||
user: User;
|
user: User;
|
||||||
static contextmenu = new Contextmenu<Group, undefined>("channel menu");
|
static contextmenu = new Contextmenu<Group, undefined>("channel menu");
|
||||||
static setupcontextmenu() {
|
static setupcontextmenu() {
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("DMs.copyId"), function(this: Group){
|
this.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("DMs.copyId"),
|
||||||
|
function (this: Group) {
|
||||||
navigator.clipboard.writeText(this.id);
|
navigator.clipboard.writeText(this.id);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("DMs.markRead"), function(this: Group){
|
this.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("DMs.markRead"),
|
||||||
|
function (this: Group) {
|
||||||
this.readbottom();
|
this.readbottom();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("DMs.close"), function(this: Group){
|
this.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("DMs.close"),
|
||||||
|
function (this: Group) {
|
||||||
this.deleteChannel();
|
this.deleteChannel();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("user.copyId"), function(){
|
this.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("user.copyId"),
|
||||||
|
function () {
|
||||||
navigator.clipboard.writeText(this.user.id);
|
navigator.clipboard.writeText(this.user.id);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
constructor(json: dirrectjson, owner: Direct) {
|
constructor(json: dirrectjson, owner: Direct) {
|
||||||
super(-1, owner, json.id);
|
super(-1, owner, json.id);
|
||||||
@@ -395,7 +411,7 @@ class Group extends Channel{
|
|||||||
div.appendChild(this.user.buildpfp());
|
div.appendChild(this.user.buildpfp());
|
||||||
div.appendChild(myhtml);
|
div.appendChild(myhtml);
|
||||||
(div as any).myinfo = this;
|
(div as any).myinfo = this;
|
||||||
div.onclick = _=>{
|
div.onclick = (_) => {
|
||||||
this.getHTML();
|
this.getHTML();
|
||||||
const toggle = document.getElementById("maintoggle") as HTMLInputElement;
|
const toggle = document.getElementById("maintoggle") as HTMLInputElement;
|
||||||
toggle.checked = true;
|
toggle.checked = true;
|
||||||
@@ -436,7 +452,6 @@ class Group extends Channel{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.buildmessages();
|
this.buildmessages();
|
||||||
|
|
||||||
}
|
}
|
||||||
messageCreate(messagep: {d: messagejson}) {
|
messageCreate(messagep: {d: messagejson}) {
|
||||||
this.mentions++;
|
this.mentions++;
|
||||||
@@ -525,7 +540,7 @@ class Group extends Channel{
|
|||||||
buildpfp.classList.add("mentioned");
|
buildpfp.classList.add("mentioned");
|
||||||
div.append(buildpfp);
|
div.append(buildpfp);
|
||||||
sentdms.append(div);
|
sentdms.append(div);
|
||||||
div.onclick = _=>{
|
div.onclick = (_) => {
|
||||||
this.guild.loadGuild();
|
this.guild.loadGuild();
|
||||||
this.getHTML();
|
this.getHTML();
|
||||||
const toggle = document.getElementById("maintoggle") as HTMLInputElement;
|
const toggle = document.getElementById("maintoggle") as HTMLInputElement;
|
||||||
@@ -545,4 +560,4 @@ class Group extends Channel{
|
|||||||
}
|
}
|
||||||
export {Direct, Group};
|
export {Direct, Group};
|
||||||
|
|
||||||
Group.setupcontextmenu()
|
Group.setupcontextmenu();
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class ImagesDisplay{
|
|||||||
this.background = document.createElement("div");
|
this.background = document.createElement("div");
|
||||||
this.background.classList.add("background");
|
this.background.classList.add("background");
|
||||||
this.background.appendChild(this.makeHTML());
|
this.background.appendChild(this.makeHTML());
|
||||||
this.background.onclick = _=>{
|
this.background.onclick = (_) => {
|
||||||
this.hide();
|
this.hide();
|
||||||
};
|
};
|
||||||
document.body.append(this.background);
|
document.body.append(this.background);
|
||||||
@@ -34,4 +34,4 @@ class ImagesDisplay{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export{ImagesDisplay}
|
export {ImagesDisplay};
|
||||||
|
|||||||
@@ -17,12 +17,7 @@ class Embed{
|
|||||||
}
|
}
|
||||||
getType(json: embedjson) {
|
getType(json: embedjson) {
|
||||||
const instances = getInstances();
|
const instances = getInstances();
|
||||||
if(
|
if (instances && json.type === "link" && json.url && URL.canParse(json.url)) {
|
||||||
instances &&
|
|
||||||
json.type === "link" &&
|
|
||||||
json.url &&
|
|
||||||
URL.canParse(json.url)
|
|
||||||
){
|
|
||||||
const Url = new URL(json.url);
|
const Url = new URL(json.url);
|
||||||
for (const instance of instances) {
|
for (const instance of instances) {
|
||||||
if (instance.url && URL.canParse(instance.url)) {
|
if (instance.url && URL.canParse(instance.url)) {
|
||||||
@@ -40,8 +35,7 @@ URL.canParse(json.url)
|
|||||||
host = Url.host;
|
host = Url.host;
|
||||||
}
|
}
|
||||||
if (IUrl.host === host) {
|
if (IUrl.host === host) {
|
||||||
const code =
|
const code = Url.pathname.split("/")[Url.pathname.split("/").length - 1];
|
||||||
Url.pathname.split("/")[Url.pathname.split("/").length - 1];
|
|
||||||
json.invite = {
|
json.invite = {
|
||||||
url: instance.url,
|
url: instance.url,
|
||||||
code,
|
code,
|
||||||
@@ -67,10 +61,7 @@ Url.pathname.split("/")[Url.pathname.split("/").length - 1];
|
|||||||
case "article":
|
case "article":
|
||||||
return this.generateArticle();
|
return this.generateArticle();
|
||||||
default:
|
default:
|
||||||
console.warn(
|
console.warn(`unsupported embed type ${this.type}, please add support dev :3`, this.json);
|
||||||
`unsupported embed type ${this.type}, please add support dev :3`,
|
|
||||||
this.json
|
|
||||||
);
|
|
||||||
return document.createElement("div"); //prevent errors by giving blank div
|
return document.createElement("div"); //prevent errors by giving blank div
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,21 +237,21 @@ Url.pathname.split("/")[Url.pathname.split("/").length - 1];
|
|||||||
let info: {cdn: string; api: string};
|
let info: {cdn: string; api: string};
|
||||||
if (!this.invcache) {
|
if (!this.invcache) {
|
||||||
if (!json1) {
|
if (!json1) {
|
||||||
div.classList.remove("embed", "inviteEmbed", "flexttb")
|
div.classList.remove("embed", "inviteEmbed", "flexttb");
|
||||||
div.append(this.generateLink());
|
div.append(this.generateLink());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tempinfo = await getapiurls(json1.url);
|
const tempinfo = await getapiurls(json1.url);
|
||||||
|
|
||||||
if (!tempinfo) {
|
if (!tempinfo) {
|
||||||
div.classList.remove("embed", "inviteEmbed", "flexttb")
|
div.classList.remove("embed", "inviteEmbed", "flexttb");
|
||||||
div.append(this.generateLink());
|
div.append(this.generateLink());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
info = tempinfo;
|
info = tempinfo;
|
||||||
const res = await fetch(info.api + "/invites/" + json1.code);
|
const res = await fetch(info.api + "/invites/" + json1.code);
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
div.classList.remove("embed", "inviteEmbed", "flexttb")
|
div.classList.remove("embed", "inviteEmbed", "flexttb");
|
||||||
div.append(this.generateLink());
|
div.append(this.generateLink());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -271,21 +262,24 @@ Url.pathname.split("/")[Url.pathname.split("/").length - 1];
|
|||||||
}
|
}
|
||||||
if (!json) {
|
if (!json) {
|
||||||
div.append(this.generateLink());
|
div.append(this.generateLink());
|
||||||
div.classList.remove("embed", "inviteEmbed", "flexttb")
|
div.classList.remove("embed", "inviteEmbed", "flexttb");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (json.guild.banner) {
|
if (json.guild.banner) {
|
||||||
const banner = document.createElement("img");
|
const banner = document.createElement("img");
|
||||||
banner.src = this.localuser.info.cdn + "/icons/" + json.guild.id + "/" + json.guild.banner + ".png?size=256";
|
banner.src =
|
||||||
|
this.localuser.info.cdn +
|
||||||
|
"/icons/" +
|
||||||
|
json.guild.id +
|
||||||
|
"/" +
|
||||||
|
json.guild.banner +
|
||||||
|
".png?size=256";
|
||||||
banner.classList.add("banner");
|
banner.classList.add("banner");
|
||||||
div.append(banner);
|
div.append(banner);
|
||||||
}
|
}
|
||||||
const guild: invitejson["guild"] & { info?: { cdn: string } } =
|
const guild: invitejson["guild"] & {info?: {cdn: string}} = json.guild;
|
||||||
json.guild;
|
|
||||||
guild.info = info;
|
guild.info = info;
|
||||||
const icon = Guild.generateGuildIcon(
|
const icon = Guild.generateGuildIcon(guild as invitejson["guild"] & {info: {cdn: string}});
|
||||||
guild as invitejson["guild"] & { info: { cdn: string } }
|
|
||||||
);
|
|
||||||
const iconrow = document.createElement("div");
|
const iconrow = document.createElement("div");
|
||||||
iconrow.classList.add("flexltr");
|
iconrow.classList.add("flexltr");
|
||||||
iconrow.append(icon);
|
iconrow.append(icon);
|
||||||
@@ -315,14 +309,14 @@ guild as invitejson["guild"] & { info: { cdn: string } }
|
|||||||
}
|
}
|
||||||
button.classList.add("acceptinvbutton");
|
button.classList.add("acceptinvbutton");
|
||||||
div.append(button);
|
div.append(button);
|
||||||
button.onclick = _=>{
|
button.onclick = (_) => {
|
||||||
if (this.localuser.info.api.startsWith(info.api)) {
|
if (this.localuser.info.api.startsWith(info.api)) {
|
||||||
fetch(this.localuser.info.api + "/invites/" + json.code, {
|
fetch(this.localuser.info.api + "/invites/" + json.code, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: this.localuser.headers,
|
headers: this.localuser.headers,
|
||||||
})
|
})
|
||||||
.then(r=>r.json())
|
.then((r) => r.json())
|
||||||
.then(_=>{
|
.then((_) => {
|
||||||
if (_.message) {
|
if (_.message) {
|
||||||
alert(_.message);
|
alert(_.message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,7 @@ class Emoji{
|
|||||||
get info() {
|
get info() {
|
||||||
return this.owner.info;
|
return this.owner.info;
|
||||||
}
|
}
|
||||||
constructor(
|
constructor(json: emojijson, owner: Guild | Localuser) {
|
||||||
json: emojijson,
|
|
||||||
owner: Guild | Localuser
|
|
||||||
){
|
|
||||||
this.name = json.name;
|
this.name = json.name;
|
||||||
this.id = json.id;
|
this.id = json.id;
|
||||||
this.animated = json.animated || false;
|
this.animated = json.animated || false;
|
||||||
@@ -50,7 +47,8 @@ class Emoji{
|
|||||||
emojiElem.classList.add("md-emoji");
|
emojiElem.classList.add("md-emoji");
|
||||||
emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji");
|
emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji");
|
||||||
emojiElem.crossOrigin = "anonymous";
|
emojiElem.crossOrigin = "anonymous";
|
||||||
emojiElem.src =this.info.cdn+"/emojis/"+this.id+"."+(this.animated ? "gif" : "png")+"?size=32";
|
emojiElem.src =
|
||||||
|
this.info.cdn + "/emojis/" + this.id + "." + (this.animated ? "gif" : "png") + "?size=32";
|
||||||
emojiElem.alt = this.name;
|
emojiElem.alt = this.name;
|
||||||
emojiElem.loading = "lazy";
|
emojiElem.loading = "lazy";
|
||||||
return emojiElem;
|
return emojiElem;
|
||||||
@@ -65,7 +63,7 @@ class Emoji{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
static decodeEmojiList(buffer: ArrayBuffer) {
|
static decodeEmojiList(buffer: ArrayBuffer) {
|
||||||
const reader=new BinRead(buffer)
|
const reader = new BinRead(buffer);
|
||||||
const build: {name: string; emojis: {name: string; emoji: string}[]}[] = [];
|
const build: {name: string; emojis: {name: string; emoji: string}[]}[] = [];
|
||||||
let cats = reader.read16();
|
let cats = reader.read16();
|
||||||
|
|
||||||
@@ -98,20 +96,16 @@ class Emoji{
|
|||||||
}
|
}
|
||||||
static grabEmoji() {
|
static grabEmoji() {
|
||||||
fetch("/emoji.bin")
|
fetch("/emoji.bin")
|
||||||
.then(e=>{
|
.then((e) => {
|
||||||
return e.arrayBuffer();
|
return e.arrayBuffer();
|
||||||
})
|
})
|
||||||
.then(e=>{
|
.then((e) => {
|
||||||
Emoji.decodeEmojiList(e);
|
Emoji.decodeEmojiList(e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
static async emojiPicker(
|
static async emojiPicker(x: number, y: number, localuser: Localuser): Promise<Emoji | string> {
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
localuser: Localuser
|
|
||||||
): Promise<Emoji | string>{
|
|
||||||
let res: (r: Emoji | string) => void;
|
let res: (r: Emoji | string) => void;
|
||||||
const promise: Promise<Emoji | string> = new Promise(r=>{
|
const promise: Promise<Emoji | string> = new Promise((r) => {
|
||||||
res = r;
|
res = r;
|
||||||
});
|
});
|
||||||
const menu = document.createElement("div");
|
const menu = document.createElement("div");
|
||||||
@@ -130,8 +124,8 @@ class Emoji{
|
|||||||
|
|
||||||
let isFirst = true;
|
let isFirst = true;
|
||||||
localuser.guilds
|
localuser.guilds
|
||||||
.filter(guild=>guild.id != "@me" && guild.emojis.length > 0)
|
.filter((guild) => guild.id != "@me" && guild.emojis.length > 0)
|
||||||
.forEach(guild=>{
|
.forEach((guild) => {
|
||||||
const select = document.createElement("div");
|
const select = document.createElement("div");
|
||||||
select.classList.add("emojiSelect");
|
select.classList.add("emojiSelect");
|
||||||
|
|
||||||
@@ -139,14 +133,20 @@ class Emoji{
|
|||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.classList.add("pfp", "servericon", "emoji-server");
|
img.classList.add("pfp", "servericon", "emoji-server");
|
||||||
img.crossOrigin = "anonymous";
|
img.crossOrigin = "anonymous";
|
||||||
img.src = localuser.info.cdn+"/icons/"+guild.properties.id+"/"+guild.properties.icon+".png?size=48";
|
img.src =
|
||||||
|
localuser.info.cdn +
|
||||||
|
"/icons/" +
|
||||||
|
guild.properties.id +
|
||||||
|
"/" +
|
||||||
|
guild.properties.icon +
|
||||||
|
".png?size=48";
|
||||||
img.alt = "Server: " + guild.properties.name;
|
img.alt = "Server: " + guild.properties.name;
|
||||||
select.appendChild(img);
|
select.appendChild(img);
|
||||||
} else {
|
} else {
|
||||||
const div = document.createElement("span");
|
const div = document.createElement("span");
|
||||||
div.textContent = guild.properties.name
|
div.textContent = guild.properties.name
|
||||||
.replace(/'s /g, " ")
|
.replace(/'s /g, " ")
|
||||||
.replace(/\w+/g, word=>word[0])
|
.replace(/\w+/g, (word) => word[0])
|
||||||
.replace(/\s/g, "");
|
.replace(/\s/g, "");
|
||||||
select.append(div);
|
select.append(div);
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ class Emoji{
|
|||||||
name: emojit.name,
|
name: emojit.name,
|
||||||
animated: emojit.animated as boolean,
|
animated: emojit.animated as boolean,
|
||||||
},
|
},
|
||||||
localuser
|
localuser,
|
||||||
);
|
);
|
||||||
emojiElem.append(emojiClass.getHTML());
|
emojiElem.append(emojiClass.getHTML());
|
||||||
body.append(emojiElem);
|
body.append(emojiElem);
|
||||||
@@ -210,7 +210,7 @@ class Emoji{
|
|||||||
emoji.classList.add("emojiSelect");
|
emoji.classList.add("emojiSelect");
|
||||||
emoji.textContent = emojit.emoji;
|
emoji.textContent = emojit.emoji;
|
||||||
body.append(emoji);
|
body.append(emoji);
|
||||||
emoji.onclick = _=>{
|
emoji.onclick = (_) => {
|
||||||
res(emojit.emoji);
|
res(emojit.emoji);
|
||||||
if (Contextmenu.currentmenu !== "") {
|
if (Contextmenu.currentmenu !== "") {
|
||||||
Contextmenu.currentmenu.remove();
|
Contextmenu.currentmenu.remove();
|
||||||
@@ -243,7 +243,7 @@ class Emoji{
|
|||||||
}
|
}
|
||||||
for (const group of this.emojis) {
|
for (const group of this.emojis) {
|
||||||
for (const emoji of group.emojis) {
|
for (const emoji of group.emojis) {
|
||||||
similar(emoji)
|
similar(emoji);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const weakGuild = new WeakMap<emojijson, Guild>();
|
const weakGuild = new WeakMap<emojijson, Guild>();
|
||||||
@@ -252,15 +252,14 @@ class Emoji{
|
|||||||
for (const emoji of guild.emojis) {
|
for (const emoji of guild.emojis) {
|
||||||
if (similar(emoji)) {
|
if (similar(emoji)) {
|
||||||
weakGuild.set(emoji, guild);
|
weakGuild.set(emoji, guild);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ranked.sort((a, b) => b[1] - a[1]);
|
ranked.sort((a, b) => b[1] - a[1]);
|
||||||
return ranked.splice(0,results).map(a=>{
|
return ranked.splice(0, results).map((a) => {
|
||||||
return [new Emoji(a[0], weakGuild.get(a[0]) || localuser), a[1]];
|
return [new Emoji(a[0], weakGuild.get(a[0]) || localuser), a[1]];
|
||||||
|
});
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Emoji.grabEmoji();
|
Emoji.grabEmoji();
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class File{
|
|||||||
const icon = document.createElement("span");
|
const icon = document.createElement("span");
|
||||||
icon.classList.add("svgicon", "svg-delete");
|
icon.classList.add("svgicon", "svg-delete");
|
||||||
garbage.append(icon);
|
garbage.append(icon);
|
||||||
garbage.onclick = _=>{
|
garbage.onclick = (_) => {
|
||||||
div.remove();
|
div.remove();
|
||||||
files.splice(files.indexOf(file), 1);
|
files.splice(files.indexOf(file), 1);
|
||||||
};
|
};
|
||||||
@@ -105,7 +105,7 @@ class File{
|
|||||||
url: URL.createObjectURL(file),
|
url: URL.createObjectURL(file),
|
||||||
proxy_url: undefined,
|
proxy_url: undefined,
|
||||||
},
|
},
|
||||||
null
|
null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
createunknown(): HTMLElement {
|
createunknown(): HTMLElement {
|
||||||
@@ -143,7 +143,9 @@ class File{
|
|||||||
static filesizehuman(fsize: number) {
|
static filesizehuman(fsize: number) {
|
||||||
const i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024));
|
const i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024));
|
||||||
return (
|
return (
|
||||||
Number((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + " " + ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i] // I don't think this changes across languages, correct me if I'm wrong
|
Number((fsize / Math.pow(1024, i)).toFixed(2)) * 1 +
|
||||||
|
" " +
|
||||||
|
["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i] // I don't think this changes across languages, correct me if I'm wrong
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,14 @@ import{ Member }from"./member.js";
|
|||||||
import {Dialog, Options, Settings} from "./settings.js";
|
import {Dialog, Options, Settings} from "./settings.js";
|
||||||
import {Permissions} from "./permissions.js";
|
import {Permissions} from "./permissions.js";
|
||||||
import {SnowFlake} from "./snowflake.js";
|
import {SnowFlake} from "./snowflake.js";
|
||||||
import{channeljson,guildjson,emojijson,memberjson,invitejson,rolesjson, emojipjson,}from"./jsontypes.js";
|
import {
|
||||||
|
channeljson,
|
||||||
|
guildjson,
|
||||||
|
memberjson,
|
||||||
|
invitejson,
|
||||||
|
rolesjson,
|
||||||
|
emojipjson,
|
||||||
|
} from "./jsontypes.js";
|
||||||
import {User} from "./user.js";
|
import {User} from "./user.js";
|
||||||
import {I18n} from "./i18n.js";
|
import {I18n} from "./i18n.js";
|
||||||
import {Emoji} from "./emoji.js";
|
import {Emoji} from "./emoji.js";
|
||||||
@@ -32,23 +39,32 @@ class Guild extends SnowFlake{
|
|||||||
members = new Set<Member>();
|
members = new Set<Member>();
|
||||||
static contextmenu = new Contextmenu<Guild, undefined>("guild menu");
|
static contextmenu = new Contextmenu<Guild, undefined>("guild menu");
|
||||||
static setupcontextmenu() {
|
static setupcontextmenu() {
|
||||||
Guild.contextmenu.addbutton(()=>I18n.getTranslation("guild.copyId"), function(this: Guild){
|
Guild.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("guild.copyId"),
|
||||||
|
function (this: Guild) {
|
||||||
navigator.clipboard.writeText(this.id);
|
navigator.clipboard.writeText(this.id);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Guild.contextmenu.addbutton(()=>I18n.getTranslation("guild.markRead"), function(this: Guild){
|
Guild.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("guild.markRead"),
|
||||||
|
function (this: Guild) {
|
||||||
this.markAsRead();
|
this.markAsRead();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
Guild.contextmenu.addbutton(()=>I18n.getTranslation("guild.notifications"), function(this: Guild){
|
Guild.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("guild.notifications"),
|
||||||
|
function (this: Guild) {
|
||||||
this.setnotifcation();
|
this.setnotifcation();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("user.editServerProfile"),
|
() => I18n.getTranslation("user.editServerProfile"),
|
||||||
function () {
|
function () {
|
||||||
this.member.showEditProfile();
|
this.member.showEditProfile();
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Guild.contextmenu.addbutton(
|
Guild.contextmenu.addbutton(
|
||||||
@@ -59,7 +75,7 @@ class Guild extends SnowFlake{
|
|||||||
null,
|
null,
|
||||||
function (_) {
|
function (_) {
|
||||||
return this.properties.owner_id !== this.member.user.id;
|
return this.properties.owner_id !== this.member.user.id;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Guild.contextmenu.addbutton(
|
Guild.contextmenu.addbutton(
|
||||||
@@ -70,7 +86,7 @@ class Guild extends SnowFlake{
|
|||||||
null,
|
null,
|
||||||
function (_) {
|
function (_) {
|
||||||
return this.properties.owner_id === this.member.user.id;
|
return this.properties.owner_id === this.member.user.id;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Guild.contextmenu.addbutton(
|
Guild.contextmenu.addbutton(
|
||||||
@@ -81,16 +97,21 @@ class Guild extends SnowFlake{
|
|||||||
d.show();
|
d.show();
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
_=>true,
|
(_) => true,
|
||||||
function () {
|
function () {
|
||||||
return this.member.hasPermission("CREATE_INSTANT_INVITE");
|
return this.member.hasPermission("CREATE_INSTANT_INVITE");
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
Guild.contextmenu.addbutton(()=>I18n.getTranslation("guild.settings"), function(this: Guild){
|
Guild.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("guild.settings"),
|
||||||
|
function (this: Guild) {
|
||||||
this.generateSettings();
|
this.generateSettings();
|
||||||
},null,function(){
|
},
|
||||||
|
null,
|
||||||
|
function () {
|
||||||
return this.member.hasPermission("MANAGE_GUILD");
|
return this.member.hasPermission("MANAGE_GUILD");
|
||||||
});
|
},
|
||||||
|
);
|
||||||
/* -----things left for later-----
|
/* -----things left for later-----
|
||||||
guild.contextmenu.addbutton("Leave Guild",function(){
|
guild.contextmenu.addbutton("Leave Guild",function(){
|
||||||
console.log(this)
|
console.log(this)
|
||||||
@@ -104,19 +125,21 @@ class Guild extends SnowFlake{
|
|||||||
}
|
}
|
||||||
generateSettings() {
|
generateSettings() {
|
||||||
const settings = new Settings(I18n.getTranslation("guild.settingsFor", this.properties.name));
|
const settings = new Settings(I18n.getTranslation("guild.settingsFor", this.properties.name));
|
||||||
const textChannels=this.channels.filter(e=>{
|
const textChannels = this.channels.filter((e) => {
|
||||||
//TODO there are almost certainly more types. is Voice valid?
|
//TODO there are almost certainly more types. is Voice valid?
|
||||||
return new Set([0, 5]).has(e.type);
|
return new Set([0, 5]).has(e.type);
|
||||||
});
|
});
|
||||||
{
|
{
|
||||||
const overview = settings.addButton(I18n.getTranslation("guild.overview"));
|
const overview = settings.addButton(I18n.getTranslation("guild.overview"));
|
||||||
const form = overview.addForm("", _=>{}, {
|
const form = overview.addForm("", (_) => {}, {
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
traditionalSubmit: true,
|
traditionalSubmit: true,
|
||||||
fetchURL: this.info.api + "/guilds/" + this.id,
|
fetchURL: this.info.api + "/guilds/" + this.id,
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
});
|
});
|
||||||
form.addTextInput(I18n.getTranslation("guild.name:"), "name", { initText: this.properties.name });
|
form.addTextInput(I18n.getTranslation("guild.name:"), "name", {
|
||||||
|
initText: this.properties.name,
|
||||||
|
});
|
||||||
form.addMDInput(I18n.getTranslation("guild.description:"), "description", {
|
form.addMDInput(I18n.getTranslation("guild.description:"), "description", {
|
||||||
initText: this.properties.description,
|
initText: this.properties.description,
|
||||||
});
|
});
|
||||||
@@ -126,22 +149,26 @@ class Guild extends SnowFlake{
|
|||||||
|
|
||||||
form.addHR();
|
form.addHR();
|
||||||
|
|
||||||
const sysmap=[null,...textChannels.map(e=>e.id)];
|
const sysmap = [null, ...textChannels.map((e) => e.id)];
|
||||||
form.addSelect(I18n.getTranslation("guild.systemSelect:"), "system_channel_id",
|
form.addSelect(
|
||||||
["No system messages",...textChannels.map(e=>e.name)],{defaultIndex:sysmap.indexOf(this.properties.system_channel_id)}
|
I18n.getTranslation("guild.systemSelect:"),
|
||||||
,sysmap);
|
"system_channel_id",
|
||||||
|
["No system messages", ...textChannels.map((e) => e.name)],
|
||||||
|
{defaultIndex: sysmap.indexOf(this.properties.system_channel_id)},
|
||||||
|
sysmap,
|
||||||
|
);
|
||||||
|
|
||||||
form.addCheckboxInput(I18n.getTranslation("guild.sendrandomwelcome?"), "s1", {
|
form.addCheckboxInput(I18n.getTranslation("guild.sendrandomwelcome?"), "s1", {
|
||||||
initState:!(this.properties.system_channel_flags&1)
|
initState: !(this.properties.system_channel_flags & 1),
|
||||||
});
|
});
|
||||||
form.addCheckboxInput(I18n.getTranslation("guild.stickWelcomeReact?"), "s4", {
|
form.addCheckboxInput(I18n.getTranslation("guild.stickWelcomeReact?"), "s4", {
|
||||||
initState:!(this.properties.system_channel_flags&8)
|
initState: !(this.properties.system_channel_flags & 8),
|
||||||
});
|
});
|
||||||
form.addCheckboxInput(I18n.getTranslation("guild.boostMessage?"), "s2", {
|
form.addCheckboxInput(I18n.getTranslation("guild.boostMessage?"), "s2", {
|
||||||
initState:!(this.properties.system_channel_flags&2)
|
initState: !(this.properties.system_channel_flags & 2),
|
||||||
});
|
});
|
||||||
form.addCheckboxInput(I18n.getTranslation("guild.helpTips?"), "s3", {
|
form.addCheckboxInput(I18n.getTranslation("guild.helpTips?"), "s3", {
|
||||||
initState:!(this.properties.system_channel_flags&4)
|
initState: !(this.properties.system_channel_flags & 4),
|
||||||
});
|
});
|
||||||
form.addPreprocessor((e: any) => {
|
form.addPreprocessor((e: any) => {
|
||||||
let bits = 0;
|
let bits = 0;
|
||||||
@@ -154,15 +181,19 @@ class Guild extends SnowFlake{
|
|||||||
bits += (1 - e.s4) * 8;
|
bits += (1 - e.s4) * 8;
|
||||||
delete e.s4;
|
delete e.s4;
|
||||||
e.system_channel_flags = bits;
|
e.system_channel_flags = bits;
|
||||||
})
|
});
|
||||||
|
|
||||||
form.addHR();
|
form.addHR();
|
||||||
form.addSelect(I18n.getTranslation("guild.defaultNoti"),"default_message_notifications",
|
form.addSelect(
|
||||||
|
I18n.getTranslation("guild.defaultNoti"),
|
||||||
|
"default_message_notifications",
|
||||||
[I18n.getTranslation("guild.onlyMentions"), I18n.getTranslation("guild.all")],
|
[I18n.getTranslation("guild.onlyMentions"), I18n.getTranslation("guild.all")],
|
||||||
{
|
{
|
||||||
defaultIndex: [1, 0].indexOf(this.properties.default_message_notifications),
|
defaultIndex: [1, 0].indexOf(this.properties.default_message_notifications),
|
||||||
radio:true
|
radio: true,
|
||||||
},[1,0]);
|
},
|
||||||
|
[1, 0],
|
||||||
|
);
|
||||||
form.addHR();
|
form.addHR();
|
||||||
let region = this.properties.region;
|
let region = this.properties.region;
|
||||||
if (!region) {
|
if (!region) {
|
||||||
@@ -170,26 +201,31 @@ class Guild extends SnowFlake{
|
|||||||
}
|
}
|
||||||
form.addTextInput(I18n.getTranslation("guild.region:"), "region", {initText: region});
|
form.addTextInput(I18n.getTranslation("guild.region:"), "region", {initText: region});
|
||||||
}
|
}
|
||||||
this.makeInviteMenu(settings.addButton(I18n.getTranslation("invite.inviteMaker")),textChannels);
|
this.makeInviteMenu(
|
||||||
|
settings.addButton(I18n.getTranslation("invite.inviteMaker")),
|
||||||
|
textChannels,
|
||||||
|
);
|
||||||
const s1 = settings.addButton(I18n.getTranslation("guild.roles"));
|
const s1 = settings.addButton(I18n.getTranslation("guild.roles"));
|
||||||
const permlist: [Role, Permissions][] = [];
|
const permlist: [Role, Permissions][] = [];
|
||||||
for (const thing of this.roles) {
|
for (const thing of this.roles) {
|
||||||
permlist.push([thing, thing.permissions]);
|
permlist.push([thing, thing.permissions]);
|
||||||
}
|
}
|
||||||
s1.options.push(
|
s1.options.push(new RoleList(permlist, this, this.updateRolePermissions.bind(this), false));
|
||||||
new RoleList(permlist, this, this.updateRolePermissions.bind(this),false)
|
|
||||||
);
|
|
||||||
{
|
{
|
||||||
const emoji = settings.addButton("Emojis");
|
const emoji = settings.addButton("Emojis");
|
||||||
emoji.addButtonInput("", "Upload Emoji", () => {
|
emoji.addButtonInput("", "Upload Emoji", () => {
|
||||||
const popup = new Dialog("Upload emoji");
|
const popup = new Dialog("Upload emoji");
|
||||||
const form=popup.options.addForm("",()=>{
|
const form = popup.options.addForm(
|
||||||
|
"",
|
||||||
|
() => {
|
||||||
popup.hide();
|
popup.hide();
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
fetchURL: `${this.info.api}/guilds/${this.id}/emojis`,
|
fetchURL: `${this.info.api}/guilds/${this.id}/emojis`,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers:this.headers
|
headers: this.headers,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
form.addFileInput("Image:", "image", {required: true});
|
form.addFileInput("Image:", "image", {required: true});
|
||||||
form.addTextInput("Name:", "name", {required: true});
|
form.addTextInput("Name:", "name", {required: true});
|
||||||
popup.show();
|
popup.show();
|
||||||
@@ -209,8 +245,10 @@ class Guild extends SnowFlake{
|
|||||||
fetch(`${this.info.api}/guilds/${this.id}/emojis/${emoji.id}`, {
|
fetch(`${this.info.api}/guilds/${this.id}/emojis/${emoji.id}`, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
body:JSON.stringify({name:text.value})
|
body: JSON.stringify({name: text.value}),
|
||||||
}).then(e=>{if(!e.ok)text.value=emoji.name;})//if not ok, undo
|
}).then((e) => {
|
||||||
|
if (!e.ok) text.value = emoji.name;
|
||||||
|
}); //if not ok, undo
|
||||||
});
|
});
|
||||||
|
|
||||||
const del = document.createElement("span");
|
const del = document.createElement("span");
|
||||||
@@ -222,37 +260,36 @@ class Guild extends SnowFlake{
|
|||||||
options.addButtonInput("", I18n.getTranslation("yes"), () => {
|
options.addButtonInput("", I18n.getTranslation("yes"), () => {
|
||||||
fetch(`${this.info.api}/guilds/${this.id}/emojis/${emoji.id}`, {
|
fetch(`${this.info.api}/guilds/${this.id}/emojis/${emoji.id}`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers:this.headers
|
headers: this.headers,
|
||||||
})
|
});
|
||||||
diaolog.hide();
|
diaolog.hide();
|
||||||
});
|
});
|
||||||
options.addButtonInput("", I18n.getTranslation("no"), () => {
|
options.addButtonInput("", I18n.getTranslation("no"), () => {
|
||||||
diaolog.hide();
|
diaolog.hide();
|
||||||
})
|
});
|
||||||
diaolog.show();
|
diaolog.show();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
div.append(emojic.getHTML(true), ":", text, ":", del);
|
div.append(emojic.getHTML(true), ":", text, ":", del);
|
||||||
|
|
||||||
containdiv.append(div);
|
containdiv.append(div);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
this.onEmojiUpdate = () => {
|
this.onEmojiUpdate = () => {
|
||||||
if (!document.body.contains(containdiv)) {
|
if (!document.body.contains(containdiv)) {
|
||||||
this.onEmojiUpdate = () => {};
|
this.onEmojiUpdate = () => {};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
genDiv();
|
genDiv();
|
||||||
}
|
};
|
||||||
genDiv();
|
genDiv();
|
||||||
emoji.addHTMLArea(containdiv);
|
emoji.addHTMLArea(containdiv);
|
||||||
}
|
}
|
||||||
settings.show();
|
settings.show();
|
||||||
}
|
}
|
||||||
makeInviteMenu(options:Options,valid:void|(Channel[])){
|
makeInviteMenu(options: Options, valid: void | Channel[]) {
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
valid=this.channels.filter(e=>{
|
valid = this.channels.filter((e) => {
|
||||||
//TODO there are almost certainly more types. is Voice valid?
|
//TODO there are almost certainly more types. is Voice valid?
|
||||||
return new Set([0, 5]).has(e.type);
|
return new Set([0, 5]).has(e.type);
|
||||||
});
|
});
|
||||||
@@ -270,7 +307,7 @@ class Guild extends SnowFlake{
|
|||||||
const copy = document.createElement("span");
|
const copy = document.createElement("span");
|
||||||
copy.classList.add("copybutton", "svgicon", "svg-copy");
|
copy.classList.add("copybutton", "svgicon", "svg-copy");
|
||||||
copycontainer.append(copy);
|
copycontainer.append(copy);
|
||||||
copycontainer.onclick = _=>{
|
copycontainer.onclick = (_) => {
|
||||||
if (text.textContent) {
|
if (text.textContent) {
|
||||||
navigator.clipboard.writeText(text.textContent);
|
navigator.clipboard.writeText(text.textContent);
|
||||||
}
|
}
|
||||||
@@ -286,11 +323,11 @@ class Guild extends SnowFlake{
|
|||||||
target_user_id: null,
|
target_user_id: null,
|
||||||
max_age: expires + "",
|
max_age: expires + "",
|
||||||
max_uses: uses,
|
max_uses: uses,
|
||||||
temporary: uses !== 0
|
temporary: uses !== 0,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.then(_=>_.json())
|
.then((_) => _.json())
|
||||||
.then(json=>{
|
.then((json) => {
|
||||||
const params = new URLSearchParams("");
|
const params = new URLSearchParams("");
|
||||||
params.set("instance", this.info.wellknown);
|
params.set("instance", this.info.wellknown);
|
||||||
const encoded = params.toString();
|
const encoded = params.toString();
|
||||||
@@ -300,43 +337,58 @@ class Guild extends SnowFlake{
|
|||||||
|
|
||||||
options.addTitle(I18n.getTranslation("inviteOptions.title"));
|
options.addTitle(I18n.getTranslation("inviteOptions.title"));
|
||||||
const text2 = options.addText("");
|
const text2 = options.addText("");
|
||||||
options.addSelect(I18n.getTranslation("invite.channel:"),()=>{},valid.map(e=>e.name))
|
options
|
||||||
|
.addSelect(
|
||||||
|
I18n.getTranslation("invite.channel:"),
|
||||||
|
() => {},
|
||||||
|
valid.map((e) => e.name),
|
||||||
|
)
|
||||||
.watchForChange((e) => {
|
.watchForChange((e) => {
|
||||||
channel = valid[e];
|
channel = valid[e];
|
||||||
text2.setText(I18n.getTranslation("invite.subtext", channel.name, this.properties.name));
|
text2.setText(I18n.getTranslation("invite.subtext", channel.name, this.properties.name));
|
||||||
})
|
});
|
||||||
|
|
||||||
|
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];
|
||||||
|
};
|
||||||
|
|
||||||
options.addSelect(I18n.getTranslation("invite.expireAfter"),()=>{},
|
const timeOptions = ["1", "5", "10", "25", "50", "100"].map((e) =>
|
||||||
["30m","1h","6h","12h","1d","7d","30d","never"].map((e)=>I18n.getTranslation("inviteOptions."+e))
|
I18n.getTranslation("inviteOptions.limit", e),
|
||||||
).onchange=(e)=>{expires=[1800, 3600, 21600, 43200, 86400, 604800, 2592000, 0][e];};
|
);
|
||||||
|
timeOptions.unshift(I18n.getTranslation("inviteOptions.noLimit"));
|
||||||
const timeOptions=["1","5","10","25","50","100"].map((e)=>I18n.getTranslation("inviteOptions.limit",e))
|
options.addSelect(I18n.getTranslation("invite.expireAfter"), () => {}, timeOptions).onchange = (
|
||||||
timeOptions.unshift(I18n.getTranslation("inviteOptions.noLimit"))
|
e,
|
||||||
options.addSelect(I18n.getTranslation("invite.expireAfter"),()=>{},timeOptions)
|
) => {
|
||||||
.onchange=(e)=>{uses=[0, 1, 5, 10, 25, 50, 100][e];};
|
uses = [0, 1, 5, 10, 25, 50, 100][e];
|
||||||
|
};
|
||||||
|
|
||||||
options.addButtonInput("", I18n.getTranslation("invite.createInvite"), () => {
|
options.addButtonInput("", I18n.getTranslation("invite.createInvite"), () => {
|
||||||
update();
|
update();
|
||||||
})
|
});
|
||||||
|
|
||||||
options.addHTMLArea(div);
|
options.addHTMLArea(div);
|
||||||
}
|
}
|
||||||
roleUpdate: (role: Role, added: -1 | 0 | 1) => unknown = () => {};
|
roleUpdate: (role: Role, added: -1 | 0 | 1) => unknown = () => {};
|
||||||
sortRoles() {
|
sortRoles() {
|
||||||
this.roles.sort((a,b)=>(b.position-a.position));
|
this.roles.sort((a, b) => b.position - a.position);
|
||||||
}
|
}
|
||||||
async recalcRoles() {
|
async recalcRoles() {
|
||||||
let position = this.roles.length;
|
let position = this.roles.length;
|
||||||
const map=this.roles.map(_=>{
|
const map = this.roles.map((_) => {
|
||||||
position--;
|
position--;
|
||||||
return {id: _.id, position};
|
return {id: _.id, position};
|
||||||
})
|
});
|
||||||
await fetch(this.info.api + "/guilds/" + this.id + "/roles", {
|
await fetch(this.info.api + "/guilds/" + this.id + "/roles", {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
body: JSON.stringify(map),
|
body: JSON.stringify(map),
|
||||||
headers:this.headers
|
headers: this.headers,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
newRole(rolej: rolesjson) {
|
newRole(rolej: rolesjson) {
|
||||||
const role = new Role(rolej, this);
|
const role = new Role(rolej, this);
|
||||||
@@ -374,11 +426,7 @@ class Guild extends SnowFlake{
|
|||||||
this.roleUpdate(role, -1);
|
this.roleUpdate(role, -1);
|
||||||
}
|
}
|
||||||
onEmojiUpdate = (_: emojipjson[]) => {};
|
onEmojiUpdate = (_: emojipjson[]) => {};
|
||||||
constructor(
|
constructor(json: guildjson | -1, owner: Localuser, member: memberjson | User | null) {
|
||||||
json: guildjson | -1,
|
|
||||||
owner: Localuser,
|
|
||||||
member: memberjson | User | null
|
|
||||||
){
|
|
||||||
if (json === -1 || member === null) {
|
if (json === -1 || member === null) {
|
||||||
super("@me");
|
super("@me");
|
||||||
return;
|
return;
|
||||||
@@ -406,7 +454,7 @@ class Guild extends SnowFlake{
|
|||||||
this.sortRoles();
|
this.sortRoles();
|
||||||
if (member instanceof User) {
|
if (member instanceof User) {
|
||||||
console.warn(member);
|
console.warn(member);
|
||||||
Member.resolveMember(member, this).then(_=>{
|
Member.resolveMember(member, this).then((_) => {
|
||||||
if (_) {
|
if (_) {
|
||||||
this.member = _;
|
this.member = _;
|
||||||
} else {
|
} else {
|
||||||
@@ -414,7 +462,7 @@ class Guild extends SnowFlake{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Member.new(member, this).then(_=>{
|
Member.new(member, this).then((_) => {
|
||||||
if (_) {
|
if (_) {
|
||||||
this.member = _;
|
this.member = _;
|
||||||
}
|
}
|
||||||
@@ -443,7 +491,12 @@ class Guild extends SnowFlake{
|
|||||||
this.localuser.perminfo.guilds[this.id] = e;
|
this.localuser.perminfo.guilds[this.id] = e;
|
||||||
}
|
}
|
||||||
notisetting(settings: {
|
notisetting(settings: {
|
||||||
channel_overrides: {message_notifications: number,muted: boolean,mute_config: {selected_time_window: number,end_time: number},channel_id: string}[];
|
channel_overrides: {
|
||||||
|
message_notifications: number;
|
||||||
|
muted: boolean;
|
||||||
|
mute_config: {selected_time_window: number; end_time: number};
|
||||||
|
channel_id: string;
|
||||||
|
}[];
|
||||||
message_notifications: any;
|
message_notifications: any;
|
||||||
flags?: number;
|
flags?: number;
|
||||||
hide_muted_channels?: boolean;
|
hide_muted_channels?: boolean;
|
||||||
@@ -465,29 +518,38 @@ class Guild extends SnowFlake{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setnotifcation() {
|
setnotifcation() {
|
||||||
|
const options = ["all", "onlyMentions", "none"].map((e) => I18n.getTranslation("guild." + e));
|
||||||
const options=["all", "onlyMentions", "none"].map(e=>I18n.getTranslation("guild."+e));
|
|
||||||
const notiselect = new Dialog("");
|
const notiselect = new Dialog("");
|
||||||
const form=notiselect.options.addForm("",(_,sent:any)=>{
|
const form = notiselect.options.addForm(
|
||||||
|
"",
|
||||||
|
(_, sent: any) => {
|
||||||
notiselect.hide();
|
notiselect.hide();
|
||||||
this.message_notifications = sent.message_notifications;
|
this.message_notifications = sent.message_notifications;
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
fetchURL: `${this.info.api}/users/@me/guilds/${this.id}/settings/`,
|
fetchURL: `${this.info.api}/users/@me/guilds/${this.id}/settings/`,
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers:this.headers
|
headers: this.headers,
|
||||||
});
|
},
|
||||||
form.addSelect(I18n.getTranslation("guild.selectnoti"),"message_notifications",options,{
|
);
|
||||||
|
form.addSelect(
|
||||||
|
I18n.getTranslation("guild.selectnoti"),
|
||||||
|
"message_notifications",
|
||||||
|
options,
|
||||||
|
{
|
||||||
radio: true,
|
radio: true,
|
||||||
defaultIndex:this.message_notifications
|
defaultIndex: this.message_notifications,
|
||||||
},[0,1,2]);
|
},
|
||||||
|
[0, 1, 2],
|
||||||
|
);
|
||||||
notiselect.show();
|
notiselect.show();
|
||||||
}
|
}
|
||||||
confirmleave() {
|
confirmleave() {
|
||||||
const full = new Dialog("");
|
const full = new Dialog("");
|
||||||
full.options.addTitle(I18n.getTranslation("guild.confirmLeave"))
|
full.options.addTitle(I18n.getTranslation("guild.confirmLeave"));
|
||||||
const options = full.options.addOptions("", {ltr: true});
|
const options = full.options.addOptions("", {ltr: true});
|
||||||
options.addButtonInput("", I18n.getTranslation("guild.yesLeave"), () => {
|
options.addButtonInput("", I18n.getTranslation("guild.yesLeave"), () => {
|
||||||
this.leave().then(_=>{
|
this.leave().then((_) => {
|
||||||
full.hide();
|
full.hide();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -619,7 +681,7 @@ class Guild extends SnowFlake{
|
|||||||
}
|
}
|
||||||
const build = name
|
const build = name
|
||||||
.replace(/'s /g, " ")
|
.replace(/'s /g, " ")
|
||||||
.replace(/\w+/g, word=>word[0])
|
.replace(/\w+/g, (word) => word[0])
|
||||||
.replace(/\s/g, "");
|
.replace(/\s/g, "");
|
||||||
div.textContent = build;
|
div.textContent = build;
|
||||||
div.classList.add("blankserver", "servericon");
|
div.classList.add("blankserver", "servericon");
|
||||||
@@ -642,7 +704,8 @@ class Guild extends SnowFlake{
|
|||||||
|
|
||||||
const full = new Dialog("");
|
const full = new Dialog("");
|
||||||
full.options.addTitle(I18n.getTranslation("guild.confirmDelete", this.properties.name));
|
full.options.addTitle(I18n.getTranslation("guild.confirmDelete", this.properties.name));
|
||||||
full.options.addTextInput(I18n.getTranslation("guild.serverName"),()=>{}).onchange=(e)=>confirmname=e;
|
full.options.addTextInput(I18n.getTranslation("guild.serverName"), () => {}).onchange = (e) =>
|
||||||
|
(confirmname = e);
|
||||||
|
|
||||||
const options = full.options.addOptions("", {ltr: true});
|
const options = full.options.addOptions("", {ltr: true});
|
||||||
options.addButtonInput("", I18n.getTranslation("guild.yesDelete"), () => {
|
options.addButtonInput("", I18n.getTranslation("guild.yesDelete"), () => {
|
||||||
@@ -651,7 +714,7 @@ class Guild extends SnowFlake{
|
|||||||
alert("names don't match");
|
alert("names don't match");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.delete().then(_=>{
|
this.delete().then((_) => {
|
||||||
full.hide();
|
full.hide();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -815,7 +878,7 @@ class Guild extends SnowFlake{
|
|||||||
thing.remove();
|
thing.remove();
|
||||||
}
|
}
|
||||||
const h1 = document.createElement("h1");
|
const h1 = document.createElement("h1");
|
||||||
h1.classList.add("messagecontainer")
|
h1.classList.add("messagecontainer");
|
||||||
h1.textContent = I18n.getTranslation("guild.emptytext");
|
h1.textContent = I18n.getTranslation("guild.emptytext");
|
||||||
messages.append(h1);
|
messages.append(h1);
|
||||||
}
|
}
|
||||||
@@ -853,7 +916,9 @@ class Guild extends SnowFlake{
|
|||||||
return thischannel;
|
return thischannel;
|
||||||
}
|
}
|
||||||
createchannels(func = this.createChannel) {
|
createchannels(func = this.createChannel) {
|
||||||
const options=["text", "announcement","voice"].map(e=>I18n.getTranslation("channel."+e));
|
const options = ["text", "announcement", "voice"].map((e) =>
|
||||||
|
I18n.getTranslation("channel." + e),
|
||||||
|
);
|
||||||
|
|
||||||
const channelselect = new Dialog("");
|
const channelselect = new Dialog("");
|
||||||
const form = channelselect.options.addForm("", (e: any) => {
|
const form = channelselect.options.addForm("", (e: any) => {
|
||||||
@@ -861,7 +926,13 @@ class Guild extends SnowFlake{
|
|||||||
channelselect.hide();
|
channelselect.hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
form.addSelect(I18n.getTranslation("channel.selectType"),"type",options,{radio:true},[0,5,2]);
|
form.addSelect(
|
||||||
|
I18n.getTranslation("channel.selectType"),
|
||||||
|
"type",
|
||||||
|
options,
|
||||||
|
{radio: true},
|
||||||
|
[0, 5, 2],
|
||||||
|
);
|
||||||
form.addTextInput(I18n.getTranslation("channel.selectName"), "name");
|
form.addTextInput(I18n.getTranslation("channel.selectName"), "name");
|
||||||
channelselect.show();
|
channelselect.show();
|
||||||
}
|
}
|
||||||
@@ -913,9 +984,7 @@ class Guild extends SnowFlake{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
async createRole(name: string) {
|
async createRole(name: string) {
|
||||||
const fetched = await fetch(
|
const fetched = await fetch(this.info.api + "/guilds/" + this.id + "roles", {
|
||||||
this.info.api + "/guilds/" + this.id + "roles",
|
|
||||||
{
|
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@@ -923,8 +992,7 @@ class Guild extends SnowFlake{
|
|||||||
color: 0,
|
color: 0,
|
||||||
permissions: "0",
|
permissions: "0",
|
||||||
}),
|
}),
|
||||||
}
|
});
|
||||||
);
|
|
||||||
const json = await fetched.json();
|
const json = await fetched.json();
|
||||||
const role = new Role(json, this);
|
const role = new Role(json, this);
|
||||||
this.roleids.set(role.id, role);
|
this.roleids.set(role.id, role);
|
||||||
|
|||||||
@@ -1,39 +1,44 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jank Client</title>
|
<title>Jank Client</title>
|
||||||
<meta content="Jank Client" property="og:title">
|
<meta content="Jank Client" property="og:title" />
|
||||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description">
|
<meta content="A spacebar client that has DMs, replying and more" property="og:description" />
|
||||||
<meta content="/logo.webp" property="og:image">
|
<meta content="/logo.webp" property="og:image" />
|
||||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||||
<link href="/style.css" rel="stylesheet">
|
<link href="/style.css" rel="stylesheet" />
|
||||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
<link href="/themes.css" rel="stylesheet" id="lightcss" />
|
||||||
<style>body.no-theme{background:#16191b;}@media(prefers-color-scheme:light){body.no-theme{background:#9397bd;}}</style>
|
<style>
|
||||||
|
body.no-theme {
|
||||||
|
background: #16191b;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
body.no-theme {
|
||||||
|
background: #9397bd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="no-theme" style="overflow-y: scroll;">
|
<body class="no-theme" style="overflow-y: scroll">
|
||||||
<div id="titleDiv">
|
<div id="titleDiv">
|
||||||
<img src="/logo.svg" width="40">
|
<img src="/logo.svg" width="40" />
|
||||||
<h1 id="pageTitle">Jank Client</h1>
|
<h1 id="pageTitle">Jank Client</h1>
|
||||||
<a href="/invite/USgYJo?instance=https%3A%2F%2Fspacebar.chat"
|
<a href="/invite/USgYJo?instance=https%3A%2F%2Fspacebar.chat" class="TitleButtons">
|
||||||
class="TitleButtons">
|
|
||||||
Spacebar Guild
|
Spacebar Guild
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/MathMan05/JankClient" class="TitleButtons">
|
<a href="https://github.com/MathMan05/JankClient" class="TitleButtons"> Github </a>
|
||||||
Github
|
<a href="/channels/@me" class="TitleButtons" id="openClient"> Open Client </a>
|
||||||
</a>
|
|
||||||
<a href="/channels/@me" class="TitleButtons" id="openClient">
|
|
||||||
Open Client
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="homePage">
|
<div id="homePage">
|
||||||
|
|
||||||
<h1 class="pagehead" id="welcomeJank">Welcome to Jank Client</h1>
|
<h1 class="pagehead" id="welcomeJank">Welcome to Jank Client</h1>
|
||||||
<div class="pagebox">
|
<div class="pagebox">
|
||||||
<p id="box1title">Jank Client is a Spacebar-compatible client seeking to be as good as it can be with many features including:</p>
|
<p id="box1title">
|
||||||
|
Jank Client is a Spacebar-compatible client seeking to be as good as it can be with many
|
||||||
|
features including:
|
||||||
|
</p>
|
||||||
<ul id="box1Items">
|
<ul id="box1Items">
|
||||||
<li>Direct Messaging</li>
|
<li>Direct Messaging</li>
|
||||||
<li>Reactions support</li>
|
<li>Reactions support</li>
|
||||||
@@ -47,18 +52,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="pagebox">
|
<div class="pagebox">
|
||||||
<h2 id="compatableInstances">Spacebar-Compatible Instances:</h2>
|
<h2 id="compatableInstances">Spacebar-Compatible Instances:</h2>
|
||||||
<div id="instancebox">
|
<div id="instancebox"></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="pagebox">
|
<div class="pagebox">
|
||||||
<h2 id="box3title">Contribute to Jank Client</h2>
|
<h2 id="box3title">Contribute to Jank Client</h2>
|
||||||
<p id="box3description">We always appreciate some help, whether that be in the form of bug reports, code, help translate, or even just pointing out some typos.</p><br>
|
<p id="box3description">
|
||||||
<a href="https://github.com/MathMan05/JankClient" class="TitleButtons">
|
We always appreciate some help, whether that be in the form of bug reports, code, help
|
||||||
Github
|
translate, or even just pointing out some typos.
|
||||||
</a>
|
</p>
|
||||||
|
<br />
|
||||||
|
<a href="https://github.com/MathMan05/JankClient" class="TitleButtons"> Github </a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script src="/home.js" type="module"></script>
|
<script src="/home.js" type="module"></script>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -5,14 +5,22 @@ const serverbox = document.getElementById("instancebox") as HTMLDivElement;
|
|||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await I18n.done;
|
await I18n.done;
|
||||||
const openClient=document.getElementById("openClient")
|
const openClient = document.getElementById("openClient");
|
||||||
const welcomeJank=document.getElementById("welcomeJank")
|
const welcomeJank = document.getElementById("welcomeJank");
|
||||||
const box1title=document.getElementById("box1title")
|
const box1title = document.getElementById("box1title");
|
||||||
const box1Items=document.getElementById("box1Items")
|
const box1Items = document.getElementById("box1Items");
|
||||||
const compatableInstances=document.getElementById("compatableInstances")
|
const compatableInstances = document.getElementById("compatableInstances");
|
||||||
const box3title=document.getElementById("box3title")
|
const box3title = document.getElementById("box3title");
|
||||||
const box3description=document.getElementById("box3description")
|
const box3description = document.getElementById("box3description");
|
||||||
if(openClient&&welcomeJank&&compatableInstances&&box3title&&box3description&&box1title&&box1Items){
|
if (
|
||||||
|
openClient &&
|
||||||
|
welcomeJank &&
|
||||||
|
compatableInstances &&
|
||||||
|
box3title &&
|
||||||
|
box3description &&
|
||||||
|
box1title &&
|
||||||
|
box1Items
|
||||||
|
) {
|
||||||
openClient.textContent = I18n.getTranslation("htmlPages.openClient");
|
openClient.textContent = I18n.getTranslation("htmlPages.openClient");
|
||||||
welcomeJank.textContent = I18n.getTranslation("htmlPages.welcomeJank");
|
welcomeJank.textContent = I18n.getTranslation("htmlPages.welcomeJank");
|
||||||
box1title.textContent = I18n.getTranslation("htmlPages.box1title");
|
box1title.textContent = I18n.getTranslation("htmlPages.box1title");
|
||||||
@@ -29,12 +37,20 @@ const serverbox = document.getElementById("instancebox") as HTMLDivElement;
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error(openClient,welcomeJank,compatableInstances,box3title,box3description,box1title,box1Items)
|
console.error(
|
||||||
|
openClient,
|
||||||
|
welcomeJank,
|
||||||
|
compatableInstances,
|
||||||
|
box3title,
|
||||||
|
box3description,
|
||||||
|
box1title,
|
||||||
|
box1Items,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
})()
|
})();
|
||||||
|
|
||||||
fetch("/instances.json")
|
fetch("/instances.json")
|
||||||
.then(_=>_.json())
|
.then((_) => _.json())
|
||||||
.then(
|
.then(
|
||||||
async (
|
async (
|
||||||
json: {
|
json: {
|
||||||
@@ -53,7 +69,7 @@ fetch("/instances.json")
|
|||||||
gateway: string;
|
gateway: string;
|
||||||
login?: string;
|
login?: string;
|
||||||
};
|
};
|
||||||
}[]
|
}[],
|
||||||
) => {
|
) => {
|
||||||
await I18n.done;
|
await I18n.done;
|
||||||
console.warn(json);
|
console.warn(json);
|
||||||
@@ -98,16 +114,17 @@ fetch("/instances.json")
|
|||||||
const stats = document.createElement("div");
|
const stats = document.createElement("div");
|
||||||
stats.classList.add("flexltr");
|
stats.classList.add("flexltr");
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.innerText = I18n.getTranslation("home.uptimeStats",Math.round(
|
span.innerText = I18n.getTranslation(
|
||||||
instance.uptime.alltime * 100
|
"home.uptimeStats",
|
||||||
)+"",Math.round(
|
Math.round(instance.uptime.alltime * 100) + "",
|
||||||
instance.uptime.weektime * 100
|
Math.round(instance.uptime.weektime * 100) + "",
|
||||||
)+"",Math.round(instance.uptime.daytime * 100)+"")
|
Math.round(instance.uptime.daytime * 100) + "",
|
||||||
|
);
|
||||||
stats.append(span);
|
stats.append(span);
|
||||||
statbox.append(stats);
|
statbox.append(stats);
|
||||||
}
|
}
|
||||||
div.append(statbox);
|
div.append(statbox);
|
||||||
div.onclick = _=>{
|
div.onclick = (_) => {
|
||||||
if (instance.online) {
|
if (instance.online) {
|
||||||
window.location.href = "/register.html?instance=" + encodeURI(instance.name);
|
window.location.href = "/register.html?instance=" + encodeURI(instance.name);
|
||||||
} else {
|
} else {
|
||||||
@@ -116,5 +133,5 @@ fetch("/instances.json")
|
|||||||
};
|
};
|
||||||
serverbox.append(div);
|
serverbox.append(div);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class Hover{
|
|||||||
elm.addEventListener("mouseover", () => {
|
elm.addEventListener("mouseover", () => {
|
||||||
timeOut = setTimeout(async () => {
|
timeOut = setTimeout(async () => {
|
||||||
elm2 = await this.makeHover(elm);
|
elm2 = await this.makeHover(elm);
|
||||||
},750)
|
}, 750);
|
||||||
});
|
});
|
||||||
elm.addEventListener("mouseout", () => {
|
elm.addEventListener("mouseout", () => {
|
||||||
clearTimeout(timeOut);
|
clearTimeout(timeOut);
|
||||||
@@ -22,14 +22,15 @@ class Hover{
|
|||||||
if (e[0].removedNodes) {
|
if (e[0].removedNodes) {
|
||||||
clearTimeout(timeOut);
|
clearTimeout(timeOut);
|
||||||
elm2.remove();
|
elm2.remove();
|
||||||
};
|
}
|
||||||
}).observe(elm, {childList: true});
|
}).observe(elm, {childList: true});
|
||||||
}
|
}
|
||||||
async makeHover(elm: HTMLElement) {
|
async makeHover(elm: HTMLElement) {
|
||||||
if(!document.contains(elm)) return document.createDocumentFragment() as unknown as HTMLDivElement;
|
if (!document.contains(elm))
|
||||||
|
return document.createDocumentFragment() as unknown as HTMLDivElement;
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
if (this.str instanceof MarkDown) {
|
if (this.str instanceof MarkDown) {
|
||||||
div.append(this.str.makeHTML())
|
div.append(this.str.makeHTML());
|
||||||
} else if (this.str instanceof Function) {
|
} else if (this.str instanceof Function) {
|
||||||
const hover = await this.str();
|
const hover = await this.str();
|
||||||
if (hover instanceof MarkDown) {
|
if (hover instanceof MarkDown) {
|
||||||
@@ -41,17 +42,17 @@ class Hover{
|
|||||||
div.innerText = this.str;
|
div.innerText = this.str;
|
||||||
}
|
}
|
||||||
const box = elm.getBoundingClientRect();
|
const box = elm.getBoundingClientRect();
|
||||||
div.style.top=(box.bottom+4)+"px";
|
div.style.top = box.bottom + 4 + "px";
|
||||||
div.style.left = Math.floor(box.left + box.width / 2) + "px";
|
div.style.left = Math.floor(box.left + box.width / 2) + "px";
|
||||||
div.classList.add("hoverthing");
|
div.classList.add("hoverthing");
|
||||||
div.style.opacity = "0";
|
div.style.opacity = "0";
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
div.style.opacity = "1";
|
div.style.opacity = "1";
|
||||||
},10)
|
}, 10);
|
||||||
document.body.append(div);
|
document.body.append(div);
|
||||||
Contextmenu.keepOnScreen(div);
|
Contextmenu.keepOnScreen(div);
|
||||||
console.log(div, elm);
|
console.log(div, elm);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export{Hover}
|
export {Hover};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ for(const lang of Object.keys(langs) as string[]){
|
|||||||
}
|
}
|
||||||
console.log(langs);
|
console.log(langs);
|
||||||
type translation = {
|
type translation = {
|
||||||
[key:string]:string|translation
|
[key: string]: string | translation;
|
||||||
};
|
};
|
||||||
let res: () => unknown = () => {};
|
let res: () => unknown = () => {};
|
||||||
class I18n {
|
class I18n {
|
||||||
@@ -16,12 +16,11 @@ class I18n{
|
|||||||
res = res2;
|
res = res2;
|
||||||
});
|
});
|
||||||
static async create(lang: string) {
|
static async create(lang: string) {
|
||||||
|
const json = (await (await fetch("/translations/" + lang + ".json")).json()) as translation;
|
||||||
const json=await (await fetch("/translations/"+lang+".json")).json() as translation;
|
|
||||||
const translations: translation[] = [];
|
const translations: translation[] = [];
|
||||||
translations.push(json);
|
translations.push(json);
|
||||||
if (lang !== "en") {
|
if (lang !== "en") {
|
||||||
translations.push(await (await fetch("/translations/en.json")).json() as translation);
|
translations.push((await (await fetch("/translations/en.json")).json()) as translation);
|
||||||
}
|
}
|
||||||
this.lang = lang;
|
this.lang = lang;
|
||||||
this.translations = translations;
|
this.translations = translations;
|
||||||
@@ -36,7 +35,6 @@ class I18n{
|
|||||||
for (const thing of path) {
|
for (const thing of path) {
|
||||||
if (typeof jsont !== "string" && jsont !== undefined) {
|
if (typeof jsont !== "string" && jsont !== undefined) {
|
||||||
jsont = jsont[thing];
|
jsont = jsont[thing];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
jsont = json;
|
jsont = json;
|
||||||
break;
|
break;
|
||||||
@@ -51,7 +49,7 @@ class I18n{
|
|||||||
if (str) {
|
if (str) {
|
||||||
return this.fillInBlanks(str, params);
|
return this.fillInBlanks(str, params);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(msg+" not found")
|
throw new Error(msg + " not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static fillInBlanks(msg: string, params: string[]): string {
|
static fillInBlanks(msg: string, params: string[]): string {
|
||||||
@@ -64,8 +62,7 @@ class I18n{
|
|||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
msg=msg.replace(/{{(.+?)}}/g,
|
msg = msg.replace(/{{(.+?)}}/g, (str, match: string) => {
|
||||||
(str, match:string) => {
|
|
||||||
const [op, strsSplit] = this.fillInBlanks(match, params).split(":");
|
const [op, strsSplit] = this.fillInBlanks(match, params).split(":");
|
||||||
const [first, ...strs] = strsSplit.split("|");
|
const [first, ...strs] = strsSplit.split("|");
|
||||||
switch (op.toUpperCase()) {
|
switch (op.toUpperCase()) {
|
||||||
@@ -91,13 +88,12 @@ class I18n{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
static options() {
|
static options() {
|
||||||
return [...langmap.keys()].map(e=>e.replace(".json",""));
|
return [...langmap.keys()].map((e) => e.replace(".json", ""));
|
||||||
}
|
}
|
||||||
static setLanguage(lang: string) {
|
static setLanguage(lang: string) {
|
||||||
if (this.options().indexOf(userLocale) !== -1) {
|
if (this.options().indexOf(userLocale) !== -1) {
|
||||||
@@ -115,7 +111,7 @@ const storage=localStorage.getItem("lang");
|
|||||||
if (storage) {
|
if (storage) {
|
||||||
userLocale = storage;
|
userLocale = storage;
|
||||||
} else {
|
} else {
|
||||||
localStorage.setItem("lang",userLocale)
|
localStorage.setItem("lang", userLocale);
|
||||||
}
|
}
|
||||||
I18n.create(userLocale);
|
I18n.create(userLocale);
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,37 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||||
|
/>
|
||||||
<title>Jank Client</title>
|
<title>Jank Client</title>
|
||||||
<meta content="Jank Client" property="og:title">
|
<meta content="Jank Client" property="og:title" />
|
||||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description">
|
<meta content="A spacebar client that has DMs, replying and more" property="og:description" />
|
||||||
<meta content="/logo.webp" property="og:image">
|
<meta content="/logo.webp" property="og:image" />
|
||||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||||
<link href="/style.css" rel="stylesheet">
|
<link href="/style.css" rel="stylesheet" />
|
||||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
<link href="/themes.css" rel="stylesheet" id="lightcss" />
|
||||||
<style>body.no-theme,#loading{background:#16191b;}@media(prefers-color-scheme:light){body.no-theme,#loading{background:#9397bd;}}</style>
|
<style>
|
||||||
<link rel="manifest" href="/manifest.json">
|
body.no-theme,
|
||||||
|
#loading {
|
||||||
|
background: #16191b;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
body.no-theme,
|
||||||
|
#loading {
|
||||||
|
background: #9397bd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<link rel="manifest" href="/manifest.json" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="no-theme">
|
<body class="no-theme">
|
||||||
<div id="loading" class="loading">
|
<div id="loading" class="loading">
|
||||||
<div class="centeritem">
|
<div class="centeritem">
|
||||||
<img src="/logo.svg" style="width:3in;height:3in;">
|
<img src="/logo.svg" style="width: 3in; height: 3in" />
|
||||||
<h1 id="loadingText">Jank Client is loading</h1>
|
<h1 id="loadingText">Jank Client is loading</h1>
|
||||||
<h2 id="load-desc">This shouldn't take long</h2>
|
<h2 id="load-desc">This shouldn't take long</h2>
|
||||||
<h1 id="switchaccounts">Switch Accounts</h1>
|
<h1 id="switchaccounts">Switch Accounts</h1>
|
||||||
@@ -36,7 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flexltr" id="userdock">
|
<div class="flexltr" id="userdock">
|
||||||
<div class="flexltr" id="userinfo">
|
<div class="flexltr" id="userinfo">
|
||||||
<img id="userpfp" class="pfp">
|
<img id="userpfp" class="pfp" />
|
||||||
|
|
||||||
<div class="flexttb userflex">
|
<div class="flexttb userflex">
|
||||||
<p id="username">USERNAME</p>
|
<p id="username">USERNAME</p>
|
||||||
@@ -55,8 +69,8 @@
|
|||||||
<label for="maintoggle" id="maintoggleicon">
|
<label for="maintoggle" id="maintoggleicon">
|
||||||
<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" style="align-items: center;">
|
<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>
|
||||||
@@ -64,15 +78,14 @@
|
|||||||
<label for="memberlisttoggle" id="memberlisttoggleicon">
|
<label for="memberlisttoggle" id="memberlisttoggleicon">
|
||||||
<span class="svgicon svg-friends"></span>
|
<span class="svgicon svg-friends"></span>
|
||||||
</label>
|
</label>
|
||||||
<input type="checkbox" id="memberlisttoggle" checked>
|
<input type="checkbox" id="memberlisttoggle" checked />
|
||||||
</div>
|
</div>
|
||||||
<div class="flexltr flexgrow">
|
<div class="flexltr flexgrow">
|
||||||
<div class="flexttb flexgrow">
|
<div class="flexttb flexgrow">
|
||||||
<div id="channelw" class="flexltr">
|
<div id="channelw" class="flexltr">
|
||||||
<div id="loadingdiv">
|
<div id="loadingdiv"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div style="position: relative">
|
||||||
<div style="position: relative;">
|
|
||||||
<div id="searchOptions" class="flexttb searchOptions"></div>
|
<div id="searchOptions" class="flexttb searchOptions"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="pasteimage" class="flexltr"></div>
|
<div id="pasteimage" class="flexltr"></div>
|
||||||
@@ -81,7 +94,7 @@
|
|||||||
<div id="realbox">
|
<div id="realbox">
|
||||||
<div class="outerTypeBox">
|
<div class="outerTypeBox">
|
||||||
<span class="svg-upload svgicon" id="upload"></span>
|
<span class="svg-upload svgicon" id="upload"></span>
|
||||||
<div id="typebox" contentEditable="true"></div>
|
<div id="typebox" contenteditable="true"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="typing" class="hidden flexltr">
|
<div id="typing" class="hidden flexltr">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import{ Message }from"./message.js";
|
|||||||
import {File} from "./file.js";
|
import {File} from "./file.js";
|
||||||
import {I18n} from "./i18n.js";
|
import {I18n} from "./i18n.js";
|
||||||
(async () => {
|
(async () => {
|
||||||
await I18n.done
|
await I18n.done;
|
||||||
const users = getBulkUsers();
|
const users = getBulkUsers();
|
||||||
if (!users.currentuser) {
|
if (!users.currentuser) {
|
||||||
window.location.href = "/login.html";
|
window.location.href = "/login.html";
|
||||||
@@ -25,7 +25,7 @@ import { I18n } from "./i18n.js";
|
|||||||
filedroptext.textContent = I18n.getTranslation("uploadFilesText");
|
filedroptext.textContent = I18n.getTranslation("uploadFilesText");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
I18n
|
I18n;
|
||||||
function showAccountSwitcher(): void {
|
function showAccountSwitcher(): void {
|
||||||
const table = document.createElement("div");
|
const table = document.createElement("div");
|
||||||
table.classList.add("flexttb", "accountSwitcher");
|
table.classList.add("flexttb", "accountSwitcher");
|
||||||
@@ -94,13 +94,13 @@ import { I18n } from "./i18n.js";
|
|||||||
}
|
}
|
||||||
|
|
||||||
const userInfoElement = document.getElementById("userinfo") as HTMLDivElement;
|
const userInfoElement = document.getElementById("userinfo") as HTMLDivElement;
|
||||||
userInfoElement.addEventListener("click", event=>{
|
userInfoElement.addEventListener("click", (event) => {
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
showAccountSwitcher();
|
showAccountSwitcher();
|
||||||
});
|
});
|
||||||
|
|
||||||
const switchAccountsElement = document.getElementById("switchaccounts") as HTMLDivElement;
|
const switchAccountsElement = document.getElementById("switchaccounts") as HTMLDivElement;
|
||||||
switchAccountsElement.addEventListener("click", event=>{
|
switchAccountsElement.addEventListener("click", (event) => {
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
showAccountSwitcher();
|
showAccountSwitcher();
|
||||||
});
|
});
|
||||||
@@ -119,7 +119,8 @@ import { I18n } from "./i18n.js";
|
|||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
(document.getElementById("load-desc") as HTMLSpanElement).textContent = I18n.getTranslation("accountNotStart");
|
(document.getElementById("load-desc") as HTMLSpanElement).textContent =
|
||||||
|
I18n.getTranslation("accountNotStart");
|
||||||
thisUser = new Localuser(-1);
|
thisUser = new Localuser(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +133,7 @@ import { I18n } from "./i18n.js";
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
()=>thisUser.isAdmin()
|
() => thisUser.isAdmin(),
|
||||||
);
|
);
|
||||||
|
|
||||||
menu.addbutton(
|
menu.addbutton(
|
||||||
@@ -143,7 +144,7 @@ import { I18n } from "./i18n.js";
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
()=>thisUser.isAdmin()
|
() => thisUser.isAdmin(),
|
||||||
);
|
);
|
||||||
|
|
||||||
menu.bindContextmenu(document.getElementById("channels") as HTMLDivElement);
|
menu.bindContextmenu(document.getElementById("channels") as HTMLDivElement);
|
||||||
@@ -155,9 +156,11 @@ import { I18n } from "./i18n.js";
|
|||||||
thisUser.goToChannel(e.state[1], false);
|
thisUser.goToChannel(e.state[1], false);
|
||||||
}
|
}
|
||||||
//console.log(e.state,"state:3")
|
//console.log(e.state,"state:3")
|
||||||
})
|
});
|
||||||
async function handleEnter(event: KeyboardEvent): Promise<void> {
|
async function handleEnter(event: KeyboardEvent): Promise<void> {
|
||||||
if(thisUser.keyup(event)){return}
|
if (thisUser.keyup(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const channel = thisUser.channelfocus;
|
const channel = thisUser.channelfocus;
|
||||||
if (!channel) return;
|
if (!channel) return;
|
||||||
if (markdown.rawString === "" && event.key === "ArrowUp") {
|
if (markdown.rawString === "" && event.key === "ArrowUp") {
|
||||||
@@ -193,14 +196,16 @@ import { I18n } from "./i18n.js";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CustomHTMLDivElement extends HTMLDivElement {markdown: MarkDown;}
|
interface CustomHTMLDivElement extends HTMLDivElement {
|
||||||
|
markdown: MarkDown;
|
||||||
|
}
|
||||||
|
|
||||||
const typebox = document.getElementById("typebox") as CustomHTMLDivElement;
|
const typebox = document.getElementById("typebox") as CustomHTMLDivElement;
|
||||||
const markdown = new MarkDown("", thisUser);
|
const markdown = new MarkDown("", thisUser);
|
||||||
typebox.markdown = markdown;
|
typebox.markdown = markdown;
|
||||||
typebox.addEventListener("keyup", handleEnter);
|
typebox.addEventListener("keyup", handleEnter);
|
||||||
typebox.addEventListener("keydown", event=>{
|
typebox.addEventListener("keydown", (event) => {
|
||||||
thisUser.keydown(event)
|
thisUser.keydown(event);
|
||||||
if (event.key === "Enter" && !event.shiftKey) event.preventDefault();
|
if (event.key === "Enter" && !event.shiftKey) event.preventDefault();
|
||||||
});
|
});
|
||||||
markdown.giveBox(typebox);
|
markdown.giveBox(typebox);
|
||||||
@@ -209,12 +214,11 @@ import { I18n } from "./i18n.js";
|
|||||||
const markdown = new MarkDown("", thisUser);
|
const markdown = new MarkDown("", thisUser);
|
||||||
searchBox.markdown = markdown;
|
searchBox.markdown = markdown;
|
||||||
|
|
||||||
searchBox.addEventListener("keydown", event=>{
|
searchBox.addEventListener("keydown", (event) => {
|
||||||
|
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
thisUser.mSearch(markdown.rawString)
|
thisUser.mSearch(markdown.rawString);
|
||||||
};
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
markdown.giveBox(searchBox);
|
markdown.giveBox(searchBox);
|
||||||
@@ -223,8 +227,6 @@ import { I18n } from "./i18n.js";
|
|||||||
span.textContent = e.replace("\n", "");
|
span.textContent = e.replace("\n", "");
|
||||||
return span;
|
return span;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
const images: Blob[] = [];
|
const images: Blob[] = [];
|
||||||
const imagesHtml: HTMLElement[] = [];
|
const imagesHtml: HTMLElement[] = [];
|
||||||
@@ -248,8 +250,7 @@ import { I18n } from "./i18n.js";
|
|||||||
thisUser.showusersettings();
|
thisUser.showusersettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
(document.getElementById("settings") as HTMLImageElement).onclick =
|
(document.getElementById("settings") as HTMLImageElement).onclick = userSettings;
|
||||||
userSettings;
|
|
||||||
|
|
||||||
if (mobile) {
|
if (mobile) {
|
||||||
const channelWrapper = document.getElementById("channelw") as HTMLDivElement;
|
const channelWrapper = document.getElementById("channelw") as HTMLDivElement;
|
||||||
@@ -260,7 +261,7 @@ import { I18n } from "./i18n.js";
|
|||||||
const memberListToggle = document.getElementById("memberlisttoggle") as HTMLInputElement;
|
const memberListToggle = document.getElementById("memberlisttoggle") as HTMLInputElement;
|
||||||
memberListToggle.checked = false;
|
memberListToggle.checked = false;
|
||||||
}
|
}
|
||||||
let dragendtimeout=setTimeout(()=>{})
|
let dragendtimeout = setTimeout(() => {});
|
||||||
document.addEventListener("dragover", (e) => {
|
document.addEventListener("dragover", (e) => {
|
||||||
clearTimeout(dragendtimeout);
|
clearTimeout(dragendtimeout);
|
||||||
const data = e.dataTransfer;
|
const data = e.dataTransfer;
|
||||||
@@ -283,12 +284,12 @@ import { I18n } from "./i18n.js";
|
|||||||
dragendtimeout = setTimeout(() => {
|
dragendtimeout = setTimeout(() => {
|
||||||
const bg = document.getElementById("gimmefile") as HTMLDivElement;
|
const bg = document.getElementById("gimmefile") as HTMLDivElement;
|
||||||
bg.hidden = true;
|
bg.hidden = true;
|
||||||
},1000)
|
}, 1000);
|
||||||
});
|
});
|
||||||
document.addEventListener("dragenter", (e) => {
|
document.addEventListener("dragenter", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
})
|
});
|
||||||
document.addEventListener("drop",e=>{
|
document.addEventListener("drop", (e) => {
|
||||||
const data = e.dataTransfer;
|
const data = e.dataTransfer;
|
||||||
const bg = document.getElementById("gimmefile") as HTMLDivElement;
|
const bg = document.getElementById("gimmefile") as HTMLDivElement;
|
||||||
bg.hidden = true;
|
bg.hidden = true;
|
||||||
@@ -311,8 +312,8 @@ import { I18n } from "./i18n.js";
|
|||||||
const input = document.createElement("input");
|
const input = document.createElement("input");
|
||||||
input.type = "file";
|
input.type = "file";
|
||||||
input.click();
|
input.click();
|
||||||
console.log("clicked")
|
console.log("clicked");
|
||||||
input.onchange=(() => {
|
input.onchange = () => {
|
||||||
if (input.files) {
|
if (input.files) {
|
||||||
for (const file of Array.from(input.files)) {
|
for (const file of Array.from(input.files)) {
|
||||||
const fileInstance = File.initFromBlob(file);
|
const fileInstance = File.initFromBlob(file);
|
||||||
@@ -322,7 +323,6 @@ import { I18n } from "./i18n.js";
|
|||||||
imagesHtml.push(html);
|
imagesHtml.push(html);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
class InfiniteScroller {
|
class InfiniteScroller {
|
||||||
readonly getIDFromOffset: (
|
readonly getIDFromOffset: (ID: string, offset: number) => Promise<string | undefined>;
|
||||||
ID: string,
|
|
||||||
offset: number
|
|
||||||
) => Promise<string | undefined>;
|
|
||||||
readonly getHTMLFromID: (ID: string) => Promise<HTMLElement>;
|
readonly getHTMLFromID: (ID: string) => Promise<HTMLElement>;
|
||||||
readonly destroyFromID: (ID: string) => Promise<boolean>;
|
readonly destroyFromID: (ID: string) => Promise<boolean>;
|
||||||
readonly reachesBottom: () => void;
|
readonly reachesBottom: () => void;
|
||||||
@@ -42,7 +39,7 @@ offset: number
|
|||||||
getIDFromOffset: InfiniteScroller["getIDFromOffset"],
|
getIDFromOffset: InfiniteScroller["getIDFromOffset"],
|
||||||
getHTMLFromID: InfiniteScroller["getHTMLFromID"],
|
getHTMLFromID: InfiniteScroller["getHTMLFromID"],
|
||||||
destroyFromID: InfiniteScroller["destroyFromID"],
|
destroyFromID: InfiniteScroller["destroyFromID"],
|
||||||
reachesBottom: InfiniteScroller["reachesBottom"] = ()=>{}
|
reachesBottom: InfiniteScroller["reachesBottom"] = () => {},
|
||||||
) {
|
) {
|
||||||
this.getIDFromOffset = getIDFromOffset;
|
this.getIDFromOffset = getIDFromOffset;
|
||||||
this.getHTMLFromID = getHTMLFromID;
|
this.getHTMLFromID = getHTMLFromID;
|
||||||
@@ -107,8 +104,7 @@ offset: number
|
|||||||
this.timeout = null;
|
this.timeout = null;
|
||||||
if (!this.div) return;
|
if (!this.div) return;
|
||||||
|
|
||||||
this.scrollBottom =
|
this.scrollBottom = this.div.scrollHeight - this.div.scrollTop - this.div.clientHeight;
|
||||||
this.div.scrollHeight - this.div.scrollTop - this.div.clientHeight;
|
|
||||||
this.averageheight = this.div.scrollHeight / this.HTMLElements.length;
|
this.averageheight = this.div.scrollHeight / this.HTMLElements.length;
|
||||||
if (this.averageheight < 10) {
|
if (this.averageheight < 10) {
|
||||||
this.averageheight = 60;
|
this.averageheight = 60;
|
||||||
@@ -147,10 +143,7 @@ offset: number
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async watchForTop(
|
private async watchForTop(already = false, fragment = new DocumentFragment()): Promise<boolean> {
|
||||||
already = false,
|
|
||||||
fragment = new DocumentFragment()
|
|
||||||
): Promise<boolean>{
|
|
||||||
if (!this.div) return false;
|
if (!this.div) return false;
|
||||||
try {
|
try {
|
||||||
let again = false;
|
let again = false;
|
||||||
@@ -173,7 +166,6 @@ offset: number
|
|||||||
fragment.prepend(html);
|
fragment.prepend(html);
|
||||||
this.HTMLElements.unshift([html, nextid]);
|
this.HTMLElements.unshift([html, nextid]);
|
||||||
this.scrollTop += this.averageheight;
|
this.scrollTop += this.averageheight;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.scrollTop > this.maxDist) {
|
if (this.scrollTop > this.maxDist) {
|
||||||
@@ -183,7 +175,6 @@ offset: number
|
|||||||
await this.destroyFromID(html[1]);
|
await this.destroyFromID(html[1]);
|
||||||
|
|
||||||
this.scrollTop -= this.averageheight;
|
this.scrollTop -= this.averageheight;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (again) {
|
if (again) {
|
||||||
@@ -201,10 +192,7 @@ offset: number
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async watchForBottom(
|
async watchForBottom(already = false, fragment = new DocumentFragment()): Promise<boolean> {
|
||||||
already = false,
|
|
||||||
fragment = new DocumentFragment()
|
|
||||||
): Promise<boolean>{
|
|
||||||
let func: Function | undefined;
|
let func: Function | undefined;
|
||||||
if (!already) func = this.snapBottom();
|
if (!already) func = this.snapBottom();
|
||||||
if (!this.div) return false;
|
if (!this.div) return false;
|
||||||
@@ -256,15 +244,14 @@ offset: number
|
|||||||
this.watchtime = false;
|
this.watchtime = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.changePromise = new Promise<boolean>(async res=>{
|
this.changePromise = new Promise<boolean>(async (res) => {
|
||||||
try {
|
try {
|
||||||
if (!this.div) {
|
if (!this.div) {
|
||||||
res(false);
|
res(false);
|
||||||
}
|
}
|
||||||
const out = (await Promise.allSettled([
|
const out = (await Promise.allSettled([this.watchForTop(), this.watchForBottom()])) as {
|
||||||
this.watchForTop(),
|
value: boolean;
|
||||||
this.watchForBottom(),
|
}[];
|
||||||
])) as { value: boolean }[];
|
|
||||||
const changed = out[0].value || out[1].value;
|
const changed = out[0].value || out[1].value;
|
||||||
if (this.timeout === null && changed) {
|
if (this.timeout === null && changed) {
|
||||||
this.timeout = setTimeout(this.updatestuff.bind(this), 300);
|
this.timeout = setTimeout(this.updatestuff.bind(this), 300);
|
||||||
@@ -298,11 +285,11 @@ offset: number
|
|||||||
behavior: "smooth",
|
behavior: "smooth",
|
||||||
block: "center",
|
block: "center",
|
||||||
});
|
});
|
||||||
await new Promise(resolve=>{
|
await new Promise((resolve) => {
|
||||||
setTimeout(resolve, 1000);
|
setTimeout(resolve, 1000);
|
||||||
});
|
});
|
||||||
element.classList.remove("jumped");
|
element.classList.remove("jumped");
|
||||||
await new Promise(resolve=>{
|
await new Promise((resolve) => {
|
||||||
setTimeout(resolve, 100);
|
setTimeout(resolve, 100);
|
||||||
});
|
});
|
||||||
element.classList.add("jumped");
|
element.classList.add("jumped");
|
||||||
@@ -319,7 +306,7 @@ offset: number
|
|||||||
await this.firstElement(id);
|
await this.firstElement(id);
|
||||||
this.updatestuff();
|
this.updatestuff();
|
||||||
await this.watchForChange();
|
await this.watchForChange();
|
||||||
await new Promise(resolve=>{
|
await new Promise((resolve) => {
|
||||||
setTimeout(resolve, 100);
|
setTimeout(resolve, 100);
|
||||||
});
|
});
|
||||||
await this.focus(id, true);
|
await this.focus(id, true);
|
||||||
|
|||||||
@@ -1,17 +1,26 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jank Client</title>
|
<title>Jank Client</title>
|
||||||
<meta content="Invite" property="og:title">
|
<meta content="Invite" property="og:title" />
|
||||||
<meta content="Accept this invite for a spacebar guild" property="og:description">
|
<meta content="Accept this invite for a spacebar guild" property="og:description" />
|
||||||
<meta name="description" content="You shouldn't see this, but this is an invite URL">
|
<meta name="description" content="You shouldn't see this, but this is an invite URL" />
|
||||||
<meta content="/logo.webp" property="og:image">
|
<meta content="/logo.webp" property="og:image" />
|
||||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||||
<link href="/style.css" rel="stylesheet">
|
<link href="/style.css" rel="stylesheet" />
|
||||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
<link href="/themes.css" rel="stylesheet" id="lightcss" />
|
||||||
<style>body.no-theme{background:#16191b;}@media(prefers-color-scheme:light){body.no-theme{background:#9397bd;}}</style>
|
<style>
|
||||||
|
body.no-theme {
|
||||||
|
background: #16191b;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
body.no-theme {
|
||||||
|
background: #9397bd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="no-theme">
|
<body class="no-theme">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -33,16 +33,15 @@ import { getBulkUsers, Specialuser } from "./utils/utils.js";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error("Someone needs to handle the case where the servers don't exist");
|
||||||
"Someone needs to handle the case where the servers don't exist"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
urls = joinable[0].serverurls;
|
urls = joinable[0].serverurls;
|
||||||
}
|
}
|
||||||
await I18n.done;
|
await I18n.done;
|
||||||
if (!joinable.length) {
|
if (!joinable.length) {
|
||||||
document.getElementById("AcceptInvite")!.textContent = I18n.getTranslation("htmlPages.noAccount");
|
document.getElementById("AcceptInvite")!.textContent =
|
||||||
|
I18n.getTranslation("htmlPages.noAccount");
|
||||||
}
|
}
|
||||||
|
|
||||||
const code = window.location.pathname.split("/")[2];
|
const code = window.location.pathname.split("/")[2];
|
||||||
@@ -51,14 +50,16 @@ import { getBulkUsers, Specialuser } from "./utils/utils.js";
|
|||||||
fetch(`${urls!.api}/invites/${code}`, {
|
fetch(`${urls!.api}/invites/${code}`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
})
|
})
|
||||||
.then(response=>response.json())
|
.then((response) => response.json())
|
||||||
.then(json=>{
|
.then((json) => {
|
||||||
const guildjson = json.guild;
|
const guildjson = json.guild;
|
||||||
guildinfo = guildjson;
|
guildinfo = guildjson;
|
||||||
document.getElementById("invitename")!.textContent = guildjson.name;
|
document.getElementById("invitename")!.textContent = guildjson.name;
|
||||||
document.getElementById(
|
document.getElementById("invitedescription")!.textContent = I18n.getTranslation(
|
||||||
"invitedescription"
|
"invite.longInvitedBy",
|
||||||
)!.textContent = I18n.getTranslation("invite.longInvitedBy",json.inviter.username,guildjson.name)
|
json.inviter.username,
|
||||||
|
guildjson.name,
|
||||||
|
);
|
||||||
if (guildjson.icon) {
|
if (guildjson.icon) {
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.src = `${urls!.cdn}/icons/${guildjson.id}/${guildjson.icon}.png`;
|
img.src = `${urls!.cdn}/icons/${guildjson.id}/${guildjson.icon}.png`;
|
||||||
@@ -95,9 +96,7 @@ document.getElementById("inviteimg")!.append(div);
|
|||||||
userDiv.append(document.createElement("br"));
|
userDiv.append(document.createElement("br"));
|
||||||
|
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = user.serverurls.wellknown
|
span.textContent = user.serverurls.wellknown.replace("https://", "").replace("http://", "");
|
||||||
.replace("https://", "")
|
|
||||||
.replace("http://", "");
|
|
||||||
span.classList.add("serverURL");
|
span.classList.add("serverURL");
|
||||||
userDiv.append(span);
|
userDiv.append(span);
|
||||||
|
|
||||||
@@ -142,7 +141,5 @@ document.getElementById("inviteimg")!.append(div);
|
|||||||
document.body.append(table);
|
document.body.append(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
document
|
document.getElementById("AcceptInvite")!.addEventListener("click", showAccounts);
|
||||||
.getElementById("AcceptInvite")!
|
|
||||||
.addEventListener("click", showAccounts);
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -63,7 +63,12 @@ type readyjson = {
|
|||||||
};
|
};
|
||||||
user_guild_settings: {
|
user_guild_settings: {
|
||||||
entries: {
|
entries: {
|
||||||
channel_overrides: {message_notifications: number,muted: boolean,mute_config: {selected_time_window: number,end_time: number},channel_id: string}[];
|
channel_overrides: {
|
||||||
|
message_notifications: number;
|
||||||
|
muted: boolean;
|
||||||
|
mute_config: {selected_time_window: number; end_time: number};
|
||||||
|
channel_id: string;
|
||||||
|
}[];
|
||||||
message_notifications: number;
|
message_notifications: number;
|
||||||
flags: number;
|
flags: number;
|
||||||
hide_muted_channels: boolean;
|
hide_muted_channels: boolean;
|
||||||
@@ -154,7 +159,7 @@ type memberjson = {
|
|||||||
guild: {
|
guild: {
|
||||||
id: string;
|
id: string;
|
||||||
} | null;
|
} | null;
|
||||||
presence?:presencejson
|
presence?: presencejson;
|
||||||
nick?: string;
|
nick?: string;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
joined_at: string;
|
joined_at: string;
|
||||||
@@ -171,16 +176,15 @@ type emojijson = {
|
|||||||
emoji?: string;
|
emoji?: string;
|
||||||
};
|
};
|
||||||
type emojipjson = emojijson & {
|
type emojipjson = emojijson & {
|
||||||
available: boolean,
|
available: boolean;
|
||||||
guild_id:string,
|
guild_id: string;
|
||||||
user_id:string,
|
user_id: string;
|
||||||
managed:boolean,
|
managed: boolean;
|
||||||
require_colons:boolean,
|
require_colons: boolean;
|
||||||
roles:string[],
|
roles: string[];
|
||||||
groups:null//TODO figure out what this means lol
|
groups: null; //TODO figure out what this means lol
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
type guildjson = {
|
type guildjson = {
|
||||||
application_command_counts: {[key: string]: number};
|
application_command_counts: {[key: string]: number};
|
||||||
channels: channeljson[];
|
channels: channeljson[];
|
||||||
@@ -405,16 +409,17 @@ type messageCreateJson = {
|
|||||||
t: "MESSAGE_CREATE";
|
t: "MESSAGE_CREATE";
|
||||||
};
|
};
|
||||||
type roleCreate = {
|
type roleCreate = {
|
||||||
op: 0,
|
op: 0;
|
||||||
t: "GUILD_ROLE_CREATE",
|
t: "GUILD_ROLE_CREATE";
|
||||||
d: {
|
d: {
|
||||||
guild_id: string,
|
guild_id: string;
|
||||||
role: rolesjson
|
role: rolesjson;
|
||||||
},
|
};
|
||||||
s: 6
|
s: 6;
|
||||||
}
|
};
|
||||||
type wsjson =
|
type wsjson =
|
||||||
roleCreate | {
|
| roleCreate
|
||||||
|
| {
|
||||||
op: 0;
|
op: 0;
|
||||||
d: any;
|
d: any;
|
||||||
s: number;
|
s: number;
|
||||||
@@ -492,77 +497,89 @@ roleCreate | {
|
|||||||
emoji: emojijson;
|
emoji: emojijson;
|
||||||
};
|
};
|
||||||
s: number;
|
s: number;
|
||||||
}|{
|
}
|
||||||
op: 0,
|
| {
|
||||||
t: "GUILD_ROLE_UPDATE",
|
op: 0;
|
||||||
|
t: "GUILD_ROLE_UPDATE";
|
||||||
d: {
|
d: {
|
||||||
guild_id: string,
|
guild_id: string;
|
||||||
role: rolesjson
|
role: rolesjson;
|
||||||
},
|
};
|
||||||
"s": number
|
s: number;
|
||||||
}|{
|
}
|
||||||
op: 0,
|
| {
|
||||||
t: "GUILD_ROLE_DELETE",
|
op: 0;
|
||||||
d: {
|
t: "GUILD_ROLE_DELETE";
|
||||||
guild_id: string,
|
d: {
|
||||||
role_id: string
|
guild_id: string;
|
||||||
},
|
role_id: string;
|
||||||
s:number
|
};
|
||||||
}|{
|
s: number;
|
||||||
op: 0,
|
}
|
||||||
t: "GUILD_MEMBER_UPDATE",
|
| {
|
||||||
d: memberjson,
|
op: 0;
|
||||||
s: 3
|
t: "GUILD_MEMBER_UPDATE";
|
||||||
}|{
|
d: memberjson;
|
||||||
op:9,
|
s: 3;
|
||||||
d:boolean,
|
}
|
||||||
s:number
|
| {
|
||||||
}|memberlistupdatejson|voiceupdate|voiceserverupdate|{
|
op: 9;
|
||||||
op: 0,
|
d: boolean;
|
||||||
t: "RELATIONSHIP_ADD",
|
s: number;
|
||||||
d: {
|
}
|
||||||
id: string,
|
| memberlistupdatejson
|
||||||
type: 0|1|2|3|4|5|6,
|
| voiceupdate
|
||||||
user: userjson
|
| voiceserverupdate
|
||||||
},
|
| {
|
||||||
s: number
|
op: 0;
|
||||||
}|{
|
t: "RELATIONSHIP_ADD";
|
||||||
op: 0,
|
d: {
|
||||||
t: "RELATIONSHIP_REMOVE",
|
id: string;
|
||||||
d: {
|
type: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
||||||
id: string,
|
user: userjson;
|
||||||
type: number,
|
};
|
||||||
nickname: null
|
s: number;
|
||||||
},
|
}
|
||||||
s: number
|
| {
|
||||||
}|{
|
op: 0;
|
||||||
op: 0,
|
t: "RELATIONSHIP_REMOVE";
|
||||||
t: "PRESENCE_UPDATE",
|
d: {
|
||||||
d: presencejson,
|
id: string;
|
||||||
s:number
|
type: number;
|
||||||
}|{
|
nickname: null;
|
||||||
op:0,
|
};
|
||||||
t:"GUILD_MEMBER_ADD",
|
s: number;
|
||||||
d:memberjson,
|
}
|
||||||
s:number
|
| {
|
||||||
}|{
|
op: 0;
|
||||||
op:0,
|
t: "PRESENCE_UPDATE";
|
||||||
t:"GUILD_MEMBER_REMOVE",
|
d: presencejson;
|
||||||
d:{
|
s: number;
|
||||||
guild_id:string,
|
}
|
||||||
user:userjson
|
| {
|
||||||
},
|
op: 0;
|
||||||
s:number
|
t: "GUILD_MEMBER_ADD";
|
||||||
}|{
|
d: memberjson;
|
||||||
op: 0,
|
s: number;
|
||||||
t: "GUILD_EMOJIS_UPDATE",
|
}
|
||||||
d: {
|
| {
|
||||||
guild_id: string,
|
op: 0;
|
||||||
emojis: emojipjson[]
|
t: "GUILD_MEMBER_REMOVE";
|
||||||
},
|
d: {
|
||||||
s: number
|
guild_id: string;
|
||||||
|
user: userjson;
|
||||||
|
};
|
||||||
|
s: number;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
op: 0;
|
||||||
|
t: "GUILD_EMOJIS_UPDATE";
|
||||||
|
d: {
|
||||||
|
guild_id: string;
|
||||||
|
emojis: emojipjson[];
|
||||||
|
};
|
||||||
|
s: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
type memberChunk = {
|
type memberChunk = {
|
||||||
guild_id: string;
|
guild_id: string;
|
||||||
@@ -574,132 +591,138 @@ type memberChunk = {
|
|||||||
not_found: string[];
|
not_found: string[];
|
||||||
};
|
};
|
||||||
type voiceupdate = {
|
type voiceupdate = {
|
||||||
op: 0,
|
op: 0;
|
||||||
t: "VOICE_STATE_UPDATE",
|
t: "VOICE_STATE_UPDATE";
|
||||||
d: {
|
d: {
|
||||||
guild_id: string,
|
guild_id: string;
|
||||||
channel_id: string,
|
channel_id: string;
|
||||||
user_id: string,
|
user_id: string;
|
||||||
member: memberjson,
|
member: memberjson;
|
||||||
session_id: string,
|
session_id: string;
|
||||||
token: string,
|
token: string;
|
||||||
deaf: boolean,
|
deaf: boolean;
|
||||||
mute: boolean,
|
mute: boolean;
|
||||||
self_deaf: boolean,
|
self_deaf: boolean;
|
||||||
self_mute: boolean,
|
self_mute: boolean;
|
||||||
self_video: boolean,
|
self_video: boolean;
|
||||||
suppress: boolean
|
suppress: boolean;
|
||||||
},
|
};
|
||||||
s: number
|
s: number;
|
||||||
};
|
};
|
||||||
type voiceserverupdate = {
|
type voiceserverupdate = {
|
||||||
op: 0,
|
op: 0;
|
||||||
t: "VOICE_SERVER_UPDATE",
|
t: "VOICE_SERVER_UPDATE";
|
||||||
d: {
|
d: {
|
||||||
token: string,
|
token: string;
|
||||||
guild_id: string,
|
guild_id: string;
|
||||||
endpoint: string
|
endpoint: string;
|
||||||
},
|
};
|
||||||
s: 6
|
s: 6;
|
||||||
};
|
};
|
||||||
type memberlistupdatejson = {
|
type memberlistupdatejson = {
|
||||||
op: 0,
|
op: 0;
|
||||||
s: number,
|
s: number;
|
||||||
t: "GUILD_MEMBER_LIST_UPDATE",
|
t: "GUILD_MEMBER_LIST_UPDATE";
|
||||||
d: {
|
d: {
|
||||||
ops: [
|
ops: [
|
||||||
{
|
{
|
||||||
items:({
|
items: (
|
||||||
|
| {
|
||||||
group: {
|
group: {
|
||||||
count:number,
|
count: number;
|
||||||
id:string
|
id: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}|{
|
| {
|
||||||
member:memberjson
|
member: memberjson;
|
||||||
})[]
|
|
||||||
op: "SYNC",
|
|
||||||
range: [
|
|
||||||
number,
|
|
||||||
number
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
)[];
|
||||||
online_count: number,
|
op: "SYNC";
|
||||||
member_count: number,
|
range: [number, number];
|
||||||
id: string,
|
},
|
||||||
guild_id: string,
|
];
|
||||||
|
online_count: number;
|
||||||
|
member_count: number;
|
||||||
|
id: string;
|
||||||
|
guild_id: string;
|
||||||
groups: {
|
groups: {
|
||||||
count: number,
|
count: number;
|
||||||
id: string
|
id: string;
|
||||||
}[]
|
}[];
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
type webRTCSocket= {
|
type webRTCSocket =
|
||||||
op: 8,
|
| {
|
||||||
|
op: 8;
|
||||||
d: {
|
d: {
|
||||||
heartbeat_interval: number
|
heartbeat_interval: number;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}|{
|
| {
|
||||||
op:6,
|
op: 6;
|
||||||
d:{t: number}
|
d: {t: number};
|
||||||
}|{
|
}
|
||||||
op: 2,
|
| {
|
||||||
|
op: 2;
|
||||||
d: {
|
d: {
|
||||||
ssrc: number,
|
ssrc: number;
|
||||||
"streams": {
|
streams: {
|
||||||
type: "video",//probally more options, but idk
|
type: "video"; //probally more options, but idk
|
||||||
rid: string,
|
rid: string;
|
||||||
quality: number,
|
quality: number;
|
||||||
ssrc: number,
|
ssrc: number;
|
||||||
rtx_ssrc:number
|
rtx_ssrc: number;
|
||||||
}[],
|
}[];
|
||||||
ip: number,
|
ip: number;
|
||||||
port: number,
|
port: number;
|
||||||
"modes": [],//no clue
|
modes: []; //no clue
|
||||||
"experiments": []//no clue
|
experiments: []; //no clue
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}|sdpback|opRTC12|{
|
| sdpback
|
||||||
op: 5,
|
| opRTC12
|
||||||
|
| {
|
||||||
|
op: 5;
|
||||||
d: {
|
d: {
|
||||||
user_id: string,
|
user_id: string;
|
||||||
speaking: 0,
|
speaking: 0;
|
||||||
ssrc: 940464811
|
ssrc: 940464811;
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
type sdpback = {
|
type sdpback = {
|
||||||
op: 4,
|
op: 4;
|
||||||
d: {
|
d: {
|
||||||
audioCodec: string,
|
audioCodec: string;
|
||||||
videoCodec: string,
|
videoCodec: string;
|
||||||
media_session_id: string,
|
media_session_id: string;
|
||||||
sdp: string
|
sdp: string;
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
type opRTC12 = {
|
type opRTC12 = {
|
||||||
op: 12,
|
op: 12;
|
||||||
d: {
|
d: {
|
||||||
user_id: string,
|
user_id: string;
|
||||||
audio_ssrc: number,
|
audio_ssrc: number;
|
||||||
video_ssrc: number,
|
video_ssrc: number;
|
||||||
streams: [
|
streams: [
|
||||||
{
|
{
|
||||||
type: "video",
|
type: "video";
|
||||||
rid: "100",
|
rid: "100";
|
||||||
ssrc: number,
|
ssrc: number;
|
||||||
active: boolean,
|
active: boolean;
|
||||||
quality: 100,
|
quality: 100;
|
||||||
rtx_ssrc: number,
|
rtx_ssrc: number;
|
||||||
max_bitrate: 2500000,
|
max_bitrate: 2500000;
|
||||||
max_framerate: number,
|
max_framerate: number;
|
||||||
max_resolution: {
|
max_resolution: {
|
||||||
type: "fixed",
|
type: "fixed";
|
||||||
width: number,
|
width: number;
|
||||||
height: number
|
height: number;
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
export {
|
export {
|
||||||
readyjson,
|
readyjson,
|
||||||
dirrectjson,
|
dirrectjson,
|
||||||
@@ -725,5 +748,5 @@ export{
|
|||||||
webRTCSocket,
|
webRTCSocket,
|
||||||
sdpback,
|
sdpback,
|
||||||
opRTC12,
|
opRTC12,
|
||||||
emojipjson
|
emojipjson,
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,25 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jank Client</title>
|
<title>Jank Client</title>
|
||||||
<meta content="Jank Client" property="og:title">
|
<meta content="Jank Client" property="og:title" />
|
||||||
<meta
|
<meta content="A spacebar client that has DMs, replying and more" property="og:description" />
|
||||||
content="A spacebar client that has DMs, replying and more"
|
<meta content="/logo.webp" property="og:image" />
|
||||||
property="og:description"
|
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||||
>
|
<link href="/style.css" rel="stylesheet" />
|
||||||
<meta content="/logo.webp" property="og:image">
|
<link href="/themes.css" rel="stylesheet" id="lightcss" />
|
||||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
<style>
|
||||||
<link href="/style.css" rel="stylesheet">
|
body.no-theme {
|
||||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
background: #16191b;
|
||||||
<style>body.no-theme{background:#16191b;}@media(prefers-color-scheme:light){body.no-theme{background:#9397bd;}}</style>
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
body.no-theme {
|
||||||
|
background: #9397bd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="no-theme">
|
<body class="no-theme">
|
||||||
<div id="logindiv">
|
<div id="logindiv">
|
||||||
@@ -29,25 +35,13 @@
|
|||||||
id="instancein"
|
id="instancein"
|
||||||
value=""
|
value=""
|
||||||
required
|
required
|
||||||
>
|
/>
|
||||||
|
|
||||||
<label for="uname" id="emailField"><b>Email:</b></label>
|
<label for="uname" id="emailField"><b>Email:</b></label>
|
||||||
<input
|
<input type="text" placeholder="Enter email address" name="uname" id="uname" required />
|
||||||
type="text"
|
|
||||||
placeholder="Enter email address"
|
|
||||||
name="uname"
|
|
||||||
id="uname"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
|
|
||||||
<label for="psw" id="pwField"><b>Password:</b></label>
|
<label for="psw" id="pwField"><b>Password:</b></label>
|
||||||
<input
|
<input type="password" placeholder="Enter Password" name="psw" id="psw" required />
|
||||||
type="password"
|
|
||||||
placeholder="Enter Password"
|
|
||||||
name="psw"
|
|
||||||
id="psw"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<p class="wrongred" id="wrong"></p>
|
<p class="wrongred" id="wrong"></p>
|
||||||
|
|
||||||
<div id="h-captcha"></div>
|
<div id="h-captcha"></div>
|
||||||
|
|||||||
@@ -3,19 +3,15 @@ import { I18n } from "./i18n.js";
|
|||||||
import {Dialog, FormError} from "./settings.js";
|
import {Dialog, FormError} from "./settings.js";
|
||||||
import {checkInstance} from "./utils/utils.js";
|
import {checkInstance} from "./utils/utils.js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
await I18n.done;
|
await I18n.done;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await I18n.done
|
await I18n.done;
|
||||||
const instanceField = document.getElementById("instanceField");
|
const instanceField = document.getElementById("instanceField");
|
||||||
const emailField = document.getElementById("emailField");
|
const emailField = document.getElementById("emailField");
|
||||||
const pwField = document.getElementById("pwField");
|
const pwField = document.getElementById("pwField");
|
||||||
const loginButton = document.getElementById("loginButton");
|
const loginButton = document.getElementById("loginButton");
|
||||||
const noAccount=document.getElementById("switch")
|
const noAccount = document.getElementById("switch");
|
||||||
if (instanceField && emailField && pwField && loginButton && noAccount) {
|
if (instanceField && emailField && pwField && loginButton && noAccount) {
|
||||||
instanceField.textContent = I18n.getTranslation("htmlPages.instanceField");
|
instanceField.textContent = I18n.getTranslation("htmlPages.instanceField");
|
||||||
emailField.textContent = I18n.getTranslation("htmlPages.emailField");
|
emailField.textContent = I18n.getTranslation("htmlPages.emailField");
|
||||||
@@ -23,8 +19,7 @@ await I18n.done;
|
|||||||
loginButton.textContent = I18n.getTranslation("htmlPages.loginButton");
|
loginButton.textContent = I18n.getTranslation("htmlPages.loginButton");
|
||||||
noAccount.textContent = I18n.getTranslation("htmlPages.noAccount");
|
noAccount.textContent = I18n.getTranslation("htmlPages.noAccount");
|
||||||
}
|
}
|
||||||
})()
|
})();
|
||||||
|
|
||||||
|
|
||||||
function trimswitcher() {
|
function trimswitcher() {
|
||||||
const json = getBulkInfo();
|
const json = getBulkInfo();
|
||||||
@@ -59,8 +54,6 @@ function trimswitcher(){
|
|||||||
console.log(json);
|
console.log(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function adduser(user: typeof Specialuser.prototype.json) {
|
function adduser(user: typeof Specialuser.prototype.json) {
|
||||||
user = new Specialuser(user);
|
user = new Specialuser(user);
|
||||||
const info = getBulkInfo();
|
const info = getBulkInfo();
|
||||||
@@ -73,8 +66,6 @@ const instancein = document.getElementById("instancein") as HTMLInputElement;
|
|||||||
let timeout: ReturnType<typeof setTimeout> | string | number | undefined | null = null;
|
let timeout: ReturnType<typeof setTimeout> | string | number | undefined | null = null;
|
||||||
// let instanceinfo;
|
// let instanceinfo;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (instancein) {
|
if (instancein) {
|
||||||
console.log(instancein);
|
console.log(instancein);
|
||||||
instancein.addEventListener("keydown", () => {
|
instancein.addEventListener("keydown", () => {
|
||||||
@@ -117,8 +108,8 @@ async function login(username: string, password: string, captcha: string){
|
|||||||
const info = JSON.parse(localStorage.getItem("instanceinfo")!);
|
const info = JSON.parse(localStorage.getItem("instanceinfo")!);
|
||||||
const api = info.login + (info.login.startsWith("/") ? "/" : "");
|
const api = info.login + (info.login.startsWith("/") ? "/" : "");
|
||||||
return await fetch(api + "/auth/login", options)
|
return await fetch(api + "/auth/login", options)
|
||||||
.then(response=>response.json())
|
.then((response) => response.json())
|
||||||
.then(response=>{
|
.then((response) => {
|
||||||
console.log(response, response.message);
|
console.log(response, response.message);
|
||||||
if (response.message === "Invalid Form Body") {
|
if (response.message === "Invalid Form Body") {
|
||||||
return response.errors.login._errors[0].message;
|
return response.errors.login._errors[0].message;
|
||||||
@@ -145,7 +136,9 @@ async function login(username: string, password: string, captcha: string){
|
|||||||
console.log(response);
|
console.log(response);
|
||||||
if (response.ticket) {
|
if (response.ticket) {
|
||||||
const better = new Dialog("");
|
const better = new Dialog("");
|
||||||
const form=better.options.addForm("",(res:any)=>{
|
const form = better.options.addForm(
|
||||||
|
"",
|
||||||
|
(res: any) => {
|
||||||
if (res.message) {
|
if (res.message) {
|
||||||
throw new FormError(ti, res.message);
|
throw new FormError(ti, res.message);
|
||||||
} else {
|
} else {
|
||||||
@@ -156,25 +149,25 @@ async function login(username: string, password: string, captcha: string){
|
|||||||
email: username,
|
email: username,
|
||||||
token: res.token,
|
token: res.token,
|
||||||
}).username = username;
|
}).username = username;
|
||||||
const redir = new URLSearchParams(
|
const redir = new URLSearchParams(window.location.search).get("goback");
|
||||||
window.location.search
|
|
||||||
).get("goback");
|
|
||||||
if (redir) {
|
if (redir) {
|
||||||
window.location.href = redir;
|
window.location.href = redir;
|
||||||
} else {
|
} else {
|
||||||
window.location.href = "/channels/@me";
|
window.location.href = "/channels/@me";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
fetchURL: api + "/auth/mfa/totp",
|
fetchURL: api + "/auth/mfa/totp",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
form.addTitle(I18n.getTranslation("2faCode"));
|
form.addTitle(I18n.getTranslation("2faCode"));
|
||||||
const ti = form.addTextInput("", "code");
|
const ti = form.addTextInput("", "code");
|
||||||
better.show()
|
better.show();
|
||||||
} else {
|
} else {
|
||||||
console.warn(response);
|
console.warn(response);
|
||||||
if (!response.token) return;
|
if (!response.token) return;
|
||||||
@@ -183,9 +176,7 @@ async function login(username: string, password: string, captcha: string){
|
|||||||
email: username,
|
email: username,
|
||||||
token: response.token,
|
token: response.token,
|
||||||
}).username = username;
|
}).username = username;
|
||||||
const redir = new URLSearchParams(window.location.search).get(
|
const redir = new URLSearchParams(window.location.search).get("goback");
|
||||||
"goback"
|
|
||||||
);
|
|
||||||
if (redir) {
|
if (redir) {
|
||||||
window.location.href = redir;
|
window.location.href = redir;
|
||||||
} else {
|
} else {
|
||||||
@@ -206,7 +197,7 @@ async function check(e: SubmitEvent){
|
|||||||
const h = await login(
|
const h = await login(
|
||||||
(target[1] as HTMLInputElement).value,
|
(target[1] as HTMLInputElement).value,
|
||||||
(target[2] as HTMLInputElement).value,
|
(target[2] as HTMLInputElement).value,
|
||||||
(target[3] as HTMLInputElement).value
|
(target[3] as HTMLInputElement).value,
|
||||||
);
|
);
|
||||||
const wrongElement = document.getElementById("wrong");
|
const wrongElement = document.getElementById("wrong");
|
||||||
if (wrongElement) {
|
if (wrongElement) {
|
||||||
@@ -237,11 +228,4 @@ if(switchurl){
|
|||||||
}
|
}
|
||||||
trimswitcher();
|
trimswitcher();
|
||||||
|
|
||||||
export{
|
export {adduser};
|
||||||
adduser,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class MarkDown{
|
|||||||
constructor(
|
constructor(
|
||||||
text: string | string[],
|
text: string | string[],
|
||||||
owner: MarkDown["owner"],
|
owner: MarkDown["owner"],
|
||||||
{ keep = false, stdsize = false } = {}
|
{keep = false, stdsize = false} = {},
|
||||||
) {
|
) {
|
||||||
if (typeof text === typeof "") {
|
if (typeof text === typeof "") {
|
||||||
this.txt = (text as string).split("");
|
this.txt = (text as string).split("");
|
||||||
@@ -300,7 +300,8 @@ class MarkDown{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
find === count &&(count != 1 ||txt[j + 1] === " " ||txt[j + 1] === "\n" ||txt[j + 1] === undefined)
|
find === count &&
|
||||||
|
(count != 1 || txt[j + 1] === " " || txt[j + 1] === "\n" || txt[j + 1] === undefined)
|
||||||
) {
|
) {
|
||||||
appendcurrent();
|
appendcurrent();
|
||||||
i = j;
|
i = j;
|
||||||
@@ -442,10 +443,10 @@ class MarkDown{
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if((txt[i] === "<" && (txt[i + 1] === "@" || txt[i + 1] === "#"))&&this.localuser){
|
if (txt[i] === "<" && (txt[i + 1] === "@" || txt[i + 1] === "#") && this.localuser) {
|
||||||
let id = "";
|
let id = "";
|
||||||
let j = i + 2;
|
let j = i + 2;
|
||||||
const numbers = new Set(["0","1","2","3","4","5","6","7","8","9",]);
|
const numbers = new Set(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
|
||||||
for (; txt[j] !== undefined; j++) {
|
for (; txt[j] !== undefined; j++) {
|
||||||
const char = txt[j];
|
const char = txt[j];
|
||||||
if (!numbers.has(char)) {
|
if (!numbers.has(char)) {
|
||||||
@@ -474,7 +475,7 @@ class MarkDown{
|
|||||||
user.bind(mention, guild);
|
user.bind(mention, guild);
|
||||||
}
|
}
|
||||||
if (guild) {
|
if (guild) {
|
||||||
Member.resolveMember(user, guild).then(member=>{
|
Member.resolveMember(user, guild).then((member) => {
|
||||||
if (member) {
|
if (member) {
|
||||||
mention.textContent = `@${member.name}`;
|
mention.textContent = `@${member.name}`;
|
||||||
}
|
}
|
||||||
@@ -489,7 +490,7 @@ class MarkDown{
|
|||||||
if (channel) {
|
if (channel) {
|
||||||
mention.textContent = `#${channel.name}`;
|
mention.textContent = `#${channel.name}`;
|
||||||
if (!keep) {
|
if (!keep) {
|
||||||
mention.onclick = _=>{
|
mention.onclick = (_) => {
|
||||||
if (!this.localuser) return;
|
if (!this.localuser) return;
|
||||||
this.localuser.goToChannel(id);
|
this.localuser.goToChannel(id);
|
||||||
};
|
};
|
||||||
@@ -576,7 +577,9 @@ class MarkDown{
|
|||||||
second: "2-digit",
|
second: "2-digit",
|
||||||
});
|
});
|
||||||
else if (parts[3] === "R")
|
else if (parts[3] === "R")
|
||||||
time =Math.round((Date.now() - Number.parseInt(parts[1]) * 1000) / 1000 / 60) + " minutes ago";
|
time =
|
||||||
|
Math.round((Date.now() - Number.parseInt(parts[1]) * 1000) / 1000 / 60) +
|
||||||
|
" minutes ago";
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeElem = document.createElement("span");
|
const timeElem = document.createElement("span");
|
||||||
@@ -587,7 +590,10 @@ class MarkDown{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(txt[i] === "<" && (txt[i + 1] === ":" || (txt[i + 1] === "a" && txt[i + 2] === ":")&&this.owner)){
|
if (
|
||||||
|
txt[i] === "<" &&
|
||||||
|
(txt[i + 1] === ":" || (txt[i + 1] === "a" && txt[i + 2] === ":" && this.owner))
|
||||||
|
) {
|
||||||
let found = false;
|
let found = false;
|
||||||
const build = txt[i + 1] === "a" ? ["<", "a", ":"] : ["<", ":"];
|
const build = txt[i + 1] === "a" ? ["<", "a", ":"] : ["<", ":"];
|
||||||
let j = i + build.length;
|
let j = i + build.length;
|
||||||
@@ -611,7 +617,7 @@ class MarkDown{
|
|||||||
if (!owner) continue;
|
if (!owner) continue;
|
||||||
const emoji = new Emoji(
|
const emoji = new Emoji(
|
||||||
{name: buildjoin, id: parts[2], animated: Boolean(parts[1])},
|
{name: buildjoin, id: parts[2], animated: Boolean(parts[1])},
|
||||||
owner
|
owner,
|
||||||
);
|
);
|
||||||
span.appendChild(emoji.getHTML(isEmojiOnly));
|
span.appendChild(emoji.getHTML(isEmojiOnly));
|
||||||
|
|
||||||
@@ -649,9 +655,7 @@ class MarkDown{
|
|||||||
if (partsFound === 2) {
|
if (partsFound === 2) {
|
||||||
appendcurrent();
|
appendcurrent();
|
||||||
|
|
||||||
const parts = build
|
const parts = build.join("").match(/^\[(.+)\]\((https?:.+?)( ('|").+('|"))?\)$/);
|
||||||
.join("")
|
|
||||||
.match(/^\[(.+)\]\((https?:.+?)( ('|").+('|"))?\)$/);
|
|
||||||
if (parts) {
|
if (parts) {
|
||||||
const linkElem = document.createElement("a");
|
const linkElem = document.createElement("a");
|
||||||
if (URL.canParse(parts[2])) {
|
if (URL.canParse(parts[2])) {
|
||||||
@@ -661,9 +665,7 @@ class MarkDown{
|
|||||||
linkElem.target = "_blank";
|
linkElem.target = "_blank";
|
||||||
linkElem.rel = "noopener noreferrer";
|
linkElem.rel = "noopener noreferrer";
|
||||||
linkElem.title =
|
linkElem.title =
|
||||||
(parts[3]
|
(parts[3] ? parts[3].substring(2, parts[3].length - 1) + "\n\n" : "") + parts[2];
|
||||||
? parts[3].substring(2, parts[3].length - 1) + "\n\n"
|
|
||||||
: "") + parts[2];
|
|
||||||
span.appendChild(linkElem);
|
span.appendChild(linkElem);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -686,11 +688,11 @@ class MarkDown{
|
|||||||
giveBox(box: HTMLDivElement, onUpdate: (upto: string, pre: boolean) => unknown = () => {}) {
|
giveBox(box: HTMLDivElement, onUpdate: (upto: string, pre: boolean) => unknown = () => {}) {
|
||||||
this.box = new WeakRef(box);
|
this.box = new WeakRef(box);
|
||||||
this.onUpdate = onUpdate;
|
this.onUpdate = onUpdate;
|
||||||
box.onkeydown = _=>{
|
box.onkeydown = (_) => {
|
||||||
//console.log(_);
|
//console.log(_);
|
||||||
};
|
};
|
||||||
let prevcontent = "";
|
let prevcontent = "";
|
||||||
box.onkeyup = _=>{
|
box.onkeyup = (_) => {
|
||||||
const content = MarkDown.gatherBoxText(box);
|
const content = MarkDown.gatherBoxText(box);
|
||||||
if (content !== prevcontent) {
|
if (content !== prevcontent) {
|
||||||
prevcontent = content;
|
prevcontent = content;
|
||||||
@@ -698,9 +700,8 @@ class MarkDown{
|
|||||||
this.boxupdate();
|
this.boxupdate();
|
||||||
MarkDown.gatherBoxText(box);
|
MarkDown.gatherBoxText(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
box.onpaste = _=>{
|
box.onpaste = (_) => {
|
||||||
if (!_.clipboardData) return;
|
if (!_.clipboardData) return;
|
||||||
console.log(_.clipboardData.types);
|
console.log(_.clipboardData.types);
|
||||||
const data = _.clipboardData.getData("text");
|
const data = _.clipboardData.getData("text");
|
||||||
@@ -711,11 +712,14 @@ class MarkDown{
|
|||||||
box.onkeyup(new KeyboardEvent("_"));
|
box.onkeyup(new KeyboardEvent("_"));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
customBox?:[(arg1:string)=>HTMLElement,((arg1:HTMLElement)=>string)];
|
customBox?: [(arg1: string) => HTMLElement, (arg1: HTMLElement) => string];
|
||||||
clearCustom() {
|
clearCustom() {
|
||||||
this.customBox = undefined;
|
this.customBox = undefined;
|
||||||
}
|
}
|
||||||
setCustomBox(stringToHTML:(arg1:string)=>HTMLElement,HTMLToString=MarkDown.gatherBoxText.bind(MarkDown)){
|
setCustomBox(
|
||||||
|
stringToHTML: (arg1: string) => HTMLElement,
|
||||||
|
HTMLToString = MarkDown.gatherBoxText.bind(MarkDown),
|
||||||
|
) {
|
||||||
this.customBox = [stringToHTML, HTMLToString];
|
this.customBox = [stringToHTML, HTMLToString];
|
||||||
}
|
}
|
||||||
boxupdate(offset = 0) {
|
boxupdate(offset = 0) {
|
||||||
@@ -725,7 +729,7 @@ class MarkDown{
|
|||||||
if (this.customBox) {
|
if (this.customBox) {
|
||||||
restore = saveCaretPosition(box, offset, this.customBox[1]);
|
restore = saveCaretPosition(box, offset, this.customBox[1]);
|
||||||
} else {
|
} else {
|
||||||
restore= saveCaretPosition(box,offset)
|
restore = saveCaretPosition(box, offset);
|
||||||
}
|
}
|
||||||
box.innerHTML = "";
|
box.innerHTML = "";
|
||||||
if (this.customBox) {
|
if (this.customBox) {
|
||||||
@@ -784,7 +788,7 @@ class MarkDown{
|
|||||||
elm.target = "_blank";
|
elm.target = "_blank";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
elm.onmouseup = _=>{
|
elm.onmouseup = (_) => {
|
||||||
if (_.button === 2) return;
|
if (_.button === 2) return;
|
||||||
console.log(":3");
|
console.log(":3");
|
||||||
function open() {
|
function open() {
|
||||||
@@ -833,7 +837,11 @@ class MarkDown{
|
|||||||
//solution from https://stackoverflow.com/questions/4576694/saving-and-restoring-caret-position-for-contenteditable-div
|
//solution from https://stackoverflow.com/questions/4576694/saving-and-restoring-caret-position-for-contenteditable-div
|
||||||
let text = "";
|
let text = "";
|
||||||
let formatted = false;
|
let formatted = false;
|
||||||
function saveCaretPosition(context: HTMLElement,offset=0,txtLengthFunc=MarkDown.gatherBoxText.bind(MarkDown)){
|
function saveCaretPosition(
|
||||||
|
context: HTMLElement,
|
||||||
|
offset = 0,
|
||||||
|
txtLengthFunc = MarkDown.gatherBoxText.bind(MarkDown),
|
||||||
|
) {
|
||||||
const selection = window.getSelection() as Selection;
|
const selection = window.getSelection() as Selection;
|
||||||
if (!selection) return;
|
if (!selection) return;
|
||||||
try {
|
try {
|
||||||
@@ -854,7 +862,7 @@ function saveCaretPosition(context: HTMLElement,offset=0,txtLengthFunc=MarkDown.
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (base instanceof HTMLElement) {
|
if (base instanceof HTMLElement) {
|
||||||
baseString=txtLengthFunc(base)
|
baseString = txtLengthFunc(base);
|
||||||
} else {
|
} else {
|
||||||
baseString = base.textContent as string;
|
baseString = base.textContent as string;
|
||||||
}
|
}
|
||||||
@@ -862,7 +870,6 @@ function saveCaretPosition(context: HTMLElement,offset=0,txtLengthFunc=MarkDown.
|
|||||||
baseString = selection.toString();
|
baseString = selection.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
range.setStart(context, 0);
|
range.setStart(context, 0);
|
||||||
|
|
||||||
let build = "";
|
let build = "";
|
||||||
@@ -885,7 +892,6 @@ function saveCaretPosition(context: HTMLElement,offset=0,txtLengthFunc=MarkDown.
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const node of children as Node[]) {
|
for (const node of children as Node[]) {
|
||||||
|
|
||||||
if (selection.containsNode(node, false)) {
|
if (selection.containsNode(node, false)) {
|
||||||
if (node instanceof HTMLElement) {
|
if (node instanceof HTMLElement) {
|
||||||
build += txtLengthFunc(node);
|
build += txtLengthFunc(node);
|
||||||
@@ -896,7 +902,7 @@ function saveCaretPosition(context: HTMLElement,offset=0,txtLengthFunc=MarkDown.
|
|||||||
if (node instanceof HTMLElement) {
|
if (node instanceof HTMLElement) {
|
||||||
crawlForText(node);
|
crawlForText(node);
|
||||||
} else {
|
} else {
|
||||||
console.error(node,"This shouldn't happen")
|
console.error(node, "This shouldn't happen");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//console.error(node,"This shouldn't happen");
|
//console.error(node,"This shouldn't happen");
|
||||||
@@ -909,7 +915,7 @@ function saveCaretPosition(context: HTMLElement,offset=0,txtLengthFunc=MarkDown.
|
|||||||
}
|
}
|
||||||
text = build;
|
text = build;
|
||||||
let len = build.length + offset;
|
let len = build.length + offset;
|
||||||
len=Math.min(len,txtLengthFunc(context).length)
|
len = Math.min(len, txtLengthFunc(context).length);
|
||||||
return function restore() {
|
return function restore() {
|
||||||
if (!selection) return;
|
if (!selection) return;
|
||||||
const pos = getTextNodeAtPosition(context, len, txtLengthFunc);
|
const pos = getTextNodeAtPosition(context, len, txtLengthFunc);
|
||||||
@@ -923,9 +929,13 @@ function saveCaretPosition(context: HTMLElement,offset=0,txtLengthFunc=MarkDown.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTextNodeAtPosition(root: Node, index: number,txtLengthFunc=MarkDown.gatherBoxText.bind(MarkDown)):{
|
function getTextNodeAtPosition(
|
||||||
node: Node,
|
root: Node,
|
||||||
position: number,
|
index: number,
|
||||||
|
txtLengthFunc = MarkDown.gatherBoxText.bind(MarkDown),
|
||||||
|
): {
|
||||||
|
node: Node;
|
||||||
|
position: number;
|
||||||
} {
|
} {
|
||||||
if (root instanceof Text) {
|
if (root instanceof Text) {
|
||||||
return {
|
return {
|
||||||
@@ -946,11 +956,11 @@ function getTextNodeAtPosition(root: Node, index: number,txtLengthFunc=MarkDown.
|
|||||||
let lastElm: Node = root;
|
let lastElm: Node = root;
|
||||||
for (const node of root.childNodes as unknown as Node[]) {
|
for (const node of root.childNodes as unknown as Node[]) {
|
||||||
lastElm = node;
|
lastElm = node;
|
||||||
let len:number
|
let len: number;
|
||||||
if (node instanceof HTMLElement) {
|
if (node instanceof HTMLElement) {
|
||||||
len = txtLengthFunc(node).length;
|
len = txtLengthFunc(node).length;
|
||||||
} else {
|
} else {
|
||||||
len=(node.textContent as string).length
|
len = (node.textContent as string).length;
|
||||||
}
|
}
|
||||||
if (len <= index && (len < index || len !== 0)) {
|
if (len <= index && (len < index || len !== 0)) {
|
||||||
index -= len;
|
index -= len;
|
||||||
@@ -964,7 +974,7 @@ function getTextNodeAtPosition(root: Node, index: number,txtLengthFunc=MarkDown.
|
|||||||
return returny;
|
return returny;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( !((lastElm instanceof HTMLElement && lastElm.hasAttribute("real")))){
|
if (!(lastElm instanceof HTMLElement && lastElm.hasAttribute("real"))) {
|
||||||
while (lastElm && !(lastElm instanceof Text || lastElm instanceof HTMLBRElement)) {
|
while (lastElm && !(lastElm instanceof Text || lastElm instanceof HTMLBRElement)) {
|
||||||
lastElm = lastElm.childNodes[lastElm.childNodes.length - 1];
|
lastElm = lastElm.childNodes[lastElm.childNodes.length - 1];
|
||||||
}
|
}
|
||||||
@@ -972,16 +982,15 @@ function getTextNodeAtPosition(root: Node, index: number,txtLengthFunc=MarkDown.
|
|||||||
const position = (lastElm.textContent as string).length;
|
const position = (lastElm.textContent as string).length;
|
||||||
return {
|
return {
|
||||||
node: lastElm,
|
node: lastElm,
|
||||||
position
|
position,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
root.appendChild(span)
|
root.appendChild(span);
|
||||||
return {
|
return {
|
||||||
node: span,
|
node: span,
|
||||||
position: 0,
|
position: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
export {MarkDown, saveCaretPosition, getTextNodeAtPosition};
|
export {MarkDown, saveCaretPosition, getTextNodeAtPosition};
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ class Member extends SnowFlake{
|
|||||||
}
|
}
|
||||||
if (!this.user.bot) {
|
if (!this.user.bot) {
|
||||||
const everyone = this.guild.roleids.get(this.guild.id);
|
const everyone = this.guild.roleids.get(this.guild.id);
|
||||||
if(everyone&&(this.roles.indexOf(everyone)===-1)){
|
if (everyone && this.roles.indexOf(everyone) === -1) {
|
||||||
this.roles.push(everyone)
|
this.roles.push(everyone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.roles.sort((a, b) => {
|
this.roles.sort((a, b) => {
|
||||||
@@ -78,7 +78,7 @@ class Member extends SnowFlake{
|
|||||||
if (this.banner) {
|
if (this.banner) {
|
||||||
return `${this.info.cdn}/banners/${this.guild.id}/${
|
return `${this.info.cdn}/banners/${this.guild.id}/${
|
||||||
this.banner
|
this.banner
|
||||||
}.${this.banner.startsWith("a_")?"gif":"png"}`;;
|
}.${this.banner.startsWith("a_") ? "gif" : "png"}`;
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -87,25 +87,27 @@ class Member extends SnowFlake{
|
|||||||
premium_since!: string;
|
premium_since!: string;
|
||||||
deaf!: boolean;
|
deaf!: boolean;
|
||||||
mute!: boolean;
|
mute!: boolean;
|
||||||
pending!:boolean
|
pending!: boolean;
|
||||||
clone() {
|
clone() {
|
||||||
return new Member({
|
return new Member(
|
||||||
|
{
|
||||||
id: this.id + "#clone",
|
id: this.id + "#clone",
|
||||||
user: this.user.tojson(),
|
user: this.user.tojson(),
|
||||||
guild_id: this.guild.id,
|
guild_id: this.guild.id,
|
||||||
guild: {id: this.guild.id},
|
guild: {id: this.guild.id},
|
||||||
avatar:this.avatar as (string|undefined),
|
avatar: this.avatar as string | undefined,
|
||||||
banner:this.banner as (string|undefined),
|
banner: this.banner as string | undefined,
|
||||||
//TODO presence
|
//TODO presence
|
||||||
nick: this.nick,
|
nick: this.nick,
|
||||||
roles:this.roles.map(_=>_.id),
|
roles: this.roles.map((_) => _.id),
|
||||||
joined_at: this.joined_at,
|
joined_at: this.joined_at,
|
||||||
premium_since: this.premium_since,
|
premium_since: this.premium_since,
|
||||||
deaf: this.deaf,
|
deaf: this.deaf,
|
||||||
mute: this.mute,
|
mute: this.mute,
|
||||||
pending:this.pending
|
pending: this.pending,
|
||||||
|
},
|
||||||
},this.owner)
|
this.owner,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
pronouns?: string;
|
pronouns?: string;
|
||||||
bio?: string;
|
bio?: string;
|
||||||
@@ -153,11 +155,7 @@ class Member extends SnowFlake{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProfile(json: {
|
updateProfile(json: {bio?: string | null; pronouns?: string | null; nick?: string | null}) {
|
||||||
bio?: string|null;
|
|
||||||
pronouns?: string|null;
|
|
||||||
nick?:string|null;
|
|
||||||
}){
|
|
||||||
console.log(JSON.stringify(json));
|
console.log(JSON.stringify(json));
|
||||||
/*
|
/*
|
||||||
if(json.bio===""){
|
if(json.bio===""){
|
||||||
@@ -178,7 +176,9 @@ class Member extends SnowFlake{
|
|||||||
}
|
}
|
||||||
showEditProfile() {
|
showEditProfile() {
|
||||||
const settings = new Settings("");
|
const settings = new Settings("");
|
||||||
this.editProfile(settings.addButton(I18n.getTranslation("user.editServerProfile"),{ltr:true}));
|
this.editProfile(
|
||||||
|
settings.addButton(I18n.getTranslation("user.editServerProfile"), {ltr: true}),
|
||||||
|
);
|
||||||
settings.show();
|
settings.show();
|
||||||
}
|
}
|
||||||
editProfile(options: Options) {
|
editProfile(options: Options) {
|
||||||
@@ -203,24 +203,24 @@ class Member extends SnowFlake{
|
|||||||
settingsRight.addHTMLArea(hypotheticalProfile);
|
settingsRight.addHTMLArea(hypotheticalProfile);
|
||||||
|
|
||||||
const nicky = settingsLeft.addTextInput(I18n.getTranslation("member.nick:"), () => {}, {
|
const nicky = settingsLeft.addTextInput(I18n.getTranslation("member.nick:"), () => {}, {
|
||||||
initText:this.nick||""
|
initText: this.nick || "",
|
||||||
});
|
});
|
||||||
nicky.watchForChange(_=>{
|
nicky.watchForChange((_) => {
|
||||||
hypomember.nick = _;
|
hypomember.nick = _;
|
||||||
nick = _;
|
nick = _;
|
||||||
regen();
|
regen();
|
||||||
})
|
});
|
||||||
|
|
||||||
const finput = settingsLeft.addFileInput(
|
const finput = settingsLeft.addFileInput(
|
||||||
I18n.getTranslation("uploadPfp"),
|
I18n.getTranslation("uploadPfp"),
|
||||||
_=>{
|
(_) => {
|
||||||
if (file) {
|
if (file) {
|
||||||
this.updatepfp(file);
|
this.updatepfp(file);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ clear: true }
|
{clear: true},
|
||||||
);
|
);
|
||||||
finput.watchForChange(_=>{
|
finput.watchForChange((_) => {
|
||||||
if (!_) {
|
if (!_) {
|
||||||
file = null;
|
file = null;
|
||||||
hypomember.avatar = undefined;
|
hypomember.avatar = undefined;
|
||||||
@@ -239,14 +239,14 @@ class Member extends SnowFlake{
|
|||||||
let bfile: undefined | File | null;
|
let bfile: undefined | File | null;
|
||||||
const binput = settingsLeft.addFileInput(
|
const binput = settingsLeft.addFileInput(
|
||||||
I18n.getTranslation("uploadBanner"),
|
I18n.getTranslation("uploadBanner"),
|
||||||
_=>{
|
(_) => {
|
||||||
if (bfile !== undefined) {
|
if (bfile !== undefined) {
|
||||||
this.updatebanner(bfile);
|
this.updatebanner(bfile);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ clear: true }
|
{clear: true},
|
||||||
);
|
);
|
||||||
binput.watchForChange(_=>{
|
binput.watchForChange((_) => {
|
||||||
if (!_) {
|
if (!_) {
|
||||||
bfile = null;
|
bfile = null;
|
||||||
hypomember.banner = undefined;
|
hypomember.banner = undefined;
|
||||||
@@ -265,27 +265,27 @@ class Member extends SnowFlake{
|
|||||||
let changed = false;
|
let changed = false;
|
||||||
const pronounbox = settingsLeft.addTextInput(
|
const pronounbox = settingsLeft.addTextInput(
|
||||||
I18n.getTranslation("pronouns"),
|
I18n.getTranslation("pronouns"),
|
||||||
_=>{
|
(_) => {
|
||||||
if (newpronouns !== undefined || newbio !== undefined || changed !== undefined) {
|
if (newpronouns !== undefined || newbio !== undefined || changed !== undefined) {
|
||||||
this.updateProfile({
|
this.updateProfile({
|
||||||
pronouns: newpronouns,
|
pronouns: newpronouns,
|
||||||
bio: newbio,
|
bio: newbio,
|
||||||
//accent_color: Number.parseInt("0x" + color.substr(1), 16),
|
//accent_color: Number.parseInt("0x" + color.substr(1), 16),
|
||||||
nick
|
nick,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ initText: this.pronouns }
|
{initText: this.pronouns},
|
||||||
);
|
);
|
||||||
pronounbox.watchForChange(_=>{
|
pronounbox.watchForChange((_) => {
|
||||||
hypomember.pronouns = _;
|
hypomember.pronouns = _;
|
||||||
newpronouns = _;
|
newpronouns = _;
|
||||||
regen();
|
regen();
|
||||||
});
|
});
|
||||||
const bioBox = settingsLeft.addMDInput(I18n.getTranslation("bio"), _=>{}, {
|
const bioBox = settingsLeft.addMDInput(I18n.getTranslation("bio"), (_) => {}, {
|
||||||
initText: this.bio,
|
initText: this.bio,
|
||||||
});
|
});
|
||||||
bioBox.watchForChange(_=>{
|
bioBox.watchForChange((_) => {
|
||||||
newbio = _;
|
newbio = _;
|
||||||
hypomember.bio = _;
|
hypomember.bio = _;
|
||||||
regen();
|
regen();
|
||||||
@@ -298,10 +298,10 @@ class Member extends SnowFlake{
|
|||||||
}
|
}
|
||||||
const colorPicker = settingsLeft.addColorInput(
|
const colorPicker = settingsLeft.addColorInput(
|
||||||
I18n.getTranslation("profileColor"),
|
I18n.getTranslation("profileColor"),
|
||||||
_=>{},
|
(_) => {},
|
||||||
{ initColor: color }
|
{initColor: color},
|
||||||
);
|
);
|
||||||
colorPicker.watchForChange(_=>{
|
colorPicker.watchForChange((_) => {
|
||||||
console.log();
|
console.log();
|
||||||
color = _;
|
color = _;
|
||||||
hypomember.accent_color = Number.parseInt("0x" + _.substr(1), 16);
|
hypomember.accent_color = Number.parseInt("0x" + _.substr(1), 16);
|
||||||
@@ -327,8 +327,8 @@ class Member extends SnowFlake{
|
|||||||
}
|
}
|
||||||
if (!this.user.bot) {
|
if (!this.user.bot) {
|
||||||
const everyone = this.guild.roleids.get(this.guild.id);
|
const everyone = this.guild.roleids.get(this.guild.id);
|
||||||
if(everyone&&(this.roles.indexOf(everyone)===-1)){
|
if (everyone && this.roles.indexOf(everyone) === -1) {
|
||||||
this.roles.push(everyone)
|
this.roles.push(everyone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -353,10 +353,7 @@ class Member extends SnowFlake{
|
|||||||
get info() {
|
get info() {
|
||||||
return this.owner.info;
|
return this.owner.info;
|
||||||
}
|
}
|
||||||
static async new(
|
static async new(memberjson: memberjson, owner: Guild): Promise<Member | undefined> {
|
||||||
memberjson: memberjson,
|
|
||||||
owner: Guild
|
|
||||||
): Promise<Member | undefined>{
|
|
||||||
let user: User;
|
let user: User;
|
||||||
if (owner.localuser.userMap.has(memberjson.id)) {
|
if (owner.localuser.userMap.has(memberjson.id)) {
|
||||||
if (memberjson.user) {
|
if (memberjson.user) {
|
||||||
@@ -398,7 +395,7 @@ class Member extends SnowFlake{
|
|||||||
compare(str: string) {
|
compare(str: string) {
|
||||||
function similar(str2: string | null | undefined) {
|
function similar(str2: string | null | undefined) {
|
||||||
if (!str2) return 0;
|
if (!str2) return 0;
|
||||||
const strl=Math.max(str.length,1)
|
const strl = Math.max(str.length, 1);
|
||||||
if (str2.includes(str)) {
|
if (str2.includes(str)) {
|
||||||
return strl / str2.length;
|
return strl / str2.length;
|
||||||
} else if (str2.toLowerCase().includes(str.toLowerCase())) {
|
} else if (str2.toLowerCase().includes(str.toLowerCase())) {
|
||||||
@@ -406,16 +403,19 @@ class Member extends SnowFlake{
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return Math.max(similar(this.user.name),similar(this.user.nickname),similar(this.nick),similar(this.user.username),similar(this.id)/1.5);
|
return Math.max(
|
||||||
|
similar(this.user.name),
|
||||||
|
similar(this.user.nickname),
|
||||||
|
similar(this.nick),
|
||||||
|
similar(this.user.username),
|
||||||
|
similar(this.id) / 1.5,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
static async resolveMember(
|
static async resolveMember(user: User, guild: Guild): Promise<Member | undefined> {
|
||||||
user: User,
|
|
||||||
guild: Guild
|
|
||||||
): Promise<Member | undefined>{
|
|
||||||
const maybe = user.members.get(guild);
|
const maybe = user.members.get(guild);
|
||||||
if (!user.members.has(guild)) {
|
if (!user.members.has(guild)) {
|
||||||
const membpromise = guild.localuser.resolvemember(user.id, guild.id);
|
const membpromise = guild.localuser.resolvemember(user.id, guild.id);
|
||||||
const promise = new Promise<Member | undefined>(async res=>{
|
const promise = new Promise<Member | undefined>(async (res) => {
|
||||||
const membjson = await membpromise;
|
const membjson = await membpromise;
|
||||||
if (membjson === undefined) {
|
if (membjson === undefined) {
|
||||||
return res(undefined);
|
return res(undefined);
|
||||||
@@ -454,7 +454,7 @@ class Member extends SnowFlake{
|
|||||||
this.id +
|
this.id +
|
||||||
"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" +
|
"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" +
|
||||||
this.guild.id,
|
this.guild.id,
|
||||||
{ headers: this.guild.headers }
|
{headers: this.guild.headers},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
hasRole(ID: string) {
|
hasRole(ID: string) {
|
||||||
@@ -505,10 +505,10 @@ class Member extends SnowFlake{
|
|||||||
}
|
}
|
||||||
kick() {
|
kick() {
|
||||||
const menu = new Dialog("");
|
const menu = new Dialog("");
|
||||||
const form=menu.options.addForm("",((e:any)=>{
|
const form = menu.options.addForm("", (e: any) => {
|
||||||
this.kickAPI(e.reason);
|
this.kickAPI(e.reason);
|
||||||
menu.hide();
|
menu.hide();
|
||||||
}));
|
});
|
||||||
form.addTitle(I18n.getTranslation("member.kick", this.name, this.guild.properties.name));
|
form.addTitle(I18n.getTranslation("member.kick", this.name, this.guild.properties.name));
|
||||||
form.addTextInput(I18n.getTranslation("member.reason:"), "reason");
|
form.addTextInput(I18n.getTranslation("member.reason:"), "reason");
|
||||||
menu.show();
|
menu.show();
|
||||||
@@ -523,31 +523,31 @@ class Member extends SnowFlake{
|
|||||||
}
|
}
|
||||||
ban() {
|
ban() {
|
||||||
const menu = new Dialog("");
|
const menu = new Dialog("");
|
||||||
const form=menu.options.addForm("",((e:any)=>{
|
const form = menu.options.addForm("", (e: any) => {
|
||||||
this.banAPI(e.reason);
|
this.banAPI(e.reason);
|
||||||
menu.hide();
|
menu.hide();
|
||||||
}));
|
});
|
||||||
form.addTitle(I18n.getTranslation("member.ban", this.name, this.guild.properties.name));
|
form.addTitle(I18n.getTranslation("member.ban", this.name, this.guild.properties.name));
|
||||||
form.addTextInput(I18n.getTranslation("member.reason:"), "reason");
|
form.addTextInput(I18n.getTranslation("member.reason:"), "reason");
|
||||||
menu.show();
|
menu.show();
|
||||||
}
|
}
|
||||||
addRole(role: Role) {
|
addRole(role: Role) {
|
||||||
const roles=this.roles.map(_=>_.id)
|
const roles = this.roles.map((_) => _.id);
|
||||||
roles.push(role.id);
|
roles.push(role.id);
|
||||||
fetch(this.info.api + "/guilds/" + this.guild.id + "/members/" + this.id, {
|
fetch(this.info.api + "/guilds/" + this.guild.id + "/members/" + this.id, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers: this.guild.headers,
|
headers: this.guild.headers,
|
||||||
body:JSON.stringify({roles})
|
body: JSON.stringify({roles}),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
removeRole(role: Role) {
|
removeRole(role: Role) {
|
||||||
let roles=this.roles.map(_=>_.id)
|
let roles = this.roles.map((_) => _.id);
|
||||||
roles=roles.filter(_=>_!==role.id);
|
roles = roles.filter((_) => _ !== role.id);
|
||||||
fetch(this.info.api + "/guilds/" + this.guild.id + "/members/" + this.id, {
|
fetch(this.info.api + "/guilds/" + this.guild.id + "/members/" + this.id, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers: this.guild.headers,
|
headers: this.guild.headers,
|
||||||
body:JSON.stringify({roles})
|
body: JSON.stringify({roles}),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
banAPI(reason: string) {
|
banAPI(reason: string) {
|
||||||
const headers = structuredClone(this.guild.headers);
|
const headers = structuredClone(this.guild.headers);
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ class Message extends SnowFlake{
|
|||||||
mention_roles!: Role[];
|
mention_roles!: Role[];
|
||||||
attachments!: File[]; //probably should be its own class tbh, should be Attachments[]
|
attachments!: File[]; //probably should be its own class tbh, should be Attachments[]
|
||||||
message_reference!: {
|
message_reference!: {
|
||||||
guild_id: string,
|
guild_id: string;
|
||||||
channel_id: string,
|
channel_id: string;
|
||||||
message_id: string
|
message_id: string;
|
||||||
};
|
};
|
||||||
type!: number;
|
type!: number;
|
||||||
timestamp!: number;
|
timestamp!: number;
|
||||||
@@ -51,28 +51,37 @@ class Message extends SnowFlake{
|
|||||||
member: Member | undefined;
|
member: Member | undefined;
|
||||||
reactions!: messagejson["reactions"];
|
reactions!: messagejson["reactions"];
|
||||||
static setup() {
|
static setup() {
|
||||||
this.del = new Promise(_=>{
|
this.del = new Promise((_) => {
|
||||||
this.resolve = _;
|
this.resolve = _;
|
||||||
});
|
});
|
||||||
Message.setupcmenu();
|
Message.setupcmenu();
|
||||||
}
|
}
|
||||||
static setupcmenu() {
|
static setupcmenu() {
|
||||||
Message.contextmenu.addbutton(()=>I18n.getTranslation("copyrawtext"), function(this: Message){
|
Message.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("copyrawtext"),
|
||||||
|
function (this: Message) {
|
||||||
navigator.clipboard.writeText(this.content.rawString);
|
navigator.clipboard.writeText(this.content.rawString);
|
||||||
});
|
},
|
||||||
Message.contextmenu.addbutton(()=>I18n.getTranslation("reply"), function(this: Message){
|
);
|
||||||
|
Message.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("reply"),
|
||||||
|
function (this: Message) {
|
||||||
this.channel.setReplying(this);
|
this.channel.setReplying(this);
|
||||||
});
|
},
|
||||||
Message.contextmenu.addbutton(()=>I18n.getTranslation("copymessageid"), function(this: Message){
|
);
|
||||||
|
Message.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("copymessageid"),
|
||||||
|
function (this: Message) {
|
||||||
navigator.clipboard.writeText(this.id);
|
navigator.clipboard.writeText(this.id);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
Message.contextmenu.addsubmenu(
|
Message.contextmenu.addsubmenu(
|
||||||
() => I18n.getTranslation("message.reactionAdd"),
|
() => I18n.getTranslation("message.reactionAdd"),
|
||||||
function (this: Message, _, e: MouseEvent) {
|
function (this: Message, _, e: MouseEvent) {
|
||||||
Emoji.emojiPicker(e.x, e.y, this.localuser).then(_=>{
|
Emoji.emojiPicker(e.x, e.y, this.localuser).then((_) => {
|
||||||
this.reactionToggle(_);
|
this.reactionToggle(_);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
Message.contextmenu.addbutton(
|
Message.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("message.edit"),
|
() => I18n.getTranslation("message.edit"),
|
||||||
@@ -82,7 +91,7 @@ class Message extends SnowFlake{
|
|||||||
null,
|
null,
|
||||||
function () {
|
function () {
|
||||||
return this.author.id === this.localuser.user.id;
|
return this.author.id === this.localuser.user.id;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
Message.contextmenu.addbutton(
|
Message.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("message.delete"),
|
() => I18n.getTranslation("message.delete"),
|
||||||
@@ -92,14 +101,14 @@ class Message extends SnowFlake{
|
|||||||
null,
|
null,
|
||||||
function () {
|
function () {
|
||||||
return this.canDelete();
|
return this.canDelete();
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
setEdit() {
|
setEdit() {
|
||||||
const prev = this.channel.editing;
|
const prev = this.channel.editing;
|
||||||
this.channel.editing = this;
|
this.channel.editing = this;
|
||||||
if (prev) prev.generateMessage();
|
if (prev) prev.generateMessage();
|
||||||
this.generateMessage(undefined,false)
|
this.generateMessage(undefined, false);
|
||||||
}
|
}
|
||||||
constructor(messagejson: messagejson, owner: Channel, dontStore = false) {
|
constructor(messagejson: messagejson, owner: Channel, dontStore = false) {
|
||||||
super(messagejson.id);
|
super(messagejson.id);
|
||||||
@@ -129,7 +138,7 @@ class Message extends SnowFlake{
|
|||||||
{
|
{
|
||||||
method: remove ? "DELETE" : "PUT",
|
method: remove ? "DELETE" : "PUT",
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
edited_timestamp: string | null = null;
|
edited_timestamp: string | null = null;
|
||||||
@@ -148,7 +157,7 @@ class Message extends SnowFlake{
|
|||||||
} else if (thing === "id") {
|
} else if (thing === "id") {
|
||||||
continue;
|
continue;
|
||||||
} else if (thing === "member") {
|
} else if (thing === "member") {
|
||||||
Member.new(messagejson.member as memberjson, this.guild).then(_=>{
|
Member.new(messagejson.member as memberjson, this.guild).then((_) => {
|
||||||
this.member = _ as Member;
|
this.member = _ as Member;
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
@@ -167,13 +176,10 @@ class Message extends SnowFlake{
|
|||||||
|
|
||||||
this.author = new User(messagejson.author, this.localuser);
|
this.author = new User(messagejson.author, this.localuser);
|
||||||
for (const thing in messagejson.mentions) {
|
for (const thing in messagejson.mentions) {
|
||||||
this.mentions[thing] = new User(
|
this.mentions[thing] = new User(messagejson.mentions[thing], this.localuser);
|
||||||
messagejson.mentions[thing],
|
|
||||||
this.localuser
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (!this.member && this.guild.id !== "@me") {
|
if (!this.member && this.guild.id !== "@me") {
|
||||||
this.author.resolvemember(this.guild).then(_=>{
|
this.author.resolvemember(this.guild).then((_) => {
|
||||||
this.member = _;
|
this.member = _;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -193,10 +199,7 @@ class Message extends SnowFlake{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
canDelete() {
|
canDelete() {
|
||||||
return(
|
return this.channel.hasPermission("MANAGE_MESSAGES") || this.author === this.localuser.user;
|
||||||
this.channel.hasPermission("MANAGE_MESSAGES") ||
|
|
||||||
this.author === this.localuser.user
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
get channel() {
|
get channel() {
|
||||||
return this.owner;
|
return this.owner;
|
||||||
@@ -212,26 +215,30 @@ class Message extends SnowFlake{
|
|||||||
}
|
}
|
||||||
messageevents(obj: HTMLDivElement) {
|
messageevents(obj: HTMLDivElement) {
|
||||||
let drag = false;
|
let drag = false;
|
||||||
Message.contextmenu.bindContextmenu(obj, this, undefined,(x)=>{
|
Message.contextmenu.bindContextmenu(
|
||||||
|
obj,
|
||||||
|
this,
|
||||||
|
undefined,
|
||||||
|
(x) => {
|
||||||
//console.log(x,y);
|
//console.log(x,y);
|
||||||
if (!drag && x < 20) {
|
if (!drag && x < 20) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
drag = true;
|
drag = true;
|
||||||
this.channel.moveForDrag(Math.max(x, 0));
|
this.channel.moveForDrag(Math.max(x, 0));
|
||||||
|
},
|
||||||
},(x,y)=>{
|
(x, y) => {
|
||||||
drag = false;
|
drag = false;
|
||||||
console.log(x, y);
|
console.log(x, y);
|
||||||
this.channel.moveForDrag(-1);
|
this.channel.moveForDrag(-1);
|
||||||
if (x > 60) {
|
if (x > 60) {
|
||||||
console.log("In here?")
|
console.log("In here?");
|
||||||
const toggle = document.getElementById("maintoggle") as HTMLInputElement;
|
const toggle = document.getElementById("maintoggle") as HTMLInputElement;
|
||||||
toggle.checked = false;
|
toggle.checked = false;
|
||||||
console.log(toggle);
|
console.log(toggle);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
},);
|
);
|
||||||
this.div = obj;
|
this.div = obj;
|
||||||
obj.classList.add("messagediv");
|
obj.classList.add("messagediv");
|
||||||
}
|
}
|
||||||
@@ -249,7 +256,7 @@ class Message extends SnowFlake{
|
|||||||
return this.mentions.includes(userd);
|
return this.mentions.includes(userd);
|
||||||
} else if (userd instanceof Member) {
|
} else if (userd instanceof Member) {
|
||||||
if (this.mentions.includes(userd.user)) {
|
if (this.mentions.includes(userd.user)) {
|
||||||
return true
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return !new Set(this.mentions).isDisjointFrom(new Set(userd.roles)); //if the message mentions a role the user has
|
return !new Set(this.mentions).isDisjointFrom(new Set(userd.roles)); //if the message mentions a role the user has
|
||||||
}
|
}
|
||||||
@@ -267,14 +274,11 @@ class Message extends SnowFlake{
|
|||||||
return build;
|
return build;
|
||||||
}
|
}
|
||||||
async edit(content: string) {
|
async edit(content: string) {
|
||||||
return await fetch(
|
return await fetch(this.info.api + "/channels/" + this.channel.id + "/messages/" + this.id, {
|
||||||
this.info.api + "/channels/" + this.channel.id + "/messages/" + this.id,
|
|
||||||
{
|
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
body: JSON.stringify({content}),
|
body: JSON.stringify({content}),
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
delete() {
|
delete() {
|
||||||
fetch(`${this.info.api}/channels/${this.channel.id}/messages/${this.id}`, {
|
fetch(`${this.info.api}/channels/${this.channel.id}/messages/${this.id}`, {
|
||||||
@@ -308,10 +312,7 @@ class Message extends SnowFlake{
|
|||||||
prevmessage.generateMessage();
|
prevmessage.generateMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(
|
if (this.channel.lastmessage === this || this.channel.lastmessageid === this.id) {
|
||||||
this.channel.lastmessage === this ||
|
|
||||||
this.channel.lastmessageid === this.id
|
|
||||||
){
|
|
||||||
if (prev) {
|
if (prev) {
|
||||||
this.channel.lastmessage = this.channel.messages.get(prev);
|
this.channel.lastmessage = this.channel.messages.get(prev);
|
||||||
this.channel.lastmessageid = prev;
|
this.channel.lastmessageid = prev;
|
||||||
@@ -343,15 +344,17 @@ class Message extends SnowFlake{
|
|||||||
this.generateMessage();
|
this.generateMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
generateMessage(premessage?: Message | undefined, ignoredblock = false,dupe:false|HTMLDivElement=false){
|
generateMessage(
|
||||||
|
premessage?: Message | undefined,
|
||||||
|
ignoredblock = false,
|
||||||
|
dupe: false | HTMLDivElement = false,
|
||||||
|
) {
|
||||||
const div = dupe || this.div;
|
const div = dupe || this.div;
|
||||||
if (!div) return;
|
if (!div) return;
|
||||||
|
|
||||||
const editmode = this.channel.editing === this;
|
const editmode = this.channel.editing === this;
|
||||||
if (!premessage && !dupe) {
|
if (!premessage && !dupe) {
|
||||||
premessage = this.channel.messages.get(
|
premessage = this.channel.messages.get(this.channel.idToPrev.get(this.id) as string);
|
||||||
this.channel.idToPrev.get(this.id) as string
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
for (const user of this.mentions) {
|
for (const user of this.mentions) {
|
||||||
if (user === this.localuser.user) {
|
if (user === this.localuser.user) {
|
||||||
@@ -373,7 +376,7 @@ class Message extends SnowFlake{
|
|||||||
span.textContent = I18n.getTranslation("hideBlockedMessages");
|
span.textContent = I18n.getTranslation("hideBlockedMessages");
|
||||||
div.append(span);
|
div.append(span);
|
||||||
span.classList.add("blocked");
|
span.classList.add("blocked");
|
||||||
span.onclick = _=>{
|
span.onclick = (_) => {
|
||||||
const scroll = this.channel.infinite.scrollTop;
|
const scroll = this.channel.infinite.scrollTop;
|
||||||
let next: Message | undefined = this;
|
let next: Message | undefined = this;
|
||||||
while (next?.author === this.author) {
|
while (next?.author === this.author) {
|
||||||
@@ -403,15 +406,13 @@ class Message extends SnowFlake{
|
|||||||
}
|
}
|
||||||
span.textContent = I18n.getTranslation("showBlockedMessages", count + "");
|
span.textContent = I18n.getTranslation("showBlockedMessages", count + "");
|
||||||
build.append(span);
|
build.append(span);
|
||||||
span.onclick = _=>{
|
span.onclick = (_) => {
|
||||||
const scroll = this.channel.infinite.scrollTop;
|
const scroll = this.channel.infinite.scrollTop;
|
||||||
const func = this.channel.infinite.snapBottom();
|
const func = this.channel.infinite.snapBottom();
|
||||||
let next: Message | undefined = this;
|
let next: Message | undefined = this;
|
||||||
while (next?.author === this.author) {
|
while (next?.author === this.author) {
|
||||||
next.generateMessage(undefined, true);
|
next.generateMessage(undefined, true);
|
||||||
next = this.channel.messages.get(
|
next = this.channel.messages.get(this.channel.idToNext.get(next.id) as string);
|
||||||
this.channel.idToNext.get(next.id) as string
|
|
||||||
);
|
|
||||||
console.log("loopy");
|
console.log("loopy");
|
||||||
}
|
}
|
||||||
if (this.channel.infinite.scollDiv && scroll) {
|
if (this.channel.infinite.scollDiv && scroll) {
|
||||||
@@ -440,7 +441,7 @@ class Message extends SnowFlake{
|
|||||||
line2.classList.add("reply");
|
line2.classList.add("reply");
|
||||||
replyline.classList.add("flexltr", "replyflex");
|
replyline.classList.add("flexltr", "replyflex");
|
||||||
// TODO: Fix this
|
// TODO: Fix this
|
||||||
this.channel.getmessage(this.message_reference.message_id).then(message=>{
|
this.channel.getmessage(this.message_reference.message_id).then((message) => {
|
||||||
if (!message) {
|
if (!message) {
|
||||||
minipfp.remove();
|
minipfp.remove();
|
||||||
username.textContent = I18n.getTranslation("message.deleted");
|
username.textContent = I18n.getTranslation("message.deleted");
|
||||||
@@ -457,13 +458,13 @@ class Message extends SnowFlake{
|
|||||||
author.bind(minipfp, this.guild);
|
author.bind(minipfp, this.guild);
|
||||||
username.textContent = author.username;
|
username.textContent = author.username;
|
||||||
author.bind(username, this.guild);
|
author.bind(username, this.guild);
|
||||||
Member.resolveMember(author, this.guild).then(_=>{
|
Member.resolveMember(author, this.guild).then((_) => {
|
||||||
if (_) {
|
if (_) {
|
||||||
username.textContent = _.name;
|
username.textContent = _.name;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
});
|
});
|
||||||
reply.onclick = _=>{
|
});
|
||||||
|
reply.onclick = (_) => {
|
||||||
// TODO: FIX this
|
// TODO: FIX this
|
||||||
this.channel.infinite.focus(this.message_reference.message_id);
|
this.channel.infinite.focus(this.message_reference.message_id);
|
||||||
};
|
};
|
||||||
@@ -484,7 +485,11 @@ class Message extends SnowFlake{
|
|||||||
const newt = new Date(this.timestamp).getTime() / 1000;
|
const newt = new Date(this.timestamp).getTime() / 1000;
|
||||||
current = newt - old > 600;
|
current = newt - old > 600;
|
||||||
}
|
}
|
||||||
const combine = premessage?.author != this.author || current || this.message_reference || !messageTypes.has(premessage.type);
|
const combine =
|
||||||
|
premessage?.author != this.author ||
|
||||||
|
current ||
|
||||||
|
this.message_reference ||
|
||||||
|
!messageTypes.has(premessage.type);
|
||||||
if (combine) {
|
if (combine) {
|
||||||
const pfp = this.author.buildpfp();
|
const pfp = this.author.buildpfp();
|
||||||
this.author.bind(pfp, this.guild, false);
|
this.author.bind(pfp, this.guild, false);
|
||||||
@@ -500,11 +505,11 @@ class Message extends SnowFlake{
|
|||||||
const username = document.createElement("span");
|
const username = document.createElement("span");
|
||||||
username.classList.add("username");
|
username.classList.add("username");
|
||||||
this.author.bind(username, this.guild);
|
this.author.bind(username, this.guild);
|
||||||
Member.resolveMember(this.author, this.guild).then(_=>{
|
Member.resolveMember(this.author, this.guild).then((_) => {
|
||||||
if (_) {
|
if (_) {
|
||||||
username.textContent = _.name;
|
username.textContent = _.name;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
div.classList.add("topMessage");
|
div.classList.add("topMessage");
|
||||||
username.textContent = this.author.username;
|
username.textContent = this.author.username;
|
||||||
const userwrap = document.createElement("div");
|
const userwrap = document.createElement("div");
|
||||||
@@ -555,7 +560,7 @@ class Message extends SnowFlake{
|
|||||||
this.generateMessage();
|
this.generateMessage();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
area.addEventListener("keydown", event=>{
|
area.addEventListener("keydown", (event) => {
|
||||||
this.localuser.keydown(event);
|
this.localuser.keydown(event);
|
||||||
if (event.key === "Enter" && !event.shiftKey) event.preventDefault();
|
if (event.key === "Enter" && !event.shiftKey) event.preventDefault();
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
@@ -564,8 +569,8 @@ class Message extends SnowFlake{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
md.giveBox(area, (str, pre) => {
|
md.giveBox(area, (str, pre) => {
|
||||||
this.localuser.search(search,md,str,pre)
|
this.localuser.search(search, md, str, pre);
|
||||||
})
|
});
|
||||||
sb.append(search);
|
sb.append(search);
|
||||||
box.append(sb, area);
|
box.append(sb, area);
|
||||||
messagedwrap.append(box);
|
messagedwrap.append(box);
|
||||||
@@ -573,14 +578,13 @@ class Message extends SnowFlake{
|
|||||||
area.focus();
|
area.focus();
|
||||||
const fun = saveCaretPosition(area, Infinity);
|
const fun = saveCaretPosition(area, Infinity);
|
||||||
if (fun) fun();
|
if (fun) fun();
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
this.content.onUpdate = () => {};
|
this.content.onUpdate = () => {};
|
||||||
const messaged = this.content.makeHTML();
|
const messaged = this.content.makeHTML();
|
||||||
(div as any).txt = messaged;
|
(div as any).txt = messaged;
|
||||||
messagedwrap.classList.add("flexttb");
|
messagedwrap.classList.add("flexttb");
|
||||||
messagedwrap.appendChild(messaged);
|
messagedwrap.appendChild(messaged);
|
||||||
|
|
||||||
}
|
}
|
||||||
text.appendChild(messagedwrap);
|
text.appendChild(messagedwrap);
|
||||||
build.appendChild(text);
|
build.appendChild(text);
|
||||||
@@ -635,7 +639,7 @@ class Message extends SnowFlake{
|
|||||||
bindButtonEvent() {
|
bindButtonEvent() {
|
||||||
if (this.div) {
|
if (this.div) {
|
||||||
let buttons: HTMLDivElement | undefined;
|
let buttons: HTMLDivElement | undefined;
|
||||||
this.div.onmouseenter = _=>{
|
this.div.onmouseenter = (_) => {
|
||||||
if (mobile) return;
|
if (mobile) return;
|
||||||
if (buttons) {
|
if (buttons) {
|
||||||
buttons.remove();
|
buttons.remove();
|
||||||
@@ -650,7 +654,7 @@ class Message extends SnowFlake{
|
|||||||
reply.classList.add("svg-reply", "svgicon");
|
reply.classList.add("svg-reply", "svgicon");
|
||||||
container.append(reply);
|
container.append(reply);
|
||||||
buttons.append(container);
|
buttons.append(container);
|
||||||
container.onclick = _=>{
|
container.onclick = (_) => {
|
||||||
this.channel.setReplying(this);
|
this.channel.setReplying(this);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -660,8 +664,8 @@ class Message extends SnowFlake{
|
|||||||
reply.classList.add("svg-emoji", "svgicon");
|
reply.classList.add("svg-emoji", "svgicon");
|
||||||
container.append(reply);
|
container.append(reply);
|
||||||
buttons.append(container);
|
buttons.append(container);
|
||||||
container.onclick = e=>{
|
container.onclick = (e) => {
|
||||||
Emoji.emojiPicker(e.x, e.y, this.localuser).then(_=>{
|
Emoji.emojiPicker(e.x, e.y, this.localuser).then((_) => {
|
||||||
this.reactionToggle(_);
|
this.reactionToggle(_);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -672,7 +676,7 @@ class Message extends SnowFlake{
|
|||||||
edit.classList.add("svg-edit", "svgicon");
|
edit.classList.add("svg-edit", "svgicon");
|
||||||
container.append(edit);
|
container.append(edit);
|
||||||
buttons.append(container);
|
buttons.append(container);
|
||||||
container.onclick = _=>{
|
container.onclick = (_) => {
|
||||||
this.setEdit();
|
this.setEdit();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -682,7 +686,7 @@ class Message extends SnowFlake{
|
|||||||
reply.classList.add("svg-delete", "svgicon");
|
reply.classList.add("svg-delete", "svgicon");
|
||||||
container.append(reply);
|
container.append(reply);
|
||||||
buttons.append(container);
|
buttons.append(container);
|
||||||
container.onclick = _=>{
|
container.onclick = (_) => {
|
||||||
if (_.shiftKey) {
|
if (_.shiftKey) {
|
||||||
this.delete();
|
this.delete();
|
||||||
return;
|
return;
|
||||||
@@ -695,7 +699,7 @@ class Message extends SnowFlake{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.div.onmouseleave = _=>{
|
this.div.onmouseleave = (_) => {
|
||||||
if (buttons) {
|
if (buttons) {
|
||||||
buttons.remove();
|
buttons.remove();
|
||||||
buttons = undefined;
|
buttons = undefined;
|
||||||
@@ -713,7 +717,7 @@ class Message extends SnowFlake{
|
|||||||
});
|
});
|
||||||
options.addButtonInput("", I18n.getTranslation("no"), () => {
|
options.addButtonInput("", I18n.getTranslation("no"), () => {
|
||||||
diaolog.hide();
|
diaolog.hide();
|
||||||
})
|
});
|
||||||
diaolog.show();
|
diaolog.show();
|
||||||
}
|
}
|
||||||
updateReactions() {
|
updateReactions() {
|
||||||
@@ -732,7 +736,10 @@ class Message extends SnowFlake{
|
|||||||
if (/\d{17,21}/.test(thing.emoji.name)) {
|
if (/\d{17,21}/.test(thing.emoji.name)) {
|
||||||
thing.emoji.id = thing.emoji.name; //Should stop being a thing once the server fixes this bug
|
thing.emoji.id = thing.emoji.name; //Should stop being a thing once the server fixes this bug
|
||||||
}
|
}
|
||||||
const emo = new Emoji(thing.emoji as { name: string; id: string; animated: boolean },this.guild);
|
const emo = new Emoji(
|
||||||
|
thing.emoji as {name: string; id: string; animated: boolean},
|
||||||
|
this.guild,
|
||||||
|
);
|
||||||
emoji = emo.getHTML(false);
|
emoji = emo.getHTML(false);
|
||||||
} else {
|
} else {
|
||||||
emoji = document.createElement("p");
|
emoji = document.createElement("p");
|
||||||
@@ -740,10 +747,13 @@ class Message extends SnowFlake{
|
|||||||
}
|
}
|
||||||
const h = new Hover(async () => {
|
const h = new Hover(async () => {
|
||||||
//TODO this can't be real, name conflicts must happen, but for now it's fine
|
//TODO this can't be real, name conflicts must happen, but for now it's fine
|
||||||
const f=await fetch(`${this.info.api}/channels/${this.channel.id}/messages/${this.id}/reactions/${thing.emoji.name}?limit=3&type=0`,{headers:this.headers});
|
const f = await fetch(
|
||||||
const json=await f.json() as userjson[];
|
`${this.info.api}/channels/${this.channel.id}/messages/${this.id}/reactions/${thing.emoji.name}?limit=3&type=0`,
|
||||||
|
{headers: this.headers},
|
||||||
|
);
|
||||||
|
const json = (await f.json()) as userjson[];
|
||||||
let build = "";
|
let build = "";
|
||||||
let users=json.map(_=>new User(_,this.localuser));
|
let users = json.map((_) => new User(_, this.localuser));
|
||||||
//FIXME this is a spacebar bug, I can't fix this the api ignores limit and just sends everything.
|
//FIXME this is a spacebar bug, I can't fix this the api ignores limit and just sends everything.
|
||||||
users = users.splice(0, 3);
|
users = users.splice(0, 3);
|
||||||
let first = true;
|
let first = true;
|
||||||
@@ -755,14 +765,12 @@ class Message extends SnowFlake{
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
if (thing.count > 3) {
|
if (thing.count > 3) {
|
||||||
build+=", and more!"
|
build += ", and more!";
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
build += "\nReacted with " + thing.emoji.name;
|
build += "\nReacted with " + thing.emoji.name;
|
||||||
console.log(build);
|
console.log(build);
|
||||||
return build;
|
return build;
|
||||||
|
|
||||||
});
|
});
|
||||||
h.addEvent(reaction);
|
h.addEvent(reaction);
|
||||||
const count = document.createElement("p");
|
const count = document.createElement("p");
|
||||||
@@ -772,7 +780,7 @@ class Message extends SnowFlake{
|
|||||||
reaction.append(emoji);
|
reaction.append(emoji);
|
||||||
reactdiv.append(reaction);
|
reactdiv.append(reaction);
|
||||||
|
|
||||||
reaction.onclick = _=>{
|
reaction.onclick = (_) => {
|
||||||
this.reactionToggle(thing.emoji.name);
|
this.reactionToggle(thing.emoji.name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -858,14 +866,20 @@ let yesterdayStr: string;
|
|||||||
function formatTime(date: Date) {
|
function formatTime(date: Date) {
|
||||||
updateTimes();
|
updateTimes();
|
||||||
const datestring = date.toLocaleDateString();
|
const datestring = date.toLocaleDateString();
|
||||||
const formatTime = (date: Date)=>date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
const formatTime = (date: Date) =>
|
||||||
|
date.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"});
|
||||||
|
|
||||||
if (datestring === now) {
|
if (datestring === now) {
|
||||||
return I18n.getTranslation("todayAt", formatTime(date));
|
return I18n.getTranslation("todayAt", formatTime(date));
|
||||||
} else if (datestring === yesterdayStr) {
|
} else if (datestring === yesterdayStr) {
|
||||||
return I18n.getTranslation("yesterdayAt", formatTime(date));
|
return I18n.getTranslation("yesterdayAt", formatTime(date));
|
||||||
} else {
|
} else {
|
||||||
return I18n.getTranslation("otherAt",formatTime(date),date.toLocaleDateString(),formatTime(date));
|
return I18n.getTranslation(
|
||||||
|
"otherAt",
|
||||||
|
formatTime(date),
|
||||||
|
date.toLocaleDateString(),
|
||||||
|
formatTime(date),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let tomorrow = 0;
|
let tomorrow = 0;
|
||||||
|
|||||||
@@ -4,46 +4,46 @@ import { getBulkUsers, Specialuser } from "../utils/utils.js";
|
|||||||
import {Permissions} from "../permissions.js";
|
import {Permissions} from "../permissions.js";
|
||||||
type botjsonfetch = {
|
type botjsonfetch = {
|
||||||
guilds: {
|
guilds: {
|
||||||
id: string,
|
id: string;
|
||||||
name: string,
|
name: string;
|
||||||
icon: string,
|
icon: string;
|
||||||
mfa_level: number,
|
mfa_level: number;
|
||||||
permissions: string
|
permissions: string;
|
||||||
}[],
|
}[];
|
||||||
"user": {
|
user: {
|
||||||
id: string,
|
id: string;
|
||||||
username: string,
|
username: string;
|
||||||
avatar: string,
|
avatar: string;
|
||||||
avatar_decoration?: string,
|
avatar_decoration?: string;
|
||||||
discriminator: string,
|
discriminator: string;
|
||||||
public_flags: number
|
public_flags: number;
|
||||||
},
|
};
|
||||||
application: {
|
application: {
|
||||||
id: string,
|
id: string;
|
||||||
name: string,
|
name: string;
|
||||||
icon: string|null,
|
icon: string | null;
|
||||||
description: string,
|
description: string;
|
||||||
summary: string,
|
summary: string;
|
||||||
type: null,//not sure what this means :P
|
type: null; //not sure what this means :P
|
||||||
hook: boolean,
|
hook: boolean;
|
||||||
guild_id: null|string,
|
guild_id: null | string;
|
||||||
bot_public: boolean,
|
bot_public: boolean;
|
||||||
bot_require_code_grant: boolean,
|
bot_require_code_grant: boolean;
|
||||||
verify_key: "IMPLEMENTME",//no clue what this is meant to be :P
|
verify_key: "IMPLEMENTME"; //no clue what this is meant to be :P
|
||||||
flags: number
|
flags: number;
|
||||||
},
|
};
|
||||||
bot: {
|
bot: {
|
||||||
id: string,
|
id: string;
|
||||||
username: string,
|
username: string;
|
||||||
avatar: string|null,
|
avatar: string | null;
|
||||||
avatar_decoration: null|string,
|
avatar_decoration: null | string;
|
||||||
discriminator: string,
|
discriminator: string;
|
||||||
public_flags: number,
|
public_flags: number;
|
||||||
bot: boolean,
|
bot: boolean;
|
||||||
approximated_guild_count: number
|
approximated_guild_count: number;
|
||||||
},
|
};
|
||||||
authorized: boolean
|
authorized: boolean;
|
||||||
}
|
};
|
||||||
(async () => {
|
(async () => {
|
||||||
const users = getBulkUsers();
|
const users = getBulkUsers();
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
@@ -77,9 +77,7 @@ type botjsonfetch={
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error("Someone needs to handle the case where the servers don't exist");
|
||||||
"Someone needs to handle the case where the servers don't exist"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
urls = joinable[0].serverurls;
|
urls = joinable[0].serverurls;
|
||||||
@@ -93,12 +91,14 @@ type botjsonfetch={
|
|||||||
if (!urls) return;
|
if (!urls) return;
|
||||||
fetch(urls.api + "/oauth2/authorize/" + window.location.search, {
|
fetch(urls.api + "/oauth2/authorize/" + window.location.search, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization:user.token
|
Authorization: user.token,
|
||||||
}
|
},
|
||||||
}).then(_=>_.json()).then((json:botjsonfetch)=>{
|
})
|
||||||
|
.then((_) => _.json())
|
||||||
|
.then((json: botjsonfetch) => {
|
||||||
const guilds: botjsonfetch["guilds"] = [];
|
const guilds: botjsonfetch["guilds"] = [];
|
||||||
for (const guild of json.guilds) {
|
for (const guild of json.guilds) {
|
||||||
const permisions=new Permissions(guild.permissions)
|
const permisions = new Permissions(guild.permissions);
|
||||||
if (permisions.hasPermission("MANAGE_GUILD")) {
|
if (permisions.hasPermission("MANAGE_GUILD")) {
|
||||||
guilds.push(guild);
|
guilds.push(guild);
|
||||||
}
|
}
|
||||||
@@ -128,26 +128,26 @@ type botjsonfetch={
|
|||||||
button.onclick = () => {
|
button.onclick = () => {
|
||||||
const id = select.value;
|
const id = select.value;
|
||||||
const params2 = new URLSearchParams("");
|
const params2 = new URLSearchParams("");
|
||||||
params2.set("client_id",params.get("client_id") as string)
|
params2.set("client_id", params.get("client_id") as string);
|
||||||
fetch(urls.api + "/oauth2/authorize?" + params2.toString(), {
|
fetch(urls.api + "/oauth2/authorize?" + params2.toString(), {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
authorize: true,
|
authorize: true,
|
||||||
guild_id: id,
|
guild_id: id,
|
||||||
permissions:permstr
|
permissions: permstr,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json; charset=UTF-8",
|
"Content-type": "application/json; charset=UTF-8",
|
||||||
Authorization: user.token,
|
Authorization: user.token,
|
||||||
}
|
},
|
||||||
}).then(req=>{
|
}).then((req) => {
|
||||||
if (req.ok) {
|
if (req.ok) {
|
||||||
alert("Bot added successfully");
|
alert("Bot added successfully");
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
document.body.append(dialog);
|
document.body.append(dialog);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
function showAccounts(): void {
|
function showAccounts(): void {
|
||||||
const table = document.createElement("dialog");
|
const table = document.createElement("dialog");
|
||||||
@@ -168,9 +168,7 @@ type botjsonfetch={
|
|||||||
userDiv.append(document.createElement("br"));
|
userDiv.append(document.createElement("br"));
|
||||||
|
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = user.serverurls.wellknown
|
span.textContent = user.serverurls.wellknown.replace("https://", "").replace("http://", "");
|
||||||
.replace("https://", "")
|
|
||||||
.replace("http://", "");
|
|
||||||
span.classList.add("serverURL");
|
span.classList.add("serverURL");
|
||||||
userDiv.append(span);
|
userDiv.append(span);
|
||||||
|
|
||||||
@@ -211,12 +209,14 @@ type botjsonfetch={
|
|||||||
}
|
}
|
||||||
fetch(urls.api + "/oauth2/authorize/" + window.location.search, {
|
fetch(urls.api + "/oauth2/authorize/" + window.location.search, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization:user.token
|
Authorization: user.token,
|
||||||
}
|
},
|
||||||
}).then(_=>_.json()).then((json:botjsonfetch)=>{
|
})
|
||||||
|
.then((_) => _.json())
|
||||||
|
.then((json: botjsonfetch) => {
|
||||||
const title = document.getElementById("invitename");
|
const title = document.getElementById("invitename");
|
||||||
if (title) {
|
if (title) {
|
||||||
title.textContent=`Invite ${json.bot.username} to your servers`
|
title.textContent = `Invite ${json.bot.username} to your servers`;
|
||||||
}
|
}
|
||||||
const desc = document.getElementById("invitedescription");
|
const desc = document.getElementById("invitedescription");
|
||||||
if (desc) {
|
if (desc) {
|
||||||
@@ -232,8 +232,8 @@ type botjsonfetch={
|
|||||||
const perms = document.getElementById("permissions") as HTMLDivElement;
|
const perms = document.getElementById("permissions") as HTMLDivElement;
|
||||||
|
|
||||||
if (perms && permstr) {
|
if (perms && permstr) {
|
||||||
perms.children[0].textContent=I18n.getTranslation("htmlPages.idpermissions")
|
perms.children[0].textContent = I18n.getTranslation("htmlPages.idpermissions");
|
||||||
const permisions=new Permissions(permstr)
|
const permisions = new Permissions(permstr);
|
||||||
for (const perm of Permissions.info()) {
|
for (const perm of Permissions.info()) {
|
||||||
if (permisions.hasPermission(perm.name, false)) {
|
if (permisions.hasPermission(perm.name, false)) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
@@ -245,10 +245,10 @@ type botjsonfetch={
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
const AcceptInvite = document.getElementById("AcceptInvite");
|
const AcceptInvite = document.getElementById("AcceptInvite");
|
||||||
if (AcceptInvite) {
|
if (AcceptInvite) {
|
||||||
AcceptInvite.addEventListener("click", showAccounts);
|
AcceptInvite.addEventListener("click", showAccounts);
|
||||||
AcceptInvite.textContent=I18n.getTranslation("htmlPages.addBot")
|
AcceptInvite.textContent = I18n.getTranslation("htmlPages.addBot");
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,16 +1,25 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jank Client</title>
|
<title>Jank Client</title>
|
||||||
<meta content="Bot Invite" property="og:title">
|
<meta content="Bot Invite" property="og:title" />
|
||||||
<meta name="description" content="Invite this bot to your server!">
|
<meta name="description" content="Invite this bot to your server!" />
|
||||||
<meta content="/logo.webp" property="og:image">
|
<meta content="/logo.webp" property="og:image" />
|
||||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||||
<link href="/style.css" rel="stylesheet">
|
<link href="/style.css" rel="stylesheet" />
|
||||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
<link href="/themes.css" rel="stylesheet" id="lightcss" />
|
||||||
<style>body.no-theme{background:#16191b;}@media(prefers-color-scheme:light){body.no-theme{background:#9397bd;}}</style>
|
<style>
|
||||||
|
body.no-theme {
|
||||||
|
background: #16191b;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
body.no-theme {
|
||||||
|
background: #9397bd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="no-theme">
|
<body class="no-theme">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class Permissions{
|
|||||||
this.allow = 0n;
|
this.allow = 0n;
|
||||||
this.deny = 0n;
|
this.deny = 0n;
|
||||||
console.error(
|
console.error(
|
||||||
`Something really stupid happened with a permission with allow being ${allow} and deny being, ${deny}, execution will still happen, but something really stupid happened, please report if you know what caused this.`
|
`Something really stupid happened with a permission with allow being ${allow} and deny being, ${deny}, execution will still happen, but something really stupid happened, please report if you know what caused this.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ class Permissions{
|
|||||||
name: thing,
|
name: thing,
|
||||||
readableName: I18n.getTranslation("permissions.readableNames." + thing),
|
readableName: I18n.getTranslation("permissions.readableNames." + thing),
|
||||||
description: I18n.getTranslation("permissions.descriptions." + thing),
|
description: I18n.getTranslation("permissions.descriptions." + thing),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static permisions = [
|
static permisions = [
|
||||||
@@ -83,7 +83,7 @@ class Permissions{
|
|||||||
"USE_EXTERNAL_SOUNDS",
|
"USE_EXTERNAL_SOUNDS",
|
||||||
"SEND_VOICE_MESSAGES",
|
"SEND_VOICE_MESSAGES",
|
||||||
"SEND_POLLS",
|
"SEND_POLLS",
|
||||||
"USE_EXTERNAL_APPS"
|
"USE_EXTERNAL_APPS",
|
||||||
];
|
];
|
||||||
getPermission(name: string): number {
|
getPermission(name: string): number {
|
||||||
if (undefined === Permissions.permisions.indexOf(name)) {
|
if (undefined === Permissions.permisions.indexOf(name)) {
|
||||||
@@ -91,9 +91,7 @@ class Permissions{
|
|||||||
}
|
}
|
||||||
if (this.getPermissionbit(Permissions.permisions.indexOf(name), this.allow)) {
|
if (this.getPermissionbit(Permissions.permisions.indexOf(name), this.allow)) {
|
||||||
return 1;
|
return 1;
|
||||||
}else if(
|
} else if (this.getPermissionbit(Permissions.permisions.indexOf(name), this.deny)) {
|
||||||
this.getPermissionbit(Permissions.permisions.indexOf(name), this.deny)
|
|
||||||
){
|
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -102,11 +100,10 @@ class Permissions{
|
|||||||
hasPermission(name: string, adminOverride = true): boolean {
|
hasPermission(name: string, adminOverride = true): boolean {
|
||||||
if (this.deny) {
|
if (this.deny) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"This function may of been used in error, think about using getPermision instead"
|
"This function may of been used in error, think about using getPermision instead",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if(this.getPermissionbit(Permissions.permisions.indexOf(name), this.allow))
|
if (this.getPermissionbit(Permissions.permisions.indexOf(name), this.allow)) return true;
|
||||||
return true;
|
|
||||||
if (name !== "ADMINISTRATOR" && adminOverride) return this.hasPermission("ADMINISTRATOR");
|
if (name !== "ADMINISTRATOR" && adminOverride) return this.hasPermission("ADMINISTRATOR");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -114,11 +111,7 @@ class Permissions{
|
|||||||
const bit = Permissions.permisions.indexOf(name);
|
const bit = Permissions.permisions.indexOf(name);
|
||||||
if (bit === undefined) {
|
if (bit === undefined) {
|
||||||
return console.error(
|
return console.error(
|
||||||
"Tried to set permission to " +
|
"Tried to set permission to " + setto + " for " + name + " but it doesn't exist",
|
||||||
setto +
|
|
||||||
" for " +
|
|
||||||
name +
|
|
||||||
" but it doesn't exist"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,25 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Jank Client</title>
|
<title>Jank Client</title>
|
||||||
<meta content="Jank Client" property="og:title">
|
<meta content="Jank Client" property="og:title" />
|
||||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description">
|
<meta content="A spacebar client that has DMs, replying and more" property="og:description" />
|
||||||
<meta content="/logo.webp" property="og:image">
|
<meta content="/logo.webp" property="og:image" />
|
||||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color">
|
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||||
<link href="/style.css" rel="stylesheet">
|
<link href="/style.css" rel="stylesheet" />
|
||||||
<link href="/themes.css" rel="stylesheet" id="lightcss">
|
<link href="/themes.css" rel="stylesheet" id="lightcss" />
|
||||||
<style>body.no-theme{background:#16191b;}@media(prefers-color-scheme:light){body.no-theme{background:#9397bd;}}</style>
|
<style>
|
||||||
|
body.no-theme {
|
||||||
|
background: #16191b;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
body.no-theme {
|
||||||
|
background: #9397bd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="no-theme">
|
<body class="no-theme">
|
||||||
<div id="logindiv">
|
<div id="logindiv">
|
||||||
@@ -19,41 +28,53 @@
|
|||||||
<div>
|
<div>
|
||||||
<label for="instance" id="instanceField"><b>Instance:</b></label>
|
<label for="instance" id="instanceField"><b>Instance:</b></label>
|
||||||
<p id="verify"></p>
|
<p id="verify"></p>
|
||||||
<input type="search" list="instances" placeholder="Instance URL" id="instancein" name="instance" value="" required>
|
<input
|
||||||
|
type="search"
|
||||||
|
list="instances"
|
||||||
|
placeholder="Instance URL"
|
||||||
|
id="instancein"
|
||||||
|
name="instance"
|
||||||
|
value=""
|
||||||
|
required
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="uname" id="emailField"><b>Email:</b></label>
|
<label for="uname" id="emailField"><b>Email:</b></label>
|
||||||
<input type="text" placeholder="Enter Email" name="uname" id="uname" required>
|
<input type="text" placeholder="Enter Email" name="uname" id="uname" required />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="uname" id="userField"><b>Username:</b></label>
|
<label for="uname" id="userField"><b>Username:</b></label>
|
||||||
<input type="text" placeholder="Enter Username" name="username" id="username" required>
|
<input type="text" placeholder="Enter Username" name="username" id="username" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="psw" id="pwField"><b>Password:</b></label>
|
<label for="psw" id="pwField"><b>Password:</b></label>
|
||||||
<input type="password" placeholder="Enter Password" name="psw" id="psw" required>
|
<input type="password" placeholder="Enter Password" name="psw" id="psw" required />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="psw2" id="pw2Field"><b>Enter password again:</b></label>
|
<label for="psw2" id="pw2Field"><b>Enter password again:</b></label>
|
||||||
<input type="password" placeholder="Enter Password Again" name="psw2" id="psw2" required>
|
<input
|
||||||
|
type="password"
|
||||||
|
placeholder="Enter Password Again"
|
||||||
|
name="psw2"
|
||||||
|
id="psw2"
|
||||||
|
required
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="date" id="dobField"><b>Date of birth:</b></label>
|
<label for="date" id="dobField"><b>Date of birth:</b></label>
|
||||||
<input type="date" id="date" name="date">
|
<input type="date" id="date" name="date" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<b id="TOSbox">I agree to the <a href="" id="TOSa">Terms of Service</a>:</b>
|
<b id="TOSbox">I agree to the <a href="" id="TOSa">Terms of Service</a>:</b>
|
||||||
<input type="checkbox" id="TOS" name="TOS">
|
<input type="checkbox" id="TOS" name="TOS" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="wrongred" id="wrong"></p>
|
<p class="wrongred" id="wrong"></p>
|
||||||
<div id="h-captcha">
|
<div id="h-captcha"></div>
|
||||||
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="dontgrow" id="createAccount">Create account</button>
|
<button type="submit" class="dontgrow" id="createAccount">Create account</button>
|
||||||
</form>
|
</form>
|
||||||
<a href="/login.html" id="switch" id="alreadyHave">Already have an account?</a>
|
<a href="/login.html" id="switch" id="alreadyHave">Already have an account?</a>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { I18n } from "./i18n.js";
|
|||||||
import {checkInstance} from "./utils/utils.js";
|
import {checkInstance} from "./utils/utils.js";
|
||||||
import {adduser} from "./login.js";
|
import {adduser} from "./login.js";
|
||||||
import {MarkDown} from "./markdown.js";
|
import {MarkDown} from "./markdown.js";
|
||||||
await I18n.done
|
await I18n.done;
|
||||||
const registerElement = document.getElementById("register");
|
const registerElement = document.getElementById("register");
|
||||||
if (registerElement) {
|
if (registerElement) {
|
||||||
registerElement.addEventListener("submit", registertry);
|
registerElement.addEventListener("submit", registertry);
|
||||||
@@ -15,17 +15,16 @@ if(registerElement){
|
|||||||
const createAccount = document.getElementById("createAccount");
|
const createAccount = document.getElementById("createAccount");
|
||||||
const alreadyHave = document.getElementById("alreadyHave");
|
const alreadyHave = document.getElementById("alreadyHave");
|
||||||
if (userField && pw2Field && alreadyHave && createAccount && dobField) {
|
if (userField && pw2Field && alreadyHave && createAccount && dobField) {
|
||||||
userField.textContent=I18n.getTranslation("htmlPages.userField")
|
userField.textContent = I18n.getTranslation("htmlPages.userField");
|
||||||
pw2Field.textContent=I18n.getTranslation("htmlPages.pw2Field")
|
pw2Field.textContent = I18n.getTranslation("htmlPages.pw2Field");
|
||||||
dobField.textContent=I18n.getTranslation("htmlPages.dobField")
|
dobField.textContent = I18n.getTranslation("htmlPages.dobField");
|
||||||
createAccount.textContent=I18n.getTranslation("htmlPages.createAccount")
|
createAccount.textContent = I18n.getTranslation("htmlPages.createAccount");
|
||||||
alreadyHave.textContent=I18n.getTranslation("htmlPages.alreadyHave")
|
alreadyHave.textContent = I18n.getTranslation("htmlPages.alreadyHave");
|
||||||
}
|
}
|
||||||
})()
|
})();
|
||||||
async function registertry(e: Event) {
|
async function registertry(e: Event) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const elements = (e.target as HTMLFormElement)
|
const elements = (e.target as HTMLFormElement).elements as HTMLFormControlsCollection;
|
||||||
.elements as HTMLFormControlsCollection;
|
|
||||||
const email = (elements[1] as HTMLInputElement).value;
|
const email = (elements[1] as HTMLInputElement).value;
|
||||||
const username = (elements[2] as HTMLInputElement).value;
|
const username = (elements[2] as HTMLInputElement).value;
|
||||||
const password = (elements[3] as HTMLInputElement).value;
|
const password = (elements[3] as HTMLInputElement).value;
|
||||||
@@ -35,7 +34,9 @@ async function registertry(e: Event){
|
|||||||
const captchaKey = (elements[7] as HTMLInputElement)?.value;
|
const captchaKey = (elements[7] as HTMLInputElement)?.value;
|
||||||
|
|
||||||
if (password !== confirmPassword) {
|
if (password !== confirmPassword) {
|
||||||
(document.getElementById("wrong") as HTMLElement).textContent = I18n.getTranslation("localuser.PasswordsNoMatch");
|
(document.getElementById("wrong") as HTMLElement).textContent = I18n.getTranslation(
|
||||||
|
"localuser.PasswordsNoMatch",
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,22 +100,22 @@ function handleErrors(errors: any, elements: HTMLFormControlsCollection){
|
|||||||
} else if (errors.password) {
|
} else if (errors.password) {
|
||||||
showError(
|
showError(
|
||||||
elements[3] as HTMLElement,
|
elements[3] as HTMLElement,
|
||||||
I18n.getTranslation("register.passwordError",errors.password._errors[0].message)
|
I18n.getTranslation("register.passwordError", errors.password._errors[0].message),
|
||||||
);
|
);
|
||||||
} else if (errors.username) {
|
} else if (errors.username) {
|
||||||
showError(
|
showError(
|
||||||
elements[2] as HTMLElement,
|
elements[2] as HTMLElement,
|
||||||
I18n.getTranslation("register.usernameError",errors.username._errors[0].message)
|
I18n.getTranslation("register.usernameError", errors.username._errors[0].message),
|
||||||
);
|
);
|
||||||
} else if (errors.email) {
|
} else if (errors.email) {
|
||||||
showError(
|
showError(
|
||||||
elements[1] as HTMLElement,
|
elements[1] as HTMLElement,
|
||||||
I18n.getTranslation("register.emailError",errors.email._errors[0].message)
|
I18n.getTranslation("register.emailError", errors.email._errors[0].message),
|
||||||
);
|
);
|
||||||
} else if (errors.date_of_birth) {
|
} else if (errors.date_of_birth) {
|
||||||
showError(
|
showError(
|
||||||
elements[5] as HTMLElement,
|
elements[5] as HTMLElement,
|
||||||
I18n.getTranslation("register.DOBError",errors.date_of_birth._errors[0].message)
|
I18n.getTranslation("register.DOBError", errors.date_of_birth._errors[0].message),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
(document.getElementById("wrong") as HTMLElement).textContent =
|
(document.getElementById("wrong") as HTMLElement).textContent =
|
||||||
@@ -124,9 +125,7 @@ errors[Object.keys(errors)[0]]._errors[0].message;
|
|||||||
|
|
||||||
function showError(element: HTMLElement, message: string) {
|
function showError(element: HTMLElement, message: string) {
|
||||||
const parent = element.parentElement!;
|
const parent = element.parentElement!;
|
||||||
let errorElement = parent.getElementsByClassName(
|
let errorElement = parent.getElementsByClassName("suberror")[0] as HTMLElement;
|
||||||
"suberror"
|
|
||||||
)[0] as HTMLElement;
|
|
||||||
if (!errorElement) {
|
if (!errorElement) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("suberror", "suberrora");
|
div.classList.add("suberror", "suberrora");
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class Role extends SnowFlake{
|
|||||||
canManage() {
|
canManage() {
|
||||||
if (this.guild.member.hasPermission("MANAGE_ROLES")) {
|
if (this.guild.member.hasPermission("MANAGE_ROLES")) {
|
||||||
let max = -Infinity;
|
let max = -Infinity;
|
||||||
this.guild.member.roles.forEach(r=>max=Math.max(max,r.position))
|
this.guild.member.roles.forEach((r) => (max = Math.max(max, r.position)));
|
||||||
return this.position <= max || this.guild.properties.owner_id === this.guild.member.id;
|
return this.position <= max || this.guild.properties.owner_id === this.guild.member.id;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -70,11 +70,7 @@ class PermissionToggle implements OptionsElement<number>{
|
|||||||
permissions: Permissions;
|
permissions: Permissions;
|
||||||
owner: Options;
|
owner: Options;
|
||||||
value!: number;
|
value!: number;
|
||||||
constructor(
|
constructor(roleJSON: PermissionToggle["rolejson"], permissions: Permissions, owner: Options) {
|
||||||
roleJSON: PermissionToggle["rolejson"],
|
|
||||||
permissions: Permissions,
|
|
||||||
owner: Options
|
|
||||||
){
|
|
||||||
this.rolejson = roleJSON;
|
this.rolejson = roleJSON;
|
||||||
this.permissions = permissions;
|
this.permissions = permissions;
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
@@ -106,7 +102,7 @@ class PermissionToggle implements OptionsElement<number>{
|
|||||||
if (state === 1) {
|
if (state === 1) {
|
||||||
on.checked = true;
|
on.checked = true;
|
||||||
}
|
}
|
||||||
on.onclick = _=>{
|
on.onclick = (_) => {
|
||||||
this.permissions.setPermission(this.rolejson.name, 1);
|
this.permissions.setPermission(this.rolejson.name, 1);
|
||||||
this.owner.changed();
|
this.owner.changed();
|
||||||
};
|
};
|
||||||
@@ -118,7 +114,7 @@ class PermissionToggle implements OptionsElement<number>{
|
|||||||
if (state === 0) {
|
if (state === 0) {
|
||||||
no.checked = true;
|
no.checked = true;
|
||||||
}
|
}
|
||||||
no.onclick = _=>{
|
no.onclick = (_) => {
|
||||||
this.permissions.setPermission(this.rolejson.name, 0);
|
this.permissions.setPermission(this.rolejson.name, 0);
|
||||||
this.owner.changed();
|
this.owner.changed();
|
||||||
};
|
};
|
||||||
@@ -130,7 +126,7 @@ class PermissionToggle implements OptionsElement<number>{
|
|||||||
if (state === -1) {
|
if (state === -1) {
|
||||||
off.checked = true;
|
off.checked = true;
|
||||||
}
|
}
|
||||||
off.onclick = _=>{
|
off.onclick = (_) => {
|
||||||
this.permissions.setPermission(this.rolejson.name, -1);
|
this.permissions.setPermission(this.rolejson.name, -1);
|
||||||
this.owner.changed();
|
this.owner.changed();
|
||||||
};
|
};
|
||||||
@@ -158,7 +154,12 @@ class RoleList extends Buttons{
|
|||||||
get headers() {
|
get headers() {
|
||||||
return this.guild.headers;
|
return this.guild.headers;
|
||||||
}
|
}
|
||||||
constructor(permissions:[Role, Permissions][], guild:Guild, onchange:Function, channel:false|Channel){
|
constructor(
|
||||||
|
permissions: [Role, Permissions][],
|
||||||
|
guild: Guild,
|
||||||
|
onchange: Function,
|
||||||
|
channel: false | Channel,
|
||||||
|
) {
|
||||||
super("");
|
super("");
|
||||||
this.guild = guild;
|
this.guild = guild;
|
||||||
this.permissions = permissions;
|
this.permissions = permissions;
|
||||||
@@ -172,9 +173,7 @@ class RoleList extends Buttons{
|
|||||||
}
|
}
|
||||||
this.makeguildmenus(options);
|
this.makeguildmenus(options);
|
||||||
for (const thing of Permissions.info()) {
|
for (const thing of Permissions.info()) {
|
||||||
options.options.push(
|
options.options.push(new PermissionToggle(thing, this.permission, options));
|
||||||
new PermissionToggle(thing, this.permission, options)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
for (const i of permissions) {
|
for (const i of permissions) {
|
||||||
this.buttons.push([i[0].name, i[0].id]);
|
this.buttons.push([i[0].name, i[0].id]);
|
||||||
@@ -192,15 +191,15 @@ class RoleList extends Buttons{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (added === -1) {
|
if (added === -1) {
|
||||||
this.permissions=this.permissions.filter(r=>r[0]!==role);
|
this.permissions = this.permissions.filter((r) => r[0] !== role);
|
||||||
}
|
}
|
||||||
this.redoButtons();
|
this.redoButtons();
|
||||||
}
|
}
|
||||||
private croleUpdate(role: Role, perm: Permissions, added: boolean) {
|
private croleUpdate(role: Role, perm: Permissions, added: boolean) {
|
||||||
if (added) {
|
if (added) {
|
||||||
this.permissions.push([role,perm])
|
this.permissions.push([role, perm]);
|
||||||
} else {
|
} else {
|
||||||
this.permissions=this.permissions.filter(r=>r[0]!==role);
|
this.permissions = this.permissions.filter((r) => r[0] !== role);
|
||||||
}
|
}
|
||||||
this.redoButtons();
|
this.redoButtons();
|
||||||
}
|
}
|
||||||
@@ -212,51 +211,59 @@ class RoleList extends Buttons{
|
|||||||
fetchURL: this.info.api + "/guilds/" + this.guild.id + "/roles/" + this.curid,
|
fetchURL: this.info.api + "/guilds/" + this.guild.id + "/roles/" + this.curid,
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
traditionalSubmit:true
|
traditionalSubmit: true,
|
||||||
});
|
});
|
||||||
form.addTextInput(I18n.getTranslation("role.name"), "name", {
|
form.addTextInput(I18n.getTranslation("role.name"), "name", {
|
||||||
initText:role.name
|
initText: role.name,
|
||||||
});
|
});
|
||||||
form.addCheckboxInput(I18n.getTranslation("role.hoisted"), "hoist", {
|
form.addCheckboxInput(I18n.getTranslation("role.hoisted"), "hoist", {
|
||||||
initState:role.hoist
|
initState: role.hoist,
|
||||||
});
|
});
|
||||||
form.addCheckboxInput(I18n.getTranslation("role.mentionable"), "mentionable", {
|
form.addCheckboxInput(I18n.getTranslation("role.mentionable"), "mentionable", {
|
||||||
initState:role.mentionable
|
initState: role.mentionable,
|
||||||
});
|
});
|
||||||
const color = "#" + role.color.toString(16).padStart(6, "0");
|
const color = "#" + role.color.toString(16).padStart(6, "0");
|
||||||
form.addColorInput(I18n.getTranslation("role.color"), "color", {
|
form.addColorInput(I18n.getTranslation("role.color"), "color", {
|
||||||
initColor:color
|
initColor: color,
|
||||||
});
|
});
|
||||||
form.addPreprocessor((obj: any) => {
|
form.addPreprocessor((obj: any) => {
|
||||||
obj.color = Number("0x" + obj.color.substring(1));
|
obj.color = Number("0x" + obj.color.substring(1));
|
||||||
console.log(obj.color);
|
console.log(obj.color);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
static channelrolemenu = this.ChannelRoleMenu();
|
static channelrolemenu = this.ChannelRoleMenu();
|
||||||
static guildrolemenu = this.GuildRoleMenu();
|
static guildrolemenu = this.GuildRoleMenu();
|
||||||
private static ChannelRoleMenu() {
|
private static ChannelRoleMenu() {
|
||||||
const menu = new Contextmenu<RoleList, Role>("role settings");
|
const menu = new Contextmenu<RoleList, Role>("role settings");
|
||||||
menu.addbutton(()=>I18n.getTranslation("role.remove"),function(role){
|
menu.addbutton(
|
||||||
|
() => I18n.getTranslation("role.remove"),
|
||||||
|
function (role) {
|
||||||
if (!this.channel) return;
|
if (!this.channel) return;
|
||||||
console.log(role);
|
console.log(role);
|
||||||
fetch(this.info.api + "/channels/" + this.channel.id + "/permissions/" + role.id, {
|
fetch(this.info.api + "/channels/" + this.channel.id + "/permissions/" + role.id, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers:this.headers
|
headers: this.headers,
|
||||||
})
|
});
|
||||||
},null);
|
},
|
||||||
|
null,
|
||||||
|
);
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
private static GuildRoleMenu() {
|
private static GuildRoleMenu() {
|
||||||
const menu = new Contextmenu<RoleList, Role>("role settings");
|
const menu = new Contextmenu<RoleList, Role>("role settings");
|
||||||
menu.addbutton(()=>I18n.getTranslation("role.delete"),function(role){
|
menu.addbutton(
|
||||||
|
() => I18n.getTranslation("role.delete"),
|
||||||
|
function (role) {
|
||||||
if (!confirm(I18n.getTranslation("role.confirmDelete"))) return;
|
if (!confirm(I18n.getTranslation("role.confirmDelete"))) return;
|
||||||
console.log(role);
|
console.log(role);
|
||||||
fetch(this.info.api + "/guilds/" + this.guild.id + "/roles/" + role.id, {
|
fetch(this.info.api + "/guilds/" + this.guild.id + "/roles/" + role.id, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers:this.headers
|
headers: this.headers,
|
||||||
})
|
});
|
||||||
},null);
|
},
|
||||||
|
null,
|
||||||
|
);
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
redoButtons() {
|
redoButtons() {
|
||||||
@@ -265,7 +272,7 @@ class RoleList extends Buttons{
|
|||||||
for (const i of this.permissions) {
|
for (const i of this.permissions) {
|
||||||
this.buttons.push([i[0].name, i[0].id]);
|
this.buttons.push([i[0].name, i[0].id]);
|
||||||
}
|
}
|
||||||
console.log("in here :P")
|
console.log("in here :P");
|
||||||
if (!this.buttonList) return;
|
if (!this.buttonList) return;
|
||||||
console.log("in here :P");
|
console.log("in here :P");
|
||||||
const elms = Array.from(this.buttonList.children);
|
const elms = Array.from(this.buttonList.children);
|
||||||
@@ -279,7 +286,7 @@ class RoleList extends Buttons{
|
|||||||
dragged?: HTMLButtonElement;
|
dragged?: HTMLButtonElement;
|
||||||
buttonDragEvents(button: HTMLButtonElement, role: Role) {
|
buttonDragEvents(button: HTMLButtonElement, role: Role) {
|
||||||
this.buttonMap.set(button, role);
|
this.buttonMap.set(button, role);
|
||||||
button.addEventListener("dragstart", e=>{
|
button.addEventListener("dragstart", (e) => {
|
||||||
this.dragged = button;
|
this.dragged = button;
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
});
|
});
|
||||||
@@ -288,18 +295,18 @@ class RoleList extends Buttons{
|
|||||||
this.dragged = undefined;
|
this.dragged = undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
button.addEventListener("dragenter", event=>{
|
button.addEventListener("dragenter", (event) => {
|
||||||
console.log("enter");
|
console.log("enter");
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
button.addEventListener("dragover", event=>{
|
button.addEventListener("dragover", (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
button.addEventListener("drop", _=>{
|
button.addEventListener("drop", (_) => {
|
||||||
const role2 = this.buttonMap.get(this.dragged as HTMLButtonElement);
|
const role2 = this.buttonMap.get(this.dragged as HTMLButtonElement);
|
||||||
if (!role2) return;
|
if (!role2) return;
|
||||||
const index2 = this.guild.roles.indexOf(role2);
|
const index2 = this.guild.roles.indexOf(role2);
|
||||||
@@ -325,7 +332,7 @@ class RoleList extends Buttons{
|
|||||||
if (this.channel) {
|
if (this.channel) {
|
||||||
const roles: [Role, string[]][] = [];
|
const roles: [Role, string[]][] = [];
|
||||||
for (const role of this.guild.roles) {
|
for (const role of this.guild.roles) {
|
||||||
if(this.permissions.find(r=>r[0]==role)){
|
if (this.permissions.find((r) => r[0] == role)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
roles.push([role, [role.name]]);
|
roles.push([role, [role.name]]);
|
||||||
@@ -334,7 +341,6 @@ class RoleList extends Buttons{
|
|||||||
|
|
||||||
const found = await search.find(box.left, box.top);
|
const found = await search.find(box.left, box.top);
|
||||||
|
|
||||||
|
|
||||||
if (!found) return;
|
if (!found) return;
|
||||||
console.log(found);
|
console.log(found);
|
||||||
this.onchange(found.id, new Permissions("0", "0"));
|
this.onchange(found.id, new Permissions("0", "0"));
|
||||||
@@ -345,7 +351,7 @@ class RoleList extends Buttons{
|
|||||||
bar.type = "text";
|
bar.type = "text";
|
||||||
div.style.left = (box.left ^ 0) + "px";
|
div.style.left = (box.left ^ 0) + "px";
|
||||||
div.style.top = (box.top ^ 0) + "px";
|
div.style.top = (box.top ^ 0) + "px";
|
||||||
div.append(bar)
|
div.append(bar);
|
||||||
document.body.append(div);
|
document.body.append(div);
|
||||||
if (Contextmenu.currentmenu != "") {
|
if (Contextmenu.currentmenu != "") {
|
||||||
Contextmenu.currentmenu.remove();
|
Contextmenu.currentmenu.remove();
|
||||||
@@ -354,7 +360,7 @@ class RoleList extends Buttons{
|
|||||||
Contextmenu.keepOnScreen(div);
|
Contextmenu.keepOnScreen(div);
|
||||||
bar.onchange = () => {
|
bar.onchange = () => {
|
||||||
div.remove();
|
div.remove();
|
||||||
console.log(bar.value)
|
console.log(bar.value);
|
||||||
if (bar.value === "") return;
|
if (bar.value === "") return;
|
||||||
fetch(this.info.api + `/guilds/${this.guild.id}/roles`, {
|
fetch(this.info.api + `/guilds/${this.guild.id}/roles`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -362,12 +368,12 @@ class RoleList extends Buttons{
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
color: 0,
|
color: 0,
|
||||||
name: bar.value,
|
name: bar.value,
|
||||||
permissions:""
|
permissions: "",
|
||||||
})
|
}),
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
roleRow.append(add);
|
roleRow.append(add);
|
||||||
|
|
||||||
buttonTable.append(roleRow);
|
buttonTable.append(roleRow);
|
||||||
@@ -381,15 +387,15 @@ class RoleList extends Buttons{
|
|||||||
if (role.canManage()) {
|
if (role.canManage()) {
|
||||||
this.buttonDragEvents(button, role);
|
this.buttonDragEvents(button, role);
|
||||||
button.draggable = true;
|
button.draggable = true;
|
||||||
RoleList.guildrolemenu.bindContextmenu(button,this,role)
|
RoleList.guildrolemenu.bindContextmenu(button, this, role);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (role.canManage()) {
|
if (role.canManage()) {
|
||||||
RoleList.channelrolemenu.bindContextmenu(button,this,role)
|
RoleList.channelrolemenu.bindContextmenu(button, this, role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button.onclick = _=>{
|
button.onclick = (_) => {
|
||||||
this.generateHTMLArea(thing[1], html);
|
this.generateHTMLArea(thing[1], html);
|
||||||
if (this.warndiv) {
|
if (this.warndiv) {
|
||||||
this.warndiv.remove();
|
this.warndiv.remove();
|
||||||
@@ -408,12 +414,12 @@ class RoleList extends Buttons{
|
|||||||
}
|
}
|
||||||
handleString(str: string): HTMLElement {
|
handleString(str: string): HTMLElement {
|
||||||
this.curid = str;
|
this.curid = str;
|
||||||
const arr = this.permissions.find(_=>_[0].id === str);
|
const arr = this.permissions.find((_) => _[0].id === str);
|
||||||
if (arr) {
|
if (arr) {
|
||||||
const perm = arr[1];
|
const perm = arr[1];
|
||||||
this.permission.deny = perm.deny;
|
this.permission.deny = perm.deny;
|
||||||
this.permission.allow = perm.allow;
|
this.permission.allow = perm.allow;
|
||||||
const role = this.permissions.find(e=>e[0].id === str);
|
const role = this.permissions.find((e) => e[0].id === str);
|
||||||
if (role) {
|
if (role) {
|
||||||
this.options.name = role[0].name;
|
this.options.name = role[0].name;
|
||||||
this.options.haschanged = false;
|
this.options.haschanged = false;
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ class Search<E>{
|
|||||||
options: Map<string, E>;
|
options: Map<string, E>;
|
||||||
readonly keys: string[];
|
readonly keys: string[];
|
||||||
constructor(options: [E, string[]][]) {
|
constructor(options: [E, string[]][]) {
|
||||||
const map=options.flatMap(e=>{
|
const map = options.flatMap((e) => {
|
||||||
const val=e[1].map(f=>[f,e[0]]);
|
const val = e[1].map((f) => [f, e[0]]);
|
||||||
return val as [string, E][];
|
return val as [string, E][];
|
||||||
})
|
});
|
||||||
this.options = new Map(map);
|
this.options = new Map(map);
|
||||||
this.keys = [...this.options.keys()];
|
this.keys = [...this.options.keys()];
|
||||||
}
|
}
|
||||||
generateList(str: string, max: number, res: (e: E) => void) {
|
generateList(str: string, max: number, res: (e: E) => void) {
|
||||||
str = str.toLowerCase();
|
str = str.toLowerCase();
|
||||||
const options=this.keys.filter(e=>{
|
const options = this.keys.filter((e) => {
|
||||||
return e.toLowerCase().includes(str)
|
return e.toLowerCase().includes(str);
|
||||||
});
|
});
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("OptionList", "flexttb");
|
div.classList.add("OptionList", "flexttb");
|
||||||
@@ -23,15 +23,14 @@ class Search<E>{
|
|||||||
hoption.textContent = option;
|
hoption.textContent = option;
|
||||||
hoption.onclick = () => {
|
hoption.onclick = () => {
|
||||||
if (!this.options.has(option)) return;
|
if (!this.options.has(option)) return;
|
||||||
res(this.options.get(option) as E)
|
res(this.options.get(option) as E);
|
||||||
}
|
};
|
||||||
div.append(hoption);
|
div.append(hoption);
|
||||||
}
|
}
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
async find(x: number, y: number, max = 4): Promise<E | undefined> {
|
async find(x: number, y: number, max = 4): Promise<E | undefined> {
|
||||||
return new Promise<E | undefined>((res) => {
|
return new Promise<E | undefined>((res) => {
|
||||||
|
|
||||||
const container = document.createElement("div");
|
const container = document.createElement("div");
|
||||||
container.classList.add("fixedsearch");
|
container.classList.add("fixedsearch");
|
||||||
console.log((x ^ 0) + "", (y ^ 0) + "");
|
console.log((x ^ 0) + "", (y ^ 0) + "");
|
||||||
@@ -41,7 +40,7 @@ class Search<E>{
|
|||||||
container.remove = () => {
|
container.remove = () => {
|
||||||
remove.call(container);
|
remove.call(container);
|
||||||
res(undefined);
|
res(undefined);
|
||||||
}
|
};
|
||||||
|
|
||||||
function resolve(e: E) {
|
function resolve(e: E) {
|
||||||
res(e);
|
res(e);
|
||||||
@@ -53,7 +52,7 @@ class Search<E>{
|
|||||||
const html = this.generateList(bar.value, max, resolve);
|
const html = this.generateList(bar.value, max, resolve);
|
||||||
options.innerHTML = "";
|
options.innerHTML = "";
|
||||||
options.append(html);
|
options.append(html);
|
||||||
}
|
};
|
||||||
bar.oninput = keydown;
|
bar.oninput = keydown;
|
||||||
keydown();
|
keydown();
|
||||||
bar.type = "text";
|
bar.type = "text";
|
||||||
@@ -65,8 +64,7 @@ class Search<E>{
|
|||||||
}
|
}
|
||||||
Contextmenu.currentmenu = container;
|
Contextmenu.currentmenu = container;
|
||||||
Contextmenu.keepOnScreen(container);
|
Contextmenu.keepOnScreen(container);
|
||||||
|
});
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export {Search};
|
export {Search};
|
||||||
|
|||||||
@@ -29,10 +29,13 @@ async function checkCache(){
|
|||||||
lastcache = await promise.text();
|
lastcache = await promise.text();
|
||||||
}
|
}
|
||||||
console.log(lastcache);
|
console.log(lastcache);
|
||||||
fetch("/getupdates").then(async data=>{
|
fetch("/getupdates").then(async (data) => {
|
||||||
setTimeout((_: any)=>{
|
setTimeout(
|
||||||
|
(_: any) => {
|
||||||
checkedrecently = false;
|
checkedrecently = false;
|
||||||
}, 1000 * 60 * 30);
|
},
|
||||||
|
1000 * 60 * 30,
|
||||||
|
);
|
||||||
if (!data.ok) return;
|
if (!data.ok) return;
|
||||||
const text = await data.clone().text();
|
const text = await data.clone().text();
|
||||||
console.log(text, lastcache);
|
console.log(text, lastcache);
|
||||||
@@ -51,7 +54,6 @@ function samedomain(url: string | URL){
|
|||||||
|
|
||||||
const htmlFiles = new Set(["/index", "/login", "/home", "/register", "/oauth2/auth"]);
|
const htmlFiles = new Set(["/index", "/login", "/home", "/register", "/oauth2/auth"]);
|
||||||
|
|
||||||
|
|
||||||
function isHtml(url: string): string | void {
|
function isHtml(url: string): string | void {
|
||||||
const path = new URL(url).pathname;
|
const path = new URL(url).pathname;
|
||||||
if (htmlFiles.has(path) || htmlFiles.has(path + ".html")) {
|
if (htmlFiles.has(path) || htmlFiles.has(path + ".html")) {
|
||||||
@@ -67,9 +69,9 @@ function toPath(url:string):string{
|
|||||||
if (!html) {
|
if (!html) {
|
||||||
const path = Url.pathname;
|
const path = Url.pathname;
|
||||||
if (path.startsWith("/channels")) {
|
if (path.startsWith("/channels")) {
|
||||||
html="./index.html"
|
html = "./index.html";
|
||||||
} else if (path.startsWith("/invite/") || path === "/invite") {
|
} else if (path.startsWith("/invite/") || path === "/invite") {
|
||||||
html="./invite.html"
|
html = "./invite.html";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return html || Url.pathname;
|
return html || Url.pathname;
|
||||||
@@ -77,7 +79,11 @@ function toPath(url:string):string{
|
|||||||
let fails = 0;
|
let fails = 0;
|
||||||
async function getfile(event: FetchEvent): Promise<Response> {
|
async function getfile(event: FetchEvent): Promise<Response> {
|
||||||
checkCache();
|
checkCache();
|
||||||
if(!samedomain(event.request.url)||enabled==="false"||(enabled==="offlineOnly"&&!offline)){
|
if (
|
||||||
|
!samedomain(event.request.url) ||
|
||||||
|
enabled === "false" ||
|
||||||
|
(enabled === "offlineOnly" && !offline)
|
||||||
|
) {
|
||||||
const responce = await fetch(event.request.clone());
|
const responce = await fetch(event.request.clone());
|
||||||
if (samedomain(event.request.url)) {
|
if (samedomain(event.request.url)) {
|
||||||
if (enabled === "offlineOnly" && responce.ok) {
|
if (enabled === "offlineOnly" && responce.ok) {
|
||||||
@@ -115,7 +121,6 @@ async function getfile(event: FetchEvent):Promise<Response>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
self.addEventListener("fetch", (e) => {
|
self.addEventListener("fetch", (e) => {
|
||||||
const event = e as FetchEvent;
|
const event = e as FetchEvent;
|
||||||
try {
|
try {
|
||||||
@@ -139,4 +144,4 @@ self.addEventListener("message", (message)=>{
|
|||||||
deleteoldcache();
|
deleteoldcache();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class Buttons implements OptionsElement<unknown>{
|
|||||||
const button = document.createElement("button");
|
const button = document.createElement("button");
|
||||||
button.classList.add("SettingsButton");
|
button.classList.add("SettingsButton");
|
||||||
button.textContent = thing[0];
|
button.textContent = thing[0];
|
||||||
button.onclick = _=>{
|
button.onclick = (_) => {
|
||||||
this.generateHTMLArea(thing[1], optionsArea);
|
this.generateHTMLArea(thing[1], optionsArea);
|
||||||
if (this.warndiv) {
|
if (this.warndiv) {
|
||||||
this.warndiv.remove();
|
this.warndiv.remove();
|
||||||
@@ -67,10 +67,7 @@ class Buttons implements OptionsElement<unknown>{
|
|||||||
div.textContent = str;
|
div.textContent = str;
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
generateHTMLArea(
|
generateHTMLArea(buttonInfo: Options | string, htmlarea: HTMLElement) {
|
||||||
buttonInfo: Options | string,
|
|
||||||
htmlarea: HTMLElement
|
|
||||||
){
|
|
||||||
let html: HTMLElement;
|
let html: HTMLElement;
|
||||||
if (buttonInfo instanceof Options) {
|
if (buttonInfo instanceof Options) {
|
||||||
buttonInfo.subOptions = undefined;
|
buttonInfo.subOptions = undefined;
|
||||||
@@ -101,7 +98,7 @@ class TextInput implements OptionsElement<string>{
|
|||||||
label: string,
|
label: string,
|
||||||
onSubmit: (str: string) => void,
|
onSubmit: (str: string) => void,
|
||||||
owner: Options,
|
owner: Options,
|
||||||
{ initText = "", password = false } = {}
|
{initText = "", password = false} = {},
|
||||||
) {
|
) {
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.value = initText;
|
this.value = initText;
|
||||||
@@ -131,7 +128,7 @@ class TextInput implements OptionsElement<string>{
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onchange: (str: string) => void = _=>{};
|
onchange: (str: string) => void = (_) => {};
|
||||||
watchForChange(func: (str: string) => void) {
|
watchForChange(func: (str: string) => void) {
|
||||||
this.onchange = func;
|
this.onchange = func;
|
||||||
}
|
}
|
||||||
@@ -190,7 +187,7 @@ class CheckboxInput implements OptionsElement<boolean>{
|
|||||||
label: string,
|
label: string,
|
||||||
onSubmit: (str: boolean) => void,
|
onSubmit: (str: boolean) => void,
|
||||||
owner: Options,
|
owner: Options,
|
||||||
{ initState = false } = {}
|
{initState = false} = {},
|
||||||
) {
|
) {
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.value = initState;
|
this.value = initState;
|
||||||
@@ -228,7 +225,7 @@ class CheckboxInput implements OptionsElement<boolean>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onchange: (str: boolean) => void = _=>{};
|
onchange: (str: boolean) => void = (_) => {};
|
||||||
watchForChange(func: (str: boolean) => void) {
|
watchForChange(func: (str: boolean) => void) {
|
||||||
this.onchange = func;
|
this.onchange = func;
|
||||||
}
|
}
|
||||||
@@ -243,13 +240,7 @@ class ButtonInput implements OptionsElement<void>{
|
|||||||
readonly onClick: () => void;
|
readonly onClick: () => void;
|
||||||
textContent: string;
|
textContent: string;
|
||||||
value!: void;
|
value!: void;
|
||||||
constructor(
|
constructor(label: string, textContent: string, onClick: () => void, owner: Options, {} = {}) {
|
||||||
label: string,
|
|
||||||
textContent: string,
|
|
||||||
onClick: () => void,
|
|
||||||
owner: Options,
|
|
||||||
{} = {}
|
|
||||||
){
|
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.onClick = onClick;
|
this.onClick = onClick;
|
||||||
@@ -287,7 +278,7 @@ class ColorInput implements OptionsElement<string>{
|
|||||||
label: string,
|
label: string,
|
||||||
onSubmit: (str: string) => void,
|
onSubmit: (str: string) => void,
|
||||||
owner: Options,
|
owner: Options,
|
||||||
{ initColor = "" } = {}
|
{initColor = ""} = {},
|
||||||
) {
|
) {
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.colorContent = initColor;
|
this.colorContent = initColor;
|
||||||
@@ -317,7 +308,7 @@ class ColorInput implements OptionsElement<string>{
|
|||||||
this.colorContent = value;
|
this.colorContent = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onchange: (str: string) => void = _=>{};
|
onchange: (str: string) => void = (_) => {};
|
||||||
watchForChange(func: (str: string) => void) {
|
watchForChange(func: (str: string) => void) {
|
||||||
this.onchange = func;
|
this.onchange = func;
|
||||||
}
|
}
|
||||||
@@ -342,7 +333,7 @@ class SelectInput implements OptionsElement<number>{
|
|||||||
onSubmit: (str: number) => void,
|
onSubmit: (str: number) => void,
|
||||||
options: string[],
|
options: string[],
|
||||||
owner: Options,
|
owner: Options,
|
||||||
{ defaultIndex = 0,radio=false } = {}
|
{defaultIndex = 0, radio = false} = {},
|
||||||
) {
|
) {
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.index = defaultIndex;
|
this.index = defaultIndex;
|
||||||
@@ -434,7 +425,7 @@ class SelectInput implements OptionsElement<number>{
|
|||||||
this.index = value;
|
this.index = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onchange: (str: number) => void = _=>{};
|
onchange: (str: number) => void = (_) => {};
|
||||||
watchForChange(func: (str: number) => void) {
|
watchForChange(func: (str: number) => void) {
|
||||||
this.onchange = func;
|
this.onchange = func;
|
||||||
}
|
}
|
||||||
@@ -452,7 +443,7 @@ class MDInput implements OptionsElement<string>{
|
|||||||
label: string,
|
label: string,
|
||||||
onSubmit: (str: string) => void,
|
onSubmit: (str: string) => void,
|
||||||
owner: Options,
|
owner: Options,
|
||||||
{ initText = "" } = {}
|
{initText = ""} = {},
|
||||||
) {
|
) {
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.value = initText;
|
this.value = initText;
|
||||||
@@ -481,7 +472,7 @@ class MDInput implements OptionsElement<string>{
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onchange: (str: string) => void = _=>{};
|
onchange: (str: string) => void = (_) => {};
|
||||||
watchForChange(func: (str: string) => void) {
|
watchForChange(func: (str: string) => void) {
|
||||||
this.onchange = func;
|
this.onchange = func;
|
||||||
}
|
}
|
||||||
@@ -500,7 +491,7 @@ class FileInput implements OptionsElement<FileList | null>{
|
|||||||
label: string,
|
label: string,
|
||||||
onSubmit: (str: FileList | null) => void,
|
onSubmit: (str: FileList | null) => void,
|
||||||
owner: Options,
|
owner: Options,
|
||||||
{ clear = false } = {}
|
{clear = false} = {},
|
||||||
) {
|
) {
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
@@ -522,7 +513,7 @@ class FileInput implements OptionsElement<FileList | null>{
|
|||||||
if (this.clear) {
|
if (this.clear) {
|
||||||
const button = document.createElement("button");
|
const button = document.createElement("button");
|
||||||
button.textContent = "Clear";
|
button.textContent = "Clear";
|
||||||
button.onclick = _=>{
|
button.onclick = (_) => {
|
||||||
if (this.onchange) {
|
if (this.onchange) {
|
||||||
this.onchange(null);
|
this.onchange(null);
|
||||||
}
|
}
|
||||||
@@ -582,7 +573,7 @@ class Float{
|
|||||||
* This is a simple wrapper class for Options to make it happy so it can be used outside of Settings.
|
* 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: true}) {
|
constructor(name: string, options = {ltr: false, noSubmit: true}) {
|
||||||
this.options=new Options(name,this,options)
|
this.options = new Options(name, this, options);
|
||||||
}
|
}
|
||||||
changed = () => {};
|
changed = () => {};
|
||||||
generateHTML() {
|
generateHTML() {
|
||||||
@@ -605,12 +596,12 @@ class Dialog{
|
|||||||
center.classList.add("centeritem", "nonimagecenter");
|
center.classList.add("centeritem", "nonimagecenter");
|
||||||
center.classList.remove("titlediv");
|
center.classList.remove("titlediv");
|
||||||
background.append(center);
|
background.append(center);
|
||||||
center.onclick=e=>{
|
center.onclick = (e) => {
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
}
|
};
|
||||||
document.body.append(background);
|
document.body.append(background);
|
||||||
this.background = new WeakRef(background);
|
this.background = new WeakRef(background);
|
||||||
background.onclick = _=>{
|
background.onclick = (_) => {
|
||||||
background.remove();
|
background.remove();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -630,13 +621,11 @@ class Options implements OptionsElement<void>{
|
|||||||
value!: void;
|
value!: void;
|
||||||
readonly html: WeakMap<OptionsElement<any>, WeakRef<HTMLDivElement>> = new WeakMap();
|
readonly html: WeakMap<OptionsElement<any>, WeakRef<HTMLDivElement>> = new WeakMap();
|
||||||
readonly noSubmit: boolean = false;
|
readonly noSubmit: boolean = false;
|
||||||
container: WeakRef<HTMLDivElement> = new WeakRef(
|
container: WeakRef<HTMLDivElement> = new WeakRef(document.createElement("div"));
|
||||||
document.createElement("div")
|
|
||||||
);
|
|
||||||
constructor(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
owner: Buttons | Options | Form | Float,
|
owner: Buttons | Options | Form | Float,
|
||||||
{ ltr = false, noSubmit=false} = {}
|
{ltr = false, noSubmit = false} = {},
|
||||||
) {
|
) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.options = [];
|
this.options = [];
|
||||||
@@ -678,9 +667,7 @@ class Options implements OptionsElement<void>{
|
|||||||
(this.owner as Form).owner.genTop();
|
(this.owner as Form).owner.genTop();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error("Tried to make a sub menu when the options weren't rendered");
|
||||||
"Tried to make a sub menu when the options weren't rendered"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addSubOptions(name: string, {ltr = false, noSubmit = false} = {}) {
|
addSubOptions(name: string, {ltr = false, noSubmit = false} = {}) {
|
||||||
@@ -699,7 +686,7 @@ class Options implements OptionsElement<void>{
|
|||||||
headers = {},
|
headers = {},
|
||||||
method = "POST",
|
method = "POST",
|
||||||
traditionalSubmit = false,
|
traditionalSubmit = false,
|
||||||
} = {}
|
} = {},
|
||||||
) {
|
) {
|
||||||
const options = new Form(name, this, onSubmit, {
|
const options = new Form(name, this, onSubmit, {
|
||||||
ltr,
|
ltr,
|
||||||
@@ -721,20 +708,17 @@ class Options implements OptionsElement<void>{
|
|||||||
label: string,
|
label: string,
|
||||||
onSubmit: (str: number) => void,
|
onSubmit: (str: number) => void,
|
||||||
selections: string[],
|
selections: string[],
|
||||||
{ defaultIndex = 0,radio=false } = {}
|
{defaultIndex = 0, radio = false} = {},
|
||||||
) {
|
) {
|
||||||
const select = new SelectInput(label, onSubmit, selections, this, {
|
const select = new SelectInput(label, onSubmit, selections, this, {
|
||||||
defaultIndex,radio
|
defaultIndex,
|
||||||
|
radio,
|
||||||
});
|
});
|
||||||
this.options.push(select);
|
this.options.push(select);
|
||||||
this.generate(select);
|
this.generate(select);
|
||||||
return select;
|
return select;
|
||||||
}
|
}
|
||||||
addFileInput(
|
addFileInput(label: string, onSubmit: (files: FileList | null) => void, {clear = false} = {}) {
|
||||||
label: string,
|
|
||||||
onSubmit: (files: FileList | null) => void,
|
|
||||||
{ clear = false } = {}
|
|
||||||
){
|
|
||||||
const FI = new FileInput(label, onSubmit, this, {clear});
|
const FI = new FileInput(label, onSubmit, this, {clear});
|
||||||
this.options.push(FI);
|
this.options.push(FI);
|
||||||
this.generate(FI);
|
this.generate(FI);
|
||||||
@@ -743,7 +727,7 @@ class Options implements OptionsElement<void>{
|
|||||||
addTextInput(
|
addTextInput(
|
||||||
label: string,
|
label: string,
|
||||||
onSubmit: (str: string) => void,
|
onSubmit: (str: string) => void,
|
||||||
{ initText = "", password = false } = {}
|
{initText = "", password = false} = {},
|
||||||
) {
|
) {
|
||||||
const textInput = new TextInput(label, onSubmit, this, {
|
const textInput = new TextInput(label, onSubmit, this, {
|
||||||
initText,
|
initText,
|
||||||
@@ -753,30 +737,19 @@ class Options implements OptionsElement<void>{
|
|||||||
this.generate(textInput);
|
this.generate(textInput);
|
||||||
return textInput;
|
return textInput;
|
||||||
}
|
}
|
||||||
addColorInput(
|
addColorInput(label: string, onSubmit: (str: string) => void, {initColor = ""} = {}) {
|
||||||
label: string,
|
|
||||||
onSubmit: (str: string) => void,
|
|
||||||
{ initColor = "" } = {}
|
|
||||||
){
|
|
||||||
const colorInput = new ColorInput(label, onSubmit, this, {initColor});
|
const colorInput = new ColorInput(label, onSubmit, this, {initColor});
|
||||||
this.options.push(colorInput);
|
this.options.push(colorInput);
|
||||||
this.generate(colorInput);
|
this.generate(colorInput);
|
||||||
return colorInput;
|
return colorInput;
|
||||||
}
|
}
|
||||||
addMDInput(
|
addMDInput(label: string, onSubmit: (str: string) => void, {initText = ""} = {}) {
|
||||||
label: string,
|
|
||||||
onSubmit: (str: string) => void,
|
|
||||||
{ initText = "" } = {}
|
|
||||||
){
|
|
||||||
const mdInput = new MDInput(label, onSubmit, this, {initText});
|
const mdInput = new MDInput(label, onSubmit, this, {initText});
|
||||||
this.options.push(mdInput);
|
this.options.push(mdInput);
|
||||||
this.generate(mdInput);
|
this.generate(mdInput);
|
||||||
return mdInput;
|
return mdInput;
|
||||||
}
|
}
|
||||||
addHTMLArea(
|
addHTMLArea(html: (() => HTMLElement) | HTMLElement, submit: () => void = () => {}) {
|
||||||
html: (() => HTMLElement) | HTMLElement,
|
|
||||||
submit: () => void = ()=>{}
|
|
||||||
){
|
|
||||||
const htmlarea = new HtmlArea(html, submit);
|
const htmlarea = new HtmlArea(html, submit);
|
||||||
this.options.push(htmlarea);
|
this.options.push(htmlarea);
|
||||||
this.generate(htmlarea);
|
this.generate(htmlarea);
|
||||||
@@ -788,11 +761,7 @@ class Options implements OptionsElement<void>{
|
|||||||
this.generate(button);
|
this.generate(button);
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
addCheckboxInput(
|
addCheckboxInput(label: string, onSubmit: (str: boolean) => void, {initState = false} = {}) {
|
||||||
label: string,
|
|
||||||
onSubmit: (str: boolean) => void,
|
|
||||||
{ initState = false } = {}
|
|
||||||
){
|
|
||||||
const box = new CheckboxInput(label, onSubmit, this, {initState});
|
const box = new CheckboxInput(label, onSubmit, this, {initState});
|
||||||
this.options.push(box);
|
this.options.push(box);
|
||||||
this.generate(box);
|
this.generate(box);
|
||||||
@@ -826,7 +795,7 @@ class Options implements OptionsElement<void>{
|
|||||||
headers = {},
|
headers = {},
|
||||||
method = "POST",
|
method = "POST",
|
||||||
traditionalSubmit = false,
|
traditionalSubmit = false,
|
||||||
} = {}
|
} = {},
|
||||||
) {
|
) {
|
||||||
const options = new Form(name, this, onSubmit, {
|
const options = new Form(name, this, onSubmit, {
|
||||||
ltr,
|
ltr,
|
||||||
@@ -898,10 +867,12 @@ class Options implements OptionsElement<void>{
|
|||||||
return build;
|
return build;
|
||||||
}
|
}
|
||||||
isTop() {
|
isTop() {
|
||||||
return (this.owner instanceof Options&&this.owner.subOptions!==this)||
|
return (
|
||||||
|
(this.owner instanceof Options && this.owner.subOptions !== this) ||
|
||||||
(this.owner instanceof Form && this.owner.owner.subOptions !== this.owner) ||
|
(this.owner instanceof Form && this.owner.owner.subOptions !== this.owner) ||
|
||||||
(this.owner instanceof Settings)||
|
this.owner instanceof Settings ||
|
||||||
(this.owner instanceof Buttons);
|
this.owner instanceof Buttons
|
||||||
|
);
|
||||||
}
|
}
|
||||||
generateContainter() {
|
generateContainter() {
|
||||||
const container = this.container.deref();
|
const container = this.container.deref();
|
||||||
@@ -957,7 +928,7 @@ class Options implements OptionsElement<void>{
|
|||||||
this.haschanged = true;
|
this.haschanged = true;
|
||||||
this.owner.changed(div);
|
this.owner.changed(div);
|
||||||
|
|
||||||
button.onclick = _=>{
|
button.onclick = (_) => {
|
||||||
if (this.owner instanceof Buttons) {
|
if (this.owner instanceof Buttons) {
|
||||||
this.owner.save();
|
this.owner.save();
|
||||||
}
|
}
|
||||||
@@ -1013,7 +984,7 @@ class Form implements OptionsElement<object>{
|
|||||||
headers = {},
|
headers = {},
|
||||||
method = "POST",
|
method = "POST",
|
||||||
traditionalSubmit = false,
|
traditionalSubmit = false,
|
||||||
} = {}
|
} = {},
|
||||||
) {
|
) {
|
||||||
this.traditionalSubmit = traditionalSubmit;
|
this.traditionalSubmit = traditionalSubmit;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -1046,17 +1017,24 @@ class Form implements OptionsElement<object>{
|
|||||||
headers = {},
|
headers = {},
|
||||||
method = "POST",
|
method = "POST",
|
||||||
traditionalSubmit = false,
|
traditionalSubmit = false,
|
||||||
} = {}
|
} = {},
|
||||||
) {
|
) {
|
||||||
if (this.button && this.button.deref()) {
|
if (this.button && this.button.deref()) {
|
||||||
console.warn("hidden");
|
console.warn("hidden");
|
||||||
(this.button.deref() as HTMLElement).hidden = true;
|
(this.button.deref() as HTMLElement).hidden = true;
|
||||||
}
|
}
|
||||||
return this.options.addSubForm(name,onSubmit,{ltr,submitText,fetchURL,headers,method,traditionalSubmit});
|
return this.options.addSubForm(name, onSubmit, {
|
||||||
|
ltr,
|
||||||
|
submitText,
|
||||||
|
fetchURL,
|
||||||
|
headers,
|
||||||
|
method,
|
||||||
|
traditionalSubmit,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
generateContainter() {
|
generateContainter() {
|
||||||
this.options.generateContainter();
|
this.options.generateContainter();
|
||||||
if((this.options.isTop())&&this.button&&this.button.deref()){
|
if (this.options.isTop() && this.button && this.button.deref()) {
|
||||||
(this.button.deref() as HTMLElement).hidden = false;
|
(this.button.deref() as HTMLElement).hidden = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1066,10 +1044,11 @@ class Form implements OptionsElement<object>{
|
|||||||
formName: string,
|
formName: string,
|
||||||
selections: string[],
|
selections: string[],
|
||||||
{defaultIndex = 0, required = false, radio = false} = {},
|
{defaultIndex = 0, required = false, radio = false} = {},
|
||||||
correct:(string|number|null)[]=selections
|
correct: (string | number | null)[] = selections,
|
||||||
) {
|
) {
|
||||||
const select = this.options.addSelect(label, _=>{}, selections, {
|
const select = this.options.addSelect(label, (_) => {}, selections, {
|
||||||
defaultIndex,radio
|
defaultIndex,
|
||||||
|
radio,
|
||||||
});
|
});
|
||||||
this.selectMap.set(select, correct);
|
this.selectMap.set(select, correct);
|
||||||
this.names.set(formName, select);
|
this.names.set(formName, select);
|
||||||
@@ -1082,11 +1061,10 @@ class Form implements OptionsElement<object>{
|
|||||||
addFileInput(
|
addFileInput(
|
||||||
label: string,
|
label: string,
|
||||||
formName: string,
|
formName: string,
|
||||||
{ required = false, files = "one", clear = false } = {}
|
{required = false, files = "one", clear = false} = {},
|
||||||
) {
|
) {
|
||||||
const FI = this.options.addFileInput(label, _=>{}, { clear });
|
const FI = this.options.addFileInput(label, (_) => {}, {clear});
|
||||||
if(files !== "one" && files !== "multi")
|
if (files !== "one" && files !== "multi") throw new Error("files should equal one or multi");
|
||||||
throw new Error("files should equal one or multi");
|
|
||||||
this.fileOptions.set(FI, {files});
|
this.fileOptions.set(FI, {files});
|
||||||
this.names.set(formName, FI);
|
this.names.set(formName, FI);
|
||||||
if (required) {
|
if (required) {
|
||||||
@@ -1098,9 +1076,9 @@ class Form implements OptionsElement<object>{
|
|||||||
addTextInput(
|
addTextInput(
|
||||||
label: string,
|
label: string,
|
||||||
formName: string,
|
formName: string,
|
||||||
{ initText = "", required = false, password = false } = {}
|
{initText = "", required = false, password = false} = {},
|
||||||
) {
|
) {
|
||||||
const textInput = this.options.addTextInput(label, _=>{}, {
|
const textInput = this.options.addTextInput(label, (_) => {}, {
|
||||||
initText,
|
initText,
|
||||||
password,
|
password,
|
||||||
});
|
});
|
||||||
@@ -1110,12 +1088,8 @@ class Form implements OptionsElement<object>{
|
|||||||
}
|
}
|
||||||
return textInput;
|
return textInput;
|
||||||
}
|
}
|
||||||
addColorInput(
|
addColorInput(label: string, formName: string, {initColor = "", required = false} = {}) {
|
||||||
label: string,
|
const colorInput = this.options.addColorInput(label, (_) => {}, {
|
||||||
formName: string,
|
|
||||||
{ initColor = "", required = false } = {}
|
|
||||||
){
|
|
||||||
const colorInput = this.options.addColorInput(label, _=>{}, {
|
|
||||||
initColor,
|
initColor,
|
||||||
});
|
});
|
||||||
this.names.set(formName, colorInput);
|
this.names.set(formName, colorInput);
|
||||||
@@ -1125,12 +1099,8 @@ class Form implements OptionsElement<object>{
|
|||||||
return colorInput;
|
return colorInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
addMDInput(
|
addMDInput(label: string, formName: string, {initText = "", required = false} = {}) {
|
||||||
label: string,
|
const mdInput = this.options.addMDInput(label, (_) => {}, {initText});
|
||||||
formName: string,
|
|
||||||
{ initText = "", required = false } = {}
|
|
||||||
){
|
|
||||||
const mdInput = this.options.addMDInput(label, _=>{}, { initText });
|
|
||||||
this.names.set(formName, mdInput);
|
this.names.set(formName, mdInput);
|
||||||
if (required) {
|
if (required) {
|
||||||
this.required.add(mdInput);
|
this.required.add(mdInput);
|
||||||
@@ -1151,12 +1121,8 @@ class Form implements OptionsElement<object>{
|
|||||||
addOptions(name: string, {ltr = false, noSubmit = false} = {}) {
|
addOptions(name: string, {ltr = false, noSubmit = false} = {}) {
|
||||||
return this.options.addOptions(name, {ltr, noSubmit});
|
return this.options.addOptions(name, {ltr, noSubmit});
|
||||||
}
|
}
|
||||||
addCheckboxInput(
|
addCheckboxInput(label: string, formName: string, {initState = false, required = false} = {}) {
|
||||||
label: string,
|
const box = this.options.addCheckboxInput(label, (_) => {}, {initState});
|
||||||
formName: string,
|
|
||||||
{ initState = false, required = false } = {}
|
|
||||||
){
|
|
||||||
const box = this.options.addCheckboxInput(label, _=>{}, { initState });
|
|
||||||
this.names.set(formName, box);
|
this.names.set(formName, box);
|
||||||
if (required) {
|
if (required) {
|
||||||
this.required.add(box);
|
this.required.add(box);
|
||||||
@@ -1179,7 +1145,7 @@ class Form implements OptionsElement<object>{
|
|||||||
div.classList.add("FormSettings");
|
div.classList.add("FormSettings");
|
||||||
if (!this.traditionalSubmit) {
|
if (!this.traditionalSubmit) {
|
||||||
const button = document.createElement("button");
|
const button = document.createElement("button");
|
||||||
button.onclick = _=>{
|
button.onclick = (_) => {
|
||||||
this.submit();
|
this.submit();
|
||||||
};
|
};
|
||||||
button.textContent = this.submitText;
|
button.textContent = this.submitText;
|
||||||
@@ -1191,7 +1157,9 @@ class Form implements OptionsElement<object>{
|
|||||||
}
|
}
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
onSubmit: ((arg1: object,sent:object) => void )|((arg1: object,sent:object) => Promise<void> );
|
onSubmit:
|
||||||
|
| ((arg1: object, sent: object) => void)
|
||||||
|
| ((arg1: object, sent: object) => Promise<void>);
|
||||||
watchForChange(func: (arg1: object) => void) {
|
watchForChange(func: (arg1: object) => void) {
|
||||||
this.onSubmit = func;
|
this.onSubmit = func;
|
||||||
}
|
}
|
||||||
@@ -1244,7 +1212,7 @@ class Form implements OptionsElement<object>{
|
|||||||
const options = this.fileOptions.get(input);
|
const options = this.fileOptions.get(input);
|
||||||
if (!options) {
|
if (!options) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"FileInput without its options is in this form, this should never happen."
|
"FileInput without its options is in this form, this should never happen.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (options.files === "one") {
|
if (options.files === "one") {
|
||||||
@@ -1252,7 +1220,7 @@ class Form implements OptionsElement<object>{
|
|||||||
if (input.value) {
|
if (input.value) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsDataURL(input.value[0]);
|
reader.readAsDataURL(input.value[0]);
|
||||||
const promise = new Promise<void>(res=>{
|
const promise = new Promise<void>((res) => {
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
(build as any)[thing] = reader.result;
|
(build as any)[thing] = reader.result;
|
||||||
res();
|
res();
|
||||||
@@ -1288,13 +1256,14 @@ class Form implements OptionsElement<object>{
|
|||||||
body: JSON.stringify(build),
|
body: JSON.stringify(build),
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
})
|
})
|
||||||
.then(_=>{
|
.then((_) => {
|
||||||
return _.text()
|
return _.text();
|
||||||
}).then(_=>{
|
|
||||||
if(_==="") return {};
|
|
||||||
return JSON.parse(_)
|
|
||||||
})
|
})
|
||||||
.then(async json=>{
|
.then((_) => {
|
||||||
|
if (_ === "") return {};
|
||||||
|
return JSON.parse(_);
|
||||||
|
})
|
||||||
|
.then(async (json) => {
|
||||||
if (json.errors) {
|
if (json.errors) {
|
||||||
if (this.errors(json)) {
|
if (this.errors(json)) {
|
||||||
return;
|
return;
|
||||||
@@ -1334,7 +1303,11 @@ class Form implements OptionsElement<object>{
|
|||||||
}
|
}
|
||||||
console.warn("needs to be implemented");
|
console.warn("needs to be implemented");
|
||||||
}
|
}
|
||||||
errors(errors: {code: number; message: string; errors: { [key: string]: { _errors: { message: string; code: string }[] } }}){
|
errors(errors: {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
errors: {[key: string]: {_errors: {message: string; code: string}[]}};
|
||||||
|
}) {
|
||||||
if (!(errors instanceof Object)) {
|
if (!(errors instanceof Object)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1375,7 +1348,7 @@ class Form implements OptionsElement<object>{
|
|||||||
element = div;
|
element = div;
|
||||||
} else {
|
} else {
|
||||||
element.classList.remove("suberror");
|
element.classList.remove("suberror");
|
||||||
setTimeout(_=>{
|
setTimeout((_) => {
|
||||||
element.classList.add("suberror");
|
element.classList.add("suberror");
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
@@ -1388,8 +1361,8 @@ class HorrizonalRule implements OptionsElement<unknown>{
|
|||||||
return document.createElement("hr");
|
return document.createElement("hr");
|
||||||
}
|
}
|
||||||
watchForChange(_: (arg1: undefined) => void) {
|
watchForChange(_: (arg1: undefined) => void) {
|
||||||
throw new Error("don't do this")
|
throw new Error("don't do this");
|
||||||
};
|
}
|
||||||
submit = () => {};
|
submit = () => {};
|
||||||
value = undefined;
|
value = undefined;
|
||||||
}
|
}
|
||||||
@@ -1419,7 +1392,7 @@ class Settings extends Buttons{
|
|||||||
const exit = document.createElement("span");
|
const exit = document.createElement("span");
|
||||||
exit.classList.add("exitsettings", "svgicon", "svg-x");
|
exit.classList.add("exitsettings", "svgicon", "svg-x");
|
||||||
background.append(exit);
|
background.append(exit);
|
||||||
exit.onclick = _=>{
|
exit.onclick = (_) => {
|
||||||
this.hide();
|
this.hide();
|
||||||
};
|
};
|
||||||
document.body.append(background);
|
document.body.append(background);
|
||||||
|
|||||||
@@ -22,22 +22,23 @@ body {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.searchOptions {
|
.searchOptions {
|
||||||
padding:.05in .15in;
|
padding: 0.05in 0.15in;
|
||||||
border-radius: .1in;
|
border-radius: 0.1in;
|
||||||
background: var(--channels-bg);
|
background: var(--channels-bg);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: calc(100% - 32px);
|
width: calc(100% - 32px);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
> span {
|
> span {
|
||||||
transition: background .1s;
|
transition: background 0.1s;
|
||||||
margin-bottom:.025in;
|
margin-bottom: 0.025in;
|
||||||
margin-top:.025in;
|
margin-top: 0.025in;
|
||||||
padding:.075in .05in;
|
padding: 0.075in 0.05in;
|
||||||
border-radius:.03in;
|
border-radius: 0.03in;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
> span, img{
|
> span,
|
||||||
margin-right:.05in;
|
img {
|
||||||
|
margin-right: 0.05in;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
span.selected {
|
span.selected {
|
||||||
@@ -47,7 +48,7 @@ body {
|
|||||||
background: var(--button-bg);
|
background: var(--button-bg);
|
||||||
}
|
}
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
border: solid .025in var(--black);
|
border: solid 0.025in var(--black);
|
||||||
}
|
}
|
||||||
.searchOptions:empty {
|
.searchOptions:empty {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -62,10 +63,15 @@ body {
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
.channelSTitle {
|
.channelSTitle {
|
||||||
margin-top:.2in;
|
margin-top: 0.2in;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
p, h1, h2, h3, pre, form {
|
p,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
pre,
|
||||||
|
form {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
h2:empty {
|
h2:empty {
|
||||||
@@ -82,13 +88,15 @@ h2:empty {
|
|||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
-webkit-line-clamp: 1;
|
-webkit-line-clamp: 1;
|
||||||
}
|
}
|
||||||
a, .clickable {
|
a,
|
||||||
|
.clickable {
|
||||||
color: var(--link);
|
color: var(--link);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
a:hover, .clickable:hover {
|
a:hover,
|
||||||
|
.clickable:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
.clickable {
|
.clickable {
|
||||||
@@ -99,20 +107,24 @@ hr {
|
|||||||
background: var(--divider);
|
background: var(--divider);
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
pre, samp {
|
pre,
|
||||||
|
samp {
|
||||||
background: var(--code-bg);
|
background: var(--code-bg);
|
||||||
color: var(--code-text);
|
color: var(--code-text);
|
||||||
text-wrap: wrap;
|
text-wrap: wrap;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
video, iframe {
|
video,
|
||||||
|
iframe {
|
||||||
max-height: 50svh;
|
max-height: 50svh;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
audio::-webkit-media-controls-panel {
|
audio::-webkit-media-controls-panel {
|
||||||
background: var(--secondary-bg);
|
background: var(--secondary-bg);
|
||||||
}
|
}
|
||||||
button, input::file-selector-button, select {
|
button,
|
||||||
|
input::file-selector-button,
|
||||||
|
select {
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
background: var(--button-bg);
|
background: var(--button-bg);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
@@ -122,15 +134,17 @@ button, input::file-selector-button, select {
|
|||||||
border: none;
|
border: none;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background .1s ease-in-out;
|
transition: background 0.1s ease-in-out;
|
||||||
}
|
}
|
||||||
input::file-selector-button {
|
input::file-selector-button {
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
button:hover, input::file-selector-button:hover {
|
button:hover,
|
||||||
|
input::file-selector-button:hover {
|
||||||
background: var(--button-hover);
|
background: var(--button-hover);
|
||||||
}
|
}
|
||||||
button:active:enabled, input::file-selector-button:active {
|
button:active:enabled,
|
||||||
|
input::file-selector-button:active {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
button:disabled {
|
button:disabled {
|
||||||
@@ -206,7 +220,8 @@ textarea {
|
|||||||
.pfpDiv {
|
.pfpDiv {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.pfp, .replypfp {
|
.pfp,
|
||||||
|
.replypfp {
|
||||||
display: block;
|
display: block;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
@@ -255,7 +270,7 @@ textarea {
|
|||||||
}
|
}
|
||||||
.svg-upload {
|
.svg-upload {
|
||||||
mask: url(/icons/upload.svg);
|
mask: url(/icons/upload.svg);
|
||||||
width: .2in !important;
|
width: 0.2in !important;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.svg-x {
|
.svg-x {
|
||||||
@@ -301,16 +316,16 @@ textarea {
|
|||||||
.hoverthing {
|
.hoverthing {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: var(--dock-bg);
|
background: var(--dock-bg);
|
||||||
padding:.04in;
|
padding: 0.04in;
|
||||||
border-radius:.05in;
|
border-radius: 0.05in;
|
||||||
transform: translate(-50%, 0);
|
transform: translate(-50%, 0);
|
||||||
transition: opacity .2s;
|
transition: opacity 0.2s;
|
||||||
border: solid .03in var(--black);
|
border: solid 0.03in var(--black);
|
||||||
}
|
}
|
||||||
.editMessage {
|
.editMessage {
|
||||||
background: var(--typebox-bg);
|
background: var(--typebox-bg);
|
||||||
padding: .05in;
|
padding: 0.05in;
|
||||||
border-radius: .04in;
|
border-radius: 0.04in;
|
||||||
}
|
}
|
||||||
#gimmefile {
|
#gimmefile {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -321,15 +336,17 @@ textarea {
|
|||||||
}
|
}
|
||||||
/* Animations */
|
/* Animations */
|
||||||
@keyframes fade {
|
@keyframes fade {
|
||||||
0%, 100% {
|
0%,
|
||||||
opacity: .2;
|
100% {
|
||||||
|
opacity: 0.2;
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@keyframes jumped {
|
@keyframes jumped {
|
||||||
0%, 100% {
|
0%,
|
||||||
|
100% {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
@@ -361,10 +378,14 @@ textarea {
|
|||||||
width: 0px;
|
width: 0px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
#servers::-webkit-scrollbar, #channels::-webkit-scrollbar, #sideDiv::-webkit-scrollbar {
|
#servers::-webkit-scrollbar,
|
||||||
|
#channels::-webkit-scrollbar,
|
||||||
|
#sideDiv::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#servers, #channels, #sideDiv {
|
#servers,
|
||||||
|
#channels,
|
||||||
|
#sideDiv {
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,7 +393,7 @@ textarea {
|
|||||||
#titleDiv {
|
#titleDiv {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background: var(--primary-bg);
|
background: var(--primary-bg);
|
||||||
font-size: .8rem;
|
font-size: 0.8rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -429,11 +450,11 @@ h1.pagehead {
|
|||||||
}
|
}
|
||||||
.instance span {
|
.instance span {
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
font-size: .9rem;
|
font-size: 0.9rem;
|
||||||
color: var(--secondary-text-soft);
|
color: var(--secondary-text-soft);
|
||||||
}
|
}
|
||||||
span.instanceStatus {
|
span.instanceStatus {
|
||||||
font-size: .75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
.instancetextbox h2 {
|
.instancetextbox h2 {
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
@@ -442,7 +463,8 @@ span.instanceStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Login/Invite */
|
/* Login/Invite */
|
||||||
#logindiv, #invitebody {
|
#logindiv,
|
||||||
|
#invitebody {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@@ -456,7 +478,8 @@ span.instanceStatus {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
#logindiv label, #TOSbox {
|
#logindiv label,
|
||||||
|
#TOSbox {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
@@ -534,7 +557,7 @@ span.instanceStatus {
|
|||||||
background: var(--loading-bg, inherit) !important;
|
background: var(--loading-bg, inherit) !important;
|
||||||
color: var(--loading-text);
|
color: var(--loading-text);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: transform .2s;
|
transition: transform 0.2s;
|
||||||
overflow: hidden; /* keep size if window height is too small */
|
overflow: hidden; /* keep size if window height is too small */
|
||||||
}
|
}
|
||||||
#loading.doneloading {
|
#loading.doneloading {
|
||||||
@@ -581,7 +604,8 @@ span.instanceStatus {
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
.servericon, #sentdms .pfp {
|
.servericon,
|
||||||
|
#sentdms .pfp {
|
||||||
height: 48px;
|
height: 48px;
|
||||||
width: 48px;
|
width: 48px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
@@ -591,9 +615,11 @@ span.instanceStatus {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-radius .2s;
|
transition: border-radius 0.2s;
|
||||||
}
|
}
|
||||||
.servericon:hover, .serveropen .servericon, #sentdms .pfp:hover {
|
.servericon:hover,
|
||||||
|
.serveropen .servericon,
|
||||||
|
#sentdms .pfp:hover {
|
||||||
border-radius: 30%;
|
border-radius: 30%;
|
||||||
}
|
}
|
||||||
.home .svgicon {
|
.home .svgicon {
|
||||||
@@ -610,10 +636,12 @@ span.instanceStatus {
|
|||||||
.lightbr {
|
.lightbr {
|
||||||
margin: 8px 4px;
|
margin: 8px 4px;
|
||||||
}
|
}
|
||||||
.blankserver, .home {
|
.blankserver,
|
||||||
|
.home {
|
||||||
background: var(--blank-bg);
|
background: var(--blank-bg);
|
||||||
}
|
}
|
||||||
.servernoti, .home {
|
.servernoti,
|
||||||
|
.home {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.unread {
|
.unread {
|
||||||
@@ -623,7 +651,9 @@ span.instanceStatus {
|
|||||||
width: 8px;
|
width: 8px;
|
||||||
background: var(--primary-text);
|
background: var(--primary-text);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
transition: transform .2s, height .2s;
|
transition:
|
||||||
|
transform 0.2s,
|
||||||
|
height 0.2s;
|
||||||
}
|
}
|
||||||
.servernoti:hover .unread.pinged {
|
.servernoti:hover .unread.pinged {
|
||||||
transform: translate(34px, 14px);
|
transform: translate(34px, 14px);
|
||||||
@@ -637,7 +667,6 @@ span.instanceStatus {
|
|||||||
transform: translate(-12px, 8px) !important;
|
transform: translate(-12px, 8px) !important;
|
||||||
height: 32px !important;
|
height: 32px !important;
|
||||||
width: 8px !important;
|
width: 8px !important;
|
||||||
|
|
||||||
}
|
}
|
||||||
.serveropen .unread.pinged {
|
.serveropen .unread.pinged {
|
||||||
color: transparent;
|
color: transparent;
|
||||||
@@ -653,7 +682,7 @@ span.instanceStatus {
|
|||||||
width: 16px;
|
width: 16px;
|
||||||
transform: translate(34px, 34px);
|
transform: translate(34px, 34px);
|
||||||
background: var(--red);
|
background: var(--red);
|
||||||
font-size: .75rem;
|
font-size: 0.75rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
line-height: 15px;
|
line-height: 15px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -690,7 +719,7 @@ span.instanceStatus {
|
|||||||
}
|
}
|
||||||
.channels {
|
.channels {
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
transition: height .2s ease-in-out;
|
transition: height 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
#channels > div > div:first-child {
|
#channels > div > div:first-child {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
@@ -707,7 +736,7 @@ span.instanceStatus {
|
|||||||
color: var(--primary-text-soft);
|
color: var(--primary-text-soft);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
transition: font-weight .1s;
|
transition: font-weight 0.1s;
|
||||||
}
|
}
|
||||||
.channelbutton:hover {
|
.channelbutton:hover {
|
||||||
background: var(--channel-hover);
|
background: var(--channel-hover);
|
||||||
@@ -716,7 +745,8 @@ span.instanceStatus {
|
|||||||
.channels .channelbutton {
|
.channels .channelbutton {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
.viewChannel .channelbutton, .viewChannel .channelbutton:hover {
|
.viewChannel .channelbutton,
|
||||||
|
.viewChannel .channelbutton:hover {
|
||||||
background: var(--channel-selected);
|
background: var(--channel-selected);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: var(--primary-text-prominent);
|
color: var(--primary-text-prominent);
|
||||||
@@ -726,7 +756,7 @@ span.instanceStatus {
|
|||||||
color: var(--primary-text-prominent);
|
color: var(--primary-text-prominent);
|
||||||
}
|
}
|
||||||
.cunread:after {
|
.cunread:after {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(50% - 4px);
|
top: calc(50% - 4px);
|
||||||
left: -10px;
|
left: -10px;
|
||||||
@@ -764,7 +794,7 @@ span.instanceStatus {
|
|||||||
height: 12px;
|
height: 12px;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
transition: rotate .2s;
|
transition: rotate 0.2s;
|
||||||
}
|
}
|
||||||
.hiddencat {
|
.hiddencat {
|
||||||
rotate: -90deg;
|
rotate: -90deg;
|
||||||
@@ -780,7 +810,7 @@ span.instanceStatus {
|
|||||||
.voiceuser {
|
.voiceuser {
|
||||||
margin-left: 32px;
|
margin-left: 32px;
|
||||||
padding: 4px 0;
|
padding: 4px 0;
|
||||||
font-size: .9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Member Info (DM/Member List) */
|
/* Member Info (DM/Member List) */
|
||||||
@@ -841,7 +871,7 @@ span.instanceStatus {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
#status {
|
#status {
|
||||||
font-size: .8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
#user-actions {
|
#user-actions {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@@ -867,10 +897,10 @@ span.instanceStatus {
|
|||||||
}
|
}
|
||||||
#channelTopic {
|
#channelTopic {
|
||||||
margin: auto 0 0 8px;
|
margin: auto 0 0 8px;
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
color: var(--primary-text-soft);
|
color: var(--primary-text-soft);
|
||||||
button {
|
button {
|
||||||
margin-right:.05in;
|
margin-right: 0.05in;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#channelTopic[hidden] {
|
#channelTopic[hidden] {
|
||||||
@@ -925,13 +955,13 @@ span.instanceStatus {
|
|||||||
padding: 0 10px 0 16px;
|
padding: 0 10px 0 16px;
|
||||||
margin: 0 16px;
|
margin: 0 16px;
|
||||||
background: var(--secondary-bg);
|
background: var(--secondary-bg);
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
color: var(--secondary-text);
|
color: var(--secondary-text);
|
||||||
border-radius: 8px 8px 0 0;
|
border-radius: 8px 8px 0 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
transition: height .2s;
|
transition: height 0.2s;
|
||||||
}
|
}
|
||||||
.cancelReply {
|
.cancelReply {
|
||||||
height: 16px;
|
height: 16px;
|
||||||
@@ -950,7 +980,7 @@ span.instanceStatus {
|
|||||||
#typebox {
|
#typebox {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-left: .06in;
|
margin-left: 0.06in;
|
||||||
}
|
}
|
||||||
.outerTypeBox {
|
.outerTypeBox {
|
||||||
max-height: 50svh;
|
max-height: 50svh;
|
||||||
@@ -967,7 +997,7 @@ span.instanceStatus {
|
|||||||
}
|
}
|
||||||
.searchBox {
|
.searchBox {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
height: .075in;
|
height: 0.075in;
|
||||||
padding: 7px 10px 13px 10px;
|
padding: 7px 10px 13px 10px;
|
||||||
background: var(--dock-bg);
|
background: var(--dock-bg);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -975,21 +1005,21 @@ span.instanceStatus {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
width: 3in;
|
width: 3in;
|
||||||
margin: 0 .1in;
|
margin: 0 0.1in;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
transition: width .2s;
|
transition: width 0.2s;
|
||||||
}
|
}
|
||||||
.outerTypeBox > span::before {
|
.outerTypeBox > span::before {
|
||||||
content: "\feff";
|
content: "\feff";
|
||||||
}
|
}
|
||||||
#typebox[contenteditable=false] {
|
#typebox[contenteditable="false"] {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
#typebox[contenteditable=false]:before {
|
#typebox[contenteditable="false"]:before {
|
||||||
content: "You can't send messages here";
|
content: "You can't send messages here";
|
||||||
opacity: .5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
#typebox.typeboxreplying {
|
#typebox.typeboxreplying {
|
||||||
border-radius: 0 0 4px 4px;
|
border-radius: 0 0 4px 4px;
|
||||||
@@ -1001,7 +1031,7 @@ span.instanceStatus {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 7px;
|
bottom: 7px;
|
||||||
margin-left: 24px;
|
margin-left: 24px;
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
#typing.hidden {
|
#typing.hidden {
|
||||||
@@ -1020,14 +1050,15 @@ span.instanceStatus {
|
|||||||
margin-right: 3px;
|
margin-right: 3px;
|
||||||
}
|
}
|
||||||
.dot:nth-child(2) {
|
.dot:nth-child(2) {
|
||||||
animation-delay: .33s;
|
animation-delay: 0.33s;
|
||||||
}
|
}
|
||||||
.dot:nth-child(3) {
|
.dot:nth-child(3) {
|
||||||
animation-delay: .66s;
|
animation-delay: 0.66s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Message */
|
/* Message */
|
||||||
.messagediv, .titlespace {
|
.messagediv,
|
||||||
|
.titlespace {
|
||||||
padding: 3px 36px 3px 16px;
|
padding: 3px 36px 3px 16px;
|
||||||
border-left: 2px solid transparent;
|
border-left: 2px solid transparent;
|
||||||
}
|
}
|
||||||
@@ -1037,32 +1068,39 @@ span.instanceStatus {
|
|||||||
.messagediv:hover {
|
.messagediv:hover {
|
||||||
background: var(--primary-hover);
|
background: var(--primary-hover);
|
||||||
}
|
}
|
||||||
.messageButtons, .controls {
|
.messageButtons,
|
||||||
|
.controls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -16px;
|
top: -16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
background: var(--secondary-bg);
|
background: var(--secondary-bg);
|
||||||
box-shadow: 0 0 4px var(--shadow), 0 0 2px var(--shadow);
|
box-shadow:
|
||||||
|
0 0 4px var(--shadow),
|
||||||
|
0 0 2px var(--shadow);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.messageButtons button, .controls button {
|
.messageButtons button,
|
||||||
|
.controls button {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
.messageButtons button span, .controls button span {
|
.messageButtons button span,
|
||||||
|
.controls button span {
|
||||||
display: block;
|
display: block;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
background: var(--secondary-text-soft);
|
background: var(--secondary-text-soft);
|
||||||
}
|
}
|
||||||
.messageButtons button:hover, .controls button:hover {
|
.messageButtons button:hover,
|
||||||
|
.controls button:hover {
|
||||||
background: var(--secondary-hover);
|
background: var(--secondary-hover);
|
||||||
}
|
}
|
||||||
.messageButtons button:hover span, .controls button:hover span {
|
.messageButtons button:hover span,
|
||||||
|
.controls button:hover span {
|
||||||
background: var(--secondary-text);
|
background: var(--secondary-text);
|
||||||
}
|
}
|
||||||
.controls {
|
.controls {
|
||||||
@@ -1119,7 +1157,7 @@ span.instanceStatus {
|
|||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
vertical-align: 1px;
|
vertical-align: 1px;
|
||||||
background: color-mix(in srgb, var(--accent-color) 75%, transparent);
|
background: color-mix(in srgb, var(--accent-color) 75%, transparent);
|
||||||
font-size: .75em;
|
font-size: 0.75em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: var(--primary-text-prominent);
|
color: var(--primary-text-prominent);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -1149,7 +1187,7 @@ span.instanceStatus {
|
|||||||
}
|
}
|
||||||
.timestamp {
|
.timestamp {
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
font-size: .75em;
|
font-size: 0.75em;
|
||||||
color: var(--primary-text-soft);
|
color: var(--primary-text-soft);
|
||||||
}
|
}
|
||||||
.spoiler {
|
.spoiler {
|
||||||
@@ -1190,13 +1228,13 @@ span .quote:last-of-type .quoteline {
|
|||||||
position: relative;
|
position: relative;
|
||||||
padding-left: 52px;
|
padding-left: 52px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
color: var(--reply-text);
|
color: var(--reply-text);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
.replyflex::before {
|
.replyflex::before {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(50% - 1px);
|
top: calc(50% - 1px);
|
||||||
left: 19px;
|
left: 19px;
|
||||||
@@ -1309,7 +1347,7 @@ span .quote:last-of-type .quoteline {
|
|||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background: var(--embed-bg);
|
background: var(--embed-bg);
|
||||||
font-size: .88em;
|
font-size: 0.88em;
|
||||||
color: var(--secondary-text);
|
color: var(--secondary-text);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
@@ -1406,7 +1444,8 @@ img.bigembedimg {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.acceptinvbutton:hover, .acceptinvbutton:disabled {
|
.acceptinvbutton:hover,
|
||||||
|
.acceptinvbutton:disabled {
|
||||||
background: color-mix(in hsl, var(--green) 80%, var(--black));
|
background: color-mix(in hsl, var(--green) 80%, var(--black));
|
||||||
}
|
}
|
||||||
#sideDiv.searchDiv {
|
#sideDiv.searchDiv {
|
||||||
@@ -1415,13 +1454,12 @@ img.bigembedimg {
|
|||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding:.05in;
|
padding: 0.05in;
|
||||||
border-radius:.075in;
|
border-radius: 0.075in;
|
||||||
background: #00000020;
|
background: #00000020;
|
||||||
}
|
}
|
||||||
.topMessage:hover {
|
.topMessage:hover {
|
||||||
background: #00000050;
|
background: #00000050;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Sidebar */
|
/* Sidebar */
|
||||||
@@ -1447,7 +1485,7 @@ img.bigembedimg {
|
|||||||
background: var(--sidebar-hover);
|
background: var(--sidebar-hover);
|
||||||
}
|
}
|
||||||
.memberList.offline .liststyle {
|
.memberList.offline .liststyle {
|
||||||
opacity: .5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
#memberlisttoggle {
|
#memberlisttoggle {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -1482,7 +1520,7 @@ img.bigembedimg {
|
|||||||
width: 180px;
|
width: 180px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
font-size: .9rem;
|
font-size: 0.9rem;
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
color: var(--secondary-text);
|
color: var(--secondary-text);
|
||||||
border: none;
|
border: none;
|
||||||
@@ -1502,7 +1540,9 @@ img.bigembedimg {
|
|||||||
width: 300px;
|
width: 300px;
|
||||||
max-height: 100svh;
|
max-height: 100svh;
|
||||||
background: var(--card-bg);
|
background: var(--card-bg);
|
||||||
box-shadow: 0 0 8px var(--shadow), inset 0 132px 64px var(--accent_color);
|
box-shadow:
|
||||||
|
0 0 8px var(--shadow),
|
||||||
|
inset 0 132px 64px var(--accent_color);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -1557,7 +1597,8 @@ img.bigembedimg {
|
|||||||
.profile:has(.banner) .infosection {
|
.profile:has(.banner) .infosection {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
.infosection h2, .infosection h3 {
|
.infosection h2,
|
||||||
|
.infosection h3 {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
.infosection hr {
|
.infosection hr {
|
||||||
@@ -1565,11 +1606,11 @@ img.bigembedimg {
|
|||||||
}
|
}
|
||||||
.tag {
|
.tag {
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
color: var(--secondary-text);
|
color: var(--secondary-text);
|
||||||
}
|
}
|
||||||
.pronouns {
|
.pronouns {
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
color: var(--secondary-text-soft);
|
color: var(--secondary-text-soft);
|
||||||
}
|
}
|
||||||
.rolesbox {
|
.rolesbox {
|
||||||
@@ -1583,7 +1624,7 @@ img.bigembedimg {
|
|||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
background: var(--role-bg);
|
background: var(--role-bg);
|
||||||
color: var(--role-text);
|
color: var(--role-text);
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
border: 1px solid var(--black);
|
border: 1px solid var(--black);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -1634,7 +1675,8 @@ img.bigembedimg {
|
|||||||
.emojiSelect:hover {
|
.emojiSelect:hover {
|
||||||
background: var(--secondary-hover);
|
background: var(--secondary-hover);
|
||||||
}
|
}
|
||||||
.emoji-server, .emojiBody .smallemoji {
|
.emoji-server,
|
||||||
|
.emojiBody .smallemoji {
|
||||||
height: auto;
|
height: auto;
|
||||||
width: auto;
|
width: auto;
|
||||||
max-height: 28px;
|
max-height: 28px;
|
||||||
@@ -1664,13 +1706,15 @@ img.bigembedimg {
|
|||||||
max-height: 85svh;
|
max-height: 85svh;
|
||||||
max-width: 85svw;
|
max-width: 85svw;
|
||||||
}
|
}
|
||||||
.centeritem, .accountSwitcher {
|
.centeritem,
|
||||||
|
.accountSwitcher {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
.nonimagecenter, .accountSwitcher {
|
.nonimagecenter,
|
||||||
|
.accountSwitcher {
|
||||||
max-height: 80svh;
|
max-height: 80svh;
|
||||||
width: 500px;
|
width: 500px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
@@ -1678,16 +1722,20 @@ img.bigembedimg {
|
|||||||
background: var(--secondary-bg);
|
background: var(--secondary-bg);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 0 24px var(--shadow), 0 0 1.5px var(--primary-text);
|
box-shadow:
|
||||||
|
0 0 24px var(--shadow),
|
||||||
|
0 0 1.5px var(--primary-text);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.nonimagecenter & .flexttb, .nonimagecenter & .flexltr {
|
.nonimagecenter & .flexttb,
|
||||||
|
.nonimagecenter & .flexltr {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
.nonimagecenter > .flexttb, .nonimagecenter > .flexltr {
|
.nonimagecenter > .flexttb,
|
||||||
|
.nonimagecenter > .flexltr {
|
||||||
padding: 0 0 16px 0 !important;
|
padding: 0 0 16px 0 !important;
|
||||||
background: var(--primary-bg);
|
background: var(--primary-bg);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -1696,7 +1744,8 @@ img.bigembedimg {
|
|||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
.nonimagecenter .flexspace, .nonimagecenter .FormSettings {
|
.nonimagecenter .flexspace,
|
||||||
|
.nonimagecenter .FormSettings {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
.nonimagecenter button {
|
.nonimagecenter button {
|
||||||
@@ -1725,7 +1774,7 @@ fieldset input[type="radio"] {
|
|||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
.serverURL {
|
.serverURL {
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
color: var(--primary-text-soft);
|
color: var(--primary-text-soft);
|
||||||
}
|
}
|
||||||
.accountSwitcher {
|
.accountSwitcher {
|
||||||
@@ -1811,7 +1860,7 @@ fieldset input[type="radio"] {
|
|||||||
}
|
}
|
||||||
.discovery-guild p {
|
.discovery-guild p {
|
||||||
margin: 0 12px;
|
margin: 0 12px;
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
color: var(--secondary-text-soft);
|
color: var(--secondary-text-soft);
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
@@ -1839,7 +1888,7 @@ fieldset input[type="radio"] {
|
|||||||
.settingbuttons.flexltr {
|
.settingbuttons.flexltr {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
border-radius: .04in;
|
border-radius: 0.04in;
|
||||||
.SettingsButton {
|
.SettingsButton {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
@@ -1890,7 +1939,8 @@ fieldset input[type="radio"] {
|
|||||||
.FormSettings {
|
.FormSettings {
|
||||||
padding-bottom: 32px;
|
padding-bottom: 32px;
|
||||||
}
|
}
|
||||||
.optionElement, .FormSettings > button {
|
.optionElement,
|
||||||
|
.FormSettings > button {
|
||||||
margin: 16px 16px 0 16px;
|
margin: 16px 16px 0 16px;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -1917,7 +1967,8 @@ fieldset input[type="radio"] {
|
|||||||
.optionElement .fileinputdiv {
|
.optionElement .fileinputdiv {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
}
|
}
|
||||||
#app-list-container div, #connection-container div {
|
#app-list-container div,
|
||||||
|
#connection-container div {
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
@@ -1958,8 +2009,8 @@ fieldset input[type="radio"] {
|
|||||||
font-size: 1.15rem;
|
font-size: 1.15rem;
|
||||||
}
|
}
|
||||||
.setting p {
|
.setting p {
|
||||||
font-size: .9em;
|
font-size: 0.9em;
|
||||||
color: var(--secondary-text-soft)
|
color: var(--secondary-text-soft);
|
||||||
}
|
}
|
||||||
.tritoggle {
|
.tritoggle {
|
||||||
display: inline;
|
display: inline;
|
||||||
@@ -1986,7 +2037,9 @@ fieldset input[type="radio"] {
|
|||||||
color: var(--secondary-text);
|
color: var(--secondary-text);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
box-shadow: 0 0 24px var(--shadow), 0 0 1px var(--primary-text);
|
box-shadow:
|
||||||
|
0 0 24px var(--shadow),
|
||||||
|
0 0 1px var(--primary-text);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.savediv button {
|
.savediv button {
|
||||||
@@ -2006,7 +2059,8 @@ fieldset input[type="radio"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Jank Mobile */
|
/* Jank Mobile */
|
||||||
#maintoggle, #maintoggleicon {
|
#maintoggle,
|
||||||
|
#maintoggleicon {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2035,7 +2089,9 @@ fieldset input[type="radio"] {
|
|||||||
display: block;
|
display: block;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
}
|
||||||
#servers, .channelflex, #mainarea {
|
#servers,
|
||||||
|
.channelflex,
|
||||||
|
#mainarea {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 100svh;
|
height: 100svh;
|
||||||
}
|
}
|
||||||
@@ -2046,18 +2102,19 @@ fieldset input[type="radio"] {
|
|||||||
left: 304px;
|
left: 304px;
|
||||||
width: 100svw;
|
width: 100svw;
|
||||||
background: var(--primary-bg);
|
background: var(--primary-bg);
|
||||||
transition: left .3s;
|
transition: left 0.3s;
|
||||||
}
|
}
|
||||||
#sideDiv {
|
#sideDiv {
|
||||||
display: block;
|
display: block;
|
||||||
right: -100svw;
|
right: -100svw;
|
||||||
width: 100svw;
|
width: 100svw;
|
||||||
transition: right .3s;
|
transition: right 0.3s;
|
||||||
}
|
}
|
||||||
.channelnamediv {
|
.channelnamediv {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
#maintoggleicon, #memberlisttoggleicon {
|
#maintoggleicon,
|
||||||
|
#memberlisttoggleicon {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -2102,10 +2159,13 @@ fieldset input[type="radio"] {
|
|||||||
left: 15px;
|
left: 15px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
}
|
}
|
||||||
.replyflex, .reactiondiv {
|
.replyflex,
|
||||||
|
.reactiondiv {
|
||||||
padding-left: 44px;
|
padding-left: 44px;
|
||||||
}
|
}
|
||||||
#realbox, #logindiv, #pasteimg {
|
#realbox,
|
||||||
|
#logindiv,
|
||||||
|
#pasteimg {
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
}
|
}
|
||||||
@@ -2113,13 +2173,17 @@ fieldset input[type="radio"] {
|
|||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
.contextmenu, .profile, .emojiPicker {
|
.contextmenu,
|
||||||
|
.profile,
|
||||||
|
.emojiPicker {
|
||||||
top: unset !important;
|
top: unset !important;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 16px 16px 0 0;
|
border-radius: 16px 16px 0 0;
|
||||||
box-shadow: 0 0 14px var(--shadow), 0 0 28px var(--shadow);
|
box-shadow:
|
||||||
|
0 0 14px var(--shadow),
|
||||||
|
0 0 28px var(--shadow);
|
||||||
}
|
}
|
||||||
.contextbutton {
|
.contextbutton {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -2127,12 +2191,19 @@ fieldset input[type="radio"] {
|
|||||||
}
|
}
|
||||||
.profile {
|
.profile {
|
||||||
height: 65%;
|
height: 65%;
|
||||||
box-shadow: 0 0 14px var(--shadow), 0 0 28px var(--shadow), inset 0 132px 64px var(--accent_color);
|
box-shadow:
|
||||||
|
0 0 14px var(--shadow),
|
||||||
|
0 0 28px var(--shadow),
|
||||||
|
inset 0 132px 64px var(--accent_color);
|
||||||
}
|
}
|
||||||
.hypoprofile {
|
.hypoprofile {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
#logindiv, #invitebody, .savediv, .nonimagecenter, .accountSwitcher {
|
#logindiv,
|
||||||
|
#invitebody,
|
||||||
|
.savediv,
|
||||||
|
.nonimagecenter,
|
||||||
|
.accountSwitcher {
|
||||||
width: 94%;
|
width: 94%;
|
||||||
min-width: unset;
|
min-width: unset;
|
||||||
}
|
}
|
||||||
@@ -2162,41 +2233,40 @@ fieldset input[type="radio"] {
|
|||||||
.friendcontainer {
|
.friendcontainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: .2in;
|
padding: 0.2in;
|
||||||
> div {
|
> div {
|
||||||
background: #00000030;
|
background: #00000030;
|
||||||
margin-bottom:.1in;
|
margin-bottom: 0.1in;
|
||||||
padding:.06in .1in;
|
padding: 0.06in 0.1in;
|
||||||
border-radius:.1in;
|
border-radius: 0.1in;
|
||||||
border: solid 1px var(--black);
|
border: solid 1px var(--black);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.fixedsearch {
|
.fixedsearch {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: var(--primary-bg);
|
background: var(--primary-bg);
|
||||||
min-height: .2in;
|
min-height: 0.2in;
|
||||||
padding:.05in;
|
padding: 0.05in;
|
||||||
border:solid .03in var(--black);
|
border: solid 0.03in var(--black);
|
||||||
border-radius:.05in;
|
border-radius: 0.05in;
|
||||||
span {
|
span {
|
||||||
margin-top:.1in;
|
margin-top: 0.1in;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding:.03in;
|
padding: 0.03in;
|
||||||
border:solid .03in var(--black);
|
border: solid 0.03in var(--black);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius:.05in;
|
border-radius: 0.05in;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
.suberror {
|
.suberror {
|
||||||
animation: goout 6s forwards;
|
animation: goout 6s forwards;
|
||||||
}
|
}
|
||||||
.suberrora {
|
.suberrora {
|
||||||
background: var(--channel-hover);
|
background: var(--channel-hover);
|
||||||
border-radius:.1in;
|
border-radius: 0.1in;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border:solid var(--primary-text) .02in;
|
border: solid var(--primary-text) 0.02in;
|
||||||
color: color-mix(in hsl, var(--yellow), var(--red));
|
color: color-mix(in hsl, var(--yellow), var(--red));
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -2206,37 +2276,39 @@ fieldset input[type="radio"] {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
padding: .075in;
|
padding: 0.075in;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
@keyframes goout {
|
@keyframes goout {
|
||||||
0%,100%{
|
0%,
|
||||||
|
100% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
5%,90%{
|
5%,
|
||||||
|
90% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.friendsbutton {
|
.friendsbutton {
|
||||||
transition: background-color .2s;
|
transition: background-color 0.2s;
|
||||||
background-color: #00000050;
|
background-color: #00000050;
|
||||||
padding: .08in;
|
padding: 0.08in;
|
||||||
}
|
}
|
||||||
.bigemoji {
|
.bigemoji {
|
||||||
width:.6in;
|
width: 0.6in;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
height: .6in;
|
height: 0.6in;
|
||||||
}
|
}
|
||||||
.friendlyButton {
|
.friendlyButton {
|
||||||
padding: .07in;
|
padding: 0.07in;
|
||||||
background: #00000045;
|
background: #00000045;
|
||||||
transition:background .2s;
|
transition: background 0.2s;
|
||||||
border-radius: 1in;
|
border-radius: 1in;
|
||||||
border: solid 1px var(--black);
|
border: solid 1px var(--black);
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
margin: 0 .05in;
|
margin: 0 0.05in;
|
||||||
}
|
}
|
||||||
.friendlyButton:hover {
|
.friendlyButton:hover {
|
||||||
background: black;
|
background: black;
|
||||||
@@ -2245,23 +2317,23 @@ fieldset input[type="radio"] {
|
|||||||
border: solid 1px var(--black);
|
border: solid 1px var(--black);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: .075in;
|
padding: 0.075in;
|
||||||
margin-bottom: .2in;
|
margin-bottom: 0.2in;
|
||||||
border-radius: .1in;
|
border-radius: 0.1in;
|
||||||
background: var(--primary-hover);
|
background: var(--primary-hover);
|
||||||
position: relative;
|
position: relative;
|
||||||
input {
|
input {
|
||||||
width: 2in !important;
|
width: 2in !important;
|
||||||
height:.3in;
|
height: 0.3in;
|
||||||
}
|
}
|
||||||
.bigemoji {
|
.bigemoji {
|
||||||
padding-right:.5in;
|
padding-right: 0.5in;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.deleteEmoji {
|
.deleteEmoji {
|
||||||
width: .3in;
|
width: 0.3in;
|
||||||
height: .3in;
|
height: 0.3in;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: .2in;
|
right: 0.2in;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ class User extends SnowFlake{
|
|||||||
premium_type!: number;
|
premium_type!: number;
|
||||||
theme_colors!: string;
|
theme_colors!: string;
|
||||||
badge_ids!: string[];
|
badge_ids!: string[];
|
||||||
members: WeakMap<Guild, Member | undefined | Promise<Member | undefined>> =
|
members: WeakMap<Guild, Member | undefined | Promise<Member | undefined>> = new WeakMap();
|
||||||
new WeakMap();
|
|
||||||
status!: string;
|
status!: string;
|
||||||
resolving: false | Promise<any> = false;
|
resolving: false | Promise<any> = false;
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ class User extends SnowFlake{
|
|||||||
super(userjson.id);
|
super(userjson.id);
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
if (localStorage.getItem("logbad") && owner.user && owner.user.id !== userjson.id) {
|
if (localStorage.getItem("logbad") && owner.user && owner.user.id !== userjson.id) {
|
||||||
this.checkfortmi(userjson)
|
this.checkfortmi(userjson);
|
||||||
}
|
}
|
||||||
if (!owner) {
|
if (!owner) {
|
||||||
console.error("missing localuser");
|
console.error("missing localuser");
|
||||||
@@ -66,9 +65,18 @@ class User extends SnowFlake{
|
|||||||
*/
|
*/
|
||||||
checkfortmi(json: any) {
|
checkfortmi(json: any) {
|
||||||
if (json.data) {
|
if (json.data) {
|
||||||
console.error("Server sent *way* too much info, this is really bad, it sent data")
|
console.error("Server sent *way* too much info, this is really bad, it sent data");
|
||||||
}
|
}
|
||||||
const bad=new Set(["fingerprints", "extended_settings", "mfa_enabled", "nsfw_allowed", "premium_usage_flags", "totp_last_ticket", "totp_secret", "webauthn_enabled"]);
|
const bad = new Set([
|
||||||
|
"fingerprints",
|
||||||
|
"extended_settings",
|
||||||
|
"mfa_enabled",
|
||||||
|
"nsfw_allowed",
|
||||||
|
"premium_usage_flags",
|
||||||
|
"totp_last_ticket",
|
||||||
|
"totp_secret",
|
||||||
|
"webauthn_enabled",
|
||||||
|
]);
|
||||||
for (const thing of bad) {
|
for (const thing of bad) {
|
||||||
if (json.hasOwnProperty(thing)) {
|
if (json.hasOwnProperty(thing)) {
|
||||||
console.error(thing + " should not be exposed to the client");
|
console.error(thing + " should not be exposed to the client");
|
||||||
@@ -91,16 +99,13 @@ class User extends SnowFlake{
|
|||||||
theme_colors: this.theme_colors,
|
theme_colors: this.theme_colors,
|
||||||
pronouns: this.pronouns,
|
pronouns: this.pronouns,
|
||||||
badge_ids: this.badge_ids,
|
badge_ids: this.badge_ids,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
clone(): User {
|
clone(): User {
|
||||||
const json = this.tojson();
|
const json = this.tojson();
|
||||||
json.id += "#clone";
|
json.id += "#clone";
|
||||||
return new User(
|
return new User(json, this.owner);
|
||||||
json,
|
|
||||||
this.owner
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPresence(presence: presencejson | undefined): void {
|
public getPresence(presence: presencejson | undefined): void {
|
||||||
@@ -111,7 +116,7 @@ class User extends SnowFlake{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
get online() {
|
get online() {
|
||||||
return (this.status)&&(this.status!="offline");
|
return this.status && this.status != "offline";
|
||||||
}
|
}
|
||||||
setstatus(status: string): void {
|
setstatus(status: string): void {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
@@ -134,8 +139,8 @@ class User extends SnowFlake{
|
|||||||
body: JSON.stringify({recipients: [this.id]}),
|
body: JSON.stringify({recipients: [this.id]}),
|
||||||
headers: this.localuser.headers,
|
headers: this.localuser.headers,
|
||||||
})
|
})
|
||||||
.then(res=>res.json())
|
.then((res) => res.json())
|
||||||
.then(json=>{
|
.then((json) => {
|
||||||
this.localuser.goToChannel(json.id);
|
this.localuser.goToChannel(json.id);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -152,18 +157,24 @@ class User extends SnowFlake{
|
|||||||
} else {
|
} else {
|
||||||
await fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
await fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: this.owner.headers
|
headers: this.owner.headers,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.relationshipType = type;
|
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) {
|
||||||
this.opendm();
|
this.opendm();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("user.block"),
|
() => I18n.getTranslation("user.block"),
|
||||||
function (this: User) {
|
function (this: User) {
|
||||||
@@ -172,7 +183,7 @@ class User extends SnowFlake{
|
|||||||
null,
|
null,
|
||||||
function () {
|
function () {
|
||||||
return this.relationshipType !== 2;
|
return this.relationshipType !== 2;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
@@ -183,25 +194,35 @@ class User extends SnowFlake{
|
|||||||
null,
|
null,
|
||||||
function () {
|
function () {
|
||||||
return this.relationshipType === 2;
|
return this.relationshipType === 2;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("user.friendReq"), function(this: User){
|
this.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("user.friendReq"),
|
||||||
|
function (this: User) {
|
||||||
this.changeRelationship(1);
|
this.changeRelationship(1);
|
||||||
},null,function(){
|
},
|
||||||
|
null,
|
||||||
|
function () {
|
||||||
return this.relationshipType === 0 || this.relationshipType === 3;
|
return this.relationshipType === 0 || this.relationshipType === 3;
|
||||||
});
|
},
|
||||||
this.contextmenu.addbutton(()=>I18n.getTranslation("friends.removeFriend"), function(this: User){
|
);
|
||||||
|
this.contextmenu.addbutton(
|
||||||
|
() => I18n.getTranslation("friends.removeFriend"),
|
||||||
|
function (this: User) {
|
||||||
this.changeRelationship(0);
|
this.changeRelationship(0);
|
||||||
},null,function(){
|
},
|
||||||
|
null,
|
||||||
|
function () {
|
||||||
return this.relationshipType === 1;
|
return this.relationshipType === 1;
|
||||||
});
|
},
|
||||||
|
);
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("user.kick"),
|
() => I18n.getTranslation("user.kick"),
|
||||||
function (this: User, member: Member | undefined) {
|
function (this: User, member: Member | undefined) {
|
||||||
member?.kick();
|
member?.kick();
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
member=>{
|
(member) => {
|
||||||
if (!member) return false;
|
if (!member) return false;
|
||||||
const us = member.guild.member;
|
const us = member.guild.member;
|
||||||
if (member.id === us.id) {
|
if (member.id === us.id) {
|
||||||
@@ -211,7 +232,7 @@ class User extends SnowFlake{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return us.hasPermission("KICK_MEMBERS") || false;
|
return us.hasPermission("KICK_MEMBERS") || false;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
@@ -223,7 +244,7 @@ class User extends SnowFlake{
|
|||||||
null,
|
null,
|
||||||
function (member) {
|
function (member) {
|
||||||
return member?.id === this.localuser.user.id;
|
return member?.id === this.localuser.user.id;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("user.ban"),
|
() => I18n.getTranslation("user.ban"),
|
||||||
@@ -231,7 +252,7 @@ class User extends SnowFlake{
|
|||||||
member?.ban();
|
member?.ban();
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
member=>{
|
(member) => {
|
||||||
if (!member) return false;
|
if (!member) return false;
|
||||||
const us = member.guild.member;
|
const us = member.guild.member;
|
||||||
if (member.id === us.id) {
|
if (member.id === us.id) {
|
||||||
@@ -241,7 +262,7 @@ class User extends SnowFlake{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return us.hasPermission("BAN_MEMBERS") || false;
|
return us.hasPermission("BAN_MEMBERS") || false;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("user.addRole"),
|
() => I18n.getTranslation("user.addRole"),
|
||||||
@@ -262,12 +283,12 @@ class User extends SnowFlake{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
member=>{
|
(member) => {
|
||||||
if (!member) return false;
|
if (!member) return false;
|
||||||
const us = member.guild.member;
|
const us = member.guild.member;
|
||||||
console.log(us.hasPermission("MANAGE_ROLES"))
|
console.log(us.hasPermission("MANAGE_ROLES"));
|
||||||
return us.hasPermission("MANAGE_ROLES") || false;
|
return us.hasPermission("MANAGE_ROLES") || false;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
() => I18n.getTranslation("user.removeRole"),
|
() => I18n.getTranslation("user.removeRole"),
|
||||||
@@ -288,12 +309,12 @@ class User extends SnowFlake{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
member=>{
|
(member) => {
|
||||||
if (!member) return false;
|
if (!member) return false;
|
||||||
const us = member.guild.member;
|
const us = member.guild.member;
|
||||||
console.log(us.hasPermission("MANAGE_ROLES"))
|
console.log(us.hasPermission("MANAGE_ROLES"));
|
||||||
return us.hasPermission("MANAGE_ROLES") || false;
|
return us.hasPermission("MANAGE_ROLES") || false;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,12 +348,12 @@ class User extends SnowFlake{
|
|||||||
return await fetch(
|
return await fetch(
|
||||||
`${this.info.api}/users/${this.id.replace(
|
`${this.info.api}/users/${this.id.replace(
|
||||||
"#clone",
|
"#clone",
|
||||||
""
|
"",
|
||||||
)}/profile?with_mutual_guilds=true&with_mutual_friends=true`,
|
)}/profile?with_mutual_guilds=true&with_mutual_friends=true`,
|
||||||
{
|
{
|
||||||
headers: this.localuser.headers,
|
headers: this.localuser.headers,
|
||||||
}
|
},
|
||||||
).then(res=>res.json());
|
).then((res) => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBadge(id: string): Promise<any> {
|
async getBadge(id: string): Promise<any> {
|
||||||
@@ -364,22 +385,20 @@ class User extends SnowFlake{
|
|||||||
if (guild) {
|
if (guild) {
|
||||||
(async () => {
|
(async () => {
|
||||||
if (guild instanceof Guild) {
|
if (guild instanceof Guild) {
|
||||||
const memb= await Member.resolveMember(this,guild)
|
const memb = await Member.resolveMember(this, guild);
|
||||||
if (!memb) return;
|
if (!memb) return;
|
||||||
pfp.src = memb.getpfpsrc();
|
pfp.src = memb.getpfpsrc();
|
||||||
} else {
|
} else {
|
||||||
pfp.src = guild.getpfpsrc();
|
pfp.src = guild.getpfpsrc();
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
}
|
}
|
||||||
return pfp;
|
return pfp;
|
||||||
}
|
}
|
||||||
|
|
||||||
async buildstatuspfp(guild: Guild | void | Member | null): Promise<HTMLDivElement> {
|
async buildstatuspfp(guild: Guild | void | Member | null): Promise<HTMLDivElement> {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("pfpDiv")
|
div.classList.add("pfpDiv");
|
||||||
const pfp = this.buildpfp(guild);
|
const pfp = this.buildpfp(guild);
|
||||||
div.append(pfp);
|
div.append(pfp);
|
||||||
const status = document.createElement("div");
|
const status = document.createElement("div");
|
||||||
@@ -406,7 +425,7 @@ class User extends SnowFlake{
|
|||||||
bind(html: HTMLElement, guild: Guild | null = null, error = true): void {
|
bind(html: HTMLElement, guild: Guild | null = null, error = true): void {
|
||||||
if (guild && guild.id !== "@me") {
|
if (guild && guild.id !== "@me") {
|
||||||
Member.resolveMember(this, guild)
|
Member.resolveMember(this, guild)
|
||||||
.then(member=>{
|
.then((member) => {
|
||||||
User.contextmenu.bindContextmenu(html, this, member);
|
User.contextmenu.bindContextmenu(html, this, member);
|
||||||
if (member === undefined && error) {
|
if (member === undefined && error) {
|
||||||
const errorSpan = document.createElement("span");
|
const errorSpan = document.createElement("span");
|
||||||
@@ -421,7 +440,7 @@ class User extends SnowFlake{
|
|||||||
User.contextmenu.bindContextmenu(html, this, undefined);
|
User.contextmenu.bindContextmenu(html, this, undefined);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(err=>{
|
.catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -435,10 +454,9 @@ class User extends SnowFlake{
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async resolve(id: string, localuser: Localuser): Promise<User> {
|
static async resolve(id: string, localuser: Localuser): Promise<User> {
|
||||||
const json = await fetch(
|
const json = await fetch(localuser.info.api.toString() + "/users/" + id + "/profile", {
|
||||||
localuser.info.api.toString() + "/users/" + id + "/profile",
|
headers: localuser.headers,
|
||||||
{ headers: localuser.headers }
|
}).then((res) => res.json());
|
||||||
).then(res=>res.json());
|
|
||||||
return new User(json.user, localuser);
|
return new User(json.user, localuser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,11 +464,9 @@ class User extends SnowFlake{
|
|||||||
this.avatar = update;
|
this.avatar = update;
|
||||||
this.hypotheticalpfp = false;
|
this.hypotheticalpfp = false;
|
||||||
const src = this.getpfpsrc();
|
const src = this.getpfpsrc();
|
||||||
Array.from(document.getElementsByClassName("userid:" + this.id)).forEach(
|
Array.from(document.getElementsByClassName("userid:" + this.id)).forEach((element) => {
|
||||||
element=>{
|
|
||||||
(element as HTMLImageElement).src = src;
|
(element as HTMLImageElement).src = src;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async block() {
|
async block() {
|
||||||
@@ -480,15 +496,13 @@ class User extends SnowFlake{
|
|||||||
return this.avatar;
|
return this.avatar;
|
||||||
}
|
}
|
||||||
if (guild) {
|
if (guild) {
|
||||||
const member=this.members.get(guild)
|
const member = this.members.get(guild);
|
||||||
if (member instanceof Member) {
|
if (member instanceof Member) {
|
||||||
return member.getpfpsrc();
|
return member.getpfpsrc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.avatar !== null) {
|
if (this.avatar !== null) {
|
||||||
return`${this.info.cdn}/avatars/${this.id.replace("#clone", "")}/${
|
return `${this.info.cdn}/avatars/${this.id.replace("#clone", "")}/${this.avatar}.png`;
|
||||||
this.avatar
|
|
||||||
}.png`;
|
|
||||||
} else {
|
} else {
|
||||||
const int = Number((BigInt(this.id.replace("#clone", "")) >> 22n) % 6n);
|
const int = Number((BigInt(this.id.replace("#clone", "")) >> 22n) % 6n);
|
||||||
return `${this.info.cdn}/embed/avatars/${int}.png`;
|
return `${this.info.cdn}/embed/avatars/${int}.png`;
|
||||||
@@ -498,7 +512,7 @@ class User extends SnowFlake{
|
|||||||
async buildprofile(
|
async buildprofile(
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
guild: Guild | null | Member = null
|
guild: Guild | null | Member = null,
|
||||||
): Promise<HTMLDivElement> {
|
): Promise<HTMLDivElement> {
|
||||||
if (Contextmenu.currentmenu != "") {
|
if (Contextmenu.currentmenu != "") {
|
||||||
Contextmenu.currentmenu.remove();
|
Contextmenu.currentmenu.remove();
|
||||||
@@ -507,33 +521,33 @@ class User extends SnowFlake{
|
|||||||
if (!guild) return;
|
if (!guild) return;
|
||||||
let member: Member | undefined;
|
let member: Member | undefined;
|
||||||
if (guild instanceof Guild) {
|
if (guild instanceof Guild) {
|
||||||
member=await Member.resolveMember(this,guild)
|
member = await Member.resolveMember(this, guild);
|
||||||
} else {
|
} else {
|
||||||
member = guild;
|
member = guild;
|
||||||
}
|
}
|
||||||
return member;
|
return member;
|
||||||
})()
|
})();
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
|
|
||||||
if (this.accent_color) {
|
if (this.accent_color) {
|
||||||
div.style.setProperty(
|
div.style.setProperty(
|
||||||
"--accent_color",
|
"--accent_color",
|
||||||
`#${this.accent_color.toString(16).padStart(6, "0")}`
|
`#${this.accent_color.toString(16).padStart(6, "0")}`,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
div.style.setProperty("--accent_color", "transparent");
|
div.style.setProperty("--accent_color", "transparent");
|
||||||
}
|
}
|
||||||
const banner = this.getBanner(guild);
|
const banner = this.getBanner(guild);
|
||||||
div.append(banner);
|
div.append(banner);
|
||||||
membres.then(member=>{
|
membres.then((member) => {
|
||||||
if (!member) return;
|
if (!member) return;
|
||||||
if (member.accent_color && member.accent_color !== 0) {
|
if (member.accent_color && member.accent_color !== 0) {
|
||||||
div.style.setProperty(
|
div.style.setProperty(
|
||||||
"--accent_color",
|
"--accent_color",
|
||||||
`#${member.accent_color.toString(16).padStart(6, "0")}`
|
`#${member.accent_color.toString(16).padStart(6, "0")}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
if (x !== -1) {
|
if (x !== -1) {
|
||||||
div.style.left = `${x}px`;
|
div.style.left = `${x}px`;
|
||||||
@@ -584,7 +598,7 @@ class User extends SnowFlake{
|
|||||||
pronounshtml.classList.add("pronouns");
|
pronounshtml.classList.add("pronouns");
|
||||||
userbody.appendChild(pronounshtml);
|
userbody.appendChild(pronounshtml);
|
||||||
|
|
||||||
membres.then(member=>{
|
membres.then((member) => {
|
||||||
if (!member) return;
|
if (!member) return;
|
||||||
if (member.pronouns && member.pronouns !== "") {
|
if (member.pronouns && member.pronouns !== "") {
|
||||||
pronounshtml.textContent = member.pronouns;
|
pronounshtml.textContent = member.pronouns;
|
||||||
@@ -596,7 +610,7 @@ class User extends SnowFlake{
|
|||||||
const biohtml = this.bio.makeHTML();
|
const biohtml = this.bio.makeHTML();
|
||||||
userbody.appendChild(biohtml);
|
userbody.appendChild(biohtml);
|
||||||
|
|
||||||
membres.then(member=>{
|
membres.then((member) => {
|
||||||
if (!member) return;
|
if (!member) return;
|
||||||
if (member.bio && member.bio !== "") {
|
if (member.bio && member.bio !== "") {
|
||||||
//TODO make markdown take Guild
|
//TODO make markdown take Guild
|
||||||
@@ -606,7 +620,7 @@ class User extends SnowFlake{
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (guild) {
|
if (guild) {
|
||||||
membres.then(member=>{
|
membres.then((member) => {
|
||||||
if (!member) return;
|
if (!member) return;
|
||||||
usernamehtml.textContent = member.name;
|
usernamehtml.textContent = member.name;
|
||||||
const roles = document.createElement("div");
|
const roles = document.createElement("div");
|
||||||
@@ -617,10 +631,7 @@ class User extends SnowFlake{
|
|||||||
roleDiv.classList.add("rolediv");
|
roleDiv.classList.add("rolediv");
|
||||||
const color = document.createElement("div");
|
const color = document.createElement("div");
|
||||||
roleDiv.append(color);
|
roleDiv.append(color);
|
||||||
color.style.setProperty(
|
color.style.setProperty("--role-color", `#${role.color.toString(16).padStart(6, "0")}`);
|
||||||
"--role-color",
|
|
||||||
`#${role.color.toString(16).padStart(6, "0")}`
|
|
||||||
);
|
|
||||||
color.classList.add("colorrolediv");
|
color.classList.add("colorrolediv");
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
roleDiv.append(span);
|
roleDiv.append(span);
|
||||||
@@ -654,24 +665,22 @@ class User extends SnowFlake{
|
|||||||
banner.classList.add("banner");
|
banner.classList.add("banner");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Member.resolveMember(this,guild).then(memb=>{
|
Member.resolveMember(this, guild).then((memb) => {
|
||||||
if (!memb) return;
|
if (!memb) return;
|
||||||
const bsrc = memb.getBannerUrl();
|
const bsrc = memb.getBannerUrl();
|
||||||
if (bsrc) {
|
if (bsrc) {
|
||||||
banner.src = bsrc;
|
banner.src = bsrc;
|
||||||
banner.classList.add("banner");
|
banner.classList.add("banner");
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return banner
|
return banner;
|
||||||
}
|
}
|
||||||
getBannerUrl(): string | undefined {
|
getBannerUrl(): string | undefined {
|
||||||
if (this.banner) {
|
if (this.banner) {
|
||||||
if (!this.hypotheticalbanner) {
|
if (!this.hypotheticalbanner) {
|
||||||
return `${this.info.cdn}/avatars/${this.id.replace("#clone", "")}/${
|
return `${this.info.cdn}/avatars/${this.id.replace("#clone", "")}/${this.banner}.png`;
|
||||||
this.banner
|
|
||||||
}.png`;
|
|
||||||
} else {
|
} else {
|
||||||
return this.banner;
|
return this.banner;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ class BinRead{
|
|||||||
private i = 0;
|
private i = 0;
|
||||||
private view: DataView;
|
private view: DataView;
|
||||||
constructor(buffer: ArrayBuffer) {
|
constructor(buffer: ArrayBuffer) {
|
||||||
this.view=new DataView(buffer, 0)
|
this.view = new DataView(buffer, 0);
|
||||||
}
|
}
|
||||||
read16() {
|
read16() {
|
||||||
const int = this.view.getUint16(this.i);
|
const int = this.view.getUint16(this.i);
|
||||||
@@ -85,4 +85,4 @@ class BinWrite{
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export {BinRead,BinWrite}
|
export {BinRead, BinWrite};
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export function setDefaults() {
|
|||||||
notifications: false,
|
notifications: false,
|
||||||
notisound: "three",
|
notisound: "three",
|
||||||
},
|
},
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
userinfos = getBulkInfo();
|
userinfos = getBulkInfo();
|
||||||
}
|
}
|
||||||
@@ -41,10 +41,7 @@ export function setDefaults() {
|
|||||||
if (userinfos.accent_color === undefined) {
|
if (userinfos.accent_color === undefined) {
|
||||||
userinfos.accent_color = "#3096f7";
|
userinfos.accent_color = "#3096f7";
|
||||||
}
|
}
|
||||||
document.documentElement.style.setProperty(
|
document.documentElement.style.setProperty("--accent-color", userinfos.accent_color);
|
||||||
"--accent-color",
|
|
||||||
userinfos.accent_color
|
|
||||||
);
|
|
||||||
if (userinfos.preferences === undefined) {
|
if (userinfos.preferences === undefined) {
|
||||||
userinfos.preferences = {
|
userinfos.preferences = {
|
||||||
theme: "Dark",
|
theme: "Dark",
|
||||||
@@ -79,27 +76,17 @@ export class Specialuser {
|
|||||||
let apistring = new URL(json.serverurls.api).toString();
|
let apistring = new URL(json.serverurls.api).toString();
|
||||||
apistring = apistring.replace(/\/(v\d+\/?)?$/, "") + "/v9";
|
apistring = apistring.replace(/\/(v\d+\/?)?$/, "") + "/v9";
|
||||||
this.serverurls.api = apistring;
|
this.serverurls.api = apistring;
|
||||||
this.serverurls.cdn = new URL(json.serverurls.cdn)
|
this.serverurls.cdn = new URL(json.serverurls.cdn).toString().replace(/\/$/, "");
|
||||||
.toString()
|
this.serverurls.gateway = new URL(json.serverurls.gateway).toString().replace(/\/$/, "");
|
||||||
.replace(/\/$/, "");
|
this.serverurls.wellknown = new URL(json.serverurls.wellknown).toString().replace(/\/$/, "");
|
||||||
this.serverurls.gateway = new URL(json.serverurls.gateway)
|
this.serverurls.login = new URL(json.serverurls.login).toString().replace(/\/$/, "");
|
||||||
.toString()
|
|
||||||
.replace(/\/$/, "");
|
|
||||||
this.serverurls.wellknown = new URL(json.serverurls.wellknown)
|
|
||||||
.toString()
|
|
||||||
.replace(/\/$/, "");
|
|
||||||
this.serverurls.login = new URL(json.serverurls.login)
|
|
||||||
.toString()
|
|
||||||
.replace(/\/$/, "");
|
|
||||||
this.email = json.email;
|
this.email = json.email;
|
||||||
this.token = json.token;
|
this.token = json.token;
|
||||||
this.loggedin = json.loggedin;
|
this.loggedin = json.loggedin;
|
||||||
this.json = json;
|
this.json = json;
|
||||||
this.json.localuserStore ??= {};
|
this.json.localuserStore ??= {};
|
||||||
if (!this.serverurls || !this.email || !this.token) {
|
if (!this.serverurls || !this.email || !this.token) {
|
||||||
console.error(
|
console.error("There are fundamentally missing pieces of info missing from this user");
|
||||||
"There are fundamentally missing pieces of info missing from this user"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set pfpsrc(e) {
|
set pfpsrc(e) {
|
||||||
@@ -144,10 +131,7 @@ export class Specialuser {
|
|||||||
}
|
}
|
||||||
const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||||
const iOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
const iOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
||||||
export{
|
export {mobile, iOS};
|
||||||
mobile,
|
|
||||||
iOS,
|
|
||||||
}
|
|
||||||
let instances:
|
let instances:
|
||||||
| {
|
| {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -170,9 +154,10 @@ let instances:
|
|||||||
const datalist = document.getElementById("instances");
|
const datalist = document.getElementById("instances");
|
||||||
console.warn(datalist);
|
console.warn(datalist);
|
||||||
const instancefetch = fetch("/instances.json")
|
const instancefetch = fetch("/instances.json")
|
||||||
.then(res=>res.json())
|
.then((res) => res.json())
|
||||||
.then(
|
.then(
|
||||||
(json: {
|
(
|
||||||
|
json: {
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
descriptionLong?: string;
|
descriptionLong?: string;
|
||||||
@@ -187,8 +172,8 @@ const instancefetch=fetch("/instances.json")
|
|||||||
cdn: string;
|
cdn: string;
|
||||||
gateway: string;
|
gateway: string;
|
||||||
login?: string;
|
login?: string;
|
||||||
}
|
};
|
||||||
}[]
|
}[],
|
||||||
) => {
|
) => {
|
||||||
instances = json;
|
instances = json;
|
||||||
if (datalist) {
|
if (datalist) {
|
||||||
@@ -223,7 +208,7 @@ const instancefetch=fetch("/instances.json")
|
|||||||
}
|
}
|
||||||
checkInstance("");
|
checkInstance("");
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
const stringURLMap = new Map<string, string>();
|
const stringURLMap = new Map<string, string>();
|
||||||
|
|
||||||
@@ -238,7 +223,7 @@ const stringURLsMap = new Map<
|
|||||||
}
|
}
|
||||||
>();
|
>();
|
||||||
export async function getapiurls(str: string): Promise<
|
export async function getapiurls(str: string): Promise<
|
||||||
{
|
| {
|
||||||
api: string;
|
api: string;
|
||||||
cdn: string;
|
cdn: string;
|
||||||
gateway: string;
|
gateway: string;
|
||||||
@@ -248,12 +233,12 @@ export async function getapiurls(str: string): Promise<
|
|||||||
| false
|
| false
|
||||||
> {
|
> {
|
||||||
function appendApi(str: string) {
|
function appendApi(str: string) {
|
||||||
return str.includes("api")?"" : (str.endsWith("/")? "api" : "/api");
|
return str.includes("api") ? "" : str.endsWith("/") ? "api" : "/api";
|
||||||
}
|
}
|
||||||
if (!URL.canParse(str)) {
|
if (!URL.canParse(str)) {
|
||||||
const val = stringURLMap.get(str);
|
const val = stringURLMap.get(str);
|
||||||
if (stringURLMap.size === 0) {
|
if (stringURLMap.size === 0) {
|
||||||
await new Promise<void>(res=>{
|
await new Promise<void>((res) => {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
if (stringURLMap.size !== 0) {
|
if (stringURLMap.size !== 0) {
|
||||||
res();
|
res();
|
||||||
@@ -266,9 +251,7 @@ export async function getapiurls(str: string): Promise<
|
|||||||
} else {
|
} else {
|
||||||
const val = stringURLsMap.get(str);
|
const val = stringURLsMap.get(str);
|
||||||
if (val) {
|
if (val) {
|
||||||
const responce = await fetch(
|
const responce = await fetch(val.api + (val.api.endsWith("/") ? "" : "/") + "ping");
|
||||||
val.api + (val.api.endsWith("/") ? "" : "/") + "ping"
|
|
||||||
);
|
|
||||||
if (responce.ok) {
|
if (responce.ok) {
|
||||||
if (val.login) {
|
if (val.login) {
|
||||||
return val as {
|
return val as {
|
||||||
@@ -297,8 +280,7 @@ export async function getapiurls(str: string): Promise<
|
|||||||
}
|
}
|
||||||
let api: string;
|
let api: string;
|
||||||
try {
|
try {
|
||||||
const info = await fetch(`${str}.well-known/spacebar`).then(x=>x.json()
|
const info = await fetch(`${str}.well-known/spacebar`).then((x) => x.json());
|
||||||
);
|
|
||||||
api = info.api;
|
api = info.api;
|
||||||
} catch {
|
} catch {
|
||||||
api = str;
|
api = str;
|
||||||
@@ -309,10 +291,8 @@ export async function getapiurls(str: string): Promise<
|
|||||||
const url = new URL(api);
|
const url = new URL(api);
|
||||||
try {
|
try {
|
||||||
const info = await fetch(
|
const info = await fetch(
|
||||||
`${api}${
|
`${api}${url.pathname.includes("api") ? "" : "api"}/policies/instance/domains`,
|
||||||
url.pathname.includes("api") ? "" : "api"
|
).then((x) => x.json());
|
||||||
}/policies/instance/domains`
|
|
||||||
).then(x=>x.json());
|
|
||||||
const apiurl = new URL(info.apiEndpoint);
|
const apiurl = new URL(info.apiEndpoint);
|
||||||
return {
|
return {
|
||||||
api: info.apiEndpoint + appendApi(apiurl.pathname),
|
api: info.apiEndpoint + appendApi(apiurl.pathname),
|
||||||
@@ -324,9 +304,7 @@ export async function getapiurls(str: string): Promise<
|
|||||||
} catch {
|
} catch {
|
||||||
const val = stringURLsMap.get(str);
|
const val = stringURLsMap.get(str);
|
||||||
if (val) {
|
if (val) {
|
||||||
const responce = await fetch(
|
const responce = await fetch(val.api + (val.api.endsWith("/") ? "" : "/") + "ping");
|
||||||
val.api + (val.api.endsWith("/") ? "" : "/") + "ping"
|
|
||||||
);
|
|
||||||
if (responce.ok) {
|
if (responce.ok) {
|
||||||
if (val.login) {
|
if (val.login) {
|
||||||
return val as {
|
return val as {
|
||||||
@@ -410,9 +388,11 @@ export class SW{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ("serviceWorker" in navigator) {
|
if ("serviceWorker" in navigator) {
|
||||||
navigator.serviceWorker.register("/service.js", {
|
navigator.serviceWorker
|
||||||
|
.register("/service.js", {
|
||||||
scope: "/",
|
scope: "/",
|
||||||
}).then((registration) => {
|
})
|
||||||
|
.then((registration) => {
|
||||||
let serviceWorker: ServiceWorker | undefined;
|
let serviceWorker: ServiceWorker | undefined;
|
||||||
if (registration.installing) {
|
if (registration.installing) {
|
||||||
serviceWorker = registration.installing;
|
serviceWorker = registration.installing;
|
||||||
@@ -432,5 +412,5 @@ if ("serviceWorker" in navigator){
|
|||||||
console.log(serviceWorker.state);
|
console.log(serviceWorker.state);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class VoiceFactory{
|
|||||||
voices = new Map<string, Map<string, Voice>>();
|
voices = new Map<string, Map<string, Voice>>();
|
||||||
voiceChannels = new Map<string, Voice>();
|
voiceChannels = new Map<string, Voice>();
|
||||||
currentVoice?: Voice;
|
currentVoice?: Voice;
|
||||||
guildUrlMap=new Map<string,{url?:string,geturl:Promise<void>,gotUrl:()=>void}>();
|
guildUrlMap = new Map<string, {url?: string; geturl: Promise<void>; gotUrl: () => void}>();
|
||||||
makeVoice(guildid: string, channelId: string, settings: Voice["settings"]) {
|
makeVoice(guildid: string, channelId: string, settings: Voice["settings"]) {
|
||||||
let guild = this.voices.get(guildid);
|
let guild = this.voices.get(guildid);
|
||||||
if (!guild) {
|
if (!guild) {
|
||||||
@@ -41,14 +41,13 @@ class VoiceFactory{
|
|||||||
self_mute: true, //todo
|
self_mute: true, //todo
|
||||||
self_deaf: false, //todo
|
self_deaf: false, //todo
|
||||||
self_video: false, //What is this? I have some guesses
|
self_video: false, //What is this? I have some guesses
|
||||||
flags: 2//?????
|
flags: 2, //?????
|
||||||
},
|
},
|
||||||
op:4
|
op: 4,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
userMap = new Map<string, Voice>();
|
userMap = new Map<string, Voice>();
|
||||||
voiceStateUpdate(update: voiceupdate) {
|
voiceStateUpdate(update: voiceupdate) {
|
||||||
|
|
||||||
const prev = this.userMap.get(update.d.user_id);
|
const prev = this.userMap.get(update.d.user_id);
|
||||||
console.log(prev, this.userMap);
|
console.log(prev, this.userMap);
|
||||||
if (prev) {
|
if (prev) {
|
||||||
@@ -62,9 +61,11 @@ class VoiceFactory{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private setUpGuild(id: string) {
|
private setUpGuild(id: string) {
|
||||||
const obj:{url?:string,geturl?:Promise<void>,gotUrl?:()=>void}={};
|
const obj: {url?: string; geturl?: Promise<void>; gotUrl?: () => void} = {};
|
||||||
obj.geturl=new Promise<void>(res=>{obj.gotUrl=res});
|
obj.geturl = new Promise<void>((res) => {
|
||||||
this.guildUrlMap.set(id,obj as {geturl:Promise<void>,gotUrl:()=>void});
|
obj.gotUrl = res;
|
||||||
|
});
|
||||||
|
this.guildUrlMap.set(id, obj as {geturl: Promise<void>; gotUrl: () => void});
|
||||||
}
|
}
|
||||||
voiceServerUpdate(update: voiceserverupdate) {
|
voiceServerUpdate(update: voiceserverupdate) {
|
||||||
const obj = this.guildUrlMap.get(update.d.guild_id);
|
const obj = this.guildUrlMap.get(update.d.guild_id);
|
||||||
@@ -86,7 +87,7 @@ class Voice{
|
|||||||
}
|
}
|
||||||
readonly userid: string;
|
readonly userid: string;
|
||||||
settings: {bitrate: number};
|
settings: {bitrate: number};
|
||||||
urlobj:{url?:string,geturl:Promise<void>,gotUrl:()=>void};
|
urlobj: {url?: string; geturl: Promise<void>; gotUrl: () => void};
|
||||||
constructor(userid: string, settings: Voice["settings"], urlobj: Voice["urlobj"]) {
|
constructor(userid: string, settings: Voice["settings"], urlobj: Voice["urlobj"]) {
|
||||||
this.userid = userid;
|
this.userid = userid;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
@@ -128,7 +129,7 @@ class Voice{
|
|||||||
this.onMemberChange(userid, false);
|
this.onMemberChange(userid, false);
|
||||||
}
|
}
|
||||||
packet(message: MessageEvent) {
|
packet(message: MessageEvent) {
|
||||||
const data=message.data
|
const data = message.data;
|
||||||
if (typeof data === "string") {
|
if (typeof data === "string") {
|
||||||
const json: webRTCSocket = JSON.parse(data);
|
const json: webRTCSocket = JSON.parse(data);
|
||||||
switch (json.op) {
|
switch (json.op) {
|
||||||
@@ -164,7 +165,7 @@ class Voice{
|
|||||||
offer?: string;
|
offer?: string;
|
||||||
cleanServerSDP(sdp: string): string {
|
cleanServerSDP(sdp: string): string {
|
||||||
const pc = this.pc;
|
const pc = this.pc;
|
||||||
if(!pc) throw new Error("pc isn't defined")
|
if (!pc) throw new Error("pc isn't defined");
|
||||||
const ld = pc.localDescription;
|
const ld = pc.localDescription;
|
||||||
if (!ld) throw new Error("localDescription isn't defined");
|
if (!ld) throw new Error("localDescription isn't defined");
|
||||||
const parsed = Voice.parsesdp(ld.sdp);
|
const parsed = Voice.parsesdp(ld.sdp);
|
||||||
@@ -175,21 +176,22 @@ class Voice{
|
|||||||
console.log(bundles);
|
console.log(bundles);
|
||||||
|
|
||||||
if (!this.offer) throw new Error("Offer is missing :P");
|
if (!this.offer) throw new Error("Offer is missing :P");
|
||||||
let cline=sdp.split("\n").find(line=>line.startsWith("c="));
|
let cline = sdp.split("\n").find((line) => line.startsWith("c="));
|
||||||
if (!cline) throw new Error("c line wasn't found");
|
if (!cline) throw new Error("c line wasn't found");
|
||||||
const parsed1 = Voice.parsesdp(sdp).medias[0];
|
const parsed1 = Voice.parsesdp(sdp).medias[0];
|
||||||
//const parsed2=Voice.parsesdp(this.offer);
|
//const parsed2=Voice.parsesdp(this.offer);
|
||||||
const rtcport = (parsed1.atr.get("rtcp") as Set<string>).values().next().value as string;
|
const rtcport = (parsed1.atr.get("rtcp") as Set<string>).values().next().value as string;
|
||||||
const ICE_UFRAG = (parsed1.atr.get("ice-ufrag") as Set<string>).values().next().value as string;
|
const ICE_UFRAG = (parsed1.atr.get("ice-ufrag") as Set<string>).values().next().value as string;
|
||||||
const ICE_PWD = (parsed1.atr.get("ice-pwd") as Set<string>).values().next().value as string;
|
const ICE_PWD = (parsed1.atr.get("ice-pwd") as Set<string>).values().next().value as string;
|
||||||
const FINGERPRINT=(parsed1.atr.get("fingerprint") as Set<string>).values().next().value as string;
|
const FINGERPRINT = (parsed1.atr.get("fingerprint") as Set<string>).values().next()
|
||||||
|
.value as string;
|
||||||
const candidate = (parsed1.atr.get("candidate") as Set<string>).values().next().value as string;
|
const candidate = (parsed1.atr.get("candidate") as Set<string>).values().next().value as string;
|
||||||
let build = `v=0\r
|
let build = `v=0\r
|
||||||
o=- 1420070400000 0 IN IP4 127.0.0.1\r
|
o=- 1420070400000 0 IN IP4 127.0.0.1\r
|
||||||
s=-\r
|
s=-\r
|
||||||
t=0 0\r
|
t=0 0\r
|
||||||
a=msid-semantic: WMS *\r
|
a=msid-semantic: WMS *\r
|
||||||
a=group:BUNDLE ${bundles.join(" ")}\r`
|
a=group:BUNDLE ${bundles.join(" ")}\r`;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const grouping of parsed.medias) {
|
for (const grouping of parsed.medias) {
|
||||||
let mode = "recvonly";
|
let mode = "recvonly";
|
||||||
@@ -216,7 +218,7 @@ a=ice-ufrag:${ICE_UFRAG}\r
|
|||||||
a=ice-pwd:${ICE_PWD}\r
|
a=ice-pwd:${ICE_PWD}\r
|
||||||
a=fingerprint:${FINGERPRINT}\r
|
a=fingerprint:${FINGERPRINT}\r
|
||||||
a=candidate:${candidate}\r
|
a=candidate:${candidate}\r
|
||||||
a=rtcp-mux\r`
|
a=rtcp-mux\r`;
|
||||||
} else {
|
} else {
|
||||||
build += `
|
build += `
|
||||||
m=video ${rtcport} UDP/TLS/RTP/SAVPF 102 103\r
|
m=video ${rtcport} UDP/TLS/RTP/SAVPF 102 103\r
|
||||||
@@ -244,7 +246,7 @@ a=fingerprint:${FINGERPRINT}\r
|
|||||||
a=candidate:${candidate}\r
|
a=candidate:${candidate}\r
|
||||||
a=rtcp-mux\r`;
|
a=rtcp-mux\r`;
|
||||||
}
|
}
|
||||||
i++
|
i++;
|
||||||
}
|
}
|
||||||
build += "\n";
|
build += "\n";
|
||||||
return build;
|
return build;
|
||||||
@@ -254,20 +256,25 @@ a=rtcp-mux\r`;
|
|||||||
if (this.pc && this.offer) {
|
if (this.pc && this.offer) {
|
||||||
const pc = this.pc;
|
const pc = this.pc;
|
||||||
pc.addEventListener("negotiationneeded", async () => {
|
pc.addEventListener("negotiationneeded", async () => {
|
||||||
this.offer=(await pc.createOffer({
|
this.offer = (
|
||||||
|
await pc.createOffer({
|
||||||
offerToReceiveAudio: true,
|
offerToReceiveAudio: true,
|
||||||
offerToReceiveVideo: true
|
offerToReceiveVideo: true,
|
||||||
})).sdp;
|
})
|
||||||
|
).sdp;
|
||||||
await pc.setLocalDescription({sdp: this.offer});
|
await pc.setLocalDescription({sdp: this.offer});
|
||||||
|
|
||||||
if (!this.counter) throw new Error("counter isn't defined");
|
if (!this.counter) throw new Error("counter isn't defined");
|
||||||
const counter = this.counter;
|
const counter = this.counter;
|
||||||
const remote:{sdp:string,type:RTCSdpType}={sdp:this.cleanServerSDP(counter),type:"answer"};
|
const remote: {sdp: string; type: RTCSdpType} = {
|
||||||
|
sdp: this.cleanServerSDP(counter),
|
||||||
|
type: "answer",
|
||||||
|
};
|
||||||
console.log(remote);
|
console.log(remote);
|
||||||
await pc.setRemoteDescription(remote);
|
await pc.setRemoteDescription(remote);
|
||||||
const senders = this.senders.difference(this.ssrcMap);
|
const senders = this.senders.difference(this.ssrcMap);
|
||||||
for (const sender of senders) {
|
for (const sender of senders) {
|
||||||
for(const thing of (await sender.getStats() as Map<string, any>)){
|
for (const thing of (await sender.getStats()) as Map<string, any>) {
|
||||||
if (thing[1].ssrc) {
|
if (thing[1].ssrc) {
|
||||||
this.ssrcMap.set(sender, thing[1].ssrc);
|
this.ssrcMap.set(sender, thing[1].ssrc);
|
||||||
this.makeOp12(sender);
|
this.makeOp12(sender);
|
||||||
@@ -278,13 +285,16 @@ a=rtcp-mux\r`;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async makeOp12(sender:RTCRtpSender|undefined|[RTCRtpSender,number]=(this.ssrcMap.entries().next().value)){
|
async makeOp12(
|
||||||
|
sender: RTCRtpSender | undefined | [RTCRtpSender, number] = this.ssrcMap.entries().next().value,
|
||||||
|
) {
|
||||||
if (!sender) throw new Error("sender doesn't exist");
|
if (!sender) throw new Error("sender doesn't exist");
|
||||||
if (sender instanceof Array) {
|
if (sender instanceof Array) {
|
||||||
sender = sender[0];
|
sender = sender[0];
|
||||||
}
|
}
|
||||||
if (this.ws) {
|
if (this.ws) {
|
||||||
this.ws.send(JSON.stringify({
|
this.ws.send(
|
||||||
|
JSON.stringify({
|
||||||
op: 12,
|
op: 12,
|
||||||
d: {
|
d: {
|
||||||
audio_ssrc: this.ssrcMap.get(sender),
|
audio_ssrc: this.ssrcMap.get(sender),
|
||||||
@@ -303,12 +313,13 @@ a=rtcp-mux\r`;
|
|||||||
max_resolution: {
|
max_resolution: {
|
||||||
type: "fixed",
|
type: "fixed",
|
||||||
width: 0, //TODO
|
width: 0, //TODO
|
||||||
height: 0//TODO
|
height: 0, //TODO
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
this.status = "Sending audio streams";
|
this.status = "Sending audio streams";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -336,7 +347,7 @@ a=rtcp-mux\r`;
|
|||||||
if (this.speaking) {
|
if (this.speaking) {
|
||||||
this.speaking = false;
|
this.speaking = false;
|
||||||
this.sendSpeaking();
|
this.sendSpeaking();
|
||||||
console.log("not speaking")
|
console.log("not speaking");
|
||||||
}
|
}
|
||||||
} else if (!this.speaking) {
|
} else if (!this.speaking) {
|
||||||
console.log("speaking");
|
console.log("speaking");
|
||||||
@@ -348,15 +359,17 @@ a=rtcp-mux\r`;
|
|||||||
async sendSpeaking() {
|
async sendSpeaking() {
|
||||||
if (!this.ws) return;
|
if (!this.ws) return;
|
||||||
const pair = this.ssrcMap.entries().next().value;
|
const pair = this.ssrcMap.entries().next().value;
|
||||||
if(!pair) return
|
if (!pair) return;
|
||||||
this.ws.send(JSON.stringify({
|
this.ws.send(
|
||||||
|
JSON.stringify({
|
||||||
op: 5,
|
op: 5,
|
||||||
d: {
|
d: {
|
||||||
speaking: +this.speaking,
|
speaking: +this.speaking,
|
||||||
delay: 5, //not sure
|
delay: 5, //not sure
|
||||||
ssrc:pair[1]
|
ssrc: pair[1],
|
||||||
}
|
},
|
||||||
}))
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
async continueWebRTC(data: sdpback) {
|
async continueWebRTC(data: sdpback) {
|
||||||
if (this.pc && this.offer) {
|
if (this.pc && this.offer) {
|
||||||
@@ -370,20 +383,20 @@ a=rtcp-mux\r`;
|
|||||||
this.setupMic(audioStream);
|
this.setupMic(audioStream);
|
||||||
const sender = pc.addTrack(track);
|
const sender = pc.addTrack(track);
|
||||||
this.senders.add(sender);
|
this.senders.add(sender);
|
||||||
console.log(sender)
|
console.log(sender);
|
||||||
}
|
}
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
pc.addTransceiver("audio", {
|
pc.addTransceiver("audio", {
|
||||||
direction: "recvonly",
|
direction: "recvonly",
|
||||||
streams: [],
|
streams: [],
|
||||||
sendEncodings:[{active:true,maxBitrate:this.settings.bitrate}]
|
sendEncodings: [{active: true, maxBitrate: this.settings.bitrate}],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
pc.addTransceiver("video", {
|
pc.addTransceiver("video", {
|
||||||
direction: "recvonly",
|
direction: "recvonly",
|
||||||
streams: [],
|
streams: [],
|
||||||
sendEncodings:[{active:true,maxBitrate:this.settings.bitrate}]
|
sendEncodings: [{active: true, maxBitrate: this.settings.bitrate}],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.counter = data.d.sdp;
|
this.counter = data.d.sdp;
|
||||||
@@ -405,21 +418,20 @@ a=rtcp-mux\r`;
|
|||||||
console.log(media);
|
console.log(media);
|
||||||
ss.connect(context.destination);
|
ss.connect(context.destination);
|
||||||
new Audio().srcObject = media; //weird I know, but it's for chromium/webkit bug
|
new Audio().srcObject = media; //weird I know, but it's for chromium/webkit bug
|
||||||
this.recivers.add(e.receiver)
|
this.recivers.add(e.receiver);
|
||||||
};
|
};
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.status = "Connection failed";
|
this.status = "Connection failed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reciverMap=new Map<number,RTCRtpReceiver>()
|
reciverMap = new Map<number, RTCRtpReceiver>();
|
||||||
async figureRecivers() {
|
async figureRecivers() {
|
||||||
await new Promise(res=>setTimeout(res,500));
|
await new Promise((res) => setTimeout(res, 500));
|
||||||
for (const reciver of this.recivers) {
|
for (const reciver of this.recivers) {
|
||||||
const stats=await reciver.getStats() as Map<string,any>;
|
const stats = (await reciver.getStats()) as Map<string, any>;
|
||||||
for(const thing of (stats)){
|
for (const thing of stats) {
|
||||||
if (thing[1].ssrc) {
|
if (thing[1].ssrc) {
|
||||||
this.reciverMap.set(thing[1].ssrc,reciver)
|
this.reciverMap.set(thing[1].ssrc, reciver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,7 +443,7 @@ a=rtcp-mux\r`;
|
|||||||
this.pc = pc;
|
this.pc = pc;
|
||||||
const offer = await pc.createOffer({
|
const offer = await pc.createOffer({
|
||||||
offerToReceiveAudio: true,
|
offerToReceiveAudio: true,
|
||||||
offerToReceiveVideo: true
|
offerToReceiveVideo: true,
|
||||||
});
|
});
|
||||||
this.status = "Starting RTC connection";
|
this.status = "Starting RTC connection";
|
||||||
const sdp = offer.sdp;
|
const sdp = offer.sdp;
|
||||||
@@ -453,12 +465,11 @@ a=rtcp-mux\r`;
|
|||||||
const rtpmap = thing.atr.get("rtpmap");
|
const rtpmap = thing.atr.get("rtpmap");
|
||||||
if (!rtpmap) continue;
|
if (!rtpmap) continue;
|
||||||
for (const codecpair of rtpmap) {
|
for (const codecpair of rtpmap) {
|
||||||
|
|
||||||
const [port, codec] = codecpair.split(" ");
|
const [port, codec] = codecpair.split(" ");
|
||||||
if (cur && codec.split("/")[0] === "rtx") {
|
if (cur && codec.split("/")[0] === "rtx") {
|
||||||
cur[1] = Number(port);
|
cur[1] = Number(port);
|
||||||
cur = undefined;
|
cur = undefined;
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
if (video.has(codec.split("/")[0])) continue;
|
if (video.has(codec.split("/")[0])) continue;
|
||||||
cur = [Number(port), -1];
|
cur = [Number(port), -1];
|
||||||
@@ -469,7 +480,9 @@ a=rtcp-mux\r`;
|
|||||||
if (!rtpmap) continue;
|
if (!rtpmap) continue;
|
||||||
for (const codecpair of rtpmap) {
|
for (const codecpair of rtpmap) {
|
||||||
const [port, codec] = codecpair.split(" ");
|
const [port, codec] = codecpair.split(" ");
|
||||||
if(audio.has(codec.split("/")[0])) { continue};
|
if (audio.has(codec.split("/")[0])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
audio.set(codec.split("/")[0], Number(port));
|
audio.set(codec.split("/")[0], Number(port));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -479,14 +492,14 @@ a=rtcp-mux\r`;
|
|||||||
}
|
}
|
||||||
|
|
||||||
const codecs: {
|
const codecs: {
|
||||||
name: string,
|
name: string;
|
||||||
type: "video"|"audio",
|
type: "video" | "audio";
|
||||||
priority: number,
|
priority: number;
|
||||||
payload_type: number,
|
payload_type: number;
|
||||||
rtx_payload_type: number|null
|
rtx_payload_type: number | null;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
const include = new Set<string>();
|
const include = new Set<string>();
|
||||||
const audioAlloweds=new Map([["opus",{priority:1000,}]]);
|
const audioAlloweds = new Map([["opus", {priority: 1000}]]);
|
||||||
for (const thing of audio) {
|
for (const thing of audio) {
|
||||||
if (audioAlloweds.has(thing[0])) {
|
if (audioAlloweds.has(thing[0])) {
|
||||||
include.add(thing[0]);
|
include.add(thing[0]);
|
||||||
@@ -495,11 +508,15 @@ a=rtcp-mux\r`;
|
|||||||
type: "audio",
|
type: "audio",
|
||||||
priority: audioAlloweds.get(thing[0])?.priority as number,
|
priority: audioAlloweds.get(thing[0])?.priority as number,
|
||||||
payload_type: thing[1],
|
payload_type: thing[1],
|
||||||
rtx_payload_type:null
|
rtx_payload_type: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const videoAlloweds=new Map([["H264",{priority:1000}],["VP8",{priority:2000}],["VP9",{priority:3000}]]);
|
const videoAlloweds = new Map([
|
||||||
|
["H264", {priority: 1000}],
|
||||||
|
["VP8", {priority: 2000}],
|
||||||
|
["VP9", {priority: 3000}],
|
||||||
|
]);
|
||||||
for (const thing of video) {
|
for (const thing of video) {
|
||||||
if (videoAlloweds.has(thing[0])) {
|
if (videoAlloweds.has(thing[0])) {
|
||||||
include.add(thing[0]);
|
include.add(thing[0]);
|
||||||
@@ -508,15 +525,16 @@ a=rtcp-mux\r`;
|
|||||||
type: "video",
|
type: "video",
|
||||||
priority: videoAlloweds.get(thing[0])?.priority as number,
|
priority: videoAlloweds.get(thing[0])?.priority as number,
|
||||||
payload_type: thing[1][0],
|
payload_type: thing[1][0],
|
||||||
rtx_payload_type:thing[1][1]
|
rtx_payload_type: thing[1][1],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let sendsdp = "a=extmap-allow-mixed";
|
let sendsdp = "a=extmap-allow-mixed";
|
||||||
let first = true;
|
let first = true;
|
||||||
for (const media of parsed.medias) {
|
for (const media of parsed.medias) {
|
||||||
|
for (const thing of first
|
||||||
for(const thing of first?["ice-ufrag","ice-pwd","ice-options","fingerprint","extmap","rtpmap"]:["extmap","rtpmap"]){
|
? ["ice-ufrag", "ice-pwd", "ice-options", "fingerprint", "extmap", "rtpmap"]
|
||||||
|
: ["extmap", "rtpmap"]) {
|
||||||
const thing2 = media.atr.get(thing);
|
const thing2 = media.atr.get(thing);
|
||||||
if (!thing2) continue;
|
if (!thing2) continue;
|
||||||
for (const thing3 of thing2) {
|
for (const thing3 of thing2) {
|
||||||
@@ -534,20 +552,32 @@ a=rtcp-mux\r`;
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
if (this.ws) {
|
if (this.ws) {
|
||||||
this.ws.send(JSON.stringify({
|
this.ws.send(
|
||||||
|
JSON.stringify({
|
||||||
d: {
|
d: {
|
||||||
codecs,
|
codecs,
|
||||||
protocol: "webrtc",
|
protocol: "webrtc",
|
||||||
data: sendsdp,
|
data: sendsdp,
|
||||||
sdp:sendsdp
|
sdp: sendsdp,
|
||||||
},
|
},
|
||||||
op:1
|
op: 1,
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static parsesdp(sdp: string) {
|
static parsesdp(sdp: string) {
|
||||||
let currentA = new Map<string, Set<string>>();
|
let currentA = new Map<string, Set<string>>();
|
||||||
const out:{version?:number,medias:{media:string,port:number,proto:string,ports:number[],atr:Map<string,Set<string>>}[],atr:Map<string,Set<string>>}={medias:[],atr:currentA};
|
const out: {
|
||||||
|
version?: number;
|
||||||
|
medias: {
|
||||||
|
media: string;
|
||||||
|
port: number;
|
||||||
|
proto: string;
|
||||||
|
ports: number[];
|
||||||
|
atr: Map<string, Set<string>>;
|
||||||
|
}[];
|
||||||
|
atr: Map<string, Set<string>>;
|
||||||
|
} = {medias: [], atr: currentA};
|
||||||
for (const line of sdp.split("\n")) {
|
for (const line of sdp.split("\n")) {
|
||||||
const [code, setinfo] = line.split("=");
|
const [code, setinfo] = line.split("=");
|
||||||
switch (code) {
|
switch (code) {
|
||||||
@@ -578,7 +608,7 @@ a=rtcp-mux\r`;
|
|||||||
open = false;
|
open = false;
|
||||||
async join() {
|
async join() {
|
||||||
console.warn("Joining");
|
console.warn("Joining");
|
||||||
this.open=true
|
this.open = true;
|
||||||
this.status = "waiting for main WS";
|
this.status = "waiting for main WS";
|
||||||
}
|
}
|
||||||
onMemberChange = (_member: memberjson | string, _joined: boolean) => {};
|
onMemberChange = (_member: memberjson | string, _joined: boolean) => {};
|
||||||
@@ -591,49 +621,54 @@ a=rtcp-mux\r`;
|
|||||||
if (!update) {
|
if (!update) {
|
||||||
this.status = "bad responce from WS";
|
this.status = "bad responce from WS";
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
if (!this.urlobj.url) {
|
if (!this.urlobj.url) {
|
||||||
this.status = "waiting for Voice URL";
|
this.status = "waiting for Voice URL";
|
||||||
await this.urlobj.geturl;
|
await this.urlobj.geturl;
|
||||||
if(!this.open){this.leave();return}
|
if (!this.open) {
|
||||||
|
this.leave();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ws=new WebSocket("ws://"+this.urlobj.url as string);
|
const ws = new WebSocket(("ws://" + this.urlobj.url) as string);
|
||||||
this.ws = ws;
|
this.ws = ws;
|
||||||
ws.onclose = () => {
|
ws.onclose = () => {
|
||||||
this.leave();
|
this.leave();
|
||||||
}
|
};
|
||||||
this.status = "waiting for WS to open";
|
this.status = "waiting for WS to open";
|
||||||
ws.addEventListener("message", (m) => {
|
ws.addEventListener("message", (m) => {
|
||||||
this.packet(m);
|
this.packet(m);
|
||||||
})
|
});
|
||||||
await new Promise<void>(res=>{
|
await new Promise<void>((res) => {
|
||||||
ws.addEventListener("open", () => {
|
ws.addEventListener("open", () => {
|
||||||
res()
|
res();
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
if (!this.ws) {
|
if (!this.ws) {
|
||||||
this.leave();
|
this.leave();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.status = "waiting for WS to authorize";
|
this.status = "waiting for WS to authorize";
|
||||||
ws.send(JSON.stringify({
|
ws.send(
|
||||||
"op": 0,
|
JSON.stringify({
|
||||||
"d": {
|
op: 0,
|
||||||
|
d: {
|
||||||
server_id: update.d.guild_id,
|
server_id: update.d.guild_id,
|
||||||
user_id: update.d.user_id,
|
user_id: update.d.user_id,
|
||||||
session_id: update.d.session_id,
|
session_id: update.d.session_id,
|
||||||
token: update.d.token,
|
token: update.d.token,
|
||||||
video: false,
|
video: false,
|
||||||
"streams": [
|
streams: [
|
||||||
{
|
{
|
||||||
type: "video",
|
type: "video",
|
||||||
rid: "100",
|
rid: "100",
|
||||||
quality: 100
|
quality: 100,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async leave() {
|
async leave() {
|
||||||
|
|||||||
Reference in New Issue
Block a user