Upload to github
This commit is contained in:
parent
54f655c204
commit
835976568b
|
@ -47,6 +47,7 @@ export default class BetterDiscord {
|
|||
}
|
||||
|
||||
static async injectRenderer(browserWindow) {
|
||||
return;
|
||||
const location = path.join(__dirname, "renderer.js");
|
||||
if (!fs.existsSync(location)) return; // TODO: cut a fatal log
|
||||
const content = fs.readFileSync(location).toString();
|
||||
|
@ -81,7 +82,7 @@ export default class BetterDiscord {
|
|||
process.env.BETTERDISCORD_DATA_PATH = dataPath;
|
||||
|
||||
// When DOM is available, pass the renderer over the wall
|
||||
browserWindow.webContents.on("dom-ready", () => {
|
||||
/*browserWindow.webContents.on*/(/*"ready-to-show",*/ () => {
|
||||
if (!hasCrashed) return this.injectRenderer(browserWindow);
|
||||
|
||||
// If a previous crash was detected, show a message explaining why BD isn't there
|
||||
|
@ -101,7 +102,7 @@ export default class BetterDiscord {
|
|||
}
|
||||
});
|
||||
hasCrashed = false;
|
||||
});
|
||||
})();
|
||||
|
||||
// This is used to alert renderer code to onSwitch events
|
||||
browserWindow.webContents.on("did-navigate-in-page", () => {
|
||||
|
|
|
@ -1,7 +1,30 @@
|
|||
import {ipcRenderer as IPC} from "electron";
|
||||
import {ipcRenderer as IPC, webFrame} from "electron";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import * as IPCEvents from "common/constants/ipcevents";
|
||||
|
||||
export default function() {
|
||||
export default function () {
|
||||
try {
|
||||
const location = path.join(__dirname, "renderer.js");
|
||||
if (!fs.existsSync(location)) return; // TODO: cut a fatal log
|
||||
const content = fs.readFileSync(location).toString();
|
||||
webFrame.top.executeJavaScript(`
|
||||
(() => {
|
||||
console.log("We are early baby!");
|
||||
try {
|
||||
${content}
|
||||
return true;
|
||||
} catch(error) {
|
||||
console.error(error);
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
//# sourceURL=betterdiscord/renderer.js
|
||||
`);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
// Load Discord's original preload
|
||||
const preload = process.env.DISCORD_PRELOAD;
|
||||
if (preload) {
|
||||
|
@ -19,4 +42,4 @@ export default function() {
|
|||
// TODO bail out
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ export default function () {
|
|||
};
|
||||
|
||||
if (!Reflect.has(window, chunkName)) {
|
||||
return;
|
||||
predefine(window, chunkName, instance => {
|
||||
predefine(instance, "push", () => {
|
||||
instance.push([[Symbol()], {}, require => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Builtin from "../structs/builtin";
|
||||
import {Settings, DataStore, React, WebpackModules, Events, DOMManager, Strings, DiscordModules} from "modules";
|
||||
import {React, Settings, DataStore, WebpackModules, Events, DOMManager, Strings, DiscordModules} from "modules";
|
||||
import CSSEditor from "../ui/customcss/csseditor";
|
||||
import FloatingWindows from "../ui/floatingwindows";
|
||||
import SettingsTitle from "../ui/settings/title";
|
||||
|
@ -27,7 +27,7 @@ export default new class CustomCSS extends Builtin {
|
|||
async enabled() {
|
||||
Settings.registerPanel(this.id, Strings.Panels.customcss, {
|
||||
order: 2,
|
||||
element: () => [<SettingsTitle text={Strings.CustomCSS.editorTitle} />, React.createElement(CSSEditor, {
|
||||
element: () => [<SettingsTitle text={Strings.CustomCSS.editorTitle} />, DiscordModules.React.createElement(CSSEditor, {
|
||||
css: this.savedCss,
|
||||
save: this.saveCSS.bind(this),
|
||||
update: this.insertCSS.bind(this),
|
||||
|
@ -115,8 +115,8 @@ export default new class CustomCSS extends Builtin {
|
|||
}
|
||||
|
||||
openDetached(currentCSS) {
|
||||
const editorRef = React.createRef();
|
||||
const editor = React.createElement(CSSEditor, {
|
||||
const editorRef = DiscordModules.React.createRef();
|
||||
const editor = DiscordModules.React.createElement(CSSEditor, {
|
||||
id: "bd-floating-editor",
|
||||
ref: editorRef,
|
||||
css: currentCSS,
|
||||
|
@ -152,4 +152,4 @@ export default new class CustomCSS extends Builtin {
|
|||
UserSettings.close();
|
||||
Dispatcher.dispatch({type: "LAYER_POP"});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -2,17 +2,23 @@ import require from "./polyfill"; // eslint-disable-line no-unused-vars
|
|||
import secure from "./secure";
|
||||
import LoadingIcon from "./loadingicon";
|
||||
import BetterDiscord from "./modules/core";
|
||||
import Events from "./modules/emitter";
|
||||
import BdApi from "./modules/api/index";
|
||||
|
||||
// Perform some setup
|
||||
secure();
|
||||
Object.defineProperty(window, "BdApi", {
|
||||
value: BdApi,
|
||||
writable: false,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
// Perform some setup
|
||||
secure();
|
||||
window.global = window;
|
||||
|
||||
// Add loading icon at the bottom right
|
||||
Events.addListener("CLIENT_READY", async () => {
|
||||
BetterDiscord.startup();
|
||||
});
|
||||
|
||||
BetterDiscord.preload();
|
||||
LoadingIcon.show();
|
||||
BetterDiscord.startup();
|
|
@ -1,45 +1,47 @@
|
|||
const css = `/* BEGIN V2 LOADER */
|
||||
/* =============== */
|
||||
|
||||
#bd-loading-icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjAwMCAyMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyMDAwIDIwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGZpbGw9IiMzRTgyRTUiIGQ9Ik0xNDAyLjIsNjMxLjdjLTkuNy0zNTMuNC0yODYuMi00OTYtNjQyLjYtNDk2SDY4LjR2NzE0LjFsNDQyLDM5OFY0OTAuN2gyNTdjMjc0LjUsMCwyNzQuNSwzNDQuOSwwLDM0NC45SDU5Ny42djMyOS41aDE2OS44YzI3NC41LDAsMjc0LjUsMzQ0LjgsMCwzNDQuOGgtNjk5djM1NC45aDY5MS4yYzM1Ni4zLDAsNjMyLjgtMTQyLjYsNjQyLjYtNDk2YzAtMTYyLjYtNDQuNS0yODQuMS0xMjIuOS0zNjguNkMxMzU3LjcsOTE1LjgsMTQwMi4yLDc5NC4zLDE0MDIuMiw2MzEuN3oiLz48cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMTI2Mi41LDEzNS4yTDEyNjIuNSwxMzUuMmwtNzYuOCwwYzI2LjYsMTMuMyw1MS43LDI4LjEsNzUsNDQuM2M3MC43LDQ5LjEsMTI2LjEsMTExLjUsMTY0LjYsMTg1LjNjMzkuOSw3Ni42LDYxLjUsMTY1LjYsNjQuMywyNjQuNmwwLDEuMnYxLjJjMCwxNDEuMSwwLDU5Ni4xLDAsNzM3LjF2MS4ybDAsMS4yYy0yLjcsOTktMjQuMywxODgtNjQuMywyNjQuNmMtMzguNSw3My44LTkzLjgsMTM2LjItMTY0LjYsMTg1LjNjLTIyLjYsMTUuNy00Ni45LDMwLjEtNzIuNiw0My4xaDcyLjVjMzQ2LjIsMS45LDY3MS0xNzEuMiw2NzEtNTY3LjlWNzE2LjdDMTkzMy41LDMxMi4yLDE2MDguNywxMzUuMiwxMjYyLjUsMTM1LjJ6Ii8+PC9nPjwvc3ZnPg==);
|
||||
}
|
||||
#bd-loading-icon {
|
||||
position: fixed;
|
||||
bottom:5px;
|
||||
right:5px;
|
||||
z-index: 2147483647;
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-size: 100% 100%;
|
||||
animation: bd-loading-animation 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes bd-loading-animation {
|
||||
0% { opacity: 0.05; }
|
||||
50% { opacity: 0.6; }
|
||||
100% { opacity: 0.05; }
|
||||
}
|
||||
/* =============== */
|
||||
/* END V2 LOADER */`;
|
||||
|
||||
const iconStyle = document.createElement("style");
|
||||
iconStyle.textContent = css;
|
||||
|
||||
const loadingIcon = document.createElement("div");
|
||||
loadingIcon.id = "bd-loading-icon";
|
||||
loadingIcon.className = "bd-loaderv2";
|
||||
loadingIcon.title = "BetterDiscord is loading...";
|
||||
|
||||
export default class {
|
||||
static show() {
|
||||
document.body.appendChild(iconStyle);
|
||||
document.body.appendChild(loadingIcon);
|
||||
}
|
||||
|
||||
static hide() {
|
||||
if (iconStyle) iconStyle.remove();
|
||||
if (loadingIcon) loadingIcon.remove();
|
||||
}
|
||||
}
|
||||
const css = `/* BEGIN V2 LOADER */
|
||||
/* =============== */
|
||||
|
||||
#bd-loading-icon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjAwMCAyMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyMDAwIDIwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGZpbGw9IiMzRTgyRTUiIGQ9Ik0xNDAyLjIsNjMxLjdjLTkuNy0zNTMuNC0yODYuMi00OTYtNjQyLjYtNDk2SDY4LjR2NzE0LjFsNDQyLDM5OFY0OTAuN2gyNTdjMjc0LjUsMCwyNzQuNSwzNDQuOSwwLDM0NC45SDU5Ny42djMyOS41aDE2OS44YzI3NC41LDAsMjc0LjUsMzQ0LjgsMCwzNDQuOGgtNjk5djM1NC45aDY5MS4yYzM1Ni4zLDAsNjMyLjgtMTQyLjYsNjQyLjYtNDk2YzAtMTYyLjYtNDQuNS0yODQuMS0xMjIuOS0zNjguNkMxMzU3LjcsOTE1LjgsMTQwMi4yLDc5NC4zLDE0MDIuMiw2MzEuN3oiLz48cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMTI2Mi41LDEzNS4yTDEyNjIuNSwxMzUuMmwtNzYuOCwwYzI2LjYsMTMuMyw1MS43LDI4LjEsNzUsNDQuM2M3MC43LDQ5LjEsMTI2LjEsMTExLjUsMTY0LjYsMTg1LjNjMzkuOSw3Ni42LDYxLjUsMTY1LjYsNjQuMywyNjQuNmwwLDEuMnYxLjJjMCwxNDEuMSwwLDU5Ni4xLDAsNzM3LjF2MS4ybDAsMS4yYy0yLjcsOTktMjQuMywxODgtNjQuMywyNjQuNmMtMzguNSw3My44LTkzLjgsMTM2LjItMTY0LjYsMTg1LjNjLTIyLjYsMTUuNy00Ni45LDMwLjEtNzIuNiw0My4xaDcyLjVjMzQ2LjIsMS45LDY3MS0xNzEuMiw2NzEtNTY3LjlWNzE2LjdDMTkzMy41LDMxMi4yLDE2MDguNywxMzUuMiwxMjYyLjUsMTM1LjJ6Ii8+PC9nPjwvc3ZnPg==);
|
||||
}
|
||||
#bd-loading-icon {
|
||||
position: fixed;
|
||||
bottom:5px;
|
||||
right:5px;
|
||||
z-index: 2147483647;
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-size: 100% 100%;
|
||||
animation: bd-loading-animation 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes bd-loading-animation {
|
||||
0% { opacity: 0.05; }
|
||||
50% { opacity: 0.6; }
|
||||
100% { opacity: 0.05; }
|
||||
}
|
||||
/* =============== */
|
||||
/* END V2 LOADER */`;
|
||||
|
||||
const iconStyle = document.createElement("style");
|
||||
iconStyle.textContent = css;
|
||||
|
||||
const loadingIcon = document.createElement("div");
|
||||
loadingIcon.id = "bd-loading-icon";
|
||||
loadingIcon.className = "bd-loaderv2";
|
||||
loadingIcon.title = "BetterDiscord is loading...";
|
||||
|
||||
export default class {
|
||||
static show() {
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
document.body.appendChild(iconStyle);
|
||||
document.body.appendChild(loadingIcon);
|
||||
}, {once: true});
|
||||
}
|
||||
|
||||
static hide() {
|
||||
if (iconStyle) iconStyle.remove();
|
||||
if (loadingIcon) loadingIcon.remove();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,9 @@ import AddonError from "../structs/addonerror";
|
|||
import Toasts from "../ui/toasts";
|
||||
import DiscordModules from "./discordmodules";
|
||||
import Strings from "./strings";
|
||||
import AddonEditor from "../ui/misc/addoneditor";
|
||||
import FloatingWindows from "../ui/floatingwindows";
|
||||
|
||||
const React = DiscordModules.React;
|
||||
import Utilities from "./utilities";
|
||||
import Notices from "../ui/notices";
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
|
@ -26,6 +25,10 @@ const stripBOM = function(fileContent) {
|
|||
return fileContent;
|
||||
};
|
||||
|
||||
const AddonEditor = Utilities.makeLazy(() => import("../ui/misc/addoneditor"));
|
||||
|
||||
let needsReload = false;
|
||||
|
||||
export default class AddonManager {
|
||||
|
||||
get name() {return "";}
|
||||
|
@ -41,10 +44,24 @@ export default class AddonManager {
|
|||
this.addonList = [];
|
||||
this.state = {};
|
||||
this.windows = new Set();
|
||||
this.delayedAddons = [];
|
||||
}
|
||||
|
||||
initialize() {
|
||||
return this.loadAllAddons();
|
||||
const partial = this.loadAllAddons();
|
||||
|
||||
Events.addListener("LOAD_DELAYED_ADDONS", () => {
|
||||
if (typeof this.onClientReady === "function") {
|
||||
this.onClientReady();
|
||||
}
|
||||
|
||||
partial.push(
|
||||
...this.delayedAddons.map(this.finalizeAddon.bind(this))
|
||||
.filter(Boolean)
|
||||
);
|
||||
});
|
||||
|
||||
return partial;
|
||||
}
|
||||
|
||||
// Subclasses should overload this and modify the addon object as needed to fully load it
|
||||
|
@ -68,6 +85,24 @@ export default class AddonManager {
|
|||
Logger.log(this.name, `Starting to watch ${this.prefix} addons.`);
|
||||
this.watcher = fs.watch(this.addonFolder, {persistent: false}, async (eventType, filename) => {
|
||||
// console.log("watcher", eventType, filename, !eventType || !filename, !filename.endsWith(this.extension));
|
||||
const isEarly = this.addonList.some(addon => addon.filename === filename && addon["run-at"] === "client-start");
|
||||
|
||||
if (isEarly) {
|
||||
if (needsReload) return;
|
||||
|
||||
needsReload = true;
|
||||
|
||||
Notices.show("One or more addons require a reload", {
|
||||
type: "error",
|
||||
buttons: [
|
||||
{label: "Reload Now", onClick() {location.reload();} },
|
||||
{label: "Ignore", onClick() {} }
|
||||
]
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!eventType || !filename) return;
|
||||
// console.log(eventType, filename)
|
||||
|
||||
|
@ -211,7 +246,12 @@ export default class AddonManager {
|
|||
return e;
|
||||
}
|
||||
|
||||
// if (!this.delayedAddons.includes(addon)) {
|
||||
// return this.finalizeAddon(addon, shouldToast);
|
||||
// }
|
||||
}
|
||||
|
||||
finalizeAddon(addon, shouldToast) {
|
||||
const error = this.initializeAddon(addon);
|
||||
if (error) {
|
||||
this.state[addon.id] = false;
|
||||
|
@ -361,8 +401,8 @@ export default class AddonManager {
|
|||
if (this.windows.has(fullPath)) return;
|
||||
this.windows.add(fullPath);
|
||||
|
||||
const editorRef = React.createRef();
|
||||
const editor = React.createElement(AddonEditor, {
|
||||
const editorRef = DiscordModules.React.createRef();
|
||||
const editor = DiscordModules.React.createElement(AddonEditor, {
|
||||
id: "bd-floating-editor-" + addon.id,
|
||||
ref: editorRef,
|
||||
content: content,
|
||||
|
@ -394,4 +434,4 @@ export default class AddonManager {
|
|||
confirmationText: Strings.Addons.confirmationText.format({name: addon.name})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,12 +7,10 @@ import Data from "./data";
|
|||
import DOM from "./dom";
|
||||
import Patcher from "./patcher";
|
||||
import ReactUtils from "./reactutils";
|
||||
import UI from "./ui";
|
||||
import Utils from "./utils";
|
||||
import Webpack from "./webpack";
|
||||
import * as Legacy from "./legacy";
|
||||
import ContextMenu from "./contextmenu";
|
||||
import {DiscordModules} from "modules";
|
||||
import {DiscordModules, Events} from "modules";
|
||||
|
||||
const bounded = new Map();
|
||||
const PluginAPI = new AddonAPI(PluginManager);
|
||||
|
@ -20,7 +18,7 @@ const ThemeAPI = new AddonAPI(ThemeManager);
|
|||
const PatcherAPI = new Patcher();
|
||||
const DataAPI = new Data();
|
||||
const DOMAPI = new DOM();
|
||||
const ContextMenuAPI = new ContextMenu();
|
||||
// const ContextMenuAPI = new ContextMenu();
|
||||
|
||||
/**
|
||||
* `BdApi` is a globally (`window.BdApi`) accessible object for use by plugins and developers to make their lives easier.
|
||||
|
@ -51,9 +49,9 @@ export default class BdApi {
|
|||
get Themes() {return ThemeAPI;}
|
||||
get Webpack() {return Webpack;}
|
||||
get Utils() {return Utils;}
|
||||
get UI() {return UI;}
|
||||
get UI() {return BdApi.UI;}
|
||||
get ReactUtils() {return ReactUtils;}
|
||||
get ContextMenu() {return ContextMenuAPI;}
|
||||
get ContextMenu() {return BdApi.ContextMenuAPI;}
|
||||
Components = {
|
||||
get Tooltip() {return DiscordModules.Tooltip;}
|
||||
}
|
||||
|
@ -90,13 +88,13 @@ BdApi.Webpack = Webpack;
|
|||
* An instance of {@link Data} to manage data.
|
||||
* @type Data
|
||||
*/
|
||||
BdApi.Data = DataAPI;
|
||||
BdApi.Data = DataAPI;
|
||||
|
||||
/**
|
||||
* An instance of {@link UI} to create interfaces.
|
||||
* @type UI
|
||||
*/
|
||||
BdApi.UI = UI;
|
||||
// BdApi.UI = UI;
|
||||
|
||||
/**
|
||||
* An instance of {@link ReactUtils} to work with React.
|
||||
|
@ -120,12 +118,22 @@ BdApi.DOM = DOMAPI;
|
|||
* An instance of {@link ContextMenu} for interacting with context menus.
|
||||
* @type ContextMenu
|
||||
*/
|
||||
BdApi.ContextMenu = ContextMenuAPI;
|
||||
// BdApi.ContextMenu = ContextMenuAPI;
|
||||
|
||||
BdApi.Components = {
|
||||
get Tooltip() {return DiscordModules.Tooltip;}
|
||||
};
|
||||
|
||||
Object.freeze(BdApi);
|
||||
Events.addListener("CLIENT_READY", async () => {
|
||||
const [UI, ContextMenu] = await Promise.all([
|
||||
import("./ui"),
|
||||
import("./contextmenu")
|
||||
].map(e => e.then(e => e.default)));
|
||||
|
||||
BdApi.UI = UI;
|
||||
BdApi.ContextMenu = new ContextMenu;
|
||||
});
|
||||
|
||||
// Object.freeze(BdApi);
|
||||
Object.freeze(BdApi.prototype);
|
||||
Object.freeze(BdApi.Components);
|
||||
|
|
|
@ -10,20 +10,21 @@ import Settings from "../settingsmanager";
|
|||
import Logger from "common/logger";
|
||||
import Patcher from "../patcher";
|
||||
import ipc from "../ipc";
|
||||
import {React, ReactDOM} from "modules";
|
||||
|
||||
/**
|
||||
* The React module being used inside Discord.
|
||||
* @type React
|
||||
* @memberof BdApi
|
||||
*/
|
||||
const React = DiscordModules.React;
|
||||
// const React = DiscordModules.React;
|
||||
|
||||
/**
|
||||
* The ReactDOM module being used inside Discord.
|
||||
* @type ReactDOM
|
||||
* @memberof BdApi
|
||||
*/
|
||||
const ReactDOM = DiscordModules.ReactDOM;
|
||||
// const ReactDOM = DiscordModules.ReactDOM;
|
||||
|
||||
/**
|
||||
* A reference object to get BD's settings.
|
||||
|
@ -500,4 +501,4 @@ export {
|
|||
getBDData,
|
||||
setBDData,
|
||||
openDialog
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Logger from "common/logger";
|
||||
import {default as MainPatcher} from "../patcher";
|
||||
import {Patcher as WebpackPatcher} from "../webpackmodules";
|
||||
|
||||
/**
|
||||
* `Patcher` is a utility class for modifying existing functions. Instance is accessible through the {@link BdApi}.
|
||||
|
@ -98,8 +99,18 @@ class Patcher {
|
|||
if (typeof(caller) !== "string") return Logger.err("BdApi.Patcher", "Parameter 0 of unpatchAll must be a string representing the caller");
|
||||
MainPatcher.unpatchAll(caller);
|
||||
}
|
||||
|
||||
patchSource(patch) {
|
||||
const required = ["test", "regex", "replace"];
|
||||
let missing;
|
||||
if ((missing = required.filter(p => typeof patch[p] === "undefined")).length) {
|
||||
return Logger.error("BdApi.Patcher", `Parameter 0 of patchSource is missing the following properties: ${missing.join(", ")}`);
|
||||
}
|
||||
|
||||
return WebpackPatcher.addPatch(patch);
|
||||
}
|
||||
}
|
||||
|
||||
Object.freeze(Patcher);
|
||||
Object.freeze(Patcher.prototype);
|
||||
export default Patcher;
|
||||
export default Patcher;
|
||||
|
|
|
@ -1,30 +1,77 @@
|
|||
import LocaleManager from "./localemanager";
|
||||
// import LocaleManager from "./localemanager";
|
||||
|
||||
import Logger from "common/logger";
|
||||
// import Logger from "common/logger";
|
||||
import {Config, Changelog} from "data";
|
||||
import DOMManager from "./dommanager";
|
||||
import PluginManager from "./pluginmanager";
|
||||
import ThemeManager from "./thememanager";
|
||||
import Settings from "./settingsmanager";
|
||||
import * as Builtins from "builtins";
|
||||
import Modals from "../ui/modals";
|
||||
import FloatingWindows from "../ui/floatingwindows";
|
||||
import DataStore from "./datastore";
|
||||
import DiscordModules from "./discordmodules";
|
||||
import LoadingIcon from "../loadingicon";
|
||||
import Styles from "../styles/index.css";
|
||||
import Editor from "./editor";
|
||||
import Updater from "./updater";
|
||||
|
||||
import Events from "./emitter";
|
||||
// import DOMManager from "./dommanager";
|
||||
// import PluginManager from "./pluginmanager";
|
||||
// import ThemeManager from "./thememanager";
|
||||
// import Settings from "./settingsmanager";
|
||||
// import * as Builtins from "builtins";
|
||||
// import Modals from "../ui/modals";
|
||||
// import FloatingWindows from "../ui/floatingwindows";
|
||||
// import DataStore from "./datastore";
|
||||
// import DiscordModules from "./discordmodules";
|
||||
// import LoadingIcon from "../loadingicon";
|
||||
// import Styles from "../styles/index.css";
|
||||
// import Editor from "./editor";
|
||||
// import Updater from "./updater";
|
||||
console.log("[BD] We are early baby!");
|
||||
export default new class Core {
|
||||
async startup() {
|
||||
if (this.hasStarted) return;
|
||||
this.hasStarted = true;
|
||||
|
||||
async preload() {
|
||||
Config.appPath = process.env.DISCORD_APP_PATH;
|
||||
Config.userData = process.env.DISCORD_USER_DATA;
|
||||
Config.dataPath = process.env.BETTERDISCORD_DATA_PATH;
|
||||
|
||||
const [DataStore, PluginManager] = await Promise.all([
|
||||
import("./datastore"),
|
||||
import("./pluginmanager")
|
||||
].map(i => i.then(v => v.default ? v.default : v)));
|
||||
|
||||
DataStore.initialize();
|
||||
this.pluginErrors = PluginManager.initialize();
|
||||
};
|
||||
|
||||
async startup() {
|
||||
if (this.hasStarted) return;
|
||||
|
||||
const [
|
||||
{default: DiscordModules},
|
||||
{default: Logger},
|
||||
{default: LocaleManager},
|
||||
{default: DOMManager},
|
||||
{default: PluginManager},
|
||||
{default: ThemeManager},
|
||||
{default: Settings},
|
||||
Builtins,
|
||||
{default: Modals},
|
||||
{default: FloatingWindows},
|
||||
{default: DataStore},
|
||||
{default: LoadingIcon},
|
||||
{default: Styles},
|
||||
{default: Editor},
|
||||
{default: Updater}
|
||||
] = await Promise.all([
|
||||
import("./discordmodules"),
|
||||
import("common/logger"),
|
||||
import("./localemanager"),
|
||||
import("./dommanager"),
|
||||
import("./pluginmanager"),
|
||||
import("./thememanager"),
|
||||
import("./settingsmanager"),
|
||||
import("builtins"),
|
||||
import("../ui/modals"),
|
||||
import("../ui/floatingwindows"),
|
||||
import("./datastore"),
|
||||
import("../loadingicon"),
|
||||
import("../styles/index.css"),
|
||||
import("./editor"),
|
||||
import("./updater")
|
||||
]);
|
||||
|
||||
this.DiscordModules = DiscordModules;
|
||||
this.hasStarted = true;
|
||||
|
||||
// Load css early
|
||||
Logger.log("Startup", "Injecting BD Styles");
|
||||
DOMManager.injectStyle("bd-stylesheet", Styles.toString());
|
||||
|
@ -57,7 +104,7 @@ export default new class Core {
|
|||
|
||||
Logger.log("Startup", "Loading Plugins");
|
||||
// const pluginErrors = [];
|
||||
const pluginErrors = PluginManager.initialize();
|
||||
Events.dispatch("LOAD_DELAYED_ADDONS");
|
||||
|
||||
Logger.log("Startup", "Loading Themes");
|
||||
// const themeErrors = [];
|
||||
|
@ -71,7 +118,7 @@ export default new class Core {
|
|||
|
||||
// Show loading errors
|
||||
Logger.log("Startup", "Collecting Startup Errors");
|
||||
Modals.showAddonErrors({plugins: pluginErrors, themes: themeErrors});
|
||||
Modals.showAddonErrors({plugins: this.pluginErrors, themes: themeErrors});
|
||||
|
||||
const previousVersion = DataStore.getBDData("version");
|
||||
if (Config.version !== previousVersion) {
|
||||
|
@ -82,8 +129,8 @@ export default new class Core {
|
|||
|
||||
waitForConnection() {
|
||||
return new Promise(done => {
|
||||
if (DiscordModules.UserStore.getCurrentUser()) return done();
|
||||
DiscordModules.Dispatcher.subscribe("CONNECTION_OPEN", done);
|
||||
if (this.DiscordModules.UserStore.getCurrentUser()) return done();
|
||||
this.DiscordModules.Dispatcher.subscribe("CONNECTION_OPEN", done);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -198,9 +198,11 @@ export default class DOMManager {
|
|||
}
|
||||
}
|
||||
|
||||
DOMManager.createElement("bd-head", {target: document.head});
|
||||
DOMManager.createElement("bd-body", {target: document.body});
|
||||
DOMManager.createElement("bd-scripts", {target: DOMManager.bdHead});
|
||||
DOMManager.createElement("bd-styles", {target: DOMManager.bdHead});
|
||||
DOMManager.createElement("bd-themes", {target: DOMManager.bdHead});
|
||||
DOMManager.createElement("style", {id: "customcss", target: DOMManager.bdHead});
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
DOMManager.createElement("bd-head", {target: document.head});
|
||||
DOMManager.createElement("bd-body", {target: document.body});
|
||||
DOMManager.createElement("bd-scripts", {target: DOMManager.bdHead});
|
||||
DOMManager.createElement("bd-styles", {target: DOMManager.bdHead});
|
||||
DOMManager.createElement("bd-themes", {target: DOMManager.bdHead});
|
||||
DOMManager.createElement("style", {id: "customcss", target: DOMManager.bdHead});
|
||||
}, {once: true});
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
const EventEmitter = require("events");
|
||||
|
||||
export default new class BDEvents extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.setMaxListeners(20);
|
||||
}
|
||||
|
||||
dispatch(eventName, ...args) {
|
||||
this.emit(eventName, ...args);
|
||||
}
|
||||
};
|
||||
import EventEmitter from "../../../common/events";
|
||||
|
||||
export default new class BDEvents extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.setMaxListeners(20);
|
||||
}
|
||||
|
||||
addListener() {
|
||||
return this.on.apply(this, arguments);
|
||||
}
|
||||
|
||||
removeListener() {
|
||||
return this.off.apply(this, arguments);
|
||||
}
|
||||
|
||||
dispatch(eventName, ...args) {
|
||||
this.emit(eventName, ...args);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,10 +3,8 @@ import DiscordModules from "./discordmodules";
|
|||
import Utilities from "./utilities";
|
||||
import Events from "./emitter";
|
||||
|
||||
const {LocaleStore} = DiscordModules;
|
||||
|
||||
export default new class LocaleManager {
|
||||
get discordLocale() {return LocaleStore?.locale ?? this.defaultLocale;}
|
||||
get discordLocale() {return DiscordModules.LocaleStore?.locale ?? this.defaultLocale;}
|
||||
get defaultLocale() {return "en-US";}
|
||||
|
||||
constructor() {
|
||||
|
@ -16,7 +14,7 @@ export default new class LocaleManager {
|
|||
|
||||
initialize() {
|
||||
this.setLocale(this.discordLocale);
|
||||
LocaleStore?.addChangeListener((newLocale) => this.setLocale(newLocale));
|
||||
DiscordModules.LocaleStore?.addChangeListener((newLocale) => this.setLocale(newLocale));
|
||||
}
|
||||
|
||||
setLocale(newLocale) {
|
||||
|
@ -32,4 +30,4 @@ export default new class LocaleManager {
|
|||
Utilities.extendTruthy(this.strings, newStrings);
|
||||
Events.emit("strings-updated");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
import DiscordModules from "./discordmodules";
|
||||
import Events from "./emitter";
|
||||
|
||||
export {default as WebpackModules} from "./webpackmodules";
|
||||
|
||||
import DiscordModules from "./discordmodules";
|
||||
export const React = DiscordModules.React;
|
||||
export const ReactDOM = DiscordModules.ReactDOM;
|
||||
export {DiscordModules};
|
||||
// import DiscordModules from "./discordmodules";
|
||||
const makeProxy = name => new Proxy({}, {
|
||||
get(_, key) {
|
||||
return DiscordModules[name][key];
|
||||
},
|
||||
set(_, key, value) {
|
||||
return DiscordModules[name][key] = value;
|
||||
}
|
||||
})
|
||||
|
||||
export const React = makeProxy("React");
|
||||
export const ReactDOM = makeProxy("ReactDOM");
|
||||
|
||||
export {Events, DiscordModules};
|
||||
|
||||
export {default as Utilities} from "./utilities";
|
||||
export {default as DataStore} from "./datastore";
|
||||
export {default as Events} from "./emitter";
|
||||
export {default as Settings} from "./settingsmanager";
|
||||
export {default as DOMManager} from "./dommanager";
|
||||
export {default as Patcher} from "./patcher";
|
||||
|
@ -15,4 +27,4 @@ export {default as LocaleManager} from "./localemanager";
|
|||
export {default as Strings} from "./strings";
|
||||
export {default as IPC} from "./ipc";
|
||||
export {default as Logger} from "common/logger";
|
||||
export {default as DiscordClasses} from "./discordclasses";
|
||||
export {default as DiscordClasses} from "./discordclasses";
|
||||
|
|
|
@ -39,8 +39,7 @@ export default new class PluginManager extends AddonManager {
|
|||
});
|
||||
}
|
||||
|
||||
initialize() {
|
||||
const errors = super.initialize();
|
||||
onClientReady() {
|
||||
this.setupFunctions();
|
||||
Settings.registerPanel("plugins", Strings.Panels.plugins, {
|
||||
order: 3,
|
||||
|
@ -56,7 +55,6 @@ export default new class PluginManager extends AddonManager {
|
|||
prefix: this.prefix
|
||||
})
|
||||
});
|
||||
return errors;
|
||||
}
|
||||
|
||||
/* Aliases */
|
||||
|
@ -117,21 +115,37 @@ export default new class PluginManager extends AddonManager {
|
|||
|
||||
requireAddon(filename) {
|
||||
const addon = super.requireAddon(filename);
|
||||
|
||||
if (addon["run-at"] !== "client-start") {
|
||||
this.delayedAddons.push(addon);
|
||||
|
||||
return addon;
|
||||
}
|
||||
|
||||
this.finalizeAddon(addon);
|
||||
|
||||
return addon;
|
||||
}
|
||||
|
||||
finalizeAddon(addon) {
|
||||
if (!addon) debugger;
|
||||
try {
|
||||
const module = {filename, exports: {}};
|
||||
const module = {filename: addon.filename, exports: {}};
|
||||
// Test if the code is valid gracefully
|
||||
vm.compileFunction(addon.fileContent, ["require", "module", "exports", "__filename", "__dirname"], {filename: path.basename(filename)});
|
||||
vm.compileFunction(addon.fileContent, ["require", "module", "exports", "__filename", "__dirname"], {filename: path.basename(addon.filename)});
|
||||
addon.fileContent += normalizeExports(addon.exports || addon.name);
|
||||
addon.fileContent += `\n//# sourceURL=betterdiscord://plugins/${addon.filename}`;
|
||||
const wrappedPlugin = new Function(["require", "module", "exports", "__filename", "__dirname"], addon.fileContent); // eslint-disable-line no-new-func
|
||||
wrappedPlugin(window.require, module, module.exports, module.filename, this.addonFolder);
|
||||
addon.exports = module.exports;
|
||||
delete addon.fileContent;
|
||||
return addon;
|
||||
}
|
||||
catch (err) {
|
||||
Logger.error("PluginManager", "Could not compile addon.", err, {addon});
|
||||
throw new AddonError(addon.name || addon.filename, module.filename, Strings.Addons.compileError, {message: err.message, stack: err.stack}, this.prefix);
|
||||
}
|
||||
|
||||
return super.finalizeAddon(addon);
|
||||
}
|
||||
|
||||
startAddon(id) {return this.startPlugin(id);}
|
||||
|
@ -207,4 +221,4 @@ export default new class PluginManager extends AddonManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -20,7 +20,6 @@ export default new class ThemeManager extends AddonManager {
|
|||
get language() {return "css";}
|
||||
|
||||
initialize() {
|
||||
const errors = super.initialize();
|
||||
Settings.registerPanel("themes", Strings.Panels.themes, {
|
||||
order: 4,
|
||||
element: SettingsRenderer.getAddonPanel(Strings.Panels.themes, this.addonList, this.state, {
|
||||
|
@ -35,7 +34,8 @@ export default new class ThemeManager extends AddonManager {
|
|||
prefix: this.prefix
|
||||
})
|
||||
});
|
||||
return errors;
|
||||
|
||||
return super.initialize();
|
||||
}
|
||||
|
||||
/* Aliases */
|
||||
|
@ -85,4 +85,4 @@ export default new class ThemeManager extends AddonManager {
|
|||
DOMManager.removeTheme(addon.slug + "-theme-container");
|
||||
Toasts.show(Strings.Addons.disabled.format({name: addon.name, version: addon.version}));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Logger from "common/logger";
|
||||
import DiscordModules from "./discordmodules";
|
||||
|
||||
export default class Utilities {
|
||||
/**
|
||||
|
@ -215,4 +216,34 @@ export default class Utilities {
|
|||
|
||||
return classes.join(" ");
|
||||
}
|
||||
}
|
||||
|
||||
static makeLazy(component, fallback = "Loading...") {
|
||||
let cache = null;
|
||||
|
||||
const comp = props => {
|
||||
cache ??= DiscordModules.React.lazy(component);
|
||||
|
||||
return DiscordModules.React.createElement(DiscordModules.React.Suspense, {
|
||||
fallback,
|
||||
}, DiscordModules.React.createElement(cache, props));
|
||||
};
|
||||
|
||||
comp.displayName = "LazyComponent";
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
static makeModuleLazy(getter) {
|
||||
let cache = null;
|
||||
|
||||
return () => {
|
||||
cache ??= getter();
|
||||
|
||||
if (typeof cache === "undefined") {
|
||||
Logger.warn("Utilities~makeModuleLazy", "The following module getter resulted in undefined.", getter);
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,36 @@
|
|||
* @module WebpackModules
|
||||
* @version 0.0.2
|
||||
*/
|
||||
import Events from "./emitter";
|
||||
import Logger from "../../../common/logger";
|
||||
|
||||
const predefine = function (target, prop, effect) {
|
||||
const value = target[prop];
|
||||
Object.defineProperty(target, prop, {
|
||||
get() {return value;},
|
||||
set(newValue) {
|
||||
Object.defineProperty(target, prop, {
|
||||
value: newValue,
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
});
|
||||
|
||||
try {
|
||||
effect(newValue);
|
||||
}
|
||||
catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-setter-return
|
||||
return newValue;
|
||||
},
|
||||
configurable: true
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a given module matches a set of parameters.
|
||||
* @callback module:WebpackModules.Filters~filter
|
||||
|
@ -143,7 +171,72 @@ const wrapFilter = filter => (exports, module, moduleId) => {
|
|||
}
|
||||
};
|
||||
|
||||
export class Patcher {
|
||||
static patches = [];
|
||||
static patchesCount = new Map;
|
||||
|
||||
static initialize() {
|
||||
window.$$bd_string_patches = {};
|
||||
}
|
||||
|
||||
static findPatches(moduleSource) {
|
||||
return this.patches.filter(patch => (patch.once ? !patch._ran : true) && patch.test.test(moduleSource));
|
||||
}
|
||||
|
||||
static constructModule(moduleId, moduleSource) {
|
||||
return (
|
||||
"{" +
|
||||
`const count = ${this.patchesCount.get(moduleId)};\n` +
|
||||
`const id = "${moduleId}";\n` +
|
||||
"const capture = function (variable) {\n" +
|
||||
" return window.$$bd_string_patches[id]?.[variable];\n" +
|
||||
"};\n" +
|
||||
moduleSource +
|
||||
"}\n" +
|
||||
`//# sourceURL=${moduleId}.patched.js`
|
||||
);
|
||||
}
|
||||
|
||||
static patchModule(moduleId, moduleSource) {
|
||||
const patches = this.findPatches(moduleSource);
|
||||
|
||||
if (!patches.length) return {code: moduleSource, count: 0};
|
||||
|
||||
window.$$bd_string_patches[moduleId] = {};
|
||||
this.patchesCount.set(moduleId, 0);
|
||||
|
||||
for (const patch of patches) {
|
||||
if (!patch.regex.test(moduleSource)) {
|
||||
Logger.warn("WebpackModules~Patcher", `The following patch`, patch, "didn't have any affect.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (patch.once) patch._ran = true;
|
||||
|
||||
moduleSource = moduleSource.replace(patch.regex, patch.replace);
|
||||
|
||||
if (patch.variables) {
|
||||
for (const key in patch.variables) {
|
||||
Object.defineProperty(window.$$bd_string_patches, key, Object.getOwnPropertyDescriptor(patch.variables, key));
|
||||
}
|
||||
}
|
||||
|
||||
this.patchesCount.set(moduleId, this.patchesCount.get(moduleId) + 1);
|
||||
}
|
||||
|
||||
return {
|
||||
code: this.constructModule(moduleId, moduleSource),
|
||||
count: this.patchesCount.get(moduleId)
|
||||
};
|
||||
}
|
||||
|
||||
static addPatch(patch) {
|
||||
return this.patches.push(patch);
|
||||
}
|
||||
}
|
||||
|
||||
export default class WebpackModules {
|
||||
static ready = false;
|
||||
|
||||
static find(filter, first = true) {return this.getModule(filter, {first});}
|
||||
static findAll(filter) {return this.getModule(filter, {first: false});}
|
||||
|
@ -458,7 +551,7 @@ export default class WebpackModules {
|
|||
* @return {Array}
|
||||
*/
|
||||
static getAllModules() {
|
||||
return this.require.c;
|
||||
return this.ready ? this.require.c : {};
|
||||
}
|
||||
|
||||
// Webpack Chunk Observing
|
||||
|
@ -467,20 +560,48 @@ export default class WebpackModules {
|
|||
static initialize() {
|
||||
this.handlePush = this.handlePush.bind(this);
|
||||
this.listeners = new Set();
|
||||
|
||||
this.__ORIGINAL_PUSH__ = window[this.chunkName].push;
|
||||
Object.defineProperty(window[this.chunkName], "push", {
|
||||
configurable: true,
|
||||
get: () => this.handlePush,
|
||||
set: (newPush) => {
|
||||
this.__ORIGINAL_PUSH__ = newPush;
|
||||
|
||||
Object.defineProperty(window[this.chunkName], "push", {
|
||||
value: this.handlePush,
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
}
|
||||
Patcher.initialize();
|
||||
|
||||
predefine(window, this.chunkName, webpack => {
|
||||
|
||||
predefine(webpack, "push", originalPush => {
|
||||
this.__ORIGINAL_PUSH__ = originalPush;
|
||||
|
||||
webpack.push([[Symbol()], {}, require => {
|
||||
require.d = (target, exports) => {
|
||||
for (const key in exports) {
|
||||
if (!Reflect.has(exports, key) || target[key]) continue;
|
||||
|
||||
Object.defineProperty(target, key, {
|
||||
get: () => exports[key](),
|
||||
set: v => {exports[key] = () => v;},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
webpack.pop();
|
||||
webpack.push = this.handlePush;
|
||||
});
|
||||
|
||||
const fn = exports => {
|
||||
if (!exports?.Z?.addInterceptor) return;
|
||||
|
||||
this.removeListener(fn);
|
||||
|
||||
const cb = () => {
|
||||
exports.Z.unsubscribe("CONNECTION_OPEN", cb);
|
||||
this.ready = true;
|
||||
Events.dispatch("CLIENT_READY");
|
||||
};
|
||||
|
||||
exports.Z.subscribe("CONNECTION_OPEN", cb);
|
||||
};
|
||||
|
||||
this.addListener(fn);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -505,7 +626,19 @@ export default class WebpackModules {
|
|||
const [, modules] = chunk;
|
||||
|
||||
for (const moduleId in modules) {
|
||||
const originalModule = modules[moduleId];
|
||||
|
||||
const moduleSource = Patcher.patchModule(moduleId, modules[moduleId].toString());
|
||||
let originalModule = modules[moduleId];
|
||||
|
||||
if (moduleSource.count) try {
|
||||
const res = window.eval(moduleSource.code);
|
||||
|
||||
if (typeof res === "function") {
|
||||
originalModule = res;
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.error("WebpackModules~Patcher", `Couldn't patch module ${moduleId}:`, err);
|
||||
}
|
||||
|
||||
modules[moduleId] = (module, exports, require) => {
|
||||
try {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import Events from "../modules/emitter";
|
||||
import WebpackModules from "../modules/webpackmodules";
|
||||
|
||||
Object.defineProperty(window, "Buffer", {
|
||||
get() {return Buffer.getBuffer().Buffer;},
|
||||
configurable: true,
|
||||
enumerable: false
|
||||
Events.addListener("CLIENT_READY", () => {
|
||||
Object.defineProperty(window, "Buffer", {
|
||||
get() {return Buffer.getBuffer().Buffer;},
|
||||
configurable: true,
|
||||
enumerable: false
|
||||
});
|
||||
});
|
||||
|
||||
export default class Buffer {
|
||||
|
@ -14,4 +17,4 @@ export default class Buffer {
|
|||
|
||||
return this.cached;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,4 +76,4 @@ export default function AddonErrorModal({pluginErrors, themeErrors}) {
|
|||
</div>
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,4 +12,4 @@ export default function EmptyImage(props) {
|
|||
</div>
|
||||
{props.children}
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,4 +8,4 @@ export default function NoResults(props) {
|
|||
{props.text || DiscordModules.Strings.SEARCH_NO_RESULTS || ""}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ import {React} from "modules";
|
|||
|
||||
const {useState, useCallback} = React;
|
||||
|
||||
|
||||
export default function Checkbox({checked: initialState, text, onChange: notifyParent}) {
|
||||
const [checked, setChecked] = useState(initialState);
|
||||
const onClick = useCallback(() => {
|
||||
|
@ -20,4 +19,4 @@ export default function Checkbox({checked: initialState, text, onChange: notifyP
|
|||
<span></span>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,4 +62,4 @@ export default forwardRef(function CssEditor({css, openNative, update, save, onC
|
|||
].filter(c => c)}
|
||||
value={css}
|
||||
/>;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {React, DiscordModules, Settings} from "modules";
|
||||
import {React, Settings} from "modules";
|
||||
|
||||
import Checkbox from "./checkbox";
|
||||
|
||||
|
@ -144,4 +144,4 @@ export default forwardRef(function CodeEditor({value, language: requestedLang =
|
|||
<div id={id} className={"editor " + theme}></div>
|
||||
</div>
|
||||
</div>;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import {React} from "modules";
|
||||
import {DiscordModules} from "modules";
|
||||
|
||||
export default ({className}) => <div className={`bd-divider ${className || ""}`}></div>;
|
||||
const React = DiscordModules.React;
|
||||
|
||||
export default ({className}) => <div className={`bd-divider ${className || ""}`}></div>;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import Logger from "common/logger";
|
||||
import {React, IPC} from "modules";
|
||||
import {DiscordModules, IPC} from "modules";
|
||||
|
||||
const React = DiscordModules.React;
|
||||
|
||||
export default class ErrorBoundary extends React.Component {
|
||||
constructor(props) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {React, Events} from "modules";
|
||||
import {Events, React} from "modules";
|
||||
|
||||
import FloatingWindow from "./window";
|
||||
|
||||
|
@ -33,4 +33,4 @@ export default function FloatingWindowContainer() {
|
|||
{window.children}
|
||||
</FloatingWindow>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,4 +154,4 @@ export default function FloatingWindow({id, title, resizable, children, classNam
|
|||
{children}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
import {WebpackModules, React, ReactDOM, DOMManager, Events} from "modules";
|
||||
import FloatingWindowContainer from "./floating/container";
|
||||
import {React, ReactDOM, WebpackModules, DOMManager, Events} from "modules";
|
||||
import Utilities from "../modules/utilities";
|
||||
|
||||
/* eslint-disable new-cap */
|
||||
|
||||
const AppLayerProvider = WebpackModules.getByDisplayName("AppLayerProvider");
|
||||
const FloatingWindowContainer = Utilities.makeLazy(() => import("./floating/container"));
|
||||
const AppLayerProvider = Utilities.makeModuleLazy(() => WebpackModules.getByDisplayName("AppLayerProvider")());
|
||||
|
||||
let hasInitialized = false;
|
||||
export default class FloatingWindows {
|
||||
static initialize() {
|
||||
const container = <FloatingWindowContainer />;
|
||||
const wrapped = AppLayerProvider
|
||||
? React.createElement(AppLayerProvider().props.layerContext.Provider, {value: [document.querySelector("#app-mount > .layerContainer-2v_Sit")]}, container) // eslint-disable-line new-cap
|
||||
: container;
|
||||
const wrapped = container;
|
||||
const div = DOMManager.parseHTML(`<div id="floating-windows-layer">`);
|
||||
DOMManager.bdBody.append(div);
|
||||
ReactDOM.render(wrapped, div);
|
||||
|
@ -22,4 +20,4 @@ export default class FloatingWindows {
|
|||
if (!hasInitialized) this.initialize();
|
||||
return Events.emit("open-window", window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import {React, Strings} from "modules";
|
||||
import {DiscordModules, Strings} from "modules";
|
||||
|
||||
import Editor from "../customcss/editor";
|
||||
import Save from "../icons/save";
|
||||
import Edit from "../icons/edit";
|
||||
|
||||
const {useState, useCallback, forwardRef, useImperativeHandle, useRef} = React;
|
||||
const {useState, useCallback, forwardRef, useImperativeHandle, useRef} = DiscordModules.React;
|
||||
|
||||
|
||||
export default forwardRef(function AddonEditor({content, language, save, openNative, id = "bd-addon-editor"}, ref) {
|
||||
|
@ -39,4 +39,4 @@ export default forwardRef(function AddonEditor({content, language, save, openNat
|
|||
value={content}
|
||||
onChange={onChange}
|
||||
/>;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import {Config} from "data";
|
||||
import Logger from "common/logger";
|
||||
import {WebpackModules, React, ReactDOM, Settings, Strings, DOMManager, DiscordModules, DiscordClasses} from "modules";
|
||||
import {WebpackModules, React, ReactDOM, Settings, Strings, DOMManager, DiscordModules, DiscordClasses, Utilities} from "modules";
|
||||
import FormattableString from "../structs/string";
|
||||
import AddonErrorModal from "./addonerrormodal";
|
||||
import ErrorBoundary from "./errorboundary";
|
||||
|
||||
const AddonErrorModal = Utilities.makeLazy(() => import("./addonerrormodal"));
|
||||
const ErrorBoundary = Utilities.makeLazy(() => import("./errorboundary"));
|
||||
|
||||
export default class Modals {
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import {React, WebpackModules, Patcher, Utilities, Settings, Events, DataStore} from "modules";
|
||||
|
||||
import AddonList from "./settings/addonlist";
|
||||
import SettingsGroup from "./settings/group";
|
||||
import SettingsTitle from "./settings/title";
|
||||
import Header from "./settings/sidebarheader";
|
||||
import {Filters} from "../modules/webpackmodules";
|
||||
|
||||
const AddonList = Utilities.makeLazy(() => import("./settings/addonlist"));
|
||||
const SettingsGroup = Utilities.makeLazy(() => import("./settings/group"));
|
||||
const SettingsTitle = Utilities.makeLazy(() => import("./settings/title"));
|
||||
const Header = Utilities.makeLazy(() => import("./settings/sidebarheader"));
|
||||
|
||||
|
||||
export default new class SettingsRenderer {
|
||||
|
||||
constructor() {
|
||||
|
@ -99,4 +100,4 @@ export default new class SettingsRenderer {
|
|||
const stateNode = Utilities.findInTree(node?.__reactFiber$, m => m && m.getPredicateSections, {walkable: ["return", "stateNode"]});
|
||||
if (stateNode) stateNode.forceUpdate();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -4,9 +4,10 @@ const CircularDependencyPlugin = require("circular-dependency-plugin");
|
|||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
const basePkg = require("../package.json");
|
||||
|
||||
/**@type {import("webpack").Configuration} */
|
||||
module.exports = {
|
||||
mode: "development",
|
||||
target: "node",
|
||||
target: "web",
|
||||
devtool: false,
|
||||
entry: "./src/index.js",
|
||||
output: {
|
||||
|
@ -14,6 +15,7 @@ module.exports = {
|
|||
path: path.resolve(__dirname, "..", "dist")
|
||||
},
|
||||
externals: {
|
||||
"vm": `require("vm")`,
|
||||
"electron": `require("electron")`,
|
||||
"fs": `require("fs")`,
|
||||
"original-fs": `require("original-fs")`,
|
||||
|
@ -53,6 +55,9 @@ module.exports = {
|
|||
}),
|
||||
new webpack.DefinePlugin({
|
||||
"process.env.__VERSION__": JSON.stringify(basePkg.version)
|
||||
}),
|
||||
new webpack.optimize.LimitChunkCountPlugin({
|
||||
maxChunks: 1
|
||||
})
|
||||
],
|
||||
optimization: {
|
||||
|
@ -64,4 +69,4 @@ module.exports = {
|
|||
})
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue