commit
363c7e9f7c
|
@ -35,7 +35,7 @@
|
|||
},
|
||||
{
|
||||
"id": "ui",
|
||||
"text": "UI",
|
||||
"text": "UI",
|
||||
"settings": [
|
||||
|
||||
]
|
||||
|
@ -50,6 +50,6 @@
|
|||
"text": "Security",
|
||||
"settings": [
|
||||
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1,54 +1,40 @@
|
|||
/**
|
||||
* BetterDiscord Client Core
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const styles = require('./styles/index.scss');
|
||||
const { Global, Logger, Utils, PluginManager, BDIpc, WebpackModules, SocketProxy, Events, Vendor } = require('./modules');
|
||||
//const { UI } = require('./modules/ui/index.jsx');
|
||||
import { DOM, BdUI } from 'ui';
|
||||
import BdCss from './styles/index.scss';
|
||||
import { Events, CssEditor, Globals, PluginManager, ThemeManager } from 'modules';
|
||||
|
||||
class BetterDiscord {
|
||||
|
||||
constructor() {
|
||||
window.bdUtils = Utils;
|
||||
window.wpm = WebpackModules;
|
||||
Events.on('global-ready', e => {
|
||||
const { UI } = require('./modules/ui/vueui.js');
|
||||
this.ui = new UI();
|
||||
this.init();
|
||||
});
|
||||
|
||||
//Inject styles to head for now
|
||||
const style = document.createElement('style');
|
||||
style.id = 'bd-main';
|
||||
style.type = 'text/css';
|
||||
style.appendChild(document.createTextNode(styles));
|
||||
document.head.appendChild(style);
|
||||
|
||||
this.init();
|
||||
window.pom = PluginManager;
|
||||
DOM.injectStyle(BdCss, 'bdmain');
|
||||
Events.on('global-ready', this.globalReady.bind(this));
|
||||
}
|
||||
|
||||
async init() {
|
||||
try {
|
||||
await PluginManager.loadAllPlugins();
|
||||
} catch (err) {
|
||||
}
|
||||
|
||||
await PluginManager.loadAllPlugins();
|
||||
await ThemeManager.loadAllThemes();
|
||||
Events.emit('ready');
|
||||
}
|
||||
|
||||
globalReady() {
|
||||
this.vueInstance = BdUI.injectUi();
|
||||
(async () => {
|
||||
this.init();
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
if (window.BetterDiscord) {
|
||||
Logger.log('main', 'Attempting to inject again?');
|
||||
} else {
|
||||
let bdInstance = new BetterDiscord();
|
||||
window.BetterDiscord = {'vendor': Vendor};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/**
|
||||
* BetterDiscord Content Manager Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import Globals from './globals';
|
||||
import { FileUtils, ClientLogger as Logger } from 'common';
|
||||
import path from 'path';
|
||||
|
||||
export default class {
|
||||
|
||||
static get localContent() {
|
||||
return this._localContent ? this._localContent : (this._localContent = []);
|
||||
}
|
||||
|
||||
static get contentPath() {
|
||||
return this._contentPath ? this._contentPath : (this._contentPath = Globals.getObject('paths').find(path => path.id === this.pathId).path);
|
||||
}
|
||||
|
||||
static async loadAllContent() {
|
||||
try {
|
||||
await FileUtils.ensureDirectory(this.contentPath);
|
||||
const directories = await FileUtils.listDirectory(this.contentPath);
|
||||
|
||||
for (let dir of directories) {
|
||||
try {
|
||||
await this.preloadContent(dir);
|
||||
} catch (err) {
|
||||
//We don't want every plugin/theme to fail loading when one does
|
||||
Logger.err(this.moduleName, err);
|
||||
}
|
||||
}
|
||||
|
||||
return this.localContent;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
static async refreshContent() {
|
||||
if (!this.localContent.length) return this.loadAllContent();
|
||||
|
||||
try {
|
||||
await FileUtils.ensureDirectory(this.contentPath);
|
||||
const directories = await FileUtils.listDirectory(this.contentPath);
|
||||
|
||||
for (let dir of directories) {
|
||||
// If content is already loaded this should resolve.
|
||||
if (this.getContentByDirName(dir)) continue;
|
||||
|
||||
try {
|
||||
// Load if not
|
||||
await this.preloadContent(dir);
|
||||
} catch (err) {
|
||||
//We don't want every plugin/theme to fail loading when one does
|
||||
Logger.err(this.moduleName, err);
|
||||
}
|
||||
}
|
||||
|
||||
for (let content of this.localContent) {
|
||||
if (directories.includes(content.dirName)) continue;
|
||||
//Plugin/theme was deleted manually, stop it and remove any reference
|
||||
this.unloadContent(content);
|
||||
}
|
||||
|
||||
return this.localContent;
|
||||
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
static async preloadContent(dirName, reload = false, index) {
|
||||
try {
|
||||
const contentPath = path.join(this.contentPath, dirName);
|
||||
|
||||
await FileUtils.directoryExists(contentPath);
|
||||
|
||||
if (!reload) {
|
||||
const loaded = this.localContent.find(content => content.contentPath === contentPath);
|
||||
if (loaded) {
|
||||
throw { 'message': `Attempted to load already loaded user content: ${path}` };
|
||||
}
|
||||
}
|
||||
|
||||
const readConfig = await this.readConfig(contentPath);
|
||||
const mainPath = path.join(contentPath, readConfig.main);
|
||||
|
||||
const userConfig = {
|
||||
enabled: false,
|
||||
config: readConfig.defaultConfig
|
||||
};
|
||||
|
||||
try {
|
||||
const readUserConfig = await this.readUserConfig(contentPath);
|
||||
userConfig.config = userConfig.defaultConfig.map(config => {
|
||||
const userSet = readUserConfig.config.find(c => c.id === config.id);
|
||||
return userSet || config;
|
||||
});
|
||||
} catch (err) {/*We don't care if this fails it either means that user config doesn't exist or there's something wrong with it so we revert to default config*/ }
|
||||
|
||||
const configs = {
|
||||
defaultConfig: readConfig.defaultConfig,
|
||||
userConfig
|
||||
}
|
||||
|
||||
const paths = {
|
||||
contentPath,
|
||||
dirName,
|
||||
mainPath
|
||||
}
|
||||
|
||||
const content = await this.loadContent(paths, configs, readConfig.info, readConfig.main);
|
||||
if (reload) this.localContent[index] = content;
|
||||
else this.localContent.push(content);
|
||||
return content;
|
||||
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
static async readConfig(configPath) {
|
||||
configPath = path.resolve(configPath, 'config.json');
|
||||
return FileUtils.readJsonFromFile(configPath);
|
||||
}
|
||||
|
||||
static async readUserConfig(configPath) {
|
||||
configPath = path.resolve(configPath, 'user.config.json');
|
||||
return FileUtils.readJsonFromFile(configPath);
|
||||
}
|
||||
|
||||
//TODO make this nicer
|
||||
static findContent(wild) {
|
||||
let content = this.getContentByName(wild);
|
||||
if (content) return content;
|
||||
content = this.getContentById(wild);
|
||||
if (content) return content;
|
||||
content = this.getContentByPath(wild);
|
||||
if (content) return content;
|
||||
return this.getContentByDirName(wild);
|
||||
}
|
||||
|
||||
static getContentIndex(content) { return this.localContent.findIndex(c => c === content) }
|
||||
static getContentByName(name) { return this.localContent.find(c => c.name === name) }
|
||||
static getContentById(id) { return this.localContent.find(c => c.id === id) }
|
||||
static getContentByPath(path) { return this.localContent.find(c => c.contentPath === path) }
|
||||
static getContentByDirName(dirName) { return this.localContent.find(c => c.dirName === dirName) }
|
||||
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
* BetterDiscord Client IPC Module
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const { ipcRenderer } = require('electron');
|
||||
|
||||
class BDIpc {
|
||||
static on(channel, cb) {
|
||||
ipcRenderer.on(channel, (event, message) => cb(event, message));
|
||||
}
|
||||
|
||||
static async send(channel, message) {
|
||||
channel = channel.startsWith('bd-') ? channel : `bd-${channel}`;
|
||||
const __eid = Date.now().toString();
|
||||
ipcRenderer.send(channel, Object.assign(message ? message : {}, { __eid }));
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcRenderer.once(__eid, (event, arg) => resolve(arg));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = { BDIpc };
|
|
@ -1,34 +0,0 @@
|
|||
/**
|
||||
* BetterDiscord CSS Editor
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const { Module } = require('./modulebase');
|
||||
const { BDIpc } = require('./bdipc');
|
||||
const $ = require('jquery');
|
||||
|
||||
class CssEditor extends Module {
|
||||
|
||||
setInitialState() {
|
||||
this.state = {
|
||||
css: ''
|
||||
}
|
||||
this.customcss = $('<style id="customcss">').appendTo("head");
|
||||
window.cssEditor = this;
|
||||
|
||||
BDIpc.on("bd-update-css", (_, css) => this.customcss.text(css));
|
||||
BDIpc.on("bd-save-css", (_, css) => this.setState({css}));
|
||||
}
|
||||
|
||||
show() {
|
||||
BDIpc.send('openCssEditor', {}).then(() => BDIpc.send('setCss', {css: this.state.css}));
|
||||
}
|
||||
}
|
||||
|
||||
const _instance = new CssEditor();
|
||||
module.exports = { 'CssEditor': _instance }
|
|
@ -1,60 +0,0 @@
|
|||
/**
|
||||
* BetterDiscord Discord Socket Proxy
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const { Events } = require('./events');
|
||||
const { Module } = require('./modulebase');
|
||||
const { Global } = require('./global');
|
||||
const { Utils } = require('./utils');
|
||||
|
||||
class SocketProxy extends Module {
|
||||
|
||||
events() {
|
||||
Events.on('socket-created', this.socketCreated);
|
||||
}
|
||||
|
||||
bindings() {
|
||||
this.socketCreated = this.socketCreated.bind(this);
|
||||
this.onmessage = this.onmessage.bind(this);
|
||||
}
|
||||
|
||||
socketCreated() {
|
||||
const wsHook = Global.getObject('wsHook');
|
||||
|
||||
wsHook.addEventListener('message', this.onmessage);
|
||||
}
|
||||
|
||||
onmessage(e) {
|
||||
console.log(e);
|
||||
//TODO fix unpacking
|
||||
const unpacked = this.erlpack.unpack(e.data);
|
||||
console.log(unpacked);
|
||||
}
|
||||
|
||||
get erlpack() {
|
||||
if (this._erlpack) return this._erlpack;
|
||||
|
||||
try {
|
||||
this._erlpack = window.require('erlpack');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
try {
|
||||
this._erlpack = window.require('discord_erlpack');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
return this._erlpack;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const _instance = new SocketProxy();
|
||||
module.exports = { 'SocketProxy': _instance }
|
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
* BetterDiscord Client Globals
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const { Module } = require('./modulebase');
|
||||
const { Events } = require('./events');
|
||||
const { BDIpc } = require('./bdipc');
|
||||
const { WebpackModules } = require('./webpackmodules');
|
||||
|
||||
class Global extends Module {
|
||||
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.first();
|
||||
window.gl = this;
|
||||
}
|
||||
|
||||
bindings() {
|
||||
this.first = this.first.bind(this);
|
||||
this.setWS = this.setWS.bind(this);
|
||||
this.getObject = this.getObject.bind(this);
|
||||
}
|
||||
|
||||
first() {
|
||||
(async () => {
|
||||
const config = await BDIpc.send('getConfig');
|
||||
this.setState(config);
|
||||
/* const getReact = await WebpackModules.getModuleByProps(('createElement', 'cloneElement'));
|
||||
this.React = getReact[0].exports;
|
||||
window.React = this.React;
|
||||
const getReactDom = await WebpackModules.getModuleByProps(('render', 'findDOMNode'));
|
||||
this.reactDOM = getReactDom[0].exports;*/
|
||||
// this.setState(Object.assign(config, { React, reactDOM }));
|
||||
Events.emit('global-ready');
|
||||
})();
|
||||
|
||||
if (window.__bd) {
|
||||
this.setState(window.__bd);
|
||||
window.__bd = {
|
||||
setWS: this.setWS
|
||||
}
|
||||
Events.emit('socket-created');
|
||||
}
|
||||
}
|
||||
|
||||
setWS(wSocket) {
|
||||
const state = this.state;
|
||||
state.wsHook = wSocket;
|
||||
this.setState(state);
|
||||
Events.emit('socket-created');
|
||||
}
|
||||
|
||||
getObject(name) {
|
||||
return this.state[name];
|
||||
}
|
||||
|
||||
getLoadedModule(name) {
|
||||
return this[name];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const _instance = new Global();
|
||||
module.exports = { 'Global': _instance }
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* BetterDiscord Plugin Base Class
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
class Plugin {
|
||||
|
||||
constructor() {}
|
||||
|
||||
}
|
||||
|
||||
module.exports = { Plugin }
|
|
@ -1,275 +0,0 @@
|
|||
/**
|
||||
* BetterDiscord Plugin Manager
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const { Module } = require('./modulebase');
|
||||
const { FileUtils, Logger } = require('./utils');
|
||||
const { Global } = require('./global');
|
||||
const path = window.require('path');
|
||||
|
||||
class Plugin {
|
||||
|
||||
constructor(pluginInternals) {
|
||||
this.__pluginInternals = pluginInternals;
|
||||
this.hasSettings = this.pluginConfig && this.pluginConfig.length > 0;
|
||||
this.start = this.start.bind(this);
|
||||
this.stop = this.stop.bind(this);
|
||||
}
|
||||
|
||||
get configs() { return this.__pluginInternals.configs }
|
||||
get info() { return this.__pluginInternals.info }
|
||||
get paths() { return this.__pluginInternals.paths }
|
||||
get main() { return this.__pluginInternals.main }
|
||||
get defaultConfig() { return this.configs.defaultConfig }
|
||||
get userConfig() { return this.configs.userConfig }
|
||||
get name() { return this.info.name }
|
||||
get authors() { return this.info.authors }
|
||||
get version() { return this.info.version }
|
||||
get pluginPath() { return this.paths.pluginPath }
|
||||
get dirName() { return this.paths.dirName }
|
||||
get enabled() { return this.userConfig.enabled }
|
||||
get pluginConfig() { return this.userConfig.pluginConfig }
|
||||
|
||||
start() {
|
||||
if (this.onStart) {
|
||||
const started = this.onStart();
|
||||
if (started) {
|
||||
return this.userConfig.enabled = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return this.userConfig.enabled = true; //Assume plugin started since it doesn't have onStart
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.onStop) {
|
||||
const stopped = this.onStop();
|
||||
if (stopped) {
|
||||
this.userConfig.enabled = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.userConfig.enabled = false;
|
||||
return true; //Assume plugin stopped since it doesn't have onStop
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PluginManager extends Module {
|
||||
|
||||
setInitialState() {
|
||||
window.pm = this;
|
||||
this.setState({
|
||||
plugins: []
|
||||
});
|
||||
}
|
||||
|
||||
get plugins() {
|
||||
return this.state.plugins;
|
||||
}
|
||||
|
||||
get pluginsPath() {
|
||||
return Global.getObject('paths').find(path => path.id === 'plugins').path;
|
||||
}
|
||||
|
||||
async loadAllPlugins() {
|
||||
try {
|
||||
const directories = await FileUtils.readDir(this.pluginsPath);
|
||||
|
||||
for (let dir of directories) {
|
||||
try {
|
||||
await this.loadPlugin(dir);
|
||||
} catch (err) {
|
||||
//We don't want every plugin to fail loading when one does
|
||||
Logger.err('PluginManager', err);
|
||||
}
|
||||
}
|
||||
|
||||
return this.plugins;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async refreshPlugins() {
|
||||
if (this.plugins.length <= 0) return this.loadAllPlugins();
|
||||
try {
|
||||
const directories = await FileUtils.readDir(this.pluginsPath);
|
||||
for (let dir of directories) {
|
||||
//If a plugin is already loaded this should resolve.
|
||||
if (this.getPluginByDirName(dir)) continue;
|
||||
|
||||
try {
|
||||
//Load the plugin if not
|
||||
await this.loadPlugin(dir);
|
||||
} catch (err) {
|
||||
//We don't want every plugin to fail loading when one does
|
||||
Logger.err('PluginManager', err);
|
||||
}
|
||||
}
|
||||
|
||||
for (let plugin of this.plugins) {
|
||||
if (directories.includes(plugin.dirName)) continue;
|
||||
//Plugin was deleted manually, stop it and remove any reference
|
||||
try {
|
||||
if (plugin.enabled) plugin.stop();
|
||||
const { pluginPath } = plugin;
|
||||
const index = this.getPluginIndex(plugin);
|
||||
|
||||
delete window.require.cache[window.require.resolve(pluginPath)];
|
||||
this.plugins.splice(index, 1);
|
||||
} catch (err) {
|
||||
//This might fail but we don't have any other option at this point
|
||||
Logger.err('PluginManager', err);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async loadPlugin(pluginPath, reload = false, index) {
|
||||
const { plugins } = this.state;
|
||||
const dirName = pluginPath;
|
||||
|
||||
try {
|
||||
pluginPath = path.join(this.pluginsPath, pluginPath);
|
||||
|
||||
// Make sure this is a directory
|
||||
await FileUtils.directoryExists(pluginPath);
|
||||
|
||||
if (!reload) {
|
||||
const loaded = plugins.find(plugin => plugin.pluginPath === pluginPath);
|
||||
if (loaded) {
|
||||
throw { 'message': 'Attempted to load an already loaded plugin' };
|
||||
}
|
||||
}
|
||||
|
||||
const readConfig = await this.readConfig(pluginPath);
|
||||
const mainPath = path.join(pluginPath, readConfig.main);
|
||||
const userConfigPath = path.join(pluginPath, 'user.config.json');
|
||||
|
||||
const userConfig = {
|
||||
enabled: false,
|
||||
pluginConfig: readConfig.defaultConfig
|
||||
};
|
||||
try {
|
||||
const readUserConfig = await FileUtils.readJsonFromFile(userConfigPath);
|
||||
//userConfig = Object.assign({}, userConfig, readUserConfig);
|
||||
userConfig.pluginConfig = readConfig.defaultConfig.map(config => {
|
||||
const userSet = readUserConfig.pluginConfig.find(c => c.id === config.id);
|
||||
return userSet || config;
|
||||
});
|
||||
} catch (err) {/*We don't care if this fails it either means that user config doesn't exist or there's something wrong with it so we revert to default config*/}
|
||||
|
||||
const configs = {
|
||||
defaultConfig: readConfig.defaultConfig,
|
||||
userConfig
|
||||
};
|
||||
|
||||
const plugin = window.require(mainPath)(Plugin, {}, {});
|
||||
const instance = new plugin({configs, info: readConfig.info, main: readConfig.main, paths: { pluginPath, dirName }});
|
||||
|
||||
if (instance.enabled) instance.start();
|
||||
if (reload) plugins[index] = instance;
|
||||
else plugins.push(instance);
|
||||
|
||||
this.setState(plugins);
|
||||
|
||||
return instance;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async reloadPlugin(plugin) {
|
||||
const _plugin = plugin instanceof Plugin ? plugin : this.findPlugin(plugin);
|
||||
if (!_plugin) throw { 'message': 'Attempted to reload a plugin that is not loaded?' };
|
||||
if (!_plugin.stop()) throw { 'message': 'Plugin failed to stop!' };
|
||||
const index = this.getPluginIndex(_plugin);
|
||||
const { pluginPath, dirName } = _plugin;
|
||||
delete window.require.cache[window.require.resolve(pluginPath)];
|
||||
|
||||
// this.plugins.splice(index, 1);
|
||||
|
||||
return this.loadPlugin(dirName, true, index);
|
||||
}
|
||||
|
||||
//TODO make this nicer
|
||||
findPlugin(wild) {
|
||||
let plugin = this.getPluginByName(wild);
|
||||
if (plugin) return plugin;
|
||||
plugin = this.getPluginById(wild);
|
||||
if (plugin) return plugin;
|
||||
plugin = this.getPluginByPath(wild);
|
||||
if (plugin) return plugin;
|
||||
return this.getPluginByDirName(wild);
|
||||
}
|
||||
|
||||
getPluginIndex(plugin) { return this.plugins.findIndex(p => p === plugin) }
|
||||
getPluginByName(name) { return this.plugins.find(p => p.name === name) }
|
||||
getPluginById(id) { return this.plugins.find(p => p.id === id) }
|
||||
getPluginByPath(path) { return this.plugins.find(p => p.pluginPath === path) }
|
||||
getPluginByDirName(dirName) { return this.plugins.find(p => p.dirName === dirName) }
|
||||
|
||||
stopPlugin(name) {
|
||||
const plugin = name instanceof Plugin ? name : this.getPluginByName(name);
|
||||
try {
|
||||
if (plugin) return plugin.stop();
|
||||
} catch (err) {
|
||||
Logger.err('PluginManager', err);
|
||||
}
|
||||
return true; //Return true anyways since plugin doesn't exist
|
||||
}
|
||||
|
||||
startPlugin(name) {
|
||||
const plugin = name instanceof Plugin ? name : this.getPluginByName(name);
|
||||
try {
|
||||
if (plugin) return plugin.start();
|
||||
} catch (err) {
|
||||
Logger.err('PluginManager', err);
|
||||
}
|
||||
return true; //Return true anyways since plugin doesn't exist
|
||||
}
|
||||
|
||||
async readConfig(path) {
|
||||
path = `${path}/config.json`;
|
||||
return FileUtils.readJsonFromFile(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const _instance = new PluginManager();
|
||||
|
||||
async function pluginManager(pluginName) {
|
||||
|
||||
try {
|
||||
//Load test plugin
|
||||
const plugin = await _instance.loadPlugin(pluginName);
|
||||
//Attempt to load the same plugin again
|
||||
const plugin2 = await _instance.loadPlugin(pluginName);
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.log(`Failed to load plugin! ${err.message}`);
|
||||
}
|
||||
|
||||
try {
|
||||
//Reload test plugin
|
||||
const reloadedPlugin = await _instance.reloadPlugin('Example Plugin');
|
||||
} catch (err) {
|
||||
console.log(`Failed to reload plugin! ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.bdTests) window.bdTests.pluginManager = pluginManager;
|
||||
else window.bdTests = { pluginManager };
|
||||
|
||||
module.exports = { PluginManager: _instance, Plugin };
|
|
@ -1,11 +0,0 @@
|
|||
const defaultSettings = require('../../data/user.settings.default');
|
||||
|
||||
class Settings {
|
||||
|
||||
static get getSettings() {
|
||||
return defaultSettings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = { Settings };
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* BetterDiscord CSS Editor Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import { ClientIPC } from 'common';
|
||||
import { DOM } from 'ui';
|
||||
|
||||
export default class {
|
||||
|
||||
static async show() {
|
||||
const t = await ClientIPC.send('openCssEditor', {});
|
||||
ClientIPC.send('setCss', { css: DOM.getStyleCss('bd-customcss') });
|
||||
|
||||
ClientIPC.on('bd-update-css', this.updateCss);
|
||||
}
|
||||
|
||||
static updateCss(e, css) {
|
||||
DOM.injectStyle(css, 'bd-customcss');
|
||||
}
|
||||
}
|
|
@ -1,19 +1,17 @@
|
|||
/**
|
||||
* BetterDiscord Events
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* BetterDiscord Events Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
|
||||
const { EventEmitter } = require('events');
|
||||
import { EventEmitter } from 'events';
|
||||
const emitter = new EventEmitter();
|
||||
|
||||
class Events {
|
||||
|
||||
export default class {
|
||||
static on(eventName, callBack) {
|
||||
emitter.on(eventName, callBack);
|
||||
}
|
||||
|
@ -25,7 +23,4 @@ class Events {
|
|||
static emit(...args) {
|
||||
emitter.emit(...args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = { Events }
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* BetterDiscord Globals Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import Module from './module';
|
||||
import Events from './events';
|
||||
import { ClientIPC } from 'bdipc';
|
||||
|
||||
export default new class extends Module {
|
||||
|
||||
constructor(args) {
|
||||
super(args);
|
||||
this.first();
|
||||
}
|
||||
|
||||
bindings() {
|
||||
this.first = this.first.bind(this);
|
||||
this.setWS = this.setWS.bind(this);
|
||||
this.getObject = this.getObject.bind(this);
|
||||
}
|
||||
|
||||
first() {
|
||||
(async() => {
|
||||
const config = await ClientIPC.send('getConfig');
|
||||
this.setState(config);
|
||||
|
||||
// This is for Discord to stop error reporting :3
|
||||
window.BetterDiscord = {
|
||||
'version': config.version,
|
||||
'v': config.version
|
||||
};
|
||||
window.jQuery = {};
|
||||
|
||||
Events.emit('global-ready');
|
||||
})();
|
||||
|
||||
if (window.__bd) {
|
||||
this.setState(window.__bd);
|
||||
window.__bd = {
|
||||
setWS: this.setWS
|
||||
}
|
||||
Events.emit('socket-created', this.state.wsHook);
|
||||
}
|
||||
}
|
||||
|
||||
setWS(wSocket) {
|
||||
const state = this.state;
|
||||
state.wsHook = wSocket;
|
||||
this.setState(state);
|
||||
Events.emit('socket-created');
|
||||
}
|
||||
|
||||
getObject(name) {
|
||||
return this.state[name];
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
export { Global } from './core/global';
|
||||
export { Logger, Utils, FileUtils } from './core/utils';
|
||||
export { PluginManager, Plugin } from './core/pluginmanager';
|
||||
export { Pluging } from './core/plugin';
|
||||
export { BDIpc } from './core/bdipc';
|
||||
export { WebpackModules } from './core/webpackmodules';
|
||||
export { Events } from './core/events';
|
||||
export { SocketProxy } from './core/discordsocket';
|
||||
export { CssEditor } from './core/csseditor';
|
||||
export { Settings } from './core/settings';
|
||||
export { Vendor } from './core/vendor';
|
|
@ -12,7 +12,7 @@
|
|||
Base Module that every non-static module should extend
|
||||
*/
|
||||
|
||||
class Module {
|
||||
export default class Module {
|
||||
|
||||
constructor(args) {
|
||||
this.__ = {
|
||||
|
@ -43,5 +43,3 @@ class Module {
|
|||
get state() { return this.__.state; }
|
||||
|
||||
}
|
||||
|
||||
module.exports = { Module };
|
|
@ -0,0 +1,7 @@
|
|||
export { default as Events } from './events';
|
||||
export { default as Settings } from './settings';
|
||||
export { default as CssEditor } from './csseditor';
|
||||
export { default as PluginManager } from './pluginmanager';
|
||||
export { default as ThemeManager } from './thememanager';
|
||||
export { default as Globals } from './globals';
|
||||
export { default as Vendor } from './vendor';
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* BetterDiscord Plugin Base
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
export default class {
|
||||
|
||||
constructor(pluginInternals) {
|
||||
this.__pluginInternals = pluginInternals;
|
||||
this.hasSettings = this.pluginConfig && this.pluginConfig.length > 0;
|
||||
this.start = this.start.bind(this);
|
||||
this.stop = this.stop.bind(this);
|
||||
}
|
||||
|
||||
get configs() { return this.__pluginInternals.configs }
|
||||
get info() { return this.__pluginInternals.info }
|
||||
get paths() { return this.__pluginInternals.paths }
|
||||
get main() { return this.__pluginInternals.main }
|
||||
get defaultConfig() { return this.configs.defaultConfig }
|
||||
get userConfig() { return this.configs.userConfig }
|
||||
get name() { return this.info.name }
|
||||
get authors() { return this.info.authors }
|
||||
get version() { return this.info.version }
|
||||
get pluginPath() { return this.paths.contentPath }
|
||||
get dirName() { return this.paths.dirName }
|
||||
get enabled() { return this.userConfig.enabled }
|
||||
get pluginConfig() { return this.userConfig.config }
|
||||
|
||||
start() {
|
||||
if (this.onStart) {
|
||||
const started = this.onStart();
|
||||
if (started) {
|
||||
return this.userConfig.enabled = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return this.userConfig.enabled = true; //Assume plugin started since it doesn't have onStart
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.onStop) {
|
||||
const stopped = this.onStop();
|
||||
if (stopped) {
|
||||
this.userConfig.enabled = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.userConfig.enabled = false;
|
||||
return true; //Assume plugin stopped since it doesn't have onStop
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* BetterDiscord Plugin Manager Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import ContentManager from './contentmanager';
|
||||
import Plugin from './plugin';
|
||||
|
||||
export default class extends ContentManager {
|
||||
|
||||
static get localPlugins() {
|
||||
return this.localContent;
|
||||
}
|
||||
|
||||
static get moduleName() {
|
||||
return 'PluginManager';
|
||||
}
|
||||
|
||||
static get pathId() {
|
||||
return 'plugins';
|
||||
}
|
||||
|
||||
static get loadAllPlugins() { return this.loadAllContent }
|
||||
static get refreshPlugins() { return this.refreshContent }
|
||||
|
||||
static get loadContent() { return this.loadPlugin }
|
||||
static async loadPlugin(paths, configs, info, main) {
|
||||
const plugin = window.require(paths.mainPath)(Plugin, {}, {});
|
||||
const instance = new plugin({ configs, info, main, paths: { contentPath: paths.contentPath, dirName: paths.dirName } });
|
||||
|
||||
if (instance.enabled) instance.start();
|
||||
return instance;
|
||||
}
|
||||
|
||||
static get unloadContent() { return this.unloadPlugin }
|
||||
static async unloadPlugin(plugin) {
|
||||
try {
|
||||
if (plugin.enabled) plugin.stop();
|
||||
const { pluginPath } = plugin;
|
||||
const index = this.getPluginIndex(plugin);
|
||||
|
||||
delete window.require.cache[window.require.resolve(pluginPath)];
|
||||
this.localPlugins.splice(index, 1);
|
||||
} catch (err) {
|
||||
//This might fail but we don't have any other option at this point
|
||||
Logger.err('PluginManager', err);
|
||||
}
|
||||
}
|
||||
|
||||
static async reloadPlugin(plugin) {
|
||||
const _plugin = plugin instanceof Plugin ? plugin : this.findPlugin(plugin);
|
||||
if (!_plugin) throw { 'message': 'Attempted to reload a plugin that is not loaded?' };
|
||||
if (!_plugin.stop()) throw { 'message': 'Plugin failed to stop!' };
|
||||
const index = this.getPluginIndex(_plugin);
|
||||
const { pluginPath, dirName } = _plugin;
|
||||
|
||||
delete window.require.cache[window.require.resolve(pluginPath)];
|
||||
|
||||
return this.preloadContent(dirName, true, index);
|
||||
}
|
||||
|
||||
static stopPlugin(name) {
|
||||
const plugin = name instanceof Plugin ? name : this.getPluginByName(name);
|
||||
try {
|
||||
if (plugin) return plugin.stop();
|
||||
} catch (err) {
|
||||
// Logger.err('PluginManager', err);
|
||||
}
|
||||
return true; //Return true anyways since plugin doesn't exist
|
||||
}
|
||||
|
||||
static startPlugin(name) {
|
||||
const plugin = name instanceof Plugin ? name : this.getPluginByName(name);
|
||||
try {
|
||||
if (plugin) return plugin.start();
|
||||
} catch (err) {
|
||||
// Logger.err('PluginManager', err);
|
||||
}
|
||||
return true; //Return true anyways since plugin doesn't exist
|
||||
}
|
||||
|
||||
static get findPlugin() { return this.findContent }
|
||||
static get getPluginIndex() { return this.getContentIndex }
|
||||
static get getPluginByName() { return this.getContentByName }
|
||||
static get getPluginById() { return this.getContentById }
|
||||
static get getPluginByPath() { return this.getContentByPath }
|
||||
static get getPluginByDirName() { return this.getContentByDirName }
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* BetterDiscord Settings Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import defaultSettings from '../data/user.settings.default';
|
||||
|
||||
export default class {
|
||||
static get getSettings() {
|
||||
return defaultSettings;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* BetterDiscord Theme Manager Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import ContentManager from './contentmanager';
|
||||
|
||||
export default class extends ContentManager {
|
||||
|
||||
static get localThemes() {
|
||||
return this.localContent;
|
||||
}
|
||||
|
||||
static get pathId() {
|
||||
return 'themes';
|
||||
}
|
||||
|
||||
static get loadAllThemes() {
|
||||
return this.loadAllContent;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
<template src="./templates/BdSettings.html"></template>
|
||||
|
||||
<script>
|
||||
|
||||
const { Settings } = require('../../');
|
||||
|
||||
/*Imports*/
|
||||
import { SidebarView, Sidebar, SidebarItem, ContentColumn } from './sidebar';
|
||||
import { CoreSettings, UISettings, EmoteSettings, PluginsView, CssEditorView } from './bd';
|
||||
const components = { SidebarView, Sidebar, SidebarItem, ContentColumn, CoreSettings, UISettings, EmoteSettings, PluginsView, CssEditorView };
|
||||
|
||||
/*Constants*/
|
||||
const sidebarItems = [
|
||||
{ text: 'Internal', _type: 'header' },
|
||||
{ id: 0, contentid: "core", text: 'Core', active: false, _type: 'button' },
|
||||
{ id: 1, contentid: "ui", text: 'UI', active: false, _type: 'button' },
|
||||
{ id: 2, contentid: "emotes", text: 'Emotes', active: false, _type: 'button' },
|
||||
{ id: 3, contentid: "css", text: 'CSS Editor', active: false, _type: 'button' },
|
||||
{ text: 'External', _type: 'header' },
|
||||
{ id: 4, contentid: "plugins", text: 'Plugins', active: false, _type: 'button' },
|
||||
{ id: 5, contentid: "themes", text: 'Themes', active: false, _type: 'button' }
|
||||
];
|
||||
|
||||
/*Methods*/
|
||||
function itemOnClick(id) {
|
||||
if (this.animating || id === this.activeIndex) return;
|
||||
if (this.activeIndex >= 0) this.sidebarItems.find(item => item.id === this.activeIndex).active = false;
|
||||
this.sidebarItems.find(item => item.id === id).active = true;
|
||||
this.animating = true;
|
||||
this.lastActiveIndex = this.activeIndex;
|
||||
this.activeIndex = id;
|
||||
|
||||
if (this.first) {
|
||||
this.first = false;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.animating = false;
|
||||
this.lastActiveIndex = -1;
|
||||
}, 400);
|
||||
}
|
||||
|
||||
function animatingContent(s) {
|
||||
const item = this.sidebarItems.find(item => item.contentid === s);
|
||||
if (!item) return false;
|
||||
return item.id === this.lastActiveIndex;
|
||||
}
|
||||
|
||||
function activeContent(s) {
|
||||
const item = this.sidebarItems.find(item => item.contentid === s);
|
||||
if (!item) return false;
|
||||
return item.id === this.activeIndex;
|
||||
}
|
||||
|
||||
function enableSetting(cat, id) {
|
||||
switch (cat) {
|
||||
case 'core':
|
||||
return this.coreSettings.find(setting => setting.id === id).enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
function disableSetting(cat, id) {
|
||||
switch (cat) {
|
||||
case 'core':
|
||||
return this.coreSettings.find(setting => setting.id === id).enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
const methods = { itemOnClick, animatingContent, activeContent, enableSetting, disableSetting };
|
||||
|
||||
export default {
|
||||
components,
|
||||
props: ['active', 'close'],
|
||||
methods,
|
||||
data() {
|
||||
return {
|
||||
sidebarItems,
|
||||
activeIndex: -1,
|
||||
lastActiveIndex: -1,
|
||||
animating: false,
|
||||
first: true,
|
||||
settings: Settings.getSettings
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
coreSettings: function () {
|
||||
return this.settings.find(settingset => settingset.id === 'core').settings;
|
||||
}
|
||||
},
|
||||
updated: function () {
|
||||
if (this.active) return;
|
||||
this.activeIndex = this.lastActiveIndex = -1;
|
||||
this.sidebarItems.forEach(item => item.active = false);
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,54 +0,0 @@
|
|||
<template src="./templates/BdSettingsWrapper.html"></template>
|
||||
<script>
|
||||
const { Events } = require('../../');
|
||||
|
||||
/*Imports*/
|
||||
import BdSettings from './BdSettings.vue';
|
||||
const components = { BdSettings };
|
||||
|
||||
/*Methods*/
|
||||
function showSettings() {
|
||||
if (!this.loaded) return;
|
||||
this.active = true;
|
||||
}
|
||||
function hideSettings() {
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
const methods = { showSettings, hideSettings };
|
||||
|
||||
let globalKeyListener;
|
||||
|
||||
export default {
|
||||
components,
|
||||
methods,
|
||||
data() {
|
||||
return {
|
||||
loaded: false,
|
||||
active: false,
|
||||
platform: global.process.platform
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
|
||||
Events.on('ready', e => {
|
||||
this.loaded = true;
|
||||
});
|
||||
|
||||
window.addEventListener('keyup', globalKeyListener = e => {
|
||||
if (this.active && e.which === 27) {
|
||||
this.hideSettings();
|
||||
return;
|
||||
}
|
||||
if (!e.metaKey && !e.ctrlKey || e.key !== 'b') return;
|
||||
|
||||
!this.active ? this.showSettings() : this.hideSettings();
|
||||
|
||||
e.stopImmediatePropagation();
|
||||
});
|
||||
},
|
||||
destroyed: function () {
|
||||
if (globalKeyListener) window.removeEventListener('keyup', globalKeyListener);
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,29 +0,0 @@
|
|||
<template>
|
||||
<SettingsWrapper headertext="Core Settings">
|
||||
<div class="bd-form-item" v-for="setting in settings" :key="setting.id">
|
||||
<SettingSwitch key="setting.id" :setting="setting" :onClick="settingOnClick" :disabled="setting.disabled"/>
|
||||
<div class="bd-form-divider"/>
|
||||
</div>
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/*Imports*/
|
||||
import { SettingsWrapper } from './';
|
||||
import { SettingSwitch } from '../generic';
|
||||
const components = { SettingsWrapper, SettingSwitch };
|
||||
|
||||
/*Methods*/
|
||||
function settingOnClick(setting) {
|
||||
if (setting.enabled) return this.disableSetting('core', setting.id);
|
||||
this.enableSetting('core', setting.id);
|
||||
}
|
||||
|
||||
const methods = { settingOnClick };
|
||||
|
||||
export default {
|
||||
components,
|
||||
methods,
|
||||
props: ['settings', 'enableSetting', 'disableSetting']
|
||||
}
|
||||
</script>
|
|
@ -1,32 +0,0 @@
|
|||
<template src="./templates/CssEditor.html"></template>
|
||||
|
||||
<script>
|
||||
const { CssEditor } = require('../../../');
|
||||
|
||||
/*Imports*/
|
||||
import { SettingsWrapper } from './';
|
||||
import { SettingSwitch, FormButton } from '../generic';
|
||||
const components = { SettingsWrapper, SettingSwitch, FormButton };
|
||||
|
||||
function openInternalEditor() {
|
||||
CssEditor.show();
|
||||
}
|
||||
|
||||
function settingClicked() {
|
||||
this.dummySetting.checked = !this.dummySetting.checked;
|
||||
}
|
||||
|
||||
export default {
|
||||
components,
|
||||
methods: { openInternalEditor, settingClicked },
|
||||
data() {
|
||||
return {
|
||||
dummySetting: {
|
||||
title: "Live Update",
|
||||
hint: "Automatically update client css when saved.",
|
||||
checked: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,14 +0,0 @@
|
|||
<template>
|
||||
<SettingsWrapper headertext="Emote Settings">
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/*Imports*/
|
||||
import { SettingsWrapper } from './';
|
||||
const components = { SettingsWrapper };
|
||||
|
||||
export default {
|
||||
components
|
||||
}
|
||||
</script>
|
|
@ -1,37 +0,0 @@
|
|||
<template src="./templates/PluginCard.html"></template>
|
||||
|
||||
<script>
|
||||
/*Imports*/
|
||||
import { Button, ButtonGroup, SettingSwitch } from '../generic';
|
||||
import MiSettings from 'vue-material-design-icons/settings.vue';
|
||||
import MiReload from 'vue-material-design-icons/refresh.vue';
|
||||
import MiEdit from 'vue-material-design-icons/pencil.vue';
|
||||
import MiDelete from 'vue-material-design-icons/delete.vue';
|
||||
const components = { MiSettings, Button, ButtonGroup, SettingSwitch, MiReload, MiEdit, MiDelete };
|
||||
|
||||
/*Methods*/
|
||||
function showSettings() {
|
||||
this.settingsOpen = true;
|
||||
}
|
||||
function editPlugin() {
|
||||
try {
|
||||
window.require('electron').shell.openItem(this.plugin.pluginPath);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
const methods = { editPlugin };
|
||||
|
||||
export default {
|
||||
props: ['plugin', 'togglePlugin', 'reloadPlugin', 'showSettings'],
|
||||
components,
|
||||
name: "PluginCard",
|
||||
methods,
|
||||
data() {
|
||||
return {
|
||||
'settingsOpen': false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,77 +0,0 @@
|
|||
<template src="./templates/PluginSettingsModal.html"></template>
|
||||
<script>
|
||||
/*Imports*/
|
||||
import { Modal } from '../generic';
|
||||
const components = { Modal };
|
||||
|
||||
/*Methods*/
|
||||
function textInputKd(e) {
|
||||
console.log(e);
|
||||
this.changed = true;
|
||||
}
|
||||
const methods = { textInputKd };
|
||||
|
||||
export default {
|
||||
props: ['plugin'],
|
||||
data() {
|
||||
return {
|
||||
'changed': false
|
||||
}
|
||||
},
|
||||
components,
|
||||
methods
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.bd-modal-inner {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bd-modal-footer .footer-alert {
|
||||
opacity: 0;
|
||||
transform: translateY(100%);
|
||||
height: 30px;
|
||||
display: flex;
|
||||
background: rgba(32, 34, 37, 0.9);
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
box-shadow: 0 2px 10px 0 rgba(0,0,0,.2);
|
||||
padding: 10px 10px 10px 16px;
|
||||
border-radius: 5px;
|
||||
transition: all .3s ease-in-out;
|
||||
}
|
||||
|
||||
.bd-modal-footer .footer-alert.bd-active {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.bd-modal-footer .footer-alert .footer-alert-text {
|
||||
color: #FFF;
|
||||
flex: 1 1 auto;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.bd-modal-footer .footer-alert {
|
||||
height: 30px;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.bd-modal-footer .footer-alert .footer-alert-text {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.bd-modal-footer .footer-alert .bd-button {
|
||||
width: 120px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.bd-modal-footer .footer-alert .bd-reset-button {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
|
@ -1,68 +0,0 @@
|
|||
<template src="./templates/PluginsView.html"></template>
|
||||
<script>
|
||||
const { PluginManager, Plugin } = require('../../../');
|
||||
|
||||
/*Imports*/
|
||||
import { SettingsWrapper } from './';
|
||||
import PluginSettingsModal from './PluginSettingsModal.vue';
|
||||
import PluginCard from './PluginCard.vue';
|
||||
import Refresh from 'vue-material-design-icons/refresh.vue';
|
||||
const components = { SettingsWrapper, PluginCard, Refresh, PluginSettingsModal };
|
||||
|
||||
/*Variables*/
|
||||
|
||||
/*Methods*/
|
||||
async function refreshLocalPlugins() {
|
||||
try {
|
||||
await PluginManager.refreshPlugins();
|
||||
this.$forceUpdate();
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function showLocal() {
|
||||
this.local = true;
|
||||
}
|
||||
|
||||
function showOnline() {
|
||||
this.local = false;
|
||||
}
|
||||
|
||||
//TODO Display error if plugin fails to start/stop
|
||||
function togglePlugin(plugin) {
|
||||
if (plugin.enabled) {
|
||||
this.pluginManager.stopPlugin(plugin);
|
||||
} else {
|
||||
this.pluginManager.startPlugin(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
async function reloadPlugin(plugin) {
|
||||
await this.pluginManager.reloadPlugin(plugin.name);
|
||||
this.$forceUpdate();
|
||||
}
|
||||
|
||||
function showSettings(plugin) {
|
||||
this.settingsOpen = plugin;
|
||||
}
|
||||
|
||||
const methods = { showLocal, showOnline, refreshLocalPlugins, togglePlugin, reloadPlugin, showSettings };
|
||||
|
||||
export default {
|
||||
components,
|
||||
data() {
|
||||
return {
|
||||
local: true,
|
||||
pluginManager: PluginManager,
|
||||
settingsOpen: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
localPlugins: function () {
|
||||
return this.pluginManager.plugins;
|
||||
}
|
||||
},
|
||||
methods
|
||||
}
|
||||
</script>
|
|
@ -1,11 +0,0 @@
|
|||
<template src="./templates/SettingsWrapper.html"></template>
|
||||
<script>
|
||||
/*Imports*/
|
||||
import { ScrollerWrap } from '../generic';
|
||||
const components = { ScrollerWrap };
|
||||
|
||||
export default {
|
||||
components,
|
||||
props: ['headertext']
|
||||
}
|
||||
</script>
|
|
@ -1,14 +0,0 @@
|
|||
<template>
|
||||
<SettingsWrapper headertext="UI Settings">
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/*Imports*/
|
||||
import { SettingsWrapper } from './';
|
||||
const components = { SettingsWrapper };
|
||||
|
||||
export default {
|
||||
components
|
||||
}
|
||||
</script>
|
|
@ -1,33 +0,0 @@
|
|||
<SettingsWrapper headertext="CSS Editor">
|
||||
<div class="bd-css-editor">
|
||||
<div class="bd-form-item">
|
||||
<h5>Custom Editor</h5>
|
||||
<div class="bd-form-warning">
|
||||
<div class="bd-text">Custom Editor is not installed!</div>
|
||||
<FormButton>
|
||||
Install
|
||||
</FormButton>
|
||||
</div>
|
||||
<span style="color: #FFF; font-size: 12px; font-weight: 700;">*This is displayed if editor is not installed</span>
|
||||
<FormButton :onClick="openInternalEditor">
|
||||
Open
|
||||
</FormButton>
|
||||
</div>
|
||||
<div class="bd-form-divider"></div>
|
||||
<SettingSwitch :setting="dummySetting" :onClick="settingClicked"/>
|
||||
<div class="bd-form-item">
|
||||
<h5>System Editor</h5>
|
||||
<FormButton>
|
||||
Open
|
||||
</FormButton>
|
||||
</div>
|
||||
<div class="bd-form-divider"></div>
|
||||
<FormButton :onClick="settingClicked">
|
||||
Enabled
|
||||
</FormButton>
|
||||
<FormButton :disabled="true">
|
||||
<span>Disabled</span>
|
||||
</FormButton>
|
||||
<FormButton :loading="true"/>
|
||||
</div>
|
||||
</SettingsWrapper>
|
|
@ -1,34 +0,0 @@
|
|||
<div class="bd-plugin-card">
|
||||
<div class="bd-plugin-header">
|
||||
<span v-tooltip="'wat'">{{plugin.name}}</span>
|
||||
<div class="bd-flex-spacer"/>
|
||||
<label class="bd-switch-wrapper" @click="togglePlugin(plugin)">
|
||||
<input type="checkbox" class="bd-switch-checkbox" />
|
||||
<div class="bd-switch" :class="{'bd-checked': plugin.enabled}" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="bd-plugin-body">
|
||||
<div class="bd-plugin-description">{{plugin.description}}</div>
|
||||
<div class="bd-plugin-footer">
|
||||
<div class="bd-plugin-extra">v{{plugin.version}} by {{plugin.authors.join(', ').replace(/,(?!.*,)/gmi, ' and')}}</div>
|
||||
<div class="bd-controls">
|
||||
<ButtonGroup>
|
||||
<Button v-tooltip="'Settings'" v-if="plugin.hasSettings" :onClick="() => showSettings(plugin)">
|
||||
<MiSettings/>
|
||||
</Button>
|
||||
<Button v-tooltip="'Reload'" :onClick="() => reloadPlugin(plugin)">
|
||||
<MiReload/>
|
||||
</Button>
|
||||
<Button v-tooltip="'Edit'" :onClick="editPlugin">
|
||||
<MiEdit/>
|
||||
</Button>
|
||||
<Button v-tooltip="'Uninstall'" type="err">
|
||||
<MiDelete/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -1,38 +0,0 @@
|
|||
<Modal :headerText="plugin.name + ' Settings'" :close="() => { }">
|
||||
<div slot="body" v-for="setting in plugin.pluginConfig" class="bd-plugin-settings-body">
|
||||
<div class="bd-form-item">
|
||||
|
||||
<div v-if="setting.type === 'bool'" class="bd-setting-switch">
|
||||
<div class="bd-title">
|
||||
<h3>{{setting.text}}</h3>
|
||||
<label class="bd-switch-wrapper">
|
||||
<input type="checkbox" class="bd-switch-checkbox" />
|
||||
<div class="bd-switch" :class="{'bd-checked': setting.value}" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="bd-hint">{{setting.hint}}</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="setting.type === 'text'" class="bd-form-textinput">
|
||||
<div class="bd-title">
|
||||
<h3>{{setting.text}}</h3>
|
||||
<div class="bd-textinput-wrapper">
|
||||
<input type="text" v-model="setting.value" @keyup.stop @keydown="textInputKd"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bd-hint">{{setting.hint}}</div>
|
||||
</div>
|
||||
|
||||
<div class="bd-form-divider"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div slot="footer">
|
||||
<div class="footer-alert" :class="{'bd-active': changed}">
|
||||
<div class="footer-alert-text">Unsaved changes</div>
|
||||
<div class="bd-reset-button">Reset</div>
|
||||
<div class="bd-button bd-ok">Save Changes</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
|
@ -1,29 +0,0 @@
|
|||
<SettingsWrapper headertext="Plugins">
|
||||
|
||||
<div class="bd-flex bd-flex-col bd-pluginsView">
|
||||
<div class="bd-flex bd-tabheader">
|
||||
<div class="bd-flex-grow bd-button" :class="{'bd-active': local}" @click="showLocal">
|
||||
<h3>Local</h3>
|
||||
<div class="bd-material-button" @click="refreshLocalPlugins">
|
||||
<refresh/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bd-flex-grow bd-button" :class="{'bd-active': !local}" @click="showOnline">
|
||||
<h3>Online</h3>
|
||||
<div class="bd-material-button">
|
||||
<refresh/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="local" class="bd-flex bd-flex-grow bd-flex-col bd-plugins-container bd-local-plugins">
|
||||
<PluginCard v-for="plugin in localPlugins" :plugin="plugin" :key="plugin.id" :togglePlugin="togglePlugin" :reloadPlugin="reloadPlugin" :showSettings="showSettings"/>
|
||||
</div>
|
||||
<div v-if="!local" class="bd-spinner-container">
|
||||
<div class="bd-spinner-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="settingsOpen !== null" class="bd-backdrop" @click="settingsOpen = null"></div>
|
||||
<div v-if="settingsOpen !== null" class="bd-modal">
|
||||
<PluginSettingsModal :plugin="settingsOpen"/>
|
||||
</div>
|
||||
</SettingsWrapper>
|
|
@ -1,8 +0,0 @@
|
|||
<div class="bd-settingsWrap">
|
||||
<div class="bd-settingsWrap-header">{{headertext}}</div>
|
||||
<ScrollerWrap>
|
||||
<div class="bd-scroller">
|
||||
<slot/>
|
||||
</div>
|
||||
</ScrollerWrap>
|
||||
</div>
|
|
@ -1,9 +0,0 @@
|
|||
<template>
|
||||
<div class="bd-button-group">
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
|
@ -1,11 +0,0 @@
|
|||
<template>
|
||||
<div class="bd-form-button bd-button" :class="{'bd-disabled': disabled}" @click="!disabled && !loading ? onClick() : null">
|
||||
<div v-if="loading" class="bd-spinner-7"></div>
|
||||
<slot v-else />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['loading', 'disabled', 'type', 'onClick']
|
||||
}
|
||||
</script>
|
|
@ -1,10 +0,0 @@
|
|||
<template>
|
||||
<div class="bd-scroller-wrap" :class="{'bd-dark': dark}">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['dark']
|
||||
}
|
||||
</script>
|
|
@ -1,6 +0,0 @@
|
|||
<template src="./templates/Button.html"></template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['item', 'onClick']
|
||||
}
|
||||
</script>
|
|
@ -1,2 +0,0 @@
|
|||
<template src="./templates/ContentColumn.html"></template>
|
||||
<script> export default { }</script>
|
|
@ -1,6 +0,0 @@
|
|||
<template src="./templates/Header.html"></template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['item']
|
||||
}
|
||||
</script>
|
|
@ -1,11 +0,0 @@
|
|||
<template src="./templates/Item.html"></template>
|
||||
<script>
|
||||
/*Imports*/
|
||||
import { SidebarHeader, SidebarButton } from './';
|
||||
const components = { SidebarHeader, SidebarButton };
|
||||
|
||||
export default {
|
||||
components,
|
||||
props: ['item', 'onClick']
|
||||
}
|
||||
</script>
|
|
@ -1,2 +0,0 @@
|
|||
<template src="./templates/Sidebar.html"></template>
|
||||
<script> export default { }</script>
|
|
@ -1,11 +0,0 @@
|
|||
<template src="./templates/View.html"></template>
|
||||
<script>
|
||||
/*Imports*/
|
||||
import { ScrollerWrap } from '../generic';
|
||||
const components = { ScrollerWrap };
|
||||
|
||||
export default {
|
||||
components,
|
||||
props: ['contentVisible', 'animating']
|
||||
}
|
||||
</script>
|
|
@ -1 +0,0 @@
|
|||
<div class="bd-item" :class="{active: item.active}" @click="onClick(item.id)">{{item.text}}</div>
|
|
@ -1,3 +0,0 @@
|
|||
<div class="bd-content bd-content-column">
|
||||
<slot />
|
||||
</div>
|
|
@ -1 +0,0 @@
|
|||
<div class='bd-header'>{{item.text}}</div>
|
|
@ -1,2 +0,0 @@
|
|||
<SidebarButton v-if="item._type == 'button'" :item="item" :onClick="onClick" />
|
||||
<SidebarHeader v-else-if="item._type == 'header'" :item="item" />
|
|
@ -1,3 +0,0 @@
|
|||
<div class="bd-sidebar bd-scroller">
|
||||
<slot/>
|
||||
</div>
|
|
@ -1,12 +0,0 @@
|
|||
<div class="bd-sidebar-view" :class="{active: contentVisible, animating: animating}">
|
||||
<div class="bd-sidebar-region">
|
||||
<div class="bd-settingsWrap">
|
||||
<ScrollerWrap dark="true">
|
||||
<slot name="sidebar"/>
|
||||
</ScrollerWrap>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bd-content-region">
|
||||
<slot name="content"/>
|
||||
</div>
|
||||
</div>
|
|
@ -1,32 +0,0 @@
|
|||
<div class="bd-settings" :class="{active: active}" @keyup="close">
|
||||
<SidebarView :contentVisible="this.activeIndex >= 0" :animating="this.animating">
|
||||
<Sidebar slot="sidebar">
|
||||
<div class="bd-settings-x" @click="close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 12 12"><g fill="none" fill-rule="evenodd"><path d="M0 0h12v12H0"></path><path class="fill" fill="#dcddde" d="M9.5 3.205L8.795 2.5 6 5.295 3.205 2.5l-.705.705L5.295 6 2.5 8.795l.705.705L6 6.705 8.795 9.5l.705-.705L6.705 6"></path></g></svg>
|
||||
<span>ESC</span>
|
||||
</div>
|
||||
<SidebarItem v-for="item in sidebarItems" :item="item" :key="item.id" :onClick="itemOnClick" />
|
||||
<div class="bd-info">
|
||||
<span>v2.0.0a by Jiiks/JsSucks</span>
|
||||
</div>
|
||||
</Sidebar>
|
||||
<ContentColumn slot="content">
|
||||
<div v-if="activeContent('core') || animatingContent('core')" :class="{active: activeContent('core'), animating: animatingContent('core')}">
|
||||
<CoreSettings :settings="coreSettings" :enableSetting="enableSetting" :disableSetting="disableSetting"/>
|
||||
</div>
|
||||
<div v-if="activeContent('ui') || animatingContent('ui')" :class="{active: activeContent('ui'), animating: animatingContent('ui')}">
|
||||
<UISettings />
|
||||
</div>
|
||||
<div v-if="activeContent('css') || animatingContent('css')" :class="{active: activeContent('css'), animating: animatingContent('css')}">
|
||||
<CssEditorView />
|
||||
</div>
|
||||
<div v-if="activeContent('emotes') || animatingContent('emotes')" :class="{active: activeContent('emotes'), animating: animatingContent('emotes')}">
|
||||
<EmoteSettings />
|
||||
</div>
|
||||
<div v-if="activeContent('plugins') || animatingContent('plugins')" :class="{active: activeContent('plugins'), animating: animatingContent('plugins')}">
|
||||
<PluginsView />
|
||||
</div>
|
||||
</ContentColumn>
|
||||
|
||||
</SidebarView>
|
||||
</div>
|
|
@ -1,6 +0,0 @@
|
|||
<div class="bd-settings-wrapper" :class="[{active: active}, 'platform-' + this.platform]">
|
||||
<div class="bd-settings-button" :class="{active: active}" @click="showSettings">
|
||||
<div class="bd-settings-button-btn" :class="[{'bd-loading': !loaded}]"></div>
|
||||
</div>
|
||||
<BdSettings :active="active" :close="hideSettings"/>
|
||||
</div>
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* BetterDiscord Client Renderer
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const { WebpackModules } = require('../');
|
||||
|
||||
class Renderer {
|
||||
|
||||
static async render(component, root) {
|
||||
if (!this.React) this.React = await this.getReact();
|
||||
if (!this.reactDom) this.reactDom = await this.getReactDom();
|
||||
const React = this.React;
|
||||
window.React = React;
|
||||
this.reactDom.render(component, root);
|
||||
}
|
||||
|
||||
static async getReact() {
|
||||
const getReact = await WebpackModules.getModuleByProps(('createElement', 'cloneElement'));
|
||||
return getReact[0].exports;
|
||||
}
|
||||
|
||||
static async getReactDom() {
|
||||
const getReactDom = await WebpackModules.getModuleByProps(('render', 'findDOMNode'));
|
||||
return getReactDom[0].exports;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = { Renderer };
|
|
@ -1,45 +0,0 @@
|
|||
/**
|
||||
* BetterDiscord Client UI Module
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const $ = require('jquery');
|
||||
const Vue = require('vue').default;
|
||||
const VTooltip = require('v-tooltip');
|
||||
|
||||
const BdSettingsWrapper = (require('./components/BdSettingsWrapper.vue')).default;
|
||||
class UI {
|
||||
|
||||
constructor() {
|
||||
$('body').append($('<bdbody/>')
|
||||
.append($('<div/>', {
|
||||
id: 'bd-settings'
|
||||
})).append($('<bdtooltips/>')));
|
||||
|
||||
Vue.use(VTooltip, {
|
||||
defaultContainer: 'bdtooltips',
|
||||
defaultClass: 'bd-tooltip',
|
||||
defaultTargetClass: 'bd-has-tooltip',
|
||||
defaultInnerSelector: '.bd-tooltip-inner',
|
||||
defaultTemplate: '<div class="bd-tooltip"><span class="bd-tooltip-inner"></span></div>'
|
||||
});
|
||||
|
||||
|
||||
this.vueInstance = new Vue({
|
||||
el: '#bd-settings',
|
||||
components: { BdSettingsWrapper },
|
||||
template: '<BdSettingsWrapper/>'
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
module.exports = { UI }
|
||||
|
||||
|
|
@ -1,24 +1,24 @@
|
|||
/**
|
||||
* BetterDiscord Client Utils Module
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* BetterDiscord Vendor Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
*/
|
||||
|
||||
const {WebpackModules} = require('./webpackmodules');
|
||||
const jQuery = require('jquery');
|
||||
import WebpackModules from './webpackmodules';
|
||||
import jQuery from 'jquery';
|
||||
|
||||
class Vendor {
|
||||
export default class {
|
||||
|
||||
static get jQuery() {
|
||||
return jQuery;
|
||||
}
|
||||
|
||||
static get $() {
|
||||
return jQuery;
|
||||
return this.jQuery;
|
||||
}
|
||||
|
||||
static get moment() {
|
||||
|
@ -26,5 +26,3 @@ class Vendor {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = {Vendor};
|
|
@ -1,13 +1,51 @@
|
|||
/**
|
||||
* BetterDiscord Client WebpackModules Module
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* BetterDiscord WebpackModules Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
const { Filters } = require('./utils');
|
||||
|
||||
class Filters {
|
||||
static byProperties(props, selector = m => m) {
|
||||
return module => {
|
||||
const component = selector(module);
|
||||
if (!component) return false;
|
||||
return props.every(property => component[property] !== undefined);
|
||||
};
|
||||
}
|
||||
|
||||
static byPrototypeFields(fields, selector = m => m) {
|
||||
return module => {
|
||||
const component = selector(module);
|
||||
if (!component) return false;
|
||||
if (!component.prototype) return false;
|
||||
return fields.every(field => component.prototype[field] !== undefined);
|
||||
};
|
||||
}
|
||||
|
||||
static byCode(search, selector = m => m) {
|
||||
return module => {
|
||||
const method = selector(module);
|
||||
if (!method) return false;
|
||||
return method.toString().search(search) !== -1;
|
||||
};
|
||||
}
|
||||
|
||||
static byDisplayName(name) {
|
||||
return module => {
|
||||
return module && module.displayName === name;
|
||||
};
|
||||
}
|
||||
|
||||
static combine(...filters) {
|
||||
return module => {
|
||||
return filters.every(filter => filter(module));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const KnownModules = {
|
||||
React: Filters.byProperties(['createElement', 'cloneElement']),
|
||||
|
@ -163,11 +201,7 @@ const KnownModules = {
|
|||
ExternalLink: Filters.byCode(/\.trusted\b/)
|
||||
};
|
||||
|
||||
const Cache = {};
|
||||
|
||||
|
||||
class WebpackModules {
|
||||
|
||||
export default class {
|
||||
/* Synchronous */
|
||||
static getModuleByName(name, fallback) {
|
||||
if (Cache.hasOwnProperty(name)) return Cache[name];
|
||||
|
@ -224,5 +258,3 @@ class WebpackModules {
|
|||
return __webpack_require__.c;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { WebpackModules };
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* BetterDiscord Client UI Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import Dom from './dom';
|
||||
import Vue from 'vue';
|
||||
import VTooltip from 'v-tooltip';
|
||||
import { BdSettingsWrapper } from './components';
|
||||
|
||||
export default class {
|
||||
static injectUi() {
|
||||
Vue.use(VTooltip, {
|
||||
defaultContainer: 'bdtooltips',
|
||||
defaultClass: 'bd-tooltip',
|
||||
defaultTargetClass: 'bd-has-tooltip',
|
||||
defaultInnerSelector: '.bd-tooltip-inner',
|
||||
defaultTemplate: '<div class="bd-tooltip"><span class="bd-tooltip-inner"></span></div>'
|
||||
});
|
||||
|
||||
Dom.createElement('div', null, 'bd-settings').appendTo(Dom.bdBody);
|
||||
|
||||
const vueInstance = new Vue({
|
||||
el: '#bd-settings',
|
||||
components: { BdSettingsWrapper },
|
||||
template: '<BdSettingsWrapper/>'
|
||||
});
|
||||
|
||||
return vueInstance;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/**
|
||||
* BetterDiscord Settings Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-settings" :class="{active: active}" @keyup="close">
|
||||
<SidebarView :contentVisible="this.activeIndex >= 0" :animating="this.animating">
|
||||
<Sidebar slot="sidebar">
|
||||
<div class="bd-settings-x" @click="close">
|
||||
<SvgX size="17"/>
|
||||
<span>ESC</span>
|
||||
</div>
|
||||
<SidebarItem v-for="item in sidebarItems" :item="item" :key="item.id" :onClick="itemOnClick" />
|
||||
<div class="bd-info">
|
||||
<span>v2.0.0a by Jiiks/JsSucks</span>
|
||||
</div>
|
||||
</Sidebar>
|
||||
<ContentColumn slot="content">
|
||||
<div v-if="activeContent('core') || animatingContent('core')" :class="{active: activeContent('core'), animating: animatingContent('core')}">
|
||||
<CoreSettings :settings="coreSettings" :enableSetting="enableSetting" :disableSetting="disableSetting" />
|
||||
</div>
|
||||
<div v-if="activeContent('ui') || animatingContent('ui')" :class="{active: activeContent('ui'), animating: animatingContent('ui')}">
|
||||
<UISettings />
|
||||
</div>
|
||||
<div v-if="activeContent('css') || animatingContent('css')" :class="{active: activeContent('css'), animating: animatingContent('css')}">
|
||||
<CssEditorView />
|
||||
</div>
|
||||
<div v-if="activeContent('emotes') || animatingContent('emotes')" :class="{active: activeContent('emotes'), animating: animatingContent('emotes')}">
|
||||
<EmoteSettings />
|
||||
</div>
|
||||
<div v-if="activeContent('plugins') || animatingContent('plugins')" :class="{active: activeContent('plugins'), animating: animatingContent('plugins')}">
|
||||
<PluginsView />
|
||||
</div>
|
||||
</ContentColumn>
|
||||
</SidebarView>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
// Imports
|
||||
import { Settings } from 'modules';
|
||||
import { SidebarView, Sidebar, SidebarItem, ContentColumn } from './sidebar';
|
||||
import { CoreSettings, UISettings, EmoteSettings, CssEditorView, PluginsView } from './bd';
|
||||
import { SvgX } from './common';
|
||||
|
||||
// Constants
|
||||
const sidebarItems = [
|
||||
{ text: 'Internal', _type: 'header' },
|
||||
{ id: 0, contentid: "core", text: 'Core', active: false, _type: 'button' },
|
||||
{ id: 1, contentid: "ui", text: 'UI', active: false, _type: 'button' },
|
||||
{ id: 2, contentid: "emotes", text: 'Emotes', active: false, _type: 'button' },
|
||||
{ id: 3, contentid: "css", text: 'CSS Editor', active: false, _type: 'button' },
|
||||
{ text: 'External', _type: 'header' },
|
||||
{ id: 4, contentid: "plugins", text: 'Plugins', active: false, _type: 'button' },
|
||||
{ id: 5, contentid: "themes", text: 'Themes', active: false, _type: 'button' }
|
||||
];
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
sidebarItems,
|
||||
activeIndex: -1,
|
||||
lastActiveIndex: -1,
|
||||
animating: false,
|
||||
first: true,
|
||||
settings: Settings.getSettings
|
||||
}
|
||||
},
|
||||
props: ['active', 'close'],
|
||||
computed: {
|
||||
coreSettings() {
|
||||
return this.settings.find(settingset => settingset.id === 'core').settings;
|
||||
}
|
||||
},
|
||||
components: {
|
||||
SidebarView, Sidebar, SidebarItem, ContentColumn,
|
||||
CoreSettings, UISettings, EmoteSettings, CssEditorView, PluginsView,
|
||||
SvgX
|
||||
},
|
||||
methods: {
|
||||
itemOnClick(id) {
|
||||
if (this.animating || id === this.activeIndex) return;
|
||||
if (this.activeIndex >= 0) this.sidebarItems.find(item => item.id === this.activeIndex).active = false;
|
||||
this.sidebarItems.find(item => item.id === id).active = true;
|
||||
this.animating = true;
|
||||
this.lastActiveIndex = this.activeIndex;
|
||||
this.activeIndex = id;
|
||||
|
||||
if (this.first) {
|
||||
this.first = false;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.animating = false;
|
||||
this.lastActiveIndex = -1;
|
||||
}, 400);
|
||||
},
|
||||
activeContent(s) {
|
||||
const item = this.sidebarItems.find(item => item.contentid === s);
|
||||
if (!item) return false;
|
||||
return item.id === this.activeIndex;
|
||||
},
|
||||
animatingContent(s) {
|
||||
const item = this.sidebarItems.find(item => item.contentid === s);
|
||||
if (!item) return false;
|
||||
return item.id === this.lastActiveIndex;
|
||||
},
|
||||
enableSetting(cat, id) {
|
||||
switch (cat) {
|
||||
case 'core':
|
||||
return this.coreSettings.find(setting => setting.id === id).enabled = true;
|
||||
}
|
||||
},
|
||||
disableSetting(cat, id) {
|
||||
switch (cat) {
|
||||
case 'core':
|
||||
return this.coreSettings.find(setting => setting.id === id).enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* BetterDiscord Settings Wrapper Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-settings-wrapper" :class="[{active: active}, 'platform-' + this.platform]">
|
||||
<div class="bd-settings-button" :class="{active: active}" @click="showSettings">
|
||||
<div class="bd-settings-button-btn" :class="[{'bd-loading': !loaded}]"></div>
|
||||
</div>
|
||||
<BdSettings :active="active" :close="hideSettings" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
// Imports
|
||||
import { Events } from 'modules';
|
||||
import BdSettings from './BdSettings.vue';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loaded: false,
|
||||
active: false,
|
||||
platform: global.process.platform
|
||||
}
|
||||
},
|
||||
components: {
|
||||
BdSettings
|
||||
},
|
||||
methods: {
|
||||
showSettings() {
|
||||
if (!this.loaded) return;
|
||||
this.active = true;
|
||||
},
|
||||
hideSettings() { this.active = false },
|
||||
toggleSettings() { this.active = !this.active },
|
||||
keyupListener(e) {
|
||||
if (this.active && e.which === 27) return this.hideSettings();
|
||||
if (!e.metaKey && !e.ctrlKey || e.key !== 'b') return;
|
||||
this.toggleSettings();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
Events.on('ready', e => this.loaded = true);
|
||||
window.addEventListener('keyup', this.keyupListener);
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('keyup', this.keyupListener);
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* BetterDiscord Core Settings Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<SettingsWrapper headertext="Core Settings">
|
||||
<div class="bd-form-item" v-for="setting in settings" :key="setting.id">
|
||||
<SettingSwitch key="setting.id" :setting="setting" :onClick="settingOnClick" :disabled="setting.disabled" />
|
||||
<div class="bd-form-divider" />
|
||||
</div>
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import { SettingsWrapper } from './';
|
||||
import { SettingSwitch } from '../common';
|
||||
|
||||
/*Methods*/
|
||||
function settingOnClick(setting) {
|
||||
if (setting.enabled) return this.disableSetting('core', setting.id);
|
||||
this.enableSetting('core', setting.id);
|
||||
}
|
||||
|
||||
const methods = { settingOnClick };
|
||||
|
||||
export default {
|
||||
props: ['settings', 'enableSetting', 'disableSetting'],
|
||||
components: {
|
||||
SettingsWrapper, SettingSwitch
|
||||
},
|
||||
methods: {
|
||||
settingOnClick(setting) {
|
||||
if (setting.enabled) return this.disableSetting('core', setting.id);
|
||||
this.enableSetting('core', setting.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* BetterDiscord Css Editor Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<SettingsWrapper headertext="CSS Editor">
|
||||
<div class="bd-css-editor">
|
||||
<div class="bd-form-item">
|
||||
<h5>Custom Editor</h5>
|
||||
<div class="bd-form-warning">
|
||||
<div class="bd-text">Custom Editor is not installed!</div>
|
||||
<FormButton>
|
||||
Install
|
||||
</FormButton>
|
||||
</div>
|
||||
<span style="color: #FFF; font-size: 12px; font-weight: 700;">*This is displayed if editor is not installed</span>
|
||||
<FormButton :onClick="openInternalEditor">
|
||||
Open
|
||||
</FormButton>
|
||||
</div>
|
||||
<div class="bd-form-divider"></div>
|
||||
<SettingSwitch :setting="dummySetting" :onClick="settingClicked" />
|
||||
<div class="bd-form-item">
|
||||
<h5>System Editor</h5>
|
||||
<FormButton>
|
||||
Open
|
||||
</FormButton>
|
||||
</div>
|
||||
<div class="bd-form-divider"></div>
|
||||
<FormButton :onClick="settingClicked">
|
||||
Enabled
|
||||
</FormButton>
|
||||
<FormButton :disabled="true">
|
||||
<span>Disabled</span>
|
||||
</FormButton>
|
||||
<FormButton :loading="true" />
|
||||
</div>
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import { CssEditor } from 'modules';
|
||||
import { SettingsWrapper } from './';
|
||||
import { SettingSwitch, FormButton } from '../common';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingsWrapper,
|
||||
SettingSwitch, FormButton
|
||||
},
|
||||
methods: {
|
||||
openInternalEditor() {
|
||||
CssEditor.show();
|
||||
},
|
||||
settingClicked() {
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dummySetting: {
|
||||
title: "Live Update",
|
||||
hint: "Automatically update client css when saved.",
|
||||
checked: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* BetterDiscord Emote Settings Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<SettingsWrapper headertext="Emote Settings">
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import { SettingsWrapper } from './';
|
||||
import { SettingSwitch } from '../common';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingsWrapper,
|
||||
SettingSwitch
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* BetterDiscord Plugin Card Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-plugin-card">
|
||||
<div class="bd-plugin-header">
|
||||
<span v-tooltip="'wat'">{{plugin.name}}</span>
|
||||
<div class="bd-flex-spacer" />
|
||||
<label class="bd-switch-wrapper" @click="() => { togglePlugin(plugin); this.$forceUpdate(); }">
|
||||
<input type="checkbox" class="bd-switch-checkbox" />
|
||||
<div class="bd-switch" :class="{'bd-checked': plugin.enabled}" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="bd-plugin-body">
|
||||
<div class="bd-plugin-description">{{plugin.description}}</div>
|
||||
<div class="bd-plugin-footer">
|
||||
<div class="bd-plugin-extra">v{{plugin.version}} by {{plugin.authors.join(', ').replace(/,(?!.*,)/gmi, ' and')}}</div>
|
||||
<div class="bd-controls">
|
||||
<ButtonGroup>
|
||||
<Button v-tooltip="'Settings'" v-if="plugin.hasSettings" :onClick="() => showSettings(plugin)">
|
||||
<MiSettings />
|
||||
</Button>
|
||||
<Button v-tooltip="'Reload'" :onClick="() => reloadPlugin(plugin)">
|
||||
<MiReload />
|
||||
</Button>
|
||||
<Button v-tooltip="'Edit'" :onClick="editPlugin">
|
||||
<MiEdit />
|
||||
</Button>
|
||||
<Button v-tooltip="'Uninstall'" type="err">
|
||||
<MiDelete />
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
// Imports
|
||||
import { shell } from 'electron';
|
||||
import { Button, ButtonGroup, SettingSwitch } from '../common';
|
||||
import MiSettings from 'vue-material-design-icons/settings.vue';
|
||||
import MiReload from 'vue-material-design-icons/refresh.vue';
|
||||
import MiEdit from 'vue-material-design-icons/pencil.vue';
|
||||
import MiDelete from 'vue-material-design-icons/delete.vue';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
settingsOpen: false
|
||||
}
|
||||
},
|
||||
props: ['plugin', 'togglePlugin', 'reloadPlugin', 'showSettings'],
|
||||
components: {
|
||||
Button, ButtonGroup, SettingSwitch,
|
||||
MiSettings, MiReload, MiEdit, MiDelete
|
||||
},
|
||||
methods: {
|
||||
editPlugin() {
|
||||
try {
|
||||
shell.openItem(this.plugin.pluginPath);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* BetterDiscord Plugin Settings Modal Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<Modal :headerText="plugin.name + ' Settings'" :close="() => { }">
|
||||
<div slot="body" v-for="setting in plugin.pluginConfig" class="bd-plugin-settings-body">
|
||||
<div class="bd-form-item">
|
||||
|
||||
<div v-if="setting.type === 'bool'" class="bd-setting-switch">
|
||||
<div class="bd-title">
|
||||
<h3>{{setting.text}}</h3>
|
||||
<label class="bd-switch-wrapper">
|
||||
<input type="checkbox" class="bd-switch-checkbox" />
|
||||
<div class="bd-switch" :class="{'bd-checked': setting.value}" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="bd-hint">{{setting.hint}}</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="setting.type === 'text'" class="bd-form-textinput">
|
||||
<div class="bd-title">
|
||||
<h3>{{setting.text}}</h3>
|
||||
<div class="bd-textinput-wrapper">
|
||||
<input type="text" v-model="setting.value" @keyup.stop @keydown="textInputKd" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="bd-hint">{{setting.hint}}</div>
|
||||
</div>
|
||||
|
||||
<div class="bd-form-divider"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div slot="footer">
|
||||
<div class="footer-alert" :class="{'bd-active': changed}">
|
||||
<div class="footer-alert-text">Unsaved changes</div>
|
||||
<div class="bd-reset-button">Reset</div>
|
||||
<div class="bd-button bd-ok">Save Changes</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
<script>
|
||||
// Imports
|
||||
import { Modal } from '../common';
|
||||
|
||||
export default {
|
||||
props: ['plugin'],
|
||||
data() {
|
||||
return {
|
||||
'changed': false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Modal
|
||||
},
|
||||
methods: {
|
||||
textInputKd(e) {
|
||||
this.changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* BetterDiscord Plugins View Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<SettingsWrapper headertext="Plugins">
|
||||
<div class="bd-flex bd-flex-col bd-pluginsView">
|
||||
<div class="bd-flex bd-tabheader">
|
||||
<div class="bd-flex-grow bd-button" :class="{'bd-active': local}" @click="showLocal">
|
||||
<h3>Local</h3>
|
||||
<div class="bd-material-button" @click="refreshLocal">
|
||||
<refresh />
|
||||
</div>
|
||||
</div>
|
||||
<div class="bd-flex-grow bd-button" :class="{'bd-active': !local}" @click="showOnline">
|
||||
<h3>Online</h3>
|
||||
<div class="bd-material-button">
|
||||
<refresh />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="local" class="bd-flex bd-flex-grow bd-flex-col bd-plugins-container bd-local-plugins">
|
||||
<PluginCard v-for="plugin in localPlugins" :plugin="plugin" :key="plugin.id" :togglePlugin="togglePlugin" :reloadPlugin="reloadPlugin" :showSettings="showSettings" />
|
||||
</div>
|
||||
<div v-if="!local" class="bd-spinner-container">
|
||||
<div class="bd-spinner-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="settingsOpen !== null" class="bd-backdrop" @click="settingsOpen = null"></div>
|
||||
<div v-if="settingsOpen !== null" class="bd-modal">
|
||||
<PluginSettingsModal :plugin="settingsOpen" />
|
||||
</div>
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import { PluginManager } from 'modules';
|
||||
import { SettingsWrapper } from './';
|
||||
import PluginCard from './PluginCard.vue';
|
||||
import PluginSettingsModal from './PluginSettingsModal.vue';
|
||||
import Refresh from 'vue-material-design-icons/refresh.vue';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
local: true,
|
||||
settingsOpen: null,
|
||||
localPlugins: PluginManager.localPlugins
|
||||
}
|
||||
},
|
||||
components: {
|
||||
SettingsWrapper, PluginCard, PluginSettingsModal, Refresh
|
||||
},
|
||||
methods: {
|
||||
showLocal() {
|
||||
this.local = true;
|
||||
},
|
||||
showOnline() {
|
||||
this.local = false;
|
||||
},
|
||||
refreshLocal() {
|
||||
(async () => {
|
||||
await PluginManager.refreshPlugins();
|
||||
})();
|
||||
},
|
||||
togglePlugin(plugin) {
|
||||
// TODO Display error if plugin fails to start/stop
|
||||
try {
|
||||
if (plugin.enabled) {
|
||||
PluginManager.stopPlugin(plugin);
|
||||
} else {
|
||||
PluginManager.startPlugin(plugin);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
reloadPlugin(plugin) {
|
||||
(async () => {
|
||||
try {
|
||||
await PluginManager.reloadPlugin(plugin);
|
||||
this.$forceUpdate();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
})();
|
||||
},
|
||||
showSettings(plugin) {
|
||||
this.settingsOpen = plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* BetterDiscord Settings Wrapper Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-settingsWrap">
|
||||
<div class="bd-settingsWrap-header">{{headertext}}</div>
|
||||
<ScrollerWrap>
|
||||
<slot />
|
||||
</ScrollerWrap>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
// Imports
|
||||
import { ScrollerWrap } from '../common';
|
||||
|
||||
export default {
|
||||
props: ['headertext'],
|
||||
components: {
|
||||
ScrollerWrap
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* BetterDiscord UI Settings Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<SettingsWrapper headertext="UI Settings">
|
||||
</SettingsWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import { SettingsWrapper } from './';
|
||||
import { SettingSwitch } from '../common';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingsWrapper,
|
||||
SettingSwitch
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -2,7 +2,5 @@ export { default as SettingsWrapper } from './SettingsWrapper.vue';
|
|||
export { default as CoreSettings } from './CoreSettings.vue';
|
||||
export { default as UISettings } from './UISettings.vue';
|
||||
export { default as EmoteSettings } from './EmoteSettings.vue';
|
||||
export { default as PluginsView } from './PluginsView.vue';
|
||||
export { default as PluginCard } from './PluginCard.vue';
|
||||
export { default as CssEditorView } from './CssEditor.vue';
|
||||
export { default as PluginSettingsModal } from './PluginSettingsModal.vue';
|
||||
export { default as PluginsView } from './PluginsView.vue';
|
|
@ -1,3 +1,13 @@
|
|||
/**
|
||||
* BetterDiscord Button Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-button" :class="[{'bd-disabled': disabled}, {'bd-err': type === 'err'}]" @click="!disabled && !loading ? onClick() : null">
|
||||
<div v-if="loading" class="bd-spinner-7"></div>
|
||||
|
@ -8,4 +18,4 @@
|
|||
export default {
|
||||
props: ['loading', 'disabled', 'type', 'onClick', 'type']
|
||||
}
|
||||
</script>
|
||||
</script>
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* BetterDiscord Button Group Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-button-group">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* BetterDiscord Form Button Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-form-button bd-button" :class="{'bd-disabled': disabled}" @click="!disabled && !loading ? onClick() : null">
|
||||
<div v-if="loading" class="bd-spinner-7"></div>
|
||||
<slot v-else />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['loading', 'disabled', 'type', 'onClick']
|
||||
}
|
||||
</script>
|
|
@ -1,10 +1,20 @@
|
|||
/**
|
||||
* BetterDiscord ¨Modal Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-modal">
|
||||
<div class="bd-modal-inner">
|
||||
<div class="bd-modal-header">
|
||||
<span>{{headerText}}</span>
|
||||
<div class="bd-modal-x" @click="close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 12 12"><g fill="none" fill-rule="evenodd"><path d="M0 0h12v12H0"></path><path class="fill" fill="#dcddde" d="M9.5 3.205L8.795 2.5 6 5.295 3.205 2.5l-.705.705L5.295 6 2.5 8.795l.705.705L6 6.705 8.795 9.5l.705-.705L6.705 6"></path></g></svg>
|
||||
<SvgX size="18"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bd-modal-body">
|
||||
|
@ -18,7 +28,13 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
// Imports
|
||||
import SvgX from './SvgX.vue';
|
||||
|
||||
export default {
|
||||
props: ['headerText', 'close']
|
||||
props: ['headerText', 'close'],
|
||||
components: {
|
||||
SvgX
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</script>
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* BetterDiscord Scroller Wrap Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-scroller-wrap" :class="{'bd-dark': dark}">
|
||||
<div class="bd-scroller">
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['dark']
|
||||
}
|
||||
</script>
|
|
@ -1,3 +1,13 @@
|
|||
/**
|
||||
* BetterDiscord Setting Switch Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-setting-switch" :class="{'bd-disabled': disabled}">
|
||||
<div class="bd-title">
|
||||
|
@ -14,4 +24,4 @@
|
|||
export default {
|
||||
props: ['setting', 'onClick', 'disabled']
|
||||
}
|
||||
</script>
|
||||
</script>
|
|
@ -0,0 +1,13 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" :width="size" :height="size" viewBox="0 0 12 12">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path d="M0 0h12v12H0"></path>
|
||||
<path class="fill" fill="#dcddde" d="M9.5 3.205L8.795 2.5 6 5.295 3.205 2.5l-.705.705L5.295 6 2.5 8.795l.705.705L6 6.705 8.795 9.5l.705-.705L6.705 6"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['size']
|
||||
}
|
||||
</script>
|
|
@ -3,4 +3,5 @@ export { default as SettingSwitch } from './SettingSwitch.vue';
|
|||
export { default as FormButton } from './FormButton.vue';
|
||||
export { default as ButtonGroup } from './ButtonGroup.vue';
|
||||
export { default as Button } from './Button.vue';
|
||||
export { default as Modal } from './Modal.vue';
|
||||
export { default as Modal } from './Modal.vue';
|
||||
export { default as SvgX } from './SvgX.vue';
|
|
@ -0,0 +1,2 @@
|
|||
export { default as BdSettingsWrapper } from './BdSettingsWrapper.vue';
|
||||
export { default as BdSettings } from './BdSettings.vue';
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* BetterDiscord Sidebar Button Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-item" :class="{active: item.active}" @click="onClick(item.id)">
|
||||
{{item.text}}
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['item', 'onClick']
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* BetterDiscord Sidebar Content Column Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-content bd-content-column">
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* BetterDiscord Sidebar Header Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class='bd-header'>
|
||||
{{item.text}}
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: ['item']
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* BetterDiscord Sidebar Item Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<SidebarButton v-if="item._type === 'button'" :item="item" :onClick="onClick"/>
|
||||
<SidebarHeader v-else :item="item" />
|
||||
</template>
|
||||
<script>
|
||||
// Imports
|
||||
import { SidebarHeader, SidebarButton } from './';
|
||||
|
||||
export default {
|
||||
props: ['item', 'onClick'],
|
||||
components: {
|
||||
SidebarHeader,
|
||||
SidebarButton
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* BetterDiscord Sidebar Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-sidebar bd-scroller">
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* BetterDiscord Sidebar View Component
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-sidebar-view" :class="{active: contentVisible, animating: animating}">
|
||||
<div class="bd-sidebar-region">
|
||||
<div class="bd-settingsWrap">
|
||||
<ScrollerWrap dark="true">
|
||||
<slot name="sidebar" />
|
||||
</ScrollerWrap>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bd-content-region">
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
// Imports
|
||||
import { ScrollerWrap } from '../common';
|
||||
|
||||
export default {
|
||||
props: ['contentVisible', 'animating'],
|
||||
components: {
|
||||
ScrollerWrap
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* BetterDiscord Client DOM Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
class BdNode {
|
||||
constructor(tag, className, id) {
|
||||
this.element = document.createElement(tag);
|
||||
if (className) this.element.className = className;
|
||||
if (id) this.element.id = id;
|
||||
}
|
||||
|
||||
appendTo(e) {
|
||||
const el = DOM.getElement(e);
|
||||
if (!el) return null;
|
||||
el.append(this.element);
|
||||
return this.element;
|
||||
}
|
||||
|
||||
prependTo(e) {
|
||||
const el = DOM.getElement(e);
|
||||
if (!el) return null;
|
||||
el.prepend(this.element);
|
||||
return this.element;
|
||||
}
|
||||
}
|
||||
|
||||
class DOM {
|
||||
|
||||
static get bdHead() {
|
||||
return this.getElement('bd-head') || this.createElement('bd-head').appendTo('head');
|
||||
}
|
||||
static get bdBody() {
|
||||
return this.getElement('bd-body') || this.createElement('bd-body').appendTo('body');
|
||||
}
|
||||
static get bdStyles() {
|
||||
return this.getElement('bd-styles') || this.createElement('bd-styles').appendTo(this.bdHead);
|
||||
}
|
||||
static get bdThemes() {
|
||||
return this.getElement('bd-themes') || this.createElement('bd-themes').appendTo(this.bdHead);
|
||||
}
|
||||
static get bdTooltips() {
|
||||
return this.getElement('bd-tooltips') || this.createElement('bd-tooltips').appendTo(this.bdBody);
|
||||
}
|
||||
|
||||
static getElement(e) {
|
||||
if (e instanceof BdNode) return e.element;
|
||||
if (e instanceof window.Node) return e;
|
||||
if ('string' !== typeof e) return null;
|
||||
return document.querySelector(e);
|
||||
}
|
||||
|
||||
static createElement(tag = 'div', className = null, id = null) {
|
||||
return new BdNode(tag, className, id);
|
||||
}
|
||||
|
||||
static deleteStyle(id) {
|
||||
const exists = this.getElement(`bd-styles > #${id}`);
|
||||
if (exists) exists.remove();
|
||||
}
|
||||
|
||||
static injectStyle(css, id) {
|
||||
this.deleteStyle(id);
|
||||
this.bdStyles.append(this.createStyle(css, id));
|
||||
}
|
||||
|
||||
static getStyleCss(id) {
|
||||
const exists = this.getElement(`bd-styles > #${id}`);
|
||||
return exists ? exists.textContent : '';
|
||||
}
|
||||
|
||||
static deleteTheme(id) {
|
||||
const exists = this.getElement(`bd-themes > #${id}`);
|
||||
if (exists) exists.remove();
|
||||
}
|
||||
|
||||
static injectTheme(css, id) {
|
||||
this.deleteTheme(id);
|
||||
this.bdThemes.append(this.createStyle(css, id));
|
||||
}
|
||||
|
||||
static createStyle(css, id) {
|
||||
const style = document.createElement('style');
|
||||
style.id = id;
|
||||
style.type = 'text/css';
|
||||
style.appendChild(document.createTextNode(css));
|
||||
return style;
|
||||
}
|
||||
}
|
||||
|
||||
export default DOM;
|
|
@ -0,0 +1,2 @@
|
|||
export { default as DOM } from './dom';
|
||||
export { default as BdUI } from './bdui';
|
|
@ -32,12 +32,20 @@ module.exports = {
|
|||
loaders: [jsLoader, vueLoader, scssLoader]
|
||||
},
|
||||
externals: {
|
||||
'electron': 'window.require("electron")'
|
||||
'electron': 'window.require("electron")',
|
||||
'fs': 'window.require("fs")',
|
||||
'path': 'window.require("path")'
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js')
|
||||
}
|
||||
},
|
||||
modules: [
|
||||
path.resolve('..', 'node_modules'),
|
||||
path.resolve('..', 'common', 'modules'),
|
||||
path.resolve('src', 'modules'),
|
||||
path.resolve('src', 'ui')
|
||||
]
|
||||
}
|
||||
/* resolve: {
|
||||
alias: {
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* BetterDiscord IPC Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const { ipcRenderer, ipcMain } = require('electron');
|
||||
|
||||
export class ClientIPC {
|
||||
static on(channel, cb) {
|
||||
ipcRenderer.on(channel, (event, message) => cb(event, message));
|
||||
}
|
||||
|
||||
static async send(channel, message) {
|
||||
channel = channel.startsWith('bd-') ? channel : `bd-${channel}`;
|
||||
const __eid = Date.now().toString();
|
||||
ipcRenderer.send(channel, Object.assign(message ? message : {}, { __eid }));
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcRenderer.once(__eid, (event, arg) => resolve(arg));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class BDIpcEvent {
|
||||
|
||||
constructor(event, args) {
|
||||
this.args = args;
|
||||
this.ipcEvent = event;
|
||||
}
|
||||
|
||||
bindings() {
|
||||
this.send = this.send.bind(this);
|
||||
this.reply = this.reply.bind(this);
|
||||
}
|
||||
|
||||
send(message) {
|
||||
this.ipcEvent.sender.send(this.args.__eid, message);
|
||||
}
|
||||
|
||||
reply(message) {
|
||||
this.send(message);
|
||||
}
|
||||
}
|
||||
|
||||
export class CoreIPC {
|
||||
static on(channel, cb) {
|
||||
ipcMain.on(channel, (event, args) => cb(new BDIpcEvent(event, args)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export { ClientIPC } from './bdipc';
|
||||
export * from './utils';
|
|
@ -1,69 +1,23 @@
|
|||
/**
|
||||
* BetterDiscord Client Utils Module
|
||||
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||
* BetterDiscord Utils Module
|
||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||
* All rights reserved.
|
||||
* https://github.com/JsSucks - https://betterdiscord.net
|
||||
* https://betterdiscord.net
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const { Module } = require('./modulebase');
|
||||
const { Vendor } = require('./vendor');
|
||||
const fs = window.require('fs');
|
||||
const path = window.require('path');
|
||||
const
|
||||
path = require('path'),
|
||||
fs = require('fs');
|
||||
|
||||
const logs = [];
|
||||
|
||||
class Logger {
|
||||
|
||||
static err(module, message) { this.log(module, message, 'err'); }
|
||||
static warn(module, message) { this.log(module, message, 'warn'); }
|
||||
static info(module, message) { this.log(module, message, 'info'); }
|
||||
static dbg(module, message) { this.log(module, message, 'dbg'); }
|
||||
static log(module, message, level = 'log') {
|
||||
message = message.message || message;
|
||||
if (typeof message === 'object') {
|
||||
//TODO object handler for logs
|
||||
console.log(message);
|
||||
return;
|
||||
}
|
||||
level = this.parseLevel(level);
|
||||
console[level]('[%cBetter%cDiscord:%s] %s', 'color: #3E82E5', '', `${module}${level === 'debug' ? '|DBG' : ''}`, message);
|
||||
logs.push(`[${Vendor.moment().format('DD/MM/YY hh:mm:ss')}|${module}|${level}] ${message}`);
|
||||
window.bdlogs = logs;
|
||||
}
|
||||
|
||||
static logError(err) {
|
||||
if (!err.module && !err.message) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
this.err(err.module, err.message);
|
||||
}
|
||||
|
||||
static get levels() {
|
||||
return {
|
||||
'log': 'log',
|
||||
'warn': 'warn',
|
||||
'err': 'error',
|
||||
'error': 'error',
|
||||
'debug': 'debug',
|
||||
'dbg': 'debug',
|
||||
'info': 'info'
|
||||
};
|
||||
}
|
||||
|
||||
static parseLevel(level) {
|
||||
return this.levels.hasOwnProperty(level) ? this.levels[level] : 'log';
|
||||
}
|
||||
}
|
||||
|
||||
class Utils {
|
||||
import { Vendor } from 'modules';
|
||||
|
||||
export class Utils {
|
||||
static overload(fn, cb) {
|
||||
const orig = fn;
|
||||
return function(...args) {
|
||||
return function (...args) {
|
||||
orig(...args);
|
||||
cb(...args);
|
||||
}
|
||||
|
@ -79,11 +33,9 @@ class Utils {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FileUtils {
|
||||
|
||||
export class FileUtils {
|
||||
static async fileExists(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.stat(path, (err, stats) => {
|
||||
|
@ -120,6 +72,32 @@ class FileUtils {
|
|||
});
|
||||
}
|
||||
|
||||
static async createDirectory(path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.mkdir(path, err => {
|
||||
if (err) {
|
||||
if (err.code === 'EEXIST') return resolve();
|
||||
else return reject(err);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static async ensureDirectory(path) {
|
||||
try {
|
||||
await this.directoryExists(path);
|
||||
return true;
|
||||
} catch (err) {
|
||||
try {
|
||||
await this.createDirectory(path);
|
||||
return true;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static async readFile(path) {
|
||||
try {
|
||||
await this.fileExists(path);
|
||||
|
@ -168,7 +146,7 @@ class FileUtils {
|
|||
return this.writeFile(path, JSON.stringify(json));
|
||||
}
|
||||
|
||||
static async readDir(path) {
|
||||
static async listDirectory(path) {
|
||||
try {
|
||||
await this.directoryExists(path);
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -181,45 +159,53 @@ class FileUtils {
|
|||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Filters {
|
||||
static byProperties(props, selector = m => m) {
|
||||
return module => {
|
||||
const component = selector(module);
|
||||
if (!component) return false;
|
||||
return props.every(property => component[property] !== undefined);
|
||||
};
|
||||
}
|
||||
|
||||
static byPrototypeFields(fields, selector = m => m) {
|
||||
return module => {
|
||||
const component = selector(module);
|
||||
if (!component) return false;
|
||||
if (!component.prototype) return false;
|
||||
return fields.every(field => component.prototype[field] !== undefined);
|
||||
};
|
||||
}
|
||||
|
||||
static byCode(search, selector = m => m) {
|
||||
return module => {
|
||||
const method = selector(module);
|
||||
if (!method) return false;
|
||||
return method.toString().search(search) !== -1;
|
||||
};
|
||||
}
|
||||
|
||||
static byDisplayName(name) {
|
||||
return module => {
|
||||
return module && module.displayName === name;
|
||||
};
|
||||
}
|
||||
|
||||
static combine(...filters) {
|
||||
return module => {
|
||||
return filters.every(filter => filter(module));
|
||||
};
|
||||
static async readDir(path) {
|
||||
return this.listDirectory(path);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Logger, Utils, FileUtils, Filters };
|
||||
const logs = [];
|
||||
|
||||
export class ClientLogger {
|
||||
static err(module, message) { this.log(module, message, 'err'); }
|
||||
static warn(module, message) { this.log(module, message, 'warn'); }
|
||||
static info(module, message) { this.log(module, message, 'info'); }
|
||||
static dbg(module, message) { this.log(module, message, 'dbg'); }
|
||||
static log(module, message, level = 'log') {
|
||||
message = message.message || message;
|
||||
if (typeof message === 'object') {
|
||||
//TODO object handler for logs
|
||||
console.log(message);
|
||||
return;
|
||||
}
|
||||
level = this.parseLevel(level);
|
||||
console[level]('[%cBetter%cDiscord:%s] %s', 'color: #3E82E5', '', `${module}${level === 'debug' ? '|DBG' : ''}`, message);
|
||||
logs.push(`${level.toUpperCase()} : [${Vendor.moment().format('DD/MM/YY hh:mm:ss')}|${module}] ${message}`);
|
||||
window.bdlogs = logs;
|
||||
}
|
||||
|
||||
static logError(err) {
|
||||
if (!err.module && !err.message) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
this.err(err.module, err.message);
|
||||
}
|
||||
|
||||
static get levels() {
|
||||
return {
|
||||
'log': 'log',
|
||||
'warn': 'warn',
|
||||
'err': 'error',
|
||||
'error': 'error',
|
||||
'debug': 'debug',
|
||||
'dbg': 'debug',
|
||||
'info': 'info'
|
||||
};
|
||||
}
|
||||
|
||||
static parseLevel(level) {
|
||||
return this.levels.hasOwnProperty(level) ? this.levels[level] : 'log';
|
||||
}
|
||||
}
|
|
@ -11,7 +11,12 @@ module.exports = (Plugin, Api, Vendor) => {
|
|||
}
|
||||
|
||||
onStart() {
|
||||
console.log('On Start!');
|
||||
console.log('Example Plugin 1 onStart');
|
||||
return true;
|
||||
}
|
||||
|
||||
onStop() {
|
||||
console.log('Example Plugin 1 onStop');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue