finish managers + basic plugins page

This commit is contained in:
Zack Rauen 2019-06-08 02:35:43 -04:00
parent 0ccf84f803
commit ee47005321
20 changed files with 566 additions and 8370 deletions

7284
js/main.js

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
import Builtin from "../structs/builtin";
import {Config, SettingsCookie, Emotes, EmoteBlacklist, EmoteInfo, EmoteModifiers, EmoteOverrides, State} from "data";
import {Utilities, WebpackModules, DataStore, DiscordModules, Events} from "modules";
import {Config, Emotes, EmoteBlacklist, EmoteInfo, EmoteModifiers, EmoteOverrides, State} from "data";
import {Utilities, WebpackModules, DataStore, DiscordModules, Events, Settings} from "modules";
import BDEmote from "../ui/emote";
import {Toasts} from "ui";
@ -72,7 +72,7 @@ export default new class EmoteModule extends Builtin {
let emoteOverride = emoteModifier.slice(0);
if (emoteName.length < 4 || EmoteBlacklist.includes(emoteName)) continue;
if (!EmoteModifiers.includes(emoteModifier) || !SettingsCookie["bda-es-8"]) emoteModifier = "";
if (!EmoteModifiers.includes(emoteModifier) || !Settings.get(this.category, "general", "modifiers")) emoteModifier = "";
if (!EmoteOverrides.includes(emoteOverride)) emoteOverride = "";
else emoteModifier = emoteOverride;
@ -89,7 +89,7 @@ export default new class EmoteModule extends Builtin {
if (Emotes.FrankerFaceZ[emoteName]) current = "FrankerFaceZ";
}
if (!Emotes[current][emoteName] || !SettingsCookie[bdEmoteSettingIDs[current]]) continue;
if (!Emotes[current][emoteName] || !Settings.get(this.category, "categories", bdEmoteSettingIDs[current])) continue;
const results = nodes[n].match(new RegExp(`([\\s]|^)${Utilities.escape(emoteModifier ? emoteName + ":" + emoteModifier : emoteName)}([\\s]|$)`));
if (!results) continue;
const pre = nodes[n].substring(0, results.index + results[1].length);
@ -154,7 +154,7 @@ export default new class EmoteModule extends Builtin {
_fs.unlinkSync(file);
}
if (!SettingsCookie["fork-es-3"]) return;
if (!Settings.get(this.category, "general", "download")) return;
Toasts.show("Downloading emotes in the background do not reload.", {type: "info"});
for (const e in emoteInfo) {

View File

@ -1,11 +1,11 @@
import State from "./state";
import SettingsInfo from "./settings";
import SettingsCookie from "./cookies/settingscookie";
// import SettingsInfo from "./settings";
// import SettingsCookie from "./cookies/settingscookie";
import Config from "./config";
import PluginCookie from "./cookies/plugincookie";
import ThemeCookie from "./cookies/themecookie";
import Themes from "./themes";
import Plugins from "./plugins";
// import PluginCookie from "./cookies/plugincookie";
// import ThemeCookie from "./cookies/themecookie";
// import Themes from "./themes";
// import Plugins from "./plugins";
import Emotes from "./emotes/emotes";
import EmoteBlacklist from "./emotes/blacklist";
import EmoteInfo from "./emotes/info";
@ -15,4 +15,4 @@ import EmoteOverrides from "./emotes/overrides";
import SettingsConfig from "./settings/config";
import SettingsState from "./settings/state";
export {State, SettingsInfo, SettingsCookie, Config, PluginCookie, ThemeCookie, Themes, Plugins, Emotes, EmoteBlacklist, EmoteInfo, EmoteModifiers, EmoteOverrides, SettingsConfig, SettingsState};
export {State, Config, /*SettingsInfo, SettingsCookie, PluginCookie, ThemeCookie, Themes, Plugins,*/ Emotes, EmoteBlacklist, EmoteInfo, EmoteModifiers, EmoteOverrides, SettingsConfig, SettingsState};

View File

@ -1,9 +1,9 @@
import {SettingsCookie, SettingsInfo, Config, PluginCookie, ThemeCookie, Plugins, Themes, Emotes, EmoteBlacklist} from "data";
import {Config, /*SettingsCookie, SettingsInfo, PluginCookie, ThemeCookie, Plugins, Themes,*/ Emotes, EmoteBlacklist} from "data";
import proxyLocalStorage from "./localstorage";
import Core from "./modules/core";
import BdApi from "./modules/pluginapi";
import PluginManager from "./modules/pluginmanager2";
import ThemeManager from "./modules/thememanager2";
import PluginManager from "./modules/pluginmanager";
import ThemeManager from "./modules/thememanager";
import {bdPluginStorage} from "./modules/oldstorage";
import Events from "./modules/emitter";
@ -16,14 +16,14 @@ document.body.appendChild(loadingIcon);
// window.Core = Core;
window.BdApi = BdApi;
window.settings = SettingsInfo;
window.settingsCookie = SettingsCookie;
window.pluginCookie = PluginCookie;
window.themeCookie = ThemeCookie;
// window.settings = SettingsInfo;
// window.settingsCookie = SettingsCookie;
// window.pluginCookie = PluginCookie;
// window.themeCookie = ThemeCookie;
window.pluginModule = PluginManager;
window.themeModule = ThemeManager;
window.bdthemes = Themes;
window.bdplugins = Plugins;
// window.bdthemes = Themes;
// window.bdplugins = Plugins;
window.bdEmotes = Emotes;
window.bemotes = EmoteBlacklist;
window.bdPluginStorage = bdPluginStorage;

View File

@ -1,194 +1,247 @@
import {Config, Plugins, Themes} from "data";
import Utilities from "./utilities";
import PluginManager from "./pluginmanager";
import ThemeManager from "./thememanager";
import Settings from "./settingsmanager";
import Events from "./emitter";
import DataStore from "./datastore";
import ContentError from "../structs/contenterror";
import MetaError from "../structs/metaerror";
import {Toasts} from "ui";
const path = require("path");
const fs = require("fs");
const Module = require("module").Module;
Module.globalPaths.push(path.resolve(require("electron").remote.app.getAppPath(), "node_modules"));
class MetaError extends Error {
constructor(message) {
super(message);
this.name = "MetaError";
}
}
const originalJSRequire = Module._extensions[".js"];
const originalCSSRequire = Module._extensions[".css"] ? Module._extensions[".css"] : () => {return null;};
export default new class ContentManager {
const splitRegex = /[^\S\r\n]*?\n[^\S\r\n]*?\*[^\S\r\n]?/;
const escapedAtRegex = /^\\@/;
export default class ContentManager {
get name() {return "";}
get moduleExtension() {return "";}
get extension() {return "";}
get contentFolder() {return "";}
get prefix() {return "content";}
get collection() {return "settings";}
get category() {return "content";}
get id() {return "autoReload";}
emit(event, ...args) {return Events.emit(`${this.prefix}-${event}`, ...args);}
constructor() {
this.timeCache = {};
this.watchers = {};
Module._extensions[".js"] = this.getContentRequire("plugin");
Module._extensions[".css"] = this.getContentRequire("theme");
this.contentList = [];
this.state = {};
this.originalRequire = Module._extensions[this.moduleExtension];
Module._extensions[this.moduleExtension] = this.getContentRequire();
Settings.on(this.collection, this.category, this.id, (enabled) => {
if (enabled) this.watchContent();
else this.unwatchContent();
});
}
get pluginsFolder() {return this._pluginsFolder || (this._pluginsFolder = fs.realpathSync(path.resolve(Config.dataPath + "plugins/")));}
get themesFolder() {return this._themesFolder || (this._themesFolder = fs.realpathSync(path.resolve(Config.dataPath + "themes/")));}
// Subclasses should overload this and modify the content object as needed to fully load it
initializeContent() {return;}
watchContent(contentType) {
if (this.watchers[contentType]) return;
const isPlugin = contentType === "plugin";
const baseFolder = isPlugin ? this.pluginsFolder : this.themesFolder;
const fileEnding = isPlugin ? ".plugin.js" : ".theme.css";
this.watchers[contentType] = fs.watch(baseFolder, {persistent: false}, async (eventType, filename) => {
if (!eventType || !filename || !filename.endsWith(fileEnding)) return;
// Subclasses should overload this and modify the content as needed to require() the file
getContentModification(module, content) {return content;}
startContent() {return;}
stopContent() {return;}
loadState() {
const saved = DataStore.getData(`${this.prefix}s`);
console.log(saved);
if (!saved) return;
Object.assign(this.state, saved);
}
saveState() {
DataStore.setData(`${this.prefix}s`, this.state);
}
watchContent() {
if (this.watcher) return Utilities.err(this.name, "Already watching content.");
Utilities.log(this.name, "Starting to watch content.");
this.watcher = fs.watch(this.contentFolder, {persistent: false}, async (eventType, filename) => {
if (!eventType || !filename || !filename.endsWith(this.extension)) return;
await new Promise(r => setTimeout(r, 50));
try {fs.statSync(path.resolve(baseFolder, filename));}
try {fs.statSync(path.resolve(this.contentFolder, filename));}
catch (err) {
if (err.code !== "ENOENT") return;
delete this.timeCache[filename];
if (isPlugin) return PluginManager.unloadPlugin(filename);
return ThemeManager.unloadTheme(filename);
this.unloadContent(filename, true);
}
if (!fs.statSync(path.resolve(baseFolder, filename)).isFile()) return;
const stats = fs.statSync(path.resolve(baseFolder, filename));
if (!fs.statSync(path.resolve(this.contentFolder, filename)).isFile()) return;
const stats = fs.statSync(path.resolve(this.contentFolder, filename));
if (!stats || !stats.mtime || !stats.mtime.getTime()) return;
if (typeof(stats.mtime.getTime()) !== "number") return;
if (this.timeCache[filename] == stats.mtime.getTime()) return;
this.timeCache[filename] = stats.mtime.getTime();
if (eventType == "rename") {
if (isPlugin) PluginManager.loadPlugin(filename);
else ThemeManager.loadTheme(filename);
}
if (eventType == "change") {
if (isPlugin) PluginManager.reloadPlugin(filename);
else ThemeManager.reloadTheme(filename);
}
if (eventType == "rename") this.loadContent(filename, true);
if (eventType == "change") this.reloadContent(filename, true);
});
}
unwatchContent(contentType) {
if (!this.watchers[contentType]) return;
this.watchers[contentType].close();
delete this.watchers[contentType];
unwatchContent() {
if (!this.watcher) return Utilities.err(this.name, "Was not watching content.");
this.watcher.close();
delete this.watcher;
Utilities.log(this.name, "No longer watching content.");
}
extractMeta(content) {
const meta = content.split("\n")[0];
const rawMeta = meta.substring(meta.lastIndexOf("//META") + 6, meta.lastIndexOf("*//"));
if (meta.indexOf("META") < 0) throw new MetaError("META was not found.");
if (!Utilities.testJSON(rawMeta)) throw new MetaError("META could not be parsed.");
const firstLine = content.split("\n")[0];
const hasOldMeta = firstLine.includes("//META");
if (hasOldMeta) return this.parseOldMeta(content);
const hasNewMeta = firstLine.includes("/**");
if (hasNewMeta) return this.parseNewMeta(content);
throw new MetaError("META was not found.");
}
const parsed = JSON.parse(rawMeta);
parseOldMeta(content) {
const meta = content.split("\n")[0];
const metaData = meta.substring(meta.lastIndexOf("//META") + 6, meta.lastIndexOf("*//"));
if (!Utilities.testJSON(metaData)) throw new MetaError("META could not be parsed.");
const parsed = JSON.parse(metaData);
if (!parsed.name) throw new MetaError("META missing name data.");
return parsed;
}
getContentRequire(type) {
const isPlugin = type === "plugin";
parseNewMeta(content) {
const block = content.split("/**", 2)[1].split("*/", 1)[0];
const out = {};
let field = "";
let accum = "";
for (const line of block.split(splitRegex)) {
if (line.length === 0) continue;
if (line.charAt(0) === "@" && line.charAt(1) !== " ") {
out[field] = accum;
const l = line.indexOf(" ");
field = line.substr(1, l - 1);
accum = line.substr(l + 1);
}
else {
accum += " " + line.replace("\\n", "\n").replace(escapedAtRegex, "@");
}
}
out[field] = accum.trim();
delete out[""];
return out;
}
getContentRequire() {
const self = this;
const originalRequire = isPlugin ? originalJSRequire : originalCSSRequire;
// const baseFolder = this.contentFolder;
const originalRequire = this.originalRequire;
return function(module, filename) {
const baseFolder = isPlugin ? self.pluginsFolder : self.themesFolder;
const possiblePath = path.resolve(baseFolder, path.basename(filename));
const possiblePath = path.resolve(self.contentFolder, path.basename(filename));
if (!fs.existsSync(possiblePath) || filename !== fs.realpathSync(possiblePath)) return Reflect.apply(originalRequire, this, arguments);
let content = fs.readFileSync(filename, "utf8");
content = Utilities.stripBOM(content);
const meta = self.extractMeta(content);
meta.id = meta.name;
meta.filename = path.basename(filename);
if (!isPlugin) {
meta.css = content.split("\n").slice(1).join("\n");
content = `module.exports = ${JSON.stringify(meta)};`;
}
if (isPlugin) {
content += `\nmodule.exports = ${JSON.stringify(meta)};\nmodule.exports.type = ${meta.name};`;
}
content = self.getContentModification(module, content, meta);
module._compile(content, filename);
};
}
makePlaceholderPlugin(data) {
return {plugin: {
start: () => {},
getName: () => {return data.name || data.filename;},
getAuthor: () => {return "???";},
getDescription: () => {return data.message ? data.message : "This plugin was unable to be loaded. Check the author's page for updates.";},
getVersion: () => {return "???";}
},
name: data.name || data.filename,
filename: data.filename,
source: data.source ? data.source : "",
website: data.website ? data.website : ""
};
// Subclasses should use the return (if not ContentError) and push to this.contentList
loadContent(filename, shouldToast = true) {
if (typeof(filename) === "undefined") return;
try {__non_webpack_require__(path.resolve(this.contentFolder, filename));}
catch (error) {return new ContentError(filename, filename, "Could not be compiled.", {message: error.message, stack: error.stack});}
const content = __non_webpack_require__(path.resolve(this.contentFolder, filename));
console.log(content);
if (this.contentList.find(c => c.id == content.id)) return new ContentError(content.name, filename, `There is already a plugin with name ${content.name}`);
const error = this.initializeContent(content);
if (error) return error;
this.contentList.push(content);
if (shouldToast) Toasts.success(`${content.name} v${content.version} was loaded.`);
this.emit("loaded", content.id);
if (!this.state[content.id]) return this.state[content.id] = false;
return this.startContent(content);
}
loadContent(filename, type) {
if (typeof(filename) === "undefined" || typeof(type) === "undefined") return;
const isPlugin = type === "plugin";
const baseFolder = isPlugin ? this.pluginsFolder : this.themesFolder;
try {__non_webpack_require__(path.resolve(baseFolder, filename));}
catch (error) {return {name: filename, file: filename, message: "Could not be compiled.", error: {message: error.message, stack: error.stack}};}
const content = __non_webpack_require__(path.resolve(baseFolder, filename));
if (isPlugin) {
if (!content.type) return;
try {
content.plugin = new content.type();
delete Plugins[content.plugin.getName()];
Plugins[content.plugin.getName()] = content;
}
catch (error) {return {name: filename, file: filename, message: "Could not be constructed.", error: {message: error.message, stack: error.stack}};}
}
else {
delete Themes[content.name];
Themes[content.name] = content;
}
}
unloadContent(filename, type) {
if (typeof(filename) === "undefined" || typeof(type) === "undefined") return;
const isPlugin = type === "plugin";
const baseFolder = isPlugin ? this.pluginsFolder : this.themesFolder;
try {
delete __non_webpack_require__.cache[__non_webpack_require__.resolve(path.resolve(baseFolder, filename))];
}
catch (err) {return {name: filename, file: filename, message: "Could not be unloaded.", error: {message: err.message, stack: err.stack}};}
}
isLoaded(filename, type) {
const isPlugin = type === "plugin";
const baseFolder = isPlugin ? this.pluginsFolder : this.themesFolder;
try {__non_webpack_require__.cache[__non_webpack_require__.resolve(path.resolve(baseFolder, filename))];}
catch (err) {return false;}
unloadContent(idOrFileOrContent, shouldToast = true) {
const content = typeof(idOrFileOrContent) == "string" ? this.contentList.find(c => c.id == idOrFileOrContent || c.filename == idOrFileOrContent) : idOrFileOrContent;
if (!content) return false;
if (this.state[content.id]) this.disableContent(content);
delete __non_webpack_require__.cache[__non_webpack_require__.resolve(path.resolve(this.contentFolder, content.filename))];
this.contentList.splice(this.contentList.indexOf(content), 1);
this.emit("unloaded", content.id);
if (shouldToast) Toasts.success(`${content.name} was unloaded.`);
return true;
}
reloadContent(filename, type) {
const cantUnload = this.unloadContent(filename, type);
if (cantUnload) return cantUnload;
return this.loadContent(filename, type);
reloadContent(filename) {
const didUnload = this.unloadContent(filename);
if (!didUnload) return didUnload;
return this.loadContent(filename);
}
loadNewContent(type) {
const isPlugin = type === "plugin";
const fileEnding = isPlugin ? ".plugin.js" : ".theme.css";
const basedir = isPlugin ? this.pluginsFolder : this.themesFolder;
const files = fs.readdirSync(basedir);
const contentList = Object.values(isPlugin ? Plugins : Themes);
const removed = contentList.filter(t => !files.includes(t.filename)).map(c => isPlugin ? c.plugin.getName() : c.name);
const added = files.filter(f => !contentList.find(t => t.filename == f) && f.endsWith(fileEnding) && fs.statSync(path.resolve(basedir, f)).isFile());
isLoaded(idOrFile) {
const content = this.contentList.find(c => c.id == idOrFile || c.filename == idOrFile);
if (!content) return false;
return true;
}
isEnabled(idOrFile) {
const content = this.contentList.find(c => c.id == idOrFile || c.filename == idOrFile);
if (!content) return false;
return this.state[content.id];
}
enableContent(idOrContent) {
const content = typeof(idOrContent) == "string" ? this.contentList.find(p => p.id == idOrContent) : idOrContent;
if (!content) return;
if (this.state[content.id]) return;
this.state[content.id] = true;
this.startContent(content);
this.saveState();
}
disableContent(idOrContent) {
const content = typeof(idOrContent) == "string" ? this.contentList.find(p => p.id == idOrContent) : idOrContent;
if (!content) return;
if (!this.state[content.id]) return;
this.state[content.id] = false;
this.stopContent(content);
this.saveState();
}
toggleContent(id) {
if (this.state[id]) this.disableContent(id);
else this.enableContent(id);
}
loadNewContent() {
const files = fs.readdirSync(this.contentFolder);
const removed = this.contentList.filter(t => !files.includes(t.filename)).map(c => c.id);
const added = files.filter(f => !this.contentList.find(t => t.filename == f) && f.endsWith(this.extension) && fs.statSync(path.resolve(this.contentFolder, f)).isFile());
return {added, removed};
}
loadAllContent(type) {
const isPlugin = type === "plugin";
const fileEnding = isPlugin ? ".plugin.js" : ".theme.css";
const basedir = isPlugin ? this.pluginsFolder : this.themesFolder;
const errors = [];
const files = fs.readdirSync(basedir);
for (const filename of files) {
if (!fs.statSync(path.resolve(basedir, filename)).isFile() || !filename.endsWith(fileEnding)) continue;
const error = this.loadContent(filename, type);
if (error) errors.push(error);
}
return errors;
updateList() {
const results = this.loadNewContent();
for (const filename of results.added) this.loadContent(filename);
for (const name of results.removed) this.unloadContent(name);
}
loadPlugins() {return this.loadAllContent("plugin");}
loadThemes() {return this.loadAllContent("theme");}
};
loadAllContent() {
this.loadState();
const errors = [];
const files = fs.readdirSync(this.contentFolder);
for (const filename of files) {
if (!fs.statSync(path.resolve(this.contentFolder, filename)).isFile() || !filename.endsWith(this.extension)) continue;
const content = this.loadContent(filename, false);
if (content instanceof ContentError) errors.push(content);
}
this.saveState();
if (Settings.get(this.collection, this.category, this.id)) this.watchContent();
return errors;
}
}

View File

@ -1,248 +0,0 @@
import Utilities from "./utilities";
import Settings from "./settingsmanager";
import Events from "./emitter";
import DataStore from "./datastore";
import ContentError from "../structs/contenterror";
import MetaError from "../structs/metaerror";
const path = require("path");
const fs = require("fs");
const Module = require("module").Module;
Module.globalPaths.push(path.resolve(require("electron").remote.app.getAppPath(), "node_modules"));
const splitRegex = /[^\S\r\n]*?\n[^\S\r\n]*?\*[^\S\r\n]?/;
const escapedAtRegex = /^\\@/;
export default class ContentManager {
get name() {return "";}
get moduleExtension() {return "";}
get extension() {return "";}
get contentFolder() {return "";}
get prefix() {return "content";}
get collection() {return "settings";}
get category() {return "content";}
get id() {return "autoReload";}
emit(event, ...args) {return Events.emit(`${this.prefix}-${event}`, ...args);}
constructor() {
this.timeCache = {};
this.contentList = [];
this.state = {};
this.originalRequire = Module._extensions[this.moduleExtension];
Module._extensions[this.moduleExtension] = this.getContentRequire();
Settings.on(this.collection, this.category, this.id, (enabled) => {
if (enabled) this.watchContent();
else this.unwatchContent();
});
}
loadState() {
const saved = DataStore.getData(`${this.prefix}s`);
console.log(saved);
if (!saved) return;
Object.assign(this.state, saved);
}
saveState() {
DataStore.setData(`${this.prefix}s`, this.state);
}
watchContent() {
if (this.watcher) return Utilities.err(this.name, "Already watching content.");
Utilities.log(this.name, "Starting to watch content.");
this.watcher = fs.watch(this.contentFolder, {persistent: false}, async (eventType, filename) => {
if (!eventType || !filename || !filename.endsWith(this.extension)) return;
await new Promise(r => setTimeout(r, 50));
try {fs.statSync(path.resolve(this.contentFolder, filename));}
catch (err) {
if (err.code !== "ENOENT") return;
delete this.timeCache[filename];
this.unloadContent(filename, true);
}
if (!fs.statSync(path.resolve(this.contentFolder, filename)).isFile()) return;
const stats = fs.statSync(path.resolve(this.contentFolder, filename));
if (!stats || !stats.mtime || !stats.mtime.getTime()) return;
if (typeof(stats.mtime.getTime()) !== "number") return;
if (this.timeCache[filename] == stats.mtime.getTime()) return;
this.timeCache[filename] = stats.mtime.getTime();
if (eventType == "rename") this.loadContent(filename, true);
if (eventType == "change") this.reloadContent(filename, true);
});
}
unwatchContent() {
if (!this.watcher) return Utilities.err(this.name, "Was not watching content.");
this.watcher.close();
delete this.watcher;
Utilities.log(this.name, "No longer watching content.");
}
extractMeta(content) {
const firstLine = content.split("\n")[0];
const hasOldMeta = firstLine.includes("//META");
if (hasOldMeta) return this.parseOldMeta(content);
const hasNewMeta = firstLine.includes("/**");
if (hasNewMeta) return this.parseNewMeta(content);
throw new MetaError("META was not found.");
}
parseOldMeta(content) {
const meta = content.split("\n")[0];
const rawMeta = meta.substring(meta.lastIndexOf("//META") + 6, meta.lastIndexOf("*//"));
if (meta.indexOf("META") < 0) throw new MetaError("META was not found.");
if (!Utilities.testJSON(rawMeta)) throw new MetaError("META could not be parsed.");
const parsed = JSON.parse(rawMeta);
if (!parsed.name) throw new MetaError("META missing name data.");
return parsed;
}
parseNewMeta(content) {
const block = content.split("/**", 2)[1].split("*/", 1)[0];
const stripped = block.replace(/^\s*\*\s?/mg, "");
const out = {};
let field = "";
let accum = "";
stripped.split("\n").forEach(line => {
const fieldCandidate = line.split(/\s/g, 1)[0];
if (fieldCandidate.length > 1 && fieldCandidate.charAt(0) === "@") {
out[field] = accum.trim();
field = fieldCandidate.substr(1);
accum = line.substr(fieldCandidate.length);
}
else {
accum += " " + line.trim().replace("\\n", "\n").replace(/^\\@/, "@");
}
});
out[field] = accum.trim();
delete out[""];
return out;
}
parseNewMeta2(content) {
const block = content.split("/**", 2)[1].split("*/", 1)[0];
const out = {};
let field = "";
let accum = "";
for (const line of block.split(splitRegex)) {
if (line.length === 0) continue;
if (line.charAt(0) === "@" && line.charAt(1) !== " ") {
out[field] = accum;
const l = line.indexOf(" ");
field = line.substr(1, l - 1);
accum = line.substr(l + 1);
}
else {
accum += " " + line.replace("\\n", "\n").replace(escapedAtRegex, "@");
}
}
out[field] = accum.trim();
delete out[""];
return out;
}
getContentRequire() {
const self = this;
// const baseFolder = this.contentFolder;
const originalRequire = this.originalRequire;
return function(module, filename) {
const possiblePath = path.resolve(self.contentFolder, path.basename(filename));
if (!fs.existsSync(possiblePath) || filename !== fs.realpathSync(possiblePath)) return Reflect.apply(originalRequire, this, arguments);
let content = fs.readFileSync(filename, "utf8");
content = Utilities.stripBOM(content);
const meta = self.extractMeta(content);
meta.id = meta.name;
meta.filename = path.basename(filename);
content = self.getContentModification(module, content, meta);
module._compile(content, filename);
};
}
// Subclasses should use the return (if not ContentError) and push to this.contentList
loadContent(filename) {
if (typeof(filename) === "undefined") return;
try {__non_webpack_require__(path.resolve(this.contentFolder, filename));}
catch (error) {return new ContentError(filename, filename, "Could not be compiled.", {message: error.message, stack: error.stack});}
return __non_webpack_require__(path.resolve(this.contentFolder, filename));
}
// Subclasses should overload this and modify the content as needed to require() the file
getContentModification(module, content) {return content;}
unloadContent(idOrFileOrContent, fromWatcher) {
const content = typeof(idOrFileOrContent) == "string" ? this.contentList.find(c => c.id == idOrFileOrContent || c.filename == idOrFileOrContent) : idOrFileOrContent;
if (!content) return false;
if (this.state[content.id]) this.disableContent(content, fromWatcher);
delete __non_webpack_require__.cache[__non_webpack_require__.resolve(path.resolve(this.contentFolder, content.filename))];
this.contentList.splice(this.contentList.indexOf(content), 1);
this.emit("unloaded", content.id);
Toasts.success(`${content.name} was unloaded.`);
return true;
}
isLoaded(idOrFile) {
const content = this.contentList.find(c => c.id == idOrFile || c.filename == idOrFile);
if (!content) return false;
return true;
}
reloadContent(filename, fromWatcher) {
const didUnload = this.unloadContent(filename, fromWatcher);
if (!didUnload) return didUnload;
return this.loadContent(filename, fromWatcher);
}
enableContent(idOrContent, fromWatcher = false) {
const content = typeof(idOrContent) == "string" ? this.contentList.find(p => p.id == idOrContent) : idOrContent;
if (!content) return;
if (this.state[content.id]) return;
this.state[content.id] = true;
this.startContent(content);
if (!fromWatcher) this.saveState();
}
disableContent(idOrContent, fromWatcher = false) {
const content = typeof(idOrContent) == "string" ? this.contentList.find(p => p.id == idOrContent) : idOrContent;
if (!content) return;
if (!this.state[content.id]) return;
this.state[content.id] = false;
this.stopContent(content);
if (!fromWatcher) this.saveState();
}
toggleContent(id) {
if (this.state[id]) this.disableContent(id);
else this.enableContent(id);
}
loadNewContent() {
const files = fs.readdirSync(this.contentFolder);
const removed = this.contentList.filter(t => !files.includes(t.filename)).map(c => c.id);
const added = files.filter(f => !this.contentList.find(t => t.filename == f) && f.endsWith(this.extension) && fs.statSync(path.resolve(this.contentFolder, f)).isFile());
return {added, removed};
}
updateList() {
const results = this.loadNewContent();
for (const filename of results.added) this.loadContent(filename);
for (const name of results.removed) this.unloadContent(name);
}
loadAllContent() {
this.loadState();
const errors = [];
const files = fs.readdirSync(this.contentFolder);
for (const filename of files) {
if (!fs.statSync(path.resolve(this.contentFolder, filename)).isFile() || !filename.endsWith(this.extension)) continue;
const content = this.loadContent(filename);
if (content instanceof ContentError) errors.push(content);
}
this.saveState();
if (Settings.get(this.collection, this.category, this.id)) this.watchContent();
return errors;
}
}

View File

@ -3,8 +3,8 @@ import Utilities from "./utilities";
import {Config} from "data";
// import EmoteModule from "./emotes";
// import QuickEmoteMenu from "../builtins/emotemenu";
import PluginManager from "./pluginmanager2";
import ThemeManager from "./thememanager2";
import PluginManager from "./pluginmanager";
import ThemeManager from "./thememanager";
import Settings from "./settingsmanager";
import * as Builtins from "builtins";
import {Modals} from "ui";
@ -48,10 +48,10 @@ Core.prototype.init = async function() {
for (const module in Builtins) Builtins[module].initialize();
Utilities.log("Startup", "Loading Plugins");
const pluginErrors = PluginManager.loadAllContent();
const pluginErrors = PluginManager.loadAllPlugins();
Utilities.log("Startup", "Loading Themes");
const themeErrors = ThemeManager.loadAllContent();
const themeErrors = ThemeManager.loadAllThemes();
$("#customcss").detach().appendTo(document.head);

View File

@ -15,16 +15,11 @@ import Events from "./emitter";
import PluginManager from "./pluginmanager";
// import PublicServers from "./publicservers";
import ThemeManager from "./thememanager";
import Settings from "./settingsmanager";
export const React = DiscordModules.React;
export const ReactDOM = DiscordModules.ReactDOM;
export {BDV2, BdApi, Core, ContentManager, DataStore,
Events, PluginManager, /*PublicServers,*/ ThemeManager,
Utilities, WebpackModules, DiscordModules};
// export {{
// get React() {return DiscordModules.React;}
// }}
Utilities, WebpackModules, DiscordModules, Settings};

View File

@ -1,4 +1,3 @@
import {Plugins, SettingsCookie, PluginCookie, ThemeCookie} from "data";
import Utilities from "./utilities";
import WebpackModules, {DiscordModules} from "./webpackmodules";
import DataStore from "./datastore";
@ -67,15 +66,6 @@ BdApi.unlinkJS = function (id) {
$("#" + Utilities.escapeID(id)).remove();
};
//Get another plugin
//name = name of plugin
BdApi.getPlugin = function (name) {
if (Plugins.hasOwnProperty(name)) {
return Plugins[name].plugin;
}
return null;
};
/**
* Shows a generic but very customizable modal.
* @param {string} title - title of the modal
@ -183,17 +173,26 @@ BdApi.testJSON = function(data) {
return Utilities.testJSON(data);
};
BdApi.isPluginEnabled = function(name) {
return !!PluginCookie[name];
};
//Get another plugin
//name = name of plugin
// BdApi.getPlugin = function (name) {
// if (Plugins.hasOwnProperty(name)) {
// return Plugins[name].plugin;
// }
// return null;
// };
BdApi.isThemeEnabled = function(name) {
return !!ThemeCookie[name];
};
// BdApi.isPluginEnabled = function(name) {
// return !!PluginCookie[name];
// };
BdApi.isSettingEnabled = function(id) {
return !!SettingsCookie[id];
};
// BdApi.isThemeEnabled = function(name) {
// return !!ThemeCookie[name];
// };
// BdApi.isSettingEnabled = function(id) {
// return !!SettingsCookie[id];
// };
// Gets data
BdApi.getBDData = function(key) {

View File

@ -1,214 +1,155 @@
import {PluginCookie, Plugins} from "data";
import {Config} from "data";
import ContentManager from "./contentmanager";
import Utilities from "./utilities";
import Emitter from "./emitter";
import DataStore from "./datastore";
import {Toasts, Modals} from "ui";
import ContentError from "../structs/contenterror";
import Settings from "./settingsmanager";
import {SettingsPanel as SettingsRenderer} from "ui";
function PluginModule() {
const path = require("path");
const electronRemote = require("electron").remote;
}
export default new class PluginManager extends ContentManager {
get name() {return "PluginManager";}
get moduleExtension() {return ".js";}
get extension() {return ".plugin.js";}
get contentFolder() {return path.resolve(Config.dataPath, "plugins");}
get prefix() {return "plugin";}
PluginModule.prototype.loadPlugins = function () {
this.loadPluginData();
const errors = ContentManager.loadPlugins();
const plugins = Object.keys(Plugins);
for (let i = 0; i < plugins.length; i++) {
let plugin, name;
constructor() {
super();
this.onSwitch = this.onSwitch.bind(this);
this.observer = new MutationObserver((mutations) => {
for (let i = 0, mlen = mutations.length; i < mlen; i++) {
this.onMutation(mutations[i]);
}
});
}
/* Aliases */
updatePluginList() {return this.updateList();}
enablePlugin(idOrContent) {return this.enableContent(idOrContent);}
disablePlugin(idOrContent) {return this.disableContent(idOrContent);}
togglePlugin(id) {return this.toggleContent(id);}
unloadPlugin(idOrFileOrContent) {return this.unloadContent(idOrFileOrContent);}
loadPlugin(filename) {
const error = this.loadContent(filename);
if (error) Modals.showContentErrors({themes: [error]});
}
reloadPlugin(filename) {
const error = this.reloadContent(filename);
if (error) Modals.showContentErrors({themes: [error]});
}
loadAllPlugins() {
const errors = this.loadAllContent();
this.setupFunctions();
Settings.registerPanel("Plugins", {element: () => SettingsRenderer.getPluginsPanel(this.contentList)});
return errors;
}
/* Overrides */
initializeContent(content) {
if (!content.type) return new ContentError(content.name, content.filename, "Plugin had no exports", {message: "Plugin had no exports or no name property.", stack: ""});
try {
plugin = Plugins[plugins[i]].plugin;
name = plugin.getName();
if (plugin.load && typeof(plugin.load) == "function") plugin.load();
const thePlugin = new content.type();
content.plugin = thePlugin;
content.name = content.name || thePlugin.getName();
content.author = content.author || thePlugin.getAuthor() || "No author";
content.description = content.description || thePlugin.getDescription() || "No description";
content.version = content.version || thePlugin.getVersion() || "No version";
try {
if (typeof(content.plugin.load) == "function") content.plugin.load();
}
catch (error) {
this.state[content.id] = false;
return new ContentError(content.name, content.filename, "load() could not be fired.", {message: error.message, stack: error.stack});
}
}
catch (error) {return new ContentError(content.name, content.filename, "Could not be constructed.", {message: error.message, stack: error.stack});}
}
getContentModification(module, content, meta) {
module._compile(content, module.filename);
const didExport = !Utilities.isEmpty(module.exports);
if (didExport) {
meta.type = module.exports;
module.exports = meta;
return "";
}
content += `\nmodule.exports = ${JSON.stringify(meta)};\nmodule.exports.type = ${meta.exports || meta.name};`;
return content;
}
startContent(id) {return this.startPlugin(id);}
stopContent(id) {return this.stopPlugin(id);}
startPlugin(idOrContent) {
const content = typeof(idOrContent) == "string" ? this.contentList.find(p => p.id == idOrContent) : idOrContent;
if (!content) return;
const plugin = content.plugin;
try {
plugin.start();
this.emit("started", content.id);
Toasts.show(`${content.name} v${content.version} has started.`);
}
catch (err) {
PluginCookie[name] = false;
Utilities.err("Plugins", name + " could not be loaded.", err);
errors.push({name: name, file: Plugins[plugins[i]].filename, message: "load() could not be fired.", error: {message: err.message, stack: err.stack}});
continue;
this.state[content.id] = false;
Toasts.error(`${content.name} v${content.version} could not be started.`);
Utilities.err("Plugins", content.name + " could not be started.", err);
return new ContentError(content.name, content.filename, "start() could not be fired.", {message: err.message, stack: err.stack});
}
}
if (!PluginCookie[name]) PluginCookie[name] = false;
stopPlugin(idOrContent) {
const content = typeof(idOrContent) == "string" ? this.contentList.find(p => p.id == idOrContent) : idOrContent;
if (!content) return;
const plugin = content.plugin;
try {
plugin.stop();
this.emit("stopped", content.id);
Toasts.show(`${content.name} v${content.version} has stopped.`);
}
catch (err) {
this.state[content.id] = false;
Toasts.error(`${content.name} v${content.version} could not be stopped.`);
Utilities.err("Plugins", content.name + " could not be stopped.", err);
return new ContentError(content.name, content.filename, "stop() could not be fired.", {message: err.message, stack: err.stack});
}
}
if (PluginCookie[name]) {
try {
plugin.start();
Toasts.show(`${plugin.getName()} v${plugin.getVersion()} has started.`);
}
catch (err) {
PluginCookie[name] = false;
Utilities.err("Plugins", name + " could not be started.", err);
errors.push({name: name, file: Plugins[plugins[i]].filename, message: "start() could not be fired.", error: {message: err.message, stack: err.stack}});
setupFunctions() {
electronRemote.getCurrentWebContents().on("did-navigate-in-page", this.onSwitch.bind(this));
this.observer.observe(document, {
childList: true,
subtree: true
});
}
onSwitch() {
this.emit("page-switch");
for (let i = 0; i < this.contentList.length; i++) {
const plugin = this.contentList[i].plugin;
if (!this.state[this.contentList[i].id]) continue;
if (typeof(plugin.onSwitch) === "function") {
try { plugin.onSwitch(); }
catch (err) { Utilities.err("Plugins", "Unable to fire onSwitch for " + this.contentList[i].name + ".", err); }
}
}
}
this.savePluginData();
require("electron").remote.getCurrentWebContents().on("did-navigate-in-page", this.channelSwitch.bind(this));
// if (SettingsCookie["fork-ps-5"]) ContentManager.watchContent("plugin");
return errors;
};
PluginModule.prototype.startPlugin = function(plugin, reload = false) {
try {
Plugins[plugin].plugin.start();
if (!reload) Toasts.show(`${Plugins[plugin].plugin.getName()} v${Plugins[plugin].plugin.getVersion()} has started.`);
}
catch (err) {
if (!reload) Toasts.show(`${Plugins[plugin].plugin.getName()} v${Plugins[plugin].plugin.getVersion()} could not be started.`, {type: "error"});
PluginCookie[plugin] = false;
this.savePluginData();
Utilities.err("Plugins", plugin + " could not be started.", err);
}
};
PluginModule.prototype.stopPlugin = function(plugin, reload = false) {
try {
Plugins[plugin].plugin.stop();
if (!reload) Toasts.show(`${Plugins[plugin].plugin.getName()} v${Plugins[plugin].plugin.getVersion()} has stopped.`);
}
catch (err) {
if (!reload) Toasts.show(`${Plugins[plugin].plugin.getName()} v${Plugins[plugin].plugin.getVersion()} could not be stopped.`, {type: "error"});
Utilities.err("Plugins", Plugins[plugin].plugin.getName() + " could not be stopped.", err);
}
};
PluginModule.prototype.enablePlugin = function (plugin, reload = false) {
if (PluginCookie[plugin]) return;
PluginCookie[plugin] = true;
this.savePluginData();
this.startPlugin(plugin, reload);
};
PluginModule.prototype.disablePlugin = function (plugin, reload = false) {
if (!PluginCookie[plugin]) return;
PluginCookie[plugin] = false;
this.savePluginData();
this.stopPlugin(plugin, reload);
};
PluginModule.prototype.togglePlugin = function (plugin) {
if (PluginCookie[plugin]) this.disablePlugin(plugin);
else this.enablePlugin(plugin);
};
PluginModule.prototype.loadPlugin = function(filename) {
const error = ContentManager.loadContent(filename, "plugin");
if (error) {
Modals.showContentErrors({plugins: [error]});
Toasts.show(`${filename} could not be loaded.`, {type: "error"});
return Utilities.err("ContentManager", `${filename} could not be loaded.`, error);
}
const plugin = Object.values(Plugins).find(p => p.filename == filename).plugin;
try { if (plugin.load && typeof(plugin.load) == "function") plugin.load();}
catch (err) {Modals.showContentErrors({plugins: [err]});}
Utilities.log("ContentManager", `${plugin.getName()} v${plugin.getVersion()} was loaded.`);
Toasts.show(`${plugin.getName()} v${plugin.getVersion()} was loaded.`, {type: "success"});
Emitter.dispatch("plugin-loaded", plugin.getName());
};
PluginModule.prototype.unloadPlugin = function(filenameOrName) {
const bdplugin = Object.values(Plugins).find(p => p.filename == filenameOrName) || Plugins[filenameOrName];
if (!bdplugin) return;
const plugin = bdplugin.plugin.getName();
if (PluginCookie[plugin]) this.disablePlugin(plugin, true);
const error = ContentManager.unloadContent(Plugins[plugin].filename, "plugin");
delete Plugins[plugin];
if (error) {
Modals.showContentErrors({plugins: [error]});
Toasts.show(`${plugin} could not be unloaded. It may have not been loaded yet.`, {type: "error"});
return Utilities.err("ContentManager", `${plugin} could not be unloaded. It may have not been loaded yet.`, error);
}
Utilities.log("ContentManager", `${plugin} was unloaded.`);
Toasts.show(`${plugin} was unloaded.`, {type: "success"});
Emitter.dispatch("plugin-unloaded", plugin);
};
PluginModule.prototype.reloadPlugin = function(filenameOrName) {
const bdplugin = Object.values(Plugins).find(p => p.filename == filenameOrName) || Plugins[filenameOrName];
if (!bdplugin) return this.loadPlugin(filenameOrName);
const plugin = bdplugin.plugin.getName();
const enabled = PluginCookie[plugin];
if (enabled) this.stopPlugin(plugin, true);
const error = ContentManager.reloadContent(Plugins[plugin].filename, "plugin");
if (error) {
Modals.showContentErrors({plugins: [error]});
Toasts.show(`${plugin} could not be reloaded.`, {type: "error"});
return Utilities.err("ContentManager", `${plugin} could not be reloaded.`, error);
}
if (Plugins[plugin].plugin.load && typeof(Plugins[plugin].plugin.load) == "function") Plugins[plugin].plugin.load();
if (enabled) this.startPlugin(plugin, true);
Utilities.log("ContentManager", `${plugin} v${Plugins[plugin].plugin.getVersion()} was reloaded.`);
Toasts.show(`${plugin} v${Plugins[plugin].plugin.getVersion()} was reloaded.`, {type: "success"});
Emitter.dispatch("plugin-reloaded", plugin);
};
PluginModule.prototype.updatePluginList = function() {
const results = ContentManager.loadNewContent("plugin");
for (const filename of results.added) this.loadPlugin(filename);
for (const name of results.removed) this.unloadPlugin(name);
};
PluginModule.prototype.loadPluginData = function () {
const saved = DataStore.getData("plugins");
if (!saved) return;
Object.assign(PluginCookie, saved);
};
PluginModule.prototype.savePluginData = function () {
DataStore.setData("plugins", PluginCookie);
};
PluginModule.prototype.newMessage = function () {
const plugins = Object.keys(Plugins);
for (let i = 0; i < plugins.length; i++) {
const plugin = Plugins[plugins[i]].plugin;
if (!PluginCookie[plugin.getName()]) continue;
if (typeof plugin.onMessage === "function") {
try { plugin.onMessage(); }
catch (err) { Utilities.err("Plugins", "Unable to fire onMessage for " + plugin.getName() + ".", err); }
onMutation(mutation) {
for (let i = 0; i < this.contentList.length; i++) {
const plugin = this.contentList[i].plugin;
if (!this.state[this.contentList[i].id]) continue;
if (typeof plugin.observer === "function") {
try { plugin.observer(mutation); }
catch (err) { Utilities.err("Plugins", "Unable to fire observer for " + this.contentList[i].name + ".", err); }
}
}
}
};
PluginModule.prototype.channelSwitch = function () {
const plugins = Object.keys(Plugins);
for (let i = 0; i < plugins.length; i++) {
const plugin = Plugins[plugins[i]].plugin;
if (!PluginCookie[plugin.getName()]) continue;
if (typeof plugin.onSwitch === "function") {
try { plugin.onSwitch(); }
catch (err) { Utilities.err("Plugins", "Unable to fire onSwitch for " + plugin.getName() + ".", err); }
}
}
};
PluginModule.prototype.rawObserver = function(e) {
const plugins = Object.keys(Plugins);
for (let i = 0; i < plugins.length; i++) {
const plugin = Plugins[plugins[i]].plugin;
if (!PluginCookie[plugin.getName()]) continue;
if (typeof plugin.observer === "function") {
try { plugin.observer(e); }
catch (err) { Utilities.err("Plugins", "Unable to fire observer for " + plugin.getName() + ".", err); }
}
}
};
export default new PluginModule();
// makePlaceholderPlugin(data) {
// return {plugin: {
// start: () => {},
// getName: () => {return data.name || data.filename;},
// getAuthor: () => {return "???";},
// getDescription: () => {return data.message ? data.message : "This plugin was unable to be loaded. Check the author's page for updates.";},
// getVersion: () => {return "???";}
// },
// name: data.name || data.filename,
// filename: data.filename,
// source: data.source ? data.source : "",
// website: data.website ? data.website : ""
// };
// }
};

View File

@ -1,165 +0,0 @@
import {Config} from "data";
import ContentManager from "./contentmanager2";
import Utilities from "./utilities";
import {Toasts, Modals} from "ui";
import ContentError from "../structs/contenterror";
const path = require("path");
const electronRemote = require("electron").remote;
export default new class PluginManager extends ContentManager {
get name() {return "PluginManager";}
get moduleExtension() {return ".js";}
get extension() {return ".plugin.js";}
get contentFolder() {return path.resolve(Config.dataPath, "plugins");}
get prefix() {return "plugin";}
constructor() {
super();
this.onSwitch = this.onSwitch.bind(this);
this.observer = new MutationObserver((mutations) => {
for (let i = 0, mlen = mutations.length; i < mlen; i++) {
this.onMutation(mutations[i]);
}
});
}
/* Aliases */
updatePluginList() {return this.updateList();}
loadAllPlugins() {return this.loadAllContent();}
enablePlugin(idOrContent, fromWatcher = false) {return this.enableContent(idOrContent, fromWatcher);}
disablePlugin(idOrContent, fromWatcher = false) {return this.disableContent(idOrContent, fromWatcher);}
togglePlugin(id) {return this.toggleContent(id);}
loadContent(filename, fromWatcher) {
const error = this.loadPlugin(filename, fromWatcher);
if (!fromWatcher) return error;
if (error) Modals.showContentErrors({plugins: [error]});
}
unloadContent(idOrFileOrContent, fromWatcher) {return this.unloadPlugin(idOrFileOrContent, fromWatcher);}
/* Overrides */
getContentModification(module, content, meta) {
module._compile(content, module.filename);
const didExport = !Utilities.isEmpty(module.exports);
if (didExport) {
meta.type = module.exports;
module.exports = meta;
return "";
}
content += `\nmodule.exports = ${JSON.stringify(meta)};\nmodule.exports.type = ${meta.exports || meta.name};`;
return content;
}
loadPlugin(filename) {
const content = super.loadContent(filename);
if (content instanceof ContentError) return content;
console.log(content);
if (!content.type) return new ContentError(filename, filename, "Plugin had no exports", {message: "Plugin had no exports or no name property.", stack: ""});
try {
const thePlugin = new content.type();
if (this.contentList.find(c => c.id == content.id)) return new ContentError(content.id, filename, `There is already a plugin with name ${content.id}`);
content.plugin = thePlugin;
content.name = content.name || thePlugin.getName();
content.author = content.author || thePlugin.getAuthor();
content.description = content.description || thePlugin.getDescription();
content.version = content.version || thePlugin.getVersion();
this.contentList.push(content);
try {
if (typeof(content.plugin.load) == "function") content.plugin.load();
}
catch (error) {
this.state[content.id] = false;
return new ContentError(content.name, filename, "load() could not be fired.", {message: error.message, stack: error.stack});
}
this.emit("loaded", content.id);
Toasts.success(`${content.name} was loaded.`);
if (!this.state[content.id]) return this.state[content.id] = false;
return this.startPlugin(content);
}
catch (error) {return new ContentError(filename, filename, "Could not be constructed.", {message: error.message, stack: error.stack});}
}
unloadPlugin(idOrFileOrContent, fromWatcher) {
const content = typeof(idOrFileOrContent) == "string" ? this.contentList.find(c => c.id == idOrFileOrContent || c.filename == idOrFileOrContent) : idOrFileOrContent;
if (!content) return false;
if (this.state[content.id]) this.disablePlugin(content, fromWatcher);
super.unloadContent(content);
Toasts.success(`${content.name} was unloaded.`);
this.emit("unloaded", content.id);
return true;
}
reloadPlugin(filename) {
this.reloadContent(filename);
}
startContent(id) {return this.startPlugin(id);}
stopContent(id) {return this.stopPlugin(id);}
startPlugin(idOrContent) {
const content = typeof(idOrContent) == "string" ? this.contentList.find(p => p.id == idOrContent) : idOrContent;
if (!content) return;
const plugin = content.plugin;
try {
plugin.start();
this.emit("started", content.id);
Toasts.show(`${content.name} v${content.version} has started.`);
}
catch (err) {
this.state[content.id] = false;
Toasts.error(`${content.name} v${content.version} could not be started.`);
Utilities.err("Plugins", content.name + " could not be started.", err);
return new ContentError(content.name, content.filename, "start() could not be fired.", {message: err.message, stack: err.stack});
}
}
stopPlugin(idOrContent) {
const content = typeof(idOrContent) == "string" ? this.contentList.find(p => p.id == idOrContent) : idOrContent;
if (!content) return;
const plugin = content.plugin;
try {
plugin.stop();
this.emit("stopped", content.id);
Toasts.show(`${content.name} v${content.version} has stopped.`);
}
catch (err) {
this.state[content.id] = false;
Toasts.error(`${content.name} v${content.version} could not be stopped.`);
Utilities.err("Plugins", content.name + " could not be stopped.", err);
return new ContentError(content.name, content.filename, "stop() could not be fired.", {message: err.message, stack: err.stack});
}
}
setupFunctions() {
electronRemote.getCurrentWebContents().on("did-navigate-in-page", this.onSwitch.bind(this));
this.observer.observe(document, {
childList: true,
subtree: true
});
}
onSwitch() {
this.emit("page-switch");
for (let i = 0; i < this.contentList.length; i++) {
const plugin = this.contentList[i].plugin;
if (!this.state[this.contentList[i].id]) continue;
if (typeof(plugin.onSwitch) === "function") {
try { plugin.onSwitch(); }
catch (err) { Utilities.err("Plugins", "Unable to fire onSwitch for " + this.contentList[i].name + ".", err); }
}
}
}
onMutation(mutation) {
for (let i = 0; i < this.contentList.length; i++) {
const plugin = this.contentList[i].plugin;
if (!this.state[this.contentList[i].id]) continue;
if (typeof plugin.observer === "function") {
try { plugin.observer(mutation); }
catch (err) { Utilities.err("Plugins", "Unable to fire observer for " + this.contentList[i].name + ".", err); }
}
}
}
};

View File

@ -1,9 +1,9 @@
import {SettingsConfig, SettingsState} from "data";
import DataStore from "./datastore";
import ContentManager from "./contentmanager";
// import PluginManager from "./pluginmanager";
import BdApi from "./pluginapi";
import Events from "./emitter";
import WebpackModules from "./webpackmodules";
import WebpackModules, {DiscordModules} from "./webpackmodules";
import {SettingsPanel as SettingsRenderer} from "ui";
import Utilities from "./utilities";
@ -12,26 +12,25 @@ import {Toasts} from "ui";
export default new class SettingsManager {
constructor() {
this.renderer = new SettingsRenderer();
this.config = SettingsConfig;
this.state = SettingsState;
this.panels = [];
this.setup(SettingsConfig, SettingsState);
}
initialize() {
DataStore.initialize();
// if (!DataStore.getSettingGroup("settings")) return this.saveSettings();
// const savedSettings = this.loadSettings();
// $("<style id=\"customcss\">").text(atob(DataStore.getBDData("bdcustomcss"))).appendTo(document.head);
// for (const setting in savedSettings) {
// if (savedSettings[setting] !== undefined) SettingsCookie[setting] = savedSettings[setting];
// }
// this.saveSettings();
this.loadSettings();
this.patchSections();
// this.registerPanel("Plugins", {element: () => SettingsRenderer.getPluginsPanel(PluginManager.contentList)});
}
// Object.assign(this.state, this.defaultState);
// this.initializeConfig(EmoteSettings, EmoteState);
registerPanel(name, options) {
const {element, onClick} = options;
const section = {label: name, section: name};
if (onClick) section.onClick = onClick;
else section.element = element instanceof DiscordModules.React.Component ? () => DiscordModules.React.createElement(element, {}) : typeof(element) == "function" ? element : () => element;
this.panels.push(section);
}
getPath(path, collectionId = "", categoryId = "") {
@ -80,13 +79,6 @@ export default new class SettingsManager {
Object.assign(this.state, this.defaultState);
}
buildSettingsPanel(title, config, state, onChange) {
config.forEach(section => {
section.settings.forEach(item => item.value = state[section.id][item.id]);
});
return this.renderer.getSettingsPanel(title, config, onChange);
}
async patchSections() {
const UserSettings = await this.getUserSettings();
Utilities.monkeyPatch(UserSettings.prototype, "generateSections", {after: (data) => {
@ -103,11 +95,12 @@ export default new class SettingsManager {
insert({
section: collection.name,
label: collection.name,
element: () => this.buildSettingsPanel(collection.name, collection.settings, SettingsState[collection.id], this.onSettingChange.bind(this, collection.id))
element: () => SettingsRenderer.buildSettingsPanel(collection.name, collection.settings, SettingsState[collection.id], this.onSettingChange.bind(this, collection.id))
});
}
for (const panel of this.panels) insert(panel);
insert({section: "BBD Test", label: "Test Tab", onClick: function() {Toasts.success("This can just be a click listener!", {forceShow: true});}});
insert({section: "CUSTOM", element: () => this.renderer.attribution});
insert({section: "CUSTOM", element: () => SettingsRenderer.attribution});
}});
this.forceUpdate();
}
@ -179,17 +172,6 @@ export default new class SettingsManager {
updateSettings(collection, category, id, enabled) {
if (id == "fork-ps-5") {
if (enabled) {
ContentManager.watchContent("plugin");
ContentManager.watchContent("theme");
}
else {
ContentManager.unwatchContent("plugin");
ContentManager.unwatchContent("theme");
}
}
if (id == "fork-wp-1") {
BdApi.setWindowPreference("transparent", enabled);
if (enabled) BdApi.setWindowPreference("backgroundColor", null);
@ -198,15 +180,4 @@ export default new class SettingsManager {
// this.saveSettings();
}
initializeSettings() {
// if (SettingsCookie["bda-es-4"]) EmoteModule.autoCapitalize();
// if (SettingsCookie["fork-ps-5"]) {
// ContentManager.watchContent("plugin");
// ContentManager.watchContent("theme");
// }
this.saveSettings();
}
};

View File

@ -1,111 +1,60 @@
import {ThemeCookie, Themes} from "data";
import {Config} from "data";
import ContentManager from "./contentmanager";
import Utilities from "./utilities";
import Emitter from "./emitter";
import DataStore from "./datastore";
import {Toasts, Modals} from "ui";
import {Modals} from "ui";
function ThemeModule() {
const path = require("path");
}
export default new class ThemeManager extends ContentManager {
get name() {return "ThemeManager";}
get moduleExtension() {return ".css";}
get extension() {return ".theme.css";}
get contentFolder() {return path.resolve(Config.dataPath, "themes");}
get prefix() {return "theme";}
ThemeModule.prototype.loadThemes = function () {
this.loadThemeData();
const errors = ContentManager.loadThemes();
const themes = Object.keys(Themes);
/* Aliases */
updateThemeList() {return this.updateList();}
loadAllThemes() {return this.loadAllContent();}
for (let i = 0; i < themes.length; i++) {
const name = Themes[themes[i]].name;
if (!ThemeCookie[name]) ThemeCookie[name] = false;
if (ThemeCookie[name]) $("head").append($("<style>", {id: Utilities.escapeID(name), text: unescape(Themes[name].css)}));
enableTheme(idOrContent) {return this.enableContent(idOrContent);}
disableTheme(idOrContent) {return this.disableContent(idOrContent);}
toggleTheme(id) {return this.toggleContent(id);}
unloadTheme(idOrFileOrContent) {return this.unloadContent(idOrFileOrContent);}
loadTheme(filename) {
const error = this.loadContent(filename);
if (error) Modals.showContentErrors({themes: [error]});
}
for (const theme in ThemeCookie) {
if (!Themes[theme]) delete ThemeCookie[theme];
reloadTheme(filename) {
const error = this.reloadContent(filename);
if (error) Modals.showContentErrors({themes: [error]});
}
this.saveThemeData();
return errors;
// if (SettingsCookie["fork-ps-5"]) ContentManager.watchContent("theme");
};
ThemeModule.prototype.enableTheme = function(theme, reload = false) {
ThemeCookie[theme] = true;
this.saveThemeData();
$("head").append($("<style>", {id: Utilities.escapeID(theme), text: unescape(Themes[theme].css)}));
if (!reload) Toasts.show(`${Themes[theme].name} v${Themes[theme].version} has been applied.`);
};
/* Overrides */
getContentModification(module, content, meta) {
meta.css = content.split("\n").slice(1).join("\n");
return `module.exports = ${JSON.stringify(meta)};`;
}
ThemeModule.prototype.disableTheme = function(theme, reload = false) {
ThemeCookie[theme] = false;
this.saveThemeData();
$(`#${Utilities.escapeID(Themes[theme].name)}`).remove();
if (!reload) Toasts.show(`${Themes[theme].name} v${Themes[theme].version} has been disabled.`);
};
startContent(id) {return this.addTheme(id);}
stopContent(id) {return this.removeTheme(id);}
ThemeModule.prototype.toggleTheme = function(theme) {
if (ThemeCookie[theme]) this.disableTheme(theme);
else this.enableTheme(theme);
};
ThemeModule.prototype.loadTheme = function(filename) {
const error = ContentManager.loadContent(filename, "theme");
if (error) {
Modals.showContentErrors({themes: [error]});
Toasts.show(`${filename} could not be loaded. It may not have been loaded.`, {type: "error"});
return Utilities.err("ContentManager", `${filename} could not be loaded.`, error);
addTheme(idOrContent) {
const content = typeof(idOrContent) == "string" ? this.contentList.find(p => p.id == idOrContent) : idOrContent;
if (!content) return;
const style = document.createElement("style");
style.id = Utilities.escapeID(content.id);
style.textContent = unescape(content.css);
document.head.append(style);
content.element = style;
}
const theme = Object.values(Themes).find(p => p.filename == filename);
Utilities.log("ContentManager", `${theme.name} v${theme.version} was loaded.`);
Toasts.show(`${theme.name} v${theme.version} was loaded.`, {type: "success"});
Emitter.dispatch("theme-loaded", theme.name);
};
ThemeModule.prototype.unloadTheme = function(filenameOrName) {
const bdtheme = Object.values(Themes).find(p => p.filename == filenameOrName) || Themes[filenameOrName];
if (!bdtheme) return;
const theme = bdtheme.name;
if (ThemeCookie[theme]) this.disableTheme(theme, true);
const error = ContentManager.unloadContent(Themes[theme].filename, "theme");
delete Themes[theme];
if (error) {
Modals.showContentErrors({themes: [error]});
Toasts.show(`${theme} could not be unloaded. It may have not been loaded yet.`, {type: "error"});
return Utilities.err("ContentManager", `${theme} could not be unloaded. It may have not been loaded yet.`, error);
removeTheme(idOrContent) {
const content = typeof(idOrContent) == "string" ? this.contentList.find(p => p.id == idOrContent) : idOrContent;
if (!content) return;
const element = content.element || document.getElementById(Utilities.escapeID(content.id));
if (element) element.remove();
}
Utilities.log("ContentManager", `${theme} was unloaded.`);
Toasts.show(`${theme} was unloaded.`, {type: "success"});
Emitter.dispatch("theme-unloaded", theme);
};
ThemeModule.prototype.reloadTheme = function(filenameOrName) {
const bdtheme = Object.values(Themes).find(p => p.filename == filenameOrName) || Themes[filenameOrName];
if (!bdtheme) return this.loadTheme(filenameOrName);
const theme = bdtheme.name;
const error = ContentManager.reloadContent(Themes[theme].filename, "theme");
if (ThemeCookie[theme]) this.disableTheme(theme, true), this.enableTheme(theme, true);
if (error) {
Modals.showContentErrors({themes: [error]});
Toasts.show(`${theme} could not be reloaded.`, {type: "error"});
return Utilities.err("ContentManager", `${theme} could not be reloaded.`, error);
}
Utilities.log("ContentManager", `${theme} v${Themes[theme].version} was reloaded.`);
Toasts.show(`${theme} v${Themes[theme].version} was reloaded.`, {type: "success"});
Emitter.dispatch("theme-reloaded", theme);
};
ThemeModule.prototype.updateThemeList = function() {
const results = ContentManager.loadNewContent("theme");
for (const filename of results.added) this.loadTheme(filename);
for (const name of results.removed) this.unloadTheme(name);
};
ThemeModule.prototype.loadThemeData = function() {
const saved = DataStore.getData("themes");
if (!saved) return;
Object.assign(ThemeCookie, saved);
};
ThemeModule.prototype.saveThemeData = function () {
DataStore.setData("themes", ThemeCookie);
};
export default new ThemeModule();
};

View File

@ -1,119 +0,0 @@
import {Config} from "data";
import ContentManager from "./contentmanager2";
import Utilities from "./utilities";
import ContentError from "../structs/contenterror";
import {Toasts, Modals} from "ui";
const path = require("path");
export default new class ThemeManager extends ContentManager {
get name() {return "ThemeManager";}
get moduleExtension() {return ".css";}
get extension() {return ".theme.css";}
get contentFolder() {return path.resolve(Config.dataPath, "themes");}
get prefix() {return "theme";}
/* Aliases */
updateThemeList() {return this.updateList();}
loadAllThemes() {return this.loadAllContent();}
enableTheme(idOrContent, fromWatcher = false) {return this.enableContent(idOrContent, fromWatcher);}
disableTheme(idOrContent, fromWatcher = false) {return this.disableContent(idOrContent, fromWatcher);}
toggleTheme(id) {return this.toggleContent(id);}
unloadTheme(idOrFileOrContent, fromWatcher) {return this.unloadContent(idOrFileOrContent, fromWatcher);}
loadContent(filename, fromWatcher) {
const error = this.loadTheme(filename, fromWatcher);
if (!fromWatcher) return error;
if (error) Modals.showContentErrors({themes: [error]});
}
/* Overrides */
getContentModification(module, content, meta) {
meta.css = content.split("\n").slice(1).join("\n");
return `module.exports = ${JSON.stringify(meta)};`;
}
loadTheme(filename) {
const content = super.loadContent(filename);
if (content instanceof ContentError) return content;
console.log(content);
if (this.contentList.find(c => c.id == content.name)) return new ContentError(content.name, filename, `There is already a plugin with name ${content.name}`);
this.contentList.push(content);
Toasts.success(`${content.name} v${content.version} was loaded.`);
this.emit("loaded", content.name);
if (!this.state[content.id]) return this.state[content.id] = false;
return this.addTheme(content);
}
reloadTheme(filename) {
this.reloadContent(filename);
}
startContent(id) {return this.addTheme(id);}
stopContent(id) {return this.removeTheme(id);}
addTheme() {
}
removeTheme() {
}
};
function ThemeModule() {
}
ThemeModule.prototype.enableTheme = function(theme, reload = false) {
ThemeCookie[theme] = true;
this.saveThemeData();
$("head").append($("<style>", {id: Utilities.escapeID(theme), text: unescape(Themes[theme].css)}));
if (!reload) Toasts.show(`${Themes[theme].name} v${Themes[theme].version} has been applied.`);
};
ThemeModule.prototype.disableTheme = function(theme, reload = false) {
ThemeCookie[theme] = false;
this.saveThemeData();
$(`#${Utilities.escapeID(Themes[theme].name)}`).remove();
if (!reload) Toasts.show(`${Themes[theme].name} v${Themes[theme].version} has been disabled.`);
};
ThemeModule.prototype.toggleTheme = function(theme) {
if (ThemeCookie[theme]) this.disableTheme(theme);
else this.enableTheme(theme);
};
ThemeModule.prototype.unloadTheme = function(filenameOrName) {
const bdtheme = Object.values(Themes).find(p => p.filename == filenameOrName) || Themes[filenameOrName];
if (!bdtheme) return;
const theme = bdtheme.name;
if (ThemeCookie[theme]) this.disableTheme(theme, true);
const error = ContentManager.unloadContent(Themes[theme].filename, "theme");
delete Themes[theme];
if (error) {
Modals.showContentErrors({themes: [error]});
Toasts.show(`${theme} could not be unloaded. It may have not been loaded yet.`, {type: "error"});
return Utilities.err("ContentManager", `${theme} could not be unloaded. It may have not been loaded yet.`, error);
}
Utilities.log("ContentManager", `${theme} was unloaded.`);
Toasts.show(`${theme} was unloaded.`, {type: "success"});
Emitter.dispatch("theme-unloaded", theme);
};
ThemeModule.prototype.reloadTheme = function(filenameOrName) {
const bdtheme = Object.values(Themes).find(p => p.filename == filenameOrName) || Themes[filenameOrName];
if (!bdtheme) return this.loadTheme(filenameOrName);
const theme = bdtheme.name;
const error = ContentManager.reloadContent(Themes[theme].filename, "theme");
if (ThemeCookie[theme]) this.disableTheme(theme, true), this.enableTheme(theme, true);
if (error) {
Modals.showContentErrors({themes: [error]});
Toasts.show(`${theme} could not be reloaded.`, {type: "error"});
return Utilities.err("ContentManager", `${theme} could not be reloaded.`, error);
}
Utilities.log("ContentManager", `${theme} v${Themes[theme].version} was reloaded.`);
Toasts.show(`${theme} v${Themes[theme].version} was reloaded.`, {type: "success"});
Emitter.dispatch("theme-reloaded", theme);
};

View File

@ -1,5 +1,4 @@
import {SettingsCookie} from "data";
import {BDV2, DiscordModules} from "modules";
import {BDV2, DiscordModules, Settings} from "modules";
import EmoteMenu from "../builtins/emotemenu";
export default class BDEmote extends DiscordModules.React.Component {
@ -18,7 +17,7 @@ export default class BDEmote extends DiscordModules.React.Component {
}
get animateOnHover() {
return SettingsCookie["fork-es-2"];
return Settings.get("emotes", "general", "animateOnHover");
}
get label() {

View File

@ -1,9 +1,8 @@
import {SettingsCookie} from "data";
import {Utilities, WebpackModules, React} from "modules";
import {Utilities, WebpackModules, React, Settings} from "modules";
export default class Modals {
static get shouldShowContentErrors() {return SettingsCookie["fork-ps-1"];}
static get shouldShowContentErrors() {return Settings.get("settings", "content", "contentErrors");}
static get ModalStack() {return WebpackModules.getByProps("push", "update", "pop", "popWithKey");}
static get AlertModal() {return WebpackModules.getByPrototypes("handleCancel", "handleSubmit", "handleMinorConfirm");}

View File

@ -1,7 +1,7 @@
import {SettingsCookie, PluginCookie, Plugins} from "data";
// import {SettingsCookie, PluginCookie, Plugins} from "data";
import {React, ReactDOM, Utilities, PluginManager} from "modules";
import CloseButton from "../icons/close";
import ReloadIcon from "../icons/reload";
// import ReloadIcon from "../icons/reload";
export default class V2C_PluginCard extends React.Component {
@ -9,33 +9,15 @@ export default class V2C_PluginCard extends React.Component {
super(props);
this.onChange = this.onChange.bind(this);
this.showSettings = this.showSettings.bind(this);
this.setInitialState();
this.hasSettings = typeof this.props.plugin.getSettingsPanel === "function";
this.state = {
checked: PluginManager.isEnabled(this.props.content.id),
settings: false
};
this.hasSettings = typeof this.props.content.plugin.getSettingsPanel === "function";
this.settingsPanel = "";
this.reload = this.reload.bind(this);
this.onReload = this.onReload.bind(this);
}
setInitialState() {
this.state = {
checked: PluginCookie[this.props.plugin.getName()],
settings: false,
reloads: 0
};
}
// componentDidMount() {
// BDEvents.on("plugin-reloaded", this.onReload);
// }
// componentWillUnmount() {
// BDEvents.off("plugin-reloaded", this.onReload);
// }
onReload(pluginName) {
if (pluginName !== this.props.plugin.getName()) return;
this.setState({reloads: this.state.reloads + 1});
// this.reload = this.reload.bind(this);
// this.onReload = this.onReload.bind(this);
}
componentDidUpdate() {
@ -44,7 +26,7 @@ export default class V2C_PluginCard extends React.Component {
this.refs.settingspanel.appendChild(this.settingsPanel);
}
if (!SettingsCookie["fork-ps-3"]) return;
// if (!SettingsCookie["fork-ps-3"]) return;
const isHidden = (container, element) => {
const cTop = container.scrollTop;
@ -65,30 +47,23 @@ export default class V2C_PluginCard extends React.Component {
}
}
reload() {
const plugin = this.props.plugin.getName();
PluginManager.reloadPlugin(plugin);
this.props.plugin = Plugins[plugin].plugin;
this.onReload(this.props.plugin.getName());
}
getString(value) {
return typeof value == "string" ? value : value.toString();
}
render() {
const self = this;
const {plugin} = this.props;
const name = this.getString(plugin.getName());
const author = this.getString(plugin.getAuthor());
const description = this.getString(plugin.getDescription());
const version = this.getString(plugin.getVersion());
const website = Plugins[name].website;
const source = Plugins[name].source;
const {content} = this.props;
const name = this.getString(content.name);
const author = this.getString(content.author);
const description = this.getString(content.description);
const version = this.getString(content.version);
const website = content.website;
const source = content.source;
if (this.state.settings) {
try { self.settingsPanel = plugin.getSettingsPanel(); }
catch (err) { Utilities.err("Plugins", "Unable to get settings panel for " + plugin.getName() + ".", err); }
try { self.settingsPanel = content.plugin.getSettingsPanel(); }
catch (err) { Utilities.err("Plugins", "Unable to get settings panel for " + content.name + ".", err); }
return React.createElement("li", {className: "settings-open ui-switch-item"},
React.createElement("div", {style: {"float": "right", "cursor": "pointer"}, onClick: () => {
@ -112,7 +87,7 @@ export default class V2C_PluginCard extends React.Component {
React.createElement("span", {className: "bda-author"}, author)
),
React.createElement("div", {className: "bda-controls"},
!SettingsCookie["fork-ps-5"] && React.createElement(ReloadIcon, {className: "bd-reload-card", onClick: this.reload}),
//!SettingsCookie["fork-ps-5"] && React.createElement(ReloadIcon, {className: "bd-reload-card", onClick: this.reload}),
React.createElement("label", {className: "ui-switch-wrapper ui-flex-child", style: {flex: "0 0 auto"}},
React.createElement("input", {checked: this.state.checked, onChange: this.onChange, className: "ui-switch-checkbox", type: "checkbox"}),
React.createElement("div", {className: this.state.checked ? "ui-switch checked" : "ui-switch"})
@ -135,7 +110,7 @@ export default class V2C_PluginCard extends React.Component {
onChange() {
this.setState({checked: !this.state.checked});
PluginManager.togglePlugin(this.props.plugin.getName());
PluginManager.togglePlugin(this.props.content.id);
}
showSettings() {

View File

@ -1,4 +1,4 @@
import {SettingsInfo, Config, SettingsCookie/*, Plugins, Themes*/} from "data";
import {Config} from "data";
import {React/*, ReactDOM, Utilities, ContentManager, Events, PluginManager, ThemeManager*/} from "modules";
// import Sidebar from "./sidebar";
// import Scroller from "../scroller";
@ -7,73 +7,51 @@ import {React/*, ReactDOM, Utilities, ContentManager, Events, PluginManager, The
// import SectionedSettingsPanel from "./sectionedsettings";
// import Tools from "./exitbutton";
// import SettingsPanel from "./panel";
// import PluginCard from "./plugincard";
import PluginCard from "./plugincard";
// import ThemeCard from "./themecard";
// import ReloadIcon from "../icons/reload";
// import CssEditor from "../customcss/editor";
// import SettingsGroup from "../settings/settingsgroup";
import SettingsGroup2 from "../settings/group";
import {Toasts} from "../ui";
import Settings from "../../data/settings/config";
import State from "../../data/settings/state";
import SettingsGroup from "../settings/group";
import SettingsTitle from "./title";
export default class V2_SettingsPanel {
get coreSettings() {
const settings = this.getSettings("core");
const categories = [...new Set(settings.map(s => s.category))];
const sections = categories.map(c => {return {title: c, settings: settings.filter(s => s.category == c)};});
return sections;
static buildSettingsPanel(title, config, state, onChange) {
config.forEach(section => {
section.settings.forEach(item => item.value = state[section.id][item.id]);
});
return this.getSettingsPanel(title, config, onChange);
}
get emoteSettings() {
return this.getSettings("emote");
}
getSettings(category) {
return Object.keys(SettingsInfo).reduce((arr, key) => {
const setting = SettingsInfo[key];
if (setting.cat === category && setting.implemented && !setting.hidden) {
setting.text = key;
arr.push(setting);
}
return arr;
}, []);
}
getSettingsPanel(title, groups, onChange) {
static getSettingsPanel(title, groups, onChange) {
return [React.createElement(SettingsTitle, {text: title}), groups.map(section => {
return React.createElement(SettingsGroup2, Object.assign({}, section, {onChange}));
return React.createElement(SettingsGroup, Object.assign({}, section, {onChange}));
})];
}
get core3() {
const groups = Settings;
return groups.map((section, i) => {
if (i == 0) section.button = {title: "Call to Action!", onClick: () => {Toasts.success("You did it!", {forceShow: true});}};
// console.log(section);
section.settings.forEach(item => item.value = State[section.id][item.id]);
// if (section.settings.find(s => s.text == "Hide Channels")) section.settings.find(s => s.text == "Hide Channels").shouldHide = () => !SettingsCookie["bda-gs-2"];
return React.createElement(SettingsGroup2, Object.assign({}, section, {onChange: this.onChange}));
});
static getPluginsPanel(plugins) {
const titleComponent = React.createElement(SettingsTitle, {text: "Plugins", button: {title: "Open Plugin Folder", onClick: () => { require("electron").shell.openItem(""); }}});
const cards = plugins.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())).map(plugin =>
React.createElement(PluginCard, {key: plugin.id, content: plugin})
);
console.log(cards);
return [titleComponent, ...cards];
// const plugins = Object.keys(Plugins).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())).reduce((arr, key) => {
// arr.push(React.createElement(PluginCard, {key: key, plugin: Plugins[key].plugin}));return arr;
// }, []);
// const list = React.createElement(List, {key: "plugin-list", className: "bda-slist", children: plugins});
// const refreshIcon = !SettingsCookie["fork-ps-5"] && React.createElement(ReloadIcon, {className: "bd-reload-header", size: "18px", onClick: async () => {
// PluginManager.updatePluginList();
// this.sideBarOnClick("plugins");
// }});
// const pfBtn = React.createElement("button", {key: "folder-button", className: "bd-pfbtn", onClick: () => { require("electron").shell.openItem(ContentManager.pluginsFolder); }}, "Open Plugin Folder");
// const contentColumn = React.createElement(ContentColumn, {key: "pcolumn", title: "Plugins", children: [refreshIcon, pfBtn, list]});
// return React.createElement(Scroller, {contentColumn: true, fade: true, dark: true, children: [contentColumn, React.createElement(Tools, {key: "tools"})]});
}
get core2() {
return this.coreSettings.map((section, i) => {
if (i == 0) section.button = {title: "Call to Action!", onClick: () => {Toasts.success("You did it!", {forceShow: true});}};
// console.log(section);
if (section.settings.find(s => s.text == "Hide Channels")) section.settings.find(s => s.text == "Hide Channels").shouldHide = () => !SettingsCookie["bda-gs-2"];
return React.createElement(SettingsGroup2, Object.assign({}, section, {onChange: this.onChange, collapsible: true, collapsed: i > 1}));
});
}
get attribution() {
static get attribution() {
return React.createElement(
"div",
{style: {fontSize: "12px", fontWeight: "600", color: "#72767d", padding: "2px 10px"}},

View File

@ -1,12 +1,11 @@
import {SettingsCookie} from "data";
import {WebpackModules} from "modules";
import {WebpackModules, Settings} from "modules";
const channelsClass = WebpackModules.getByProps("channels").channels.split(" ")[0];
const membersWrapClass = WebpackModules.getByProps("membersWrap").membersWrap.split(" ")[0];
export default class Toasts {
static get shouldShowToasts() {return SettingsCookie["fork-ps-2"];}
static get shouldShowToasts() {return Settings.get("settings", "general", "showToasts");}
/** Shorthand for `type = "success"` for {@link module:Toasts.show} */
static async success(content, options = {}) {return this.show(content, Object.assign(options, {type: "success"}));}

View File

@ -3,7 +3,7 @@ const path = require("path");
module.exports = {
mode: "development",
target: "node",
devtool: "none",
devtool: "eval-source-map",
entry: "./src/index.js",
output: {
filename: "main.js",