Comments and fix tooltip arrow positioning
This commit is contained in:
parent
994faf94d6
commit
b4bd9e9c7b
|
@ -91,9 +91,9 @@ export default class Content {
|
||||||
config: this.settings.strip().settings,
|
config: this.settings.strip().settings,
|
||||||
data: this.data
|
data: this.data
|
||||||
});
|
});
|
||||||
this.settings.setSaved();
|
this.settings.setSaved();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Logger.err(this.name, ['Failed to save configuration', err]);
|
Logger.err(this.name, ['Failed to save configuration', err]);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,12 @@ export default class {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts or updates data in the database.
|
||||||
|
* @param {Object} args The record to find
|
||||||
|
* @param {Object} data The new record
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async insertOrUpdate(args, data) {
|
static async insertOrUpdate(args, data) {
|
||||||
try {
|
try {
|
||||||
return ClientIPC.send('bd-dba', { action: 'update', args, data });
|
return ClientIPC.send('bd-dba', { action: 'update', args, data });
|
||||||
|
@ -24,6 +30,11 @@ export default class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds data in the database.
|
||||||
|
* @param {Object} args The record to find
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async find(args) {
|
static async find(args) {
|
||||||
try {
|
try {
|
||||||
return ClientIPC.send('bd-dba', { action: 'find', args });
|
return ClientIPC.send('bd-dba', { action: 'find', args });
|
||||||
|
|
|
@ -402,7 +402,7 @@ export default class DiscordApi {
|
||||||
|
|
||||||
static get currentChannel() {
|
static get currentChannel() {
|
||||||
const channel = Modules.ChannelStore.getChannel(Modules.SelectedChannelStore.getChannelId());
|
const channel = Modules.ChannelStore.getChannel(Modules.SelectedChannelStore.getChannelId());
|
||||||
return channel.isPrivate ? new PrivateChannel(channel) : new GuildChannel(channel);
|
if (channel) return channel.isPrivate() ? new PrivateChannel(channel) : new GuildChannel(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get currentUser() {
|
static get currentUser() {
|
||||||
|
@ -415,5 +415,5 @@ export default class DiscordApi {
|
||||||
for (const id of friends) returnUsers.push(User.fromId(id));
|
for (const id of friends) returnUsers.push(User.fromId(id));
|
||||||
return returnUsers;
|
return returnUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* BetterDiscord WebpackModules Module
|
* BetterDiscord Event Hook
|
||||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
* https://betterdiscord.net
|
* https://betterdiscord.net
|
||||||
|
@ -8,14 +8,13 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import EventListener from './eventlistener';
|
import { Utils, ClientLogger as Logger } from 'common';
|
||||||
import { Utils } from 'common';
|
|
||||||
import Events from './events';
|
|
||||||
import { WebpackModules } from './webpackmodules';
|
import { WebpackModules } from './webpackmodules';
|
||||||
|
import Events from './events';
|
||||||
|
import EventListener from './eventlistener';
|
||||||
|
|
||||||
import * as SocketStructs from '../structs/socketstructs';
|
import * as SocketStructs from '../structs/socketstructs';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discord socket event hook
|
* Discord socket event hook
|
||||||
* @extends {EventListener}
|
* @extends {EventListener}
|
||||||
|
@ -23,7 +22,7 @@ import * as SocketStructs from '../structs/socketstructs';
|
||||||
export default class extends EventListener {
|
export default class extends EventListener {
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
console.log(SocketStructs);
|
Logger.log('EventHook', SocketStructs);
|
||||||
this.hook();
|
this.hook();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,11 +43,11 @@ export default class extends EventListener {
|
||||||
orig.call(this, ...args);
|
orig.call(this, ...args);
|
||||||
self.wsc = this;
|
self.wsc = this;
|
||||||
self.emit(...args);
|
self.emit(...args);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get eventsModule() {
|
get eventsModule() {
|
||||||
return WebpackModules.getModuleByPrototypes(['setMaxListeners', 'emit']);
|
return WebpackModules.getModuleByName('Events');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,8 +65,8 @@ export default class extends EventListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit callback
|
* Emit callback
|
||||||
* @param {any} e Event Action
|
* @param {any} event Event
|
||||||
* @param {any} d Event Args
|
* @param {any} data Event data
|
||||||
*/
|
*/
|
||||||
dispatch(e, d) {
|
dispatch(e, d) {
|
||||||
Events.emit('raw-event', { type: e, data: d });
|
Events.emit('raw-event', { type: e, data: d });
|
||||||
|
@ -143,7 +142,7 @@ export default class extends EventListener {
|
||||||
LFG_LISTING_CREATE: 'LFG_LISTING_CREATE', // No groups here
|
LFG_LISTING_CREATE: 'LFG_LISTING_CREATE', // No groups here
|
||||||
LFG_LISTING_DELETE: 'LFG_LISTING_DELETE', // Thank you
|
LFG_LISTING_DELETE: 'LFG_LISTING_DELETE', // Thank you
|
||||||
BRAINTREE_POPUP_BRIDGE_CALLBACK: 'BRAINTREE_POPUP_BRIDGE_CALLBACK' // What
|
BRAINTREE_POPUP_BRIDGE_CALLBACK: 'BRAINTREE_POPUP_BRIDGE_CALLBACK' // What
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,14 +12,39 @@ import { EventEmitter } from 'events';
|
||||||
const emitter = new EventEmitter();
|
const emitter = new EventEmitter();
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
static on(eventName, callBack) {
|
|
||||||
emitter.on(eventName, callBack);
|
/**
|
||||||
|
* Adds an event listener.
|
||||||
|
* @param {String} event The event to listen for
|
||||||
|
* @param {Function} callback The function to call when the event is emitted
|
||||||
|
*/
|
||||||
|
static on(event, callback) {
|
||||||
|
emitter.on(event, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
static off(eventName, callBack) {
|
/**
|
||||||
emitter.removeListener(eventName, callBack);
|
* Adds an event listener that is only called once.
|
||||||
|
* @param {String} event The event to listen for
|
||||||
|
* @param {Function} callback The function to call when the event is emitted
|
||||||
|
*/
|
||||||
|
static once(event, callback) {
|
||||||
|
emitter.once(event, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an event listener.
|
||||||
|
* @param {String} event The event to remove
|
||||||
|
* @param {Function} callback The listener to remove
|
||||||
|
*/
|
||||||
|
static off(event, callback) {
|
||||||
|
emitter.removeListener(event, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits an event
|
||||||
|
* @param {String} event The event to emit
|
||||||
|
* @param {Any} ...data Data to pass to the event listeners
|
||||||
|
*/
|
||||||
static emit(...args) {
|
static emit(...args) {
|
||||||
emitter.emit(...args);
|
emitter.emit(...args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
const eventemitters = new WeakMap();
|
const eventemitters = new WeakMap();
|
||||||
|
|
||||||
export default class EventsWrapper {
|
export default class EventsWrapper {
|
||||||
constructor(eventemitter) {
|
|
||||||
|
constructor(eventemitter, bind) {
|
||||||
eventemitters.set(this, eventemitter);
|
eventemitters.set(this, eventemitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,26 +20,33 @@ export default class EventsWrapper {
|
||||||
return this._eventSubs || (this._eventSubs = []);
|
return this._eventSubs || (this._eventSubs = []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get on() { return this.subscribe }
|
||||||
subscribe(event, callback) {
|
subscribe(event, callback) {
|
||||||
if (this.eventSubs.find(e => e.event === event && e.callback === callback)) return;
|
if (this.eventSubs.find(e => e.event === event && e.callback === callback)) return;
|
||||||
this.eventSubs.push({
|
const boundCallback = () => callback.apply(this.bind, arguments);
|
||||||
event,
|
this.eventSubs.push({ event, callback, boundCallback });
|
||||||
callback
|
eventemitters.get(this).on(event, boundCallback);
|
||||||
});
|
|
||||||
eventemitters.get(this).on(event, callback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
once(event, callback) {
|
||||||
|
if (this.eventSubs.find(e => e.event === event && e.callback === callback)) return;
|
||||||
|
const boundCallback = () => this.off(event, callback) && callback.apply(this.bind, arguments);
|
||||||
|
this.eventSubs.push({ event, callback, boundCallback });
|
||||||
|
eventemitters.get(this).on(event, boundCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
get off() { return this.unsubscribe }
|
||||||
unsubscribe(event, callback) {
|
unsubscribe(event, callback) {
|
||||||
for (let index of this.eventSubs) {
|
for (let index of this.eventSubs) {
|
||||||
if (this.eventSubs[index].event !== event || (callback && this.eventSubs[index].callback === callback)) return;
|
if (this.eventSubs[index].event !== event || (callback && this.eventSubs[index].callback === callback)) continue;
|
||||||
eventemitters.get(this).off(event, this.eventSubs[index].callback);
|
eventemitters.get(this).off(event, this.eventSubs[index].boundCallback);
|
||||||
this.eventSubs.splice(index, 1);
|
this.eventSubs.splice(index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsubscribeAll() {
|
unsubscribeAll() {
|
||||||
for (let event of this.eventSubs) {
|
for (let event of this.eventSubs) {
|
||||||
eventemitters.get(this).off(event.event, event.callback);
|
eventemitters.get(this).off(event.event, event.boundCallback);
|
||||||
}
|
}
|
||||||
this.eventSubs.splice(0, this.eventSubs.length);
|
this.eventSubs.splice(0, this.eventSubs.length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,20 +5,19 @@
|
||||||
* https://github.com/JsSucks - https://betterdiscord.net
|
* https://github.com/JsSucks - https://betterdiscord.net
|
||||||
*
|
*
|
||||||
* This source code is licensed under the MIT license found in the
|
* 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.
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Base Module that every non-static module should extend
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Module that every non-static module should extend
|
||||||
|
*/
|
||||||
export default class Module {
|
export default class Module {
|
||||||
|
|
||||||
constructor(args) {
|
constructor(args) {
|
||||||
this.__ = {
|
this.__ = {
|
||||||
state: args || {},
|
state: args || {},
|
||||||
args
|
args
|
||||||
}
|
};
|
||||||
this.setState = this.setState.bind(this);
|
this.setState = this.setState.bind(this);
|
||||||
this.initialize();
|
this.initialize();
|
||||||
}
|
}
|
||||||
|
@ -38,7 +37,6 @@ export default class Module {
|
||||||
set args(t) { }
|
set args(t) { }
|
||||||
get args() { return this.__.args; }
|
get args() { return this.__.args; }
|
||||||
|
|
||||||
|
|
||||||
set state(state) { return this.__.state = state; }
|
set state(state) { return this.__.state = state; }
|
||||||
get state() { return this.__.state; }
|
get state() { return this.__.state; }
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,9 @@ import Updater from './updater';
|
||||||
*/
|
*/
|
||||||
export default class {
|
export default class {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of modules.
|
||||||
|
*/
|
||||||
static get modules() {
|
static get modules() {
|
||||||
return this._modules ? this._modules : (this._modules = [
|
return this._modules ? this._modules : (this._modules = [
|
||||||
new ProfileBadges(),
|
new ProfileBadges(),
|
||||||
|
@ -28,6 +31,10 @@ export default class {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes all modules.
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async initModules() {
|
static async initModules() {
|
||||||
for (let module of this.modules) {
|
for (let module of this.modules) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -15,12 +15,8 @@ export default class Plugin extends Content {
|
||||||
|
|
||||||
get type() { return 'plugin' }
|
get type() { return 'plugin' }
|
||||||
|
|
||||||
// Don't use - these will eventually be removed!
|
|
||||||
get pluginPath() { return this.contentPath }
|
|
||||||
get pluginConfig() { return this.config }
|
|
||||||
|
|
||||||
get start() { return this.enable }
|
get start() { return this.enable }
|
||||||
get stop() { return this.disable }
|
get stop() { return this.disable }
|
||||||
|
|
||||||
unload() {
|
unload() {
|
||||||
PluginManager.unloadPlugin(this);
|
PluginManager.unloadPlugin(this);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* BetterDiscord Plugin Api
|
* BetterDiscord Plugin API
|
||||||
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
* https://betterdiscord.net
|
* https://betterdiscord.net
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Utils, ClientLogger as Logger, ClientIPC } from 'common';
|
import { Utils, ClientLogger as Logger, ClientIPC, AsyncEventEmitter } from 'common';
|
||||||
import Settings from './settings';
|
import Settings from './settings';
|
||||||
import ExtModuleManager from './extmodulemanager';
|
import ExtModuleManager from './extmodulemanager';
|
||||||
import PluginManager from './pluginmanager';
|
import PluginManager from './pluginmanager';
|
||||||
|
@ -24,27 +24,20 @@ import { MonkeyPatch } from './patcher';
|
||||||
|
|
||||||
export default class PluginApi {
|
export default class PluginApi {
|
||||||
|
|
||||||
constructor(pluginInfo) {
|
constructor(pluginInfo, pluginPath) {
|
||||||
this.pluginInfo = pluginInfo;
|
this.pluginInfo = pluginInfo;
|
||||||
|
this.pluginPath = pluginPath;
|
||||||
|
|
||||||
this.Events = new EventsWrapper(Events);
|
this.Events = new EventsWrapper(Events);
|
||||||
|
Utils.defineSoftGetter(this.Events, 'bind', () => this.plugin);
|
||||||
|
|
||||||
this._menuItems = undefined;
|
this._menuItems = undefined;
|
||||||
this._injectedStyles = undefined;
|
this._injectedStyles = undefined;
|
||||||
this._modalStack = undefined;
|
this._modalStack = undefined;
|
||||||
}
|
}
|
||||||
get Discord() {
|
|
||||||
return DiscordApi;
|
|
||||||
}
|
|
||||||
get ReactComponents() {
|
|
||||||
return ReactComponents;
|
|
||||||
}
|
|
||||||
get Reflection() {
|
|
||||||
return Reflection;
|
|
||||||
}
|
|
||||||
get MonkeyPatch() {
|
|
||||||
return module => MonkeyPatch(this.pluginInfo.id, module);
|
|
||||||
}
|
|
||||||
get plugin() {
|
get plugin() {
|
||||||
return PluginManager.getPluginById(this.pluginInfo.id || this.pluginInfo.name.toLowerCase().replace(/[^a-zA-Z0-9-]/g, '-').replace(/--/g, '-'));
|
return PluginManager.getPluginByPath(this.pluginPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
async bridge(plugin_id) {
|
async bridge(plugin_id) {
|
||||||
|
@ -61,15 +54,18 @@ export default class PluginApi {
|
||||||
|
|
||||||
get Api() { return this }
|
get Api() { return this }
|
||||||
|
|
||||||
|
get AsyncEventEmitter() { return AsyncEventEmitter }
|
||||||
|
get EventsWrapper() { return EventsWrapper }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
|
|
||||||
loggerLog(...message) { Logger.log(this.pluginInfo.name, message) }
|
loggerLog(...message) { Logger.log(this.plugin.name, message) }
|
||||||
loggerErr(...message) { Logger.err(this.pluginInfo.name, message) }
|
loggerErr(...message) { Logger.err(this.plugin.name, message) }
|
||||||
loggerWarn(...message) { Logger.warn(this.pluginInfo.name, message) }
|
loggerWarn(...message) { Logger.warn(this.plugin.name, message) }
|
||||||
loggerInfo(...message) { Logger.info(this.pluginInfo.name, message) }
|
loggerInfo(...message) { Logger.info(this.plugin.name, message) }
|
||||||
loggerDbg(...message) { Logger.dbg(this.pluginInfo.name, message) }
|
loggerDbg(...message) { Logger.dbg(this.plugin.name, message) }
|
||||||
get Logger() {
|
get Logger() {
|
||||||
return {
|
return {
|
||||||
log: this.loggerLog.bind(this),
|
log: this.loggerLog.bind(this),
|
||||||
|
@ -381,6 +377,24 @@ export default class PluginApi {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DiscordApi
|
||||||
|
*/
|
||||||
|
|
||||||
|
get Discord() {
|
||||||
|
return DiscordApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
get ReactComponents() {
|
||||||
|
return ReactComponents;
|
||||||
|
}
|
||||||
|
get Reflection() {
|
||||||
|
return Reflection;
|
||||||
|
}
|
||||||
|
get MonkeyPatch() {
|
||||||
|
return module => MonkeyPatch(this.plugin.id, module);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop plugins from modifying the plugin API for all plugins
|
// Stop plugins from modifying the plugin API for all plugins
|
||||||
|
|
|
@ -76,12 +76,12 @@ export default class extends ContentManager {
|
||||||
static async loadPlugin(paths, configs, info, main, dependencies, permissions) {
|
static async loadPlugin(paths, configs, info, main, dependencies, permissions) {
|
||||||
if (permissions && permissions.length > 0) {
|
if (permissions && permissions.length > 0) {
|
||||||
for (let perm of permissions) {
|
for (let perm of permissions) {
|
||||||
console.log(`Permission: ${Permissions.permissionText(perm).HEADER} - ${Permissions.permissionText(perm).BODY}`);
|
Logger.log(this.moduleName, `Permission: ${Permissions.permissionText(perm).HEADER} - ${Permissions.permissionText(perm).BODY}`);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const allowed = await Modals.permissions(`${info.name} wants to:`, info.name, permissions).promise;
|
const allowed = await Modals.permissions(`${info.name} wants to:`, info.name, permissions).promise;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ 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, paths.contentPath), Vendor, deps);
|
||||||
if (!(plugin.prototype instanceof Plugin))
|
if (!(plugin.prototype instanceof Plugin))
|
||||||
throw {message: `Plugin ${info.name} did not return a class that extends Plugin.`};
|
throw {message: `Plugin ${info.name} did not return a class that extends Plugin.`};
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,23 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import defaultSettings from '../data/user.settings.default';
|
|
||||||
import Globals from './globals';
|
|
||||||
import CssEditor from './csseditor';
|
|
||||||
import Events from './events';
|
|
||||||
import { Utils, FileUtils, ClientLogger as Logger } from 'common';
|
import { Utils, FileUtils, ClientLogger as Logger } from 'common';
|
||||||
import { SettingsSet, SettingUpdatedEvent } from 'structs';
|
import { SettingsSet, SettingUpdatedEvent } from 'structs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import Globals from './globals';
|
||||||
|
import CssEditor from './csseditor';
|
||||||
|
import Events from './events';
|
||||||
|
import defaultSettings from '../data/user.settings.default';
|
||||||
|
|
||||||
export default new class Settings {
|
export default new class Settings {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.settings = defaultSettings.map(_set => {
|
this.settings = defaultSettings.map(_set => {
|
||||||
const set = new SettingsSet(_set);
|
const set = new SettingsSet(_set);
|
||||||
|
|
||||||
set.on('setting-updated', event => {
|
set.on('setting-updated', event => {
|
||||||
const { category, setting, value, old_value } = event;
|
const { category, setting, value, old_value } = event;
|
||||||
Logger.log('Settings', `${set.id}/${category.id}/${setting.id} was changed from ${old_value} to ${value}`);
|
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', event);
|
||||||
Events.emit(`setting-updated-${set.id}_${category.id}_${setting.id}`, event);
|
Events.emit(`setting-updated-${set.id}_${category.id}_${setting.id}`, event);
|
||||||
});
|
});
|
||||||
|
@ -37,6 +38,9 @@ export default new class Settings {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads BetterDiscord's settings.
|
||||||
|
*/
|
||||||
async loadSettings() {
|
async loadSettings() {
|
||||||
try {
|
try {
|
||||||
await FileUtils.ensureDirectory(this.dataPath);
|
await FileUtils.ensureDirectory(this.dataPath);
|
||||||
|
@ -48,7 +52,7 @@ export default new class Settings {
|
||||||
for (let set of this.settings) {
|
for (let set of this.settings) {
|
||||||
const newSet = settings.find(s => s.id === set.id);
|
const newSet = settings.find(s => s.id === set.id);
|
||||||
if (!newSet) continue;
|
if (!newSet) continue;
|
||||||
set.merge(newSet);
|
await set.merge(newSet);
|
||||||
set.setSaved();
|
set.setSaved();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +65,9 @@ export default new class Settings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves BetterDiscord's settings including CSS editor data.
|
||||||
|
*/
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
try {
|
try {
|
||||||
await FileUtils.ensureDirectory(this.dataPath);
|
await FileUtils.ensureDirectory(this.dataPath);
|
||||||
|
@ -72,15 +79,10 @@ export default new class Settings {
|
||||||
css: CssEditor.css,
|
css: CssEditor.css,
|
||||||
css_editor_files: CssEditor.files,
|
css_editor_files: CssEditor.files,
|
||||||
scss_error: CssEditor.error,
|
scss_error: CssEditor.error,
|
||||||
css_editor_bounds: {
|
css_editor_bounds: CssEditor.editor_bounds
|
||||||
width: CssEditor.editor_bounds.width,
|
|
||||||
height: CssEditor.editor_bounds.height,
|
|
||||||
x: CssEditor.editor_bounds.x,
|
|
||||||
y: CssEditor.editor_bounds.y
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let set of this.getSettings) {
|
for (let set of this.settings) {
|
||||||
set.setSaved();
|
set.setSaved();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -90,8 +92,13 @@ export default new class Settings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds one of BetterDiscord's settings sets.
|
||||||
|
* @param {String} set_id The ID of the set to find
|
||||||
|
* @return {SettingsSet}
|
||||||
|
*/
|
||||||
getSet(set_id) {
|
getSet(set_id) {
|
||||||
return this.getSettings.find(s => s.id === set_id);
|
return this.settings.find(s => s.id === set_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
get core() { return this.getSet('core') }
|
get core() { return this.getSet('core') }
|
||||||
|
@ -100,39 +107,46 @@ export default new class Settings {
|
||||||
get css() { return this.getSet('css') }
|
get css() { return this.getSet('css') }
|
||||||
get security() { return this.getSet('security') }
|
get security() { return this.getSet('security') }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a category in one of BetterDiscord's settings sets.
|
||||||
|
* @param {String} set_id The ID of the set to look in
|
||||||
|
* @param {String} category_id The ID of the category to find
|
||||||
|
* @return {SettingsCategory}
|
||||||
|
*/
|
||||||
getCategory(set_id, category_id) {
|
getCategory(set_id, category_id) {
|
||||||
const set = this.getSet(set_id);
|
const set = this.getSet(set_id);
|
||||||
return set ? set.getCategory(category_id) : undefined;
|
return set ? set.getCategory(category_id) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a setting in one of BetterDiscord's settings sets.
|
||||||
|
* @param {String} set_id The ID of the set to look in
|
||||||
|
* @param {String} category_id The ID of the category to look in
|
||||||
|
* @param {String} setting_id The ID of the setting to find
|
||||||
|
* @return {Setting}
|
||||||
|
*/
|
||||||
getSetting(set_id, category_id, setting_id) {
|
getSetting(set_id, category_id, setting_id) {
|
||||||
const set = this.getSet(set_id);
|
const set = this.getSet(set_id);
|
||||||
return set ? set.getSetting(category_id, setting_id) : undefined;
|
return set ? set.getSetting(category_id, setting_id) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a setting's value in one of BetterDiscord's settings sets.
|
||||||
|
* @param {String} set_id The ID of the set to look in
|
||||||
|
* @param {String} category_id The ID of the category to look in
|
||||||
|
* @param {String} setting_id The ID of the setting to find
|
||||||
|
* @return {Any}
|
||||||
|
*/
|
||||||
get(set_id, category_id, setting_id) {
|
get(set_id, category_id, setting_id) {
|
||||||
const set = this.getSet(set_id);
|
const set = this.getSet(set_id);
|
||||||
return set ? set.get(category_id, setting_id) : undefined;
|
return set ? set.get(category_id, setting_id) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async mergeSettings(set_id, newSettings) {
|
/**
|
||||||
const set = this.getSet(set_id);
|
* The path to store user data in.
|
||||||
if (!set) return;
|
*/
|
||||||
|
|
||||||
return await set.merge(newSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSetting(set_id, category_id, setting_id, value) {
|
|
||||||
const setting = this.getSetting(set_id, category_id, setting_id);
|
|
||||||
if (!setting) throw {message: `Tried to set ${set_id}/${category_id}/${setting_id}, which doesn't exist`};
|
|
||||||
setting.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
get getSettings() {
|
|
||||||
return this.settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
get dataPath() {
|
get dataPath() {
|
||||||
return Globals.getPath('data');
|
return Globals.getPath('data');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ClientLogger as Logger } from 'common';
|
||||||
import EventListener from './eventlistener';
|
import EventListener from './eventlistener';
|
||||||
|
|
||||||
export default class SocketProxy extends EventListener {
|
export default class SocketProxy extends EventListener {
|
||||||
|
@ -19,7 +20,7 @@ export default class SocketProxy extends EventListener {
|
||||||
|
|
||||||
get eventBindings() {
|
get eventBindings() {
|
||||||
return [
|
return [
|
||||||
{ id: 'socket-created', 'callback': this.socketCreated }
|
{ id: 'socket-created', callback: this.socketCreated }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,11 +30,11 @@ export default class SocketProxy extends EventListener {
|
||||||
|
|
||||||
socketCreated(socket) {
|
socketCreated(socket) {
|
||||||
this.activeSocket = socket;
|
this.activeSocket = socket;
|
||||||
// socket.addEventListener('message', this.onMessage);
|
// socket.addEventListener('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMessage(e) {
|
onMessage(e) {
|
||||||
console.info(e);
|
Logger.info('SocketProxy', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,6 @@ export default class Theme extends Content {
|
||||||
get type() { return 'theme' }
|
get type() { return 'theme' }
|
||||||
get css() { return this.data.css }
|
get css() { return this.data.css }
|
||||||
|
|
||||||
// Don't use - these will eventually be removed!
|
|
||||||
get themePath() { return this.contentPath }
|
|
||||||
get themeConfig() { return this.config }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when settings are updated.
|
* Called when settings are updated.
|
||||||
* This can be overridden by other content types.
|
* This can be overridden by other content types.
|
||||||
|
@ -63,7 +59,7 @@ export default class Theme extends Content {
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
async compile() {
|
async compile() {
|
||||||
console.log('Compiling CSS');
|
Logger.log(this.name, 'Compiling CSS');
|
||||||
|
|
||||||
if (this.info.type === 'sass') {
|
if (this.info.type === 'sass') {
|
||||||
const config = await ThemeManager.getConfigAsSCSS(this.settings);
|
const config = await ThemeManager.getConfigAsSCSS(this.settings);
|
||||||
|
@ -76,7 +72,7 @@ export default class Theme extends Content {
|
||||||
Logger.log(this.name, ['Finished compiling theme', new class Info {
|
Logger.log(this.name, ['Finished compiling theme', new class Info {
|
||||||
get SCSS_variables() { console.log(config); }
|
get SCSS_variables() { console.log(config); }
|
||||||
get Compiled_SCSS() { console.log(result.css.toString()); }
|
get Compiled_SCSS() { console.log(result.css.toString()); }
|
||||||
get Result() { console.log(result); }
|
get Result() { console.log(result); }
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -121,6 +117,7 @@ export default class Theme extends Content {
|
||||||
*/
|
*/
|
||||||
set files(files) {
|
set files(files) {
|
||||||
this.data.files = files;
|
this.data.files = files;
|
||||||
|
|
||||||
if (Settings.get('css', 'default', 'watch-files'))
|
if (Settings.get('css', 'default', 'watch-files'))
|
||||||
this.watchfiles = files;
|
this.watchfiles = files;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,11 @@ export default class ThemeManager extends ContentManager {
|
||||||
return theme instanceof Theme;
|
return theme instanceof Theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a representation of a settings set's values in SCSS.
|
||||||
|
* @param {SettingsSet} settingsset The set to convert to SCSS
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async getConfigAsSCSS(settingsset) {
|
static async getConfigAsSCSS(settingsset) {
|
||||||
const variables = [];
|
const variables = [];
|
||||||
|
|
||||||
|
@ -87,6 +92,11 @@ export default class ThemeManager extends ContentManager {
|
||||||
return variables.join('\n');
|
return variables.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a representation of a settings set's values as an SCSS map.
|
||||||
|
* @param {SettingsSet} settingsset The set to convert to an SCSS map
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async getConfigAsSCSSMap(settingsset) {
|
static async getConfigAsSCSSMap(settingsset) {
|
||||||
const variables = [];
|
const variables = [];
|
||||||
|
|
||||||
|
@ -100,6 +110,11 @@ export default class ThemeManager extends ContentManager {
|
||||||
return '(' + variables.join(', ') + ')';
|
return '(' + variables.join(', ') + ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a setting's name and value as a string that can be included in SCSS.
|
||||||
|
* @param {Setting} setting The setting to convert to SCSS
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async parseSetting(setting) {
|
static async parseSetting(setting) {
|
||||||
const { type, id, value } = setting;
|
const { type, id, value } = setting;
|
||||||
const name = id.replace(/[^a-zA-Z0-9-]/g, '-').replace(/--/g, '-');
|
const name = id.replace(/[^a-zA-Z0-9-]/g, '-').replace(/--/g, '-');
|
||||||
|
@ -108,6 +123,11 @@ export default class ThemeManager extends ContentManager {
|
||||||
if (scss) return [name, scss];
|
if (scss) return [name, scss];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escapes a string so it can be included in SCSS.
|
||||||
|
* @param {String} value The string to escape
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
static toSCSSString(value) {
|
static toSCSSString(value) {
|
||||||
if (typeof value !== 'string' && value.toString) value = value.toString();
|
if (typeof value !== 'string' && value.toString) value = value.toString();
|
||||||
return `'${typeof value === 'string' ? value.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') : ''}'`;
|
return `'${typeof value === 'string' ? value.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') : ''}'`;
|
||||||
|
|
|
@ -22,6 +22,9 @@ export default class {
|
||||||
this.checkForUpdates = this.checkForUpdates.bind(this);
|
this.checkForUpdates = this.checkForUpdates.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interval to wait before checking for updates.
|
||||||
|
*/
|
||||||
get interval() {
|
get interval() {
|
||||||
return 60 * 1000 * 30;
|
return 60 * 1000 * 30;
|
||||||
}
|
}
|
||||||
|
@ -30,34 +33,51 @@ export default class {
|
||||||
this.updateInterval = setInterval(this.checkForUpdates, this.interval);
|
this.updateInterval = setInterval(this.checkForUpdates, this.interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs an update.
|
||||||
|
* TODO
|
||||||
|
*/
|
||||||
update() {
|
update() {
|
||||||
// TODO
|
|
||||||
this.updatesAvailable = false;
|
this.updatesAvailable = false;
|
||||||
Events.emit('update-check-end');
|
Events.emit('update-check-end');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for updates.
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
checkForUpdates() {
|
checkForUpdates() {
|
||||||
if (this.updatesAvailable) return;
|
return new Promise((resolve, reject) => {
|
||||||
Events.emit('update-check-start');
|
if (this.updatesAvailable) return resolve(true);
|
||||||
Logger.info('Updater', 'Checking for updates');
|
Events.emit('update-check-start');
|
||||||
$.ajax({
|
Logger.info('Updater', 'Checking for updates');
|
||||||
type: 'GET',
|
|
||||||
url: 'https://rawgit.com/JsSucks/BetterDiscordApp/master/package.json',
|
$.ajax({
|
||||||
cache: false,
|
type: 'GET',
|
||||||
success: e => {
|
url: 'https://rawgit.com/JsSucks/BetterDiscordApp/master/package.json',
|
||||||
try {
|
cache: false,
|
||||||
Events.emit('update-check-end');
|
success: e => {
|
||||||
Logger.info('Updater',
|
try {
|
||||||
`Latest Version: ${e.version} - Current Version: ${Globals.version}`);
|
Events.emit('update-check-end');
|
||||||
if (e.version !== Globals.version) {
|
Logger.info('Updater', `Latest Version: ${e.version} - Current Version: ${Globals.getObject('version')}`);
|
||||||
this.updatesAvailable = true;
|
|
||||||
Events.emit('updates-available');
|
if (e.version !== Globals.getObject('version')) {
|
||||||
|
this.updatesAvailable = true;
|
||||||
|
Events.emit('updates-available');
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(false);
|
||||||
|
} catch (err) {
|
||||||
|
Events.emit('update-check-fail', err);
|
||||||
|
reject(err);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
},
|
||||||
|
fail: err => {
|
||||||
Events.emit('update-check-fail', err);
|
Events.emit('update-check-fail', err);
|
||||||
|
reject(err);
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
fail: e => Events.emit('update-check-fail', e)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,22 +16,21 @@ export { jQuery as $ };
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
|
|
||||||
static get jQuery() {
|
/**
|
||||||
return jQuery;
|
* jQuery
|
||||||
}
|
*/
|
||||||
|
static get jQuery() { return jQuery }
|
||||||
|
static get $() { return this.jQuery }
|
||||||
|
|
||||||
static get $() {
|
/**
|
||||||
return this.jQuery;
|
* Lodash
|
||||||
}
|
*/
|
||||||
|
static get lodash() { return lodash }
|
||||||
static get lodash() {
|
static get _() { return this.lodash }
|
||||||
return lodash;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get _() {
|
|
||||||
return this.lodash;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moment
|
||||||
|
*/
|
||||||
static get moment() {
|
static get moment() {
|
||||||
return WebpackModules.getModuleByName('Moment');
|
return WebpackModules.getModuleByName('Moment');
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ const KnownModules = {
|
||||||
React: Filters.byProperties(['createElement', 'cloneElement']),
|
React: Filters.byProperties(['createElement', 'cloneElement']),
|
||||||
ReactDOM: Filters.byProperties(['render', 'findDOMNode']),
|
ReactDOM: Filters.byProperties(['render', 'findDOMNode']),
|
||||||
|
|
||||||
|
Events: Filters.byPrototypeFields(['setMaxListeners', 'emit']),
|
||||||
|
|
||||||
/* Guild Info, Stores, and Utilities */
|
/* Guild Info, Stores, and Utilities */
|
||||||
GuildStore: Filters.byProperties(['getGuild']),
|
GuildStore: Filters.byProperties(['getGuild']),
|
||||||
SortedGuildStore: Filters.byProperties(['getSortedGuilds']),
|
SortedGuildStore: Filters.byProperties(['getSortedGuilds']),
|
||||||
|
@ -207,37 +209,37 @@ const KnownModules = {
|
||||||
|
|
||||||
export class WebpackModules {
|
export class WebpackModules {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a module using a filter function.
|
* Finds a module using a filter function.
|
||||||
* @param {Function} filter A function to use to filter modules
|
* @param {Function} filter A function to use to filter modules
|
||||||
* @param {Boolean} first Whether to return only the first matching module
|
* @param {Boolean} first Whether to return only the first matching module
|
||||||
* @return {Any}
|
* @return {Any}
|
||||||
*/
|
*/
|
||||||
static getModule(filter, first = true) {
|
static getModule(filter, first = true) {
|
||||||
const modules = this.getAllModules();
|
const modules = this.getAllModules();
|
||||||
const rm = [];
|
const rm = [];
|
||||||
for (let index in modules) {
|
for (let index in modules) {
|
||||||
if (!modules.hasOwnProperty(index)) continue;
|
if (!modules.hasOwnProperty(index)) continue;
|
||||||
const module = modules[index];
|
const module = modules[index];
|
||||||
const { exports } = module;
|
const { exports } = module;
|
||||||
let foundModule = null;
|
let foundModule = null;
|
||||||
|
|
||||||
if (!exports) continue;
|
if (!exports) continue;
|
||||||
if (exports.__esModule && exports.default && filter(exports.default)) foundModule = exports.default;
|
if (exports.__esModule && exports.default && filter(exports.default)) foundModule = exports.default;
|
||||||
if (filter(exports)) foundModule = exports;
|
if (filter(exports)) foundModule = exports;
|
||||||
if (!foundModule) continue;
|
if (!foundModule) continue;
|
||||||
if (first) return foundModule;
|
if (first) return foundModule;
|
||||||
rm.push(foundModule);
|
rm.push(foundModule);
|
||||||
}
|
}
|
||||||
return first || rm.length == 0 ? undefined : rm;
|
return first || rm.length == 0 ? undefined : rm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a module by it's name.
|
* Finds a module by it's name.
|
||||||
* @param {String} name The name of the module
|
* @param {String} name The name of the module
|
||||||
* @param {Function} fallback A function to use to filter modules if not finding a known module
|
* @param {Function} fallback A function to use to filter modules if not finding a known module
|
||||||
* @return {Any}
|
* @return {Any}
|
||||||
*/
|
*/
|
||||||
static getModuleByName(name, fallback) {
|
static getModuleByName(name, fallback) {
|
||||||
if (Cache.hasOwnProperty(name)) return Cache[name];
|
if (Cache.hasOwnProperty(name)) return Cache[name];
|
||||||
if (KnownModules.hasOwnProperty(name)) fallback = KnownModules[name];
|
if (KnownModules.hasOwnProperty(name)) fallback = KnownModules[name];
|
||||||
|
@ -246,48 +248,48 @@ export class WebpackModules {
|
||||||
return module ? Cache[name] = module : undefined;
|
return module ? Cache[name] = module : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a module by it's display name.
|
* Finds a module by it's display name.
|
||||||
* @param {String} name The display name of the module
|
* @param {String} name The display name of the module
|
||||||
* @return {Any}
|
* @return {Any}
|
||||||
*/
|
*/
|
||||||
static getModuleByDisplayName(name) {
|
static getModuleByDisplayName(name) {
|
||||||
return this.getModule(Filters.byDisplayName(name), true);
|
return this.getModule(Filters.byDisplayName(name), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a module using it's code.
|
* Finds a module using it's code.
|
||||||
* @param {RegEx} regex A regular expression to use to filter modules
|
* @param {RegEx} regex A regular expression to use to filter modules
|
||||||
* @param {Boolean} first Whether to return the only the first matching module
|
* @param {Boolean} first Whether to return the only the first matching module
|
||||||
* @return {Any}
|
* @return {Any}
|
||||||
*/
|
*/
|
||||||
static getModuleByRegex(regex, first = true) {
|
static getModuleByRegex(regex, first = true) {
|
||||||
return this.getModule(Filters.byCode(regex), first);
|
return this.getModule(Filters.byCode(regex), first);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a module using properties on it's prototype.
|
* Finds a module using properties on it's prototype.
|
||||||
* @param {Array} props Properties to use to filter modules
|
* @param {Array} props Properties to use to filter modules
|
||||||
* @param {Boolean} first Whether to return only the first matching module
|
* @param {Boolean} first Whether to return only the first matching module
|
||||||
* @return {Any}
|
* @return {Any}
|
||||||
*/
|
*/
|
||||||
static getModuleByPrototypes(prototypes, first = true) {
|
static getModuleByPrototypes(prototypes, first = true) {
|
||||||
return this.getModule(Filters.byPrototypeFields(prototypes), first);
|
return this.getModule(Filters.byPrototypeFields(prototypes), first);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a module using it's own properties.
|
* Finds a module using it's own properties.
|
||||||
* @param {Array} props Properties to use to filter modules
|
* @param {Array} props Properties to use to filter modules
|
||||||
* @param {Boolean} first Whether to return only the first matching module
|
* @param {Boolean} first Whether to return only the first matching module
|
||||||
* @return {Any}
|
* @return {Any}
|
||||||
*/
|
*/
|
||||||
static getModuleByProps(props, first = true) {
|
static getModuleByProps(props, first = true) {
|
||||||
return this.getModule(Filters.byProperties(props), first);
|
return this.getModule(Filters.byProperties(props), first);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discord's __webpack_require__ function.
|
* Discord's __webpack_require__ function.
|
||||||
*/
|
*/
|
||||||
static get require() {
|
static get require() {
|
||||||
if (this._require) return this._require;
|
if (this._require) return this._require;
|
||||||
const id = 'bd-webpackmodules';
|
const id = 'bd-webpackmodules';
|
||||||
|
|
|
@ -17,22 +17,37 @@ export default class ErrorEvent extends Event {
|
||||||
this.showStack = false; // For error modal
|
this.showStack = false; // For error modal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The module the error occured in.
|
||||||
|
*/
|
||||||
get module() {
|
get module() {
|
||||||
return this.args.module;
|
return this.args.module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message describing the error.
|
||||||
|
*/
|
||||||
get message() {
|
get message() {
|
||||||
return this.args.message;
|
return this.args.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The original error object.
|
||||||
|
*/
|
||||||
get err() {
|
get err() {
|
||||||
return this.args.err;
|
return this.args.err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trace showing which functions were called when the error occured.
|
||||||
|
*/
|
||||||
get stackTrace() {
|
get stackTrace() {
|
||||||
return this.err.stack;
|
return this.err.stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of event.
|
||||||
|
*/
|
||||||
get __eventType() {
|
get __eventType() {
|
||||||
return 'error';
|
return 'error';
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,23 @@ export default class Event {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object containing information about the event.
|
||||||
|
*/
|
||||||
get event() {
|
get event() {
|
||||||
return this.__eventInfo;
|
return this.__eventInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first argument that was passed to the constructor, which contains information about the event.
|
||||||
|
*/
|
||||||
get args() {
|
get args() {
|
||||||
return this.event.args[0];
|
return this.event.args[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
get __eventType() { return null; }
|
/**
|
||||||
|
* The type of event.
|
||||||
|
*/
|
||||||
|
get __eventType() { return undefined; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,16 @@ import Event from './event';
|
||||||
|
|
||||||
export default class SettingsUpdatedEvent extends Event {
|
export default class SettingsUpdatedEvent extends Event {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of SettingUpdated events.
|
||||||
|
*/
|
||||||
get updatedSettings() {
|
get updatedSettings() {
|
||||||
return this.args.updatedSettings;
|
return this.args.updatedSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of event.
|
||||||
|
*/
|
||||||
get __eventType() {
|
get __eventType() {
|
||||||
return 'settings-updated';
|
return 'settings-updated';
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,38 +12,65 @@ import Event from './event';
|
||||||
|
|
||||||
export default class SettingUpdatedEvent extends Event {
|
export default class SettingUpdatedEvent extends Event {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set containing the setting that was updated.
|
||||||
|
*/
|
||||||
get set() {
|
get set() {
|
||||||
return this.args.set;
|
return this.args.set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the set containing the setting that was updated.
|
||||||
|
*/
|
||||||
get set_id() {
|
get set_id() {
|
||||||
return this.args.set.id;
|
return this.set.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The category containing the setting that was updated.
|
||||||
|
*/
|
||||||
get category() {
|
get category() {
|
||||||
return this.args.category;
|
return this.args.category;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the category containing the setting that was updated.
|
||||||
|
*/
|
||||||
get category_id() {
|
get category_id() {
|
||||||
return this.args.category.id;
|
return this.category.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting that was updated.
|
||||||
|
*/
|
||||||
get setting() {
|
get setting() {
|
||||||
return this.args.setting;
|
return this.args.setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the setting that was updated.
|
||||||
|
*/
|
||||||
get setting_id() {
|
get setting_id() {
|
||||||
return this.args.setting.id;
|
return this.setting.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting's new value.
|
||||||
|
*/
|
||||||
get value() {
|
get value() {
|
||||||
return this.args.value;
|
return this.args.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setting's old value.
|
||||||
|
*/
|
||||||
get old_value() {
|
get old_value() {
|
||||||
return this.args.old_value;
|
return this.args.old_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of event.
|
||||||
|
*/
|
||||||
get __eventType() {
|
get __eventType() {
|
||||||
return 'setting-updated';
|
return 'setting-updated';
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,22 +14,29 @@ export default class MultipleChoiceOption {
|
||||||
|
|
||||||
constructor(args) {
|
constructor(args) {
|
||||||
this.args = args.args || args;
|
this.args = args.args || args;
|
||||||
|
|
||||||
|
Object.freeze(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This option's ID.
|
||||||
|
*/
|
||||||
get id() {
|
get id() {
|
||||||
return this.args.id || this.value;
|
return this.args.id || this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string describing this option.
|
||||||
|
*/
|
||||||
get text() {
|
get text() {
|
||||||
return this.args.text;
|
return this.args.text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value to return when this option is active.
|
||||||
|
*/
|
||||||
get value() {
|
get value() {
|
||||||
return this.args.value;
|
return this.args.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
clone() {
|
|
||||||
return new MultipleChoiceOption(Utils.deepclone(this.args));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,26 +24,46 @@ export default class SettingsScheme {
|
||||||
Object.freeze(this);
|
Object.freeze(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The scheme's ID.
|
||||||
|
*/
|
||||||
get id() {
|
get id() {
|
||||||
return this.args.id;
|
return this.args.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of the scheme's icon. This should be a base64 encoded data URI.
|
||||||
|
*/
|
||||||
get icon_url() {
|
get icon_url() {
|
||||||
return this.args.icon_url;
|
return this.args.icon_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The scheme's name.
|
||||||
|
*/
|
||||||
get name() {
|
get name() {
|
||||||
return this.args.name;
|
return this.args.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string to be displayed under the scheme.
|
||||||
|
*/
|
||||||
get hint() {
|
get hint() {
|
||||||
return this.args.hint;
|
return this.args.hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of stripped settings categories this scheme manages.
|
||||||
|
*/
|
||||||
get settings() {
|
get settings() {
|
||||||
return this.args.settings || [];
|
return this.args.settings || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this scheme's values are currently applied to a set.
|
||||||
|
* @param {SettingsSet} set The set to check
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
isActive(set) {
|
isActive(set) {
|
||||||
for (let schemeCategory of this.settings) {
|
for (let schemeCategory of this.settings) {
|
||||||
const category = set.categories.find(c => c.category === schemeCategory.category);
|
const category = set.categories.find(c => c.category === schemeCategory.category);
|
||||||
|
@ -66,12 +86,13 @@ export default class SettingsScheme {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies this scheme's values to a set.
|
||||||
|
* @param {SettingsSet} set The set to merge this scheme's values into
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
applyTo(set) {
|
applyTo(set) {
|
||||||
return set.merge({ settings: this.settings });
|
return set.merge(this);
|
||||||
}
|
|
||||||
|
|
||||||
clone() {
|
|
||||||
return new SettingsScheme(Utils.deepclone(this.args));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -446,7 +446,7 @@ export default class SettingsSet {
|
||||||
text: this.text,
|
text: this.text,
|
||||||
headertext: this.headertext,
|
headertext: this.headertext,
|
||||||
settings: this.categories.map(category => category.clone()),
|
settings: this.categories.map(category => category.clone()),
|
||||||
schemes: this.schemes.map(scheme => scheme.clone())
|
schemes: this.schemes
|
||||||
}, ...merge);
|
}, ...merge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,16 +25,21 @@
|
||||||
width: 16px;
|
width: 16px;
|
||||||
filter: brightness(10);
|
filter: brightness(10);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
.theme-light [class*="topSectionNormal-"] & {
|
}
|
||||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FscXVlXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjAwMCAyMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyMDAwIDIwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGZpbGw9IiMzRTgyRTUiIGQ9Ik0xNDAyLjIsNjMxLjdjLTkuNy0zNTMuNC0yODYuMi00OTYtNjQyLjYtNDk2SDY4LjR2NzE0LjFsNDQyLDM5OFY0OTAuN2gyNTdjMjc0LjUsMCwyNzQuNSwzNDQuOSwwLDM0NC45SDU5Ny42djMyOS41aDE2OS44YzI3NC41LDAsMjc0LjUsMzQ0LjgsMCwzNDQuOGgtNjk5djM1NC45aDY5MS4yYzM1Ni4zLDAsNjMyLjgtMTQyLjYsNjQyLjYtNDk2YzAtMTYyLjYtNDQuNS0yODQuMS0xMjIuOS0zNjguNkMxMzU3LjcsOTE1LjgsMTQwMi4yLDc5NC4zLDE0MDIuMiw2MzEuN3oiLz48cGF0aCBmaWxsPSIjYmJiYmJiIiBkPSJNMTI2Mi41LDEzNS4yTDEyNjIuNSwxMzUuMmwtNzYuOCwwYzI2LjYsMTMuMyw1MS43LDI4LjEsNzUsNDQuM2M3MC43LDQ5LjEsMTI2LjEsMTExLjUsMTY0LjYsMTg1LjNjMzkuOSw3Ni42LDYxLjUsMTY1LjYsNjQuMywyNjQuNmwwLDEuMnYxLjJjMCwxNDEuMSwwLDU5Ni4xLDAsNzM3LjF2MS4ybDAsMS4yYy0yLjcsOTktMjQuMywxODgtNjQuMywyNjQuNmMtMzguNSw3My44LTkzLjgsMTM2LjItMTY0LjYsMTg1LjNjLTIyLjYsMTUuNy00Ni45LDMwLjEtNzIuNiw0My4xaDcyLjVjMzQ2LjIsMS45LDY3MS0xNzEuMiw2NzEtNTY3LjlWNzE2LjdDMTkzMy41LDMxMi4yLDE2MDguNywxMzUuMiwxMjYyLjUsMTM1LjJ6Ii8+PC9nPjwvc3ZnPg==');
|
|
||||||
filter: none;
|
.theme-light [class*="topSectionNormal-"] .bd-profile-badge-developer,
|
||||||
}
|
.theme-light [class*="topSectionNormal-"] .bd-profile-badge-contributor,
|
||||||
|
.theme-light .bd-message-badge-developer,
|
||||||
|
.theme-light .bd-message-badge-contributor {
|
||||||
|
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FscXVlXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjAwMCAyMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAyMDAwIDIwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGZpbGw9IiMzRTgyRTUiIGQ9Ik0xNDAyLjIsNjMxLjdjLTkuNy0zNTMuNC0yODYuMi00OTYtNjQyLjYtNDk2SDY4LjR2NzE0LjFsNDQyLDM5OFY0OTAuN2gyNTdjMjc0LjUsMCwyNzQuNSwzNDQuOSwwLDM0NC45SDU5Ny42djMyOS41aDE2OS44YzI3NC41LDAsMjc0LjUsMzQ0LjgsMCwzNDQuOGgtNjk5djM1NC45aDY5MS4yYzM1Ni4zLDAsNjMyLjgtMTQyLjYsNjQyLjYtNDk2YzAtMTYyLjYtNDQuNS0yODQuMS0xMjIuOS0zNjguNkMxMzU3LjcsOTE1LjgsMTQwMi4yLDc5NC4zLDE0MDIuMiw2MzEuN3oiLz48cGF0aCBmaWxsPSIjYmJiYmJiIiBkPSJNMTI2Mi41LDEzNS4yTDEyNjIuNSwxMzUuMmwtNzYuOCwwYzI2LjYsMTMuMyw1MS43LDI4LjEsNzUsNDQuM2M3MC43LDQ5LjEsMTI2LjEsMTExLjUsMTY0LjYsMTg1LjNjMzkuOSw3Ni42LDYxLjUsMTY1LjYsNjQuMywyNjQuNmwwLDEuMnYxLjJjMCwxNDEuMSwwLDU5Ni4xLDAsNzM3LjF2MS4ybDAsMS4yYy0yLjcsOTktMjQuMywxODgtNjQuMywyNjQuNmMtMzguNSw3My44LTkzLjgsMTM2LjItMTY0LjYsMTg1LjNjLTIyLjYsMTUuNy00Ni45LDMwLjEtNzIuNiw0My4xaDcyLjVjMzQ2LjIsMS45LDY3MS0xNzEuMiw2NzEtNTY3LjlWNzE2LjdDMTkzMy41LDMxMi4yLDE2MDguNywxMzUuMiwxMjYyLjUsMTM1LjJ6Ii8+PC9nPjwvc3ZnPg==');
|
||||||
|
filter: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-message-badges-wrap {
|
.bd-message-badges-wrap {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
height: 11px;
|
height: 11px;
|
||||||
|
|
||||||
.bd-message-badge-developer,
|
.bd-message-badge-developer,
|
||||||
.bd-message-badge-contributor {
|
.bd-message-badge-contributor {
|
||||||
width: 12px;
|
width: 12px;
|
||||||
|
|
|
@ -20,17 +20,17 @@ bd-tooltips {
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
z-index: 9001;
|
z-index: 9001;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
|
||||||
|
|
||||||
.bd-tooltip:after {
|
.bd-tooltip-arrow {
|
||||||
border: 5px solid transparent;
|
border: 5px solid transparent;
|
||||||
content: " ";
|
content: " ";
|
||||||
height: 0;
|
height: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
width: 0;
|
width: 0;
|
||||||
border-top-color: #000;
|
border-top-color: #000;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin-left: -5px;
|
margin-left: -5px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,37 +8,14 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Events, WebpackModules, EventListener, ReactComponents, Renderer } from 'modules';
|
import { Events, WebpackModules, EventListener, DiscordApi, ReactComponents, Renderer } from 'modules';
|
||||||
|
import { ClientLogger as Logger } from 'common';
|
||||||
import Reflection from './reflection';
|
import Reflection from './reflection';
|
||||||
import DOM from './dom';
|
import DOM from './dom';
|
||||||
import VueInjector from './vueinjector';
|
import VueInjector from './vueinjector';
|
||||||
import EditedTimeStamp from './components/common/EditedTimestamp.vue';
|
import EditedTimeStamp from './components/common/EditedTimestamp.vue';
|
||||||
import Autocomplete from './components/common/Autocomplete.vue';
|
import Autocomplete from './components/common/Autocomplete.vue';
|
||||||
|
|
||||||
class TempApi {
|
|
||||||
static get currentGuildId() {
|
|
||||||
try {
|
|
||||||
return WebpackModules.getModuleByName('SelectedGuildStore').getGuildId();
|
|
||||||
} catch (err) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static get currentChannelId() {
|
|
||||||
try {
|
|
||||||
return WebpackModules.getModuleByName('SelectedChannelStore').getChannelId();
|
|
||||||
} catch (err) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static get currentUserId() {
|
|
||||||
try {
|
|
||||||
return WebpackModules.getModuleByName('UserStore').getCurrentUser().id;
|
|
||||||
} catch (err) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class extends EventListener {
|
export default class extends EventListener {
|
||||||
|
|
||||||
constructor(args) {
|
constructor(args) {
|
||||||
|
@ -54,22 +31,19 @@ export default class extends EventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
get eventBindings() {
|
get eventBindings() {
|
||||||
return [{ id: 'gkh:keyup', callback: this.injectAutocomplete }];
|
|
||||||
/*
|
|
||||||
return [
|
return [
|
||||||
{ id: 'server-switch', callback: this.manipAll },
|
// { id: 'server-switch', callback: this.manipAll },
|
||||||
{ id: 'channel-switch', callback: this.manipAll },
|
// { id: 'channel-switch', callback: this.manipAll },
|
||||||
{ id: 'discord:MESSAGE_CREATE', callback: this.markupInjector },
|
// { id: 'discord:MESSAGE_CREATE', callback: this.markupInjector },
|
||||||
{ id: 'discord:MESSAGE_UPDATE', callback: this.markupInjector },
|
// { id: 'discord:MESSAGE_UPDATE', callback: this.markupInjector },
|
||||||
{ id: 'gkh:keyup', callback: this.injectAutocomplete }
|
{ id: 'gkh:keyup', callback: this.injectAutocomplete }
|
||||||
];
|
];
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
manipAll() {
|
manipAll() {
|
||||||
try {
|
try {
|
||||||
this.appMount.setAttribute('guild-id', TempApi.currentGuildId);
|
this.appMount.setAttribute('guild-id', DiscordApi.currentGuild.id);
|
||||||
this.appMount.setAttribute('channel-id', TempApi.currentChannelId);
|
this.appMount.setAttribute('channel-id', DiscordApi.currentChannel.id);
|
||||||
this.setIds();
|
this.setIds();
|
||||||
this.makeMutable();
|
this.makeMutable();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -172,14 +146,14 @@ export default class extends EventListener {
|
||||||
const userTest = Reflection(msgGroup).prop('user');
|
const userTest = Reflection(msgGroup).prop('user');
|
||||||
if (!userTest) return;
|
if (!userTest) return;
|
||||||
msgGroup.setAttribute('data-author-id', userTest.id);
|
msgGroup.setAttribute('data-author-id', userTest.id);
|
||||||
if (userTest.id === TempApi.currentUserId) msgGroup.setAttribute('data-currentuser', true);
|
if (userTest.id === DiscordApi.currentUserId) msgGroup.setAttribute('data-currentuser', true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
msg.setAttribute('data-message-id', messageid);
|
msg.setAttribute('data-message-id', messageid);
|
||||||
const msgGroup = msg.closest('.message-group');
|
const msgGroup = msg.closest('.message-group');
|
||||||
if (!msgGroup) return;
|
if (!msgGroup) return;
|
||||||
msgGroup.setAttribute('data-author-id', authorid);
|
msgGroup.setAttribute('data-author-id', authorid);
|
||||||
if (authorid === TempApi.currentUserId) msgGroup.setAttribute('data-currentuser', true);
|
if (authorid === DiscordApi.currentUser.id) msgGroup.setAttribute('data-currentuser', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
setUserId(user) {
|
setUserId(user) {
|
||||||
|
@ -187,7 +161,7 @@ export default class extends EventListener {
|
||||||
const userid = Reflection(user).prop('user.id');
|
const userid = Reflection(user).prop('user.id');
|
||||||
if (!userid) return;
|
if (!userid) return;
|
||||||
user.setAttribute('data-user-id', userid);
|
user.setAttribute('data-user-id', userid);
|
||||||
const currentUser = userid === TempApi.currentUserId;
|
const currentUser = userid === DiscordApi.currentUser.id;
|
||||||
if (currentUser) user.setAttribute('data-currentuser', true);
|
if (currentUser) user.setAttribute('data-currentuser', true);
|
||||||
Events.emit('ui:useridset', user);
|
Events.emit('ui:useridset', user);
|
||||||
}
|
}
|
||||||
|
@ -218,4 +192,5 @@ export default class extends EventListener {
|
||||||
template: '<Autocomplete :initial="initial" />'
|
template: '<Autocomplete :initial="initial" />'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,14 @@ const BdMenuItems = new class {
|
||||||
this.add({category: 'External', contentid: 'themes', text: 'Themes'});
|
this.add({category: 'External', contentid: 'themes', text: 'Themes'});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an item to the menu.
|
||||||
|
* @param {Object} item The item to add to the menu
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
add(item) {
|
add(item) {
|
||||||
|
if (this.items.includes(item)) return item;
|
||||||
|
|
||||||
item.id = items++;
|
item.id = items++;
|
||||||
item.contentid = item.contentid || (items++ + '');
|
item.contentid = item.contentid || (items++ + '');
|
||||||
item.active = false;
|
item.active = false;
|
||||||
|
@ -39,6 +46,13 @@ const BdMenuItems = new class {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a settings set to the menu.
|
||||||
|
* @param {String} category The category to display this item under
|
||||||
|
* @param {SettingsSet} set The settings set to display when this item is active
|
||||||
|
* @param {String} text The text to display in the menu (optional)
|
||||||
|
* @return {Object} The item that was added
|
||||||
|
*/
|
||||||
addSettingsSet(category, set, text) {
|
addSettingsSet(category, set, text) {
|
||||||
return this.add({
|
return this.add({
|
||||||
category, set,
|
category, set,
|
||||||
|
@ -46,12 +60,23 @@ const BdMenuItems = new class {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a Vue component to the menu.
|
||||||
|
* @param {String} category The category to display this item under
|
||||||
|
* @param {String} text The text to display in the menu
|
||||||
|
* @param {Object} component The Vue component to display when this item is active
|
||||||
|
* @return {Object} The item that was added
|
||||||
|
*/
|
||||||
addVueComponent(category, text, component) {
|
addVueComponent(category, text, component) {
|
||||||
return this.add({
|
return this.add({
|
||||||
category, text, component
|
category, text, component
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an item from the menu.
|
||||||
|
* @param {Object} item The item to remove from the menu
|
||||||
|
*/
|
||||||
remove(item) {
|
remove(item) {
|
||||||
Utils.removeFromArray(this.items, item);
|
Utils.removeFromArray(this.items, item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,48 +8,21 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Events, WebpackModules, DiscordApi } from 'modules';
|
||||||
|
import { Utils } from 'common';
|
||||||
|
import { remote } from 'electron';
|
||||||
import DOM from './dom';
|
import DOM from './dom';
|
||||||
import Vue from './vue';
|
import Vue from './vue';
|
||||||
import { BdSettingsWrapper } from './components';
|
|
||||||
import BdModals from './components/bd/BdModals.vue';
|
|
||||||
import { Events, WebpackModules } from 'modules';
|
|
||||||
import { Utils } from 'common';
|
|
||||||
import AutoManip from './automanip';
|
import AutoManip from './automanip';
|
||||||
import { remote } from 'electron';
|
import { BdSettingsWrapper, BdModals } from './components';
|
||||||
|
|
||||||
class TempApi {
|
|
||||||
static get currentGuild() {
|
|
||||||
try {
|
|
||||||
const currentGuildId = WebpackModules.getModuleByName('SelectedGuildStore').getGuildId();
|
|
||||||
return WebpackModules.getModuleByName('GuildStore').getGuild(currentGuildId);
|
|
||||||
} catch (err) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static get currentChannel() {
|
|
||||||
try {
|
|
||||||
const currentChannelId = WebpackModules.getModuleByName('SelectedChannelStore').getChannelId();
|
|
||||||
return WebpackModules.getModuleByName('ChannelStore').getChannel(currentChannelId);
|
|
||||||
} catch (err) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static get currentUserId() {
|
|
||||||
try {
|
|
||||||
return WebpackModules.getModuleByName('UserStore').getCurrentUser().id;
|
|
||||||
} catch (err) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
|
|
||||||
static initUiEvents() {
|
static initUiEvents() {
|
||||||
this.pathCache = {
|
this.pathCache = {
|
||||||
isDm: null,
|
isDm: null,
|
||||||
server: TempApi.currentGuild,
|
server: DiscordApi.currentGuild,
|
||||||
channel: TempApi.currentChannel
|
channel: DiscordApi.currentChannel
|
||||||
};
|
};
|
||||||
window.addEventListener('keyup', e => Events.emit('gkh:keyup', e));
|
window.addEventListener('keyup', e => Events.emit('gkh:keyup', e));
|
||||||
this.autoManip = new AutoManip();
|
this.autoManip = new AutoManip();
|
||||||
|
@ -67,9 +40,9 @@ export default class {
|
||||||
if (!remote.BrowserWindow.getFocusedWindow()) return;
|
if (!remote.BrowserWindow.getFocusedWindow()) return;
|
||||||
clearInterval(ehookInterval);
|
clearInterval(ehookInterval);
|
||||||
remote.BrowserWindow.getFocusedWindow().webContents.on('did-navigate-in-page', (e, url, isMainFrame) => {
|
remote.BrowserWindow.getFocusedWindow().webContents.on('did-navigate-in-page', (e, url, isMainFrame) => {
|
||||||
const { currentGuild, currentChannel } = TempApi;
|
const { currentGuild, currentChannel } = DiscordApi;
|
||||||
if (!this.pathCache.server) {
|
if (!this.pathCache.server) {
|
||||||
Events.emit('server-switch', { 'server': currentGuild, 'channel': currentChannel });
|
Events.emit('server-switch', { server: currentGuild, channel: currentChannel });
|
||||||
this.pathCache.server = currentGuild;
|
this.pathCache.server = currentGuild;
|
||||||
this.pathCache.channel = currentChannel;
|
this.pathCache.channel = currentChannel;
|
||||||
return;
|
return;
|
||||||
|
@ -84,7 +57,7 @@ export default class {
|
||||||
currentGuild.id &&
|
currentGuild.id &&
|
||||||
this.pathCache.server &&
|
this.pathCache.server &&
|
||||||
this.pathCache.server.id !== currentGuild.id) {
|
this.pathCache.server.id !== currentGuild.id) {
|
||||||
Events.emit('server-switch', { 'server': currentGuild, 'channel': currentChannel });
|
Events.emit('server-switch', { server: currentGuild, channel: currentChannel });
|
||||||
this.pathCache.server = currentGuild;
|
this.pathCache.server = currentGuild;
|
||||||
this.pathCache.channel = currentChannel;
|
this.pathCache.channel = currentChannel;
|
||||||
return;
|
return;
|
||||||
|
@ -110,19 +83,19 @@ export default class {
|
||||||
DOM.createElement('div', null, 'bd-modals').appendTo(DOM.bdModals);
|
DOM.createElement('div', null, 'bd-modals').appendTo(DOM.bdModals);
|
||||||
DOM.createElement('bd-tooltips').appendTo(DOM.bdBody);
|
DOM.createElement('bd-tooltips').appendTo(DOM.bdBody);
|
||||||
|
|
||||||
const modals = new Vue({
|
this.modals = new Vue({
|
||||||
el: '#bd-modals',
|
el: '#bd-modals',
|
||||||
components: { BdModals },
|
components: { BdModals },
|
||||||
template: '<BdModals/>'
|
template: '<BdModals />'
|
||||||
});
|
});
|
||||||
|
|
||||||
const vueInstance = new Vue({
|
this.vueInstance = new Vue({
|
||||||
el: '#bd-settings',
|
el: '#bd-settings',
|
||||||
components: { BdSettingsWrapper },
|
components: { BdSettingsWrapper },
|
||||||
template: '<BdSettingsWrapper/>'
|
template: '<BdSettingsWrapper />'
|
||||||
});
|
});
|
||||||
|
|
||||||
return vueInstance;
|
return this.vueInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Imports
|
// Imports
|
||||||
import { Events } from 'modules';
|
import { Events } from 'modules';
|
||||||
import { Modals } from 'ui';
|
import { Modals } from 'ui';
|
||||||
import { Modal } from '../common';
|
import { Modal } from './common';
|
||||||
import { MiError } from '../common/MaterialIcon';
|
import { MiError } from './common/MaterialIcon';
|
||||||
import ErrorModal from './modals/ErrorModal.vue';
|
import ErrorModal from './bd/modals/ErrorModal.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
|
@ -131,7 +131,7 @@
|
||||||
this.timeout = setTimeout(() => {
|
this.timeout = setTimeout(() => {
|
||||||
this.animating = false;
|
this.animating = false;
|
||||||
this.lastActiveIndex = -1;
|
this.lastActiveIndex = -1;
|
||||||
this.timeout = null;
|
this.timeout = null;
|
||||||
}, 400);
|
}, 400);
|
||||||
},
|
},
|
||||||
openGithub() {
|
openGithub() {
|
||||||
|
|
|
@ -21,16 +21,12 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
// Imports
|
// Imports
|
||||||
|
import { ClientLogger as Logger } from 'common';
|
||||||
import { shell } from 'electron';
|
import { shell } from 'electron';
|
||||||
import Card from './Card.vue';
|
import Card from './Card.vue';
|
||||||
import { Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension } from '../common';
|
import { Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension } from '../common';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
settingsOpen: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
props: ['plugin', 'togglePlugin', 'reloadPlugin', 'deletePlugin', 'showSettings'],
|
props: ['plugin', 'togglePlugin', 'reloadPlugin', 'deletePlugin', 'showSettings'],
|
||||||
components: {
|
components: {
|
||||||
Card, Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension
|
Card, Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension
|
||||||
|
@ -38,9 +34,9 @@
|
||||||
methods: {
|
methods: {
|
||||||
editPlugin() {
|
editPlugin() {
|
||||||
try {
|
try {
|
||||||
shell.openItem(this.plugin.pluginPath);
|
shell.openItem(this.plugin.contentPath);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
Logger.err('PluginCard', [`Error opening plugin directory ${this.plugin.contentPath}:`, err]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,17 +37,19 @@
|
||||||
// Imports
|
// Imports
|
||||||
import { PluginManager } from 'modules';
|
import { PluginManager } from 'modules';
|
||||||
import { Modals } from 'ui';
|
import { Modals } from 'ui';
|
||||||
import { SettingsWrapper } from './';
|
import { ClientLogger as Logger } from 'common';
|
||||||
import PluginCard from './PluginCard.vue';
|
|
||||||
import { MiRefresh } from '../common';
|
import { MiRefresh } from '../common';
|
||||||
|
import SettingsWrapper from './SettingsWrapper.vue';
|
||||||
|
import PluginCard from './PluginCard.vue';
|
||||||
import RefreshBtn from '../common/RefreshBtn.vue';
|
import RefreshBtn from '../common/RefreshBtn.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
PluginManager,
|
||||||
local: true,
|
local: true,
|
||||||
localPlugins: PluginManager.localPlugins
|
localPlugins: PluginManager.localPlugins
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
SettingsWrapper, PluginCard,
|
SettingsWrapper, PluginCard,
|
||||||
|
@ -62,32 +64,32 @@
|
||||||
this.local = false;
|
this.local = false;
|
||||||
},
|
},
|
||||||
async refreshLocal() {
|
async refreshLocal() {
|
||||||
await PluginManager.refreshPlugins();
|
await this.PluginManager.refreshPlugins();
|
||||||
},
|
},
|
||||||
async refreshOnline() {
|
async refreshOnline() {
|
||||||
|
// TODO
|
||||||
},
|
},
|
||||||
async togglePlugin(plugin) {
|
async togglePlugin(plugin) {
|
||||||
// TODO Display error if plugin fails to start/stop
|
// TODO: display error if plugin fails to start/stop
|
||||||
|
const enabled = plugin.enabled;
|
||||||
try {
|
try {
|
||||||
await plugin.enabled ? PluginManager.stopPlugin(plugin) : PluginManager.startPlugin(plugin);
|
await enabled ? this.PluginManager.stopPlugin(plugin) : this.PluginManager.startPlugin(plugin);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
Logger.err('PluginsView', [`Error ${enabled ? 'stopp' : 'start'}ing plugin ${plugin.name}:`, err]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async reloadPlugin(plugin) {
|
async reloadPlugin(plugin) {
|
||||||
try {
|
try {
|
||||||
await PluginManager.reloadPlugin(plugin);
|
await this.PluginManager.reloadPlugin(plugin);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
Logger.err('PluginsView', [`Error reloading plugin ${plugin.name}:`, err]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async deletePlugin(plugin, unload) {
|
async deletePlugin(plugin, unload) {
|
||||||
try {
|
try {
|
||||||
if (unload) await PluginManager.unloadPlugin(plugin);
|
await unload ? this.PluginManager.unloadPlugin(plugin) : this.PluginManager.deletePlugin(plugin);
|
||||||
else await PluginManager.deletePlugin(plugin);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
Logger.err('PluginsView', [`Error ${unload ? 'unload' : 'delet'}ing plugin ${plugin.name}:`, err]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showSettings(plugin, dont_clone) {
|
showSettings(plugin, dont_clone) {
|
||||||
|
|
|
@ -26,11 +26,6 @@
|
||||||
import { Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension } from '../common';
|
import { Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension } from '../common';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
settingsOpen: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
props: ['theme', 'toggleTheme', 'reloadTheme', 'deleteTheme', 'showSettings'],
|
props: ['theme', 'toggleTheme', 'reloadTheme', 'deleteTheme', 'showSettings'],
|
||||||
components: {
|
components: {
|
||||||
Card, Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension
|
Card, Button, ButtonGroup, SettingSwitch, MiSettings, MiRefresh, MiPencil, MiDelete, MiExtension
|
||||||
|
@ -40,7 +35,7 @@
|
||||||
try {
|
try {
|
||||||
shell.openItem(this.theme.themePath);
|
shell.openItem(this.theme.themePath);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
Logger.err('ThemeCard', [`Error opening theme directory ${this.theme.contentPath}:`, err]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,17 +37,19 @@
|
||||||
// Imports
|
// Imports
|
||||||
import { ThemeManager } from 'modules';
|
import { ThemeManager } from 'modules';
|
||||||
import { Modals } from 'ui';
|
import { Modals } from 'ui';
|
||||||
import { SettingsWrapper } from './';
|
import { ClientLogger as Logger } from 'common';
|
||||||
import { MiRefresh } from '../common';
|
import { MiRefresh } from '../common';
|
||||||
|
import SettingsWrapper from './SettingsWrapper.vue';
|
||||||
import ThemeCard from './ThemeCard.vue';
|
import ThemeCard from './ThemeCard.vue';
|
||||||
import RefreshBtn from '../common/RefreshBtn.vue';
|
import RefreshBtn from '../common/RefreshBtn.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
ThemeManager,
|
||||||
local: true,
|
local: true,
|
||||||
localThemes: ThemeManager.localThemes
|
localThemes: ThemeManager.localThemes
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
SettingsWrapper, ThemeCard,
|
SettingsWrapper, ThemeCard,
|
||||||
|
@ -62,33 +64,31 @@
|
||||||
this.local = false;
|
this.local = false;
|
||||||
},
|
},
|
||||||
async refreshLocal() {
|
async refreshLocal() {
|
||||||
await ThemeManager.refreshThemes();
|
await this.ThemeManager.refreshThemes();
|
||||||
},
|
},
|
||||||
async refreshOnline() {
|
async refreshOnline() {
|
||||||
|
// TODO
|
||||||
},
|
},
|
||||||
async toggleTheme(theme) {
|
async toggleTheme(theme) {
|
||||||
// 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 ? this.ThemeManager.disableTheme(theme) : this.ThemeManager.enableTheme(theme);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
Logger.err('ThemesView', [`Error ${enabled ? 'stopp' : 'start'}ing theme ${theme.name}:`, err]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async reloadTheme(theme, reload) {
|
async reloadTheme(theme, reload) {
|
||||||
try {
|
try {
|
||||||
if (reload) await ThemeManager.reloadTheme(theme);
|
await reload ? this.ThemeManager.reloadTheme(theme) : theme.recompile();
|
||||||
else await theme.recompile();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
Logger.err('ThemesView', [`Error ${reload ? 'reload' : 'recompil'}ing theme ${theme.name}:`, err]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async deleteTheme(theme, unload) {
|
async deleteTheme(theme, unload) {
|
||||||
try {
|
try {
|
||||||
if (unload) await ThemeManager.unloadTheme(theme);
|
await unload ? this.ThemeManager.unloadTheme(theme) : this.ThemeManager.deleteTheme(theme);
|
||||||
else await ThemeManager.deleteTheme(theme);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
Logger.err('ThemesView', [`Error ${unload ? 'unload' : 'delet'}ing theme ${theme.name}:`, err]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showSettings(theme, dont_clone) {
|
showSettings(theme, dont_clone) {
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { shell } from 'electron';
|
import { shell } from 'electron';
|
||||||
import { ClientIPC } from 'common';
|
import { ClientIPC, ClientLogger as Logger } from 'common';
|
||||||
import Combokeys from 'combokeys';
|
import Combokeys from 'combokeys';
|
||||||
import CombokeysRecord from 'combokeys/plugins/record';
|
import CombokeysRecord from 'combokeys/plugins/record';
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
this.active = false;
|
this.active = false;
|
||||||
this.recordingValue = undefined;
|
this.recordingValue = undefined;
|
||||||
this.setting.value = sequence.join(' ');
|
this.setting.value = sequence.join(' ');
|
||||||
console.log('keypress', sequence);
|
Logger.log('Keybind', ['Recorded sequence', sequence]);
|
||||||
},
|
},
|
||||||
getDisplayString(value) {
|
getDisplayString(value) {
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
export { default as BdSettingsWrapper } from './BdSettingsWrapper.vue';
|
export { default as BdSettingsWrapper } from './BdSettingsWrapper.vue';
|
||||||
export { default as BdSettings } from './BdSettings.vue';
|
export { default as BdSettings } from './BdSettings.vue';
|
||||||
|
export { default as BdModals } from './BdModals.vue';
|
||||||
|
|
|
@ -186,4 +186,5 @@ export default class DOM {
|
||||||
node.setAttribute(attribute.name, attribute.value);
|
node.setAttribute(attribute.name, attribute.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,7 +209,7 @@ export default class Modals {
|
||||||
ThemeManager._errors = [];
|
ThemeManager._errors = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return modal;
|
return modal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,9 @@ Vue.use(VTooltip, {
|
||||||
defaultContainer: 'bd-tooltips',
|
defaultContainer: 'bd-tooltips',
|
||||||
defaultClass: 'bd-tooltip',
|
defaultClass: 'bd-tooltip',
|
||||||
defaultTargetClass: 'bd-has-tooltip',
|
defaultTargetClass: 'bd-has-tooltip',
|
||||||
|
defaultArrowSelector: '.bd-tooltip-arrow',
|
||||||
defaultInnerSelector: '.bd-tooltip-inner',
|
defaultInnerSelector: '.bd-tooltip-inner',
|
||||||
defaultTemplate: '<div class="bd-tooltip"><span class="bd-tooltip-inner"></span></div>',
|
defaultTemplate: '<div class="bd-tooltip"><div class="bd-tooltip-arrow"></div><span class="bd-tooltip-inner"></span></div>',
|
||||||
defaultBoundariesElement: DOM.getElement('#app-mount')
|
defaultBoundariesElement: DOM.getElement('#app-mount')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -12,17 +12,14 @@ import Vue from './vue';
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
|
|
||||||
static inject(root, bdnode, components, template, replaceRoot) {
|
/**
|
||||||
if(!replaceRoot) bdnode.appendTo(root);
|
* Creates a new Vue object and mounts it in the passed element.
|
||||||
|
* @param {HTMLElement} root The element to mount the new Vue object at
|
||||||
return new Vue({
|
* @param {Object} options Options to pass to Vue
|
||||||
el: replaceRoot ? root : bdnode.element,
|
* @param {BdNode} bdnode The element to append to
|
||||||
components,
|
* @return {Vue}
|
||||||
template
|
*/
|
||||||
});
|
static inject(root, options, bdnode) {
|
||||||
}
|
|
||||||
|
|
||||||
static _inject(root, options, bdnode) {
|
|
||||||
if(bdnode) bdnode.appendTo(root);
|
if(bdnode) bdnode.appendTo(root);
|
||||||
|
|
||||||
const vue = new Vue(options);
|
const vue = new Vue(options);
|
||||||
|
|
|
@ -8,19 +8,13 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const
|
|
||||||
path = require('path'),
|
|
||||||
fs = require('fs'),
|
|
||||||
_ = require('lodash');
|
|
||||||
|
|
||||||
import { PatchedFunction, Patch } from './monkeypatch';
|
import { PatchedFunction, Patch } from './monkeypatch';
|
||||||
import { Vendor } from 'modules';
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import _ from 'lodash';
|
||||||
import filetype from 'file-type';
|
import filetype from 'file-type';
|
||||||
|
|
||||||
export class Utils {
|
export class Utils {
|
||||||
static isArrowFunction(fn) {
|
|
||||||
return !fn.toString().startsWith('function');
|
|
||||||
}
|
|
||||||
static overload(fn, cb) {
|
static overload(fn, cb) {
|
||||||
const orig = fn;
|
const orig = fn;
|
||||||
return function (...args) {
|
return function (...args) {
|
||||||
|
@ -31,6 +25,10 @@ export class Utils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Monkey-patches an object's method.
|
* Monkey-patches an object's method.
|
||||||
|
* @param {Object} object The object containing the function to monkey patch
|
||||||
|
* @param {String} methodName The name of the method to monkey patch
|
||||||
|
* @param {Object|String|Function} options Options to pass to the Patch constructor
|
||||||
|
* @param {Function} function If {options} is either "before" or "after", this function will be used as that hook
|
||||||
*/
|
*/
|
||||||
static monkeyPatch(object, methodName, options, f) {
|
static monkeyPatch(object, methodName, options, f) {
|
||||||
const patchedFunction = new PatchedFunction(object, methodName);
|
const patchedFunction = new PatchedFunction(object, methodName);
|
||||||
|
@ -41,12 +39,31 @@ export class Utils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Monkey-patches an object's method and returns a promise that will be resolved with the data object when the method is called.
|
* Monkey-patches an object's method and returns a promise that will be resolved with the data object when the method is called.
|
||||||
* You will have to call data.callOriginalMethod() if it wants the original method to be called.
|
* This can only be used to get the arguments and return data. If you want to change anything, call Utils.monkeyPatch with the once option set to true.
|
||||||
*/
|
*/
|
||||||
static monkeyPatchOnce(object, methodName) {
|
static monkeyPatchOnce(object, methodName) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.monkeyPatch(object, methodName, 'after', data => {
|
||||||
|
data.patch.cancel();
|
||||||
|
resolve(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monkey-patches an object's method and returns a promise that will be resolved with the data object when the method is called.
|
||||||
|
* You will have to call data.callOriginalMethod() if you wants the original method to be called.
|
||||||
|
*/
|
||||||
|
static monkeyPatchAsync(object, methodName, callback) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.monkeyPatch(object, methodName, data => {
|
this.monkeyPatch(object, methodName, data => {
|
||||||
data.patch.cancel();
|
data.patch.cancel();
|
||||||
|
|
||||||
|
data.promise = data.return = callback ? Promise.all(callback.call(global, data, ...data.arguments)) : new Promise((resolve, reject) => {
|
||||||
|
data.resolve = resolve;
|
||||||
|
data.reject = reject;
|
||||||
|
});
|
||||||
|
|
||||||
resolve(data);
|
resolve(data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -81,15 +98,20 @@ export class Utils {
|
||||||
};
|
};
|
||||||
|
|
||||||
const patch = this.monkeyPatch(what, methodName, {
|
const patch = this.monkeyPatch(what, methodName, {
|
||||||
before: before ? compatible_function(before) : undefined,
|
before: !instead && before ? compatible_function(before) : undefined,
|
||||||
instead: instead ? compatible_function(instead) : undefined,
|
instead: instead ? compatible_function(instead) : undefined,
|
||||||
after: after ? compatible_function(after) : undefined,
|
after: !instead && after ? compatible_function(after) : undefined,
|
||||||
once
|
once
|
||||||
});
|
});
|
||||||
|
|
||||||
return cancelPatch;
|
return cancelPatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to parse a string as JSON.
|
||||||
|
* @param {String} json The string to parse
|
||||||
|
* @return {Any}
|
||||||
|
*/
|
||||||
static async tryParseJson(jsonString) {
|
static async tryParseJson(jsonString) {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(jsonString);
|
return JSON.parse(jsonString);
|
||||||
|
@ -101,6 +123,11 @@ export class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new object with normalised keys.
|
||||||
|
* @param {Object} object
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
static toCamelCase(o) {
|
static toCamelCase(o) {
|
||||||
const camelCased = {};
|
const camelCased = {};
|
||||||
_.forEach(o, (value, key) => {
|
_.forEach(o, (value, key) => {
|
||||||
|
@ -112,17 +139,20 @@ export class Utils {
|
||||||
return camelCased;
|
return camelCased;
|
||||||
}
|
}
|
||||||
|
|
||||||
static compare(value1, value2) {
|
/**
|
||||||
|
* Checks if two or more values contain the same data.
|
||||||
|
* @param {Any} ...value The value to compare
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
|
static compare(value1, value2, ...values) {
|
||||||
// Check to see if value1 and value2 contain the same data
|
// Check to see if value1 and value2 contain the same data
|
||||||
if (typeof value1 !== typeof value2) return false;
|
if (typeof value1 !== typeof value2) return false;
|
||||||
if (value1 === null && value2 === null) return true;
|
if (value1 === null && value2 === null) return true;
|
||||||
if (value1 === null || value2 === null) return false;
|
if (value1 === null || value2 === null) return false;
|
||||||
|
|
||||||
if (typeof value1 === 'object' || typeof value1 === 'array') {
|
if (typeof value1 === 'object') {
|
||||||
// Loop through the object and check if everything's the same
|
// Loop through the object and check if everything's the same
|
||||||
let value1array = typeof value1 === 'array' ? value1 : Object.keys(value1);
|
if (Object.keys(value1).length !== Object.keys(value2).length) return false;
|
||||||
let value2array = typeof value2 === 'array' ? value2 : Object.keys(value2);
|
|
||||||
if (value1array.length !== value2array.length) return false;
|
|
||||||
|
|
||||||
for (let key in value1) {
|
for (let key in value1) {
|
||||||
if (!this.compare(value1[key], value2[key])) return false;
|
if (!this.compare(value1[key], value2[key])) return false;
|
||||||
|
@ -130,9 +160,20 @@ export class Utils {
|
||||||
} else if (value1 !== value2) return false;
|
} else if (value1 !== value2) return false;
|
||||||
|
|
||||||
// value1 and value2 contain the same data
|
// value1 and value2 contain the same data
|
||||||
|
// Check any more values
|
||||||
|
for (let value3 of values) {
|
||||||
|
if (!this.compare(value1, value3))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones an object and all it's properties.
|
||||||
|
* @param {Any} value The value to clone
|
||||||
|
* @return {Any} The cloned value
|
||||||
|
*/
|
||||||
static deepclone(value) {
|
static deepclone(value) {
|
||||||
if (typeof value === 'object') {
|
if (typeof value === 'object') {
|
||||||
if (value instanceof Array) return value.map(i => this.deepclone(i));
|
if (value instanceof Array) return value.map(i => this.deepclone(i));
|
||||||
|
@ -149,6 +190,11 @@ export class Utils {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Freezes an object and all it's properties.
|
||||||
|
* @param {Any} object The object to freeze
|
||||||
|
* @param {Function} exclude A function to filter object that shouldn't be frozen
|
||||||
|
*/
|
||||||
static deepfreeze(object, exclude) {
|
static deepfreeze(object, exclude) {
|
||||||
if (exclude && exclude(object)) return;
|
if (exclude && exclude(object)) return;
|
||||||
|
|
||||||
|
@ -165,38 +211,57 @@ export class Utils {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
static filterArray(array, filter) {
|
/**
|
||||||
const indexes = [];
|
* Removes an item from an array. This differs from Array.prototype.filter as it mutates the original array instead of creating a new one.
|
||||||
for (let index in array) {
|
* @param {Array} array The array to filter
|
||||||
if (!filter(array[index], index))
|
* @param {Any} item The item to remove from the array
|
||||||
indexes.push(index);
|
* @return {Array}
|
||||||
}
|
*/
|
||||||
|
|
||||||
for (let i in indexes)
|
|
||||||
array.splice(indexes[i] - i, 1);
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
static removeFromArray(array, item) {
|
static removeFromArray(array, item) {
|
||||||
let index;
|
let index;
|
||||||
while ((index = array.indexOf(item)) > -1)
|
while ((index = array.indexOf(item)) > -1)
|
||||||
array.splice(index, 1);
|
array.splice(index, 1);
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a property with a getter that can be changed like a normal property.
|
||||||
|
* @param {Object} object The object to define a property on
|
||||||
|
* @param {String} property The property to define
|
||||||
|
* @param {Function} getter The property's getter
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
static defineSoftGetter(object, property, get) {
|
||||||
|
return Object.defineProperty(object, property, {
|
||||||
|
get,
|
||||||
|
set: value => Object.defineProperty(object, property, {
|
||||||
|
value,
|
||||||
|
writable: true,
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true
|
||||||
|
}),
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FileUtils {
|
export class FileUtils {
|
||||||
|
/**
|
||||||
|
* Checks if a file exists and is a file.
|
||||||
|
* @param {String} path The file's path
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async fileExists(path) {
|
static async fileExists(path) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fs.stat(path, (err, stats) => {
|
fs.stat(path, (err, stats) => {
|
||||||
if (err) return reject({
|
if (err) return reject({
|
||||||
'message': `No such file or directory: ${err.path}`,
|
message: `No such file or directory: ${err.path}`,
|
||||||
err
|
err
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!stats.isFile()) return reject({
|
if (!stats.isFile()) return reject({
|
||||||
'message': `Not a file: ${path}`,
|
message: `Not a file: ${path}`,
|
||||||
stats
|
stats
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -205,16 +270,21 @@ export class FileUtils {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a directory exists and is a directory.
|
||||||
|
* @param {String} path The directory's path
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async directoryExists(path) {
|
static async directoryExists(path) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fs.stat(path, (err, stats) => {
|
fs.stat(path, (err, stats) => {
|
||||||
if (err) return reject({
|
if (err) return reject({
|
||||||
'message': `Directory does not exist: ${path}`,
|
message: `Directory does not exist: ${path}`,
|
||||||
err
|
err
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!stats.isDirectory()) return reject({
|
if (!stats.isDirectory()) return reject({
|
||||||
'message': `Not a directory: ${path}`,
|
message: `Not a directory: ${path}`,
|
||||||
stats
|
stats
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -223,18 +293,25 @@ export class FileUtils {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a directory.
|
||||||
|
* @param {String} path The directory's path
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async createDirectory(path) {
|
static async createDirectory(path) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fs.mkdir(path, err => {
|
fs.mkdir(path, err => {
|
||||||
if (err) {
|
if (err) reject(err);
|
||||||
if (err.code === 'EEXIST') return resolve();
|
else resolve();
|
||||||
else return reject(err);
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a directory exists and creates it if it doesn't.
|
||||||
|
* @param {String} path The directory's path
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async ensureDirectory(path) {
|
static async ensureDirectory(path) {
|
||||||
try {
|
try {
|
||||||
await this.directoryExists(path);
|
await this.directoryExists(path);
|
||||||
|
@ -249,17 +326,22 @@ export class FileUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the contents of a file.
|
||||||
|
* @param {String} path The file's path
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async readFile(path) {
|
static async readFile(path) {
|
||||||
try {
|
try {
|
||||||
await this.fileExists(path);
|
await this.fileExists(path);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw (err);
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fs.readFile(path, 'utf-8', (err, data) => {
|
fs.readFile(path, 'utf-8', (err, data) => {
|
||||||
if (err) reject({
|
if (err) return reject({
|
||||||
'message': `Could not read file: ${path}`,
|
message: `Could not read file: ${path}`,
|
||||||
err
|
err
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -268,24 +350,47 @@ export class FileUtils {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the contents of a file.
|
||||||
|
* @param {String} path The file's path
|
||||||
|
* @param {Object} options Additional options to pass to fs.readFile
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async readFileBuffer(path, options) {
|
static async readFileBuffer(path, options) {
|
||||||
|
try {
|
||||||
|
await this.fileExists(path);
|
||||||
|
} catch (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fs.readFile(path, options || {}, (err, data) => {
|
fs.readFile(path, options || {}, (err, data) => {
|
||||||
if (err) return reject(err);
|
if (err) reject(err);
|
||||||
resolve(data);
|
else resolve(data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes to a file.
|
||||||
|
* @param {String} path The file's path
|
||||||
|
* @param {String} data The file's new contents
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async writeFile(path, data) {
|
static async writeFile(path, data) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fs.writeFile(path, data, err => {
|
fs.writeFile(path, data, err => {
|
||||||
if (err) return reject(err);
|
if (err) reject(err);
|
||||||
resolve();
|
else resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the contents of a file parsed as JSON.
|
||||||
|
* @param {String} path The file's path
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async readJsonFromFile(path) {
|
static async readJsonFromFile(path) {
|
||||||
let readFile;
|
let readFile;
|
||||||
try {
|
try {
|
||||||
|
@ -295,41 +400,57 @@ export class FileUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const parsed = await Utils.tryParseJson(readFile);
|
return await Utils.tryParseJson(readFile);
|
||||||
return parsed;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw (Object.assign(err, { path }));
|
throw Object.assign(err, { path });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes to a file as JSON.
|
||||||
|
* @param {String} path The file's path
|
||||||
|
* @param {Any} data The file's new contents
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async writeJsonToFile(path, json) {
|
static async writeJsonToFile(path, json) {
|
||||||
return this.writeFile(path, JSON.stringify(json));
|
return this.writeFile(path, JSON.stringify(json));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of items in a directory.
|
||||||
|
* @param {String} path The directory's path
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async listDirectory(path) {
|
static async listDirectory(path) {
|
||||||
try {
|
await this.directoryExists(path);
|
||||||
await this.directoryExists(path);
|
return new Promise((resolve, reject) => {
|
||||||
return new Promise((resolve, reject) => {
|
fs.readdir(path, (err, files) => {
|
||||||
fs.readdir(path, (err, files) => {
|
if (err) reject(err);
|
||||||
if (err) return reject(err);
|
else resolve(files);
|
||||||
resolve(files);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} catch (err) {
|
});
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async readDir(path) {
|
static async readDir(path) {
|
||||||
return this.listDirectory(path);
|
return this.listDirectory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a file or buffer's MIME type and typical file extension.
|
||||||
|
* @param {String|Buffer} buffer A buffer or the path of a file
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async getFileType(buffer) {
|
static async getFileType(buffer) {
|
||||||
if (typeof buffer === 'string') buffer = await this.readFileBuffer(buffer);
|
if (typeof buffer === 'string') buffer = await this.readFileBuffer(buffer);
|
||||||
|
|
||||||
return filetype(buffer);
|
return filetype(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a file's contents as a data URI.
|
||||||
|
* @param {String} path The directory's path
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
static async toDataURI(buffer, type) {
|
static async toDataURI(buffer, type) {
|
||||||
if (typeof buffer === 'string') buffer = await this.readFileBuffer(buffer);
|
if (typeof buffer === 'string') buffer = await this.readFileBuffer(buffer);
|
||||||
if (!type) type = this.getFileType(buffer).mime;
|
if (!type) type = this.getFileType(buffer).mime;
|
||||||
|
|
Loading…
Reference in New Issue