remove jquery and stuff

This commit is contained in:
Zack Rauen 2020-03-29 05:17:12 -04:00
parent dbcf2f9cef
commit ded3f96b07
33 changed files with 1444 additions and 1160 deletions

View File

@ -45,6 +45,7 @@
"Promise": false, "Promise": false,
"ace": false, "ace": false,
"Reflect": false, "Reflect": false,
"Array": false,
"DiscordNative": false, "DiscordNative": false,
"self": "off", "self": "off",
"name": "off", "name": "off",

File diff suppressed because one or more lines are too long

2
js/main.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -2,34 +2,24 @@
export const minimumDiscordVersion = "0.0.306"; export const minimumDiscordVersion = "0.0.306";
export const currentDiscordVersion = (window.DiscordNative && window.DiscordNative.remoteApp && window.DiscordNative.remoteApp.getVersion && window.DiscordNative.remoteApp.getVersion()) || "0.0.306"; export const currentDiscordVersion = (window.DiscordNative && window.DiscordNative.remoteApp && window.DiscordNative.remoteApp.getVersion && window.DiscordNative.remoteApp.getVersion()) || "0.0.306";
export const minSupportedVersion = "0.3.0"; export const minSupportedVersion = "0.3.0";
export const bbdVersion = "0.3.1"; export const bbdVersion = "0.3.2";
export const bbdChangelog = { export const bbdChangelog = {
description: "There's some pretty big things in this one, and even bigger things coming. Most of this information is repeated from the `0.3.0` update just in case people hadn't seen the changelog yet.", description: "More big things.",
changes: [ changes: [
{ {
title: "What's New?", title: "What's New?",
items: [ items: [
"**RepoControls**-like controls are now integrated into BD and everyone can enjoy sorting and searching their plugins and themes.", "**jQuery** is no longer used internally in BBD. This should speed things up and hopefully close some memory leaks.",
"BandagedBD has undergone an internal restructure--it's no longer one messy file but *several*. Users shouldn't see any breaking changes (hopefully).", "**VoiceMode** was redone to act more like it used to."
"**Plugin Developers:** You'll begin (or continue for some) to see deprecation notices for several BD globals. Please take these seriously and update your plugins to use `BdApi`, the globals **_will_** be removed. If you find the API to be missing something that you could do before, please message me in BD2's <#603225817262194699> chat.",
"**Also Plugin Developers:** There is now an option to enable React Developer Tools in the Developer Options in settings. Just make sure to have the extension installed in your local Chrome installation."
] ]
}, },
{ {
title: "Minor Stuff", title: "Improvements",
type: "improved", type: "improved",
items: [ items: [
"**BD Blue** is now the default accent color for BBD elements in settings. Themes can customize it easily through some new variables: `--bd-blue`, `--bd-blue-hover`, `--bd-blue-active`", "**Copy Selector** option was revamped to be more consistent and functional.",
"Some improvements have been made to the plugins and themes pages that should hopefully prevent plugins from causing errors when displaying.", "**Emote Menu** has gone through some serious changes to be more efficient and less buggy.",
"You can now review the changelog after you close it by clicking this button in settings: https://i.imgur.com/I3ZdAxG.png" "Some speed improvements when entering the plugins and themes tabs."
]
},
{
title: "Minor Stuff",
type: "fixed",
items: [
"**Quick Emote Menu** works again, sorry about that!",
"Fixed an issue with searching plugin/theme lists."
] ]
} }
] ]
@ -76,7 +66,7 @@ export const settings = {
"BetterTTV Emotes": {id: "bda-es-2", info: "Show BetterTTV Emotes", implemented: true, hidden: false, cat: "emote"}, "BetterTTV Emotes": {id: "bda-es-2", info: "Show BetterTTV Emotes", implemented: true, hidden: false, cat: "emote"},
"Emote Menu": {id: "bda-es-0", info: "Show Twitch/Favourite emotes in emote menu", implemented: true, hidden: false, cat: "emote"}, "Emote Menu": {id: "bda-es-0", info: "Show Twitch/Favourite emotes in emote menu", implemented: true, hidden: false, cat: "emote"},
"Emoji Menu": {id: "bda-es-9", info: "Show Discord emoji menu", implemented: true, hidden: false, cat: "emote"}, "Emoji Menu": {id: "bda-es-9", info: "Show Discord emoji menu", implemented: true, hidden: false, cat: "emote"},
"Emote Auto Capitalization": {id: "bda-es-4", info: "Autocapitalize emote commands", implemented: true, hidden: false, cat: "emote"}, "Emote Auto Capitalization": {id: "bda-es-4", info: "Autocapitalize emote commands", implemented: false, hidden: false, cat: "emote"},
"Show Names": {id: "bda-es-6", info: "Show emote names on hover", implemented: true, hidden: false, cat: "emote"}, "Show Names": {id: "bda-es-6", info: "Show emote names on hover", implemented: true, hidden: false, cat: "emote"},
"Show emote modifiers": {id: "bda-es-8", info: "Enable emote mods (flip, spin, pulse, spin2, spin3, 1spin, 2spin, 3spin, tr, bl, br, shake, shake2, shake3, flap)", implemented: true, hidden: false, cat: "emote"}, "Show emote modifiers": {id: "bda-es-8", info: "Enable emote mods (flip, spin, pulse, spin2, spin3, 1spin, 2spin, 3spin, tr, bl, br, shake, shake2, shake3, flap)", implemented: true, hidden: false, cat: "emote"},
"Animate On Hover": {id: "fork-es-2", info: "Only animate the emote modifiers on hover", implemented: true, hidden: false, cat: "emote"} "Animate On Hover": {id: "fork-es-2", info: "Only animate the emote modifiers on hover", implemented: true, hidden: false, cat: "emote"}

View File

@ -30,7 +30,6 @@ import DataStore from "./modules/dataStore";
import emoteModule from "./modules/emoteModule"; import emoteModule from "./modules/emoteModule";
import ContentManager from "./modules/contentManager"; import ContentManager from "./modules/contentManager";
import ClassNormalizer from "./modules/classNormalizer"; import ClassNormalizer from "./modules/classNormalizer";
import quickEmoteMenu from "./modules/quickEmoteMenu";
deprecateGlobal("BDV2", BDV2); deprecateGlobal("BDV2", BDV2);
deprecateGlobal("pluginModule", pluginModule); deprecateGlobal("pluginModule", pluginModule);
@ -44,7 +43,6 @@ deprecateGlobal("ContentManager", ContentManager);
deprecateGlobal("ClassNormalizer", ClassNormalizer); deprecateGlobal("ClassNormalizer", ClassNormalizer);
window.BdApi = BdApi; window.BdApi = BdApi;
window.quickEmoteMenu = quickEmoteMenu;
import Core from "./modules/core"; import Core from "./modules/core";
export default class CoreWrapper { export default class CoreWrapper {

View File

@ -6,6 +6,7 @@ import DataStore from "./dataStore";
import pluginModule from "./pluginModule"; import pluginModule from "./pluginModule";
import themeModule from "./themeModule"; import themeModule from "./themeModule";
import settingsPanel from "./settingsPanel"; import settingsPanel from "./settingsPanel";
import DOM from "./domtools";
const BdApi = { const BdApi = {
get React() { return BDV2.React; }, get React() { return BDV2.React; },
@ -34,26 +35,26 @@ BdApi.setWindowPreference = function(key, value) {
//id = id of element //id = id of element
//css = custom css //css = custom css
BdApi.injectCSS = function (id, css) { BdApi.injectCSS = function (id, css) {
$("head").append($("<style>", {id: Utils.escapeID(id), text: css})); DOM.addStyle(DOM.escapeID(id), css);
}; };
//Clear css/remove any element //Clear css/remove any element
//id = id of element //id = id of element
BdApi.clearCSS = function (id) { BdApi.clearCSS = function (id) {
$("#" + Utils.escapeID(id)).remove(); DOM.removeStyle(DOM.escapeID(id));
}; };
//Inject CSS to document head //Inject CSS to document head
//id = id of element //id = id of element
//css = custom css //css = custom css
BdApi.linkJS = function (id, url) { BdApi.linkJS = function (id, url) {
$("head").append($("<script>", {id: Utils.escapeID(id), src: url, type: "text/javascript"})); DOM.addScript(DOM.escapeID(id), url);
}; };
//Clear css/remove any element //Clear css/remove any element
//id = id of element //id = id of element
BdApi.unlinkJS = function (id) { BdApi.unlinkJS = function (id) {
$("#" + Utils.escapeID(id)).remove(); DOM.removeScript(DOM.escapeID(id));
}; };
//Get another plugin //Get another plugin

View File

@ -113,8 +113,6 @@ export default new class ContentManager {
return out; return out;
} }
getContentRequire(type) { getContentRequire(type) {
const isPlugin = type === "plugin"; const isPlugin = type === "plugin";
const self = this; const self = this;

View File

@ -1,16 +1,15 @@
import {bdConfig, minSupportedVersion, bbdVersion, settingsCookie, bdpluginErrors, bdthemeErrors, bbdChangelog, defaultCookie, minimumDiscordVersion, currentDiscordVersion} from "../0globals"; import {bdConfig, minSupportedVersion, bbdVersion, settingsCookie, bdpluginErrors, bdthemeErrors, bbdChangelog, defaultCookie, currentDiscordVersion} from "../0globals";
import Utils from "./utils"; import Utils from "./utils";
import emoteModule from "./emoteModule"; import emoteModule from "./emoteModule";
import quickEmoteMenu from "./quickEmoteMenu"; import quickEmoteMenu from "./quickEmoteMenu";
// import publicServersModule from "./publicServers";
// import voiceMode from "./voiceMode";
// import dMode from "./devMode";
import BDV2 from "./v2"; import BDV2 from "./v2";
import settingsPanel from "./settingsPanel"; import settingsPanel from "./settingsPanel";
import pluginModule from "./pluginModule"; import pluginModule from "./pluginModule";
import themeModule from "./themeModule"; import themeModule from "./themeModule";
import DataStore from "./dataStore"; import DataStore from "./dataStore";
import WebpackModules from "./webpackModules"; import WebpackModules from "./webpackModules";
import DOM from "./domtools";
import BDLogo from "../ui/bdLogo"; import BDLogo from "../ui/bdLogo";
import TooltipWrap from "../ui/tooltipWrap"; import TooltipWrap from "../ui/tooltipWrap";
@ -22,10 +21,10 @@ Core.prototype.setConfig = function(config) {
}; };
Core.prototype.init = async function() { Core.prototype.init = async function() {
// if (currentDiscordVersion < minimumDiscordVersion) { if (!Array.prototype.flat) {
// Utils.alert("Not Supported", "BetterDiscord v" + bbdVersion + " does not support this old version (" + currentDiscordVersion + ") of Discord. Please update your Discord installation before proceeding."); Utils.alert("Not Supported", "BetterDiscord v" + bbdVersion + " does not support this old version (" + currentDiscordVersion + ") of Discord. Please update your Discord installation before proceeding.");
// return; return;
// } }
if (bdConfig.version < minSupportedVersion) { if (bdConfig.version < minSupportedVersion) {
Utils.alert("Not Supported", "BetterDiscord v" + bdConfig.version + " (your version)" + " is not supported by the latest js (" + bbdVersion + ").<br><br> Please download the latest version from <a href='https://github.com/rauenzi/BetterDiscordApp/releases/latest' target='_blank'>GitHub</a>"); Utils.alert("Not Supported", "BetterDiscord v" + bdConfig.version + " (your version)" + " is not supported by the latest js (" + bbdVersion + ").<br><br> Please download the latest version from <a href='https://github.com/rauenzi/BetterDiscordApp/releases/latest' target='_blank'>GitHub</a>");
@ -52,43 +51,33 @@ Core.prototype.init = async function() {
Utils.log("Startup", "Initializing Settings"); Utils.log("Startup", "Initializing Settings");
this.initSettings(); this.initSettings();
// emoteModule = new EmoteModule();
// quickEmoteMenu = new QuickEmoteMenu();
Utils.log("Startup", "Initializing EmoteModule"); Utils.log("Startup", "Initializing EmoteModule");
window.emotePromise = emoteModule.init().then(() => { window.emotePromise = emoteModule.init().then(() => {
emoteModule.initialized = true; emoteModule.initialized = true;
Utils.log("Startup", "Initializing QuickEmoteMenu"); Utils.log("Startup", "Initializing QuickEmoteMenu");
quickEmoteMenu.init(); quickEmoteMenu.init();
}); });
// publicServersModule = new V2_PublicServers();
// voiceMode = new VoiceMode();
// dMode = new devMode();
this.injectExternals(); this.injectExternals();
await this.checkForGuilds(); await this.checkForGuilds();
BDV2.initialize(); BDV2.initialize();
Utils.log("Startup", "Updating Settings"); Utils.log("Startup", "Updating Settings");
// settingsPanel = new V2_SettingsPanel();
settingsPanel.initializeSettings(); settingsPanel.initializeSettings();
Utils.log("Startup", "Loading Plugins"); Utils.log("Startup", "Loading Plugins");
// pluginModule = new PluginModule();
pluginModule.loadPlugins(); pluginModule.loadPlugins();
Utils.log("Startup", "Loading Themes"); Utils.log("Startup", "Loading Themes");
// themeModule = new ThemeModule();
themeModule.loadThemes(); themeModule.loadThemes();
$("#customcss").detach().appendTo(document.head); DOM.addStyle("customcss", atob(DataStore.getBDData("bdcustomcss")));
window.addEventListener("beforeunload", function() { window.addEventListener("beforeunload", function() {
if (settingsCookie["bda-dc-0"]) document.querySelector(".btn.btn-disconnect").click(); if (settingsCookie["bda-dc-0"]) document.querySelector(".btn.btn-disconnect").click();
}); });
emoteModule.autoCapitalize();
Utils.log("Startup", "Removing Loading Icon"); Utils.log("Startup", "Removing Loading Icon");
if (document.getElementsByClassName("bd-loaderv2").length) document.getElementsByClassName("bd-loaderv2")[0].remove(); if (document.getElementsByClassName("bd-loaderv2").length) document.getElementsByClassName("bd-loaderv2")[0].remove();
Utils.log("Startup", "Initializing Main Observer"); Utils.log("Startup", "Initializing Main Observer");
@ -124,14 +113,13 @@ Core.prototype.checkForGuilds = function() {
else if (timesChecked >= 50) return resolve(bdConfig.deferLoaded = true); else if (timesChecked >= 50) return resolve(bdConfig.deferLoaded = true);
setTimeout(checkForGuilds, 100); setTimeout(checkForGuilds, 100);
}; };
$(document).ready(function () { if (document.readyState != "loading") setTimeout(checkForGuilds, 100);
setTimeout(checkForGuilds, 100); document.addEventListener("DOMContentLoaded", () => {setTimeout(checkForGuilds, 100);});
});
}); });
}; };
Core.prototype.injectExternals = async function() { Core.prototype.injectExternals = async function() {
await Utils.injectJs("https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js"); await DOM.addScript("ace-script", "https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js");
if (window.require.original) window.require = window.require.original; if (window.require.original) window.require = window.require.original;
}; };
@ -143,7 +131,6 @@ Core.prototype.initSettings = function () {
} }
else { else {
settingsPanel.loadSettings(); settingsPanel.loadSettings();
$("<style id=\"customcss\">").text(atob(DataStore.getBDData("bdcustomcss"))).appendTo(document.head);
for (const setting in defaultCookie) { for (const setting in defaultCookie) {
if (settingsCookie[setting] == undefined) { if (settingsCookie[setting] == undefined) {
settingsCookie[setting] = defaultCookie[setting]; settingsCookie[setting] = defaultCookie[setting];

View File

@ -1,89 +1,104 @@
import {settingsCookie} from "../0globals";
import BDV2 from "./v2"; import BDV2 from "./v2";
import DOM from "./domtools";
function devMode() {} export default new class DevMode {
constructor() {
this.debugListener = this.debugListener.bind(this);
this.copySelectorListener = this.copySelectorListener.bind(this);
}
devMode.prototype.enable = function(selectorMode) { start() {
const self = this; this.startDebugListener();
this.disable(); if (settingsCookie["fork-dm-1"]) this.startCopySelector();
$(document).on("keydown.bdDevmode", function(e) { }
if (e.which === 119 || e.which == 118) {//F8
stop() {
this.stopDebugListener();
this.stopCopySelector();
}
startDebugListener() {
this.stopDebugListener();
document.addEventListener("keydown", this.debugListener);
}
stopDebugListener() {
document.removeEventListener("keydown", this.debugListener);
}
startCopySelector() {
this.stopCopySelector();
document.addEventListener("contextmenu", this.copySelectorListener);
}
stopCopySelector() {
document.removeEventListener("contextmenu", this.copySelectorListener);
}
debugListener(e) {
if (e.which === 119 || e.which == 118) {//F8
console.log("%c[%cDevMode%c] %cBreak/Resume", "color: red;", "color: #303030; font-weight:700;", "color:red;", ""); console.log("%c[%cDevMode%c] %cBreak/Resume", "color: red;", "color: #303030; font-weight:700;", "color:red;", "");
debugger; // eslint-disable-line no-debugger debugger; // eslint-disable-line no-debugger
e.preventDefault(); e.preventDefault();
e.stopImmediatePropagation(); e.stopImmediatePropagation();
} }
}); }
if (!selectorMode) return; copySelectorListener(e) {
$(document).on("contextmenu.bdDevmode", function(e) { e.stopPropagation();
self.lastSelector = self.getSelector(e.toElement); const selector = this.getSelector(e.target);
function attach() {
function attach() { let cm = DOM.query(".contextMenu-HLZMGh");
let cm = $(".contextMenu-HLZMGh"); if (!cm) {
if (cm.length <= 0) { const container = DOM.query("#app-mount");
cm = $("<div class=\"contextMenu-HLZMGh bd-context-menu\"></div>"); const cmWrap = DOM.createElement(`<div class="layer-v9HyYc da-layer">`);
cm.addClass($(".app, .app-2rEoOp").hasClass("theme-dark") ? "theme-dark" : "theme-light"); cm = DOM.createElement(`<div class="contextMenu-HLZMGh da-contextMenu bd-context-menu"></div>`);
cm.appendTo(".app, .app-2rEoOp"); cmWrap.append(cm);
cm.css("top", e.clientY); container.append(cmWrap);
cm.css("left", e.clientX); cmWrap.style.top = e.clientY + "px";
$(document).on("click.bdDevModeCtx", () => { cmWrap.style.left = e.clientX + "px";
cm.remove(); cmWrap.style.zIndex = "1002";
$(document).off(".bdDevModeCtx"); const removeCM = function(e) {
}); if (e.keyCode && e.keyCode !== 27) return;
$(document).on("contextmenu.bdDevModeCtx", () => { cmWrap.remove();
cm.remove(); document.removeEventListener("click", removeCM);
$(document).off(".bdDevModeCtx"); document.removeEventListener("contextmenu", removeCM);
}); document.removeEventListener("keyup", removeCM);
$(document).on("keyup.bdDevModeCtx", (e) => { };
if (e.keyCode === 27) { document.addEventListener("click", removeCM);
cm.remove(); document.addEventListener("contextmenu", removeCM);
$(document).off(".bdDevModeCtx"); document.addEventListener("keyup", removeCM);
}
});
} }
const cmo = $("<div/>", { const cmg = DOM.createElement(`<div class="itemGroup-1tL0uz da-itemGroup">`);
"class": "itemGroup-1tL0uz" const cmi = DOM.createElement(`<div class="item-1Yvehc itemBase-tz5SeC da-item da-itemBase clickable-11uBi- da-clickable">`);
cmi.append(DOM.createElement(`<div class="label-JWQiNe da-label">Copy Selector</div>`));
cmi.addEventListener("click", () => {
BDV2.NativeModule.copy(selector);
cm.style.display = "none";
}); });
const cmi = $("<div/>", { cmg.append(cmi);
"class": "item-1Yvehc", cm.append(cmg);
"click": function() { }
BDV2.NativeModule.copy(self.lastSelector);
cm.hide();
}
}).append($("<span/>", {text: "Copy Selector"}));
cmo.append(cmi);
cm.append(cmo);
if (cm.hasClass("undefined")) cm.css("top", "-=" + cmo.outerHeight());
}
setImmediate(attach); setImmediate(attach);
}
e.stopPropagation(); getSelector(element) {
}); if (element.id) return `#${element.id}`;
}; const rules = this.getRules(element);
const latestRule = rules[rules.length - 1];
if (latestRule) return latestRule.selectorText;
else if (element.classList.length) return `.${Array.from(element.classList).join(".")}`;
return `.${Array.from(element.parentElement.classList).join(".")}`;
}
devMode.prototype.getRules = function(element, css = element.ownerDocument.styleSheets) { getRules(element, css = element.ownerDocument.styleSheets) {
//if (window.getMatchedCSSRules) return window.getMatchedCSSRules(element); //if (window.getMatchedCSSRules) return window.getMatchedCSSRules(element);
const sheets = [...css].filter(s => !s.href || !s.href.includes("BetterDiscordApp")); const sheets = [...css].filter(s => !s.href || !s.href.includes("BetterDiscordApp"));
const rules = sheets.map(s => [...(s.cssRules || [])]).flat(); const rules = sheets.map(s => [...(s.cssRules || [])]).flat();
const elementRules = rules.filter(r => r && r.selectorText && element.matches(r.selectorText) && r.style.length && r.selectorText.split(", ").length < 8 && !r.selectorText.split(", ").includes("*")); const elementRules = rules.filter(r => r && r.selectorText && element.matches(r.selectorText) && r.style.length && r.selectorText.split(", ").length < 8 && !r.selectorText.split(", ").includes("*"));
return elementRules; return elementRules;
}; }
};
devMode.prototype.getSelector = function(element) {
if (element.id) return `#${element.id}`;
const rules = this.getRules(element);
const latestRule = rules[rules.length - 1];
if (latestRule) return latestRule.selectorText;
else if (element.classList.length) return `.${Array.from(element.classList).join(".")}`;
return `.${Array.from(element.parentElement.classList).join(".")}`;
};
devMode.prototype.disable = function() {
$(document).off("keydown.bdDevmode");
$(document).off("contextmenu.bdDevmode");
$(document).off("contextmenu.bdDevModeCtx");
};
export default new devMode();

753
src/modules/domtools.js Normal file
View File

@ -0,0 +1,753 @@
/**
* Copyright 2018 Zachary Rauen
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* From: https://github.com/rauenzi/BDPluginLibrary
*/
/**
* @interface
* @name Offset
* @property {number} top - Top offset of the target element.
* @property {number} right - Right offset of the target element.
* @property {number} bottom - Bottom offset of the target element.
* @property {number} left - Left offset of the target element.
* @property {number} height - Outer height of the target element.
* @property {number} width - Outer width of the target element.
*/
/**
* Function that automatically removes added listener.
* @callback module:DOMTools~CancelListener
*/
export default class DOMTools {
static escapeID(id) {
return id.replace(/^[^a-z]+|[^\w-]+/gi, "-");
}
/**
* Adds a style to the document.
* @param {string} id - identifier to use as the element id
* @param {string} css - css to add to the document
*/
static addStyle(id, css) {
document.head.append(DOMTools.createElement(`<style id="${id}">${css}</style>`));
}
/**
* Removes a style from the document.
* @param {string} id - original identifier used
*/
static removeStyle(id) {
const element = document.getElementById(id);
if (element) element.remove();
}
/**
* Adds/requires a remote script to be loaded
* @param {string} id - identifier to use for this script
* @param {string} url - url from which to load the script
* @returns {Promise} promise that resolves when the script is loaded
*/
static addScript(id, url) {
return new Promise(resolve => {
const script = document.createElement("script");
script.id = id;
script.src = url;
script.type = "text/javascript";
script.onload = resolve;
document.head.append(script);
});
}
/**
* Removes a remote script from the document.
* @param {string} id - original identifier used
*/
static removeScript(id) {
id = this.escapeID(id);
const element = document.getElementById(id);
if (element) element.remove();
}
// https://javascript.info/js-animation
static animate({timing = _ => _, update, duration}) {
const start = performance.now();
requestAnimationFrame(function animate(time) {
// timeFraction goes from 0 to 1
let timeFraction = (time - start) / duration;
if (timeFraction > 1) timeFraction = 1;
// calculate the current animation state
const progress = timing(timeFraction);
update(progress); // draw it
if (timeFraction < 1) {
requestAnimationFrame(animate);
}
});
}
/**
* This is my shit version of not having to use `$` from jQuery. Meaning
* that you can pass a selector and it will automatically run {@link module:DOMTools.query}.
* It also means that you can pass a string of html and it will perform and return `parseHTML`.
* @see module:DOMTools.parseHTML
* @see module:DOMTools.query
* @param {string} selector - Selector to query or HTML to parse
* @returns {(DocumentFragment|NodeList|HTMLElement)} - Either the result of `parseHTML` or `query`
*/
static Q(selector) {
const element = this.parseHTML(selector);
const isHTML = element instanceof NodeList ? Array.from(element).some(n => n.nodeType === 1) : element.nodeType === 1;
if (isHTML) return element;
return this.query(selector);
}
/**
* Essentially a shorthand for `document.querySelector`. If the `baseElement` is not provided
* `document` is used by default.
* @param {string} selector - Selector to query
* @param {Element} [baseElement] - Element to base the query from
* @returns {(Element|null)} - The found element or null if not found
*/
static query(selector, baseElement) {
if (!baseElement) baseElement = document;
return baseElement.querySelector(selector);
}
/**
* Essentially a shorthand for `document.querySelectorAll`. If the `baseElement` is not provided
* `document` is used by default.
* @param {string} selector - Selector to query
* @param {Element} [baseElement] - Element to base the query from
* @returns {Array<Element>} - Array of all found elements
*/
static queryAll(selector, baseElement) {
if (!baseElement) baseElement = document;
return baseElement.querySelectorAll(selector);
}
/**
* Parses a string of HTML and returns the results. If the second parameter is true,
* the parsed HTML will be returned as a document fragment {@see https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment}.
* This is extremely useful if you have a list of elements at the top level, they can then be appended all at once to another node.
*
* If the second parameter is false, then the return value will be the list of parsed
* nodes and there were multiple top level nodes, otherwise the single node is returned.
* @param {string} html - HTML to be parsed
* @param {boolean} [fragment=false] - Whether or not the return should be the raw `DocumentFragment`
* @returns {(DocumentFragment|NodeList|HTMLElement)} - The result of HTML parsing
*/
static parseHTML(html, fragment = false) {
const template = document.createElement("template");
template.innerHTML = html;
const node = template.content.cloneNode(true);
if (fragment) return node;
return node.childNodes.length > 1 ? node.childNodes : node.childNodes[0];
}
/** Alternate name for {@link module:DOMTools.parseHTML} */
static createElement(html, fragment = false) {return this.parseHTML(html, fragment);}
/**
* Takes a string of html and escapes it using the brower's own escaping mechanism.
* @param {String} html - html to be escaped
*/
static escapeHTML(html) {
const textNode = document.createTextNode("");
const spanElement = document.createElement("span");
spanElement.append(textNode);
textNode.nodeValue = html;
return spanElement.innerHTML;
}
/**
* Adds a list of classes from the target element.
* @param {Element} element - Element to edit classes of
* @param {...string} classes - Names of classes to add
* @returns {Element} - `element` to allow for chaining
*/
static addClass(element, ...classes) {
classes = classes.flat().filter(c => c);
for (let c = 0; c < classes.length; c++) classes[c] = classes[c].toString().split(" ");
classes = classes.flat().filter(c => c);
element.classList.add(...classes);
return element;
}
/**
* Removes a list of classes from the target element.
* @param {Element} element - Element to edit classes of
* @param {...string} classes - Names of classes to remove
* @returns {Element} - `element` to allow for chaining
*/
static removeClass(element, ...classes) {
for (let c = 0; c < classes.length; c++) classes[c] = classes[c].toString().split(" ");
classes = classes.flat().filter(c => c);
element.classList.remove(...classes);
return element;
}
/**
* When only one argument is present: Toggle class value;
* i.e., if class exists then remove it and return false, if not, then add it and return true.
* When a second argument is present:
* If the second argument evaluates to true, add specified class value, and if it evaluates to false, remove it.
* @param {Element} element - Element to edit classes of
* @param {string} classname - Name of class to toggle
* @param {boolean} [indicator] - Optional indicator for if the class should be toggled
* @returns {Element} - `element` to allow for chaining
*/
static toggleClass(element, classname, indicator) {
classname = classname.toString().split(" ").filter(c => c);
if (typeof(indicator) !== "undefined") classname.forEach(c => element.classList.toggle(c, indicator));
else classname.forEach(c => element.classList.toggle(c));
return element;
}
/**
* Checks if an element has a specific class
* @param {Element} element - Element to edit classes of
* @param {string} classname - Name of class to check
* @returns {boolean} - `true` if the element has the class, `false` otherwise.
*/
static hasClass(element, classname) {
return classname.toString().split(" ").filter(c => c).every(c => element.classList.contains(c));
}
/**
* Replaces one class with another
* @param {Element} element - Element to edit classes of
* @param {string} oldName - Name of class to replace
* @param {string} newName - New name for the class
* @returns {Element} - `element` to allow for chaining
*/
static replaceClass(element, oldName, newName) {
element.classList.replace(oldName, newName);
return element;
}
/**
* Appends `thisNode` to `thatNode`
* @param {Node} thisNode - Node to be appended to another node
* @param {Node} thatNode - Node for `thisNode` to be appended to
* @returns {Node} - `thisNode` to allow for chaining
*/
static appendTo(thisNode, thatNode) {
if (typeof(thatNode) == "string") thatNode = this.query(thatNode);
if (!thatNode) return null;
thatNode.append(thisNode);
return thisNode;
}
/**
* Prepends `thisNode` to `thatNode`
* @param {Node} thisNode - Node to be prepended to another node
* @param {Node} thatNode - Node for `thisNode` to be prepended to
* @returns {Node} - `thisNode` to allow for chaining
*/
static prependTo(thisNode, thatNode) {
if (typeof(thatNode) == "string") thatNode = this.query(thatNode);
if (!thatNode) return null;
thatNode.prepend(thisNode);
return thisNode;
}
/**
* Insert after a specific element, similar to jQuery's `thisElement.insertAfter(otherElement)`.
* @param {Node} thisNode - The node to insert
* @param {Node} targetNode - Node to insert after in the tree
* @returns {Node} - `thisNode` to allow for chaining
*/
static insertAfter(thisNode, targetNode) {
targetNode.parentNode.insertBefore(thisNode, targetNode.nextSibling);
return thisNode;
}
/**
* Insert after a specific element, similar to jQuery's `thisElement.after(newElement)`.
* @param {Node} thisNode - The node to insert
* @param {Node} newNode - Node to insert after in the tree
* @returns {Node} - `thisNode` to allow for chaining
*/
static after(thisNode, newNode) {
thisNode.parentNode.insertBefore(newNode, thisNode.nextSibling);
return thisNode;
}
/**
* Gets the next sibling element that matches the selector.
* @param {Element} element - Element to get the next sibling of
* @param {string} [selector=""] - Optional selector
* @returns {Element} - The sibling element
*/
static next(element, selector = "") {
return selector ? element.querySelector("+ " + selector) : element.nextElementSibling;
}
/**
* Gets all subsequent siblings.
* @param {Element} element - Element to get next siblings of
* @returns {NodeList} - The list of siblings
*/
static nextAll(element) {
return element.querySelectorAll("~ *");
}
/**
* Gets the subsequent siblings until an element matches the selector.
* @param {Element} element - Element to get the following siblings of
* @param {string} selector - Selector to stop at
* @returns {Array<Element>} - The list of siblings
*/
static nextUntil(element, selector) {
const next = [];
while (element.nextElementSibling && !element.nextElementSibling.matches(selector)) next.push(element = element.nextElementSibling);
return next;
}
/**
* Gets the previous sibling element that matches the selector.
* @param {Element} element - Element to get the previous sibling of
* @param {string} [selector=""] - Optional selector
* @returns {Element} - The sibling element
*/
static previous(element, selector = "") {
const previous = element.previousElementSibling;
if (selector) return previous && previous.matches(selector) ? previous : null;
return previous;
}
/**
* Gets all preceeding siblings.
* @param {Element} element - Element to get preceeding siblings of
* @returns {NodeList} - The list of siblings
*/
static previousAll(element) {
const previous = [];
while (element.previousElementSibling) previous.push(element = element.previousElementSibling);
return previous;
}
/**
* Gets the preceeding siblings until an element matches the selector.
* @param {Element} element - Element to get the preceeding siblings of
* @param {string} selector - Selector to stop at
* @returns {Array<Element>} - The list of siblings
*/
static previousUntil(element, selector) {
const previous = [];
while (element.previousElementSibling && !element.previousElementSibling.matches(selector)) previous.push(element = element.previousElementSibling);
return previous;
}
/**
* Find which index in children a certain node is. Similar to jQuery's `$.index()`
* @param {HTMLElement} node - The node to find its index in parent
* @returns {number} Index of the node
*/
static indexInParent(node) {
const children = node.parentNode.childNodes;
let num = 0;
for (let i = 0; i < children.length; i++) {
if (children[i] == node) return num;
if (children[i].nodeType == 1) num++;
}
return -1;
}
/** Shorthand for {@link module:DOMTools.indexInParent} */
static index(node) {return this.indexInParent(node);}
/**
* Gets the parent of the element if it matches the selector,
* otherwise returns null.
* @param {Element} element - Element to get parent of
* @param {string} [selector=""] - Selector to match parent
* @returns {(Element|null)} - The sibling element or null
*/
static parent(element, selector = "") {
return !selector || element.parentElement.matches(selector) ? element.parentElement : null;
}
/**
* Gets all children of Element that match the selector if provided.
* @param {Element} element - Element to get all children of
* @param {string} selector - Selector to match the children to
* @returns {Array<Element>} - The list of children
*/
static findChild(element, selector) {
return element.querySelector(":scope > " + selector);
}
/**
* Gets all children of Element that match the selector if provided.
* @param {Element} element - Element to get all children of
* @param {string} selector - Selector to match the children to
* @returns {Array<Element>} - The list of children
*/
static findChildren(element, selector) {
return element.querySelectorAll(":scope > " + selector);
}
/**
* Gets all ancestors of Element that match the selector if provided.
* @param {Element} element - Element to get all parents of
* @param {string} [selector=""] - Selector to match the parents to
* @returns {Array<Element>} - The list of parents
*/
static parents(element, selector = "") {
const parents = [];
if (selector) while (element.parentElement && element.parentElement.closest(selector)) parents.push(element = element.parentElement.closest(selector));
else while (element.parentElement) parents.push(element = element.parentElement);
return parents;
}
/**
* Gets the ancestors until an element matches the selector.
* @param {Element} element - Element to get the ancestors of
* @param {string} selector - Selector to stop at
* @returns {Array<Element>} - The list of parents
*/
static parentsUntil(element, selector) {
const parents = [];
while (element.parentElement && !element.parentElement.matches(selector)) parents.push(element = element.parentElement);
return parents;
}
/**
* Gets all siblings of the element that match the selector.
* @param {Element} element - Element to get all siblings of
* @param {string} [selector="*"] - Selector to match the siblings to
* @returns {Array<Element>} - The list of siblings
*/
static siblings(element, selector = "*") {
return Array.from(element.parentElement.children).filter(e => e != element && e.matches(selector));
}
/**
* Sets or gets css styles for a specific element. If `value` is provided
* then it sets the style and returns the element to allow for chaining,
* otherwise returns the style.
* @param {Element} element - Element to set the CSS of
* @param {string} attribute - Attribute to get or set
* @param {string} [value] - Value to set for attribute
* @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned.
*/
static css(element, attribute, value) {
if (typeof(value) == "undefined") return global.getComputedStyle(element)[attribute];
element.style[attribute] = value;
return element;
}
/**
* Sets or gets the width for a specific element. If `value` is provided
* then it sets the width and returns the element to allow for chaining,
* otherwise returns the width.
* @param {Element} element - Element to set the CSS of
* @param {string} [value] - Width to set
* @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned.
*/
static width(element, value) {
if (typeof(value) == "undefined") return parseInt(getComputedStyle(element).width);
element.style.width = value;
return element;
}
/**
* Sets or gets the height for a specific element. If `value` is provided
* then it sets the height and returns the element to allow for chaining,
* otherwise returns the height.
* @param {Element} element - Element to set the CSS of
* @param {string} [value] - Height to set
* @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned.
*/
static height(element, value) {
if (typeof(value) == "undefined") return parseInt(getComputedStyle(element).height);
element.style.height = value;
return element;
}
/**
* Sets the inner text of an element if given a value, otherwise returns it.
* @param {Element} element - Element to set the text of
* @param {string} [text] - Content to set
* @returns {string} - Either the string set by this call or the current text content of the node.
*/
static text(element, text) {
if (typeof(text) == "undefined") return element.textContent;
return element.textContent = text;
}
/**
* Returns the innerWidth of the element.
* @param {Element} element - Element to retrieve inner width of
* @return {number} - The inner width of the element.
*/
static innerWidth(element) {
return element.clientWidth;
}
/**
* Returns the innerHeight of the element.
* @param {Element} element - Element to retrieve inner height of
* @return {number} - The inner height of the element.
*/
static innerHeight(element) {
return element.clientHeight;
}
/**
* Returns the outerWidth of the element.
* @param {Element} element - Element to retrieve outer width of
* @return {number} - The outer width of the element.
*/
static outerWidth(element) {
return element.offsetWidth;
}
/**
* Returns the outerHeight of the element.
* @param {Element} element - Element to retrieve outer height of
* @return {number} - The outer height of the element.
*/
static outerHeight(element) {
return element.offsetHeight;
}
/**
* Gets the offset of the element in the page.
* @param {Element} element - Element to get offset of
* @return {Offset} - The offset of the element
*/
static offset(element) {
return element.getBoundingClientRect();
}
static get listeners() { return this._listeners || (this._listeners = {}); }
/**
* This is similar to jQuery's `on` function and can *hopefully* be used in the same way.
*
* Rather than attempt to explain, I'll show some example usages.
*
* The following will add a click listener (in the `myPlugin` namespace) to `element`.
* `DOMTools.on(element, "click.myPlugin", () => {console.log("clicked!");});`
*
* The following will add a click listener (in the `myPlugin` namespace) to `element` that only fires when the target is a `.block` element.
* `DOMTools.on(element, "click.myPlugin", ".block", () => {console.log("clicked!");});`
*
* The following will add a click listener (without namespace) to `element`.
* `DOMTools.on(element, "click", () => {console.log("clicked!");});`
*
* The following will add a click listener (without namespace) to `element` that only fires once.
* `const cancel = DOMTools.on(element, "click", () => {console.log("fired!"); cancel();});`
*
* @param {Element} element - Element to add listener to
* @param {string} event - Event to listen to with option namespace (e.g. "event.namespace")
* @param {(string|callable)} delegate - Selector to run on element to listen to
* @param {callable} [callback] - Function to fire on event
* @returns {module:DOMTools~CancelListener} - A function that will undo the listener
*/
static on(element, event, delegate, callback) {
const [type, namespace] = event.split(".");
const hasDelegate = delegate && callback;
if (!callback) callback = delegate;
const eventFunc = !hasDelegate ? callback : function(event) {
if (event.target.matches(delegate)) {
callback(event);
}
};
element.addEventListener(type, eventFunc);
const cancel = () => {
element.removeEventListener(type, eventFunc);
};
if (namespace) {
if (!this.listeners[namespace]) this.listeners[namespace] = [];
const newCancel = () => {
cancel();
this.listeners[namespace].splice(this.listeners[namespace].findIndex(l => l.event == type && l.element == element), 1);
};
this.listeners[namespace].push({
event: type,
element: element,
cancel: newCancel
});
return newCancel;
}
return cancel;
}
/**
* Functionality for this method matches {@link module:DOMTools.on} but automatically cancels itself
* and removes the listener upon the first firing of the desired event.
*
* @param {Element} element - Element to add listener to
* @param {string} event - Event to listen to with option namespace (e.g. "event.namespace")
* @param {(string|callable)} delegate - Selector to run on element to listen to
* @param {callable} [callback] - Function to fire on event
* @returns {module:DOMTools~CancelListener} - A function that will undo the listener
*/
static once(element, event, delegate, callback) {
const [type, namespace] = event.split(".");
const hasDelegate = delegate && callback;
if (!callback) callback = delegate;
const eventFunc = !hasDelegate ? function(event) {
callback(event);
element.removeEventListener(type, eventFunc);
} : function(event) {
if (!event.target.matches(delegate)) return;
callback(event);
element.removeEventListener(type, eventFunc);
};
element.addEventListener(type, eventFunc);
const cancel = () => {
element.removeEventListener(type, eventFunc);
};
if (namespace) {
if (!this.listeners[namespace]) this.listeners[namespace] = [];
const newCancel = () => {
cancel();
this.listeners[namespace].splice(this.listeners[namespace].findIndex(l => l.event == type && l.element == element), 1);
};
this.listeners[namespace].push({
event: type,
element: element,
cancel: newCancel
});
return newCancel;
}
return cancel;
}
static __offAll(event, element) {
const [type, namespace] = event.split(".");
let matchFilter = listener => listener.event == type, defaultFilter = _ => _;
if (element) matchFilter = l => l.event == type && l.element == element, defaultFilter = l => l.element == element;
const listeners = this.listeners[namespace] || [];
const list = type ? listeners.filter(matchFilter) : listeners.filter(defaultFilter);
for (let c = 0; c < list.length; c++) list[c].cancel();
}
/**
* This is similar to jQuery's `off` function and can *hopefully* be used in the same way.
*
* Rather than attempt to explain, I'll show some example usages.
*
* The following will remove a click listener called `onClick` (in the `myPlugin` namespace) from `element`.
* `DOMTools.off(element, "click.myPlugin", onClick);`
*
* The following will remove a click listener called `onClick` (in the `myPlugin` namespace) from `element` that only fired when the target is a `.block` element.
* `DOMTools.off(element, "click.myPlugin", ".block", onClick);`
*
* The following will remove a click listener (without namespace) from `element`.
* `DOMTools.off(element, "click", onClick);`
*
* The following will remove all listeners in namespace `myPlugin` from `element`.
* `DOMTools.off(element, ".myPlugin");`
*
* The following will remove all click listeners in namespace `myPlugin` from *all elements*.
* `DOMTools.off("click.myPlugin");`
*
* The following will remove all listeners in namespace `myPlugin` from *all elements*.
* `DOMTools.off(".myPlugin");`
*
* @param {(Element|string)} element - Element to remove listener from
* @param {string} [event] - Event to listen to with option namespace (e.g. "event.namespace")
* @param {(string|callable)} [delegate] - Selector to run on element to listen to
* @param {callable} [callback] - Function to fire on event
* @returns {Element} - The original element to allow for chaining
*/
static off(element, event, delegate, callback) {
if (typeof(element) == "string") return this.__offAll(element);
const [type, namespace] = event.split(".");
if (namespace) return this.__offAll(event, element);
const hasDelegate = delegate && callback;
if (!callback) callback = delegate;
const eventFunc = !hasDelegate ? callback : function(event) {
if (event.target.matches(delegate)) {
callback(event);
}
};
element.removeEventListener(type, eventFunc);
return element;
}
/**
* Adds a listener for when the node is added/removed from the document body.
* The listener is automatically removed upon firing.
* @param {HTMLElement} node - node to wait for
* @param {callable} callback - function to be performed on event
* @param {boolean} onMount - determines if it should fire on Mount or on Unmount
*/
static onMountChange(node, callback, onMount = true) {
const wrappedCallback = () => {
this.observer.unsubscribe(wrappedCallback);
callback();
};
this.observer.subscribe(wrappedCallback, mutation => {
const nodes = Array.from(onMount ? mutation.addedNodes : mutation.removedNodes);
const directMatch = nodes.indexOf(node) > -1;
const parentMatch = nodes.some(parent => parent.contains(node));
return directMatch || parentMatch;
});
return node;
}
/** Shorthand for {@link module:DOMTools.onMountChange} with third parameter `true` */
static onMount(node, callback) { return this.onMountChange(node, callback); }
/** Shorthand for {@link module:DOMTools.onMountChange} with third parameter `false` */
static onUnmount(node, callback) { return this.onMountChange(node, callback, false); }
/** Alias for {@link module:DOMTools.onMount} */
static onAdded(node, callback) { return this.onMount(node, callback); }
/** Alias for {@link module:DOMTools.onUnmount} */
static onRemoved(node, callback) { return this.onUnmount(node, callback, false); }
/**
* Helper function which combines multiple elements into one parent element
* @param {Array<HTMLElement>} elements - array of elements to put into a single parent
*/
static wrap(elements) {
const domWrapper = this.parseHTML(`<div class="dom-wrapper"></div>`);
for (let e = 0; e < elements.length; e++) domWrapper.appendChild(elements[e]);
return domWrapper;
}
/**
* Resolves the node to an HTMLElement. This is mainly used by library modules.
* @param {(jQuery|Element)} node - node to resolve
*/
static resolveElement(node) {
if (!(node instanceof jQuery) && !(node instanceof Element)) return undefined;
return node instanceof jQuery ? node[0] : node;
}
}

View File

@ -122,7 +122,6 @@ EmoteModule.prototype.init = async function () {
}; };
EmoteModule.prototype.disable = function() { EmoteModule.prototype.disable = function() {
this.disableAutoCapitalize();
if (this.cancelEmoteRender) return; if (this.cancelEmoteRender) return;
this.cancelEmoteRender(); this.cancelEmoteRender();
this.cancelEmoteRender = null; this.cancelEmoteRender = null;
@ -247,42 +246,11 @@ EmoteModule.prototype.downloadEmotes = function(emoteMeta) {
EmoteModule.prototype.getBlacklist = function () { EmoteModule.prototype.getBlacklist = function () {
return new Promise(resolve => { return new Promise(resolve => {
$.getJSON(`https://rauenzi.github.io/BetterDiscordApp/data/emotefilter.json`, function (data) { require("request").get({url: "https://rauenzi.github.io/BetterDiscordApp/data/emotefilter.json", json: true}, function (err, resp, data) {
resolve(bemotes.concat(data.blacklist)); if (err) return resolve(bemotes);
resolve(bemotes.splice(0, 0, ...data.blacklist));
}); });
}); });
}; };
EmoteModule.prototype.autoCapitalize = function () {
if (!settingsCookie["bda-es-4"] || this.autoCapitalizeActive) return;
$("body").on("keyup.bdac change.bdac paste.bdac", $(".channelTextArea-rNsIhG textarea:first"), () => {
const text = $(".channelTextArea-rNsIhG textarea:first").val();
if (text == undefined) return;
const lastWord = text.split(" ").pop();
if (lastWord.length > 3) {
if (lastWord == "danSgame") return;
const ret = this.capitalize(lastWord.toLowerCase());
if (ret !== null && ret !== undefined) {
Utils.insertText(Utils.getTextArea()[0], text.replace(lastWord, ret));
}
}
});
this.autoCapitalizeActive = true;
};
EmoteModule.prototype.capitalize = function (value) {
const res = bdEmotes.TwitchGlobal;
for (const p in res) {
if (res.hasOwnProperty(p) && value == (p + "").toLowerCase()) {
return p;
}
}
};
EmoteModule.prototype.disableAutoCapitalize = function() {
this.autoCapitalizeActive = false;
$("body").off(".bdac");
};
export default new EmoteModule(); export default new EmoteModule();

View File

@ -5,12 +5,15 @@ import BDEvents from "./bdEvents";
import Utils from "./utils"; import Utils from "./utils";
function PluginModule() { function PluginModule() {
this.getString = function(value) {
if (!value) return "???";
return typeof value == "string" ? value : value.toString();
};
} }
PluginModule.prototype.loadPlugins = function () { PluginModule.prototype.loadPlugins = function () {
this.loadPluginData(); this.loadPluginData();
bdpluginErrors.concat(ContentManager.loadPlugins()); bdpluginErrors.splice(0, 0, ...ContentManager.loadPlugins());
const plugins = Object.keys(bdplugins); const plugins = Object.keys(bdplugins);
for (let i = 0; i < plugins.length; i++) { for (let i = 0; i < plugins.length; i++) {
let plugin, name; let plugin, name;
@ -19,6 +22,11 @@ PluginModule.prototype.loadPlugins = function () {
plugin = bdplugins[plugins[i]].plugin; plugin = bdplugins[plugins[i]].plugin;
name = plugin.getName(); name = plugin.getName();
if (plugin.load && typeof(plugin.load) == "function") plugin.load(); if (plugin.load && typeof(plugin.load) == "function") plugin.load();
const meta = bdplugins[plugins[i]];
meta.name = this.getString(plugin.getName());
meta.author = this.getString(plugin.getAuthor());
meta.description = this.getString(plugin.getDescription());
meta.version = this.getString(plugin.getVersion());
} }
catch (err) { catch (err) {
pluginCookie[name] = false; pluginCookie[name] = false;

View File

@ -2,9 +2,10 @@ import {settingsCookie} from "../0globals";
import BDV2 from "./v2"; import BDV2 from "./v2";
import webpackModules from "./webpackModules"; import webpackModules from "./webpackModules";
import Utils from "./utils"; import Utils from "./utils";
import DOM from "./domtools";
import V2C_PublicServers from "../ui/publicServers"; import V2C_PublicServers from "../ui/publicservers/publicServers";
import Layer from "../ui/layer"; import Layer from "../ui/publicservers/layer";
export default new class V2_PublicServers { export default new class V2_PublicServers {
@ -13,7 +14,7 @@ export default new class V2_PublicServers {
} }
get component() { get component() {
return BDV2.react.createElement(Layer, {rootId: "pubslayerroot", id: "pubslayer", children: BDV2.react.createElement(V2C_PublicServers, {rootId: "pubslayerroot"})}); return BDV2.react.createElement(Layer, {rootId: "pubslayerroot", id: "pubslayer"}, BDV2.react.createElement(V2C_PublicServers, {rootId: "pubslayerroot"}));
} }
get root() { get root() {
@ -26,15 +27,13 @@ export default new class V2_PublicServers {
} }
injectRoot() { injectRoot() {
if (!$(".layers, .layers-3iHuyZ").length) return false; const layers = DOM.query(".layers, .layers-3iHuyZ");
$(".layers, .layers-3iHuyZ").append($("<div/>", { if (!layers) return false;
id: "pubslayerroot" layers.append(DOM.createElement("<div id='pubslayerroot'>"));
}));
return true; return true;
} }
render() { render() {
// BdApi.alert("Broken", "Sorry but the Public Servers modules is currently broken, I recommend disabling this feature for now.");
const root = this.root; const root = this.root;
if (!root) { if (!root) {
console.log("FAILED TO LOCATE ROOT: .layers"); console.log("FAILED TO LOCATE ROOT: .layers");
@ -44,25 +43,19 @@ export default new class V2_PublicServers {
} }
get button() { get button() {
const btn = $("<div/>", { const btn = DOM.createElement(`<div id="bd-pub-li" class="${BDV2.guildClasses.listItem}">`);
"class": BDV2.guildClasses.listItem, if (!settingsCookie["bda-gs-1"]) btn.style.display = "none";
"id": "bd-pub-li", const label = DOM.createElement(`<div id="bd-pub-button" class="${"wrapper-25eVIn " + BDV2.guildClasses.circleButtonMask}">public</div>`);
"style": settingsCookie["bda-gs-1"] ? "" : "display: none;" label.addEventListener("click", () => {this.render();});
}).append($("<div/>", { btn.append(label);
"class": "wrapper-25eVIn " + BDV2.guildClasses.circleButtonMask,
"text": "public",
"id": "bd-pub-button",
"click": () => { this.render(); }
}));
return btn; return btn;
} }
_appendButton() { _appendButton() {
if ($("#bd-pub-li").length) return; if (DOM.query("#bd-pub-li")) return;
const wrapper = BDV2.guildClasses.wrapper.split(" ")[0]; const wrapper = BDV2.guildClasses.wrapper.split(" ")[0];
const guilds = $(`.${wrapper} .scroller-2FKFPG >:first-child`); const guilds = DOM.query(`.${wrapper} .scroller-2FKFPG >:first-child`);
guilds.after(this.button); DOM.after(guilds, this.button);
} }
addButton() { addButton() {
@ -75,6 +68,6 @@ export default new class V2_PublicServers {
removeButton() { removeButton() {
this.guildPatch(); this.guildPatch();
delete this.guildPatch; delete this.guildPatch;
$("#bd-pub-li").remove(); DOM.query("#bd-pub-li").remove();
} }
}; };

View File

@ -2,194 +2,154 @@ import {settingsCookie, bdEmotes} from "../0globals";
import DataStore from "./dataStore"; import DataStore from "./dataStore";
import BDV2 from "./v2"; import BDV2 from "./v2";
import Utils from "./utils"; import Utils from "./utils";
import DOM from "./domtools";
function QuickEmoteMenu() { function QuickEmoteMenu() {
this.switchHandler = this.switchHandler.bind(this);
this.favContext = this.favContext.bind(this);
} }
const insertEmote = function(e) {
const emote = e.target.getAttribute("title");
const newTextarea = document.querySelector(`.${BDV2.slateEditorClasses.slateTextArea.split(" ")[0]}`);
if (newTextarea) {
const instance = BDV2.getInternalInstance(newTextarea);
const insert = Utils.getNestedProp(instance, "memoizedProps.children.props.editor.insertText");
if (insert) insert(` ${emote} `);
}
else {
const ta = Utils.getTextArea();
Utils.insertText(ta, ta.value.slice(-1) == " " ? ta.value + emote : ta.value + " " + emote);
}
};
const makeEmote = function(name, url, {click = insertEmote, contextmenu} = {}) {
const emote = DOM.createElement(`<div class="emote-container"><img class="emote-icon" alt="${name}" src="${url}" title="${name}"></div>`);
if (click) emote.addEventListener("click", click);
if (contextmenu) emote.addEventListener("contextmenu", contextmenu);
return emote;
};
QuickEmoteMenu.prototype.init = function() { QuickEmoteMenu.prototype.init = function() {
this.initialized = true; this.initialized = true;
$(document).on("mousedown", function(e) {
if (e.target.id != "rmenu") $("#rmenu").remove();
});
this.favoriteEmotes = {}; this.favoriteEmotes = {};
const fe = DataStore.getBDData("bdfavemotes"); const fe = DataStore.getBDData("bdfavemotes");
if (fe !== "" && fe !== null) { if (fe !== "" && fe !== null) this.favoriteEmotes = JSON.parse(atob(fe));
this.favoriteEmotes = JSON.parse(atob(fe));
}
let qmeHeader = ""; this.qmeHeader = DOM.createElement(`<div id="bda-qem">`);
qmeHeader += "<div id=\"bda-qem\">"; this.twitchButton = DOM.createElement(`<button class="active" id="bda-qem-twitch">Twitch</button>`);
qmeHeader += " <button class=\"active\" id=\"bda-qem-twitch\" onclick='quickEmoteMenu.switchHandler(this); return false;'>Twitch</button>"; this.favoriteButton = DOM.createElement(`<button id="bda-qem-favourite">Favorite</button>`);
qmeHeader += " <button id=\"bda-qem-favourite\" onclick='quickEmoteMenu.switchHandler(this); return false;'>Favourite</button>"; this.emojiButton = DOM.createElement(`<button id="bda-qem-emojis">Emojis</buttond>`);
qmeHeader += " <button id=\"bda-qem-emojis\" onclick='quickEmoteMenu.switchHandler(this); return false;'>Emojis</buttond>"; this.twitchButton.addEventListener("click", this.switchHandler);
qmeHeader += "</div>"; this.favoriteButton.addEventListener("click", this.switchHandler);
this.qmeHeader = qmeHeader; this.emojiButton.addEventListener("click", this.switchHandler);
this.qmeHeader.append(this.twitchButton, this.favoriteButton, this.emojiButton);
let teContainer = "";
teContainer += "<div id=\"bda-qem-twitch-container\">"; this.teContainer = DOM.createElement(`<div id="bda-qem-twitch-container"><div class="scroller-wrap scrollerWrap-2lJEkd fade"><div class="scroller scroller-2FKFPG"><div class="emote-menu-inner"></div></div></div></div>`);
teContainer += " <div class=\"scroller-wrap scrollerWrap-2lJEkd fade\">"; this.teInner = this.teContainer.querySelector(".emote-menu-inner");
teContainer += " <div class=\"scroller scroller-2FKFPG\">";
teContainer += " <div class=\"emote-menu-inner\">";
let url = "";
for (const emote in bdEmotes.TwitchGlobal) { for (const emote in bdEmotes.TwitchGlobal) {
if (bdEmotes.TwitchGlobal.hasOwnProperty(emote)) { if (!bdEmotes.TwitchGlobal.hasOwnProperty(emote)) continue;
url = bdEmotes.TwitchGlobal[emote]; this.teInner.append(makeEmote(emote, bdEmotes.TwitchGlobal[emote]));
teContainer += "<div class=\"emote-container\">";
teContainer += " <img class=\"emote-icon\" alt=\"\" src=\"" + url + "\" title=\"" + emote + "\">";
teContainer += " </img>";
teContainer += "</div>";
}
} }
teContainer += " </div>";
teContainer += " </div>";
teContainer += " </div>";
teContainer += "</div>";
this.teContainer = teContainer;
let faContainer = ""; this.faContainer = DOM.createElement(`<div id="bda-qem-favourite-container"><div class="scroller-wrap scrollerWrap-2lJEkd fade"><div class="scroller scroller-2FKFPG"><div class="emote-menu-inner"></div></div></div></div>`);
faContainer += "<div id=\"bda-qem-favourite-container\">"; this.faInner = this.faContainer.querySelector(".emote-menu-inner");
faContainer += " <div class=\"scroller-wrap scrollerWrap-2lJEkd fade\">";
faContainer += " <div class=\"scroller scroller-2FKFPG\">";
faContainer += " <div class=\"emote-menu-inner\">";
for (const emote in this.favoriteEmotes) { for (const emote in this.favoriteEmotes) {
url = this.favoriteEmotes[emote]; this.faInner.append(makeEmote(emote, this.favoriteEmotes[emote], {contextmenu: this.favContext}));
faContainer += "<div class=\"emote-container\">";
faContainer += " <img class=\"emote-icon\" alt=\"\" src=\"" + url + "\" title=\"" + emote + "\" oncontextmenu='quickEmoteMenu.favContext(event, this);'>";
faContainer += " </img>";
faContainer += "</div>";
} }
faContainer += " </div>";
faContainer += " </div>";
faContainer += " </div>";
faContainer += "</div>";
this.faContainer = faContainer;
}; };
QuickEmoteMenu.prototype.favContext = function(e, em) { QuickEmoteMenu.prototype.favContext = function(e) {
e.stopPropagation(); e.stopPropagation();
const menu = $("<div>", {"id": "removemenu", "data-emoteid": $(em).prop("title"), "text": "Remove", "class": "bd-context-menu context-menu theme-dark"}); const container = DOM.query("#app-mount");
menu.css({ const cmWrap = DOM.createElement(`<div class="layer-v9HyYc da-layer">`);
top: e.pageY - $("#bda-qem-favourite-container").offset().top, const cm = DOM.createElement(`<div class="contextMenu-HLZMGh da-contextMenu bd-context-menu"></div>`);
left: e.pageX - $("#bda-qem-favourite-container").offset().left cmWrap.append(cm);
}); container.append(cmWrap);
$(em).parent().append(menu); cmWrap.style.top = e.clientY + "px";
const self = this; cmWrap.style.left = e.clientX + "px";
menu.on("click", function(e) { cmWrap.style.zIndex = "1002";
e.preventDefault(); const removeCM = function(e) {
e.stopPropagation(); if (e && e.keyCode && e.keyCode !== 27) return;
$(this).remove(); cmWrap.remove();
document.removeEventListener("click", removeCM);
document.removeEventListener("contextmenu", removeCM);
document.removeEventListener("keyup", removeCM);
};
document.addEventListener("click", removeCM);
document.addEventListener("contextmenu", removeCM);
document.addEventListener("keyup", removeCM);
delete self.favoriteEmotes[$(this).data("emoteid")]; const cmg = DOM.createElement(`<div class="itemGroup-1tL0uz da-itemGroup">`);
self.updateFavorites(); const cmi = DOM.createElement(`<div class="item-1Yvehc itemBase-tz5SeC da-item da-itemBase clickable-11uBi- da-clickable">`);
return false; cmi.append(DOM.createElement(`<div class="label-JWQiNe da-label">Remove</div>`));
cmi.addEventListener("click", () => {
delete this.favoriteEmotes[e.target.getAttribute("title")];
e.target.parentElement.remove();
this.saveFavorites();
removeCM();
}); });
return false; cmg.append(cmi);
cm.append(cmg);
}; };
QuickEmoteMenu.prototype.switchHandler = function(e) { QuickEmoteMenu.prototype.switchHandler = function(e) {
this.switchQem($(e).attr("id")); this.switchQem(e.target.id);
}; };
QuickEmoteMenu.prototype.switchQem = function(id) { QuickEmoteMenu.prototype.switchQem = function(id) {
const twitch = $("#bda-qem-twitch"); this.twitchButton.classList.remove("active");
const fav = $("#bda-qem-favourite"); this.favoriteButton.classList.remove("active");
const emojis = $("#bda-qem-emojis"); this.emojiButton.classList.remove("active");
twitch.removeClass("active");
fav.removeClass("active");
emojis.removeClass("active");
$(".emojiPicker-3m1S-j").hide(); const emojiPicker = DOM.query(".emojiPicker-3m1S-j");
$("#bda-qem-favourite-container").hide(); emojiPicker.style.display = "none";
$("#bda-qem-twitch-container").hide(); this.faContainer.style.display = "none";
this.teContainer.style.display = "none";
switch (id) { switch (id) {
case "bda-qem-twitch": case "bda-qem-twitch":
twitch.addClass("active"); this.twitchButton.classList.add("active");
$("#bda-qem-twitch-container").show(); this.teContainer.style.display = "";
break; break;
case "bda-qem-favourite": case "bda-qem-favourite":
fav.addClass("active"); this.favoriteButton.classList.add("active");
$("#bda-qem-favourite-container").show(); this.faContainer.style.display = "";
break; break;
case "bda-qem-emojis": case "bda-qem-emojis":
emojis.addClass("active"); this.emojiButton.classList.add("active");
$(".emojiPicker-3m1S-j").show(); emojiPicker.style.display = "";
$(".emojiPicker-3m1S-j input").focus(); emojiPicker.querySelector("input").focus();
break; break;
} }
this.lastTab = id;
const emoteIcon = $(".emote-icon");
emoteIcon.off();
emoteIcon.on("click", function () {
const emote = $(this).attr("title");
const newTextarea = document.querySelector(`.${BDV2.slateEditorClasses.slateTextArea.split(" ")[0]}`);
if (newTextarea) {
const instance = BDV2.getInternalInstance(newTextarea);
const insert = Utils.getNestedProp(instance, "memoizedProps.children.props.editor.insertText");
if (insert) insert(` ${emote} `);
}
else {
const ta = Utils.getTextArea();
Utils.insertText(ta[0], ta.val().slice(-1) == " " ? ta.val() + emote : ta.val() + " " + emote);
}
});
}; };
QuickEmoteMenu.prototype.obsCallback = function (elem) { QuickEmoteMenu.prototype.obsCallback = function (elem) {
if (!this.initialized) return; if (!this.initialized) return;
const e = $(elem); if (!settingsCookie["bda-es-9"]) elem.classList.add("bda-qme-hidden");
if (!settingsCookie["bda-es-9"]) { else elem.classList.remove("bda-qme-hidden");
e.addClass("bda-qme-hidden");
}
else {
e.removeClass("bda-qme-hidden");
}
if (!settingsCookie["bda-es-0"]) return; if (!settingsCookie["bda-es-0"]) return;
DOM.prependTo(this.qmeHeader, elem);
e.prepend(this.qmeHeader); elem.append(this.teContainer);
e.append(this.teContainer); elem.append(this.faContainer);
e.append(this.faContainer); this.switchQem("bda-qem-emojis");
if (this.lastTab == undefined) {
this.lastTab = "bda-qem-emojis";
}
this.switchQem(this.lastTab);
}; };
QuickEmoteMenu.prototype.favorite = function (name, url) { QuickEmoteMenu.prototype.favorite = function (name, url) {
if (!this.favoriteEmotes.hasOwnProperty(name)) this.favoriteEmotes[name] = url;
if (!this.favoriteEmotes.hasOwnProperty(name)) {
this.favoriteEmotes[name] = url;
}
this.updateFavorites(); this.updateFavorites();
}; };
QuickEmoteMenu.prototype.updateFavorites = function () { QuickEmoteMenu.prototype.saveFavorites = function () {
let faContainer = "";
faContainer += "<div id=\"bda-qem-favourite-container\">";
faContainer += " <div class=\"scroller-wrap scrollerWrap-2lJEkd fade\">";
faContainer += " <div class=\"scroller scroller-2FKFPG\">";
faContainer += " <div class=\"emote-menu-inner\">";
for (const emote in this.favoriteEmotes) {
const url = this.favoriteEmotes[emote];
faContainer += "<div class=\"emote-container\">";
faContainer += " <img class=\"emote-icon\" alt=\"\" src=\"" + url + "\" title=\"" + emote + "\" oncontextmenu=\"quickEmoteMenu.favContext(event, this);\">";
faContainer += " </img>";
faContainer += "</div>";
}
faContainer += " </div>";
faContainer += " </div>";
faContainer += " </div>";
faContainer += "</div>";
this.faContainer = faContainer;
$("#bda-qem-favourite-container").replaceWith(faContainer);
DataStore.setBDData("bdfavemotes", btoa(JSON.stringify(this.favoriteEmotes))); DataStore.setBDData("bdfavemotes", btoa(JSON.stringify(this.favoriteEmotes)));
}; };
QuickEmoteMenu.prototype.updateFavorites = function () {
this.faInner.innerHTML = "";
for (const emote in this.favoriteEmotes) this.faInner.append(makeEmote(emote, this.favoriteEmotes[emote], {contextmenu: this.favContext}));
this.saveFavorites();
};
export default new QuickEmoteMenu(); export default new QuickEmoteMenu();

View File

@ -8,6 +8,7 @@ import BDEvents from "./bdEvents";
import coloredText from "./coloredText"; import coloredText from "./coloredText";
import tfHour from "./24hour"; import tfHour from "./24hour";
import reactDevTools from "./reactDevTools"; import reactDevTools from "./reactDevTools";
import DOM from "./domtools";
import publicServersModule from "./publicServers"; import publicServersModule from "./publicServers";
import voiceMode from "./voiceMode"; import voiceMode from "./voiceMode";
@ -26,34 +27,32 @@ import CardList from "../ui/addonlist";
export default new class V2_SettingsPanel { export default new class V2_SettingsPanel {
constructor() { constructor() {
const self = this; this.sideBarOnClick = this.sideBarOnClick.bind(this);
self.sideBarOnClick = self.sideBarOnClick.bind(self); this.onChange = this.onChange.bind(this);
self.onChange = self.onChange.bind(self); this.updateSettings = this.updateSettings.bind(this);
self.updateSettings = this.updateSettings.bind(self); this.sidebar = new V2_SettingsPanel_Sidebar(this.sideBarOnClick);
self.sidebar = new V2_SettingsPanel_Sidebar(self.sideBarOnClick);
this.buildPluginProps = this.buildPluginProps.bind(this); this.buildPluginProps = this.buildPluginProps.bind(this);
this.buildThemeProps = this.buildThemeProps.bind(this); this.buildThemeProps = this.buildThemeProps.bind(this);
this.showOriginal = this.showOriginal.bind(this);
} }
get root() { get root() {
const _root = $("#bd-settingspane-container"); const _root = DOM.query("#bd-settingspane-container");
if (!_root.length) { if (!_root) {
if (!this.injectRoot()) return null; if (!this.injectRoot()) return null;
return this.root; return this.root;
} }
return _root[0]; return _root;
} }
injectRoot() { injectRoot() {
if (!$(".layer-3QrUeG .standardSidebarView-3F1I7i, .layer-3QrUeG .ui-standard-sidebar-view").length) return false; const sidebar = DOM.query(".layer-3QrUeG .standardSidebarView-3F1I7i, .layer-3QrUeG .ui-standard-sidebar-view");
const root = $("<div/>", { if (!sidebar) return false;
"class": "contentRegion-3nDuYy content-region", const root = DOM.createElement(`<div id="bd-settingspane-container" class="contentRegion-3nDuYy content-region">`);
"id": "bd-settingspane-container" sidebar.append(root);
});
$(".layer-3QrUeG .standardSidebarView-3F1I7i, .layer-3QrUeG .ui-standard-sidebar-view").append(root);
Utils.onRemoved(root[0], () => { Utils.onRemoved(root, () => {
BDV2.reactDom.unmountComponentAtNode(root[0]); BDV2.reactDom.unmountComponentAtNode(root);
}); });
return true; return true;
} }
@ -80,24 +79,24 @@ export default new class V2_SettingsPanel {
} }
sideBarOnClick(id) { sideBarOnClick(id) {
const self = this; const contentRegion = DOM.query(".contentRegion-3nDuYy, .content-region");
$(".contentRegion-3nDuYy, .content-region").first().hide(); contentRegion.style.display = "none";
$(self.root).show(); this.root.style.display = "";
switch (id) { switch (id) {
case "core": case "core":
self.renderCoreSettings(); this.renderCoreSettings();
break; break;
case "emotes": case "emotes":
self.renderEmoteSettings(); this.renderEmoteSettings();
break; break;
case "customcss": case "customcss":
self.renderCustomCssEditor(); this.renderCustomCssEditor();
break; break;
case "plugins": case "plugins":
self.renderPluginPane(); this.renderPluginPane();
break; break;
case "themes": case "themes":
self.renderThemePane(); this.renderThemePane();
break; break;
} }
} }
@ -111,19 +110,14 @@ export default new class V2_SettingsPanel {
updateSettings(id, enabled) { updateSettings(id, enabled) {
settingsCookie[id] = enabled; settingsCookie[id] = enabled;
// if (id == "bda-gs-b") {
// if (enabled) $("body").addClass("bd-blue");
// else $("body").removeClass("bd-blue");
// }
if (id == "bda-gs-2") { if (id == "bda-gs-2") {
if (enabled) $("body").addClass("bd-minimal"); if (enabled) DOM.addClass(document.body, "bd-minimal");
else $("body").removeClass("bd-minimal"); else DOM.removeClass(document.body, "bd-minimal");
} }
if (id == "bda-gs-3") { if (id == "bda-gs-3") {
if (enabled) $("body").addClass("bd-minimal-chan"); if (enabled) DOM.addClass(document.body, "bd-minimal-chan");
else $("body").removeClass("bd-minimal-chan"); else DOM.removeClass(document.body, "bd-minimal-chan");
} }
if (id == "bda-gs-1") { if (id == "bda-gs-1") {
@ -132,13 +126,13 @@ export default new class V2_SettingsPanel {
} }
if (id == "bda-gs-4") { if (id == "bda-gs-4") {
if (enabled) voiceMode.enable(); if (enabled) voiceMode.start();
else voiceMode.disable(); else voiceMode.stop();
} }
if (id == "bda-gs-5") { if (id == "bda-gs-5") {
if (enabled) $("#app-mount").addClass("bda-dark"); if (enabled) DOM.addClass(DOM.query("#app-mount"), "bda-dark");
else $("#app-mount").removeClass("bda-dark"); else DOM.removeClass(DOM.query("#app-mount"), "bda-dark");
} }
if (enabled && id == "bda-gs-6") tfHour.inject24Hour(); if (enabled && id == "bda-gs-6") tfHour.inject24Hour();
@ -148,11 +142,6 @@ export default new class V2_SettingsPanel {
else coloredText.removeColoredText(); else coloredText.removeColoredText();
} }
if (id == "bda-es-4") {
if (enabled) emoteModule.autoCapitalize();
else emoteModule.disableAutoCapitalize();
}
if (id == "fork-ps-4") { if (id == "fork-ps-4") {
if (enabled) ClassNormalizer.start(); if (enabled) ClassNormalizer.start();
else ClassNormalizer.stop(); else ClassNormalizer.stop();
@ -182,12 +171,13 @@ export default new class V2_SettingsPanel {
if (id == "bda-gs-8") { if (id == "bda-gs-8") {
if (enabled) dMode.enable(settingsCookie["fork-dm-1"]); if (enabled) dMode.startDebugListener();
else dMode.disable(); else dMode.stopDebugListener();
} }
if (id == "fork-dm-1") { if (id == "fork-dm-1") {
if (settingsCookie["bda-gs-8"]) dMode.enable(enabled); if (enabled) dMode.startCopySelector();
else dMode.stopCopySelector();
} }
if (id === "reactDevTools") { if (id === "reactDevTools") {
@ -199,15 +189,13 @@ export default new class V2_SettingsPanel {
} }
async initializeSettings() { async initializeSettings() {
// if (settingsCookie["bda-gs-b"]) $("body").addClass("bd-blue"); if (settingsCookie["bda-gs-2"]) DOM.addClass(document.body, "bd-minimal");
if (settingsCookie["bda-gs-2"]) $("body").addClass("bd-minimal"); if (settingsCookie["bda-gs-3"]) DOM.addClass(document.body, "bd-minimal-chan");
if (settingsCookie["bda-gs-3"]) $("body").addClass("bd-minimal-chan");
if (settingsCookie["bda-gs-1"]) publicServersModule.addButton(); if (settingsCookie["bda-gs-1"]) publicServersModule.addButton();
if (settingsCookie["bda-gs-4"]) voiceMode.enable(); if (settingsCookie["bda-gs-4"]) voiceMode.start();
if (settingsCookie["bda-gs-5"]) $("#app-mount").addClass("bda-dark"); if (settingsCookie["bda-gs-5"]) DOM.addClass(DOM.query("#app-mount"), "bda-dark");
if (settingsCookie["bda-gs-6"]) tfHour.inject24Hour(); if (settingsCookie["bda-gs-6"]) tfHour.inject24Hour();
if (settingsCookie["bda-gs-7"]) coloredText.injectColoredText(); if (settingsCookie["bda-gs-7"]) coloredText.injectColoredText();
if (settingsCookie["bda-es-4"]) emoteModule.autoCapitalize();
if (settingsCookie["fork-ps-4"]) ClassNormalizer.start(); if (settingsCookie["fork-ps-4"]) ClassNormalizer.start();
if (settingsCookie["fork-ps-5"]) { if (settingsCookie["fork-ps-5"]) {
@ -215,7 +203,8 @@ export default new class V2_SettingsPanel {
ContentManager.watchContent("theme"); ContentManager.watchContent("theme");
} }
if (settingsCookie["bda-gs-8"]) dMode.enable(settingsCookie["fork-dm-1"]); if (settingsCookie["bda-gs-8"]) dMode.startDebugListener();
if (settingsCookie["fork-dm-1"]) dMode.startCopySelector();
if (settingsCookie.reactDevTools) reactDevTools.start(); if (settingsCookie.reactDevTools) reactDevTools.start();
this.saveSettings(); this.saveSettings();
@ -229,14 +218,19 @@ export default new class V2_SettingsPanel {
Object.assign(settingsCookie, DataStore.getSettingGroup("settings")); Object.assign(settingsCookie, DataStore.getSettingGroup("settings"));
} }
showOriginal() {
BDV2.reactDom.unmountComponentAtNode(this.root);
this.root.style.display = "none";
DOM.query(".contentRegion-3nDuYy, .content-region").style.display = "";
}
renderSidebar() { renderSidebar() {
const self = this; const tabs = document.querySelectorAll("[class*='side-'] > [class*='item-']");
$("[class*='side-'] > [class*='item-']").off("click.v2settingspanel").on("click.v2settingspanel", () => { for (const element of tabs) {
BDV2.reactDom.unmountComponentAtNode(self.root); element.removeEventListener("click", this.showOriginal);
$(self.root).hide(); element.addEventListener("click", this.showOriginal);
$(".contentRegion-3nDuYy, .content-region").first().show(); }
}); this.sidebar.render();
self.sidebar.render();
} }
get coreComponent() { get coreComponent() {
@ -322,7 +316,7 @@ export default new class V2_SettingsPanel {
getAddonList(type) { getAddonList(type) {
const isPlugins = type === "plugins"; const isPlugins = type === "plugins";
const list = isPlugins ? Object.values(bdplugins).map(this.buildPluginProps) : Object.values(bdthemes).map(this.buildThemeProps); const list = isPlugins ? Object.values(bdplugins) : Object.values(bdthemes);
return BDV2.react.createElement(CardList, {type, list}); return BDV2.react.createElement(CardList, {type, list});
} }

View File

@ -1,6 +1,7 @@
import {bbdChangelog} from "../0globals"; import {bbdChangelog} from "../0globals";
import Utils from "./utils"; import Utils from "./utils";
import BDV2 from "./v2"; import BDV2 from "./v2";
import DOM from "./domtools";
import SideBar from "../ui/sidebar"; import SideBar from "../ui/sidebar";
import History from "../ui/icons/history"; import History from "../ui/icons/history";
@ -28,18 +29,19 @@ export default class V2_SettingsPanel_Sidebar {
} }
get root() { get root() {
const _root = $("#bd-settings-sidebar"); const _root = DOM.query("#bd-settings-sidebar");
if (!_root.length) { if (!_root) {
if (!this.injectRoot()) return null; if (!this.injectRoot()) return null;
return this.root; return this.root;
} }
return _root[0]; return _root;
} }
injectRoot() { injectRoot() {
const changeLog = $("[class*='side-'] > [class*='item-']:not([class*=Danger])").last(); const tabs = DOM.queryAll("[class*='side-'] > [class*='item-']:not([class*=Danger])");
if (!changeLog.length) return false; const changeLog = tabs[tabs.length - 1];
$("<span/>", {id: "bd-settings-sidebar"}).insertBefore(changeLog.prev()); if (!changeLog) return false;
changeLog.parentElement.insertBefore(DOM.createElement(`<div id="bd-settings-sidebar">`), changeLog.previousElementSibling);
return true; return true;
} }

View File

@ -3,20 +3,28 @@ import ContentManager from "./contentManager";
import DataStore from "./dataStore"; import DataStore from "./dataStore";
import BDEvents from "./bdEvents"; import BDEvents from "./bdEvents";
import Utils from "./utils"; import Utils from "./utils";
import DOM from "./domtools";
function ThemeModule() { function ThemeModule() {
this.getString = function(value) {
if (!value) return "???";
return typeof value == "string" ? value : value.toString();
};
} }
ThemeModule.prototype.loadThemes = function () { ThemeModule.prototype.loadThemes = function () {
this.loadThemeData(); this.loadThemeData();
bdthemeErrors.concat(ContentManager.loadThemes()); bdthemeErrors.splice(0, 0, ...ContentManager.loadThemes());
const themes = Object.keys(bdthemes); const themes = Object.keys(bdthemes);
for (let i = 0; i < themes.length; i++) { for (let i = 0; i < themes.length; i++) {
const theme = bdthemes[themes[i]]; const theme = bdthemes[themes[i]];
theme.name = this.getString(theme.name);
theme.author = this.getString(theme.author);
theme.description = this.getString(theme.description);
theme.version = this.getString(theme.version);
if (!themeCookie[theme.name]) themeCookie[theme.name] = false; if (!themeCookie[theme.name]) themeCookie[theme.name] = false;
if (themeCookie[theme.name]) $("head").append($("<style>", {id: theme.id, text: unescape(theme.css)})); if (themeCookie[theme.name]) DOM.addStyle(DOM.escapeID(theme.id), unescape(theme.css));
} }
for (const theme in themeCookie) { for (const theme in themeCookie) {
if (!bdthemes[theme]) delete themeCookie[theme]; if (!bdthemes[theme]) delete themeCookie[theme];
@ -29,7 +37,7 @@ ThemeModule.prototype.enableTheme = function(name, reload = false) {
themeCookie[name] = true; themeCookie[name] = true;
this.saveThemeData(); this.saveThemeData();
const theme = bdthemes[name]; const theme = bdthemes[name];
$("head").append($("<style>", {id: theme.id, text: unescape(theme.css)})); DOM.addStyle(DOM.escapeID(theme.id), unescape(theme.css));
if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${theme.name} v${theme.version} has been applied.`); if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${theme.name} v${theme.version} has been applied.`);
}; };
@ -41,7 +49,7 @@ ThemeModule.prototype.disableTheme = function(name, reload = false) {
themeCookie[name] = false; themeCookie[name] = false;
this.saveThemeData(); this.saveThemeData();
const theme = bdthemes[name]; const theme = bdthemes[name];
$(`#${theme.id}`).remove(); DOM.removeStyle(DOM.escapeID(theme.id));
if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${theme.name} v${theme.version} has been disabled.`); if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${theme.name} v${theme.version} has been disabled.`);
}; };

View File

@ -1,6 +1,7 @@
import {bbdVersion} from "../0globals"; import {bbdVersion} from "../0globals";
import WebpackModules from "./webpackModules"; import WebpackModules from "./webpackModules";
import BDV2 from "./v2"; import BDV2 from "./v2";
import DOM from "./domtools";
export default class Utils { export default class Utils {
/** Document/window width */ /** Document/window width */
@ -49,7 +50,7 @@ export default class Utils {
} }
static getTextArea() { static getTextArea() {
return $(".channelTextArea-rNsIhG textarea"); return DOM.query(".channelTextArea-rNsIhG textarea");
} }
static insertText(textarea, text) { static insertText(textarea, text) {
@ -59,24 +60,6 @@ export default class Utils {
document.execCommand("insertText", false, text); document.execCommand("insertText", false, text);
} }
static injectCss(uri) {
$("<link/>", {
type: "text/css",
rel: "stylesheet",
href: uri
}).appendTo($("head"));
}
static injectJs(uri) {
return new Promise(resolve => {
$("<script/>", {
type: "text/javascript",
src: uri,
onload: resolve
}).appendTo($("body"));
});
}
static escapeID(id) { static escapeID(id) {
return id.replace(/^[^a-z]+|[^\w-]+/gi, "-"); return id.replace(/^[^a-z]+|[^\w-]+/gi, "-");
} }
@ -231,7 +214,7 @@ export default class Utils {
} }
static alert(title, content) { static alert(title, content) {
const modal = $(`<div class="bd-modal-wrapper theme-dark"> const modal = DOM.createElement(`<div class="bd-modal-wrapper theme-dark">
<div class="bd-backdrop backdrop-1wrmKB"></div> <div class="bd-backdrop backdrop-1wrmKB"></div>
<div class="bd-modal modal-1UGdnR"> <div class="bd-modal modal-1UGdnR">
<div class="bd-modal-inner inner-1JeGVc"> <div class="bd-modal-inner inner-1JeGVc">
@ -251,21 +234,21 @@ export default class Utils {
</div> </div>
</div> </div>
</div>`); </div>`);
modal.find(".footer button").on("click", () => { modal.querySelector(".footer button").addEventListener("click", () => {
modal.addClass("closing"); DOM.addClass(modal, "closing");
setTimeout(() => { modal.remove(); }, 300); setTimeout(() => { modal.remove(); }, 300);
}); });
modal.find(".bd-backdrop").on("click", () => { modal.querySelector(".bd-backdrop").addEventListener("click", () => {
modal.addClass("closing"); DOM.addClass(modal, "closing");
setTimeout(() => { modal.remove(); }, 300); setTimeout(() => { modal.remove(); }, 300);
}); });
modal.appendTo("#app-mount"); DOM.query("#app-mount").append(modal);
} }
static showContentErrors({plugins: pluginErrors = [], themes: themeErrors = []}) { static showContentErrors({plugins: pluginErrors = [], themes: themeErrors = []}) {
if (!pluginErrors || !themeErrors) return; if (!pluginErrors || !themeErrors) return;
if (!pluginErrors.length && !themeErrors.length) return; if (!pluginErrors.length && !themeErrors.length) return;
const modal = $(`<div class="bd-modal-wrapper theme-dark"> const modal = DOM.createElement(`<div class="bd-modal-wrapper theme-dark">
<div class="bd-backdrop backdrop-1wrmKB"></div> <div class="bd-backdrop backdrop-1wrmKB"></div>
<div class="bd-modal bd-content-modal modal-1UGdnR"> <div class="bd-modal bd-content-modal modal-1UGdnR">
<div class="bd-modal-inner inner-1JeGVc"> <div class="bd-modal-inner inner-1JeGVc">
@ -288,7 +271,7 @@ export default class Utils {
</div> </div>
</div> </div>
</div> </div>
<div class="footer footer-2yfCgX"> <div class="footer footer-2yfCgX footer-3rDWdC footer-2gL1pp">
<button type="button">Okay</button> <button type="button">Okay</button>
</div> </div>
</div> </div>
@ -296,19 +279,19 @@ export default class Utils {
</div>`); </div>`);
function generateTab(errors) { function generateTab(errors) {
const container = $(`<div class="errors">`); const container = DOM.createElement(`<div class="errors">`);
for (const err of errors) { for (const err of errors) {
const error = $(`<div class="error"> const error = DOM.createElement(`<div class="error">
<div class="table-column column-name">${err.name ? err.name : err.file}</div> <div class="table-column column-name">${err.name ? err.name : err.file}</div>
<div class="table-column column-message">${err.message}</div> <div class="table-column column-message">${err.message}</div>
<div class="table-column column-error"><a class="error-link" href="">${err.error ? err.error.message : ""}</a></div> <div class="table-column column-error"><a class="error-link" href="">${err.error ? err.error.message : ""}</a></div>
</div>`); </div>`);
container.append(error); container.append(error);
if (err.error) { if (err.error) {
error.find("a").on("click", (e) => { error.querySelectorAll("a").forEach(el => el.addEventListener("click", (e) => {
e.preventDefault(); e.preventDefault();
Utils.err("ContentManager", `Error details for ${err.name ? err.name : err.file}.`, err.error); Utils.err("ContentManager", `Error details for ${err.name ? err.name : err.file}.`, err.error);
}); }));
} }
} }
return container; return container;
@ -316,24 +299,27 @@ export default class Utils {
const tabs = [generateTab(pluginErrors), generateTab(themeErrors)]; const tabs = [generateTab(pluginErrors), generateTab(themeErrors)];
modal.find(".tab-bar-item").on("click", (e) => { modal.querySelectorAll(".tab-bar-item").forEach(el => el.addEventListener("click", (e) => {
e.preventDefault(); e.preventDefault();
modal.find(".tab-bar-item").removeClass("selected"); const selected = modal.querySelector(".tab-bar-item.selected");
$(e.target).addClass("selected"); if (selected) DOM.removeClass(selected, "selected");
modal.find(".scroller").empty().append(tabs[$(e.target).index()]); DOM.addClass(e.target, "selected");
}); const scroller = modal.querySelector(".scroller");
scroller.innerHTML = "";
scroller.append(tabs[DOM.index(e.target)]);
}));
modal.find(".footer button").on("click", () => { modal.querySelector(".footer button").addEventListener("click", () => {
modal.addClass("closing"); DOM.addClass(modal, "closing");
setTimeout(() => { modal.remove(); }, 300); setTimeout(() => { modal.remove(); }, 300);
}); });
modal.find(".bd-backdrop").on("click", () => { modal.querySelector(".bd-backdrop").on("click", () => {
modal.addClass("closing"); DOM.addClass(modal, "closing");
setTimeout(() => { modal.remove(); }, 300); setTimeout(() => { modal.remove(); }, 300);
}); });
modal.appendTo("#app-mount"); DOM.query("#app-mount").append(modal);
if (pluginErrors.length) modal.find(".tab-bar-item")[0].click(); if (pluginErrors.length) modal.querySelector(".tab-bar-item").click();
else modal.find(".tab-bar-item")[1].click(); else modal.querySelectorAll(".tab-bar-item")[1].click();
} }
static showChangelogModal(options = {}) { static showChangelogModal(options = {}) {

View File

@ -1,23 +1,25 @@
function VoiceMode() { import DOM from "./domtools";
} const style = `
.container-2Rl01u {
display: none!important;
}
VoiceMode.prototype.enable = function () { .chat-3bRxxu {
$(".scroller.guild-channels ul").first().css("display", "none"); display: none!important;
$(".scroller.guild-channels header").first().css("display", "none"); }
$(".app.flex-vertical, .app-2rEoOp").first().css("overflow", "hidden");
$(".chat-3bRxxu").first().css("visibility", "hidden").css("min-width", "0px");
$(".flex-vertical.channels-wrap").first().css("flex-grow", "100000");
$(".guild-header .btn.btn-hamburger").first().css("visibility", "hidden");
};
VoiceMode.prototype.disable = function () { .sidebar-2K8pFh {
$(".scroller.guild-channels ul").first().css("display", ""); flex-grow: 1!important;
$(".scroller.guild-channels header").first().css("display", ""); }
$(".app.flex-vertical, .app-2rEoOp").first().css("overflow", ""); `;
$(".chat-3bRxxu").first().css("visibility", "").css("min-width", "");
$(".flex-vertical.channels-wrap").first().css("flex-grow", "");
$(".guild-header .btn.btn-hamburger").first().css("visibility", "");
};
export default new VoiceMode(); export default new class VoiceMode {
start() {
DOM.addStyle("VoiceMode", style);
}
stop() {
DOM.removeStyle("VoiceMode");
}
};

View File

@ -1,6 +1,7 @@
import {settingsCookie} from "../0globals"; import {settingsCookie} from "../0globals";
import BDV2 from "../modules/v2"; import BDV2 from "../modules/v2";
import Utils from "../modules/utils"; import Utils from "../modules/utils";
import DOM from "../modules/domtools";
import XSvg from "./xSvg"; import XSvg from "./xSvg";
import ReloadIcon from "./reloadIcon"; import ReloadIcon from "./reloadIcon";
@ -18,7 +19,7 @@ export default class V2C_PluginCard extends BDV2.reactComponent {
this.onChange = this.onChange.bind(this); this.onChange = this.onChange.bind(this);
this.showSettings = this.showSettings.bind(this); this.showSettings = this.showSettings.bind(this);
this.setInitialState(); this.setInitialState();
this.hasSettings = typeof this.props.addon.getSettingsPanel === "function"; this.hasSettings = this.props.addon.plugin && typeof this.props.addon.plugin.getSettingsPanel === "function";
this.settingsPanel = ""; this.settingsPanel = "";
this.edit = this.edit.bind(this); this.edit = this.edit.bind(this);
@ -51,20 +52,30 @@ export default class V2C_PluginCard extends BDV2.reactComponent {
} }
if (!settingsCookie["fork-ps-3"]) return; if (!settingsCookie["fork-ps-3"]) return;
const isHidden = (container, element) => { setImmediate(() => {
const cTop = container.scrollTop; const isHidden = (container, element) => {
const cBottom = cTop + container.clientHeight; const cTop = container.scrollTop;
const eTop = element.offsetTop; const cBottom = cTop + container.clientHeight;
const eBottom = eTop + element.clientHeight; const eTop = element.offsetTop;
return (eTop < cTop || eBottom > cBottom); const eBottom = eTop + element.clientHeight;
}; return (eTop < cTop || eBottom > cBottom);
};
const thisNode = $(BDV2.reactDom.findDOMNode(this)); const thisNode = this.refs.cardNode;
const container = thisNode.parents(".scroller"); const container = thisNode.closest(".scroller");
if (!isHidden(container[0], thisNode[0])) return; if (!isHidden(container, thisNode)) return;
container.animate({ const thisNodeOffset = DOM.offset(thisNode);
scrollTop: thisNode.offset().top - container.offset().top + container.scrollTop() - 30 const containerOffset = DOM.offset(container);
}, 300); const original = container.scrollTop;
const endPoint = thisNodeOffset.top - containerOffset.top + container.scrollTop - 30;
DOM.animate({
duration: 300,
update: function(progress) {
if (endPoint > original) container.scrollTop = original + (progress * (endPoint - original));
else container.scrollTop = original - (progress * (original - endPoint));
}
});
});
} }
@ -76,10 +87,10 @@ export default class V2C_PluginCard extends BDV2.reactComponent {
get settingsComponent() { get settingsComponent() {
const name = this.getString(this.props.addon.name); const name = this.getString(this.props.addon.name);
try { this.settingsPanel = this.props.addon.getSettingsPanel(); } try { this.settingsPanel = this.props.addon.plugin.getSettingsPanel(); }
catch (err) { Utils.err("Plugins", "Unable to get settings panel for " + this.props.addon.name + ".", err); } catch (err) { Utils.err("Plugins", "Unable to get settings panel for " + this.props.addon.name + ".", err); }
return BDV2.react.createElement("div", {className: "bd-card bd-addon-card settings-open ui-switch-item"}, return BDV2.react.createElement("div", {className: "bd-card bd-addon-card settings-open ui-switch-item", ref: "cardNode"},
BDV2.react.createElement("div", {style: {"float": "right", "cursor": "pointer"}, onClick: () => { BDV2.react.createElement("div", {style: {"float": "right", "cursor": "pointer"}, onClick: () => {
this.refs.settingspanel.innerHTML = ""; this.refs.settingspanel.innerHTML = "";
this.setState({settings: false}); this.setState({settings: false});
@ -184,41 +195,4 @@ export default class V2C_PluginCard extends BDV2.reactComponent {
this.footer this.footer
); );
} }
} }
// get settingsComponent() {
// const addon = this.props.addon;
// const name = this.getString(addon.name);
// try { this.settingsPanel = this.props.getSettingsPanel(); }
// catch (err) { Logger.stacktrace("Addon Settings", "Unable to get settings panel for " + name + ".", err); }
// const props = {id: `${name}-settings`, className: "addon-settings", ref: this.panelRef};
// if (typeof(settingsPanel) == "string") props.dangerouslySetInnerHTML = this.settingsPanel;
// return <div className="bd-addon-card settings-open bd-switch-item">
// <div className="bd-close" onClick={this.closeSettings}><CloseButton /></div>
// <div {...props}>{this.settingsPanel instanceof React.Component ? this.settingsPanel : null}</div>
// </div>;
// }
// componentDidUpdate() {
// if (!this.state.settingsOpen) return;
// if (this.settingsPanel instanceof Node) this.panelRef.current.appendChild(this.settingsPanel);
// // if (!SettingsCookie["fork-ps-3"]) return;
// const isHidden = (container, element) => {
// const cTop = container.scrollTop;
// const cBottom = cTop + container.clientHeight;
// const eTop = element.offsetTop;
// const eBottom = eTop + element.clientHeight;
// return (eTop < cTop || eBottom > cBottom);
// };
// const panel = $(this.panelRef.current);
// const container = panel.parents(".scroller-2FKFPG");
// if (!isHidden(container[0], panel[0])) return;
// container.animate({
// scrollTop: panel.offset().top - container.offset().top + container.scrollTop() - 30
// }, 300);
// }

View File

@ -33,7 +33,7 @@ export default class CardList extends BDV2.reactComponent {
} }
openFolder() { openFolder() {
require("electron").shell.openItem(this.isPlugins ? ContentManager.pluginsFolder : ContentManager.themesFolder); require("electron").shell.showItemInFolder(this.isPlugins ? ContentManager.pluginsFolder : ContentManager.themesFolder);
} }
edit(name) { edit(name) {
@ -109,18 +109,20 @@ export default class CardList extends BDV2.reactComponent {
return 0; return 0;
}); });
if (!this.state.ascending) sortedAddons.reverse(); if (!this.state.ascending) sortedAddons.reverse();
const rendered = sortedAddons.map((addon) => { const rendered = [];
for (let a = 0; a < sortedAddons.length; a++) {
const addon = sortedAddons[a];
if (this.state.query) { if (this.state.query) {
let matches = null; let matches = null;
if (addon.name) matches = addon.name.toLocaleLowerCase().includes(this.state.query); if (addon.name) matches = addon.name.toLocaleLowerCase().includes(this.state.query);
if (addon.author) matches = matches || addon.author.toLocaleLowerCase().includes(this.state.query); if (addon.author) matches = matches || addon.author.toLocaleLowerCase().includes(this.state.query);
if (addon.description) matches = matches || addon.description.toLocaleLowerCase().includes(this.state.query); if (addon.description) matches = matches || addon.description.toLocaleLowerCase().includes(this.state.query);
if (addon.version) matches = matches || addon.version.toLocaleLowerCase().includes(this.state.query); if (addon.version) matches = matches || addon.version.toLocaleLowerCase().includes(this.state.query);
if (!matches) return null; if (!matches) continue;
} }
const props = this.getProps(addon); const props = this.getProps(addon);
return <ErrorBoundary><AddonCard {...props} reload={!settingsCookie["fork-ps-5"] && this.manager.reload.bind(this.manager)} /></ErrorBoundary>; rendered.push(<ErrorBoundary><AddonCard {...props} reload={!settingsCookie["fork-ps-5"] && this.manager.reload.bind(this.manager)} /></ErrorBoundary>);
}); }
return rendered; return rendered;
} }
@ -133,7 +135,7 @@ export default class CardList extends BDV2.reactComponent {
this.forceUpdate(); this.forceUpdate();
}} /> }} />
}</Tooltip>; }</Tooltip>;
const addonCards = this.getAddons().filter(c => c); const addonCards = this.getAddons();
return <Scroller contentColumn={true} fade={true} dark={true}> return <Scroller contentColumn={true} fade={true} dark={true}>
<ContentColumn title={`${this.props.type.toUpperCase()}${addonCards.length}`}> <ContentColumn title={`${this.props.type.toUpperCase()}${addonCards.length}`}>

View File

@ -2,6 +2,7 @@ import {settingsCookie} from "../0globals";
import Settings from "../modules/settingsPanel"; import Settings from "../modules/settingsPanel";
import BDV2 from "../modules/v2"; import BDV2 from "../modules/v2";
import DataStore from "../modules/dataStore"; import DataStore from "../modules/dataStore";
import DOM from "../modules/domtools";
import SettingsTitle from "./settingsTitle"; import SettingsTitle from "./settingsTitle";
import Checkbox from "./checkbox"; import Checkbox from "./checkbox";
@ -188,10 +189,8 @@ export default class V2C_CssEditor extends BDV2.reactComponent {
} }
updateCss() { updateCss() {
if ($("#customcss").length == 0) { DOM.removeStyle("customcss");
$("head").append("<style id=\"customcss\"></style>"); DOM.addStyle("customcss", this.editor.session.getValue());
}
$("#customcss").text(this.editor.session.getValue()).detach().appendTo(document.head);
} }
saveCss() { saveCss() {
@ -212,19 +211,18 @@ export default class V2C_CssEditor extends BDV2.reactComponent {
} }
get detachedRoot() { get detachedRoot() {
const _root = $("#bd-customcss-detach-container"); const _root = DOM.query("#bd-customcss-detach-container");
if (!_root.length) { if (!_root) {
if (!this.injectDetachedRoot()) return null; if (!this.injectDetachedRoot()) return null;
return this.detachedRoot; return this.detachedRoot;
} }
return _root[0]; return _root;
} }
injectDetachedRoot() { injectDetachedRoot() {
if (!$(".app, .app-2rEoOp").length) return false; const app = DOM.query(".app, .app-2rEoOp");
$("<div/>", { if (!app) return false;
id: "bd-customcss-detach-container" DOM.insertAfter(DOM.createElement(`<div id="bd-customcss-detach-container">`), app);
}).insertAfter($(".app, .app-2rEoOp"));
return true; return true;
} }

View File

@ -2,6 +2,7 @@ import {settingsCookie} from "../0globals";
import Settings from "../modules/settingsPanel"; import Settings from "../modules/settingsPanel";
import BDV2 from "../modules/v2"; import BDV2 from "../modules/v2";
import DataStore from "../modules/dataStore"; import DataStore from "../modules/dataStore";
import DOM from "../modules/domtools";
import Checkbox from "./checkbox"; import Checkbox from "./checkbox";
@ -17,7 +18,7 @@ export default class V2C_CssEditorDetached extends BDV2.reactComponent {
} }
componentDidMount() { componentDidMount() {
$("#app-mount").addClass("bd-detached-editor"); DOM.addClass(DOM.query("#app-mount"), "bd-detached-editor");
BDV2.editorDetached = true; BDV2.editorDetached = true;
// this.updateLineCount(); // this.updateLineCount();
this.editor = ace.edit("bd-customcss-editor-detached"); this.editor = ace.edit("bd-customcss-editor-detached");
@ -34,7 +35,7 @@ export default class V2C_CssEditorDetached extends BDV2.reactComponent {
} }
componentWillUnmount() { componentWillUnmount() {
$("#app-mount").removeClass("bd-detached-editor"); DOM.removeClass(DOM.query("#app-mount"), "bd-detached-editor");
BDV2.editorDetached = false; BDV2.editorDetached = false;
this.editor.destroy(); this.editor.destroy();
} }
@ -66,19 +67,18 @@ export default class V2C_CssEditorDetached extends BDV2.reactComponent {
} }
get root() { get root() {
const _root = $("#bd-customcss-detach-container"); const _root = DOM.query("#bd-customcss-detach-container");
if (!_root.length) { if (!_root) {
if (!this.injectRoot()) return null; if (!this.injectRoot()) return null;
return this.detachedRoot; return this.detachedRoot;
} }
return _root[0]; return _root;
} }
injectRoot() { injectRoot() {
if (!$(".app, .app-2rEoOp").length) return false; const app = DOM.query(".app, .app-2rEoOp");
$("<div/>", { if (!app) return false;
id: "bd-customcss-detach-container" DOM.insertAfter(DOM.createElement(`<div id="bd-customcss-detach-container">`), app);
}).insertAfter($(".app, .app-2rEoOp"));
return true; return true;
} }
@ -149,7 +149,7 @@ export default class V2C_CssEditorDetached extends BDV2.reactComponent {
const self = this; const self = this;
switch (id) { switch (id) {
case "attach": case "attach":
if ($("#editor-detached").length) self.props.attach(); if (DOM.query("#editor-detached")) self.props.attach();
BDV2.reactDom.unmountComponentAtNode(self.root); BDV2.reactDom.unmountComponentAtNode(self.root);
self.root.remove(); self.root.remove();
break; break;
@ -163,10 +163,8 @@ export default class V2C_CssEditorDetached extends BDV2.reactComponent {
} }
updateCss() { updateCss() {
if ($("#customcss").length == 0) { DOM.removeStyle("customcss");
$("head").append("<style id=\"customcss\"></style>"); DOM.addStyle("customcss", this.editor.session.getValue());
}
$("#customcss").text(this.editor.session.getValue()).detach().appendTo(document.head);
} }
saveCss() { saveCss() {

View File

@ -1,61 +0,0 @@
import BDV2 from "../modules/v2";
export default class V2C_Layer extends BDV2.reactComponent {
constructor(props) {
super(props);
}
componentDidMount() {
$(window).on(`keyup.${this.props.id}`, e => {
if (e.which === 27) {
BDV2.reactDom.unmountComponentAtNode(this.refs.root.parentNode);
}
});
$(`#${this.props.id}`).animate({opacity: 1}, {
step: function(now) {
$(this).css("transform", `scale(${1.1 - 0.1 * now}) translateZ(0px)`);
},
duration: 200,
done: () => {$(`#${this.props.id}`).css("opacity", "").css("transform", "");}
});
}
componentWillUnmount() {
$(window).off(`keyup.${this.props.id}`);
$(`#${this.props.id}`).animate({opacity: 0}, {
step: function(now) {
$(this).css("transform", `scale(${1.1 - 0.1 * now}) translateZ(0px)`);
},
duration: 200,
done: () => {$(`#${this.props.rootId}`).remove();}
});
$("[class*=\"layer-\"]").removeClass("publicServersOpen").animate({opacity: 1}, {
step: function(now) {
$(this).css("transform", `scale(${0.07 * now + 0.93}) translateZ(0px)`);
},
duration: 200,
done: () => {$("[class*=\"layer-\"]").css("opacity", "").css("transform", "");}
});
}
componentWillMount() {
$("[class*=\"layer-\"]").addClass("publicServersOpen").animate({opacity: 0}, {
step: function(now) {
$(this).css("transform", `scale(${0.07 * now + 0.93}) translateZ(0px)`);
},
duration: 200
});
}
render() {
return BDV2.react.createElement(
"div",
{className: "layer bd-layer layer-3QrUeG", id: this.props.id, ref: "root", style: {opacity: 0, transform: "scale(1.1) translateZ(0px)"}},
this.props.children
);
}
}

View File

@ -1,257 +0,0 @@
import {settingsCookie, pluginCookie, bdplugins} from "../0globals";
import BDV2 from "../modules/v2";
import pluginModule from "../modules/pluginModule";
import Utils from "../modules/utils";
import XSvg from "./xSvg";
import ReloadIcon from "./reloadIcon";
import TooltipWrap from "./tooltipWrap";
import Switch from "./components/switch";
const React = BDV2.React;
export default class V2C_PluginCard extends BDV2.reactComponent {
constructor(props) {
super(props);
const self = this;
self.onChange = self.onChange.bind(self);
self.showSettings = self.showSettings.bind(self);
self.setInitialState();
self.hasSettings = typeof self.props.plugin.getSettingsPanel === "function";
self.settingsPanel = "";
this.reload = this.reload.bind(this);
this.onReload = this.onReload.bind(this);
}
setInitialState() {
this.state = {
checked: pluginCookie[this.props.plugin.getName()],
settings: false,
reloads: 0
};
}
// componentDidMount() {
// BDEvents.on("plugin-reloaded", this.onReload);
// }
// componentWillUnmount() {
// BDEvents.off("plugin-reloaded", this.onReload);
// }
onReload(pluginName) {
if (pluginName !== this.props.plugin.getName()) return;
this.setState({reloads: this.state.reloads + 1});
}
componentDidUpdate() {
if (this.state.settings) {
if (typeof this.settingsPanel === "object") {
this.refs.settingspanel.appendChild(this.settingsPanel);
}
if (!settingsCookie["fork-ps-3"]) return;
const isHidden = (container, element) => {
const cTop = container.scrollTop;
const cBottom = cTop + container.clientHeight;
const eTop = element.offsetTop;
const eBottom = eTop + element.clientHeight;
return (eTop < cTop || eBottom > cBottom);
};
const self = $(BDV2.reactDom.findDOMNode(this));
const container = self.parents(".scroller");
if (!isHidden(container[0], self[0])) return;
container.animate({
scrollTop: self.offset().top - container.offset().top + container.scrollTop() - 30
}, 300);
}
}
reload() {
const plugin = this.props.plugin.getName();
pluginModule.reloadPlugin(plugin);
this.props.plugin = bdplugins[plugin].plugin;
this.onReload(this.props.plugin.getName());
}
getString(value) {
if (!value) return "???";
return typeof value == "string" ? value : value.toString();
}
get settingsComponent() {
const self = this;
const {plugin} = this.props;
const name = this.getString(plugin.getName());
try { self.settingsPanel = plugin.getSettingsPanel(); }
catch (err) { Utils.err("Plugins", "Unable to get settings panel for " + plugin.getName() + ".", err); }
return BDV2.react.createElement("div", {className: "settings-open ui-switch-item bd-addon-card"},
BDV2.react.createElement("div", {style: {"float": "right", "cursor": "pointer"}, onClick: () => {
this.refs.settingspanel.innerHTML = "";
self.setState({settings: false});
}},
BDV2.react.createElement(XSvg, null)
),
typeof self.settingsPanel === "object" && BDV2.react.createElement("div", {id: `plugin-settings-${name}`, className: "plugin-settings", ref: "settingspanel"}),
typeof self.settingsPanel !== "object" && BDV2.react.createElement("div", {id: `plugin-settings-${name}`, className: "plugin-settings", ref: "settingspanel", dangerouslySetInnerHTML: {__html: self.settingsPanel}})
);
}
buildTitle(name, version, author) {
const title = "{{name}} v{{version}} by {{author}}".split(/({{[A-Za-z]+}})/);
const nameIndex = title.findIndex(s => s == "{{name}}");
if (nameIndex) title[nameIndex] = React.createElement("span", {className: "bd-name bda-name"}, name);
const versionIndex = title.findIndex(s => s == "{{version}}");
if (nameIndex) title[versionIndex] = React.createElement("span", {className: "bd-version bda-version"}, version);
const authorIndex = title.findIndex(s => s == "{{author}}");
if (nameIndex) {
const props = {className: "bd-author bda-author"};
if (author.link || author.id) {
props.className += ` ${BDV2.anchorClasses.anchor} ${BDV2.anchorClasses.anchorUnderlineOnHover}`;
props.target = "_blank";
if (author.link) props.href = author.link;
if (author.id) props.onClick = () => {BDV2.LayerStack.popLayer(); BDV2.openDM(author.id);};
}
title[authorIndex] = React.createElement(author.link || author.id ? "a" : "span", props, author.name);
}
return title.flat();
}
makeLink(title, url) {
const props = {className: "bda-link bda-link-website", target: "_blank"};
if (typeof(url) == "string") props.href = url;
if (typeof(url) == "function") props.onClick = (event) => {event.preventDefault(); event.stopPropagation(); url();};
return BDV2.react.createElement("a", props, title);
}
makeButton(title, children, action) {
return <TooltipWrap color="black" position="top" text={title}>
{(props) => {
return <div {...props} className="bd-addon-button" onClick={action}>{children}</div>;
}}
</TooltipWrap>;
}
getLinks(meta) {
const links = [];
if (meta.website) links.push(this.makeLink("Website", meta.website));
if (meta.source) links.push(this.makeLink("Source", meta.source));
if (meta.invite) {
links.push(this.makeLink("Support Server", () => {
const tester = /\.gg\/(.*)$/;
let code = meta.invite;
if (tester.test(code)) code = code.match(tester)[1];
BDV2.LayerStack.popLayer();
BDV2.InviteActions.acceptInviteAndTransitionToInviteChannel(code);
}));
}
if (meta.donate) links.push(this.makeLink("Donate", meta.donate));
if (meta.patreon) links.push(this.makeLink("Patreon", meta.patreon));
return links;
}
getFooter(meta) {
const links = this.getLinks(meta);
return (links.length || this.hasSettings) && BDV2.react.createElement("div", {className: "bda-footer"},
BDV2.react.createElement("span", {className: "bda-links"},
...(links.map((element, index) => index < links.length - 1 ? [element, " | "] : element).flat())
),
this.hasSettings && BDV2.react.createElement("button", {onClick: this.showSettings, className: "bda-settings-button", disabled: !this.state.checked}, "Settings")
);
}
render() {
if (this.state.settings) return this.settingsComponent;
const {plugin} = this.props;
const name = this.getString(plugin.getName());
const author = this.getString(plugin.getAuthor());
const description = this.getString(plugin.getDescription());
const version = this.getString(plugin.getVersion());
const meta = bdplugins[name];
return BDV2.react.createElement("div", {"data-name": name, "data-version": version, "className": "settings-closed ui-switch-item bd-addon-card"},
BDV2.react.createElement("div", {className: "bd-addon-header bda-header"},
BDV2.react.createElement("div", {className: "bd-title bda-header-title"}, this.buildTitle(name, version, {name: author, id: meta.authorId, link: meta.authorLink})),
BDV2.react.createElement("div", {className: "bd-addon-controls bda-controls"},
!settingsCookie["fork-ps-5"] && BDV2.react.createElement(TooltipWrap(ReloadIcon, {color: "black", side: "top", text: "Reload"}), {className: "bd-reload-card", onClick: this.reload}),
React.createElement(Switch, {onChange: this.onChange, checked: this.state.checked})
// BDV2.react.createElement("label", {className: "ui-switch-wrapper ui-flex-child", style: {flex: "0 0 auto"}},
// BDV2.react.createElement("input", {checked: this.state.checked, onChange: this.onChange, className: "ui-switch-checkbox", type: "checkbox"}),
// BDV2.react.createElement("div", {className: this.state.checked ? "ui-switch checked" : "ui-switch"})
// )
)
),
BDV2.react.createElement("div", {className: "bd-scroller-wrap bda-description-wrap scroller-wrap fade"},
BDV2.react.createElement("div", {className: "bd-addon-description bda-description scroller"}, description)
),
this.getFooter(meta)
);
}
onChange() {
this.setState({checked: !this.state.checked});
pluginModule.togglePlugin(this.props.plugin.getName());
}
showSettings() {
if (!this.hasSettings) return;
this.setState({settings: true});
}
}
// <div className="bd-controls">
// {this.props.editAddon && this.makeButton(Strings.Addons.editAddon, <EditIcon />, this.props.editAddon)}
// {this.props.deleteAddon && this.makeButton(Strings.Addons.deleteAddon, <DeleteIcon />, this.props.deleteAddon)}
// {this.props.showReloadIcon && this.makeButton(Strings.Addons.reload, <ReloadIcon className="bd-reload bd-reload-card" />, this.reload)}
// <Switch checked={this.props.enabled} onChange={this.onChange} />
// </div>
// componentDidUpdate() {
// if (!this.state.settingsOpen) return;
// if (this.settingsPanel instanceof Node) this.panelRef.current.appendChild(this.settingsPanel);
// // if (!SettingsCookie["fork-ps-3"]) return;
// const isHidden = (container, element) => {
// const cTop = container.scrollTop;
// const cBottom = cTop + container.clientHeight;
// const eTop = element.offsetTop;
// const eBottom = eTop + element.clientHeight;
// return (eTop < cTop || eBottom > cBottom);
// };
// const panel = $(this.panelRef.current);
// const container = panel.parents(".scroller-2FKFPG");
// if (!isHidden(container[0], panel[0])) return;
// container.animate({
// scrollTop: panel.offset().top - container.offset().top + container.scrollTop() - 30
// }, 300);
// }
// get settingsComponent() {
// const addon = this.props.addon;
// const name = this.getString(addon.name);
// try { this.settingsPanel = this.props.getSettingsPanel(); }
// catch (err) { Logger.stacktrace("Addon Settings", "Unable to get settings panel for " + name + ".", err); }
// const props = {id: `${name}-settings`, className: "addon-settings", ref: this.panelRef};
// if (typeof(settingsPanel) == "string") props.dangerouslySetInnerHTML = this.settingsPanel;
// return <div className="bd-addon-card settings-open bd-switch-item">
// <div className="bd-close" onClick={this.closeSettings}><CloseButton /></div>
// <div {...props}>{this.settingsPanel instanceof React.Component ? this.settingsPanel : null}</div>
// </div>;
// }

View File

@ -0,0 +1,89 @@
import BDV2 from "../../modules/v2";
import DOM from "../../modules/domtools";
export default class V2C_Layer extends BDV2.reactComponent {
constructor(props) {
super(props);
this.keyupListener = this.keyupListener.bind(this);
}
keyupListener(e) {
if (e.which === 27) {
BDV2.reactDom.unmountComponentAtNode(this.refs.root.parentNode);
}
}
componentDidMount() {
window.addEventListener("keyup", this.keyupListener);
const thisNode = DOM.query(`#${this.props.id}`);
DOM.animate({
duration: 200,
update: function(progress) {
thisNode.style.transform = `scale(${1.1 - 0.1 * progress}) translateZ(0px)`;
thisNode.style.opacity = progress;
if (progress == 1) {
setImmediate(() => {
thisNode.style.transform = "";
thisNode.style.opacity = "";
});
}
}
});
}
componentWillUnmount() {
window.removeEventListener("keyup", this.keyupListener);
const thisNode = DOM.query(`#${this.props.id}`);
DOM.animate({
duration: 200,
update: function(progress) {
thisNode.style.transform = `scale(${1.1 - 0.1 * (1 - progress)}) translateZ(0px)`;
thisNode.style.opacity = 1 - progress;
if (progress == 1) {
setImmediate(() => {
thisNode.remove();
});
}
}
});
const layer = DOM.query(".publicServersOpen");
layer.classList.remove("publicServersOpen");
DOM.animate({
duration: 200,
update: function(progress) {
layer.style.transform = `scale(${0.07 * progress + 0.93}) translateZ(0px)`;
layer.style.opacity = progress;
if (progress == 1) {
setImmediate(() => {
layer.style.transform = "";
layer.style.opacity = "";
});
}
}
});
}
componentWillMount() {
const layer = DOM.query("[class*=\"layer-\"]");
layer.classList.add("publicServersOpen");
DOM.animate({
duration: 200,
update: function(progress) {
layer.style.transform = `scale(${0.07 * (1 - progress) + 0.93}) translateZ(0px)`;
layer.style.opacity = 1 - progress;
}
});
}
render() {
return BDV2.react.createElement(
"div",
{className: "layer bd-layer layer-3QrUeG", id: this.props.id, ref: "root", style: {opacity: 0, transform: "scale(1.1) translateZ(0px)"}},
this.props.children
);
}
}

View File

@ -1,12 +1,13 @@
import BDV2 from "../modules/v2"; import BDV2 from "../../modules/v2";
import Tools from "../tools";
import SettingsTitle from "../settingsTitle";
import TabBarSeparator from "../tabBarSeparator";
import TabBarHeader from "../tabBarHeader";
import TabBarItem from "../tabBarItem";
import Tools from "./tools";
import ServerCard from "./serverCard"; import ServerCard from "./serverCard";
import SidebarView from "./sidebarView"; import SidebarView from "./sidebarView";
import SettingsTitle from "./settingsTitle";
import TabBarSeparator from "./tabBarSeparator";
import TabBarHeader from "./tabBarHeader";
import TabBarItem from "./tabBarItem";
export default class V2C_PublicServers extends BDV2.reactComponent { export default class V2C_PublicServers extends BDV2.reactComponent {
@ -51,76 +52,68 @@ export default class V2C_PublicServers extends BDV2.reactComponent {
search(query, clear) { search(query, clear) {
const self = this; const self = this;
const request = require("request");
$.ajax({ request.get({url: `${self.endPoint}${query}${query ? "&schema=new" : "?schema=new"}`, json: true}, function (err, resp, data) {
method: "GET", if (err) {
url: `${self.endPoint}${query}${query ? "&schema=new" : "?schema=new"}`, return self.setState({
success: data => {
let servers = data.results.reduce((arr, server) => {
server.joined = false;
arr.push(server);
// arr.push(<ServerCard server={server} join={self.join}/>);
return arr;
}, []);
if (!clear) {
servers = self.state.servers.concat(servers);
}
else {
//servers.unshift(self.bdServer);
}
let end = data.size + data.from;
data.next = `?from=${end}`;
if (self.state.term) data.next += `&term=${self.state.term}`;
if (self.state.selectedCategory) data.next += `&category=${self.categoryButtons[self.state.selectedCategory]}`;
if (end >= data.total) {
end = data.total;
data.next = null;
}
let title = `Showing 1-${end} of ${data.total} results in ${self.categoryButtons[self.state.selectedCategory]}`;
if (self.state.term) title += ` for ${self.state.term}`;
self.setState({
loading: false,
title: title,
servers: servers,
next: data.next
});
if (clear) {
//console.log(self);
self.refs.sbv.refs.contentScroller.scrollTop = 0;
}
},
error: () => {
self.setState({
loading: false, loading: false,
title: "Failed to load servers. Check console for details" title: "Failed to load servers. Check console for details"
}); });
} }
let servers = data.results.reduce((arr, server) => {
server.joined = false;
arr.push(server);
// arr.push(<ServerCard server={server} join={self.join}/>);
return arr;
}, []);
if (!clear) {
servers = self.state.servers.concat(servers);
}
else {
//servers.unshift(self.bdServer);
}
let end = data.size + data.from;
data.next = `?from=${end}`;
if (self.state.term) data.next += `&term=${self.state.term}`;
if (self.state.selectedCategory) data.next += `&category=${self.categoryButtons[self.state.selectedCategory]}`;
if (end >= data.total) {
end = data.total;
data.next = null;
}
let title = `Showing 1-${end} of ${data.total} results in ${self.categoryButtons[self.state.selectedCategory]}`;
if (self.state.term) title += ` for ${self.state.term}`;
self.setState({
loading: false,
title: title,
servers: servers,
next: data.next
});
if (clear) {
//console.log(self);
self.refs.sbv.refs.contentScroller.scrollTop = 0;
}
}); });
} }
join(serverCard) { async join(serverCard) {
if (serverCard.props.pinned) return this.InviteActions.acceptInvite(serverCard.props.invite_code); if (serverCard.props.pinned) return this.InviteActions.acceptInvite(serverCard.props.invite_code);
$.ajax({
await fetch(`${this.joinEndPoint}/${serverCard.props.server.identifier}`,{
method: "GET", method: "GET",
url: `${this.joinEndPoint}/${serverCard.props.server.identifier}`, credentials: "include",
mode: "cors",
headers: { headers: {
"Accept": "application/json;", "Accept": "application/json",
"Content-Type": "application/json;" , "Content-Type": "application/json"
"x-discord-token": this.state.connection.user.accessToken
},
crossDomain: true,
xhrFields: {
withCredentials: true
},
success: () => {
serverCard.setState({joined: true});
} }
}); });
serverCard.setState({joined: true});
} }
connect() { connect() {
@ -187,44 +180,27 @@ export default class V2C_PublicServers extends BDV2.reactComponent {
return "https://join.discordservers.com/connect"; return "https://join.discordservers.com/connect";
} }
checkConnection() { async checkConnection() {
const self = this; const self = this;
try { try {
$.ajax({ const response = await fetch(`https://auth.discordservers.com/info`,{
method: "GET", method: "GET",
url: `https://auth.discordservers.com/info`, credentials: "include",
mode: "cors",
headers: { headers: {
"Accept": "application/json;", "Accept": "application/json",
"Content-Type": "application/json;" "Content-Type": "application/json"
},
crossDomain: true,
xhrFields: {
withCredentials: true
},
success: data => {
// Utils.log("PublicServer", "Got data: " + JSON.stringify(data));
self.setState({
selectedCategory: 0,
connection: {
state: 2,
user: data
}
});
self.search("", true);
},
error: () => {
self.setState({
title: "Not connected to discordservers.com!",
loading: true,
selectedCategory: -1,
connection: {
state: 1,
user: null
}
});
} }
}); });
const data = await response.json();
self.setState({
selectedCategory: 0,
connection: {
state: 2,
user: data
}
});
self.search("", true);
} }
catch (error) { catch (error) {
self.setState({ self.setState({
@ -240,7 +216,7 @@ export default class V2C_PublicServers extends BDV2.reactComponent {
} }
render() { render() {
return BDV2.react.createElement(SidebarView, {ref: "sbv", children: this.component}); return BDV2.react.createElement(SidebarView, {ref: "sbv"}, this.component);
} }
get component() { get component() {

View File

@ -1,4 +1,4 @@
import BDV2 from "../modules/v2"; import BDV2 from "../../modules/v2";
export default class V2C_ServerCard extends BDV2.reactComponent { export default class V2C_ServerCard extends BDV2.reactComponent {
constructor(props) { constructor(props) {

View File

@ -1,6 +1,6 @@
import BDV2 from "../modules/v2"; import BDV2 from "../../modules/v2";
import Scroller from "./scroller"; import Scroller from "../scroller";
export default class V2C_SidebarView extends BDV2.reactComponent { export default class V2C_SidebarView extends BDV2.reactComponent {
@ -16,7 +16,7 @@ export default class V2C_SidebarView extends BDV2.reactComponent {
BDV2.react.createElement( BDV2.react.createElement(
"div", "div",
{className: "sidebarRegion-VFTUkN sidebar-region"}, {className: "sidebarRegion-VFTUkN sidebar-region"},
BDV2.react.createElement(Scroller, {key: "sidebarScroller", ref: "sidebarScroller", sidebar: true, fade: sidebar.fade || true, dark: sidebar.dark || true, children: sidebar.component}) BDV2.react.createElement(Scroller, {key: "sidebarScroller", ref: "sidebarScroller", sidebar: true, fade: sidebar.fade || true, dark: sidebar.dark || true}, sidebar.component)
), ),
BDV2.react.createElement("div", {className: "contentRegion-3nDuYy content-region"}, BDV2.react.createElement("div", {className: "contentRegion-3nDuYy content-region"},
BDV2.react.createElement("div", {className: "contentTransitionWrap-3hqOEW content-transition-wrap"}, BDV2.react.createElement("div", {className: "contentTransitionWrap-3hqOEW content-transition-wrap"},

View File

@ -8,18 +8,22 @@ export default class V2C_SideBar extends BDV2.reactComponent {
constructor(props) { constructor(props) {
super(props); super(props);
const self = this; const si = document.querySelector("[class*=side-] > [class*=selected]");
const si = $("[class*=side-] > [class*=selected]"); if (si) this.scn = si.className;
if (si.length) self.scn = si.attr("class"); const ns = document.querySelector("[class*=side-] > [class*='item-']:not([class*=selected])");
const ns = $("[class*=side-] > [class*='item-']:not([class*=selected])"); if (ns) this.nscn = ns.className;
if (ns.length) self.nscn = ns.attr("class"); const tabs = document.querySelectorAll("[class*='side-'] > [class*='item-']");
$("[class*='side-'] > [class*='item-']").on("click", () => { for (const element of tabs) {
self.setState({ element.addEventListener("click", () => {
selected: null this.setState({
selected: null
});
}); });
}); }
self.setInitialState();
self.onClick = self.onClick.bind(self); this.setInitialState();
this.onClick = this.onClick.bind(this);
this.setSelected = this.setSelected.bind(this);
} }
setInitialState() { setInitialState() {
@ -53,19 +57,21 @@ export default class V2C_SideBar extends BDV2.reactComponent {
); );
} }
setSelected(e) {
e.target.className = this.scn;
}
onClick(id) { onClick(id) {
const self = this; const si = document.querySelector("[class*=side] > [class*=selected]");
const si = $("[class*=side] > [class*=selected]"); if (si) {
if (si.length) { si.removeEventListener("click", this.setSelected);
si.off("click.bdsb").on("click.bsb", e => { si.addEventListener("click", this.setSelected);
$(e.target).attr("class", self.scn); si.className = this.nscn;
});
si.attr("class", self.nscn);
} }
self.setState({selected: null}); this.setState({selected: null});
self.setState({selected: id}); this.setState({selected: id});
if (self.props.onClick) self.props.onClick(id); if (this.props.onClick) this.props.onClick(id);
} }
} }

View File

@ -1,119 +0,0 @@
import {settingsCookie, themeCookie, bdthemes} from "../0globals";
import Utils from "../modules/utils";
import BDV2 from "../modules/v2";
import themeModule from "../modules/themeModule";
import ReloadIcon from "./reloadIcon";
import TooltipWrap from "./tooltipWrap";
export default class V2C_ThemeCard extends BDV2.reactComponent {
constructor(props) {
super(props);
this.setInitialState();
this.onChange = this.onChange.bind(this);
this.reload = this.reload.bind(this);
}
setInitialState() {
this.state = {
checked: themeCookie[this.props.theme.name],
reloads: 0
};
}
// componentDidMount() {
// BDEvents.on("theme-reloaded", this.onReload);
// }
// componentWillUnmount() {
// BDEvents.off("theme-reloaded", this.onReload);
// }
onReload(themeName) {
if (themeName !== this.props.theme.name) return;
this.setState({reloads: this.state.reloads + 1});
}
reload() {
const theme = this.props.theme.name;
const error = themeModule.reloadTheme(theme);
if (error) Utils.showToast(`Could not reload ${bdthemes[theme].name}. Check console for details.`, {type: "error"});
else Utils.showToast(`${bdthemes[theme].name} v${bdthemes[theme].version} has been reloaded.`, {type: "success"});
// this.setState(this.state);
this.props.theme = bdthemes[theme];
this.onReload(this.props.theme.name);
}
makeLink(title, url) {
const props = {className: "bda-link bda-link-website", target: "_blank"};
if (typeof(url) == "string") props.href = url;
if (typeof(url) == "function") props.onClick = (event) => {event.preventDefault(); event.stopPropagation(); url();};
return BDV2.react.createElement("a", props, title);
}
render() {
const {theme} = this.props;
const name = theme.name;
const description = theme.description;
const version = theme.version;
const author = theme.author;
const meta = bdthemes[name];
const links = [];
if (meta.website) links.push(this.makeLink("Website", meta.website));
if (meta.source) links.push(this.makeLink("Source", meta.source));
if (meta.invite) {
links.push(this.makeLink("Support Server", () => {
const tester = /\.gg\/(.*)$/;
let code = meta.invite;
if (tester.test(code)) code = code.match(tester)[1];
BDV2.LayerStack.popLayer();
BDV2.InviteActions.acceptInviteAndTransitionToInviteChannel(code);
}));
}
if (meta.donate) links.push(this.makeLink("Donate", meta.donate));
if (meta.patreon) links.push(this.makeLink("Patreon", meta.patreon));
const authorProps = {className: "bda-author"};
if (meta.authorLink || meta.authorId) {
authorProps.className += ` ${BDV2.anchorClasses.anchor} ${BDV2.anchorClasses.anchorUnderlineOnHover}`;
authorProps.target = "_blank";
if (meta.authorLink) authorProps.href = meta.authorLink;
if (meta.authorId) authorProps.onClick = () => {BDV2.LayerStack.popLayer(); BDV2.openDM(meta.authorId);};
}
return BDV2.react.createElement("div", {"data-name": name, "data-version": version, "className": "settings-closed ui-switch-item bd-addon-card"},
BDV2.react.createElement("div", {className: "bda-header"},
BDV2.react.createElement("span", {className: "bda-header-title"},
BDV2.react.createElement("span", {className: "bda-name"}, name),
" v",
BDV2.react.createElement("span", {className: "bda-version"}, version),
" by ",
BDV2.react.createElement(meta.authorLink || meta.authorId ? "a" : "span", authorProps, author)
),
BDV2.react.createElement("div", {className: "bda-controls"},
!settingsCookie["fork-ps-5"] && BDV2.react.createElement(TooltipWrap(ReloadIcon, {color: "black", side: "top", text: "Reload"}), {className: "bd-reload-card", onClick: this.reload}),
BDV2.react.createElement("label", {className: "ui-switch-wrapper ui-flex-child", style: {flex: "0 0 auto"}},
BDV2.react.createElement("input", {checked: this.state.checked, onChange: this.onChange, className: "ui-switch-checkbox", type: "checkbox"}),
BDV2.react.createElement("div", {className: this.state.checked ? "ui-switch checked" : "ui-switch"})
)
)
),
BDV2.react.createElement("div", {className: "bda-description-wrap scroller-wrap fade"},
BDV2.react.createElement("div", {className: "bda-description scroller"}, description)
),
(!!links.length) && BDV2.react.createElement("div", {className: "bda-footer"},
BDV2.react.createElement("span", {className: "bda-links"},
...(links.map((element, index) => index < links.length - 1 ? [element, " | "] : element).flat())
)
)
);
}
onChange() {
this.setState({checked: !this.state.checked});
themeModule.toggleTheme(this.props.theme.name);
}
}

View File

@ -31,6 +31,7 @@ export default class V2C_Tools extends BDV2.reactComponent {
if (this.props.onClick) { if (this.props.onClick) {
this.props.onClick(); this.props.onClick();
} }
$(".closeButton-1tv5uR").first().click(); const closeButton = document.querySelector(".closeButton-1tv5uR");
if (closeButton) closeButton.click();
} }
} }

View File

@ -12,6 +12,7 @@
import Utils from "../modules/utils"; import Utils from "../modules/utils";
import WebpackModules from "../modules/webpackModules"; import WebpackModules from "../modules/webpackModules";
import DOM from "../modules/domtools";
const TooltipClasses = WebpackModules.findByProps("tooltip", "tooltipBlack"); const TooltipClasses = WebpackModules.findByProps("tooltip", "tooltipBlack");
const TooltipLayers = WebpackModules.findByProps("layer", "layerContainer"); const TooltipLayers = WebpackModules.findByProps("layer", "layerContainer");
@ -62,8 +63,8 @@ export default class EmulatedTooltip {
if (!classExists(this.side)) return Utils.err("EmulatedTooltip", `Side ${this.side} does not exist.`); if (!classExists(this.side)) return Utils.err("EmulatedTooltip", `Side ${this.side} does not exist.`);
if (!classExists(this.style)) return Utils.err("EmulatedTooltip", `Style ${this.style} does not exist.`); if (!classExists(this.style)) return Utils.err("EmulatedTooltip", `Style ${this.style} does not exist.`);
this.element = $(`<div class="${TooltipLayers.layer}">`)[0]; this.element = DOM.createElement(`<div class="${TooltipLayers.layer}">`);
this.tooltipElement = $(`<div class="${TooltipClasses.tooltip} ${getClass(this.style)}"><div class="${TooltipClasses.tooltipPointer}"></div>${this.label}</div>`)[0]; this.tooltipElement = DOM.createElement(`<div class="${TooltipClasses.tooltip} ${getClass(this.style)}"><div class="${TooltipClasses.tooltipPointer}"></div>${this.label}</div>`);
this.labelElement = this.tooltipElement.childNodes[1]; this.labelElement = this.tooltipElement.childNodes[1];
this.element.append(this.tooltipElement); this.element.append(this.tooltipElement);