First pass -- it loads
This commit is contained in:
parent
6c03d9090c
commit
d21f492bf3
|
@ -32,16 +32,11 @@
|
|||
"Set": false,
|
||||
"WeakMap": false,
|
||||
"Promise": false,
|
||||
"bdplugins": false,
|
||||
"bdthemes": false,
|
||||
"betterDiscordIPC": false,
|
||||
"bdVersion": false,
|
||||
"version": false,
|
||||
"_bdhash": true,
|
||||
"ace": false,
|
||||
"Reflect": false,
|
||||
"DiscordNative": false,
|
||||
"self": "off",
|
||||
"name": "off"
|
||||
"name": "off",
|
||||
"__non_webpack_require__": false
|
||||
}
|
||||
}
|
|
@ -1,4 +1 @@
|
|||
node_modules
|
||||
src
|
||||
webpack.config.js
|
||||
current.js
|
||||
node_modules
|
5715
js/main.js
5715
js/main.js
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
|
@ -4,11 +4,13 @@
|
|||
"description": "Enhances Discord adding functionality and themes.",
|
||||
"main": "js/main.js",
|
||||
"scripts": {
|
||||
"build": "webpack --progress --colors",
|
||||
"watch": "webpack --progress --colors --watch",
|
||||
"build-prod": "webpack --progress --colors --mode production -o js/main.min.js --devtool none",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"minify": "gulp minify-js && gulp minify-css",
|
||||
"minify-js": "gulp minify-js",
|
||||
"minify-css": "gulp minify-css",
|
||||
"watch": "gulp watch",
|
||||
"watch-js": "gulp watch-js",
|
||||
"watch-css": "gulp watch-css"
|
||||
},
|
||||
|
@ -23,9 +25,16 @@
|
|||
},
|
||||
"homepage": "https://github.com/rauenzi/BetterDiscordApp#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.3.4",
|
||||
"@babel/preset-env": "^7.3.4",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/register": "^7.0.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"circular-dependency-plugin": "^5.0.2",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-babel-minify": "^0.5.0",
|
||||
"gulp-csso": "^3.0.1",
|
||||
"gulp-rename": "^1.4.0"
|
||||
"gulp-rename": "^1.4.0",
|
||||
"webpack": "^4.29.6",
|
||||
"webpack-cli": "^3.2.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
// var settingsPanel, emoteModule, quickEmoteMenu, voiceMode, pluginModule, themeModule, dMode, publicServersModule, mainCore, BDV2;
|
||||
export const minSupportedVersion = "0.3.0";
|
||||
export const bbdVersion = "0.2.24";
|
||||
export const bbdChangelog = {
|
||||
description: "Mostly behind the scenes changes here.",
|
||||
changes: [
|
||||
{title: "What's New?", items: ["**Dark Mode is back!** Or rather... it's toggleable again and no longer forced on.", "**Changes for developers!** Plugin and theme developers will now have more options to customize their plugin cards in their METAs and also a new META structure."]},
|
||||
{title: "Fixes", type: "fixed", items: ["**Emote Menu** should now show both Twich Global emotes and your favorites, you should even be able to click on them again!"]},
|
||||
{title: "Minor Stuff", type: "improved", items: ["**Clean Code.** Well not really. But BD's code is starting to be cleaned up to make it easier to maintain and better performing."]}
|
||||
]
|
||||
};
|
||||
|
||||
export const settings = {
|
||||
"Custom css live update": {id: "bda-css-0", info: "", implemented: true, hidden: true, cat: "core"},
|
||||
"Custom css auto udpate": {id: "bda-css-1", info: "", implemented: true, hidden: true, cat: "core"},
|
||||
"BetterDiscord Blue": {id: "bda-gs-b", info: "Replace Discord blue with BD Blue", implemented: false, hidden: false, cat: "core"},
|
||||
|
||||
/* Core */
|
||||
/* ====== */
|
||||
"Public Servers": {id: "bda-gs-1", info: "Display public servers button", implemented: true, hidden: false, cat: "core", category: "modules"},
|
||||
"Minimal Mode": {id: "bda-gs-2", info: "Hide elements and reduce the size of elements.", implemented: true, hidden: false, cat: "core", category: "modules"},
|
||||
"Voice Mode": {id: "bda-gs-4", info: "Only show voice chat", implemented: true, hidden: false, cat: "core", category: "modules"},
|
||||
"Hide Channels": {id: "bda-gs-3", info: "Hide channels in minimal mode", implemented: true, hidden: false, cat: "core", category: "modules"},
|
||||
"Dark Mode": {id: "bda-gs-5", info: "Make certain elements dark by default(wip)", implemented: true, hidden: false, cat: "core", category: "modules"},
|
||||
"Voice Disconnect": {id: "bda-dc-0", info: "Disconnect from voice server when closing Discord", implemented: true, hidden: false, cat: "core", category: "modules"},
|
||||
"24 Hour Timestamps": {id: "bda-gs-6", info: "Replace 12hr timestamps with proper ones", implemented: true, hidden: false, cat: "core", category: "modules"},
|
||||
"Colored Text": {id: "bda-gs-7", info: "Make text color the same as role color", implemented: true, hidden: false, cat: "core", category: "modules"},
|
||||
"Normalize Classes": {id: "fork-ps-4", info: "Adds stable classes to elements to help themes. (e.g. adds .da-channels to .channels-Ie2l6A)", implemented: true, hidden: false, cat: "core", category: "modules"},
|
||||
|
||||
/* Content */
|
||||
"Content Error Modal": {id: "fork-ps-1", info: "Shows a modal with plugin/theme errors", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Show Toasts": {id: "fork-ps-2", info: "Shows a small notification for important information", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Scroll To Settings": {id: "fork-ps-3", info: "Auto-scrolls to a plugin's settings when the button is clicked (only if out of view)", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Automatic Loading": {id: "fork-ps-5", info: "Automatically loads, reloads, and unloads plugins and themes", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
|
||||
/* Developer */
|
||||
"Developer Mode": {id: "bda-gs-8", info: "Developer Mode", implemented: true, hidden: false, cat: "core", category: "developer settings"},
|
||||
"Copy Selector": {id: "fork-dm-1", info: "Adds a \"Copy Selector\" option to context menus when developer mode is active", implemented: true, hidden: false, cat: "core", category: "developer settings"},
|
||||
|
||||
/* Window Prefs */
|
||||
"Enable Transparency": {id: "fork-wp-1", info: "Enables the main window to be see-through (requires restart)", implemented: true, hidden: false, cat: "core", category: "window preferences"},
|
||||
"Window Frame": {id: "fork-wp-2", info: "Adds the native os window frame to the main window", implemented: false, hidden: true, cat: "core", category: "window preferences"},
|
||||
|
||||
|
||||
/* Emotes */
|
||||
/* ====== */
|
||||
"Download Emotes": {id: "fork-es-3", info: "Download emotes when the cache is expired", implemented: true, hidden: false, cat: "emote"},
|
||||
"Twitch Emotes": {id: "bda-es-7", info: "Show Twitch emotes", implemented: true, hidden: false, cat: "emote"},
|
||||
"FrankerFaceZ Emotes": {id: "bda-es-1", info: "Show FrankerFaceZ 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"},
|
||||
"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"},
|
||||
"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"},
|
||||
"Animate On Hover": {id: "fork-es-2", info: "Only animate the emote modifiers on hover", implemented: true, hidden: false, cat: "emote"}
|
||||
};
|
||||
|
||||
export const defaultCookie = {
|
||||
"bda-gs-1": true,
|
||||
"bda-gs-2": false,
|
||||
"bda-gs-3": false,
|
||||
"bda-gs-4": false,
|
||||
"bda-gs-5": true,
|
||||
"bda-gs-6": false,
|
||||
"bda-gs-7": false,
|
||||
"bda-gs-8": false,
|
||||
"bda-es-0": true,
|
||||
"bda-es-1": true,
|
||||
"bda-es-2": true,
|
||||
"bda-es-4": false,
|
||||
"bda-es-6": true,
|
||||
"bda-es-7": true,
|
||||
"bda-gs-b": false,
|
||||
"bda-es-8": true,
|
||||
"bda-dc-0": false,
|
||||
"bda-css-0": false,
|
||||
"bda-css-1": false,
|
||||
"bda-es-9": true,
|
||||
"fork-dm-1": false,
|
||||
"fork-ps-1": true,
|
||||
"fork-ps-2": true,
|
||||
"fork-ps-3": true,
|
||||
"fork-ps-4": true,
|
||||
"fork-ps-5": true,
|
||||
"fork-es-2": false,
|
||||
"fork-es-3": true,
|
||||
"fork-wp-1": false,
|
||||
"fork-wp-2": false
|
||||
};
|
||||
|
||||
|
||||
export const settingsCookie = {};
|
||||
|
||||
export const bdpluginErrors = [];
|
||||
export const bdthemeErrors = []; // define for backwards compatibility
|
||||
|
||||
export const bdConfig = {};
|
||||
|
||||
export const bemotes = [];
|
||||
export const emotesFfz = {};
|
||||
export const emotesBTTV = {};
|
||||
export const emotesBTTV2 = {};
|
||||
export const emotesTwitch = {};
|
||||
export const subEmotesTwitch = {};
|
||||
|
||||
export const bdEmotes = {
|
||||
TwitchGlobal: {},
|
||||
TwitchSubscriber: {},
|
||||
BTTV: {},
|
||||
FrankerFaceZ: {},
|
||||
BTTV2: {}
|
||||
};
|
||||
|
||||
export const bdEmoteSettingIDs = {
|
||||
TwitchGlobal: "bda-es-7",
|
||||
TwitchSubscriber: "bda-es-7",
|
||||
BTTV: "bda-es-2",
|
||||
FrankerFaceZ: "bda-es-1",
|
||||
BTTV2: "bda-es-2"
|
||||
};
|
||||
|
||||
export const bdthemes = {};
|
||||
export const bdplugins = {};
|
||||
|
||||
export const pluginCookie = {};
|
||||
export const themeCookie = {};
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
import {pluginCookie, themeCookie, settingsCookie, bdplugins} from "./0globals";
|
||||
import mainCore from "./core";
|
||||
import Utils from "./utils";
|
||||
import BDV2 from "./v2";
|
||||
import DataStore from "./dataStore";
|
||||
|
||||
const BdApi = {
|
||||
get React() { return BDV2.react; },
|
||||
get ReactDOM() { return BDV2.reactDom; },
|
||||
get WindowConfigFile() {
|
||||
if (this._windowConfigFile) return this._windowConfigFile;
|
||||
const electron = require("electron").remote.app;
|
||||
const path = require("path");
|
||||
const base = electron.getAppPath();
|
||||
const roamingBase = electron.getPath("userData");
|
||||
const roamingLocation = path.resolve(roamingBase, electron.getVersion(), "modules", "discord_desktop_core", "injector", "config.json");
|
||||
const location = path.resolve(base, "..", "app", "config.json");
|
||||
const fs = require("fs");
|
||||
const realLocation = fs.existsSync(location) ? location : fs.existsSync(roamingLocation) ? roamingLocation : null;
|
||||
if (!realLocation) return this._windowConfigFile = null;
|
||||
return this._windowConfigFile = realLocation;
|
||||
}
|
||||
};
|
||||
|
||||
BdApi.getAllWindowPreferences = function() {
|
||||
if (!this.WindowConfigFile) return {}; // Tempfix until new injection on other platforms
|
||||
return __non_webpack_require__(this.WindowConfigFile);
|
||||
};
|
||||
|
||||
BdApi.getWindowPreference = function(key) {
|
||||
if (!this.WindowConfigFile) return undefined; // Tempfix until new injection on other platforms
|
||||
return this.getAllWindowPreferences()[key];
|
||||
};
|
||||
|
||||
BdApi.setWindowPreference = function(key, value) {
|
||||
if (!this.WindowConfigFile) return; // Tempfix until new injection on other platforms
|
||||
const fs = require("fs");
|
||||
const prefs = this.getAllWindowPreferences();
|
||||
prefs[key] = value;
|
||||
delete require.cache[this.WindowConfigFile];
|
||||
fs.writeFileSync(this.WindowConfigFile, JSON.stringify(prefs, null, 4));
|
||||
};
|
||||
|
||||
//Inject CSS to document head
|
||||
//id = id of element
|
||||
//css = custom css
|
||||
BdApi.injectCSS = function (id, css) {
|
||||
$("head").append($("<style>", {id: Utils.escapeID(id), text: css}));
|
||||
};
|
||||
|
||||
//Clear css/remove any element
|
||||
//id = id of element
|
||||
BdApi.clearCSS = function (id) {
|
||||
$("#" + Utils.escapeID(id)).remove();
|
||||
};
|
||||
|
||||
//Inject CSS to document head
|
||||
//id = id of element
|
||||
//css = custom css
|
||||
BdApi.linkJS = function (id, url) {
|
||||
$("head").append($("<script>", {id: Utils.escapeID(id), src: url, type: "text/javascript"}));
|
||||
};
|
||||
|
||||
//Clear css/remove any element
|
||||
//id = id of element
|
||||
BdApi.unlinkJS = function (id) {
|
||||
$("#" + Utils.escapeID(id)).remove();
|
||||
};
|
||||
|
||||
//Get another plugin
|
||||
//name = name of plugin
|
||||
BdApi.getPlugin = function (name) {
|
||||
if (bdplugins.hasOwnProperty(name)) {
|
||||
return bdplugins[name].plugin;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
//Get BetterDiscord Core
|
||||
BdApi.getCore = function () {
|
||||
return mainCore;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows a generic but very customizable modal.
|
||||
* @param {string} title - title of the modal
|
||||
* @param {string} content - a string of text to display in the modal
|
||||
*/
|
||||
BdApi.alert = function (title, content) {
|
||||
const ModalStack = BdApi.findModuleByProps("push", "update", "pop", "popWithKey");
|
||||
const AlertModal = BdApi.findModuleByPrototypes("handleCancel", "handleSubmit", "handleMinorConfirm");
|
||||
if (!ModalStack || !AlertModal) return mainCore.alert(title, content);
|
||||
|
||||
ModalStack.push(function(props) {
|
||||
return BdApi.React.createElement(AlertModal, Object.assign({
|
||||
title: title,
|
||||
body: content,
|
||||
}, props));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows a generic but very customizable confirmation modal with optional confirm and cancel callbacks.
|
||||
* @param {string} title - title of the modal
|
||||
* @param {(string|ReactElement|Array<string|ReactElement>)} children - a single or mixed array of react elements and strings. Everything is wrapped in Discord's `TextElement` component so strings will show and render properly.
|
||||
* @param {object} [options] - options to modify the modal
|
||||
* @param {boolean} [options.danger=false] - whether the main button should be red or not
|
||||
* @param {string} [options.confirmText=Okay] - text for the confirmation/submit button
|
||||
* @param {string} [options.cancelText=Cancel] - text for the cancel button
|
||||
* @param {callable} [options.onConfirm=NOOP] - callback to occur when clicking the submit button
|
||||
* @param {callable} [options.onCancel=NOOP] - callback to occur when clicking the cancel button
|
||||
*/
|
||||
BdApi.showConfirmationModal = function (title, content, options = {}) {
|
||||
const ModalStack = BdApi.findModuleByProps("push", "update", "pop", "popWithKey");
|
||||
const TextElement = BdApi.findModuleByProps("Sizes", "Weights");
|
||||
const ConfirmationModal = BdApi.findModule(m => m.defaultProps && m.key && m.key() == "confirm-modal");
|
||||
if (!ModalStack || !ConfirmationModal || !TextElement) return mainCore.alert(title, content);
|
||||
|
||||
const {onConfirm, onCancel, confirmText, cancelText, danger = false} = options;
|
||||
if (typeof(content) == "string") content = TextElement({color: TextElement.Colors.PRIMARY, children: [content]});
|
||||
else if (Array.isArray(content)) content = TextElement({color: TextElement.Colors.PRIMARY, children: content});
|
||||
content = [content];
|
||||
|
||||
const emptyFunction = () => {};
|
||||
ModalStack.push(function(props) {
|
||||
return BdApi.React.createElement(ConfirmationModal, Object.assign({
|
||||
header: title,
|
||||
children: content,
|
||||
red: danger,
|
||||
confirmText: confirmText ? confirmText : "Okay",
|
||||
cancelText: cancelText ? cancelText : "Cancel",
|
||||
onConfirm: onConfirm ? onConfirm : emptyFunction,
|
||||
onCancel: onCancel ? onCancel : emptyFunction
|
||||
}, props));
|
||||
});
|
||||
};
|
||||
|
||||
//Show toast alert
|
||||
BdApi.showToast = function(content, options = {}) {
|
||||
Utils.showToast(content, options);
|
||||
};
|
||||
|
||||
// Finds module
|
||||
BdApi.findModule = function(filter) {
|
||||
return BDV2.WebpackModules.find(filter);
|
||||
};
|
||||
|
||||
// Finds module
|
||||
BdApi.findAllModules = function(filter) {
|
||||
return BDV2.WebpackModules.findAll(filter);
|
||||
};
|
||||
|
||||
// Finds module
|
||||
BdApi.findModuleByProps = function(...props) {
|
||||
return BDV2.WebpackModules.findByUniqueProperties(props);
|
||||
};
|
||||
|
||||
BdApi.findModuleByPrototypes = function(...protos) {
|
||||
return BDV2.WebpackModules.findByPrototypes(protos);
|
||||
};
|
||||
|
||||
BdApi.findModuleByDisplayName = function(name) {
|
||||
return BDV2.WebpackModules.findByDisplayName(name);
|
||||
};
|
||||
|
||||
// Gets react instance
|
||||
BdApi.getInternalInstance = function(node) {
|
||||
if (!(node instanceof window.jQuery) && !(node instanceof Element)) return undefined;
|
||||
if (node instanceof jQuery) node = node[0];
|
||||
return BDV2.getInternalInstance(node);
|
||||
};
|
||||
|
||||
// Gets data
|
||||
BdApi.loadData = function(pluginName, key) {
|
||||
return DataStore.getPluginData(pluginName, key);
|
||||
};
|
||||
|
||||
BdApi.getData = BdApi.loadData;
|
||||
|
||||
// Sets data
|
||||
BdApi.saveData = function(pluginName, key, data) {
|
||||
return DataStore.setPluginData(pluginName, key, data);
|
||||
};
|
||||
|
||||
BdApi.setData = BdApi.saveData;
|
||||
|
||||
// Deletes data
|
||||
BdApi.deleteData = function(pluginName, key) {
|
||||
return DataStore.deletePluginData(pluginName, key);
|
||||
};
|
||||
|
||||
// Patches other functions
|
||||
BdApi.monkeyPatch = function(what, methodName, options) {
|
||||
return Utils.monkeyPatch(what, methodName, options);
|
||||
};
|
||||
|
||||
// Event when element is removed
|
||||
BdApi.onRemoved = function(node, callback) {
|
||||
return Utils.onRemoved(node, callback);
|
||||
};
|
||||
|
||||
// Wraps function in try..catch
|
||||
BdApi.suppressErrors = function(method, message) {
|
||||
return Utils.suppressErrors(method, message);
|
||||
};
|
||||
|
||||
// Tests for valid JSON
|
||||
BdApi.testJSON = function(data) {
|
||||
return Utils.testJSON(data);
|
||||
};
|
||||
|
||||
BdApi.isPluginEnabled = function(name) {
|
||||
return !!pluginCookie[name];
|
||||
};
|
||||
|
||||
BdApi.isThemeEnabled = function(name) {
|
||||
return !!themeCookie[name];
|
||||
};
|
||||
|
||||
BdApi.isSettingEnabled = function(id) {
|
||||
return !!settingsCookie[id];
|
||||
};
|
||||
|
||||
// Gets data
|
||||
BdApi.getBDData = function(key) {
|
||||
return DataStore.getBDData(key);
|
||||
};
|
||||
|
||||
// Sets data
|
||||
BdApi.setBDData = function(key, data) {
|
||||
return DataStore.setBDData(key, data);
|
||||
};
|
||||
|
||||
export default BdApi;
|
|
@ -0,0 +1,6 @@
|
|||
/* BDEvents */
|
||||
const EventEmitter = require("events");
|
||||
export default new class BDEvents extends EventEmitter {
|
||||
dispatch(eventName, ...args) {this.emit(eventName, ...args);}
|
||||
off(eventName, eventAction) {this.removeListener(eventName, eventAction);}
|
||||
};
|
|
@ -0,0 +1,119 @@
|
|||
import WebpackModules from "./webpackModules";
|
||||
|
||||
const normalizedPrefix = "da";
|
||||
const randClass = new RegExp(`^(?!${normalizedPrefix}-)((?:[A-Za-z]|[0-9]|-)+)-(?:[A-Za-z]|[0-9]|-|_){6}$`);
|
||||
|
||||
export default new class ClassNormalizer {
|
||||
|
||||
stop() {
|
||||
if (!this.hasPatched) return;
|
||||
this.unpatchClassModules(WebpackModules.findAll(this.moduleFilter.bind(this)));
|
||||
this.revertElement(document.querySelector("#app-mount"));
|
||||
this.hasPatched = false;
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.hasPatched) return;
|
||||
this.patchClassModules(WebpackModules.findAll(this.moduleFilter.bind(this)));
|
||||
this.normalizeElement(document.querySelector("#app-mount"));
|
||||
this.hasPatched = true;
|
||||
this.patchDOMMethods();
|
||||
}
|
||||
|
||||
patchClassModules(modules) {
|
||||
for (const module of modules) {
|
||||
this.patchClassModule(normalizedPrefix, module);
|
||||
}
|
||||
}
|
||||
|
||||
unpatchClassModules(modules) {
|
||||
for (const module of modules) {
|
||||
this.unpatchClassModule(normalizedPrefix, module);
|
||||
}
|
||||
}
|
||||
|
||||
shouldIgnore(value) {
|
||||
if (!isNaN(value)) return true;
|
||||
if (value.endsWith("px") || value.endsWith("ch") || value.endsWith("em") || value.endsWith("ms")) return true;
|
||||
if (value.startsWith("layerContainer-")) return true;
|
||||
if (value.startsWith("#") && (value.length == 7 || value.length == 4)) return true;
|
||||
if (value.includes("calc(") || value.includes("rgba")) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
moduleFilter(module) {
|
||||
if (typeof module !== "object" || Array.isArray(module)) return false;
|
||||
if (module.__esModule) return false;
|
||||
if (!Object.keys(module).length) return false;
|
||||
for (const baseClassName in module) {
|
||||
const value = module[baseClassName];
|
||||
if (typeof value !== "string") return false;
|
||||
if (this.shouldIgnore(value)) continue;
|
||||
if (value.split("-").length === 1) return false;
|
||||
if (!randClass.test(value.split(" ")[0])) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
patchClassModule(componentName, classNames) {
|
||||
for (const baseClassName in classNames) {
|
||||
const value = classNames[baseClassName];
|
||||
if (this.shouldIgnore(value)) continue;
|
||||
const classList = value.split(" ");
|
||||
for (const normalClass of classList) {
|
||||
const match = normalClass.match(randClass);
|
||||
if (!match || !match.length || match.length < 2) continue; // Shouldn't ever happen since they passed the moduleFilter, but you never know
|
||||
const camelCase = match[1].split("-").map((s, i) => i ? s[0].toUpperCase() + s.slice(1) : s).join("");
|
||||
classNames[baseClassName] += ` ${componentName}-${camelCase}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unpatchClassModule(componentName, classNames) {
|
||||
for (const baseClassName in classNames) {
|
||||
const value = classNames[baseClassName];
|
||||
if (this.shouldIgnore(value)) continue;
|
||||
let newString = "";
|
||||
const classList = value.split(" ");
|
||||
for (const normalClass of classList) {
|
||||
if (normalClass.startsWith(`${componentName}-`)) continue;
|
||||
newString += ` ${normalClass}`;
|
||||
}
|
||||
classNames[baseClassName] = newString.trim();
|
||||
}
|
||||
}
|
||||
|
||||
normalizeElement(element) {
|
||||
if (!(element instanceof Element)) return;
|
||||
const classes = element.classList;
|
||||
for (let c = 0, clen = classes.length; c < clen; c++) {
|
||||
if (!randClass.test(classes[c])) continue;
|
||||
const match = classes[c].match(randClass)[1];
|
||||
const newClass = match.split("-").map((s, i) => i ? s[0].toUpperCase() + s.slice(1) : s).join("");
|
||||
element.classList.add(`${normalizedPrefix}-${newClass}`);
|
||||
}
|
||||
for (const child of element.children) this.normalizeElement(child);
|
||||
}
|
||||
|
||||
revertElement(element) {
|
||||
if (!(element instanceof Element)) return;
|
||||
if (element.children && element.children.length) this.revertElement(element.children[0]);
|
||||
if (element.nextElementSibling) this.revertElement(element.nextElementSibling);
|
||||
const classes = element.classList;
|
||||
const toRemove = [];
|
||||
for (let c = 0; c < classes.length; c++) {
|
||||
if (classes[c].startsWith(`${normalizedPrefix}-`)) toRemove.push(classes[c]);
|
||||
}
|
||||
element.classList.remove(...toRemove);
|
||||
}
|
||||
|
||||
patchDOMMethods() {
|
||||
const contains = DOMTokenList.prototype.contains;
|
||||
DOMTokenList.prototype.contains = function(token) {
|
||||
const tokens = token.split(" ");
|
||||
return tokens.every(t => contains.call(this, t));
|
||||
};
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
import {settingsCookie} from "./0globals";
|
||||
import BDV2 from "./v2";
|
||||
import Utils from "./utils";
|
||||
|
||||
export default new class ColoredText {
|
||||
injectColoredText() {
|
||||
if (this.cancelColoredText) return;
|
||||
if (!BDV2.MessageComponent) return;
|
||||
|
||||
this.cancelColoredText = Utils.monkeyPatch(BDV2.MessageComponent, "default", {before: (data) => {
|
||||
const props = data.methodArguments[0];
|
||||
if (!props || !props.childrenMessageContent) return;
|
||||
const messageContent = props.childrenMessageContent;
|
||||
|
||||
if (!messageContent.type || !messageContent.type.type || messageContent.type.type.displayName != "MessageContent") return;
|
||||
const originalType = messageContent.type.type;
|
||||
if (originalType.__originalMethod) return; // Don't patch again
|
||||
messageContent.type.type = function(props) {
|
||||
const returnValue = originalType(props);
|
||||
const roleColor = settingsCookie["bda-gs-7"] ? props.message.colorString || "" : "";
|
||||
returnValue.props.style = {color: roleColor};
|
||||
return returnValue;
|
||||
};
|
||||
|
||||
messageContent.type.type.__originalMethod = originalType;
|
||||
Object.assign(messageContent.type.type, originalType);
|
||||
}});
|
||||
}
|
||||
|
||||
removeColoredText() {
|
||||
document.querySelectorAll(".markup-2BOw-j").forEach(elem => {
|
||||
elem.style.setProperty("color", "");
|
||||
});
|
||||
}
|
||||
};
|
|
@ -0,0 +1,243 @@
|
|||
|
||||
import {bdConfig, bdplugins, bdthemes} from "./0globals";
|
||||
import pluginModule from "./pluginModule";
|
||||
import themeModule from "./themeModule";
|
||||
import Utils from "./utils";
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const Module = require("module").Module;
|
||||
Module.globalPaths.push(path.resolve(require("electron").remote.app.getAppPath(), "node_modules"));
|
||||
class MetaError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = "MetaError";
|
||||
}
|
||||
}
|
||||
const originalJSRequire = Module._extensions[".js"];
|
||||
const originalCSSRequire = Module._extensions[".css"] ? Module._extensions[".css"] : () => {return null;};
|
||||
const splitRegex = /[^\S\r\n]*?(?:\r\n|\n)[^\S\r\n]*?\*[^\S\r\n]?/;
|
||||
const escapedAtRegex = /^\\@/;
|
||||
|
||||
|
||||
export default new class ContentManager {
|
||||
|
||||
constructor() {
|
||||
this.timeCache = {};
|
||||
this.watchers = {};
|
||||
Module._extensions[".js"] = this.getContentRequire("plugin");
|
||||
Module._extensions[".css"] = this.getContentRequire("theme");
|
||||
}
|
||||
|
||||
get pluginsFolder() {return this._pluginsFolder || (this._pluginsFolder = fs.realpathSync(path.resolve(bdConfig.dataPath + "plugins/")));}
|
||||
get themesFolder() {return this._themesFolder || (this._themesFolder = fs.realpathSync(path.resolve(bdConfig.dataPath + "themes/")));}
|
||||
|
||||
watchContent(contentType) {
|
||||
if (this.watchers[contentType]) return;
|
||||
const isPlugin = contentType === "plugin";
|
||||
const baseFolder = isPlugin ? this.pluginsFolder : this.themesFolder;
|
||||
const fileEnding = isPlugin ? ".plugin.js" : ".theme.css";
|
||||
this.watchers[contentType] = fs.watch(baseFolder, {persistent: false}, async (eventType, filename) => {
|
||||
if (!eventType || !filename || !filename.endsWith(fileEnding)) return;
|
||||
await new Promise(r => setTimeout(r, 50));
|
||||
try {fs.statSync(path.resolve(baseFolder, filename));}
|
||||
catch (err) {
|
||||
if (err.code !== "ENOENT") return;
|
||||
delete this.timeCache[filename];
|
||||
if (isPlugin) return pluginModule.unloadPlugin(filename);
|
||||
return themeModule.unloadTheme(filename);
|
||||
}
|
||||
if (!fs.statSync(path.resolve(baseFolder, filename)).isFile()) return;
|
||||
const stats = fs.statSync(path.resolve(baseFolder, filename));
|
||||
if (!stats || !stats.mtime || !stats.mtime.getTime()) return;
|
||||
if (typeof(stats.mtime.getTime()) !== "number") return;
|
||||
if (this.timeCache[filename] == stats.mtime.getTime()) return;
|
||||
this.timeCache[filename] = stats.mtime.getTime();
|
||||
if (eventType == "rename") {
|
||||
if (isPlugin) pluginModule.loadPlugin(filename);
|
||||
else themeModule.loadTheme(filename);
|
||||
}
|
||||
if (eventType == "change") {
|
||||
if (isPlugin) pluginModule.reloadPlugin(filename);
|
||||
else themeModule.reloadTheme(filename);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unwatchContent(contentType) {
|
||||
if (!this.watchers[contentType]) return;
|
||||
this.watchers[contentType].close();
|
||||
delete this.watchers[contentType];
|
||||
}
|
||||
|
||||
extractMeta(content) {
|
||||
const firstLine = content.split("\n")[0];
|
||||
const hasOldMeta = firstLine.includes("//META");
|
||||
if (hasOldMeta) return this.parseOldMeta(content);
|
||||
const hasNewMeta = firstLine.includes("/**");
|
||||
if (hasNewMeta) return this.parseNewMeta(content);
|
||||
throw new MetaError("META was not found.");
|
||||
}
|
||||
|
||||
parseOldMeta(content) {
|
||||
const meta = content.split("\n")[0];
|
||||
const rawMeta = meta.substring(meta.lastIndexOf("//META") + 6, meta.lastIndexOf("*//"));
|
||||
if (meta.indexOf("META") < 0) throw new MetaError("META was not found.");
|
||||
const parsed = Utils.testJSON(rawMeta);
|
||||
if (!parsed) throw new MetaError("META could not be parsed.");
|
||||
if (!parsed.name) throw new MetaError("META missing name data.");
|
||||
parsed.format = "json";
|
||||
return parsed;
|
||||
}
|
||||
|
||||
parseNewMeta(content) {
|
||||
const block = content.split("/**", 2)[1].split("*/", 1)[0];
|
||||
const out = {};
|
||||
let field = "";
|
||||
let accum = "";
|
||||
for (const line of block.split(splitRegex)) {
|
||||
if (line.length === 0) continue;
|
||||
if (line.charAt(0) === "@" && line.charAt(1) !== " ") {
|
||||
out[field] = accum;
|
||||
const l = line.indexOf(" ");
|
||||
field = line.substr(1, l - 1);
|
||||
accum = line.substr(l + 1);
|
||||
}
|
||||
else {
|
||||
accum += " " + line.replace("\\n", "\n").replace(escapedAtRegex, "@");
|
||||
}
|
||||
}
|
||||
out[field] = accum.trim();
|
||||
delete out[""];
|
||||
out.format = "jsdoc";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
getContentRequire(type) {
|
||||
const isPlugin = type === "plugin";
|
||||
const self = this;
|
||||
const originalRequire = isPlugin ? originalJSRequire : originalCSSRequire;
|
||||
return function(module, filename) {
|
||||
const baseFolder = isPlugin ? self.pluginsFolder : self.themesFolder;
|
||||
const possiblePath = path.resolve(baseFolder, path.basename(filename));
|
||||
if (!fs.existsSync(possiblePath) || filename !== fs.realpathSync(possiblePath)) return Reflect.apply(originalRequire, this, arguments);
|
||||
let content = fs.readFileSync(filename, "utf8");
|
||||
content = Utils.stripBOM(content);
|
||||
|
||||
const meta = self.extractMeta(content);
|
||||
meta.filename = path.basename(filename);
|
||||
if (!isPlugin) {
|
||||
meta.css = content;
|
||||
if (meta.format == "json") meta.css = meta.css.split("\n").slice(1).join("\n");
|
||||
content = `module.exports = ${JSON.stringify(meta)};`;
|
||||
}
|
||||
if (isPlugin) {
|
||||
module._compile(content, module.filename);
|
||||
const didExport = !Utils.isEmpty(module.exports);
|
||||
if (didExport) {
|
||||
meta.type = module.exports;
|
||||
module.exports = meta;
|
||||
content = "";
|
||||
}
|
||||
else {
|
||||
content += `\nmodule.exports = ${JSON.stringify(meta)};\nmodule.exports.type = ${meta.exports || meta.name};`;
|
||||
}
|
||||
}
|
||||
module._compile(content, filename);
|
||||
};
|
||||
}
|
||||
|
||||
makePlaceholderPlugin(data) {
|
||||
return {plugin: {
|
||||
start: () => {},
|
||||
getName: () => {return data.name || data.filename;},
|
||||
getAuthor: () => {return "???";},
|
||||
getDescription: () => {return data.message ? data.message : "This plugin was unable to be loaded. Check the author's page for updates.";},
|
||||
getVersion: () => {return "???";}
|
||||
},
|
||||
name: data.name || data.filename,
|
||||
filename: data.filename,
|
||||
source: data.source ? data.source : "",
|
||||
website: data.website ? data.website : ""
|
||||
};
|
||||
}
|
||||
|
||||
loadContent(filename, type) {
|
||||
if (typeof(filename) === "undefined" || typeof(type) === "undefined") return;
|
||||
const isPlugin = type === "plugin";
|
||||
const baseFolder = isPlugin ? this.pluginsFolder : this.themesFolder;
|
||||
try {__non_webpack_require__(path.resolve(baseFolder, filename));}
|
||||
catch (error) {return {name: filename, file: filename, message: "Could not be compiled.", error: {message: error.message, stack: error.stack}};}
|
||||
const content = __non_webpack_require__(path.resolve(baseFolder, filename));
|
||||
content.id = Utils.escapeID(content.name);
|
||||
if (isPlugin) {
|
||||
if (!content.type) return;
|
||||
try {
|
||||
content.plugin = new content.type();
|
||||
delete bdplugins[content.plugin.getName()];
|
||||
bdplugins[content.plugin.getName()] = content;
|
||||
}
|
||||
catch (error) {return {name: filename, file: filename, message: "Could not be constructed.", error: {message: error.message, stack: error.stack}};}
|
||||
}
|
||||
else {
|
||||
delete bdthemes[content.name];
|
||||
bdthemes[content.name] = content;
|
||||
}
|
||||
}
|
||||
|
||||
unloadContent(filename, type) {
|
||||
if (typeof(filename) === "undefined" || typeof(type) === "undefined") return;
|
||||
const isPlugin = type === "plugin";
|
||||
const baseFolder = isPlugin ? this.pluginsFolder : this.themesFolder;
|
||||
try {
|
||||
delete require.cache[require.resolve(path.resolve(baseFolder, filename))];
|
||||
}
|
||||
catch (err) {return {name: filename, file: filename, message: "Could not be unloaded.", error: {message: err.message, stack: err.stack}};}
|
||||
}
|
||||
|
||||
isLoaded(filename, type) {
|
||||
const isPlugin = type === "plugin";
|
||||
const baseFolder = isPlugin ? this.pluginsFolder : this.themesFolder;
|
||||
try {require.cache[require.resolve(path.resolve(baseFolder, filename))];}
|
||||
catch (err) {return false;}
|
||||
return true;
|
||||
}
|
||||
|
||||
reloadContent(filename, type) {
|
||||
const cantUnload = this.unloadContent(filename, type);
|
||||
if (cantUnload) return cantUnload;
|
||||
return this.loadContent(filename, type);
|
||||
}
|
||||
|
||||
loadNewContent(type) {
|
||||
const isPlugin = type === "plugin";
|
||||
const fileEnding = isPlugin ? ".plugin.js" : ".theme.css";
|
||||
const basedir = isPlugin ? this.pluginsFolder : this.themesFolder;
|
||||
const files = fs.readdirSync(basedir);
|
||||
const contentList = Object.values(isPlugin ? bdplugins : bdthemes);
|
||||
const removed = contentList.filter(t => !files.includes(t.filename)).map(c => isPlugin ? c.plugin.getName() : c.name);
|
||||
const added = files.filter(f => !contentList.find(t => t.filename == f) && f.endsWith(fileEnding) && fs.statSync(path.resolve(basedir, f)).isFile());
|
||||
return {added, removed};
|
||||
}
|
||||
|
||||
loadAllContent(type) {
|
||||
const isPlugin = type === "plugin";
|
||||
const fileEnding = isPlugin ? ".plugin.js" : ".theme.css";
|
||||
const basedir = isPlugin ? this.pluginsFolder : this.themesFolder;
|
||||
const errors = [];
|
||||
const files = fs.readdirSync(basedir);
|
||||
|
||||
for (const filename of files) {
|
||||
if (!fs.statSync(path.resolve(basedir, filename)).isFile() || !filename.endsWith(fileEnding)) continue;
|
||||
const error = this.loadContent(filename, type);
|
||||
if (error) errors.push(error);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
loadPlugins() {return this.loadAllContent("plugin");}
|
||||
loadThemes() {return this.loadAllContent("theme");}
|
||||
};
|
|
@ -0,0 +1,350 @@
|
|||
import {bdConfig, minSupportedVersion, bbdVersion, settingsCookie, bdpluginErrors, bdthemeErrors, bbdChangelog, defaultCookie} from "./0globals";
|
||||
import Utils from "./utils";
|
||||
import emoteModule from "./emoteModule";
|
||||
import quickEmoteMenu from "./quickEmoteMenu";
|
||||
// import publicServersModule from "./publicServers";
|
||||
// import voiceMode from "./voiceMode";
|
||||
// import dMode from "./devMode";
|
||||
import BDV2 from "./v2";
|
||||
import settingsPanel from "./settingsPanel";
|
||||
import pluginModule from "./pluginModule";
|
||||
import themeModule from "./themeModule";
|
||||
import DataStore from "./dataStore";
|
||||
import WebpackModules from "./webpackModules";
|
||||
|
||||
import BDLogo from "./react/bdLogo";
|
||||
|
||||
function Core(config) {
|
||||
Object.assign(bdConfig, config);
|
||||
}
|
||||
|
||||
Core.prototype.init = async function() {
|
||||
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>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.ED) {
|
||||
Utils.alert("Not Supported", "BandagedBD does not work with EnhancedDiscord. Please uninstall one of them.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.WebSocket && window.WebSocket.name && window.WebSocket.name.includes("Patched")) {
|
||||
Utils.alert("Not Supported", "BandagedBD does not work with Powercord. Please uninstall one of them.");
|
||||
return;
|
||||
}
|
||||
|
||||
const latestLocalVersion = bdConfig.updater ? bdConfig.updater.LatestVersion : bdConfig.latestVersion;
|
||||
if (latestLocalVersion > bdConfig.version) {
|
||||
Utils.alert("Update Available", `
|
||||
An update for BandagedBD is available (${latestLocalVersion})! Please Reinstall!<br /><br />
|
||||
<a href='https://github.com/rauenzi/BetterDiscordApp/releases/latest' target='_blank'>Download Installer</a>
|
||||
`);
|
||||
}
|
||||
|
||||
Utils.log("Startup", "Initializing Settings");
|
||||
this.initSettings();
|
||||
// emoteModule = new EmoteModule();
|
||||
// quickEmoteMenu = new QuickEmoteMenu();
|
||||
Utils.log("Startup", "Initializing EmoteModule");
|
||||
window.emotePromise = emoteModule.init().then(() => {
|
||||
emoteModule.initialized = true;
|
||||
Utils.log("Startup", "Initializing QuickEmoteMenu");
|
||||
quickEmoteMenu.init();
|
||||
});
|
||||
// publicServersModule = new V2_PublicServers();
|
||||
|
||||
// voiceMode = new VoiceMode();
|
||||
// dMode = new devMode();
|
||||
|
||||
this.injectExternals();
|
||||
|
||||
await this.checkForGuilds();
|
||||
BDV2.initialize();
|
||||
Utils.log("Startup", "Updating Settings");
|
||||
// settingsPanel = new V2_SettingsPanel();
|
||||
settingsPanel.initializeSettings();
|
||||
|
||||
Utils.log("Startup", "Loading Plugins");
|
||||
// pluginModule = new PluginModule();
|
||||
pluginModule.loadPlugins();
|
||||
|
||||
Utils.log("Startup", "Loading Themes");
|
||||
// themeModule = new ThemeModule();
|
||||
themeModule.loadThemes();
|
||||
|
||||
$("#customcss").detach().appendTo(document.head);
|
||||
|
||||
window.addEventListener("beforeunload", function() {
|
||||
if (settingsCookie["bda-dc-0"]) document.querySelector(".btn.btn-disconnect").click();
|
||||
});
|
||||
|
||||
emoteModule.autoCapitalize();
|
||||
|
||||
Utils.log("Startup", "Removing Loading Icon");
|
||||
if (document.getElementsByClassName("bd-loaderv2").length) document.getElementsByClassName("bd-loaderv2")[0].remove();
|
||||
Utils.log("Startup", "Initializing Main Observer");
|
||||
this.initObserver();
|
||||
|
||||
// Show loading errors
|
||||
if (settingsCookie["fork-ps-1"]) {
|
||||
Utils.log("Startup", "Collecting Startup Errors");
|
||||
Utils.showContentErrors({plugins: bdpluginErrors, themes: bdthemeErrors});
|
||||
}
|
||||
|
||||
const previousVersion = DataStore.getBDData("version");
|
||||
if (bbdVersion > previousVersion) {
|
||||
if (bbdChangelog) this.showChangelogModal(bbdChangelog);
|
||||
DataStore.setBDData("version", bbdVersion);
|
||||
}
|
||||
|
||||
Utils.suppressErrors(this.patchSocial.bind(this), "BD Social Patch")();
|
||||
Utils.suppressErrors(this.patchGuildPills.bind(this), "BD Guild Pills Patch")();
|
||||
Utils.suppressErrors(this.patchGuildListItems.bind(this), "BD Guild List Items Patch")();
|
||||
Utils.suppressErrors(this.patchGuildSeparator.bind(this), "BD Guild Separator Patch")();
|
||||
};
|
||||
|
||||
Core.prototype.checkForGuilds = function() {
|
||||
let timesChecked = 0;
|
||||
return new Promise(resolve => {
|
||||
const checkForGuilds = function() {
|
||||
const wrapper = BDV2.guildClasses.wrapper.split(" ")[0];
|
||||
if (document.querySelectorAll(`.${wrapper}`).length > 0) timesChecked++;
|
||||
const guild = BDV2.guildClasses.listItem.split(" ")[0];
|
||||
const blob = BDV2.guildClasses.blobContainer.split(" ")[0];
|
||||
if (document.querySelectorAll(`.${wrapper} .${guild} .${blob}`).length > 0) return resolve(bdConfig.deferLoaded = true);
|
||||
else if (timesChecked >= 50) return resolve(bdConfig.deferLoaded = true);
|
||||
setTimeout(checkForGuilds, 100);
|
||||
};
|
||||
$(document).ready(function () {
|
||||
setTimeout(checkForGuilds, 100);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Core.prototype.injectExternals = async function() {
|
||||
await Utils.injectJs("https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js");
|
||||
if (require.original) window.require = require.original;
|
||||
};
|
||||
|
||||
Core.prototype.initSettings = function () {
|
||||
DataStore.initialize();
|
||||
if (!DataStore.getSettingGroup("settings")) {
|
||||
Object.assign(settingsCookie, defaultCookie);
|
||||
settingsPanel.saveSettings();
|
||||
}
|
||||
else {
|
||||
settingsPanel.loadSettings();
|
||||
$("<style id=\"customcss\">").text(atob(DataStore.getBDData("bdcustomcss"))).appendTo(document.head);
|
||||
for (const setting in defaultCookie) {
|
||||
if (settingsCookie[setting] == undefined) {
|
||||
settingsCookie[setting] = defaultCookie[setting];
|
||||
settingsPanel.saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Core.prototype.initObserver = function () {
|
||||
const mainObserver = new MutationObserver((mutations) => {
|
||||
|
||||
for (let i = 0, mlen = mutations.length; i < mlen; i++) {
|
||||
const mutation = mutations[i];
|
||||
if (typeof pluginModule !== "undefined") pluginModule.rawObserver(mutation);
|
||||
|
||||
// if there was nothing added, skip
|
||||
if (!mutation.addedNodes.length || !(mutation.addedNodes[0] instanceof Element)) continue;
|
||||
|
||||
const node = mutation.addedNodes[0];
|
||||
|
||||
if (node.classList.contains("layer-3QrUeG")) {
|
||||
if (node.getElementsByClassName("guild-settings-base-section").length) node.setAttribute("layer-id", "server-settings");
|
||||
|
||||
if (node.getElementsByClassName("socialLinks-3jqNFy").length) {
|
||||
node.setAttribute("layer-id", "user-settings");
|
||||
node.setAttribute("id", "user-settings");
|
||||
if (!document.getElementById("bd-settings-sidebar")) settingsPanel.renderSidebar();
|
||||
}
|
||||
}
|
||||
|
||||
if (node.parentElement == document.body && node.querySelector("#ace_settingsmenu")) node.id = "ace_settingsmenu_container";
|
||||
|
||||
// Emoji Picker
|
||||
//node.getElementsByClassName("emojiPicker-3m1S-j").length && !node.querySelector(".emojiPicker-3m1S-j").parentElement.classList.contains("animatorLeft-1EQxU0")
|
||||
if (node.classList.contains("layer-v9HyYc") && node.getElementsByClassName("emojiPicker-3m1S-j").length && !node.querySelector(".emojiPicker-3m1S-j").parentElement.classList.contains("animatorLeft-1EQxU0")) quickEmoteMenu.obsCallback(node);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
mainObserver.observe(document, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
};
|
||||
|
||||
Core.prototype.inject24Hour = function() {
|
||||
if (this.cancel24Hour) return;
|
||||
|
||||
const twelveHour = new RegExp(`([0-9]{1,2}):([0-9]{1,2})\\s(AM|PM)`);
|
||||
const convert = (data) => {
|
||||
if (!settingsCookie["bda-gs-6"]) return;
|
||||
const matched = data.returnValue.match(twelveHour);
|
||||
if (!matched || matched.length !== 4) return;
|
||||
if (matched[3] === "AM") return data.returnValue = data.returnValue.replace(matched[0], `${matched[1] === "12" ? "00" : matched[1].padStart(2, "0")}:${matched[2]}`);
|
||||
return data.returnValue = data.returnValue.replace(matched[0], `${matched[1] === "12" ? "12" : parseInt(matched[1]) + 12}:${matched[2]}`);
|
||||
};
|
||||
|
||||
const cancelCozy = Utils.monkeyPatch(BDV2.TimeFormatter, "calendarFormat", {after: convert}); // Called in Cozy mode
|
||||
const cancelCompact = Utils.monkeyPatch(BDV2.TimeFormatter, "dateFormat", {after: convert}); // Called in Compact mode
|
||||
this.cancel24Hour = () => {cancelCozy(); cancelCompact();}; // Cancel both
|
||||
};
|
||||
|
||||
Core.prototype.showChangelogModal = function(options = {}) {
|
||||
const ModalStack = WebpackModules.findByProps("push", "update", "pop", "popWithKey");
|
||||
const ChangelogClasses = WebpackModules.findByProps("fixed", "improved");
|
||||
const TextElement = WebpackModules.findByProps("Sizes", "Weights");
|
||||
const FlexChild = WebpackModules.findByProps("Child");
|
||||
const Titles = WebpackModules.findByProps("Tags", "default");
|
||||
const Changelog = WebpackModules.find(m => m.defaultProps && m.defaultProps.selectable == false);
|
||||
const MarkdownParser = WebpackModules.findByProps("defaultRules", "parse");
|
||||
if (!Changelog || !ModalStack || !ChangelogClasses || !TextElement || !FlexChild || !Titles || !MarkdownParser) return;
|
||||
|
||||
const {image = "https://repository-images.githubusercontent.com/105473537/957b5480-7c26-11e9-8401-50fa820cbae5", description = "", changes = [], title = "BandagedBD", subtitle = `v${bbdVersion}`, footer} = options;
|
||||
const ce = BDV2.React.createElement;
|
||||
const changelogItems = [ce("img", {src: image})];
|
||||
if (description) changelogItems.push(ce("p", null, MarkdownParser.parse(description)));
|
||||
for (let c = 0; c < changes.length; c++) {
|
||||
const entry = changes[c];
|
||||
const type = ChangelogClasses[entry.type] ? ChangelogClasses[entry.type] : ChangelogClasses.added;
|
||||
const margin = c == 0 ? ChangelogClasses.marginTop : "";
|
||||
changelogItems.push(ce("h1", {className: `${type} ${margin}`,}, entry.title));
|
||||
const list = ce("ul", null, entry.items.map(i => ce("li", null, MarkdownParser.parse(i))));
|
||||
changelogItems.push(list);
|
||||
}
|
||||
const renderHeader = function() {
|
||||
return ce(FlexChild.Child, {grow: 1, shrink: 1},
|
||||
ce(Titles.default, {tag: Titles.Tags.H4}, title),
|
||||
ce(TextElement,{size: TextElement.Sizes.SMALL, color: TextElement.Colors.PRIMARY, className: ChangelogClasses.date}, subtitle)
|
||||
);
|
||||
};
|
||||
|
||||
const renderFooter = () => {
|
||||
const Anchor = WebpackModules.find(m => m.displayName == "Anchor");
|
||||
const AnchorClasses = WebpackModules.findByProps("anchorUnderlineOnHover") || {anchor: "anchor-3Z-8Bb", anchorUnderlineOnHover: "anchorUnderlineOnHover-2ESHQB"};
|
||||
const joinSupportServer = (click) => {
|
||||
click.preventDefault();
|
||||
click.stopPropagation();
|
||||
ModalStack.pop();
|
||||
BDV2.joinBD2();
|
||||
};
|
||||
const supportLink = Anchor ? ce(Anchor, {onClick: joinSupportServer}, "Join our Discord Server.") : ce("a", {className: `${AnchorClasses.anchor} ${AnchorClasses.anchorUnderlineOnHover}`, onClick: joinSupportServer}, "Join our Discord Server.");
|
||||
const defaultFooter = ce(TextElement,{size: TextElement.Sizes.SMALL, color: TextElement.Colors.PRIMARY}, "Need support? ", supportLink);
|
||||
return ce(FlexChild.Child, {grow: 1, shrink: 1}, footer ? footer : defaultFooter);
|
||||
};
|
||||
|
||||
ModalStack.push(function(props) {
|
||||
return ce(Changelog, Object.assign({
|
||||
className: ChangelogClasses.container,
|
||||
selectable: true,
|
||||
onScroll: _ => _,
|
||||
onClose: _ => _,
|
||||
renderHeader: renderHeader,
|
||||
renderFooter: renderFooter,
|
||||
children: changelogItems
|
||||
}, props));
|
||||
});
|
||||
};
|
||||
|
||||
Core.prototype.patchSocial = function() {
|
||||
if (this.socialPatch) return;
|
||||
const TabBar = WebpackModules.find(m => m.displayName == "TabBar");
|
||||
const Anchor = WebpackModules.find(m => m.displayName == "Anchor");
|
||||
if (!TabBar || !Anchor) return;
|
||||
this.socialPatch = Utils.monkeyPatch(TabBar.prototype, "render", {after: (data) => {
|
||||
const children = data.returnValue.props.children;
|
||||
if (!children || !children.length || children.length < 3) return;
|
||||
if (children[children.length - 3].type.displayName !== "Separator") return;
|
||||
if (!children[children.length - 2].type.toString().includes("socialLinks")) return;
|
||||
const original = children[children.length - 2].type;
|
||||
const newOne = function() {
|
||||
const returnVal = original(...arguments);
|
||||
returnVal.props.children.push(BDV2.React.createElement(Anchor, {className: "bd-social-link", href: "https://github.com/rauenzi/BetterDiscordApp", title: "BandagedBD", target: "_blank"},
|
||||
BDV2.React.createElement(BDLogo, {size: "16px", className: "bd-social-logo"})
|
||||
));
|
||||
return returnVal;
|
||||
};
|
||||
children[children.length - 2].type = newOne;
|
||||
|
||||
const BBDLink = BDV2.React.createElement(Anchor, {className: "bd-social-link", href: "https://twitter.com/BandagedBD", title: "BandagedBD", target: "_blank"}, "BandagedBD");
|
||||
const AuthorLink = BDV2.React.createElement(Anchor, {className: "bd-social-link", href: "https://twitter.com/ZackRauen", title: "Zerebos", target: "_blank"}, "Zerebos");
|
||||
const additional = BDV2.react.createElement("div", {className: "colorMuted-HdFt4q size12-3cLvbJ"}, [BBDLink, ` ${bbdVersion} by `, AuthorLink]);
|
||||
|
||||
const originalVersions = children[children.length - 1].type;
|
||||
children[children.length - 1].type = function() {
|
||||
const returnVal = originalVersions(...arguments);
|
||||
returnVal.props.children.push(additional);
|
||||
return returnVal;
|
||||
};
|
||||
}});
|
||||
};
|
||||
|
||||
const getGuildClasses = function() {
|
||||
const guildsWrapper = WebpackModules.findByProps("wrapper", "unreadMentionsBar");
|
||||
const guilds = WebpackModules.findByProps("guildsError", "selected");
|
||||
const pill = WebpackModules.findByProps("blobContainer");
|
||||
return Object.assign({}, guildsWrapper, guilds, pill);
|
||||
};
|
||||
|
||||
Core.prototype.patchGuildListItems = function() {
|
||||
if (this.guildListItemsPatch) return;
|
||||
const GuildClasses = getGuildClasses();
|
||||
const listItemClass = GuildClasses.listItem.split(" ")[0];
|
||||
const blobClass = GuildClasses.blobContainer.split(" ")[0];
|
||||
const reactInstance = BDV2.getInternalInstance(document.querySelector(`.${listItemClass} .${blobClass}`).parentElement);
|
||||
const GuildComponent = reactInstance.return.type;
|
||||
if (!GuildComponent) return;
|
||||
this.guildListItemsPatch = Utils.monkeyPatch(GuildComponent.prototype, "render", {after: (data) => {
|
||||
if (data.returnValue && data.thisObject) {
|
||||
const returnValue = data.returnValue;
|
||||
const guildData = data.thisObject.props;
|
||||
returnValue.props.className += " bd-guild";
|
||||
if (guildData.unread) returnValue.props.className += " bd-unread";
|
||||
if (guildData.selected) returnValue.props.className += " bd-selected";
|
||||
if (guildData.audio) returnValue.props.className += " bd-audio";
|
||||
if (guildData.video) returnValue.props.className += " bd-video";
|
||||
if (guildData.badge) returnValue.props.className += " bd-badge";
|
||||
if (guildData.animatable) returnValue.props.className += " bd-animatable";
|
||||
return returnValue;
|
||||
}
|
||||
}});
|
||||
};
|
||||
|
||||
Core.prototype.patchGuildPills = function() {
|
||||
if (this.guildPillPatch) return;
|
||||
const guildPill = WebpackModules.find(m => m.default && !m.default.displayName && m.default.toString && m.default.toString().includes("translate3d"));
|
||||
if (!guildPill) return;
|
||||
this.guildPillPatch = Utils.monkeyPatch(guildPill, "default", {after: (data) => {
|
||||
const props = data.methodArguments[0];
|
||||
if (props.unread) data.returnValue.props.className += " bd-unread";
|
||||
if (props.selected) data.returnValue.props.className += " bd-selected";
|
||||
if (props.hovered) data.returnValue.props.className += " bd-hovered";
|
||||
return data.returnValue;
|
||||
}});
|
||||
};
|
||||
|
||||
Core.prototype.patchGuildSeparator = function() {
|
||||
if (this.guildSeparatorPatch) return;
|
||||
const Guilds = WebpackModules.findByDisplayName("Guilds");
|
||||
const guildComponents = WebpackModules.findByProps("renderListItem");
|
||||
if (!guildComponents || !Guilds) return;
|
||||
const GuildSeparator = function() {
|
||||
const returnValue = guildComponents.Separator(...arguments);
|
||||
returnValue.props.className += " bd-guild-separator";
|
||||
return returnValue;
|
||||
};
|
||||
this.guildSeparatorPatch = Utils.monkeyPatch(Guilds.prototype, "render", {after: (data) => {
|
||||
data.returnValue.props.children[1].props.children[3].type = GuildSeparator;
|
||||
}});
|
||||
};
|
||||
|
||||
export default Core;
|
|
@ -0,0 +1,74 @@
|
|||
import {bdConfig} from "./0globals";
|
||||
import Utils from "./utils";
|
||||
import ContentManager from "./contentManager";
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const releaseChannel = DiscordNative.globals.releaseChannel;
|
||||
|
||||
export default new class DataStore {
|
||||
constructor() {
|
||||
this.data = {settings: {stable: {}, canary: {}, ptb: {}}};
|
||||
this.pluginData = {};
|
||||
}
|
||||
|
||||
initialize() {
|
||||
try {
|
||||
if (!fs.existsSync(this.BDFile)) fs.writeFileSync(this.BDFile, JSON.stringify(this.data, null, 4));
|
||||
const data = __non_webpack_require__(this.BDFile);
|
||||
if (data.hasOwnProperty("settings")) this.data = data;
|
||||
if (!fs.existsSync(this.settingsFile)) return;
|
||||
let settings = __non_webpack_require__(this.settingsFile);
|
||||
fs.unlinkSync(this.settingsFile);
|
||||
if (settings.hasOwnProperty("settings")) settings = Object.assign({stable: {}, canary: {}, ptb: {}}, {[releaseChannel]: settings});
|
||||
else settings = Object.assign({stable: {}, canary: {}, ptb: {}}, settings);
|
||||
this.setBDData("settings", settings);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
Utils.alert("Corrupt Storage", "The bd storage has somehow become corrupt. You may either try to salvage the file or delete it then reload.");
|
||||
}
|
||||
}
|
||||
|
||||
get BDFile() {return this._BDFile || (this._BDFile = path.resolve(bdConfig.dataPath, "bdstorage.json"));}
|
||||
get settingsFile() {return this._settingsFile || (this._settingsFile = path.resolve(bdConfig.dataPath, "bdsettings.json"));}
|
||||
getPluginFile(pluginName) {return path.resolve(ContentManager.pluginsFolder, pluginName + ".config.json");}
|
||||
|
||||
getSettingGroup(key) {
|
||||
return this.data.settings[releaseChannel][key] || null;
|
||||
}
|
||||
|
||||
setSettingGroup(key, data) {
|
||||
this.data.settings[releaseChannel][key] = data;
|
||||
fs.writeFileSync(this.BDFile, JSON.stringify(this.data, null, 4));
|
||||
}
|
||||
|
||||
getBDData(key) {
|
||||
return this.data[key] || "";
|
||||
}
|
||||
|
||||
setBDData(key, value) {
|
||||
this.data[key] = value;
|
||||
fs.writeFileSync(this.BDFile, JSON.stringify(this.data, null, 4));
|
||||
}
|
||||
|
||||
getPluginData(pluginName, key) {
|
||||
if (this.pluginData[pluginName] !== undefined) return this.pluginData[pluginName][key] || undefined;
|
||||
if (!fs.existsSync(this.getPluginFile(pluginName))) return undefined;
|
||||
this.pluginData[pluginName] = JSON.parse(fs.readFileSync(this.getPluginFile(pluginName)));
|
||||
return this.pluginData[pluginName][key] || undefined;
|
||||
}
|
||||
|
||||
setPluginData(pluginName, key, value) {
|
||||
if (value === undefined) return;
|
||||
if (this.pluginData[pluginName] === undefined) this.pluginData[pluginName] = {};
|
||||
this.pluginData[pluginName][key] = value;
|
||||
fs.writeFileSync(this.getPluginFile(pluginName), JSON.stringify(this.pluginData[pluginName], null, 4));
|
||||
}
|
||||
|
||||
deletePluginData(pluginName, key) {
|
||||
if (this.pluginData[pluginName] === undefined) this.pluginData[pluginName] = {};
|
||||
delete this.pluginData[pluginName][key];
|
||||
fs.writeFileSync(this.getPluginFile(pluginName), JSON.stringify(this.pluginData[pluginName], null, 4));
|
||||
}
|
||||
};
|
|
@ -0,0 +1,89 @@
|
|||
import BDV2 from "./v2";
|
||||
|
||||
function devMode() {}
|
||||
|
||||
devMode.prototype.enable = function(selectorMode) {
|
||||
const self = this;
|
||||
this.disable();
|
||||
$(document).on("keydown.bdDevmode", function(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;", "");
|
||||
debugger; // eslint-disable-line no-debugger
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
|
||||
if (!selectorMode) return;
|
||||
$(document).on("contextmenu.bdDevmode", function(e) {
|
||||
self.lastSelector = self.getSelector(e.toElement);
|
||||
|
||||
function attach() {
|
||||
let cm = $(".contextMenu-HLZMGh");
|
||||
if (cm.length <= 0) {
|
||||
cm = $("<div class=\"contextMenu-HLZMGh bd-context-menu\"></div>");
|
||||
cm.addClass($(".app, .app-2rEoOp").hasClass("theme-dark") ? "theme-dark" : "theme-light");
|
||||
cm.appendTo(".app, .app-2rEoOp");
|
||||
cm.css("top", e.clientY);
|
||||
cm.css("left", e.clientX);
|
||||
$(document).on("click.bdDevModeCtx", () => {
|
||||
cm.remove();
|
||||
$(document).off(".bdDevModeCtx");
|
||||
});
|
||||
$(document).on("contextmenu.bdDevModeCtx", () => {
|
||||
cm.remove();
|
||||
$(document).off(".bdDevModeCtx");
|
||||
});
|
||||
$(document).on("keyup.bdDevModeCtx", (e) => {
|
||||
if (e.keyCode === 27) {
|
||||
cm.remove();
|
||||
$(document).off(".bdDevModeCtx");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const cmo = $("<div/>", {
|
||||
"class": "itemGroup-1tL0uz"
|
||||
});
|
||||
const cmi = $("<div/>", {
|
||||
"class": "item-1Yvehc",
|
||||
"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);
|
||||
|
||||
e.stopPropagation();
|
||||
});
|
||||
};
|
||||
|
||||
devMode.prototype.getRules = function(element, css = element.ownerDocument.styleSheets) {
|
||||
//if (window.getMatchedCSSRules) return window.getMatchedCSSRules(element);
|
||||
const sheets = [...css].filter(s => !s.href || !s.href.includes("BetterDiscordApp"));
|
||||
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("*"));
|
||||
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();
|
|
@ -0,0 +1,288 @@
|
|||
import {bdConfig, settingsCookie, bemotes, bdEmoteSettingIDs, bdEmotes} from "./0globals";
|
||||
import DataStore from "./dataStore";
|
||||
import BDV2 from "./v2";
|
||||
import Utils from "./utils";
|
||||
|
||||
import BDEmote from "./react/bdEmote";
|
||||
|
||||
function EmoteModule() {
|
||||
Object.defineProperty(this, "categories", {
|
||||
get: function() {
|
||||
const cats = [];
|
||||
for (const current in bdEmoteSettingIDs) {
|
||||
if (settingsCookie[bdEmoteSettingIDs[current]]) cats.push(current);
|
||||
}
|
||||
return cats;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
EmoteModule.prototype.init = async function () {
|
||||
this.modifiers = ["flip", "spin", "pulse", "spin2", "spin3", "1spin", "2spin", "3spin", "tr", "bl", "br", "shake", "shake2", "shake3", "flap"];
|
||||
this.overrides = ["twitch", "bttv", "ffz"];
|
||||
|
||||
const emoteInfo = {
|
||||
TwitchGlobal: {
|
||||
url: `https://rauenzi.github.io/BetterDiscordApp/data/emotedata_twitch_global.json`,
|
||||
variable: "TwitchGlobal",
|
||||
oldVariable: "emotesTwitch",
|
||||
getEmoteURL: (e) => `https://static-cdn.jtvnw.net/emoticons/v1/${e}/1.0`
|
||||
},
|
||||
TwitchSubscriber: {
|
||||
url: `https://rauenzi.github.io/BetterDiscordApp/data/emotedata_twitch_subscriber.json`,
|
||||
variable: "TwitchSubscriber",
|
||||
oldVariable: "subEmotesTwitch",
|
||||
getEmoteURL: (e) => `https://static-cdn.jtvnw.net/emoticons/v1/${e}/1.0`
|
||||
},
|
||||
FrankerFaceZ: {
|
||||
url: `https://rauenzi.github.io/BetterDiscordApp/data/emotedata_ffz.json`,
|
||||
variable: "FrankerFaceZ",
|
||||
oldVariable: "emotesFfz",
|
||||
getEmoteURL: (e) => `https://cdn.frankerfacez.com/emoticon/${e}/1`
|
||||
},
|
||||
BTTV: {
|
||||
url: `https://rauenzi.github.io/BetterDiscordApp/data/emotedata_bttv.json`,
|
||||
variable: "BTTV",
|
||||
oldVariable: "emotesBTTV",
|
||||
getEmoteURL: (e) => `https://cdn.betterttv.net/emote/${e}/1x`
|
||||
},
|
||||
BTTV2: {
|
||||
url: `https://rauenzi.github.io/BetterDiscordApp/data/emotedata_bttv2.json`,
|
||||
variable: "BTTV2",
|
||||
oldVariable: "emotesBTTV2",
|
||||
getEmoteURL: (e) => `https://cdn.betterttv.net/emote/${e}/1x`
|
||||
}
|
||||
};
|
||||
|
||||
await this.getBlacklist();
|
||||
await this.loadEmoteData(emoteInfo);
|
||||
|
||||
while (!BDV2.MessageComponent) await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
if (this.cancelEmoteRender) return;
|
||||
this.cancelEmoteRender = Utils.monkeyPatch(BDV2.MessageComponent, "default", {before: ({methodArguments}) => {
|
||||
const nodes = methodArguments[0].childrenMessageContent.props.content;
|
||||
if (!nodes || !nodes.length) return;
|
||||
for (let n = 0; n < nodes.length; n++) {
|
||||
const node = nodes[n];
|
||||
if (typeof(node) !== "string") continue;
|
||||
const words = node.split(/([^\s]+)([\s]|$)/g);
|
||||
for (let c = 0, clen = this.categories.length; c < clen; c++) {
|
||||
for (let w = 0, wlen = words.length; w < wlen; w++) {
|
||||
const emote = words[w];
|
||||
const emoteSplit = emote.split(":");
|
||||
const emoteName = emoteSplit[0];
|
||||
let emoteModifier = emoteSplit[1] ? emoteSplit[1] : "";
|
||||
let emoteOverride = emoteModifier.slice(0);
|
||||
|
||||
if (emoteName.length < 4 || bemotes.includes(emoteName)) continue;
|
||||
if (!this.modifiers.includes(emoteModifier) || !settingsCookie["bda-es-8"]) emoteModifier = "";
|
||||
if (!this.overrides.includes(emoteOverride)) emoteOverride = "";
|
||||
else emoteModifier = emoteOverride;
|
||||
|
||||
let current = this.categories[c];
|
||||
if (emoteOverride === "twitch") {
|
||||
if (bdEmotes.TwitchGlobal[emoteName]) current = "TwitchGlobal";
|
||||
else if (bdEmotes.TwitchSubscriber[emoteName]) current = "TwitchSubscriber";
|
||||
}
|
||||
else if (emoteOverride === "bttv") {
|
||||
if (bdEmotes.BTTV[emoteName]) current = "BTTV";
|
||||
else if (bdEmotes.BTTV2[emoteName]) current = "BTTV2";
|
||||
}
|
||||
else if (emoteOverride === "ffz") {
|
||||
if (bdEmotes.FrankerFaceZ[emoteName]) current = "FrankerFaceZ";
|
||||
}
|
||||
|
||||
if (!bdEmotes[current][emoteName] || !settingsCookie[bdEmoteSettingIDs[current]]) continue;
|
||||
const results = nodes[n].match(new RegExp(`([\\s]|^)${Utils.escape(emoteModifier ? emoteName + ":" + emoteModifier : emoteName)}([\\s]|$)`));
|
||||
if (!results) continue;
|
||||
const pre = nodes[n].substring(0, results.index + results[1].length);
|
||||
const post = nodes[n].substring(results.index + results[0].length - results[2].length);
|
||||
nodes[n] = pre;
|
||||
const emoteComponent = BDV2.react.createElement(BDEmote, {name: emoteName, url: bdEmotes[current][emoteName], modifier: emoteModifier});
|
||||
nodes.splice(n + 1, 0, post);
|
||||
nodes.splice(n + 1, 0, emoteComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
const onlyEmotes = nodes.every(r => {
|
||||
if (typeof(r) == "string" && r.replace(/\s*/, "") == "") return true;
|
||||
else if (r.type && r.type.name == "BDEmote") return true;
|
||||
else if (r.props && r.props.children && r.props.children.props && r.props.children.props.emojiName) return true;
|
||||
return false;
|
||||
});
|
||||
if (!onlyEmotes) return;
|
||||
|
||||
for (const node of nodes) {
|
||||
if (typeof(node) != "object") continue;
|
||||
if (node.type.name == "BDEmote") node.props.jumboable = true;
|
||||
else if (node.props && node.props.children && node.props.children.props && node.props.children.props.emojiName) node.props.children.props.jumboable = true;
|
||||
}
|
||||
}});
|
||||
};
|
||||
|
||||
EmoteModule.prototype.disable = function() {
|
||||
this.disableAutoCapitalize();
|
||||
if (this.cancelEmoteRender) return;
|
||||
this.cancelEmoteRender();
|
||||
this.cancelEmoteRender = null;
|
||||
};
|
||||
|
||||
EmoteModule.prototype.clearEmoteData = async function() {
|
||||
const _fs = require("fs");
|
||||
const emoteFile = "emote_data.json";
|
||||
const file = bdConfig.dataPath + emoteFile;
|
||||
const exists = _fs.existsSync(file);
|
||||
if (exists) _fs.unlinkSync(file);
|
||||
DataStore.setBDData("emoteCacheDate", (new Date()).toJSON());
|
||||
|
||||
Object.assign(bdEmotes, {
|
||||
TwitchGlobal: {},
|
||||
TwitchSubscriber: {},
|
||||
BTTV: {},
|
||||
FrankerFaceZ: {},
|
||||
BTTV2: {}
|
||||
});
|
||||
};
|
||||
|
||||
EmoteModule.prototype.isCacheValid = function() {
|
||||
const cacheLength = DataStore.getBDData("emoteCacheDays") || DataStore.setBDData("emoteCacheDays", 7) || 7;
|
||||
const cacheDate = new Date(DataStore.getBDData("emoteCacheDate") || null);
|
||||
const currentDate = new Date();
|
||||
const daysBetween = Math.round(Math.abs((currentDate.getTime() - cacheDate.getTime()) / (24 * 60 * 60 * 1000)));
|
||||
if (daysBetween > cacheLength) {
|
||||
DataStore.setBDData("emoteCacheDate", currentDate.toJSON());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
EmoteModule.prototype.loadEmoteData = async function(emoteInfo) {
|
||||
const fs = require("fs");
|
||||
const emoteFile = "emote_data.json";
|
||||
const file = bdConfig.dataPath + emoteFile;
|
||||
const exists = await new Promise(r => fs.exists(file, r));
|
||||
|
||||
if (exists && this.isCacheValid()) {
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast("Loading emotes from cache.", {type: "info"});
|
||||
Utils.log("Emotes", "Loading emotes from local cache.");
|
||||
|
||||
const data = await new Promise(resolve => {
|
||||
fs.readFile(file, "utf8", (err, data) => {
|
||||
Utils.log("Emotes", "Emote file read.");
|
||||
if (err) data = {};
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
const parsed = Utils.testJSON(data);
|
||||
let isValid = !!parsed;
|
||||
if (isValid) Object.assign(bdEmotes, parsed);
|
||||
|
||||
for (const e in emoteInfo) {
|
||||
isValid = Object.keys(bdEmotes[emoteInfo[e].variable]).length > 0;
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast("Emotes successfully loaded.", {type: "success"});
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.log("Emotes", "Cache was corrupt, downloading...");
|
||||
await new Promise(r => fs.unlink(file, r));
|
||||
}
|
||||
|
||||
if (!settingsCookie["fork-es-3"]) return;
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast("Downloading emotes in the background do not reload.", {type: "info"});
|
||||
|
||||
for (const e in emoteInfo) {
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
const data = await this.downloadEmotes(emoteInfo[e]);
|
||||
bdEmotes[emoteInfo[e].variable] = data;
|
||||
}
|
||||
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast("All emotes successfully downloaded.", {type: "success"});
|
||||
|
||||
try { await new Promise(r => fs.writeFile(file, JSON.stringify(bdEmotes), "utf8", r)); }
|
||||
catch (err) { Utils.err("Emotes", "Could not save emote data.", err); }
|
||||
};
|
||||
|
||||
EmoteModule.prototype.downloadEmotes = function(emoteMeta) {
|
||||
const request = require("request");
|
||||
const options = {
|
||||
url: emoteMeta.url,
|
||||
timeout: emoteMeta.timeout ? emoteMeta.timeout : 5000,
|
||||
json: true
|
||||
};
|
||||
|
||||
Utils.log("Emotes", `Downloading: ${emoteMeta.variable} (${emoteMeta.url})`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request(options, (error, response, parsedData) => {
|
||||
if (error) {
|
||||
Utils.err("Emotes", "Could not download " + emoteMeta.variable, error);
|
||||
if (emoteMeta.backup) {
|
||||
emoteMeta.url = emoteMeta.backup;
|
||||
emoteMeta.backup = null;
|
||||
if (emoteMeta.backupParser) emoteMeta.parser = emoteMeta.backupParser;
|
||||
return resolve(this.downloadEmotes(emoteMeta));
|
||||
}
|
||||
return reject({});
|
||||
}
|
||||
|
||||
if (typeof(emoteMeta.parser) === "function") parsedData = emoteMeta.parser(parsedData);
|
||||
|
||||
for (const emote in parsedData) {
|
||||
if (emote.length < 4 || bemotes.includes(emote)) {
|
||||
delete parsedData[emote];
|
||||
continue;
|
||||
}
|
||||
parsedData[emote] = emoteMeta.getEmoteURL(parsedData[emote]);
|
||||
}
|
||||
resolve(parsedData);
|
||||
Utils.log("Emotes", "Downloaded: " + emoteMeta.variable);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
EmoteModule.prototype.getBlacklist = function () {
|
||||
return new Promise(resolve => {
|
||||
$.getJSON(`https://rauenzi.github.io/BetterDiscordApp/data/emotefilter.json`, function (data) {
|
||||
resolve(bemotes.concat(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();
|
|
@ -0,0 +1,80 @@
|
|||
import localStorageFix from "./localStorageFix";
|
||||
import loadingIcon from "./loadingIcon";
|
||||
localStorageFix();
|
||||
loadingIcon();
|
||||
|
||||
import Core from "./core";
|
||||
import BdApi from "./bdApi";
|
||||
|
||||
window.BdApi = BdApi;
|
||||
// DataStore
|
||||
// BDEvents
|
||||
// settingsPanel
|
||||
// emoteModule
|
||||
// quickEmoteMenu
|
||||
// voiceMode
|
||||
// pluginModule
|
||||
// themeModule
|
||||
// dMode
|
||||
// publicServersModule
|
||||
// minSupportedVersion
|
||||
// bbdVersion
|
||||
// bbdChangelog
|
||||
// mainCore
|
||||
// settings
|
||||
// defaultCookie
|
||||
// settingsCookie
|
||||
// bdpluginErrors
|
||||
// bdthemeErrors
|
||||
// bdConfig
|
||||
// bemotes
|
||||
// Utils
|
||||
// ContentManager
|
||||
// pluginCookie
|
||||
// themeCookie
|
||||
// devMode
|
||||
// ClassNormalizer
|
||||
// BDV2
|
||||
// localStorage
|
||||
// bdEmotes
|
||||
// bdEmoteSettingIDs
|
||||
// bdthemes
|
||||
// bdplugins
|
||||
// emotePromise
|
||||
|
||||
export default Core;
|
||||
|
||||
// function patchModuleLoad() {
|
||||
// const namespace = "betterdiscord";
|
||||
// const prefix = `${namespace}/`;
|
||||
// const Module = require("module");
|
||||
// const load = Module._load;
|
||||
// // const resolveFilename = Module._resolveFilename;
|
||||
|
||||
// Module._load = function(request) {
|
||||
// if (request === namespace || request.startsWith(prefix)) {
|
||||
// const requested = request.substr(prefix.length);
|
||||
// if (requested == "api") return BdApi;
|
||||
// }
|
||||
|
||||
// return load.apply(this, arguments);
|
||||
// };
|
||||
|
||||
// // Module._resolveFilename = function (request, parent, isMain) {
|
||||
// // if (request === "betterdiscord" || request.startsWith("betterdiscord/")) {
|
||||
// // const contentPath = PluginManager.getPluginPathByModule(parent);
|
||||
// // if (contentPath) return request;
|
||||
// // }
|
||||
|
||||
// // return resolveFilename.apply(this, arguments);
|
||||
// // };
|
||||
|
||||
// return function() {
|
||||
// Module._load = load;
|
||||
// };
|
||||
// }
|
||||
|
||||
// patchModuleLoad();
|
||||
|
||||
// var settingsPanel, emoteModule, quickEmoteMenu, voiceMode,, dMode, publicServersModule;
|
||||
// var bdConfig = null;
|
|
@ -0,0 +1,6 @@
|
|||
export default () => {
|
||||
const v2Loader = document.createElement("div");
|
||||
v2Loader.className = "bd-loaderv2";
|
||||
v2Loader.title = "BandagedBD is loading...";
|
||||
document.body.appendChild(v2Loader);
|
||||
};
|
|
@ -0,0 +1,50 @@
|
|||
export default function() {
|
||||
|
||||
const __fs = window.require("fs");
|
||||
const __process = window.require("process");
|
||||
const __platform = __process.platform;
|
||||
const __dataPath = (__platform === "win32" ? __process.env.APPDATA : __platform === "darwin" ? __process.env.HOME + "/Library/Preferences" : process.env.HOME + "/.config") + "/BetterDiscord/";
|
||||
const localStorageFile = "localStorage.json";
|
||||
|
||||
let __data = {};
|
||||
if (__fs.existsSync(`${__dataPath}${localStorageFile}`)) {
|
||||
try {
|
||||
__data = JSON.parse(__fs.readFileSync(`${__dataPath}${localStorageFile}`));
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
else if (__fs.existsSync(localStorageFile)) {
|
||||
try {
|
||||
__data = JSON.parse(__fs.readFileSync(localStorageFile));
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
const __ls = __data;
|
||||
__ls.setItem = function(i, v) {
|
||||
__ls[i] = v;
|
||||
this.save();
|
||||
};
|
||||
__ls.getItem = function(i) {
|
||||
return __ls[i] || null;
|
||||
};
|
||||
__ls.save = function() {
|
||||
__fs.writeFileSync(`${__dataPath}${localStorageFile}`, JSON.stringify(this), null, 4);
|
||||
};
|
||||
|
||||
const __proxy = new Proxy(__ls, {
|
||||
set: function(target, name, val) {
|
||||
__ls[name] = val;
|
||||
__ls.save();
|
||||
},
|
||||
get: function(target, name) {
|
||||
return __ls[name] || null;
|
||||
}
|
||||
});
|
||||
|
||||
window.localStorage = __proxy;
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
import {bdpluginErrors, pluginCookie, settingsCookie, bdplugins} from "./0globals";
|
||||
import ContentManager from "./contentManager";
|
||||
import DataStore from "./dataStore";
|
||||
import BDEvents from "./bdEvents";
|
||||
import Utils from "./utils";
|
||||
|
||||
function PluginModule() {
|
||||
|
||||
}
|
||||
|
||||
PluginModule.prototype.loadPlugins = function () {
|
||||
this.loadPluginData();
|
||||
bdpluginErrors.concat(ContentManager.loadPlugins());
|
||||
const plugins = Object.keys(bdplugins);
|
||||
for (let i = 0; i < plugins.length; i++) {
|
||||
let plugin, name;
|
||||
|
||||
try {
|
||||
plugin = bdplugins[plugins[i]].plugin;
|
||||
name = plugin.getName();
|
||||
if (plugin.load && typeof(plugin.load) == "function") plugin.load();
|
||||
}
|
||||
catch (err) {
|
||||
pluginCookie[name] = false;
|
||||
Utils.err("Plugins", name + " could not be loaded.", err);
|
||||
bdpluginErrors.push({name: name, file: bdplugins[plugins[i]].filename, message: "load() could not be fired.", error: {message: err.message, stack: err.stack}});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pluginCookie[name]) pluginCookie[name] = false;
|
||||
|
||||
if (pluginCookie[name]) {
|
||||
try {
|
||||
plugin.start();
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${plugin.getName()} v${plugin.getVersion()} has started.`);
|
||||
}
|
||||
catch (err) {
|
||||
pluginCookie[name] = false;
|
||||
Utils.err("Plugins", name + " could not be started.", err);
|
||||
bdpluginErrors.push({name: name, file: bdplugins[plugins[i]].filename, message: "start() could not be fired.", error: {message: err.message, stack: err.stack}});
|
||||
}
|
||||
}
|
||||
}
|
||||
this.savePluginData();
|
||||
|
||||
require("electron").remote.getCurrentWebContents().on("did-navigate-in-page", this.channelSwitch.bind(this));
|
||||
// if (settingsCookie["fork-ps-5"]) ContentManager.watchContent("plugin");
|
||||
};
|
||||
|
||||
PluginModule.prototype.startPlugin = function(plugin, reload = false) {
|
||||
try {
|
||||
bdplugins[plugin].plugin.start();
|
||||
if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${bdplugins[plugin].plugin.getName()} v${bdplugins[plugin].plugin.getVersion()} has started.`);
|
||||
}
|
||||
catch (err) {
|
||||
if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${bdplugins[plugin].plugin.getName()} v${bdplugins[plugin].plugin.getVersion()} could not be started.`, {type: "error"});
|
||||
pluginCookie[plugin] = false;
|
||||
this.savePluginData();
|
||||
Utils.err("Plugins", plugin + " could not be started.", err);
|
||||
}
|
||||
};
|
||||
|
||||
PluginModule.prototype.stopPlugin = function(plugin, reload = false) {
|
||||
try {
|
||||
bdplugins[plugin].plugin.stop();
|
||||
if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${bdplugins[plugin].plugin.getName()} v${bdplugins[plugin].plugin.getVersion()} has stopped.`);
|
||||
}
|
||||
catch (err) {
|
||||
if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${bdplugins[plugin].plugin.getName()} v${bdplugins[plugin].plugin.getVersion()} could not be stopped.`, {type: "error"});
|
||||
Utils.err("Plugins", bdplugins[plugin].plugin.getName() + " could not be stopped.", err);
|
||||
}
|
||||
};
|
||||
|
||||
PluginModule.prototype.enablePlugin = function (plugin, reload = false) {
|
||||
if (pluginCookie[plugin]) return;
|
||||
pluginCookie[plugin] = true;
|
||||
this.savePluginData();
|
||||
this.startPlugin(plugin, reload);
|
||||
};
|
||||
|
||||
PluginModule.prototype.disablePlugin = function (plugin, reload = false) {
|
||||
if (!pluginCookie[plugin]) return;
|
||||
pluginCookie[plugin] = false;
|
||||
this.savePluginData();
|
||||
this.stopPlugin(plugin, reload);
|
||||
};
|
||||
|
||||
PluginModule.prototype.togglePlugin = function (plugin) {
|
||||
if (pluginCookie[plugin]) this.disablePlugin(plugin);
|
||||
else this.enablePlugin(plugin);
|
||||
};
|
||||
|
||||
PluginModule.prototype.loadPlugin = function(filename) {
|
||||
const error = ContentManager.loadContent(filename, "plugin");
|
||||
if (error) {
|
||||
if (settingsCookie["fork-ps-1"]) Utils.showContentErrors({plugins: [error]});
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${filename} could not be loaded.`, {type: "error"});
|
||||
return Utils.err("ContentManager", `${filename} could not be loaded.`, error);
|
||||
}
|
||||
const plugin = Object.values(bdplugins).find(p => p.filename == filename).plugin;
|
||||
try { if (plugin.load && typeof(plugin.load) == "function") plugin.load();}
|
||||
catch (err) {if (settingsCookie["fork-ps-1"]) Utils.showContentErrors({plugins: [err]});}
|
||||
Utils.log("ContentManager", `${plugin.getName()} v${plugin.getVersion()} was loaded.`);
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${plugin.getName()} v${plugin.getVersion()} was loaded.`, {type: "success"});
|
||||
BDEvents.dispatch("plugin-loaded", plugin.getName());
|
||||
};
|
||||
|
||||
PluginModule.prototype.unloadPlugin = function(filenameOrName) {
|
||||
const bdplugin = Object.values(bdplugins).find(p => p.filename == filenameOrName) || bdplugins[filenameOrName];
|
||||
if (!bdplugin) return;
|
||||
const plugin = bdplugin.plugin.getName();
|
||||
if (pluginCookie[plugin]) this.disablePlugin(plugin, true);
|
||||
const error = ContentManager.unloadContent(bdplugins[plugin].filename, "plugin");
|
||||
delete bdplugins[plugin];
|
||||
if (error) {
|
||||
if (settingsCookie["fork-ps-1"]) Utils.showContentErrors({plugins: [error]});
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${plugin} could not be unloaded. It may have not been loaded yet.`, {type: "error"});
|
||||
return Utils.err("ContentManager", `${plugin} could not be unloaded. It may have not been loaded yet.`, error);
|
||||
}
|
||||
Utils.log("ContentManager", `${plugin} was unloaded.`);
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${plugin} was unloaded.`, {type: "success"});
|
||||
BDEvents.dispatch("plugin-unloaded", plugin);
|
||||
};
|
||||
|
||||
PluginModule.prototype.reloadPlugin = function(filenameOrName) {
|
||||
const bdplugin = Object.values(bdplugins).find(p => p.filename == filenameOrName) || bdplugins[filenameOrName];
|
||||
if (!bdplugin) return this.loadPlugin(filenameOrName);
|
||||
const plugin = bdplugin.plugin.getName();
|
||||
const enabled = pluginCookie[plugin];
|
||||
if (enabled) this.stopPlugin(plugin, true);
|
||||
const error = ContentManager.reloadContent(bdplugins[plugin].filename, "plugin");
|
||||
if (error) {
|
||||
if (settingsCookie["fork-ps-1"]) Utils.showContentErrors({plugins: [error]});
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${plugin} could not be reloaded.`, {type: "error"});
|
||||
return Utils.err("ContentManager", `${plugin} could not be reloaded.`, error);
|
||||
}
|
||||
if (bdplugins[plugin].plugin.load && typeof(bdplugins[plugin].plugin.load) == "function") bdplugins[plugin].plugin.load();
|
||||
if (enabled) this.startPlugin(plugin, true);
|
||||
Utils.log("ContentManager", `${plugin} v${bdplugins[plugin].plugin.getVersion()} was reloaded.`);
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${plugin} v${bdplugins[plugin].plugin.getVersion()} was reloaded.`, {type: "success"});
|
||||
BDEvents.dispatch("plugin-reloaded", plugin);
|
||||
};
|
||||
|
||||
PluginModule.prototype.updatePluginList = function() {
|
||||
const results = ContentManager.loadNewContent("plugin");
|
||||
for (const filename of results.added) this.loadPlugin(filename);
|
||||
for (const name of results.removed) this.unloadPlugin(name);
|
||||
};
|
||||
|
||||
PluginModule.prototype.loadPluginData = function () {
|
||||
const saved = DataStore.getSettingGroup("plugins");
|
||||
if (saved) {
|
||||
Object.assign(pluginCookie, saved);
|
||||
}
|
||||
};
|
||||
|
||||
PluginModule.prototype.savePluginData = function () {
|
||||
DataStore.setSettingGroup("plugins", pluginCookie);
|
||||
};
|
||||
|
||||
PluginModule.prototype.newMessage = function () {
|
||||
const plugins = Object.keys(bdplugins);
|
||||
for (let i = 0; i < plugins.length; i++) {
|
||||
const plugin = bdplugins[plugins[i]].plugin;
|
||||
if (!pluginCookie[plugin.getName()]) continue;
|
||||
if (typeof plugin.onMessage === "function") {
|
||||
try { plugin.onMessage(); }
|
||||
catch (err) { Utils.err("Plugins", "Unable to fire onMessage for " + plugin.getName() + ".", err); }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PluginModule.prototype.channelSwitch = function () {
|
||||
const plugins = Object.keys(bdplugins);
|
||||
for (let i = 0; i < plugins.length; i++) {
|
||||
const plugin = bdplugins[plugins[i]].plugin;
|
||||
if (!pluginCookie[plugin.getName()]) continue;
|
||||
if (typeof plugin.onSwitch === "function") {
|
||||
try { plugin.onSwitch(); }
|
||||
catch (err) { Utils.err("Plugins", "Unable to fire onSwitch for " + plugin.getName() + ".", err); }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PluginModule.prototype.rawObserver = function(e) {
|
||||
const plugins = Object.keys(bdplugins);
|
||||
for (let i = 0; i < plugins.length; i++) {
|
||||
const plugin = bdplugins[plugins[i]].plugin;
|
||||
if (!pluginCookie[plugin.getName()]) continue;
|
||||
if (typeof plugin.observer === "function") {
|
||||
try { plugin.observer(e); }
|
||||
catch (err) { Utils.err("Plugins", "Unable to fire observer for " + plugin.getName() + ".", err); }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default new PluginModule();
|
|
@ -0,0 +1,79 @@
|
|||
import {settingsCookie} from "./0globals";
|
||||
import BDV2 from "./v2";
|
||||
import webpackModules from "./webpackModules";
|
||||
|
||||
import V2C_PublicServers from "./react/publicServers";
|
||||
import Layer from "./react/layer";
|
||||
|
||||
export default new class V2_PublicServers {
|
||||
|
||||
constructor() {
|
||||
this._appendButton = this._appendButton.bind(this);
|
||||
}
|
||||
|
||||
get component() {
|
||||
return BDV2.react.createElement(Layer, {rootId: "pubslayerroot", id: "pubslayer", children: BDV2.react.createElement(V2C_PublicServers, {rootId: "pubslayerroot"})});
|
||||
}
|
||||
|
||||
get root() {
|
||||
const _root = document.getElementById("pubslayerroot");
|
||||
if (!_root) {
|
||||
if (!this.injectRoot()) return null;
|
||||
return this.root;
|
||||
}
|
||||
return _root;
|
||||
}
|
||||
|
||||
injectRoot() {
|
||||
if (!$(".layers, .layers-3iHuyZ").length) return false;
|
||||
$(".layers, .layers-3iHuyZ").append($("<div/>", {
|
||||
id: "pubslayerroot"
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
// BdApi.alert("Broken", "Sorry but the Public Servers modules is currently broken, I recommend disabling this feature for now.");
|
||||
const root = this.root;
|
||||
if (!root) {
|
||||
console.log("FAILED TO LOCATE ROOT: .layers");
|
||||
return;
|
||||
}
|
||||
BDV2.reactDom.render(this.component, root);
|
||||
}
|
||||
|
||||
get button() {
|
||||
const btn = $("<div/>", {
|
||||
"class": BDV2.guildClasses.listItem,
|
||||
"id": "bd-pub-li",
|
||||
"style": settingsCookie["bda-gs-1"] ? "" : "display: none;"
|
||||
}).append($("<div/>", {
|
||||
"class": "wrapper-25eVIn " + BDV2.guildClasses.circleButtonMask,
|
||||
"text": "public",
|
||||
"id": "bd-pub-button",
|
||||
"click": () => { this.render(); }
|
||||
}));
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
_appendButton() {
|
||||
if ($("#bd-pub-li").length) return;
|
||||
const wrapper = BDV2.guildClasses.wrapper.split(" ")[0];
|
||||
const guilds = $(`.${wrapper} .scroller-2FKFPG >:first-child`);
|
||||
guilds.after(this.button);
|
||||
}
|
||||
|
||||
addButton() {
|
||||
if (this.guildPatch) return;
|
||||
const GuildList = webpackModules.findModuleByDisplayName("Guilds");
|
||||
this.guildPatch = webpackModules.monkeyPatch(GuildList.prototype, "render", {after: this._appendButton});
|
||||
this._appendButton();
|
||||
}
|
||||
|
||||
removeButton() {
|
||||
this.guildPatch();
|
||||
delete this.guildPatch;
|
||||
$("#bd-pub-li").remove();
|
||||
}
|
||||
};
|
|
@ -0,0 +1,195 @@
|
|||
import {settingsCookie, bdEmotes} from "./0globals";
|
||||
import DataStore from "./dataStore";
|
||||
import BDV2 from "./v2";
|
||||
import Utils from "./utils";
|
||||
|
||||
function QuickEmoteMenu() {
|
||||
|
||||
}
|
||||
|
||||
QuickEmoteMenu.prototype.init = function() {
|
||||
this.initialized = true;
|
||||
$(document).on("mousedown", function(e) {
|
||||
if (e.target.id != "rmenu") $("#rmenu").remove();
|
||||
});
|
||||
this.favoriteEmotes = {};
|
||||
const fe = DataStore.getBDData("bdfavemotes");
|
||||
if (fe !== "" && fe !== null) {
|
||||
this.favoriteEmotes = JSON.parse(atob(fe));
|
||||
}
|
||||
|
||||
let qmeHeader = "";
|
||||
qmeHeader += "<div id=\"bda-qem\">";
|
||||
qmeHeader += " <button class=\"active\" id=\"bda-qem-twitch\" onclick='quickEmoteMenu.switchHandler(this); return false;'>Twitch</button>";
|
||||
qmeHeader += " <button id=\"bda-qem-favourite\" onclick='quickEmoteMenu.switchHandler(this); return false;'>Favourite</button>";
|
||||
qmeHeader += " <button id=\"bda-qem-emojis\" onclick='quickEmoteMenu.switchHandler(this); return false;'>Emojis</buttond>";
|
||||
qmeHeader += "</div>";
|
||||
this.qmeHeader = qmeHeader;
|
||||
|
||||
let teContainer = "";
|
||||
teContainer += "<div id=\"bda-qem-twitch-container\">";
|
||||
teContainer += " <div class=\"scroller-wrap scrollerWrap-2lJEkd fade\">";
|
||||
teContainer += " <div class=\"scroller scroller-2FKFPG\">";
|
||||
teContainer += " <div class=\"emote-menu-inner\">";
|
||||
let url = "";
|
||||
for (const emote in bdEmotes.TwitchGlobal) {
|
||||
if (bdEmotes.TwitchGlobal.hasOwnProperty(emote)) {
|
||||
url = 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 = "";
|
||||
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) {
|
||||
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;
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.favContext = function(e, em) {
|
||||
e.stopPropagation();
|
||||
const menu = $("<div>", {"id": "removemenu", "data-emoteid": $(em).prop("title"), "text": "Remove", "class": "bd-context-menu context-menu theme-dark"});
|
||||
menu.css({
|
||||
top: e.pageY - $("#bda-qem-favourite-container").offset().top,
|
||||
left: e.pageX - $("#bda-qem-favourite-container").offset().left
|
||||
});
|
||||
$(em).parent().append(menu);
|
||||
const self = this;
|
||||
menu.on("click", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$(this).remove();
|
||||
|
||||
delete self.favoriteEmotes[$(this).data("emoteid")];
|
||||
self.updateFavorites();
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.switchHandler = function(e) {
|
||||
this.switchQem($(e).attr("id"));
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.switchQem = function(id) {
|
||||
const twitch = $("#bda-qem-twitch");
|
||||
const fav = $("#bda-qem-favourite");
|
||||
const emojis = $("#bda-qem-emojis");
|
||||
twitch.removeClass("active");
|
||||
fav.removeClass("active");
|
||||
emojis.removeClass("active");
|
||||
|
||||
$(".emojiPicker-3m1S-j").hide();
|
||||
$("#bda-qem-favourite-container").hide();
|
||||
$("#bda-qem-twitch-container").hide();
|
||||
|
||||
switch (id) {
|
||||
case "bda-qem-twitch":
|
||||
twitch.addClass("active");
|
||||
$("#bda-qem-twitch-container").show();
|
||||
break;
|
||||
case "bda-qem-favourite":
|
||||
fav.addClass("active");
|
||||
$("#bda-qem-favourite-container").show();
|
||||
break;
|
||||
case "bda-qem-emojis":
|
||||
emojis.addClass("active");
|
||||
$(".emojiPicker-3m1S-j").show();
|
||||
$(".emojiPicker-3m1S-j input").focus();
|
||||
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) {
|
||||
if (!this.initialized) return;
|
||||
const e = $(elem);
|
||||
if (!settingsCookie["bda-es-9"]) {
|
||||
e.addClass("bda-qme-hidden");
|
||||
}
|
||||
else {
|
||||
e.removeClass("bda-qme-hidden");
|
||||
}
|
||||
|
||||
if (!settingsCookie["bda-es-0"]) return;
|
||||
|
||||
e.prepend(this.qmeHeader);
|
||||
e.append(this.teContainer);
|
||||
e.append(this.faContainer);
|
||||
|
||||
if (this.lastTab == undefined) {
|
||||
this.lastTab = "bda-qem-emojis";
|
||||
}
|
||||
this.switchQem(this.lastTab);
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.favorite = function (name, url) {
|
||||
|
||||
if (!this.favoriteEmotes.hasOwnProperty(name)) {
|
||||
this.favoriteEmotes[name] = url;
|
||||
}
|
||||
|
||||
this.updateFavorites();
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.updateFavorites = 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)));
|
||||
};
|
||||
|
||||
export default new QuickEmoteMenu();
|
|
@ -0,0 +1,87 @@
|
|||
import {settingsCookie} from "../0globals";
|
||||
import quickEmoteMenu from "../quickEmoteMenu";
|
||||
import BDV2 from "../v2";
|
||||
|
||||
export default class BDEmote extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const isFav = quickEmoteMenu && quickEmoteMenu.favoriteEmotes && quickEmoteMenu.favoriteEmotes[this.label] ? true : false;
|
||||
this.state = {
|
||||
shouldAnimate: !this.animateOnHover,
|
||||
isFavorite: isFav
|
||||
};
|
||||
|
||||
this.onMouseEnter = this.onMouseEnter.bind(this);
|
||||
this.onMouseLeave = this.onMouseLeave.bind(this);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
}
|
||||
|
||||
get animateOnHover() {
|
||||
return settingsCookie["fork-es-2"];
|
||||
}
|
||||
|
||||
get label() {
|
||||
return this.props.modifier ? `${this.props.name}:${this.props.modifier}` : this.props.name;
|
||||
}
|
||||
|
||||
get modifierClass() {
|
||||
return this.props.modifier ? ` emote${this.props.modifier}` : "";
|
||||
}
|
||||
|
||||
onMouseEnter() {
|
||||
if (!this.state.shouldAnimate && this.animateOnHover) this.setState({shouldAnimate: true});
|
||||
if (!this.state.isFavorite && quickEmoteMenu.favoriteEmotes[this.label]) this.setState({isFavorite: true});
|
||||
else if (this.state.isFavorite && !quickEmoteMenu.favoriteEmotes[this.label]) this.setState({isFavorite: false});
|
||||
}
|
||||
|
||||
onMouseLeave() {
|
||||
if (this.state.shouldAnimate && this.animateOnHover) this.setState({shouldAnimate: false});
|
||||
}
|
||||
|
||||
onClick(e) {
|
||||
if (this.props.onClick) this.props.onClick(e);
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(BDV2.TooltipWrapper, {
|
||||
color: "black",
|
||||
position: "top",
|
||||
text: this.label,
|
||||
delay: 750
|
||||
},
|
||||
(childProps) => {
|
||||
return BDV2.react.createElement("div", Object.assign({
|
||||
className: "emotewrapper" + (this.props.jumboable ? " jumboable" : ""),
|
||||
onMouseEnter: this.onMouseEnter,
|
||||
onMouseLeave: this.onMouseLeave,
|
||||
onClick: this.onClick
|
||||
}, childProps),
|
||||
BDV2.react.createElement("img", {
|
||||
draggable: false,
|
||||
className: "emote" + this.modifierClass + (this.props.jumboable ? " jumboable" : "") + (!this.state.shouldAnimate ? " stop-animation" : ""),
|
||||
dataModifier: this.props.modifier,
|
||||
alt: this.label,
|
||||
src: this.props.url
|
||||
}),
|
||||
BDV2.react.createElement("input", {
|
||||
className: "fav" + (this.state.isFavorite ? " active" : ""),
|
||||
title: "Favorite!",
|
||||
type: "button",
|
||||
onClick: (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (this.state.isFavorite) {
|
||||
delete quickEmoteMenu.favoriteEmotes[this.label];
|
||||
quickEmoteMenu.updateFavorites();
|
||||
}
|
||||
else {
|
||||
quickEmoteMenu.favorite(this.label, this.props.url);
|
||||
}
|
||||
this.setState({isFavorite: !this.state.isFavorite});
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class BDLogo extends BDV2.reactComponent {
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"svg",
|
||||
{height: "100%", width: this.props.size || "16px", className: "bd-logo " + this.props.className, style: {fillRule: "evenodd", clipRule: "evenodd", strokeLinecap: "round", strokeLinejoin: "round"}, viewBox: "0 0 2000 2000"},
|
||||
BDV2.react.createElement("metadata", null),
|
||||
BDV2.react.createElement("defs", null,
|
||||
BDV2.react.createElement("filter", {id: "shadow1"}, BDV2.react.createElement("feDropShadow", {"dx": "20", "dy": "0", "stdDeviation": "20", "flood-color": "rgba(0,0,0,0.35)"})),
|
||||
BDV2.react.createElement("filter", {id: "shadow2"}, BDV2.react.createElement("feDropShadow", {"dx": "15", "dy": "0", "stdDeviation": "20", "flood-color": "rgba(255,255,255,0.15)"})),
|
||||
BDV2.react.createElement("filter", {id: "shadow3"}, BDV2.react.createElement("feDropShadow", {"dx": "10", "dy": "0", "stdDeviation": "20", "flood-color": "rgba(0,0,0,0.35)"}))
|
||||
),
|
||||
BDV2.react.createElement("g", null,
|
||||
BDV2.react.createElement("path", {style: {filter: "url(#shadow3)"}, d: "M1195.44+135.442L1195.44+135.442L997.6+136.442C1024.2+149.742+1170.34+163.542+1193.64+179.742C1264.34+228.842+1319.74+291.242+1358.24+365.042C1398.14+441.642+1419.74+530.642+1422.54+629.642L1422.54+630.842L1422.54+632.042C1422.54+773.142+1422.54+1228.14+1422.54+1369.14L1422.54+1370.34L1422.54+1371.54C1419.84+1470.54+1398.24+1559.54+1358.24+1636.14C1319.74+1709.94+1264.44+1772.34+1193.64+1821.44C1171.04+1837.14+1025.7+1850.54+1000+1863.54L1193.54+1864.54C1539.74+1866.44+1864.54+1693.34+1864.54+1296.64L1864.54+716.942C1866.44+312.442+1541.64+135.442+1195.44+135.442Z", fill: "#171717", opacity: "1"}),
|
||||
BDV2.react.createElement("path", {style: {filter: "url(#shadow2)"}, d: "M1695.54+631.442C1685.84+278.042+1409.34+135.442+1052.94+135.442L361.74+136.442L803.74+490.442L1060.74+490.442C1335.24+490.442+1335.24+835.342+1060.74+835.342L1060.74+1164.84C1150.22+1164.84+1210.53+1201.48+1241.68+1250.87C1306.07+1353+1245.76+1509.64+1060.74+1509.64L361.74+1863.54L1052.94+1864.54C1409.24+1864.54+1685.74+1721.94+1695.54+1368.54C1695.54+1205.94+1651.04+1084.44+1572.64+999.942C1651.04+915.542+1695.54+794.042+1695.54+631.442Z", fill: "#3E82E5", opacity: "1"}),
|
||||
BDV2.react.createElement("path", {style: {filter: "url(#shadow1)"}, d: "M1469.25+631.442C1459.55+278.042+1183.05+135.442+826.65+135.442L135.45+135.442L135.45+1004C135.45+1004+135.427+1255.21+355.626+1255.21C575.825+1255.21+575.848+1004+575.848+1004L577.45+490.442L834.45+490.442C1108.95+490.442+1108.95+835.342+834.45+835.342L664.65+835.342L664.65+1164.84L834.45+1164.84C923.932+1164.84+984.244+1201.48+1015.39+1250.87C1079.78+1353+1019.47+1509.64+834.45+1509.64L135.45+1509.64L135.45+1864.54L826.65+1864.54C1182.95+1864.54+1459.45+1721.94+1469.25+1368.54C1469.25+1205.94+1424.75+1084.44+1346.35+999.942C1424.75+915.542+1469.25+794.042+1469.25+631.442Z", fill: "#FFFFFF", opacity: "1"})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_Checkbox extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.setInitialState();
|
||||
}
|
||||
|
||||
setInitialState() {
|
||||
this.state = {
|
||||
checked: this.props.checked || false
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"li",
|
||||
null,
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "checkbox checkbox-3kaeSU da-checkbox", onClick: this.onClick},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "checkbox-inner checkboxInner-3yjcPe da-checkboxInner"},
|
||||
BDV2.react.createElement("input", {className: "checkboxElement-1qV33p da-checkboxElement", checked: this.state.checked, onChange: () => {}, type: "checkbox"}),
|
||||
BDV2.react.createElement("span", null)
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"span",
|
||||
null,
|
||||
this.props.text
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onClick() {
|
||||
this.props.onChange(this.props.id, !this.state.checked);
|
||||
this.setState({
|
||||
checked: !this.state.checked
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_ContentColumn extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "contentColumn-2hrIYH contentColumnDefault-1VQkGM content-column default"},
|
||||
BDV2.react.createElement(
|
||||
"h2",
|
||||
{className: "ui-form-title h2 margin-reset margin-bottom-20"},
|
||||
this.props.title
|
||||
),
|
||||
this.props.children
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
import {settingsCookie} from "../0globals";
|
||||
import Settings from "../settingsPanel";
|
||||
import BDV2 from "../v2";
|
||||
import DataStore from "../dataStore";
|
||||
|
||||
import SettingsTitle from "./settingsTitle";
|
||||
import Checkbox from "./checkbox";
|
||||
import V2C_CssEditorDetached from "./cssEditorDetached";
|
||||
|
||||
export default class V2C_CssEditor extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const self = this;
|
||||
self.props.lines = 0;
|
||||
self.setInitialState();
|
||||
self.attach = self.attach.bind(self);
|
||||
self.detachedEditor = BDV2.react.createElement(V2C_CssEditorDetached, {attach: self.attach});
|
||||
self.onClick = self.onClick.bind(self);
|
||||
self.updateCss = self.updateCss.bind(self);
|
||||
self.saveCss = self.saveCss.bind(self);
|
||||
self.detach = self.detach.bind(self);
|
||||
}
|
||||
|
||||
setInitialState() {
|
||||
this.state = {
|
||||
detached: this.props.detached || BDV2.editorDetached
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// this.updateLineCount();
|
||||
this.editor = ace.edit("bd-customcss-editor");
|
||||
this.editor.setTheme("ace/theme/monokai");
|
||||
this.editor.session.setMode("ace/mode/css");
|
||||
this.editor.setShowPrintMargin(false);
|
||||
this.editor.setFontSize(14);
|
||||
this.editor.on("change", () => {
|
||||
if (!settingsCookie["bda-css-0"]) return;
|
||||
this.saveCss();
|
||||
this.updateCss();
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.editor.destroy();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const self = this;
|
||||
if (prevState.detached && !self.state.detached) {
|
||||
BDV2.reactDom.unmountComponentAtNode(self.detachedRoot);
|
||||
}
|
||||
}
|
||||
|
||||
codeMirror() {
|
||||
}
|
||||
|
||||
get options() {
|
||||
return {
|
||||
lineNumbers: true,
|
||||
mode: "css",
|
||||
indentUnit: 4,
|
||||
theme: "material",
|
||||
scrollbarStyle: "simple"
|
||||
};
|
||||
}
|
||||
|
||||
get css() {
|
||||
const _ccss = DataStore.getBDData("bdcustomcss");
|
||||
let ccss = "";
|
||||
if (_ccss && _ccss !== "") {
|
||||
ccss = atob(_ccss);
|
||||
}
|
||||
return ccss;
|
||||
}
|
||||
|
||||
updateLineCount() {
|
||||
const lineCount = this.refs.editor.value.split("\n").length;
|
||||
if (lineCount == this.props.lines) return;
|
||||
this.refs.lines.textContent = Array.from(new Array(lineCount), (_, i) => i + 1).join(".\n") + ".";
|
||||
this.props.lines = lineCount;
|
||||
}
|
||||
|
||||
render() {
|
||||
const self = this;
|
||||
|
||||
const {detached} = self.state;
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "contentColumn-2hrIYH contentColumnDefault-1VQkGM content-column default", style: {padding: "60px 40px 0px"}},
|
||||
detached && BDV2.react.createElement(
|
||||
"div",
|
||||
{id: "editor-detached"},
|
||||
BDV2.react.createElement(SettingsTitle, {text: "Custom CSS Editor"}),
|
||||
BDV2.react.createElement(
|
||||
"h3",
|
||||
null,
|
||||
"Editor Detached"
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"button",
|
||||
{className: "btn btn-primary", onClick: () => {
|
||||
self.attach();
|
||||
}},
|
||||
"Attach"
|
||||
)
|
||||
),
|
||||
!detached && BDV2.react.createElement(
|
||||
"div",
|
||||
null,
|
||||
BDV2.react.createElement(SettingsTitle, {text: "Custom CSS Editor"}),
|
||||
BDV2.react.createElement("div", {className: "editor-wrapper"},
|
||||
BDV2.react.createElement("div", {id: "bd-customcss-editor", className: "editor", ref: "editor"}, self.css)
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{id: "bd-customcss-attach-controls"},
|
||||
BDV2.react.createElement(
|
||||
"ul",
|
||||
{className: "checkbox-group"},
|
||||
BDV2.react.createElement(Checkbox, {id: "live-update", text: "Live Update", onChange: this.onChange, checked: settingsCookie["bda-css-0"]})
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{id: "bd-customcss-detach-controls-button"},
|
||||
BDV2.react.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "3px 0 0 3px", borderRight: "1px solid #3f4146"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("update");
|
||||
}},
|
||||
"Update"
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "0", borderLeft: "1px solid #2d2d2d", borderRight: "1px solid #2d2d2d"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("save");
|
||||
}},
|
||||
"Save"
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "0 3px 3px 0", borderLeft: "1px solid #3f4146"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("detach");
|
||||
}},
|
||||
"Detach"
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"span",
|
||||
{style: {fontSize: "10px", marginLeft: "5px"}},
|
||||
"Unsaved changes are lost on detach"
|
||||
),
|
||||
BDV2.react.createElement("div", {className: "help-text"},
|
||||
"Press ",
|
||||
BDV2.react.createElement("code", {className: "inline"}, "ctrl"),
|
||||
"+",
|
||||
BDV2.react.createElement("span", {className: "inline"}, ","),
|
||||
" with the editor focused to access the editor's settings."
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onClick(arg) {
|
||||
const self = this;
|
||||
switch (arg) {
|
||||
case "update":
|
||||
self.updateCss();
|
||||
break;
|
||||
case "save":
|
||||
self.saveCss();
|
||||
break;
|
||||
case "detach":
|
||||
self.detach();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onChange(id, checked) {
|
||||
switch (id) {
|
||||
case "live-update":
|
||||
settingsCookie["bda-css-0"] = checked;
|
||||
Settings.saveSettings();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateCss() {
|
||||
if ($("#customcss").length == 0) {
|
||||
$("head").append("<style id=\"customcss\"></style>");
|
||||
}
|
||||
$("#customcss").text(this.editor.session.getValue()).detach().appendTo(document.head);
|
||||
}
|
||||
|
||||
saveCss() {
|
||||
DataStore.setBDData("bdcustomcss", btoa(this.editor.session.getValue()));
|
||||
}
|
||||
|
||||
detach() {
|
||||
const self = this;
|
||||
self.setState({
|
||||
detached: true
|
||||
});
|
||||
const droot = self.detachedRoot;
|
||||
if (!droot) {
|
||||
console.log("FAILED TO INJECT ROOT: .app");
|
||||
return;
|
||||
}
|
||||
BDV2.reactDom.render(self.detachedEditor, droot);
|
||||
}
|
||||
|
||||
get detachedRoot() {
|
||||
const _root = $("#bd-customcss-detach-container");
|
||||
if (!_root.length) {
|
||||
if (!this.injectDetachedRoot()) return null;
|
||||
return this.detachedRoot;
|
||||
}
|
||||
return _root[0];
|
||||
}
|
||||
|
||||
injectDetachedRoot() {
|
||||
if (!$(".app, .app-2rEoOp").length) return false;
|
||||
$("<div/>", {
|
||||
id: "bd-customcss-detach-container"
|
||||
}).insertAfter($(".app, .app-2rEoOp"));
|
||||
return true;
|
||||
}
|
||||
|
||||
attach() {
|
||||
const self = this;
|
||||
self.setState({
|
||||
detached: false
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
import {settingsCookie} from "../0globals";
|
||||
import Settings from "../settingsPanel";
|
||||
import BDV2 from "../v2";
|
||||
import DataStore from "../dataStore";
|
||||
|
||||
import Checkbox from "./checkbox";
|
||||
|
||||
export default class V2C_CssEditorDetached extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const self = this;
|
||||
self.onClick = self.onClick.bind(self);
|
||||
self.updateCss = self.updateCss.bind(self);
|
||||
self.saveCss = self.saveCss.bind(self);
|
||||
self.onChange = self.onChange.bind(self);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
$("#app-mount").addClass("bd-detached-editor");
|
||||
BDV2.editorDetached = true;
|
||||
// this.updateLineCount();
|
||||
this.editor = ace.edit("bd-customcss-editor-detached");
|
||||
this.editor.setTheme("ace/theme/monokai");
|
||||
this.editor.session.setMode("ace/mode/css");
|
||||
this.editor.setShowPrintMargin(false);
|
||||
this.editor.setFontSize(14);
|
||||
this.editor.on("change", () => {
|
||||
if (!settingsCookie["bda-css-0"]) return;
|
||||
this.saveCss();
|
||||
this.updateCss();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
$("#app-mount").removeClass("bd-detached-editor");
|
||||
BDV2.editorDetached = false;
|
||||
this.editor.destroy();
|
||||
}
|
||||
|
||||
updateLineCount() {
|
||||
const lineCount = this.refs.editor.value.split("\n").length;
|
||||
if (lineCount == this.props.lines) return;
|
||||
this.refs.lines.textContent = Array.from(new Array(lineCount), (_, i) => i + 1).join(".\n") + ".";
|
||||
this.props.lines = lineCount;
|
||||
}
|
||||
|
||||
get options() {
|
||||
return {
|
||||
lineNumbers: true,
|
||||
mode: "css",
|
||||
indentUnit: 4,
|
||||
theme: "material",
|
||||
scrollbarStyle: "simple"
|
||||
};
|
||||
}
|
||||
|
||||
get css() {
|
||||
const _ccss = DataStore.getBDData("bdcustomcss");
|
||||
let ccss = "";
|
||||
if (_ccss && _ccss !== "") {
|
||||
ccss = atob(_ccss);
|
||||
}
|
||||
return ccss;
|
||||
}
|
||||
|
||||
get root() {
|
||||
const _root = $("#bd-customcss-detach-container");
|
||||
if (!_root.length) {
|
||||
if (!this.injectRoot()) return null;
|
||||
return this.detachedRoot;
|
||||
}
|
||||
return _root[0];
|
||||
}
|
||||
|
||||
injectRoot() {
|
||||
if (!$(".app, .app-2rEoOp").length) return false;
|
||||
$("<div/>", {
|
||||
id: "bd-customcss-detach-container"
|
||||
}).insertAfter($(".app, .app-2rEoOp"));
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
const self = this;
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "bd-detached-css-editor", id: "bd-customcss-detach-editor"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{id: "bd-customcss-innerpane"},
|
||||
BDV2.react.createElement("div", {className: "editor-wrapper"},
|
||||
BDV2.react.createElement("div", {id: "bd-customcss-editor-detached", className: "editor", ref: "editor"}, self.css)
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{id: "bd-customcss-attach-controls"},
|
||||
BDV2.react.createElement(
|
||||
"ul",
|
||||
{className: "checkbox-group"},
|
||||
BDV2.react.createElement(Checkbox, {id: "live-update", text: "Live Update", onChange: self.onChange, checked: settingsCookie["bda-css-0"]})
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{id: "bd-customcss-detach-controls-button"},
|
||||
BDV2.react.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "3px 0 0 3px", borderRight: "1px solid #3f4146"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("update");
|
||||
}},
|
||||
"Update"
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "0", borderLeft: "1px solid #2d2d2d", borderRight: "1px solid #2d2d2d"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("save");
|
||||
}},
|
||||
"Save"
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"button",
|
||||
{style: {borderRadius: "0 3px 3px 0", borderLeft: "1px solid #3f4146"}, className: "btn btn-primary", onClick: () => {
|
||||
self.onClick("attach");
|
||||
}},
|
||||
"Attach"
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"span",
|
||||
{style: {fontSize: "10px", marginLeft: "5px"}},
|
||||
"Unsaved changes are lost on attach"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onChange(id, checked) {
|
||||
switch (id) {
|
||||
case "live-update":
|
||||
settingsCookie["bda-css-0"] = checked;
|
||||
Settings.saveSettings();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onClick(id) {
|
||||
const self = this;
|
||||
switch (id) {
|
||||
case "attach":
|
||||
if ($("#editor-detached").length) self.props.attach();
|
||||
BDV2.reactDom.unmountComponentAtNode(self.root);
|
||||
self.root.remove();
|
||||
break;
|
||||
case "update":
|
||||
self.updateCss();
|
||||
break;
|
||||
case "save":
|
||||
self.saveCss();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateCss() {
|
||||
if ($("#customcss").length == 0) {
|
||||
$("head").append("<style id=\"customcss\"></style>");
|
||||
}
|
||||
$("#customcss").text(this.editor.session.getValue()).detach().appendTo(document.head);
|
||||
}
|
||||
|
||||
saveCss() {
|
||||
DataStore.setBDData("bdcustomcss", btoa(this.editor.session.getValue()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import BDV2 from "../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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_List extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"ul",
|
||||
{className: this.props.className},
|
||||
this.props.children
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
import {settingsCookie, pluginCookie, bdplugins} from "../0globals";
|
||||
import BDV2 from "../v2";
|
||||
import pluginModule from "../pluginModule";
|
||||
import Utils from "../utils";
|
||||
|
||||
import XSvg from "./xSvg";
|
||||
import ReloadIcon from "./reloadIcon";
|
||||
import TooltipWrap from "./tooltipWrap";
|
||||
|
||||
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) {
|
||||
return typeof value == "string" ? value : value.toString();
|
||||
}
|
||||
|
||||
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 self = this;
|
||||
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];
|
||||
|
||||
if (this.state.settings) {
|
||||
try { self.settingsPanel = plugin.getSettingsPanel(); }
|
||||
catch (err) { Utils.err("Plugins", "Unable to get settings panel for " + plugin.getName() + ".", err); }
|
||||
|
||||
return BDV2.react.createElement("li", {className: "settings-open ui-switch-item"},
|
||||
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}})
|
||||
);
|
||||
}
|
||||
|
||||
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("li", {"data-name": name, "data-version": version, "className": "settings-closed ui-switch-item"},
|
||||
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 || 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")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.setState({checked: !this.state.checked});
|
||||
pluginModule.togglePlugin(this.props.plugin.getName());
|
||||
}
|
||||
|
||||
showSettings() {
|
||||
if (!this.hasSettings) return;
|
||||
this.setState({settings: true});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,437 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
import Tools from "./tools";
|
||||
import ServerCard from "./serverCard";
|
||||
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 {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.setInitialState();
|
||||
this.close = this.close.bind(this);
|
||||
this.changeCategory = this.changeCategory.bind(this);
|
||||
this.search = this.search.bind(this);
|
||||
this.searchKeyDown = this.searchKeyDown.bind(this);
|
||||
this.checkConnection = this.checkConnection.bind(this);
|
||||
this.join = this.join.bind(this);
|
||||
this.connect = this.connect.bind(this);
|
||||
|
||||
this.GuildStore = BDV2.WebpackModules.findByUniqueProperties(["getGuilds"]);
|
||||
this.AvatarDefaults = BDV2.WebpackModules.findByUniqueProperties(["getUserAvatarURL", "DEFAULT_AVATARS"]);
|
||||
this.InviteActions = BDV2.WebpackModules.findByUniqueProperties(["acceptInvite"]);
|
||||
this.SortedGuildStore = BDV2.WebpackModules.findByUniqueProperties(["getSortedGuilds"]);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.checkConnection();
|
||||
}
|
||||
|
||||
setInitialState() {
|
||||
this.state = {
|
||||
selectedCategory: -1,
|
||||
title: "Loading...",
|
||||
loading: true,
|
||||
servers: [],
|
||||
next: null,
|
||||
connection: {
|
||||
state: 0,
|
||||
user: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
close() {
|
||||
BDV2.reactDom.unmountComponentAtNode(document.getElementById(this.props.rootId));
|
||||
}
|
||||
|
||||
search(query, clear) {
|
||||
const self = this;
|
||||
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: `${self.endPoint}${query}${query ? "&schema=new" : "?schema=new"}`,
|
||||
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,
|
||||
title: "Failed to load servers. Check console for details"
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
join(serverCard) {
|
||||
if (serverCard.props.pinned) return this.InviteActions.acceptInvite(serverCard.props.invite_code);
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: `${this.joinEndPoint}/${serverCard.props.server.identifier}`,
|
||||
headers: {
|
||||
"Accept": "application/json;",
|
||||
"Content-Type": "application/json;" ,
|
||||
"x-discord-token": this.state.connection.user.accessToken
|
||||
},
|
||||
crossDomain: true,
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
},
|
||||
success: () => {
|
||||
serverCard.setState({joined: true});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
connect() {
|
||||
const self = this;
|
||||
const options = self.windowOptions;
|
||||
options.x = Math.round(window.screenX + window.innerWidth / 2 - options.width / 2);
|
||||
options.y = Math.round(window.screenY + window.innerHeight / 2 - options.height / 2);
|
||||
|
||||
self.joinWindow = new (window.require("electron").remote.BrowserWindow)(options);
|
||||
const url = "https://auth.discordservers.com/connect?scopes=guilds.join&previousUrl=https://auth.discordservers.com/info";
|
||||
self.joinWindow.webContents.on("did-navigate", (event, url) => {
|
||||
if (url != "https://auth.discordservers.com/info") return;
|
||||
self.joinWindow.close();
|
||||
self.checkConnection();
|
||||
});
|
||||
self.joinWindow.loadURL(url);
|
||||
}
|
||||
|
||||
get windowOptions() {
|
||||
return {
|
||||
width: 500,
|
||||
height: 550,
|
||||
backgroundColor: "#282b30",
|
||||
show: true,
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
minimizable: false,
|
||||
alwaysOnTop: true,
|
||||
frame: false,
|
||||
center: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get bdServer() {
|
||||
const server = {
|
||||
name: "BetterDiscord",
|
||||
online: "7500+",
|
||||
members: "20000+",
|
||||
categories: ["community", "programming", "support"],
|
||||
description: "Official BetterDiscord server for support etc",
|
||||
identifier: "86004744966914048",
|
||||
iconUrl: "https://cdn.discordapp.com/icons/86004744966914048/292e7f6bfff2b71dfd13e508a859aedd.webp",
|
||||
nativejoin: true,
|
||||
invite_code: "0Tmfo5ZbORCRqbAd",
|
||||
pinned: true
|
||||
};
|
||||
const guildList = this.SortedGuildStore.getFlattenedGuildIds();
|
||||
const defaultList = this.AvatarDefaults.DEFAULT_AVATARS;
|
||||
return BDV2.react.createElement(ServerCard, {server: server, pinned: true, join: this.join, guildList: guildList, fallback: defaultList[Math.floor(Math.random() * 5)]});
|
||||
}
|
||||
|
||||
get endPoint() {
|
||||
return "https://search.discordservers.com";
|
||||
}
|
||||
|
||||
get joinEndPoint() {
|
||||
return "https://j.discordservers.com";
|
||||
}
|
||||
|
||||
get connectEndPoint() {
|
||||
return "https://join.discordservers.com/connect";
|
||||
}
|
||||
|
||||
checkConnection() {
|
||||
const self = this;
|
||||
try {
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: `https://auth.discordservers.com/info`,
|
||||
headers: {
|
||||
"Accept": "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
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
self.setState({
|
||||
title: "Not connected to discordservers.com!",
|
||||
loading: true,
|
||||
selectedCategory: -1,
|
||||
connection: {
|
||||
state: 1,
|
||||
user: null
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(SidebarView, {ref: "sbv", children: this.component});
|
||||
}
|
||||
|
||||
get component() {
|
||||
return {
|
||||
sidebar: {
|
||||
component: this.sidebar
|
||||
},
|
||||
content: {
|
||||
component: this.content
|
||||
},
|
||||
tools: {
|
||||
component: BDV2.react.createElement(Tools, {key: "pt", ref: "tools", onClick: this.close})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get sidebar() {
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "sidebar", key: "ps"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-tab-bar SIDE"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-tab-bar-header", style: {fontSize: "16px"}},
|
||||
"Public Servers"
|
||||
),
|
||||
BDV2.react.createElement(TabBarSeparator, null),
|
||||
this.searchInput,
|
||||
BDV2.react.createElement(TabBarSeparator, null),
|
||||
BDV2.react.createElement(TabBarHeader, {text: "Categories"}),
|
||||
this.categoryButtons.map((value, index) => {
|
||||
return BDV2.react.createElement(TabBarItem, {id: index, onClick: this.changeCategory, key: index, text: value, selected: this.state.selectedCategory === index});
|
||||
}),
|
||||
BDV2.react.createElement(TabBarSeparator, null),
|
||||
this.footer,
|
||||
this.connection
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
get searchInput() {
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-form-item"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-text-input flex-vertical", style: {width: "172px", marginLeft: "10px"}},
|
||||
BDV2.react.createElement("input", {ref: "searchinput", onKeyDown: this.searchKeyDown, onChange: () => {}, type: "text", className: "input default", placeholder: "Search...", maxLength: "50"})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
searchKeyDown(e) {
|
||||
const self = this;
|
||||
if (self.state.loading || e.which !== 13) return;
|
||||
self.setState({
|
||||
loading: true,
|
||||
title: "Loading...",
|
||||
term: e.target.value
|
||||
});
|
||||
let query = `?term=${e.target.value}`;
|
||||
if (self.state.selectedCategory !== 0) {
|
||||
query += `&category=${self.categoryButtons[self.state.selectedCategory]}`;
|
||||
}
|
||||
self.search(query, true);
|
||||
}
|
||||
|
||||
get categoryButtons() {
|
||||
return ["All", "FPS Games", "MMO Games", "Strategy Games", "MOBA Games", "RPG Games", "Tabletop Games", "Sandbox Games", "Simulation Games", "Music", "Community", "Language", "Programming", "Other"];
|
||||
}
|
||||
|
||||
changeCategory(id) {
|
||||
const self = this;
|
||||
if (self.state.loading) return;
|
||||
self.refs.searchinput.value = "";
|
||||
self.setState({
|
||||
loading: true,
|
||||
selectedCategory: id,
|
||||
title: "Loading...",
|
||||
term: null
|
||||
});
|
||||
if (id === 0) {
|
||||
self.search("", true);
|
||||
return;
|
||||
}
|
||||
self.search(`?category=${self.categoryButtons[id]}`, true);
|
||||
}
|
||||
|
||||
get content() {
|
||||
const self = this;
|
||||
const guildList = this.SortedGuildStore.getFlattenedGuildIds();
|
||||
const defaultList = this.AvatarDefaults.DEFAULT_AVATARS;
|
||||
if (self.state.connection.state === 1) return self.notConnected;
|
||||
return [BDV2.react.createElement(
|
||||
"div",
|
||||
{ref: "content", key: "pc", className: "contentColumn-2hrIYH contentColumnDefault-1VQkGM content-column default"},
|
||||
BDV2.react.createElement(SettingsTitle, {text: self.state.title}),
|
||||
self.bdServer,
|
||||
self.state.servers.map((server) => {
|
||||
return BDV2.react.createElement(ServerCard, {key: server.identifier, server: server, join: self.join, guildList: guildList, fallback: defaultList[Math.floor(Math.random() * 5)]});
|
||||
}),
|
||||
self.state.next && BDV2.react.createElement(
|
||||
"button",
|
||||
{type: "button", onClick: () => {
|
||||
if (self.state.loading) return;self.setState({loading: true}); self.search(self.state.next, false);
|
||||
}, className: "ui-button filled brand small grow", style: {width: "100%", marginTop: "10px", marginBottom: "10px"}},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-button-contents"},
|
||||
self.state.loading ? "Loading" : "Load More"
|
||||
)
|
||||
),
|
||||
self.state.servers.length > 0 && BDV2.react.createElement(SettingsTitle, {text: self.state.title})
|
||||
)];
|
||||
}
|
||||
|
||||
get notConnected() {
|
||||
const self = this;
|
||||
//return BDV2.react.createElement(SettingsTitle, { text: self.state.title });
|
||||
return [BDV2.react.createElement(
|
||||
"div",
|
||||
{key: "ncc", ref: "content", className: "contentColumn-2hrIYH contentColumnDefault-1VQkGM content-column default"},
|
||||
BDV2.react.createElement(
|
||||
"h2",
|
||||
{className: "ui-form-title h2 margin-reset margin-bottom-20"},
|
||||
"Not connected to discordservers.com!",
|
||||
BDV2.react.createElement(
|
||||
"button",
|
||||
{
|
||||
onClick: self.connect,
|
||||
type: "button",
|
||||
className: "ui-button filled brand small grow",
|
||||
style: {
|
||||
display: "inline-block",
|
||||
minHeight: "18px",
|
||||
marginLeft: "10px",
|
||||
lineHeight: "14px"
|
||||
}
|
||||
},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-button-contents"},
|
||||
"Connect"
|
||||
)
|
||||
)
|
||||
), self.bdServer
|
||||
)];
|
||||
}
|
||||
|
||||
get footer() {
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-tab-bar-header"},
|
||||
BDV2.react.createElement(
|
||||
"a",
|
||||
{href: "https://discordservers.com", target: "_blank"},
|
||||
"Discordservers.com"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
get connection() {
|
||||
const self = this;
|
||||
const {connection} = self.state;
|
||||
if (connection.state !== 2) return BDV2.react.createElement("span", null);
|
||||
|
||||
return BDV2.react.createElement(
|
||||
"span",
|
||||
null,
|
||||
BDV2.react.createElement(TabBarSeparator, null),
|
||||
BDV2.react.createElement(
|
||||
"span",
|
||||
{style: {color: "#b9bbbe", fontSize: "10px", marginLeft: "10px"}},
|
||||
"Connected as: ",
|
||||
`${connection.user.username}#${connection.user.discriminator}`
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{style: {padding: "5px 10px 0 10px"}},
|
||||
BDV2.react.createElement(
|
||||
"button",
|
||||
{style: {width: "100%", minHeight: "20px"}, type: "button", className: "ui-button filled brand small grow"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-button-contents", onClick: self.connect},
|
||||
"Reconnect"
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_ReloadIcon extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement("svg", {
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
viewBox: "0 0 24 24",
|
||||
fill: "#dcddde",
|
||||
className: "bd-reload " + this.props.className,
|
||||
onClick: this.props.onClick,
|
||||
style: {width: this.props.size || "24px", height: this.props.size || "24px"}
|
||||
},
|
||||
BDV2.react.createElement("path", {d: "M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"}),
|
||||
BDV2.react.createElement("path", {fill: "none", d: "M0 0h24v24H0z"})
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_Scroller extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
//scrollerWrap-2lJEkd scrollerThemed-2oenus themeGhostHairline-DBD-2d scrollerFade-1Ijw5y
|
||||
let wrapperClass = `scrollerWrap-2lJEkd scrollerThemed-2oenus themeGhostHairline-DBD-2d${this.props.fade ? " scrollerFade-1Ijw5y" : ""}`;
|
||||
let scrollerClass = "scroller-2FKFPG scroller"; /* fuck */
|
||||
if (this.props.sidebar) scrollerClass = "scroller-2FKFPG firefoxFixScrollFlex-cnI2ix sidebarRegionScroller-3MXcoP sidebar-region-scroller scroller";
|
||||
if (this.props.contentColumn) {
|
||||
scrollerClass = "scroller-2FKFPG firefoxFixScrollFlex-cnI2ix contentRegionScroller-26nc1e content-region-scroller scroller"; /* fuck */
|
||||
wrapperClass = "scrollerWrap-2lJEkd firefoxFixScrollFlex-cnI2ix contentRegionScrollerWrap-3YZXdm content-region-scroller-wrap scrollerThemed-2oenus themeGhost-28MSn0 scrollerTrack-1ZIpsv";
|
||||
}
|
||||
const {children} = this.props;
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{key: "scrollerwrap", className: wrapperClass},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{key: "scroller", ref: "scroller", className: scrollerClass},
|
||||
children
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
import SettingsGroup from "./settingsGroup";
|
||||
|
||||
export default class V2C_SectionedSettingsPanel extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"div", {className: "contentColumn-2hrIYH contentColumnDefault-1VQkGM content-column default"},
|
||||
this.props.sections.map(section => {
|
||||
return BDV2.react.createElement(SettingsGroup, Object.assign({}, section, {onChange: this.props.onChange}));
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_ServerCard extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (!this.props.server.iconUrl) this.props.server.iconUrl = this.props.fallback;
|
||||
this.state = {
|
||||
imageError: false,
|
||||
joined: this.props.guildList.includes(this.props.server.identifier)
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {server} = this.props;
|
||||
return BDV2.react.createElement(
|
||||
"div", // cardPrimary-1Hv-to
|
||||
{className: `card-3Qj_Yx cardPrimary-1Hv-to marginBottom8-AtZOdT bd-server-card${server.pinned ? " bd-server-card-pinned" : ""}`},
|
||||
// BDV2.react.createElement(
|
||||
// "div",
|
||||
// { className: "flex-1xMQg5 flex-1O1GKY horizontal-1ae9ci horizontal-2EEEnY flex-1O1GKY directionRow-3v3tfG justifyStart-2yIZo0 alignStretch-1hwxMa noWrap-3jynv6" },
|
||||
BDV2.react.createElement("img", {ref: "img", className: "bd-server-image", src: server.iconUrl, onError: this.handleError.bind(this)}),
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "flexChild-faoVW3 bd-server-content"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "flex-1xMQg5 flex-1O1GKY horizontal-1ae9ci horizontal-2EEEnY directionRow-3v3tfG noWrap-3jynv6 bd-server-header"},
|
||||
BDV2.react.createElement(
|
||||
"h5",
|
||||
{className: "h5-18_1nd defaultColor-1_ajX0 margin-reset bd-server-name"},
|
||||
server.name
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"h5",
|
||||
{className: "h5-18_1nd defaultColor-1_ajX0 margin-reset bd-server-member-count"},
|
||||
server.members,
|
||||
" Members"
|
||||
)
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "flex-1xMQg5 flex-1O1GKY horizontal-1ae9ci horizontal-2EEEnY directionRow-3v3tfG noWrap-3jynv6"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "scrollerWrap-2lJEkd scrollerThemed-2oenus themeGhostHairline-DBD-2d scrollerFade-1Ijw5y bd-server-description-container"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "scroller-2FKFPG scroller bd-server-description"},
|
||||
server.description
|
||||
)
|
||||
)
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "flex-1xMQg5 flex-1O1GKY horizontal-1ae9ci horizontal-2EEEnY directionRow-3v3tfG noWrap-3jynv6 bd-server-footer"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "flexChild-faoVW3 bd-server-tags", style: {flex: "1 1 auto"}},
|
||||
server.categories.join(", ")
|
||||
),
|
||||
this.state.joined && BDV2.react.createElement(
|
||||
"button",
|
||||
{type: "button", className: "button-38aScr lookFilled-1Gx00P colorBrand-3pXr91 sizeMin-1mJd1x grow-q77ONN colorGreen-29iAKY", style: {minHeight: "12px", marginTop: "4px", backgroundColor: "#3ac15c"}},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-button-contents"},
|
||||
"Joined"
|
||||
)
|
||||
),
|
||||
server.error && BDV2.react.createElement(
|
||||
"button",
|
||||
{type: "button", className: "button-38aScr lookFilled-1Gx00P colorBrand-3pXr91 sizeMin-1mJd1x grow-q77ONN disabled-9aF2ug", style: {minHeight: "12px", marginTop: "4px", backgroundColor: "#c13a3a"}},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-button-contents"},
|
||||
"Error"
|
||||
)
|
||||
),
|
||||
!server.error && !this.state.joined && BDV2.react.createElement(
|
||||
"button",
|
||||
{type: "button", className: "button-38aScr lookFilled-1Gx00P colorBrand-3pXr91 sizeMin-1mJd1x grow-q77ONN", style: {minHeight: "12px", marginTop: "4px"}, onClick: () => {this.join();}},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-button-contents"},
|
||||
"Join"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
// )
|
||||
);
|
||||
}
|
||||
|
||||
handleError() {
|
||||
this.props.server.iconUrl = this.props.fallback;
|
||||
this.setState({imageError: true});
|
||||
}
|
||||
|
||||
join() {
|
||||
this.props.join(this);
|
||||
//this.setState({joined: true});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import {settingsCookie} from "../0globals";
|
||||
import BDV2 from "../v2";
|
||||
|
||||
import SettingsTitle from "./settingsTitle";
|
||||
import Switch from "./switch";
|
||||
|
||||
export default class V2C_SettingsGroup extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {title, settings, button} = this.props;
|
||||
const buttonComponent = button ? BDV2.react.createElement("button", {key: "title-button", className: "bd-pfbtn", onClick: button.onClick}, button.title) : null;
|
||||
return [BDV2.react.createElement(SettingsTitle, {text: title}),
|
||||
buttonComponent,
|
||||
settings.map(setting => {
|
||||
return BDV2.react.createElement(Switch, {id: setting.id, key: setting.id, data: setting, checked: settingsCookie[setting.id], onChange: (id, checked) => {
|
||||
this.props.onChange(id, checked);
|
||||
}});
|
||||
})];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import {settingsCookie} from "../0globals";
|
||||
import BDV2 from "../v2";
|
||||
|
||||
import SettingsTitle from "./settingsTitle";
|
||||
import Switch from "./switch";
|
||||
|
||||
export default class V2C_SettingsPanel extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {settings} = this.props;
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "contentColumn-2hrIYH contentColumnDefault-1VQkGM content-column default"},
|
||||
BDV2.react.createElement(SettingsTitle, {text: this.props.title}),
|
||||
this.props.button && BDV2.react.createElement("button", {key: "title-button", className: "bd-pfbtn", onClick: this.props.button.onClick}, this.props.button.title),
|
||||
settings.map(setting => {
|
||||
return BDV2.react.createElement(Switch, {id: setting.id, key: setting.id, data: setting, checked: settingsCookie[setting.id], onChange: (id, checked) => {
|
||||
this.props.onChange(id, checked);
|
||||
}});
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_SettingsTitle extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
//h2-2gWE-o title-3sZWYQ size16-14cGz5 height20-mO2eIN weightSemiBold-NJexzi da-h2 da-title da-size16 da-height20 da-weightSemiBold defaultColor-1_ajX0 da-defaultColor marginTop60-3PGbtK da-marginTop60 marginBottom20-32qID7 da-marginBottom20
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"h2",
|
||||
{className: "ui-form-title h2 margin-reset margin-bottom-20 marginTop60-3PGbtK da-marginTop6"},
|
||||
this.props.text
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
import TabBarSeparator from "./tabBarSeparator";
|
||||
import TabBarHeader from "./tabBarHeader";
|
||||
import TabBarItem from "./tabBarItem";
|
||||
|
||||
export default class V2C_SideBar extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const self = this;
|
||||
const si = $("[class*=side-] > [class*=selected]");
|
||||
if (si.length) self.scn = si.attr("class");
|
||||
const ns = $("[class*=side-] > [class*='item-']:not([class*=selected])");
|
||||
if (ns.length) self.nscn = ns.attr("class");
|
||||
$("[class*='side-'] > [class*='item-']").on("click", () => {
|
||||
self.setState({
|
||||
selected: null
|
||||
});
|
||||
});
|
||||
self.setInitialState();
|
||||
self.onClick = self.onClick.bind(self);
|
||||
}
|
||||
|
||||
setInitialState() {
|
||||
const self = this;
|
||||
self.state = {
|
||||
selected: null,
|
||||
items: self.props.items
|
||||
};
|
||||
|
||||
const initialSelection = self.props.items.find(item => {
|
||||
return item.selected;
|
||||
});
|
||||
if (initialSelection) {
|
||||
self.state.selected = initialSelection.id;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const self = this;
|
||||
const {headerText} = self.props;
|
||||
const {items, selected} = self.state;
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
null,
|
||||
BDV2.react.createElement(TabBarSeparator, null),
|
||||
BDV2.react.createElement(TabBarHeader, {text: headerText}),
|
||||
items.map(item => {
|
||||
const {id, text} = item;
|
||||
return BDV2.react.createElement(TabBarItem, {key: id, selected: selected === id, text: text, id: id, onClick: self.onClick});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
onClick(id) {
|
||||
const self = this;
|
||||
const si = $("[class*=side] > [class*=selected]");
|
||||
if (si.length) {
|
||||
si.off("click.bdsb").on("click.bsb", e => {
|
||||
$(e.target).attr("class", self.scn);
|
||||
});
|
||||
si.attr("class", self.nscn);
|
||||
}
|
||||
|
||||
self.setState({selected: null});
|
||||
self.setState({selected: id});
|
||||
|
||||
if (self.props.onClick) self.props.onClick(id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
import Scroller from "./scroller";
|
||||
|
||||
export default class V2C_SidebarView extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {sidebar, content, tools} = this.props.children;
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "standardSidebarView-3F1I7i ui-standard-sidebar-view"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{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("div", {className: "contentRegion-3nDuYy content-region"},
|
||||
BDV2.react.createElement("div", {className: "contentTransitionWrap-3hqOEW content-transition-wrap"},
|
||||
BDV2.react.createElement("div", {className: "scrollerWrap-2lJEkd firefoxFixScrollFlex-cnI2ix contentRegionScrollerWrap-3YZXdm content-region-scroller-wrap scrollerThemed-2oenus themeGhost-28MSn0 scrollerTrack-1ZIpsv"},
|
||||
BDV2.react.createElement("div", {className: "scroller-2FKFPG firefoxFixScrollFlex-cnI2ix contentRegionScroller-26nc1e content-region-scroller scroller", ref: "contentScroller"},
|
||||
BDV2.react.createElement("div", {className: "contentColumn-2hrIYH contentColumnDefault-1VQkGM content-column default"}, content.component),
|
||||
tools.component
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_Switch extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.setInitialState();
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
|
||||
setInitialState() {
|
||||
this.state = {
|
||||
checked: this.props.checked
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {text, info} = this.props.data;
|
||||
const {checked} = this.state;
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-flex flex-vertical flex-justify-start flex-align-stretch flex-nowrap ui-switch-item"},
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-flex flex-horizontal flex-justify-start flex-align-stretch flex-nowrap"},
|
||||
BDV2.react.createElement(
|
||||
"h3",
|
||||
{className: "ui-form-title h3 margin-reset margin-reset ui-flex-child"},
|
||||
text
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"label",
|
||||
{className: "ui-switch-wrapper ui-flex-child", style: {flex: "0 0 auto"}},
|
||||
BDV2.react.createElement("input", {className: "ui-switch-checkbox", type: "checkbox", checked: checked, onChange: e => this.onChange(e)}),
|
||||
BDV2.react.createElement("div", {className: `ui-switch ${checked ? "checked" : ""}`})
|
||||
)
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-form-text style-description margin-top-4", style: {flex: "1 1 auto"}},
|
||||
info
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.props.onChange(this.props.id, !this.state.checked);
|
||||
this.setState({
|
||||
checked: !this.state.checked
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_TabBarHeader extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "ui-tab-bar-header"},
|
||||
this.props.text
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_TabBarItem extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.setInitialState();
|
||||
this.onClick = this.onClick.bind(this);
|
||||
}
|
||||
|
||||
setInitialState() {
|
||||
this.state = {
|
||||
selected: this.props.selected || false
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: `ui-tab-bar-item${this.props.selected ? " selected" : ""}`, onClick: this.onClick},
|
||||
this.props.text
|
||||
);
|
||||
}
|
||||
|
||||
onClick() {
|
||||
if (this.props.onClick) {
|
||||
this.props.onClick(this.props.id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_TabBarSeparator extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement("div", {className: "ui-tab-bar-separator margin-top-8 margin-bottom-8"});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
import {settingsCookie, themeCookie, bdthemes} from "../0globals";
|
||||
import Utils from "../utils";
|
||||
import BDV2 from "../v2";
|
||||
import themeModule from "../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("li", {"data-name": name, "data-version": version, "className": "settings-closed ui-switch-item"},
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
import XSvg from "./xSvg";
|
||||
|
||||
export default class V2C_Tools extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement("div", {className: "tools-container toolsContainer-1edPuj"},
|
||||
BDV2.react.createElement("div", {className: "tools tools-3-3s-N"},
|
||||
BDV2.react.createElement("div", {className: "container-1sFeqf"},
|
||||
BDV2.react.createElement("div",
|
||||
{className: "btn-close closeButton-1tv5uR", onClick: this.onClick},
|
||||
BDV2.react.createElement(XSvg, null)
|
||||
),
|
||||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "esc-text keybind-KpFkfr"},
|
||||
"ESC"
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onClick() {
|
||||
if (this.props.onClick) {
|
||||
this.props.onClick();
|
||||
}
|
||||
$(".closeButton-1tv5uR").first().click();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
import BDV2 from "../v2";
|
||||
import Utils from "../utils";
|
||||
|
||||
export default function(Component, options) {
|
||||
const {style = "black", side = "top", text = ""} = options;
|
||||
const id = BDV2.KeyGenerator();
|
||||
|
||||
return class extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onMouseEnter = this.onMouseEnter.bind(this);
|
||||
this.onMouseLeave = this.onMouseLeave.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.node = BDV2.reactDom.findDOMNode(this);
|
||||
this.node.addEventListener("mouseenter", this.onMouseEnter);
|
||||
this.node.addEventListener("mouseleave", this.onMouseLeave);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.node.removeEventListener("mouseenter", this.onMouseEnter);
|
||||
this.node.removeEventListener("mouseleave", this.onMouseLeave);
|
||||
}
|
||||
|
||||
onMouseEnter() {
|
||||
if (!BDV2.Tooltips) return;
|
||||
const {left, top, width, height} = this.node.getBoundingClientRect();
|
||||
BDV2.Tooltips.show(id, {
|
||||
position: side,
|
||||
text: text,
|
||||
color: style,
|
||||
targetWidth: width,
|
||||
targetHeight: height,
|
||||
windowWidth: Utils.screenWidth,
|
||||
windowHeight: Utils.screenHeight,
|
||||
x: left,
|
||||
y: top
|
||||
});
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
const nodes = Array.from(mutation.removedNodes);
|
||||
const directMatch = nodes.indexOf(this.node) > -1;
|
||||
const parentMatch = nodes.some(parent => parent.contains(this.node));
|
||||
if (directMatch || parentMatch) {
|
||||
this.onMouseLeave();
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
observer.observe(document.body, {subtree: true, childList: true});
|
||||
}
|
||||
|
||||
onMouseLeave() {
|
||||
if (!BDV2.Tooltips) return;
|
||||
BDV2.Tooltips.hide(id);
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(Component, this.props);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import BDV2 from "../v2";
|
||||
|
||||
export default class V2C_XSvg extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"svg",
|
||||
{xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 12 12", style: {width: "18px", height: "18px"}},
|
||||
BDV2.react.createElement(
|
||||
"g",
|
||||
{className: "background", fill: "none", fillRule: "evenodd"},
|
||||
BDV2.react.createElement("path", {d: "M0 0h12v12H0"}),
|
||||
BDV2.react.createElement("path", {className: "fill", fill: "#dcddde", d: "M9.5 3.205L8.795 2.5 6 5.295 3.205 2.5l-.705.705L5.295 6 2.5 8.795l.705.705L6 6.705 8.795 9.5l.705-.705L6.705 6"})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,365 @@
|
|||
import {settings, settingsCookie, bdplugins, bdthemes} from "./0globals";
|
||||
import DataStore from "./dataStore";
|
||||
import V2_SettingsPanel_Sidebar from "./settingsPanelSidebar";
|
||||
import Utils from "./utils";
|
||||
import BDV2 from "./v2";
|
||||
import ContentManager from "./contentManager";
|
||||
import BDEvents from "./bdEvents";
|
||||
import pluginModule from "./pluginModule";
|
||||
import themeModule from "./themeModule";
|
||||
import coloredText from "./coloredText";
|
||||
|
||||
import publicServersModule from "./publicServers";
|
||||
import voiceMode from "./voiceMode";
|
||||
import emoteModule from "./emoteModule";
|
||||
import ClassNormalizer from "./classNormalizer";
|
||||
import dMode from "./devMode";
|
||||
import quickEmoteMenu from "./quickEmoteMenu";
|
||||
|
||||
import Tools from "./react/tools";
|
||||
import ReloadIcon from "./react/reloadIcon";
|
||||
import TooltipWrap from "./react/tooltipWrap";
|
||||
import Scroller from "./react/scroller";
|
||||
import List from "./react/list";
|
||||
import PluginCard from "./react/pluginCard";
|
||||
import ThemeCard from "./react/themeCard";
|
||||
import SectionedSettingsPanel from "./react/sectionedSettingsPanel";
|
||||
import SettingsPanel from "./react/settingsPanel";
|
||||
import CssEditor from "./react/cssEditor";
|
||||
import ContentColumn from "./react/contentColumn";
|
||||
|
||||
export default new class V2_SettingsPanel {
|
||||
|
||||
constructor() {
|
||||
const self = this;
|
||||
self.sideBarOnClick = self.sideBarOnClick.bind(self);
|
||||
self.onChange = self.onChange.bind(self);
|
||||
self.updateSettings = this.updateSettings.bind(self);
|
||||
self.sidebar = new V2_SettingsPanel_Sidebar(self.sideBarOnClick);
|
||||
}
|
||||
|
||||
get root() {
|
||||
const _root = $("#bd-settingspane-container");
|
||||
if (!_root.length) {
|
||||
if (!this.injectRoot()) return null;
|
||||
return this.root;
|
||||
}
|
||||
return _root[0];
|
||||
}
|
||||
|
||||
injectRoot() {
|
||||
if (!$(".layer-3QrUeG .standardSidebarView-3F1I7i, .layer-3QrUeG .ui-standard-sidebar-view").length) return false;
|
||||
const root = $("<div/>", {
|
||||
"class": "contentRegion-3nDuYy content-region",
|
||||
"id": "bd-settingspane-container"
|
||||
});
|
||||
$(".layer-3QrUeG .standardSidebarView-3F1I7i, .layer-3QrUeG .ui-standard-sidebar-view").append(root);
|
||||
|
||||
Utils.onRemoved(root[0], () => {
|
||||
BDV2.reactDom.unmountComponentAtNode(root[0]);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
get coreSettings() {
|
||||
const settings = this.getSettings("core");
|
||||
const categories = [...new Set(settings.map(s => s.category))];
|
||||
const sections = categories.map(c => {return {title: c, settings: settings.filter(s => s.category == c)};});
|
||||
return sections;
|
||||
}
|
||||
|
||||
get emoteSettings() {
|
||||
return this.getSettings("emote");
|
||||
}
|
||||
getSettings(category) {
|
||||
return Object.keys(settings).reduce((arr, key) => {
|
||||
const setting = settings[key];
|
||||
if (setting.cat === category && setting.implemented && !setting.hidden) {
|
||||
setting.text = key;
|
||||
arr.push(setting);
|
||||
}
|
||||
return arr;
|
||||
}, []);
|
||||
}
|
||||
|
||||
sideBarOnClick(id) {
|
||||
const self = this;
|
||||
$(".contentRegion-3nDuYy, .content-region").first().hide();
|
||||
$(self.root).show();
|
||||
switch (id) {
|
||||
case "core":
|
||||
self.renderCoreSettings();
|
||||
break;
|
||||
case "emotes":
|
||||
self.renderEmoteSettings();
|
||||
break;
|
||||
case "customcss":
|
||||
self.renderCustomCssEditor();
|
||||
break;
|
||||
case "plugins":
|
||||
self.renderPluginPane();
|
||||
break;
|
||||
case "themes":
|
||||
self.renderThemePane();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onClick() {}
|
||||
|
||||
onChange(id, checked) {
|
||||
this.updateSettings(id, checked);
|
||||
}
|
||||
|
||||
updateSettings(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 (enabled) $("body").addClass("bd-minimal");
|
||||
else $("body").removeClass("bd-minimal");
|
||||
}
|
||||
|
||||
if (id == "bda-gs-3") {
|
||||
if (enabled) $("body").addClass("bd-minimal-chan");
|
||||
else $("body").removeClass("bd-minimal-chan");
|
||||
}
|
||||
|
||||
if (id == "bda-gs-1") {
|
||||
if (enabled) publicServersModule.addButton();
|
||||
else publicServersModule.removeButton();
|
||||
}
|
||||
|
||||
if (id == "bda-gs-4") {
|
||||
if (enabled) voiceMode.enable();
|
||||
else voiceMode.disable();
|
||||
}
|
||||
|
||||
if (id == "bda-gs-5") {
|
||||
if (enabled) $("#app-mount").addClass("bda-dark");
|
||||
else $("#app-mount").removeClass("bda-dark");
|
||||
}
|
||||
|
||||
if (enabled && id == "bda-gs-6") coloredText.inject24Hour();
|
||||
|
||||
if (id == "bda-gs-7") {
|
||||
if (enabled) coloredText.injectColoredText();
|
||||
else coloredText.removeColoredText();
|
||||
}
|
||||
|
||||
if (id == "bda-es-4") {
|
||||
if (enabled) emoteModule.autoCapitalize();
|
||||
else emoteModule.disableAutoCapitalize();
|
||||
}
|
||||
|
||||
if (id == "fork-ps-4") {
|
||||
if (enabled) ClassNormalizer.start();
|
||||
else ClassNormalizer.stop();
|
||||
}
|
||||
|
||||
if (id == "fork-ps-5") {
|
||||
if (enabled) {
|
||||
ContentManager.watchContent("plugin");
|
||||
ContentManager.watchContent("theme");
|
||||
}
|
||||
else {
|
||||
ContentManager.unwatchContent("plugin");
|
||||
ContentManager.unwatchContent("theme");
|
||||
}
|
||||
}
|
||||
|
||||
if (id == "fork-wp-1") {
|
||||
// BdApi.setWindowPreference("transparent", enabled);
|
||||
// if (enabled) BdApi.setWindowPreference("backgroundColor", null);
|
||||
// else BdApi.setWindowPreference("backgroundColor", "#2f3136");
|
||||
}
|
||||
|
||||
/*if (_c["fork-wp-2"]) {
|
||||
const current = BdApi.getWindowPreference("frame");
|
||||
if (current != _c["fork-wp-2"]) BdApi.setWindowPreference("frame", _c["fork-wp-2"]);
|
||||
}*/
|
||||
|
||||
|
||||
if (id == "bda-gs-8") {
|
||||
if (enabled) dMode.enable(settingsCookie["fork-dm-1"]);
|
||||
else dMode.disable();
|
||||
}
|
||||
|
||||
if (id == "fork-dm-1") {
|
||||
if (settingsCookie["bda-gs-8"]) dMode.enable(enabled);
|
||||
}
|
||||
|
||||
this.saveSettings();
|
||||
}
|
||||
|
||||
initializeSettings() {
|
||||
|
||||
// if (settingsCookie["bda-gs-b"]) $("body").addClass("bd-blue");
|
||||
if (settingsCookie["bda-gs-2"]) $("body").addClass("bd-minimal");
|
||||
if (settingsCookie["bda-gs-3"]) $("body").addClass("bd-minimal-chan");
|
||||
if (settingsCookie["bda-gs-1"]) publicServersModule.addButton();
|
||||
if (settingsCookie["bda-gs-4"]) voiceMode.enable();
|
||||
if (settingsCookie["bda-gs-5"]) $("#app-mount").addClass("bda-dark");
|
||||
if (settingsCookie["bda-gs-6"]) coloredText.inject24Hour();
|
||||
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-5"]) {
|
||||
ContentManager.watchContent("plugin");
|
||||
ContentManager.watchContent("theme");
|
||||
}
|
||||
|
||||
if (settingsCookie["bda-gs-8"]) dMode.enable(settingsCookie["fork-dm-1"]);
|
||||
|
||||
this.saveSettings();
|
||||
}
|
||||
|
||||
saveSettings() {
|
||||
DataStore.setSettingGroup("settings", settingsCookie);
|
||||
}
|
||||
|
||||
loadSettings() {
|
||||
Object.assign(settingsCookie, DataStore.getSettingGroup("settings"));
|
||||
}
|
||||
|
||||
renderSidebar() {
|
||||
const self = this;
|
||||
$("[class*='side-'] > [class*='item-']").off("click.v2settingspanel").on("click.v2settingspanel", () => {
|
||||
BDV2.reactDom.unmountComponentAtNode(self.root);
|
||||
$(self.root).hide();
|
||||
$(".contentRegion-3nDuYy, .content-region").first().show();
|
||||
});
|
||||
self.sidebar.render();
|
||||
}
|
||||
|
||||
get coreComponent() {
|
||||
return BDV2.react.createElement(Scroller, {contentColumn: true, fade: true, dark: true, children: [
|
||||
BDV2.react.createElement(SectionedSettingsPanel, {key: "cspanel", onChange: this.onChange, sections: this.coreSettings}),
|
||||
BDV2.react.createElement(Tools, {key: "tools"})
|
||||
]});
|
||||
}
|
||||
|
||||
get emoteComponent() {
|
||||
return BDV2.react.createElement(Scroller, {
|
||||
contentColumn: true, fade: true, dark: true, children: [
|
||||
BDV2.react.createElement(SettingsPanel, {key: "espanel", title: "Emote Settings", onChange: this.onChange, settings: this.emoteSettings, button: {
|
||||
title: "Clear Emote Cache",
|
||||
onClick: () => { emoteModule.clearEmoteData(); emoteModule.init(); quickEmoteMenu.init(); }
|
||||
}}),
|
||||
BDV2.react.createElement(Tools, {key: "tools"})
|
||||
]});
|
||||
}
|
||||
|
||||
get customCssComponent() {
|
||||
return BDV2.react.createElement(Scroller, {contentColumn: true, fade: true, dark: true, children: [BDV2.react.createElement(CssEditor, {key: "csseditor"}), BDV2.react.createElement(Tools, {key: "tools"})]});
|
||||
}
|
||||
|
||||
contentComponent(type) {
|
||||
const componentElement = type == "plugins" ? this.pluginsComponent : this.themesComponent;
|
||||
const prefix = type.replace("s", "");
|
||||
const settingsList = this;
|
||||
class ContentList extends BDV2.react.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
BDEvents.on(`${prefix}-reloaded`, this.onChange);
|
||||
BDEvents.on(`${prefix}-loaded`, this.onChange);
|
||||
BDEvents.on(`${prefix}-unloaded`, this.onChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
BDEvents.off(`${prefix}-reloaded`, this.onChange);
|
||||
BDEvents.off(`${prefix}-loaded`, this.onChange);
|
||||
BDEvents.off(`${prefix}-unloaded`, this.onChange);
|
||||
}
|
||||
|
||||
onChange() {
|
||||
settingsList.sideBarOnClick(type);
|
||||
}
|
||||
|
||||
render() {return componentElement;}
|
||||
}
|
||||
return BDV2.react.createElement(ContentList);
|
||||
}
|
||||
|
||||
get pluginsComponent() {
|
||||
const plugins = Object.keys(bdplugins).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())).reduce((arr, key) => {
|
||||
arr.push(BDV2.react.createElement(PluginCard, {key: key, plugin: bdplugins[key].plugin}));return arr;
|
||||
}, []);
|
||||
const list = BDV2.react.createElement(List, {key: "plugin-list", className: "bda-slist", children: plugins});
|
||||
const refreshIcon = !settingsCookie["fork-ps-5"] && BDV2.react.createElement(TooltipWrap(ReloadIcon, {color: "black", side: "top", text: "Reload Plugin List"}), {className: "bd-reload-header", size: "18px", onClick: async () => {
|
||||
pluginModule.updatePluginList();
|
||||
this.sideBarOnClick("plugins");
|
||||
}});
|
||||
const pfBtn = BDV2.react.createElement("button", {key: "folder-button", className: "bd-pfbtn", onClick: () => { require("electron").shell.openItem(ContentManager.pluginsFolder); }}, "Open Plugin Folder");
|
||||
const contentColumn = BDV2.react.createElement(ContentColumn, {key: "pcolumn", title: "Plugins", children: [refreshIcon, pfBtn, list]});
|
||||
return BDV2.react.createElement(Scroller, {contentColumn: true, fade: true, dark: true, children: [contentColumn, BDV2.react.createElement(Tools, {key: "tools"})]});
|
||||
}
|
||||
|
||||
get themesComponent() {
|
||||
const themes = Object.keys(bdthemes).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())).reduce((arr, key) => {
|
||||
arr.push(BDV2.react.createElement(ThemeCard, {key: key, theme: bdthemes[key]}));return arr;
|
||||
}, []);
|
||||
const list = BDV2.react.createElement(List, {key: "theme-list", className: "bda-slist", children: themes});
|
||||
const refreshIcon = !settingsCookie["fork-ps-5"] && BDV2.react.createElement(TooltipWrap(ReloadIcon, {color: "black", side: "top", text: "Reload Theme List"}), {className: "bd-reload-header", size: "18px", onClick: async () => {
|
||||
themeModule.updateThemeList();
|
||||
this.sideBarOnClick("themes");
|
||||
}});
|
||||
const tfBtn = BDV2.react.createElement("button", {key: "folder-button", className: "bd-pfbtn", onClick: () => { require("electron").shell.openItem(ContentManager.themesFolder); }}, "Open Theme Folder");
|
||||
const contentColumn = BDV2.react.createElement(ContentColumn, {key: "tcolumn", title: "Themes", children: [refreshIcon, tfBtn, list]});
|
||||
return BDV2.react.createElement(Scroller, {contentColumn: true, fade: true, dark: true, children: [contentColumn, BDV2.react.createElement(Tools, {key: "tools"})]});
|
||||
}
|
||||
|
||||
renderCoreSettings() {
|
||||
const root = this.root;
|
||||
if (!root) {
|
||||
console.log("FAILED TO LOCATE ROOT: .layer-3QrUeG .standardSidebarView-3F1I7i");
|
||||
return;
|
||||
}
|
||||
BDV2.reactDom.render(this.coreComponent, root);
|
||||
}
|
||||
|
||||
renderEmoteSettings() {
|
||||
const root = this.root;
|
||||
if (!root) {
|
||||
console.log("FAILED TO LOCATE ROOT: .layer-3QrUeG .standardSidebarView-3F1I7i");
|
||||
return;
|
||||
}
|
||||
BDV2.reactDom.render(this.emoteComponent, root);
|
||||
}
|
||||
|
||||
renderCustomCssEditor() {
|
||||
const root = this.root;
|
||||
if (!root) {
|
||||
console.log("FAILED TO LOCATE ROOT: .layer-3QrUeG .standardSidebarView-3F1I7i");
|
||||
return;
|
||||
}
|
||||
BDV2.reactDom.render(this.customCssComponent, root);
|
||||
}
|
||||
|
||||
renderPluginPane() {
|
||||
const root = this.root;
|
||||
if (!root) {
|
||||
console.log("FAILED TO LOCATE ROOT: .layer-3QrUeG .standardSidebarView-3F1I7i");
|
||||
return;
|
||||
}
|
||||
BDV2.reactDom.render(this.contentComponent("plugins"), root);
|
||||
}
|
||||
|
||||
renderThemePane() {
|
||||
const root = this.root;
|
||||
if (!root) {
|
||||
console.log("FAILED TO LOCATE ROOT: .layer-3QrUeG .standardSidebarView-3F1I7i");
|
||||
return;
|
||||
}
|
||||
BDV2.reactDom.render(this.contentComponent("themes"), root);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
import Utils from "./utils";
|
||||
import BDV2 from "./v2";
|
||||
|
||||
import SideBar from "./react/sidebar";
|
||||
|
||||
export default class V2_SettingsPanel_Sidebar {
|
||||
|
||||
constructor(onClick) {
|
||||
this.onClick = onClick;
|
||||
}
|
||||
|
||||
get items() {
|
||||
return [{text: "Settings", id: "core"}, {text: "Emotes", id: "emotes"}, {text: "Plugins", id: "plugins"}, {text: "Themes", id: "themes"}, {text: "Custom CSS", id: "customcss"}];
|
||||
}
|
||||
|
||||
get component() {
|
||||
return BDV2.react.createElement("span", null, BDV2.react.createElement(SideBar, {onClick: this.onClick, headerText: "Bandaged BD", items: this.items}));
|
||||
}
|
||||
|
||||
get root() {
|
||||
const _root = $("#bd-settings-sidebar");
|
||||
if (!_root.length) {
|
||||
if (!this.injectRoot()) return null;
|
||||
return this.root;
|
||||
}
|
||||
return _root[0];
|
||||
}
|
||||
|
||||
injectRoot() {
|
||||
const changeLog = $("[class*='side-'] > [class*='item-']:not([class*=Danger])").last();
|
||||
if (!changeLog.length) return false;
|
||||
$("<span/>", {id: "bd-settings-sidebar"}).insertBefore(changeLog.prev());
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
const root = this.root;
|
||||
if (!root) {
|
||||
console.log("FAILED TO LOCATE ROOT: [class*='side-'] > [class*='item-']:not([class*=Danger])");
|
||||
return;
|
||||
}
|
||||
BDV2.reactDom.render(this.component, root);
|
||||
Utils.onRemoved(root, () => {
|
||||
BDV2.reactDom.unmountComponentAtNode(root);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
import {bdthemeErrors, themeCookie, settingsCookie, bdthemes} from "./0globals";
|
||||
import ContentManager from "./contentManager";
|
||||
import DataStore from "./dataStore";
|
||||
import BDEvents from "./bdEvents";
|
||||
import Utils from "./utils";
|
||||
|
||||
function ThemeModule() {
|
||||
|
||||
}
|
||||
|
||||
ThemeModule.prototype.loadThemes = function () {
|
||||
this.loadThemeData();
|
||||
bdthemeErrors.concat(ContentManager.loadThemes());
|
||||
const themes = Object.keys(bdthemes);
|
||||
|
||||
for (let i = 0; i < themes.length; i++) {
|
||||
const theme = bdthemes[themes[i]];
|
||||
if (!themeCookie[theme.name]) themeCookie[theme.name] = false;
|
||||
if (themeCookie[theme.name]) $("head").append($("<style>", {id: theme.id, text: unescape(theme.css)}));
|
||||
}
|
||||
for (const theme in themeCookie) {
|
||||
if (!bdthemes[theme]) delete themeCookie[theme];
|
||||
}
|
||||
this.saveThemeData();
|
||||
// if (settingsCookie["fork-ps-5"]) ContentManager.watchContent("theme");
|
||||
};
|
||||
|
||||
ThemeModule.prototype.enableTheme = function(name, reload = false) {
|
||||
themeCookie[name] = true;
|
||||
this.saveThemeData();
|
||||
const theme = bdthemes[name];
|
||||
$("head").append($("<style>", {id: theme.id, text: unescape(theme.css)}));
|
||||
if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${theme.name} v${theme.version} has been applied.`);
|
||||
};
|
||||
|
||||
ThemeModule.prototype.disableTheme = function(name, reload = false) {
|
||||
themeCookie[name] = false;
|
||||
this.saveThemeData();
|
||||
const theme = bdthemes[name];
|
||||
$(`#${theme.id}`).remove();
|
||||
if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${theme.name} v${theme.version} has been disabled.`);
|
||||
};
|
||||
|
||||
ThemeModule.prototype.toggleTheme = function(theme) {
|
||||
if (themeCookie[theme]) this.disableTheme(theme);
|
||||
else this.enableTheme(theme);
|
||||
};
|
||||
|
||||
ThemeModule.prototype.loadTheme = function(filename) {
|
||||
const error = ContentManager.loadContent(filename, "theme");
|
||||
if (error) {
|
||||
if (settingsCookie["fork-ps-1"]) Utils.showContentErrors({themes: [error]});
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${filename} could not be loaded. It may not have been loaded.`, {type: "error"});
|
||||
return Utils.err("ContentManager", `${filename} could not be loaded.`, error);
|
||||
}
|
||||
const theme = Object.values(bdthemes).find(p => p.filename == filename);
|
||||
Utils.log("ContentManager", `${theme.name} v${theme.version} was loaded.`);
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${theme.name} v${theme.version} was loaded.`, {type: "success"});
|
||||
BDEvents.dispatch("theme-loaded", theme.name);
|
||||
};
|
||||
|
||||
ThemeModule.prototype.unloadTheme = function(filenameOrName) {
|
||||
const bdtheme = Object.values(bdthemes).find(p => p.filename == filenameOrName) || bdthemes[filenameOrName];
|
||||
if (!bdtheme) return;
|
||||
const theme = bdtheme.name;
|
||||
if (themeCookie[theme]) this.disableTheme(theme, true);
|
||||
const error = ContentManager.unloadContent(bdthemes[theme].filename, "theme");
|
||||
delete bdthemes[theme];
|
||||
if (error) {
|
||||
if (settingsCookie["fork-ps-1"]) Utils.showContentErrors({themes: [error]});
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${theme} could not be unloaded. It may have not been loaded yet.`, {type: "error"});
|
||||
return Utils.err("ContentManager", `${theme} could not be unloaded. It may have not been loaded yet.`, error);
|
||||
}
|
||||
Utils.log("ContentManager", `${theme} was unloaded.`);
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${theme} was unloaded.`, {type: "success"});
|
||||
BDEvents.dispatch("theme-unloaded", theme);
|
||||
};
|
||||
|
||||
ThemeModule.prototype.reloadTheme = function(filenameOrName) {
|
||||
const bdtheme = Object.values(bdthemes).find(p => p.filename == filenameOrName) || bdthemes[filenameOrName];
|
||||
if (!bdtheme) return this.loadTheme(filenameOrName);
|
||||
const theme = bdtheme.name;
|
||||
const error = ContentManager.reloadContent(bdthemes[theme].filename, "theme");
|
||||
if (themeCookie[theme]) this.disableTheme(theme, true), this.enableTheme(theme, true);
|
||||
if (error) {
|
||||
if (settingsCookie["fork-ps-1"]) Utils.showContentErrors({themes: [error]});
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${theme} could not be reloaded.`, {type: "error"});
|
||||
return Utils.err("ContentManager", `${theme} could not be reloaded.`, error);
|
||||
}
|
||||
Utils.log("ContentManager", `${theme} v${bdthemes[theme].version} was reloaded.`);
|
||||
if (settingsCookie["fork-ps-2"]) Utils.showToast(`${theme} v${bdthemes[theme].version} was reloaded.`, {type: "success"});
|
||||
BDEvents.dispatch("theme-reloaded", theme);
|
||||
};
|
||||
|
||||
ThemeModule.prototype.updateThemeList = function() {
|
||||
const results = ContentManager.loadNewContent("theme");
|
||||
for (const filename of results.added) this.loadTheme(filename);
|
||||
for (const name of results.removed) this.unloadTheme(name);
|
||||
};
|
||||
|
||||
ThemeModule.prototype.loadThemeData = function() {
|
||||
const saved = DataStore.getSettingGroup("themes");
|
||||
if (saved) {
|
||||
Object.assign(themeCookie, saved);
|
||||
}
|
||||
};
|
||||
|
||||
ThemeModule.prototype.saveThemeData = function () {
|
||||
DataStore.setSettingGroup("themes", themeCookie);
|
||||
};
|
||||
|
||||
export default new ThemeModule();
|
|
@ -0,0 +1,301 @@
|
|||
export default class Utils {
|
||||
/** Document/window width */
|
||||
static get screenWidth() { return Math.max(document.documentElement.clientWidth, window.innerWidth || 0); }
|
||||
/** Document/window height */
|
||||
static get screenHeight() { return Math.max(document.documentElement.clientHeight, window.innerHeight || 0); }
|
||||
|
||||
static stripBOM(content) {
|
||||
if (content.charCodeAt(0) === 0xFEFF) {
|
||||
content = content.slice(1);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
static getTextArea() {
|
||||
return $(".channelTextArea-rNsIhG textarea");
|
||||
}
|
||||
|
||||
static insertText(textarea, text) {
|
||||
textarea.focus();
|
||||
textarea.selectionStart = 0;
|
||||
textarea.selectionEnd = textarea.value.length;
|
||||
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) {
|
||||
return id.replace(/^[^a-z]+|[^\w-]+/gi, "-");
|
||||
}
|
||||
|
||||
static log(moduleName, message) {
|
||||
console.log(`%c[BandagedBD]%c [${moduleName}]%c ${message}`, "color: #3a71c1; font-weight: 700;", "color: #3a71c1;", "");
|
||||
}
|
||||
|
||||
static warn(moduleName, message) {
|
||||
console.warn(`%c[BandagedBD]%c [${moduleName}]%c ${message}`, "color: #E8A400; font-weight: 700;", "color: #E8A400;", "");
|
||||
}
|
||||
|
||||
static err(moduleName, message, error) {
|
||||
console.log(`%c[BandagedBD]%c [${moduleName}]%c ${message}`, "color: red; font-weight: 700;", "color: red;", "");
|
||||
if (error) {
|
||||
console.groupCollapsed("%cError: " + error.message, "color: red;");
|
||||
console.error(error.stack);
|
||||
console.groupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
static escape(s) {
|
||||
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
||||
}
|
||||
|
||||
static testJSON(data) {
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
}
|
||||
catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static isEmpty(obj) {
|
||||
if (obj == null || obj == undefined || obj == "") return true;
|
||||
if (typeof(obj) !== "object") return false;
|
||||
if (Array.isArray(obj)) return obj.length == 0;
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty(key)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static suppressErrors(method, message) {
|
||||
return (...params) => {
|
||||
try { return method(...params); }
|
||||
catch (e) { this.err("SuppressedError", "Error occurred in " + message, e); }
|
||||
};
|
||||
}
|
||||
|
||||
static monkeyPatch(what, methodName, options) {
|
||||
const {before, after, instead, once = false, silent = false, force = false} = options;
|
||||
const displayName = options.displayName || what.displayName || what[methodName].displayName || what.name || what.constructor.displayName || what.constructor.name;
|
||||
if (!silent) console.log("patch", methodName, "of", displayName); // eslint-disable-line no-console
|
||||
if (!what[methodName]) {
|
||||
if (force) what[methodName] = function() {};
|
||||
else return console.error(methodName, "does not exist for", displayName); // eslint-disable-line no-console
|
||||
}
|
||||
const origMethod = what[methodName];
|
||||
const cancel = () => {
|
||||
if (!silent) console.log("unpatch", methodName, "of", displayName); // eslint-disable-line no-console
|
||||
what[methodName] = origMethod;
|
||||
};
|
||||
what[methodName] = function() {
|
||||
const data = {
|
||||
thisObject: this,
|
||||
methodArguments: arguments,
|
||||
cancelPatch: cancel,
|
||||
originalMethod: origMethod,
|
||||
callOriginalMethod: () => data.returnValue = data.originalMethod.apply(data.thisObject, data.methodArguments)
|
||||
};
|
||||
if (instead) {
|
||||
const tempRet = Utils.suppressErrors(instead, "`instead` callback of " + what[methodName].displayName)(data);
|
||||
if (tempRet !== undefined) data.returnValue = tempRet;
|
||||
}
|
||||
else {
|
||||
if (before) Utils.suppressErrors(before, "`before` callback of " + what[methodName].displayName)(data);
|
||||
data.callOriginalMethod();
|
||||
if (after) Utils.suppressErrors(after, "`after` callback of " + what[methodName].displayName)(data);
|
||||
}
|
||||
if (once) cancel();
|
||||
return data.returnValue;
|
||||
};
|
||||
Object.assign(what[methodName], origMethod);
|
||||
what[methodName].__monkeyPatched = true;
|
||||
what[methodName].displayName = displayName;
|
||||
if (!what[methodName].__originalMethod) {
|
||||
what[methodName].__originalMethod = origMethod;
|
||||
what[methodName].toString = function() {return origMethod.toString();};
|
||||
}
|
||||
return cancel;
|
||||
}
|
||||
|
||||
static onRemoved(node, callback) {
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
for (let m = 0; m < mutations.length; m++) {
|
||||
const mutation = mutations[m];
|
||||
const nodes = Array.from(mutation.removedNodes);
|
||||
const directMatch = nodes.indexOf(node) > -1;
|
||||
const parentMatch = nodes.some(parent => parent.contains(node));
|
||||
if (directMatch || parentMatch) {
|
||||
observer.disconnect();
|
||||
callback();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body, {subtree: true, childList: true});
|
||||
}
|
||||
|
||||
static getNestedProp(obj, path) {
|
||||
return path.split(/\s?\.\s?/).reduce(function(obj, prop) {
|
||||
return obj && obj[prop];
|
||||
}, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* This shows a toast similar to android towards the bottom of the screen.
|
||||
*
|
||||
* @param {string} content The string to show in the toast.
|
||||
* @param {object} options Options object. Optional parameter.
|
||||
* @param {string} options.type Changes the type of the toast stylistically and semantically. Choices: "", "info", "success", "danger"/"error", "warning"/"warn". Default: ""
|
||||
* @param {boolean} options.icon Determines whether the icon should show corresponding to the type. A toast without type will always have no icon. Default: true
|
||||
* @param {number} options.timeout Adjusts the time (in ms) the toast should be shown for before disappearing automatically. Default: 3000
|
||||
*/
|
||||
static showToast(content, options = {}) {
|
||||
// if (!bdConfig.deferLoaded) return;
|
||||
if (!document.querySelector(".bd-toasts")) {
|
||||
const toastWrapper = document.createElement("div");
|
||||
toastWrapper.classList.add("bd-toasts");
|
||||
const boundingElement = document.querySelector(".chat-3bRxxu form, #friends, .noChannel-Z1DQK7, .activityFeed-28jde9");
|
||||
toastWrapper.style.setProperty("left", boundingElement ? boundingElement.getBoundingClientRect().left + "px" : "0px");
|
||||
toastWrapper.style.setProperty("width", boundingElement ? boundingElement.offsetWidth + "px" : "100%");
|
||||
toastWrapper.style.setProperty("bottom", (document.querySelector(".chat-3bRxxu form") ? document.querySelector(".chat-3bRxxu form").offsetHeight : 80) + "px");
|
||||
document.querySelector(".app, .app-2rEoOp").appendChild(toastWrapper);
|
||||
}
|
||||
const {type = "", icon = true, timeout = 3000} = options;
|
||||
const toastElem = document.createElement("div");
|
||||
toastElem.classList.add("bd-toast");
|
||||
if (type) toastElem.classList.add("toast-" + type);
|
||||
if (type && icon) toastElem.classList.add("icon");
|
||||
toastElem.innerText = content;
|
||||
document.querySelector(".bd-toasts").appendChild(toastElem);
|
||||
setTimeout(() => {
|
||||
toastElem.classList.add("closing");
|
||||
setTimeout(() => {
|
||||
toastElem.remove();
|
||||
if (!document.querySelectorAll(".bd-toasts .bd-toast").length) document.querySelector(".bd-toasts").remove();
|
||||
}, 300);
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
alert(title, content) {
|
||||
const modal = $(`<div class="bd-modal-wrapper theme-dark">
|
||||
<div class="bd-backdrop backdrop-1wrmKB"></div>
|
||||
<div class="bd-modal modal-1UGdnR">
|
||||
<div class="bd-modal-inner inner-1JeGVc">
|
||||
<div class="header header-1R_AjF">
|
||||
<div class="title">${title}</div>
|
||||
</div>
|
||||
<div class="bd-modal-body">
|
||||
<div class="scroller-wrap fade">
|
||||
<div class="scroller">
|
||||
${content}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer footer-2yfCgX">
|
||||
<button type="button">Okay</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`);
|
||||
modal.find(".footer button").on("click", () => {
|
||||
modal.addClass("closing");
|
||||
setTimeout(() => { modal.remove(); }, 300);
|
||||
});
|
||||
modal.find(".bd-backdrop").on("click", () => {
|
||||
modal.addClass("closing");
|
||||
setTimeout(() => { modal.remove(); }, 300);
|
||||
});
|
||||
modal.appendTo("#app-mount");
|
||||
}
|
||||
|
||||
showContentErrors({plugins: pluginErrors = [], themes: themeErrors = []}) {
|
||||
if (!pluginErrors || !themeErrors) return;
|
||||
if (!pluginErrors.length && !themeErrors.length) return;
|
||||
const modal = $(`<div class="bd-modal-wrapper theme-dark">
|
||||
<div class="bd-backdrop backdrop-1wrmKB"></div>
|
||||
<div class="bd-modal bd-content-modal modal-1UGdnR">
|
||||
<div class="bd-modal-inner inner-1JeGVc">
|
||||
<div class="header header-1R_AjF"><div class="title">Content Errors</div></div>
|
||||
<div class="bd-modal-body">
|
||||
<div class="tab-bar-container">
|
||||
<div class="tab-bar TOP">
|
||||
<div class="tab-bar-item">Plugins</div>
|
||||
<div class="tab-bar-item">Themes</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-header">
|
||||
<div class="table-column column-name">Name</div>
|
||||
<div class="table-column column-message">Message</div>
|
||||
<div class="table-column column-error">Error</div>
|
||||
</div>
|
||||
<div class="scroller-wrap fade">
|
||||
<div class="scroller">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer footer-2yfCgX">
|
||||
<button type="button">Okay</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`);
|
||||
|
||||
function generateTab(errors) {
|
||||
const container = $(`<div class="errors">`);
|
||||
for (const err of errors) {
|
||||
const error = $(`<div class="error">
|
||||
<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-error"><a class="error-link" href="">${err.error ? err.error.message : ""}</a></div>
|
||||
</div>`);
|
||||
container.append(error);
|
||||
if (err.error) {
|
||||
error.find("a").on("click", (e) => {
|
||||
e.preventDefault();
|
||||
Utils.err("ContentManager", `Error details for ${err.name ? err.name : err.file}.`, err.error);
|
||||
});
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
const tabs = [generateTab(pluginErrors), generateTab(themeErrors)];
|
||||
|
||||
modal.find(".tab-bar-item").on("click", (e) => {
|
||||
e.preventDefault();
|
||||
modal.find(".tab-bar-item").removeClass("selected");
|
||||
$(e.target).addClass("selected");
|
||||
modal.find(".scroller").empty().append(tabs[$(e.target).index()]);
|
||||
});
|
||||
|
||||
modal.find(".footer button").on("click", () => {
|
||||
modal.addClass("closing");
|
||||
setTimeout(() => { modal.remove(); }, 300);
|
||||
});
|
||||
modal.find(".bd-backdrop").on("click", () => {
|
||||
modal.addClass("closing");
|
||||
setTimeout(() => { modal.remove(); }, 300);
|
||||
});
|
||||
modal.appendTo("#app-mount");
|
||||
if (pluginErrors.length) modal.find(".tab-bar-item")[0].click();
|
||||
else modal.find(".tab-bar-item")[1].click();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
import {settings} from "./0globals";
|
||||
|
||||
export default new class V2 {
|
||||
|
||||
constructor() {
|
||||
this.editorDetached = false;
|
||||
this.WebpackModules = (() => {
|
||||
const req = webpackJsonp.push([[], {__extra_id__: (module, exports, req) => module.exports = req}, [["__extra_id__"]]]);
|
||||
delete req.m.__extra_id__;
|
||||
delete req.c.__extra_id__;
|
||||
const find = (filter) => {
|
||||
for (const i in req.c) {
|
||||
if (req.c.hasOwnProperty(i)) {
|
||||
const m = req.c[i].exports;
|
||||
if (m && m.__esModule && m.default && filter(m.default)) return m.default;
|
||||
if (m && filter(m)) return m;
|
||||
}
|
||||
}
|
||||
// console.warn("Cannot find loaded module in cache");
|
||||
return null;
|
||||
};
|
||||
|
||||
const findAll = (filter) => {
|
||||
const modules = [];
|
||||
for (const i in req.c) {
|
||||
if (req.c.hasOwnProperty(i)) {
|
||||
const m = req.c[i].exports;
|
||||
if (m && m.__esModule && m.default && filter(m.default)) modules.push(m.default);
|
||||
else if (m && filter(m)) modules.push(m);
|
||||
}
|
||||
}
|
||||
return modules;
|
||||
};
|
||||
|
||||
const findByUniqueProperties = (propNames) => find(module => propNames.every(prop => module[prop] !== undefined));
|
||||
const findByPrototypes = (protoNames) => find(module => module.prototype && protoNames.every(protoProp => module.prototype[protoProp] !== undefined));
|
||||
const findByDisplayName = (displayName) => find(module => module.displayName === displayName);
|
||||
|
||||
return {find, findAll, findByUniqueProperties, findByPrototypes, findByDisplayName};
|
||||
})();
|
||||
|
||||
this.internal = {
|
||||
react: this.WebpackModules.findByUniqueProperties(["Component", "PureComponent", "Children", "createElement", "cloneElement"]),
|
||||
reactDom: this.WebpackModules.findByUniqueProperties(["findDOMNode"])
|
||||
};
|
||||
this.getInternalInstance = e => e[Object.keys(e).find(k => k.startsWith("__reactInternalInstance"))];
|
||||
}
|
||||
|
||||
initialize() {
|
||||
|
||||
}
|
||||
|
||||
joinBD1() {this.InviteActions.acceptInviteAndTransitionToInviteChannel("0Tmfo5ZbORCRqbAd");}
|
||||
leaveBD1() {this.GuildActions.leaveGuild("86004744966914048");}
|
||||
|
||||
joinBD2() {this.InviteActions.acceptInviteAndTransitionToInviteChannel("2HScm8j");}
|
||||
leaveBD2() {this.GuildActions.leaveGuild("280806472928198656");}
|
||||
|
||||
get react() {return this.internal.react;}
|
||||
get reactDom() {return this.internal.reactDom;}
|
||||
get reactComponent() {return this.internal.react.Component;}
|
||||
|
||||
get anchorClasses() {return this.WebpackModules.findByUniqueProperties(["anchorUnderlineOnHover"]) || {anchor: "anchor-3Z-8Bb", anchorUnderlineOnHover: "anchorUnderlineOnHover-2ESHQB"};}
|
||||
get slateEditorClasses() {return this.WebpackModules.findByUniqueProperties(["slateTextArea"]);}
|
||||
get messageClasses() {return this.WebpackModules.findByUniqueProperties(["message", "containerCozy"]);}
|
||||
get guildClasses() {
|
||||
const guildsWrapper = this.WebpackModules.findByUniqueProperties(["wrapper", "unreadMentionsBar"]);
|
||||
const guilds = this.WebpackModules.findByUniqueProperties(["guildsError", "selected"]);
|
||||
const pill = this.WebpackModules.findByUniqueProperties(["blobContainer"]);
|
||||
return Object.assign({}, guildsWrapper, guilds, pill);
|
||||
}
|
||||
|
||||
get MessageContentComponent() {return this.WebpackModules.find(m => m.defaultProps && m.defaultProps.hasOwnProperty("disableButtons"));}
|
||||
get MessageComponent() {return this.WebpackModules.find(m => m.default && m.default.displayName && m.default.displayName == "Message");}
|
||||
get TimeFormatter() {return this.WebpackModules.findByUniqueProperties(["dateFormat"]);}
|
||||
get TooltipWrapper() {return this.WebpackModules.findByDisplayName("Tooltip");}
|
||||
get NativeModule() {return this.WebpackModules.findByUniqueProperties(["setBadge"]);}
|
||||
get InviteActions() {return this.WebpackModules.findByUniqueProperties(["acceptInvite"]);}
|
||||
get GuildActions() {return this.WebpackModules.findByUniqueProperties(["leaveGuild"]);}
|
||||
get Tooltips() {return this.WebpackModules.find(m => m.hide && m.show && !m.search && !m.submit && !m.search && !m.activateRagingDemon && !m.dismiss);}
|
||||
get KeyGenerator() {return this.WebpackModules.find(m => m.toString && /"binary"/.test(m.toString()));}
|
||||
get LayerStack() {return this.WebpackModules.findByUniqueProperties(["popLayer"]);}
|
||||
get UserStore() {return this.WebpackModules.findByUniqueProperties(["getCurrentUser"]);}
|
||||
get ChannelStore() {return this.WebpackModules.findByUniqueProperties(["getChannel"]);}
|
||||
get ChannelActions() {return this.WebpackModules.findByUniqueProperties(["openPrivateChannel"]);}
|
||||
get PrivateChannelActions() {return this.WebpackModules.findByUniqueProperties(["selectPrivateChannel"]);}
|
||||
|
||||
openDM(userId) {
|
||||
const selfId = this.UserStore.getCurrentUser().id;
|
||||
if (selfId == userId) return;
|
||||
const privateChannelId = this.ChannelStore.getDMFromUserId(userId);
|
||||
if (privateChannelId) return this.PrivateChannelActions.selectPrivateChannel(privateChannelId);
|
||||
this.ChannelActions.openPrivateChannel(selfId, userId);
|
||||
}
|
||||
|
||||
parseSettings(cat) {
|
||||
return Object.keys(settings).reduce((arr, key) => {
|
||||
const setting = settings[key];
|
||||
if (setting.cat === cat && setting.implemented && !setting.hidden) {
|
||||
setting.text = key;
|
||||
arr.push(setting);
|
||||
} return arr;
|
||||
}, []);
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
function VoiceMode() {
|
||||
|
||||
}
|
||||
|
||||
VoiceMode.prototype.enable = function () {
|
||||
$(".scroller.guild-channels ul").first().css("display", "none");
|
||||
$(".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 () {
|
||||
$(".scroller.guild-channels ul").first().css("display", "");
|
||||
$(".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();
|
|
@ -0,0 +1,32 @@
|
|||
const req = webpackJsonp.push([[], {__extra_id__: (module, exports, req) => module.exports = req}, [["__extra_id__"]]]);
|
||||
delete req.m.__extra_id__;
|
||||
delete req.c.__extra_id__;
|
||||
const find = (filter) => {
|
||||
for (const i in req.c) {
|
||||
if (req.c.hasOwnProperty(i)) {
|
||||
const m = req.c[i].exports;
|
||||
if (m && m.__esModule && m.default && filter(m.default)) return m.default;
|
||||
if (m && filter(m)) return m;
|
||||
}
|
||||
}
|
||||
// console.warn("Cannot find loaded module in cache");
|
||||
return null;
|
||||
};
|
||||
|
||||
const findAll = (filter) => {
|
||||
const modules = [];
|
||||
for (const i in req.c) {
|
||||
if (req.c.hasOwnProperty(i)) {
|
||||
const m = req.c[i].exports;
|
||||
if (m && m.__esModule && m.default && filter(m.default)) modules.push(m.default);
|
||||
else if (m && filter(m)) modules.push(m);
|
||||
}
|
||||
}
|
||||
return modules;
|
||||
};
|
||||
|
||||
const findByProps = (...propNames) => find(module => propNames.every(prop => module[prop] !== undefined));
|
||||
const findByPrototypes = (...protoNames) => find(module => module.prototype && protoNames.every(protoProp => module.prototype[protoProp] !== undefined));
|
||||
const findByDisplayName = (displayName) => find(module => module.displayName === displayName);
|
||||
|
||||
export default {find, findAll, findByProps, findByPrototypes, findByDisplayName};
|
|
@ -0,0 +1,59 @@
|
|||
const path = require("path");
|
||||
const CircularDependencyPlugin = require("circular-dependency-plugin");
|
||||
|
||||
module.exports = {
|
||||
mode: "development",
|
||||
target: "node",
|
||||
devtool: "eval-source-map",
|
||||
entry: "./src/index.js",
|
||||
output: {
|
||||
filename: "main.js",
|
||||
path: path.resolve(__dirname, "js"),
|
||||
library: "Core",
|
||||
libraryTarget: "var",
|
||||
libraryExport: "default"
|
||||
},
|
||||
externals: {
|
||||
electron: `require("electron")`,
|
||||
fs: `require("fs")`,
|
||||
path: `require("path")`,
|
||||
request: `require("request")`,
|
||||
events: `require("events")`
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".js", ".jsx"],
|
||||
modules: [
|
||||
path.resolve("src", "builtins"),
|
||||
path.resolve("src", "data"),
|
||||
path.resolve("src", "modules")
|
||||
]
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /.jsx?$/,
|
||||
loader: "babel-loader",
|
||||
exclude: /node_modules/,
|
||||
query: {
|
||||
presets: [["@babel/env", {
|
||||
targets: {
|
||||
node: "12.8.1",
|
||||
chrome: "78"
|
||||
}
|
||||
}], "@babel/react"]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new CircularDependencyPlugin({
|
||||
// exclude detection of files based on a RegExp
|
||||
exclude: /a\.js|node_modules/,
|
||||
// add errors to webpack instead of warnings
|
||||
// failOnError: true,
|
||||
// set the current working directory for displaying module paths
|
||||
cwd: process.cwd(),
|
||||
})
|
||||
]
|
||||
|
||||
};
|
Loading…
Reference in New Issue