Cleaning BD and fixing bugs

This commit is contained in:
Jean Ouina 2020-07-28 18:55:37 +02:00
parent 45ac98cb2d
commit 84923849b3
23 changed files with 1423 additions and 3020 deletions

View File

@ -1,165 +1,168 @@
# Disclaimer
BandagedBD from Lightcord is a fork from the original BandagedBD (https://github.com/rauenzi/BetterDiscordApp).
If a bug happens on the lightcord version, please report on Lightcord repo. If it applies as well on BandagedBD, please report it too on https://github.com/rauenzi/BetterDiscordApp/issues.
Lightcord does not own the code at https://github.com/rauenzi/BetterDiscordApp. It only owns the modifications that were added here.
# BandagedBD [![Patreon][patreon-badge]][patreon-link] [![Paypal][paypal-badge]][paypal-link]
[patreon-badge]: https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.herokuapp.com%2FZerebos&style=flat-square
[patreon-link]: https://patreon.com/Zerebos
[paypal-badge]: https://img.shields.io/badge/Paypal-Donate!-%2300457C.svg?logo=paypal&style=flat-square
[paypal-link]: https://paypal.me/ZackRauen
BandagedBD (Bandaged BetterDiscord) is a fork of the original [BetterDiscord](https://github.com/Jiiks/BetterDiscordApp) by Jiiks. This has a number of improvements over the original. The original version has been unmaintained hence this fork existing. There have been attempts to rewrite the original that I have been and will continue to be involved in, but in the meantime I will continue to maintain and improve BBD.
# Installation
## Auto Installers
### Windows
Grab the `exe` file from [here](https://github.com/rauenzi/BetterDiscordApp/releases/latest/download/BandagedBD_Windows.exe).
### macOS/OS X
Grab the `zip` file from [here](https://github.com/rauenzi/BetterDiscordApp/releases/latest/download/BandagedBD_Mac.zip).
### Linux
See this [gist](https://gist.github.com/ObserverOfTime/d7e60eb9aa7fe837545c8cb77cf31172).
## Manual Installation
### Windows
1. Download and extract this: https://github.com/rauenzi/BetterDiscordApp/archive/injector.zip
2. Rename `BetterDiscordApp-injector` to `app`.
3. Go to `%localappdata%\Discord\`, and locate the directory with the largest version number (e.g. `app-0.0.306`).
4. Within `app-0.0.306` navigate to `resources`.
5. If an `app` folder already exists inside `resources`, delete it.
6. Move the `app` folder (the one you downloaded and renamed) inside of `resources`.
7. Fully quit Discord and restart it.
### macOS/OS X
1. Download and extract this: https://github.com/rauenzi/BetterDiscordApp/archive/injector.zip
2. Rename `BetterDiscordApp-injector` to `app`.
3. Go to `/Applications/`, right click `Discord.app` and select `Show Package Contents`.
4. Within `Discord.app` navigate to `Contents` -> `Resources`.
5. If an `app` folder already exists inside `Resources`, delete it.
6. Move the `app` folder (the one you downloaded and renamed) inside of `Resources`.
7. Fully quit Discord and restart it.
# FAQ
### What is this?
This is a client modification for Discord. It allows you to add plugins and themes to your client. Plugins can add functionality and useful features. Themes can completely change the look and feel of Discord.
BBD has some other built-in features such as Emotes from Twitch, FFZ, and BBTV, as well as an in-client server browser.
### Where can I get plugins and themes?
In our support servers we have channels with lists of official plugins and themes. Please note we do not have an official listing on a website and are **not affiliated with any of those websites**.
### Support Servers?
There are two: [The main server](https://discord.gg/0Tmfo5ZbORCRqbAd), and [the backup](https://discord.gg/2HScm8j).
# Supporters
These people have all subscribed to the `True Supporter` tier on Patreon to support BandagedBD.
<table>
<tr>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/196098063092154368/90f1a7202955dac7a6c685cca3181ab1.webp" width="100px;" alt="Kraken"/><br />
<strong>Kraken</strong><br />
</td>
<td align="center">
<img src="https://cdn.discordapp.com/attachments/585514483699417089/585552300354043915/34959069_500_500.jpg" width="100px;" alt="SPHHAX"/><br />
<a href="http://sphh.ax/" target="_blank" rel="noreferrer noopener"><strong>SPHHAX</strong></a><br />
</td>
<td align="center">
<img src="https://cdn.discordapp.com/attachments/622954403262889995/622957122765848587/5364774.jpg" width="100px;" alt="DefCon42"/><br />
<a href="https://twitter.com/def_con42" target="_blank" rel="noreferrer noopener"><strong>DefCon42</strong></a><br />
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/629231564261425163/a_36cc7d2940b4ffb8a660b1076ab2087f.webp" width="100px;" alt="Justxn"/><br />
<strong>Justxn</strong><br />
</td>
<td align="center">
<img src="https://cdn.discordapp.com/attachments/682750073448169513/682763113296429087/definitely_not_the_dick_police.png" width="100px;" alt="monkey"/><br />
<a href="https://heartunderbla.de" target="_blank" rel="noreferrer noopener"><strong>monkey</strong></a><br />
</td>
</tr>
</table>
# Bandagers
These people have all subscribed to the `Bandager` tier on Patreon to support BandagedBD.
<table>
<tr>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/332199319169925120/4709f8f0c9cb7ababd85459bf71848b9.png" width="50px;" alt="William JCM"/><br />
<a href="https://github.com/williamjcm" target="_blank" rel="noreferrer noopener"><strong>William JCM</strong></a>
</td>
<td align="center">
<img src="https://avatars0.githubusercontent.com/u/24623601" width="50px;" alt="NFLD99"/><br />
<a href="https://github.com/NFLD99" target="_blank" rel="noreferrer noopener"><strong>NFLD99</strong></a>
</td>
<td align="center">
<img src="https://avatars3.githubusercontent.com/u/20338746?s=460&u=d9ebab4f6f0f5221390bca1eaf8f191acd275afe&v=4" width="50px;" alt="Gibbu"/><br />
<a href="https://github.com/Gibbu" target="_blank" rel="noreferrer noopener"><strong>Gibbu</strong></a>
</td>
<td align="center">
<img src="https://i.postimg.cc/5NVxqMnb/Cute-Squid-Circle.png" width="50px;" alt="Tenuit"/><br />
<strong>Tenuit</strong>
</td>
</tr>
</table>
# Donors
These people have either donated or subscribed to the most basic patron tier to support BandagedBD.
<table>
<tr>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/284122164582416385/ebaa1b63191ce70e48ae24f32f452773.webp" width="25px;" /><br />
<strong>aetheryx</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/216782345779281921/d4b651b606f108cd2f96a19af68f942f.png" width="25px;" /><br />
<strong>JBeauDee</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/261673576216789004/31d590fb92329e270a6225a13d500c1d.png" width="25px;" /><br />
<strong>vantiss</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/122204411962327043/7f44a9b036b9e2691f4e81d9e34a78b4.webp" width="25px;" /><br />
<strong>xstefen</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/219400174869413888/7c88015869990ba97b614b1ac784f8e8.png" width="25px;" /><br />
<strong>『Sorey』</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/95263213842608128/5024b83e1bff3096d7fc93e8de09d582.gif" width="25px;" /><br />
<strong>LiVeR</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/144458450192171008/13a3e66d73d216974504b8aad257b7b4.png" width="25px;" /><br />
<strong>SweetLilyCake</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/398951709336010793/eb6f63eb2f3a5102fb900e60d1a26cdc.png" width="25px;" /><br />
<strong>GameKuchen</strong>
</td>
<td align="center">
<img src="https://i.imgur.com/qrWcKfH.png" width="25px;" /><br />
<strong>Lozo</strong>
</td>
<td align="center">
<img src="https://media.discordapp.net/attachments/575576868166828032/692136786893340752/pfp.gif" width="25px;" /><br />
<strong>Akira</strong>
</td>
</tr>
</table>
# Disclaimer
BandagedBD from Lightcord is a fork from the original BandagedBD (https://github.com/rauenzi/BetterDiscordApp).
If a bug happens on the lightcord version, please report on Lightcord repo. If it applies as well on BandagedBD, please report it too on https://github.com/rauenzi/BetterDiscordApp/issues.
Lightcord does not own the code at https://github.com/rauenzi/BetterDiscordApp. It only owns the modifications that were added here.
# BandagedBD [![Patreon][patreon-badge]][patreon-link] [![Paypal][paypal-badge]][paypal-link]
[patreon-badge]: https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.herokuapp.com%2FZerebos&style=flat-square
[patreon-link]: https://patreon.com/Zerebos
[paypal-badge]: https://img.shields.io/badge/Paypal-Donate!-%2300457C.svg?logo=paypal&style=flat-square
[paypal-link]: https://paypal.me/ZackRauen
BandagedBD (Bandaged BetterDiscord) is a fork of the original [BetterDiscord](https://github.com/Jiiks/BetterDiscordApp) by Jiiks. This has a number of improvements over the original. The original version has been unmaintained hence this fork existing. There have been attempts to rewrite the original that I have been and will continue to be involved in, but in the meantime I will continue to maintain and improve BBD.
# Installation
## Auto Installers
### Windows
Grab the `exe` file from [here](https://github.com/rauenzi/BetterDiscordApp/releases/latest/download/BandagedBD_Windows.exe).
### macOS/OS X
Grab the `zip` file from [here](https://github.com/rauenzi/BetterDiscordApp/releases/latest/download/BandagedBD_Mac.zip).
### Linux
See this [gist](https://gist.github.com/ObserverOfTime/d7e60eb9aa7fe837545c8cb77cf31172).
## Manual Installation
### Windows
1. Download and extract this: https://github.com/rauenzi/BetterDiscordApp/archive/injector.zip
2. Rename `BetterDiscordApp-injector` to `app`.
3. Go to `%localappdata%\Discord\`, and locate the directory with the largest version number (e.g. `app-0.0.306`).
4. Within `app-0.0.306` navigate to `resources`.
5. If an `app` folder already exists inside `resources`, delete it.
6. Move the `app` folder (the one you downloaded and renamed) inside of `resources`.
7. Fully quit Discord and restart it.
### macOS/OS X
1. Download and extract this: https://github.com/rauenzi/BetterDiscordApp/archive/injector.zip
2. Rename `BetterDiscordApp-injector` to `app`.
3. Go to `/Applications/`, right click `Discord.app` and select `Show Package Contents`.
4. Within `Discord.app` navigate to `Contents` -> `Resources`.
5. If an `app` folder already exists inside `Resources`, delete it.
6. Move the `app` folder (the one you downloaded and renamed) inside of `Resources`.
7. Fully quit Discord and restart it.
# FAQ
### What is this?
This is a client modification for Discord. It allows you to add plugins and themes to your client. Plugins can add functionality and useful features. Themes can completely change the look and feel of Discord.
BBD has some other built-in features such as Emotes from Twitch, FFZ, and BBTV, as well as an in-client server browser.
### Where can I get plugins and themes?
In our support servers we have channels with lists of official plugins and themes. Please note we do not have an official listing on a website and are **not affiliated with any of those websites**.
### Support Servers?
There are two: [The main server](https://discord.gg/0Tmfo5ZbORCRqbAd), and [the backup](https://discord.gg/2HScm8j).
# Supporters
These people have all subscribed to the `True Supporter` tier on Patreon to support BandagedBD.
<table>
<tr>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/196098063092154368/90f1a7202955dac7a6c685cca3181ab1.webp" width="100px;" alt="Kraken"/><br />
<strong>Kraken</strong><br />
</td>
<td align="center">
<img src="https://cdn.discordapp.com/attachments/585514483699417089/585552300354043915/34959069_500_500.jpg" width="100px;" alt="SPHHAX"/><br />
<a href="http://sphh.ax/" target="_blank" rel="noreferrer noopener"><strong>SPHHAX</strong></a><br />
</td>
<td align="center">
<img src="https://cdn.discordapp.com/attachments/622954403262889995/622957122765848587/5364774.jpg" width="100px;" alt="DefCon42"/><br />
<a href="https://twitter.com/def_con42" target="_blank" rel="noreferrer noopener"><strong>DefCon42</strong></a><br />
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/629231564261425163/a_36cc7d2940b4ffb8a660b1076ab2087f.webp" width="100px;" alt="Justxn"/><br />
<strong>Justxn</strong><br />
</td>
<td align="center">
<img src="https://cdn.discordapp.com/attachments/682750073448169513/682763113296429087/definitely_not_the_dick_police.png" width="100px;" alt="monkey"/><br />
<a href="https://heartunderbla.de" target="_blank" rel="noreferrer noopener"><strong>monkey</strong></a><br />
</td>
<td align="center">
<img src="https://avatars3.githubusercontent.com/u/20338746?s=460&u=d9ebab4f6f0f5221390bca1eaf8f191acd275afe&v=4" width="100px;" alt="Gibbu"/><br />
<a href="https://github.com/Gibbu" target="_blank" rel="noreferrer noopener"><strong>Gibbu</strong></a>
</td>
<td align="center">
<img src="https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/25717114/c100599e58174499b44b4307c26f9312/1.jpeg" width="100px;" alt="Orekieh"/><br />
<strong>Orekieh</strong>
</td>
</tr>
</table>
# Bandagers
These people have all subscribed to the `Bandager` tier on Patreon to support BandagedBD.
<table>
<tr>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/332199319169925120/4709f8f0c9cb7ababd85459bf71848b9.png" width="50px;" alt="William JCM"/><br />
<a href="https://github.com/williamjcm" target="_blank" rel="noreferrer noopener"><strong>William JCM</strong></a>
</td>
<td align="center">
<img src="https://avatars0.githubusercontent.com/u/24623601" width="50px;" alt="NFLD99"/><br />
<a href="https://github.com/NFLD99" target="_blank" rel="noreferrer noopener"><strong>NFLD99</strong></a>
</td>
<td align="center">
<img src="https://i.postimg.cc/5NVxqMnb/Cute-Squid-Circle.png" width="50px;" alt="Tenuit"/><br />
<strong>Tenuit</strong>
</td>
</tr>
</table>
# Donors
These people have either donated or subscribed to the most basic patron tier to support BandagedBD.
<table>
<tr>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/284122164582416385/ebaa1b63191ce70e48ae24f32f452773.webp" width="25px;" /><br />
<strong>aetheryx</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/216782345779281921/d4b651b606f108cd2f96a19af68f942f.png" width="25px;" /><br />
<strong>JBeauDee</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/261673576216789004/31d590fb92329e270a6225a13d500c1d.png" width="25px;" /><br />
<strong>vantiss</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/122204411962327043/7f44a9b036b9e2691f4e81d9e34a78b4.webp" width="25px;" /><br />
<strong>xstefen</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/219400174869413888/7c88015869990ba97b614b1ac784f8e8.png" width="25px;" /><br />
<strong>『Sorey』</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/95263213842608128/5024b83e1bff3096d7fc93e8de09d582.gif" width="25px;" /><br />
<strong>LiVeR</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/144458450192171008/13a3e66d73d216974504b8aad257b7b4.png" width="25px;" /><br />
<strong>SweetLilyCake</strong>
</td>
<td align="center">
<img src="https://cdn.discordapp.com/avatars/398951709336010793/eb6f63eb2f3a5102fb900e60d1a26cdc.png" width="25px;" /><br />
<strong>GameKuchen</strong>
</td>
<td align="center">
<img src="https://i.imgur.com/qrWcKfH.png" width="25px;" /><br />
<strong>Lozo</strong>
</td>
<td align="center">
<img src="https://media.discordapp.net/attachments/575576868166828032/692136786893340752/pfp.gif" width="25px;" /><br />
<strong>Akira</strong>
</td>
</tr>
</table>

File diff suppressed because one or more lines are too long

View File

@ -35,8 +35,5 @@
"gulp-rename": "^2.0.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
},
"dependencies": {
"react": "^16.13.1"
}
}

View File

@ -1,3 +0,0 @@
console.log("lalalalala gettoken() email 2fa")
const token

View File

@ -1,45 +1,9 @@
import { remote } from "electron"
import BDV2 from "./modules/v2";
import WebpackModules from "./modules/webpackModules";
export const minimumDiscordVersion = "0.0.306";
export const currentDiscordVersion = (window.DiscordNative && window.DiscordNative.remoteApp && window.DiscordNative.remoteApp.getVersion && window.DiscordNative.remoteApp.getVersion()) || "0.0.306";
export const minSupportedVersion = "0.3.0";
export const bbdVersion = "0.3.5";
/*
export const LCChanelog = {
description: "Lightcord's changelog",
changes: [
{
title: "What's New?",
items: [
"Lightcord is now available !",
"We removed emotes. That's sad for people who were actually using it, but it was leading to more loading time and some basic words were emote."
]
}
],
image: "https://i.imgur.com/sfNhqwP.png",
title: "Lightcord",
subtitle: "v"+remote.getGlobal("BuildInfo").version,
footer: (function(){
const TextElement = WebpackModules.findByDisplayName("Text");
const ModalStack = WebpackModules.findByProps("push", "update", "pop", "popWithKey");
if(!TextElement || !ModalStack)return null
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.joinLC();
};
const supportLink = Anchor ? BDV2.React.createElement(Anchor, {onClick: joinSupportServer}, "Join our Discord Server.") : BDV2.React.createElement("a", {className: `${AnchorClasses.anchor} ${AnchorClasses.anchorUnderlineOnHover}`, onClick: joinSupportServer}, "Join our Discord Server.");
return BDV2.React.createElement(TextElement, {size: TextElement.Sizes.SMALL, color: TextElement.Colors.STANDARD}, "Need support? ", supportLink);
})()
}*/
export const bbdChangelog = {
description: "BBD's changelog.",
description: "Big things are coming.",
changes: [
{
title: "Bug Fixes",
@ -111,7 +75,7 @@ export const defaultCookie = {
"bda-gs-5": true,
"bda-gs-6": false,
"bda-gs-7": false,
"bda-gs-8": true,
"bda-gs-8": false,
"bda-es-0": true,
"bda-es-1": true,
"bda-es-2": true,

View File

@ -1,254 +1,254 @@
import {pluginCookie, themeCookie, bdplugins, bdthemes, settingsCookie, settings} from "../0globals";
import mainCore from "./core";
import Utils from "./utils";
import BDV2 from "./v2";
import DataStore from "./dataStore";
import pluginModule from "./pluginModule";
import themeModule from "./themeModule";
import settingsPanel from "./settingsPanel";
import DOM from "./domtools";
const BdApi = {
get React() { return BDV2.React; },
get ReactDOM() { return BDV2.ReactDom; },
get ReactComponent() {return BDV2.ReactComponent;},
get WindowConfigFile() {return Utils.WindowConfigFile;},
get settings() {return settings;},
get emotes() {return {}}, // deprecated, deleted all emotes from betterdiscord.
get screenWidth() { return Math.max(document.documentElement.clientWidth, window.innerWidth || 0); },
get screenHeight() { return Math.max(document.documentElement.clientHeight, window.innerHeight || 0); }
};
BdApi.getAllWindowPreferences = function() {
return Utils.getAllWindowPreferences();
};
BdApi.getWindowPreference = function(key) {
return Utils.getWindowPreference(key);
};
BdApi.setWindowPreference = function(key, value) {
return Utils.setWindowPreference(key, value);
};
//Inject CSS to document head
//id = id of element
//css = custom css
BdApi.injectCSS = function (id, css) {
DOM.addStyle(DOM.escapeID(id), css);
};
//Clear css/remove any element
//id = id of element
BdApi.clearCSS = function (id) {
DOM.removeStyle(DOM.escapeID(id));
};
//Inject CSS to document head
//id = id of element
//css = custom css
BdApi.linkJS = function (id, url) {
DOM.addScript(DOM.escapeID(id), url);
};
//Clear css/remove any element
//id = id of element
BdApi.unlinkJS = function (id) {
DOM.removeScript(DOM.escapeID(id));
};
//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 () {
Utils.warn("Deprecation Notice", `BdApi.getCore() will be removed in future versions.`);
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) {
return Utils.showConfirmationModal(title, content, {cancelText: null});
};
/**
* 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. Every string is wrapped in Discord's `Markdown` 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
* @param {string} [options.key] - key used to identify the modal. If not provided, one is generated and returned
* @returns {string} - the key used for this modal
*/
BdApi.showConfirmationModal = function (title, content, options = {}) {
return Utils.showConfirmationModal(title, content, options);
};
//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];
};
BdApi.enableSetting = function(id) {
return settingsPanel.onChange(id, true);
};
BdApi.disableSetting = function(id) {
return settingsPanel.onChange(id, false);
};
BdApi.toggleSetting = function(id) {
return settingsPanel.onChange(id, !settingsCookie[id]);
};
// Gets data
BdApi.getBDData = function(key) {
return DataStore.getBDData(key);
};
// Sets data
BdApi.setBDData = function(key, data) {
return DataStore.setBDData(key, data);
};
const makeAddonAPI = (cookie, list, manager) => new class AddonAPI {
get folder() {return manager.folder;}
isEnabled(name) {
return !!cookie[name];
}
enable(name) {
return manager.enable(name);
}
disable(name) {
return manager.disable(name);
}
toggle(name) {
if (cookie[name]) this.disable(name);
else this.enable(name);
}
reload(name) {
return manager.reload(name);
}
get(name) {
if (list.hasOwnProperty(name)) {
if (list[name].plugin) return list[name].plugin;
return list[name];
}
return null;
}
getAll() {
return Object.keys(list).map(k => this.get(k)).filter(a => a);
}
};
BdApi.Plugins = makeAddonAPI(pluginCookie, bdplugins, pluginModule);
BdApi.Themes = makeAddonAPI(themeCookie, bdthemes, themeModule);
export default BdApi;
import {pluginCookie, themeCookie, bdplugins, bdthemes, settingsCookie, settings} from "../0globals";
import mainCore from "./core";
import Utils from "./utils";
import BDV2 from "./v2";
import DataStore from "./dataStore";
import pluginModule from "./pluginModule";
import themeModule from "./themeModule";
import settingsPanel from "./settingsPanel";
import DOM from "./domtools";
const BdApi = {
get React() { return BDV2.React; },
get ReactDOM() { return BDV2.ReactDom; },
get ReactComponent() {return BDV2.ReactComponent;},
get WindowConfigFile() {return Utils.WindowConfigFile;},
get settings() {return settings;},
get emotes() {return null}, // deprecated, deleted all emotes from betterdiscord.
get screenWidth() { return Math.max(document.documentElement.clientWidth, window.innerWidth || 0); },
get screenHeight() { return Math.max(document.documentElement.clientHeight, window.innerHeight || 0); }
};
BdApi.getAllWindowPreferences = function() {
return Utils.getAllWindowPreferences();
};
BdApi.getWindowPreference = function(key) {
return Utils.getWindowPreference(key);
};
BdApi.setWindowPreference = function(key, value) {
return Utils.setWindowPreference(key, value);
};
//Inject CSS to document head
//id = id of element
//css = custom css
BdApi.injectCSS = function (id, css) {
DOM.addStyle(DOM.escapeID(id), css);
};
//Clear css/remove any element
//id = id of element
BdApi.clearCSS = function (id) {
DOM.removeStyle(DOM.escapeID(id));
};
//Inject CSS to document head
//id = id of element
//css = custom css
BdApi.linkJS = function (id, url) {
DOM.addScript(DOM.escapeID(id), url);
};
//Clear css/remove any element
//id = id of element
BdApi.unlinkJS = function (id) {
DOM.removeScript(DOM.escapeID(id));
};
//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 () {
Utils.warn("Deprecation Notice", `BdApi.getCore() will be removed in future versions.`);
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) {
return Utils.showConfirmationModal(title, content, {cancelText: null});
};
/**
* 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. Every string is wrapped in Discord's `Markdown` 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
* @param {string} [options.key] - key used to identify the modal. If not provided, one is generated and returned
* @returns {string} - the key used for this modal
*/
BdApi.showConfirmationModal = function (title, content, options = {}) {
return Utils.showConfirmationModal(title, content, options);
};
//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];
};
BdApi.enableSetting = function(id) {
return settingsPanel.onChange(id, true);
};
BdApi.disableSetting = function(id) {
return settingsPanel.onChange(id, false);
};
BdApi.toggleSetting = function(id) {
return settingsPanel.onChange(id, !settingsCookie[id]);
};
// Gets data
BdApi.getBDData = function(key) {
return DataStore.getBDData(key);
};
// Sets data
BdApi.setBDData = function(key, data) {
return DataStore.setBDData(key, data);
};
const makeAddonAPI = (cookie, list, manager) => new class AddonAPI {
get folder() {return manager.folder;}
isEnabled(name) {
return !!cookie[name];
}
enable(name) {
return manager.enable(name);
}
disable(name) {
return manager.disable(name);
}
toggle(name) {
if (cookie[name]) this.disable(name);
else this.enable(name);
}
reload(name) {
return manager.reload(name);
}
get(name) {
if (list.hasOwnProperty(name)) {
if (list[name].plugin) return list[name].plugin;
return list[name];
}
return null;
}
getAll() {
return Object.keys(list).map(k => this.get(k)).filter(a => a);
}
};
BdApi.Plugins = makeAddonAPI(pluginCookie, bdplugins, pluginModule);
BdApi.Themes = makeAddonAPI(themeCookie, bdthemes, themeModule);
export default BdApi;
window.Lightcord.BetterDiscord.BdApi = BdApi

View File

@ -1,6 +1,5 @@
/* BDEvents */
const EventEmitter = require("events");
export default new class BDEvents extends EventEmitter {
constructor(){
super()

View File

@ -2,10 +2,8 @@ import {bdConfig, bdplugins, bdthemes, settingsCookie} from "../0globals";
import pluginModule from "./pluginModule";
import themeModule from "./themeModule";
import Utils from "./utils";
import * as crypto from "crypto"
import dataStore from "./dataStore";
import pluginCertifier, { encryptSettingsCache, decryptSettingsCache, processFile } from "./pluginCertifier";
import { captureRejectionSymbol } from "events";
import { encryptSettingsCache, decryptSettingsCache, processFile } from "./pluginCertifier";
const path = require("path");
const fs = require("fs");

View File

@ -19,14 +19,9 @@ import {remote as electron} from "electron"
import v2 from "./v2";
import contentManager from "./contentManager";
const {ipcRenderer} = require("electron");
function Core() {
// Object.assign(bdConfig, __non_webpack_require__(DataStore.configFile));
// this.init();
}
let methods
function Core() {}
Core.prototype.setConfig = function(config) {
if (this.hasStarted) return;
@ -70,28 +65,6 @@ Core.prototype.init = async function() {
Utils.suppressErrors(this.patchAttributes.bind(this), "LC Plugin Certifier Patch")();
/*
const latestLocalVersion = bdConfig.updater ? bdConfig.updater.LatestVersion : bdConfig.latestVersion;
if (latestLocalVersion > bdConfig.version) {
Utils.showConfirmationModal("Update Available", [`There is an update available for BandagedBD's Injector (${latestLocalVersion}).`, "You can either update and restart now, or later."], {
confirmText: "Update Now",
cancelText: "Maybe Later",
onConfirm: async () => {
const onUpdateFailed = () => {Utils.alert("Could Not Update", `Unable to update automatically, please download the installer and reinstall normally.<br /><br /><a href='https://github.com/rauenzi/BetterDiscordApp/releases/latest' target='_blank'>Download Installer</a>`);};
try {
const didUpdate = await this.updateInjector();
if (!didUpdate) return onUpdateFailed();
const app = require("electron").remote.app;
app.relaunch();
app.exit();
}
catch (err) {
onUpdateFailed();
}
}
});
}*/
Utils.log("Startup", "Initializing Settings");
this.initSettings();
@ -673,15 +646,20 @@ Core.prototype.patchMemberList = function() {
};
Core.prototype.updateInjector = async function() {
// There will never be an injection path, so we do not need the code below.
// Insert comments so it will be erased when production.
const injectionPath = DataStore.injectionPath;
if (!injectionPath) return false;
/*
const fs = require("fs");
const path = require("path");
const rmrf = require("rimraf");
const yauzl = require("yauzl");
const mkdirp = require("mkdirp");
const request = /*require("request");*/ null
const request = require("request");
const parentPath = path.resolve(injectionPath, "..");
const folderName = path.basename(injectionPath);
@ -755,7 +733,7 @@ Core.prototype.updateInjector = async function() {
await new Promise(resolve => fs.unlink(savedZip, resolve));
Utils.log("InjectorUpdate", "Injector Updated!");
return success;
return success;*/
};
export default new Core();

View File

@ -1,6 +1,5 @@
const __non_webpack_require__ = window.require
import {bdConfig} from "../0globals";
import Utils from "./utils";
import ContentManager from "./contentManager";

View File

@ -1,175 +1,161 @@
import {settingsCookie} from "../0globals";
import BDV2 from "./v2";
import DOM from "./domtools";
import Utils from "./utils";
export default new class DevMode {
constructor() {
this.debugListener = this.debugListener.bind(this);
this.copySelectorListener = this.copySelectorListener.bind(this);
}
start() {
this.startDebugListener();
if (settingsCookie["fork-dm-1"]) this.startCopySelector();
}
stop() {
this.stopDebugListener();
this.stopCopySelector();
}
startDebugListener() {
this.stopDebugListener();
document.addEventListener("keydown", this.debugListener);
}
stopDebugListener() {
document.removeEventListener("keydown", this.debugListener);
}
startCopySelector() {
this.stopCopySelector();
document.addEventListener("contextmenu", this.copySelectorListener);
}
stopCopySelector() {
document.removeEventListener("contextmenu", this.copySelectorListener);
}
debugListener(e) {
if (e.which === 119 || e.which == 118) {//F8
console.log("%c[%cDevMode%c] %cBreak/Resume", "color: red;", "color: #303030; font-weight:700;", "color:red;", "");
debugger; // eslint-disable-line no-debugger
e.preventDefault();
e.stopImmediatePropagation();
}
}
copySelectorListener(e) {
try{
e.stopPropagation();
const selector = this.getSelector(e.target);
let [
classLayer,
classItems
] = [
BDModules.get((e) => e.layer && typeof e.layer === "string" && e.disabledPointerEvents)[0],
BDModules.get((e) => e.menu)[0]
]
function attach() {
if(!classItems || !classLayer.layer)return console.log(classItems, classLayer.layer)
let cm = DOM.query("."+Utils.removeDa(classItems.menu));
if (!cm) {
const container = DOM.query("#app-mount > ."+Utils.removeDa(classLayer.layerContainer));
const cmWrap = DOM.createElement(`<div class="${classLayer.layer}">`);
cm = DOM.createElement(`<div class="${classItems.menu} ${classItems.styleFlexible} ${classItems.accommodateScrollbar} bd-context-menu" style=""></div>`);
cmWrap.append(cm);
container.append(cmWrap);
cmWrap.style.top = e.clientY + "px";
cmWrap.style.left = e.clientX + "px";
cmWrap.setAttribute("role", "menu")
cmWrap.setAttribute("tabindex", "-1")
cmWrap.id = "bd-copy-selector-context"
cmWrap.setAttribute("aria-label", "Copy Selector Actions")
const scrollerClasses = BDModules.get((e) => e.scrollerWrap)[0]
const scrollerWrap = DOM.createElement(`<div class="${scrollerClasses.scrollerWrap} ${scrollerClasses.scrollerThemed} ${scrollerClasses.themeGhostHairline}"></div>`)
const scroller = DOM.createElement(`<div class="${BDModules.get(e => e.scroller)[0].scroller} ${classItems.scroller}"></div>`)
scrollerWrap.append(scroller)
cm.append(scrollerWrap)
const removeCM = function(e) {
if (e.keyCode && e.keyCode !== 27) return;
cmWrap.remove();
document.removeEventListener("click", removeCM);
document.removeEventListener("contextmenu", removeCM);
document.removeEventListener("keyup", removeCM);
};
document.addEventListener("click", removeCM);
document.addEventListener("contextmenu", removeCM);
document.addEventListener("keyup", removeCM);
}
const cmWrap = cm.parentElement
const scroller = cm.childNodes[0].childNodes[0]
const cmg = DOM.createElement(`<div role="group"></div>`);
/**
* @type {HTMLElement}
*/
const cmi = DOM.createElement(`<div class="${classItems.item} ${classItems.labelContainer} ${classItems.colorDefault}" role="menuitem" id="bd-copy-selector-item-cm"></div>`);
cmi.append(DOM.createElement(`<div class="${classItems.label}">Copy Selector</div>`));
cmi.addEventListener("click", () => {
BDV2.NativeModule.copy(selector);
cmWrap.style.display = "none"
});
cmi.addEventListener("mouseover", (e) => {
let elements = DOM.queryAll("div[role=menuitem]."+Utils.removeDa(classItems.focused))
elements && elements.forEach(elem => elem.classList.remove(classItems.focused))
cmi.classList.add(classItems.focused)
})
cmi.addEventListener("mouseout", (e) => {
cmi.classList.remove(classItems.focused)
})
cmg.append(cmi);
if(scroller.childNodes.length){ // apend a separator
const separator = DOM.createElement(`<div role="separator" class="${classItems.separator}"></div>`)
scroller.append(separator)
}
scroller.append(cmg);
if(cmWrap.clientHeight < cmWrap.scrollHeight){
console.log("overflowing "+cmWrap.style.top)
cmWrap.style.top = (cmWrap.style.top - cmg.clientHeight) + "px";
console.log("overflowing"+cmWrap.style.top)
}
}
setTimeout(attach, 1);
}catch(e){
console.error(e)
}
}
getSelector(element) {
if (element.id) return `#${element.id}`;
/**
*
* @param {HTMLElement} el
*/
function fullPath(el){
var names = [];
while (el.parentNode){
if (el.id){
names.unshift('#'+el.id);
break;
}else{
if (el==el.ownerDocument.documentElement) names.unshift(el.tagName.toLowerCase()+Array.from(el.classList.entries()).map(e => "."+e).join(""));
else{
for (var c=1,e=el;e.previousElementSibling;e=e.previousElementSibling,c++);
names.unshift(el.tagName.toLowerCase()+((typeof el.className === "string" && el.className) || "").split(" ").filter(e => !!e).map(e => "."+e).join("")+":nth-child("+c+")");
}
el=el.parentNode;
}
}
return names.join(" > ");
}
return fullPath(element)
/*
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(".")}`;*/
}
getRules(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;
}
import {settingsCookie} from "../0globals";
import BDV2 from "./v2";
import DOM from "./domtools";
import Utils from "./utils";
export default new class DevMode {
constructor() {
this.debugListener = this.debugListener.bind(this);
this.copySelectorListener = this.copySelectorListener.bind(this);
}
start() {
this.startDebugListener();
if (settingsCookie["fork-dm-1"]) this.startCopySelector();
}
stop() {
this.stopDebugListener();
this.stopCopySelector();
}
startDebugListener() {
this.stopDebugListener();
document.addEventListener("keydown", this.debugListener);
}
stopDebugListener() {
document.removeEventListener("keydown", this.debugListener);
}
startCopySelector() {
this.stopCopySelector();
document.addEventListener("contextmenu", this.copySelectorListener);
}
stopCopySelector() {
document.removeEventListener("contextmenu", this.copySelectorListener);
}
debugListener(e) {
if (e.which === 119 || e.which == 118) {//F8
console.log("%c[%cDevMode%c] %cBreak/Resume", "color: red;", "color: #303030; font-weight:700;", "color:red;", "");
debugger; // eslint-disable-line no-debugger
e.preventDefault();
e.stopImmediatePropagation();
}
}
copySelectorListener(e) {
try{
e.stopPropagation();
const selector = this.getSelector(e.target);
let [
classLayer,
classItems
] = [
BDModules.get((e) => e.layer && typeof e.layer === "string" && e.disabledPointerEvents)[0],
BDModules.get((e) => e.menu)[0]
]
function attach() {
if(!classItems || !classLayer.layer)return console.log(classItems, classLayer.layer)
let cm = DOM.query("."+Utils.removeDa(classItems.menu));
if (!cm) {
const container = DOM.query("#app-mount > ."+Utils.removeDa(classLayer.layerContainer));
const cmWrap = DOM.createElement(`<div class="${classLayer.layer}">`);
cm = DOM.createElement(`<div class="${classItems.menu} ${classItems.styleFlexible} ${classItems.accommodateScrollbar} bd-context-menu" style=""></div>`);
cmWrap.append(cm);
container.append(cmWrap);
cmWrap.style.top = e.clientY + "px";
cmWrap.style.left = e.clientX + "px";
cmWrap.setAttribute("role", "menu")
cmWrap.setAttribute("tabindex", "-1")
cmWrap.id = "bd-copy-selector-context"
cmWrap.setAttribute("aria-label", "Copy Selector Actions")
const scrollerClasses = BDModules.get((e) => e.scrollerWrap)[0]
const scrollerWrap = DOM.createElement(`<div class="${scrollerClasses.scrollerWrap} ${scrollerClasses.scrollerThemed} ${scrollerClasses.themeGhostHairline}"></div>`)
const scroller = DOM.createElement(`<div class="${BDModules.get(e => e.scroller)[0].scroller} ${classItems.scroller}"></div>`)
scrollerWrap.append(scroller)
cm.append(scrollerWrap)
const removeCM = function(e) {
if (e.keyCode && e.keyCode !== 27) return;
cmWrap.remove();
document.removeEventListener("click", removeCM);
document.removeEventListener("contextmenu", removeCM);
document.removeEventListener("keyup", removeCM);
};
document.addEventListener("click", removeCM);
document.addEventListener("contextmenu", removeCM);
document.addEventListener("keyup", removeCM);
}
const cmWrap = cm.parentElement
const scroller = cm.childNodes[0].childNodes[0]
const cmg = DOM.createElement(`<div role="group"></div>`);
/**
* @type {HTMLElement}
*/
const cmi = DOM.createElement(`<div class="${classItems.item} ${classItems.labelContainer} ${classItems.colorDefault}" role="menuitem" id="bd-copy-selector-item-cm"></div>`);
cmi.append(DOM.createElement(`<div class="${classItems.label}">Copy Selector</div>`));
cmi.addEventListener("click", () => {
BDV2.NativeModule.copy(selector);
cmWrap.style.display = "none"
});
cmi.addEventListener("mouseover", (e) => {
let elements = DOM.queryAll("div[role=menuitem]."+Utils.removeDa(classItems.focused))
elements && elements.forEach(elem => elem.classList.remove(classItems.focused))
cmi.classList.add(classItems.focused)
})
cmi.addEventListener("mouseout", (e) => {
cmi.classList.remove(classItems.focused)
})
cmg.append(cmi);
if(scroller.childNodes.length){ // apend a separator
const separator = DOM.createElement(`<div role="separator" class="${classItems.separator}"></div>`)
scroller.append(separator)
}
scroller.append(cmg);
if(cmWrap.clientHeight < cmWrap.scrollHeight){
console.log("overflowing "+cmWrap.style.top)
cmWrap.style.top = (cmWrap.style.top - cmg.clientHeight) + "px";
console.log("overflowing"+cmWrap.style.top)
}
}
setTimeout(attach, 1);
}catch(e){
console.error(e)
}
}
getSelector(element) {
if (element.id) return `#${element.id}`;
/**
*
* @param {HTMLElement} el
*/
function fullPath(el){
var names = [];
while (el.parentNode){
if (el.id){
names.unshift('#'+el.id);
break;
}else{
if (el==el.ownerDocument.documentElement) names.unshift(el.tagName.toLowerCase()+Array.from(el.classList.entries()).map(e => "."+e).join(""));
else{
for (var c=1,e=el;e.previousElementSibling;e=e.previousElementSibling,c++);
names.unshift(el.tagName.toLowerCase()+((typeof el.className === "string" && el.className) || "").split(" ").filter(e => !!e).map(e => "."+e).join("")+":nth-child("+c+")");
}
el=el.parentNode;
}
}
return names.join(" > ");
}
return fullPath(element)
}
};

View File

@ -1,5 +1,4 @@
import BugHunterBadge from "../svg/bug_hunter"
import LightcordUserBadge from "../svg/LightcordUser";
import nodeFetch from "node-fetch"
import { settingsCookie } from "../0globals";
import Circus from "../svg/circus";
@ -31,25 +30,7 @@ export default new class DistantServer {
set cache(data){
if(typeof data !== "object" || typeof this._cache !== "object")return this._cache = data
return this._cache = Object.assign(this._cache, data)
}/*
async delete(){
BdApi.showToast("Deleting all infos about you on Lightcord Servers...", {type: "warn"})
return handleRequest(Routes.delete, "delete")
.then(async res => {
if(res.status !== 200){
BdApi.showToast("An error occured, couldn't delete informations. See console for more infos", {type: "error"})
throw new Error(`Couldn't delete all informations: ${(res.status+" "+res.statusText+" "+await res.text())}`)
}
console.info(`Succesfully deleted informations.`)
BdApi.showToast("Succesfully deleted informations", {type: "success"})
window.Lightcord.Api.Authorization = null
return res.json()
}).catch((err) => {
BdApi.showToast("An error occured, couldn't delete informations. See console for more infos", {type: "error"})
throw new Error(`Couldn't delete all informations: ${err.stack}`)
})
}*/
}
/**
* Get custom badges from the user ID.

View File

@ -1,85 +1,86 @@
import {settingsCookie} from "../0globals";
import BDV2 from "./v2";
import webpackModules from "./webpackModules";
import Utils from "./utils";
import DOM from "./domtools";
import V2C_PublicServers from "../ui/publicservers/publicServers";
import Layer from "../ui/publicservers/layer";
export default new class V2_PublicServers {
constructor() {
this._appendButton = this._appendButton.bind(this);
window.Lightcord.BetterDiscord.V2_PublicServers = this
}
get component() {
return BDV2.react.createElement(Layer, {rootId: "pubslayerroot", id: "pubslayer"}, 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() {
let [
classNameLayers
] = [
BDModules.get(e => e.layers && e.layer)[0].layers.split(" ")[0]
]
const layers = DOM.query(".layers, ."+classNameLayers);
if (!layers) return false;
layers.append(DOM.createElement("<div id='pubslayerroot'>"));
return true;
}
render() {
const root = this.root;
if (!root) {
console.log("FAILED TO LOCATE ROOT: .layers");
return;
}
BDV2.reactDom.render(this.component, root);
}
get button() {
const btn = DOM.createElement(`<div id="bd-pub-li" class="${BDV2.guildClasses.listItem}">`);
if (!settingsCookie["bda-gs-1"]) btn.style.display = "none";
const label = DOM.createElement(`<div id="bd-pub-button" class="${"wrapper-25eVIn " + BDV2.guildClasses.circleButtonMask}">public</div>`);
label.addEventListener("click", () => {this.render();});
btn.append(label);
return btn;
}
_appendButton() {
let [
classNametutorialContainer
] = [
Utils.removeDa(BDModules.get(e => e.downloadProgress && e.tutorialContainer)[0].tutorialContainer)
]
if (DOM.query("#bd-pub-li")) return;
const guilds = DOM.query(`div.${classNametutorialContainer} > div`);
DOM.after(guilds, this.button);
}
addButton() {
if (this.guildPatch) return;
const GuildList = webpackModules.find(m => m.default && m.default.displayName == "NavigableGuilds");
const GuildListOld = webpackModules.findByDisplayName("Guilds");
if (!GuildList && !GuildListOld) Utils.warn("PublicServer", "Can't find GuildList component");
this.guildPatch = Utils.monkeyPatch(GuildList ? GuildList : GuildListOld.prototype, GuildList ? "default" : "render", {after: this._appendButton});
this._appendButton();
}
removeButton() {
this.guildPatch();
delete this.guildPatch;
DOM.query("#bd-pub-li").remove();
}
import {settingsCookie} from "../0globals";
import BDV2 from "./v2";
import webpackModules from "./webpackModules";
import Utils from "./utils";
import DOM from "./domtools";
import V2C_PublicServers from "../ui/publicservers/publicServers";
import Layer from "../ui/publicservers/layer";
export default new class V2_PublicServers {
constructor() {
this._appendButton = this._appendButton.bind(this);
window.Lightcord.BetterDiscord.V2_PublicServers = this
}
get component() {
return BDV2.react.createElement(Layer, {rootId: "pubslayerroot", id: "pubslayer"}, 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() {
let [
classNameLayers
] = [
Utils.removeDa(BDModules.get(e => e.layers && e.layer)[0].layers)
]
const layers = DOM.query(".layers, ."+classNameLayers);
if (!layers) return false;
layers.append(DOM.createElement("<div id='pubslayerroot'>"));
return true;
}
render() {
const root = this.root;
if (!root) {
console.log("FAILED TO LOCATE ROOT: .layers");
return;
}
BDV2.reactDom.render(this.component, root);
}
get button() {
const btn = DOM.createElement(`<div id="bd-pub-li" class="${BDV2.guildClasses.listItem}">`);
if (!settingsCookie["bda-gs-1"]) btn.style.display = "none";
const label = DOM.createElement(`<div id="bd-pub-button" class="${"wrapper-25eVIn " + BDV2.guildClasses.circleButtonMask}">public</div>`);
label.addEventListener("click", () => {this.render();});
btn.append(label);
return btn;
}
_appendButton() {
let [
classNametutorialContainer
] = [
Utils.removeDa(BDModules.get(e => e.downloadProgress && e.tutorialContainer)[0].tutorialContainer)
]
if (DOM.query("#bd-pub-li")) return;
const guilds = DOM.query(`div.${classNametutorialContainer} > div`);
DOM.after(guilds, this.button);
}
addButton() {
if (this.guildPatch) return;
const GuildList = webpackModules.find(m => m.default && m.default.displayName == "NavigableGuilds");
const GuildListOld = webpackModules.findByDisplayName("Guilds");
if (!GuildList && !GuildListOld) Utils.warn("PublicServer", "Can't find GuildList component");
this.guildPatch = Utils.monkeyPatch(GuildList ? GuildList : GuildListOld.prototype, GuildList ? "default" : "render", {after: this._appendButton});
this._appendButton();
}
removeButton() {
this.guildPatch();
delete this.guildPatch;
const button = DOM.query("#bd-pub-li");
if (button) button.remove();
}
};

View File

@ -76,35 +76,7 @@ export default new class V2_SettingsPanel {
this.sidebar.register("plugins", makeComponent(this.renderAddonPane("plugins")))
this.sidebar.register("themes", makeComponent(this.renderAddonPane("themes")))
}
get root() {
const _root = DOM.query("#bd-settingspane-container");
if (!_root) {
if (!this.injectRoot()) return null;
return this.root;
}
return _root;
}
injectRoot() {
let [
classNameLayer,
classSidebar
] = [
BDModules.get(e => e.layer && e.animating)[0].layer.split(" ")[0],
BDModules.get(e => e.standardSidebarView)[0]
]
const sidebar = DOM.query("."+classNameLayer+" ."+classSidebar.standardSidebarView.split(" ")[0]+", ."+classNameLayer+" .ui-standard-sidebar-view");
if (!sidebar) return false;
const root = DOM.createElement(`<div id="bd-settingspane-container" class="${classSidebar.contentRegion} content-region">`);
sidebar.append(root);
Utils.onRemoved(root, () => {
BDV2.reactDom.unmountComponentAtNode(root);
});
return true;
}
get coreSettings() {
const settings = this.getSettings("core");
const categories = [...new Set(settings.map(s => s.category))];
@ -123,10 +95,6 @@ export default new class V2_SettingsPanel {
return this.getSettings("status")
}
get MsgLogSettings() {
return this.getSettings("msglog")
}
getSettings(category) {
return Object.keys(settings).reduce((arr, key) => {
const setting = settings[key];
@ -138,7 +106,6 @@ export default new class V2_SettingsPanel {
}, []);
}
onClick() {}
onChange(id, checked, sidebar) {
this.updateSettings(id, checked, sidebar);
@ -212,10 +179,10 @@ export default new class V2_SettingsPanel {
else dMode.stopCopySelector();
}
/*if (id === "reactDevTools") {
if (id === "reactDevTools") {
if (enabled) reactDevTools.start();
else reactDevTools.stop();
}*/
}
if (id === "lightcord-1") {
if (enabled) window.Lightcord.Settings.devMode = true
else window.Lightcord.Settings.devMode = false
@ -292,7 +259,7 @@ export default new class V2_SettingsPanel {
}
async initializeSettings() {
//if (settingsCookie.reactDevTools) reactDevTools.start();
if (settingsCookie.reactDevTools) reactDevTools.start();
if (settingsCookie["bda-gs-2"]) DOM.addClass(document.body, "bd-minimal");
if (settingsCookie["bda-gs-3"]) DOM.addClass(document.body, "bd-minimal-chan");
if (settingsCookie["bda-gs-1"]) publicServersModule.addButton();

View File

@ -1,4 +1,4 @@
import {bbdVersion, settingsCookie} from "../0globals";
import {bbdVersion} from "../0globals";
import WebpackModules from "./webpackModules";
import BDV2 from "./v2";
import DOM from "./domtools";
@ -40,7 +40,7 @@ export default class Utils {
}
static getTextArea() {
return DOM.query("."+BDModules.get(e => e.channelTextArea && e.titleWrapper)[0].channelTextArea.split(" ")[0]+" textarea");
return DOM.query("."+this.removeDa(BDModules.get(e => e.channelTextArea && e.titleWrapper)[0].channelTextArea)+" textarea");
}
static insertText(textarea, text) {
@ -201,8 +201,8 @@ export default class Utils {
*/
static showToast(content, options = {}) {
if (!document.querySelector(".bd-toasts")) {
const container = document.querySelector("."+BDModules.get(e => e.sidebar && e.hasNotice)[0].sidebar.split(" ")[9]+" + div") || null;
const memberlist = container ? container.querySelector("."+BDModules.get(e => e.membersWrap)[0].membersWrap) : null;
const container = document.querySelector("."+this.removeDa(BDModules.get(e => e.sidebar && e.hasNotice)[0].sidebar)+" + div") || null;
const memberlist = container ? container.querySelector("."+this.removeDa(BDModules.get(e => e.membersWrap)[0].membersWrap)) : null;
const form = container ? container.querySelector("form") : null;
const left = container ? container.getBoundingClientRect().left : 310;
const right = memberlist ? memberlist.getBoundingClientRect().left : 0;

View File

@ -237,4 +237,4 @@ Object.defineProperty(CardList.prototype, "render", {
configurable: false,
set: function() {console.warn("Addon policy for plugins #5 https://github.com/rauenzi/BetterDiscordApp/wiki/Addon-Policies#plugins");},
get: () => originalRender
});
});

View File

@ -1,233 +1,234 @@
import {settingsCookie} from "../0globals";
import Settings from "../modules/settingsPanel";
import BDV2 from "../modules/v2";
import DataStore from "../modules/dataStore";
import DOM from "../modules/domtools";
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 [
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() {
DOM.removeStyle("customcss");
DOM.addStyle("customcss", this.editor.session.getValue());
}
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 = DOM.query("#bd-customcss-detach-container");
if (!_root) {
if (!this.injectDetachedRoot()) return null;
return this.detachedRoot;
}
return _root;
}
injectDetachedRoot() {
const app = DOM.query(".app, ."+BDModules.get(e => e.app && e.layers)[0].app.split(" ")[0]);
if (!app) return false;
DOM.insertAfter(DOM.createElement(`<div id="bd-customcss-detach-container">`), app);
return true;
}
attach() {
const self = this;
self.setState({
detached: false
});
}
import {settingsCookie} from "../0globals";
import Settings from "../modules/settingsPanel";
import BDV2 from "../modules/v2";
import DataStore from "../modules/dataStore";
import DOM from "../modules/domtools";
import Utils from "../modules/utils"
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 [
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() {
DOM.removeStyle("customcss");
DOM.addStyle("customcss", this.editor.session.getValue());
}
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 = DOM.query("#bd-customcss-detach-container");
if (!_root) {
if (!this.injectDetachedRoot()) return null;
return this.detachedRoot;
}
return _root;
}
injectDetachedRoot() {
const app = DOM.query(".app, ."+Utils.removeDa(BDModules.get(e => e.app && e.layers)[0].app));
if (!app) return false;
DOM.insertAfter(DOM.createElement(`<div id="bd-customcss-detach-container">`), app);
return true;
}
attach() {
const self = this;
self.setState({
detached: false
});
}
}

View File

@ -1,173 +1,174 @@
import {settingsCookie} from "../0globals";
import Settings from "../modules/settingsPanel";
import BDV2 from "../modules/v2";
import DataStore from "../modules/dataStore";
import DOM from "../modules/domtools";
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() {
DOM.addClass(DOM.query("#app-mount"), "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() {
DOM.removeClass(DOM.query("#app-mount"), "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 = DOM.query("#bd-customcss-detach-container");
if (!_root) {
if (!this.injectRoot()) return null;
return this.detachedRoot;
}
return _root;
}
injectRoot() {
const app = DOM.query(".app, ."+BDModules.get(e => e.app && e.layers)[0].app.split(" ")[0]);
if (!app) return false;
DOM.insertAfter(DOM.createElement(`<div id="bd-customcss-detach-container">`), app);
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 (DOM.query("#editor-detached")) self.props.attach();
BDV2.reactDom.unmountComponentAtNode(self.root);
self.root.remove();
break;
case "update":
self.updateCss();
break;
case "save":
self.saveCss();
break;
}
}
updateCss() {
DOM.removeStyle("customcss");
DOM.addStyle("customcss", this.editor.session.getValue());
}
saveCss() {
DataStore.setBDData("bdcustomcss", btoa(this.editor.session.getValue()));
}
import {settingsCookie} from "../0globals";
import Settings from "../modules/settingsPanel";
import BDV2 from "../modules/v2";
import DataStore from "../modules/dataStore";
import DOM from "../modules/domtools";
import Utils from "../modules/utils"
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() {
DOM.addClass(DOM.query("#app-mount"), "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() {
DOM.removeClass(DOM.query("#app-mount"), "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 = DOM.query("#bd-customcss-detach-container");
if (!_root) {
if (!this.injectRoot()) return null;
return this.detachedRoot;
}
return _root;
}
injectRoot() {
const app = DOM.query(".app, ."+Utils.removeDa(BDModules.get(e => e.app && e.layers)[0].app));
if (!app) return false;
DOM.insertAfter(DOM.createElement(`<div id="bd-customcss-detach-container">`), app);
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 (DOM.query("#editor-detached")) self.props.attach();
BDV2.reactDom.unmountComponentAtNode(self.root);
self.root.remove();
break;
case "update":
self.updateCss();
break;
case "save":
self.saveCss();
break;
}
}
updateCss() {
DOM.removeStyle("customcss");
DOM.addStyle("customcss", this.editor.session.getValue());
}
saveCss() {
DataStore.setBDData("bdcustomcss", btoa(this.editor.session.getValue()));
}
}

View File

@ -4,11 +4,9 @@ import V2C_SettingsGroup from "./settingsGroup";
import dataStore from "../modules/dataStore";
import { defaultRPC, settingsRPC } from "../0globals";
import CustomRichPresence from "../modules/CustomRichPresence"
import timestampRender from "./timestampRender"
import { remote } from "electron";
import MarginTop from "./margintop";
import Utils from "../modules/utils";
import { uuidv4 } from "../modules/distant";
const React = BDV2.React;
@ -739,438 +737,4 @@ class Profile extends React.Component {
{profile}
</div>
}
}
/*
let popoutModule
class Popout extends React.Component { // TODO: Probably use internal Components instead of making it from scratch.
get modules(){
return popoutModule || (popoutModule = [
BDModules.get(e => e.userPopout)[0],
BDModules.get(e => e._horizontal)[0],
BDModules.get(e => e.vertical && e.alignStretch && !e.streamerModeEnabledBtn)[0],
BDModules.get(e => e.bot)[0],
BDModules.get(e => e.activityUserPopout)[0],
BDModules.get(e => e.muted && e.wrapper && e.base)[0],
BDModules.get(e => e.size32)[0],
BDModules.get(e => e.themeGhostHairlineChannels)[0],
BDModules.get(e => e.note && Object.keys(e).length === 1)[0],
BDModules.get(e => e.pro && e.inline)[0],
BDModules.get(e => e.colorStandard)[0],
BDModules.get(e => e.default && e.default.Messages)[0].default.Messages,
BDModules.get(e => e.pointerEvents)[0],
BDModules.get(e => e.default && e.default.getCurrentUser)[0].default
])
}
render(){
let [
rootModule1,
flexModule1,
stylingModule1,
nameTagModule1,
activityModule1,
textModule1,
sizeModule1,
scrollerModule1,
noteModule1,
protipModule1,
colorModule1,
Messages,
avatarModule1,
userModule1
] = this.modules
let user = userModule1.getCurrentUser()
let avatarURL = user.avatarURL
if(user.avatar && user.avatar.startsWith("a_")){
avatarURL = user.getAvatarURL("gif")
}
let data = Object.assign({}, defaultRPC, this.props.preview.props.settings.state.data)
timestampClass = timestampClass || activityModule1.timestamp
let images = (() => {
if(!data["assets.large"])return null
let images = []
if(data["assets.large"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.large"]}.png`} class={`${activityModule1.assetsLargeImageUserPopout} ${data["assets.small"] ? activityModule1.assetsLargeMaskUserPopout : ""}`} />)
}
if(data["assets.small"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.small"]}.png`} class={activityModule1.assetsSmallImageUserPopout} />)
}
if(!images.length)return null
return <div class={activityModule1.assets}>
{images}
</div>
})()
return (<div className="lc-userPopout lc-tab-box-shadow">
<div class={rootModule1.userPopout} role="dialog" tabindex="-1">
<div class={rootModule1.headerPlaying}>
<div class={`${flexModule1.flex} ${stylingModule1.vertical} ${stylingModule1.justifyCenter} ${stylingModule1.alignCenter} ${stylingModule1.noWrap} ${rootModule1.headerTop}`} style={{flex: "1 1 auto"}}>
<div class={rootModule1.avatarWrapperNormal} role="button" tabindex="0">
<div class={avatarModule1} role="img" style={{width: "80px", height: "80px"}}>
<svg width="92" height="80" viewBox="0 0 92 80" class={`${avatarModule1.mask} ${avatarModule1.svg}`}>
<foreignObject x="0" y="0" width="80" height="80" mask="url(#svg-mask-avatar-status-round-80)">
<img src={avatarURL} alt=" " class={avatarModule1.avatar} />
</foreignObject>
<Status />
</svg>
</div>
<svg width="80" height="80" class={rootModule1.avatarHint} viewBox="0 0 80 80">
<foreignObject x="0" y="0" width="80" height="80" mask="url(#svg-mask-avatar-status-round-80)">
<div class={rootModule1.avatarHintInner}>{Messages.VIEW_PROFILE}</div>
</foreignObject>
</svg>
</div>
<div class={rootModule1.headerText}>
<div class={`${flexModule1.flex} ${stylingModule1.horizontal} ${stylingModule1.justifyStart} ${stylingModule1.alignCenter} ${stylingModule1.noWrap}`} style={{flex: "1 1 auto"}}>
<div class={`${rootModule1.headerTagNoNickname} ${nameTagModule1.nameTag}`}>
<span class={`${nameTagModule1.username} ${rootModule1.headerTagUsernameNoNickname}`}>{user.username}</span>
<span>#{user.discriminator}</span>
</div>
</div>
</div>
</div>
<div class={`${activityModule1.activityUserPopout} ${rootModule1.activity}`}>
<h3 class={`${activityModule1.headerTextNormal} ${textModule1.base} ${sizeModule1.size12}`}>{Messages.USER_ACTIVITY_HEADER_PLAYING}</h3>
<div class={activityModule1.bodyNormal}>
{images}
<div class={images ? activityModule1.contentImagesUserPopout : activityModule1.contentNoImagesUserPopout} style={{flex: "1 1 auto"}}>
{(() => {
if(!data.name)return null
return <h3 class={`${activityModule1.nameNormal} ${textModule1.base} ${sizeModule1.size14}`} title={data.name}>
<span class={activityModule1.activityName}>{data.name}</span>
</h3>
})()}
{(() => {
if(!data.details)return null
return <div title={data.title} class={activityModule1.details}>{data.details}</div>
})()}
{(() => {
if(!data.state)return null
return <div class={activityModule1.state}>
<span title={data.state}>{data.state}</span>
</div>
})()}
{(() => {
if(!data["timestamps.start"])return null
let timeComponent = timestampRender(Timestamp, Messages)
return (<div class={activityModule1.timestamp}>
{React.createElement(timeComponent, {
timestamps: {
end: null,
start: data["timestamps.start"]
}
})}
</div>)
})()}
</div>
</div>
</div>
</div>
<div class={`${scrollerModule1.scrollerWrap} ${rootModule1.body} ${scrollerModule1.scrollerThemed} ${scrollerModule1.themeGhostHairline} ${scrollerModule1.scrollerFade}`}>
<div class={`${scrollerModule1.scroller} ${rootModule1.bodyInner}`}>
<div class={rootModule1.bodyTitle}>{Messages.NOTE}</div>
<div class={`${noteModule1.note} ${rootModule1.note}`}>
<textarea placeholder={Messages.NOTE_PLACEHOLDER} maxlength="256" autocorrect="off" class={BDModules.get(e => e.scrollbarGhostHairline)[0].scrollbarGhostHairline} style={{height: "36px"}} disabled></textarea>
</div>
</div>
</div>
<div class={rootModule1.footer}>
<div class={`${rootModule1.protip} ${protipModule1.inline}`}>
<h3 class={`${protipModule1.pro} ${textModule1.base} ${sizeModule1.size12}`} style={{color: "rgb(67, 181, 129)"}}>{Messages.PINNED_MESSAGES_PRO_TIP}</h3>
<div class={`${colorModule1.colorStandard} ${sizeModule1.size14} ${protipModule1.tip}`}>{Messages.CONTEXT_MENU_HINT}</div>
</div>
</div>
</div>
</div>)
}
}
let StatusModules
class Status extends React.Component {
get modules(){
return StatusModules || (StatusModules = [
BDModules.get(e => e.default && e.default.getPresence)[0],
BDModules.get(e => e.pointerEvents)[0].pointerEvents
])
}
render(){
let [
getPresence,
pointerEvents
] = this.modules
let status = getPresence.default.getPresence().status
if(status === "invisible")status = "offline"
return <rect width="16" height="16" x="60" y="60" fill="#ffffff" mask={`url(#svg-mask-status-${status})`} className={pointerEvents}></rect>
}
}
let timestampClass = ""
let ProfileModules
class Profile extends React.Component { // TODO: Probably use internal Components instead of making it from scratch.
get modules(){
return ProfileModules || (ProfileModules = [
BDModules.get(e => e.flex && e._horizontal)[0],
BDModules.get(e => e.vertical && e.alignStretch && !e.streamerModeEnabledBtn)[0],
BDModules.get(e => e.topSectionStreaming)[0],
BDModules.get(e => e.pointerEvents)[0],
BDModules.get(e => e.bot)[0],
BDModules.get(e => e.activityProfile)[0],
BDModules.get(e => e.muted && e.wrapper && e.base)[0],
BDModules.get(e => e.size32)[0],
BDModules.get(e => e.scrollerFade)[0],
BDModules.get(e => e.note && Object.keys(e).length === 1)[0],
BDModules.get(e => e.default && e.default.Messages)[0].default.Messages
])
}
render(){
let user = BDModules.get(e => e.default && e.default.getCurrentUser)[0].default.getCurrentUser()
let avatarURL = user.avatarURL
if(user.avatar && user.avatar.startsWith("a_")){
avatarURL = user.getAvatarURL("gif")
}
let [
flexModule1,
stylingModule1,
rootModule1,
avatarModule1,
nameTagModule1,
activityModule1,
textModule1,
sizeModule1,
scrollerModule1,
noteModule1,
Messages
] = this.modules
let data = Object.assign({}, defaultRPC, this.props.preview.props.settings.state.data)
timestampClass = timestampClass || activityModule1.timestamp
let images = (() => {
if(!data["assets.large"])return null
let images = []
if(data["assets.large"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.large"]}.png`} class={`${activityModule1.assetsLargeImageProfile} ${data["assets.small"] ? activityModule1.assetsLargeMaskProfile : ""}`} />)
}
if(data["assets.small"]){
images.push(<img alt="" src={`https://cdn.discordapp.com/app-assets/${data.application_id}/${data["assets.small"]}.png`} class={activityModule1.assetsSmallImageProfile} />)
}
if(!images.length)return null
return <div class={activityModule1.assets}>
{images}
</div>
})()
return [
<div className="lc-tab lc-tab-box-shadow">
<div class={`${flexModule1.flex} ${stylingModule1.vertical} ${stylingModule1.justifyStart} ${stylingModule1.alignStretch} ${stylingModule1.noWrap} ${rootModule1.root}`} style={{flex: "1 1 auto"}}>
<div class={rootModule1.topSectionPlaying}>
<header class={rootModule1.header}>
<div class={`${rootModule1.avatar} ${avatarModule1.wrapper}`} role="img" style={{width: "80px", height: "80px"}}>
<svg width="92" height="80" viewBox="0 0 92 80" class={`${avatarModule1.mask} ${avatarModule1.svg}`}>
<foreignObject x="0" y="0" width="80" height="80" mask="url(#svg-mask-avatar-status-round-80)">
<img src={avatarURL} alt=" " class={avatarModule1.avatar} />
</foreignObject>
<Status />
</svg>
</div>
<div class={`${rootModule1.headerInfo}`}>
<div class={`${rootModule1.nameTag} ${nameTagModule1.nameTag}`}>
<span class={`${rootModule1.username} ${rootModule1.username}`}>{user.username}</span>
<span class={rootModule1.discriminator}>#{user.discriminator}</span>
</div>
<div class={`${flexModule1.flex} ${flexModule1.horizontal} ${stylingModule1.justifyStart} ${stylingModule1.alignStretch} ${stylingModule1.noWrap} ${rootModule1.profileBadges}`} style={{flex: "1 1 auto"}}>
<Badges />
</div>
</div>
</header>
<div class={rootModule1.headerFill}>
<div class={`${activityModule1.activityProfile} ${rootModule1.activity}`}>
<h3 class={`${activityModule1.headerTextNormal} ${textModule1.base} ${sizeModule1.size12}`}>
{Messages.USER_ACTIVITY_HEADER_PLAYING}
</h3>
<div class={activityModule1.bodyNormal}>
{images}
<div class={images ? activityModule1.contentImagesProfile : activityModule1.contentNoImagesUserPopout} style={{flex: "1 1 auto"}}>
{(() => {
if(!data.name)return null
return <h3 class={`${activityModule1.nameNormal} ${textModule1.base} ${sizeModule1.size14}`} title={data.name}>
<span class={activityModule1.activityName}>{data.name}</span>
</h3>
})()}
{(() => {
if(!data.details)return null
return <div title={data.title} class={activityModule1.details}>{data.details}</div>
})()}
{(() => {
if(!data.state)return null
return <div class={activityModule1.state}>
<span title={data.state}>{data.state}</span>
</div>
})()}
{(() => {
if(!data["timestamps.start"])return null
let timeComponent = timestampRender(Timestamp, Messages)
return (<div class={activityModule1.timestamp}>
{React.createElement(timeComponent, {
timestamps: {
end: null,
start: data["timestamps.start"]
}
})}
</div>)
})()}
</div>
</div>
</div>
</div>
</div>
<div class={rootModule1.body}>
<div class={`${scrollerModule1.scrollerWrap} ${scrollerModule1.scrollerFade}`}>
<div class={scrollerModule1.scroller}>
<div class={rootModule1.userInfoSection}>
<div class={rootModule1.userInfoSectionHeader}>{Messages.NOTE}</div>
<div class={`${rootModule1.note} ${noteModule1.note}`}>
<textarea placeholder={Messages.NOTE_PLACEHOLDER} maxlength="256" autocorrect="off"
class={BDModules.get(e => e.scrollbarGhostHairline)[0].scrollbarGhostHairline} style={{height: "40px"}} disabled>
</textarea>
</div>
</div>
<ConnectedAccounts />
</div>
</div>
</div>
</div>
</div>
]
}
}
class ConnectedAccounts extends React.Component {
render(){
let accounts = []
let rootModule1 = BDModules.get(e => e.topSectionStreaming)[0]
let AccountModule1 = BDModules.get(e => e.default && e.default.getAccounts)[0].default
let accs = AccountModule1.getAccounts().filter(e => e.visibility === 1)
for(let acc of accs){
accounts.push(<ConnectedAccount acc={acc} />)
}
if(accounts.length > 0){
return (<div class={rootModule1.userInfoSection}>
<div class={rootModule1.connectedAccounts}>
{accounts}
</div>
</div>)
}
return null
}
}
class ConnectedAccount extends React.Component {
render(){
let [
flexModule1,
stylingModule1,
rootModule1,
flowerModule1,
anchorModule1,
SocialConstants
] = [
BDModules.get(e => e.flex && e._horizontal)[0],
BDModules.get(e => e.vertical && e.alignStretch && !e.streamerModeEnabledBtn)[0],
BDModules.get(e => e.topSectionStreaming)[0],
BDModules.get(e => e.flowerStarContainer)[0],
BDModules.get(e => e.anchor)[0],
BDModules.get(e => e.default && e.default.get && e.default.map)[0].default
]
let acc = this.props.acc
let constantsSocial = SocialConstants.get(acc.type)
return (<div class={`${flexModule1.flex} ${flexModule1.horizontal} ${stylingModule1.justifyStart} ${stylingModule1.alignCenter} ${stylingModule1.noWrap} ${rootModule1.connectedAccount}`} style={{flex: "0 1 auto"}}>
<img alt={`Logo ${constantsSocial.name}`} class={rootModule1.connectedAccountIcon} src={constantsSocial.icon.color || constantsSocial.icon.white || constantsSocial.icon.grey} />
<div class={rootModule1.connectedAccountNameInner}>
<div class={rootModule1.connectedAccountName}>{acc.name}</div>
{acc.verified ? (<span>
<div class={`${flowerModule1.flowerStarContainer} ${rootModule1.connectedAccountVerifiedIcon}`} style={{width: "16px", height: "16px"}}>
<svg class={flowerModule1.flowerStar} width="16" height="16" viewBox="0 0 16 15.2">
<path fill="#4f545c" fill-rule="evenodd" d="m16 7.6c0 .79-1.28 1.38-1.52 2.09s.44 2 0 2.59-1.84.35-2.46.8-.79 1.84-1.54 2.09-1.67-.8-2.47-.8-1.75 1-2.47.8-.92-1.64-1.54-2.09-2-.18-2.46-.8.23-1.84 0-2.59-1.54-1.3-1.54-2.09 1.28-1.38 1.52-2.09-.44-2 0-2.59 1.85-.35 2.48-.8.78-1.84 1.53-2.12 1.67.83 2.47.83 1.75-1 2.47-.8.91 1.64 1.53 2.09 2 .18 2.46.8-.23 1.84 0 2.59 1.54 1.3 1.54 2.09z"></path>
</svg>
<div class={flowerModule1.childContainer}>
<svg width="16" height="16" viewBox="0 0 16 15.2">
<path d="M7.4,11.17,4,8.62,5,7.26l2,1.53L10.64,4l1.36,1Z" fill="#ffffff"></path>
</svg>
</div>
</div>
</span>) : null}
</div>
<a class={`${anchorModule1.anchor} ${anchorModule1.anchorUnderlineOnHover}`} rel="noreferrer noopener" target="_blank" role="button" tabindex="0">
<svg class={rootModule1.connectedAccountOpenIcon} width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M10 5V3H5.375C4.06519 3 3 4.06519 3 5.375V18.625C3 19.936 4.06519 21 5.375 21H18.625C19.936 21 21 19.936 21 18.625V14H19V19H5V5H10Z"></path>
<path fill="currentColor" d="M21 2.99902H14V4.99902H17.586L9.29297 13.292L10.707 14.706L19 6.41302V9.99902H21V2.99902Z"></path>
</svg>
</a>
</div>)
}
}
class Badges extends React.Component {
render(){
let user = BDModules.get(e => e.default && e.default.getCurrentUser)[0].default.getCurrentUser()
let rootModule = BDModules.get(e => e.topSectionStreaming)[0]
let UserFlags = BDModules.get(e => e.UserFlags)[0].UserFlags
let badges = []
let serialized = []
for(let flagName in UserFlags){
if(user.hasFlag(UserFlags[flagName]))serialized.push(flagName)
}
for(let flagName of serialized){
let searchable = `profileBadge${flagName.toLowerCase().replace(/_/g, " ").split(" ").map(e => e[0].toUpperCase()+e.slice(1)).join("")}`
searchable = searchable.replace("HypesquadOnline", "HypeSquadOnline")
if(!rootModule[searchable])continue
badges.push(<Badge name={searchable}/>)
}
if(user.hasPremiumSubscription){
badges.push(<Badge name="profileBadgePremium" />)
}
return badges
}
}
class Badge extends React.Component {
render(){
let rootModule1 = BDModules.get(e => e.topSectionStreaming)[0]
return (<div class={rootModule1.profileBadgeWrapper}>
<div>
<div class="" role="button" tabindex="0">
<div class={`${rootModule1.profileBadge} ${rootModule1[this.props.name]}`}>
</div>
</div>
</div>
</div>)
}
}
class Timestamp extends React.Component {
render(){
return <div className={timestampClass}>
{this.props.message}
</div>
}
}*/
}

View File

@ -1,95 +0,0 @@
import BDV2 from "../modules/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 si = document.querySelector("[class*=side-] > [class*=selected]");
if (si) this.scn = si.className;
const ns = document.querySelector("[class*=side-] > [class*='item-']:not([class*=selected])");
if (ns) this.nscn = ns.className;
const tabs = document.querySelectorAll("[class*='side-'] > [class*='item-']");
for (const element of tabs) {
element.addEventListener("click", () => {
this.setState({
selected: null
});
});
}
this.setInitialState();
this.onClick = this.onClick.bind(this);
this.setSelected = this.setSelected.bind(this);
sidebars.push(this)
}
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, button: this.props.headerButton}),
items.map(item => {
const {id, text} = item;
return BDV2.react.createElement(TabBarItem, {key: id, selected: selected === id, text: text, id: id, onClick: self.onClick});
})
);
}
setSelected(e) {
e.target.className = this.scn;
}
onClick(id) {
const si = document.querySelector("[class*=side] > [class*=selected]");
if (si) {
si.removeEventListener("click", this.setSelected);
si.addEventListener("click", this.setSelected);
si.className = this.nscn;
}
setUnselected()
this.setState({selected: id});
if (this.props.onClick) this.props.onClick(id);
}
componentWillUnmount(){
let sidebarIndex = sidebars.findIndex(e => e === this)
if(sidebarIndex)sidebars.splice(sidebarIndex, 1)
}
}
const sidebars = []
export function setUnselected(){
sidebars.forEach((sidebar) => {
if(!sidebar.state.selected)return
sidebar.setState({
selected: null
})
})
}

View File

@ -5,7 +5,7 @@ let classnames = []
function getClassName(name){
let className = classnames.find(e => e.startsWith(name+"-"))
if(className)return className
className = BDModules.get(e => e.name)[0]
className = BDModules.get(e => e[name])[0][name]
classnames.push(className)
return className
}

View File

@ -1,114 +0,0 @@
"use strict";
import BDV2 from "../modules/v2"
const React = BDV2.react
const intervalModule1 = BDModules.get(e => e.Interval)[0]
export default function(component, Messages) {
class TimeRender extends React.PureComponent {
constructor(props){
super(props)
this._interval = new intervalModule1.Interval()
this.state = Object.assign({}, this.getUpdatedTime())
}
componentDidMount(){
let self = this;
this._interval.start(1e3, (function() {
return self.setState(self.getUpdatedTime())
}))
}
componentWillUnmount(){
this._interval.stop()
}
componentDidUpdate(activity){
if(activity.timestamps.end === this.props.timestamps.end && activity.timestamps.start === this.props.timestamps.start)return
this.setState(this.getUpdatedTime())
}
getUpdatedTime(){
let timestamps = this.props.timestamps
let now = Date.now() / 1e3;
if(null != timestamps.end){
return this.getDiff(now, checkUnix(timestamps.end) / 1e3)
}
if(null != timestamps.start){
return this.getDiff(checkUnix(timestamps.start) / 1e3, now)
}
return {
hours: 0,
minutes: 0,
seconds: 0
}
}
renderTime(number, removeZero){
if(removeZero === undefined)removeZero = false
if(removeZero && number <= 0)return -1
if(number < 10)return "0"+number
return number
}
getDiff(timestamp, now){
let hours = Math.max(now - timestamp, 0)
let seconds = Math.floor(hours) % 60
let minutes = Math.floor(hours / 60) % 60
return {
hours: Math.floor(hours / 3600) % 24,
minutes,
seconds
}
}
render(){
let props = this.props
let timestamps = props.timestamps
let usedProps = function(props, items) {
if (null == props) return {};
let timestamps = {}
let keys = Object.keys(props);
for (let i = 0; i < keys.length; i++){
let key = keys[i]
if(!items.indexOf(key) >= 0){
timestamps[key] = props[key]
}
}
return timestamps
}(props, ["timestamps"])
let state = this.state
let hours = state.hours
let minutes = state.minutes
let seconds = state.seconds
let data = {
hours: this.renderTime(hours, !0),
minutes: this.renderTime(minutes),
seconds: this.renderTime(seconds)
};
if(timestamps.end !== null){
return React.createElement(component, Object.assign({}, usedProps, {
message: Messages.USER_ACTIVITY_TIMESTAMP_END.format(data)
}))
}
if(timestamps.start !== null){
return React.createElement(component, Object.assign({}, usedProps, {
message: Messages.USER_ACTIVITY_TIMESTAMP_START.format(data)
}))
}
return null
}
}
return TimeRender
};
function checkUnix(e) {
return ("" + e).length < 13 ? 1e3 * e : e
}

View File

@ -1,207 +1,195 @@
/**
* Tooltip that automatically show and hide themselves on mouseenter and mouseleave events.
* Will also remove themselves if the node to watch is removed from DOM through
* a MutationObserver.
*
* Note this is not using Discord's internals but normal DOM manipulation and emulates
* Discord's own tooltips as closely as possible.
*
* @module EmulatedTooltip
* @version 0.0.1
*/
import Utils from "../modules/utils";
import WebpackModules from "../modules/webpackModules";
//<div class="layer-v9HyYc disabledPointerEvents-1ptgTB" style="position: absolute; left: 237px; bottom: 51px;">
// <div class="tooltip-2QfLtc tooltipTop-XDDSxx tooltipBlack-PPG47z tooltipDisablePointerEvents-3eaBGN" style="opacity: 1; transform: none;">
// <div class="tooltipPointer-3ZfirK"></div>
// <div class="tooltipContent-bqVLWK">User Settings</div>
// </div>
//</div>
//<div class="layer-v9HyYc" style="top: 860px; left: 632.5px;">
// <div class="tooltip-2QfLtc tooltipBlack-PPG47z tooltipTop-XDDSxx">
// <div class="tooltipPointer-3ZfirK"></div>
// Changelog
// </div>
//</div>
let TooltipClasses
function getTooltipClasses(){
if(TooltipClasses)return TooltipClasses
return TooltipClasses = WebpackModules.findByProps("tooltip", "tooltipBlack");
}
let TooltipLayers
function getTooltipLayers(){
if(TooltipLayers)return TooltipLayers
return TooltipLayers = WebpackModules.findByProps("layer", "layerContainer");
}
const getClass = function(sideOrColor) {
const upperCase = sideOrColor[0].toUpperCase() + sideOrColor.slice(1);
const tooltipClass = getTooltipClasses()[`tooltip${upperCase}`];
if (tooltipClass) return tooltipClass;
return null;
};
const classExists = function(sideOrColor) {
return getClass(sideOrColor) ? true : false;
};
const toPx = function(value) {
return `${value}px`;
};
/* <div class="layer-v9HyYc da-layer" style="left: 234.5px; bottom: 51px;">
<div class="tooltip-2QfLtc da-tooltip tooltipTop-XDDSxx tooltipBlack-PPG47z">
<div class="tooltipPointer-3ZfirK da-tooltipPointer"></div>
User Settings
</div>
</div> */
export default class EmulatedTooltip {
/**
*
* @constructor
* @param {(HTMLElement|jQuery)} node - DOM node to monitor and show the tooltip on
* @param {string} tip - string to show in the tooltip
* @param {object} options - additional options for the tooltip
* @param {string} [options.style=black] - correlates to the discord styling/colors (black, brand, green, grey, red, yellow)
* @param {string} [options.side=top] - can be any of top, right, bottom, left
* @param {boolean} [options.preventFlip=false] - prevents moving the tooltip to the opposite side if it is too big or goes offscreen
* @param {boolean} [options.disabled=false] - whether the tooltip should be disabled from showing on hover
*/
constructor(node, text, options = {}) {
const {style = "black", side = "top", preventFlip = false, disabled = false} = options;
this.node = node instanceof jQuery ? node[0] : node;
this.label = text;
this.style = style.toLowerCase();
this.side = side.toLowerCase();
this.preventFlip = preventFlip;
this.disabled = disabled;
if (!classExists(this.side)) return Utils.err("EmulatedTooltip", `Side ${this.side} does not exist.`);
if (!classExists(this.style)) return Utils.err("EmulatedTooltip", `Style ${this.style} does not exist.`);
this.element = document.createElement("div");
this.element.className = getTooltipLayers().layer + " " + getTooltipLayers().disabledPointerEvents;
this.tooltipElement = document.createElement("div");
this.tooltipElement.className = `${getTooltipClasses().tooltip} ${getClass(this.style)}`;
this.labelElement = document.createElement("div");
this.labelElement.className = getTooltipClasses().tooltipContent
const pointerElement = document.createElement("div");
pointerElement.className = getTooltipClasses().tooltipPointer;
this.tooltipElement.append(pointerElement);
this.tooltipElement.append(this.labelElement);
this.element.append(this.tooltipElement);
this.node.addEventListener("mouseenter", () => {
if (this.disabled) return;
this.show();
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.hide();
observer.disconnect();
}
});
});
observer.observe(document.body, {subtree: true, childList: true});
});
this.node.addEventListener("mouseleave", () => {
this.hide();
});
}
/** Container where the tooltip will be appended. */
get container() { return document.querySelector("."+BDModules.get(e => e.popouts)[0].popouts.split(" ")[0]+" ~ ."+BDModules.get(e => e.layerContainer)[0].layerContainer.split(" ")[0]); }
/** Boolean representing if the tooltip will fit on screen above the element */
get canShowAbove() { return this.node.getBoundingClientRect().top - this.element.offsetHeight >= 0; }
/** Boolean representing if the tooltip will fit on screen below the element */
get canShowBelow() { return this.node.getBoundingClientRect().top + this.node.offsetHeight + this.element.offsetHeight <= Utils.screenHeight; }
/** Boolean representing if the tooltip will fit on screen to the left of the element */
get canShowLeft() { return this.node.getBoundingClientRect().left - this.element.offsetWidth >= 0; }
/** Boolean representing if the tooltip will fit on screen to the right of the element */
get canShowRight() { return this.node.getBoundingClientRect().left + this.node.offsetWidth + this.element.offsetWidth <= Utils.screenWidth; }
/** Hides the tooltip. Automatically called on mouseleave. */
hide() {
this.element.remove();
this.tooltipElement.className = this._className;
}
/** Shows the tooltip. Automatically called on mouseenter. Will attempt to flip if position was wrong. */
show() {
this.tooltipElement.className = `${getTooltipClasses().tooltip} ${getClass(this.style)}`;
this.labelElement.textContent = this.label;
this.container.append(this.element);
if (this.side == "top") {
if (this.canShowAbove || (!this.canShowAbove && this.preventFlip)) this.showAbove();
else this.showBelow();
}
if (this.side == "bottom") {
if (this.canShowBelow || (!this.canShowBelow && this.preventFlip)) this.showBelow();
else this.showAbove();
}
if (this.side == "left") {
if (this.canShowLeft || (!this.canShowLeft && this.preventFlip)) this.showLeft();
else this.showRight();
}
if (this.side == "right") {
if (this.canShowRight || (!this.canShowRight && this.preventFlip)) this.showRight();
else this.showLeft();
}
}
/** Force showing the tooltip above the node. */
showAbove() {
this.tooltipElement.classList.add(getClass("top"));
this.element.style.setProperty("top", toPx(this.node.getBoundingClientRect().top - this.element.offsetHeight - 10));
this.centerHorizontally();
}
/** Force showing the tooltip below the node. */
showBelow() {
this.tooltipElement.classList.add(getClass("bottom"));
this.element.style.setProperty("top", toPx(this.node.getBoundingClientRect().top + this.node.offsetHeight + 10));
this.centerHorizontally();
}
/** Force showing the tooltip to the left of the node. */
showLeft() {
this.tooltipElement.classList.add(getClass("left"));
this.element.style.setProperty("left", toPx(this.node.getBoundingClientRect().left - this.element.offsetWidth - 10));
this.centerVertically();
}
/** Force showing the tooltip to the right of the node. */
showRight() {
this.tooltipElement.classList.add(getClass("right"));
this.element.style.setProperty("left", toPx(this.node.getBoundingClientRect().left + this.node.offsetWidth + 10));
this.centerVertically();
}
centerHorizontally() {
const nodecenter = this.node.getBoundingClientRect().left + (this.node.offsetWidth / 2);
this.element.style.setProperty("left", toPx(nodecenter - (this.element.offsetWidth / 2)));
}
centerVertically() {
const nodecenter = this.node.getBoundingClientRect().top + (this.node.offsetHeight / 2);
this.element.style.setProperty("top", toPx(nodecenter - (this.element.offsetHeight / 2)));
}
/**
* Tooltip that automatically show and hide themselves on mouseenter and mouseleave events.
* Will also remove themselves if the node to watch is removed from DOM through
* a MutationObserver.
*
* Note this is not using Discord's internals but normal DOM manipulation and emulates
* Discord's own tooltips as closely as possible.
*
* @module EmulatedTooltip
* @version 0.0.1
*/
import Utils from "../modules/utils";
import WebpackModules from "../modules/webpackModules";
let TooltipClasses
function getTooltipClasses(){
if(TooltipClasses)return TooltipClasses
return TooltipClasses = WebpackModules.findByProps("tooltip", "tooltipBlack");
}
let TooltipLayers
function getTooltipLayers(){
if(TooltipLayers)return TooltipLayers
return TooltipLayers = WebpackModules.findByProps("layer", "layerContainer");
}
const getClass = function(sideOrColor) {
const upperCase = sideOrColor[0].toUpperCase() + sideOrColor.slice(1);
const tooltipClass = getTooltipClasses()[`tooltip${upperCase}`];
if (tooltipClass) return tooltipClass;
return null;
};
const classExists = function(sideOrColor) {
return getClass(sideOrColor) ? true : false;
};
const toPx = function(value) {
return `${value}px`;
};
/* <div class="layer-v9HyYc da-layer" style="left: 234.5px; bottom: 51px;">
<div class="tooltip-2QfLtc da-tooltip tooltipTop-XDDSxx tooltipBlack-PPG47z">
<div class="tooltipPointer-3ZfirK da-tooltipPointer"></div>
User Settings
</div>
</div> */
export default class EmulatedTooltip {
/**
*
* @constructor
* @param {(HTMLElement|jQuery)} node - DOM node to monitor and show the tooltip on
* @param {string} tip - string to show in the tooltip
* @param {object} options - additional options for the tooltip
* @param {string} [options.style=black] - correlates to the discord styling/colors (black, brand, green, grey, red, yellow)
* @param {string} [options.side=top] - can be any of top, right, bottom, left
* @param {boolean} [options.preventFlip=false] - prevents moving the tooltip to the opposite side if it is too big or goes offscreen
* @param {boolean} [options.disabled=false] - whether the tooltip should be disabled from showing on hover
*/
constructor(node, text, options = {}) {
const {style = "black", side = "top", preventFlip = false, disabled = false} = options;
this.node = node instanceof jQuery ? node[0] : node;
this.label = text;
this.style = style.toLowerCase();
this.side = side.toLowerCase();
this.preventFlip = preventFlip;
this.disabled = disabled;
if (!classExists(this.side)) return Utils.err("EmulatedTooltip", `Side ${this.side} does not exist.`);
if (!classExists(this.style)) return Utils.err("EmulatedTooltip", `Style ${this.style} does not exist.`);
this.element = document.createElement("div");
this.element.className = getTooltipLayers().layer + " " + getTooltipLayers().disabledPointerEvents;
this.tooltipElement = document.createElement("div");
this.tooltipElement.className = `${getTooltipClasses().tooltip} ${getClass(this.style)}`;
this.labelElement = document.createElement("div");
this.labelElement.className = getTooltipClasses().tooltipContent
const pointerElement = document.createElement("div");
pointerElement.className = getTooltipClasses().tooltipPointer;
this.tooltipElement.append(pointerElement);
this.tooltipElement.append(this.labelElement);
this.element.append(this.tooltipElement);
this.node.addEventListener("mouseenter", () => {
if (this.disabled) return;
this.show();
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.hide();
observer.disconnect();
}
});
});
observer.observe(document.body, {subtree: true, childList: true});
});
this.node.addEventListener("mouseleave", () => {
this.hide();
});
}
/** Container where the tooltip will be appended. */
get container() {
return document.querySelector("."+Utils.removeDa(BDModules.get(e => e.popouts)[0].popouts)+" ~ ."+Utils.removeDa(BDModules.get(e => e.layerContainer)[0].layerContainer));
}
/** Boolean representing if the tooltip will fit on screen above the element */
get canShowAbove() { return this.node.getBoundingClientRect().top - this.element.offsetHeight >= 0; }
/** Boolean representing if the tooltip will fit on screen below the element */
get canShowBelow() { return this.node.getBoundingClientRect().top + this.node.offsetHeight + this.element.offsetHeight <= Utils.screenHeight; }
/** Boolean representing if the tooltip will fit on screen to the left of the element */
get canShowLeft() { return this.node.getBoundingClientRect().left - this.element.offsetWidth >= 0; }
/** Boolean representing if the tooltip will fit on screen to the right of the element */
get canShowRight() { return this.node.getBoundingClientRect().left + this.node.offsetWidth + this.element.offsetWidth <= Utils.screenWidth; }
/** Hides the tooltip. Automatically called on mouseleave. */
hide() {
this.element.remove();
this.tooltipElement.className = this._className;
}
/** Shows the tooltip. Automatically called on mouseenter. Will attempt to flip if position was wrong. */
show() {
this.tooltipElement.className = `${getTooltipClasses().tooltip} ${getClass(this.style)}`;
this.labelElement.textContent = this.label;
this.container.append(this.element);
if (this.side == "top") {
if (this.canShowAbove || (!this.canShowAbove && this.preventFlip)) this.showAbove();
else this.showBelow();
}
if (this.side == "bottom") {
if (this.canShowBelow || (!this.canShowBelow && this.preventFlip)) this.showBelow();
else this.showAbove();
}
if (this.side == "left") {
if (this.canShowLeft || (!this.canShowLeft && this.preventFlip)) this.showLeft();
else this.showRight();
}
if (this.side == "right") {
if (this.canShowRight || (!this.canShowRight && this.preventFlip)) this.showRight();
else this.showLeft();
}
}
/** Force showing the tooltip above the node. */
showAbove() {
this.tooltipElement.classList.add(getClass("top"));
this.element.style.setProperty("top", toPx(this.node.getBoundingClientRect().top - this.element.offsetHeight - 10));
this.centerHorizontally();
}
/** Force showing the tooltip below the node. */
showBelow() {
this.tooltipElement.classList.add(getClass("bottom"));
this.element.style.setProperty("top", toPx(this.node.getBoundingClientRect().top + this.node.offsetHeight + 10));
this.centerHorizontally();
}
/** Force showing the tooltip to the left of the node. */
showLeft() {
this.tooltipElement.classList.add(getClass("left"));
this.element.style.setProperty("left", toPx(this.node.getBoundingClientRect().left - this.element.offsetWidth - 10));
this.centerVertically();
}
/** Force showing the tooltip to the right of the node. */
showRight() {
this.tooltipElement.classList.add(getClass("right"));
this.element.style.setProperty("left", toPx(this.node.getBoundingClientRect().left + this.node.offsetWidth + 10));
this.centerVertically();
}
centerHorizontally() {
const nodecenter = this.node.getBoundingClientRect().left + (this.node.offsetWidth / 2);
this.element.style.setProperty("left", toPx(nodecenter - (this.element.offsetWidth / 2)));
}
centerVertically() {
const nodecenter = this.node.getBoundingClientRect().top + (this.node.offsetHeight / 2);
this.element.style.setProperty("top", toPx(nodecenter - (this.element.offsetHeight / 2)));
}
}