finish managers + basic plugins page
This commit is contained in:
parent
0ccf84f803
commit
ee47005321
7284
js/main.js
7284
js/main.js
File diff suppressed because one or more lines are too long
|
@ -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) {
|
||||
|
|
|
@ -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};
|
18
src/index.js
18
src/index.js
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 : ""
|
||||
// };
|
||||
// }
|
||||
};
|
|
@ -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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
};
|
|
@ -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();
|
||||
};
|
|
@ -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);
|
||||
};
|
|
@ -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() {
|
||||
|
|
|
@ -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");}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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"}},
|
||||
|
|
|
@ -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"}));}
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue