Merge branch 'master' into dom-attributes
This commit is contained in:
commit
ef19f4723e
|
@ -30,6 +30,12 @@
|
||||||
"hint": "Disconnect from voice server when Discord closes",
|
"hint": "Disconnect from voice server when Discord closes",
|
||||||
"value": false,
|
"value": false,
|
||||||
"disabled": true
|
"disabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "menu-keybind",
|
||||||
|
"type": "keybind",
|
||||||
|
"text": "Menu keybind",
|
||||||
|
"value": "mod+b"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -45,6 +51,13 @@
|
||||||
"hint": "BetterDiscord developer mode",
|
"hint": "BetterDiscord developer mode",
|
||||||
"value": false,
|
"value": false,
|
||||||
"disabled": true
|
"disabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ignore-content-manager-errors",
|
||||||
|
"type": "bool",
|
||||||
|
"text": "Ignore content manager errors",
|
||||||
|
"hint": "Only when starting Discord. It gets annoying when you're reloading Discord often and have plugins that are meant to fail.",
|
||||||
|
"value": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import BdCss from './styles/index.scss';
|
||||||
import { Events, CssEditor, Globals, ExtModuleManager, PluginManager, ThemeManager, ModuleManager, WebpackModules, Settings, Database } from 'modules';
|
import { Events, CssEditor, Globals, ExtModuleManager, PluginManager, ThemeManager, ModuleManager, WebpackModules, Settings, Database } from 'modules';
|
||||||
import { ClientLogger as Logger, ClientIPC } from 'common';
|
import { ClientLogger as Logger, ClientIPC } from 'common';
|
||||||
import { EmoteModule } from 'builtin';
|
import { EmoteModule } from 'builtin';
|
||||||
const ignoreExternal = true;
|
const ignoreExternal = false;
|
||||||
|
|
||||||
class BetterDiscord {
|
class BetterDiscord {
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ class BetterDiscord {
|
||||||
window.emotes = EmoteModule;
|
window.emotes = EmoteModule;
|
||||||
window.dom = DOM;
|
window.dom = DOM;
|
||||||
EmoteModule.observe();
|
EmoteModule.observe();
|
||||||
|
|
||||||
DOM.injectStyle(BdCss, 'bdmain');
|
DOM.injectStyle(BdCss, 'bdmain');
|
||||||
Events.on('global-ready', this.globalReady.bind(this));
|
Events.on('global-ready', this.globalReady.bind(this));
|
||||||
}
|
}
|
||||||
|
@ -41,25 +42,25 @@ class BetterDiscord {
|
||||||
await Database.init();
|
await Database.init();
|
||||||
await Settings.loadSettings();
|
await Settings.loadSettings();
|
||||||
await ModuleManager.initModules();
|
await ModuleManager.initModules();
|
||||||
|
Modals.showContentManagerErrors();
|
||||||
if (!ignoreExternal) {
|
if (!ignoreExternal) {
|
||||||
await ExtModuleManager.loadAllModules(true);
|
await ExtModuleManager.loadAllModules(true);
|
||||||
await PluginManager.loadAllPlugins(true);
|
await PluginManager.loadAllPlugins(true);
|
||||||
await ThemeManager.loadAllThemes(true);
|
await ThemeManager.loadAllThemes(true);
|
||||||
}
|
}
|
||||||
Modals.showContentManagerErrors();
|
if (!Settings.get('core', 'advanced', 'ignore-content-manager-errors'))
|
||||||
|
Modals.showContentManagerErrors();
|
||||||
Events.emit('ready');
|
Events.emit('ready');
|
||||||
Events.emit('discord-ready');
|
Events.emit('discord-ready');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('FAILED TO LOAD!', err);
|
Logger.err('main', ['FAILED TO LOAD!', err]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
globalReady() {
|
globalReady() {
|
||||||
BdUI.initUiEvents();
|
BdUI.initUiEvents();
|
||||||
this.vueInstance = BdUI.injectUi();
|
this.vueInstance = BdUI.injectUi();
|
||||||
(async () => {
|
this.init();
|
||||||
this.init();
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,9 @@ import Database from './database';
|
||||||
export default class Content {
|
export default class Content {
|
||||||
|
|
||||||
constructor(internals) {
|
constructor(internals) {
|
||||||
|
Utils.deepfreeze(internals.info);
|
||||||
|
Object.freeze(internals.paths);
|
||||||
|
|
||||||
this.__internals = internals;
|
this.__internals = internals;
|
||||||
|
|
||||||
this.settings.on('setting-updated', event => this.events.emit('setting-updated', event));
|
this.settings.on('setting-updated', event => this.events.emit('setting-updated', event));
|
||||||
|
@ -170,3 +173,5 @@ export default class Content {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object.freeze(Content.prototype);
|
||||||
|
|
|
@ -10,15 +10,16 @@
|
||||||
|
|
||||||
import Content from './content';
|
import Content from './content';
|
||||||
import Globals from './globals';
|
import Globals from './globals';
|
||||||
|
import Database from './database';
|
||||||
import { Utils, FileUtils, ClientLogger as Logger } from 'common';
|
import { Utils, FileUtils, ClientLogger as Logger } from 'common';
|
||||||
import path from 'path';
|
|
||||||
import { Events } from 'modules';
|
import { Events } from 'modules';
|
||||||
import { SettingsSet, ErrorEvent } from 'structs';
|
import { SettingsSet, ErrorEvent } from 'structs';
|
||||||
import { Modals } from 'ui';
|
import { Modals } from 'ui';
|
||||||
import Database from './database';
|
import path from 'path';
|
||||||
|
import Combokeys from 'combokeys';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for external content managing
|
* Base class for managing external content
|
||||||
*/
|
*/
|
||||||
export default class {
|
export default class {
|
||||||
|
|
||||||
|
@ -209,10 +210,12 @@ export default class {
|
||||||
userConfig.config.setSaved();
|
userConfig.config.setSaved();
|
||||||
|
|
||||||
for (let setting of userConfig.config.findSettings(() => true)) {
|
for (let setting of userConfig.config.findSettings(() => true)) {
|
||||||
|
// This will load custom settings
|
||||||
|
// Setting the content's path on only the live config (and not the default config) ensures that custom settings will not be loaded on the default settings
|
||||||
setting.setContentPath(contentPath);
|
setting.setContentPath(contentPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils.deepfreeze(defaultConfig);
|
Utils.deepfreeze(defaultConfig, object => object instanceof Combokeys);
|
||||||
|
|
||||||
const configs = {
|
const configs = {
|
||||||
defaultConfig,
|
defaultConfig,
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Events Wrapper 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 eventemitters = new WeakMap();
|
||||||
|
|
||||||
|
export default class EventsWrapper {
|
||||||
|
constructor(eventemitter) {
|
||||||
|
eventemitters.set(this, eventemitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
get eventSubs() {
|
||||||
|
return this._eventSubs || (this._eventSubs = []);
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe(event, callback) {
|
||||||
|
if (this.eventSubs.find(e => e.event === event && e.callback === callback)) return;
|
||||||
|
this.eventSubs.push({
|
||||||
|
event,
|
||||||
|
callback
|
||||||
|
});
|
||||||
|
eventemitters.get(this).on(event, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribe(event, callback) {
|
||||||
|
for (let index of this.eventSubs) {
|
||||||
|
if (this.eventSubs[index].event !== event || (callback && this.eventSubs[index].callback === callback)) return;
|
||||||
|
eventemitters.get(this).off(event, this.eventSubs[index].callback);
|
||||||
|
this.eventSubs.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribeAll() {
|
||||||
|
for (let event of this.eventSubs) {
|
||||||
|
eventemitters.get(this).off(event.event, event.callback);
|
||||||
|
}
|
||||||
|
this.eventSubs.splice(0, this.eventSubs.length);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,3 +13,4 @@ export { default as SocketProxy } from './socketproxy';
|
||||||
export { default as EventHook } from './eventhook';
|
export { default as EventHook } from './eventhook';
|
||||||
export { default as Permissions } from './permissionmanager';
|
export { default as Permissions } from './permissionmanager';
|
||||||
export { default as Database } from './database';
|
export { default as Database } from './database';
|
||||||
|
export { default as EventsWrapper } from './eventswrapper';
|
||||||
|
|
|
@ -11,27 +11,27 @@
|
||||||
const PermissionMap = {
|
const PermissionMap = {
|
||||||
IDENTIFY: {
|
IDENTIFY: {
|
||||||
HEADER: 'Access your account information',
|
HEADER: 'Access your account information',
|
||||||
BODY: 'Allows :NAME: to read your account information(excluding user token)'
|
BODY: 'Allows :NAME: to read your account information (excluding user token).'
|
||||||
},
|
},
|
||||||
READ_MESSAGES: {
|
READ_MESSAGES: {
|
||||||
HEADER: 'Read all messages',
|
HEADER: 'Read all messages',
|
||||||
BODY: 'Allows :NAME: to read all messages accessible through your Discord account'
|
BODY: 'Allows :NAME: to read all messages accessible through your Discord account.'
|
||||||
},
|
},
|
||||||
SEND_MESSAGES: {
|
SEND_MESSAGES: {
|
||||||
HEADER: 'Send messages',
|
HEADER: 'Send messages',
|
||||||
BODY: 'Allows :NAME: to send messages on your behalf'
|
BODY: 'Allows :NAME: to send messages on your behalf.'
|
||||||
},
|
},
|
||||||
DELETE_MESSAGES: {
|
DELETE_MESSAGES: {
|
||||||
HEADER: 'Delete messages',
|
HEADER: 'Delete messages',
|
||||||
BODY: 'Allows :NAME: to delete messages on your behalf'
|
BODY: 'Allows :NAME: to delete messages on your behalf.'
|
||||||
},
|
},
|
||||||
EDIT_MESSAGES: {
|
EDIT_MESSAGES: {
|
||||||
HEADER: 'Edit messages',
|
HEADER: 'Edit messages',
|
||||||
BODY: 'Allows :NAME: to edit messages on your behalf'
|
BODY: 'Allows :NAME: to edit messages on your behalf.'
|
||||||
},
|
},
|
||||||
JOIN_SERVERS: {
|
JOIN_SERVERS: {
|
||||||
HEADER: 'Join servers for you',
|
HEADER: 'Join servers for you',
|
||||||
BODY: 'Allows :NAME: to join servers on your behalf'
|
BODY: 'Allows :NAME: to join servers on your behalf.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,50 +14,20 @@ import ExtModuleManager from './extmodulemanager';
|
||||||
import PluginManager from './pluginmanager';
|
import PluginManager from './pluginmanager';
|
||||||
import ThemeManager from './thememanager';
|
import ThemeManager from './thememanager';
|
||||||
import Events from './events';
|
import Events from './events';
|
||||||
|
import EventsWrapper from './eventswrapper';
|
||||||
import WebpackModules from './webpackmodules';
|
import WebpackModules from './webpackmodules';
|
||||||
import { SettingsSet, SettingsCategory, Setting, SettingsScheme } from 'structs';
|
import { SettingsSet, SettingsCategory, Setting, SettingsScheme } from 'structs';
|
||||||
import { Modals, DOM } from 'ui';
|
import { BdMenuItems, Modals, DOM } from 'ui';
|
||||||
import SettingsModal from '../ui/components/bd/modals/SettingsModal.vue';
|
import SettingsModal from '../ui/components/bd/modals/SettingsModal.vue';
|
||||||
|
|
||||||
class EventsWrapper {
|
|
||||||
constructor(eventemitter) {
|
|
||||||
this.__eventemitter = eventemitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
get eventSubs() {
|
|
||||||
return this._eventSubs || (this._eventSubs = []);
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe(event, callback) {
|
|
||||||
if (this.eventSubs.find(e => e.event === event && e.callback === callback)) return;
|
|
||||||
this.eventSubs.push({
|
|
||||||
event,
|
|
||||||
callback
|
|
||||||
});
|
|
||||||
this.__eventemitter.on(event, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsubscribe(event, callback) {
|
|
||||||
for (let index of this.eventSubs) {
|
|
||||||
if (this.eventSubs[index].event !== event || (callback && this.eventSubs[index].callback === callback)) return;
|
|
||||||
this.__eventemitter.off(event, this.eventSubs[index].callback);
|
|
||||||
this.eventSubs.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsubscribeAll() {
|
|
||||||
for (let event of this.eventSubs) {
|
|
||||||
this.__eventemitter.off(event.event, event.callback);
|
|
||||||
}
|
|
||||||
this._eventSubs = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class PluginApi {
|
export default class PluginApi {
|
||||||
|
|
||||||
constructor(pluginInfo) {
|
constructor(pluginInfo) {
|
||||||
this.pluginInfo = pluginInfo;
|
this.pluginInfo = pluginInfo;
|
||||||
this.Events = new EventsWrapper(Events);
|
this.Events = new EventsWrapper(Events);
|
||||||
|
this._menuItems = undefined;
|
||||||
|
this._injectedStyles = undefined;
|
||||||
|
this._modalStack = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
get plugin() {
|
get plugin() {
|
||||||
|
@ -153,6 +123,54 @@ export default class PluginApi {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BdMenu
|
||||||
|
*/
|
||||||
|
|
||||||
|
get BdMenu() {
|
||||||
|
return {
|
||||||
|
BdMenuItems: this.BdMenuItems
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BdMenuItems
|
||||||
|
*/
|
||||||
|
|
||||||
|
get menuItems() {
|
||||||
|
return this._menuItems || (this._menuItems = []);
|
||||||
|
}
|
||||||
|
addMenuItem(item) {
|
||||||
|
return BdMenuItems.add(item);
|
||||||
|
}
|
||||||
|
addMenuSettingsSet(category, set, text) {
|
||||||
|
const item = BdMenuItems.addSettingsSet(category, set, text);
|
||||||
|
return this.menuItems.push(item);
|
||||||
|
}
|
||||||
|
addMenuVueComponent(category, text, component) {
|
||||||
|
const item = BdMenuItems.addVueComponent(category, text, component);
|
||||||
|
return this.menuItems.push(item);
|
||||||
|
}
|
||||||
|
removeMenuItem(item) {
|
||||||
|
BdMenuItems.remove(item);
|
||||||
|
Utils.removeFromArray(this.menuItems, item);
|
||||||
|
}
|
||||||
|
removeAllMenuItems() {
|
||||||
|
for (let item of this.menuItems)
|
||||||
|
BdMenuItems.remove(item);
|
||||||
|
}
|
||||||
|
get BdMenuItems() {
|
||||||
|
return Object.defineProperty({
|
||||||
|
add: this.addMenuItem.bind(this),
|
||||||
|
addSettingsSet: this.addMenuSettingsSet.bind(this),
|
||||||
|
addVueComponent: this.addMenuVueComponent.bind(this),
|
||||||
|
remove: this.removeMenuItem.bind(this),
|
||||||
|
removeAll: this.removeAllMenuItems.bind(this)
|
||||||
|
}, 'items', {
|
||||||
|
get: () => this.menuItems
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CssUtils
|
* CssUtils
|
||||||
*/
|
*/
|
||||||
|
@ -172,8 +190,8 @@ export default class PluginApi {
|
||||||
injectStyle(id, css) {
|
injectStyle(id, css) {
|
||||||
if (id && !css) css = id, id = undefined;
|
if (id && !css) css = id, id = undefined;
|
||||||
this.deleteStyle(id);
|
this.deleteStyle(id);
|
||||||
const styleid = `plugin-${this.getPlugin().id}-${id}`;
|
const styleid = `plugin-${this.plugin.id}-${id}`;
|
||||||
this.injectedStyles.push(styleid);
|
this.injectedStyles.push(id);
|
||||||
DOM.injectStyle(css, styleid);
|
DOM.injectStyle(css, styleid);
|
||||||
}
|
}
|
||||||
async injectSass(id, scss, options) {
|
async injectSass(id, scss, options) {
|
||||||
|
@ -183,7 +201,7 @@ export default class PluginApi {
|
||||||
this.injectStyle(id, css, options);
|
this.injectStyle(id, css, options);
|
||||||
}
|
}
|
||||||
deleteStyle(id) {
|
deleteStyle(id) {
|
||||||
const styleid = `plugin-${this.getPlugin().id}-${id}`;
|
const styleid = `plugin-${this.plugin.id}-${id}`;
|
||||||
this.injectedStyles.splice(this.injectedStyles.indexOf(styleid), 1);
|
this.injectedStyles.splice(this.injectedStyles.indexOf(styleid), 1);
|
||||||
DOM.deleteStyle(styleid);
|
DOM.deleteStyle(styleid);
|
||||||
}
|
}
|
||||||
|
@ -216,7 +234,6 @@ export default class PluginApi {
|
||||||
}
|
}
|
||||||
addModal(_modal, component) {
|
addModal(_modal, component) {
|
||||||
const modal = Modals.add(_modal, component);
|
const modal = Modals.add(_modal, component);
|
||||||
modal.close = force => this.closeModal(modal, force);
|
|
||||||
modal.on('close', () => {
|
modal.on('close', () => {
|
||||||
let index;
|
let index;
|
||||||
while ((index = this.modalStack.findIndex(m => m === modal)) > -1)
|
while ((index = this.modalStack.findIndex(m => m === modal)) > -1)
|
||||||
|
@ -245,16 +262,20 @@ export default class PluginApi {
|
||||||
return this.addModal(Modals.settings(settingsset, headertext, options));
|
return this.addModal(Modals.settings(settingsset, headertext, options));
|
||||||
}
|
}
|
||||||
get Modals() {
|
get Modals() {
|
||||||
return Object.defineProperty(Object.defineProperty({
|
return Object.defineProperties({
|
||||||
add: this.addModal.bind(this),
|
add: this.addModal.bind(this),
|
||||||
close: this.closeModal.bind(this),
|
close: this.closeModal.bind(this),
|
||||||
closeAll: this.closeAllModals.bind(this),
|
closeAll: this.closeAllModals.bind(this),
|
||||||
closeLast: this.closeLastModal.bind(this),
|
closeLast: this.closeLastModal.bind(this),
|
||||||
|
basic: this.basicModal.bind(this),
|
||||||
settings: this.settingsModal.bind(this)
|
settings: this.settingsModal.bind(this)
|
||||||
}, 'stack', {
|
}, {
|
||||||
get: () => this.modalStack
|
stack: {
|
||||||
}), 'baseComponent', {
|
get: () => this.modalStack
|
||||||
get: () => this.baseModalComponent
|
},
|
||||||
|
baseComponent: {
|
||||||
|
get: () => this.baseModalComponent
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,3 +369,8 @@ export default class PluginApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop plugins from modifying the plugin API for all plugins
|
||||||
|
// Plugins can still modify their own plugin API object
|
||||||
|
Object.freeze(PluginApi);
|
||||||
|
Object.freeze(PluginApi.prototype);
|
||||||
|
|
|
@ -99,6 +99,9 @@ export default class extends ContentManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugin = window.require(paths.mainPath)(Plugin, new PluginApi(info), Vendor, deps);
|
const plugin = window.require(paths.mainPath)(Plugin, new PluginApi(info), Vendor, deps);
|
||||||
|
if (!(plugin.prototype instanceof Plugin))
|
||||||
|
throw {message: `Plugin ${info.name} did not return a class that extends Plugin.`};
|
||||||
|
|
||||||
const instance = new plugin({
|
const instance = new plugin({
|
||||||
configs, info, main,
|
configs, info, main,
|
||||||
paths: {
|
paths: {
|
||||||
|
|
|
@ -18,7 +18,23 @@ import path from 'path';
|
||||||
|
|
||||||
export default new class Settings {
|
export default new class Settings {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.settings = [];
|
this.settings = defaultSettings.map(_set => {
|
||||||
|
const set = new SettingsSet(_set);
|
||||||
|
|
||||||
|
set.on('setting-updated', event => {
|
||||||
|
const { category, setting, value, old_value } = event;
|
||||||
|
Logger.log('Settings', `${set.id}/${category.id}/${setting.id} was changed from ${old_value} to ${value}`);
|
||||||
|
Events.emit('setting-updated', event);
|
||||||
|
Events.emit(`setting-updated-${set.id}_${category.id}_${setting.id}`, event);
|
||||||
|
});
|
||||||
|
|
||||||
|
set.on('settings-updated', async (event) => {
|
||||||
|
await this.saveSettings();
|
||||||
|
Events.emit('settings-updated', event);
|
||||||
|
});
|
||||||
|
|
||||||
|
return set;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadSettings() {
|
async loadSettings() {
|
||||||
|
@ -29,22 +45,12 @@ export default new class Settings {
|
||||||
const user_config = await FileUtils.readJsonFromFile(settingsPath);
|
const user_config = await FileUtils.readJsonFromFile(settingsPath);
|
||||||
const { settings, scss, css, css_editor_files, scss_error, css_editor_bounds } = user_config;
|
const { settings, scss, css, css_editor_files, scss_error, css_editor_bounds } = user_config;
|
||||||
|
|
||||||
this.settings = defaultSettings.map(set => {
|
for (let set of this.settings) {
|
||||||
const newSet = new SettingsSet(set);
|
const newSet = settings.find(s => s.id === set.id);
|
||||||
newSet.merge(settings.find(s => s.id === newSet.id));
|
if (!newSet) continue;
|
||||||
newSet.setSaved();
|
set.merge(newSet);
|
||||||
newSet.on('setting-updated', event => {
|
set.setSaved();
|
||||||
const { category, setting, value, old_value } = event;
|
}
|
||||||
Logger.log('Settings', `${newSet.id}/${category.id}/${setting.id} was changed from ${old_value} to ${value}`);
|
|
||||||
Events.emit('setting-updated', event);
|
|
||||||
Events.emit(`setting-updated-${newSet.id}_${category.id}_${setting.id}`, event);
|
|
||||||
});
|
|
||||||
newSet.on('settings-updated', async (event) => {
|
|
||||||
await this.saveSettings();
|
|
||||||
Events.emit('settings-updated', event);
|
|
||||||
});
|
|
||||||
return newSet;
|
|
||||||
});
|
|
||||||
|
|
||||||
CssEditor.setState(scss, css, css_editor_files, scss_error);
|
CssEditor.setState(scss, css, css_editor_files, scss_error);
|
||||||
CssEditor.editor_bounds = css_editor_bounds || {};
|
CssEditor.editor_bounds = css_editor_bounds || {};
|
||||||
|
|
|
@ -46,7 +46,8 @@ export default class Theme extends Content {
|
||||||
/**
|
/**
|
||||||
* This is called when the theme is enabled.
|
* This is called when the theme is enabled.
|
||||||
*/
|
*/
|
||||||
onstart() {
|
async onstart() {
|
||||||
|
if (!this.css) await this.recompile();
|
||||||
DOM.injectTheme(this.css, this.id);
|
DOM.injectTheme(this.css, this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,10 @@ export default class ThemeManager extends ContentManager {
|
||||||
mainPath: paths.mainPath
|
mainPath: paths.mainPath
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!instance.css) instance.recompile();
|
if (instance.enabled) {
|
||||||
else if (instance.enabled) instance.enable();
|
instance.userConfig.enabled = false;
|
||||||
|
instance.enable();
|
||||||
|
}
|
||||||
return instance;
|
return instance;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw err;
|
throw err;
|
||||||
|
|
|
@ -17,27 +17,29 @@ import DropdownSetting from './types/dropdown';
|
||||||
import RadioSetting from './types/radio';
|
import RadioSetting from './types/radio';
|
||||||
import SliderSetting from './types/slider';
|
import SliderSetting from './types/slider';
|
||||||
import ColourSetting from './types/colour';
|
import ColourSetting from './types/colour';
|
||||||
|
import KeybindSetting from './types/keybind';
|
||||||
import FileSetting from './types/file';
|
import FileSetting from './types/file';
|
||||||
import ArraySetting from './types/array';
|
import ArraySetting from './types/array';
|
||||||
import CustomSetting from './types/custom';
|
import CustomSetting from './types/custom';
|
||||||
|
|
||||||
export default class Setting {
|
export default class Setting {
|
||||||
|
|
||||||
constructor(args) {
|
constructor(args, ...merge) {
|
||||||
args = args.args || args;
|
args = args.args || args;
|
||||||
|
|
||||||
if (args.type === 'color') args.type = 'colour';
|
if (args.type === 'color') args.type = 'colour';
|
||||||
|
|
||||||
if (args.type === 'bool') return new BoolSetting(args);
|
if (args.type === 'bool') return new BoolSetting(args, ...merge);
|
||||||
else if (args.type === 'text') return new StringSetting(args);
|
else if (args.type === 'text') return new StringSetting(args, ...merge);
|
||||||
else if (args.type === 'number') return new NumberSetting(args);
|
else if (args.type === 'number') return new NumberSetting(args, ...merge);
|
||||||
else if (args.type === 'dropdown') return new DropdownSetting(args);
|
else if (args.type === 'dropdown') return new DropdownSetting(args, ...merge);
|
||||||
else if (args.type === 'radio') return new RadioSetting(args);
|
else if (args.type === 'radio') return new RadioSetting(args, ...merge);
|
||||||
else if (args.type === 'slider') return new SliderSetting(args);
|
else if (args.type === 'slider') return new SliderSetting(args, ...merge);
|
||||||
else if (args.type === 'colour') return new ColourSetting(args);
|
else if (args.type === 'colour') return new ColourSetting(args, ...merge);
|
||||||
else if (args.type === 'file') return new FileSetting(args);
|
else if (args.type === 'keybind') return new KeybindSetting(args, ...merge);
|
||||||
else if (args.type === 'array') return new ArraySetting(args);
|
else if (args.type === 'file') return new FileSetting(args, ...merge);
|
||||||
else if (args.type === 'custom') return new CustomSetting(args);
|
else if (args.type === 'array') return new ArraySetting(args, ...merge);
|
||||||
|
else if (args.type === 'custom') return new CustomSetting(args, ...merge);
|
||||||
else throw {message: `Setting type ${args.type} unknown`};
|
else throw {message: `Setting type ${args.type} unknown`};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Keybind Setting Struct
|
||||||
|
* 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 Setting from './basesetting';
|
||||||
|
import Combokeys from 'combokeys';
|
||||||
|
|
||||||
|
export default class KeybindSetting extends Setting {
|
||||||
|
|
||||||
|
constructor(args, ...merge) {
|
||||||
|
super(args, ...merge);
|
||||||
|
|
||||||
|
this.combokeys = new Combokeys(document);
|
||||||
|
this.combokeys.bind(this.value, event => this.emit('keybind-activated', event));
|
||||||
|
}
|
||||||
|
|
||||||
|
setValueHook() {
|
||||||
|
this.combokeys.reset();
|
||||||
|
this.combokeys.bind(this.value, event => this.emit('keybind-activated', event));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
@import './main.scss';
|
@import './main.scss';
|
||||||
|
@import './switches.scss';
|
||||||
@import './text.scss';
|
@import './text.scss';
|
||||||
@import './files.scss';
|
@import './files.scss';
|
||||||
@import './dropdowns.scss';
|
@import './dropdowns.scss';
|
||||||
@import './radios.scss';
|
@import './radios.scss';
|
||||||
@import './sliders.scss';
|
@import './sliders.scss';
|
||||||
@import './switches.scss';
|
@import './colourpickers.scss';
|
||||||
|
@import './keybinds.scss';
|
||||||
@import './arrays.scss';
|
@import './arrays.scss';
|
||||||
@import './colourpicker.scss';
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
.bd-keybind {
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
// width: 180px;
|
||||||
|
margin-top: 10px;
|
||||||
|
background-color: rgba(0,0,0,.1);
|
||||||
|
border: 1px solid rgba(0,0,0,.3);
|
||||||
|
transition: border .15s ease;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
min-height: 40px;
|
||||||
|
|
||||||
|
.bd-keybind-selected {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
color: #f6f6f7;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bd-keybind-unset {
|
||||||
|
.bd-keybind-selected {
|
||||||
|
color: hsla(240,6%,97%,.3);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bd-button {
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: -4px -4px -4px 10px;
|
||||||
|
padding: 2px 20px;
|
||||||
|
transition: background-color .2s ease-in-out, color .2s ease-in-out;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bd-active {
|
||||||
|
border-color: $colerr;
|
||||||
|
animation: bd-keybind-pulse 1s infinite;
|
||||||
|
|
||||||
|
.bd-button {
|
||||||
|
color: $colerr;
|
||||||
|
background-color: rgba($colerr, .3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bd-keybind-pulse {
|
||||||
|
0% { box-shadow: 0 0 6px rgba(240,71,71,.3) }
|
||||||
|
50% { box-shadow: 0 0 10px rgba(240,71,71,.6) }
|
||||||
|
100% { box-shadow: 0 0 6px rgba(240,71,71,.3) }
|
||||||
|
}
|
|
@ -1,12 +1,13 @@
|
||||||
|
.bd-setting-switch,
|
||||||
.bd-form-textinput,
|
.bd-form-textinput,
|
||||||
.bd-form-textarea,
|
.bd-form-textarea,
|
||||||
.bd-form-fileinput,
|
.bd-form-numberinput,
|
||||||
.bd-form-dropdown,
|
.bd-form-dropdown,
|
||||||
.bd-form-radio,
|
.bd-form-radio,
|
||||||
.bd-form-numberinput,
|
|
||||||
.bd-form-slider,
|
.bd-form-slider,
|
||||||
.bd-form-colourpicker,
|
.bd-form-colourpicker,
|
||||||
.bd-setting-switch,
|
.bd-form-keybind,
|
||||||
|
.bd-form-fileinput,
|
||||||
.bd-form-settingsarray {
|
.bd-form-settingsarray {
|
||||||
.bd-title {
|
.bd-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Menu 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 { Utils } from 'common';
|
||||||
|
|
||||||
|
let items = 0;
|
||||||
|
|
||||||
|
const BdMenuItems = new class {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
window.bdmenu = this;
|
||||||
|
|
||||||
|
this.items = [];
|
||||||
|
|
||||||
|
this.addSettingsSet('Internal', 'core', 'Core');
|
||||||
|
this.addSettingsSet('Internal', 'ui', 'UI');
|
||||||
|
this.addSettingsSet('Internal', 'emotes', 'Emotes');
|
||||||
|
|
||||||
|
this.add({category: 'Internal', contentid: 'css', text: 'CSS Editor'});
|
||||||
|
this.add({category: 'External', contentid: 'plugins', text: 'Plugins'});
|
||||||
|
this.add({category: 'External', contentid: 'themes', text: 'Themes'});
|
||||||
|
}
|
||||||
|
|
||||||
|
add(item) {
|
||||||
|
item.id = items++;
|
||||||
|
item.contentid = item.contentid || (items++ + '');
|
||||||
|
item.active = false;
|
||||||
|
item.hidden = item.hidden || false;
|
||||||
|
item._type = item._type || 'button';
|
||||||
|
|
||||||
|
this.items.push(item);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
addSettingsSet(category, set, text) {
|
||||||
|
return this.add({
|
||||||
|
category, set,
|
||||||
|
text: text || set.text
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addVueComponent(category, text, component) {
|
||||||
|
return this.add({
|
||||||
|
category, text, component
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(item) {
|
||||||
|
Utils.removeFromArray(this.items, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export { BdMenuItems };
|
|
@ -123,4 +123,5 @@ export default class {
|
||||||
|
|
||||||
return vueInstance;
|
return vueInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
<MiClose size="17"/>
|
<MiClose size="17"/>
|
||||||
<span class="bd-x-text">ESC</span>
|
<span class="bd-x-text">ESC</span>
|
||||||
</div>
|
</div>
|
||||||
<SidebarItem v-for="item in sidebarItems" :item="item" :key="item.id" :onClick="itemOnClick" />
|
<template v-for="(category, text) in sidebar">
|
||||||
|
<SidebarItem :item="{text, type: 'header'}" />
|
||||||
|
<SidebarItem v-for="item in category" :item="item" :key="item.id" :onClick="itemOnClick" />
|
||||||
|
</template>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
<div slot="sidebarfooter" class="bd-info">
|
<div slot="sidebarfooter" class="bd-info">
|
||||||
<span class="bd-vtext">v2.0.0a by Jiiks/JsSucks</span>
|
<span class="bd-vtext">v2.0.0a by Jiiks/JsSucks</span>
|
||||||
|
@ -31,19 +34,21 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ContentColumn slot="content">
|
<ContentColumn slot="content">
|
||||||
<div v-for="set in Settings.settings" v-if="!set.hidden && activeContent(set.id) || animatingContent(set.id)" :class="{active: activeContent(set.id), animating: animatingContent(set.id)}">
|
<div v-for="item in sidebarItems" v-if="activeContent(item.contentid) || animatingContent(item.contentid)" :class="{active: activeContent(item.contentid), animating: animatingContent(item.contentid)}">
|
||||||
<SettingsWrapper :headertext="set.headertext">
|
<template v-if="item.component">
|
||||||
<SettingsPanel :settings="set" :schemes="set.schemes" />
|
<component :is="item.component" :SettingsWrapper="SettingsWrapper" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<SettingsWrapper v-if="typeof item.set === 'string'" :headertext="Settings.getSet(item.set).headertext">
|
||||||
|
<SettingsPanel :settings="Settings.getSet(item.set)" :schemes="Settings.getSet(item.set).schemes" />
|
||||||
</SettingsWrapper>
|
</SettingsWrapper>
|
||||||
</div>
|
<SettingsWrapper v-else-if="item.set" :headertext="item.set.headertext">
|
||||||
<div v-if="activeContent('css') || animatingContent('css')" :class="{active: activeContent('css'), animating: animatingContent('css')}">
|
<SettingsPanel :settings="item.set" :schemes="item.set.schemes" />
|
||||||
<CssEditorView />
|
</SettingsWrapper>
|
||||||
</div>
|
|
||||||
<div v-if="activeContent('plugins') || animatingContent('plugins')" :class="{active: activeContent('plugins'), animating: animatingContent('plugins')}">
|
<CssEditorView v-if="item.contentid === 'css'" />
|
||||||
<PluginsView />
|
<PluginsView v-if="item.contentid === 'plugins'" />
|
||||||
</div>
|
<ThemesView v-if="item.contentid === 'themes'" />
|
||||||
<div v-if="activeContent('themes') || animatingContent('themes')" :class="{active: activeContent('themes'), animating: animatingContent('themes')}">
|
|
||||||
<ThemesView />
|
|
||||||
</div>
|
</div>
|
||||||
</ContentColumn>
|
</ContentColumn>
|
||||||
</SidebarView>
|
</SidebarView>
|
||||||
|
@ -53,32 +58,22 @@
|
||||||
// Imports
|
// Imports
|
||||||
import { shell } from 'electron';
|
import { shell } from 'electron';
|
||||||
import { Settings } from 'modules';
|
import { Settings } from 'modules';
|
||||||
|
import { BdMenuItems } from 'ui';
|
||||||
import { SidebarView, Sidebar, SidebarItem, ContentColumn } from './sidebar';
|
import { SidebarView, Sidebar, SidebarItem, ContentColumn } from './sidebar';
|
||||||
import { SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView } from './bd';
|
import { SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView } from './bd';
|
||||||
import { SvgX, MiGithubCircle, MiWeb, MiClose, MiTwitterCircle } from './common';
|
import { SvgX, MiGithubCircle, MiWeb, MiClose, MiTwitterCircle } 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 {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
sidebarItems,
|
BdMenuItems,
|
||||||
activeIndex: -1,
|
activeIndex: -1,
|
||||||
lastActiveIndex: -1,
|
lastActiveIndex: -1,
|
||||||
animating: false,
|
animating: false,
|
||||||
first: true,
|
first: true,
|
||||||
Settings,
|
Settings,
|
||||||
timeout: null
|
timeout: null,
|
||||||
|
SettingsWrapper
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: ['active', 'close'],
|
props: ['active', 'close'],
|
||||||
|
@ -87,6 +82,20 @@
|
||||||
SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView,
|
SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView,
|
||||||
MiGithubCircle, MiWeb, MiClose, MiTwitterCircle
|
MiGithubCircle, MiWeb, MiClose, MiTwitterCircle
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
sidebarItems() {
|
||||||
|
return this.BdMenuItems.items;
|
||||||
|
},
|
||||||
|
sidebar() {
|
||||||
|
const categories = {};
|
||||||
|
for (let item of this.sidebarItems) {
|
||||||
|
if (item.hidden) continue;
|
||||||
|
const category = categories[item.category] || (categories[item.category] = []);
|
||||||
|
category.push(item);
|
||||||
|
}
|
||||||
|
return categories;
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
itemOnClick(id) {
|
itemOnClick(id) {
|
||||||
if (this.animating || id === this.activeIndex) return;
|
if (this.animating || id === this.activeIndex) return;
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
// Imports
|
// Imports
|
||||||
import { Events } from 'modules';
|
import { Events, Settings } from 'modules';
|
||||||
|
import { Modals } from 'ui';
|
||||||
import BdSettings from './BdSettings.vue';
|
import BdSettings from './BdSettings.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -45,11 +46,9 @@
|
||||||
hideSettings() { this.active = false },
|
hideSettings() { this.active = false },
|
||||||
toggleSettings() { this.active = !this.active },
|
toggleSettings() { this.active = !this.active },
|
||||||
keyupListener(e) {
|
keyupListener(e) {
|
||||||
if (document.getElementsByClassName('bd-backdrop').length) return;
|
if (Modals.stack.length || !this.active || e.which !== 27) return;
|
||||||
if (this.$refs.settings.activeIndex !== -1 && e.which === 27) return this.$refs.settings.closeContent();
|
if (this.$refs.settings.activeIndex !== -1) this.$refs.settings.closeContent();
|
||||||
if (this.active && e.which === 27) return this.hideSettings();
|
else this.hideSettings();
|
||||||
if (!e.metaKey && !e.ctrlKey || e.key !== 'b') return;
|
|
||||||
this.toggleSettings();
|
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -69,6 +68,9 @@
|
||||||
Events.on('update-check-end', e => this.updating = 1);
|
Events.on('update-check-end', e => this.updating = 1);
|
||||||
Events.on('updates-available', e => this.updating = 2);
|
Events.on('updates-available', e => this.updating = 2);
|
||||||
window.addEventListener('keyup', this.keyupListener);
|
window.addEventListener('keyup', this.keyupListener);
|
||||||
|
|
||||||
|
const menuKeybind = Settings.getSetting('core', 'default', 'menu-keybind');
|
||||||
|
menuKeybind.on('keybind-activated', () => this.active = !this.active);
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
window.removeEventListener('keyup', this.keyupListener);
|
window.removeEventListener('keyup', this.keyupListener);
|
||||||
|
|
|
@ -71,7 +71,6 @@
|
||||||
// TODO Display error if plugin fails to start/stop
|
// TODO Display error if plugin fails to start/stop
|
||||||
try {
|
try {
|
||||||
await plugin.enabled ? PluginManager.stopPlugin(plugin) : PluginManager.startPlugin(plugin);
|
await plugin.enabled ? PluginManager.stopPlugin(plugin) : PluginManager.startPlugin(plugin);
|
||||||
this.$forceUpdate();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
@ -79,7 +78,6 @@
|
||||||
async reloadPlugin(plugin) {
|
async reloadPlugin(plugin) {
|
||||||
try {
|
try {
|
||||||
await PluginManager.reloadPlugin(plugin);
|
await PluginManager.reloadPlugin(plugin);
|
||||||
this.$forceUpdate();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
@ -88,7 +86,6 @@
|
||||||
try {
|
try {
|
||||||
if (unload) await PluginManager.unloadPlugin(plugin);
|
if (unload) await PluginManager.unloadPlugin(plugin);
|
||||||
else await PluginManager.deletePlugin(plugin);
|
else await PluginManager.deletePlugin(plugin);
|
||||||
this.$forceUpdate();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,6 @@
|
||||||
// TODO Display error if theme fails to enable/disable
|
// TODO Display error if theme fails to enable/disable
|
||||||
try {
|
try {
|
||||||
await theme.enabled ? ThemeManager.disableTheme(theme) : ThemeManager.enableTheme(theme);
|
await theme.enabled ? ThemeManager.disableTheme(theme) : ThemeManager.enableTheme(theme);
|
||||||
this.$forceUpdate();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
@ -80,7 +79,6 @@
|
||||||
try {
|
try {
|
||||||
if (reload) await ThemeManager.reloadTheme(theme);
|
if (reload) await ThemeManager.reloadTheme(theme);
|
||||||
else await theme.recompile();
|
else await theme.recompile();
|
||||||
this.$forceUpdate();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
@ -89,7 +87,6 @@
|
||||||
try {
|
try {
|
||||||
if (unload) await ThemeManager.unloadTheme(theme);
|
if (unload) await ThemeManager.unloadTheme(theme);
|
||||||
else await ThemeManager.deleteTheme(theme);
|
else await ThemeManager.deleteTheme(theme);
|
||||||
this.$forceUpdate();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Setting Keybind 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-keybind">
|
||||||
|
<div class="bd-form-keybind-details">
|
||||||
|
<div class="bd-title">
|
||||||
|
<h3>{{ setting.text }}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="bd-hint">{{ setting.hint }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="bd-keybind" :class="{'bd-active': active, 'bd-disabled': setting.disabled, 'bd-keybind-unset': !setting.value}">
|
||||||
|
<div class="bd-keybind-selected">{{ selected || 'No Keybind Set' }}</div>
|
||||||
|
<button class="bd-button" v-tooltip="`Click to record a new keybind sequence${setting.value ? ' (shift + click to delete the sequence)' : ''}`" @click="$event.shiftKey ? deleteKeybind() : toggleActive(); $event.target.blur()">{{ active ? 'Stop Recording' : setting.value ? 'Edit Keybind' : 'Record Keybind' }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { shell } from 'electron';
|
||||||
|
import { ClientIPC } from 'common';
|
||||||
|
import Combokeys from 'combokeys';
|
||||||
|
import CombokeysRecord from 'combokeys/plugins/record';
|
||||||
|
|
||||||
|
const combokeys = new Combokeys(document);
|
||||||
|
CombokeysRecord(combokeys);
|
||||||
|
|
||||||
|
const process = window.require('process');
|
||||||
|
const modifierKey = process.platform === 'darwin' ? 'meta' : 'ctrl';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['setting'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
active: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
selected() {
|
||||||
|
return this.getDisplayString(this.setting.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
active(active) {
|
||||||
|
if (active) combokeys.record(this.recorded);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleActive() {
|
||||||
|
if (this.setting.disabled) return;
|
||||||
|
this.active = !this.active;
|
||||||
|
},
|
||||||
|
deleteKeybind() {
|
||||||
|
this.setting.value = '';
|
||||||
|
},
|
||||||
|
recorded(sequence) {
|
||||||
|
if (!this.active) return;
|
||||||
|
this.active = false;
|
||||||
|
this.recordingValue = undefined;
|
||||||
|
this.setting.value = sequence.join(' ');
|
||||||
|
console.log('keypress', sequence);
|
||||||
|
},
|
||||||
|
getDisplayString(value) {
|
||||||
|
if (!value) return;
|
||||||
|
return value.split(' ').map(pattern => {
|
||||||
|
return pattern.toUpperCase().replace(/\+/g, ' + ').replace(/mod/gi, modifierKey).replace(/meta/gi, 'Cmd').replace(/ctrl/gi, 'Ctrl').replace(/alt/gi, 'Alt').replace(/shift/gi, 'Shift');
|
||||||
|
}).join(', ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -10,17 +10,18 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bd-form-item" :class="{'bd-form-item-changed': setting.changed, 'bd-disabled': disabled, 'bd-form-item-noheader': !setting.text, 'bd-form-item-fullwidth': setting.fullwidth}">
|
<div class="bd-form-item" :class="{'bd-form-item-changed': setting.changed, 'bd-disabled': disabled, 'bd-form-item-noheader': !setting.text, 'bd-form-item-fullwidth': setting.fullwidth}">
|
||||||
<BoolSetting v-if="setting.type === 'bool'" :setting="setting" :change="change"/>
|
<BoolSetting v-if="setting.type === 'bool'" :setting="setting" :change="change" />
|
||||||
<DropdownSetting v-if="setting.type === 'dropdown'" :setting="setting" :change="change"/>
|
<DropdownSetting v-if="setting.type === 'dropdown'" :setting="setting" :change="change" />
|
||||||
<NumberSetting v-if="setting.type === 'number'" :setting="setting" :change="change"/>
|
<NumberSetting v-if="setting.type === 'number'" :setting="setting" :change="change" />
|
||||||
<RadioSetting v-if="setting.type === 'radio'" :setting="setting" :change="change"/>
|
<RadioSetting v-if="setting.type === 'radio'" :setting="setting" :change="change" />
|
||||||
<StringSetting v-if="setting.type === 'text' && !setting.multiline" :setting="setting" :change="change"/>
|
<StringSetting v-if="setting.type === 'text' && !setting.multiline" :setting="setting" :change="change" />
|
||||||
<MultilineTextSetting v-if="setting.type === 'text' && setting.multiline" :setting="setting" :change="change"/>
|
<MultilineTextSetting v-if="setting.type === 'text' && setting.multiline" :setting="setting" />
|
||||||
<SliderSetting v-if="setting.type === 'slider'" :setting="setting" :change="change"/>
|
<SliderSetting v-if="setting.type === 'slider'" :setting="setting" :change="change" />
|
||||||
<FileSetting v-if="setting.type === 'file'" :setting="setting" :change="change"/>
|
<ColourSetting v-if="setting.type === 'colour'" :setting="setting" :change="change" />
|
||||||
|
<KeybindSetting v-if="setting.type === 'keybind'" :setting="setting" />
|
||||||
|
<FileSetting v-if="setting.type === 'file'" :setting="setting" :change="change" />
|
||||||
<ArraySetting v-if="setting.type === 'array'" :setting="setting" :change="change" />
|
<ArraySetting v-if="setting.type === 'array'" :setting="setting" :change="change" />
|
||||||
<CustomSetting v-if="setting.type === 'custom'" :setting="setting" :change="change" />
|
<CustomSetting v-if="setting.type === 'custom'" :setting="setting" :change="change" />
|
||||||
<ColourSetting v-if="setting.type === 'colour'" :setting="setting" :change="change"/>
|
|
||||||
<div class="bd-form-divider"></div>
|
<div class="bd-form-divider"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -33,10 +34,11 @@
|
||||||
import StringSetting from './String.vue';
|
import StringSetting from './String.vue';
|
||||||
import MultilineTextSetting from './Multiline.vue';
|
import MultilineTextSetting from './Multiline.vue';
|
||||||
import SliderSetting from './Slider.vue';
|
import SliderSetting from './Slider.vue';
|
||||||
|
import ColourSetting from './Colour.vue';
|
||||||
|
import KeybindSetting from './Keybind.vue';
|
||||||
import FileSetting from './File.vue';
|
import FileSetting from './File.vue';
|
||||||
import ArraySetting from './Array.vue';
|
import ArraySetting from './Array.vue';
|
||||||
import CustomSetting from './Custom.vue';
|
import CustomSetting from './Custom.vue';
|
||||||
import ColourSetting from './Colour.vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
|
@ -50,10 +52,11 @@
|
||||||
StringSetting,
|
StringSetting,
|
||||||
MultilineTextSetting,
|
MultilineTextSetting,
|
||||||
SliderSetting,
|
SliderSetting,
|
||||||
|
ColourSetting,
|
||||||
|
KeybindSetting,
|
||||||
FileSetting,
|
FileSetting,
|
||||||
ArraySetting,
|
ArraySetting,
|
||||||
CustomSetting,
|
CustomSetting
|
||||||
ColourSetting
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
changed() {
|
changed() {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
export { default as DOM } from './dom';
|
export { default as DOM } from './dom';
|
||||||
export { default as BdUI } from './bdui';
|
export { default as BdUI } from './bdui';
|
||||||
export { default as VueInjector } from './vueinjector';
|
export { default as VueInjector } from './vueinjector';
|
||||||
|
export * from './bdmenu';
|
||||||
export { default as Modals } from './modals';
|
export { default as Modals } from './modals';
|
||||||
export { default as ProfileBadges } from './profilebadges';
|
export { default as ProfileBadges } from './profilebadges';
|
||||||
export { default as Reflection } from './reflection';
|
export { default as Reflection } from './reflection';
|
||||||
|
|
|
@ -10,10 +10,15 @@
|
||||||
|
|
||||||
import { ClientLogger as Logger } from './logger';
|
import { ClientLogger as Logger } from './logger';
|
||||||
|
|
||||||
|
const patchedFunctions = new WeakMap();
|
||||||
|
|
||||||
export class PatchedFunction {
|
export class PatchedFunction {
|
||||||
constructor(object, methodName, replaceOriginal = true) {
|
constructor(object, methodName, replaceOriginal = true) {
|
||||||
if (object[methodName].__monkeyPatch)
|
if (patchedFunctions.has(object[methodName])) {
|
||||||
return object[methodName].__monkeyPatch;
|
const patchedFunction = patchedFunctions.get(object[methodName]);
|
||||||
|
if (replaceOriginal) patchedFunction.replaceOriginal();
|
||||||
|
return patchedFunction;
|
||||||
|
}
|
||||||
|
|
||||||
this.object = object;
|
this.object = object;
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
|
@ -25,7 +30,9 @@ export class PatchedFunction {
|
||||||
this.replace = function(...args) {
|
this.replace = function(...args) {
|
||||||
patchedFunction.call(this, arguments);
|
patchedFunction.call(this, arguments);
|
||||||
};
|
};
|
||||||
this.replace.__monkeyPatch = this;
|
|
||||||
|
patchedFunctions.set(object[methodName], this);
|
||||||
|
patchedFunctions.set(this.replace, this);
|
||||||
|
|
||||||
if (replaceOriginal)
|
if (replaceOriginal)
|
||||||
this.replaceOriginal();
|
this.replaceOriginal();
|
||||||
|
|
|
@ -146,12 +146,14 @@ export class Utils {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static deepfreeze(object) {
|
static deepfreeze(object, exclude) {
|
||||||
|
if (exclude && exclude(object)) return;
|
||||||
|
|
||||||
if (typeof object === 'object' && object !== null) {
|
if (typeof object === 'object' && object !== null) {
|
||||||
const properties = Object.getOwnPropertyNames(object);
|
const properties = Object.getOwnPropertyNames(object);
|
||||||
|
|
||||||
for (let property of properties) {
|
for (let property of properties) {
|
||||||
this.deepfreeze(object[property]);
|
this.deepfreeze(object[property], exclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.freeze(object);
|
Object.freeze(object);
|
||||||
|
@ -159,6 +161,13 @@ export class Utils {
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static removeFromArray(array, item) {
|
||||||
|
let index;
|
||||||
|
while ((index = array.indexOf(item)) > -1)
|
||||||
|
array.splice(index, 1);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FileUtils {
|
export class FileUtils {
|
||||||
|
|
|
@ -1323,6 +1323,15 @@
|
||||||
"integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=",
|
"integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"binary-search-tree": {
|
||||||
|
"version": "0.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary-search-tree/-/binary-search-tree-0.2.5.tgz",
|
||||||
|
"integrity": "sha1-fbs7IQ/coIJFDa0jNMMErzm9x4Q=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"underscore": "1.4.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"block-stream": {
|
"block-stream": {
|
||||||
"version": "0.0.9",
|
"version": "0.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
|
||||||
|
@ -2023,6 +2032,12 @@
|
||||||
"delayed-stream": "1.0.0"
|
"delayed-stream": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"combokeys": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/combokeys/-/combokeys-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-lVxZo5Wa9A0mhGq2/DxoJEjnVy4=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"commander": {
|
"commander": {
|
||||||
"version": "2.14.1",
|
"version": "2.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
|
||||||
|
@ -5652,6 +5667,12 @@
|
||||||
"integrity": "sha1-YSKJv7PCIOGGpYEYYY1b6MG6sCE=",
|
"integrity": "sha1-YSKJv7PCIOGGpYEYYY1b6MG6sCE=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"immediate": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||||
|
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"imurmurhash": {
|
"imurmurhash": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||||
|
@ -6293,6 +6314,15 @@
|
||||||
"type-check": "0.3.2"
|
"type-check": "0.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lie": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
|
||||||
|
"integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"immediate": "3.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"liftoff": {
|
"liftoff": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz",
|
||||||
|
@ -6347,6 +6377,15 @@
|
||||||
"json5": "0.5.1"
|
"json5": "0.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"localforage": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.6.0.tgz",
|
||||||
|
"integrity": "sha1-iwBZvus4dcSBJChsp/2/I9UrjJc=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"lie": "3.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"locate-path": {
|
"locate-path": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
|
||||||
|
@ -6979,6 +7018,27 @@
|
||||||
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"nedb": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nedb/-/nedb-1.8.0.tgz",
|
||||||
|
"integrity": "sha1-DjUCzYLABNU1WkPJ5VV3vXvZHYg=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"async": "0.2.10",
|
||||||
|
"binary-search-tree": "0.2.5",
|
||||||
|
"localforage": "1.6.0",
|
||||||
|
"mkdirp": "0.5.1",
|
||||||
|
"underscore": "1.4.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"async": {
|
||||||
|
"version": "0.2.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
|
||||||
|
"integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"neo-async": {
|
"neo-async": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.0.tgz",
|
||||||
|
@ -10569,6 +10629,12 @@
|
||||||
"integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
|
"integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"underscore": {
|
||||||
|
"version": "1.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz",
|
||||||
|
"integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"union-value": {
|
"union-value": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
"codemirror": "^5.23.0",
|
"codemirror": "^5.23.0",
|
||||||
|
"combokeys": "^3.0.0",
|
||||||
"css-loader": "^0.28.9",
|
"css-loader": "^0.28.9",
|
||||||
"electron": "^1.6.15",
|
"electron": "^1.6.15",
|
||||||
"electron-rebuild": "^1.7.3",
|
"electron-rebuild": "^1.7.3",
|
||||||
|
|
|
@ -77,6 +77,13 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "keybind-1",
|
||||||
|
"type": "keybind",
|
||||||
|
"value": "mod+.",
|
||||||
|
"text": "Test Keybind Setting 1",
|
||||||
|
"hint": "Test Keybind Setting Hint 1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
module.exports = (Plugin, { Logger, Settings }) => class extends Plugin {
|
module.exports = (Plugin, { Logger, Settings, Modals, BdMenu: { BdMenuItems }, Api }) => class extends Plugin {
|
||||||
async onstart() {
|
async onstart() {
|
||||||
|
this.keybindEvent = this.keybindEvent.bind(this);
|
||||||
|
|
||||||
// Some array event examples
|
// Some array event examples
|
||||||
const arraySetting = this.settings.getSetting('default', 'array-1');
|
const arraySetting = this.settings.getSetting('default', 'array-1');
|
||||||
Logger.log('Array setting', arraySetting);
|
Logger.log('Array setting', arraySetting);
|
||||||
|
@ -7,8 +9,15 @@ module.exports = (Plugin, { Logger, Settings }) => class extends Plugin {
|
||||||
arraySetting.on('item-updated', event => Logger.log('Item', event.item, 'of the array setting was updated', event));
|
arraySetting.on('item-updated', event => Logger.log('Item', event.item, 'of the array setting was updated', event));
|
||||||
arraySetting.on('item-removed', event => Logger.log('Item', event.item, 'removed from the array setting'));
|
arraySetting.on('item-removed', event => Logger.log('Item', event.item, 'removed from the array setting'));
|
||||||
|
|
||||||
// Create a new settings set and show it in a modal
|
// Keybind setting examples
|
||||||
const set = Settings.createSet({});
|
const keybindSetting = this.settings.getSetting('default', 'keybind-1');
|
||||||
|
Logger.log('Keybind setting', keybindSetting);
|
||||||
|
keybindSetting.on('keybind-activated', this.keybindEvent);
|
||||||
|
|
||||||
|
// Create a new settings set and add it to the menu
|
||||||
|
const set = Settings.createSet({
|
||||||
|
text: this.name
|
||||||
|
});
|
||||||
const category = await set.addCategory({ id: 'default' });
|
const category = await set.addCategory({ id: 'default' });
|
||||||
|
|
||||||
const setting = await category.addSetting({
|
const setting = await category.addSetting({
|
||||||
|
@ -33,6 +42,37 @@ module.exports = (Plugin, { Logger, Settings }) => class extends Plugin {
|
||||||
set.setSaved();
|
set.setSaved();
|
||||||
})
|
})
|
||||||
|
|
||||||
set.showModal('Custom settings panel');
|
const setting2 = await category.addSetting({
|
||||||
|
id: 'setting-2',
|
||||||
|
type: 'text',
|
||||||
|
text: 'Enter some text',
|
||||||
|
fullwidth: true
|
||||||
|
});
|
||||||
|
|
||||||
|
setting2.on('setting-updated', event => Logger.log('Setting 2 was changed to', event.value));
|
||||||
|
|
||||||
|
this.menuItem = BdMenuItems.addSettingsSet('Plugins', set, 'Plugin 4');
|
||||||
|
|
||||||
|
this.menuItem2 = BdMenuItems.addVueComponent('Plugins', 'Also Plugin 4', {
|
||||||
|
template: `<component :is="SettingsWrapper" :headertext="plugin.name + ' custom menu panel'">
|
||||||
|
<p style="margin-top: 0; color: #f6f6f7;">Test</p>
|
||||||
|
</component>`,
|
||||||
|
props: ['SettingsWrapper'],
|
||||||
|
data() { return {
|
||||||
|
Api, plugin: Api.plugin
|
||||||
|
}; }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onstop() {
|
||||||
|
const keybindSetting = this.settings.getSetting('default', 'keybind-1');
|
||||||
|
keybindSetting.off('keybind-activated', this.keybindEvent);
|
||||||
|
|
||||||
|
BdMenuItems.removeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
keybindEvent(event) {
|
||||||
|
Logger.log('Keybind pressed', event);
|
||||||
|
Modals.basic('Example Plugin 4', 'Test keybind activated.');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue