2018-02-11 23:07:23 +01:00
|
|
|
/**
|
2018-03-21 00:24:31 +01:00
|
|
|
* BetterDiscord Plugin API
|
2018-02-11 23:07:23 +01:00
|
|
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
|
|
|
* All rights reserved.
|
|
|
|
* https://betterdiscord.net
|
|
|
|
*
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
*/
|
|
|
|
|
2018-03-31 17:51:14 +02:00
|
|
|
import { EmoteModule } from 'builtin';
|
|
|
|
import { SettingsSet, SettingsCategory, Setting, SettingsScheme } from 'structs';
|
2018-08-24 18:05:27 +02:00
|
|
|
import { BdMenu, Modals, DOM, DOMObserver, VueInjector, Toasts, Notifications, BdContextMenu, DiscordContextMenu } from 'ui';
|
2018-04-29 02:57:09 +02:00
|
|
|
import * as CommonComponents from 'commoncomponents';
|
2018-08-26 16:34:54 +02:00
|
|
|
import { default as Components } from '../ui/components/generic';
|
2018-04-27 18:33:05 +02:00
|
|
|
import { Utils, Filters, ClientLogger as Logger, ClientIPC, AsyncEventEmitter } from 'common';
|
2018-02-13 23:37:24 +01:00
|
|
|
import Settings from './settings';
|
2018-02-13 23:24:04 +01:00
|
|
|
import ExtModuleManager from './extmodulemanager';
|
2018-02-12 23:49:44 +01:00
|
|
|
import PluginManager from './pluginmanager';
|
|
|
|
import ThemeManager from './thememanager';
|
2018-02-12 00:04:07 +01:00
|
|
|
import Events from './events';
|
2018-03-09 00:43:26 +01:00
|
|
|
import EventsWrapper from './eventswrapper';
|
2018-08-24 18:05:27 +02:00
|
|
|
import Reflection from './reflection/index';
|
2018-03-14 13:19:46 +01:00
|
|
|
import DiscordApi from './discordapi';
|
2018-05-03 16:56:07 +02:00
|
|
|
import { ReactComponents, ReactHelpers } from './reactcomponents';
|
2018-03-21 21:52:42 +01:00
|
|
|
import { Patcher, MonkeyPatch } from './patcher';
|
2018-08-22 20:07:06 +02:00
|
|
|
import GlobalAc from '../ui/autocomplete';
|
2018-08-26 00:37:37 +02:00
|
|
|
import Vue from 'vue';
|
2018-08-26 02:48:23 +02:00
|
|
|
import path from 'path';
|
|
|
|
import Globals from './globals';
|
2018-03-02 20:42:17 +01:00
|
|
|
|
2018-02-11 23:07:23 +01:00
|
|
|
export default class PluginApi {
|
|
|
|
|
2018-03-21 00:24:31 +01:00
|
|
|
constructor(pluginInfo, pluginPath) {
|
2018-02-11 23:07:23 +01:00
|
|
|
this.pluginInfo = pluginInfo;
|
2018-03-21 00:24:31 +01:00
|
|
|
this.pluginPath = pluginPath;
|
|
|
|
|
2018-03-02 20:42:17 +01:00
|
|
|
this.Events = new EventsWrapper(Events);
|
2018-03-21 00:24:31 +01:00
|
|
|
Utils.defineSoftGetter(this.Events, 'bind', () => this.plugin);
|
|
|
|
|
2018-03-09 00:43:26 +01:00
|
|
|
this._menuItems = undefined;
|
|
|
|
this._injectedStyles = undefined;
|
|
|
|
this._modalStack = undefined;
|
2018-02-11 23:07:23 +01:00
|
|
|
}
|
2018-03-21 00:24:31 +01:00
|
|
|
|
2018-03-02 20:42:17 +01:00
|
|
|
get plugin() {
|
2018-03-21 00:24:31 +01:00
|
|
|
return PluginManager.getPluginByPath(this.pluginPath);
|
2018-03-02 20:42:17 +01:00
|
|
|
}
|
|
|
|
|
2018-03-06 22:58:09 +01:00
|
|
|
async bridge(plugin_id) {
|
|
|
|
const plugin = await PluginManager.waitForPlugin(plugin_id);
|
|
|
|
return plugin.bridge;
|
|
|
|
}
|
|
|
|
|
|
|
|
get require() { return this.import }
|
|
|
|
import(m) {
|
|
|
|
const module = ExtModuleManager.findModule(m);
|
|
|
|
if (module && module.__require) return module.__require;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
get Api() { return this }
|
|
|
|
|
2018-03-21 00:24:31 +01:00
|
|
|
get AsyncEventEmitter() { return AsyncEventEmitter }
|
|
|
|
get EventsWrapper() { return EventsWrapper }
|
|
|
|
|
2018-04-29 02:57:09 +02:00
|
|
|
get CommonComponents() { return CommonComponents }
|
2018-08-26 16:34:54 +02:00
|
|
|
get Components() { return Components }
|
2018-04-29 02:57:09 +02:00
|
|
|
get Filters() { return Filters }
|
|
|
|
get Discord() { return DiscordApi }
|
|
|
|
get DiscordApi() { return DiscordApi }
|
|
|
|
get ReactComponents() { return ReactComponents }
|
2018-05-03 16:56:07 +02:00
|
|
|
get ReactHelpers() { return ReactHelpers }
|
2018-04-29 02:57:09 +02:00
|
|
|
get Reflection() { return Reflection }
|
2018-05-14 17:33:24 +02:00
|
|
|
get DOM() { return DOM }
|
|
|
|
get VueInjector() { return VueInjector }
|
|
|
|
|
|
|
|
get observer() {
|
|
|
|
return this._observer || (this._observer = new DOMObserver());
|
|
|
|
}
|
2018-04-29 02:57:09 +02:00
|
|
|
|
2018-03-06 22:58:09 +01:00
|
|
|
/**
|
|
|
|
* Logger
|
|
|
|
*/
|
|
|
|
|
2018-02-11 23:07:23 +01:00
|
|
|
get Logger() {
|
|
|
|
return {
|
2018-04-02 00:12:23 +02:00
|
|
|
log: (...message) => Logger.log(this.plugin.name, message),
|
|
|
|
error: (...message) => Logger.err(this.plugin.name, message),
|
|
|
|
err: (...message) => Logger.err(this.plugin.name, message),
|
|
|
|
warn: (...message) => Logger.warn(this.plugin.name, message),
|
|
|
|
info: (...message) => Logger.info(this.plugin.name, message),
|
|
|
|
debug: (...message) => Logger.dbg(this.plugin.name, message),
|
|
|
|
dbg: (...message) => Logger.dbg(this.plugin.name, message)
|
2018-02-11 23:07:23 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-03-06 22:58:09 +01:00
|
|
|
/**
|
|
|
|
* Utils
|
|
|
|
*/
|
|
|
|
|
2018-03-02 20:42:17 +01:00
|
|
|
get Utils() {
|
|
|
|
return {
|
2018-04-02 00:12:23 +02:00
|
|
|
overload: (...args) => Utils.overload.apply(Utils, args),
|
|
|
|
tryParseJson: (...args) => Utils.tryParseJson.apply(Utils, args),
|
|
|
|
toCamelCase: (...args) => Utils.toCamelCase.apply(Utils, args),
|
|
|
|
compare: (...args) => Utils.compare.apply(Utils, args),
|
|
|
|
deepclone: (...args) => Utils.deepclone.apply(Utils, args),
|
|
|
|
deepfreeze: (...args) => Utils.deepfreeze.apply(Utils, args),
|
|
|
|
removeFromArray: (...args) => Utils.removeFromArray.apply(Utils, args),
|
|
|
|
defineSoftGetter: (...args) => Utils.defineSoftGetter.apply(Utils, args),
|
2018-04-04 22:53:02 +02:00
|
|
|
wait: (...args) => Utils.wait.apply(Utils, args),
|
2018-08-25 21:34:18 +02:00
|
|
|
until: (...args) => Utils.until.apply(Utils, args),
|
|
|
|
findInTree: (...args) => Utils.findInTree.apply(Utils, args),
|
|
|
|
findInReactTree: (...args) => Utils.findInReactTree.apply(Utils, args)
|
2018-03-02 20:42:17 +01:00
|
|
|
};
|
2018-02-12 00:04:07 +01:00
|
|
|
}
|
2018-02-11 23:07:23 +01:00
|
|
|
|
2018-03-06 22:58:09 +01:00
|
|
|
/**
|
|
|
|
* Settings
|
|
|
|
*/
|
|
|
|
|
2018-03-04 21:21:18 +01:00
|
|
|
createSettingsSet(args, ...merge) {
|
2018-03-06 22:58:09 +01:00
|
|
|
return new SettingsSet(args || {}, ...merge);
|
2018-03-04 21:21:18 +01:00
|
|
|
}
|
|
|
|
createSettingsCategory(args, ...merge) {
|
|
|
|
return new SettingsCategory(args, ...merge);
|
|
|
|
}
|
|
|
|
createSetting(args, ...merge) {
|
|
|
|
return new Setting(args, ...merge);
|
|
|
|
}
|
|
|
|
createSettingsScheme(args) {
|
|
|
|
return new SettingsScheme(args);
|
|
|
|
}
|
|
|
|
get Settings() {
|
|
|
|
return {
|
2018-03-06 02:15:11 +01:00
|
|
|
createSet: this.createSettingsSet.bind(this),
|
2018-03-04 21:21:18 +01:00
|
|
|
createCategory: this.createSettingsCategory.bind(this),
|
|
|
|
createSetting: this.createSetting.bind(this),
|
|
|
|
createScheme: this.createSettingsScheme.bind(this)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-03-06 22:58:09 +01:00
|
|
|
/**
|
|
|
|
* InternalSettings
|
|
|
|
*/
|
|
|
|
|
2018-03-02 20:42:17 +01:00
|
|
|
getInternalSetting(set, category, setting) {
|
|
|
|
return Settings.get(set, category, setting);
|
2018-02-12 00:04:07 +01:00
|
|
|
}
|
2018-03-02 20:42:17 +01:00
|
|
|
get InternalSettings() {
|
2018-02-11 23:07:23 +01:00
|
|
|
return {
|
2018-03-02 20:42:17 +01:00
|
|
|
get: this.getInternalSetting.bind(this)
|
|
|
|
};
|
2018-02-11 23:07:23 +01:00
|
|
|
}
|
2018-02-12 23:49:44 +01:00
|
|
|
|
2018-03-07 21:32:04 +01:00
|
|
|
/**
|
|
|
|
* BdMenu
|
|
|
|
*/
|
|
|
|
|
|
|
|
get BdMenu() {
|
|
|
|
return {
|
2018-03-31 02:03:13 +02:00
|
|
|
open: BdMenu.open.bind(BdMenu),
|
|
|
|
close: BdMenu.close.bind(BdMenu),
|
|
|
|
items: this.BdMenuItems,
|
2018-03-07 21:32:04 +01:00
|
|
|
BdMenuItems: this.BdMenuItems
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* BdMenuItems
|
|
|
|
*/
|
|
|
|
|
|
|
|
get menuItems() {
|
|
|
|
return this._menuItems || (this._menuItems = []);
|
|
|
|
}
|
|
|
|
addMenuItem(item) {
|
2018-03-31 02:03:13 +02:00
|
|
|
return BdMenu.items.add(item);
|
2018-03-07 21:32:04 +01:00
|
|
|
}
|
|
|
|
addMenuSettingsSet(category, set, text) {
|
2018-03-31 02:03:13 +02:00
|
|
|
const item = BdMenu.items.addSettingsSet(category, set, text);
|
2018-03-07 21:32:04 +01:00
|
|
|
return this.menuItems.push(item);
|
|
|
|
}
|
|
|
|
addMenuVueComponent(category, text, component) {
|
2018-03-31 02:03:13 +02:00
|
|
|
const item = BdMenu.items.addVueComponent(category, text, component);
|
2018-03-07 21:32:04 +01:00
|
|
|
return this.menuItems.push(item);
|
|
|
|
}
|
|
|
|
removeMenuItem(item) {
|
2018-03-31 02:03:13 +02:00
|
|
|
BdMenu.items.remove(item);
|
2018-03-07 21:32:04 +01:00
|
|
|
Utils.removeFromArray(this.menuItems, item);
|
|
|
|
}
|
|
|
|
removeAllMenuItems() {
|
2018-08-15 08:01:47 +02:00
|
|
|
for (const item of this.menuItems)
|
2018-03-31 02:03:13 +02:00
|
|
|
BdMenu.items.remove(item);
|
2018-03-07 21:32:04 +01:00
|
|
|
}
|
|
|
|
get BdMenuItems() {
|
|
|
|
return Object.defineProperty({
|
|
|
|
add: this.addMenuItem.bind(this),
|
|
|
|
addSettingsSet: this.addMenuSettingsSet.bind(this),
|
|
|
|
addVueComponent: this.addMenuVueComponent.bind(this),
|
|
|
|
remove: this.removeMenuItem.bind(this),
|
|
|
|
removeAll: this.removeAllMenuItems.bind(this)
|
|
|
|
}, 'items', {
|
|
|
|
get: () => this.menuItems
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-08-22 13:55:30 +02:00
|
|
|
/**
|
|
|
|
* BdContextMenu
|
|
|
|
*/
|
|
|
|
|
|
|
|
showContextMenu(event, groups) {
|
|
|
|
BdContextMenu.show(event, groups);
|
|
|
|
this.activeMenu.menu = BdContextMenu.activeMenu.menu;
|
|
|
|
}
|
|
|
|
get activeMenu() {
|
|
|
|
return this._activeMenu || (this._activeMenu = { menu: null });
|
|
|
|
}
|
|
|
|
get BdContextMenu() {
|
|
|
|
return Object.defineProperty({
|
|
|
|
show: this.showContextMenu.bind(this)
|
|
|
|
}, 'activeMenu', {
|
|
|
|
get: () => this.activeMenu
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-03-06 22:58:09 +01:00
|
|
|
/**
|
|
|
|
* CssUtils
|
|
|
|
*/
|
|
|
|
|
2018-03-02 20:42:17 +01:00
|
|
|
get injectedStyles() {
|
|
|
|
return this._injectedStyles || (this._injectedStyles = []);
|
|
|
|
}
|
|
|
|
compileSass(scss, options) {
|
|
|
|
return ClientIPC.send('bd-compileSass', Object.assign({ data: scss }, options));
|
|
|
|
}
|
|
|
|
getConfigAsSCSS(settingsset) {
|
|
|
|
return ThemeManager.getConfigAsSCSS(settingsset ? settingsset : this.plugin.settings);
|
|
|
|
}
|
2018-03-04 00:36:17 +01:00
|
|
|
getConfigAsSCSSMap(settingsset) {
|
|
|
|
return ThemeManager.getConfigAsSCSSMap(settingsset ? settingsset : this.plugin.settings);
|
|
|
|
}
|
2018-03-02 20:42:17 +01:00
|
|
|
injectStyle(id, css) {
|
|
|
|
if (id && !css) css = id, id = undefined;
|
|
|
|
this.deleteStyle(id);
|
2018-03-09 02:26:45 +01:00
|
|
|
const styleid = `plugin-${this.plugin.id}-${id}`;
|
|
|
|
this.injectedStyles.push(id);
|
2018-03-02 20:42:17 +01:00
|
|
|
DOM.injectStyle(css, styleid);
|
|
|
|
}
|
|
|
|
async injectSass(id, scss, options) {
|
|
|
|
// In most cases a plugin's styles should be precompiled instead of using this
|
|
|
|
if (id && !scss && !options) scss = id, id = undefined;
|
2018-03-03 02:43:54 +01:00
|
|
|
const css = (await this.compileSass(scss, options)).css.toString();
|
2018-03-02 20:42:17 +01:00
|
|
|
this.injectStyle(id, css, options);
|
|
|
|
}
|
|
|
|
deleteStyle(id) {
|
2018-03-09 02:26:45 +01:00
|
|
|
const styleid = `plugin-${this.plugin.id}-${id}`;
|
2018-03-02 20:42:17 +01:00
|
|
|
this.injectedStyles.splice(this.injectedStyles.indexOf(styleid), 1);
|
|
|
|
DOM.deleteStyle(styleid);
|
|
|
|
}
|
2018-07-18 21:57:05 +02:00
|
|
|
deleteAllStyles(id) {
|
2018-08-15 08:01:47 +02:00
|
|
|
for (const id of this.injectedStyles) {
|
2018-03-02 20:42:17 +01:00
|
|
|
this.deleteStyle(id);
|
|
|
|
}
|
2018-02-13 23:37:24 +01:00
|
|
|
}
|
2018-03-02 20:42:17 +01:00
|
|
|
get CssUtils() {
|
2018-02-13 23:37:24 +01:00
|
|
|
return {
|
2018-03-02 20:42:17 +01:00
|
|
|
compileSass: this.compileSass.bind(this),
|
|
|
|
getConfigAsSCSS: this.getConfigAsSCSS.bind(this),
|
2018-03-04 00:36:17 +01:00
|
|
|
getConfigAsSCSSMap: this.getConfigAsSCSSMap.bind(this),
|
2018-03-02 20:42:17 +01:00
|
|
|
injectStyle: this.injectStyle.bind(this),
|
|
|
|
injectSass: this.injectSass.bind(this),
|
|
|
|
deleteStyle: this.deleteStyle.bind(this),
|
|
|
|
deleteAllStyles: this.deleteAllStyles.bind(this)
|
2018-02-13 23:37:24 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-03-06 22:58:09 +01:00
|
|
|
/**
|
|
|
|
* Modals
|
|
|
|
*/
|
|
|
|
|
2018-03-02 21:19:59 +01:00
|
|
|
get modalStack() {
|
|
|
|
return this._modalStack || (this._modalStack = []);
|
|
|
|
}
|
2018-03-02 21:48:29 +01:00
|
|
|
addModal(_modal, component) {
|
|
|
|
const modal = Modals.add(_modal, component);
|
2018-08-22 18:44:30 +02:00
|
|
|
modal.on('close', () => Utils.removeFromArray(this.modalStack, modal));
|
2018-03-02 21:48:29 +01:00
|
|
|
this.modalStack.push(modal);
|
|
|
|
return modal;
|
2018-03-02 21:19:59 +01:00
|
|
|
}
|
2018-03-07 02:10:06 +01:00
|
|
|
closeModal(modal, force) {
|
|
|
|
return Modals.close(modal, force);
|
2018-03-02 21:19:59 +01:00
|
|
|
}
|
2018-03-07 02:10:06 +01:00
|
|
|
closeAllModals(force) {
|
|
|
|
const promises = [];
|
2018-08-15 08:01:47 +02:00
|
|
|
for (const modal of this.modalStack)
|
2018-03-07 02:10:06 +01:00
|
|
|
promises.push(modal.close(force));
|
|
|
|
return Promise.all(promises);
|
2018-03-02 21:19:59 +01:00
|
|
|
}
|
2018-03-07 02:10:06 +01:00
|
|
|
closeLastModal(force) {
|
2018-03-02 21:19:59 +01:00
|
|
|
if (!this.modalStack.length) return;
|
2018-03-07 02:10:06 +01:00
|
|
|
return this.modalStack[this.modalStack.length - 1].close(force);
|
|
|
|
}
|
|
|
|
basicModal(title, text) {
|
2018-07-19 01:13:57 +02:00
|
|
|
return this.addModal(Modals.createBasicModal(title, text));
|
2018-03-02 21:19:59 +01:00
|
|
|
}
|
2018-03-02 21:48:29 +01:00
|
|
|
settingsModal(settingsset, headertext, options) {
|
2018-07-19 01:13:57 +02:00
|
|
|
return this.addModal(Modals.createSettingsModal(settingsset, headertext, options));
|
2018-03-02 21:48:29 +01:00
|
|
|
}
|
2018-03-02 21:19:59 +01:00
|
|
|
get Modals() {
|
2018-03-09 00:43:26 +01:00
|
|
|
return Object.defineProperties({
|
2018-03-02 21:19:59 +01:00
|
|
|
add: this.addModal.bind(this),
|
|
|
|
close: this.closeModal.bind(this),
|
|
|
|
closeAll: this.closeAllModals.bind(this),
|
2018-03-02 21:48:29 +01:00
|
|
|
closeLast: this.closeLastModal.bind(this),
|
2018-03-08 14:59:19 +01:00
|
|
|
basic: this.basicModal.bind(this),
|
2018-03-02 21:48:29 +01:00
|
|
|
settings: this.settingsModal.bind(this)
|
2018-03-09 00:43:26 +01:00
|
|
|
}, {
|
|
|
|
stack: {
|
|
|
|
get: () => this.modalStack
|
|
|
|
},
|
|
|
|
baseComponent: {
|
2018-08-22 20:42:22 +02:00
|
|
|
get: () => Modals.baseComponent
|
2018-03-09 00:43:26 +01:00
|
|
|
}
|
2018-03-31 17:51:14 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-07-19 23:21:20 +02:00
|
|
|
/**
|
2018-05-13 05:17:04 +02:00
|
|
|
* Toasts
|
|
|
|
*/
|
2018-08-22 20:42:22 +02:00
|
|
|
|
2018-05-13 05:17:04 +02:00
|
|
|
showToast(message, options = {}) {
|
|
|
|
return Toasts.push(message, options);
|
|
|
|
}
|
|
|
|
showSuccessToast(message, options = {}) {
|
|
|
|
return Toasts.success(message, options);
|
|
|
|
}
|
|
|
|
showInfoToast(message, options = {}) {
|
|
|
|
return Toasts.info(message, options);
|
|
|
|
}
|
|
|
|
showErrorToast(message, options = {}) {
|
|
|
|
return Toasts.error(message, options);
|
|
|
|
}
|
|
|
|
showWarningToast(message, options = {}) {
|
|
|
|
return Toasts.warning(message, options);
|
|
|
|
}
|
2018-07-19 23:21:20 +02:00
|
|
|
get Toasts() {
|
|
|
|
return {
|
|
|
|
push: this.showToast.bind(this),
|
|
|
|
success: this.showSuccessToast.bind(this),
|
|
|
|
error: this.showErrorToast.bind(this),
|
|
|
|
info: this.showInfoToast.bind(this),
|
2018-08-10 16:17:57 +02:00
|
|
|
warning: this.showWarningToast.bind(this),
|
|
|
|
get enabled() { return Toasts.enabled }
|
2018-07-19 23:21:20 +02:00
|
|
|
};
|
|
|
|
}
|
2018-07-19 23:03:29 +02:00
|
|
|
|
2018-08-22 20:42:22 +02:00
|
|
|
/**
|
|
|
|
* Notifications
|
|
|
|
*/
|
|
|
|
|
|
|
|
get notificationStack() {
|
|
|
|
return this._notificationStack || (this._notificationStack = []);
|
|
|
|
}
|
2018-08-23 04:16:18 +02:00
|
|
|
addNotification(title, text, buttons = []) {
|
|
|
|
if (arguments.length <= 1) text = title, title = undefined;
|
|
|
|
if (arguments[1] instanceof Array) [text, buttons] = arguments, title = undefined;
|
|
|
|
|
|
|
|
const notification = Notifications.add(title, text, buttons, () => Utils.removeFromArray(this.notificationStack, notification));
|
2018-08-22 20:42:22 +02:00
|
|
|
this.notificationStack.push(notification);
|
|
|
|
return notification;
|
|
|
|
}
|
|
|
|
dismissNotification(index) {
|
|
|
|
index = Notifications.stack.indexOf(this.notificationStack[index]);
|
|
|
|
if (index) Notifications.dismiss(index);
|
|
|
|
}
|
2018-08-23 04:16:18 +02:00
|
|
|
dismissAllNotifications() {
|
2018-08-23 05:02:01 +02:00
|
|
|
for (const index in this.notificationStack) {
|
2018-08-22 20:42:22 +02:00
|
|
|
this.dismissNotification(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
get Notifications() {
|
|
|
|
return Object.defineProperty({
|
|
|
|
add: this.addNotification.bind(this),
|
2018-08-23 04:16:18 +02:00
|
|
|
dismiss: this.dismissNotification.bind(this),
|
|
|
|
dismissAll: this.dismissAllNotifications.bind(this)
|
2018-08-22 20:42:22 +02:00
|
|
|
}, 'stack', {
|
|
|
|
get: () => this.notificationStack
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-08-22 20:07:06 +02:00
|
|
|
/**
|
|
|
|
* Autocomplete
|
|
|
|
*/
|
|
|
|
|
|
|
|
get autocompleteSets() {
|
|
|
|
return this._autocompleteSets || (this._autocompleteSets = new Map());
|
|
|
|
}
|
|
|
|
addAutocompleteController(prefix, controller) {
|
|
|
|
if (!controller) controller = this.plugin;
|
|
|
|
if (GlobalAc.validPrefix(prefix)) return;
|
|
|
|
GlobalAc.add(prefix, controller);
|
|
|
|
this.autocompleteSets.set(prefix, controller);
|
|
|
|
}
|
|
|
|
removeAutocompleteController(prefix) {
|
|
|
|
if (this.autocompleteSets.get(prefix) !== GlobalAc.sets.get(prefix)) return;
|
|
|
|
GlobalAc.remove(prefix);
|
|
|
|
this.autocompleteSets.delete(prefix);
|
|
|
|
}
|
|
|
|
removeAllAutocompleteControllers() {
|
2018-08-23 05:02:01 +02:00
|
|
|
for (const [prefix] of this.autocompleteSets) {
|
2018-08-22 20:07:06 +02:00
|
|
|
this.removeAutocompleteController(prefix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
validAutocompletePrefix(prefix) {
|
|
|
|
return GlobalAc.validPrefix(prefix);
|
|
|
|
}
|
2018-08-23 17:36:22 +02:00
|
|
|
toggleAutocompleteMode(prefix, sterm) {
|
|
|
|
return GlobalAc.toggle(prefix, sterm);
|
|
|
|
}
|
|
|
|
searchAutocomplete(prefix, sterm) {
|
|
|
|
return GlobalAc.items(prefix, sterm);
|
|
|
|
}
|
2018-08-22 20:07:06 +02:00
|
|
|
get Autocomplete() {
|
|
|
|
return Object.defineProperty({
|
|
|
|
add: this.addAutocompleteController.bind(this),
|
|
|
|
remove: this.removeAutocompleteController.bind(this),
|
|
|
|
removeAll: this.removeAllAutocompleteControllers.bind(this),
|
2018-08-23 17:36:22 +02:00
|
|
|
validPrefix: this.validAutocompletePrefix.bind(this),
|
|
|
|
toggle: this.toggleAutocompleteMode.bind(this),
|
|
|
|
search: this.searchAutocomplete.bind(this)
|
2018-08-22 20:07:06 +02:00
|
|
|
}, 'sets', {
|
|
|
|
get: () => this.autocompleteSets
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-03-31 17:51:14 +02:00
|
|
|
/**
|
|
|
|
* Emotes
|
|
|
|
*/
|
|
|
|
|
|
|
|
get emotes() {
|
2018-08-23 00:44:46 +02:00
|
|
|
return EmoteModule.database;
|
2018-03-31 17:51:14 +02:00
|
|
|
}
|
2018-08-23 00:44:46 +02:00
|
|
|
get favouriteEmotes() {
|
|
|
|
return EmoteModule.favourites;
|
|
|
|
}
|
|
|
|
get mostUsedEmotes() {
|
|
|
|
return EmoteModule.mostUsed;
|
2018-03-31 17:51:14 +02:00
|
|
|
}
|
|
|
|
setFavouriteEmote(emote, favourite) {
|
2018-08-23 00:44:46 +02:00
|
|
|
return EmoteModule[favourite ? 'removeFavourite' : 'addFavourite'](emote);
|
2018-03-31 17:51:14 +02:00
|
|
|
}
|
|
|
|
addFavouriteEmote(emote) {
|
|
|
|
return EmoteModule.addFavourite(emote);
|
|
|
|
}
|
|
|
|
removeFavouriteEmote(emote) {
|
2018-08-23 00:44:46 +02:00
|
|
|
return EmoteModule.removeFavourite(emote);
|
2018-03-31 17:51:14 +02:00
|
|
|
}
|
|
|
|
isFavouriteEmote(emote) {
|
|
|
|
return EmoteModule.isFavourite(emote);
|
|
|
|
}
|
|
|
|
getEmote(emote) {
|
2018-08-23 00:44:46 +02:00
|
|
|
return EmoteModule.findByName(emote, true);
|
|
|
|
}
|
|
|
|
getEmoteUseCount(emote) {
|
|
|
|
const mostUsed = EmoteModule.mostUsed.find(mu => mu.key === emote.name);
|
|
|
|
return mostUsed ? mostUsed.useCount : 0;
|
2018-03-31 17:51:14 +02:00
|
|
|
}
|
2018-08-23 00:44:46 +02:00
|
|
|
incrementEmoteUseCount(emote) {
|
|
|
|
return EmoteModule.addToMostUsed(emote);
|
|
|
|
}
|
|
|
|
searchEmotes(regex, limit) {
|
|
|
|
return EmoteModule.search(regex, limit);
|
2018-03-31 17:51:14 +02:00
|
|
|
}
|
|
|
|
get Emotes() {
|
|
|
|
return Object.defineProperties({
|
|
|
|
setFavourite: this.setFavouriteEmote.bind(this),
|
|
|
|
addFavourite: this.addFavouriteEmote.bind(this),
|
|
|
|
removeFavourite: this.removeFavouriteEmote.bind(this),
|
|
|
|
isFavourite: this.isFavouriteEmote.bind(this),
|
|
|
|
getEmote: this.getEmote.bind(this),
|
2018-08-23 00:44:46 +02:00
|
|
|
getUseCount: this.getEmoteUseCount.bind(this),
|
|
|
|
incrementUseCount: this.incrementEmoteUseCount.bind(this),
|
|
|
|
search: this.searchEmotes.bind(this)
|
2018-03-31 17:51:14 +02:00
|
|
|
}, {
|
|
|
|
emotes: {
|
|
|
|
get: () => this.emotes
|
|
|
|
},
|
2018-08-23 00:44:46 +02:00
|
|
|
favourites: {
|
|
|
|
get: () => this.favouriteEmotes
|
|
|
|
},
|
|
|
|
mostused: {
|
|
|
|
get: () => this.mostUsedEmotes
|
2018-03-31 17:51:14 +02:00
|
|
|
}
|
2018-03-02 21:48:29 +01:00
|
|
|
});
|
2018-03-02 21:19:59 +01:00
|
|
|
}
|
|
|
|
|
2018-03-06 22:58:09 +01:00
|
|
|
/**
|
|
|
|
* Plugins
|
|
|
|
*/
|
|
|
|
|
2018-02-12 23:49:44 +01:00
|
|
|
async getPlugin(plugin_id) {
|
|
|
|
// This should require extra permissions
|
2018-08-15 08:01:47 +02:00
|
|
|
return PluginManager.waitForPlugin(plugin_id);
|
2018-02-12 23:49:44 +01:00
|
|
|
}
|
2018-03-06 22:58:09 +01:00
|
|
|
listPlugins() {
|
2018-02-12 23:49:44 +01:00
|
|
|
return PluginManager.localContent.map(plugin => plugin.id);
|
|
|
|
}
|
|
|
|
get Plugins() {
|
|
|
|
return {
|
|
|
|
getPlugin: this.getPlugin.bind(this),
|
2018-03-02 20:42:17 +01:00
|
|
|
listPlugins: this.listPlugins.bind(this)
|
2018-02-12 23:49:44 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-03-06 22:58:09 +01:00
|
|
|
/**
|
|
|
|
* Themes
|
|
|
|
*/
|
|
|
|
|
2018-02-12 23:49:44 +01:00
|
|
|
async getTheme(theme_id) {
|
|
|
|
// This should require extra permissions
|
2018-08-15 08:01:47 +02:00
|
|
|
return ThemeManager.waitForContent(theme_id);
|
2018-02-12 23:49:44 +01:00
|
|
|
}
|
2018-03-06 22:58:09 +01:00
|
|
|
listThemes() {
|
2018-02-12 23:49:44 +01:00
|
|
|
return ThemeManager.localContent.map(theme => theme.id);
|
|
|
|
}
|
|
|
|
get Themes() {
|
|
|
|
return {
|
|
|
|
getTheme: this.getTheme.bind(this),
|
2018-03-06 22:58:09 +01:00
|
|
|
listThemes: this.listThemes.bind(this)
|
2018-02-12 23:49:44 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-03-07 03:07:17 +01:00
|
|
|
/**
|
|
|
|
* ExtModules
|
|
|
|
*/
|
|
|
|
|
|
|
|
async getModule(module_id) {
|
|
|
|
// This should require extra permissions
|
2018-08-15 08:01:47 +02:00
|
|
|
return ExtModuleManager.waitForContent(module_id);
|
2018-03-07 03:07:17 +01:00
|
|
|
}
|
|
|
|
listModules() {
|
|
|
|
return ExtModuleManager.localContent.map(module => module.id);
|
|
|
|
}
|
|
|
|
get ExtModules() {
|
|
|
|
return {
|
|
|
|
getModule: this.getModule.bind(this),
|
|
|
|
listModules: this.listModules.bind(this)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-03-21 21:48:36 +01:00
|
|
|
/**
|
|
|
|
* Patcher
|
|
|
|
*/
|
|
|
|
|
|
|
|
get patches() {
|
|
|
|
return Patcher.getPatchesByCaller(this.plugin.id);
|
|
|
|
}
|
|
|
|
patchBefore(...args) { return this.pushChildPatch(...args, 'before') }
|
|
|
|
patchAfter(...args) { return this.pushChildPatch(...args, 'after') }
|
|
|
|
patchInstead(...args) { return this.pushChildPatch(...args, 'instead') }
|
|
|
|
pushChildPatch(...args) {
|
|
|
|
return Patcher.pushChildPatch(this.plugin.id, ...args);
|
|
|
|
}
|
|
|
|
unpatchAll(patches) {
|
|
|
|
return Patcher.unpatchAll(patches || this.plugin.id);
|
|
|
|
}
|
|
|
|
get Patcher() {
|
|
|
|
return Object.defineProperty({
|
|
|
|
before: this.patchBefore.bind(this),
|
|
|
|
after: this.patchAfter.bind(this),
|
|
|
|
instead: this.patchInstead.bind(this),
|
|
|
|
pushChildPatch: this.pushChildPatch.bind(this),
|
|
|
|
unpatchAll: this.unpatchAll.bind(this),
|
2018-03-29 21:04:01 +02:00
|
|
|
monkeyPatch: this.monkeyPatch.bind(this)
|
2018-03-21 21:48:36 +01:00
|
|
|
}, 'patches', {
|
|
|
|
get: () => this.patches
|
|
|
|
});
|
|
|
|
}
|
2018-04-02 00:02:02 +02:00
|
|
|
get monkeyPatch() {
|
|
|
|
return m => MonkeyPatch(this.plugin.id, m);
|
2018-03-21 00:24:31 +01:00
|
|
|
}
|
|
|
|
|
2018-08-22 14:19:15 +02:00
|
|
|
/**
|
|
|
|
* DiscordContextMenu
|
|
|
|
*/
|
|
|
|
|
|
|
|
get discordContextMenus() {
|
|
|
|
return this._discordContextMenus || (this._discordContextMenus = []);
|
|
|
|
}
|
|
|
|
addDiscordContextMenu(items, filter) {
|
|
|
|
const menu = DiscordContextMenu.add(items, filter);
|
|
|
|
this.discordContextMenus.push(menu);
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
removeDiscordContextMenu(menu) {
|
|
|
|
DiscordContextMenu.remove(menu);
|
|
|
|
Utils.removeFromArray(this.discordContextMenus, menu);
|
|
|
|
}
|
|
|
|
removeAllDiscordContextMenus() {
|
2018-08-23 05:02:01 +02:00
|
|
|
for (const menu of this.discordContextMenus) {
|
2018-08-22 14:19:15 +02:00
|
|
|
this.removeDiscordContextMenu(menu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
get DiscordContextMenu() {
|
|
|
|
return Object.defineProperty({
|
|
|
|
add: this.addDiscordContextMenu.bind(this),
|
|
|
|
remove: this.removeDiscordContextMenu.bind(this),
|
|
|
|
removeAll: this.removeAllDiscordContextMenus.bind(this)
|
|
|
|
}, 'menus', {
|
|
|
|
get: () => this.discordContextMenus
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-08-26 02:48:23 +02:00
|
|
|
Vuewrap(id, component, props) {
|
|
|
|
return VueInjector.createReactElement(Vue.component(id, component), props);
|
2018-08-26 00:37:37 +02:00
|
|
|
}
|
|
|
|
|
2018-02-11 23:07:23 +01:00
|
|
|
}
|
2018-03-09 00:43:26 +01:00
|
|
|
|
|
|
|
// Stop plugins from modifying the plugin API for all plugins
|
|
|
|
// Plugins can still modify their own plugin API object
|
|
|
|
Object.freeze(PluginApi);
|
|
|
|
Object.freeze(PluginApi.prototype);
|