Ran eslint
Signed-off-by: Scott Gould <greysilly7@gmail.com>
This commit is contained in:
parent
a81bc02a5a
commit
a5b521e373
34 changed files with 11972 additions and 12065 deletions
310
eslint.config.js
310
eslint.config.js
|
@ -1,310 +0,0 @@
|
||||||
const globals = require("globals");
|
|
||||||
|
|
||||||
const unicorn = require("eslint-plugin-unicorn");
|
|
||||||
const sonarjs = require("eslint-plugin-sonarjs");
|
|
||||||
const stylistic = require("@stylistic/eslint-plugin-js");
|
|
||||||
const htmlESLint = require("@html-eslint/eslint-plugin");
|
|
||||||
const html = require("eslint-plugin-html");
|
|
||||||
|
|
||||||
const tsParser = require("@typescript-eslint/parser");
|
|
||||||
|
|
||||||
const linterOptions = {
|
|
||||||
reportUnusedDisableDirectives: "error"
|
|
||||||
};
|
|
||||||
const global = {
|
|
||||||
...globals.browser
|
|
||||||
};
|
|
||||||
|
|
||||||
const rules = {
|
|
||||||
"array-callback-return": 2,
|
|
||||||
"block-scoped-var": 2,
|
|
||||||
"default-case-last": 2,
|
|
||||||
"default-param-last": 1,
|
|
||||||
"dot-notation": 1,
|
|
||||||
"func-name-matching": 2,
|
|
||||||
"func-style": 0,
|
|
||||||
"no-array-constructor": 2,
|
|
||||||
"no-compare-neg-zero": 2,
|
|
||||||
"no-const-assign": 2,
|
|
||||||
"no-constructor-return": 2,
|
|
||||||
"no-dupe-args": 1,
|
|
||||||
"no-dupe-keys": 2,
|
|
||||||
"no-duplicate-case": 2,
|
|
||||||
"no-div-regex": 2,
|
|
||||||
"no-eq-null": 2,
|
|
||||||
"no-extra-boolean-cast": 2,
|
|
||||||
"no-extra-bind": 2,
|
|
||||||
"no-extend-native": 2,
|
|
||||||
"no-empty-pattern": 2,
|
|
||||||
"no-duplicate-imports": 2,
|
|
||||||
"no-fallthrough": 2,
|
|
||||||
"no-func-assign": 2,
|
|
||||||
"no-import-assign": 2,
|
|
||||||
"no-invalid-regexp": 2,
|
|
||||||
"no-invalid-this": 2,
|
|
||||||
"no-implicit-coercion": [2, {
|
|
||||||
string: false
|
|
||||||
}],
|
|
||||||
"no-implied-eval": 2,
|
|
||||||
"no-loss-of-precision": 2,
|
|
||||||
"no-multi-assign": 1,
|
|
||||||
"no-negated-condition": 1,
|
|
||||||
"no-new-native-nonconstructor": 2,
|
|
||||||
"no-new-object": 2,
|
|
||||||
"no-obj-calls": 2,
|
|
||||||
"no-self-assign": 2,
|
|
||||||
"no-unreachable": 1,
|
|
||||||
"no-unreachable-loop": 1,
|
|
||||||
"no-unsafe-finally": 2,
|
|
||||||
"no-unused-vars": 1,
|
|
||||||
"no-useless-computed-key": 2,
|
|
||||||
"no-useless-rename": 1,
|
|
||||||
"no-useless-escape": 1,
|
|
||||||
"no-unused-expressions": 1,
|
|
||||||
"no-useless-return": 1,
|
|
||||||
"no-useless-call": 2,
|
|
||||||
"no-use-before-define": 0,
|
|
||||||
"no-useless-concat": 1,
|
|
||||||
"no-useless-backreference": 1,
|
|
||||||
"no-useless-catch": 1,
|
|
||||||
"no-unneeded-ternary": 1,
|
|
||||||
"no-undef": [2, {
|
|
||||||
typeof: true
|
|
||||||
}],
|
|
||||||
"no-undef-init": 2,
|
|
||||||
"no-useless-constructor": 1,
|
|
||||||
"no-redeclare": 1,
|
|
||||||
"no-shadow-restricted-names": 2,
|
|
||||||
"no-empty-static-block": 1,
|
|
||||||
"no-throw-literal": 2,
|
|
||||||
"no-template-curly-in-string": 1,
|
|
||||||
"no-unsafe-optional-chaining": 2,
|
|
||||||
"no-unmodified-loop-condition": 1,
|
|
||||||
"no-promise-executor-return": 2,
|
|
||||||
"no-warning-comments": 1,
|
|
||||||
"no-var": 1,
|
|
||||||
"no-new-func": 2,
|
|
||||||
"no-new-wrappers": 2,
|
|
||||||
"no-multi-str": 2,
|
|
||||||
"no-shadow": [1, {
|
|
||||||
builtinGlobals: false
|
|
||||||
}],
|
|
||||||
"no-self-compare": 2,
|
|
||||||
"no-regex-spaces": 1,
|
|
||||||
"no-constant-binary-expression": 2,
|
|
||||||
"no-sequences": 2,
|
|
||||||
"no-irregular-whitespace": [2, {
|
|
||||||
skipRegExps: true
|
|
||||||
}],
|
|
||||||
"no-constant-condition": 1,
|
|
||||||
"no-unsafe-negation": 2,
|
|
||||||
"no-lone-blocks": 2,
|
|
||||||
"object-shorthand": 1,
|
|
||||||
"prefer-arrow-callback": 1,
|
|
||||||
"prefer-const": 1,
|
|
||||||
"use-isnan": 1,
|
|
||||||
"valid-typeof": 2,
|
|
||||||
yoda: 2,
|
|
||||||
|
|
||||||
"@stylistic/array-bracket-spacing": 2,
|
|
||||||
"@stylistic/arrow-parens": [2, "as-needed"],
|
|
||||||
"@stylistic/arrow-spacing": [2, { before: false, after: false }],
|
|
||||||
"@stylistic/block-spacing": [2, "never"],
|
|
||||||
"@stylistic/brace-style": 1,
|
|
||||||
"@stylistic/comma-style": 2,
|
|
||||||
"@stylistic/computed-property-spacing": 2,
|
|
||||||
"@stylistic/dot-location": [2, "property"],
|
|
||||||
"@stylistic/function-call-spacing": 2,
|
|
||||||
"@stylistic/generator-star-spacing": 2,
|
|
||||||
"@stylistic/key-spacing": 2,
|
|
||||||
"@stylistic/indent": [1, "tab"],
|
|
||||||
"@stylistic/keyword-spacing": [1, { before: false, after: false }],
|
|
||||||
"@stylistic/new-parens": 2,
|
|
||||||
"@stylistic/no-mixed-operators": [2, {
|
|
||||||
groups: [["*", "/"], ["+", "-"]]
|
|
||||||
}],
|
|
||||||
"@stylistic/no-extra-semi": 1,
|
|
||||||
"@stylistic/no-multi-spaces": 1,
|
|
||||||
"@stylistic/no-mixed-spaces-and-tabs": 2,
|
|
||||||
"@stylistic/no-floating-decimal": 2,
|
|
||||||
"@stylistic/no-whitespace-before-property": 2,
|
|
||||||
"@stylistic/no-trailing-spaces": 1,
|
|
||||||
"@stylistic/max-statements-per-line": 1,
|
|
||||||
"@stylistic/max-len": [1, {
|
|
||||||
code: 200
|
|
||||||
}],
|
|
||||||
"@stylistic/quote-props": [2, "as-needed"],
|
|
||||||
"@stylistic/quotes": [1, "double", {
|
|
||||||
avoidEscape: false
|
|
||||||
}],
|
|
||||||
"@stylistic/padded-blocks": [2, "never"],
|
|
||||||
"@stylistic/rest-spread-spacing": 2,
|
|
||||||
"@stylistic/semi": 1,
|
|
||||||
"@stylistic/space-before-blocks": [2, "never"],
|
|
||||||
"@stylistic/space-before-function-paren": [2, {
|
|
||||||
named: "never",
|
|
||||||
anonymous: "never",
|
|
||||||
asyncArrow: "always"
|
|
||||||
}],
|
|
||||||
"@stylistic/space-in-parens": 2,
|
|
||||||
"@stylistic/space-unary-ops": 2,
|
|
||||||
"@stylistic/yield-star-spacing": 2,
|
|
||||||
|
|
||||||
"unicorn/error-message": 2,
|
|
||||||
"unicorn/new-for-builtins": 2,
|
|
||||||
"unicorn/consistent-empty-array-spread": 2,
|
|
||||||
"unicorn/consistent-destructuring": 2,
|
|
||||||
"unicorn/consistent-function-scoping": 2,
|
|
||||||
"unicorn/no-array-method-this-argument": 2,
|
|
||||||
"unicorn/no-lonely-if": 1,
|
|
||||||
"unicorn/no-invalid-fetch-options": 2,
|
|
||||||
"unicorn/no-instanceof-array": 2,
|
|
||||||
"unicorn/no-magic-array-flat-depth": 2,
|
|
||||||
"unicorn/no-nested-ternary": 2,
|
|
||||||
"unicorn/no-new-buffer": 2,
|
|
||||||
"unicorn/no-console-spaces": 2,
|
|
||||||
"unicorn/no-for-loop": 2,
|
|
||||||
"unicorn/no-useless-undefined": 2,
|
|
||||||
"unicorn/no-unreadable-iife": 2,
|
|
||||||
"unicorn/no-unnecessary-await": 2,
|
|
||||||
"unicorn/no-unreadable-array-destructuring": 2,
|
|
||||||
"unicorn/no-useless-switch-case": 2,
|
|
||||||
"unicorn/no-typeof-undefined": 2,
|
|
||||||
"unicorn/no-useless-fallback-in-spread": 2,
|
|
||||||
"unicorn/no-useless-length-check": 2,
|
|
||||||
"unicorn/no-useless-spread": 2,
|
|
||||||
"unicorn/no-useless-promise-resolve-reject": 2,
|
|
||||||
"unicorn/no-zero-fractions": 2,
|
|
||||||
"unicorn/prefer-array-find": 1,
|
|
||||||
"unicorn/prefer-array-index-of": 1,
|
|
||||||
"unicorn/prefer-includes": 1,
|
|
||||||
"unicorn/prefer-logical-operator-over-ternary": 1,
|
|
||||||
"unicorn/prefer-date-now": 1,
|
|
||||||
"unicorn/prefer-default-parameters": 1,
|
|
||||||
"unicorn/prefer-array-some": 1,
|
|
||||||
"unicorn/prefer-blob-reading-methods": 1,
|
|
||||||
"unicorn/prefer-at": 1,
|
|
||||||
"unicorn/prefer-optional-catch-binding": 1,
|
|
||||||
"unicorn/prefer-regexp-test": 1,
|
|
||||||
"unicorn/prefer-set-has": 1,
|
|
||||||
"unicorn/prefer-set-size": 1,
|
|
||||||
"unicorn/prefer-keyboard-event-key": 1,
|
|
||||||
"unicorn/prefer-negative-index": 1,
|
|
||||||
"unicorn/prefer-node-protocol": 1,
|
|
||||||
"unicorn/prefer-number-properties": [1, {
|
|
||||||
checkInfinity: true
|
|
||||||
}],
|
|
||||||
"unicorn/prefer-prototype-methods": 1,
|
|
||||||
"unicorn/prefer-string-trim-start-end": 1,
|
|
||||||
"unicorn/prefer-string-starts-ends-with": 1,
|
|
||||||
"unicorn/prefer-structured-clone": 1,
|
|
||||||
"unicorn/throw-new-error": 2,
|
|
||||||
"unicorn/require-number-to-fixed-digits-argument": 2,
|
|
||||||
"unicorn/switch-case-braces": [1, "avoid"],
|
|
||||||
"unicorn/text-encoding-identifier-case": 2,
|
|
||||||
"unicorn/no-await-in-promise-methods": 2,
|
|
||||||
"unicorn/no-single-promise-in-promise-methods": 2,
|
|
||||||
"unicorn/no-negation-in-equality-check": 2,
|
|
||||||
"unicorn/no-length-as-slice-end": 2,
|
|
||||||
|
|
||||||
"sonarjs/no-extra-arguments": 2,
|
|
||||||
"sonarjs/no-empty-collection": 2,
|
|
||||||
"sonarjs/no-element-overwrite": 2,
|
|
||||||
"sonarjs/no-use-of-empty-return-value": 2,
|
|
||||||
"sonarjs/no-all-duplicated-branches": 2,
|
|
||||||
"sonarjs/no-ignored-return": 2,
|
|
||||||
"sonarjs/no-identical-expressions": 2,
|
|
||||||
"sonarjs/no-one-iteration-loop": 2,
|
|
||||||
"sonarjs/non-existent-operator": 2,
|
|
||||||
"sonarjs/no-redundant-boolean": 2,
|
|
||||||
"sonarjs/no-unused-collection": 1,
|
|
||||||
"sonarjs/prefer-immediate-return": 2,
|
|
||||||
"sonarjs/no-inverted-boolean-check": 2,
|
|
||||||
"sonarjs/no-redundant-jump": 2,
|
|
||||||
"sonarjs/no-same-line-conditional": 2,
|
|
||||||
"sonarjs/prefer-object-literal": 2,
|
|
||||||
"sonarjs/no-collection-size-mischeck": 2,
|
|
||||||
"sonarjs/prefer-while": 2,
|
|
||||||
"sonarjs/no-gratuitous-expressions": 2,
|
|
||||||
"sonarjs/no-duplicated-branches": 2
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = [
|
|
||||||
{
|
|
||||||
linterOptions,
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsParser,
|
|
||||||
globals: global
|
|
||||||
},
|
|
||||||
files: ["webpage/*.ts"],
|
|
||||||
ignores: ["!*.js", "!*.ts"],
|
|
||||||
plugins: {
|
|
||||||
unicorn,
|
|
||||||
sonarjs,
|
|
||||||
"@stylistic": stylistic
|
|
||||||
},
|
|
||||||
rules
|
|
||||||
},{
|
|
||||||
linterOptions,
|
|
||||||
languageOptions: {
|
|
||||||
parser: tsParser,
|
|
||||||
globals: globals.node
|
|
||||||
},
|
|
||||||
files: ["*.js", "*.ts"],
|
|
||||||
plugins: {
|
|
||||||
unicorn,
|
|
||||||
sonarjs,
|
|
||||||
"@stylistic": stylistic
|
|
||||||
},
|
|
||||||
rules
|
|
||||||
},{
|
|
||||||
linterOptions,
|
|
||||||
languageOptions: {
|
|
||||||
globals: global,
|
|
||||||
parser: require("@html-eslint/parser")
|
|
||||||
},
|
|
||||||
files: ["**/*.html"],
|
|
||||||
plugins: {
|
|
||||||
unicorn,
|
|
||||||
sonarjs,
|
|
||||||
"@stylistic": stylistic,
|
|
||||||
"@html-eslint": htmlESLint,
|
|
||||||
html
|
|
||||||
},
|
|
||||||
settings: {
|
|
||||||
"html/html-extensions": [".html"]
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
...rules,
|
|
||||||
|
|
||||||
"@html-eslint/require-meta-charset": 2,
|
|
||||||
"@html-eslint/require-button-type": 2,
|
|
||||||
"@html-eslint/no-restricted-attrs": 2,
|
|
||||||
"@html-eslint/no-multiple-h1": 1,
|
|
||||||
"@html-eslint/require-meta-description": 1,
|
|
||||||
"@html-eslint/no-skip-heading-levels": 2,
|
|
||||||
"@html-eslint/require-frame-title": 2,
|
|
||||||
"@html-eslint/no-non-scalable-viewport": 2,
|
|
||||||
"@html-eslint/no-positive-tabindex": 2,
|
|
||||||
"@html-eslint/require-meta-viewport": 2,
|
|
||||||
"@html-eslint/no-abstract-roles": 2,
|
|
||||||
"@html-eslint/no-aria-hidden-body": 2,
|
|
||||||
"@html-eslint/no-accesskey-attrs": 2,
|
|
||||||
"@html-eslint/no-multiple-empty-lines": 2,
|
|
||||||
"@html-eslint/no-trailing-spaces": 2,
|
|
||||||
"@html-eslint/indent": [1, "tab"],
|
|
||||||
"@html-eslint/no-duplicate-attrs": 2,
|
|
||||||
"@html-eslint/no-inline-styles": 1,
|
|
||||||
"@html-eslint/no-duplicate-id": 2,
|
|
||||||
"@html-eslint/no-script-style-type": 2,
|
|
||||||
"@html-eslint/require-li-container": 2,
|
|
||||||
"@html-eslint/require-closing-tags": 2,
|
|
||||||
"@html-eslint/require-doctype": 2,
|
|
||||||
"@html-eslint/require-lang": 2,
|
|
||||||
"@html-eslint/require-title": 2,
|
|
||||||
"@html-eslint/no-extra-spacing-attrs": 2,
|
|
||||||
"@html-eslint/quotes": 2,
|
|
||||||
"@html-eslint/require-img-alt": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
183
eslint.config.mjs
Normal file
183
eslint.config.mjs
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
import eslint from "@eslint/js";
|
||||||
|
import tseslint from "typescript-eslint";
|
||||||
|
import html from "@html-eslint/eslint-plugin";
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
eslint.configs.recommended,
|
||||||
|
...tseslint.configs.stylisticTypeChecked,
|
||||||
|
html.configs["flat/recommended"],
|
||||||
|
{
|
||||||
|
languageOptions: {
|
||||||
|
parserOptions: {
|
||||||
|
projectService: true,
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
files: ["**/*.ts", "**/*.html"],
|
||||||
|
rules: {
|
||||||
|
"array-callback-return": 2,
|
||||||
|
"block-scoped-var": 2,
|
||||||
|
"default-case-last": 2,
|
||||||
|
"default-param-last": 1,
|
||||||
|
"dot-notation": 1,
|
||||||
|
"func-name-matching": 2,
|
||||||
|
"func-style": 0,
|
||||||
|
"no-array-constructor": 2,
|
||||||
|
"no-compare-neg-zero": 2,
|
||||||
|
"no-const-assign": 2,
|
||||||
|
"no-constructor-return": 2,
|
||||||
|
"no-dupe-args": 1,
|
||||||
|
"no-dupe-keys": 2,
|
||||||
|
"no-duplicate-case": 2,
|
||||||
|
"no-div-regex": 2,
|
||||||
|
"no-eq-null": 2,
|
||||||
|
"no-extra-boolean-cast": 2,
|
||||||
|
"no-extra-bind": 2,
|
||||||
|
"no-extend-native": 2,
|
||||||
|
"no-empty-pattern": 2,
|
||||||
|
"no-duplicate-imports": 2,
|
||||||
|
"no-fallthrough": 2,
|
||||||
|
"no-func-assign": 2,
|
||||||
|
"no-import-assign": 2,
|
||||||
|
"no-invalid-regexp": 2,
|
||||||
|
"no-invalid-this": 2,
|
||||||
|
"no-implicit-coercion": [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
string: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"no-implied-eval": 2,
|
||||||
|
"no-loss-of-precision": 2,
|
||||||
|
"no-multi-assign": 1,
|
||||||
|
"no-negated-condition": 1,
|
||||||
|
"no-new-native-nonconstructor": 2,
|
||||||
|
"no-new-object": 2,
|
||||||
|
"no-obj-calls": 2,
|
||||||
|
"no-self-assign": 2,
|
||||||
|
"no-unreachable": 1,
|
||||||
|
"no-unreachable-loop": 1,
|
||||||
|
"no-unsafe-finally": 2,
|
||||||
|
"no-unused-vars": 1,
|
||||||
|
"no-useless-computed-key": 2,
|
||||||
|
"no-useless-rename": 1,
|
||||||
|
"no-useless-escape": 1,
|
||||||
|
"no-unused-expressions": 1,
|
||||||
|
"no-useless-return": 1,
|
||||||
|
"no-useless-call": 2,
|
||||||
|
"no-use-before-define": 0,
|
||||||
|
"no-useless-concat": 1,
|
||||||
|
"no-useless-backreference": 1,
|
||||||
|
"no-useless-catch": 1,
|
||||||
|
"no-unneeded-ternary": 1,
|
||||||
|
"no-undef": [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
typeof: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"no-undef-init": 2,
|
||||||
|
"no-useless-constructor": 1,
|
||||||
|
"no-redeclare": 1,
|
||||||
|
"no-shadow-restricted-names": 2,
|
||||||
|
"no-empty-static-block": 1,
|
||||||
|
"no-throw-literal": 2,
|
||||||
|
"no-template-curly-in-string": 1,
|
||||||
|
"no-unsafe-optional-chaining": 2,
|
||||||
|
"no-unmodified-loop-condition": 1,
|
||||||
|
"no-promise-executor-return": 2,
|
||||||
|
"no-warning-comments": 1,
|
||||||
|
"no-var": 1,
|
||||||
|
"no-new-func": 2,
|
||||||
|
"no-new-wrappers": 2,
|
||||||
|
"no-multi-str": 2,
|
||||||
|
"no-shadow": [
|
||||||
|
1,
|
||||||
|
{
|
||||||
|
builtinGlobals: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"no-self-compare": 2,
|
||||||
|
"no-regex-spaces": 1,
|
||||||
|
"no-constant-binary-expression": 2,
|
||||||
|
"no-sequences": 2,
|
||||||
|
"no-irregular-whitespace": [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
skipRegExps: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"no-constant-condition": 1,
|
||||||
|
"no-unsafe-negation": 2,
|
||||||
|
"no-lone-blocks": 2,
|
||||||
|
"object-shorthand": 1,
|
||||||
|
"prefer-arrow-callback": 1,
|
||||||
|
"prefer-const": 1,
|
||||||
|
"use-isnan": 1,
|
||||||
|
"valid-typeof": 2,
|
||||||
|
yoda: 2,
|
||||||
|
|
||||||
|
"@stylistic/array-bracket-spacing": 2,
|
||||||
|
"@stylistic/arrow-parens": [2, "as-needed"],
|
||||||
|
"@stylistic/arrow-spacing": [2, { before: false, after: false }],
|
||||||
|
"@stylistic/block-spacing": [2, "never"],
|
||||||
|
"@stylistic/brace-style": 1,
|
||||||
|
"@stylistic/comma-style": 2,
|
||||||
|
"@stylistic/computed-property-spacing": 2,
|
||||||
|
"@stylistic/dot-location": [2, "property"],
|
||||||
|
"@stylistic/function-call-spacing": 2,
|
||||||
|
"@stylistic/generator-star-spacing": 2,
|
||||||
|
"@stylistic/key-spacing": 2,
|
||||||
|
"@stylistic/indent": [1, "tab"],
|
||||||
|
"@stylistic/keyword-spacing": [1, { before: false, after: false }],
|
||||||
|
"@stylistic/new-parens": 2,
|
||||||
|
"@stylistic/no-mixed-operators": [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
groups: [
|
||||||
|
["*", "/"],
|
||||||
|
["+", "-"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@stylistic/no-extra-semi": 1,
|
||||||
|
"@stylistic/no-multi-spaces": 1,
|
||||||
|
"@stylistic/no-mixed-spaces-and-tabs": 2,
|
||||||
|
"@stylistic/no-floating-decimal": 2,
|
||||||
|
"@stylistic/no-whitespace-before-property": 2,
|
||||||
|
"@stylistic/no-trailing-spaces": 1,
|
||||||
|
"@stylistic/max-statements-per-line": 1,
|
||||||
|
"@stylistic/max-len": [
|
||||||
|
1,
|
||||||
|
{
|
||||||
|
code: 200,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@stylistic/quote-props": [2, "as-needed"],
|
||||||
|
"@stylistic/quotes": [
|
||||||
|
1,
|
||||||
|
"double",
|
||||||
|
{
|
||||||
|
avoidEscape: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@stylistic/padded-blocks": [2, "never"],
|
||||||
|
"@stylistic/rest-spread-spacing": 2,
|
||||||
|
"@stylistic/semi": 1,
|
||||||
|
"@stylistic/space-before-blocks": [2, "never"],
|
||||||
|
"@stylistic/space-before-function-paren": [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
named: "never",
|
||||||
|
anonymous: "never",
|
||||||
|
asyncArrow: "always",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@stylistic/space-in-parens": 2,
|
||||||
|
"@stylistic/space-unary-ops": 2,
|
||||||
|
"@stylistic/yield-star-spacing": 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
240
package-lock.json
generated
240
package-lock.json
generated
|
@ -15,7 +15,7 @@
|
||||||
"ts-to-jsdoc": "^2.2.0"
|
"ts-to-jsdoc": "^2.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.7.0",
|
"@eslint/js": "^9.10.0",
|
||||||
"@html-eslint/eslint-plugin": "^0.25.0",
|
"@html-eslint/eslint-plugin": "^0.25.0",
|
||||||
"@html-eslint/parser": "^0.25.0",
|
"@html-eslint/parser": "^0.25.0",
|
||||||
"@stylistic/eslint-plugin": "^2.3.0",
|
"@stylistic/eslint-plugin": "^2.3.0",
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
"@types/eslint__js": "^8.42.3",
|
"@types/eslint__js": "^8.42.3",
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/node-fetch": "^2.6.11",
|
"@types/node-fetch": "^2.6.11",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.1",
|
||||||
"eslint-plugin-html": "^8.1.1",
|
"eslint-plugin-html": "^8.1.1",
|
||||||
"eslint-plugin-sonarjs": "^1.0.4",
|
"eslint-plugin-sonarjs": "^1.0.4",
|
||||||
"eslint-plugin-unicorn": "^55.0.0",
|
"eslint-plugin-unicorn": "^55.0.0",
|
||||||
|
@ -31,8 +31,8 @@
|
||||||
"gulp-copy": "^5.0.0",
|
"gulp-copy": "^5.0.0",
|
||||||
"gulp-typescript": "^6.0.0-alpha.1",
|
"gulp-typescript": "^6.0.0-alpha.1",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.6.2",
|
||||||
"typescript-eslint": "^7.17.0"
|
"typescript-eslint": "^7.18.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
|
@ -290,10 +290,11 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.7.0",
|
"version": "9.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz",
|
||||||
"integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==",
|
"integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
}
|
}
|
||||||
|
@ -326,6 +327,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.25.0.tgz",
|
||||||
"integrity": "sha512-5DlvqO8bbe90cKSfFDuEblyrEnhAdgNTjWxXeUxt/XXC2OuMC8CsxzLZjtK3+0X6yM8m4xcE3fymCPwg7zdcXQ==",
|
"integrity": "sha512-5DlvqO8bbe90cKSfFDuEblyrEnhAdgNTjWxXeUxt/XXC2OuMC8CsxzLZjtK3+0X6yM8m4xcE3fymCPwg7zdcXQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
|
@ -335,6 +337,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.25.0.tgz",
|
||||||
"integrity": "sha512-dj6U1klMorS/g1QFI6j15AXknsqMDtdingSF6Sdtm1Z7WOVISfDwVyeNbb+JLUG+ATo9aECPQP5A7MHqgP6J9A==",
|
"integrity": "sha512-dj6U1klMorS/g1QFI6j15AXknsqMDtdingSF6Sdtm1Z7WOVISfDwVyeNbb+JLUG+ATo9aECPQP5A7MHqgP6J9A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-html-parser": "^0.0.9"
|
"es-html-parser": "^0.0.9"
|
||||||
},
|
},
|
||||||
|
@ -343,13 +346,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.11.14",
|
"version": "0.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
|
||||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
"integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
|
||||||
"deprecated": "Use @eslint/config-array instead",
|
"deprecated": "Use @eslint/config-array instead",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@humanwhocodes/object-schema": "^2.0.2",
|
"@humanwhocodes/object-schema": "^2.0.3",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"minimatch": "^3.0.5"
|
"minimatch": "^3.0.5"
|
||||||
},
|
},
|
||||||
|
@ -362,18 +366,20 @@
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@humanwhocodes/config-array/node_modules/debug": {
|
"node_modules/@humanwhocodes/config-array/node_modules/debug": {
|
||||||
"version": "4.3.5",
|
"version": "4.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||||
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
|
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "^2.1.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0"
|
"node": ">=6.0"
|
||||||
|
@ -389,6 +395,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
},
|
},
|
||||||
|
@ -397,10 +404,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@humanwhocodes/config-array/node_modules/ms": {
|
"node_modules/@humanwhocodes/config-array/node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@humanwhocodes/module-importer": {
|
"node_modules/@humanwhocodes/module-importer": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
@ -420,7 +428,8 @@
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
|
||||||
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
|
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
|
||||||
"deprecated": "Use @eslint/object-schema instead",
|
"deprecated": "Use @eslint/object-schema instead",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/resolve-uri": {
|
"node_modules/@jridgewell/resolve-uri": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
|
@ -653,6 +662,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/eslint__js/-/eslint__js-8.42.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/eslint__js/-/eslint__js-8.42.3.tgz",
|
||||||
"integrity": "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==",
|
"integrity": "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/eslint": "*"
|
"@types/eslint": "*"
|
||||||
}
|
}
|
||||||
|
@ -774,16 +784,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "7.17.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz",
|
||||||
"integrity": "sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==",
|
"integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "7.17.0",
|
"@typescript-eslint/scope-manager": "7.18.0",
|
||||||
"@typescript-eslint/type-utils": "7.17.0",
|
"@typescript-eslint/type-utils": "7.18.0",
|
||||||
"@typescript-eslint/utils": "7.17.0",
|
"@typescript-eslint/utils": "7.18.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.17.0",
|
"@typescript-eslint/visitor-keys": "7.18.0",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
|
@ -807,15 +818,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "7.17.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz",
|
||||||
"integrity": "sha512-puiYfGeg5Ydop8eusb/Hy1k7QmOU6X3nvsqCgzrB2K4qMavK//21+PzNE8qeECgNOIoertJPUC1SpegHDI515A==",
|
"integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "7.17.0",
|
"@typescript-eslint/scope-manager": "7.18.0",
|
||||||
"@typescript-eslint/types": "7.17.0",
|
"@typescript-eslint/types": "7.18.0",
|
||||||
"@typescript-eslint/typescript-estree": "7.17.0",
|
"@typescript-eslint/typescript-estree": "7.18.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.17.0",
|
"@typescript-eslint/visitor-keys": "7.18.0",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -835,12 +847,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser/node_modules/debug": {
|
"node_modules/@typescript-eslint/parser/node_modules/debug": {
|
||||||
"version": "4.3.5",
|
"version": "4.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||||
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
|
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "^2.1.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0"
|
"node": ">=6.0"
|
||||||
|
@ -852,19 +865,21 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser/node_modules/ms": {
|
"node_modules/@typescript-eslint/parser/node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "7.17.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz",
|
||||||
"integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==",
|
"integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.17.0",
|
"@typescript-eslint/types": "7.18.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.17.0"
|
"@typescript-eslint/visitor-keys": "7.18.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
|
@ -875,13 +890,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "7.17.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz",
|
||||||
"integrity": "sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA==",
|
"integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "7.17.0",
|
"@typescript-eslint/typescript-estree": "7.18.0",
|
||||||
"@typescript-eslint/utils": "7.17.0",
|
"@typescript-eslint/utils": "7.18.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^1.3.0"
|
"ts-api-utils": "^1.3.0"
|
||||||
},
|
},
|
||||||
|
@ -902,12 +918,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils/node_modules/debug": {
|
"node_modules/@typescript-eslint/type-utils/node_modules/debug": {
|
||||||
"version": "4.3.5",
|
"version": "4.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||||
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
|
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "^2.1.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0"
|
"node": ">=6.0"
|
||||||
|
@ -919,16 +936,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils/node_modules/ms": {
|
"node_modules/@typescript-eslint/type-utils/node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "7.17.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz",
|
||||||
"integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==",
|
"integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
},
|
},
|
||||||
|
@ -938,13 +957,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "7.17.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz",
|
||||||
"integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==",
|
"integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.17.0",
|
"@typescript-eslint/types": "7.18.0",
|
||||||
"@typescript-eslint/visitor-keys": "7.17.0",
|
"@typescript-eslint/visitor-keys": "7.18.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"globby": "^11.1.0",
|
"globby": "^11.1.0",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
|
@ -966,12 +986,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/debug": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/debug": {
|
||||||
"version": "4.3.5",
|
"version": "4.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||||
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
|
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "^2.1.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0"
|
"node": ">=6.0"
|
||||||
|
@ -983,21 +1004,23 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/ms": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "7.17.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz",
|
||||||
"integrity": "sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==",
|
"integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "7.17.0",
|
"@typescript-eslint/scope-manager": "7.18.0",
|
||||||
"@typescript-eslint/types": "7.17.0",
|
"@typescript-eslint/types": "7.18.0",
|
||||||
"@typescript-eslint/typescript-estree": "7.17.0"
|
"@typescript-eslint/typescript-estree": "7.18.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
|
@ -1011,12 +1034,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "7.17.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz",
|
||||||
"integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==",
|
"integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "7.17.0",
|
"@typescript-eslint/types": "7.18.0",
|
||||||
"eslint-visitor-keys": "^3.4.3"
|
"eslint-visitor-keys": "^3.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -1032,6 +1056,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
|
||||||
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
|
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
},
|
},
|
||||||
|
@ -1257,6 +1282,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
|
@ -2024,6 +2050,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||||
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"path-type": "^4.0.0"
|
"path-type": "^4.0.0"
|
||||||
},
|
},
|
||||||
|
@ -2239,16 +2266,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "8.57.0",
|
"version": "8.57.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
|
||||||
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
|
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.6.1",
|
"@eslint-community/regexpp": "^4.6.1",
|
||||||
"@eslint/eslintrc": "^2.1.4",
|
"@eslint/eslintrc": "^2.1.4",
|
||||||
"@eslint/js": "8.57.0",
|
"@eslint/js": "8.57.1",
|
||||||
"@humanwhocodes/config-array": "^0.11.14",
|
"@humanwhocodes/config-array": "^0.13.0",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
"@nodelib/fs.walk": "^1.2.8",
|
"@nodelib/fs.walk": "^1.2.8",
|
||||||
"@ungap/structured-clone": "^1.2.0",
|
"@ungap/structured-clone": "^1.2.0",
|
||||||
|
@ -2391,10 +2419,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint/node_modules/@eslint/js": {
|
"node_modules/eslint/node_modules/@eslint/js": {
|
||||||
"version": "8.57.0",
|
"version": "8.57.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
|
||||||
"integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
|
"integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
|
@ -3135,6 +3164,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
|
||||||
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"array-union": "^2.1.0",
|
"array-union": "^2.1.0",
|
||||||
"dir-glob": "^3.0.1",
|
"dir-glob": "^3.0.1",
|
||||||
|
@ -4743,6 +4773,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
|
@ -5458,6 +5489,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
|
@ -5893,10 +5925,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.5.4",
|
"version": "5.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
|
||||||
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
|
"integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
@ -5906,14 +5939,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "7.17.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.18.0.tgz",
|
||||||
"integrity": "sha512-spQxsQvPguduCUfyUvLItvKqK3l8KJ/kqs5Pb/URtzQ5AC53Z6us32St37rpmlt2uESG23lOFpV4UErrmy4dZQ==",
|
"integrity": "sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "7.17.0",
|
"@typescript-eslint/eslint-plugin": "7.18.0",
|
||||||
"@typescript-eslint/parser": "7.17.0",
|
"@typescript-eslint/parser": "7.18.0",
|
||||||
"@typescript-eslint/utils": "7.17.0"
|
"@typescript-eslint/utils": "7.18.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || >=20.0.0"
|
"node": "^18.18.0 || >=20.0.0"
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
"ts-to-jsdoc": "^2.2.0"
|
"ts-to-jsdoc": "^2.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.7.0",
|
"@eslint/js": "^9.10.0",
|
||||||
"@html-eslint/eslint-plugin": "^0.25.0",
|
"@html-eslint/eslint-plugin": "^0.25.0",
|
||||||
"@html-eslint/parser": "^0.25.0",
|
"@html-eslint/parser": "^0.25.0",
|
||||||
"@stylistic/eslint-plugin": "^2.3.0",
|
"@stylistic/eslint-plugin": "^2.3.0",
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
"@types/eslint__js": "^8.42.3",
|
"@types/eslint__js": "^8.42.3",
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/node-fetch": "^2.6.11",
|
"@types/node-fetch": "^2.6.11",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.1",
|
||||||
"eslint-plugin-html": "^8.1.1",
|
"eslint-plugin-html": "^8.1.1",
|
||||||
"eslint-plugin-sonarjs": "^1.0.4",
|
"eslint-plugin-sonarjs": "^1.0.4",
|
||||||
"eslint-plugin-unicorn": "^55.0.0",
|
"eslint-plugin-unicorn": "^55.0.0",
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
"gulp-copy": "^5.0.0",
|
"gulp-copy": "^5.0.0",
|
||||||
"gulp-typescript": "^6.0.0-alpha.1",
|
"gulp-typescript": "^6.0.0-alpha.1",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.6.2",
|
||||||
"typescript-eslint": "^7.17.0"
|
"typescript-eslint": "^7.18.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
170
src/index.ts
170
src/index.ts
|
@ -13,108 +13,108 @@ const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
interface Instance {
|
interface Instance {
|
||||||
name: string;
|
name: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
import instances from "./webpage/instances.json" with { type: "json" };
|
import instances from "./webpage/instances.json" with { type: "json" };
|
||||||
const instanceNames = new Map<string, Instance>();
|
const instanceNames = new Map<string, Instance>();
|
||||||
|
|
||||||
for (const instance of instances) {
|
for (const instance of instances) {
|
||||||
instanceNames.set(instance.name, instance);
|
instanceNames.set(instance.name, instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(compression());
|
app.use(compression());
|
||||||
|
|
||||||
async function updateInstances(): Promise<void> {
|
async function updateInstances(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
"https://raw.githubusercontent.com/spacebarchat/spacebarchat/master/instances/instances.json"
|
"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)) {
|
||||||
instances.push(instance as any);
|
instances.push(instance as any);
|
||||||
} else {
|
} else {
|
||||||
const existingInstance = instanceNames.get(instance.name);
|
const existingInstance = instanceNames.get(instance.name);
|
||||||
if (existingInstance) {
|
if (existingInstance) {
|
||||||
for (const key of Object.keys(instance)) {
|
for (const key of Object.keys(instance)) {
|
||||||
if (!existingInstance[key]) {
|
if (!existingInstance[key]) {
|
||||||
existingInstance[key] = instance[key];
|
existingInstance[key] = instance[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
observe(instances);
|
observe(instances);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error updating instances:", error);
|
console.error("Error updating instances:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateInstances();
|
updateInstances();
|
||||||
|
|
||||||
app.use("/getupdates", (_req: Request, res: Response) => {
|
app.use("/getupdates", (_req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const stats = fs.statSync(path.join(__dirname, "webpage"));
|
const stats = fs.statSync(path.join(__dirname, "webpage"));
|
||||||
res.send(stats.mtimeMs.toString());
|
res.send(stats.mtimeMs.toString());
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error getting updates:", error);
|
console.error("Error getting updates:", error);
|
||||||
res.status(500).send("Error getting updates");
|
res.status(500).send("Error getting updates");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use("/services/oembed", (req: Request, res: Response) => {
|
app.use("/services/oembed", (req: Request, res: Response) => {
|
||||||
inviteResponse(req, res);
|
inviteResponse(req, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use("/uptime", (req: Request, res: Response) => {
|
app.use("/uptime", (req: Request, res: Response) => {
|
||||||
const instanceUptime = uptime[req.query.name as string];
|
const instanceUptime = uptime[req.query.name as string];
|
||||||
res.send(instanceUptime);
|
res.send(instanceUptime);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use("/", async (req: Request, res: Response) => {
|
app.use("/", async (req: Request, res: Response) => {
|
||||||
const scheme = req.secure ? "https" : "http";
|
const scheme = req.secure ? "https" : "http";
|
||||||
const host = `${scheme}://${req.get("Host")}`;
|
const host = `${scheme}://${req.get("Host")}`;
|
||||||
const ref = host + req.originalUrl;
|
const ref = host + req.originalUrl;
|
||||||
|
|
||||||
if (host && ref) {
|
if (host && ref) {
|
||||||
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"`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.path === "/") {
|
if (req.path === "/") {
|
||||||
res.sendFile(path.join(__dirname, "webpage", "home.html"));
|
res.sendFile(path.join(__dirname, "webpage", "home.html"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.path.startsWith("/instances.json")) {
|
if (req.path.startsWith("/instances.json")) {
|
||||||
res.json(instances);
|
res.json(instances);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.path.startsWith("/invite/")) {
|
if (req.path.startsWith("/invite/")) {
|
||||||
res.sendFile(path.join(__dirname, "webpage", "invite.html"));
|
res.sendFile(path.join(__dirname, "webpage", "invite.html"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = path.join(__dirname, "webpage", req.path);
|
const filePath = path.join(__dirname, "webpage", req.path);
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
res.sendFile(filePath);
|
res.sendFile(filePath);
|
||||||
} else if (fs.existsSync(`${filePath}.html`)) {
|
} else if (fs.existsSync(`${filePath}.html`)) {
|
||||||
res.sendFile(`${filePath}.html`);
|
res.sendFile(`${filePath}.html`);
|
||||||
} else {
|
} else {
|
||||||
res.sendFile(path.join(__dirname, "webpage", "index.html"));
|
res.sendFile(path.join(__dirname, "webpage", "index.html"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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, () => {
|
||||||
console.log(`Server running on port ${PORT}`);
|
console.log(`Server running on port ${PORT}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
export { getApiUrls };
|
export { getApiUrls };
|
||||||
|
|
388
src/stats.ts
388
src/stats.ts
|
@ -8,244 +8,244 @@ const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
interface UptimeEntry {
|
interface UptimeEntry {
|
||||||
time: number;
|
time: number;
|
||||||
online: boolean;
|
online: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UptimeObject {
|
interface UptimeObject {
|
||||||
[key: string]: UptimeEntry[];
|
[key: string]: UptimeEntry[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Instance {
|
interface Instance {
|
||||||
name: string;
|
name: string;
|
||||||
urls?: { api: string };
|
urls?: { api: string };
|
||||||
url?: string;
|
url?: string;
|
||||||
online?: boolean;
|
online?: boolean;
|
||||||
uptime?: {
|
uptime?: {
|
||||||
daytime: number;
|
daytime: number;
|
||||||
weektime: number;
|
weektime: number;
|
||||||
alltime: number;
|
alltime: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let uptimeObject: UptimeObject = loadUptimeObject();
|
let uptimeObject: UptimeObject = loadUptimeObject();
|
||||||
export { uptimeObject as uptime };
|
export { uptimeObject as uptime };
|
||||||
|
|
||||||
function loadUptimeObject(): UptimeObject {
|
function loadUptimeObject(): UptimeObject {
|
||||||
const filePath = path.join(__dirname, "..", "uptime.json");
|
const filePath = path.join(__dirname, "..", "uptime.json");
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error reading uptime.json:", error);
|
console.error("Error reading uptime.json:", error);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveUptimeObject(): void {
|
function saveUptimeObject(): void {
|
||||||
fs.writeFile(
|
fs.writeFile(
|
||||||
`${__dirname}/uptime.json`,
|
`${__dirname}/uptime.json`,
|
||||||
JSON.stringify(uptimeObject),
|
JSON.stringify(uptimeObject),
|
||||||
(error) => {
|
(error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Error saving uptime.json:", error);
|
console.error("Error saving uptime.json:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeUndefinedKey(): void {
|
function removeUndefinedKey(): void {
|
||||||
if (uptimeObject.undefined) {
|
if (uptimeObject.undefined) {
|
||||||
delete uptimeObject.undefined;
|
delete uptimeObject.undefined;
|
||||||
saveUptimeObject();
|
saveUptimeObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUndefinedKey();
|
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) =>
|
const instancePromises = instances.map((instance) =>
|
||||||
resolveInstance(instance, activeInstances)
|
resolveInstance(instance, activeInstances)
|
||||||
);
|
);
|
||||||
await Promise.allSettled(instancePromises);
|
await Promise.allSettled(instancePromises);
|
||||||
updateInactiveInstances(activeInstances);
|
updateInactiveInstances(activeInstances);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveInstance(
|
async function resolveInstance(
|
||||||
instance: Instance,
|
instance: Instance,
|
||||||
activeInstances: Set<string>
|
activeInstances: Set<string>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
calcStats(instance);
|
calcStats(instance);
|
||||||
const api = await getApiUrl(instance);
|
const api = await getApiUrl(instance);
|
||||||
if (!api) {
|
if (!api) {
|
||||||
handleUnresolvedApi(instance);
|
handleUnresolvedApi(instance);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
activeInstances.add(instance.name);
|
activeInstances.add(instance.name);
|
||||||
scheduleHealthCheck(instance, api);
|
scheduleHealthCheck(instance, api);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error resolving instance:", error);
|
console.error("Error resolving instance:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getApiUrl(instance: Instance): Promise<string | null> {
|
async function getApiUrl(instance: Instance): Promise<string | null> {
|
||||||
if (instance.urls) {
|
if (instance.urls) {
|
||||||
return instance.urls.api;
|
return instance.urls.api;
|
||||||
}
|
}
|
||||||
if (instance.url) {
|
if (instance.url) {
|
||||||
const urls = await getApiUrls(instance.url);
|
const urls = await getApiUrls(instance.url);
|
||||||
return urls ? urls.api : null;
|
return urls ? urls.api : null;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUnresolvedApi(instance: Instance): void {
|
function handleUnresolvedApi(instance: Instance): void {
|
||||||
setStatus(instance, false);
|
setStatus(instance, false);
|
||||||
console.warn(`${instance.name} does not resolve api URL`, instance);
|
console.warn(`${instance.name} does not resolve api URL`, instance);
|
||||||
setTimeout(() => resolveInstance(instance, new Set()), 1000 * 60 * 30);
|
setTimeout(() => resolveInstance(instance, new Set()), 1000 * 60 * 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
function scheduleHealthCheck(instance: Instance, api: string): void {
|
function scheduleHealthCheck(instance: Instance, api: string): void {
|
||||||
const checkInterval = 1000 * 60 * 30;
|
const checkInterval = 1000 * 60 * 30;
|
||||||
const initialDelay = Math.random() * 1000 * 60 * 10;
|
const initialDelay = Math.random() * 1000 * 60 * 10;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
checkHealth(instance, api);
|
checkHealth(instance, api);
|
||||||
setInterval(() => checkHealth(instance, api), checkInterval);
|
setInterval(() => checkHealth(instance, api), checkInterval);
|
||||||
}, initialDelay);
|
}, initialDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkHealth(
|
async function checkHealth(
|
||||||
instance: Instance,
|
instance: Instance,
|
||||||
api: string,
|
api: string,
|
||||||
tries = 0
|
tries = 0
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${api}ping`, { method: "HEAD" });
|
const response = await fetch(`${api}ping`, { method: "HEAD" });
|
||||||
if (response.ok || tries > 3) {
|
if (response.ok || tries > 3) {
|
||||||
setStatus(instance, response.ok);
|
setStatus(instance, response.ok);
|
||||||
} else {
|
} else {
|
||||||
retryHealthCheck(instance, api, tries);
|
retryHealthCheck(instance, api, tries);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error checking health:", error);
|
console.error("Error checking health:", error);
|
||||||
if (tries > 3) {
|
if (tries > 3) {
|
||||||
setStatus(instance, false);
|
setStatus(instance, false);
|
||||||
} else {
|
} else {
|
||||||
retryHealthCheck(instance, api, tries);
|
retryHealthCheck(instance, api, tries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function retryHealthCheck(
|
function retryHealthCheck(
|
||||||
instance: Instance,
|
instance: Instance,
|
||||||
api: string,
|
api: string,
|
||||||
tries: number
|
tries: number
|
||||||
): void {
|
): void {
|
||||||
setTimeout(() => checkHealth(instance, api, tries + 1), 30000);
|
setTimeout(() => checkHealth(instance, api, tries + 1), 30000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateInactiveInstances(activeInstances: Set<string>): void {
|
function updateInactiveInstances(activeInstances: Set<string>): void {
|
||||||
for (const key of Object.keys(uptimeObject)) {
|
for (const key of Object.keys(uptimeObject)) {
|
||||||
if (!activeInstances.has(key)) {
|
if (!activeInstances.has(key)) {
|
||||||
setStatus(key, false);
|
setStatus(key, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function calcStats(instance: Instance): void {
|
function calcStats(instance: Instance): void {
|
||||||
const obj = uptimeObject[instance.name];
|
const obj = uptimeObject[instance.name];
|
||||||
if (!obj) return;
|
if (!obj) return;
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const day = now - 1000 * 60 * 60 * 24;
|
const day = now - 1000 * 60 * 60 * 24;
|
||||||
const week = now - 1000 * 60 * 60 * 24 * 7;
|
const week = now - 1000 * 60 * 60 * 24 * 7;
|
||||||
|
|
||||||
let totalTimePassed = 0;
|
let totalTimePassed = 0;
|
||||||
let alltime = 0;
|
let alltime = 0;
|
||||||
let daytime = 0;
|
let daytime = 0;
|
||||||
let weektime = 0;
|
let weektime = 0;
|
||||||
let online = false;
|
let online = false;
|
||||||
|
|
||||||
for (let i = 0; i < obj.length; i++) {
|
for (let i = 0; i < obj.length; i++) {
|
||||||
const entry = obj[i];
|
const entry = obj[i];
|
||||||
online = entry.online;
|
online = entry.online;
|
||||||
const stamp = entry.time;
|
const stamp = entry.time;
|
||||||
const nextStamp = obj[i + 1]?.time || now;
|
const nextStamp = obj[i + 1]?.time || now;
|
||||||
const timePassed = nextStamp - stamp;
|
const timePassed = nextStamp - stamp;
|
||||||
|
|
||||||
totalTimePassed += timePassed;
|
totalTimePassed += timePassed;
|
||||||
alltime += Number(online) * timePassed;
|
alltime += Number(online) * timePassed;
|
||||||
|
|
||||||
if (stamp + timePassed > week) {
|
if (stamp + timePassed > week) {
|
||||||
const weekTimePassed = Math.min(timePassed, nextStamp - week);
|
const weekTimePassed = Math.min(timePassed, nextStamp - week);
|
||||||
weektime += Number(online) * weekTimePassed;
|
weektime += Number(online) * weekTimePassed;
|
||||||
|
|
||||||
if (stamp + timePassed > day) {
|
if (stamp + timePassed > day) {
|
||||||
const dayTimePassed = Math.min(weekTimePassed, nextStamp - day);
|
const dayTimePassed = Math.min(weekTimePassed, nextStamp - day);
|
||||||
daytime += Number(online) * dayTimePassed;
|
daytime += Number(online) * dayTimePassed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.online = online;
|
instance.online = online;
|
||||||
instance.uptime = calculateUptimeStats(
|
instance.uptime = calculateUptimeStats(
|
||||||
totalTimePassed,
|
totalTimePassed,
|
||||||
alltime,
|
alltime,
|
||||||
daytime,
|
daytime,
|
||||||
weektime,
|
weektime,
|
||||||
online
|
online
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateUptimeStats(
|
function calculateUptimeStats(
|
||||||
totalTimePassed: number,
|
totalTimePassed: number,
|
||||||
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;
|
||||||
|
|
||||||
alltime /= totalTimePassed;
|
alltime /= totalTimePassed;
|
||||||
|
|
||||||
if (totalTimePassed > dayInMs) {
|
if (totalTimePassed > dayInMs) {
|
||||||
daytime = daytime || (online ? dayInMs : 0);
|
daytime = daytime || (online ? dayInMs : 0);
|
||||||
daytime /= dayInMs;
|
daytime /= dayInMs;
|
||||||
|
|
||||||
if (totalTimePassed > weekInMs) {
|
if (totalTimePassed > weekInMs) {
|
||||||
weektime = weektime || (online ? weekInMs : 0);
|
weektime = weektime || (online ? weekInMs : 0);
|
||||||
weektime /= weekInMs;
|
weektime /= weekInMs;
|
||||||
} else {
|
} else {
|
||||||
weektime = alltime;
|
weektime = alltime;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
weektime = alltime;
|
weektime = alltime;
|
||||||
daytime = alltime;
|
daytime = alltime;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { daytime, weektime, alltime };
|
return { daytime, weektime, alltime };
|
||||||
}
|
}
|
||||||
|
|
||||||
function setStatus(instance: string | Instance, status: boolean): void {
|
function setStatus(instance: string | Instance, status: boolean): void {
|
||||||
const name = typeof instance === "string" ? instance : instance.name;
|
const name = typeof instance === "string" ? instance : instance.name;
|
||||||
let obj = uptimeObject[name];
|
let obj = uptimeObject[name];
|
||||||
|
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
obj = [];
|
obj = [];
|
||||||
uptimeObject[name] = obj;
|
uptimeObject[name] = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.at(-1)?.online !== status) {
|
if (obj.at(-1)?.online !== status) {
|
||||||
obj.push({ time: Date.now(), online: status });
|
obj.push({ time: Date.now(), online: status });
|
||||||
saveUptimeObject();
|
saveUptimeObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof instance !== "string") {
|
if (typeof instance !== "string") {
|
||||||
calcStats(instance);
|
calcStats(instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
196
src/utils.ts
196
src/utils.ts
|
@ -2,113 +2,113 @@ import fetch from "node-fetch";
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
interface ApiUrls {
|
interface ApiUrls {
|
||||||
api: string;
|
api: string;
|
||||||
gateway: string;
|
gateway: string;
|
||||||
cdn: string;
|
cdn: string;
|
||||||
wellknown: string;
|
wellknown: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Invite {
|
interface Invite {
|
||||||
guild: {
|
guild: {
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
inviter?: {
|
inviter?: {
|
||||||
username: string;
|
username: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getApiUrls(url: string): Promise<ApiUrls | null> {
|
export async function getApiUrls(url: string): Promise<ApiUrls | null> {
|
||||||
if (!url.endsWith("/")) {
|
if (!url.endsWith("/")) {
|
||||||
url += "/";
|
url += "/";
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const info: ApiUrls = await fetch(`${url}.well-known/spacebar`).then(
|
const info: ApiUrls = await fetch(`${url}.well-known/spacebar`).then(
|
||||||
(res) => res.json() as Promise<ApiUrls>
|
(res) => res.json() as Promise<ApiUrls>
|
||||||
);
|
);
|
||||||
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}${
|
`${api}${
|
||||||
apiUrl.pathname.includes("api") ? "" : "api"
|
apiUrl.pathname.includes("api") ? "" : "api"
|
||||||
}/policies/instance/domains`
|
}/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,
|
||||||
cdn: policies.cdn,
|
cdn: policies.cdn,
|
||||||
wellknown: url,
|
wellknown: url,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching API URLs:", error);
|
console.error("Error fetching API URLs:", error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function inviteResponse(
|
export async function inviteResponse(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let url: URL;
|
let url: URL;
|
||||||
if (URL.canParse(req.query.url as string)) {
|
if (URL.canParse(req.query.url as string)) {
|
||||||
url = new URL(req.query.url as string);
|
url = new URL(req.query.url as string);
|
||||||
} else {
|
} else {
|
||||||
const scheme = req.secure ? "https" : "http";
|
const scheme = req.secure ? "https" : "http";
|
||||||
const host = `${scheme}://${req.get("Host")}`;
|
const host = `${scheme}://${req.get("Host")}`;
|
||||||
url = new URL(host);
|
url = new URL(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (url.pathname.startsWith("invite")) {
|
if (url.pathname.startsWith("invite")) {
|
||||||
throw new Error("Invalid invite URL");
|
throw new Error("Invalid invite URL");
|
||||||
}
|
}
|
||||||
|
|
||||||
const code = url.pathname.split("/")[2];
|
const code = url.pathname.split("/")[2];
|
||||||
const instance = url.searchParams.get("instance");
|
const instance = url.searchParams.get("instance");
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
throw new Error("Instance not specified");
|
throw new Error("Instance not specified");
|
||||||
}
|
}
|
||||||
const urls = await getApiUrls(instance);
|
const urls = await getApiUrls(instance);
|
||||||
if (!urls) {
|
if (!urls) {
|
||||||
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(
|
const invite = await fetch(`${urls.api}/invites/${code}`).then(
|
||||||
(res) => res.json() as Promise<Invite>
|
(res) => res.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.inviter.username} has invited you to ${invite.guild.name}${
|
||||||
invite.guild.description ? `\n${invite.guild.description}` : ""
|
invite.guild.description ? `\n${invite.guild.description}` : ""
|
||||||
}`
|
}`
|
||||||
: `You've been invited to ${invite.guild.name}${
|
: `You've been invited to ${invite.guild.name}${
|
||||||
invite.guild.description ? `\n${invite.guild.description}` : ""
|
invite.guild.description ? `\n${invite.guild.description}` : ""
|
||||||
}`;
|
}`;
|
||||||
const thumbnail = invite.guild.icon
|
const thumbnail = invite.guild.icon
|
||||||
? `${urls.cdn}/icons/${invite.guild.id}/${invite.guild.icon}.png`
|
? `${urls.cdn}/icons/${invite.guild.id}/${invite.guild.icon}.png`
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const jsonResponse = {
|
const jsonResponse = {
|
||||||
type: "link",
|
type: "link",
|
||||||
version: "1.0",
|
version: "1.0",
|
||||||
title,
|
title,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
description,
|
description,
|
||||||
};
|
};
|
||||||
|
|
||||||
res.json(jsonResponse);
|
res.json(jsonResponse);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error processing invite response:", error);
|
console.error("Error processing invite response:", error);
|
||||||
const jsonResponse = {
|
const jsonResponse = {
|
||||||
type: "link",
|
type: "link",
|
||||||
version: "1.0",
|
version: "1.0",
|
||||||
title: "Jank Client",
|
title: "Jank Client",
|
||||||
thumbnail: "/logo.webp",
|
thumbnail: "/logo.webp",
|
||||||
description: "A spacebar client that has DMs, replying and more",
|
description: "A spacebar client that has DMs, replying and more",
|
||||||
url: url.toString(),
|
url: url.toString(),
|
||||||
};
|
};
|
||||||
res.json(jsonResponse);
|
res.json(jsonResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,164 +1,164 @@
|
||||||
import { getBulkInfo } from "./login.js";
|
import { getBulkInfo } from "./login.js";
|
||||||
|
|
||||||
class Voice {
|
class Voice {
|
||||||
audioCtx: AudioContext;
|
audioCtx: AudioContext;
|
||||||
info: { wave: string | Function; freq: number };
|
info: { wave: string | Function; freq: number };
|
||||||
playing: boolean;
|
playing: boolean;
|
||||||
myArrayBuffer: AudioBuffer;
|
myArrayBuffer: AudioBuffer;
|
||||||
gainNode: GainNode;
|
gainNode: GainNode;
|
||||||
buffer: Float32Array;
|
buffer: Float32Array;
|
||||||
source: AudioBufferSourceNode;
|
source: AudioBufferSourceNode;
|
||||||
constructor(wave: string | Function, freq: number, volume = 1) {
|
constructor(wave: string | Function, freq: number, volume = 1) {
|
||||||
this.audioCtx = new window.AudioContext();
|
this.audioCtx = new window.AudioContext();
|
||||||
this.info = { wave, freq };
|
this.info = { wave, freq };
|
||||||
this.playing = false;
|
this.playing = false;
|
||||||
this.myArrayBuffer = this.audioCtx.createBuffer(
|
this.myArrayBuffer = this.audioCtx.createBuffer(
|
||||||
1,
|
1,
|
||||||
this.audioCtx.sampleRate,
|
this.audioCtx.sampleRate,
|
||||||
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;
|
||||||
this.gainNode.connect(this.audioCtx.destination);
|
this.gainNode.connect(this.audioCtx.destination);
|
||||||
this.buffer = this.myArrayBuffer.getChannelData(0);
|
this.buffer = this.myArrayBuffer.getChannelData(0);
|
||||||
this.source = this.audioCtx.createBufferSource();
|
this.source = this.audioCtx.createBufferSource();
|
||||||
this.source.buffer = this.myArrayBuffer;
|
this.source.buffer = this.myArrayBuffer;
|
||||||
this.source.loop = true;
|
this.source.loop = true;
|
||||||
this.source.start();
|
this.source.start();
|
||||||
this.updateWave();
|
this.updateWave();
|
||||||
}
|
}
|
||||||
get wave(): string | Function {
|
get wave(): string | Function {
|
||||||
return this.info.wave;
|
return this.info.wave;
|
||||||
}
|
}
|
||||||
get freq(): number {
|
get freq(): number {
|
||||||
return this.info.freq;
|
return this.info.freq;
|
||||||
}
|
}
|
||||||
set wave(wave: string | Function) {
|
set wave(wave: string | Function) {
|
||||||
this.info.wave = wave;
|
this.info.wave = wave;
|
||||||
this.updateWave();
|
this.updateWave();
|
||||||
}
|
}
|
||||||
set freq(freq: number) {
|
set freq(freq: number) {
|
||||||
this.info.freq = freq;
|
this.info.freq = freq;
|
||||||
this.updateWave();
|
this.updateWave();
|
||||||
}
|
}
|
||||||
updateWave(): void {
|
updateWave(): void {
|
||||||
const func = this.waveFunction();
|
const func = this.waveFunction();
|
||||||
for (let i = 0; i < this.buffer.length; i++) {
|
for (let i = 0; i < this.buffer.length; i++) {
|
||||||
this.buffer[i] = func(i / this.audioCtx.sampleRate, this.freq);
|
this.buffer[i] = func(i / this.audioCtx.sampleRate, this.freq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
waveFunction(): Function {
|
waveFunction(): Function {
|
||||||
if (typeof this.wave === "function") {
|
if (typeof this.wave === "function") {
|
||||||
return this.wave;
|
return this.wave;
|
||||||
}
|
}
|
||||||
switch (this.wave) {
|
switch (this.wave) {
|
||||||
case "sin":
|
case "sin":
|
||||||
return (t: number, freq: number) => {
|
return (t: number, freq: number) => {
|
||||||
return Math.sin(t * Math.PI * 2 * freq);
|
return Math.sin(t * Math.PI * 2 * freq);
|
||||||
};
|
};
|
||||||
case "triangle":
|
case "triangle":
|
||||||
return (t: number, freq: number) => {
|
return (t: number, freq: number) => {
|
||||||
return Math.abs(((4 * t * freq) % 4) - 2) - 1;
|
return Math.abs(((4 * t * freq) % 4) - 2) - 1;
|
||||||
};
|
};
|
||||||
case "sawtooth":
|
case "sawtooth":
|
||||||
return (t: number, freq: number) => {
|
return (t: number, freq: number) => {
|
||||||
return ((t * freq) % 1) * 2 - 1;
|
return ((t * freq) % 1) * 2 - 1;
|
||||||
};
|
};
|
||||||
case "square":
|
case "square":
|
||||||
return (t: number, freq: number) => {
|
return (t: number, freq: number) => {
|
||||||
return (t * freq) % 2 < 1 ? 1 : -1;
|
return (t * freq) % 2 < 1 ? 1 : -1;
|
||||||
};
|
};
|
||||||
case "white":
|
case "white":
|
||||||
return (_t: number, _freq: number) => {
|
return (_t: number, _freq: number) => {
|
||||||
return Math.random() * 2 - 1;
|
return Math.random() * 2 - 1;
|
||||||
};
|
};
|
||||||
case "noise":
|
case "noise":
|
||||||
return (_t: number, _freq: number) => {
|
return (_t: number, _freq: number) => {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return new Function();
|
return new Function();
|
||||||
}
|
}
|
||||||
play(): void {
|
play(): void {
|
||||||
if (this.playing) {
|
if (this.playing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.source.connect(this.gainNode);
|
this.source.connect(this.gainNode);
|
||||||
this.playing = true;
|
this.playing = true;
|
||||||
}
|
}
|
||||||
stop(): void {
|
stop(): void {
|
||||||
if (this.playing) {
|
if (this.playing) {
|
||||||
this.source.disconnect();
|
this.source.disconnect();
|
||||||
this.playing = false;
|
this.playing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static noises(noise: string): void {
|
static noises(noise: string): void {
|
||||||
switch (noise) {
|
switch (noise) {
|
||||||
case "three": {
|
case "three": {
|
||||||
const voicy = new Voice("sin", 800);
|
const voicy = new Voice("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;
|
||||||
}
|
}
|
||||||
case "zip": {
|
case "zip": {
|
||||||
const voicy = new Voice((t: number, freq: number) => {
|
const voicy = new Voice((t: number, freq: number) => {
|
||||||
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;
|
||||||
}
|
}
|
||||||
case "square": {
|
case "square": {
|
||||||
const voicy = new Voice("square", 600, 0.4);
|
const voicy = new Voice("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;
|
||||||
}
|
}
|
||||||
case "beep": {
|
case "beep": {
|
||||||
const voicy = new Voice("sin", 800);
|
const voicy = new Voice("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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static get sounds() {
|
static get sounds() {
|
||||||
return ["three", "zip", "square", "beep"];
|
return ["three", "zip", "square", "beep"];
|
||||||
}
|
}
|
||||||
static setNotificationSound(sound: string) {
|
static setNotificationSound(sound: string) {
|
||||||
const userinfos = getBulkInfo();
|
const userinfos = getBulkInfo();
|
||||||
userinfos.preferences.notisound = sound;
|
userinfos.preferences.notisound = sound;
|
||||||
localStorage.setItem("userinfos", JSON.stringify(userinfos));
|
localStorage.setItem("userinfos", JSON.stringify(userinfos));
|
||||||
}
|
}
|
||||||
static getNotificationSound() {
|
static getNotificationSound() {
|
||||||
const userinfos = getBulkInfo();
|
const userinfos = getBulkInfo();
|
||||||
return userinfos.preferences.notisound;
|
return userinfos.preferences.notisound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { Voice };
|
export { Voice };
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,107 +1,107 @@
|
||||||
class Contextmenu<x, y> {
|
class Contextmenu<x, y> {
|
||||||
static currentmenu: HTMLElement | "";
|
static currentmenu: HTMLElement | "";
|
||||||
name: string;
|
name: string;
|
||||||
buttons: [
|
buttons: [
|
||||||
string,
|
string,
|
||||||
(this: x, arg: y, e: MouseEvent) => void,
|
(this: x, arg: y, e: MouseEvent) => void,
|
||||||
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;
|
||||||
}
|
}
|
||||||
if (!Contextmenu.currentmenu.contains(event.target as Node)) {
|
if (!Contextmenu.currentmenu.contains(event.target as Node)) {
|
||||||
Contextmenu.currentmenu.remove();
|
Contextmenu.currentmenu.remove();
|
||||||
Contextmenu.currentmenu = "";
|
Contextmenu.currentmenu = "";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
constructor(name: string) {
|
constructor(name: string) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.buttons = [];
|
this.buttons = [];
|
||||||
}
|
}
|
||||||
addbutton(
|
addbutton(
|
||||||
text: string,
|
text: 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 {};
|
||||||
}
|
}
|
||||||
addsubmenu(
|
addsubmenu(
|
||||||
text: string,
|
text: 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 {};
|
||||||
}
|
}
|
||||||
private makemenu(x: number, y: number, addinfo: x, other: y) {
|
private makemenu(x: number, y: number, addinfo: x, other: y) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("contextmenu", "flexttb");
|
div.classList.add("contextmenu", "flexttb");
|
||||||
|
|
||||||
let visibleButtons = 0;
|
let visibleButtons = 0;
|
||||||
for (const thing of this.buttons) {
|
for (const thing of this.buttons) {
|
||||||
if (!thing[3].bind(addinfo).call(addinfo, other)) continue;
|
if (!thing[3].bind(addinfo).call(addinfo, other)) continue;
|
||||||
visibleButtons++;
|
visibleButtons++;
|
||||||
|
|
||||||
const intext = document.createElement("button");
|
const intext = document.createElement("button");
|
||||||
intext.disabled = !thing[4].bind(addinfo).call(addinfo, other);
|
intext.disabled = !thing[4].bind(addinfo).call(addinfo, other);
|
||||||
intext.classList.add("contextbutton");
|
intext.classList.add("contextbutton");
|
||||||
intext.textContent = thing[0];
|
intext.textContent = thing[0];
|
||||||
console.log(thing);
|
console.log(thing);
|
||||||
if (thing[5] === "button" || thing[5] === "submenu") {
|
if (thing[5] === "button" || thing[5] === "submenu") {
|
||||||
intext.onclick = thing[1].bind(addinfo, other);
|
intext.onclick = thing[1].bind(addinfo, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
div.appendChild(intext);
|
div.appendChild(intext);
|
||||||
}
|
}
|
||||||
if (visibleButtons == 0) return;
|
if (visibleButtons == 0) return;
|
||||||
|
|
||||||
if (Contextmenu.currentmenu != "") {
|
if (Contextmenu.currentmenu != "") {
|
||||||
Contextmenu.currentmenu.remove();
|
Contextmenu.currentmenu.remove();
|
||||||
}
|
}
|
||||||
div.style.top = y + "px";
|
div.style.top = y + "px";
|
||||||
div.style.left = x + "px";
|
div.style.left = x + "px";
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
Contextmenu.keepOnScreen(div);
|
Contextmenu.keepOnScreen(div);
|
||||||
console.log(div);
|
console.log(div);
|
||||||
Contextmenu.currentmenu = div;
|
Contextmenu.currentmenu = div;
|
||||||
return this.div;
|
return this.div;
|
||||||
}
|
}
|
||||||
bindContextmenu(obj: HTMLElement, addinfo: x, other: y) {
|
bindContextmenu(obj: HTMLElement, addinfo: x, other: y) {
|
||||||
const func = (event: MouseEvent) => {
|
const func = (event: MouseEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
this.makemenu(event.clientX, event.clientY, addinfo, other);
|
this.makemenu(event.clientX, event.clientY, addinfo, other);
|
||||||
};
|
};
|
||||||
obj.addEventListener("contextmenu", func);
|
obj.addEventListener("contextmenu", func);
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
static keepOnScreen(obj: HTMLElement) {
|
static keepOnScreen(obj: HTMLElement) {
|
||||||
const html = document.documentElement.getBoundingClientRect();
|
const html = document.documentElement.getBoundingClientRect();
|
||||||
const docheight = html.height;
|
const docheight = html.height;
|
||||||
const docwidth = html.width;
|
const docwidth = html.width;
|
||||||
const box = obj.getBoundingClientRect();
|
const box = obj.getBoundingClientRect();
|
||||||
console.log(box, docheight, docwidth);
|
console.log(box, docheight, docwidth);
|
||||||
if (box.right > docwidth) {
|
if (box.right > docwidth) {
|
||||||
console.log("test");
|
console.log("test");
|
||||||
obj.style.left = docwidth - box.width + "px";
|
obj.style.left = docwidth - box.width + "px";
|
||||||
}
|
}
|
||||||
if (box.bottom > docheight) {
|
if (box.bottom > docheight) {
|
||||||
obj.style.top = docheight - box.height + "px";
|
obj.style.top = docheight - box.height + "px";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Contextmenu.setup();
|
Contextmenu.setup();
|
||||||
export { Contextmenu };
|
export { Contextmenu };
|
||||||
|
|
|
@ -1,273 +1,273 @@
|
||||||
type dialogjson =
|
type dialogjson =
|
||||||
| ["hdiv", ...dialogjson[]]
|
| ["hdiv", ...dialogjson[]]
|
||||||
| ["vdiv", ...dialogjson[]]
|
| ["vdiv", ...dialogjson[]]
|
||||||
| ["img", string, [number, number] | undefined | ["fit"]]
|
| ["img", string, [number, number] | undefined | ["fit"]]
|
||||||
| ["checkbox", string, boolean, (this: HTMLInputElement, e: Event) => unknown]
|
| ["checkbox", string, boolean, (this: HTMLInputElement, e: Event) => unknown]
|
||||||
| ["button", string, string, (this: HTMLButtonElement, e: Event) => unknown]
|
| ["button", string, string, (this: HTMLButtonElement, e: Event) => unknown]
|
||||||
| ["mdbox", string, string, (this: HTMLTextAreaElement, e: Event) => unknown]
|
| ["mdbox", string, string, (this: HTMLTextAreaElement, e: Event) => unknown]
|
||||||
| ["textbox", string, string, (this: HTMLInputElement, e: Event) => unknown]
|
| ["textbox", string, string, (this: HTMLInputElement, e: Event) => unknown]
|
||||||
| ["fileupload", string, (this: HTMLInputElement, e: Event) => unknown]
|
| ["fileupload", string, (this: HTMLInputElement, e: Event) => unknown]
|
||||||
| ["text", string]
|
| ["text", string]
|
||||||
| ["title", string]
|
| ["title", string]
|
||||||
| ["radio", string, string[], (this: unknown, e: string) => unknown, number]
|
| ["radio", string, string[], (this: unknown, e: string) => unknown, number]
|
||||||
| ["html", HTMLElement]
|
| ["html", HTMLElement]
|
||||||
| [
|
| [
|
||||||
"select",
|
"select",
|
||||||
string,
|
string,
|
||||||
string[],
|
string[],
|
||||||
(this: HTMLSelectElement, e: Event) => unknown,
|
(this: HTMLSelectElement, e: Event) => unknown,
|
||||||
number
|
number
|
||||||
]
|
]
|
||||||
| ["tabs", [string, dialogjson][]];
|
| ["tabs", [string, dialogjson][]];
|
||||||
class Dialog {
|
class Dialog {
|
||||||
layout: dialogjson;
|
layout: dialogjson;
|
||||||
onclose: Function;
|
onclose: Function;
|
||||||
onopen: Function;
|
onopen: Function;
|
||||||
html: HTMLDivElement;
|
html: HTMLDivElement;
|
||||||
background!: HTMLDivElement;
|
background!: HTMLDivElement;
|
||||||
constructor(
|
constructor(
|
||||||
layout: dialogjson,
|
layout: dialogjson,
|
||||||
onclose = (_: any) => {},
|
onclose = (_: any) => {},
|
||||||
onopen = (_: any) => {}
|
onopen = (_: any) => {}
|
||||||
) {
|
) {
|
||||||
this.layout = layout;
|
this.layout = layout;
|
||||||
this.onclose = onclose;
|
this.onclose = onclose;
|
||||||
this.onopen = onopen;
|
this.onopen = onopen;
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.appendChild(this.tohtml(layout));
|
div.appendChild(this.tohtml(layout));
|
||||||
this.html = div;
|
this.html = div;
|
||||||
this.html.classList.add("centeritem");
|
this.html.classList.add("centeritem");
|
||||||
if (!(layout[0] === "img")) {
|
if (!(layout[0] === "img")) {
|
||||||
this.html.classList.add("nonimagecenter");
|
this.html.classList.add("nonimagecenter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tohtml(array: dialogjson): HTMLElement {
|
tohtml(array: dialogjson): HTMLElement {
|
||||||
switch (array[0]) {
|
switch (array[0]) {
|
||||||
case "img":
|
case "img":
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.src = array[1];
|
img.src = array[1];
|
||||||
if (array[2] != undefined) {
|
if (array[2] != undefined) {
|
||||||
if (array[2].length === 2) {
|
if (array[2].length === 2) {
|
||||||
img.width = array[2][0];
|
img.width = array[2][0];
|
||||||
img.height = array[2][1];
|
img.height = array[2][1];
|
||||||
} else if (array[2][0] === "fit") {
|
} else if (array[2][0] === "fit") {
|
||||||
img.classList.add("imgfit");
|
img.classList.add("imgfit");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return img;
|
return img;
|
||||||
case "hdiv":
|
case "hdiv":
|
||||||
const hdiv = document.createElement("div");
|
const hdiv = document.createElement("div");
|
||||||
hdiv.classList.add("flexltr");
|
hdiv.classList.add("flexltr");
|
||||||
|
|
||||||
for (const thing of array) {
|
for (const thing of array) {
|
||||||
if (thing === "hdiv") {
|
if (thing === "hdiv") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
hdiv.appendChild(this.tohtml(thing));
|
hdiv.appendChild(this.tohtml(thing));
|
||||||
}
|
}
|
||||||
return hdiv;
|
return hdiv;
|
||||||
case "vdiv":
|
case "vdiv":
|
||||||
const vdiv = document.createElement("div");
|
const vdiv = document.createElement("div");
|
||||||
vdiv.classList.add("flexttb");
|
vdiv.classList.add("flexttb");
|
||||||
for (const thing of array) {
|
for (const thing of array) {
|
||||||
if (thing === "vdiv") {
|
if (thing === "vdiv") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
vdiv.appendChild(this.tohtml(thing));
|
vdiv.appendChild(this.tohtml(thing));
|
||||||
}
|
}
|
||||||
return vdiv;
|
return vdiv;
|
||||||
case "checkbox": {
|
case "checkbox": {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const checkbox = document.createElement("input");
|
const checkbox = document.createElement("input");
|
||||||
div.appendChild(checkbox);
|
div.appendChild(checkbox);
|
||||||
const label = document.createElement("span");
|
const label = document.createElement("span");
|
||||||
checkbox.checked = array[2];
|
checkbox.checked = array[2];
|
||||||
label.textContent = array[1];
|
label.textContent = array[1];
|
||||||
div.appendChild(label);
|
div.appendChild(label);
|
||||||
checkbox.addEventListener("change", array[3]);
|
checkbox.addEventListener("change", array[3]);
|
||||||
checkbox.type = "checkbox";
|
checkbox.type = "checkbox";
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
case "button": {
|
case "button": {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const input = document.createElement("button");
|
const input = document.createElement("button");
|
||||||
|
|
||||||
const label = document.createElement("span");
|
const label = document.createElement("span");
|
||||||
input.textContent = array[2];
|
input.textContent = array[2];
|
||||||
label.textContent = array[1];
|
label.textContent = array[1];
|
||||||
div.appendChild(label);
|
div.appendChild(label);
|
||||||
div.appendChild(input);
|
div.appendChild(input);
|
||||||
input.addEventListener("click", array[3]);
|
input.addEventListener("click", array[3]);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
case "mdbox": {
|
case "mdbox": {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const input = document.createElement("textarea");
|
const input = document.createElement("textarea");
|
||||||
input.value = array[2];
|
input.value = array[2];
|
||||||
const label = document.createElement("span");
|
const label = document.createElement("span");
|
||||||
label.textContent = array[1];
|
label.textContent = array[1];
|
||||||
input.addEventListener("input", array[3]);
|
input.addEventListener("input", array[3]);
|
||||||
div.appendChild(label);
|
div.appendChild(label);
|
||||||
div.appendChild(document.createElement("br"));
|
div.appendChild(document.createElement("br"));
|
||||||
div.appendChild(input);
|
div.appendChild(input);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
case "textbox": {
|
case "textbox": {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const input = document.createElement("input");
|
const input = document.createElement("input");
|
||||||
input.value = array[2];
|
input.value = array[2];
|
||||||
input.type = "text";
|
input.type = "text";
|
||||||
const label = document.createElement("span");
|
const label = document.createElement("span");
|
||||||
label.textContent = array[1];
|
label.textContent = array[1];
|
||||||
console.log(array[3]);
|
console.log(array[3]);
|
||||||
input.addEventListener("input", array[3]);
|
input.addEventListener("input", array[3]);
|
||||||
div.appendChild(label);
|
div.appendChild(label);
|
||||||
div.appendChild(input);
|
div.appendChild(input);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
case "fileupload": {
|
case "fileupload": {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const input = document.createElement("input");
|
const input = document.createElement("input");
|
||||||
input.type = "file";
|
input.type = "file";
|
||||||
const label = document.createElement("span");
|
const label = document.createElement("span");
|
||||||
label.textContent = array[1];
|
label.textContent = array[1];
|
||||||
div.appendChild(label);
|
div.appendChild(label);
|
||||||
div.appendChild(input);
|
div.appendChild(input);
|
||||||
input.addEventListener("change", array[2]);
|
input.addEventListener("change", array[2]);
|
||||||
console.log(array);
|
console.log(array);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
case "text": {
|
case "text": {
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = array[1];
|
span.textContent = array[1];
|
||||||
return span;
|
return span;
|
||||||
}
|
}
|
||||||
case "title": {
|
case "title": {
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.classList.add("title");
|
span.classList.add("title");
|
||||||
span.textContent = array[1];
|
span.textContent = array[1];
|
||||||
return span;
|
return span;
|
||||||
}
|
}
|
||||||
case "radio": {
|
case "radio": {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const fieldset = document.createElement("fieldset");
|
const fieldset = document.createElement("fieldset");
|
||||||
fieldset.addEventListener("change", () => {
|
fieldset.addEventListener("change", () => {
|
||||||
let i = -1;
|
let i = -1;
|
||||||
for (const thing of Array.from(fieldset.children)) {
|
for (const thing of Array.from(fieldset.children)) {
|
||||||
i++;
|
i++;
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const checkbox = thing.children[0].children[0] as HTMLInputElement;
|
const checkbox = thing.children[0].children[0] as HTMLInputElement;
|
||||||
if (checkbox.checked) {
|
if (checkbox.checked) {
|
||||||
array[3](checkbox.value);
|
array[3](checkbox.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const legend = document.createElement("legend");
|
const legend = document.createElement("legend");
|
||||||
legend.textContent = array[1];
|
legend.textContent = array[1];
|
||||||
fieldset.appendChild(legend);
|
fieldset.appendChild(legend);
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const thing of array[2]) {
|
for (const thing of array[2]) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const input = document.createElement("input");
|
const input = document.createElement("input");
|
||||||
input.classList.add("radio");
|
input.classList.add("radio");
|
||||||
input.type = "radio";
|
input.type = "radio";
|
||||||
input.name = array[1];
|
input.name = array[1];
|
||||||
input.value = thing;
|
input.value = thing;
|
||||||
if (i === array[4]) {
|
if (i === array[4]) {
|
||||||
input.checked = true;
|
input.checked = true;
|
||||||
}
|
}
|
||||||
const label = document.createElement("label");
|
const label = document.createElement("label");
|
||||||
|
|
||||||
label.appendChild(input);
|
label.appendChild(input);
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = thing;
|
span.textContent = thing;
|
||||||
label.appendChild(span);
|
label.appendChild(span);
|
||||||
div.appendChild(label);
|
div.appendChild(label);
|
||||||
fieldset.appendChild(div);
|
fieldset.appendChild(div);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
div.appendChild(fieldset);
|
div.appendChild(fieldset);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
case "html":
|
case "html":
|
||||||
return array[1];
|
return array[1];
|
||||||
|
|
||||||
case "select": {
|
case "select": {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const label = document.createElement("label");
|
const label = document.createElement("label");
|
||||||
const select = document.createElement("select");
|
const select = document.createElement("select");
|
||||||
|
|
||||||
label.textContent = array[1];
|
label.textContent = array[1];
|
||||||
div.append(label);
|
div.append(label);
|
||||||
div.appendChild(select);
|
div.appendChild(select);
|
||||||
for (const thing of array[2]) {
|
for (const thing of array[2]) {
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
option.textContent = thing;
|
option.textContent = thing;
|
||||||
select.appendChild(option);
|
select.appendChild(option);
|
||||||
}
|
}
|
||||||
select.selectedIndex = array[4];
|
select.selectedIndex = array[4];
|
||||||
select.addEventListener("change", array[3]);
|
select.addEventListener("change", array[3]);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
case "tabs": {
|
case "tabs": {
|
||||||
const table = document.createElement("div");
|
const table = document.createElement("div");
|
||||||
table.classList.add("flexttb");
|
table.classList.add("flexttb");
|
||||||
const tabs = document.createElement("div");
|
const tabs = document.createElement("div");
|
||||||
tabs.classList.add("flexltr");
|
tabs.classList.add("flexltr");
|
||||||
tabs.classList.add("tabbed-head");
|
tabs.classList.add("tabbed-head");
|
||||||
table.appendChild(tabs);
|
table.appendChild(tabs);
|
||||||
const content = document.createElement("div");
|
const content = document.createElement("div");
|
||||||
content.classList.add("tabbed-content");
|
content.classList.add("tabbed-content");
|
||||||
table.appendChild(content);
|
table.appendChild(content);
|
||||||
|
|
||||||
let shown: HTMLElement | undefined;
|
let shown: HTMLElement | undefined;
|
||||||
for (const thing of array[1]) {
|
for (const thing of array[1]) {
|
||||||
const button = document.createElement("button");
|
const button = document.createElement("button");
|
||||||
button.textContent = thing[0];
|
button.textContent = thing[0];
|
||||||
tabs.appendChild(button);
|
tabs.appendChild(button);
|
||||||
|
|
||||||
const html = this.tohtml(thing[1]);
|
const html = this.tohtml(thing[1]);
|
||||||
content.append(html);
|
content.append(html);
|
||||||
if (!shown) {
|
if (!shown) {
|
||||||
shown = html;
|
shown = html;
|
||||||
} else {
|
} else {
|
||||||
html.style.display = "none";
|
html.style.display = "none";
|
||||||
}
|
}
|
||||||
button.addEventListener("click", (_) => {
|
button.addEventListener("click", (_) => {
|
||||||
if (shown) {
|
if (shown) {
|
||||||
shown.style.display = "none";
|
shown.style.display = "none";
|
||||||
}
|
}
|
||||||
html.style.display = "";
|
html.style.display = "";
|
||||||
shown = html;
|
shown = html;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
console.error(
|
console.error(
|
||||||
"can't find element:" + array[0],
|
"can't find element:" + array[0],
|
||||||
" full element:",
|
" full element:",
|
||||||
array
|
array
|
||||||
);
|
);
|
||||||
return document.createElement("span");
|
return document.createElement("span");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
show() {
|
show() {
|
||||||
this.onopen();
|
this.onopen();
|
||||||
console.log("fullscreen");
|
console.log("fullscreen");
|
||||||
this.background = document.createElement("div");
|
this.background = document.createElement("div");
|
||||||
this.background.classList.add("background");
|
this.background.classList.add("background");
|
||||||
document.body.appendChild(this.background);
|
document.body.appendChild(this.background);
|
||||||
document.body.appendChild(this.html);
|
document.body.appendChild(this.html);
|
||||||
this.background.onclick = (_) => {
|
this.background.onclick = (_) => {
|
||||||
this.hide();
|
this.hide();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
hide() {
|
hide() {
|
||||||
document.body.removeChild(this.background);
|
document.body.removeChild(this.background);
|
||||||
document.body.removeChild(this.html);
|
document.body.removeChild(this.html);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { Dialog };
|
export { Dialog };
|
||||||
|
|
|
@ -4,75 +4,75 @@ import { Message } from "./message.js";
|
||||||
import { Localuser } from "./localuser.js";
|
import { Localuser } from "./localuser.js";
|
||||||
import { User } from "./user.js";
|
import { User } from "./user.js";
|
||||||
import {
|
import {
|
||||||
channeljson,
|
channeljson,
|
||||||
dirrectjson,
|
dirrectjson,
|
||||||
memberjson,
|
memberjson,
|
||||||
messagejson,
|
messagejson,
|
||||||
} from "./jsontypes.js";
|
} from "./jsontypes.js";
|
||||||
import { Permissions } from "./permissions.js";
|
import { Permissions } from "./permissions.js";
|
||||||
import { SnowFlake } from "./snowflake.js";
|
import { SnowFlake } from "./snowflake.js";
|
||||||
import { Contextmenu } from "./contextmenu.js";
|
import { Contextmenu } from "./contextmenu.js";
|
||||||
|
|
||||||
class Direct extends Guild {
|
class Direct extends Guild {
|
||||||
declare channelids: { [key: string]: Group };
|
declare channelids: { [key: string]: Group };
|
||||||
getUnixTime(): number {
|
getUnixTime(): number {
|
||||||
throw new Error("Do not call this for Direct, it does not make sense");
|
throw new Error("Do not call this for Direct, it does not make sense");
|
||||||
}
|
}
|
||||||
constructor(json: dirrectjson[], owner: Localuser) {
|
constructor(json: dirrectjson[], owner: Localuser) {
|
||||||
super(-1, owner, null);
|
super(-1, owner, null);
|
||||||
this.message_notifications = 0;
|
this.message_notifications = 0;
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
if (!this.localuser) {
|
if (!this.localuser) {
|
||||||
console.error("Owner was not included, please fix");
|
console.error("Owner was not included, please fix");
|
||||||
}
|
}
|
||||||
this.headers = this.localuser.headers;
|
this.headers = this.localuser.headers;
|
||||||
this.channels = [];
|
this.channels = [];
|
||||||
this.channelids = {};
|
this.channelids = {};
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.properties = {};
|
this.properties = {};
|
||||||
this.roles = [];
|
this.roles = [];
|
||||||
this.roleids = new Map();
|
this.roleids = new Map();
|
||||||
this.prevchannel = undefined;
|
this.prevchannel = undefined;
|
||||||
this.properties.name = "Direct Messages";
|
this.properties.name = "Direct Messages";
|
||||||
for (const thing of json) {
|
for (const thing of json) {
|
||||||
const temp = new Group(thing, this);
|
const temp = new Group(thing, this);
|
||||||
this.channels.push(temp);
|
this.channels.push(temp);
|
||||||
this.channelids[temp.id] = temp;
|
this.channelids[temp.id] = temp;
|
||||||
}
|
}
|
||||||
this.headchannels = this.channels;
|
this.headchannels = this.channels;
|
||||||
}
|
}
|
||||||
createChannelpac(json: any) {
|
createChannelpac(json: any) {
|
||||||
const thischannel = new Group(json, this);
|
const thischannel = new Group(json, this);
|
||||||
this.channelids[thischannel.id] = thischannel;
|
this.channelids[thischannel.id] = thischannel;
|
||||||
this.channels.push(thischannel);
|
this.channels.push(thischannel);
|
||||||
this.sortchannels();
|
this.sortchannels();
|
||||||
this.printServers();
|
this.printServers();
|
||||||
return thischannel;
|
return thischannel;
|
||||||
}
|
}
|
||||||
delChannel(json: channeljson) {
|
delChannel(json: channeljson) {
|
||||||
const channel = this.channelids[json.id];
|
const channel = this.channelids[json.id];
|
||||||
super.delChannel(json);
|
super.delChannel(json);
|
||||||
if (channel) {
|
if (channel) {
|
||||||
channel.del();
|
channel.del();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
giveMember(_member: memberjson) {
|
giveMember(_member: memberjson) {
|
||||||
console.error("not a real guild, can't give member object");
|
console.error("not a real guild, can't give member object");
|
||||||
}
|
}
|
||||||
getRole(/* ID: string */) {
|
getRole(/* ID: string */) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
hasRole(/* r: string */) {
|
hasRole(/* r: string */) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
isAdmin() {
|
isAdmin() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
unreaddms() {
|
unreaddms() {
|
||||||
for (const thing of this.channels) {
|
for (const thing of this.channels) {
|
||||||
(thing as Group).unreads();
|
(thing as Group).unreads();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const dmPermissions = new Permissions("0");
|
const dmPermissions = new Permissions("0");
|
||||||
|
@ -100,207 +100,207 @@ dmPermissions.setPermission("USE_VAD", 1);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
class Group extends Channel {
|
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("Copy DM id", function (this: Group) {
|
this.contextmenu.addbutton("Copy DM id", function (this: Group) {
|
||||||
navigator.clipboard.writeText(this.id);
|
navigator.clipboard.writeText(this.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.contextmenu.addbutton("Mark as read", function (this: Group) {
|
this.contextmenu.addbutton("Mark as read", function (this: Group) {
|
||||||
this.readbottom();
|
this.readbottom();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.contextmenu.addbutton("Close DM", function (this: Group) {
|
this.contextmenu.addbutton("Close DM", function (this: Group) {
|
||||||
this.deleteChannel();
|
this.deleteChannel();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.contextmenu.addbutton("Copy user ID", function () {
|
this.contextmenu.addbutton("Copy user ID", 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);
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.headers = this.guild.headers;
|
this.headers = this.guild.headers;
|
||||||
this.name = json.recipients[0]?.username;
|
this.name = json.recipients[0]?.username;
|
||||||
if (json.recipients[0]) {
|
if (json.recipients[0]) {
|
||||||
this.user = new User(json.recipients[0], this.localuser);
|
this.user = new User(json.recipients[0], this.localuser);
|
||||||
} else {
|
} else {
|
||||||
this.user = this.localuser.user;
|
this.user = this.localuser.user;
|
||||||
}
|
}
|
||||||
this.name ??= this.localuser.user.username;
|
this.name ??= this.localuser.user.username;
|
||||||
this.parent_id!;
|
this.parent_id!;
|
||||||
this.parent!;
|
this.parent!;
|
||||||
this.children = [];
|
this.children = [];
|
||||||
this.guild_id = "@me";
|
this.guild_id = "@me";
|
||||||
this.permission_overwrites = new Map();
|
this.permission_overwrites = new Map();
|
||||||
this.lastmessageid = json.last_message_id;
|
this.lastmessageid = json.last_message_id;
|
||||||
this.mentions = 0;
|
this.mentions = 0;
|
||||||
this.setUpInfiniteScroller();
|
this.setUpInfiniteScroller();
|
||||||
this.updatePosition();
|
this.updatePosition();
|
||||||
}
|
}
|
||||||
updatePosition() {
|
updatePosition() {
|
||||||
if (this.lastmessageid) {
|
if (this.lastmessageid) {
|
||||||
this.position = SnowFlake.stringToUnixTime(this.lastmessageid);
|
this.position = SnowFlake.stringToUnixTime(this.lastmessageid);
|
||||||
} else {
|
} else {
|
||||||
this.position = 0;
|
this.position = 0;
|
||||||
}
|
}
|
||||||
this.position = -Math.max(this.position, this.getUnixTime());
|
this.position = -Math.max(this.position, this.getUnixTime());
|
||||||
}
|
}
|
||||||
createguildHTML() {
|
createguildHTML() {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
Group.contextmenu.bindContextmenu(div, this, undefined);
|
Group.contextmenu.bindContextmenu(div, this, undefined);
|
||||||
this.html = new WeakRef(div);
|
this.html = new WeakRef(div);
|
||||||
div.classList.add("channeleffects");
|
div.classList.add("channeleffects");
|
||||||
const myhtml = document.createElement("span");
|
const myhtml = document.createElement("span");
|
||||||
myhtml.textContent = this.name;
|
myhtml.textContent = this.name;
|
||||||
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();
|
||||||
};
|
};
|
||||||
|
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
async getHTML() {
|
async getHTML() {
|
||||||
const id = ++Channel.genid;
|
const id = ++Channel.genid;
|
||||||
if (this.localuser.channelfocus) {
|
if (this.localuser.channelfocus) {
|
||||||
this.localuser.channelfocus.infinite.delete();
|
this.localuser.channelfocus.infinite.delete();
|
||||||
}
|
}
|
||||||
if (this.guild !== this.localuser.lookingguild) {
|
if (this.guild !== this.localuser.lookingguild) {
|
||||||
this.guild.loadGuild();
|
this.guild.loadGuild();
|
||||||
}
|
}
|
||||||
this.guild.prevchannel = this;
|
this.guild.prevchannel = this;
|
||||||
this.localuser.channelfocus = this;
|
this.localuser.channelfocus = this;
|
||||||
const prom = this.infinite.delete();
|
const prom = this.infinite.delete();
|
||||||
history.pushState(null, "", "/channels/" + this.guild_id + "/" + this.id);
|
history.pushState(null, "", "/channels/" + this.guild_id + "/" + this.id);
|
||||||
this.localuser.pageTitle("@" + this.name);
|
this.localuser.pageTitle("@" + this.name);
|
||||||
(document.getElementById("channelTopic") as HTMLElement).setAttribute(
|
(document.getElementById("channelTopic") as HTMLElement).setAttribute(
|
||||||
"hidden",
|
"hidden",
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
|
|
||||||
const loading = document.getElementById("loadingdiv") as HTMLDivElement;
|
const loading = document.getElementById("loadingdiv") as HTMLDivElement;
|
||||||
Channel.regenLoadingMessages();
|
Channel.regenLoadingMessages();
|
||||||
loading.classList.add("loading");
|
loading.classList.add("loading");
|
||||||
this.rendertyping();
|
this.rendertyping();
|
||||||
await this.putmessages();
|
await this.putmessages();
|
||||||
await prom;
|
await prom;
|
||||||
if (id !== Channel.genid) {
|
if (id !== Channel.genid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.buildmessages();
|
this.buildmessages();
|
||||||
(document.getElementById("typebox") as HTMLDivElement).contentEditable =
|
(document.getElementById("typebox") as HTMLDivElement).contentEditable =
|
||||||
"" + true;
|
"" + true;
|
||||||
}
|
}
|
||||||
messageCreate(messagep: { d: messagejson }) {
|
messageCreate(messagep: { d: messagejson }) {
|
||||||
const messagez = new Message(messagep.d, this);
|
const messagez = new Message(messagep.d, this);
|
||||||
if (this.lastmessageid) {
|
if (this.lastmessageid) {
|
||||||
this.idToNext.set(this.lastmessageid, messagez.id);
|
this.idToNext.set(this.lastmessageid, messagez.id);
|
||||||
this.idToPrev.set(messagez.id, this.lastmessageid);
|
this.idToPrev.set(messagez.id, this.lastmessageid);
|
||||||
}
|
}
|
||||||
this.lastmessageid = messagez.id;
|
this.lastmessageid = messagez.id;
|
||||||
if (messagez.author === this.localuser.user) {
|
if (messagez.author === this.localuser.user) {
|
||||||
this.lastreadmessageid = messagez.id;
|
this.lastreadmessageid = messagez.id;
|
||||||
if (this.myhtml) {
|
if (this.myhtml) {
|
||||||
this.myhtml.classList.remove("cunread");
|
this.myhtml.classList.remove("cunread");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.myhtml) {
|
if (this.myhtml) {
|
||||||
this.myhtml.classList.add("cunread");
|
this.myhtml.classList.add("cunread");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.unreads();
|
this.unreads();
|
||||||
this.updatePosition();
|
this.updatePosition();
|
||||||
this.infinite.addedBottom();
|
this.infinite.addedBottom();
|
||||||
this.guild.sortchannels();
|
this.guild.sortchannels();
|
||||||
if (this.myhtml) {
|
if (this.myhtml) {
|
||||||
const parrent = this.myhtml.parentElement as HTMLElement;
|
const parrent = this.myhtml.parentElement as HTMLElement;
|
||||||
parrent.prepend(this.myhtml);
|
parrent.prepend(this.myhtml);
|
||||||
}
|
}
|
||||||
if (this === this.localuser.channelfocus) {
|
if (this === this.localuser.channelfocus) {
|
||||||
if (!this.infinitefocus) {
|
if (!this.infinitefocus) {
|
||||||
this.tryfocusinfinate();
|
this.tryfocusinfinate();
|
||||||
}
|
}
|
||||||
this.infinite.addedBottom();
|
this.infinite.addedBottom();
|
||||||
}
|
}
|
||||||
this.unreads();
|
this.unreads();
|
||||||
if (messagez.author === this.localuser.user) {
|
if (messagez.author === this.localuser.user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
this.localuser.lookingguild?.prevchannel === this &&
|
this.localuser.lookingguild?.prevchannel === this &&
|
||||||
document.hasFocus()
|
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" &&
|
this.notification === "mentions" &&
|
||||||
messagez.mentionsuser(this.localuser.user)
|
messagez.mentionsuser(this.localuser.user)
|
||||||
) {
|
) {
|
||||||
this.notify(messagez);
|
this.notify(messagez);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notititle(message: Message) {
|
notititle(message: Message) {
|
||||||
return message.author.username;
|
return message.author.username;
|
||||||
}
|
}
|
||||||
readbottom() {
|
readbottom() {
|
||||||
super.readbottom();
|
super.readbottom();
|
||||||
this.unreads();
|
this.unreads();
|
||||||
}
|
}
|
||||||
all: WeakRef<HTMLElement> = new WeakRef(document.createElement("div"));
|
all: WeakRef<HTMLElement> = new WeakRef(document.createElement("div"));
|
||||||
noti: WeakRef<HTMLElement> = new WeakRef(document.createElement("div"));
|
noti: WeakRef<HTMLElement> = new WeakRef(document.createElement("div"));
|
||||||
del() {
|
del() {
|
||||||
const all = this.all.deref();
|
const all = this.all.deref();
|
||||||
if (all) {
|
if (all) {
|
||||||
all.remove();
|
all.remove();
|
||||||
}
|
}
|
||||||
if (this.myhtml) {
|
if (this.myhtml) {
|
||||||
this.myhtml.remove();
|
this.myhtml.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreads() {
|
unreads() {
|
||||||
const sentdms = document.getElementById("sentdms") as HTMLDivElement; //Need to change sometime
|
const sentdms = document.getElementById("sentdms") as HTMLDivElement; //Need to change sometime
|
||||||
const current = this.all.deref();
|
const current = this.all.deref();
|
||||||
if (this.hasunreads) {
|
if (this.hasunreads) {
|
||||||
{
|
{
|
||||||
const noti = this.noti.deref();
|
const noti = this.noti.deref();
|
||||||
if (noti) {
|
if (noti) {
|
||||||
noti.textContent = this.mentions + "";
|
noti.textContent = this.mentions + "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("servernoti");
|
div.classList.add("servernoti");
|
||||||
const noti = document.createElement("div");
|
const noti = document.createElement("div");
|
||||||
noti.classList.add("unread", "notiunread", "pinged");
|
noti.classList.add("unread", "notiunread", "pinged");
|
||||||
noti.textContent = "" + this.mentions;
|
noti.textContent = "" + this.mentions;
|
||||||
this.noti = new WeakRef(noti);
|
this.noti = new WeakRef(noti);
|
||||||
div.append(noti);
|
div.append(noti);
|
||||||
const buildpfp = this.user.buildpfp();
|
const buildpfp = this.user.buildpfp();
|
||||||
this.all = new WeakRef(div);
|
this.all = new WeakRef(div);
|
||||||
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();
|
||||||
};
|
};
|
||||||
} else if (current) {
|
} else if (current) {
|
||||||
current.remove();
|
current.remove();
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isAdmin(): boolean {
|
isAdmin(): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hasPermission(name: string): boolean {
|
hasPermission(name: string): boolean {
|
||||||
return dmPermissions.hasPermission(name);
|
return dmPermissions.hasPermission(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { Direct, Group };
|
export { Direct, Group };
|
||||||
Group.setupcontextmenu();
|
Group.setupcontextmenu();
|
||||||
|
|
|
@ -6,406 +6,406 @@ import { getapiurls, getInstances } from "./login.js";
|
||||||
import { Guild } from "./guild.js";
|
import { Guild } from "./guild.js";
|
||||||
|
|
||||||
class Embed {
|
class Embed {
|
||||||
type: string;
|
type: string;
|
||||||
owner: Message;
|
owner: Message;
|
||||||
json: embedjson;
|
json: embedjson;
|
||||||
constructor(json: embedjson, owner: Message) {
|
constructor(json: embedjson, owner: Message) {
|
||||||
this.type = this.getType(json);
|
this.type = this.getType(json);
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.json = json;
|
this.json = json;
|
||||||
}
|
}
|
||||||
getType(json: embedjson) {
|
getType(json: embedjson) {
|
||||||
const instances = getInstances();
|
const instances = getInstances();
|
||||||
if (
|
if (
|
||||||
instances &&
|
instances &&
|
||||||
json.type === "link" &&
|
json.type === "link" &&
|
||||||
json.url &&
|
json.url &&
|
||||||
URL.canParse(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)) {
|
||||||
const IUrl = new URL(instance.url);
|
const IUrl = new URL(instance.url);
|
||||||
const params = new URLSearchParams(Url.search);
|
const params = new URLSearchParams(Url.search);
|
||||||
let host: string;
|
let host: string;
|
||||||
if (params.has("instance")) {
|
if (params.has("instance")) {
|
||||||
const url = params.get("instance") as string;
|
const url = params.get("instance") as string;
|
||||||
if (URL.canParse(url)) {
|
if (URL.canParse(url)) {
|
||||||
host = new URL(url).host;
|
host = new URL(url).host;
|
||||||
} else {
|
} else {
|
||||||
host = Url.host;
|
host = Url.host;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
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,
|
||||||
};
|
};
|
||||||
return "invite";
|
return "invite";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return json.type || "rich";
|
return json.type || "rich";
|
||||||
}
|
}
|
||||||
generateHTML() {
|
generateHTML() {
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case "rich":
|
case "rich":
|
||||||
return this.generateRich();
|
return this.generateRich();
|
||||||
case "image":
|
case "image":
|
||||||
return this.generateImage();
|
return this.generateImage();
|
||||||
case "invite":
|
case "invite":
|
||||||
return this.generateInvite();
|
return this.generateInvite();
|
||||||
case "link":
|
case "link":
|
||||||
return this.generateLink();
|
return this.generateLink();
|
||||||
case "video":
|
case "video":
|
||||||
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`,
|
`unsupported embed type ${this.type}, please add support dev :3`,
|
||||||
this.json
|
this.json
|
||||||
);
|
);
|
||||||
return document.createElement("div"); //prevent errors by giving blank div
|
return document.createElement("div"); //prevent errors by giving blank div
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
get message() {
|
get message() {
|
||||||
return this.owner;
|
return this.owner;
|
||||||
}
|
}
|
||||||
get channel() {
|
get channel() {
|
||||||
return this.message.channel;
|
return this.message.channel;
|
||||||
}
|
}
|
||||||
get guild() {
|
get guild() {
|
||||||
return this.channel.guild;
|
return this.channel.guild;
|
||||||
}
|
}
|
||||||
get localuser() {
|
get localuser() {
|
||||||
return this.guild.localuser;
|
return this.guild.localuser;
|
||||||
}
|
}
|
||||||
generateRich() {
|
generateRich() {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
if (this.json.color) {
|
if (this.json.color) {
|
||||||
div.style.backgroundColor = "#" + this.json.color.toString(16);
|
div.style.backgroundColor = "#" + this.json.color.toString(16);
|
||||||
}
|
}
|
||||||
div.classList.add("embed-color");
|
div.classList.add("embed-color");
|
||||||
|
|
||||||
const embed = document.createElement("div");
|
const embed = document.createElement("div");
|
||||||
embed.classList.add("embed");
|
embed.classList.add("embed");
|
||||||
div.append(embed);
|
div.append(embed);
|
||||||
|
|
||||||
if (this.json.author) {
|
if (this.json.author) {
|
||||||
const authorline = document.createElement("div");
|
const authorline = document.createElement("div");
|
||||||
if (this.json.author.icon_url) {
|
if (this.json.author.icon_url) {
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.classList.add("embedimg");
|
img.classList.add("embedimg");
|
||||||
img.src = this.json.author.icon_url;
|
img.src = this.json.author.icon_url;
|
||||||
authorline.append(img);
|
authorline.append(img);
|
||||||
}
|
}
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
a.textContent = this.json.author.name as string;
|
a.textContent = this.json.author.name as string;
|
||||||
if (this.json.author.url) {
|
if (this.json.author.url) {
|
||||||
MarkDown.safeLink(a, this.json.author.url);
|
MarkDown.safeLink(a, this.json.author.url);
|
||||||
}
|
}
|
||||||
a.classList.add("username");
|
a.classList.add("username");
|
||||||
authorline.append(a);
|
authorline.append(a);
|
||||||
embed.append(authorline);
|
embed.append(authorline);
|
||||||
}
|
}
|
||||||
if (this.json.title) {
|
if (this.json.title) {
|
||||||
const title = document.createElement("a");
|
const title = document.createElement("a");
|
||||||
title.append(new MarkDown(this.json.title, this.channel).makeHTML());
|
title.append(new MarkDown(this.json.title, this.channel).makeHTML());
|
||||||
if (this.json.url) {
|
if (this.json.url) {
|
||||||
MarkDown.safeLink(title, this.json.url);
|
MarkDown.safeLink(title, this.json.url);
|
||||||
}
|
}
|
||||||
title.classList.add("embedtitle");
|
title.classList.add("embedtitle");
|
||||||
embed.append(title);
|
embed.append(title);
|
||||||
}
|
}
|
||||||
if (this.json.description) {
|
if (this.json.description) {
|
||||||
const p = document.createElement("p");
|
const p = document.createElement("p");
|
||||||
p.append(new MarkDown(this.json.description, this.channel).makeHTML());
|
p.append(new MarkDown(this.json.description, this.channel).makeHTML());
|
||||||
embed.append(p);
|
embed.append(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
embed.append(document.createElement("br"));
|
embed.append(document.createElement("br"));
|
||||||
if (this.json.fields) {
|
if (this.json.fields) {
|
||||||
for (const thing of this.json.fields) {
|
for (const thing of this.json.fields) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const b = document.createElement("b");
|
const b = document.createElement("b");
|
||||||
b.textContent = thing.name;
|
b.textContent = thing.name;
|
||||||
div.append(b);
|
div.append(b);
|
||||||
const p = document.createElement("p");
|
const p = document.createElement("p");
|
||||||
p.append(new MarkDown(thing.value, this.channel).makeHTML());
|
p.append(new MarkDown(thing.value, this.channel).makeHTML());
|
||||||
p.classList.add("embedp");
|
p.classList.add("embedp");
|
||||||
div.append(p);
|
div.append(p);
|
||||||
|
|
||||||
if (thing.inline) {
|
if (thing.inline) {
|
||||||
div.classList.add("inline");
|
div.classList.add("inline");
|
||||||
}
|
}
|
||||||
embed.append(div);
|
embed.append(div);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.json.footer || this.json.timestamp) {
|
if (this.json.footer || this.json.timestamp) {
|
||||||
const footer = document.createElement("div");
|
const footer = document.createElement("div");
|
||||||
if (this.json?.footer?.icon_url) {
|
if (this.json?.footer?.icon_url) {
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.src = this.json.footer.icon_url;
|
img.src = this.json.footer.icon_url;
|
||||||
img.classList.add("embedicon");
|
img.classList.add("embedicon");
|
||||||
footer.append(img);
|
footer.append(img);
|
||||||
}
|
}
|
||||||
if (this.json?.footer?.text) {
|
if (this.json?.footer?.text) {
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = this.json.footer.text;
|
span.textContent = this.json.footer.text;
|
||||||
span.classList.add("spaceright");
|
span.classList.add("spaceright");
|
||||||
footer.append(span);
|
footer.append(span);
|
||||||
}
|
}
|
||||||
if (this.json?.footer && this.json?.timestamp) {
|
if (this.json?.footer && this.json?.timestamp) {
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = "•";
|
span.textContent = "•";
|
||||||
span.classList.add("spaceright");
|
span.classList.add("spaceright");
|
||||||
footer.append(span);
|
footer.append(span);
|
||||||
}
|
}
|
||||||
if (this.json?.timestamp) {
|
if (this.json?.timestamp) {
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = new Date(this.json.timestamp).toLocaleString();
|
span.textContent = new Date(this.json.timestamp).toLocaleString();
|
||||||
footer.append(span);
|
footer.append(span);
|
||||||
}
|
}
|
||||||
embed.append(footer);
|
embed.append(footer);
|
||||||
}
|
}
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
generateImage() {
|
generateImage() {
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.classList.add("messageimg");
|
img.classList.add("messageimg");
|
||||||
img.onclick = function () {
|
img.onclick = function () {
|
||||||
const full = new Dialog(["img", img.src, ["fit"]]);
|
const full = new Dialog(["img", img.src, ["fit"]]);
|
||||||
full.show();
|
full.show();
|
||||||
};
|
};
|
||||||
img.src = this.json.thumbnail.proxy_url;
|
img.src = this.json.thumbnail.proxy_url;
|
||||||
if (this.json.thumbnail.width) {
|
if (this.json.thumbnail.width) {
|
||||||
let scale = 1;
|
let scale = 1;
|
||||||
const max = 96 * 3;
|
const max = 96 * 3;
|
||||||
scale = Math.max(scale, this.json.thumbnail.width / max);
|
scale = Math.max(scale, this.json.thumbnail.width / max);
|
||||||
scale = Math.max(scale, this.json.thumbnail.height / max);
|
scale = Math.max(scale, this.json.thumbnail.height / max);
|
||||||
this.json.thumbnail.width /= scale;
|
this.json.thumbnail.width /= scale;
|
||||||
this.json.thumbnail.height /= scale;
|
this.json.thumbnail.height /= scale;
|
||||||
}
|
}
|
||||||
img.style.width = this.json.thumbnail.width + "px";
|
img.style.width = this.json.thumbnail.width + "px";
|
||||||
img.style.height = this.json.thumbnail.height + "px";
|
img.style.height = this.json.thumbnail.height + "px";
|
||||||
console.log(this.json, "Image fix");
|
console.log(this.json, "Image fix");
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
generateLink() {
|
generateLink() {
|
||||||
const table = document.createElement("table");
|
const table = document.createElement("table");
|
||||||
table.classList.add("embed", "linkembed");
|
table.classList.add("embed", "linkembed");
|
||||||
const trtop = document.createElement("tr");
|
const trtop = document.createElement("tr");
|
||||||
table.append(trtop);
|
table.append(trtop);
|
||||||
if (this.json.url && this.json.title) {
|
if (this.json.url && this.json.title) {
|
||||||
const td = document.createElement("td");
|
const td = document.createElement("td");
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
MarkDown.safeLink(a, this.json.url);
|
MarkDown.safeLink(a, this.json.url);
|
||||||
a.textContent = this.json.title;
|
a.textContent = this.json.title;
|
||||||
td.append(a);
|
td.append(a);
|
||||||
trtop.append(td);
|
trtop.append(td);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const td = document.createElement("td");
|
const td = document.createElement("td");
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
if (this.json.thumbnail) {
|
if (this.json.thumbnail) {
|
||||||
img.classList.add("embedimg");
|
img.classList.add("embedimg");
|
||||||
img.onclick = function () {
|
img.onclick = function () {
|
||||||
const full = new Dialog(["img", img.src, ["fit"]]);
|
const full = new Dialog(["img", img.src, ["fit"]]);
|
||||||
full.show();
|
full.show();
|
||||||
};
|
};
|
||||||
img.src = this.json.thumbnail.proxy_url;
|
img.src = this.json.thumbnail.proxy_url;
|
||||||
td.append(img);
|
td.append(img);
|
||||||
}
|
}
|
||||||
trtop.append(td);
|
trtop.append(td);
|
||||||
}
|
}
|
||||||
const bottomtr = document.createElement("tr");
|
const bottomtr = document.createElement("tr");
|
||||||
const td = document.createElement("td");
|
const td = document.createElement("td");
|
||||||
if (this.json.description) {
|
if (this.json.description) {
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = this.json.description;
|
span.textContent = this.json.description;
|
||||||
td.append(span);
|
td.append(span);
|
||||||
}
|
}
|
||||||
bottomtr.append(td);
|
bottomtr.append(td);
|
||||||
table.append(bottomtr);
|
table.append(bottomtr);
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
invcache: [invitejson, { cdn: string; api: string }] | undefined;
|
invcache: [invitejson, { cdn: string; api: string }] | undefined;
|
||||||
generateInvite() {
|
generateInvite() {
|
||||||
if (this.invcache && (!this.json.invite || !this.localuser)) {
|
if (this.invcache && (!this.json.invite || !this.localuser)) {
|
||||||
return this.generateLink();
|
return this.generateLink();
|
||||||
}
|
}
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("embed", "inviteEmbed", "flexttb");
|
div.classList.add("embed", "inviteEmbed", "flexttb");
|
||||||
const json1 = this.json.invite;
|
const json1 = this.json.invite;
|
||||||
(async () => {
|
(async () => {
|
||||||
let json: invitejson;
|
let json: invitejson;
|
||||||
let info: { cdn: string; api: string };
|
let info: { cdn: string; api: string };
|
||||||
if (!this.invcache) {
|
if (!this.invcache) {
|
||||||
if (!json1) {
|
if (!json1) {
|
||||||
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.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.append(this.generateLink());
|
div.append(this.generateLink());
|
||||||
}
|
}
|
||||||
json = (await res.json()) as invitejson;
|
json = (await res.json()) as invitejson;
|
||||||
this.invcache = [json, info];
|
this.invcache = [json, info];
|
||||||
} else {
|
} else {
|
||||||
[json, info] = this.invcache;
|
[json, info] = this.invcache;
|
||||||
}
|
}
|
||||||
if (!json) {
|
if (!json) {
|
||||||
div.append(this.generateLink());
|
div.append(this.generateLink());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (json.guild.banner) {
|
if (json.guild.banner) {
|
||||||
const banner = document.createElement("img");
|
const banner = document.createElement("img");
|
||||||
banner.src =
|
banner.src =
|
||||||
this.localuser.info.cdn +
|
this.localuser.info.cdn +
|
||||||
"/icons/" +
|
"/icons/" +
|
||||||
json.guild.id +
|
json.guild.id +
|
||||||
"/" +
|
"/" +
|
||||||
json.guild.banner +
|
json.guild.banner +
|
||||||
".png?size=256";
|
".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", "flexstart");
|
iconrow.classList.add("flexltr", "flexstart");
|
||||||
iconrow.append(icon);
|
iconrow.append(icon);
|
||||||
{
|
{
|
||||||
const guildinfo = document.createElement("div");
|
const guildinfo = document.createElement("div");
|
||||||
guildinfo.classList.add("flexttb", "invguildinfo");
|
guildinfo.classList.add("flexttb", "invguildinfo");
|
||||||
const name = document.createElement("b");
|
const name = document.createElement("b");
|
||||||
name.textContent = guild.name;
|
name.textContent = guild.name;
|
||||||
guildinfo.append(name);
|
guildinfo.append(name);
|
||||||
|
|
||||||
const members = document.createElement("span");
|
const members = document.createElement("span");
|
||||||
members.innerText =
|
members.innerText =
|
||||||
"#" + json.channel.name + " • Members: " + guild.member_count;
|
"#" + json.channel.name + " • Members: " + guild.member_count;
|
||||||
guildinfo.append(members);
|
guildinfo.append(members);
|
||||||
members.classList.add("subtext");
|
members.classList.add("subtext");
|
||||||
iconrow.append(guildinfo);
|
iconrow.append(guildinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
div.append(iconrow);
|
div.append(iconrow);
|
||||||
const h2 = document.createElement("h2");
|
const h2 = document.createElement("h2");
|
||||||
h2.textContent = `You've been invited by ${json.inviter.username}`;
|
h2.textContent = `You've been invited by ${json.inviter.username}`;
|
||||||
div.append(h2);
|
div.append(h2);
|
||||||
const button = document.createElement("button");
|
const button = document.createElement("button");
|
||||||
button.textContent = "Accept";
|
button.textContent = "Accept";
|
||||||
if (this.localuser.info.api.startsWith(info.api)) {
|
if (this.localuser.info.api.startsWith(info.api)) {
|
||||||
if (this.localuser.guildids.has(guild.id)) {
|
if (this.localuser.guildids.has(guild.id)) {
|
||||||
button.textContent = "Already joined";
|
button.textContent = "Already joined";
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (this.json.invite) {
|
if (this.json.invite) {
|
||||||
const params = new URLSearchParams("");
|
const params = new URLSearchParams("");
|
||||||
params.set("instance", this.json.invite.url);
|
params.set("instance", this.json.invite.url);
|
||||||
const encoded = params.toString();
|
const encoded = params.toString();
|
||||||
const url = `${location.origin}/invite/${this.json.invite.code}?${encoded}`;
|
const url = `${location.origin}/invite/${this.json.invite.code}?${encoded}`;
|
||||||
window.open(url, "_blank");
|
window.open(url, "_blank");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
generateArticle() {
|
generateArticle() {
|
||||||
const colordiv = document.createElement("div");
|
const colordiv = document.createElement("div");
|
||||||
colordiv.style.backgroundColor = "#000000";
|
colordiv.style.backgroundColor = "#000000";
|
||||||
colordiv.classList.add("embed-color");
|
colordiv.classList.add("embed-color");
|
||||||
|
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("embed");
|
div.classList.add("embed");
|
||||||
if (this.json.provider) {
|
if (this.json.provider) {
|
||||||
const provider = document.createElement("p");
|
const provider = document.createElement("p");
|
||||||
provider.classList.add("provider");
|
provider.classList.add("provider");
|
||||||
provider.textContent = this.json.provider.name;
|
provider.textContent = this.json.provider.name;
|
||||||
div.append(provider);
|
div.append(provider);
|
||||||
}
|
}
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
if (this.json.url && this.json.url) {
|
if (this.json.url && this.json.url) {
|
||||||
MarkDown.safeLink(a, this.json.url);
|
MarkDown.safeLink(a, this.json.url);
|
||||||
a.textContent = this.json.url;
|
a.textContent = this.json.url;
|
||||||
div.append(a);
|
div.append(a);
|
||||||
}
|
}
|
||||||
if (this.json.description) {
|
if (this.json.description) {
|
||||||
const description = document.createElement("p");
|
const description = document.createElement("p");
|
||||||
description.textContent = this.json.description;
|
description.textContent = this.json.description;
|
||||||
div.append(description);
|
div.append(description);
|
||||||
}
|
}
|
||||||
if (this.json.thumbnail) {
|
if (this.json.thumbnail) {
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
if (this.json.thumbnail.width && this.json.thumbnail.width) {
|
if (this.json.thumbnail.width && this.json.thumbnail.width) {
|
||||||
let scale = 1;
|
let scale = 1;
|
||||||
const inch = 96;
|
const inch = 96;
|
||||||
scale = Math.max(scale, this.json.thumbnail.width / inch / 4);
|
scale = Math.max(scale, this.json.thumbnail.width / inch / 4);
|
||||||
scale = Math.max(scale, this.json.thumbnail.height / inch / 3);
|
scale = Math.max(scale, this.json.thumbnail.height / inch / 3);
|
||||||
this.json.thumbnail.width /= scale;
|
this.json.thumbnail.width /= scale;
|
||||||
this.json.thumbnail.height /= scale;
|
this.json.thumbnail.height /= scale;
|
||||||
img.style.width = this.json.thumbnail.width + "px";
|
img.style.width = this.json.thumbnail.width + "px";
|
||||||
img.style.height = this.json.thumbnail.height + "px";
|
img.style.height = this.json.thumbnail.height + "px";
|
||||||
}
|
}
|
||||||
img.classList.add("bigembedimg");
|
img.classList.add("bigembedimg");
|
||||||
if (this.json.video) {
|
if (this.json.video) {
|
||||||
img.onclick = async () => {
|
img.onclick = async () => {
|
||||||
if (this.json.video) {
|
if (this.json.video) {
|
||||||
img.remove();
|
img.remove();
|
||||||
const iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
iframe.src = this.json.video.url + "?autoplay=1";
|
iframe.src = this.json.video.url + "?autoplay=1";
|
||||||
if (this.json.thumbnail.width && this.json.thumbnail.width) {
|
if (this.json.thumbnail.width && this.json.thumbnail.width) {
|
||||||
iframe.style.width = this.json.thumbnail.width + "px";
|
iframe.style.width = this.json.thumbnail.width + "px";
|
||||||
iframe.style.height = this.json.thumbnail.height + "px";
|
iframe.style.height = this.json.thumbnail.height + "px";
|
||||||
}
|
}
|
||||||
div.append(iframe);
|
div.append(iframe);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
img.onclick = async () => {
|
img.onclick = async () => {
|
||||||
const full = new Dialog(["img", img.src, ["fit"]]);
|
const full = new Dialog(["img", img.src, ["fit"]]);
|
||||||
full.show();
|
full.show();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
img.src = this.json.thumbnail.proxy_url || this.json.thumbnail.url;
|
img.src = this.json.thumbnail.proxy_url || this.json.thumbnail.url;
|
||||||
div.append(img);
|
div.append(img);
|
||||||
}
|
}
|
||||||
colordiv.append(div);
|
colordiv.append(div);
|
||||||
return colordiv;
|
return colordiv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { Embed };
|
export { Embed };
|
||||||
|
|
|
@ -3,257 +3,257 @@ import { Guild } from "./guild.js";
|
||||||
import { Localuser } from "./localuser.js";
|
import { Localuser } from "./localuser.js";
|
||||||
|
|
||||||
class Emoji {
|
class Emoji {
|
||||||
static emojis: {
|
static emojis: {
|
||||||
name: string;
|
name: string;
|
||||||
emojis: {
|
emojis: {
|
||||||
name: string;
|
name: string;
|
||||||
emoji: string;
|
emoji: string;
|
||||||
}[];
|
}[];
|
||||||
}[];
|
}[];
|
||||||
name: string;
|
name: string;
|
||||||
id: string;
|
id: string;
|
||||||
animated: boolean;
|
animated: boolean;
|
||||||
owner: Guild | Localuser;
|
owner: Guild | Localuser;
|
||||||
get guild() {
|
get guild() {
|
||||||
if (this.owner instanceof Guild) {
|
if (this.owner instanceof Guild) {
|
||||||
return this.owner;
|
return this.owner;
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
get localuser() {
|
|
||||||
if (this.owner instanceof Guild) {
|
|
||||||
return this.owner.localuser;
|
|
||||||
} else {
|
|
||||||
return this.owner;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get info() {
|
|
||||||
return this.owner.info;
|
|
||||||
}
|
|
||||||
constructor(
|
|
||||||
json: { name: string; id: string; animated: boolean },
|
|
||||||
owner: Guild | Localuser
|
|
||||||
) {
|
|
||||||
this.name = json.name;
|
|
||||||
this.id = json.id;
|
|
||||||
this.animated = json.animated;
|
|
||||||
this.owner = owner;
|
|
||||||
}
|
|
||||||
getHTML(bigemoji: boolean = false) {
|
|
||||||
const emojiElem = document.createElement("img");
|
|
||||||
emojiElem.classList.add("md-emoji");
|
|
||||||
emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji");
|
|
||||||
emojiElem.crossOrigin = "anonymous";
|
|
||||||
emojiElem.src =
|
|
||||||
this.info.cdn +
|
|
||||||
"/emojis/" +
|
|
||||||
this.id +
|
|
||||||
"." +
|
|
||||||
(this.animated ? "gif" : "png") +
|
|
||||||
"?size=32";
|
|
||||||
|
|
||||||
emojiElem.alt = this.name;
|
|
||||||
emojiElem.loading = "lazy";
|
|
||||||
return emojiElem;
|
|
||||||
}
|
|
||||||
static decodeEmojiList(buffer: ArrayBuffer) {
|
|
||||||
const view = new DataView(buffer, 0);
|
|
||||||
let i = 0;
|
|
||||||
function read16() {
|
|
||||||
const int = view.getUint16(i);
|
|
||||||
i += 2;
|
|
||||||
return int;
|
|
||||||
}
|
|
||||||
function read8() {
|
|
||||||
const int = view.getUint8(i);
|
|
||||||
i += 1;
|
|
||||||
return int;
|
|
||||||
}
|
|
||||||
function readString8() {
|
|
||||||
return readStringNo(read8());
|
|
||||||
}
|
|
||||||
function readString16() {
|
|
||||||
return readStringNo(read16());
|
|
||||||
}
|
|
||||||
function readStringNo(length: number) {
|
|
||||||
const array = new Uint8Array(length);
|
|
||||||
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
array[i] = read8();
|
|
||||||
}
|
|
||||||
//console.log(array);
|
|
||||||
return new TextDecoder("utf-8").decode(array.buffer);
|
|
||||||
}
|
|
||||||
const build: { name: string; emojis: { name: string; emoji: string }[] }[] =
|
|
||||||
[];
|
|
||||||
let cats = read16();
|
|
||||||
|
|
||||||
for (; cats !== 0; cats--) {
|
|
||||||
const name = readString16();
|
|
||||||
const emojis: {
|
|
||||||
name: string;
|
|
||||||
skin_tone_support: boolean;
|
|
||||||
emoji: string;
|
|
||||||
}[] = [];
|
|
||||||
let emojinumber = read16();
|
|
||||||
for (; emojinumber !== 0; emojinumber--) {
|
|
||||||
//console.log(emojis);
|
|
||||||
const name = readString8();
|
|
||||||
const len = read8();
|
|
||||||
const skin_tone_support = len > 127;
|
|
||||||
const emoji = readStringNo(len - Number(skin_tone_support) * 128);
|
|
||||||
emojis.push({
|
|
||||||
name,
|
|
||||||
skin_tone_support,
|
|
||||||
emoji,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
build.push({
|
|
||||||
name,
|
|
||||||
emojis,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.emojis = build;
|
|
||||||
console.log(build);
|
|
||||||
}
|
|
||||||
static grabEmoji() {
|
|
||||||
fetch("/emoji.bin")
|
|
||||||
.then((e) => {
|
|
||||||
return e.arrayBuffer();
|
|
||||||
})
|
|
||||||
.then((e) => {
|
|
||||||
Emoji.decodeEmojiList(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
static async emojiPicker(
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
localuser: Localuser
|
|
||||||
): Promise<Emoji | string> {
|
|
||||||
let res: (r: Emoji | string) => void;
|
|
||||||
const promise: Promise<Emoji | string> = new Promise((r) => {
|
|
||||||
res = r;
|
|
||||||
});
|
|
||||||
const menu = document.createElement("div");
|
|
||||||
menu.classList.add("flexttb", "emojiPicker");
|
|
||||||
menu.style.top = y + "px";
|
|
||||||
menu.style.left = x + "px";
|
|
||||||
|
|
||||||
const title = document.createElement("h2");
|
|
||||||
title.textContent = Emoji.emojis[0].name;
|
|
||||||
title.classList.add("emojiTitle");
|
|
||||||
menu.append(title);
|
|
||||||
const selection = document.createElement("div");
|
|
||||||
selection.classList.add("flexltr", "dontshrink", "emojirow");
|
|
||||||
const body = document.createElement("div");
|
|
||||||
body.classList.add("emojiBody");
|
|
||||||
|
|
||||||
let isFirst = true;
|
|
||||||
localuser.guilds
|
|
||||||
.filter((guild) => guild.id != "@me" && guild.emojis.length > 0)
|
|
||||||
.forEach((guild) => {
|
|
||||||
const select = document.createElement("div");
|
|
||||||
select.classList.add("emojiSelect");
|
|
||||||
|
|
||||||
if (guild.properties.icon) {
|
|
||||||
const img = document.createElement("img");
|
|
||||||
img.classList.add("pfp", "servericon", "emoji-server");
|
|
||||||
img.crossOrigin = "anonymous";
|
|
||||||
img.src =
|
|
||||||
localuser.info.cdn +
|
|
||||||
"/icons/" +
|
|
||||||
guild.properties.id +
|
|
||||||
"/" +
|
|
||||||
guild.properties.icon +
|
|
||||||
".png?size=48";
|
|
||||||
img.alt = "Server: " + guild.properties.name;
|
|
||||||
select.appendChild(img);
|
|
||||||
} else {
|
|
||||||
const div = document.createElement("span");
|
|
||||||
div.textContent = guild.properties.name
|
|
||||||
.replace(/'s /g, " ")
|
|
||||||
.replace(/\w+/g, (word) => word[0])
|
|
||||||
.replace(/\s/g, "");
|
|
||||||
select.append(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
selection.append(select);
|
|
||||||
|
|
||||||
const clickEvent = () => {
|
|
||||||
title.textContent = guild.properties.name;
|
|
||||||
body.innerHTML = "";
|
|
||||||
for (const emojit of guild.emojis) {
|
|
||||||
const emojiElem = document.createElement("div");
|
|
||||||
emojiElem.classList.add("emojiSelect");
|
|
||||||
|
|
||||||
const emojiClass = new Emoji(
|
|
||||||
{
|
|
||||||
id: emojit.id as string,
|
|
||||||
name: emojit.name,
|
|
||||||
animated: emojit.animated as boolean,
|
|
||||||
},
|
|
||||||
localuser
|
|
||||||
);
|
|
||||||
emojiElem.append(emojiClass.getHTML());
|
|
||||||
body.append(emojiElem);
|
|
||||||
|
|
||||||
emojiElem.addEventListener("click", () => {
|
|
||||||
res(emojiClass);
|
|
||||||
if (Contextmenu.currentmenu !== "") {
|
|
||||||
Contextmenu.currentmenu.remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
select.addEventListener("click", clickEvent);
|
|
||||||
if (isFirst) {
|
|
||||||
clickEvent();
|
|
||||||
isFirst = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
if (Contextmenu.currentmenu != "") {
|
|
||||||
Contextmenu.currentmenu.remove();
|
|
||||||
}
|
|
||||||
document.body.append(menu);
|
|
||||||
Contextmenu.currentmenu = menu;
|
|
||||||
Contextmenu.keepOnScreen(menu);
|
|
||||||
}, 10);
|
|
||||||
|
|
||||||
let i = 0;
|
|
||||||
for (const thing of Emoji.emojis) {
|
|
||||||
const select = document.createElement("div");
|
|
||||||
select.textContent = thing.emojis[0].emoji;
|
|
||||||
select.classList.add("emojiSelect");
|
|
||||||
selection.append(select);
|
|
||||||
const clickEvent = () => {
|
|
||||||
title.textContent = thing.name;
|
|
||||||
body.innerHTML = "";
|
|
||||||
for (const emojit of thing.emojis) {
|
|
||||||
const emoji = document.createElement("div");
|
|
||||||
emoji.classList.add("emojiSelect");
|
|
||||||
emoji.textContent = emojit.emoji;
|
|
||||||
body.append(emoji);
|
|
||||||
emoji.onclick = (_) => {
|
|
||||||
res(emojit.emoji);
|
|
||||||
if (Contextmenu.currentmenu !== "") {
|
|
||||||
Contextmenu.currentmenu.remove();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
select.onclick = clickEvent;
|
|
||||||
if (i === 0) {
|
|
||||||
clickEvent();
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
menu.append(selection);
|
|
||||||
menu.append(body);
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Emoji.grabEmoji();
|
return;
|
||||||
export { Emoji };
|
}
|
||||||
|
get localuser() {
|
||||||
|
if (this.owner instanceof Guild) {
|
||||||
|
return this.owner.localuser;
|
||||||
|
} else {
|
||||||
|
return this.owner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get info() {
|
||||||
|
return this.owner.info;
|
||||||
|
}
|
||||||
|
constructor(
|
||||||
|
json: { name: string; id: string; animated: boolean },
|
||||||
|
owner: Guild | Localuser
|
||||||
|
) {
|
||||||
|
this.name = json.name;
|
||||||
|
this.id = json.id;
|
||||||
|
this.animated = json.animated;
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
getHTML(bigemoji: boolean = false) {
|
||||||
|
const emojiElem = document.createElement("img");
|
||||||
|
emojiElem.classList.add("md-emoji");
|
||||||
|
emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji");
|
||||||
|
emojiElem.crossOrigin = "anonymous";
|
||||||
|
emojiElem.src =
|
||||||
|
this.info.cdn +
|
||||||
|
"/emojis/" +
|
||||||
|
this.id +
|
||||||
|
"." +
|
||||||
|
(this.animated ? "gif" : "png") +
|
||||||
|
"?size=32";
|
||||||
|
|
||||||
|
emojiElem.alt = this.name;
|
||||||
|
emojiElem.loading = "lazy";
|
||||||
|
return emojiElem;
|
||||||
|
}
|
||||||
|
static decodeEmojiList(buffer: ArrayBuffer) {
|
||||||
|
const view = new DataView(buffer, 0);
|
||||||
|
let i = 0;
|
||||||
|
function read16() {
|
||||||
|
const int = view.getUint16(i);
|
||||||
|
i += 2;
|
||||||
|
return int;
|
||||||
|
}
|
||||||
|
function read8() {
|
||||||
|
const int = view.getUint8(i);
|
||||||
|
i += 1;
|
||||||
|
return int;
|
||||||
|
}
|
||||||
|
function readString8() {
|
||||||
|
return readStringNo(read8());
|
||||||
|
}
|
||||||
|
function readString16() {
|
||||||
|
return readStringNo(read16());
|
||||||
|
}
|
||||||
|
function readStringNo(length: number) {
|
||||||
|
const array = new Uint8Array(length);
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
array[i] = read8();
|
||||||
|
}
|
||||||
|
//console.log(array);
|
||||||
|
return new TextDecoder("utf-8").decode(array.buffer);
|
||||||
|
}
|
||||||
|
const build: { name: string; emojis: { name: string; emoji: string }[] }[] =
|
||||||
|
[];
|
||||||
|
let cats = read16();
|
||||||
|
|
||||||
|
for (; cats !== 0; cats--) {
|
||||||
|
const name = readString16();
|
||||||
|
const emojis: {
|
||||||
|
name: string;
|
||||||
|
skin_tone_support: boolean;
|
||||||
|
emoji: string;
|
||||||
|
}[] = [];
|
||||||
|
let emojinumber = read16();
|
||||||
|
for (; emojinumber !== 0; emojinumber--) {
|
||||||
|
//console.log(emojis);
|
||||||
|
const name = readString8();
|
||||||
|
const len = read8();
|
||||||
|
const skin_tone_support = len > 127;
|
||||||
|
const emoji = readStringNo(len - Number(skin_tone_support) * 128);
|
||||||
|
emojis.push({
|
||||||
|
name,
|
||||||
|
skin_tone_support,
|
||||||
|
emoji,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
build.push({
|
||||||
|
name,
|
||||||
|
emojis,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.emojis = build;
|
||||||
|
console.log(build);
|
||||||
|
}
|
||||||
|
static grabEmoji() {
|
||||||
|
fetch("/emoji.bin")
|
||||||
|
.then((e) => {
|
||||||
|
return e.arrayBuffer();
|
||||||
|
})
|
||||||
|
.then((e) => {
|
||||||
|
Emoji.decodeEmojiList(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static async emojiPicker(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
localuser: Localuser
|
||||||
|
): Promise<Emoji | string> {
|
||||||
|
let res: (r: Emoji | string) => void;
|
||||||
|
const promise: Promise<Emoji | string> = new Promise((r) => {
|
||||||
|
res = r;
|
||||||
|
});
|
||||||
|
const menu = document.createElement("div");
|
||||||
|
menu.classList.add("flexttb", "emojiPicker");
|
||||||
|
menu.style.top = y + "px";
|
||||||
|
menu.style.left = x + "px";
|
||||||
|
|
||||||
|
const title = document.createElement("h2");
|
||||||
|
title.textContent = Emoji.emojis[0].name;
|
||||||
|
title.classList.add("emojiTitle");
|
||||||
|
menu.append(title);
|
||||||
|
const selection = document.createElement("div");
|
||||||
|
selection.classList.add("flexltr", "dontshrink", "emojirow");
|
||||||
|
const body = document.createElement("div");
|
||||||
|
body.classList.add("emojiBody");
|
||||||
|
|
||||||
|
let isFirst = true;
|
||||||
|
localuser.guilds
|
||||||
|
.filter((guild) => guild.id != "@me" && guild.emojis.length > 0)
|
||||||
|
.forEach((guild) => {
|
||||||
|
const select = document.createElement("div");
|
||||||
|
select.classList.add("emojiSelect");
|
||||||
|
|
||||||
|
if (guild.properties.icon) {
|
||||||
|
const img = document.createElement("img");
|
||||||
|
img.classList.add("pfp", "servericon", "emoji-server");
|
||||||
|
img.crossOrigin = "anonymous";
|
||||||
|
img.src =
|
||||||
|
localuser.info.cdn +
|
||||||
|
"/icons/" +
|
||||||
|
guild.properties.id +
|
||||||
|
"/" +
|
||||||
|
guild.properties.icon +
|
||||||
|
".png?size=48";
|
||||||
|
img.alt = "Server: " + guild.properties.name;
|
||||||
|
select.appendChild(img);
|
||||||
|
} else {
|
||||||
|
const div = document.createElement("span");
|
||||||
|
div.textContent = guild.properties.name
|
||||||
|
.replace(/'s /g, " ")
|
||||||
|
.replace(/\w+/g, (word) => word[0])
|
||||||
|
.replace(/\s/g, "");
|
||||||
|
select.append(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
selection.append(select);
|
||||||
|
|
||||||
|
const clickEvent = () => {
|
||||||
|
title.textContent = guild.properties.name;
|
||||||
|
body.innerHTML = "";
|
||||||
|
for (const emojit of guild.emojis) {
|
||||||
|
const emojiElem = document.createElement("div");
|
||||||
|
emojiElem.classList.add("emojiSelect");
|
||||||
|
|
||||||
|
const emojiClass = new Emoji(
|
||||||
|
{
|
||||||
|
id: emojit.id as string,
|
||||||
|
name: emojit.name,
|
||||||
|
animated: emojit.animated as boolean,
|
||||||
|
},
|
||||||
|
localuser
|
||||||
|
);
|
||||||
|
emojiElem.append(emojiClass.getHTML());
|
||||||
|
body.append(emojiElem);
|
||||||
|
|
||||||
|
emojiElem.addEventListener("click", () => {
|
||||||
|
res(emojiClass);
|
||||||
|
if (Contextmenu.currentmenu !== "") {
|
||||||
|
Contextmenu.currentmenu.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
select.addEventListener("click", clickEvent);
|
||||||
|
if (isFirst) {
|
||||||
|
clickEvent();
|
||||||
|
isFirst = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (Contextmenu.currentmenu != "") {
|
||||||
|
Contextmenu.currentmenu.remove();
|
||||||
|
}
|
||||||
|
document.body.append(menu);
|
||||||
|
Contextmenu.currentmenu = menu;
|
||||||
|
Contextmenu.keepOnScreen(menu);
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
for (const thing of Emoji.emojis) {
|
||||||
|
const select = document.createElement("div");
|
||||||
|
select.textContent = thing.emojis[0].emoji;
|
||||||
|
select.classList.add("emojiSelect");
|
||||||
|
selection.append(select);
|
||||||
|
const clickEvent = () => {
|
||||||
|
title.textContent = thing.name;
|
||||||
|
body.innerHTML = "";
|
||||||
|
for (const emojit of thing.emojis) {
|
||||||
|
const emoji = document.createElement("div");
|
||||||
|
emoji.classList.add("emojiSelect");
|
||||||
|
emoji.textContent = emojit.emoji;
|
||||||
|
body.append(emoji);
|
||||||
|
emoji.onclick = (_) => {
|
||||||
|
res(emojit.emoji);
|
||||||
|
if (Contextmenu.currentmenu !== "") {
|
||||||
|
Contextmenu.currentmenu.remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
select.onclick = clickEvent;
|
||||||
|
if (i === 0) {
|
||||||
|
clickEvent();
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
menu.append(selection);
|
||||||
|
menu.append(body);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Emoji.grabEmoji();
|
||||||
|
export { Emoji };
|
||||||
|
|
|
@ -3,150 +3,150 @@ import { Dialog } from "./dialog.js";
|
||||||
import { filejson } from "./jsontypes.js";
|
import { filejson } from "./jsontypes.js";
|
||||||
|
|
||||||
class File {
|
class File {
|
||||||
owner: Message | null;
|
owner: Message | null;
|
||||||
id: string;
|
id: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
content_type: string;
|
content_type: string;
|
||||||
width: number | undefined;
|
width: number | undefined;
|
||||||
height: number | undefined;
|
height: number | undefined;
|
||||||
proxy_url: string | undefined;
|
proxy_url: string | undefined;
|
||||||
url: string;
|
url: string;
|
||||||
size: number;
|
size: number;
|
||||||
constructor(fileJSON: filejson, owner: Message | null) {
|
constructor(fileJSON: filejson, owner: Message | null) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.id = fileJSON.id;
|
this.id = fileJSON.id;
|
||||||
this.filename = fileJSON.filename;
|
this.filename = fileJSON.filename;
|
||||||
this.content_type = fileJSON.content_type;
|
this.content_type = fileJSON.content_type;
|
||||||
this.width = fileJSON.width;
|
this.width = fileJSON.width;
|
||||||
this.height = fileJSON.height;
|
this.height = fileJSON.height;
|
||||||
this.url = fileJSON.url;
|
this.url = fileJSON.url;
|
||||||
this.proxy_url = fileJSON.proxy_url;
|
this.proxy_url = fileJSON.proxy_url;
|
||||||
this.content_type = fileJSON.content_type;
|
this.content_type = fileJSON.content_type;
|
||||||
this.size = fileJSON.size;
|
this.size = fileJSON.size;
|
||||||
}
|
}
|
||||||
getHTML(temp: boolean = false): HTMLElement {
|
getHTML(temp: boolean = false): HTMLElement {
|
||||||
const src = this.proxy_url || this.url;
|
const src = this.proxy_url || this.url;
|
||||||
if (this.width && this.height) {
|
if (this.width && this.height) {
|
||||||
let scale = 1;
|
let scale = 1;
|
||||||
const max = 96 * 3;
|
const max = 96 * 3;
|
||||||
scale = Math.max(scale, this.width / max);
|
scale = Math.max(scale, this.width / max);
|
||||||
scale = Math.max(scale, this.height / max);
|
scale = Math.max(scale, this.height / max);
|
||||||
this.width /= scale;
|
this.width /= scale;
|
||||||
this.height /= scale;
|
this.height /= scale;
|
||||||
}
|
}
|
||||||
if (this.content_type.startsWith("image/")) {
|
if (this.content_type.startsWith("image/")) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.classList.add("messageimg");
|
img.classList.add("messageimg");
|
||||||
div.classList.add("messageimgdiv");
|
div.classList.add("messageimgdiv");
|
||||||
img.onclick = function () {
|
img.onclick = function () {
|
||||||
const full = new Dialog(["img", img.src, ["fit"]]);
|
const full = new Dialog(["img", img.src, ["fit"]]);
|
||||||
full.show();
|
full.show();
|
||||||
};
|
};
|
||||||
img.src = src;
|
img.src = src;
|
||||||
div.append(img);
|
div.append(img);
|
||||||
if (this.width) {
|
if (this.width) {
|
||||||
div.style.width = this.width + "px";
|
div.style.width = this.width + "px";
|
||||||
div.style.height = this.height + "px";
|
div.style.height = this.height + "px";
|
||||||
}
|
}
|
||||||
console.log(img);
|
console.log(img);
|
||||||
console.log(this.width, this.height);
|
console.log(this.width, this.height);
|
||||||
return div;
|
return div;
|
||||||
} else if (this.content_type.startsWith("video/")) {
|
} else if (this.content_type.startsWith("video/")) {
|
||||||
const video = document.createElement("video");
|
const video = document.createElement("video");
|
||||||
const source = document.createElement("source");
|
const source = document.createElement("source");
|
||||||
source.src = src;
|
source.src = src;
|
||||||
video.append(source);
|
video.append(source);
|
||||||
source.type = this.content_type;
|
source.type = this.content_type;
|
||||||
video.controls = !temp;
|
video.controls = !temp;
|
||||||
if (this.width && this.height) {
|
if (this.width && this.height) {
|
||||||
video.width = this.width;
|
video.width = this.width;
|
||||||
video.height = this.height;
|
video.height = this.height;
|
||||||
}
|
}
|
||||||
return video;
|
return video;
|
||||||
} else if (this.content_type.startsWith("audio/")) {
|
} else if (this.content_type.startsWith("audio/")) {
|
||||||
const audio = document.createElement("audio");
|
const audio = document.createElement("audio");
|
||||||
const source = document.createElement("source");
|
const source = document.createElement("source");
|
||||||
source.src = src;
|
source.src = src;
|
||||||
audio.append(source);
|
audio.append(source);
|
||||||
source.type = this.content_type;
|
source.type = this.content_type;
|
||||||
audio.controls = !temp;
|
audio.controls = !temp;
|
||||||
return audio;
|
return audio;
|
||||||
} else {
|
} else {
|
||||||
return this.createunknown();
|
return this.createunknown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
upHTML(files: Blob[], file: globalThis.File): HTMLElement {
|
upHTML(files: Blob[], file: globalThis.File): HTMLElement {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
const contained = this.getHTML(true);
|
const contained = this.getHTML(true);
|
||||||
div.classList.add("containedFile");
|
div.classList.add("containedFile");
|
||||||
div.append(contained);
|
div.append(contained);
|
||||||
const controls = document.createElement("div");
|
const controls = document.createElement("div");
|
||||||
const garbage = document.createElement("button");
|
const garbage = document.createElement("button");
|
||||||
garbage.textContent = "🗑";
|
garbage.textContent = "🗑";
|
||||||
garbage.onclick = (_) => {
|
garbage.onclick = (_) => {
|
||||||
div.remove();
|
div.remove();
|
||||||
files.splice(files.indexOf(file), 1);
|
files.splice(files.indexOf(file), 1);
|
||||||
};
|
};
|
||||||
controls.classList.add("controls");
|
controls.classList.add("controls");
|
||||||
div.append(controls);
|
div.append(controls);
|
||||||
controls.append(garbage);
|
controls.append(garbage);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
static initFromBlob(file: globalThis.File) {
|
static initFromBlob(file: globalThis.File) {
|
||||||
return new File(
|
return new File(
|
||||||
{
|
{
|
||||||
filename: file.name,
|
filename: file.name,
|
||||||
size: file.size,
|
size: file.size,
|
||||||
id: "null",
|
id: "null",
|
||||||
content_type: file.type,
|
content_type: file.type,
|
||||||
width: undefined,
|
width: undefined,
|
||||||
height: undefined,
|
height: undefined,
|
||||||
url: URL.createObjectURL(file),
|
url: URL.createObjectURL(file),
|
||||||
proxy_url: undefined,
|
proxy_url: undefined,
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
createunknown(): HTMLElement {
|
createunknown(): HTMLElement {
|
||||||
console.log("🗎");
|
console.log("🗎");
|
||||||
const src = this.proxy_url || this.url;
|
const src = this.proxy_url || this.url;
|
||||||
const div = document.createElement("table");
|
const div = document.createElement("table");
|
||||||
div.classList.add("unknownfile");
|
div.classList.add("unknownfile");
|
||||||
const nametr = document.createElement("tr");
|
const nametr = document.createElement("tr");
|
||||||
div.append(nametr);
|
div.append(nametr);
|
||||||
const fileicon = document.createElement("td");
|
const fileicon = document.createElement("td");
|
||||||
nametr.append(fileicon);
|
nametr.append(fileicon);
|
||||||
fileicon.append("🗎");
|
fileicon.append("🗎");
|
||||||
fileicon.classList.add("fileicon");
|
fileicon.classList.add("fileicon");
|
||||||
fileicon.rowSpan = 2;
|
fileicon.rowSpan = 2;
|
||||||
const nametd = document.createElement("td");
|
const nametd = document.createElement("td");
|
||||||
if (src) {
|
if (src) {
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
a.href = src;
|
a.href = src;
|
||||||
a.textContent = this.filename;
|
a.textContent = this.filename;
|
||||||
nametd.append(a);
|
nametd.append(a);
|
||||||
} else {
|
} else {
|
||||||
nametd.textContent = this.filename;
|
nametd.textContent = this.filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
nametd.classList.add("filename");
|
nametd.classList.add("filename");
|
||||||
nametr.append(nametd);
|
nametr.append(nametd);
|
||||||
const sizetr = document.createElement("tr");
|
const sizetr = document.createElement("tr");
|
||||||
const size = document.createElement("td");
|
const size = document.createElement("td");
|
||||||
sizetr.append(size);
|
sizetr.append(size);
|
||||||
size.textContent = "Size:" + File.filesizehuman(this.size);
|
size.textContent = "Size:" + File.filesizehuman(this.size);
|
||||||
size.classList.add("filesize");
|
size.classList.add("filesize");
|
||||||
div.appendChild(sizetr);
|
div.appendChild(sizetr);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
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 +
|
Number((fsize / Math.pow(1024, i)).toFixed(2)) * 1 +
|
||||||
" " +
|
" " +
|
||||||
["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i]
|
["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { File };
|
export { File };
|
||||||
|
|
1398
src/webpage/guild.ts
1398
src/webpage/guild.ts
File diff suppressed because it is too large
Load diff
|
@ -3,87 +3,87 @@ console.log(mobile);
|
||||||
const serverbox = document.getElementById("instancebox") as HTMLDivElement;
|
const serverbox = document.getElementById("instancebox") as HTMLDivElement;
|
||||||
|
|
||||||
fetch("/instances.json")
|
fetch("/instances.json")
|
||||||
.then((_) => _.json())
|
.then((_) => _.json())
|
||||||
.then(
|
.then(
|
||||||
(
|
(
|
||||||
json: {
|
json: {
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
descriptionLong?: string;
|
descriptionLong?: string;
|
||||||
image?: string;
|
image?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
display?: boolean;
|
display?: boolean;
|
||||||
online?: boolean;
|
online?: boolean;
|
||||||
uptime: { alltime: number; daytime: number; weektime: number };
|
uptime: { alltime: number; daytime: number; weektime: number };
|
||||||
urls: {
|
urls: {
|
||||||
wellknown: string;
|
wellknown: string;
|
||||||
api: string;
|
api: string;
|
||||||
cdn: string;
|
cdn: string;
|
||||||
gateway: string;
|
gateway: string;
|
||||||
login?: string;
|
login?: string;
|
||||||
};
|
};
|
||||||
}[]
|
}[]
|
||||||
) => {
|
) => {
|
||||||
console.warn(json);
|
console.warn(json);
|
||||||
for (const instance of json) {
|
for (const instance of json) {
|
||||||
if (instance.display === false) {
|
if (instance.display === false) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("flexltr", "instance");
|
div.classList.add("flexltr", "instance");
|
||||||
if (instance.image) {
|
if (instance.image) {
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.src = instance.image;
|
img.src = instance.image;
|
||||||
div.append(img);
|
div.append(img);
|
||||||
}
|
}
|
||||||
const statbox = document.createElement("div");
|
const statbox = document.createElement("div");
|
||||||
statbox.classList.add("flexttb");
|
statbox.classList.add("flexttb");
|
||||||
|
|
||||||
{
|
{
|
||||||
const textbox = document.createElement("div");
|
const textbox = document.createElement("div");
|
||||||
textbox.classList.add("flexttb", "instatancetextbox");
|
textbox.classList.add("flexttb", "instatancetextbox");
|
||||||
const title = document.createElement("h2");
|
const title = document.createElement("h2");
|
||||||
title.innerText = instance.name;
|
title.innerText = instance.name;
|
||||||
if (instance.online !== undefined) {
|
if (instance.online !== undefined) {
|
||||||
const status = document.createElement("span");
|
const status = document.createElement("span");
|
||||||
status.innerText = instance.online ? "Online" : "Offline";
|
status.innerText = instance.online ? "Online" : "Offline";
|
||||||
status.classList.add("instanceStatus");
|
status.classList.add("instanceStatus");
|
||||||
title.append(status);
|
title.append(status);
|
||||||
}
|
}
|
||||||
textbox.append(title);
|
textbox.append(title);
|
||||||
if (instance.description || instance.descriptionLong) {
|
if (instance.description || instance.descriptionLong) {
|
||||||
const p = document.createElement("p");
|
const p = document.createElement("p");
|
||||||
if (instance.descriptionLong) {
|
if (instance.descriptionLong) {
|
||||||
p.innerText = instance.descriptionLong;
|
p.innerText = instance.descriptionLong;
|
||||||
} else if (instance.description) {
|
} else if (instance.description) {
|
||||||
p.innerText = instance.description;
|
p.innerText = instance.description;
|
||||||
}
|
}
|
||||||
textbox.append(p);
|
textbox.append(p);
|
||||||
}
|
}
|
||||||
statbox.append(textbox);
|
statbox.append(textbox);
|
||||||
}
|
}
|
||||||
if (instance.uptime) {
|
if (instance.uptime) {
|
||||||
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 = `Uptime: All time: ${Math.round(
|
span.innerText = `Uptime: All time: ${Math.round(
|
||||||
instance.uptime.alltime * 100
|
instance.uptime.alltime * 100
|
||||||
)}% This week: ${Math.round(
|
)}% This week: ${Math.round(
|
||||||
instance.uptime.weektime * 100
|
instance.uptime.weektime * 100
|
||||||
)}% Today: ${Math.round(instance.uptime.daytime * 100)}%`;
|
)}% Today: ${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 =
|
window.location.href =
|
||||||
"/register.html?instance=" + encodeURI(instance.name);
|
"/register.html?instance=" + encodeURI(instance.name);
|
||||||
} else {
|
} else {
|
||||||
alert("Instance is offline, can't connect");
|
alert("Instance is offline, can't connect");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
serverbox.append(div);
|
serverbox.append(div);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,254 +6,254 @@ import { Message } from "./message.js";
|
||||||
import { File } from "./file.js";
|
import { File } from "./file.js";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
async function waitForLoad(): Promise<void> {
|
async function waitForLoad(): Promise<void> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
document.addEventListener("DOMContentLoaded", (_) => resolve());
|
document.addEventListener("DOMContentLoaded", (_) => resolve());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitForLoad();
|
await waitForLoad();
|
||||||
|
|
||||||
const users = getBulkUsers();
|
const users = getBulkUsers();
|
||||||
if (!users.currentuser) {
|
if (!users.currentuser) {
|
||||||
window.location.href = "/login.html";
|
window.location.href = "/login.html";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAccountSwitcher(): void {
|
function showAccountSwitcher(): void {
|
||||||
const table = document.createElement("div");
|
const table = document.createElement("div");
|
||||||
table.classList.add("accountSwitcher");
|
table.classList.add("accountSwitcher");
|
||||||
|
|
||||||
for (const user of Object.values(users.users)) {
|
for (const user of Object.values(users.users)) {
|
||||||
const specialUser = user as Specialuser;
|
const specialUser = user as Specialuser;
|
||||||
const userInfo = document.createElement("div");
|
const userInfo = document.createElement("div");
|
||||||
userInfo.classList.add("flexltr", "switchtable");
|
userInfo.classList.add("flexltr", "switchtable");
|
||||||
|
|
||||||
const pfp = document.createElement("img");
|
const pfp = document.createElement("img");
|
||||||
pfp.src = specialUser.pfpsrc;
|
pfp.src = specialUser.pfpsrc;
|
||||||
pfp.classList.add("pfp");
|
pfp.classList.add("pfp");
|
||||||
userInfo.append(pfp);
|
userInfo.append(pfp);
|
||||||
|
|
||||||
const userDiv = document.createElement("div");
|
const userDiv = document.createElement("div");
|
||||||
userDiv.classList.add("userinfo");
|
userDiv.classList.add("userinfo");
|
||||||
userDiv.textContent = specialUser.username;
|
userDiv.textContent = specialUser.username;
|
||||||
userDiv.append(document.createElement("br"));
|
userDiv.append(document.createElement("br"));
|
||||||
|
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = specialUser.serverurls.wellknown
|
span.textContent = specialUser.serverurls.wellknown
|
||||||
.replace("https://", "")
|
.replace("https://", "")
|
||||||
.replace("http://", "");
|
.replace("http://", "");
|
||||||
span.classList.add("serverURL");
|
span.classList.add("serverURL");
|
||||||
userDiv.append(span);
|
userDiv.append(span);
|
||||||
|
|
||||||
userInfo.append(userDiv);
|
userInfo.append(userDiv);
|
||||||
table.append(userInfo);
|
table.append(userInfo);
|
||||||
|
|
||||||
userInfo.addEventListener("click", () => {
|
userInfo.addEventListener("click", () => {
|
||||||
thisUser.unload();
|
thisUser.unload();
|
||||||
thisUser.swapped = true;
|
thisUser.swapped = true;
|
||||||
const loading = document.getElementById("loading") as HTMLDivElement;
|
const loading = document.getElementById("loading") as HTMLDivElement;
|
||||||
loading.classList.remove("doneloading");
|
loading.classList.remove("doneloading");
|
||||||
loading.classList.add("loading");
|
loading.classList.add("loading");
|
||||||
|
|
||||||
thisUser = new Localuser(specialUser);
|
thisUser = new Localuser(specialUser);
|
||||||
users.currentuser = specialUser.uid;
|
users.currentuser = specialUser.uid;
|
||||||
localStorage.setItem("userinfos", JSON.stringify(users));
|
localStorage.setItem("userinfos", JSON.stringify(users));
|
||||||
|
|
||||||
thisUser.initwebsocket().then(() => {
|
thisUser.initwebsocket().then(() => {
|
||||||
thisUser.loaduser();
|
thisUser.loaduser();
|
||||||
thisUser.init();
|
thisUser.init();
|
||||||
loading.classList.add("doneloading");
|
loading.classList.add("doneloading");
|
||||||
loading.classList.remove("loading");
|
loading.classList.remove("loading");
|
||||||
console.log("done loading");
|
console.log("done loading");
|
||||||
});
|
});
|
||||||
|
|
||||||
userInfo.remove();
|
userInfo.remove();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const switchAccountDiv = document.createElement("div");
|
const switchAccountDiv = document.createElement("div");
|
||||||
switchAccountDiv.classList.add("switchtable");
|
switchAccountDiv.classList.add("switchtable");
|
||||||
switchAccountDiv.textContent = "Switch accounts ⇌";
|
switchAccountDiv.textContent = "Switch accounts ⇌";
|
||||||
switchAccountDiv.addEventListener("click", () => {
|
switchAccountDiv.addEventListener("click", () => {
|
||||||
window.location.href = "/login.html";
|
window.location.href = "/login.html";
|
||||||
});
|
});
|
||||||
table.append(switchAccountDiv);
|
table.append(switchAccountDiv);
|
||||||
|
|
||||||
if (Contextmenu.currentmenu) {
|
if (Contextmenu.currentmenu) {
|
||||||
Contextmenu.currentmenu.remove();
|
Contextmenu.currentmenu.remove();
|
||||||
}
|
}
|
||||||
Contextmenu.currentmenu = table;
|
Contextmenu.currentmenu = table;
|
||||||
document.body.append(table);
|
document.body.append(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
const switchAccountsElement = document.getElementById(
|
||||||
"switchaccounts"
|
"switchaccounts"
|
||||||
) as HTMLDivElement;
|
) as HTMLDivElement;
|
||||||
switchAccountsElement.addEventListener("click", (event) => {
|
switchAccountsElement.addEventListener("click", (event) => {
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
showAccountSwitcher();
|
showAccountSwitcher();
|
||||||
});
|
});
|
||||||
|
|
||||||
let thisUser: Localuser;
|
let thisUser: Localuser;
|
||||||
try {
|
try {
|
||||||
console.log(users.users, users.currentuser);
|
console.log(users.users, users.currentuser);
|
||||||
thisUser = new Localuser(users.users[users.currentuser]);
|
thisUser = new Localuser(users.users[users.currentuser]);
|
||||||
thisUser.initwebsocket().then(() => {
|
thisUser.initwebsocket().then(() => {
|
||||||
thisUser.loaduser();
|
thisUser.loaduser();
|
||||||
thisUser.init();
|
thisUser.init();
|
||||||
const loading = document.getElementById("loading") as HTMLDivElement;
|
const loading = document.getElementById("loading") as HTMLDivElement;
|
||||||
loading.classList.add("doneloading");
|
loading.classList.add("doneloading");
|
||||||
loading.classList.remove("loading");
|
loading.classList.remove("loading");
|
||||||
console.log("done loading");
|
console.log("done loading");
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
(document.getElementById("load-desc") as HTMLSpanElement).textContent =
|
(document.getElementById("load-desc") as HTMLSpanElement).textContent =
|
||||||
"Account unable to start";
|
"Account unable to start";
|
||||||
thisUser = new Localuser(-1);
|
thisUser = new Localuser(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const menu = new Contextmenu("create rightclick");
|
const menu = new Contextmenu("create rightclick");
|
||||||
menu.addbutton(
|
menu.addbutton(
|
||||||
"Create channel",
|
"Create channel",
|
||||||
() => {
|
() => {
|
||||||
if (thisUser.lookingguild) {
|
if (thisUser.lookingguild) {
|
||||||
thisUser.lookingguild.createchannels();
|
thisUser.lookingguild.createchannels();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
() => thisUser.isAdmin()
|
() => thisUser.isAdmin()
|
||||||
);
|
);
|
||||||
|
|
||||||
menu.addbutton(
|
menu.addbutton(
|
||||||
"Create category",
|
"Create category",
|
||||||
() => {
|
() => {
|
||||||
if (thisUser.lookingguild) {
|
if (thisUser.lookingguild) {
|
||||||
thisUser.lookingguild.createcategory();
|
thisUser.lookingguild.createcategory();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
() => thisUser.isAdmin()
|
() => thisUser.isAdmin()
|
||||||
);
|
);
|
||||||
|
|
||||||
menu.bindContextmenu(
|
menu.bindContextmenu(
|
||||||
document.getElementById("channels") as HTMLDivElement,
|
document.getElementById("channels") as HTMLDivElement,
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
const pasteImageElement = document.getElementById(
|
const pasteImageElement = document.getElementById(
|
||||||
"pasteimage"
|
"pasteimage"
|
||||||
) as HTMLDivElement;
|
) as HTMLDivElement;
|
||||||
let replyingTo: Message | null = null;
|
let replyingTo: Message | null = null;
|
||||||
|
|
||||||
async function handleEnter(event: KeyboardEvent): Promise<void> {
|
async function handleEnter(event: KeyboardEvent): Promise<void> {
|
||||||
const channel = thisUser.channelfocus;
|
const channel = thisUser.channelfocus;
|
||||||
if (!channel) return;
|
if (!channel) return;
|
||||||
|
|
||||||
channel.typingstart();
|
channel.typingstart();
|
||||||
|
|
||||||
if (event.key === "Enter" && !event.shiftKey) {
|
if (event.key === "Enter" && !event.shiftKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (channel.editing) {
|
if (channel.editing) {
|
||||||
channel.editing.edit(markdown.rawString);
|
channel.editing.edit(markdown.rawString);
|
||||||
channel.editing = null;
|
channel.editing = null;
|
||||||
} else {
|
} else {
|
||||||
replyingTo = thisUser.channelfocus
|
replyingTo = thisUser.channelfocus
|
||||||
? thisUser.channelfocus.replyingto
|
? thisUser.channelfocus.replyingto
|
||||||
: null;
|
: null;
|
||||||
if (replyingTo?.div) {
|
if (replyingTo?.div) {
|
||||||
replyingTo.div.classList.remove("replying");
|
replyingTo.div.classList.remove("replying");
|
||||||
}
|
}
|
||||||
if (thisUser.channelfocus) {
|
if (thisUser.channelfocus) {
|
||||||
thisUser.channelfocus.replyingto = null;
|
thisUser.channelfocus.replyingto = null;
|
||||||
}
|
}
|
||||||
channel.sendMessage(markdown.rawString, {
|
channel.sendMessage(markdown.rawString, {
|
||||||
attachments: images,
|
attachments: images,
|
||||||
// @ts-ignore This is valid according to the API
|
// @ts-ignore This is valid according to the API
|
||||||
embeds: [], // Add an empty array for the embeds property
|
embeds: [], // Add an empty array for the embeds property
|
||||||
replyingto: replyingTo,
|
replyingto: replyingTo,
|
||||||
});
|
});
|
||||||
if (thisUser.channelfocus) {
|
if (thisUser.channelfocus) {
|
||||||
thisUser.channelfocus.makereplybox();
|
thisUser.channelfocus.makereplybox();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (images.length) {
|
while (images.length) {
|
||||||
images.pop();
|
images.pop();
|
||||||
pasteImageElement.removeChild(imagesHtml.pop() as HTMLElement);
|
pasteImageElement.removeChild(imagesHtml.pop() as HTMLElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
typebox.innerHTML = "";
|
typebox.innerHTML = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CustomHTMLDivElement extends HTMLDivElement {
|
interface CustomHTMLDivElement extends HTMLDivElement {
|
||||||
markdown: MarkDown;
|
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) => {
|
||||||
if (event.key === "Enter" && !event.shiftKey) event.preventDefault();
|
if (event.key === "Enter" && !event.shiftKey) event.preventDefault();
|
||||||
});
|
});
|
||||||
markdown.giveBox(typebox);
|
markdown.giveBox(typebox);
|
||||||
|
|
||||||
const images: Blob[] = [];
|
const images: Blob[] = [];
|
||||||
const imagesHtml: HTMLElement[] = [];
|
const imagesHtml: HTMLElement[] = [];
|
||||||
|
|
||||||
document.addEventListener("paste", async (e: ClipboardEvent) => {
|
document.addEventListener("paste", async (e: ClipboardEvent) => {
|
||||||
if (!e.clipboardData) return;
|
if (!e.clipboardData) return;
|
||||||
|
|
||||||
for (const file of Array.from(e.clipboardData.files)) {
|
for (const file of Array.from(e.clipboardData.files)) {
|
||||||
const fileInstance = File.initFromBlob(file);
|
const fileInstance = File.initFromBlob(file);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const html = fileInstance.upHTML(images, file);
|
const html = fileInstance.upHTML(images, file);
|
||||||
pasteImageElement.appendChild(html);
|
pasteImageElement.appendChild(html);
|
||||||
images.push(file);
|
images.push(file);
|
||||||
imagesHtml.push(html);
|
imagesHtml.push(html);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setTheme();
|
setTheme();
|
||||||
|
|
||||||
function userSettings(): void {
|
function userSettings(): void {
|
||||||
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(
|
const channelWrapper = document.getElementById(
|
||||||
"channelw"
|
"channelw"
|
||||||
) as HTMLDivElement;
|
) as HTMLDivElement;
|
||||||
channelWrapper.onclick = () => {
|
channelWrapper.onclick = () => {
|
||||||
(
|
(
|
||||||
document.getElementById("channels")!.parentNode as HTMLElement
|
document.getElementById("channels")!.parentNode as HTMLElement
|
||||||
).classList.add("collapse");
|
).classList.add("collapse");
|
||||||
document.getElementById("servertd")!.classList.add("collapse");
|
document.getElementById("servertd")!.classList.add("collapse");
|
||||||
document.getElementById("servers")!.classList.add("collapse");
|
document.getElementById("servers")!.classList.add("collapse");
|
||||||
};
|
};
|
||||||
|
|
||||||
const mobileBack = document.getElementById("mobileback") as HTMLDivElement;
|
const mobileBack = document.getElementById("mobileback") as HTMLDivElement;
|
||||||
mobileBack.textContent = "#";
|
mobileBack.textContent = "#";
|
||||||
mobileBack.onclick = () => {
|
mobileBack.onclick = () => {
|
||||||
(
|
(
|
||||||
document.getElementById("channels")!.parentNode as HTMLElement
|
document.getElementById("channels")!.parentNode as HTMLElement
|
||||||
).classList.remove("collapse");
|
).classList.remove("collapse");
|
||||||
document.getElementById("servertd")!.classList.remove("collapse");
|
document.getElementById("servertd")!.classList.remove("collapse");
|
||||||
document.getElementById("servers")!.classList.remove("collapse");
|
document.getElementById("servers")!.classList.remove("collapse");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -1,323 +1,323 @@
|
||||||
class InfiniteScroller {
|
class InfiniteScroller {
|
||||||
readonly getIDFromOffset: (
|
readonly getIDFromOffset: (
|
||||||
ID: string,
|
ID: string,
|
||||||
offset: number
|
offset: number
|
||||||
) => Promise<string | undefined>;
|
) => 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;
|
||||||
private readonly minDist = 2000;
|
private readonly minDist = 2000;
|
||||||
private readonly fillDist = 3000;
|
private readonly fillDist = 3000;
|
||||||
private readonly maxDist = 6000;
|
private readonly maxDist = 6000;
|
||||||
HTMLElements: [HTMLElement, string][] = [];
|
HTMLElements: [HTMLElement, string][] = [];
|
||||||
div: HTMLDivElement | null = null;
|
div: HTMLDivElement | null = null;
|
||||||
timeout: NodeJS.Timeout | null = null;
|
timeout: NodeJS.Timeout | null = null;
|
||||||
beenloaded = false;
|
beenloaded = false;
|
||||||
scrollBottom = 0;
|
scrollBottom = 0;
|
||||||
scrollTop = 0;
|
scrollTop = 0;
|
||||||
needsupdate = true;
|
needsupdate = true;
|
||||||
averageheight = 60;
|
averageheight = 60;
|
||||||
watchtime = false;
|
watchtime = false;
|
||||||
changePromise: Promise<boolean> | undefined;
|
changePromise: Promise<boolean> | undefined;
|
||||||
scollDiv!: { scrollTop: number; scrollHeight: number; clientHeight: number };
|
scollDiv!: { scrollTop: number; scrollHeight: number; clientHeight: number };
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
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;
|
||||||
this.destroyFromID = destroyFromID;
|
this.destroyFromID = destroyFromID;
|
||||||
this.reachesBottom = reachesBottom;
|
this.reachesBottom = reachesBottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDiv(initialId: string): Promise<HTMLDivElement> {
|
async getDiv(initialId: string): Promise<HTMLDivElement> {
|
||||||
if (this.div) {
|
if (this.div) {
|
||||||
throw new Error("Div already exists, exiting.");
|
throw new Error("Div already exists, exiting.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const scroll = document.createElement("div");
|
const scroll = document.createElement("div");
|
||||||
scroll.classList.add("flexttb", "scroller");
|
scroll.classList.add("flexttb", "scroller");
|
||||||
this.div = scroll;
|
this.div = scroll;
|
||||||
|
|
||||||
this.div.addEventListener("scroll", () => {
|
this.div.addEventListener("scroll", () => {
|
||||||
this.checkscroll();
|
this.checkscroll();
|
||||||
if (this.scrollBottom < 5) {
|
if (this.scrollBottom < 5) {
|
||||||
this.scrollBottom = 5;
|
this.scrollBottom = 5;
|
||||||
}
|
}
|
||||||
if (this.timeout === null) {
|
if (this.timeout === null) {
|
||||||
this.timeout = setTimeout(this.updatestuff.bind(this), 300);
|
this.timeout = setTimeout(this.updatestuff.bind(this), 300);
|
||||||
}
|
}
|
||||||
this.watchForChange();
|
this.watchForChange();
|
||||||
});
|
});
|
||||||
|
|
||||||
let oldheight = 0;
|
let oldheight = 0;
|
||||||
new ResizeObserver(() => {
|
new ResizeObserver(() => {
|
||||||
this.checkscroll();
|
this.checkscroll();
|
||||||
const func = this.snapBottom();
|
const func = this.snapBottom();
|
||||||
this.updatestuff();
|
this.updatestuff();
|
||||||
const change = oldheight - scroll.offsetHeight;
|
const change = oldheight - scroll.offsetHeight;
|
||||||
if (change > 0 && this.div) {
|
if (change > 0 && this.div) {
|
||||||
this.div.scrollTop += change;
|
this.div.scrollTop += change;
|
||||||
}
|
}
|
||||||
oldheight = scroll.offsetHeight;
|
oldheight = scroll.offsetHeight;
|
||||||
this.watchForChange();
|
this.watchForChange();
|
||||||
func();
|
func();
|
||||||
}).observe(scroll);
|
}).observe(scroll);
|
||||||
|
|
||||||
new ResizeObserver(this.watchForChange.bind(this)).observe(scroll);
|
new ResizeObserver(this.watchForChange.bind(this)).observe(scroll);
|
||||||
|
|
||||||
await this.firstElement(initialId);
|
await this.firstElement(initialId);
|
||||||
this.updatestuff();
|
this.updatestuff();
|
||||||
await this.watchForChange().then(() => {
|
await this.watchForChange().then(() => {
|
||||||
this.updatestuff();
|
this.updatestuff();
|
||||||
this.beenloaded = true;
|
this.beenloaded = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
return scroll;
|
return scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkscroll(): void {
|
checkscroll(): void {
|
||||||
if (this.beenloaded && this.div && !document.body.contains(this.div)) {
|
if (this.beenloaded && this.div && !document.body.contains(this.div)) {
|
||||||
console.warn("not in document");
|
console.warn("not in document");
|
||||||
this.div = null;
|
this.div = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async updatestuff(): Promise<void> {
|
async updatestuff(): Promise<void> {
|
||||||
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;
|
||||||
}
|
}
|
||||||
this.scrollTop = this.div.scrollTop;
|
this.scrollTop = this.div.scrollTop;
|
||||||
|
|
||||||
if (!this.scrollBottom && !(await this.watchForChange())) {
|
if (!this.scrollBottom && !(await this.watchForChange())) {
|
||||||
this.reachesBottom();
|
this.reachesBottom();
|
||||||
}
|
}
|
||||||
if (!this.scrollTop) {
|
if (!this.scrollTop) {
|
||||||
await this.watchForChange();
|
await this.watchForChange();
|
||||||
}
|
}
|
||||||
this.needsupdate = false;
|
this.needsupdate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async firstElement(id: string): Promise<void> {
|
async firstElement(id: string): Promise<void> {
|
||||||
if (!this.div) return;
|
if (!this.div) return;
|
||||||
const html = await this.getHTMLFromID(id);
|
const html = await this.getHTMLFromID(id);
|
||||||
this.div.appendChild(html);
|
this.div.appendChild(html);
|
||||||
this.HTMLElements.push([html, id]);
|
this.HTMLElements.push([html, id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async addedBottom(): Promise<void> {
|
async addedBottom(): Promise<void> {
|
||||||
await this.updatestuff();
|
await this.updatestuff();
|
||||||
const func = this.snapBottom();
|
const func = this.snapBottom();
|
||||||
await this.watchForChange();
|
await this.watchForChange();
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
|
||||||
snapBottom(): () => void {
|
snapBottom(): () => void {
|
||||||
const scrollBottom = this.scrollBottom;
|
const scrollBottom = this.scrollBottom;
|
||||||
return () => {
|
return () => {
|
||||||
if (this.div && scrollBottom < 4) {
|
if (this.div && scrollBottom < 4) {
|
||||||
this.div.scrollTop = this.div.scrollHeight;
|
this.div.scrollTop = this.div.scrollHeight;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async watchForTop(
|
private async watchForTop(
|
||||||
already = false,
|
already = false,
|
||||||
fragment = new DocumentFragment()
|
fragment = new DocumentFragment()
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
if (!this.div) return false;
|
if (!this.div) return false;
|
||||||
try {
|
try {
|
||||||
let again = false;
|
let again = false;
|
||||||
if (this.scrollTop < (already ? this.fillDist : this.minDist)) {
|
if (this.scrollTop < (already ? this.fillDist : this.minDist)) {
|
||||||
let nextid: string | undefined;
|
let nextid: string | undefined;
|
||||||
const firstelm = this.HTMLElements.at(0);
|
const firstelm = this.HTMLElements.at(0);
|
||||||
if (firstelm) {
|
if (firstelm) {
|
||||||
const previd = firstelm[1];
|
const previd = firstelm[1];
|
||||||
nextid = await this.getIDFromOffset(previd, 1);
|
nextid = await this.getIDFromOffset(previd, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextid) {
|
if (nextid) {
|
||||||
const html = await this.getHTMLFromID(nextid);
|
const html = await this.getHTMLFromID(nextid);
|
||||||
if (!html) {
|
if (!html) {
|
||||||
this.destroyFromID(nextid);
|
this.destroyFromID(nextid);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
again = true;
|
again = true;
|
||||||
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) {
|
||||||
const html = this.HTMLElements.shift();
|
const html = this.HTMLElements.shift();
|
||||||
if (html) {
|
if (html) {
|
||||||
again = true;
|
again = true;
|
||||||
await this.destroyFromID(html[1]);
|
await this.destroyFromID(html[1]);
|
||||||
this.scrollTop -= this.averageheight;
|
this.scrollTop -= this.averageheight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (again) {
|
if (again) {
|
||||||
await this.watchForTop(true, fragment);
|
await this.watchForTop(true, fragment);
|
||||||
}
|
}
|
||||||
return again;
|
return again;
|
||||||
} finally {
|
} finally {
|
||||||
if (!already) {
|
if (!already) {
|
||||||
if (this.div.scrollTop === 0) {
|
if (this.div.scrollTop === 0) {
|
||||||
this.scrollTop = 1;
|
this.scrollTop = 1;
|
||||||
this.div.scrollTop = 10;
|
this.div.scrollTop = 10;
|
||||||
}
|
}
|
||||||
this.div.prepend(fragment, fragment);
|
this.div.prepend(fragment, fragment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async watchForBottom(
|
async watchForBottom(
|
||||||
already = false,
|
already = false,
|
||||||
fragment = new DocumentFragment()
|
fragment = new DocumentFragment()
|
||||||
): Promise<boolean> {
|
): 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;
|
||||||
try {
|
try {
|
||||||
let again = false;
|
let again = false;
|
||||||
const scrollBottom = this.scrollBottom;
|
const scrollBottom = this.scrollBottom;
|
||||||
if (scrollBottom < (already ? this.fillDist : this.minDist)) {
|
if (scrollBottom < (already ? this.fillDist : this.minDist)) {
|
||||||
let nextid: string | undefined;
|
let nextid: string | undefined;
|
||||||
const lastelm = this.HTMLElements.at(-1);
|
const lastelm = this.HTMLElements.at(-1);
|
||||||
if (lastelm) {
|
if (lastelm) {
|
||||||
const previd = lastelm[1];
|
const previd = lastelm[1];
|
||||||
nextid = await this.getIDFromOffset(previd, -1);
|
nextid = await this.getIDFromOffset(previd, -1);
|
||||||
}
|
}
|
||||||
if (nextid) {
|
if (nextid) {
|
||||||
again = true;
|
again = true;
|
||||||
const html = await this.getHTMLFromID(nextid);
|
const html = await this.getHTMLFromID(nextid);
|
||||||
fragment.appendChild(html);
|
fragment.appendChild(html);
|
||||||
this.HTMLElements.push([html, nextid]);
|
this.HTMLElements.push([html, nextid]);
|
||||||
this.scrollBottom += this.averageheight;
|
this.scrollBottom += this.averageheight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (scrollBottom > this.maxDist) {
|
if (scrollBottom > this.maxDist) {
|
||||||
const html = this.HTMLElements.pop();
|
const html = this.HTMLElements.pop();
|
||||||
if (html) {
|
if (html) {
|
||||||
await this.destroyFromID(html[1]);
|
await this.destroyFromID(html[1]);
|
||||||
this.scrollBottom -= this.averageheight;
|
this.scrollBottom -= this.averageheight;
|
||||||
again = true;
|
again = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (again) {
|
if (again) {
|
||||||
await this.watchForBottom(true, fragment);
|
await this.watchForBottom(true, fragment);
|
||||||
}
|
}
|
||||||
return again;
|
return again;
|
||||||
} finally {
|
} finally {
|
||||||
if (!already) {
|
if (!already) {
|
||||||
this.div.append(fragment);
|
this.div.append(fragment);
|
||||||
if (func) {
|
if (func) {
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async watchForChange(): Promise<boolean> {
|
async watchForChange(): Promise<boolean> {
|
||||||
if (this.changePromise) {
|
if (this.changePromise) {
|
||||||
this.watchtime = true;
|
this.watchtime = true;
|
||||||
return await this.changePromise;
|
return await this.changePromise;
|
||||||
} else {
|
} else {
|
||||||
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);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const out = (await Promise.allSettled([
|
const out = (await Promise.allSettled([
|
||||||
this.watchForTop(),
|
this.watchForTop(),
|
||||||
this.watchForBottom(),
|
this.watchForBottom(),
|
||||||
])) as { value: boolean }[];
|
])) 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);
|
||||||
}
|
}
|
||||||
res(Boolean(changed));
|
res(Boolean(changed));
|
||||||
return Boolean(changed);
|
return Boolean(changed);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
res(false);
|
res(false);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.changePromise = undefined;
|
this.changePromise = undefined;
|
||||||
if (this.watchtime) {
|
if (this.watchtime) {
|
||||||
this.watchForChange();
|
this.watchForChange();
|
||||||
}
|
}
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return await this.changePromise;
|
return await this.changePromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
async focus(id: string, flash = true): Promise<void> {
|
async focus(id: string, flash = true): Promise<void> {
|
||||||
let element: HTMLElement | undefined;
|
let element: HTMLElement | undefined;
|
||||||
for (const thing of this.HTMLElements) {
|
for (const thing of this.HTMLElements) {
|
||||||
if (thing[1] === id) {
|
if (thing[1] === id) {
|
||||||
element = thing[0];
|
element = thing[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (element) {
|
if (element) {
|
||||||
if (flash) {
|
if (flash) {
|
||||||
element.scrollIntoView({
|
element.scrollIntoView({
|
||||||
behavior: "smooth",
|
behavior: "smooth",
|
||||||
block: "center",
|
block: "center",
|
||||||
});
|
});
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
element.classList.remove("jumped");
|
element.classList.remove("jumped");
|
||||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||||
element.classList.add("jumped");
|
element.classList.add("jumped");
|
||||||
} else {
|
} else {
|
||||||
element.scrollIntoView();
|
element.scrollIntoView();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const thing of this.HTMLElements) {
|
for (const thing of this.HTMLElements) {
|
||||||
await this.destroyFromID(thing[1]);
|
await this.destroyFromID(thing[1]);
|
||||||
}
|
}
|
||||||
this.HTMLElements = [];
|
this.HTMLElements = [];
|
||||||
await this.firstElement(id);
|
await this.firstElement(id);
|
||||||
this.updatestuff();
|
this.updatestuff();
|
||||||
await this.watchForChange();
|
await this.watchForChange();
|
||||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||||
await this.focus(id, true);
|
await this.focus(id, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(): Promise<void> {
|
async delete(): Promise<void> {
|
||||||
if (this.div) {
|
if (this.div) {
|
||||||
this.div.remove();
|
this.div.remove();
|
||||||
this.div = null;
|
this.div = null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
for (const thing of this.HTMLElements) {
|
for (const thing of this.HTMLElements) {
|
||||||
await this.destroyFromID(thing[1]);
|
await this.destroyFromID(thing[1]);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
this.HTMLElements = [];
|
this.HTMLElements = [];
|
||||||
if (this.timeout) {
|
if (this.timeout) {
|
||||||
clearTimeout(this.timeout);
|
clearTimeout(this.timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { InfiniteScroller };
|
export { InfiniteScroller };
|
||||||
|
|
|
@ -1,147 +1,147 @@
|
||||||
import { getBulkUsers, Specialuser, getapiurls } from "./login.js";
|
import { getBulkUsers, Specialuser, getapiurls } from "./login.js";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const users = getBulkUsers();
|
const users = getBulkUsers();
|
||||||
const well = new URLSearchParams(window.location.search).get("instance");
|
const well = new URLSearchParams(window.location.search).get("instance");
|
||||||
const joinable: Specialuser[] = [];
|
const joinable: Specialuser[] = [];
|
||||||
|
|
||||||
for (const key in users.users) {
|
for (const key in users.users) {
|
||||||
if (Object.prototype.hasOwnProperty.call(users.users, key)) {
|
if (Object.prototype.hasOwnProperty.call(users.users, key)) {
|
||||||
const user: Specialuser = users.users[key];
|
const user: Specialuser = users.users[key];
|
||||||
if (well && user.serverurls.wellknown.includes(well)) {
|
if (well && user.serverurls.wellknown.includes(well)) {
|
||||||
joinable.push(user);
|
joinable.push(user);
|
||||||
}
|
}
|
||||||
console.log(user);
|
console.log(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let urls: { api: string; cdn: string } | undefined;
|
let urls: { api: string; cdn: string } | undefined;
|
||||||
|
|
||||||
if (!joinable.length && well) {
|
if (!joinable.length && well) {
|
||||||
const out = await getapiurls(well);
|
const out = await getapiurls(well);
|
||||||
if (out) {
|
if (out) {
|
||||||
urls = out;
|
urls = out;
|
||||||
for (const key in users.users) {
|
for (const key in users.users) {
|
||||||
if (Object.prototype.hasOwnProperty.call(users.users, key)) {
|
if (Object.prototype.hasOwnProperty.call(users.users, key)) {
|
||||||
const user: Specialuser = users.users[key];
|
const user: Specialuser = users.users[key];
|
||||||
if (user.serverurls.api.includes(out.api)) {
|
if (user.serverurls.api.includes(out.api)) {
|
||||||
joinable.push(user);
|
joinable.push(user);
|
||||||
}
|
}
|
||||||
console.log(user);
|
console.log(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!joinable.length) {
|
if (!joinable.length) {
|
||||||
document.getElementById("AcceptInvite")!.textContent =
|
document.getElementById("AcceptInvite")!.textContent =
|
||||||
"Create an account to accept the invite";
|
"Create an account to accept the invite";
|
||||||
}
|
}
|
||||||
|
|
||||||
const code = window.location.pathname.split("/")[2];
|
const code = window.location.pathname.split("/")[2];
|
||||||
let guildinfo: any;
|
let guildinfo: any;
|
||||||
|
|
||||||
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"
|
"invitedescription"
|
||||||
)!.textContent = `${json.inviter.username} invited you to join ${guildjson.name}`;
|
)!.textContent = `${json.inviter.username} invited you to join ${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`;
|
||||||
img.classList.add("inviteGuild");
|
img.classList.add("inviteGuild");
|
||||||
document.getElementById("inviteimg")!.append(img);
|
document.getElementById("inviteimg")!.append(img);
|
||||||
} else {
|
} else {
|
||||||
const txt = guildjson.name
|
const txt = guildjson.name
|
||||||
.replace(/'s /g, " ")
|
.replace(/'s /g, " ")
|
||||||
.replace(/\w+/g, (word: any[]) => word[0])
|
.replace(/\w+/g, (word: any[]) => word[0])
|
||||||
.replace(/\s/g, "");
|
.replace(/\s/g, "");
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.textContent = txt;
|
div.textContent = txt;
|
||||||
div.classList.add("inviteGuild");
|
div.classList.add("inviteGuild");
|
||||||
document.getElementById("inviteimg")!.append(div);
|
document.getElementById("inviteimg")!.append(div);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function showAccounts(): void {
|
function showAccounts(): void {
|
||||||
const table = document.createElement("dialog");
|
const table = document.createElement("dialog");
|
||||||
for (const user of joinable) {
|
for (const user of joinable) {
|
||||||
console.log(user.pfpsrc);
|
console.log(user.pfpsrc);
|
||||||
|
|
||||||
const userinfo = document.createElement("div");
|
const userinfo = document.createElement("div");
|
||||||
userinfo.classList.add("flexltr", "switchtable");
|
userinfo.classList.add("flexltr", "switchtable");
|
||||||
|
|
||||||
const pfp = document.createElement("img");
|
const pfp = document.createElement("img");
|
||||||
pfp.src = user.pfpsrc;
|
pfp.src = user.pfpsrc;
|
||||||
pfp.classList.add("pfp");
|
pfp.classList.add("pfp");
|
||||||
userinfo.append(pfp);
|
userinfo.append(pfp);
|
||||||
|
|
||||||
const userDiv = document.createElement("div");
|
const userDiv = document.createElement("div");
|
||||||
userDiv.classList.add("userinfo");
|
userDiv.classList.add("userinfo");
|
||||||
userDiv.textContent = user.username;
|
userDiv.textContent = user.username;
|
||||||
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("https://", "")
|
||||||
.replace("http://", "");
|
.replace("http://", "");
|
||||||
span.classList.add("serverURL");
|
span.classList.add("serverURL");
|
||||||
userDiv.append(span);
|
userDiv.append(span);
|
||||||
|
|
||||||
userinfo.append(userDiv);
|
userinfo.append(userDiv);
|
||||||
table.append(userinfo);
|
table.append(userinfo);
|
||||||
|
|
||||||
userinfo.addEventListener("click", () => {
|
userinfo.addEventListener("click", () => {
|
||||||
console.log(user);
|
console.log(user);
|
||||||
fetch(`${urls!.api}/invites/${code}`, {
|
fetch(`${urls!.api}/invites/${code}`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: user.token,
|
Authorization: user.token,
|
||||||
},
|
},
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
users.currentuser = user.uid;
|
users.currentuser = user.uid;
|
||||||
localStorage.setItem("userinfos", JSON.stringify(users));
|
localStorage.setItem("userinfos", JSON.stringify(users));
|
||||||
window.location.href = "/channels/" + guildinfo.id;
|
window.location.href = "/channels/" + guildinfo.id;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const td = document.createElement("div");
|
const td = document.createElement("div");
|
||||||
td.classList.add("switchtable");
|
td.classList.add("switchtable");
|
||||||
td.textContent = "Login or create an account ⇌";
|
td.textContent = "Login or create an account ⇌";
|
||||||
td.addEventListener("click", () => {
|
td.addEventListener("click", () => {
|
||||||
const l = new URLSearchParams("?");
|
const l = new URLSearchParams("?");
|
||||||
l.set("goback", window.location.href);
|
l.set("goback", window.location.href);
|
||||||
l.set("instance", well!);
|
l.set("instance", well!);
|
||||||
window.location.href = "/login?" + l.toString();
|
window.location.href = "/login?" + l.toString();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!joinable.length) {
|
if (!joinable.length) {
|
||||||
const l = new URLSearchParams("?");
|
const l = new URLSearchParams("?");
|
||||||
l.set("goback", window.location.href);
|
l.set("goback", window.location.href);
|
||||||
l.set("instance", well!);
|
l.set("instance", well!);
|
||||||
window.location.href = "/login?" + l.toString();
|
window.location.href = "/login?" + l.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
table.append(td);
|
table.append(td);
|
||||||
table.classList.add("accountSwitcher");
|
table.classList.add("accountSwitcher");
|
||||||
console.log(table);
|
console.log(table);
|
||||||
document.body.append(table);
|
document.body.append(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
document
|
document
|
||||||
.getElementById("AcceptInvite")!
|
.getElementById("AcceptInvite")!
|
||||||
.addEventListener("click", showAccounts);
|
.addEventListener("click", showAccounts);
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -1,501 +1,501 @@
|
||||||
type readyjson = {
|
type readyjson = {
|
||||||
op: 0;
|
op: 0;
|
||||||
t: "READY";
|
t: "READY";
|
||||||
s: number;
|
s: number;
|
||||||
d: {
|
d: {
|
||||||
v: number;
|
v: number;
|
||||||
user: mainuserjson;
|
user: mainuserjson;
|
||||||
user_settings: {
|
user_settings: {
|
||||||
index: number;
|
index: number;
|
||||||
afk_timeout: number;
|
afk_timeout: number;
|
||||||
allow_accessibility_detection: boolean;
|
allow_accessibility_detection: boolean;
|
||||||
animate_emoji: boolean;
|
animate_emoji: boolean;
|
||||||
animate_stickers: number;
|
animate_stickers: number;
|
||||||
contact_sync_enabled: boolean;
|
contact_sync_enabled: boolean;
|
||||||
convert_emoticons: boolean;
|
convert_emoticons: boolean;
|
||||||
custom_status: string;
|
custom_status: string;
|
||||||
default_guilds_restricted: boolean;
|
default_guilds_restricted: boolean;
|
||||||
detect_platform_accounts: boolean;
|
detect_platform_accounts: boolean;
|
||||||
developer_mode: boolean;
|
developer_mode: boolean;
|
||||||
disable_games_tab: boolean;
|
disable_games_tab: boolean;
|
||||||
enable_tts_command: boolean;
|
enable_tts_command: boolean;
|
||||||
explicit_content_filter: 0;
|
explicit_content_filter: 0;
|
||||||
friend_discovery_flags: 0;
|
friend_discovery_flags: 0;
|
||||||
friend_source_flags: {
|
friend_source_flags: {
|
||||||
all: boolean;
|
all: boolean;
|
||||||
}; //might be missing things here
|
}; //might be missing things here
|
||||||
gateway_connected: boolean;
|
gateway_connected: boolean;
|
||||||
gif_auto_play: boolean;
|
gif_auto_play: boolean;
|
||||||
guild_folders: []; //need an example of this not empty
|
guild_folders: []; //need an example of this not empty
|
||||||
guild_positions: []; //need an example of this not empty
|
guild_positions: []; //need an example of this not empty
|
||||||
inline_attachment_media: boolean;
|
inline_attachment_media: boolean;
|
||||||
inline_embed_media: boolean;
|
inline_embed_media: boolean;
|
||||||
locale: string;
|
locale: string;
|
||||||
message_display_compact: boolean;
|
message_display_compact: boolean;
|
||||||
native_phone_integration_enabled: boolean;
|
native_phone_integration_enabled: boolean;
|
||||||
render_embeds: boolean;
|
render_embeds: boolean;
|
||||||
render_reactions: boolean;
|
render_reactions: boolean;
|
||||||
restricted_guilds: []; //need an example of this not empty
|
restricted_guilds: []; //need an example of this not empty
|
||||||
show_current_game: boolean;
|
show_current_game: boolean;
|
||||||
status: string;
|
status: string;
|
||||||
stream_notifications_enabled: boolean;
|
stream_notifications_enabled: boolean;
|
||||||
theme: string;
|
theme: string;
|
||||||
timezone_offset: number;
|
timezone_offset: number;
|
||||||
view_nsfw_guilds: boolean;
|
view_nsfw_guilds: boolean;
|
||||||
};
|
};
|
||||||
guilds: guildjson[];
|
guilds: guildjson[];
|
||||||
relationships: {
|
relationships: {
|
||||||
id: string;
|
id: string;
|
||||||
type: 0 | 1 | 2 | 3 | 4;
|
type: 0 | 1 | 2 | 3 | 4;
|
||||||
nickname: string | null;
|
nickname: string | null;
|
||||||
user: userjson;
|
user: userjson;
|
||||||
}[];
|
}[];
|
||||||
read_state: {
|
read_state: {
|
||||||
entries: {
|
entries: {
|
||||||
id: string;
|
id: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
last_message_id: string;
|
last_message_id: string;
|
||||||
last_pin_timestamp: string;
|
last_pin_timestamp: string;
|
||||||
mention_count: number; //in theory, the server doesn't actually send this as far as I'm aware
|
mention_count: number; //in theory, the server doesn't actually send this as far as I'm aware
|
||||||
}[];
|
}[];
|
||||||
partial: boolean;
|
partial: boolean;
|
||||||
version: number;
|
version: number;
|
||||||
};
|
};
|
||||||
user_guild_settings: {
|
user_guild_settings: {
|
||||||
entries: {
|
entries: {
|
||||||
channel_overrides: unknown[]; //will have to find example
|
channel_overrides: unknown[]; //will have to find example
|
||||||
message_notifications: number;
|
message_notifications: number;
|
||||||
flags: number;
|
flags: number;
|
||||||
hide_muted_channels: boolean;
|
hide_muted_channels: boolean;
|
||||||
mobile_push: boolean;
|
mobile_push: boolean;
|
||||||
mute_config: null;
|
mute_config: null;
|
||||||
mute_scheduled_events: boolean;
|
mute_scheduled_events: boolean;
|
||||||
muted: boolean;
|
muted: boolean;
|
||||||
notify_highlights: number;
|
notify_highlights: number;
|
||||||
suppress_everyone: boolean;
|
suppress_everyone: boolean;
|
||||||
suppress_roles: boolean;
|
suppress_roles: boolean;
|
||||||
version: number;
|
version: number;
|
||||||
guild_id: string;
|
guild_id: string;
|
||||||
}[];
|
}[];
|
||||||
partial: boolean;
|
partial: boolean;
|
||||||
version: number;
|
version: number;
|
||||||
};
|
};
|
||||||
private_channels: dirrectjson[];
|
private_channels: dirrectjson[];
|
||||||
session_id: string;
|
session_id: string;
|
||||||
country_code: string;
|
country_code: string;
|
||||||
users: userjson[];
|
users: userjson[];
|
||||||
merged_members: [memberjson][];
|
merged_members: [memberjson][];
|
||||||
sessions: {
|
sessions: {
|
||||||
active: boolean;
|
active: boolean;
|
||||||
activities: []; //will need to find example of this
|
activities: []; //will need to find example of this
|
||||||
client_info: {
|
client_info: {
|
||||||
version: number;
|
version: number;
|
||||||
};
|
};
|
||||||
session_id: string;
|
session_id: string;
|
||||||
status: string;
|
status: string;
|
||||||
}[];
|
}[];
|
||||||
resume_gateway_url: string;
|
resume_gateway_url: string;
|
||||||
consents: {
|
consents: {
|
||||||
personalization: {
|
personalization: {
|
||||||
consented: boolean;
|
consented: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
experiments: []; //not sure if I need to do this :P
|
experiments: []; //not sure if I need to do this :P
|
||||||
guild_join_requests: []; //need to get examples
|
guild_join_requests: []; //need to get examples
|
||||||
connected_accounts: []; //need to get examples
|
connected_accounts: []; //need to get examples
|
||||||
guild_experiments: []; //need to get examples
|
guild_experiments: []; //need to get examples
|
||||||
geo_ordered_rtc_regions: []; //need to get examples
|
geo_ordered_rtc_regions: []; //need to get examples
|
||||||
api_code_version: number;
|
api_code_version: number;
|
||||||
friend_suggestion_count: number;
|
friend_suggestion_count: number;
|
||||||
analytics_token: string;
|
analytics_token: string;
|
||||||
tutorial: boolean;
|
tutorial: boolean;
|
||||||
session_type: string;
|
session_type: string;
|
||||||
auth_session_id_hash: string;
|
auth_session_id_hash: string;
|
||||||
notification_settings: {
|
notification_settings: {
|
||||||
flags: number;
|
flags: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
type mainuserjson = userjson & {
|
type mainuserjson = userjson & {
|
||||||
flags: number;
|
flags: number;
|
||||||
mfa_enabled?: boolean;
|
mfa_enabled?: boolean;
|
||||||
email?: string;
|
email?: string;
|
||||||
phone?: string;
|
phone?: string;
|
||||||
verified: boolean;
|
verified: boolean;
|
||||||
nsfw_allowed: boolean;
|
nsfw_allowed: boolean;
|
||||||
premium: boolean;
|
premium: boolean;
|
||||||
purchased_flags: number;
|
purchased_flags: number;
|
||||||
premium_usage_flags: number;
|
premium_usage_flags: number;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
};
|
};
|
||||||
type userjson = {
|
type userjson = {
|
||||||
username: string;
|
username: string;
|
||||||
discriminator: string;
|
discriminator: string;
|
||||||
id: string;
|
id: string;
|
||||||
public_flags: number;
|
public_flags: number;
|
||||||
avatar: string | null;
|
avatar: string | null;
|
||||||
accent_color: number;
|
accent_color: number;
|
||||||
banner?: string;
|
banner?: string;
|
||||||
bio: string;
|
bio: string;
|
||||||
bot: boolean;
|
bot: boolean;
|
||||||
premium_since: string;
|
premium_since: string;
|
||||||
premium_type: number;
|
premium_type: number;
|
||||||
theme_colors: string;
|
theme_colors: string;
|
||||||
pronouns: string;
|
pronouns: string;
|
||||||
badge_ids: string[];
|
badge_ids: string[];
|
||||||
};
|
};
|
||||||
type memberjson = {
|
type memberjson = {
|
||||||
index?: number;
|
index?: number;
|
||||||
id: string;
|
id: string;
|
||||||
user: userjson | null;
|
user: userjson | null;
|
||||||
guild_id: string;
|
guild_id: string;
|
||||||
guild: {
|
guild: {
|
||||||
id: string;
|
id: string;
|
||||||
} | null;
|
} | null;
|
||||||
nick?: string;
|
nick?: string;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
joined_at: string;
|
joined_at: string;
|
||||||
premium_since: string;
|
premium_since: string;
|
||||||
deaf: boolean;
|
deaf: boolean;
|
||||||
mute: boolean;
|
mute: boolean;
|
||||||
pending: boolean;
|
pending: boolean;
|
||||||
last_message_id?: boolean; //What???
|
last_message_id?: boolean; //What???
|
||||||
};
|
};
|
||||||
type emojijson = {
|
type emojijson = {
|
||||||
name: string;
|
name: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
animated?: boolean;
|
animated?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type guildjson = {
|
type guildjson = {
|
||||||
application_command_counts: { [key: string]: number };
|
application_command_counts: { [key: string]: number };
|
||||||
channels: channeljson[];
|
channels: channeljson[];
|
||||||
data_mode: string;
|
data_mode: string;
|
||||||
emojis: emojijson[];
|
emojis: emojijson[];
|
||||||
guild_scheduled_events: [];
|
guild_scheduled_events: [];
|
||||||
id: string;
|
id: string;
|
||||||
large: boolean;
|
large: boolean;
|
||||||
lazy: boolean;
|
lazy: boolean;
|
||||||
member_count: number;
|
member_count: number;
|
||||||
premium_subscription_count: number;
|
premium_subscription_count: number;
|
||||||
properties: {
|
properties: {
|
||||||
region: string | null;
|
region: string | null;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
splash: string;
|
splash: string;
|
||||||
banner: string;
|
banner: string;
|
||||||
features: string[];
|
features: string[];
|
||||||
preferred_locale: string;
|
preferred_locale: string;
|
||||||
owner_id: string;
|
owner_id: string;
|
||||||
application_id: string;
|
application_id: string;
|
||||||
afk_channel_id: string;
|
afk_channel_id: string;
|
||||||
afk_timeout: number;
|
afk_timeout: number;
|
||||||
member_count: number;
|
member_count: number;
|
||||||
system_channel_id: string;
|
system_channel_id: string;
|
||||||
verification_level: number;
|
verification_level: number;
|
||||||
explicit_content_filter: number;
|
explicit_content_filter: number;
|
||||||
default_message_notifications: number;
|
default_message_notifications: number;
|
||||||
mfa_level: number;
|
mfa_level: number;
|
||||||
vanity_url_code: number;
|
vanity_url_code: number;
|
||||||
premium_tier: number;
|
premium_tier: number;
|
||||||
premium_progress_bar_enabled: boolean;
|
premium_progress_bar_enabled: boolean;
|
||||||
system_channel_flags: number;
|
system_channel_flags: number;
|
||||||
discovery_splash: string;
|
discovery_splash: string;
|
||||||
rules_channel_id: string;
|
rules_channel_id: string;
|
||||||
public_updates_channel_id: string;
|
public_updates_channel_id: string;
|
||||||
max_video_channel_users: number;
|
max_video_channel_users: number;
|
||||||
max_members: number;
|
max_members: number;
|
||||||
nsfw_level: number;
|
nsfw_level: number;
|
||||||
hub_type: null;
|
hub_type: null;
|
||||||
home_header: null;
|
home_header: null;
|
||||||
id: string;
|
id: string;
|
||||||
latest_onboarding_question_id: string;
|
latest_onboarding_question_id: string;
|
||||||
max_stage_video_channel_users: number;
|
max_stage_video_channel_users: number;
|
||||||
nsfw: boolean;
|
nsfw: boolean;
|
||||||
safety_alerts_channel_id: string;
|
safety_alerts_channel_id: string;
|
||||||
};
|
};
|
||||||
roles: rolesjson[];
|
roles: rolesjson[];
|
||||||
stage_instances: [];
|
stage_instances: [];
|
||||||
stickers: [];
|
stickers: [];
|
||||||
threads: [];
|
threads: [];
|
||||||
version: string;
|
version: string;
|
||||||
guild_hashes: {};
|
guild_hashes: {};
|
||||||
joined_at: string;
|
joined_at: string;
|
||||||
};
|
};
|
||||||
type startTypingjson = {
|
type startTypingjson = {
|
||||||
d: {
|
d: {
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
guild_id?: string;
|
guild_id?: string;
|
||||||
user_id: string;
|
user_id: string;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
member?: memberjson;
|
member?: memberjson;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
type channeljson = {
|
type channeljson = {
|
||||||
id: string;
|
id: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
name: string;
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
type: number;
|
type: number;
|
||||||
last_message_id: string;
|
last_message_id: string;
|
||||||
guild_id: string;
|
guild_id: string;
|
||||||
parent_id: string;
|
parent_id: string;
|
||||||
last_pin_timestamp: string;
|
last_pin_timestamp: string;
|
||||||
default_auto_archive_duration: number;
|
default_auto_archive_duration: number;
|
||||||
permission_overwrites: {
|
permission_overwrites: {
|
||||||
id: string;
|
id: string;
|
||||||
allow: string;
|
allow: string;
|
||||||
deny: string;
|
deny: string;
|
||||||
}[];
|
}[];
|
||||||
video_quality_mode: null;
|
video_quality_mode: null;
|
||||||
nsfw: boolean;
|
nsfw: boolean;
|
||||||
topic: string;
|
topic: string;
|
||||||
retention_policy_id: string;
|
retention_policy_id: string;
|
||||||
flags: number;
|
flags: number;
|
||||||
default_thread_rate_limit_per_user: number;
|
default_thread_rate_limit_per_user: number;
|
||||||
position: number;
|
position: number;
|
||||||
};
|
};
|
||||||
type rolesjson = {
|
type rolesjson = {
|
||||||
id: string;
|
id: string;
|
||||||
guild_id: string;
|
guild_id: string;
|
||||||
color: number;
|
color: number;
|
||||||
hoist: boolean;
|
hoist: boolean;
|
||||||
managed: boolean;
|
managed: boolean;
|
||||||
mentionable: boolean;
|
mentionable: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
permissions: string;
|
permissions: string;
|
||||||
position: number;
|
position: number;
|
||||||
icon: string;
|
icon: string;
|
||||||
unicode_emoji: string;
|
unicode_emoji: string;
|
||||||
flags: number;
|
flags: number;
|
||||||
};
|
};
|
||||||
type dirrectjson = {
|
type dirrectjson = {
|
||||||
id: string;
|
id: string;
|
||||||
flags: number;
|
flags: number;
|
||||||
last_message_id: string;
|
last_message_id: string;
|
||||||
type: number;
|
type: number;
|
||||||
recipients: userjson[];
|
recipients: userjson[];
|
||||||
is_spam: boolean;
|
is_spam: boolean;
|
||||||
};
|
};
|
||||||
type messagejson = {
|
type messagejson = {
|
||||||
id: string;
|
id: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
guild_id: string;
|
guild_id: string;
|
||||||
author: userjson;
|
author: userjson;
|
||||||
member?: memberjson;
|
member?: memberjson;
|
||||||
content: string;
|
content: string;
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
edited_timestamp: string;
|
edited_timestamp: string;
|
||||||
tts: boolean;
|
tts: boolean;
|
||||||
mention_everyone: boolean;
|
mention_everyone: boolean;
|
||||||
mentions: []; //need examples to fix
|
mentions: []; //need examples to fix
|
||||||
mention_roles: []; //need examples to fix
|
mention_roles: []; //need examples to fix
|
||||||
attachments: filejson[];
|
attachments: filejson[];
|
||||||
embeds: embedjson[];
|
embeds: embedjson[];
|
||||||
reactions: {
|
reactions: {
|
||||||
count: number;
|
count: number;
|
||||||
emoji: emojijson; //very likely needs expanding
|
emoji: emojijson; //very likely needs expanding
|
||||||
me: boolean;
|
me: boolean;
|
||||||
}[];
|
}[];
|
||||||
nonce: string;
|
nonce: string;
|
||||||
pinned: boolean;
|
pinned: boolean;
|
||||||
type: number;
|
type: number;
|
||||||
};
|
};
|
||||||
type filejson = {
|
type filejson = {
|
||||||
id: string;
|
id: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
content_type: string;
|
content_type: string;
|
||||||
width?: number;
|
width?: number;
|
||||||
height?: number;
|
height?: number;
|
||||||
proxy_url: string | undefined;
|
proxy_url: string | undefined;
|
||||||
url: string;
|
url: string;
|
||||||
size: number;
|
size: number;
|
||||||
};
|
};
|
||||||
type embedjson = {
|
type embedjson = {
|
||||||
type: string | null;
|
type: string | null;
|
||||||
color?: number;
|
color?: number;
|
||||||
author: {
|
author: {
|
||||||
icon_url?: string;
|
icon_url?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
};
|
};
|
||||||
title?: string;
|
title?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
fields?: {
|
fields?: {
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
inline: boolean;
|
inline: boolean;
|
||||||
}[];
|
}[];
|
||||||
footer?: {
|
footer?: {
|
||||||
icon_url?: string;
|
icon_url?: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
thumbnail?: string;
|
thumbnail?: string;
|
||||||
};
|
};
|
||||||
timestamp?: string;
|
timestamp?: string;
|
||||||
thumbnail: {
|
thumbnail: {
|
||||||
proxy_url: string;
|
proxy_url: string;
|
||||||
url: string;
|
url: string;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
provider: {
|
provider: {
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
video?: {
|
video?: {
|
||||||
url: string;
|
url: string;
|
||||||
width?: number | null;
|
width?: number | null;
|
||||||
height?: number | null;
|
height?: number | null;
|
||||||
proxy_url?: string;
|
proxy_url?: string;
|
||||||
};
|
};
|
||||||
invite?: {
|
invite?: {
|
||||||
url: string;
|
url: string;
|
||||||
code: string;
|
code: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
type invitejson = {
|
type invitejson = {
|
||||||
code: string;
|
code: string;
|
||||||
temporary: boolean;
|
temporary: boolean;
|
||||||
uses: number;
|
uses: number;
|
||||||
max_use: number;
|
max_use: number;
|
||||||
max_age: number;
|
max_age: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
expires_at: string;
|
expires_at: string;
|
||||||
guild_id: string;
|
guild_id: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
inviter_id: string;
|
inviter_id: string;
|
||||||
target_user_id: string | null;
|
target_user_id: string | null;
|
||||||
target_user_type: string | null;
|
target_user_type: string | null;
|
||||||
vanity_url: string | null;
|
vanity_url: string | null;
|
||||||
flags: number;
|
flags: number;
|
||||||
guild: guildjson["properties"];
|
guild: guildjson["properties"];
|
||||||
channel: channeljson;
|
channel: channeljson;
|
||||||
inviter: userjson;
|
inviter: userjson;
|
||||||
};
|
};
|
||||||
type presencejson = {
|
type presencejson = {
|
||||||
status: string;
|
status: string;
|
||||||
since: number | null;
|
since: number | null;
|
||||||
activities: any[]; //bit more complicated but not now
|
activities: any[]; //bit more complicated but not now
|
||||||
afk: boolean;
|
afk: boolean;
|
||||||
user?: userjson;
|
user?: userjson;
|
||||||
};
|
};
|
||||||
type messageCreateJson = {
|
type messageCreateJson = {
|
||||||
op: 0;
|
op: 0;
|
||||||
d: {
|
d: {
|
||||||
guild_id?: string;
|
guild_id?: string;
|
||||||
channel_id?: string;
|
channel_id?: string;
|
||||||
} & messagejson;
|
} & messagejson;
|
||||||
s: number;
|
s: number;
|
||||||
t: "MESSAGE_CREATE";
|
t: "MESSAGE_CREATE";
|
||||||
};
|
};
|
||||||
type wsjson =
|
type wsjson =
|
||||||
| {
|
| {
|
||||||
op: 0;
|
op: 0;
|
||||||
d: any;
|
d: any;
|
||||||
s: number;
|
s: number;
|
||||||
t:
|
t:
|
||||||
| "TYPING_START"
|
| "TYPING_START"
|
||||||
| "USER_UPDATE"
|
| "USER_UPDATE"
|
||||||
| "CHANNEL_UPDATE"
|
| "CHANNEL_UPDATE"
|
||||||
| "CHANNEL_CREATE"
|
| "CHANNEL_CREATE"
|
||||||
| "CHANNEL_DELETE"
|
| "CHANNEL_DELETE"
|
||||||
| "GUILD_DELETE"
|
| "GUILD_DELETE"
|
||||||
| "GUILD_CREATE"
|
| "GUILD_CREATE"
|
||||||
| "MESSAGE_REACTION_REMOVE_ALL"
|
| "MESSAGE_REACTION_REMOVE_ALL"
|
||||||
| "MESSAGE_REACTION_REMOVE_EMOJI";
|
| "MESSAGE_REACTION_REMOVE_EMOJI";
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
op: 0;
|
op: 0;
|
||||||
t: "GUILD_MEMBERS_CHUNK";
|
t: "GUILD_MEMBERS_CHUNK";
|
||||||
d: memberChunk;
|
d: memberChunk;
|
||||||
s: number;
|
s: number;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
op: 0;
|
op: 0;
|
||||||
d: {
|
d: {
|
||||||
id: string;
|
id: string;
|
||||||
guild_id?: string;
|
guild_id?: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
};
|
};
|
||||||
s: number;
|
s: number;
|
||||||
t: "MESSAGE_DELETE";
|
t: "MESSAGE_DELETE";
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
op: 0;
|
op: 0;
|
||||||
d: {
|
d: {
|
||||||
guild_id?: string;
|
guild_id?: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
} & messagejson;
|
} & messagejson;
|
||||||
s: number;
|
s: number;
|
||||||
t: "MESSAGE_UPDATE";
|
t: "MESSAGE_UPDATE";
|
||||||
}
|
}
|
||||||
| messageCreateJson
|
| messageCreateJson
|
||||||
| readyjson
|
| readyjson
|
||||||
| {
|
| {
|
||||||
op: 11;
|
op: 11;
|
||||||
s: undefined;
|
s: undefined;
|
||||||
d: {};
|
d: {};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
op: 10;
|
op: 10;
|
||||||
s: undefined;
|
s: undefined;
|
||||||
d: {
|
d: {
|
||||||
heartbeat_interval: number;
|
heartbeat_interval: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
op: 0;
|
op: 0;
|
||||||
t: "MESSAGE_REACTION_ADD";
|
t: "MESSAGE_REACTION_ADD";
|
||||||
d: {
|
d: {
|
||||||
user_id: string;
|
user_id: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
message_id: string;
|
message_id: string;
|
||||||
guild_id?: string;
|
guild_id?: string;
|
||||||
emoji: emojijson;
|
emoji: emojijson;
|
||||||
member?: memberjson;
|
member?: memberjson;
|
||||||
};
|
};
|
||||||
s: number;
|
s: number;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
op: 0;
|
op: 0;
|
||||||
t: "MESSAGE_REACTION_REMOVE";
|
t: "MESSAGE_REACTION_REMOVE";
|
||||||
d: {
|
d: {
|
||||||
user_id: string;
|
user_id: string;
|
||||||
channel_id: string;
|
channel_id: string;
|
||||||
message_id: string;
|
message_id: string;
|
||||||
guild_id: string;
|
guild_id: string;
|
||||||
emoji: emojijson;
|
emoji: emojijson;
|
||||||
};
|
};
|
||||||
s: 3;
|
s: 3;
|
||||||
};
|
};
|
||||||
type memberChunk = {
|
type memberChunk = {
|
||||||
guild_id: string;
|
guild_id: string;
|
||||||
nonce: string;
|
nonce: string;
|
||||||
members: memberjson[];
|
members: memberjson[];
|
||||||
presences: presencejson[];
|
presences: presencejson[];
|
||||||
chunk_index: number;
|
chunk_index: number;
|
||||||
chunk_count: number;
|
chunk_count: number;
|
||||||
not_found: string[];
|
not_found: string[];
|
||||||
};
|
};
|
||||||
export {
|
export {
|
||||||
readyjson,
|
readyjson,
|
||||||
dirrectjson,
|
dirrectjson,
|
||||||
startTypingjson,
|
startTypingjson,
|
||||||
channeljson,
|
channeljson,
|
||||||
guildjson,
|
guildjson,
|
||||||
rolesjson,
|
rolesjson,
|
||||||
userjson,
|
userjson,
|
||||||
memberjson,
|
memberjson,
|
||||||
mainuserjson,
|
mainuserjson,
|
||||||
messagejson,
|
messagejson,
|
||||||
filejson,
|
filejson,
|
||||||
embedjson,
|
embedjson,
|
||||||
emojijson,
|
emojijson,
|
||||||
presencejson,
|
presencejson,
|
||||||
wsjson,
|
wsjson,
|
||||||
messageCreateJson,
|
messageCreateJson,
|
||||||
memberChunk,
|
memberChunk,
|
||||||
invitejson,
|
invitejson,
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load diff
1180
src/webpage/login.ts
1180
src/webpage/login.ts
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -6,251 +6,251 @@ import { memberjson, presencejson } from "./jsontypes.js";
|
||||||
import { Dialog } from "./dialog.js";
|
import { Dialog } from "./dialog.js";
|
||||||
|
|
||||||
class Member extends SnowFlake {
|
class Member extends SnowFlake {
|
||||||
static already = {};
|
static already = {};
|
||||||
owner: Guild;
|
owner: Guild;
|
||||||
user: User;
|
user: User;
|
||||||
roles: Role[] = [];
|
roles: Role[] = [];
|
||||||
nick!: string;
|
nick!: string;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
|
|
||||||
private constructor(memberjson: memberjson, owner: Guild) {
|
private constructor(memberjson: memberjson, owner: Guild) {
|
||||||
super(memberjson.id);
|
super(memberjson.id);
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
if (this.localuser.userMap.has(memberjson.id)) {
|
if (this.localuser.userMap.has(memberjson.id)) {
|
||||||
this.user = this.localuser.userMap.get(memberjson.id) as User;
|
this.user = this.localuser.userMap.get(memberjson.id) as User;
|
||||||
} else if (memberjson.user) {
|
} else if (memberjson.user) {
|
||||||
this.user = new User(memberjson.user, owner.localuser);
|
this.user = new User(memberjson.user, owner.localuser);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Missing user object of this member");
|
throw new Error("Missing user object of this member");
|
||||||
}
|
|
||||||
|
|
||||||
for (const key of Object.keys(memberjson)) {
|
|
||||||
if (key === "guild" || key === "owner") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key === "roles") {
|
|
||||||
for (const strrole of memberjson.roles) {
|
|
||||||
const role = this.guild.roleids.get(strrole);
|
|
||||||
if (!role) continue;
|
|
||||||
this.roles.push(role);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
(this as any)[key] = (memberjson as any)[key];
|
|
||||||
}
|
|
||||||
if (this.localuser.userMap.has(this?.id)) {
|
|
||||||
this.user = this.localuser.userMap.get(this?.id) as User;
|
|
||||||
}
|
|
||||||
this.roles.sort((a, b) => {
|
|
||||||
return this.guild.roles.indexOf(a) - this.guild.roles.indexOf(b);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
get guild() {
|
|
||||||
return this.owner;
|
|
||||||
}
|
|
||||||
get localuser() {
|
|
||||||
return this.guild.localuser;
|
|
||||||
}
|
|
||||||
get info() {
|
|
||||||
return this.owner.info;
|
|
||||||
}
|
|
||||||
static async new(
|
|
||||||
memberjson: memberjson,
|
|
||||||
owner: Guild
|
|
||||||
): Promise<Member | undefined> {
|
|
||||||
let user: User;
|
|
||||||
if (owner.localuser.userMap.has(memberjson.id)) {
|
|
||||||
user = owner.localuser.userMap.get(memberjson.id) as User;
|
|
||||||
} else if (memberjson.user) {
|
|
||||||
user = new User(memberjson.user, owner.localuser);
|
|
||||||
} else {
|
|
||||||
throw new Error("missing user object of this member");
|
|
||||||
}
|
|
||||||
if (user.members.has(owner)) {
|
|
||||||
let memb = user.members.get(owner);
|
|
||||||
if (memb === undefined) {
|
|
||||||
memb = new Member(memberjson, owner);
|
|
||||||
user.members.set(owner, memb);
|
|
||||||
return memb;
|
|
||||||
} else if (memb instanceof Promise) {
|
|
||||||
return await memb; //I should do something else, though for now this is "good enough"
|
|
||||||
} else {
|
|
||||||
return memb;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const memb = new Member(memberjson, owner);
|
|
||||||
user.members.set(owner, memb);
|
|
||||||
return memb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static async resolveMember(
|
|
||||||
user: User,
|
|
||||||
guild: Guild
|
|
||||||
): Promise<Member | undefined> {
|
|
||||||
const maybe = user.members.get(guild);
|
|
||||||
if (!user.members.has(guild)) {
|
|
||||||
const membpromise = guild.localuser.resolvemember(user.id, guild.id);
|
|
||||||
const promise = new Promise<Member | undefined>(async (res) => {
|
|
||||||
const membjson = await membpromise;
|
|
||||||
if (membjson === undefined) {
|
|
||||||
return res(undefined);
|
|
||||||
} else {
|
|
||||||
const member = new Member(membjson, guild);
|
|
||||||
const map = guild.localuser.presences;
|
|
||||||
member.getPresence(map.get(member.id));
|
|
||||||
map.delete(member.id);
|
|
||||||
res(member);
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
user.members.set(guild, promise);
|
|
||||||
}
|
|
||||||
if (maybe instanceof Promise) {
|
|
||||||
return await maybe;
|
|
||||||
} else {
|
|
||||||
return maybe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public getPresence(presence: presencejson | undefined) {
|
|
||||||
this.user.getPresence(presence);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @todo
|
|
||||||
*/
|
|
||||||
highInfo() {
|
|
||||||
fetch(
|
|
||||||
this.info.api +
|
|
||||||
"/users/" +
|
|
||||||
this.id +
|
|
||||||
"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" +
|
|
||||||
this.guild.id,
|
|
||||||
{ headers: this.guild.headers }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
hasRole(ID: string) {
|
|
||||||
console.log(this.roles, ID);
|
|
||||||
for (const thing of this.roles) {
|
|
||||||
if (thing.id === ID) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
getColor() {
|
|
||||||
for (const thing of this.roles) {
|
|
||||||
const color = thing.getColor();
|
|
||||||
if (color) {
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
isAdmin() {
|
|
||||||
for (const role of this.roles) {
|
|
||||||
if (role.permissions.getPermission("ADMINISTRATOR")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.guild.properties.owner_id === this.user.id;
|
|
||||||
}
|
|
||||||
bind(html: HTMLElement) {
|
|
||||||
if (html.tagName === "SPAN") {
|
|
||||||
if (!this) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if(this.error){
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
html.style.color = this.getColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
//this.profileclick(html);
|
|
||||||
}
|
|
||||||
profileclick(/* html: HTMLElement */) {
|
|
||||||
//to be implemented
|
|
||||||
}
|
|
||||||
get name() {
|
|
||||||
return this.nick || this.user.username;
|
|
||||||
}
|
|
||||||
kick() {
|
|
||||||
let reason = "";
|
|
||||||
const menu = new Dialog([
|
|
||||||
"vdiv",
|
|
||||||
["title", "Kick " + this.name + " from " + this.guild.properties.name],
|
|
||||||
[
|
|
||||||
"textbox",
|
|
||||||
"Reason:",
|
|
||||||
"",
|
|
||||||
function (e: Event) {
|
|
||||||
reason = (e.target as HTMLInputElement).value;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"button",
|
|
||||||
"",
|
|
||||||
"submit",
|
|
||||||
() => {
|
|
||||||
this.kickAPI(reason);
|
|
||||||
menu.hide();
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
menu.show();
|
|
||||||
}
|
|
||||||
kickAPI(reason: string) {
|
|
||||||
const headers = structuredClone(this.guild.headers);
|
|
||||||
(headers as any)["x-audit-log-reason"] = reason;
|
|
||||||
fetch(`${this.info.api}/guilds/${this.guild.id}/members/${this.id}`, {
|
|
||||||
method: "DELETE",
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ban() {
|
|
||||||
let reason = "";
|
|
||||||
const menu = new Dialog([
|
|
||||||
"vdiv",
|
|
||||||
["title", "Ban " + this.name + " from " + this.guild.properties.name],
|
|
||||||
[
|
|
||||||
"textbox",
|
|
||||||
"Reason:",
|
|
||||||
"",
|
|
||||||
function (e: Event) {
|
|
||||||
reason = (e.target as HTMLInputElement).value;
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"button",
|
|
||||||
"",
|
|
||||||
"submit",
|
|
||||||
() => {
|
|
||||||
this.banAPI(reason);
|
|
||||||
menu.hide();
|
|
||||||
},
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
menu.show();
|
|
||||||
}
|
|
||||||
banAPI(reason: string) {
|
|
||||||
const headers = structuredClone(this.guild.headers);
|
|
||||||
(headers as any)["x-audit-log-reason"] = reason;
|
|
||||||
fetch(`${this.info.api}/guilds/${this.guild.id}/bans/${this.id}`, {
|
|
||||||
method: "PUT",
|
|
||||||
headers,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
hasPermission(name: string): boolean {
|
|
||||||
if (this.isAdmin()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (const thing of this.roles) {
|
|
||||||
if (thing.permissions.getPermission(name)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
export { Member };
|
|
||||||
|
for (const key of Object.keys(memberjson)) {
|
||||||
|
if (key === "guild" || key === "owner") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key === "roles") {
|
||||||
|
for (const strrole of memberjson.roles) {
|
||||||
|
const role = this.guild.roleids.get(strrole);
|
||||||
|
if (!role) continue;
|
||||||
|
this.roles.push(role);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(this as any)[key] = (memberjson as any)[key];
|
||||||
|
}
|
||||||
|
if (this.localuser.userMap.has(this?.id)) {
|
||||||
|
this.user = this.localuser.userMap.get(this?.id) as User;
|
||||||
|
}
|
||||||
|
this.roles.sort((a, b) => {
|
||||||
|
return this.guild.roles.indexOf(a) - this.guild.roles.indexOf(b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
get guild() {
|
||||||
|
return this.owner;
|
||||||
|
}
|
||||||
|
get localuser() {
|
||||||
|
return this.guild.localuser;
|
||||||
|
}
|
||||||
|
get info() {
|
||||||
|
return this.owner.info;
|
||||||
|
}
|
||||||
|
static async new(
|
||||||
|
memberjson: memberjson,
|
||||||
|
owner: Guild
|
||||||
|
): Promise<Member | undefined> {
|
||||||
|
let user: User;
|
||||||
|
if (owner.localuser.userMap.has(memberjson.id)) {
|
||||||
|
user = owner.localuser.userMap.get(memberjson.id) as User;
|
||||||
|
} else if (memberjson.user) {
|
||||||
|
user = new User(memberjson.user, owner.localuser);
|
||||||
|
} else {
|
||||||
|
throw new Error("missing user object of this member");
|
||||||
|
}
|
||||||
|
if (user.members.has(owner)) {
|
||||||
|
let memb = user.members.get(owner);
|
||||||
|
if (memb === undefined) {
|
||||||
|
memb = new Member(memberjson, owner);
|
||||||
|
user.members.set(owner, memb);
|
||||||
|
return memb;
|
||||||
|
} else if (memb instanceof Promise) {
|
||||||
|
return await memb; //I should do something else, though for now this is "good enough"
|
||||||
|
} else {
|
||||||
|
return memb;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const memb = new Member(memberjson, owner);
|
||||||
|
user.members.set(owner, memb);
|
||||||
|
return memb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static async resolveMember(
|
||||||
|
user: User,
|
||||||
|
guild: Guild
|
||||||
|
): Promise<Member | undefined> {
|
||||||
|
const maybe = user.members.get(guild);
|
||||||
|
if (!user.members.has(guild)) {
|
||||||
|
const membpromise = guild.localuser.resolvemember(user.id, guild.id);
|
||||||
|
const promise = new Promise<Member | undefined>(async (res) => {
|
||||||
|
const membjson = await membpromise;
|
||||||
|
if (membjson === undefined) {
|
||||||
|
return res(undefined);
|
||||||
|
} else {
|
||||||
|
const member = new Member(membjson, guild);
|
||||||
|
const map = guild.localuser.presences;
|
||||||
|
member.getPresence(map.get(member.id));
|
||||||
|
map.delete(member.id);
|
||||||
|
res(member);
|
||||||
|
return member;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
user.members.set(guild, promise);
|
||||||
|
}
|
||||||
|
if (maybe instanceof Promise) {
|
||||||
|
return await maybe;
|
||||||
|
} else {
|
||||||
|
return maybe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public getPresence(presence: presencejson | undefined) {
|
||||||
|
this.user.getPresence(presence);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @todo
|
||||||
|
*/
|
||||||
|
highInfo() {
|
||||||
|
fetch(
|
||||||
|
this.info.api +
|
||||||
|
"/users/" +
|
||||||
|
this.id +
|
||||||
|
"/profile?with_mutual_guilds=true&with_mutual_friends_count=true&guild_id=" +
|
||||||
|
this.guild.id,
|
||||||
|
{ headers: this.guild.headers }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
hasRole(ID: string) {
|
||||||
|
console.log(this.roles, ID);
|
||||||
|
for (const thing of this.roles) {
|
||||||
|
if (thing.id === ID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
getColor() {
|
||||||
|
for (const thing of this.roles) {
|
||||||
|
const color = thing.getColor();
|
||||||
|
if (color) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
isAdmin() {
|
||||||
|
for (const role of this.roles) {
|
||||||
|
if (role.permissions.getPermission("ADMINISTRATOR")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.guild.properties.owner_id === this.user.id;
|
||||||
|
}
|
||||||
|
bind(html: HTMLElement) {
|
||||||
|
if (html.tagName === "SPAN") {
|
||||||
|
if (!this) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if(this.error){
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
html.style.color = this.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
//this.profileclick(html);
|
||||||
|
}
|
||||||
|
profileclick(/* html: HTMLElement */) {
|
||||||
|
//to be implemented
|
||||||
|
}
|
||||||
|
get name() {
|
||||||
|
return this.nick || this.user.username;
|
||||||
|
}
|
||||||
|
kick() {
|
||||||
|
let reason = "";
|
||||||
|
const menu = new Dialog([
|
||||||
|
"vdiv",
|
||||||
|
["title", "Kick " + this.name + " from " + this.guild.properties.name],
|
||||||
|
[
|
||||||
|
"textbox",
|
||||||
|
"Reason:",
|
||||||
|
"",
|
||||||
|
function (e: Event) {
|
||||||
|
reason = (e.target as HTMLInputElement).value;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"button",
|
||||||
|
"",
|
||||||
|
"submit",
|
||||||
|
() => {
|
||||||
|
this.kickAPI(reason);
|
||||||
|
menu.hide();
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
menu.show();
|
||||||
|
}
|
||||||
|
kickAPI(reason: string) {
|
||||||
|
const headers = structuredClone(this.guild.headers);
|
||||||
|
(headers as any)["x-audit-log-reason"] = reason;
|
||||||
|
fetch(`${this.info.api}/guilds/${this.guild.id}/members/${this.id}`, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ban() {
|
||||||
|
let reason = "";
|
||||||
|
const menu = new Dialog([
|
||||||
|
"vdiv",
|
||||||
|
["title", "Ban " + this.name + " from " + this.guild.properties.name],
|
||||||
|
[
|
||||||
|
"textbox",
|
||||||
|
"Reason:",
|
||||||
|
"",
|
||||||
|
function (e: Event) {
|
||||||
|
reason = (e.target as HTMLInputElement).value;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"button",
|
||||||
|
"",
|
||||||
|
"submit",
|
||||||
|
() => {
|
||||||
|
this.banAPI(reason);
|
||||||
|
menu.hide();
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
menu.show();
|
||||||
|
}
|
||||||
|
banAPI(reason: string) {
|
||||||
|
const headers = structuredClone(this.guild.headers);
|
||||||
|
(headers as any)["x-audit-log-reason"] = reason;
|
||||||
|
fetch(`${this.info.api}/guilds/${this.guild.id}/bans/${this.id}`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
hasPermission(name: string): boolean {
|
||||||
|
if (this.isAdmin()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (const thing of this.roles) {
|
||||||
|
if (thing.permissions.getPermission(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export { Member };
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,347 +1,347 @@
|
||||||
class Permissions {
|
class Permissions {
|
||||||
allow: bigint;
|
allow: bigint;
|
||||||
deny: bigint;
|
deny: bigint;
|
||||||
readonly hasDeny: boolean;
|
readonly hasDeny: boolean;
|
||||||
constructor(allow: string, deny: string = "") {
|
constructor(allow: string, deny: string = "") {
|
||||||
this.hasDeny = Boolean(deny);
|
this.hasDeny = Boolean(deny);
|
||||||
try {
|
try {
|
||||||
this.allow = BigInt(allow);
|
this.allow = BigInt(allow);
|
||||||
this.deny = BigInt(deny);
|
this.deny = BigInt(deny);
|
||||||
} catch {
|
} catch {
|
||||||
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.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getPermissionbit(b: number, big: bigint): boolean {
|
getPermissionbit(b: number, big: bigint): boolean {
|
||||||
return Boolean((big >> BigInt(b)) & 1n);
|
return Boolean((big >> BigInt(b)) & 1n);
|
||||||
}
|
}
|
||||||
setPermissionbit(b: number, state: boolean, big: bigint): bigint {
|
setPermissionbit(b: number, state: boolean, big: bigint): bigint {
|
||||||
const bit = 1n << BigInt(b);
|
const bit = 1n << BigInt(b);
|
||||||
return (big & ~bit) | (BigInt(state) << BigInt(b)); //thanks to geotale for this code :3
|
return (big & ~bit) | (BigInt(state) << BigInt(b)); //thanks to geotale for this code :3
|
||||||
}
|
}
|
||||||
static map: {
|
static map: {
|
||||||
[key: number | string]:
|
[key: number | string]:
|
||||||
| { name: string; readableName: string; description: string }
|
| { name: string; readableName: string; description: string }
|
||||||
| number;
|
| number;
|
||||||
};
|
};
|
||||||
static info: { name: string; readableName: string; description: string }[];
|
static info: { name: string; readableName: string; description: string }[];
|
||||||
static makeMap() {
|
static makeMap() {
|
||||||
Permissions.info = [
|
Permissions.info = [
|
||||||
//for people in the future, do not reorder these, the creation of the map realize on the order
|
//for people in the future, do not reorder these, the creation of the map realize on the order
|
||||||
{
|
{
|
||||||
name: "CREATE_INSTANT_INVITE",
|
name: "CREATE_INSTANT_INVITE",
|
||||||
readableName: "Create invite",
|
readableName: "Create invite",
|
||||||
description: "Allows the user to create invites for the guild",
|
description: "Allows the user to create invites for the guild",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "KICK_MEMBERS",
|
name: "KICK_MEMBERS",
|
||||||
readableName: "Kick members",
|
readableName: "Kick members",
|
||||||
description: "Allows the user to kick members from the guild",
|
description: "Allows the user to kick members from the guild",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "BAN_MEMBERS",
|
name: "BAN_MEMBERS",
|
||||||
readableName: "Ban members",
|
readableName: "Ban members",
|
||||||
description: "Allows the user to ban members from the guild",
|
description: "Allows the user to ban members from the guild",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ADMINISTRATOR",
|
name: "ADMINISTRATOR",
|
||||||
readableName: "Administrator",
|
readableName: "Administrator",
|
||||||
description:
|
description:
|
||||||
"Allows all permissions and bypasses channel permission overwrites. This is a dangerous permission!",
|
"Allows all permissions and bypasses channel permission overwrites. This is a dangerous permission!",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MANAGE_CHANNELS",
|
name: "MANAGE_CHANNELS",
|
||||||
readableName: "Manage channels",
|
readableName: "Manage channels",
|
||||||
description: "Allows the user to manage and edit channels",
|
description: "Allows the user to manage and edit channels",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MANAGE_GUILD",
|
name: "MANAGE_GUILD",
|
||||||
readableName: "Manage guild",
|
readableName: "Manage guild",
|
||||||
description: "Allows management and editing of the guild",
|
description: "Allows management and editing of the guild",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ADD_REACTIONS",
|
name: "ADD_REACTIONS",
|
||||||
readableName: "Add reactions",
|
readableName: "Add reactions",
|
||||||
description: "Allows user to add reactions to messages",
|
description: "Allows user to add reactions to messages",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "VIEW_AUDIT_LOG",
|
name: "VIEW_AUDIT_LOG",
|
||||||
readableName: "View audit log",
|
readableName: "View audit log",
|
||||||
description: "Allows the user to view the audit log",
|
description: "Allows the user to view the audit log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PRIORITY_SPEAKER",
|
name: "PRIORITY_SPEAKER",
|
||||||
readableName: "Priority speaker",
|
readableName: "Priority speaker",
|
||||||
description: "Allows for using priority speaker in a voice channel",
|
description: "Allows for using priority speaker in a voice channel",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "STREAM",
|
name: "STREAM",
|
||||||
readableName: "Video",
|
readableName: "Video",
|
||||||
description: "Allows the user to stream",
|
description: "Allows the user to stream",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "VIEW_CHANNEL",
|
name: "VIEW_CHANNEL",
|
||||||
readableName: "View channels",
|
readableName: "View channels",
|
||||||
description: "Allows the user to view the channel",
|
description: "Allows the user to view the channel",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SEND_MESSAGES",
|
name: "SEND_MESSAGES",
|
||||||
readableName: "Send messages",
|
readableName: "Send messages",
|
||||||
description: "Allows user to send messages",
|
description: "Allows user to send messages",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SEND_TTS_MESSAGES",
|
name: "SEND_TTS_MESSAGES",
|
||||||
readableName: "Send text-to-speech messages",
|
readableName: "Send text-to-speech messages",
|
||||||
description: "Allows the user to send text-to-speech messages",
|
description: "Allows the user to send text-to-speech messages",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MANAGE_MESSAGES",
|
name: "MANAGE_MESSAGES",
|
||||||
readableName: "Manage messages",
|
readableName: "Manage messages",
|
||||||
description: "Allows the user to delete messages that aren't their own",
|
description: "Allows the user to delete messages that aren't their own",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "EMBED_LINKS",
|
name: "EMBED_LINKS",
|
||||||
readableName: "Embed links",
|
readableName: "Embed links",
|
||||||
description: "Allow links sent by this user to auto-embed",
|
description: "Allow links sent by this user to auto-embed",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ATTACH_FILES",
|
name: "ATTACH_FILES",
|
||||||
readableName: "Attach files",
|
readableName: "Attach files",
|
||||||
description: "Allows the user to attach files",
|
description: "Allows the user to attach files",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "READ_MESSAGE_HISTORY",
|
name: "READ_MESSAGE_HISTORY",
|
||||||
readableName: "Read message history",
|
readableName: "Read message history",
|
||||||
description: "Allows user to read the message history",
|
description: "Allows user to read the message history",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MENTION_EVERYONE",
|
name: "MENTION_EVERYONE",
|
||||||
readableName: "Mention @everyone, @here and all roles",
|
readableName: "Mention @everyone, @here and all roles",
|
||||||
description: "Allows the user to mention everyone",
|
description: "Allows the user to mention everyone",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "USE_EXTERNAL_EMOJIS",
|
name: "USE_EXTERNAL_EMOJIS",
|
||||||
readableName: "Use external emojis",
|
readableName: "Use external emojis",
|
||||||
description: "Allows the user to use external emojis",
|
description: "Allows the user to use external emojis",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "VIEW_GUILD_INSIGHTS",
|
name: "VIEW_GUILD_INSIGHTS",
|
||||||
readableName: "View guild insights",
|
readableName: "View guild insights",
|
||||||
description: "Allows the user to see guild insights",
|
description: "Allows the user to see guild insights",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CONNECT",
|
name: "CONNECT",
|
||||||
readableName: "Connect",
|
readableName: "Connect",
|
||||||
description: "Allows the user to connect to a voice channel",
|
description: "Allows the user to connect to a voice channel",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SPEAK",
|
name: "SPEAK",
|
||||||
readableName: "Speak",
|
readableName: "Speak",
|
||||||
description: "Allows the user to speak in a voice channel",
|
description: "Allows the user to speak in a voice channel",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MUTE_MEMBERS",
|
name: "MUTE_MEMBERS",
|
||||||
readableName: "Mute members",
|
readableName: "Mute members",
|
||||||
description: "Allows user to mute other members",
|
description: "Allows user to mute other members",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "DEAFEN_MEMBERS",
|
name: "DEAFEN_MEMBERS",
|
||||||
readableName: "Deafen members",
|
readableName: "Deafen members",
|
||||||
description: "Allows user to deafen other members",
|
description: "Allows user to deafen other members",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MOVE_MEMBERS",
|
name: "MOVE_MEMBERS",
|
||||||
readableName: "Move members",
|
readableName: "Move members",
|
||||||
description: "Allows the user to move members between voice channels",
|
description: "Allows the user to move members between voice channels",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "USE_VAD",
|
name: "USE_VAD",
|
||||||
readableName: "Use voice activity detection",
|
readableName: "Use voice activity detection",
|
||||||
description:
|
description:
|
||||||
"Allows users to speak in a voice channel by simply talking",
|
"Allows users to speak in a voice channel by simply talking",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CHANGE_NICKNAME",
|
name: "CHANGE_NICKNAME",
|
||||||
readableName: "Change nickname",
|
readableName: "Change nickname",
|
||||||
description: "Allows the user to change their own nickname",
|
description: "Allows the user to change their own nickname",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MANAGE_NICKNAMES",
|
name: "MANAGE_NICKNAMES",
|
||||||
readableName: "Manage nicknames",
|
readableName: "Manage nicknames",
|
||||||
description: "Allows user to change nicknames of other members",
|
description: "Allows user to change nicknames of other members",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MANAGE_ROLES",
|
name: "MANAGE_ROLES",
|
||||||
readableName: "Manage roles",
|
readableName: "Manage roles",
|
||||||
description: "Allows user to edit and manage roles",
|
description: "Allows user to edit and manage roles",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MANAGE_WEBHOOKS",
|
name: "MANAGE_WEBHOOKS",
|
||||||
readableName: "Manage webhooks",
|
readableName: "Manage webhooks",
|
||||||
description: "Allows management and editing of webhooks",
|
description: "Allows management and editing of webhooks",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MANAGE_GUILD_EXPRESSIONS",
|
name: "MANAGE_GUILD_EXPRESSIONS",
|
||||||
readableName: "Manage expressions",
|
readableName: "Manage expressions",
|
||||||
description: "Allows for managing emoji, stickers, and soundboards",
|
description: "Allows for managing emoji, stickers, and soundboards",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "USE_APPLICATION_COMMANDS",
|
name: "USE_APPLICATION_COMMANDS",
|
||||||
readableName: "Use application commands",
|
readableName: "Use application commands",
|
||||||
description: "Allows the user to use application commands",
|
description: "Allows the user to use application commands",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "REQUEST_TO_SPEAK",
|
name: "REQUEST_TO_SPEAK",
|
||||||
readableName: "Request to speak",
|
readableName: "Request to speak",
|
||||||
description: "Allows user to request to speak in stage channel",
|
description: "Allows user to request to speak in stage channel",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MANAGE_EVENTS",
|
name: "MANAGE_EVENTS",
|
||||||
readableName: "Manage events",
|
readableName: "Manage events",
|
||||||
description: "Allows user to edit and manage events",
|
description: "Allows user to edit and manage events",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MANAGE_THREADS",
|
name: "MANAGE_THREADS",
|
||||||
readableName: "Manage threads",
|
readableName: "Manage threads",
|
||||||
description:
|
description:
|
||||||
"Allows the user to delete and archive threads and view all private threads",
|
"Allows the user to delete and archive threads and view all private threads",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CREATE_PUBLIC_THREADS",
|
name: "CREATE_PUBLIC_THREADS",
|
||||||
readableName: "Create public threads",
|
readableName: "Create public threads",
|
||||||
description: "Allows the user to create public threads",
|
description: "Allows the user to create public threads",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CREATE_PRIVATE_THREADS",
|
name: "CREATE_PRIVATE_THREADS",
|
||||||
readableName: "Create private threads",
|
readableName: "Create private threads",
|
||||||
description: "Allows the user to create private threads",
|
description: "Allows the user to create private threads",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "USE_EXTERNAL_STICKERS",
|
name: "USE_EXTERNAL_STICKERS",
|
||||||
readableName: "Use external stickers",
|
readableName: "Use external stickers",
|
||||||
description: "Allows user to use external stickers",
|
description: "Allows user to use external stickers",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SEND_MESSAGES_IN_THREADS",
|
name: "SEND_MESSAGES_IN_THREADS",
|
||||||
readableName: "Send messages in threads",
|
readableName: "Send messages in threads",
|
||||||
description: "Allows the user to send messages in threads",
|
description: "Allows the user to send messages in threads",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "USE_EMBEDDED_ACTIVITIES",
|
name: "USE_EMBEDDED_ACTIVITIES",
|
||||||
readableName: "Use activities",
|
readableName: "Use activities",
|
||||||
description: "Allows the user to use embedded activities",
|
description: "Allows the user to use embedded activities",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MODERATE_MEMBERS",
|
name: "MODERATE_MEMBERS",
|
||||||
readableName: "Timeout members",
|
readableName: "Timeout members",
|
||||||
description:
|
description:
|
||||||
"Allows the user to time out other users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels",
|
"Allows the user to time out other users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "VIEW_CREATOR_MONETIZATION_ANALYTICS",
|
name: "VIEW_CREATOR_MONETIZATION_ANALYTICS",
|
||||||
readableName: "View creator monetization analytics",
|
readableName: "View creator monetization analytics",
|
||||||
description: "Allows for viewing role subscription insights",
|
description: "Allows for viewing role subscription insights",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "USE_SOUNDBOARD",
|
name: "USE_SOUNDBOARD",
|
||||||
readableName: "Use soundboard",
|
readableName: "Use soundboard",
|
||||||
description: "Allows for using soundboard in a voice channel",
|
description: "Allows for using soundboard in a voice channel",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CREATE_GUILD_EXPRESSIONS",
|
name: "CREATE_GUILD_EXPRESSIONS",
|
||||||
readableName: "Create expressions",
|
readableName: "Create expressions",
|
||||||
description:
|
description:
|
||||||
"Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user.",
|
"Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CREATE_EVENTS",
|
name: "CREATE_EVENTS",
|
||||||
readableName: "Create events",
|
readableName: "Create events",
|
||||||
description:
|
description:
|
||||||
"Allows for creating scheduled events, and editing and deleting those created by the current user.",
|
"Allows for creating scheduled events, and editing and deleting those created by the current user.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "USE_EXTERNAL_SOUNDS",
|
name: "USE_EXTERNAL_SOUNDS",
|
||||||
readableName: "Use external sounds",
|
readableName: "Use external sounds",
|
||||||
description:
|
description:
|
||||||
"Allows the usage of custom soundboard sounds from other servers",
|
"Allows the usage of custom soundboard sounds from other servers",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SEND_VOICE_MESSAGES",
|
name: "SEND_VOICE_MESSAGES",
|
||||||
readableName: "Send voice messages",
|
readableName: "Send voice messages",
|
||||||
description: "Allows sending voice messages",
|
description: "Allows sending voice messages",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SEND_POLLS",
|
name: "SEND_POLLS",
|
||||||
readableName: "Create polls",
|
readableName: "Create polls",
|
||||||
description: "Allows sending polls",
|
description: "Allows sending polls",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "USE_EXTERNAL_APPS",
|
name: "USE_EXTERNAL_APPS",
|
||||||
readableName: "Use external apps",
|
readableName: "Use external apps",
|
||||||
description:
|
description:
|
||||||
"Allows user-installed apps to send public responses. " +
|
"Allows user-installed apps to send public responses. " +
|
||||||
"When disabled, users will still be allowed to use their apps but the responses will be ephemeral. " +
|
"When disabled, users will still be allowed to use their apps but the responses will be ephemeral. " +
|
||||||
"This only applies to apps not also installed to the server.",
|
"This only applies to apps not also installed to the server.",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
Permissions.map = {};
|
Permissions.map = {};
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const thing of Permissions.info) {
|
for (const thing of Permissions.info) {
|
||||||
Permissions.map[i] = thing;
|
Permissions.map[i] = thing;
|
||||||
Permissions.map[thing.name] = i;
|
Permissions.map[thing.name] = i;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getPermission(name: string): number {
|
getPermission(name: string): number {
|
||||||
if (this.getPermissionbit(Permissions.map[name] as number, this.allow)) {
|
if (this.getPermissionbit(Permissions.map[name] as number, this.allow)) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (
|
} else if (
|
||||||
this.getPermissionbit(Permissions.map[name] as number, this.deny)
|
this.getPermissionbit(Permissions.map[name] as number, this.deny)
|
||||||
) {
|
) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hasPermission(name: string): boolean {
|
hasPermission(name: string): 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.map[name] as number, this.allow))
|
if (this.getPermissionbit(Permissions.map[name] as number, this.allow))
|
||||||
return true;
|
return true;
|
||||||
if (name != "ADMINISTRATOR") return this.hasPermission("ADMINISTRATOR");
|
if (name != "ADMINISTRATOR") return this.hasPermission("ADMINISTRATOR");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
setPermission(name: string, setto: number): void {
|
setPermission(name: string, setto: number): void {
|
||||||
const bit = Permissions.map[name] as number;
|
const bit = Permissions.map[name] as number;
|
||||||
if (!bit) {
|
if (!bit) {
|
||||||
return console.error(
|
return console.error(
|
||||||
"Tried to set permission to " +
|
"Tried to set permission to " +
|
||||||
setto +
|
setto +
|
||||||
" for " +
|
" for " +
|
||||||
name +
|
name +
|
||||||
" but it doesn't exist"
|
" but it doesn't exist"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setto === 0) {
|
if (setto === 0) {
|
||||||
this.deny = this.setPermissionbit(bit, false, this.deny);
|
this.deny = this.setPermissionbit(bit, false, this.deny);
|
||||||
this.allow = this.setPermissionbit(bit, false, this.allow);
|
this.allow = this.setPermissionbit(bit, false, this.allow);
|
||||||
} else if (setto === 1) {
|
} else if (setto === 1) {
|
||||||
this.deny = this.setPermissionbit(bit, false, this.deny);
|
this.deny = this.setPermissionbit(bit, false, this.deny);
|
||||||
this.allow = this.setPermissionbit(bit, true, this.allow);
|
this.allow = this.setPermissionbit(bit, true, this.allow);
|
||||||
} else if (setto === -1) {
|
} else if (setto === -1) {
|
||||||
this.deny = this.setPermissionbit(bit, true, this.deny);
|
this.deny = this.setPermissionbit(bit, true, this.deny);
|
||||||
this.allow = this.setPermissionbit(bit, false, this.allow);
|
this.allow = this.setPermissionbit(bit, false, this.allow);
|
||||||
} else {
|
} else {
|
||||||
console.error("invalid number entered:" + setto);
|
console.error("invalid number entered:" + setto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Permissions.makeMap();
|
Permissions.makeMap();
|
||||||
export { Permissions };
|
export { Permissions };
|
||||||
|
|
|
@ -2,149 +2,149 @@ import { checkInstance, adduser } from "./login.js";
|
||||||
|
|
||||||
const registerElement = document.getElementById("register");
|
const registerElement = document.getElementById("register");
|
||||||
if (registerElement) {
|
if (registerElement) {
|
||||||
registerElement.addEventListener("submit", registertry);
|
registerElement.addEventListener("submit", registertry);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
const confirmPassword = (elements[4] as HTMLInputElement).value;
|
const confirmPassword = (elements[4] as HTMLInputElement).value;
|
||||||
const dateofbirth = (elements[5] as HTMLInputElement).value;
|
const dateofbirth = (elements[5] as HTMLInputElement).value;
|
||||||
const consent = (elements[6] as HTMLInputElement).checked;
|
const consent = (elements[6] as HTMLInputElement).checked;
|
||||||
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 =
|
(document.getElementById("wrong") as HTMLElement).textContent =
|
||||||
"Passwords don't match";
|
"Passwords don't match";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const instanceInfo = JSON.parse(localStorage.getItem("instanceinfo") ?? "{}");
|
const instanceInfo = JSON.parse(localStorage.getItem("instanceinfo") ?? "{}");
|
||||||
const apiurl = new URL(instanceInfo.api);
|
const apiurl = new URL(instanceInfo.api);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(apiurl + "/auth/register", {
|
const response = await fetch(apiurl + "/auth/register", {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
date_of_birth: dateofbirth,
|
date_of_birth: dateofbirth,
|
||||||
email,
|
email,
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
consent,
|
consent,
|
||||||
captcha_key: captchaKey,
|
captcha_key: captchaKey,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.captcha_sitekey) {
|
if (data.captcha_sitekey) {
|
||||||
const capt = document.getElementById("h-captcha");
|
const capt = document.getElementById("h-captcha");
|
||||||
if (capt && !capt.children.length) {
|
if (capt && !capt.children.length) {
|
||||||
const capty = document.createElement("div");
|
const capty = document.createElement("div");
|
||||||
capty.classList.add("h-captcha");
|
capty.classList.add("h-captcha");
|
||||||
capty.setAttribute("data-sitekey", data.captcha_sitekey);
|
capty.setAttribute("data-sitekey", data.captcha_sitekey);
|
||||||
const script = document.createElement("script");
|
const script = document.createElement("script");
|
||||||
script.src = "https://js.hcaptcha.com/1/api.js";
|
script.src = "https://js.hcaptcha.com/1/api.js";
|
||||||
capt.append(script);
|
capt.append(script);
|
||||||
capt.append(capty);
|
capt.append(capty);
|
||||||
} else {
|
} else {
|
||||||
eval("hcaptcha.reset()");
|
eval("hcaptcha.reset()");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.token) {
|
if (!data.token) {
|
||||||
handleErrors(data.errors, elements);
|
handleErrors(data.errors, elements);
|
||||||
} else {
|
} else {
|
||||||
adduser({
|
adduser({
|
||||||
serverurls: instanceInfo,
|
serverurls: instanceInfo,
|
||||||
email,
|
email,
|
||||||
token: data.token,
|
token: data.token,
|
||||||
}).username = username;
|
}).username = username;
|
||||||
localStorage.setItem("token", data.token);
|
localStorage.setItem("token", data.token);
|
||||||
const redir = new URLSearchParams(window.location.search).get("goback");
|
const redir = new URLSearchParams(window.location.search).get("goback");
|
||||||
window.location.href = redir ? redir : "/channels/@me";
|
window.location.href = redir ? redir : "/channels/@me";
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Registration failed:", error);
|
console.error("Registration failed:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleErrors(errors: any, elements: HTMLFormControlsCollection) {
|
function handleErrors(errors: any, elements: HTMLFormControlsCollection) {
|
||||||
if (errors.consent) {
|
if (errors.consent) {
|
||||||
showError(elements[6] as HTMLElement, errors.consent._errors[0].message);
|
showError(elements[6] as HTMLElement, errors.consent._errors[0].message);
|
||||||
} else if (errors.password) {
|
} else if (errors.password) {
|
||||||
showError(
|
showError(
|
||||||
elements[3] as HTMLElement,
|
elements[3] as HTMLElement,
|
||||||
"Password: " + errors.password._errors[0].message
|
"Password: " + errors.password._errors[0].message
|
||||||
);
|
);
|
||||||
} else if (errors.username) {
|
} else if (errors.username) {
|
||||||
showError(
|
showError(
|
||||||
elements[2] as HTMLElement,
|
elements[2] as HTMLElement,
|
||||||
"Username: " + errors.username._errors[0].message
|
"Username: " + errors.username._errors[0].message
|
||||||
);
|
);
|
||||||
} else if (errors.email) {
|
} else if (errors.email) {
|
||||||
showError(
|
showError(
|
||||||
elements[1] as HTMLElement,
|
elements[1] as HTMLElement,
|
||||||
"Email: " + errors.email._errors[0].message
|
"Email: " + 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,
|
||||||
"Date of Birth: " + errors.date_of_birth._errors[0].message
|
"Date of Birth: " + errors.date_of_birth._errors[0].message
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
(document.getElementById("wrong") as HTMLElement).textContent =
|
(document.getElementById("wrong") as HTMLElement).textContent =
|
||||||
errors[Object.keys(errors)[0]]._errors[0].message;
|
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"
|
"suberror"
|
||||||
)[0] as HTMLElement;
|
)[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");
|
||||||
parent.append(div);
|
parent.append(div);
|
||||||
errorElement = div;
|
errorElement = div;
|
||||||
} else {
|
} else {
|
||||||
errorElement.classList.remove("suberror");
|
errorElement.classList.remove("suberror");
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
errorElement.classList.add("suberror");
|
errorElement.classList.add("suberror");
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
errorElement.textContent = message;
|
errorElement.textContent = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
let TOSa = document.getElementById("TOSa") as HTMLAnchorElement | null;
|
let TOSa = document.getElementById("TOSa") as HTMLAnchorElement | null;
|
||||||
|
|
||||||
async function tosLogic() {
|
async function tosLogic() {
|
||||||
const instanceInfo = JSON.parse(localStorage.getItem("instanceinfo") ?? "{}");
|
const instanceInfo = JSON.parse(localStorage.getItem("instanceinfo") ?? "{}");
|
||||||
const apiurl = new URL(instanceInfo.api);
|
const apiurl = new URL(instanceInfo.api);
|
||||||
const response = await fetch(apiurl.toString() + "/ping");
|
const response = await fetch(apiurl.toString() + "/ping");
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
const tosPage = data.instance.tosPage;
|
const tosPage = data.instance.tosPage;
|
||||||
|
|
||||||
if (tosPage) {
|
if (tosPage) {
|
||||||
document.getElementById("TOSbox")!.innerHTML =
|
document.getElementById("TOSbox")!.innerHTML =
|
||||||
'I agree to the <a href="" id="TOSa">Terms of Service</a>:';
|
'I agree to the <a href="" id="TOSa">Terms of Service</a>:';
|
||||||
TOSa = document.getElementById("TOSa") as HTMLAnchorElement;
|
TOSa = document.getElementById("TOSa") as HTMLAnchorElement;
|
||||||
TOSa.href = tosPage;
|
TOSa.href = tosPage;
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("TOSbox")!.textContent =
|
document.getElementById("TOSbox")!.textContent =
|
||||||
"This instance has no Terms of Service, accept ToS anyways:";
|
"This instance has no Terms of Service, accept ToS anyways:";
|
||||||
TOSa = null;
|
TOSa = null;
|
||||||
}
|
}
|
||||||
console.log(tosPage);
|
console.log(tosPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
tosLogic();
|
tosLogic();
|
||||||
|
|
|
@ -4,177 +4,177 @@ import { Guild } from "./guild.js";
|
||||||
import { SnowFlake } from "./snowflake.js";
|
import { SnowFlake } from "./snowflake.js";
|
||||||
import { rolesjson } from "./jsontypes.js";
|
import { rolesjson } from "./jsontypes.js";
|
||||||
class Role extends SnowFlake {
|
class Role extends SnowFlake {
|
||||||
permissions: Permissions;
|
permissions: Permissions;
|
||||||
owner: Guild;
|
owner: Guild;
|
||||||
color!: number;
|
color!: number;
|
||||||
name!: string;
|
name!: string;
|
||||||
info: Guild["info"];
|
info: Guild["info"];
|
||||||
hoist!: boolean;
|
hoist!: boolean;
|
||||||
icon!: string;
|
icon!: string;
|
||||||
mentionable!: boolean;
|
mentionable!: boolean;
|
||||||
unicode_emoji!: string;
|
unicode_emoji!: string;
|
||||||
headers: Guild["headers"];
|
headers: Guild["headers"];
|
||||||
constructor(json: rolesjson, owner: Guild) {
|
constructor(json: rolesjson, owner: Guild) {
|
||||||
super(json.id);
|
super(json.id);
|
||||||
this.headers = owner.headers;
|
this.headers = owner.headers;
|
||||||
this.info = owner.info;
|
this.info = owner.info;
|
||||||
for (const thing of Object.keys(json)) {
|
for (const thing of Object.keys(json)) {
|
||||||
if (thing === "id") {
|
if (thing === "id") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
(this as any)[thing] = (json as any)[thing];
|
(this as any)[thing] = (json as any)[thing];
|
||||||
}
|
}
|
||||||
this.permissions = new Permissions(json.permissions);
|
this.permissions = new Permissions(json.permissions);
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
get guild(): Guild {
|
get guild(): Guild {
|
||||||
return this.owner;
|
return this.owner;
|
||||||
}
|
}
|
||||||
get localuser(): Localuser {
|
get localuser(): Localuser {
|
||||||
return this.guild.localuser;
|
return this.guild.localuser;
|
||||||
}
|
}
|
||||||
getColor(): string | null {
|
getColor(): string | null {
|
||||||
if (this.color === 0) {
|
if (this.color === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return `#${this.color.toString(16)}`;
|
return `#${this.color.toString(16)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { Role };
|
export { Role };
|
||||||
import { Options } from "./settings.js";
|
import { Options } from "./settings.js";
|
||||||
class PermissionToggle implements OptionsElement<number> {
|
class PermissionToggle implements OptionsElement<number> {
|
||||||
readonly rolejson: {
|
readonly rolejson: {
|
||||||
name: string;
|
name: string;
|
||||||
readableName: string;
|
readableName: string;
|
||||||
description: string;
|
description: string;
|
||||||
};
|
};
|
||||||
permissions: Permissions;
|
permissions: Permissions;
|
||||||
owner: Options;
|
owner: Options;
|
||||||
value!: number;
|
value!: number;
|
||||||
constructor(
|
constructor(
|
||||||
roleJSON: PermissionToggle["rolejson"],
|
roleJSON: PermissionToggle["rolejson"],
|
||||||
permissions: Permissions,
|
permissions: Permissions,
|
||||||
owner: Options
|
owner: Options
|
||||||
) {
|
) {
|
||||||
this.rolejson = roleJSON;
|
this.rolejson = roleJSON;
|
||||||
this.permissions = permissions;
|
this.permissions = permissions;
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
}
|
}
|
||||||
watchForChange() {}
|
watchForChange() {}
|
||||||
generateHTML(): HTMLElement {
|
generateHTML(): HTMLElement {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("setting");
|
div.classList.add("setting");
|
||||||
const name = document.createElement("span");
|
const name = document.createElement("span");
|
||||||
name.textContent = this.rolejson.readableName;
|
name.textContent = this.rolejson.readableName;
|
||||||
name.classList.add("settingsname");
|
name.classList.add("settingsname");
|
||||||
div.append(name);
|
div.append(name);
|
||||||
|
|
||||||
div.append(this.generateCheckbox());
|
div.append(this.generateCheckbox());
|
||||||
const p = document.createElement("p");
|
const p = document.createElement("p");
|
||||||
p.textContent = this.rolejson.description;
|
p.textContent = this.rolejson.description;
|
||||||
div.appendChild(p);
|
div.appendChild(p);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
generateCheckbox(): HTMLElement {
|
generateCheckbox(): HTMLElement {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.classList.add("tritoggle");
|
div.classList.add("tritoggle");
|
||||||
const state = this.permissions.getPermission(this.rolejson.name);
|
const state = this.permissions.getPermission(this.rolejson.name);
|
||||||
|
|
||||||
const on = document.createElement("input");
|
const on = document.createElement("input");
|
||||||
on.type = "radio";
|
on.type = "radio";
|
||||||
on.name = this.rolejson.name;
|
on.name = this.rolejson.name;
|
||||||
div.append(on);
|
div.append(on);
|
||||||
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();
|
||||||
};
|
};
|
||||||
|
|
||||||
const no = document.createElement("input");
|
const no = document.createElement("input");
|
||||||
no.type = "radio";
|
no.type = "radio";
|
||||||
no.name = this.rolejson.name;
|
no.name = this.rolejson.name;
|
||||||
div.append(no);
|
div.append(no);
|
||||||
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();
|
||||||
};
|
};
|
||||||
if (this.permissions.hasDeny) {
|
if (this.permissions.hasDeny) {
|
||||||
const off = document.createElement("input");
|
const off = document.createElement("input");
|
||||||
off.type = "radio";
|
off.type = "radio";
|
||||||
off.name = this.rolejson.name;
|
off.name = this.rolejson.name;
|
||||||
div.append(off);
|
div.append(off);
|
||||||
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();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
submit() {}
|
submit() {}
|
||||||
}
|
}
|
||||||
import { OptionsElement, Buttons } from "./settings.js";
|
import { OptionsElement, Buttons } from "./settings.js";
|
||||||
class RoleList extends Buttons {
|
class RoleList extends Buttons {
|
||||||
readonly permissions: [Role, Permissions][];
|
readonly permissions: [Role, Permissions][];
|
||||||
permission: Permissions;
|
permission: Permissions;
|
||||||
readonly guild: Guild;
|
readonly guild: Guild;
|
||||||
readonly channel: boolean;
|
readonly channel: boolean;
|
||||||
declare readonly buttons: [string, string][];
|
declare readonly buttons: [string, string][];
|
||||||
readonly options: Options;
|
readonly options: Options;
|
||||||
onchange: Function;
|
onchange: Function;
|
||||||
curid!: string;
|
curid!: string;
|
||||||
constructor(
|
constructor(
|
||||||
permissions: [Role, Permissions][],
|
permissions: [Role, Permissions][],
|
||||||
guild: Guild,
|
guild: Guild,
|
||||||
onchange: Function,
|
onchange: Function,
|
||||||
channel = false
|
channel = false
|
||||||
) {
|
) {
|
||||||
super("Roles");
|
super("Roles");
|
||||||
this.guild = guild;
|
this.guild = guild;
|
||||||
this.permissions = permissions;
|
this.permissions = permissions;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
this.onchange = onchange;
|
this.onchange = onchange;
|
||||||
const options = new Options("", this);
|
const options = new Options("", this);
|
||||||
if (channel) {
|
if (channel) {
|
||||||
this.permission = new Permissions("0", "0");
|
this.permission = new Permissions("0", "0");
|
||||||
} else {
|
} else {
|
||||||
this.permission = new Permissions("0");
|
this.permission = new Permissions("0");
|
||||||
}
|
}
|
||||||
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) {
|
||||||
console.log(i);
|
console.log(i);
|
||||||
this.buttons.push([i[0].name, i[0].id]);
|
this.buttons.push([i[0].name, i[0].id]);
|
||||||
}
|
}
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.options.generateHTML();
|
return this.options.generateHTML();
|
||||||
}
|
}
|
||||||
save() {
|
save() {
|
||||||
this.onchange(this.curid, this.permission);
|
this.onchange(this.curid, this.permission);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { RoleList };
|
export { RoleList };
|
||||||
|
|
|
@ -1,96 +1,96 @@
|
||||||
function deleteoldcache() {
|
function deleteoldcache() {
|
||||||
caches.delete("cache");
|
caches.delete("cache");
|
||||||
console.log("this ran :P");
|
console.log("this ran :P");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function putInCache(request: URL | RequestInfo, response: Response) {
|
async function putInCache(request: URL | RequestInfo, response: Response) {
|
||||||
console.log(request, response);
|
console.log(request, response);
|
||||||
const cache = await caches.open("cache");
|
const cache = await caches.open("cache");
|
||||||
console.log("Grabbed");
|
console.log("Grabbed");
|
||||||
try {
|
try {
|
||||||
console.log(await cache.put(request, response));
|
console.log(await cache.put(request, response));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("test");
|
console.log("test");
|
||||||
|
|
||||||
let lastcache: string;
|
let lastcache: string;
|
||||||
self.addEventListener("activate", async () => {
|
self.addEventListener("activate", async () => {
|
||||||
console.log("test2");
|
console.log("test2");
|
||||||
checkCache();
|
checkCache();
|
||||||
});
|
});
|
||||||
async function checkCache() {
|
async function checkCache() {
|
||||||
if (checkedrecently) {
|
if (checkedrecently) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const promise = await caches.match("/getupdates");
|
const promise = await caches.match("/getupdates");
|
||||||
if (promise) {
|
if (promise) {
|
||||||
lastcache = await promise.text();
|
lastcache = await promise.text();
|
||||||
}
|
}
|
||||||
console.log(lastcache);
|
console.log(lastcache);
|
||||||
fetch("/getupdates").then(async (data) => {
|
fetch("/getupdates").then(async (data) => {
|
||||||
const text = await data.clone().text();
|
const text = await data.clone().text();
|
||||||
console.log(text, lastcache);
|
console.log(text, lastcache);
|
||||||
if (lastcache !== text) {
|
if (lastcache !== text) {
|
||||||
deleteoldcache();
|
deleteoldcache();
|
||||||
putInCache("/getupdates", data.clone());
|
putInCache("/getupdates", data.clone());
|
||||||
}
|
}
|
||||||
checkedrecently = true;
|
checkedrecently = true;
|
||||||
setTimeout((_: any) => {
|
setTimeout((_: any) => {
|
||||||
checkedrecently = false;
|
checkedrecently = false;
|
||||||
}, 1000 * 60 * 30);
|
}, 1000 * 60 * 30);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var checkedrecently = false;
|
var checkedrecently = false;
|
||||||
function samedomain(url: string | URL) {
|
function samedomain(url: string | URL) {
|
||||||
return new URL(url).origin === self.origin;
|
return new URL(url).origin === self.origin;
|
||||||
}
|
}
|
||||||
function isindexhtml(url: string | URL) {
|
function isindexhtml(url: string | URL) {
|
||||||
console.log(url);
|
console.log(url);
|
||||||
if (new URL(url).pathname.startsWith("/channels")) {
|
if (new URL(url).pathname.startsWith("/channels")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
async function getfile(event: {
|
async function getfile(event: {
|
||||||
request: { url: URL | RequestInfo; clone: () => string | URL | Request };
|
request: { url: URL | RequestInfo; clone: () => string | URL | Request };
|
||||||
}) {
|
}) {
|
||||||
checkCache();
|
checkCache();
|
||||||
if (!samedomain(event.request.url.toString())) {
|
if (!samedomain(event.request.url.toString())) {
|
||||||
return await fetch(event.request.clone());
|
return await fetch(event.request.clone());
|
||||||
}
|
}
|
||||||
const responseFromCache = await caches.match(event.request.url);
|
const responseFromCache = await caches.match(event.request.url);
|
||||||
console.log(responseFromCache, caches);
|
console.log(responseFromCache, caches);
|
||||||
if (responseFromCache) {
|
if (responseFromCache) {
|
||||||
console.log("cache hit");
|
console.log("cache hit");
|
||||||
return responseFromCache;
|
return responseFromCache;
|
||||||
}
|
}
|
||||||
if (isindexhtml(event.request.url.toString())) {
|
if (isindexhtml(event.request.url.toString())) {
|
||||||
console.log("is index.html");
|
console.log("is index.html");
|
||||||
const responseFromCache = await caches.match("/index.html");
|
const responseFromCache = await caches.match("/index.html");
|
||||||
if (responseFromCache) {
|
if (responseFromCache) {
|
||||||
console.log("cache hit");
|
console.log("cache hit");
|
||||||
return responseFromCache;
|
return responseFromCache;
|
||||||
}
|
}
|
||||||
const responseFromNetwork = await fetch("/index.html");
|
const responseFromNetwork = await fetch("/index.html");
|
||||||
await putInCache("/index.html", responseFromNetwork.clone());
|
await putInCache("/index.html", responseFromNetwork.clone());
|
||||||
return responseFromNetwork;
|
return responseFromNetwork;
|
||||||
}
|
}
|
||||||
const responseFromNetwork = await fetch(event.request.clone());
|
const responseFromNetwork = await fetch(event.request.clone());
|
||||||
console.log(event.request.clone());
|
console.log(event.request.clone());
|
||||||
await putInCache(event.request.clone(), responseFromNetwork.clone());
|
await putInCache(event.request.clone(), responseFromNetwork.clone());
|
||||||
try {
|
try {
|
||||||
return responseFromNetwork;
|
return responseFromNetwork;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.addEventListener("fetch", (event: any) => {
|
self.addEventListener("fetch", (event: any) => {
|
||||||
try {
|
try {
|
||||||
event.respondWith(getfile(event));
|
event.respondWith(getfile(event));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,20 +1,20 @@
|
||||||
abstract class SnowFlake {
|
abstract class SnowFlake {
|
||||||
public readonly id: string;
|
public readonly id: string;
|
||||||
constructor(id: string) {
|
constructor(id: string) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
getUnixTime(): number {
|
getUnixTime(): number {
|
||||||
return SnowFlake.stringToUnixTime(this.id);
|
return SnowFlake.stringToUnixTime(this.id);
|
||||||
}
|
}
|
||||||
static stringToUnixTime(str: string) {
|
static stringToUnixTime(str: string) {
|
||||||
try {
|
try {
|
||||||
return Number((BigInt(str) >> 22n) + 1420070400000n);
|
return Number((BigInt(str) >> 22n) + 1420070400000n);
|
||||||
} catch {
|
} catch {
|
||||||
console.error(
|
console.error(
|
||||||
`The ID is corrupted, it's ${str} when it should be some number.`
|
`The ID is corrupted, it's ${str} when it should be some number.`
|
||||||
);
|
);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { SnowFlake };
|
export { SnowFlake };
|
||||||
|
|
|
@ -7,483 +7,483 @@ import { SnowFlake } from "./snowflake.js";
|
||||||
import { presencejson, userjson } from "./jsontypes.js";
|
import { presencejson, userjson } from "./jsontypes.js";
|
||||||
|
|
||||||
class User extends SnowFlake {
|
class User extends SnowFlake {
|
||||||
owner: Localuser;
|
owner: Localuser;
|
||||||
hypotheticalpfp!: boolean;
|
hypotheticalpfp!: boolean;
|
||||||
avatar!: string | null;
|
avatar!: string | null;
|
||||||
username!: string;
|
username!: string;
|
||||||
nickname: string | null = null;
|
nickname: string | null = null;
|
||||||
relationshipType: 0 | 1 | 2 | 3 | 4 = 0;
|
relationshipType: 0 | 1 | 2 | 3 | 4 = 0;
|
||||||
bio!: MarkDown;
|
bio!: MarkDown;
|
||||||
discriminator!: string;
|
discriminator!: string;
|
||||||
pronouns!: string;
|
pronouns!: string;
|
||||||
bot!: boolean;
|
bot!: boolean;
|
||||||
public_flags!: number;
|
public_flags!: number;
|
||||||
accent_color!: number;
|
accent_color!: number;
|
||||||
banner: string | undefined;
|
banner: string | undefined;
|
||||||
hypotheticalbanner!: boolean;
|
hypotheticalbanner!: boolean;
|
||||||
premium_since!: string;
|
premium_since!: string;
|
||||||
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();
|
||||||
private status!: string;
|
private status!: string;
|
||||||
resolving: false | Promise<any> = false;
|
resolving: false | Promise<any> = false;
|
||||||
|
|
||||||
constructor(userjson: userjson, owner: Localuser, dontclone = false) {
|
constructor(userjson: userjson, owner: Localuser, dontclone = false) {
|
||||||
super(userjson.id);
|
super(userjson.id);
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
if (!owner) {
|
if (!owner) {
|
||||||
console.error("missing localuser");
|
console.error("missing localuser");
|
||||||
}
|
}
|
||||||
if (dontclone) {
|
if (dontclone) {
|
||||||
for (const key of Object.keys(userjson)) {
|
for (const key of Object.keys(userjson)) {
|
||||||
if (key === "bio") {
|
if (key === "bio") {
|
||||||
this.bio = new MarkDown(userjson[key], this.localuser);
|
this.bio = new MarkDown(userjson[key], this.localuser);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (key === "id") {
|
if (key === "id") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
(this as any)[key] = (userjson as any)[key];
|
(this as any)[key] = (userjson as any)[key];
|
||||||
}
|
}
|
||||||
this.hypotheticalpfp = false;
|
this.hypotheticalpfp = false;
|
||||||
} else {
|
} else {
|
||||||
return User.checkuser(userjson, owner);
|
return User.checkuser(userjson, owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clone(): User {
|
clone(): User {
|
||||||
return new User(
|
return new User(
|
||||||
{
|
{
|
||||||
username: this.username,
|
username: this.username,
|
||||||
id: this.id + "#clone",
|
id: this.id + "#clone",
|
||||||
public_flags: this.public_flags,
|
public_flags: this.public_flags,
|
||||||
discriminator: this.discriminator,
|
discriminator: this.discriminator,
|
||||||
avatar: this.avatar,
|
avatar: this.avatar,
|
||||||
accent_color: this.accent_color,
|
accent_color: this.accent_color,
|
||||||
banner: this.banner,
|
banner: this.banner,
|
||||||
bio: this.bio.rawString,
|
bio: this.bio.rawString,
|
||||||
premium_since: this.premium_since,
|
premium_since: this.premium_since,
|
||||||
premium_type: this.premium_type,
|
premium_type: this.premium_type,
|
||||||
bot: this.bot,
|
bot: this.bot,
|
||||||
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,
|
||||||
},
|
},
|
||||||
this.owner
|
this.owner
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPresence(presence: presencejson | undefined): void {
|
public getPresence(presence: presencejson | undefined): void {
|
||||||
if (presence) {
|
if (presence) {
|
||||||
this.setstatus(presence.status);
|
this.setstatus(presence.status);
|
||||||
} else {
|
} else {
|
||||||
this.setstatus("offline");
|
this.setstatus("offline");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setstatus(status: string): void {
|
setstatus(status: string): void {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStatus(): Promise<string> {
|
async getStatus(): Promise<string> {
|
||||||
return this.status || "offline";
|
return this.status || "offline";
|
||||||
}
|
}
|
||||||
|
|
||||||
static contextmenu = new Contextmenu<User, Member | undefined>("User Menu");
|
static contextmenu = new Contextmenu<User, Member | undefined>("User Menu");
|
||||||
|
|
||||||
static setUpContextMenu(): void {
|
static setUpContextMenu(): void {
|
||||||
this.contextmenu.addbutton("Copy user id", function (this: User) {
|
this.contextmenu.addbutton("Copy user id", function (this: User) {
|
||||||
navigator.clipboard.writeText(this.id);
|
navigator.clipboard.writeText(this.id);
|
||||||
});
|
});
|
||||||
this.contextmenu.addbutton("Message user", function (this: User) {
|
this.contextmenu.addbutton("Message user", function (this: User) {
|
||||||
fetch(this.info.api + "/users/@me/channels", {
|
fetch(this.info.api + "/users/@me/channels", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
"Block user",
|
"Block user",
|
||||||
function (this: User) {
|
function (this: User) {
|
||||||
this.block();
|
this.block();
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
function () {
|
function () {
|
||||||
return this.relationshipType !== 2;
|
return this.relationshipType !== 2;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
"Unblock user",
|
"Unblock user",
|
||||||
function (this: User) {
|
function (this: User) {
|
||||||
this.unblock();
|
this.unblock();
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
function () {
|
function () {
|
||||||
return this.relationshipType === 2;
|
return this.relationshipType === 2;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.contextmenu.addbutton("Friend request", function (this: User) {
|
this.contextmenu.addbutton("Friend request", function (this: User) {
|
||||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: this.owner.headers,
|
headers: this.owner.headers,
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
type: 1,
|
type: 1,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
"Kick member",
|
"Kick member",
|
||||||
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) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (member.id === member.guild.properties.owner_id) {
|
if (member.id === member.guild.properties.owner_id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return us.hasPermission("KICK_MEMBERS") || false;
|
return us.hasPermission("KICK_MEMBERS") || false;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.contextmenu.addbutton(
|
this.contextmenu.addbutton(
|
||||||
"Ban member",
|
"Ban member",
|
||||||
function (this: User, member: Member | undefined) {
|
function (this: User, member: Member | undefined) {
|
||||||
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) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (member.id === member.guild.properties.owner_id) {
|
if (member.id === member.guild.properties.owner_id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return us.hasPermission("BAN_MEMBERS") || false;
|
return us.hasPermission("BAN_MEMBERS") || false;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static checkuser(user: User | userjson, owner: Localuser): User {
|
static checkuser(user: User | userjson, owner: Localuser): User {
|
||||||
if (owner.userMap.has(user.id)) {
|
if (owner.userMap.has(user.id)) {
|
||||||
return owner.userMap.get(user.id) as User;
|
return owner.userMap.get(user.id) as User;
|
||||||
} else {
|
} else {
|
||||||
const tempuser = new User(user as userjson, owner, true);
|
const tempuser = new User(user as userjson, owner, true);
|
||||||
owner.userMap.set(user.id, tempuser);
|
owner.userMap.set(user.id, tempuser);
|
||||||
return tempuser;
|
return tempuser;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get info() {
|
get info() {
|
||||||
return this.owner.info;
|
return this.owner.info;
|
||||||
}
|
}
|
||||||
|
|
||||||
get localuser() {
|
get localuser() {
|
||||||
return this.owner;
|
return this.owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
return this.username;
|
return this.username;
|
||||||
}
|
}
|
||||||
|
|
||||||
async resolvemember(guild: Guild): Promise<Member | undefined> {
|
async resolvemember(guild: Guild): Promise<Member | undefined> {
|
||||||
return await Member.resolveMember(this, guild);
|
return await Member.resolveMember(this, guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserProfile(): Promise<any> {
|
async getUserProfile(): Promise<any> {
|
||||||
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> {
|
||||||
if (this.localuser.badges.has(id)) {
|
if (this.localuser.badges.has(id)) {
|
||||||
return this.localuser.badges.get(id);
|
return this.localuser.badges.get(id);
|
||||||
} else {
|
} else {
|
||||||
if (this.resolving) {
|
if (this.resolving) {
|
||||||
await this.resolving;
|
await this.resolving;
|
||||||
return this.localuser.badges.get(id);
|
return this.localuser.badges.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const prom = await this.getUserProfile();
|
const prom = await this.getUserProfile();
|
||||||
this.resolving = prom;
|
this.resolving = prom;
|
||||||
const badges = prom.badges;
|
const badges = prom.badges;
|
||||||
this.resolving = false;
|
this.resolving = false;
|
||||||
for (const badge of badges) {
|
for (const badge of badges) {
|
||||||
this.localuser.badges.set(badge.id, badge);
|
this.localuser.badges.set(badge.id, badge);
|
||||||
}
|
}
|
||||||
return this.localuser.badges.get(id);
|
return this.localuser.badges.get(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildpfp(): HTMLImageElement {
|
buildpfp(): HTMLImageElement {
|
||||||
const pfp = document.createElement("img");
|
const pfp = document.createElement("img");
|
||||||
pfp.loading = "lazy";
|
pfp.loading = "lazy";
|
||||||
pfp.src = this.getpfpsrc();
|
pfp.src = this.getpfpsrc();
|
||||||
pfp.classList.add("pfp");
|
pfp.classList.add("pfp");
|
||||||
pfp.classList.add("userid:" + this.id);
|
pfp.classList.add("userid:" + this.id);
|
||||||
return pfp;
|
return pfp;
|
||||||
}
|
}
|
||||||
|
|
||||||
async buildstatuspfp(): Promise<HTMLDivElement> {
|
async buildstatuspfp(): Promise<HTMLDivElement> {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.style.position = "relative";
|
div.style.position = "relative";
|
||||||
const pfp = this.buildpfp();
|
const pfp = this.buildpfp();
|
||||||
div.append(pfp);
|
div.append(pfp);
|
||||||
const status = document.createElement("div");
|
const status = document.createElement("div");
|
||||||
status.classList.add("statusDiv");
|
status.classList.add("statusDiv");
|
||||||
switch (await this.getStatus()) {
|
switch (await this.getStatus()) {
|
||||||
case "offline":
|
case "offline":
|
||||||
status.classList.add("offlinestatus");
|
status.classList.add("offlinestatus");
|
||||||
break;
|
break;
|
||||||
case "online":
|
case "online":
|
||||||
default:
|
default:
|
||||||
status.classList.add("onlinestatus");
|
status.classList.add("onlinestatus");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
div.append(status);
|
div.append(status);
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
userupdate(json: userjson): void {
|
userupdate(json: userjson): void {
|
||||||
if (json.avatar !== this.avatar) {
|
if (json.avatar !== this.avatar) {
|
||||||
this.changepfp(json.avatar);
|
this.changepfp(json.avatar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
||||||
errorSpan.textContent = "!";
|
errorSpan.textContent = "!";
|
||||||
errorSpan.classList.add("membererror");
|
errorSpan.classList.add("membererror");
|
||||||
html.after(errorSpan);
|
html.after(errorSpan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (member) {
|
if (member) {
|
||||||
member.bind(html);
|
member.bind(html);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (guild) {
|
if (guild) {
|
||||||
this.profileclick(html, guild);
|
this.profileclick(html, guild);
|
||||||
} else {
|
} else {
|
||||||
this.profileclick(html);
|
this.profileclick(html);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, localuser);
|
return new User(json, localuser);
|
||||||
}
|
}
|
||||||
|
|
||||||
changepfp(update: string | null): void {
|
changepfp(update: string | null): void {
|
||||||
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;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
block(): void {
|
block(): void {
|
||||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: this.owner.headers,
|
headers: this.owner.headers,
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
type: 2,
|
type: 2,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
this.relationshipType = 2;
|
this.relationshipType = 2;
|
||||||
const channel = this.localuser.channelfocus;
|
const channel = this.localuser.channelfocus;
|
||||||
if (channel) {
|
if (channel) {
|
||||||
for (const message of channel.messages) {
|
for (const message of channel.messages) {
|
||||||
message[1].generateMessage();
|
message[1].generateMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unblock(): void {
|
unblock(): void {
|
||||||
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
headers: this.owner.headers,
|
headers: this.owner.headers,
|
||||||
});
|
});
|
||||||
this.relationshipType = 0;
|
this.relationshipType = 0;
|
||||||
const channel = this.localuser.channelfocus;
|
const channel = this.localuser.channelfocus;
|
||||||
if (channel) {
|
if (channel) {
|
||||||
for (const message of channel.messages) {
|
for (const message of channel.messages) {
|
||||||
message[1].generateMessage();
|
message[1].generateMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getpfpsrc(): string {
|
getpfpsrc(): string {
|
||||||
if (this.hypotheticalpfp && this.avatar) {
|
if (this.hypotheticalpfp && this.avatar) {
|
||||||
return this.avatar;
|
return this.avatar;
|
||||||
}
|
}
|
||||||
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
|
this.avatar
|
||||||
}.png`;
|
}.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`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async buildprofile(
|
async buildprofile(
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
guild: Guild | null = null
|
guild: Guild | null = null
|
||||||
): Promise<HTMLDivElement> {
|
): Promise<HTMLDivElement> {
|
||||||
if (Contextmenu.currentmenu != "") {
|
if (Contextmenu.currentmenu != "") {
|
||||||
Contextmenu.currentmenu.remove();
|
Contextmenu.currentmenu.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
||||||
}
|
}
|
||||||
if (this.banner) {
|
if (this.banner) {
|
||||||
const banner = document.createElement("img");
|
const banner = document.createElement("img");
|
||||||
let src: string;
|
let src: string;
|
||||||
if (!this.hypotheticalbanner) {
|
if (!this.hypotheticalbanner) {
|
||||||
src = `${this.info.cdn}/avatars/${this.id.replace("#clone", "")}/${
|
src = `${this.info.cdn}/avatars/${this.id.replace("#clone", "")}/${
|
||||||
this.banner
|
this.banner
|
||||||
}.png`;
|
}.png`;
|
||||||
} else {
|
} else {
|
||||||
src = this.banner;
|
src = this.banner;
|
||||||
}
|
}
|
||||||
banner.src = src;
|
banner.src = src;
|
||||||
banner.classList.add("banner");
|
banner.classList.add("banner");
|
||||||
div.append(banner);
|
div.append(banner);
|
||||||
}
|
}
|
||||||
if (x !== -1) {
|
if (x !== -1) {
|
||||||
div.style.left = `${x}px`;
|
div.style.left = `${x}px`;
|
||||||
div.style.top = `${y}px`;
|
div.style.top = `${y}px`;
|
||||||
div.classList.add("profile", "flexttb");
|
div.classList.add("profile", "flexttb");
|
||||||
} else {
|
} else {
|
||||||
this.setstatus("online");
|
this.setstatus("online");
|
||||||
div.classList.add("hypoprofile", "flexttb");
|
div.classList.add("hypoprofile", "flexttb");
|
||||||
}
|
}
|
||||||
const badgediv = document.createElement("div");
|
const badgediv = document.createElement("div");
|
||||||
badgediv.classList.add("badges");
|
badgediv.classList.add("badges");
|
||||||
(async () => {
|
(async () => {
|
||||||
if (!this.badge_ids) return;
|
if (!this.badge_ids) return;
|
||||||
for (const id of this.badge_ids) {
|
for (const id of this.badge_ids) {
|
||||||
const badgejson = await this.getBadge(id);
|
const badgejson = await this.getBadge(id);
|
||||||
if (badgejson) {
|
if (badgejson) {
|
||||||
const badge = document.createElement(badgejson.link ? "a" : "div");
|
const badge = document.createElement(badgejson.link ? "a" : "div");
|
||||||
badge.classList.add("badge");
|
badge.classList.add("badge");
|
||||||
const img = document.createElement("img");
|
const img = document.createElement("img");
|
||||||
img.src = badgejson.icon;
|
img.src = badgejson.icon;
|
||||||
badge.append(img);
|
badge.append(img);
|
||||||
const span = document.createElement("span");
|
const span = document.createElement("span");
|
||||||
span.textContent = badgejson.description;
|
span.textContent = badgejson.description;
|
||||||
badge.append(span);
|
badge.append(span);
|
||||||
if (badge instanceof HTMLAnchorElement) {
|
if (badge instanceof HTMLAnchorElement) {
|
||||||
badge.href = badgejson.link;
|
badge.href = badgejson.link;
|
||||||
}
|
}
|
||||||
badgediv.append(badge);
|
badgediv.append(badge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
const pfp = await this.buildstatuspfp();
|
const pfp = await this.buildstatuspfp();
|
||||||
div.appendChild(pfp);
|
div.appendChild(pfp);
|
||||||
const userbody = document.createElement("div");
|
const userbody = document.createElement("div");
|
||||||
userbody.classList.add("infosection");
|
userbody.classList.add("infosection");
|
||||||
div.appendChild(userbody);
|
div.appendChild(userbody);
|
||||||
const usernamehtml = document.createElement("h2");
|
const usernamehtml = document.createElement("h2");
|
||||||
usernamehtml.textContent = this.username;
|
usernamehtml.textContent = this.username;
|
||||||
userbody.appendChild(usernamehtml);
|
userbody.appendChild(usernamehtml);
|
||||||
userbody.appendChild(badgediv);
|
userbody.appendChild(badgediv);
|
||||||
const discrimatorhtml = document.createElement("h3");
|
const discrimatorhtml = document.createElement("h3");
|
||||||
discrimatorhtml.classList.add("tag");
|
discrimatorhtml.classList.add("tag");
|
||||||
discrimatorhtml.textContent = `${this.username}#${this.discriminator}`;
|
discrimatorhtml.textContent = `${this.username}#${this.discriminator}`;
|
||||||
userbody.appendChild(discrimatorhtml);
|
userbody.appendChild(discrimatorhtml);
|
||||||
|
|
||||||
const pronounshtml = document.createElement("p");
|
const pronounshtml = document.createElement("p");
|
||||||
pronounshtml.textContent = this.pronouns;
|
pronounshtml.textContent = this.pronouns;
|
||||||
pronounshtml.classList.add("pronouns");
|
pronounshtml.classList.add("pronouns");
|
||||||
userbody.appendChild(pronounshtml);
|
userbody.appendChild(pronounshtml);
|
||||||
|
|
||||||
const rule = document.createElement("hr");
|
const rule = document.createElement("hr");
|
||||||
userbody.appendChild(rule);
|
userbody.appendChild(rule);
|
||||||
const biohtml = this.bio.makeHTML();
|
const biohtml = this.bio.makeHTML();
|
||||||
userbody.appendChild(biohtml);
|
userbody.appendChild(biohtml);
|
||||||
if (guild) {
|
if (guild) {
|
||||||
Member.resolveMember(this, guild).then((member) => {
|
Member.resolveMember(this, guild).then((member) => {
|
||||||
if (!member) return;
|
if (!member) return;
|
||||||
const roles = document.createElement("div");
|
const roles = document.createElement("div");
|
||||||
roles.classList.add("rolesbox");
|
roles.classList.add("rolesbox");
|
||||||
for (const role of member.roles) {
|
for (const role of member.roles) {
|
||||||
const roleDiv = document.createElement("div");
|
const roleDiv = document.createElement("div");
|
||||||
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",
|
||||||
`#${role.color.toString(16).padStart(6, "0")}`
|
`#${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);
|
||||||
span.textContent = role.name;
|
span.textContent = role.name;
|
||||||
roles.append(roleDiv);
|
roles.append(roleDiv);
|
||||||
}
|
}
|
||||||
userbody.append(roles);
|
userbody.append(roles);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (x !== -1) {
|
if (x !== -1) {
|
||||||
Contextmenu.currentmenu = div;
|
Contextmenu.currentmenu = div;
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
Contextmenu.keepOnScreen(div);
|
Contextmenu.keepOnScreen(div);
|
||||||
}
|
}
|
||||||
return div;
|
return div;
|
||||||
}
|
}
|
||||||
|
|
||||||
profileclick(obj: HTMLElement, guild?: Guild): void {
|
profileclick(obj: HTMLElement, guild?: Guild): void {
|
||||||
obj.onclick = (e: MouseEvent) => {
|
obj.onclick = (e: MouseEvent) => {
|
||||||
this.buildprofile(e.clientX, e.clientY, guild);
|
this.buildprofile(e.clientX, e.clientY, guild);
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
User.setUpContextMenu();
|
User.setUpContextMenu();
|
||||||
export { User };
|
export { User };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue