· 6 years ago · Mar 21, 2020, 01:54 AM
1//META{"name":"ZeresPluginLibrary","displayName":"ZeresPluginLibrary","website":"https://github.com/rauenzi/BDPluginLibrary","source":"https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js"}*//
2
3/*@cc_on
4@if (@_jscript)
5
6 // Offer to self-install for clueless users that try to run this directly.
7 var shell = WScript.CreateObject("WScript.Shell");
8 var fs = new ActiveXObject("Scripting.FileSystemObject");
9 var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\BetterDiscord\plugins");
10 var pathSelf = WScript.ScriptFullName;
11 // Put the user at ease by addressing them in the first person
12 shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30);
13 if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
14 shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40);
15 } else if (!fs.FolderExists(pathPlugins)) {
16 shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10);
17 } else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) {
18 fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true);
19 // Show the user where to put plugins in the future
20 shell.Exec("explorer " + pathPlugins);
21 shell.Popup("I'm installed!", 0, "Successfully installed", 0x40);
22 }
23 WScript.Quit();
24
25@else@*/
26var ZeresPluginLibrary =
27/******/ (function(modules) { // webpackBootstrap
28/******/ // The module cache
29/******/ var installedModules = {};
30/******/
31/******/ // The require function
32/******/ function __webpack_require__(moduleId) {
33/******/
34/******/ // Check if module is in cache
35/******/ if(installedModules[moduleId]) {
36/******/ return installedModules[moduleId].exports;
37/******/ }
38/******/ // Create a new module (and put it into the cache)
39/******/ var module = installedModules[moduleId] = {
40/******/ i: moduleId,
41/******/ l: false,
42/******/ exports: {}
43/******/ };
44/******/
45/******/ // Execute the module function
46/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
47/******/
48/******/ // Flag the module as loaded
49/******/ module.l = true;
50/******/
51/******/ // Return the exports of the module
52/******/ return module.exports;
53/******/ }
54/******/
55/******/
56/******/ // expose the modules object (__webpack_modules__)
57/******/ __webpack_require__.m = modules;
58/******/
59/******/ // expose the module cache
60/******/ __webpack_require__.c = installedModules;
61/******/
62/******/ // define getter function for harmony exports
63/******/ __webpack_require__.d = function(exports, name, getter) {
64/******/ if(!__webpack_require__.o(exports, name)) {
65/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
66/******/ }
67/******/ };
68/******/
69/******/ // define __esModule on exports
70/******/ __webpack_require__.r = function(exports) {
71/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
72/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
73/******/ }
74/******/ Object.defineProperty(exports, '__esModule', { value: true });
75/******/ };
76/******/
77/******/ // create a fake namespace object
78/******/ // mode & 1: value is a module id, require it
79/******/ // mode & 2: merge all properties of value into the ns
80/******/ // mode & 4: return value when already ns object
81/******/ // mode & 8|1: behave like require
82/******/ __webpack_require__.t = function(value, mode) {
83/******/ if(mode & 1) value = __webpack_require__(value);
84/******/ if(mode & 8) return value;
85/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
86/******/ var ns = Object.create(null);
87/******/ __webpack_require__.r(ns);
88/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
89/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
90/******/ return ns;
91/******/ };
92/******/
93/******/ // getDefaultExport function for compatibility with non-harmony modules
94/******/ __webpack_require__.n = function(module) {
95/******/ var getter = module && module.__esModule ?
96/******/ function getDefault() { return module['default']; } :
97/******/ function getModuleExports() { return module; };
98/******/ __webpack_require__.d(getter, 'a', getter);
99/******/ return getter;
100/******/ };
101/******/
102/******/ // Object.prototype.hasOwnProperty.call
103/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
104/******/
105/******/ // __webpack_public_path__
106/******/ __webpack_require__.p = "";
107/******/
108/******/
109/******/ // Load entry module and return exports
110/******/ return __webpack_require__(__webpack_require__.s = "./src/index.js");
111/******/ })
112/************************************************************************/
113/******/ ({
114
115/***/ "./src/config.json":
116/*!*************************!*\
117 !*** ./src/config.json ***!
118 \*************************/
119/*! exports provided: info, changelog, main, default */
120/***/ (function(module) {
121
122module.exports = {"info":{"name":"ZeresPluginLibrary","authors":[{"name":"Zerebos","discord_id":"249746236008169473","github_username":"rauenzi","twitter_username":"ZackRauen"}],"version":"1.2.11","description":"Gives other plugins utility functions and the ability to emulate v2.","github":"https://github.com/rauenzi/BDPluginLibrary","github_raw":"https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js"},"changelog":[{"title":"New Stuff","items":["**DiscordContextMenu API** is here for the developers. This should allow developers to easily create and add to context menus."]},{"title":"Improvements","type":"improved","items":["**__Markdown__** is now supported in changelog and some other modals.","**Initialization sequence** is now more consistent and better at reloading plugins."]},{"title":"Bugs Squashed","type":"fixed","items":["**Leak Plugged.** Fixed some React leakage. (Thanks Lighty)","**Patch patched.** I patched the Patch where the Patch patched too much.","**Better Settings.** Fixed extend function not working properly for arrays."]}],"main":"plugin.js"};
123
124/***/ }),
125
126/***/ "./src/index.js":
127/*!**********************!*\
128 !*** ./src/index.js ***!
129 \**********************/
130/*! exports provided: default */
131/***/ (function(module, __webpack_exports__, __webpack_require__) {
132
133"use strict";
134__webpack_require__.r(__webpack_exports__);
135/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
136/* harmony import */ var ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ui */ "./src/ui/ui.js");
137
138
139
140const Library = {};
141Library.DiscordContextMenu = ui__WEBPACK_IMPORTED_MODULE_1__["DiscordContextMenu"];
142Library.DCM = ui__WEBPACK_IMPORTED_MODULE_1__["DiscordContextMenu"];
143Library.ContextMenu = ui__WEBPACK_IMPORTED_MODULE_1__["ContextMenu"];
144Library.Tooltip = ui__WEBPACK_IMPORTED_MODULE_1__["Tooltip"];
145Library.EmulatedTooltip = ui__WEBPACK_IMPORTED_MODULE_1__["EmulatedTooltip"];
146Library.Toasts = ui__WEBPACK_IMPORTED_MODULE_1__["Toasts"];
147Library.Settings = ui__WEBPACK_IMPORTED_MODULE_1__["Settings"];
148Library.Popouts = ui__WEBPACK_IMPORTED_MODULE_1__["Popouts"];
149Library.Modals = ui__WEBPACK_IMPORTED_MODULE_1__["Modals"];
150for (const mod in modules__WEBPACK_IMPORTED_MODULE_0__) Library[mod] = modules__WEBPACK_IMPORTED_MODULE_0__[mod];
151
152const config = __webpack_require__(/*! ./src/config.json */ "./src/config.json");
153const pluginModule = __webpack_require__(/*! ./src/plugin.js */ "./src/plugin.js");
154const pluginFunction = pluginModule.default ? pluginModule.default : pluginModule;
155
156const getBoundLibrary = () => {
157 const name = config.info.name;
158 const BoundAPI = {
159 Logger: {
160 stacktrace: (message, error) => Library.Logger.stacktrace(name, message, error),
161 log: (...message) => Library.Logger.log(name, ...message),
162 error: (...message) => Library.Logger.err(name, ...message),
163 err: (...message) => Library.Logger.err(name, ...message),
164 warn: (...message) => Library.Logger.warn(name, ...message),
165 info: (...message) => Library.Logger.info(name, ...message),
166 debug: (...message) => Library.Logger.debug(name, ...message)
167 },
168 Patcher: {
169 getPatchesByCaller: () => {return Library.Patcher.getPatchesByCaller(name);},
170 unpatchAll: () => {return Library.Patcher.unpatchAll(name);},
171 before: (moduleToPatch, functionName, callback, options = {}) => {return Library.Patcher.before(name, moduleToPatch, functionName, callback, options);},
172 instead: (moduleToPatch, functionName, callback, options = {}) => {return Library.Patcher.instead(name, moduleToPatch, functionName, callback, options);},
173 after: (moduleToPatch, functionName, callback, options = {}) => {return Library.Patcher.after(name, moduleToPatch, functionName, callback, options);}
174 }
175 };
176
177 const BoundLib = Object.assign({}, Library);
178 BoundLib.Logger = BoundAPI.Logger;
179 BoundLib.Patcher = BoundAPI.Patcher;
180 return BoundLib;
181};
182
183/* harmony default export */ __webpack_exports__["default"] = (pluginFunction(Library.Structs.Plugin(config), false ? undefined : Library));
184
185/***/ }),
186
187/***/ "./src/modules/colorconverter.js":
188/*!***************************************!*\
189 !*** ./src/modules/colorconverter.js ***!
190 \***************************************/
191/*! exports provided: default */
192/***/ (function(module, __webpack_exports__, __webpack_require__) {
193
194"use strict";
195__webpack_require__.r(__webpack_exports__);
196/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return ColorConverter; });
197/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js");
198/**
199 * Helpful utilities for dealing with colors.
200 * @module ColorConverter
201 * @version 0.0.2
202 */
203
204
205
206const DiscordColorUtils = _webpackmodules__WEBPACK_IMPORTED_MODULE_0__["default"].getByProps("getDarkness", "isValidHex");
207
208class ColorConverter {
209
210 static getDarkness(color) {
211 return DiscordColorUtils.getDarkness(color);
212 }
213
214 static hex2int(color) {return DiscordColorUtils.hex2int(color);}
215
216 static hex2rgb(color) {return DiscordColorUtils.hex2rgb(color);}
217
218 static int2hex(color) {return DiscordColorUtils.int2hex(color);}
219
220 static int2rgba(color, alpha) {return DiscordColorUtils.int2rgba(color, alpha);}
221
222 static isValidHex(color) {return DiscordColorUtils.isValidHex(color);}
223
224 /**
225 * Will get the red green and blue values of any color string.
226 * @param {string} color - the color to obtain the red, green and blue values of. Can be in any of these formats: #fff, #ffffff, rgb, rgba
227 * @returns {array} - array containing the red, green, and blue values
228 */
229 static getRGB(color) {
230 let result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color);
231 if (result) return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];
232
233 result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*\)/.exec(color);
234 if (result) return [parseFloat(result[1]) * 2.55, parseFloat(result[2]) * 2.55, parseFloat(result[3]) * 2.55];
235
236 result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color);
237 if (result) return [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)];
238
239 result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color);
240 if (result) return [parseInt(result[1] + result[1], 16), parseInt(result[2] + result[2], 16), parseInt(result[3] + result[3], 16)];
241 }
242
243 /**
244 * Will get the darken the color by a certain percent
245 * @param {string} color - Can be in any of these formats: #fff, #ffffff, rgb, rgba
246 * @param {number} percent - percent to darken the color by (0-100)
247 * @returns {string} - new color in rgb format
248 */
249 static darkenColor(color, percent) {
250 const rgb = this.getRGB(color);
251 for (let i = 0; i < rgb.length; i++) rgb[i] = Math.round(Math.max(0, rgb[i] - rgb[i] * (percent / 100)));
252 return "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
253 }
254
255 /**
256 * Will get the lighten the color by a certain percent
257 * @param {string} color - Can be in any of these formats: #fff, #ffffff, rgb, rgba
258 * @param {number} percent - percent to lighten the color by (0-100)
259 * @returns {string} - new color in rgb format
260 */
261 static lightenColor(color, percent) {
262 const rgb = this.getRGB(color);
263 for (let i = 0; i < rgb.length; i++) rgb[i] = Math.round(Math.min(255, rgb[i] + rgb[i] * (percent / 100)));
264 return "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")";
265 }
266
267 /**
268 * Converts a color to rgba format string
269 * @param {string} color - Can be in any of these formats: #fff, #ffffff, rgb, rgba
270 * @param {number} alpha - alpha level for the new color
271 * @returns {string} - new color in rgb format
272 */
273 static rgbToAlpha(color, alpha) {
274 const rgb = this.getRGB(color);
275 return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + alpha + ")";
276 }
277
278}
279
280/***/ }),
281
282/***/ "./src/modules/discordapi.js":
283/*!***********************************!*\
284 !*** ./src/modules/discordapi.js ***!
285 \***********************************/
286/*! exports provided: default */
287/***/ (function(module, __webpack_exports__, __webpack_require__) {
288
289"use strict";
290__webpack_require__.r(__webpack_exports__);
291/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return DiscordAPI; });
292/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! structs */ "./src/structs/structs.js");
293/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js");
294/**
295 * BetterDiscord Discord API
296 * Copyright (c) 2018-present JsSucks
297 * All rights reserved.
298 *
299 * This source code is licensed under the MIT license found at
300 * https://github.com/JsSucks/BetterDiscordApp/blob/master/LICENSE
301*/
302
303/**
304 * A large list of known and useful webpack modules internal to Discord.
305 * Click the filename below to see the whole list.
306 * @module DiscordAPI
307 * @version 0.0.1
308 */
309
310
311
312class DiscordAPI {
313
314 static get InsufficientPermissions() {return structs__WEBPACK_IMPORTED_MODULE_0__["InsufficientPermissions"];}
315 static get List() {return structs__WEBPACK_IMPORTED_MODULE_0__["List"];}
316 static get User() {return structs__WEBPACK_IMPORTED_MODULE_0__["User"];}
317 static get Channel() {return structs__WEBPACK_IMPORTED_MODULE_0__["Channel"];}
318 static get Guild() {return structs__WEBPACK_IMPORTED_MODULE_0__["Guild"];}
319 static get Message() {return structs__WEBPACK_IMPORTED_MODULE_0__["Message"];}
320 static get UserSettings() {return structs__WEBPACK_IMPORTED_MODULE_0__["UserSettings"];}
321
322 /**
323 * A list of loaded guilds.
324 */
325 static get guilds() {
326 const guilds = _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].GuildStore.getGuilds();
327 return structs__WEBPACK_IMPORTED_MODULE_0__["List"].from(Object.values(guilds), g => structs__WEBPACK_IMPORTED_MODULE_0__["Guild"].from(g));
328 }
329
330 /**
331 * A list of loaded channels.
332 */
333 static get channels() {
334 const channels = _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].ChannelStore.getChannels();
335 return structs__WEBPACK_IMPORTED_MODULE_0__["List"].from(Object.values(channels), c => structs__WEBPACK_IMPORTED_MODULE_0__["Channel"].from(c));
336 }
337
338 /**
339 * A list of loaded users.
340 */
341 static get users() {
342 const users = _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].UserStore.getUsers();
343 return structs__WEBPACK_IMPORTED_MODULE_0__["List"].from(Object.values(users), u => structs__WEBPACK_IMPORTED_MODULE_0__["User"].from(u));
344 }
345
346 /**
347 * An object mapping guild IDs to their member counts.
348 */
349 static get memberCounts() {
350 return _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].MemberCountStore.getMemberCounts();
351 }
352
353 /**
354 * A list of guilds in the order they appear in the server list.
355 */
356 static get sortedGuilds() {
357 const guilds = _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].SortedGuildStore.getSortedGuilds();
358 return structs__WEBPACK_IMPORTED_MODULE_0__["List"].from(guilds, g => structs__WEBPACK_IMPORTED_MODULE_0__["Guild"].from(g));
359 }
360
361 /**
362 * An array of guild IDs in the order they appear in the server list.
363 */
364 static get guildPositions() {
365 return _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].SortedGuildStore.guildPositions;
366 }
367
368 /**
369 * The currently selected guild.
370 */
371 static get currentGuild() {
372 const guild = _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].GuildStore.getGuild(_discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].SelectedGuildStore.getGuildId());
373 return guild ? structs__WEBPACK_IMPORTED_MODULE_0__["Guild"].from(guild) : null;
374 }
375
376 /**
377 * The currently selected channel.
378 */
379 static get currentChannel() {
380 const channel = _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].ChannelStore.getChannel(_discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].SelectedChannelStore.getChannelId());
381 return channel ? structs__WEBPACK_IMPORTED_MODULE_0__["Channel"].from(channel) : null;
382 }
383
384 /**
385 * The current user.
386 */
387 static get currentUser() {
388 const user = _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].UserStore.getCurrentUser();
389 return user ? structs__WEBPACK_IMPORTED_MODULE_0__["User"].from(user) : null;
390 }
391
392 /**
393 * A list of the current user's friends.
394 */
395 static get friends() {
396 const friends = _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].RelationshipStore.getFriendIDs();
397 return structs__WEBPACK_IMPORTED_MODULE_0__["List"].from(friends, id => structs__WEBPACK_IMPORTED_MODULE_0__["User"].fromId(id));
398 }
399}
400
401/***/ }),
402
403/***/ "./src/modules/discordclasses.js":
404/*!***************************************!*\
405 !*** ./src/modules/discordclasses.js ***!
406 \***************************************/
407/*! exports provided: default */
408/***/ (function(module, __webpack_exports__, __webpack_require__) {
409
410"use strict";
411__webpack_require__.r(__webpack_exports__);
412/* harmony import */ var _discordclassmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./discordclassmodules */ "./src/modules/discordclassmodules.js");
413/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js");
414
415
416
417const getRaw = function(prop) {
418 if (!this.hasOwnProperty(prop)) return "";
419 return this[prop];
420};
421
422const getClass = function(prop) {
423 if (!this.hasOwnProperty(prop)) return "";
424 return this[prop].split(" ")[0];
425};
426
427/**
428 * Proxy for all the class packages, allows us to safely attempt
429 * to retrieve nested things without error. Also wraps the class in
430 * {@link module:DOMTools.ClassName} which adds features but can still
431 * be used in native function.
432 *
433 * For a list of all available class namespaces check out {@link module:DiscordClassModules}.
434 *
435 * @see module:DiscordClassModules
436 * @module DiscordClasses
437 * @version 0.1.0
438 */
439const DiscordModules = new Proxy(_discordclassmodules__WEBPACK_IMPORTED_MODULE_0__["default"], {
440 get: function(list, item) {
441 if (item == "getRaw" || item == "getClass") return (module, prop) => DiscordModules[module][item]([prop]);
442 if (list[item] === undefined) return new Proxy({}, {get: function() {return "";}});
443 return new Proxy(list[item], {
444 get: function(obj, prop) {
445 if (prop == "getRaw") return getRaw.bind(obj);
446 if (prop == "getClass") return getClass.bind(obj);
447 if (!obj.hasOwnProperty(prop)) return "";
448 return new _domtools__WEBPACK_IMPORTED_MODULE_1__["default"].ClassName(obj[prop]);
449 }
450 });
451 }
452});
453/* harmony default export */ __webpack_exports__["default"] = (DiscordModules);
454
455/***/ }),
456
457/***/ "./src/modules/discordclassmodules.js":
458/*!********************************************!*\
459 !*** ./src/modules/discordclassmodules.js ***!
460 \********************************************/
461/*! exports provided: default */
462/***/ (function(module, __webpack_exports__, __webpack_require__) {
463
464"use strict";
465__webpack_require__.r(__webpack_exports__);
466/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js");
467/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js");
468
469
470
471/**
472 * A large list of known and labelled classes in discord.
473 * Click the source link down below to view more info. Otherwise, if you
474 * have the library installed or have a plugin using this library,
475 * do `Object.keys(ZLibrary.DiscordClassModules)` in console for a list of modules.
476 *
477 * You can use this directly, however the preferred way of doing this is to use {@link module:DiscordClasses} or {@link module:DiscordSelectors}
478 *
479 * @see module:DiscordClasses
480 * @see module:DiscordSelectors
481 * @module DiscordClassModules
482 * @version 0.0.2
483 */
484/* harmony default export */ __webpack_exports__["default"] = (_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].memoizeObject({
485 get ContextMenu() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("itemToggle");},
486 get Scrollers() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("scrollerWrap", "scrollerThemed", "scrollerTrack");},
487 get AccountDetails() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("container", "avatar", "hasBuildOverride");},
488 get Typing() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("typing", "text");},
489 get UserPopout() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("userPopout");},
490 get PopoutRoles() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("roleCircle");},
491 get UserModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("profileBadge");},
492 get Textarea() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("channelTextArea", "textArea");},
493 get Popouts() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("popouts");},
494 get Titles() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("defaultMarginh5");},
495 get Notices() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("noticeInfo");},
496 get Backdrop() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("backdrop");},
497 get Modals() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.modal && m.inner && !m.header);},
498 get AuditLog() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("userHook");},
499 get ChannelList() {return Object.assign({}, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("containerDefault"), _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("name", "unread"), _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("sidebar", "hasNotice"));},
500 get MemberList() {return Object.assign({}, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("member", "memberInner"), _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("members", "membersWrap"));},
501 get TitleWrap() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("titleWrapper");},
502 get Titlebar() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("titleBar");},
503 get Embeds() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("embed", "embedAuthor");},
504 get Layers() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("layers", "layer");},
505 get TooltipLayers() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("layerContainer", "layer");},
506 get Margins() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => !m.title && m.marginBottom40 && m.marginTop40);},
507 get Dividers() {return Object.assign({}, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("dividerDefault"), _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => Object.keys(m).length == 1 && m.divider));},
508 get Changelog() {return Object.assign({}, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("container", "added"), _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("content", "modal", "size"));},
509 get BasicInputs() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("inputDefault");},
510 get Messages() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("message", "containerCozy");},
511 get Guilds() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("guildsWrapper");},
512 get EmojiPicker() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("emojiPicker", "emojiItem");},
513 get Reactions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("reaction", "reactionInner");},
514 get Checkbox() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("checkbox", "checkboxInner");},
515 get Tooltips() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("tooltip", "tooltipBlack");}
516}));
517
518
519
520/***/ }),
521
522/***/ "./src/modules/discordmodules.js":
523/*!***************************************!*\
524 !*** ./src/modules/discordmodules.js ***!
525 \***************************************/
526/*! exports provided: default */
527/***/ (function(module, __webpack_exports__, __webpack_require__) {
528
529"use strict";
530__webpack_require__.r(__webpack_exports__);
531/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js");
532/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js");
533/**
534 * A large list of known and useful webpack modules internal to Discord.
535 * Click the source link down below to view more info. Otherwise, if you
536 * have the library installed or have a plugin using this library,
537 * do `Object.keys(ZLibrary.DiscordModules)` in console for a list of modules.
538 * @module DiscordModules
539 * @version 0.0.3
540 */
541
542
543
544/* harmony default export */ __webpack_exports__["default"] = (_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].memoizeObject({
545 get React() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("createElement", "cloneElement");},
546 get ReactDOM() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("render", "findDOMNode");},
547 get Events() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("setMaxListeners", "emit");},
548
549 /* Guild Info, Stores, and Utilities */
550 get GuildStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getGuild");},
551 get SortedGuildStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getSortedGuilds");},
552 get SelectedGuildStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getLastSelectedGuildId");},
553 get GuildSync() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getSyncedGuilds");},
554 get GuildInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getAcronym");},
555 get GuildChannelsStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getChannels", "getDefaultChannel");},
556 get GuildMemberStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getMember");},
557 get MemberCountStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getMemberCounts");},
558 get GuildEmojiStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getEmojis");},
559 get GuildActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("markGuildAsRead");},
560 get GuildPermissions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getGuildPermissions");},
561
562 /* Channel Store & Actions */
563 get ChannelStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getChannels", "getDMFromUserId");},
564 get SelectedChannelStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getLastSelectedChannelId");},
565 get ChannelActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("selectChannel");},
566 get PrivateChannelActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("openPrivateChannel");},
567 get ChannelSelector() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("selectGuild", "selectChannel");},
568
569 /* Current User Info, State and Settings */
570 get UserInfoStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getToken");},
571 get UserSettingsStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("guildPositions");},
572 get AccountManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("register", "login");},
573 get UserSettingsUpdater() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("updateRemoteSettings");},
574 get OnlineWatcher() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isOnline");},
575 get CurrentUserIdle() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getIdleTime");},
576 get RelationshipStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isBlocked", "getFriendIDs");},
577 get RelationshipManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("addRelationship");},
578 get MentionStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getMentions");},
579
580 /* User Stores and Utils */
581 get UserStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getCurrentUser");},
582 get UserStatusStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getStatus", "getState");},
583 get UserTypingStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isTyping");},
584 get UserActivityStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getActivity");},
585 get UserNameResolver() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getName");},
586 get UserNoteStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getNote");},
587 get UserNoteActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("updateNote");},
588
589 /* Emoji Store and Utils */
590 get EmojiInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isEmojiDisabled");},
591 get EmojiUtils() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getGuildEmoji");},
592 get EmojiStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getByCategory", "EMOJI_NAME_RE");},
593
594 /* Invite Store and Utils */
595 get InviteStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getInvites");},
596 get InviteResolver() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("findInvite");},
597 get InviteActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("acceptInvite");},
598
599 /* Discord Objects & Utils */
600 get DiscordConstants() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Permissions", "ActivityTypes", "StatusTypes");},
601 get DiscordPermissions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Permissions", "ActivityTypes", "StatusTypes").Permissions;},
602 get Permissions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getHighestRole");},
603 get ColorConverter() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("hex2int");},
604 get ColorShader() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("darken");},
605 get TinyColor() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("toRgb");},
606 get ClassResolver() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getClass");},
607 get ButtonData() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("ButtonSizes");},
608 get IconNames() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("IconNames");},
609 get NavigationUtils() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("transitionTo", "replaceWith", "getHistory");},
610
611 /* Discord Messages */
612 get MessageStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getMessages");},
613 get MessageActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("jumpToMessage", "_sendMessage");},
614 get MessageQueue() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("enqueue");},
615 get MessageParser() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("createMessage", "parse", "unparse");},
616
617 /* In-Game Overlay */
618 get OverlayUserPopoutSettings() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("openUserPopout");},
619 get OverlayUserPopoutInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getOpenedUserPopout");},
620
621 /* Experiments */
622 get ExperimentStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getExperimentOverrides");},
623 get ExperimentsManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isDeveloper");},
624 get CurrentExperiment() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getExperimentId");},
625
626 /* Images, Avatars and Utils */
627 get ImageResolver() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getUserAvatarURL", "getGuildIconURL");},
628 get ImageUtils() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getSizedImageSrc");},
629 get AvatarDefaults() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getUserAvatarURL", "DEFAULT_AVATARS");},
630
631 /* Drag & Drop */
632 get DNDActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("beginDrag");},
633 get DNDSources() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("addTarget");},
634 get DNDObjects() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("DragSource");},
635
636 /* Electron & Other Internals with Utils*/
637 get ElectronModule() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("setBadge");},
638 get Dispatcher() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("dirtyDispatch");},
639 get PathUtils() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("hasBasename");},
640 get NotificationModule() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("showNotification");},
641 get RouterModule() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Router");},
642 get APIModule() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getAPIBaseURL");},
643 get AnalyticEvents() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("AnalyticEventConfigs");},
644 get KeyGenerator() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByRegex(/"binary"/);},
645 get Buffers() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Buffer", "kMaxLength");},
646 get DeviceStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getDevices");},
647 get SoftwareInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("os");},
648 get CurrentContext() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("setTagsContext");},
649
650 /* Media Stuff (Audio/Video) */
651 get MediaDeviceInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Codecs", "SUPPORTED_BROWSERS");},
652 get MediaInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getOutputVolume");},
653 get MediaEngineInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("MediaEngineFeatures");},
654 get VoiceInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("EchoCancellation");},
655 get VideoStream() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getVideoStream");},
656 get SoundModule() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("playSound");},
657
658 /* Window, DOM, HTML */
659 get WindowInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isFocused", "windowSize");},
660 get TagInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("VALID_TAG_NAMES");},
661 get DOMInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("canUseDOM");},
662
663 /* Locale/Location and Time */
664 get LocaleManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("setLocale");},
665 get Moment() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("parseZone");},
666 get LocationManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("createLocation");},
667 get Timestamps() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("fromTimestamp");},
668
669 /* Strings and Utils */
670 get Strings() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Messages").Messages;},
671 get StringFormats() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("a", "z");},
672 get StringUtils() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("toASCII");},
673
674 /* URLs and Utils */
675 get URLParser() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Url", "parse");},
676 get ExtraURLs() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getArticleURL");},
677
678 /* Text Processing */
679 get hljs() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("highlight", "highlightBlock");},
680 get SimpleMarkdown() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("parseBlock", "parseInline", "defaultOutput");},
681
682 /* DOM/React Components */
683 /* ==================== */
684 get LayerManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("popLayer", "pushLayer");},
685 get Tooltips() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].find(m => m.hide && m.show && !m.search && !m.submit && !m.search && !m.activateRagingDemon && !m.dismiss);},
686 get UserSettingsWindow() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "updateAccount");},
687 get ChannelSettingsWindow() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "updateChannel");},
688 get GuildSettingsWindow() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "updateGuild");},
689
690 /* Modals */
691 get ModalStack() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("push", "update", "pop", "popWithKey");},
692 get UserProfileModals() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("fetchMutualFriends", "setSection");},
693 get AlertModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("handleCancel", "handleSubmit", "handleMinorConfirm");},
694 get ConfirmationModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.defaultProps && m.key && m.key() == "confirm-modal");},
695 get UserProfileModal() {
696 return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].find(m => {
697 try {return m.modalConfig && m.prototype.render().type.displayName == "FluxContainer(Component)";}
698 catch (err) {return false;}
699 });
700 },
701 get ChangeNicknameModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "changeNickname");},
702 get CreateChannelModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "createChannel");},
703 get PruneMembersModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "prune");},
704 get NotificationSettingsModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "updateNotificationSettings");},
705 get PrivacySettingsModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByRegex(/PRIVACY_SETTINGS_MODAL_OPEN/, m => m.open);},
706 get CreateInviteModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "createInvite");},
707 get Changelog() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule((m => m.defaultProps && m.defaultProps.selectable == false));},
708 get Avatar() {
709 return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].find(m => {
710 if (m.displayName != "FluxContainer(t)") return false;
711 try {
712 const temp = new m();
713 return temp.state && temp.state.hasOwnProperty("isFocused");
714 }
715 catch (err) {return false;}
716 });
717 },
718
719 /* Popouts */
720 get PopoutStack() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "close", "closeAll");},
721 get PopoutOpener() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("openPopout");},
722 get EmojiPicker() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("FluxContainer(EmojiPicker)");},
723 get UserPopout() {
724 return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("FluxContainer(ForwardRef(SubscribeGuildMembersContainer(UserPopout)))");
725 },
726
727 /* Context Menus */
728 get ContextMenuActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("openContextMenu");},
729 get ContextMenuItemsGroup() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByRegex(/itemGroup/);},
730 get ContextMenuItem() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByRegex(/\.label\b.*\.hint\b.*\.action\b/);},
731
732 /* Misc */
733 get ExternalLink() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByRegex(/trusted/);},
734 get TextElement() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Sizes", "Weights");},
735 get FlexChild() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Child");},
736 get Titles() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Tags", "default");},
737
738 /* Settings */
739 get SettingsWrapper() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("FormItem");},
740 get SettingsNote() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("FormText");},
741 get SettingsDivider() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => !m.defaultProps && m.prototype && m.prototype.render && m.prototype.render.toString().includes("default.divider"));},
742
743 get ColorPicker() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("renderCustomColorPopout");},
744 get Dropdown() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.prototype && !m.prototype.handleClick && m.prototype.render && m.prototype.render.toString().includes("default.select"));},
745 get Keybind() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("handleComboChange");},
746 get RadioGroup() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.defaultProps && m.defaultProps.options && m.defaultProps.size);},
747 get Slider() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("renderMark");},
748 get SwitchRow() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.defaultProps && m.defaultProps.hideBorder == false);},
749 get Textbox() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.defaultProps && m.defaultProps.type == "text");},
750}));
751
752/***/ }),
753
754/***/ "./src/modules/discordselectors.js":
755/*!*****************************************!*\
756 !*** ./src/modules/discordselectors.js ***!
757 \*****************************************/
758/*! exports provided: default */
759/***/ (function(module, __webpack_exports__, __webpack_require__) {
760
761"use strict";
762__webpack_require__.r(__webpack_exports__);
763/* harmony import */ var _discordclassmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./discordclassmodules */ "./src/modules/discordclassmodules.js");
764/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js");
765
766
767
768const getSelectorAll = function(prop) {
769 if (!this.hasOwnProperty(prop)) return "";
770 return `.${this[prop].split(" ").join(".")}`;
771};
772
773const getSelector = function(prop) {
774 if (!this.hasOwnProperty(prop)) return "";
775 return `.${this[prop].split(" ")[0]}`;
776};
777
778/**
779 * Gives us a way to retrieve the internal classes as selectors without
780 * needing to concatenate strings or use string templates. Wraps the
781 * selector in {@link module:DOMTools.Selector} which adds features but can
782 * still be used in native function.
783 *
784 * For a list of all available class namespaces check out {@link module:DiscordClassModules}.
785 *
786 * @see module:DiscordClassModules
787 * @module DiscordSelectors
788 * @version 0.1.0
789 */
790const DiscordSelectors = new Proxy(_discordclassmodules__WEBPACK_IMPORTED_MODULE_0__["default"], {
791 get: function(list, item) {
792 if (item == "getSelectorAll" || item == "getSelector") return (module, prop) => DiscordSelectors[module][item]([prop]);
793 if (list[item] === undefined) return new Proxy({}, {get: function() {return "";}});
794 return new Proxy(list[item], {
795 get: function(obj, prop) {
796 if (prop == "getSelectorAll") return getSelectorAll.bind(obj);
797 if (prop == "getSelector") return getSelector.bind(obj);
798 if (!obj.hasOwnProperty(prop)) return "";
799 return new _domtools__WEBPACK_IMPORTED_MODULE_1__["default"].Selector(obj[prop]);
800 }
801 });
802 }
803});
804
805/* harmony default export */ __webpack_exports__["default"] = (DiscordSelectors);
806
807/***/ }),
808
809/***/ "./src/modules/domtools.js":
810/*!*********************************!*\
811 !*** ./src/modules/domtools.js ***!
812 \*********************************/
813/*! exports provided: default */
814/***/ (function(module, __webpack_exports__, __webpack_require__) {
815
816"use strict";
817__webpack_require__.r(__webpack_exports__);
818/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return DOMTools; });
819/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js");
820/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! structs */ "./src/structs/structs.js");
821/**
822 * Helpful utilities for dealing with DOM operations.
823 *
824 * This module also extends `HTMLElement` to add a set of utility functions,
825 * the same as the ones available in the module itself, but with the `element`
826 * parameter bound to `this`.
827 * @module DOMTools
828 * @version 0.0.5
829 */
830
831
832
833
834/**
835 * @interface
836 * @name Offset
837 * @property {number} top - Top offset of the target element.
838 * @property {number} right - Right offset of the target element.
839 * @property {number} bottom - Bottom offset of the target element.
840 * @property {number} left - Left offset of the target element.
841 * @property {number} height - Outer height of the target element.
842 * @property {number} width - Outer width of the target element.
843 */
844
845 /**
846 * Function that automatically removes added listener.
847 * @callback module:DOMTools~CancelListener
848 */
849
850class DOMTools {
851
852 static get Selector() {return structs__WEBPACK_IMPORTED_MODULE_1__["Selector"];}
853 static get ClassName() {return structs__WEBPACK_IMPORTED_MODULE_1__["ClassName"];}
854 static get DOMObserver() {return structs__WEBPACK_IMPORTED_MODULE_1__["DOMObserver"];}
855
856 /**
857 * Default DOMObserver for global usage.
858 *
859 * @see DOMObserver
860 */
861 static get observer() {
862 return this._observer || (this._observer = new structs__WEBPACK_IMPORTED_MODULE_1__["DOMObserver"]());
863 }
864
865 /**
866 * This is my shit version of not having to use `$` from jQuery. Meaning
867 * that you can pass a selector and it will automatically run {@link module:DOMTools.query}.
868 * It also means that you can pass a string of html and it will perform and return `parseHTML`.
869 * @see module:DOMTools.parseHTML
870 * @see module:DOMTools.query
871 * @param {string} selector - Selector to query or HTML to parse
872 * @returns {(DocumentFragment|NodeList|HTMLElement)} - Either the result of `parseHTML` or `query`
873 */
874 static Q(selector) {
875 const element = this.parseHTML(selector);
876 const isHTML = element instanceof NodeList ? Array.from(element).some(n => n.nodeType === 1) : element.nodeType === 1;
877 if (isHTML) return element;
878 return this.query(selector);
879 }
880
881 /**
882 * Essentially a shorthand for `document.querySelector`. If the `baseElement` is not provided
883 * `document` is used by default.
884 * @param {string} selector - Selector to query
885 * @param {Element} [baseElement] - Element to base the query from
886 * @returns {(Element|null)} - The found element or null if not found
887 */
888 static query(selector, baseElement) {
889 if (!baseElement) baseElement = document;
890 return baseElement.querySelector(selector);
891 }
892
893 /**
894 * Essentially a shorthand for `document.querySelectorAll`. If the `baseElement` is not provided
895 * `document` is used by default.
896 * @param {string} selector - Selector to query
897 * @param {Element} [baseElement] - Element to base the query from
898 * @returns {Array<Element>} - Array of all found elements
899 */
900 static queryAll(selector, baseElement) {
901 if (!baseElement) baseElement = document;
902 return baseElement.querySelectorAll(selector);
903 }
904
905 /**
906 * Parses a string of HTML and returns the results. If the second parameter is true,
907 * the parsed HTML will be returned as a document fragment {@see https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment}.
908 * This is extremely useful if you have a list of elements at the top level, they can then be appended all at once to another node.
909 *
910 * If the second parameter is false, then the return value will be the list of parsed
911 * nodes and there were multiple top level nodes, otherwise the single node is returned.
912 * @param {string} html - HTML to be parsed
913 * @param {boolean} [fragment=false] - Whether or not the return should be the raw `DocumentFragment`
914 * @returns {(DocumentFragment|NodeList|HTMLElement)} - The result of HTML parsing
915 */
916 static parseHTML(html, fragment = false) {
917 const template = document.createElement("template");
918 template.innerHTML = html;
919 const node = template.content.cloneNode(true);
920 if (fragment) return node;
921 return node.childNodes.length > 1 ? node.childNodes : node.childNodes[0];
922 }
923
924 /** Alternate name for {@link module:DOMTools.parseHTML} */
925 static createElement(html, fragment = false) {return this.parseHTML(html, fragment);}
926
927 /**
928 * Takes a string of html and escapes it using the brower's own escaping mechanism.
929 * @param {String} html - html to be escaped
930 */
931 static escapeHTML(html) {
932 const textNode = document.createTextNode("");
933 const spanElement = document.createElement("span");
934 spanElement.append(textNode);
935 textNode.nodeValue = html;
936 return spanElement.innerHTML;
937 }
938
939 /**
940 * Adds a list of classes from the target element.
941 * @param {Element} element - Element to edit classes of
942 * @param {...string} classes - Names of classes to add
943 * @returns {Element} - `element` to allow for chaining
944 */
945 static addClass(element, ...classes) {
946 classes = classes.flat().filter(c => c);
947 for (let c = 0; c < classes.length; c++) classes[c] = classes[c].toString().split(" ");
948 classes = classes.flat().filter(c => c);
949 element.classList.add(...classes);
950 return element;
951 }
952
953 /**
954 * Removes a list of classes from the target element.
955 * @param {Element} element - Element to edit classes of
956 * @param {...string} classes - Names of classes to remove
957 * @returns {Element} - `element` to allow for chaining
958 */
959 static removeClass(element, ...classes) {
960 for (let c = 0; c < classes.length; c++) classes[c] = classes[c].toString().split(" ");
961 classes = classes.flat().filter(c => c);
962 element.classList.remove(...classes);
963 return element;
964 }
965
966 /**
967 * When only one argument is present: Toggle class value;
968 * i.e., if class exists then remove it and return false, if not, then add it and return true.
969 * When a second argument is present:
970 * If the second argument evaluates to true, add specified class value, and if it evaluates to false, remove it.
971 * @param {Element} element - Element to edit classes of
972 * @param {string} classname - Name of class to toggle
973 * @param {boolean} [indicator] - Optional indicator for if the class should be toggled
974 * @returns {Element} - `element` to allow for chaining
975 */
976 static toggleClass(element, classname, indicator) {
977 classname = classname.toString().split(" ").filter(c => c);
978 if (typeof(indicator) !== "undefined") classname.forEach(c => element.classList.toggle(c, indicator));
979 else classname.forEach(c => element.classList.toggle(c));
980 return element;
981 }
982
983 /**
984 * Checks if an element has a specific class
985 * @param {Element} element - Element to edit classes of
986 * @param {string} classname - Name of class to check
987 * @returns {boolean} - `true` if the element has the class, `false` otherwise.
988 */
989 static hasClass(element, classname) {
990 return classname.toString().split(" ").filter(c => c).every(c => element.classList.contains(c));
991 }
992
993 /**
994 * Replaces one class with another
995 * @param {Element} element - Element to edit classes of
996 * @param {string} oldName - Name of class to replace
997 * @param {string} newName - New name for the class
998 * @returns {Element} - `element` to allow for chaining
999 */
1000 static replaceClass(element, oldName, newName) {
1001 element.classList.replace(oldName, newName);
1002 return element;
1003 }
1004
1005 /**
1006 * Appends `thisNode` to `thatNode`
1007 * @param {Node} thisNode - Node to be appended to another node
1008 * @param {Node} thatNode - Node for `thisNode` to be appended to
1009 * @returns {Node} - `thisNode` to allow for chaining
1010 */
1011 static appendTo(thisNode, thatNode) {
1012 if (typeof(thatNode) == "string") thatNode = this.query(thatNode);
1013 if (!thatNode) return null;
1014 thatNode.append(thisNode);
1015 return thisNode;
1016 }
1017
1018 /**
1019 * Prepends `thisNode` to `thatNode`
1020 * @param {Node} thisNode - Node to be prepended to another node
1021 * @param {Node} thatNode - Node for `thisNode` to be prepended to
1022 * @returns {Node} - `thisNode` to allow for chaining
1023 */
1024 static prependTo(thisNode, thatNode) {
1025 if (typeof(thatNode) == "string") thatNode = this.query(thatNode);
1026 if (!thatNode) return null;
1027 thatNode.prepend(thisNode);
1028 return thisNode;
1029 }
1030
1031 /**
1032 * Insert after a specific element, similar to jQuery's `thisElement.insertAfter(otherElement)`.
1033 * @param {Node} thisNode - The node to insert
1034 * @param {Node} targetNode - Node to insert after in the tree
1035 * @returns {Node} - `thisNode` to allow for chaining
1036 */
1037 static insertAfter(thisNode, targetNode) {
1038 targetNode.parentNode.insertBefore(thisNode, targetNode.nextSibling);
1039 return thisNode;
1040 }
1041
1042 /**
1043 * Insert after a specific element, similar to jQuery's `thisElement.after(newElement)`.
1044 * @param {Node} thisNode - The node to insert
1045 * @param {Node} newNode - Node to insert after in the tree
1046 * @returns {Node} - `thisNode` to allow for chaining
1047 */
1048 static after(thisNode, newNode) {
1049 thisNode.parentNode.insertBefore(newNode, thisNode.nextSibling);
1050 return thisNode;
1051 }
1052
1053 /**
1054 * Gets the next sibling element that matches the selector.
1055 * @param {Element} element - Element to get the next sibling of
1056 * @param {string} [selector=""] - Optional selector
1057 * @returns {Element} - The sibling element
1058 */
1059 static next(element, selector = "") {
1060 return selector ? element.querySelector("+ " + selector) : element.nextElementSibling;
1061 }
1062
1063 /**
1064 * Gets all subsequent siblings.
1065 * @param {Element} element - Element to get next siblings of
1066 * @returns {NodeList} - The list of siblings
1067 */
1068 static nextAll(element) {
1069 return element.querySelectorAll("~ *");
1070 }
1071
1072 /**
1073 * Gets the subsequent siblings until an element matches the selector.
1074 * @param {Element} element - Element to get the following siblings of
1075 * @param {string} selector - Selector to stop at
1076 * @returns {Array<Element>} - The list of siblings
1077 */
1078 static nextUntil(element, selector) {
1079 const next = [];
1080 while (element.nextElementSibling && !element.nextElementSibling.matches(selector)) next.push(element = element.nextElementSibling);
1081 return next;
1082 }
1083
1084 /**
1085 * Gets the previous sibling element that matches the selector.
1086 * @param {Element} element - Element to get the previous sibling of
1087 * @param {string} [selector=""] - Optional selector
1088 * @returns {Element} - The sibling element
1089 */
1090 static previous(element, selector = "") {
1091 const previous = element.previousElementSibling;
1092 if (selector) return previous && previous.matches(selector) ? previous : null;
1093 return previous;
1094 }
1095
1096 /**
1097 * Gets all preceeding siblings.
1098 * @param {Element} element - Element to get preceeding siblings of
1099 * @returns {NodeList} - The list of siblings
1100 */
1101 static previousAll(element) {
1102 const previous = [];
1103 while (element.previousElementSibling) previous.push(element = element.previousElementSibling);
1104 return previous;
1105 }
1106
1107 /**
1108 * Gets the preceeding siblings until an element matches the selector.
1109 * @param {Element} element - Element to get the preceeding siblings of
1110 * @param {string} selector - Selector to stop at
1111 * @returns {Array<Element>} - The list of siblings
1112 */
1113 static previousUntil(element, selector) {
1114 const previous = [];
1115 while (element.previousElementSibling && !element.previousElementSibling.matches(selector)) previous.push(element = element.previousElementSibling);
1116 return previous;
1117 }
1118
1119 /**
1120 * Find which index in children a certain node is. Similar to jQuery's `$.index()`
1121 * @param {HTMLElement} node - The node to find its index in parent
1122 * @returns {number} Index of the node
1123 */
1124 static indexInParent(node) {
1125 const children = node.parentNode.childNodes;
1126 let num = 0;
1127 for (let i = 0; i < children.length; i++) {
1128 if (children[i] == node) return num;
1129 if (children[i].nodeType == 1) num++;
1130 }
1131 return -1;
1132 }
1133
1134 /** Shorthand for {@link module:DOMTools.indexInParent} */
1135 static index(node) {return this.indexInParent(node);}
1136
1137 /**
1138 * Gets the parent of the element if it matches the selector,
1139 * otherwise returns null.
1140 * @param {Element} element - Element to get parent of
1141 * @param {string} [selector=""] - Selector to match parent
1142 * @returns {(Element|null)} - The sibling element or null
1143 */
1144 static parent(element, selector = "") {
1145 return !selector || element.parentElement.matches(selector) ? element.parentElement : null;
1146 }
1147
1148 /**
1149 * Gets all children of Element that match the selector if provided.
1150 * @param {Element} element - Element to get all children of
1151 * @param {string} selector - Selector to match the children to
1152 * @returns {Array<Element>} - The list of children
1153 */
1154 static findChild(element, selector) {
1155 return element.querySelector(":scope > " + selector);
1156 }
1157
1158 /**
1159 * Gets all children of Element that match the selector if provided.
1160 * @param {Element} element - Element to get all children of
1161 * @param {string} selector - Selector to match the children to
1162 * @returns {Array<Element>} - The list of children
1163 */
1164 static findChildren(element, selector) {
1165 return element.querySelectorAll(":scope > " + selector);
1166 }
1167
1168 /**
1169 * Gets all ancestors of Element that match the selector if provided.
1170 * @param {Element} element - Element to get all parents of
1171 * @param {string} [selector=""] - Selector to match the parents to
1172 * @returns {Array<Element>} - The list of parents
1173 */
1174 static parents(element, selector = "") {
1175 const parents = [];
1176 if (selector) while (element.parentElement && element.parentElement.closest(selector)) parents.push(element = element.parentElement.closest(selector));
1177 else while (element.parentElement) parents.push(element = element.parentElement);
1178 return parents;
1179 }
1180
1181 /**
1182 * Gets the ancestors until an element matches the selector.
1183 * @param {Element} element - Element to get the ancestors of
1184 * @param {string} selector - Selector to stop at
1185 * @returns {Array<Element>} - The list of parents
1186 */
1187 static parentsUntil(element, selector) {
1188 const parents = [];
1189 while (element.parentElement && !element.parentElement.matches(selector)) parents.push(element = element.parentElement);
1190 return parents;
1191 }
1192
1193 /**
1194 * Gets all siblings of the element that match the selector.
1195 * @param {Element} element - Element to get all siblings of
1196 * @param {string} [selector="*"] - Selector to match the siblings to
1197 * @returns {Array<Element>} - The list of siblings
1198 */
1199 static siblings(element, selector = "*") {
1200 return Array.from(element.parentElement.children).filter(e => e != element && e.matches(selector));
1201 }
1202
1203 /**
1204 * Sets or gets css styles for a specific element. If `value` is provided
1205 * then it sets the style and returns the element to allow for chaining,
1206 * otherwise returns the style.
1207 * @param {Element} element - Element to set the CSS of
1208 * @param {string} attribute - Attribute to get or set
1209 * @param {string} [value] - Value to set for attribute
1210 * @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned.
1211 */
1212 static css(element, attribute, value) {
1213 if (typeof(value) == "undefined") return global.getComputedStyle(element)[attribute];
1214 element.style[attribute] = value;
1215 return element;
1216 }
1217
1218 /**
1219 * Sets or gets the width for a specific element. If `value` is provided
1220 * then it sets the width and returns the element to allow for chaining,
1221 * otherwise returns the width.
1222 * @param {Element} element - Element to set the CSS of
1223 * @param {string} [value] - Width to set
1224 * @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned.
1225 */
1226 static width(element, value) {
1227 if (typeof(value) == "undefined") return parseInt(getComputedStyle(element).width);
1228 element.style.width = value;
1229 return element;
1230 }
1231
1232 /**
1233 * Sets or gets the height for a specific element. If `value` is provided
1234 * then it sets the height and returns the element to allow for chaining,
1235 * otherwise returns the height.
1236 * @param {Element} element - Element to set the CSS of
1237 * @param {string} [value] - Height to set
1238 * @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned.
1239 */
1240 static height(element, value) {
1241 if (typeof(value) == "undefined") return parseInt(getComputedStyle(element).height);
1242 element.style.height = value;
1243 return element;
1244 }
1245
1246 /**
1247 * Sets the inner text of an element if given a value, otherwise returns it.
1248 * @param {Element} element - Element to set the text of
1249 * @param {string} [text] - Content to set
1250 * @returns {string} - Either the string set by this call or the current text content of the node.
1251 */
1252 static text(element, text) {
1253 if (typeof(text) == "undefined") return element.textContent;
1254 return element.textContent = text;
1255 }
1256
1257 /**
1258 * Returns the innerWidth of the element.
1259 * @param {Element} element - Element to retrieve inner width of
1260 * @return {number} - The inner width of the element.
1261 */
1262 static innerWidth(element) {
1263 return element.clientWidth;
1264 }
1265
1266 /**
1267 * Returns the innerHeight of the element.
1268 * @param {Element} element - Element to retrieve inner height of
1269 * @return {number} - The inner height of the element.
1270 */
1271 static innerHeight(element) {
1272 return element.clientHeight;
1273 }
1274
1275 /**
1276 * Returns the outerWidth of the element.
1277 * @param {Element} element - Element to retrieve outer width of
1278 * @return {number} - The outer width of the element.
1279 */
1280 static outerWidth(element) {
1281 return element.offsetWidth;
1282 }
1283
1284 /**
1285 * Returns the outerHeight of the element.
1286 * @param {Element} element - Element to retrieve outer height of
1287 * @return {number} - The outer height of the element.
1288 */
1289 static outerHeight(element) {
1290 return element.offsetHeight;
1291 }
1292
1293 /**
1294 * Gets the offset of the element in the page.
1295 * @param {Element} element - Element to get offset of
1296 * @return {Offset} - The offset of the element
1297 */
1298 static offset(element) {
1299 return element.getBoundingClientRect();
1300 }
1301
1302 static get listeners() { return this._listeners || (this._listeners = {}); }
1303
1304 /**
1305 * This is similar to jQuery's `on` function and can *hopefully* be used in the same way.
1306 *
1307 * Rather than attempt to explain, I'll show some example usages.
1308 *
1309 * The following will add a click listener (in the `myPlugin` namespace) to `element`.
1310 * `DOMTools.on(element, "click.myPlugin", () => {console.log("clicked!");});`
1311 *
1312 * The following will add a click listener (in the `myPlugin` namespace) to `element` that only fires when the target is a `.block` element.
1313 * `DOMTools.on(element, "click.myPlugin", ".block", () => {console.log("clicked!");});`
1314 *
1315 * The following will add a click listener (without namespace) to `element`.
1316 * `DOMTools.on(element, "click", () => {console.log("clicked!");});`
1317 *
1318 * The following will add a click listener (without namespace) to `element` that only fires once.
1319 * `const cancel = DOMTools.on(element, "click", () => {console.log("fired!"); cancel();});`
1320 *
1321 * @param {Element} element - Element to add listener to
1322 * @param {string} event - Event to listen to with option namespace (e.g. "event.namespace")
1323 * @param {(string|callable)} delegate - Selector to run on element to listen to
1324 * @param {callable} [callback] - Function to fire on event
1325 * @returns {module:DOMTools~CancelListener} - A function that will undo the listener
1326 */
1327 static on(element, event, delegate, callback) {
1328 const [type, namespace] = event.split(".");
1329 const hasDelegate = delegate && callback;
1330 if (!callback) callback = delegate;
1331 const eventFunc = !hasDelegate ? callback : function(event) {
1332 if (event.target.matches(delegate)) {
1333 callback(event);
1334 }
1335 };
1336
1337 element.addEventListener(type, eventFunc);
1338 const cancel = () => {
1339 element.removeEventListener(type, eventFunc);
1340 };
1341 if (namespace) {
1342 if (!this.listeners[namespace]) this.listeners[namespace] = [];
1343 const newCancel = () => {
1344 cancel();
1345 this.listeners[namespace].splice(this.listeners[namespace].findIndex(l => l.event == type && l.element == element), 1);
1346 };
1347 this.listeners[namespace].push({
1348 event: type,
1349 element: element,
1350 cancel: newCancel
1351 });
1352 return newCancel;
1353 }
1354 return cancel;
1355 }
1356
1357 /**
1358 * Functionality for this method matches {@link module:DOMTools.on} but automatically cancels itself
1359 * and removes the listener upon the first firing of the desired event.
1360 *
1361 * @param {Element} element - Element to add listener to
1362 * @param {string} event - Event to listen to with option namespace (e.g. "event.namespace")
1363 * @param {(string|callable)} delegate - Selector to run on element to listen to
1364 * @param {callable} [callback] - Function to fire on event
1365 * @returns {module:DOMTools~CancelListener} - A function that will undo the listener
1366 */
1367 static once(element, event, delegate, callback) {
1368 const [type, namespace] = event.split(".");
1369 const hasDelegate = delegate && callback;
1370 if (!callback) callback = delegate;
1371 const eventFunc = !hasDelegate ? function(event) {
1372 callback(event);
1373 element.removeEventListener(type, eventFunc);
1374 } : function(event) {
1375 if (!event.target.matches(delegate)) return;
1376 callback(event);
1377 element.removeEventListener(type, eventFunc);
1378 };
1379
1380 element.addEventListener(type, eventFunc);
1381 const cancel = () => {
1382 element.removeEventListener(type, eventFunc);
1383 };
1384 if (namespace) {
1385 if (!this.listeners[namespace]) this.listeners[namespace] = [];
1386 const newCancel = () => {
1387 cancel();
1388 this.listeners[namespace].splice(this.listeners[namespace].findIndex(l => l.event == type && l.element == element), 1);
1389 };
1390 this.listeners[namespace].push({
1391 event: type,
1392 element: element,
1393 cancel: newCancel
1394 });
1395 return newCancel;
1396 }
1397 return cancel;
1398 }
1399
1400 static __offAll(event, element) {
1401 const [type, namespace] = event.split(".");
1402 let matchFilter = listener => listener.event == type, defaultFilter = _ => _;
1403 if (element) matchFilter = l => l.event == type && l.element == element, defaultFilter = l => l.element == element;
1404 const listeners = this.listeners[namespace] || [];
1405 const list = type ? listeners.filter(matchFilter) : listeners.filter(defaultFilter);
1406 for (let c = 0; c < list.length; c++) list[c].cancel();
1407 }
1408
1409 /**
1410 * This is similar to jQuery's `off` function and can *hopefully* be used in the same way.
1411 *
1412 * Rather than attempt to explain, I'll show some example usages.
1413 *
1414 * The following will remove a click listener called `onClick` (in the `myPlugin` namespace) from `element`.
1415 * `DOMTools.off(element, "click.myPlugin", onClick);`
1416 *
1417 * The following will remove a click listener called `onClick` (in the `myPlugin` namespace) from `element` that only fired when the target is a `.block` element.
1418 * `DOMTools.off(element, "click.myPlugin", ".block", onClick);`
1419 *
1420 * The following will remove a click listener (without namespace) from `element`.
1421 * `DOMTools.off(element, "click", onClick);`
1422 *
1423 * The following will remove all listeners in namespace `myPlugin` from `element`.
1424 * `DOMTools.off(element, ".myPlugin");`
1425 *
1426 * The following will remove all click listeners in namespace `myPlugin` from *all elements*.
1427 * `DOMTools.off("click.myPlugin");`
1428 *
1429 * The following will remove all listeners in namespace `myPlugin` from *all elements*.
1430 * `DOMTools.off(".myPlugin");`
1431 *
1432 * @param {(Element|string)} element - Element to remove listener from
1433 * @param {string} [event] - Event to listen to with option namespace (e.g. "event.namespace")
1434 * @param {(string|callable)} [delegate] - Selector to run on element to listen to
1435 * @param {callable} [callback] - Function to fire on event
1436 * @returns {Element} - The original element to allow for chaining
1437 */
1438 static off(element, event, delegate, callback) {
1439 if (typeof(element) == "string") return this.__offAll(element);
1440 const [type, namespace] = event.split(".");
1441 if (namespace) return this.__offAll(event, element);
1442
1443 const hasDelegate = delegate && callback;
1444 if (!callback) callback = delegate;
1445 const eventFunc = !hasDelegate ? callback : function(event) {
1446 if (event.target.matches(delegate)) {
1447 callback(event);
1448 }
1449 };
1450
1451 element.removeEventListener(type, eventFunc);
1452 return element;
1453 }
1454
1455 /**
1456 * Adds a listener for when the node is added/removed from the document body.
1457 * The listener is automatically removed upon firing.
1458 * @param {HTMLElement} node - node to wait for
1459 * @param {callable} callback - function to be performed on event
1460 * @param {boolean} onMount - determines if it should fire on Mount or on Unmount
1461 */
1462 static onMountChange(node, callback, onMount = true) {
1463 const wrappedCallback = () => {
1464 this.observer.unsubscribe(wrappedCallback);
1465 callback();
1466 };
1467 this.observer.subscribe(wrappedCallback, mutation => {
1468 const nodes = Array.from(onMount ? mutation.addedNodes : mutation.removedNodes);
1469 const directMatch = nodes.indexOf(node) > -1;
1470 const parentMatch = nodes.some(parent => parent.contains(node));
1471 return directMatch || parentMatch;
1472 });
1473 return node;
1474 }
1475
1476 /** Shorthand for {@link module:DOMTools.onMountChange} with third parameter `true` */
1477 static onMount(node, callback) { return this.onMountChange(node, callback); }
1478
1479 /** Shorthand for {@link module:DOMTools.onMountChange} with third parameter `false` */
1480 static onUnmount(node, callback) { return this.onMountChange(node, callback, false); }
1481
1482 /** Alias for {@link module:DOMTools.onMount} */
1483 static onAdded(node, callback) { return this.onMount(node, callback); }
1484
1485 /** Alias for {@link module:DOMTools.onUnmount} */
1486 static onRemoved(node, callback) { return this.onUnmount(node, callback, false); }
1487
1488 /**
1489 * Helper function which combines multiple elements into one parent element
1490 * @param {Array<HTMLElement>} elements - array of elements to put into a single parent
1491 */
1492 static wrap(elements) {
1493 const domWrapper = this.parseHTML(`<div class="dom-wrapper"></div>`);
1494 for (let e = 0; e < elements.length; e++) domWrapper.appendChild(elements[e]);
1495 return domWrapper;
1496 }
1497
1498 /**
1499 * Resolves the node to an HTMLElement. This is mainly used by library modules.
1500 * @param {(jQuery|Element)} node - node to resolve
1501 */
1502 static resolveElement(node) {
1503 if (!(node instanceof jQuery) && !(node instanceof Element)) return undefined;
1504 return node instanceof jQuery ? node[0] : node;
1505 }
1506}
1507
1508_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "addClass", function(...classes) {return DOMTools.addClass(this, ...classes);});
1509_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "removeClass", function(...classes) {return DOMTools.removeClass(this, ...classes);});
1510_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "toggleClass", function(className, indicator) {return DOMTools.toggleClass(this, className, indicator);});
1511_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "replaceClass", function(oldClass, newClass) {return DOMTools.replaceClass(this, oldClass, newClass);});
1512_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "hasClass", function(className) {return DOMTools.hasClass(this, className);});
1513_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "insertAfter", function(referenceNode) {return DOMTools.insertAfter(this, referenceNode);});
1514_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "after", function(newNode) {return DOMTools.after(this, newNode);});
1515_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "next", function(selector = "") {return DOMTools.next(this, selector);});
1516_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "nextAll", function() {return DOMTools.nextAll(this);});
1517_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "nextUntil", function(selector) {return DOMTools.nextUntil(this, selector);});
1518_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "previous", function(selector = "") {return DOMTools.previous(this, selector);});
1519_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "previousAll", function() {return DOMTools.previousAll(this);});
1520_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "previousUntil", function(selector) {return DOMTools.previousUntil(this, selector);});
1521_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "index", function() {return DOMTools.index(this);});
1522_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "findChild", function(selector) {return DOMTools.findChild(this, selector);});
1523_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "findChildren", function(selector) {return DOMTools.findChildren(this, selector);});
1524_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "parent", function(selector) {return DOMTools.parent(this, selector);});
1525_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "parents", function(selector = "") {return DOMTools.parents(this, selector);});
1526_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "parentsUntil", function(selector) {return DOMTools.parentsUntil(this, selector);});
1527_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "siblings", function(selector = "*") {return DOMTools.siblings(this, selector);});
1528_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "css", function(attribute, value) {return DOMTools.css(this, attribute, value);});
1529_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "width", function(value) {return DOMTools.width(this, value);});
1530_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "height", function(value) {return DOMTools.height(this, value);});
1531_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "innerWidth", function() {return DOMTools.innerWidth(this);});
1532_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "innerHeight", function() {return DOMTools.innerHeight(this);});
1533_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "outerWidth", function() {return DOMTools.outerWidth(this);});
1534_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "outerHeight", function() {return DOMTools.outerHeight(this);});
1535_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "offset", function() {return DOMTools.offset(this);});
1536_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "text", function(value) {return DOMTools.text(this, value);});
1537_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "on", function(event, delegate, callback) {return DOMTools.on(this, event, delegate, callback);});
1538_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "once", function(event, delegate, callback) {return DOMTools.once(this, event, delegate, callback);});
1539_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "off", function(event, delegate, callback) {return DOMTools.off(this, event, delegate, callback);});
1540_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "find", function(selector) {return DOMTools.query(selector, this);});
1541_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "findAll", function(selector) {return DOMTools.queryAll(selector, this);});
1542_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "appendTo", function(otherNode) {return DOMTools.appendTo(this, otherNode);});
1543_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "onAdded", function(callback) {return DOMTools.onAdded(this, callback);});
1544_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].addToPrototype(HTMLElement, "onRemoved", function(callback) {return DOMTools.onRemoved(this, callback);});
1545
1546/***/ }),
1547
1548/***/ "./src/modules/logger.js":
1549/*!*******************************!*\
1550 !*** ./src/modules/logger.js ***!
1551 \*******************************/
1552/*! exports provided: LogTypes, default */
1553/***/ (function(module, __webpack_exports__, __webpack_require__) {
1554
1555"use strict";
1556__webpack_require__.r(__webpack_exports__);
1557/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LogTypes", function() { return LogTypes; });
1558/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return Logger; });
1559/**
1560 * Simple logger for the lib and plugins.
1561 *
1562 * @module Logger
1563 * @version 0.1.0
1564 */
1565
1566/* eslint-disable no-console */
1567
1568/**
1569 * List of logging types.
1570 */
1571const LogTypes = {
1572 /** Alias for error */
1573 err: "error",
1574 error: "error",
1575 /** Alias for debug */
1576 dbg: "debug",
1577 debug: "debug",
1578 log: "log",
1579 warn: "warn",
1580 info: "info"
1581};
1582
1583class Logger {
1584
1585 /**
1586 * Logs an error using a collapsed error group with stacktrace.
1587 *
1588 * @param {string} module - Name of the calling module.
1589 * @param {string} message - Message or error to have logged.
1590 * @param {Error} error - Error object to log with the message.
1591 */
1592 static stacktrace(module, message, error) {
1593 console.error(`%c[${module}]%c ${message}\n\n%c`, "color: #3a71c1; font-weight: 700;", "color: red; font-weight: 700;", "color: red;", error);
1594 }
1595
1596 /**
1597 * Logs using error formatting. For logging an actual error object consider {@link module:Logger.stacktrace}
1598 *
1599 * @param {string} module - Name of the calling module.
1600 * @param {string} message - Messages to have logged.
1601 */
1602 static err(module, ...message) { Logger._log(module, message, "error"); }
1603
1604 /**
1605 * Logs a warning message.
1606 *
1607 * @param {string} module - Name of the calling module.
1608 * @param {...any} message - Messages to have logged.
1609 */
1610 static warn(module, ...message) { Logger._log(module, message, "warn"); }
1611
1612 /**
1613 * Logs an informational message.
1614 *
1615 * @param {string} module - Name of the calling module.
1616 * @param {...any} message - Messages to have logged.
1617 */
1618 static info(module, ...message) { Logger._log(module, message, "info"); }
1619
1620 /**
1621 * Logs used for debugging purposes.
1622 *
1623 * @param {string} module - Name of the calling module.
1624 * @param {...any} message - Messages to have logged.
1625 */
1626 static debug(module, ...message) { Logger._log(module, message, "debug"); }
1627
1628 /**
1629 * Logs used for basic loggin.
1630 *
1631 * @param {string} module - Name of the calling module.
1632 * @param {...any} message - Messages to have logged.
1633 */
1634 static log(module, ...message) { Logger._log(module, message); }
1635
1636 /**
1637 * Logs strings using different console levels and a module label.
1638 *
1639 * @param {string} module - Name of the calling module.
1640 * @param {any|Array<any>} message - Messages to have logged.
1641 * @param {module:Logger.LogTypes} type - Type of log to use in console.
1642 */
1643 static _log(module, message, type = "log") {
1644 type = Logger.parseType(type);
1645 if (!Array.isArray(message)) message = [message];
1646 console[type](`%c[${module}]%c`, "color: #3a71c1; font-weight: 700;", "", ...message);
1647 }
1648
1649 static parseType(type) {
1650 return LogTypes.hasOwnProperty(type) ? LogTypes[type] : "log";
1651 }
1652
1653}
1654
1655/***/ }),
1656
1657/***/ "./src/modules/modules.js":
1658/*!********************************!*\
1659 !*** ./src/modules/modules.js ***!
1660 \********************************/
1661/*! exports provided: Utilities, WebpackModules, Filters, DiscordModules, ColorConverter, DOMTools, DiscordClasses, DiscordSelectors, ReactTools, ReactComponents, DiscordAPI, Logger, Patcher, PluginUpdater, PluginUtilities, DiscordClassModules, Structs */
1662/***/ (function(module, __webpack_exports__, __webpack_require__) {
1663
1664"use strict";
1665__webpack_require__.r(__webpack_exports__);
1666/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js");
1667/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Utilities", function() { return _utilities__WEBPACK_IMPORTED_MODULE_0__["default"]; });
1668
1669/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js");
1670/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "WebpackModules", function() { return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"]; });
1671
1672/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Filters", function() { return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["Filters"]; });
1673
1674/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js");
1675/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DiscordModules", function() { return _discordmodules__WEBPACK_IMPORTED_MODULE_2__["default"]; });
1676
1677/* harmony import */ var _colorconverter__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./colorconverter */ "./src/modules/colorconverter.js");
1678/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ColorConverter", function() { return _colorconverter__WEBPACK_IMPORTED_MODULE_3__["default"]; });
1679
1680/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js");
1681/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DOMTools", function() { return _domtools__WEBPACK_IMPORTED_MODULE_4__["default"]; });
1682
1683/* harmony import */ var _discordclasses__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./discordclasses */ "./src/modules/discordclasses.js");
1684/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DiscordClasses", function() { return _discordclasses__WEBPACK_IMPORTED_MODULE_5__["default"]; });
1685
1686/* harmony import */ var _discordselectors__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./discordselectors */ "./src/modules/discordselectors.js");
1687/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DiscordSelectors", function() { return _discordselectors__WEBPACK_IMPORTED_MODULE_6__["default"]; });
1688
1689/* harmony import */ var _reacttools__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./reacttools */ "./src/modules/reacttools.js");
1690/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ReactTools", function() { return _reacttools__WEBPACK_IMPORTED_MODULE_7__["default"]; });
1691
1692/* harmony import */ var _reactcomponents__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./reactcomponents */ "./src/modules/reactcomponents.js");
1693/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ReactComponents", function() { return _reactcomponents__WEBPACK_IMPORTED_MODULE_8__["default"]; });
1694
1695/* harmony import */ var _discordapi__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./discordapi */ "./src/modules/discordapi.js");
1696/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DiscordAPI", function() { return _discordapi__WEBPACK_IMPORTED_MODULE_9__["default"]; });
1697
1698/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js");
1699/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Logger", function() { return _logger__WEBPACK_IMPORTED_MODULE_10__["default"]; });
1700
1701/* harmony import */ var _patcher__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./patcher */ "./src/modules/patcher.js");
1702/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Patcher", function() { return _patcher__WEBPACK_IMPORTED_MODULE_11__["default"]; });
1703
1704/* harmony import */ var _pluginupdater__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./pluginupdater */ "./src/modules/pluginupdater.js");
1705/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "PluginUpdater", function() { return _pluginupdater__WEBPACK_IMPORTED_MODULE_12__["default"]; });
1706
1707/* harmony import */ var _pluginutilities__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./pluginutilities */ "./src/modules/pluginutilities.js");
1708/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "PluginUtilities", function() { return _pluginutilities__WEBPACK_IMPORTED_MODULE_13__["default"]; });
1709
1710/* harmony import */ var _discordclassmodules__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./discordclassmodules */ "./src/modules/discordclassmodules.js");
1711/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DiscordClassModules", function() { return _discordclassmodules__WEBPACK_IMPORTED_MODULE_14__["default"]; });
1712
1713/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! structs */ "./src/structs/structs.js");
1714/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "Structs", function() { return structs__WEBPACK_IMPORTED_MODULE_15__; });
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724// export {default as DiscordComponents} from "./discordcomponents";
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740/***/ }),
1741
1742/***/ "./src/modules/patcher.js":
1743/*!********************************!*\
1744 !*** ./src/modules/patcher.js ***!
1745 \********************************/
1746/*! exports provided: default */
1747/***/ (function(module, __webpack_exports__, __webpack_require__) {
1748
1749"use strict";
1750__webpack_require__.r(__webpack_exports__);
1751/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return Patcher; });
1752/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js");
1753/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js");
1754/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js");
1755/**
1756 * Patcher that can patch other functions allowing you to run code before, after or
1757 * instead of the original function. Can also alter arguments and return values.
1758 *
1759 * This is a modified version of what we have been working on in BDv2. {@link https://github.com/JsSucks/BetterDiscordApp/blob/master/client/src/modules/patcher.js}
1760 *
1761 * @module Patcher
1762 * @version 0.0.2
1763 */
1764
1765
1766
1767
1768
1769class Patcher {
1770
1771 static get patches() { return this._patches || (this._patches = []); }
1772
1773 /**
1774 * Returns all the patches done by a specific caller
1775 * @param {string} name - Name of the patch caller
1776 * @method
1777 */
1778 static getPatchesByCaller(name) {
1779 if (!name) return [];
1780 const patches = [];
1781 for (const patch of this.patches) {
1782 for (const childPatch of patch.children) {
1783 if (childPatch.caller === name) patches.push(childPatch);
1784 }
1785 }
1786 return patches;
1787 }
1788
1789 /**
1790 * Unpatches all patches passed, or when a string is passed unpatches all
1791 * patches done by that specific caller.
1792 * @param {Array|string} patches - Either an array of patches to unpatch or a caller name
1793 */
1794 static unpatchAll(patches) {
1795 if (typeof patches === "string") patches = this.getPatchesByCaller(patches);
1796
1797 for (const patch of patches) {
1798 patch.unpatch();
1799 }
1800 }
1801
1802 static resolveModule(module) {
1803 if (module instanceof Function || (module instanceof Object && !(module instanceof Array))) return module;
1804 if (typeof module === "string") return _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"][module];
1805 if (module instanceof Array) return _webpackmodules__WEBPACK_IMPORTED_MODULE_2__["default"].findByUniqueProperties(module);
1806 return null;
1807 }
1808
1809 static makeOverride(patch) {
1810 return function () {
1811 let returnValue = undefined;
1812 if (!patch.children || !patch.children.length) return patch.originalFunction.apply(this, arguments);
1813 for (const superPatch of patch.children.filter(c => c.type === "before")) {
1814 try {
1815 superPatch.callback(this, arguments);
1816 }
1817 catch (err) {
1818 _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("Patcher", `Could not fire before callback of ${patch.functionName} for ${superPatch.caller}`, err);
1819 }
1820 }
1821
1822 const insteads = patch.children.filter(c => c.type === "instead");
1823 if (!insteads.length) {returnValue = patch.originalFunction.apply(this, arguments);}
1824 else {
1825 for (const insteadPatch of insteads) {
1826 try {
1827 const tempReturn = insteadPatch.callback(this, arguments, patch.originalFunction.bind(this));
1828 if (typeof(tempReturn) !== "undefined") returnValue = tempReturn;
1829 }
1830 catch (err) {
1831 _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("Patcher", `Could not fire instead callback of ${patch.functionName} for ${insteadPatch.caller}`, err);
1832 }
1833 }
1834 }
1835
1836 for (const slavePatch of patch.children.filter(c => c.type === "after")) {
1837 try {
1838 const tempReturn = slavePatch.callback(this, arguments, returnValue);
1839 if (typeof(tempReturn) !== "undefined") returnValue = tempReturn;
1840 }
1841 catch (err) {
1842 _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("Patcher", `Could not fire after callback of ${patch.functionName} for ${slavePatch.caller}`, err);
1843 }
1844 }
1845 return returnValue;
1846 };
1847 }
1848
1849 static rePatch(patch) {
1850 patch.proxyFunction = patch.module[patch.functionName] = this.makeOverride(patch);
1851 }
1852
1853 static makePatch(module, functionName, name) {
1854 const patch = {
1855 name,
1856 module,
1857 functionName,
1858 originalFunction: module[functionName],
1859 proxyFunction: null,
1860 revert: () => { // Calling revert will destroy any patches added to the same module after this
1861 patch.module[patch.functionName] = patch.originalFunction;
1862 patch.proxyFunction = null;
1863 patch.children = [];
1864 },
1865 counter: 0,
1866 children: []
1867 };
1868 patch.proxyFunction = module[functionName] = this.makeOverride(patch);
1869 Object.assign(module[functionName], patch.originalFunction);
1870 module[functionName].__originalFunction = patch.originalFunction;
1871 module[functionName].toString = () => patch.originalFunction.toString();
1872 return this.patches.push(patch), patch;
1873 }
1874
1875 /**
1876 * Function with no arguments and no return value that may be called to revert changes made by {@link module:Patcher}, restoring (unpatching) original method.
1877 * @callback module:Patcher~unpatch
1878 */
1879
1880 /**
1881 * A callback that modifies method logic. This callback is called on each call of the original method and is provided all data about original call. Any of the data can be modified if necessary, but do so wisely.
1882 *
1883 * The third argument for the callback will be `undefined` for `before` patches. `originalFunction` for `instead` patches and `returnValue` for `after` patches.
1884 *
1885 * @callback module:Patcher~patchCallback
1886 * @param {object} thisObject - `this` in the context of the original function.
1887 * @param {arguments} arguments - The original arguments of the original function.
1888 * @param {(function|*)} extraValue - For `instead` patches, this is the original function from the module. For `after` patches, this is the return value of the function.
1889 * @return {*} Makes sense only when using an `instead` or `after` patch. If something other than `undefined` is returned, the returned value replaces the value of `returnValue`. If used for `before` the return value is ignored.
1890 */
1891
1892 /**
1893 * This method patches onto another function, allowing your code to run beforehand.
1894 * Using this, you are also able to modify the incoming arguments before the original method is run.
1895 *
1896 * @param {string} caller - Name of the caller of the patch function. Using this you can undo all patches with the same name using {@link module:Patcher.unpatchAll}. Use `""` if you don't care.
1897 * @param {object} moduleToPatch - Object with the function to be patched. Can also patch an object's prototype.
1898 * @param {string} functionName - Name of the method to be patched
1899 * @param {module:Patcher~patchCallback} callback - Function to run before the original method
1900 * @param {object} options - Object used to pass additional options.
1901 * @param {string} [options.displayName] You can provide meaningful name for class/object provided in `what` param for logging purposes. By default, this function will try to determine name automatically.
1902 * @param {boolean} [options.forcePatch=true] Set to `true` to patch even if the function doesnt exist. (Adds noop function in place).
1903 * @return {module:Patcher~unpatch} Function with no arguments and no return value that should be called to cancel (unpatch) this patch. You should save and run it when your plugin is stopped.
1904 */
1905 static before(caller, moduleToPatch, functionName, callback, options = {}) { return this.pushChildPatch(caller, moduleToPatch, functionName, callback, Object.assign(options, {type: "before"})); }
1906
1907 /**
1908 * This method patches onto another function, allowing your code to run after.
1909 * Using this, you are also able to modify the return value, using the return of your code instead.
1910 *
1911 * @param {string} caller - Name of the caller of the patch function. Using this you can undo all patches with the same name using {@link module:Patcher.unpatchAll}. Use `""` if you don't care.
1912 * @param {object} moduleToPatch - Object with the function to be patched. Can also patch an object's prototype.
1913 * @param {string} functionName - Name of the method to be patched
1914 * @param {module:Patcher~patchCallback} callback - Function to run instead of the original method
1915 * @param {object} options - Object used to pass additional options.
1916 * @param {string} [options.displayName] You can provide meaningful name for class/object provided in `what` param for logging purposes. By default, this function will try to determine name automatically.
1917 * @param {boolean} [options.forcePatch=true] Set to `true` to patch even if the function doesnt exist. (Adds noop function in place).
1918 * @return {module:Patcher~unpatch} Function with no arguments and no return value that should be called to cancel (unpatch) this patch. You should save and run it when your plugin is stopped.
1919 */
1920 static after(caller, moduleToPatch, functionName, callback, options = {}) { return this.pushChildPatch(caller, moduleToPatch, functionName, callback, Object.assign(options, {type: "after"})); }
1921
1922 /**
1923 * This method patches onto another function, allowing your code to run instead.
1924 * Using this, you are also able to modify the return value, using the return of your code instead.
1925 *
1926 * @param {string} caller - Name of the caller of the patch function. Using this you can undo all patches with the same name using {@link module:Patcher.unpatchAll}. Use `""` if you don't care.
1927 * @param {object} moduleToPatch - Object with the function to be patched. Can also patch an object's prototype.
1928 * @param {string} functionName - Name of the method to be patched
1929 * @param {module:Patcher~patchCallback} callback - Function to run after the original method
1930 * @param {object} options - Object used to pass additional options.
1931 * @param {string} [options.displayName] You can provide meaningful name for class/object provided in `what` param for logging purposes. By default, this function will try to determine name automatically.
1932 * @param {boolean} [options.forcePatch=true] Set to `true` to patch even if the function doesnt exist. (Adds noop function in place).
1933 * @return {module:Patcher~unpatch} Function with no arguments and no return value that should be called to cancel (unpatch) this patch. You should save and run it when your plugin is stopped.
1934 */
1935 static instead(caller, moduleToPatch, functionName, callback, options = {}) { return this.pushChildPatch(caller, moduleToPatch, functionName, callback, Object.assign(options, {type: "instead"})); }
1936
1937 /**
1938 * This method patches onto another function, allowing your code to run before, instead or after the original function.
1939 * Using this you are able to modify the incoming arguments before the original function is run as well as the return
1940 * value before the original function actually returns.
1941 *
1942 * @param {string} caller - Name of the caller of the patch function. Using this you can undo all patches with the same name using {@link module:Patcher.unpatchAll}. Use `""` if you don't care.
1943 * @param {object} moduleToPatch - Object with the function to be patched. Can also patch an object's prototype.
1944 * @param {string} functionName - Name of the method to be patched
1945 * @param {module:Patcher~patchCallback} callback - Function to run after the original method
1946 * @param {object} options - Object used to pass additional options.
1947 * @param {string} [options.type=after] - Determines whether to run the function `before`, `instead`, or `after` the original.
1948 * @param {string} [options.displayName] You can provide meaningful name for class/object provided in `what` param for logging purposes. By default, this function will try to determine name automatically.
1949 * @param {boolean} [options.forcePatch=true] Set to `true` to patch even if the function doesnt exist. (Adds noop function in place).
1950 * @return {module:Patcher~unpatch} Function with no arguments and no return value that should be called to cancel (unpatch) this patch. You should save and run it when your plugin is stopped.
1951 */
1952 static pushChildPatch(caller, moduleToPatch, functionName, callback, options = {}) {
1953 const {type = "after", forcePatch = true} = options;
1954 const module = this.resolveModule(moduleToPatch);
1955 if (!module) return null;
1956 if (!module[functionName] && forcePatch) module[functionName] = function() {};
1957 if (!(module[functionName] instanceof Function)) return null;
1958
1959 if (typeof moduleToPatch === "string") options.displayName = moduleToPatch;
1960 const displayName = options.displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
1961
1962 const patchId = `${displayName}.${functionName}`;
1963 const patch = this.patches.find(p => p.module == module && p.functionName == functionName) || this.makePatch(module, functionName, patchId);
1964 if (!patch.proxyFunction) this.rePatch(patch);
1965 const child = {
1966 caller,
1967 type,
1968 id: patch.counter,
1969 callback,
1970 unpatch: () => {
1971 patch.children.splice(patch.children.findIndex(cpatch => cpatch.id === child.id && cpatch.type === type), 1);
1972 if (patch.children.length <= 0) {
1973 const patchNum = this.patches.findIndex(p => p.module == module && p.functionName == functionName);
1974 if (patchNum < 0) return;
1975 this.patches[patchNum].revert();
1976 this.patches.splice(patchNum, 1);
1977 }
1978 }
1979 };
1980 patch.children.push(child);
1981 patch.counter++;
1982 return child.unpatch;
1983 }
1984
1985}
1986
1987/***/ }),
1988
1989/***/ "./src/modules/pluginupdater.js":
1990/*!**************************************!*\
1991 !*** ./src/modules/pluginupdater.js ***!
1992 \**************************************/
1993/*! exports provided: default */
1994/***/ (function(module, __webpack_exports__, __webpack_require__) {
1995
1996"use strict";
1997__webpack_require__.r(__webpack_exports__);
1998/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return PluginUpdater; });
1999/* harmony import */ var _pluginutilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./pluginutilities */ "./src/modules/pluginutilities.js");
2000/* harmony import */ var _patcher__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./patcher */ "./src/modules/patcher.js");
2001/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js");
2002/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js");
2003/* harmony import */ var _discordclasses__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./discordclasses */ "./src/modules/discordclasses.js");
2004/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js");
2005/* harmony import */ var ui__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ui */ "./src/ui/ui.js");
2006/**
2007 * Functions that check for and update existing plugins.
2008 * @module PluginUpdater
2009 * @version 0.1.2
2010 */
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020/**
2021 * Function that gets the remote version from the file contents.
2022 * @param {string} fileContent - the content of the remote file
2023 * @returns {string} - remote version
2024 * @callback module:PluginUpdater~versioner
2025 */
2026
2027/**
2028 * Comparator that takes the current version and the remote version,
2029 * then compares them returning `true` if there is an update and `false` otherwise.
2030 * @param {string} currentVersion - the current version of the plugin
2031 * @param {string} remoteVersion - the remote version of the plugin
2032 * @returns {boolean} - whether the plugin has an update or not
2033 * @callback module:PluginUpdater~comparator
2034 */
2035
2036class PluginUpdater {
2037
2038 static get CSS() { return __webpack_require__(/*! ../styles/updates.css */ "./src/styles/updates.css"); }
2039
2040 /**
2041 * Checks for updates for the specified plugin at the specified link. The final
2042 * parameter should link to the raw text of the plugin and will compare semantic
2043 * versions.
2044 * @param {string} pluginName - name of the plugin
2045 * @param {string} currentVersion - current version (semantic versioning only)
2046 * @param {string} updateURL - url to check for update
2047 * @param {module:PluginUpdater~versioner} [versioner] - versioner that finds the remote version. If not provided uses {@link module:PluginUpdater.defaultVersioner}.
2048 * @param {module:PluginUpdater~comparator} [comparator] - comparator that determines if there is an update. If not provided uses {@link module:PluginUpdater.defaultComparator}.
2049 */
2050 static checkForUpdate(pluginName, currentVersion, updateURL, versioner, comparator) {
2051 let updateLink = "https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/" + pluginName + "/" + pluginName + ".plugin.js";
2052 if (updateURL) updateLink = updateURL;
2053 if (typeof(versioner) != "function") versioner = this.defaultVersioner;
2054 if (typeof(comparator) != "function") comparator = this.defaultComparator;
2055
2056 if (typeof window.PluginUpdates === "undefined") {
2057 window.PluginUpdates = {
2058 plugins: {},
2059 checkAll: function() {
2060 for (const key in this.plugins) {
2061 const plugin = this.plugins[key];
2062 if (!plugin.versioner) plugin.versioner = PluginUpdater.defaultVersioner;
2063 if (!plugin.comparator) plugin.comparator = PluginUpdater.defaultComparator;
2064 PluginUpdater.processUpdateCheck(plugin.name, plugin.raw);
2065 }
2066 },
2067 interval: setInterval(() => {
2068 window.PluginUpdates.checkAll();
2069 }, 7200000)
2070 };
2071 this.patchPluginList();
2072 }
2073
2074 window.PluginUpdates.plugins[updateLink] = {name: pluginName, raw: updateLink, version: currentVersion, versioner: versioner, comparator: comparator};
2075 PluginUpdater.processUpdateCheck(pluginName, updateLink);
2076 }
2077
2078 /**
2079 * Will check for updates and automatically show or remove the update notice
2080 * bar based on the internal result. Better not to call this directly and to
2081 * instead use {@link module:PluginUpdater.checkForUpdate}.
2082 * @param {string} pluginName - name of the plugin to check
2083 * @param {string} updateLink - link to the raw text version of the plugin
2084 */
2085 static processUpdateCheck(pluginName, updateLink) {
2086 const request = __webpack_require__(/*! request */ "request");
2087 request(updateLink, (error, response, result) => {
2088 if (error) return;
2089 const remoteVersion = window.PluginUpdates.plugins[updateLink].versioner(result);
2090 const hasUpdate = window.PluginUpdates.plugins[updateLink].comparator(window.PluginUpdates.plugins[updateLink].version, remoteVersion);
2091 if (hasUpdate) this.showUpdateNotice(pluginName, updateLink);
2092 else this.removeUpdateNotice(pluginName);
2093 });
2094 }
2095
2096 /**
2097 * The default versioner used as {@link module:PluginUpdater~versioner} for {@link module:PluginUpdater.checkForUpdate}.
2098 * This works on basic semantic versioning e.g. "1.0.0". You do not need to provide this as a versioner if your plugin adheres
2099 * to this style as this will be used as default.
2100 * @param {string} currentVersion
2101 * @param {string} content
2102 */
2103 static defaultVersioner(content) {
2104 const remoteVersion = content.match(/['"][0-9]+\.[0-9]+\.[0-9]+['"]/i);
2105 if (!remoteVersion) return "0.0.0";
2106 return remoteVersion.toString().replace(/['"]/g, "");
2107 }
2108
2109 /**
2110 * The default comparator used as {@link module:PluginUpdater~comparator} for {@link module:PluginUpdater.checkForUpdate}.
2111 * This works on basic semantic versioning e.g. "1.0.0". You do not need to provide this as a comparator if your plugin adheres
2112 * to this style as this will be used as default.
2113 * @param {string} currentVersion
2114 * @param {string} content
2115 */
2116 static defaultComparator(currentVersion, remoteVersion) {
2117 currentVersion = currentVersion.split(".").map((e) => {return parseInt(e);});
2118 remoteVersion = remoteVersion.split(".").map((e) => {return parseInt(e);});
2119
2120 if (remoteVersion[0] > currentVersion[0]) return true;
2121 else if (remoteVersion[0] == currentVersion[0] && remoteVersion[1] > currentVersion[1]) return true;
2122 else if (remoteVersion[0] == currentVersion[0] && remoteVersion[1] == currentVersion[1] && remoteVersion[2] > currentVersion[2]) return true;
2123 return false;
2124 }
2125
2126 static patchPluginList() {
2127 try {
2128 V2C_ContentColumn.prototype;
2129 }
2130 catch (e) {return;}
2131 _patcher__WEBPACK_IMPORTED_MODULE_1__["default"].after("ZeresLibrary", V2C_ContentColumn.prototype, "componentDidMount", (self) => {
2132 if (self._reactInternalFiber.key != "pcolumn") return;
2133 const column = _discordmodules__WEBPACK_IMPORTED_MODULE_5__["default"].ReactDOM.findDOMNode(self);
2134 if (!column) return;
2135 const button = column.getElementsByClassName("bd-pfbtn")[0];
2136 if (!button || button.nextElementSibling.classList.contains("bd-updatebtn")) return;
2137 button.after(PluginUpdater.createUpdateButton());
2138 });
2139 const button = document.getElementsByClassName("bd-pfbtn")[0];
2140 if (!button || !button.textContent.toLowerCase().includes("plugin") || button.nextElementSibling.classList.contains("bd-updatebtn")) return;
2141 button.after(PluginUpdater.createUpdateButton());
2142 }
2143
2144 /**
2145 * Creates the update button found in the plugins page of BetterDiscord
2146 * settings. Returned button will already have listeners to create the tooltip.
2147 * @returns {HTMLElement} check for update button
2148 */
2149 static createUpdateButton() {
2150 const updateButton = _domtools__WEBPACK_IMPORTED_MODULE_2__["default"].parseHTML(`<button class="bd-pfbtn bd-updatebtn" style="left: 220px;">Check for Updates</button>`);
2151 updateButton.onclick = function () {
2152 window.PluginUpdates.checkAll();
2153 };
2154 const tooltip = new ui__WEBPACK_IMPORTED_MODULE_6__["EmulatedTooltip"](updateButton, "Checks for updates of plugins that support this feature. Right-click for a list.");
2155 updateButton.oncontextmenu = function () {
2156 if (!window.PluginUpdates || !window.PluginUpdates.plugins) return;
2157 tooltip.label = Object.values(window.PluginUpdates.plugins).map(p => p.name).join(", ");
2158 tooltip.side = "bottom";
2159 tooltip.show();
2160 updateButton.onmouseout = function() {
2161 tooltip.label = "Checks for updates of plugins that support this feature. Right-click for a list.";
2162 tooltip.side = "top";
2163 };
2164 };
2165 return updateButton;
2166 }
2167
2168 /**
2169 * Will download the latest version and replace the the old plugin version.
2170 * Will also update the button in the update bar depending on if the user
2171 * is using RestartNoMore plugin by square {@link https://github.com/Inve1951/BetterDiscordStuff/blob/master/plugins/restartNoMore.plugin.js}
2172 * @param {string} pluginName - name of the plugin to download
2173 * @param {string} updateLink - link to the raw text version of the plugin
2174 */
2175 static downloadPlugin(pluginName, updateLink) {
2176 const request = __webpack_require__(/*! request */ "request");
2177 const fileSystem = __webpack_require__(/*! fs */ "fs");
2178 const path = __webpack_require__(/*! path */ "path");
2179 request(updateLink, async (error, response, body) => {
2180 if (error) return _logger__WEBPACK_IMPORTED_MODULE_3__["default"].warn("PluginUpdates", "Unable to get update for " + pluginName);
2181 const remoteVersion = window.PluginUpdates.plugins[updateLink].versioner(body);
2182 let filename = updateLink.split("/");
2183 filename = filename[filename.length - 1];
2184 const file = path.join(_pluginutilities__WEBPACK_IMPORTED_MODULE_0__["default"].getPluginsFolder(), filename);
2185 await new Promise(r => fileSystem.writeFile(file, body, r));
2186 ui__WEBPACK_IMPORTED_MODULE_6__["Toasts"].success(`${pluginName} ${window.PluginUpdates.plugins[updateLink].version} has been replaced by ${pluginName} ${remoteVersion}`);
2187 this.removeUpdateNotice(pluginName);
2188
2189 const oldRNM = window.bdplugins["Restart-No-More"] && window.pluginCookie["Restart-No-More"];
2190 const newRNM = window.bdplugins["Restart No More"] && window.pluginCookie["Restart No More"];
2191 const BBDLoader = window.settingsCookie["fork-ps-5"];
2192 if (oldRNM || newRNM || BBDLoader) return;
2193 if (!window.PluginUpdates.downloaded) {
2194 window.PluginUpdates.downloaded = [];
2195 const button = _domtools__WEBPACK_IMPORTED_MODULE_2__["default"].parseHTML(`<button class="btn btn-reload ${_discordclasses__WEBPACK_IMPORTED_MODULE_4__["default"].Notices.btn} ${_discordclasses__WEBPACK_IMPORTED_MODULE_4__["default"].Notices.button}">Reload</button>`);
2196 const tooltip = new ui__WEBPACK_IMPORTED_MODULE_6__["EmulatedTooltip"](button, window.PluginUpdates.downloaded.join(", "), {side: "top"});
2197 button.addEventListener("click", (e) => {
2198 e.preventDefault();
2199 window.location.reload(false);
2200 });
2201 button.addEventListener("mouseenter", () => {
2202 tooltip.label = window.PluginUpdates.downloaded.join(", ");
2203 });
2204 document.getElementById("pluginNotice").append(button);
2205 }
2206 window.PluginUpdates.plugins[updateLink].version = remoteVersion;
2207 window.PluginUpdates.downloaded.push(pluginName);
2208 });
2209 }
2210
2211 /**
2212 * Will show the update notice top bar seen in Discord. Better not to call
2213 * this directly and to instead use {@link module:PluginUpdater.checkForUpdate}.
2214 * @param {string} pluginName - name of the plugin
2215 * @param {string} updateLink - link to the raw text version of the plugin
2216 */
2217 static showUpdateNotice(pluginName, updateLink) {
2218 if (!document.getElementById("pluginNotice")) {
2219 const noticeElement = _domtools__WEBPACK_IMPORTED_MODULE_2__["default"].parseHTML(`<div class="${_discordclasses__WEBPACK_IMPORTED_MODULE_4__["default"].Notices.notice} ${_discordclasses__WEBPACK_IMPORTED_MODULE_4__["default"].Notices.noticeInfo}" id="pluginNotice">
2220 <div class="${_discordclasses__WEBPACK_IMPORTED_MODULE_4__["default"].Notices.dismiss}" id="pluginNoticeDismiss"></div>
2221 <span class="notice-message">The following plugins have updates:</span> <strong id="outdatedPlugins"></strong>
2222 </div>`);
2223 _domtools__WEBPACK_IMPORTED_MODULE_2__["default"].query("[class*='app-'] > [class*='app-']").prepend(noticeElement);
2224 noticeElement.querySelector("#pluginNoticeDismiss").addEventListener("click", async () => {
2225 noticeElement.classList.add("closing");
2226 await new Promise(resolve => setTimeout(resolve, 400));
2227 noticeElement.remove();
2228 });
2229 }
2230 const pluginNoticeID = pluginName + "-notice";
2231 if (document.getElementById(pluginNoticeID)) return;
2232 const pluginNoticeElement = _domtools__WEBPACK_IMPORTED_MODULE_2__["default"].parseHTML(`<span id="${pluginNoticeID}">${pluginName}</span>`);
2233 pluginNoticeElement.addEventListener("click", () => {
2234 this.downloadPlugin(pluginName, updateLink);
2235 });
2236 if (document.getElementById("outdatedPlugins").querySelectorAll("span").length) document.getElementById("outdatedPlugins").append(_domtools__WEBPACK_IMPORTED_MODULE_2__["default"].createElement("<span class='separator'>, </span>"));
2237 document.getElementById("outdatedPlugins").append(pluginNoticeElement);
2238 }
2239
2240 /**
2241 * Will remove the plugin from the update notice top bar seen in Discord.
2242 * Better not to call this directly and to instead use {@link module:PluginUpdater.checkForUpdate}.
2243 * @param {string} pluginName - name of the plugin
2244 */
2245 static removeUpdateNotice(pluginName) {
2246 if (!document.getElementById("outdatedPlugins")) return;
2247 const notice = document.getElementById(pluginName + "-notice");
2248 if (notice) {
2249 if (notice.nextElementSibling && notice.nextElementSibling.matches(".separator")) notice.nextElementSibling.remove();
2250 else if (notice.previousElementSibling && notice.previousElementSibling.matches(".separator")) notice.previousElementSibling.remove();
2251 notice.remove();
2252 }
2253
2254 if (!document.getElementById("outdatedPlugins").querySelectorAll("span").length) {
2255 if (document.querySelector("#pluginNotice .btn-reload")) document.querySelector("#pluginNotice .notice-message").textContent = "To finish updating you need to reload.";
2256 else document.getElementById("pluginNoticeDismiss").click();
2257 }
2258 }
2259}
2260
2261/***/ }),
2262
2263/***/ "./src/modules/pluginutilities.js":
2264/*!****************************************!*\
2265 !*** ./src/modules/pluginutilities.js ***!
2266 \****************************************/
2267/*! exports provided: default */
2268/***/ (function(module, __webpack_exports__, __webpack_require__) {
2269
2270"use strict";
2271__webpack_require__.r(__webpack_exports__);
2272/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return PluginUtilities; });
2273/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js");
2274/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js");
2275/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js");
2276/* harmony import */ var _ui_discordcontextmenu__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../ui/discordcontextmenu */ "./src/ui/discordcontextmenu.js");
2277
2278
2279
2280
2281
2282
2283/**
2284 * A series of useful functions for BetterDiscord plugins.
2285 * @module PluginUtilities
2286 * @version 0.2.5
2287 */
2288
2289
2290 class PluginUtilities {
2291
2292 /**
2293 * Loads data through BetterDiscord's API.
2294 * @param {string} name - name for the file (usually plugin name)
2295 * @param {string} key - which key the data is saved under
2296 * @param {object} defaultData - default data to populate the object with
2297 * @returns {object} the combined saved and default data
2298 */
2299 static loadData(name, key, defaultData) {
2300 try { return _utilities__WEBPACK_IMPORTED_MODULE_1__["default"].extend(defaultData ? defaultData : {}, BdApi.getData(name, key)); }
2301 catch (err) { _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err(name, "Unable to load data: ", err); }
2302 }
2303
2304 /**
2305 * Saves data through BetterDiscord's API.
2306 * @param {string} name - name for the file (usually plugin name)
2307 * @param {string} key - which key the data should be saved under
2308 * @param {object} data - data to save
2309 */
2310 static saveData(name, key, data) {
2311 try { BdApi.setData(name, key, data); }
2312 catch (err) { _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err(name, "Unable to save data: ", err); }
2313 }
2314
2315 /**
2316 * Loads settings through BetterDiscord's API.
2317 * @param {string} name - name for the file (usually plugin name)
2318 * @param {object} defaultData - default data to populate the object with
2319 * @returns {object} the combined saved and default settings
2320 */
2321 static loadSettings(name, defaultSettings) {
2322 return this.loadData(name, "settings", defaultSettings);
2323 }
2324
2325 /**
2326 * Saves settings through BetterDiscord's API.
2327 * @param {string} name - name for the file (usually plugin name)
2328 * @param {object} data - settings to save
2329 */
2330 static saveSettings(name, data) {
2331 this.saveData(name, "settings", data);
2332 }
2333
2334 /**
2335 * Get the full path to the BetterDiscord folder.
2336 * @returns {string} full path to the BetterDiscord folder
2337 */
2338 static getBDFolder(subtarget = "") {
2339 const process = __webpack_require__(/*! process */ "process");
2340 const path = __webpack_require__(/*! path */ "path");
2341 if (process.env.injDir) return path.resolve(process.env.injDir, subtarget);
2342 switch (process.platform) {
2343 case "win32":
2344 return path.resolve(process.env.appdata, "BetterDiscord/", subtarget);
2345 case "darwin":
2346 return path.resolve(process.env.HOME, "Library/Preferences/", "BetterDiscord/", subtarget);
2347 default:
2348 return path.resolve(process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : process.env.HOME + "/.config", "BetterDiscord/", subtarget);
2349 }
2350 }
2351
2352 /**
2353 * Get the full path to the plugins folder.
2354 * @returns {string} full path to the plugins folder
2355 */
2356 static getPluginsFolder() {
2357 return this.getBDFolder("plugins/");
2358 }
2359
2360 /**
2361 * Get the full path to the themes folder.
2362 * @returns {string} full path to the themes folder
2363 */
2364 static getThemesFolder() {
2365 return this.getBDFolder("themes/");
2366 }
2367
2368 /**
2369 * Adds a callback to a set of listeners for onSwitch.
2370 * @param {callable} callback - basic callback to happen on channel switch
2371 */
2372 static addOnSwitchListener(callback) {
2373 __webpack_require__(/*! electron */ "electron").remote.getCurrentWebContents().on("did-navigate-in-page", callback);
2374 }
2375
2376 /**
2377 * Removes the listener added by {@link InternalUtilities.addOnSwitchListener}.
2378 * @param {callable} callback - callback to remove from the listener list
2379 */
2380 static removeOnSwitchListener(callback) {
2381 __webpack_require__(/*! electron */ "electron").remote.getCurrentWebContents().removeListener("did-navigate-in-page", callback);
2382 }
2383
2384 /**
2385 * Adds a style to the document.
2386 * @param {string} id - identifier to use as the element id
2387 * @param {string} css - css to add to the document
2388 */
2389 static addStyle(id, css) {
2390 document.head.append(_domtools__WEBPACK_IMPORTED_MODULE_2__["default"].createElement(`<style id="${id}">${css}</style>`));
2391 }
2392
2393 /**
2394 * Removes a style from the document.
2395 * @param {string} id - original identifier used
2396 */
2397 static removeStyle(id) {
2398 const element = document.getElementById(id);
2399 if (element) element.remove();
2400 }
2401
2402 /**
2403 * Adds/requires a remote script to be loaded
2404 * @param {string} id - identifier to use for this script
2405 * @param {string} url - url from which to load the script
2406 * @returns {Promise} promise that resolves when the script is loaded
2407 */
2408 static addScript(id, url) {
2409 return new Promise(resolve => {
2410 const script = document.createElement("script");
2411 script.id = id;
2412 script.src = url;
2413 script.type = "text/javascript";
2414 script.onload = resolve;
2415 document.head.append(script);
2416 });
2417 }
2418
2419 /**
2420 * Removes a remote script from the document.
2421 * @param {string} id - original identifier used
2422 */
2423 static removeScript(id) {
2424 const element = document.getElementById(id);
2425 if (element) element.remove();
2426 }
2427
2428 static async getContextMenu(type) {
2429 return _ui_discordcontextmenu__WEBPACK_IMPORTED_MODULE_3__["default"].getDiscordMenu(type);
2430 }
2431
2432 static forceUpdateContextMenus() {
2433 return _ui_discordcontextmenu__WEBPACK_IMPORTED_MODULE_3__["default"].forceUpdateMenus();
2434 }
2435}
2436
2437
2438
2439
2440/***/ }),
2441
2442/***/ "./src/modules/reactcomponents.js":
2443/*!****************************************!*\
2444 !*** ./src/modules/reactcomponents.js ***!
2445 \****************************************/
2446/*! exports provided: ReactHelpers, default */
2447/***/ (function(module, __webpack_exports__, __webpack_require__) {
2448
2449"use strict";
2450__webpack_require__.r(__webpack_exports__);
2451/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReactHelpers", function() { return Helpers; });
2452/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return ReactComponents; });
2453/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js");
2454/* harmony import */ var _patcher__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./patcher */ "./src/modules/patcher.js");
2455/* harmony import */ var _reflection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./reflection */ "./src/modules/reflection.js");
2456/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js");
2457/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js");
2458/* harmony import */ var _reacttools__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./reacttools */ "./src/modules/reacttools.js");
2459/**
2460 * BetterDiscord React Component Manipulations
2461 * Original concept and some code by samogot - https://github.com/samogot / https://github.com/samogot/betterdiscord-plugins/tree/master/v2/1Lib%20Discord%20Internals
2462 *
2463 * Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
2464 * All rights reserved.
2465 * https://github.com/JsSucks - https://betterdiscord.net
2466 *
2467 * This source code is licensed under the MIT license found in the
2468 * LICENSE file in the root directory of this source tree.
2469*/
2470
2471// import Logger from "./logger";
2472
2473
2474
2475
2476
2477
2478
2479class Helpers {
2480 static get plannedActions() {
2481 return this._plannedActions || (this._plannedActions = new Map());
2482 }
2483
2484 static recursiveArray(parent, key, count = 1) {
2485 let index = 0;
2486 function* innerCall(parent, key) {
2487 const item = parent[key];
2488 if (item instanceof Array) {
2489 for (const subKey of item.keys()) {
2490 yield* innerCall(item, subKey);
2491 }
2492 return;
2493 }
2494 yield {item, parent, key, index: index++, count};
2495 }
2496
2497 return innerCall(parent, key);
2498 }
2499
2500 static recursiveArrayCount(parent, key) {
2501 let count = 0;
2502 // eslint-disable-next-line no-empty-pattern
2503 for (let {} of this.recursiveArray(parent, key)) ++count;
2504 return this.recursiveArray(parent, key, count);
2505 }
2506
2507 static get recursiveChildren() {
2508 return function* (parent, key, index = 0, count = 1) {
2509 const item = parent[key];
2510 yield {item, parent, key, index, count};
2511 if (item && item.props && item.props.children) {
2512 for (const {parent, key, index, count} of this.recursiveArrayCount(item.props, "children")) {
2513 yield* this.recursiveChildren(parent, key, index, count);
2514 }
2515 }
2516 };
2517 }
2518
2519 static returnFirst(iterator, process) {
2520 for (const child of iterator) {
2521 const retVal = process(child);
2522 if (retVal !== undefined) return retVal;
2523 }
2524 }
2525
2526 static getFirstChild(rootParent, rootKey, selector) {
2527 const getDirectChild = (item, selector) => {
2528 if (item && item.props && item.props.children) {
2529 return this.returnFirst(this.recursiveArrayCount(item.props, "children"), checkFilter.bind(null, selector));
2530 }
2531 };
2532 const checkFilter = (selector, {item, parent, key, count, index}) => {
2533 let match = true;
2534 if (selector.type) match = item && selector.type === item.type;
2535 if (match && selector.tag) match = item && typeof item.type === "string" && selector.tag === item.type;
2536 if (match && selector.className) {
2537 match = item && item.props && typeof item.props.className === "string";
2538 if (match) {
2539 const classes = item.props.className.split(" ");
2540 if (selector.className === true) match = !!classes[0];
2541 else if (typeof selector.className === "string") match = classes.includes(selector.className);
2542 else if (selector.className instanceof RegExp) match = !!classes.find(cls => selector.className.test(cls));
2543 else match = false;
2544 }
2545 }
2546 if (match && selector.text) {
2547 if (selector.text === true) match = typeof item === "string";
2548 else if (typeof selector.text === "string") match = item === selector.text;
2549 else if (selector.text instanceof RegExp) match = typeof item === "string" && selector.text.test(item);
2550 else match = false;
2551 }
2552 if (match && selector.nthChild) match = index === (selector.nthChild < 0 ? count + selector.nthChild : selector.nthChild);
2553 if (match && selector.hasChild) match = getDirectChild(item, selector.hasChild);
2554 if (match && selector.hasSuccessor) match = item && !!this.getFirstChild(parent, key, selector.hasSuccessor).item;
2555 if (match && selector.eq) {
2556 --selector.eq;
2557 return;
2558 }
2559 if (match) {
2560 if (selector.child) return getDirectChild(item, selector.child);
2561 else if (selector.successor) return this.getFirstChild(parent, key, selector.successor);
2562 return {item, parent, key};
2563 }
2564 };
2565 return this.returnFirst(this.recursiveChildren(rootParent, rootKey), checkFilter.bind(null, selector)) || {};
2566 }
2567
2568 static parseSelector(selector) {
2569 if (selector.startsWith(".")) return {className: selector.substr(1)};
2570 if (selector.startsWith("#")) return {id: selector.substr(1)};
2571 return {};
2572 }
2573
2574 static findByProp(obj, what, value) {
2575 if (obj.hasOwnProperty(what) && obj[what] === value) return obj;
2576 if (obj.props && !obj.children) return this.findByProp(obj.props, what, value);
2577 if (!obj.children) return null;
2578 if (!(obj.children instanceof Array)) return this.findByProp(obj.children, what, value);
2579 for (const child of obj.children) {
2580 if (!child) continue;
2581 const findInChild = this.findByProp(child, what, value);
2582 if (findInChild) return findInChild;
2583 }
2584 return null;
2585 }
2586
2587 static findProp(obj, what) {
2588 if (obj.hasOwnProperty(what)) return obj[what];
2589 if (obj.props && !obj.children) return this.findProp(obj.props, what);
2590 if (!obj.children) return null;
2591 if (!(obj.children instanceof Array)) return this.findProp(obj.children, what);
2592 for (const child of obj.children) {
2593 if (!child) continue;
2594 const findInChild = this.findProp(child, what);
2595 if (findInChild) return findInChild;
2596 }
2597 return null;
2598 }
2599
2600 static get React() {
2601 return _discordmodules__WEBPACK_IMPORTED_MODULE_3__["default"].React;
2602 }
2603
2604 static get ReactDOM() {
2605 return _discordmodules__WEBPACK_IMPORTED_MODULE_3__["default"].ReactDOM;
2606 }
2607}
2608
2609
2610
2611class ReactComponent {
2612 constructor(id, component, selector, filter) {
2613 this.id = id;
2614 this.component = component;
2615 // this.important = important;
2616 this.selector = selector;
2617 this.filter = filter;
2618 }
2619
2620 forceUpdateAll() {
2621 if (!this.selector) return;
2622 for (const e of document.querySelectorAll(this.selector)) {
2623 Object(_reflection__WEBPACK_IMPORTED_MODULE_2__["default"])(e).forceUpdate(this);
2624 }
2625 }
2626}
2627
2628/**
2629 * Methods for obtaining and interacting with react components.
2630 * @module ReactComponents
2631 * @version 0.0.1
2632 */
2633class ReactComponents {
2634 static get components() {return this._components || (this._components = []);}
2635 static get unknownComponents() {return this._unknownComponents || (this._unknownComponents = []);}
2636 static get listeners() {return this._listeners || (this._listeners = []);}
2637 static get nameSetters() {return this._nameSetters || (this._nameSetters = []);}
2638
2639 static get ReactComponent() {return ReactComponent;}
2640 static get Helpers() {return Helpers;}
2641 static get AutoPatcher() {return ReactAutoPatcher;}
2642
2643 static push(component, selector, filter) {
2644 if (!(component instanceof Function)) return null;
2645 const {displayName} = component;
2646 if (!displayName) return this.processUnknown(component);
2647
2648 const have = this.components.find(comp => comp.id === displayName);
2649 if (have) {
2650 if (!have.selector) have.selector = selector;
2651 if (!have.filter) have.filter = filter;
2652 return component;
2653 }
2654
2655 const c = new ReactComponent(displayName, component, selector, filter);
2656 this.components.push(c);
2657 // if (!have) this.components.push(c);
2658
2659 const listener = this.listeners.find(listener => listener.id === displayName);
2660 if (listener) {
2661 for (const l of listener.listeners) l(c);
2662 _utilities__WEBPACK_IMPORTED_MODULE_0__["default"].removeFromArray(this.listeners, listener);
2663 }
2664
2665 // for (const listen of this.listeners) {
2666 // if (!listen.filter) continue;
2667 // }
2668
2669 return c;
2670 }
2671
2672 /**
2673 * Finds a component from the components array or by waiting for it to be mounted.
2674 * @param {String} name The component's name
2675 * @param {Object} selector A selector to look for
2676 * @return {Promise<ReactComponent>}
2677 */
2678 static async getComponentByName(name, selector) {
2679 return this.getComponent(name, selector, m => m.displayName == name);
2680 }
2681
2682 /**
2683 * Finds a component from the components array or by waiting for it to be mounted.
2684 * @param {String} name The component's name
2685 * @param {Object} selector A selector to look for
2686 * @param {Function} filter A function to filter components if a single element is rendered by multiple components
2687 * @return {Promise<ReactComponent>}
2688 */
2689 static async getComponent(name, selector, filter) {
2690 const have = this.components.find(c => c.id === name);
2691 if (have) return have;
2692
2693 if (selector) {
2694 const callback = () => {
2695 if (this.components.find(c => c.id === name)) {
2696 // Logger.info("ReactComponents", `Important component ${name} already found`);
2697 _domtools__WEBPACK_IMPORTED_MODULE_4__["default"].observer.unsubscribe(observerSubscription);
2698 return;
2699 }
2700
2701 const elements = document.querySelectorAll(selector);
2702 if (!elements.length) return;
2703
2704 let component, reflect;
2705 for (const element of elements) {
2706 reflect = Object(_reflection__WEBPACK_IMPORTED_MODULE_2__["default"])(element);
2707 component = filter ? reflect.components.find(filter) : reflect.component;
2708 if (component) break;
2709 }
2710
2711 if (!component && filter) return;// Logger.log("ReactComponents", ["Found elements matching the query selector but no components passed the filter"]);
2712
2713 _domtools__WEBPACK_IMPORTED_MODULE_4__["default"].observer.unsubscribe(observerSubscription);
2714
2715 if (!component) return;// Logger.err("ReactComponents", [`FAILED TO GET IMPORTANT COMPONENT ${name} WITH REFLECTION FROM`, elements]);
2716
2717 if (!component.displayName) component.displayName = name;
2718 // if (component.displayName && component.displayName != name) {
2719 // let existing = this.listeners.find(l => l.id === component.displayName);
2720 // let current = this.listeners.find(l => l.id === name);
2721 // if (!existing) {current.id = component.displayName;}
2722 // else {
2723 // existing.listeners.push(current.listeners);
2724 // Utilities.removeFromArray(this.listeners, current);
2725 // }
2726 // }
2727 //Logger.info("ReactComponents", [`Found important component ${name} with reflection`, reflect]);
2728
2729 this.push(component, selector, filter);
2730 };
2731
2732 const observerSubscription = _domtools__WEBPACK_IMPORTED_MODULE_4__["default"].observer.subscribeToQuerySelector(callback, selector, null, true);
2733 setTimeout(callback, 0);
2734 }
2735
2736 let listener = this.listeners.find(l => l.id === name);
2737 if (!listener) {
2738 this.listeners.push(listener = {
2739 id: name,
2740 listeners: [],
2741 filter
2742 });
2743 }
2744
2745
2746 return new Promise(resolve => {
2747 listener.listeners.push(resolve);
2748 });
2749 }
2750
2751 static setName(name, filter) {
2752 const have = this.components.find(c => c.id === name);
2753 if (have) return have;
2754
2755 for (const [rci, rc] of this.unknownComponents.entries()) {
2756 if (filter(rc.component)) {
2757 rc.component.displayName = name;
2758 this.unknownComponents.splice(rci, 1);
2759 return this.push(rc.component);
2760 }
2761 }
2762 return this.nameSetters.push({name, filter});
2763 }
2764
2765 static processUnknown(component) {
2766 const have = this.unknownComponents.find(c => c.component === component);
2767 for (const [fi, filter] of this.nameSetters.entries()) {
2768 if (filter.filter.filter(component)) {
2769 // Logger.log("ReactComponents", "Filter match!");
2770 component.displayName = filter.name;
2771 this.nameSetters.splice(fi, 1);
2772 return this.push(component);
2773 }
2774 }
2775 if (have) return have;
2776 this.unknownComponents.push(component);
2777 return component;
2778 }
2779
2780 static *recursiveComponents(internalInstance = _reacttools__WEBPACK_IMPORTED_MODULE_5__["default"].rootInstance) {
2781 if (internalInstance.stateNode) yield internalInstance.stateNode;
2782 if (internalInstance.sibling) yield *this.recursiveComponents(internalInstance.sibling);
2783 if (internalInstance.child) yield *this.recursiveComponents(internalInstance.child);
2784 }
2785}
2786
2787class ReactAutoPatcher {
2788 /**
2789 * Wait for React to be loaded and patch it's createElement to store all unknown components.
2790 * Also patches some known components.
2791 */
2792 static async autoPatch() {
2793 this.autoUnpatch();
2794 _patcher__WEBPACK_IMPORTED_MODULE_1__["default"].before("ReactComponents", _discordmodules__WEBPACK_IMPORTED_MODULE_3__["default"].React, "createElement", (react, [component]) => ReactComponents.push(component));
2795 _patcher__WEBPACK_IMPORTED_MODULE_1__["default"].instead("ReactComponents", _discordmodules__WEBPACK_IMPORTED_MODULE_3__["default"].React.Component.prototype, "UNSAFE_componentWillMount", (component) => ReactComponents.push(component));
2796 _patcher__WEBPACK_IMPORTED_MODULE_1__["default"].instead("ReactComponents", _discordmodules__WEBPACK_IMPORTED_MODULE_3__["default"].React.Component.prototype, "componentWillMount", (component) => ReactComponents.push(component));
2797 // this.patchComponents();
2798 }
2799
2800 static async autoUnpatch() {
2801 _patcher__WEBPACK_IMPORTED_MODULE_1__["default"].unpatchAll("ReactComponents");
2802 }
2803
2804 /**
2805 * Finds and processes all currently available react components.
2806 */
2807 static processAll() {
2808 for (const component of ReactComponents.recursiveComponents()) {
2809 ReactComponents.push(component.constructor);
2810 }
2811 }
2812}
2813
2814
2815/***/ }),
2816
2817/***/ "./src/modules/reacttools.js":
2818/*!***********************************!*\
2819 !*** ./src/modules/reacttools.js ***!
2820 \***********************************/
2821/*! exports provided: default */
2822/***/ (function(module, __webpack_exports__, __webpack_require__) {
2823
2824"use strict";
2825__webpack_require__.r(__webpack_exports__);
2826/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return ReactTools; });
2827/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js");
2828/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js");
2829/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js");
2830/* harmony import */ var _reflection__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./reflection */ "./src/modules/reflection.js");
2831/**
2832 * Helpful utilities for dealing with getting react information from DOM objects.
2833 * @module ReactTools
2834 * @version 0.0.5
2835 */
2836
2837
2838
2839
2840
2841
2842class ReactTools {
2843
2844 /**
2845 * Performs reflection on a specific node.
2846 * @param {(HTMLElement|jQuery|Selector)} node - node or selector to reflect on.
2847 */
2848 static Reflect(node) {
2849 return Object(_reflection__WEBPACK_IMPORTED_MODULE_3__["default"])(node);
2850 }
2851
2852 static get rootInstance() {return document.getElementById("app-mount")._reactRootContainer._internalRoot.current;}
2853
2854 /**
2855 * Grabs the react internal instance of a specific node.
2856 * @param {(HTMLElement|jQuery)} node - node to obtain react instance of
2857 * @return {object} the internal react instance
2858 */
2859 static getReactInstance(node) {
2860 if (!(node instanceof window.jQuery) && !(node instanceof Element)) return undefined;
2861 const domNode = node instanceof window.jQuery ? node[0] : node;
2862 return domNode[Object.keys(domNode).find((key) => key.startsWith("__reactInternalInstance"))];
2863 }
2864
2865 /**
2866 * Grabs a value from the react internal instance. Allows you to grab
2867 * long depth values safely without accessing no longer valid properties.
2868 * @param {(HTMLElement|jQuery)} node - node to obtain react instance of
2869 * @param {string} path - path to the requested value
2870 * @return {(*|undefined)} the value requested or undefined if not found.
2871 */
2872 static getReactProperty(node, path) {
2873 return _utilities__WEBPACK_IMPORTED_MODULE_2__["default"].getNestedProp(this.getReactInstance(node), path);
2874 }
2875
2876 /**
2877 * Grabs a value from the react internal instance. Allows you to grab
2878 * long depth values safely without accessing no longer valid properties.
2879 * @param {(HTMLElement|jQuery)} node - node to obtain react instance of
2880 * @param {object} options - options for the search
2881 * @param {array} [options.include] - list of items to include from the search
2882 * @param {array} [options.exclude=["Popout", "Tooltip", "Scroller", "BackgroundFlash"]] - list of items to exclude from the search
2883 * @param {callable} [options.filter=_=>_] - filter to check the current instance with (should return a boolean)
2884 * @return {(*|null)} the owner instance or undefined if not found.
2885 */
2886 static getOwnerInstance(node, {include, exclude = ["Popout", "Tooltip", "Scroller", "BackgroundFlash"], filter = _ => _} = {}) {
2887 if (node === undefined) return undefined;
2888 const excluding = include === undefined;
2889 const nameFilter = excluding ? exclude : include;
2890 function getDisplayName(owner) {
2891 const type = owner.type;
2892 if (!type) return null;
2893 return type.displayName || type.name || null;
2894 }
2895 function classFilter(owner) {
2896 const name = getDisplayName(owner);
2897 return (name !== null && !!(nameFilter.includes(name) ^ excluding));
2898 }
2899
2900 let curr = this.getReactInstance(node);
2901 for (curr = curr && curr.return; !_utilities__WEBPACK_IMPORTED_MODULE_2__["default"].isNil(curr); curr = curr.return) {
2902 if (_utilities__WEBPACK_IMPORTED_MODULE_2__["default"].isNil(curr)) continue;
2903 const owner = curr.stateNode;
2904 if (!_utilities__WEBPACK_IMPORTED_MODULE_2__["default"].isNil(owner) && !(owner instanceof HTMLElement) && classFilter(curr) && filter(owner)) return owner;
2905 }
2906
2907 return null;
2908 }
2909
2910 /**
2911 * Creates and renders a react element that wraps dom elements.
2912 * @param {(HTMLElement|Array<HTMLElement>)} element - element or array of elements to wrap into a react element
2913 * @returns {object} - rendered react element
2914 */
2915 static createWrappedElement(element) {
2916 if (Array.isArray(element)) element = _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].wrap(element);
2917 return _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].React.createElement(this.wrapElement(element));
2918 }
2919
2920 /**
2921 * Creates an unrendered react component that wraps dom elements.
2922 * @param {(HTMLElement|Array<HTMLElement>)} element - element or array of elements to wrap into a react component
2923 * @returns {object} - unrendered react component
2924 */
2925 static wrapElement(element) {
2926 if (Array.isArray(element)) element = _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].wrap(element);
2927 return class ReactWrapper extends _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].React.Component {
2928 constructor(props) {
2929 super(props);
2930 this.element = element;
2931 }
2932
2933 componentDidMount() {this.refs.element.appendChild(this.element);}
2934 render() {return _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].React.createElement("div", {className: "react-wrapper", ref: "element"});}
2935 };
2936 }
2937}
2938
2939/***/ }),
2940
2941/***/ "./src/modules/reflection.js":
2942/*!***********************************!*\
2943 !*** ./src/modules/reflection.js ***!
2944 \***********************************/
2945/*! exports provided: default */
2946/***/ (function(module, __webpack_exports__, __webpack_require__) {
2947
2948"use strict";
2949__webpack_require__.r(__webpack_exports__);
2950/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js");
2951/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js");
2952/* harmony import */ var _reactcomponents__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./reactcomponents */ "./src/modules/reactcomponents.js");
2953/**
2954 * BetterDiscord Reflection Module
2955 * Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
2956 * All rights reserved.
2957 * https://betterdiscord.net
2958 *
2959 * This source code is licensed under the MIT license found in the
2960 * LICENSE file in the root directory of this source tree.
2961*/
2962
2963
2964
2965
2966
2967class Reflection {
2968 static reactInternalInstance(node) {
2969 if (!node) return null;
2970 if (!Object.keys(node) || !Object.keys(node).length) return null;
2971 const riiKey = Object.keys(node).find(k => k.startsWith("__reactInternalInstance"));
2972 return riiKey ? node[riiKey] : null;
2973 }
2974
2975 static findProp(node, prop) {
2976 const ii = this.reactInternalInstance(node);
2977 if (!ii) return null;
2978 const fir = this.findInReturn(ii, prop);
2979 if (fir) return fir;
2980 const fim = this.findInChildProps(ii, prop);
2981 if (fim) return fim;
2982 return null;
2983 }
2984
2985 static findInReturn(internalInstance, prop) {
2986 const r = internalInstance.return;
2987 if (!r) return null;
2988 let find = this.findMemoizedProp(r, prop);
2989 if (find) return find;
2990 find = this.findMemoizedState(r, prop);
2991 if (find) return find;
2992 return this.findInReturn(r, prop);
2993 }
2994
2995 static findMemoizedProp(obj, prop) {
2996 if (!obj.hasOwnProperty("memoizedProps")) return null;
2997 obj = obj.memoizedProps;
2998 return this.findPropIn(obj, prop);
2999 }
3000
3001 static findMemoizedState(obj, prop) {
3002 if (!obj.hasOwnProperty("memoizedState")) return null;
3003 obj = obj.memoizedState;
3004 return this.findPropIn(obj, prop);
3005 }
3006
3007 static findInChildProps(obj, prop) {
3008 try {
3009 const f = obj.children || obj.memoizedProps.children;
3010 if (!f.props) return null;
3011 if (!f.props.hasOwnProperty(prop)) return null;
3012 return f.props[prop];
3013 }
3014 catch (err) {
3015 return null;
3016 }
3017 }
3018
3019 static findPropIn(obj, prop) {
3020 if (obj && !(obj instanceof Array) && obj instanceof Object && obj.hasOwnProperty(prop)) return obj[prop];
3021 if (obj && obj instanceof Array) {
3022 const found = obj.find(mp => {
3023 if (mp.props && mp.props.hasOwnProperty(prop)) return true;
3024 });
3025 if (found) return found;
3026 }
3027 return null;
3028 }
3029
3030 static propIterator(obj, propNames) {
3031 if (obj === null || obj === undefined) return null;
3032 const curPropName = propNames.shift(1);
3033 if (!obj.hasOwnProperty(curPropName)) return null;
3034 const curProp = obj[curPropName];
3035 if (propNames.length === 0) {
3036 return curProp;
3037 }
3038 return this.propIterator(curProp, propNames);
3039 }
3040
3041 static getState(node) {
3042 const stateNode = this.getStateNode(node);
3043 if (stateNode) return stateNode.state;
3044 }
3045
3046 static getStateNode(node) {
3047 return this.getStateNodes(node)[0];
3048 }
3049
3050 static getStateNodes(node) {
3051 const instance = this.reactInternalInstance(node);
3052 const stateNodes = [];
3053 let lastInstance = instance;
3054
3055 while (lastInstance && lastInstance.return) {
3056 if (lastInstance.return.stateNode instanceof HTMLElement) break;
3057 if (lastInstance.return.stateNode) stateNodes.push(lastInstance.return.stateNode);
3058 lastInstance = lastInstance.return;
3059 }
3060
3061 return stateNodes;
3062 }
3063
3064 static getComponentStateNode(node, component) {
3065 if (component instanceof _reactcomponents__WEBPACK_IMPORTED_MODULE_2__["default"].ReactComponent) component = component.component;
3066
3067 for (const stateNode of this.getStateNodes(node)) {
3068 if (stateNode instanceof component) return stateNode;
3069 }
3070 }
3071
3072 static findStateNode(node, filter, first = true) {
3073 return this.getStateNodes(node)[first ? "find" : "filter"](filter);
3074 }
3075
3076 static getComponent(node) {
3077 return this.getComponents(node)[0];
3078 }
3079
3080 static getComponents(node) {
3081 const instance = this.reactInternalInstance(node);
3082 const components = [];
3083 let lastInstance = instance;
3084
3085 while (lastInstance && lastInstance.return) {
3086 if (typeof lastInstance.return.type === "string") break;
3087 if (lastInstance.return.type) components.push(lastInstance.return.type);
3088 lastInstance = lastInstance.return;
3089 }
3090
3091 return components;
3092 }
3093
3094 static findComponent(node, filter, first = true) {
3095 return this.getComponents(node)[first ? "find" : "filter"](filter);
3096 }
3097}
3098
3099const propsProxyHandler = {
3100 get(node, prop) {
3101 return Reflection.findProp(node, prop);
3102 }
3103};
3104
3105/* harmony default export */ __webpack_exports__["default"] = (function(node) {
3106 return new class ReflectionInstance {
3107 constructor(node) {
3108 if (typeof node === "string") node = document.querySelector(node);
3109 this.node = node instanceof window.jQuery ? node[0] : node;
3110 }
3111
3112 get el() { return this.node; }
3113 get element() { return this.node; }
3114
3115 get reactInternalInstance() {
3116 return Reflection.reactInternalInstance(this.node);
3117 }
3118
3119 get props() {
3120 return new Proxy(this.node, propsProxyHandler);
3121 }
3122 get state() {
3123 return Reflection.getState(this.node);
3124 }
3125
3126 get stateNode() {
3127 return Reflection.getStateNode(this.node);
3128 }
3129 get stateNodes() {
3130 return Reflection.getStateNodes(this.node);
3131 }
3132 getComponentStateNode(component) {
3133 return Reflection.getComponentStateNode(this.node, component);
3134 }
3135 findStateNode(filter) {
3136 if (typeof filter === "function") return Reflection.findStateNode(this.node, filter);
3137 if (filter) return Reflection.getComponentStateNode(this.node, filter);
3138 return Reflection.getStateNode(this.node);
3139 }
3140
3141 get component() {
3142 return Reflection.getComponent(this.node);
3143 }
3144 get components() {
3145 return Reflection.getComponents(this.node);
3146 }
3147 getComponentByProps(props, selector) {
3148 return Reflection.findComponent(this.node, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["Filters"].byProperties(props, selector));
3149 }
3150 getComponentByPrototypes(props, selector) {
3151 return Reflection.findComponent(this.node, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["Filters"].byPrototypeFields(props, selector));
3152 }
3153 getComponentByRegex(regex, selector) {
3154 return Reflection.findComponent(this.node, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["Filters"].byCode(regex, selector));
3155 }
3156 getComponentByDisplayName(name) {
3157 return Reflection.findComponent(this.node, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["Filters"].byDisplayName(name));
3158 }
3159
3160 forceUpdate(filter) {
3161 try {
3162 const stateNode = this.findStateNode(filter);
3163 if (!stateNode || !stateNode.forceUpdate) return;
3164 stateNode.forceUpdate();
3165 }
3166 catch (err) {
3167 _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("Reflection", err);
3168 }
3169 }
3170
3171 prop(propName) {
3172 const split = propName.split(".");
3173 const first = Reflection.findProp(this.node, split[0]);
3174 if (split.length === 1) return first;
3175 return Reflection.propIterator(first, split.slice(1));
3176 }
3177 }(node);
3178});
3179
3180
3181/***/ }),
3182
3183/***/ "./src/modules/utilities.js":
3184/*!**********************************!*\
3185 !*** ./src/modules/utilities.js ***!
3186 \**********************************/
3187/*! exports provided: default */
3188/***/ (function(module, __webpack_exports__, __webpack_require__) {
3189
3190"use strict";
3191__webpack_require__.r(__webpack_exports__);
3192/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return Utilities; });
3193/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js");
3194/**
3195 * Random set of utilities that didn't fit elsewhere.
3196 * @module Utilities
3197 * @version 0.0.2
3198 */
3199
3200
3201
3202class Utilities {
3203
3204 /**
3205 * Stably sorts arrays since `.sort()` has issues.
3206 * @param {Array} list - array to sort
3207 * @param {function} comparator - comparator to sort by
3208 */
3209 static stableSort(list, comparator) {
3210 const entries = Array(length);
3211
3212 // wrap values with initial indices
3213 for (let index = 0; index < list.length; index++) {
3214 entries[index] = [index, list[index]];
3215 }
3216
3217 // sort with fallback based on initial indices
3218 entries.sort(function (a, b) {
3219 const comparison = Number(this(a[1], b[1]));
3220 return comparison || a[0] - b[0];
3221 }.bind(comparator));
3222
3223 // re-map original array to stable sorted values
3224 for (let index = 0; index < list.length; index++) {
3225 list[index] = entries[index][1];
3226 }
3227 }
3228
3229 /**
3230 * Generates an automatically memoizing version of an object.
3231 * @param {Object} object - object to memoize
3232 * @returns {Proxy} the proxy to the object that memoizes properties
3233 */
3234 static memoizeObject(object) {
3235 const proxy = new Proxy(object, {
3236 get: function(obj, mod) {
3237 if (!obj.hasOwnProperty(mod)) return undefined;
3238 if (Object.getOwnPropertyDescriptor(obj, mod).get) {
3239 const value = obj[mod];
3240 delete obj[mod];
3241 obj[mod] = value;
3242 }
3243 return obj[mod];
3244 },
3245 set: function(obj, mod, value) {
3246 if (obj.hasOwnProperty(mod)) return _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("MemoizedObject", "Trying to overwrite existing property");
3247 obj[mod] = value;
3248 return obj[mod];
3249 }
3250 });
3251
3252 Object.defineProperty(proxy, "hasOwnProperty", {value: function(prop) {
3253 return this[prop] !== undefined;
3254 }});
3255
3256 return proxy;
3257 }
3258
3259 /**
3260 * Wraps the method in a `try..catch` block.
3261 * @param {callable} method - method to wrap
3262 * @param {string} description - description of method
3263 * @returns {callable} wrapped version of method
3264 */
3265 static suppressErrors(method, description) {
3266 return (...params) => {
3267 try { return method(...params); }
3268 catch (e) { _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("Suppression", "Error occurred in " + description, e); }
3269 };
3270 }
3271
3272 /**
3273 * This only exists because Samo relied on lodash being there... fuck lodash.
3274 * @param {*} anything - whatever you want
3275 */
3276 static isNil(anything) {
3277 return anything == null;
3278 }
3279
3280 /**
3281 * Format template strings with placeholders (`${placeholder}`) into full strings.
3282 * Quick example: `PluginUtilities.formatString("Hello, ${user}", {user: "Zerebos"})`
3283 * would return "Hello, Zerebos".
3284 * @param {string} string - string to format
3285 * @param {object} values - object literal of placeholders to replacements
3286 * @returns {string} the properly formatted string
3287 */
3288 static formatTString(string, values) {
3289 for (const val in values) {
3290 let replacement = values[val];
3291 if (Array.isArray(replacement)) replacement = JSON.stringify(replacement);
3292 if (typeof(replacement) === "object" && replacement !== null) replacement = replacement.toString();
3293 string = string.replace(new RegExp(`\\$\\{${val}\\}`, "g"), replacement);
3294 }
3295 return string;
3296 }
3297
3298 /**
3299 * Format strings with placeholders (`{{placeholder}}`) into full strings.
3300 * Quick example: `PluginUtilities.formatString("Hello, {{user}}", {user: "Zerebos"})`
3301 * would return "Hello, Zerebos".
3302 * @param {string} string - string to format
3303 * @param {object} values - object literal of placeholders to replacements
3304 * @returns {string} the properly formatted string
3305 */
3306 static formatString(string, values) {
3307 for (const val in values) {
3308 let replacement = values[val];
3309 if (Array.isArray(replacement)) replacement = JSON.stringify(replacement);
3310 if (typeof(replacement) === "object" && replacement !== null) replacement = replacement.toString();
3311 string = string.replace(new RegExp(`{{${val}}}`, "g"), replacement);
3312 }
3313 return string;
3314 }
3315
3316 /**
3317 * Finds a value, subobject, or array from a tree that matches a specific filter. Great for patching render functions.
3318 * @param {object} tree React tree to look through. Can be a rendered object or an internal instance.
3319 * @param {callable} searchFilter Filter function to check subobjects against.
3320 */
3321 static findInReactTree(tree, searchFilter) {
3322 return this.findInTree(tree, searchFilter, {walkable: ["props", "children", "child", "sibling"]});
3323 }
3324
3325 /**
3326 * Finds a value, subobject, or array from a tree that matches a specific filter.
3327 * @param {object} tree Tree that should be walked
3328 * @param {callable} searchFilter Filter to check against each object and subobject
3329 * @param {object} options Additional options to customize the search
3330 * @param {Array<string>|null} [options.walkable=null] Array of strings to use as keys that are allowed to be walked on. Null value indicates all keys are walkable
3331 * @param {Array<string>} [options.ignore=[]] Array of strings to use as keys to exclude from the search, most helpful when `walkable = null`.
3332 */
3333 static findInTree(tree, searchFilter, {walkable = null, ignore = []} = {}) {
3334 if (typeof searchFilter === "string") {
3335 if (tree.hasOwnProperty(searchFilter)) return tree[searchFilter];
3336 }
3337 else if (searchFilter(tree)) {
3338 return tree;
3339 }
3340
3341 if (typeof tree !== "object" || tree == null) return undefined;
3342
3343 let tempReturn = undefined;
3344 if (tree instanceof Array) {
3345 for (const value of tree) {
3346 tempReturn = this.findInTree(value, searchFilter, {walkable, ignore});
3347 if (typeof tempReturn != "undefined") return tempReturn;
3348 }
3349 }
3350 else {
3351 const toWalk = walkable == null ? Object.keys(tree) : walkable;
3352 for (const key of toWalk) {
3353 if (!tree.hasOwnProperty(key) || ignore.includes(key)) continue;
3354 tempReturn = this.findInTree(tree[key], searchFilter, {walkable, ignore});
3355 if (typeof tempReturn != "undefined") return tempReturn;
3356 }
3357 }
3358 return tempReturn;
3359 }
3360
3361 /**
3362 * Gets a nested property (if it exists) safely. Path should be something like `prop.prop2.prop3`.
3363 * Numbers can be used for arrays as well like `prop.prop2.array.0.id`.
3364 * @param {Object} obj - object to get nested property of
3365 * @param {string} path - representation of the property to obtain
3366 */
3367 static getNestedProp(obj, path) {
3368 return path.split(/\s?\.\s?/).reduce(function(obj, prop) {
3369 return obj && obj[prop];
3370 }, obj);
3371 }
3372
3373 /**
3374 * Builds a classname string from any number of arguments. This includes arrays and objects.
3375 * When given an array all values from the array are added to the list.
3376 * When given an object they keys are added as the classnames if the value is truthy.
3377 * Copyright (c) 2018 Jed Watson https://github.com/JedWatson/classnames MIT License
3378 * @param {...Any} argument - anything that should be used to add classnames.
3379 */
3380 static className() {
3381 const classes = [];
3382 const hasOwn = {}.hasOwnProperty;
3383
3384 for (let i = 0; i < arguments.length; i++) {
3385 const arg = arguments[i];
3386 if (!arg) continue;
3387
3388 const argType = typeof arg;
3389
3390 if (argType === "string" || argType === "number") {
3391 classes.push(arg);
3392 }
3393 else if (Array.isArray(arg) && arg.length) {
3394 const inner = this.classNames.apply(null, arg);
3395 if (inner) {
3396 classes.push(inner);
3397 }
3398 }
3399 else if (argType === "object") {
3400 for (const key in arg) {
3401 if (hasOwn.call(arg, key) && arg[key]) {
3402 classes.push(key);
3403 }
3404 }
3405 }
3406 }
3407
3408 return classes.join(" ");
3409 }
3410
3411 /**
3412 * Safely adds to the prototype of an existing object by checking if the
3413 * property exists on the prototype.
3414 * @param {object} object - Object whose prototype to extend
3415 * @param {string} prop - Name of the prototype property to add
3416 * @param {callable} func - Function to run
3417 */
3418 static addToPrototype(object, prop, func) {
3419 if (!object.prototype) return;
3420 if (object.prototype[prop]) return;
3421 return object.prototype[prop] = func;
3422 }
3423
3424 /**
3425 * Deep extends an object with a set of other objects. Objects later in the list
3426 * of `extenders` have priority, that is to say if one sets a key to be a primitive,
3427 * it will be overwritten with the next one with the same key. If it is an object,
3428 * and the keys match, the object is extended. This happens recursively.
3429 * @param {object} extendee - Object to be extended
3430 * @param {...object} extenders - Objects to extend with
3431 * @returns {object} - A reference to `extendee`
3432 */
3433 static extend(extendee, ...extenders) {
3434 for (let i = 0; i < extenders.length; i++) {
3435 for (const key in extenders[i]) {
3436 if (extenders[i].hasOwnProperty(key)) {
3437 if (Array.isArray(extendee[key]) && Array.isArray(extenders[i][key])) this.extend(extendee[key], extenders[i][key]);
3438 else if (typeof extendee[key] === "object" && typeof extenders[i][key] === "object") this.extend(extendee[key], extenders[i][key]);
3439 else if (Array.isArray(extenders[i][key])) extendee[key] = [], this.extend(extendee[key], extenders[i][key]);
3440 else if (typeof extenders[i][key] === "object") extendee[key] = {}, this.extend(extendee[key], extenders[i][key]);
3441 else extendee[key] = extenders[i][key];
3442 }
3443 }
3444 }
3445 return extendee;
3446 }
3447
3448 /* Code below comes from our work on BDv2:
3449 * https://github.com/JsSucks/BetterDiscordApp/blob/master/common/modules/utils.js
3450 */
3451
3452 /**
3453 * Clones an object and all it's properties.
3454 * @param {Any} value The value to clone
3455 * @return {Any} The cloned value
3456 */
3457 static deepclone(value) {
3458 if (typeof value === "object") {
3459 if (value instanceof Array) return value.map(i => this.deepclone(i));
3460
3461 const clone = Object.assign({}, value);
3462
3463 for (const key in clone) {
3464 clone[key] = this.deepclone(clone[key]);
3465 }
3466
3467 return clone;
3468 }
3469
3470 return value;
3471 }
3472
3473 /**
3474 * Freezes an object and all it's properties.
3475 * @param {Any} object The object to freeze
3476 * @param {Function} exclude A function to filter object that shouldn't be frozen
3477 */
3478 static deepfreeze(object, exclude) {
3479 if (exclude && exclude(object)) return;
3480
3481 if (typeof object === "object" && object !== null) {
3482 const properties = Object.getOwnPropertyNames(object);
3483
3484 for (const property of properties) {
3485 this.deepfreeze(object[property], exclude);
3486 }
3487
3488 Object.freeze(object);
3489 }
3490
3491 return object;
3492 }
3493
3494 /**
3495 * Removes an item from an array. This differs from Array.prototype.filter as it mutates the original array instead of creating a new one.
3496 * @param {Array} array The array to filter
3497 * @param {Any} item The item to remove from the array
3498 * @return {Array}
3499 */
3500 static removeFromArray(array, item, filter) {
3501 let index;
3502 while ((index = filter ? array.findIndex(item) : array.indexOf(item)) > -1) array.splice(index, 1);
3503 return array;
3504}
3505
3506 /**
3507 * Checks if a file exists and is a file.
3508 * @param {String} path The file's path
3509 * @return {Promise}
3510 */
3511 static async fileExists(path) {
3512 const fs = __webpack_require__(/*! fs */ "fs");
3513 return new Promise((resolve, reject) => {
3514 fs.stat(path, (err, stats) => {
3515 if (err) {
3516 return reject({
3517 message: `No such file or directory: ${err.path}`,
3518 err
3519 });
3520 }
3521
3522 if (!stats.isFile()) {
3523 return reject({
3524 message: `Not a file: ${path}`,
3525 stats
3526 });
3527 }
3528
3529 resolve();
3530 });
3531 });
3532 }
3533
3534 /**
3535 * Returns the contents of a file.
3536 * @param {String} path The file's path
3537 * @return {Promise}
3538 */
3539 static async readFile(path) {
3540 try {
3541 await this.fileExists(path);
3542 }
3543 catch (err) {
3544 throw err;
3545 }
3546
3547 const fs = __webpack_require__(/*! fs */ "fs");
3548 return new Promise((resolve, reject) => {
3549 fs.readFile(path, "utf-8", (err, data) => {
3550 if (err) {
3551 return reject({
3552 message: `Could not read file: ${path}`,
3553 err
3554 });
3555 }
3556
3557 resolve(data);
3558 });
3559 });
3560 }
3561
3562}
3563
3564/***/ }),
3565
3566/***/ "./src/modules/webpackmodules.js":
3567/*!***************************************!*\
3568 !*** ./src/modules/webpackmodules.js ***!
3569 \***************************************/
3570/*! exports provided: Filters, default */
3571/***/ (function(module, __webpack_exports__, __webpack_require__) {
3572
3573"use strict";
3574__webpack_require__.r(__webpack_exports__);
3575/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Filters", function() { return Filters; });
3576/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return WebpackModules; });
3577/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js");
3578/**
3579 * Random set of utilities that didn't fit elsewhere.
3580 * @module WebpackModules
3581 * @version 0.0.2
3582 */
3583
3584
3585 /**
3586 * Checks if a given module matches a set of parameters.
3587 * @callback module:WebpackModules.Filters~filter
3588 * @param {*} module - module to check
3589 * @returns {boolean} - True if the module matches the filter, false otherwise
3590 */
3591
3592/**
3593 * Filters for use with {@link module:WebpackModules} but may prove useful elsewhere.
3594 */
3595class Filters {
3596 /**
3597 * Generates a {@link module:WebpackModules.Filters~filter} that filters by a set of properties.
3598 * @param {Array<string>} props - Array of property names
3599 * @param {module:WebpackModules.Filters~filter} filter - Additional filter
3600 * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties
3601 */
3602 static byProperties(props, filter = m => m) {
3603 return module => {
3604 const component = filter(module);
3605 if (!component) return false;
3606 return props.every(property => component[property] !== undefined);
3607 };
3608 }
3609
3610 /**
3611 * Generates a {@link module:WebpackModules.Filters~filter} that filters by a set of properties on the object's prototype.
3612 * @param {Array<string>} fields - Array of property names
3613 * @param {module:WebpackModules.Filters~filter} filter - Additional filter
3614 * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties on the object's prototype
3615 */
3616 static byPrototypeFields(fields, filter = m => m) {
3617 return module => {
3618 const component = filter(module);
3619 if (!component) return false;
3620 if (!component.prototype) return false;
3621 return fields.every(field => component.prototype[field] !== undefined);
3622 };
3623 }
3624
3625 /**
3626 * Generates a {@link module:WebpackModules.Filters~filter} that filters by a regex.
3627 * @param {RegExp} search - A RegExp to check on the module
3628 * @param {module:WebpackModules.Filters~filter} filter - Additional filter
3629 * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties
3630 */
3631 static byCode(search, filter = m => m) {
3632 return module => {
3633 const method = filter(module);
3634 if (!method) return false;
3635 return method.toString([]).search(search) !== -1;
3636 };
3637 }
3638
3639 /**
3640 * Generates a {@link module:WebpackModules.Filters~filter} that filters by strings.
3641 * @param {...String} search - A RegExp to check on the module
3642 * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of strings
3643 */
3644 static byString(...strings) {
3645 return module => {
3646 const moduleString = module.toString([]);
3647 for (const s of strings) {
3648 if (!moduleString.includes(s)) return false;
3649 }
3650 return true;
3651 };
3652 }
3653
3654 /**
3655 * Generates a {@link module:WebpackModules.Filters~filter} that filters by a set of properties.
3656 * @param {string} name - Name the module should have
3657 * @param {module:WebpackModules.Filters~filter} filter - Additional filter
3658 * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties
3659 */
3660 static byDisplayName(name) {
3661 return module => {
3662 return module && module.displayName === name;
3663 };
3664 }
3665
3666 /**
3667 * Generates a combined {@link module:WebpackModules.Filters~filter} from a list of filters.
3668 * @param {...module:WebpackModules.Filters~filter} filters - A list of filters
3669 * @returns {module:WebpackModules.Filters~filter} - Combinatory filter of all arguments
3670 */
3671 static combine(...filters) {
3672 return module => {
3673 return filters.every(filter => filter(module));
3674 };
3675 }
3676}
3677
3678class WebpackModules {
3679
3680 static find(filter, first = true) {return this.getModule(filter, first);}
3681 static findAll(filter) {return this.getModule(filter, false);}
3682 static findByUniqueProperties(props, first = true) {return first ? this.getByProps(...props) : this.getAllByProps(...props);}
3683 static findByDisplayName(name) {return this.getByDisplayName(name);}
3684
3685 /**
3686 * Finds a module using a filter function.
3687 * @param {Function} filter A function to use to filter modules
3688 * @param {Boolean} first Whether to return only the first matching module
3689 * @return {Any}
3690 */
3691 static getModule(filter, first = true) {
3692 const modules = this.getAllModules();
3693 const rm = [];
3694 for (const index in modules) {
3695 if (!modules.hasOwnProperty(index)) continue;
3696 const module = modules[index];
3697 const {exports} = module;
3698 let foundModule = null;
3699
3700 if (!exports) continue;
3701 if (exports.__esModule && exports.default && filter(exports.default)) foundModule = exports.default;
3702 if (filter(exports)) foundModule = exports;
3703 if (!foundModule) continue;
3704 if (first) return foundModule;
3705 rm.push(foundModule);
3706 }
3707 return first || rm.length == 0 ? undefined : rm;
3708 }
3709
3710 /**
3711 * Gets a specific module by index of the webpack require cache.
3712 * Best used in combination with getIndex in order to patch a
3713 * specific function.
3714 *
3715 * Note: this gives the **raw** module, meaning the actual module
3716 * is in returnValue.exports. This is done in order to be able
3717 * to patch modules which export a single function directly.
3718 * @param {Number} index Index into the webpack require cache
3719 * @return {Any}
3720 */
3721
3722 /**
3723 * Gets the index in the webpack require cache of a specific
3724 * module using a filter.
3725 * @param {Function} filter A function to use to filter modules
3726 * @return {Number|null}
3727 */
3728 static getIndex(filter) {
3729 const modules = this.getAllModules();
3730 for (const index in modules) {
3731 if (!modules.hasOwnProperty(index)) continue;
3732 const module = modules[index];
3733 const {exports} = module;
3734 let foundModule = null;
3735
3736 if (!exports) continue;
3737 if (exports.__esModule && exports.default && filter(exports.default)) foundModule = exports.default;
3738 if (filter(exports)) foundModule = exports;
3739 if (!foundModule) continue;
3740 return index;
3741 }
3742 return null;
3743 }
3744
3745 /**
3746 * Gets the index in the webpack require cache of a specific
3747 * module that was already found.
3748 * @param {Any} module An already acquired module
3749 * @return {Number|null}
3750 */
3751 static getIndexByModule(module) {
3752 return this.getIndex(m => m == module);
3753 }
3754
3755 /**
3756 * Finds all modules matching a filter function.
3757 * @param {Function} filter A function to use to filter modules
3758 */
3759 static getModules(filter) {return this.getModule(filter, false);}
3760
3761 /**
3762 * Finds a module by its name.
3763 * @param {String} name The name of the module
3764 * @param {Function} fallback A function to use to filter modules if not finding a known module
3765 * @return {Any}
3766 */
3767 static getModuleByName(name, fallback) {
3768 if (_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].hasOwnProperty(name)) return _discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"][name];
3769 if (!fallback) return undefined;
3770 const module = this.getModule(fallback, true);
3771 return module ? _discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"][name] = module : undefined;
3772 }
3773
3774 /**
3775 * Finds a module by its display name.
3776 * @param {String} name The display name of the module
3777 * @return {Any}
3778 */
3779 static getByDisplayName(name) {
3780 return this.getModule(Filters.byDisplayName(name), true);
3781 }
3782
3783 /**
3784 * Finds a module using its code.
3785 * @param {RegEx} regex A regular expression to use to filter modules
3786 * @param {Boolean} first Whether to return the only the first matching module
3787 * @return {Any}
3788 */
3789 static getByRegex(regex, first = true) {
3790 return this.getModule(Filters.byCode(regex), first);
3791 }
3792
3793 /**
3794 * Finds a single module using properties on its prototype.
3795 * @param {...string} prototypes Properties to use to filter modules
3796 * @return {Any}
3797 */
3798 static getByPrototypes(...prototypes) {
3799 return this.getModule(Filters.byPrototypeFields(prototypes), true);
3800 }
3801
3802 /**
3803 * Finds all modules with a set of properties of its prototype.
3804 * @param {...string} prototypes Properties to use to filter modules
3805 * @return {Any}
3806 */
3807 static getAllByPrototypes(...prototypes) {
3808 return this.getModule(Filters.byPrototypeFields(prototypes), false);
3809 }
3810
3811 /**
3812 * Finds a single module using its own properties.
3813 * @param {...string} props Properties to use to filter modules
3814 * @return {Any}
3815 */
3816 static getByProps(...props) {
3817 return this.getModule(Filters.byProperties(props), true);
3818 }
3819
3820 /**
3821 * Finds all modules with a set of properties.
3822 * @param {...string} props Properties to use to filter modules
3823 * @return {Any}
3824 */
3825 static getAllByProps(...props) {
3826 return this.getModule(Filters.byProperties(props), false);
3827 }
3828
3829 /**
3830 * Finds a single module using a set of strings.
3831 * @param {...String} props Strings to use to filter modules
3832 * @return {Any}
3833 */
3834 static getByString(...strings) {
3835 return this.getModule(Filters.byString(...strings), true);
3836 }
3837
3838 /**
3839 * Finds all modules with a set of strings.
3840 * @param {...String} strings Strings to use to filter modules
3841 * @return {Any}
3842 */
3843 static getAllByString(...strings) {
3844 return this.getModule(Filters.byString(...strings), false);
3845 }
3846
3847 /**
3848 * Gets a specific module by index of the webpack require cache.
3849 * Best used in combination with getIndex in order to patch a
3850 * specific function.
3851 * @param {Number} index Index into the webpack require cache
3852 * @return {Any}
3853 */
3854 static getByIndex(index) {
3855 return WebpackModules.require.c[index].exports;
3856 }
3857
3858 /**
3859 * Discord's __webpack_require__ function.
3860 */
3861 static get require() {
3862 if (this._require) return this._require;
3863 const id = "zl-webpackmodules";
3864 const __webpack_require__ = typeof(window.webpackJsonp) == "function" ? window.webpackJsonp([], {
3865 [id]: (module, exports, __webpack_require__) => exports.default = __webpack_require__
3866 }, [id]).default : window.webpackJsonp.push([[], {
3867 [id]: (module, exports, __webpack_require__) => module.exports = __webpack_require__
3868 }, [[id]]]);
3869 delete __webpack_require__.m[id];
3870 delete __webpack_require__.c[id];
3871 return this._require = __webpack_require__;
3872 }
3873
3874 /**
3875 * Returns all loaded modules.
3876 * @return {Array}
3877 */
3878 static getAllModules() {
3879 return this.require.c;
3880 }
3881
3882}
3883
3884/***/ }),
3885
3886/***/ "./src/plugin.js":
3887/*!***********************!*\
3888 !*** ./src/plugin.js ***!
3889 \***********************/
3890/*! exports provided: default */
3891/***/ (function(module, __webpack_exports__, __webpack_require__) {
3892
3893"use strict";
3894__webpack_require__.r(__webpack_exports__);
3895/* harmony default export */ __webpack_exports__["default"] = ((BasePlugin, Library) => {
3896 const {PluginUpdater, Patcher, Logger, Settings, Toasts, PluginUtilities, ReactComponents} = Library;
3897 const PluginLibrary = class PluginLibrary extends BasePlugin {
3898 get Library() {return Library;}
3899
3900 load() {
3901 super.load();
3902 const wasLibLoaded = !!document.getElementById("ZLibraryCSS");
3903 const isBBDLoading = document.getElementsByClassName("bd-loaderv2").length;
3904 PluginUtilities.removeStyle("ZLibraryCSS");
3905 PluginUtilities.addStyle("ZLibraryCSS", Settings.CSS + Toasts.CSS + PluginUpdater.CSS);
3906 ReactComponents.AutoPatcher.processAll();
3907 ReactComponents.AutoPatcher.autoPatch();
3908
3909 /**
3910 * Checking if this is the library first being loaded during init
3911 * This means that subsequent loads will cause dependents to reload
3912 * This also means first load when installing for the first time
3913 * will automatically reload the dependent plugins. This is needed
3914 * for those plugins that prompt to download and install the lib.
3915 */
3916
3917 if (!wasLibLoaded && isBBDLoading) return; // If the this is the lib's first load AND this is BD's initialization
3918
3919 /**
3920 * Now we can go ahead and reload any dependent plugins by checking
3921 * for any with instance._config. Both plugins using buildPlugin()
3922 * and plugin skeletons that prompt for download should have this
3923 * instance property.
3924 */
3925
3926 const prev = window.settingsCookie["fork-ps-2"];
3927 window.settingsCookie["fork-ps-2"] = false;
3928 const list = Object.keys(window.bdplugins).filter(k => window.bdplugins[k].plugin._config && k != "ZeresPluginLibrary");
3929 for (let p = 0; p < list.length; p++) window.pluginModule.reloadPlugin(list[p]);
3930 window.settingsCookie["fork-ps-2"] = prev;
3931 }
3932
3933 static buildPlugin(config) {
3934 const name = config.info.name;
3935 const BoundAPI = {
3936 Logger: {
3937 stacktrace: (message, error) => Logger.stacktrace(name, message, error),
3938 log: (...message) => Logger.log(name, ...message),
3939 error: (...message) => Logger.err(name, ...message),
3940 err: (...message) => Logger.err(name, ...message),
3941 warn: (...message) => Logger.warn(name, ...message),
3942 info: (...message) => Logger.info(name, ...message),
3943 debug: (...message) => Logger.debug(name, ...message)
3944 },
3945 Patcher: {
3946 getPatchesByCaller: () => {return Patcher.getPatchesByCaller(name);},
3947 unpatchAll: () => {return Patcher.unpatchAll(name);},
3948 before: (moduleToPatch, functionName, callback, options = {}) => {return Patcher.before(name, moduleToPatch, functionName, callback, options);},
3949 instead: (moduleToPatch, functionName, callback, options = {}) => {return Patcher.instead(name, moduleToPatch, functionName, callback, options);},
3950 after: (moduleToPatch, functionName, callback, options = {}) => {return Patcher.after(name, moduleToPatch, functionName, callback, options);}
3951 }
3952 };
3953 const BoundLib = Object.assign({}, Library);
3954 BoundLib.Logger = BoundAPI.Logger;
3955 BoundLib.Patcher = BoundAPI.Patcher;
3956 return [Library.Structs.Plugin(config), BoundLib];
3957 }
3958 };
3959
3960 Object.assign(PluginLibrary, Library);
3961 Library.buildPlugin = PluginLibrary.buildPlugin;
3962 window.ZLibrary = Library;
3963 window.ZLibraryPromise = new Promise(r => setImmediate(r));
3964 window.ZeresPluginLibrary = PluginLibrary;
3965 return PluginLibrary;
3966});
3967
3968/***/ }),
3969
3970/***/ "./src/structs/discord/channel.js":
3971/*!****************************************!*\
3972 !*** ./src/structs/discord/channel.js ***!
3973 \****************************************/
3974/*! exports provided: Channel, PermissionOverwrite, RolePermissionOverwrite, MemberPermissionOverwrite, GuildChannel, GuildTextChannel, GuildVoiceChannel, ChannelCategory, PrivateChannel, DirectMessageChannel, GroupChannel */
3975/***/ (function(module, __webpack_exports__, __webpack_require__) {
3976
3977"use strict";
3978__webpack_require__.r(__webpack_exports__);
3979/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Channel", function() { return Channel; });
3980/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PermissionOverwrite", function() { return PermissionOverwrite; });
3981/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RolePermissionOverwrite", function() { return RolePermissionOverwrite; });
3982/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MemberPermissionOverwrite", function() { return MemberPermissionOverwrite; });
3983/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GuildChannel", function() { return GuildChannel; });
3984/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GuildTextChannel", function() { return GuildTextChannel; });
3985/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GuildVoiceChannel", function() { return GuildVoiceChannel; });
3986/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ChannelCategory", function() { return ChannelCategory; });
3987/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PrivateChannel", function() { return PrivateChannel; });
3988/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DirectMessageChannel", function() { return DirectMessageChannel; });
3989/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GroupChannel", function() { return GroupChannel; });
3990/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
3991/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! structs */ "./src/structs/structs.js");
3992/* harmony import */ var _guild__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./guild */ "./src/structs/discord/guild.js");
3993/* harmony import */ var _message__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./message */ "./src/structs/discord/message.js");
3994/* harmony import */ var _user__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./user */ "./src/structs/discord/user.js");
3995/**
3996 * BetterDiscord Channel Struct
3997 * Copyright (c) 2018-present JsSucks
3998 * All rights reserved.
3999 *
4000 * This source code is licensed under the MIT license found at
4001 * https://github.com/JsSucks/BetterDiscordApp/blob/master/LICENSE
4002*/
4003
4004
4005
4006
4007
4008
4009
4010const cache = new WeakMap();
4011
4012/**
4013 * @memberof module:DiscordAPI
4014 */
4015class Channel {
4016
4017 constructor(data) {
4018 if (cache.has(data)) return cache.get(data);
4019 cache.set(data, this);
4020
4021 this.discordObject = data;
4022 }
4023
4024 static from(channel) {
4025 switch (channel.type) {
4026 default: return new Channel(channel);
4027 case 0: return new GuildTextChannel(channel);
4028 case 1: return new DirectMessageChannel(channel);
4029 case 2: return new GuildVoiceChannel(channel);
4030 case 3: return new GroupChannel(channel);
4031 case 4: return new ChannelCategory(channel);
4032 }
4033 }
4034
4035 static fromId(id) {
4036 const channel = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].ChannelStore.getChannel(id);
4037 if (channel) return Channel.from(channel);
4038 }
4039
4040 static get GuildChannel() { return GuildChannel; }
4041 static get GuildTextChannel() { return GuildTextChannel; }
4042 static get GuildVoiceChannel() { return GuildVoiceChannel; }
4043 static get ChannelCategory() { return ChannelCategory; }
4044 static get PrivateChannel() { return PrivateChannel; }
4045 static get DirectMessageChannel() { return DirectMessageChannel; }
4046 static get GroupChannel() { return GroupChannel; }
4047
4048 get id() { return this.discordObject.id; }
4049 get applicationId() { return this.discordObject.application_id; }
4050 get type() { return this.discordObject.type; }
4051 get name() { return this.discordObject.name; }
4052
4053 /**
4054 * Send a message in this channel.
4055 * @param {String} content The new message's content
4056 * @param {Boolean} parse Whether to parse the message or send it as it is
4057 * @return {Promise<Message>}
4058 */
4059 async sendMessage(content, parse = false) {
4060 if (this.assertPermissions) this.assertPermissions("SEND_MESSAGES", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.VIEW_CHANNEL | modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.SEND_MESSAGES);
4061
4062 this.select();
4063
4064 if (parse) content = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageParser.parse(this.discordObject, content);
4065 else content = {content};
4066
4067 const response = await modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageActions._sendMessage(this.id, content);
4068 return _message__WEBPACK_IMPORTED_MODULE_3__["Message"].from(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageStore.getMessage(this.id, response.body.id));
4069 }
4070
4071 /**
4072 * Send a bot message in this channel that only the current user can see.
4073 * @param {String} content The new message's content
4074 * @return {Message}
4075 */
4076 sendBotMessage(content) {
4077 this.select();
4078 const message = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageParser.createBotMessage(this.id, content);
4079 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageActions.receiveMessage(this.id, message);
4080 return _message__WEBPACK_IMPORTED_MODULE_3__["Message"].from(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageStore.getMessage(this.id, message.id));
4081 }
4082
4083 /**
4084 * A list of messages in this channel.
4085 */
4086 get messages() {
4087 const messages = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageStore.getMessages(this.id).toArray();
4088 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(messages, m => _message__WEBPACK_IMPORTED_MODULE_3__["Message"].from(m));
4089 }
4090
4091 /**
4092 * Jumps to the latest message in this channel.
4093 */
4094 jumpToPresent() {
4095 if (this.assertPermissions) this.assertPermissions("VIEW_CHANNEL", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.VIEW_CHANNEL);
4096 if (this.hasMoreAfter) modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageActions.jumpToPresent(this.id, modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordConstants.MAX_MESSAGES_PER_CHANNEL);
4097 else this.messages[this.messages.length - 1].jumpTo(false);
4098 }
4099
4100 get hasMoreAfter() {
4101 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageStore.getMessages(this.id).hasMoreAfter;
4102 }
4103
4104 /**
4105 * Sends an invite in this channel.
4106 * @param {String} code The invite code
4107 * @return {Promise<Message>}
4108 */
4109 async sendInvite(code) {
4110 if (this.assertPermissions) this.assertPermissions("SEND_MESSAGES", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.VIEW_CHANNEL | modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.SEND_MESSAGES);
4111 const response = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageActions.sendInvite(this.id, code);
4112 return _message__WEBPACK_IMPORTED_MODULE_3__["Message"].from(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageStore.getMessage(this.id, response.body.id));
4113 }
4114
4115 /**
4116 * Opens this channel in the UI.
4117 */
4118 select() {
4119 if (this.assertPermissions) this.assertPermissions("VIEW_CHANNEL", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.VIEW_CHANNEL);
4120 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].NavigationUtils.transitionToGuild(this.guildId ? this.guildId : modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordConstants.ME, this.id);
4121 }
4122
4123 /**
4124 * Whether this channel is currently selected.
4125 */
4126 get isSelected() {
4127 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentChannel === this;
4128 }
4129
4130 /**
4131 * Updates this channel.
4132 * @return {Promise}
4133 */
4134 async updateChannel(body) {
4135 if (this.assertPermissions) this.assertPermissions("MANAGE_CHANNELS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.MANAGE_CHANNELS);
4136 await modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].APIModule.patch({
4137 url: `${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordConstants.Endpoints.CHANNELS}/${this.id}`,
4138 body
4139 });
4140 this.discordObject = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].ChannelStore.getChannel(this.id);
4141 cache.set(this.discordObject, this);
4142 }
4143
4144}
4145
4146
4147
4148class PermissionOverwrite {
4149 constructor(data, channel_id) {
4150 this.discordObject = data;
4151 this.channelId = channel_id;
4152 }
4153
4154 static from(data, channel_id) {
4155 switch (data.type) {
4156 default: return new PermissionOverwrite(data, channel_id);
4157 case "role": return new RolePermissionOverwrite(data, channel_id);
4158 case "member": return new MemberPermissionOverwrite(data, channel_id);
4159 }
4160 }
4161
4162 static get RolePermissionOverwrite() { return RolePermissionOverwrite; }
4163 static get MemberPermissionOverwrite() { return MemberPermissionOverwrite; }
4164
4165 get type() { return this.discordObject.type; }
4166 get allow() { return this.discordObject.allow; }
4167 get deny() { return this.discordObject.deny; }
4168
4169 get channel() {
4170 return Channel.fromId(this.channelId);
4171 }
4172
4173 get guild() {
4174 if (this.channel) return this.channel.guild;
4175 }
4176}
4177
4178class RolePermissionOverwrite extends PermissionOverwrite {
4179 get roleId() { return this.discordObject.id; }
4180
4181 get role() {
4182 if (this.guild) return this.guild.roles.find(r => r.id === this.roleId);
4183 }
4184}
4185
4186class MemberPermissionOverwrite extends PermissionOverwrite {
4187 get memberId() { return this.discordObject.id; }
4188
4189 get member() {
4190 return _user__WEBPACK_IMPORTED_MODULE_4__["GuildMember"].fromId(this.memberId);
4191 }
4192}
4193
4194class GuildChannel extends Channel {
4195 static get PermissionOverwrite() { return PermissionOverwrite; }
4196
4197 get guildId() { return this.discordObject.guild_id; }
4198 get parentId() { return this.discordObject.parent_id; } // Channel category
4199 get position() { return this.discordObject.position; }
4200 get nicks() { return this.discordObject.nicks; }
4201
4202 checkPermissions(perms) {
4203 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].Permissions.can(perms, modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser, this.discordObject);
4204 }
4205
4206 assertPermissions(name, perms) {
4207 if (!this.checkPermissions(perms)) throw new structs__WEBPACK_IMPORTED_MODULE_1__["InsufficientPermissions"](name);
4208 }
4209
4210 get category() {
4211 return Channel.fromId(this.parentId);
4212 }
4213
4214 /**
4215 * The current user's permissions on this channel.
4216 */
4217 get permissions() {
4218 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildPermissions.getChannelPermissions(this.id);
4219 }
4220
4221 get permissionOverwrites() {
4222 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(Object.values(this.discordObject.permissionOverwrites), p => PermissionOverwrite.from(p, this.id));
4223 }
4224
4225 get guild() {
4226 return _guild__WEBPACK_IMPORTED_MODULE_2__["Guild"].fromId(this.guildId);
4227 }
4228
4229 /**
4230 * Whether this channel is the guild's default channel.
4231 */
4232 get isDefaultChannel() {
4233 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildChannelsStore.getDefaultChannel(this.guildId).id === this.id;
4234 }
4235
4236 /**
4237 * Opens this channel's settings window.
4238 * @param {String} section The section to open (see DiscordConstants.ChannelSettingsSections)
4239 */
4240 openSettings(section = "OVERVIEW") {
4241 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].ChannelSettingsWindow.setSection(section);
4242 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].ChannelSettingsWindow.open(this.id);
4243 }
4244
4245 /**
4246 * Updates this channel's name.
4247 * @param {String} name The channel's new name
4248 * @return {Promise}
4249 */
4250 updateName(name) {
4251 return this.updateChannel({name});
4252 }
4253
4254 /**
4255 * Changes the channel's position.
4256 * @param {Number} position The channel's new position
4257 * @return {Promise}
4258 */
4259 changeSortLocation(position = 0) {
4260 if (position instanceof GuildChannel) position = position.position;
4261 return this.updateChannel({position});
4262 }
4263
4264 /**
4265 * Updates this channel's permission overwrites.
4266 * @param {Array} permissionOverwrites An array of permission overwrites
4267 * @return {Promise}
4268 */
4269 updatePermissionOverwrites(permission_overwrites) {
4270 return this.updateChannel({permission_overwrites});
4271 }
4272
4273 /**
4274 * Updates this channel's category.
4275 * @param {ChannelCategory} category The new channel category
4276 * @return {Promise}
4277 */
4278 updateCategory(category) {
4279 return this.updateChannel({parent_id: category.id || category});
4280 }
4281}
4282
4283// Type 0 - GUILD_TEXT
4284class GuildTextChannel extends GuildChannel {
4285 get type() { return "GUILD_TEXT"; }
4286 get topic() { return this.discordObject.topic; }
4287 get nsfw() { return this.discordObject.nsfw; }
4288
4289 /**
4290 * Updates this channel's topic.
4291 * @param {String} topc The new channel topic
4292 * @return {Promise}
4293 */
4294 updateTopic(topic) {
4295 return this.updateChannel({topic});
4296 }
4297
4298 /**
4299 * Updates this channel's NSFW flag.
4300 * @param {Boolean} nsfw Whether the channel should be marked as NSFW
4301 * @return {Promise}
4302 */
4303 setNsfw(nsfw = true) {
4304 return this.updateChannel({nsfw});
4305 }
4306
4307 setNotNsfw() {
4308 return this.setNswf(false);
4309 }
4310}
4311
4312// Type 2 - GUILD_VOICE
4313class GuildVoiceChannel extends GuildChannel {
4314 get type() { return "GUILD_VOICE"; }
4315 get userLimit() { return this.discordObject.userLimit; }
4316 get bitrate() { return this.discordObject.bitrate; }
4317
4318 sendMessage() { throw new Error("Cannot send messages in a voice channel."); }
4319 get messages() { return new structs__WEBPACK_IMPORTED_MODULE_1__["List"](); }
4320 jumpToPresent() { throw new Error("Cannot select a voice channel."); }
4321 get hasMoreAfter() { return false; }
4322 sendInvite() { throw new Error("Cannot invite someone to a voice channel."); }
4323 select() { throw new Error("Cannot select a voice channel."); }
4324
4325 /**
4326 * Updates this channel's bitrate.
4327 * @param {Number} bitrate The new bitrate
4328 * @return {Promise}
4329 */
4330 updateBitrate(bitrate) {
4331 return this.updateChannel({bitrate});
4332 }
4333
4334 /**
4335 * Updates this channel's user limit.
4336 * @param {Number} userLimit The new user limit
4337 * @return {Promise}
4338 */
4339 updateUserLimit(user_limit) {
4340 return this.updateChannel({user_limit});
4341 }
4342}
4343
4344// Type 4 - GUILD_CATEGORY
4345class ChannelCategory extends GuildChannel {
4346 get type() { return "GUILD_CATEGORY"; }
4347 get parentId() { return undefined; }
4348 get category() { return undefined; }
4349
4350 sendMessage() { throw new Error("Cannot send messages in a channel category."); }
4351 get messages() { return new structs__WEBPACK_IMPORTED_MODULE_1__["List"](); }
4352 jumpToPresent() { throw new Error("Cannot select a channel category."); }
4353 get hasMoreAfter() { return false; }
4354 sendInvite() { throw new Error("Cannot invite someone to a channel category."); }
4355 select() { throw new Error("Cannot select a channel category."); }
4356 updateCategory() { throw new Error("Cannot set a channel category on another channel category."); }
4357
4358 /**
4359 * A list of channels in this category.
4360 */
4361 get channels() {
4362 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(this.guild.channels, c => c.parentId === this.id);
4363 }
4364
4365 /**
4366 * Opens the create channel modal for this guild.
4367 * @param {Number} type The type of channel to create - either 0 (text), 2 (voice) or 4 (category)
4368 * @param {GuildChannel} clone A channel to clone permissions of
4369 */
4370 openCreateChannelModal(type, category, clone) {
4371 this.guild.openCreateChannelModal(type, this.id, this, clone);
4372 }
4373
4374 /**
4375 * Creates a channel in this category.
4376 * @param {Number} type The type of channel to create - either 0 (text) or 2 (voice)
4377 * @param {String} name A name for the new channel
4378 * @param {Array} permission_overwrites An array of PermissionOverwrite-like objects - leave to use the permissions of the category
4379 * @return {Promise<GuildChannel>}
4380 */
4381 createChannel(type, name, permission_overwrites) {
4382 return this.guild.createChannel(type, name, this, permission_overwrites);
4383 }
4384}
4385
4386class PrivateChannel extends Channel {
4387 get userLimit() { return this.discordObject.userLimit; }
4388 get bitrate() { return this.discordObject.bitrate; }
4389}
4390
4391// Type 1 - DM
4392class DirectMessageChannel extends PrivateChannel {
4393 get type() { return "DM"; }
4394 get recipientId() { return this.discordObject.recipients[0]; }
4395
4396 /**
4397 * The other user of this direct message channel.
4398 */
4399 get recipient() {
4400 return _user__WEBPACK_IMPORTED_MODULE_4__["User"].fromId(this.recipientId);
4401 }
4402}
4403
4404// Type 3 - GROUP_DM
4405class GroupChannel extends PrivateChannel {
4406 get ownerId() { return this.discordObject.ownerId; }
4407 get type() { return "GROUP_DM"; }
4408 get name() { return this.discordObject.name; }
4409 get icon() { return this.discordObject.icon; }
4410
4411 /**
4412 * A list of the other members of this group direct message channel.
4413 */
4414 get members() {
4415 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(this.discordObject.recipients, id => _user__WEBPACK_IMPORTED_MODULE_4__["User"].fromId(id));
4416 }
4417
4418 /**
4419 * The owner of this group direct message channel. This is usually the person who created it.
4420 */
4421 get owner() {
4422 return _user__WEBPACK_IMPORTED_MODULE_4__["User"].fromId(this.ownerId);
4423 }
4424
4425 /**
4426 * Updates this channel's name.
4427 * @param {String} name The channel's new name
4428 * @return {Promise}
4429 */
4430 updateName(name) {
4431 return this.updateChannel({name});
4432 }
4433}
4434
4435
4436// export {Channel, GuildChannel, ChannelCategory, GuildTextChannel, GuildVoiceChannel, PrivateChannel, DirectMessageChannel, GroupChannel};
4437// export {PermissionOverwrite, RolePermissionOverwrite, MemberPermissionOverwrite};
4438
4439/***/ }),
4440
4441/***/ "./src/structs/discord/guild.js":
4442/*!**************************************!*\
4443 !*** ./src/structs/discord/guild.js ***!
4444 \**************************************/
4445/*! exports provided: Role, Emoji, Guild */
4446/***/ (function(module, __webpack_exports__, __webpack_require__) {
4447
4448"use strict";
4449__webpack_require__.r(__webpack_exports__);
4450/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Role", function() { return Role; });
4451/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Emoji", function() { return Emoji; });
4452/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Guild", function() { return Guild; });
4453/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
4454/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! structs */ "./src/structs/structs.js");
4455/* harmony import */ var _channel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./channel */ "./src/structs/discord/channel.js");
4456/* harmony import */ var _user__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./user */ "./src/structs/discord/user.js");
4457/**
4458 * BetterDiscord Guild Struct
4459 * Copyright (c) 2018-present JsSucks
4460 * All rights reserved.
4461 *
4462 * This source code is licensed under the MIT license found at
4463 * https://github.com/JsSucks/BetterDiscordApp/blob/master/LICENSE
4464*/
4465
4466
4467
4468
4469
4470
4471const roles = new WeakMap();
4472
4473class Role {
4474 constructor(data, guild_id) {
4475 if (roles.has(data)) return roles.get(data);
4476 roles.set(data, this);
4477
4478 this.discordObject = data;
4479 this.guildId = guild_id;
4480 }
4481
4482 get id() { return this.discordObject.id; }
4483 get name() { return this.discordObject.name; }
4484 get position() { return this.discordObject.position; }
4485 get originalPosition() { return this.discordObject.originalPosition; }
4486 get permissions() { return this.discordObject.permissions; }
4487 get managed() { return this.discordObject.managed; }
4488 get mentionable() { return this.discordObject.mentionable; }
4489 get hoist() { return this.discordObject.hoist; }
4490 get colour() { return this.discordObject.color; }
4491 get colourString() { return this.discordObject.colorString; }
4492
4493 get guild() {
4494 return Guild.fromId(this.guildId);
4495 }
4496
4497 get members() {
4498 return this.guild.members.filter(m => m.roles.includes(this));
4499 }
4500}
4501
4502const emojis = new WeakMap();
4503
4504class Emoji {
4505 constructor(data) {
4506 if (emojis.has(data)) return emojis.get(data);
4507 emojis.set(data, this);
4508
4509 this.discordObject = data;
4510 }
4511
4512 get id() { return this.discordObject.id; }
4513 get guildId() { return this.discordObject.guild_id; }
4514 get name() { return this.discordObject.name; }
4515 get managed() { return this.discordObject.managed; }
4516 get animated() { return this.discordObject.animated; }
4517 get allNamesString() { return this.discordObject.allNamesString; }
4518 get requireColons() { return this.discordObject.require_colons; }
4519 get url() { return this.discordObject.url; }
4520 get roles() { return this.discordObject.roles; }
4521
4522 get guild() {
4523 return Guild.fromId(this.guildId);
4524 }
4525}
4526
4527const guilds = new WeakMap();
4528
4529/**
4530 * @memberof module:DiscordAPI
4531 */
4532class Guild {
4533
4534 constructor(data) {
4535 if (guilds.has(data)) return guilds.get(data);
4536 guilds.set(data, this);
4537
4538 this.discordObject = data;
4539 }
4540
4541 static from(data) {
4542 return new Guild(data);
4543 }
4544
4545 static fromId(id) {
4546 const guild = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildStore.getGuild(id);
4547 if (guild) return Guild.from(guild);
4548 }
4549
4550 static get Role() { return Role; }
4551 static get Emoji() { return Emoji; }
4552
4553 get id() { return this.discordObject.id; }
4554 get ownerId() { return this.discordObject.ownerId; }
4555 get applicationId() { return this.discordObject.application_id; }
4556 get systemChannelId() { return this.discordObject.systemChannelId; }
4557 get name() { return this.discordObject.name; }
4558 get acronym() { return this.discordObject.acronym; }
4559 get icon() { return this.discordObject.icon; }
4560 get joinedAt() { return this.discordObject.joinedAt; }
4561 get verificationLevel() { return this.discordObject.verificationLevel; }
4562 get mfaLevel() { return this.discordObject.mfaLevel; }
4563 get large() { return this.discordObject.large; }
4564 get lazy() { return this.discordObject.lazy; }
4565 get voiceRegion() { return this.discordObject.region; }
4566 get afkChannelId() { return this.discordObject.afkChannelId; }
4567 get afkTimeout() { return this.discordObject.afkTimeout; }
4568 get explicitContentFilter() { return this.discordObject.explicitContentFilter; }
4569 get defaultMessageNotifications() { return this.discordObject.defaultMessageNotifications; }
4570 get splash() { return this.discordObject.splash; }
4571 get features() { return this.discordObject.features; }
4572
4573 get owner() {
4574 return this.members.find(m => m.userId === this.ownerId);
4575 }
4576
4577 get roles() {
4578 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(Object.values(this.discordObject.roles), r => new Role(r, this.id))
4579 .sort((r1, r2) => r1.position === r2.position ? 0 : r1.position > r2.position ? 1 : -1);
4580 }
4581
4582 get channels() {
4583 const channels = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildChannelsStore.getChannels(this.id);
4584 const returnChannels = new structs__WEBPACK_IMPORTED_MODULE_1__["List"]();
4585 for (const category in channels) {
4586 if (channels.hasOwnProperty(category)) {
4587 if (!Array.isArray(channels[category])) continue;
4588 const channelList = channels[category];
4589 for (const channel of channelList) {
4590 // For some reason Discord adds a new category with the ID "null" and name "Uncategorized"
4591 if (channel.channel.id === "null") continue;
4592 returnChannels.push(_channel__WEBPACK_IMPORTED_MODULE_2__["Channel"].from(channel.channel));
4593 }
4594 }
4595 }
4596 return returnChannels;
4597 }
4598
4599 /**
4600 * Channels that don't have a parent. (Channel categories and any text/voice channel not in one.)
4601 */
4602 get mainChannels() {
4603 return this.channels.filter(c => !c.parentId);
4604 }
4605
4606 /**
4607 * The guild's default channel. (Usually the first in the list.)
4608 */
4609 get defaultChannel() {
4610 return _channel__WEBPACK_IMPORTED_MODULE_2__["Channel"].from(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildChannelsStore.getDefaultChannel(this.id));
4611 }
4612
4613 /**
4614 * The guild's AFK channel.
4615 */
4616 get afkChannel() {
4617 if (this.afkChannelId) return _channel__WEBPACK_IMPORTED_MODULE_2__["Channel"].fromId(this.afkChannelId);
4618 }
4619
4620 /**
4621 * The channel system messages are sent to.
4622 */
4623 get systemChannel() {
4624 if (this.systemChannelId) return _channel__WEBPACK_IMPORTED_MODULE_2__["Channel"].fromId(this.systemChannelId);
4625 }
4626
4627 /**
4628 * A list of GuildMember objects.
4629 */
4630 get members() {
4631 const members = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildMemberStore.getMembers(this.id);
4632 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(members, m => new _user__WEBPACK_IMPORTED_MODULE_3__["GuildMember"](m, this.id));
4633 }
4634
4635 /**
4636 * The current user as a GuildMember of this guild.
4637 */
4638 get currentUser() {
4639 return this.members.find(m => m.user === modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser);
4640 }
4641
4642 /**
4643 * The total number of members in the guild.
4644 */
4645 get memberCount() {
4646 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MemberCountStore.getMemberCount(this.id);
4647 }
4648
4649 /**
4650 * An array of the guild's custom emojis.
4651 */
4652 get emojis() {
4653 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].EmojiUtils.getGuildEmoji(this.id), e => new Emoji(e));
4654 }
4655
4656 checkPermissions(perms) {
4657 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].Permissions.can(perms, modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser, this.discordObject);
4658 }
4659
4660 assertPermissions(name, perms) {
4661 if (!this.checkPermissions(perms)) throw new structs__WEBPACK_IMPORTED_MODULE_1__["InsufficientPermissions"](name);
4662 }
4663
4664 /**
4665 * The current user's permissions on this guild.
4666 */
4667 get permissions() {
4668 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildPermissions.getGuildPermissions(this.id);
4669 }
4670
4671 getMember(id) {
4672 const member = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildMemberStore.getMember(this.id, id);
4673 if (member) return new _user__WEBPACK_IMPORTED_MODULE_3__["GuildMember"](member, this.id);
4674 }
4675
4676 isMember(id) {
4677 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildMemberStore.isMember(this.id, id);
4678 }
4679
4680 /**
4681 * Whether the user has not restricted direct messages from members of this guild.
4682 */
4683 get allowPrivateMessages() {
4684 return !modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].UserSettings.restrictedGuildIds.includes(this.id);
4685 }
4686
4687 /**
4688 * Marks all messages in the guild as read.
4689 */
4690 markAsRead() {
4691 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.markGuildAsRead(this.id);
4692 }
4693
4694 /**
4695 * Selects the guild in the UI.
4696 */
4697 select() {
4698 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.selectGuild(this.id);
4699 }
4700
4701 /**
4702 * Whether this guild is currently selected.
4703 */
4704 get isSelected() {
4705 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentGuild === this;
4706 }
4707
4708 /**
4709 * Opens this guild's settings window.
4710 * @param {String} section The section to open (see DiscordConstants.GuildSettingsSections)
4711 */
4712 openSettings(section = "OVERVIEW") {
4713 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildSettingsWindow.setSection(section);
4714 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildSettingsWindow.open(this.id);
4715 }
4716
4717 /**
4718 * Kicks members who don't have any roles and haven't been seen in the number of days passed.
4719 * @param {Number} days
4720 */
4721 pruneMembers(days) {
4722 this.assertPermissions("KICK_MEMBERS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.KICK_MEMBERS);
4723 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].PruneMembersModal.prune(this.id, days);
4724 }
4725
4726 openPruneMumbersModal() {
4727 this.assertPermissions("KICK_MEMBERS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.KICK_MEMBERS);
4728 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].PruneMembersModal.open(this.id);
4729 }
4730
4731 /**
4732 * Opens the create channel modal for this guild.
4733 * @param {Number} type The type of channel to create - either 0 (text), 2 (voice) or 4 (category)
4734 * @param {ChannelCategory} category The category to create the channel in
4735 * @param {GuildChannel} clone A channel to clone permissions, topic, bitrate and user limit of
4736 */
4737 openCreateChannelModal(type, category, clone) {
4738 this.assertPermissions("MANAGE_CHANNELS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.MANAGE_CHANNELS);
4739 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].CreateChannelModal.open(type, this.id, category ? category.id : undefined, clone ? clone.id : undefined);
4740 }
4741
4742 /**
4743 * Creates a channel in this guild.
4744 * @param {Number} type The type of channel to create - either 0 (text), 2 (voice) or 4 (category)
4745 * @param {String} name A name for the new channel
4746 * @param {ChannelCategory} category The category to create the channel in
4747 * @param {Array} permission_overwrites An array of PermissionOverwrite-like objects - leave to use the permissions of the category
4748 * @return {Promise<GuildChannel>}
4749 */
4750 async createChannel(type, name, category, permission_overwrites) {
4751 this.assertPermissions("MANAGE_CHANNELS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.MANAGE_CHANNELS);
4752 const response = await modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].APIModule.post({
4753 url: modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordConstants.Endpoints.GUILD_CHANNELS(this.id),
4754 body: {
4755 type, name,
4756 parent_id: category ? category.id : undefined,
4757 permission_overwrites: permission_overwrites ? permission_overwrites.map(p => ({
4758 type: p.type,
4759 id: (p.type === "user" ? p.userId : p.roleId) || p.id,
4760 allow: p.allow,
4761 deny: p.deny
4762 })) : undefined
4763 }
4764 });
4765
4766 return _channel__WEBPACK_IMPORTED_MODULE_2__["Channel"].fromId(response.body.id);
4767 }
4768
4769 openNotificationSettingsModal() {
4770 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].NotificationSettingsModal.open(this.id);
4771 }
4772
4773 openPrivacySettingsModal() {
4774 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].PrivacySettingsModal.open(this.id);
4775 }
4776
4777 nsfwAgree() {
4778 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.nsfwAgree(this.id);
4779 }
4780
4781 nsfwDisagree() {
4782 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.nsfwDisagree(this.id);
4783 }
4784
4785 /**
4786 * Changes the guild's position in the list.
4787 * @param {Number} index The new position
4788 */
4789 changeSortLocation(index) {
4790 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.move(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].guildPositions.indexOf(this.id), index);
4791 }
4792
4793 /**
4794 * Updates this guild.
4795 * @return {Promise}
4796 */
4797 async updateGuild(body) {
4798 this.assertPermissions("MANAGE_GUILD", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.MANAGE_GUILD);
4799 await modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildSettingsWindow.saveGuild(this.id, body);
4800 this.discordObject = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildStore.getGuild(this.id);
4801 guilds.set(this.discordObject, this);
4802 }
4803
4804 /**
4805 * Updates this guild's name.
4806 * @param {String} name The new name
4807 * @return {Promise}
4808 */
4809 updateName(name) {
4810 return this.updateGuild({ name });
4811 }
4812
4813 /**
4814 * Updates this guild's voice region.
4815 * @param {String} region The ID of the new voice region (obtainable via the API - see https://discordapp.com/developers/docs/resources/voice#list-voice-regions)
4816 * @return {Promise}
4817 */
4818 updateVoiceRegion(region) {
4819 return this.updateGuild({ region });
4820 }
4821
4822 /**
4823 * Updates this guild's verification level.
4824 * @param {Number} verificationLevel The new verification level (see https://discordapp.com/developers/docs/resources/guild#guild-object-verification-level)
4825 * @return {Promise}
4826 */
4827 updateVerificationLevel(verification_level) {
4828 return this.updateGuild({ verification_level });
4829 }
4830
4831 /**
4832 * Updates this guild's default message notification level.
4833 * @param {Number} defaultMessageNotifications The new default notification level (0: all messages, 1: only mentions)
4834 * @return {Promise}
4835 */
4836 updateDefaultMessageNotifications(default_message_notifications) {
4837 return this.updateGuild({ default_message_notifications });
4838 }
4839
4840 /**
4841 * Updates this guild's explicit content filter level.
4842 * @param {Number} explicitContentFilter The new explicit content filter level (0: disabled, 1: members without roles, 2: everyone)
4843 * @return {Promise}
4844 */
4845 updateExplicitContentFilter(explicit_content_filter) {
4846 return this.updateGuild({ explicit_content_filter });
4847 }
4848
4849 /**
4850 * Updates this guild's AFK channel.
4851 * @param {GuildVoiceChannel} afkChannel The new AFK channel
4852 * @return {Promise}
4853 */
4854 updateAfkChannel(afk_channel) {
4855 return this.updateGuild({ afk_channel_id: afk_channel.id || afk_channel });
4856 }
4857
4858 /**
4859 * Updates this guild's AFK timeout.
4860 * @param {Number} afkTimeout The new AFK timeout
4861 * @return {Promise}
4862 */
4863 updateAfkTimeout(afk_timeout) {
4864 return this.updateGuild({ afk_timeout });
4865 }
4866
4867 /**
4868 * Updates this guild's icon.
4869 * @param {Buffer|String} icon A buffer/base 64 encoded 128x128 JPEG image
4870 * @return {Promise}
4871 */
4872 updateIcon(icon) {
4873 return this.updateGuild({ icon: typeof icon === "string" ? icon : icon.toString("base64") });
4874 }
4875
4876 /**
4877 * Updates this guild's icon using a local file.
4878 * TODO
4879 * @param {String} icon_path The path to the new icon
4880 * @return {Promise}
4881 */
4882 async updateIconFromFile(icon_path) {
4883 const buffer = await modules__WEBPACK_IMPORTED_MODULE_0__["Utilities"].readFileBuffer(icon_path);
4884 return this.updateIcon(buffer);
4885 }
4886
4887 /**
4888 * Updates this guild's owner. (Should plugins really ever need to do this?)
4889 * @param {User|GuildMember} owner The user/guild member to transfer ownership to
4890 * @return {Promise}
4891 */
4892 updateOwner(owner) {
4893 return this.updateGuild({ owner_id: owner.user ? owner.user.id : owner.id || owner });
4894 }
4895
4896 /**
4897 * Updates this guild's splash image.
4898 * (I don't know what this is actually used for. The API documentation says it's VIP-only.)
4899 * @param {Buffer|String} icon A buffer/base 64 encoded 128x128 JPEG image
4900 * @return {Promise}
4901 */
4902 updateSplash(splash) {
4903 return this.updateGuild({ splash: typeof splash === "string" ? splash : splash.toString("base64") });
4904 }
4905
4906 /**
4907 * Updates this guild's splash image using a local file.
4908 * TODO
4909 * @param {String} splash_path The path to the new splash
4910 * @return {Promise}
4911 */
4912 async updateSplashFromFile(splash_path) {
4913 const buffer = await modules__WEBPACK_IMPORTED_MODULE_0__["Utilities"].readFileBuffer(splash_path);
4914 return this.updateSplash(buffer);
4915 }
4916
4917 /**
4918 * Updates this guild's system channel.
4919 * @param {GuildTextChannel} systemChannel The new system channel
4920 * @return {Promise}
4921 */
4922 updateSystemChannel(system_channel) {
4923 return this.updateGuild({ system_channel_id: system_channel.id || system_channel });
4924 }
4925
4926}
4927
4928
4929
4930/***/ }),
4931
4932/***/ "./src/structs/discord/message.js":
4933/*!****************************************!*\
4934 !*** ./src/structs/discord/message.js ***!
4935 \****************************************/
4936/*! exports provided: Reaction, Embed, Message, DefaultMessage, RecipientAddMessage, RecipientRemoveMessage, CallMessage, GroupChannelNameChangeMessage, GroupChannelIconChangeMessage, MessagePinnedMessage, GuildMemberJoinMessage */
4937/***/ (function(module, __webpack_exports__, __webpack_require__) {
4938
4939"use strict";
4940__webpack_require__.r(__webpack_exports__);
4941/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Reaction", function() { return Reaction; });
4942/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Embed", function() { return Embed; });
4943/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Message", function() { return Message; });
4944/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DefaultMessage", function() { return DefaultMessage; });
4945/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RecipientAddMessage", function() { return RecipientAddMessage; });
4946/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RecipientRemoveMessage", function() { return RecipientRemoveMessage; });
4947/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CallMessage", function() { return CallMessage; });
4948/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GroupChannelNameChangeMessage", function() { return GroupChannelNameChangeMessage; });
4949/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GroupChannelIconChangeMessage", function() { return GroupChannelIconChangeMessage; });
4950/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MessagePinnedMessage", function() { return MessagePinnedMessage; });
4951/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GuildMemberJoinMessage", function() { return GuildMemberJoinMessage; });
4952/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
4953/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! structs */ "./src/structs/structs.js");
4954/* harmony import */ var _channel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./channel */ "./src/structs/discord/channel.js");
4955/* harmony import */ var _user__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./user */ "./src/structs/discord/user.js");
4956/**
4957 * BetterDiscord Message Struct
4958 * Copyright (c) 2018-present JsSucks
4959 * All rights reserved.
4960 *
4961 * This source code is licensed under the MIT license found at
4962 * https://github.com/JsSucks/BetterDiscordApp/blob/master/LICENSE
4963*/
4964
4965
4966
4967
4968
4969
4970const reactions = new WeakMap();
4971
4972class Reaction {
4973 constructor(data, message_id, channel_id) {
4974 if (reactions.has(data)) return reactions.get(data);
4975 reactions.set(data, this);
4976
4977 this.discordObject = data;
4978 this.messageId = message_id;
4979 this.channelId = channel_id;
4980 }
4981
4982 get emoji() {
4983 const id = this.discordObject.emoji.id;
4984 if (!id || !this.guild) return this.discordObject.emoji;
4985 return this.guild.emojis.find(e => e.id === id);
4986 }
4987
4988 get count() { return this.discordObject.count; }
4989 get me() { return this.discordObject.me; }
4990
4991 get channel() {
4992 return _channel__WEBPACK_IMPORTED_MODULE_2__["Channel"].fromId(this.channel_id);
4993 }
4994
4995 get message() {
4996 if (this.channel) return this.channel.messages.find(m => m.id === this.messageId);
4997 }
4998
4999 get guild() {
5000 if (this.channel) return this.channel.guild;
5001 }
5002}
5003
5004const embeds = new WeakMap();
5005
5006class Embed {
5007 constructor(data, message_id, channel_id) {
5008 if (embeds.has(data)) return embeds.get(data);
5009 embeds.set(data, this);
5010
5011 this.discordObject = data;
5012 this.messageId = message_id;
5013 this.channelId = channel_id;
5014 }
5015
5016 get title() { return this.discordObject.title; }
5017 get type() { return this.discordObject.type; }
5018 get description() { return this.discordObject.description; }
5019 get url() { return this.discordObject.url; }
5020 get timestamp() { return this.discordObject.timestamp; }
5021 get colour() { return this.discordObject.color; }
5022 get footer() { return this.discordObject.footer; }
5023 get image() { return this.discordObject.image; }
5024 get thumbnail() { return this.discordObject.thumbnail; }
5025 get video() { return this.discordObject.video; }
5026 get provider() { return this.discordObject.provider; }
5027 get author() { return this.discordObject.author; }
5028 get fields() { return this.discordObject.fields; }
5029
5030 get channel() {
5031 return _channel__WEBPACK_IMPORTED_MODULE_2__["Channel"].fromId(this.channelId);
5032 }
5033
5034 get message() {
5035 if (this.channel) return this.channel.messages.find(m => m.id === this.messageId);
5036 }
5037
5038 get guild() {
5039 if (this.channel) return this.channel.guild;
5040 }
5041}
5042
5043const messages = new WeakMap();
5044
5045/**
5046 * @memberof module:DiscordAPI
5047 */
5048class Message {
5049
5050 constructor(data) {
5051 if (messages.has(data)) return messages.get(data);
5052 messages.set(data, this);
5053
5054 this.discordObject = data;
5055 }
5056
5057 static from(data) {
5058 switch (data.type) {
5059 default: return new Message(data);
5060 case 0: return new DefaultMessage(data);
5061 case 1: return new RecipientAddMessage(data);
5062 case 2: return new RecipientRemoveMessage(data);
5063 case 3: return new CallMessage(data);
5064 case 4: return new GroupChannelNameChangeMessage(data);
5065 case 5: return new GroupChannelIconChangeMessage(data);
5066 case 6: return new MessagePinnedMessage(data);
5067 case 7: return new GuildMemberJoinMessage(data);
5068 }
5069 }
5070
5071 static get DefaultMessage() { return DefaultMessage; }
5072 static get RecipientAddMessage() { return RecipientAddMessage; }
5073 static get RecipientRemoveMessage() { return RecipientRemoveMessage; }
5074 static get CallMessage() { return CallMessage; }
5075 static get GroupChannelNameChangeMessage() { return GroupChannelNameChangeMessage; }
5076 static get GroupChannelIconChangeMessage() { return GroupChannelIconChangeMessage; }
5077 static get MessagePinnedMessage() { return MessagePinnedMessage; }
5078 static get GuildMemberJoinMessage() { return GuildMemberJoinMessage; }
5079
5080 static get Reaction() { return Reaction; }
5081 static get Embed() { return Embed; }
5082
5083 get id() { return this.discordObject.id; }
5084 get channelId() { return this.discordObject.channel_id; }
5085 get nonce() { return this.discordObject.nonce; }
5086 get type() { return this.discordObject.type; }
5087 get timestamp() { return this.discordObject.timestamp; }
5088 get state() { return this.discordObject.state; }
5089 get nick() { return this.discordObject.nick; }
5090 get colourString() { return this.discordObject.colorString; }
5091
5092 get author() {
5093 if (this.discordObject.author && !this.webhookId) return _user__WEBPACK_IMPORTED_MODULE_3__["User"].from(this.discordObject.author);
5094 }
5095
5096 get channel() {
5097 return _channel__WEBPACK_IMPORTED_MODULE_2__["Channel"].fromId(this.channelId);
5098 }
5099
5100 get guild() {
5101 if (this.channel) return this.channel.guild;
5102 }
5103
5104 /**
5105 * Deletes the message.
5106 * @return {Promise}
5107 */
5108 delete() {
5109 if (!this.isDeletable) throw new Error(`Message type ${this.type} is not deletable.`);
5110 if (this.author !== modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser) {
5111 if (this.channel.assertPermissions) this.channel.assertPermissions("MANAGE_MESSAGES", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.MANAGE_MESSAGES);
5112 else if (!this.channel.owner === modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser) throw new structs__WEBPACK_IMPORTED_MODULE_1__["InsufficientPermissions"]("MANAGE_MESSAGES");
5113 }
5114
5115 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].APIModule.delete(`${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordConstants.Endpoints.MESSAGES(this.channelId)}/${this.id}`);
5116 }
5117
5118 get isDeletable() {
5119 return this.type === "DEFAULT" || this.type === "CHANNEL_PINNED_MESSAGE" || this.type === "GUILD_MEMBER_JOIN";
5120 }
5121
5122 /**
5123 * Jumps to the message.
5124 */
5125 jumpTo(flash = true) {
5126 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageActions.jumpToMessage(this.channelId, this.id, flash);
5127 }
5128
5129}
5130
5131
5132
5133class DefaultMessage extends Message {
5134 get webhookId() { return this.discordObject.webhookId; }
5135 get type() { return "DEFAULT"; }
5136 get content() { return this.discordObject.content; }
5137 get contentParsed() { return this.discordObject.contentParsed; }
5138 get inviteCodes() { return this.discordObject.invites; }
5139 get attachments() { return this.discordObject.attachments; }
5140 get mentionIds() { return this.discordObject.mentions; }
5141 get mentionRoleIds() { return this.discordObject.mentionRoles; }
5142 get mentionEveryone() { return this.discordObject.mentionEveryone; }
5143 get editedTimestamp() { return this.discordObject.editedTimestamp; }
5144 get tts() { return this.discordObject.tts; }
5145 get mentioned() { return this.discordObject.mentioned; }
5146 get bot() { return this.discordObject.bot; }
5147 get blocked() { return this.discordObject.blocked; }
5148 get pinned() { return this.discordObject.pinned; }
5149 get activity() { return this.discordObject.activity; }
5150 get application() { return this.discordObject.application; }
5151
5152 get webhook() {
5153 if (this.webhookId) return this.discordObject.author;
5154 }
5155
5156 get mentions() {
5157 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(this.mentionIds, id => _user__WEBPACK_IMPORTED_MODULE_3__["User"].fromId(id));
5158 }
5159
5160 get mention_roles() {
5161 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(this.mentionRoleIds, id => this.guild.roles.find(r => r.id === id));
5162 }
5163
5164 get embeds() {
5165 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(this.discordObject.embeds, r => new Embed(r, this.id, this.channelId));
5166 }
5167
5168 get reactions() {
5169 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(this.discordObject.reactions, r => new Reaction(r, this.id, this.channelId));
5170 }
5171
5172 get edited() {
5173 return !!this.editedTimestamp;
5174 }
5175
5176 /**
5177 * Programmatically update the message's content.
5178 * @param {String} content The message's new content
5179 * @param {Boolean} parse Whether to parse the message or update it as it is
5180 * @return {Promise}
5181 */
5182 async edit(content, parse = false) {
5183 if (this.author !== modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser) throw new Error("Cannot edit messages sent by other users.");
5184 if (parse) content = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageParser.parse(this.discordObject, content);
5185 else content = {content};
5186
5187 const response = await modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].APIModule.patch({
5188 url: `${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordConstants.Endpoints.MESSAGES(this.channelId)}/${this.id}`,
5189 body: content
5190 });
5191
5192 this.discordObject = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageStore.getMessage(this.id, response.body.id);
5193 messages.set(this.discordObject, this);
5194 }
5195
5196 /**
5197 * Start the edit mode of the UI.
5198 * @param {String} content A string to show in the message text area - if empty the message's current content will be used
5199 */
5200 startEdit(content) {
5201 if (this.author !== modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser) throw new Error("Cannot edit messages sent by other users.");
5202 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageActions.startEditMessage(this.channelId, this.id, content || this.content);
5203 }
5204
5205 /**
5206 * Exit the edit mode of the UI.
5207 */
5208 endEdit() {
5209 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].MessageActions.endEditMessage();
5210 }
5211}
5212
5213class RecipientAddMessage extends Message {
5214 get type() { return "RECIPIENT_ADD"; }
5215 get addedUserId() { return this.discordObject.mentions[0]; }
5216
5217 get addedUser() {
5218 return _user__WEBPACK_IMPORTED_MODULE_3__["User"].fromId(this.addedUserId);
5219 }
5220}
5221
5222class RecipientRemoveMessage extends Message {
5223 get type() { return "RECIPIENT_REMOVE"; }
5224 get removedUserId() { return this.discordObject.mentions[0]; }
5225
5226 get removedUser() {
5227 return _user__WEBPACK_IMPORTED_MODULE_3__["User"].fromId(this.removedUserId);
5228 }
5229
5230 get userLeft() {
5231 return this.author === this.removedUser;
5232 }
5233}
5234
5235class CallMessage extends Message {
5236 get type() { return "CALL"; }
5237 get mentionIds() { return this.discordObject.mentions; }
5238 get call() { return this.discordObject.call; }
5239
5240 get endedTimestamp() { return this.call.endedTimestamp; }
5241
5242 get mentions() {
5243 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(this.mentionIds, id => _user__WEBPACK_IMPORTED_MODULE_3__["User"].fromId(id));
5244 }
5245
5246 get participants() {
5247 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(this.call.participants, id => _user__WEBPACK_IMPORTED_MODULE_3__["User"].fromId(id));
5248 }
5249}
5250
5251class GroupChannelNameChangeMessage extends Message {
5252 get type() { return "CHANNEL_NAME_CHANGE"; }
5253 get newName() { return this.discordObject.content; }
5254}
5255
5256class GroupChannelIconChangeMessage extends Message {
5257 get type() { return "CHANNEL_ICON_CHANGE"; }
5258}
5259
5260class MessagePinnedMessage extends Message {
5261 get type() { return "CHANNEL_PINNED_MESSAGE"; }
5262}
5263
5264class GuildMemberJoinMessage extends Message {
5265 get type() { return "GUILD_MEMBER_JOIN"; }
5266}
5267
5268
5269/***/ }),
5270
5271/***/ "./src/structs/discord/user.js":
5272/*!*************************************!*\
5273 !*** ./src/structs/discord/user.js ***!
5274 \*************************************/
5275/*! exports provided: User, GuildMember */
5276/***/ (function(module, __webpack_exports__, __webpack_require__) {
5277
5278"use strict";
5279__webpack_require__.r(__webpack_exports__);
5280/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "User", function() { return User; });
5281/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GuildMember", function() { return GuildMember; });
5282/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
5283/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! structs */ "./src/structs/structs.js");
5284/* harmony import */ var _guild__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./guild */ "./src/structs/discord/guild.js");
5285/* harmony import */ var _channel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./channel */ "./src/structs/discord/channel.js");
5286/**
5287 * BetterDiscord User Struct
5288 * Copyright (c) 2018-present JsSucks
5289 * All rights reserved.
5290 *
5291 * This source code is licensed under the MIT license found at
5292 * https://github.com/JsSucks/BetterDiscordApp/blob/master/LICENSE
5293*/
5294
5295
5296
5297
5298
5299
5300const users = new WeakMap();
5301
5302/**
5303 * @memberof module:DiscordAPI
5304 */
5305class User {
5306
5307 constructor(data) {
5308 if (users.has(data)) return users.get(data);
5309 users.set(data, this);
5310
5311 this.discordObject = data;
5312 }
5313
5314 static from(data) {
5315 return new User(data);
5316 }
5317
5318 static fromId(id) {
5319 const user = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserStore.getUser(id);
5320 if (user) return User.from(user);
5321 }
5322
5323 get id() { return this.discordObject.id; }
5324 get username() { return this.discordObject.username; }
5325 get usernameLowerCase() { return this.discordObject.usernameLowerCase; }
5326 get discriminator() { return this.discordObject.discriminator; }
5327 get avatar() { return this.discordObject.avatar; }
5328 get email() { return undefined; }
5329 get phone() { return undefined; }
5330 get flags() { return this.discordObject.flags; }
5331 get isBot() { return this.discordObject.bot; }
5332 get premium() { return this.discordObject.premium; }
5333 get verified() { return this.discordObject.verified; }
5334 get mfaEnabled() { return this.discordObject.mfaEnabled; }
5335 get mobile() { return this.discordObject.mobile; }
5336
5337 get tag() { return this.discordObject.tag; }
5338 get avatarUrl() { return this.discordObject.avatarURL; }
5339 get createdAt() { return this.discordObject.createdAt; }
5340
5341 get isClamied() { return this.discordObject.isClaimed(); }
5342 get isLocalBot() { return this.discordObject.isLocalBot(); }
5343 get isPhoneVerified() { return this.discordObject.isPhoneVerified(); }
5344
5345 get guilds() {
5346 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].guilds.filter(g => g.members.find(m => m.user === this));
5347 }
5348
5349 get status() {
5350 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserStatusStore.getStatus(this.id);
5351 }
5352
5353 get activity() {
5354 // type can be either 0 (normal/rich presence game), 1 (streaming) or 2 (listening to Spotify)
5355 // (3 appears as watching but is undocumented)
5356 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserStatusStore.getActivity(this.id);
5357 }
5358
5359 get note() {
5360 const note = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserNoteStore.getNote(this.id);
5361 if (note) return note;
5362 }
5363
5364 /**
5365 * Updates the note for this user.
5366 * @param {String} note The new note
5367 * @return {Promise}
5368 */
5369 updateNote(note) {
5370 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].APIModule.put({
5371 url: `${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordConstants.Endpoints.NOTES}/${this.id}`,
5372 body: { note }
5373 });
5374 }
5375
5376 get privateChannel() {
5377 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].channels.find(c => c.type === "DM" && c.recipientId === this.id);
5378 }
5379
5380 async ensurePrivateChannel() {
5381 if (modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser === this)
5382 throw new Error("Cannot create a direct message channel to the current user.");
5383 return _channel__WEBPACK_IMPORTED_MODULE_3__["Channel"].fromId(await modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].PrivateChannelActions.ensurePrivateChannel(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser.id, this.id));
5384 }
5385
5386 async sendMessage(content, parse = true) {
5387 const channel = await this.ensurePrivateChannel();
5388 return channel.sendMessage(content, parse);
5389 }
5390
5391 get isFriend() {
5392 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].RelationshipStore.isFriend(this.id);
5393 }
5394
5395 get isBlocked() {
5396 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].RelationshipStore.isBlocked(this.id);
5397 }
5398
5399 addFriend() {
5400 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].RelationshipManager.addRelationship(this.id, {location: "Context Menu"});
5401 }
5402
5403 removeFriend() {
5404 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].RelationshipManager.removeRelationship(this.id, {location: "Context Menu"});
5405 }
5406
5407 block() {
5408 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].RelationshipManager.addRelationship(this.id, {location: "Context Menu"}, modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordConstants.RelationshipTypes.BLOCKED);
5409 }
5410
5411 unblock() {
5412 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].RelationshipManager.removeRelationship(this.id, {location: "Context Menu"});
5413 }
5414
5415 /**
5416 * Opens the profile modal for this user.
5417 * @param {String} section The section to open (see DiscordConstants.UserProfileSections)
5418 */
5419 openUserProfileModal(section = "USER_INFO") {
5420 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserProfileModal.open(this.id);
5421 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserProfileModal.setSection(section);
5422 }
5423}
5424
5425
5426
5427const guild_members = new WeakMap();
5428
5429class GuildMember {
5430 constructor(data, guild_id) {
5431 if (guild_members.has(data)) return guild_members.get(data);
5432 guild_members.set(data, this);
5433
5434 this.discordObject = data;
5435 this.guildId = guild_id;
5436 }
5437
5438 get userId() { return this.discordObject.userId; }
5439 get nickname() { return this.discordObject.nick; }
5440 get colourString() { return this.discordObject.colorString; }
5441 get hoistRoleId() { return this.discordObject.hoistRoleId; }
5442 get roleIds() { return this.discordObject.roles; }
5443
5444 get user() {
5445 return User.fromId(this.userId);
5446 }
5447
5448 get name() {
5449 return this.nickname || this.user.username;
5450 }
5451
5452 get guild() {
5453 return _guild__WEBPACK_IMPORTED_MODULE_2__["Guild"].fromId(this.guildId);
5454 }
5455
5456 get roles() {
5457 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(this.roleIds, id => this.guild.roles.find(r => r.id === id))
5458 .sort((r1, r2) => r1.position === r2.position ? 0 : r1.position > r2.position ? 1 : -1);
5459 }
5460
5461 get hoistRole() {
5462 return this.guild.roles.find(r => r.id === this.hoistRoleId);
5463 }
5464
5465 checkPermissions(perms) {
5466 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].Permissions.can(perms, modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser.discordObject, this.guild.discordObject);
5467 }
5468
5469 assertPermissions(name, perms) {
5470 if (!this.checkPermissions(perms)) throw new structs__WEBPACK_IMPORTED_MODULE_1__["InsufficientPermissions"](name);
5471 }
5472
5473 /**
5474 * Opens the modal to change this user's nickname.
5475 */
5476 openChangeNicknameModal() {
5477 if (modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser === this.user)
5478 this.assertPermissions("CHANGE_NICKNAME", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.CHANGE_NICKNAME);
5479 else this.assertPermissions("MANAGE_NICKNAMES", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.MANAGE_NICKNAMES);
5480
5481 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].ChangeNicknameModal.open(this.guildId, this.userId);
5482 }
5483
5484 /**
5485 * Changes the user's nickname on this guild.
5486 * @param {String} nickname The user's new nickname
5487 * @return {Promise}
5488 */
5489 changeNickname(nick) {
5490 if (modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser === this.user)
5491 this.assertPermissions("CHANGE_NICKNAME", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.CHANGE_NICKNAME);
5492 else this.assertPermissions("MANAGE_NICKNAMES", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.MANAGE_NICKNAMES);
5493
5494 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].APIModule.patch({
5495 url: `${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordConstants.Endpoints.GUILD_MEMBERS(this.guild_id)}/${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordAPI"].currentUser === this.user ? "@me/nick" : this.userId}`,
5496 body: { nick }
5497 });
5498 }
5499
5500 /**
5501 * Kicks this user from the guild.
5502 * @param {String} reason A reason to attach to the audit log entry
5503 * @return {Promise}
5504 */
5505 kick(reason = "") {
5506 this.assertPermissions("KICK_MEMBERS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.KICK_MEMBERS);
5507 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.kickUser(this.guildId, this.userId, reason);
5508 }
5509
5510 /**
5511 * Bans this user from the guild.
5512 * @param {Number} daysToDelete The number of days of the user's recent message history to delete
5513 * @param {String} reason A reason to attach to the audit log entry
5514 * @return {Promise}
5515 */
5516 ban(daysToDelete = 1, reason = "") {
5517 this.assertPermissions("BAN_MEMBERS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.BAN_MEMBERS);
5518 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.banUser(this.guildId, this.userId, daysToDelete, reason);
5519 }
5520
5521 /**
5522 * Removes the ban for this user.
5523 * @return {Promise}
5524 */
5525 unban() {
5526 this.assertPermissions("BAN_MEMBERS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.BAN_MEMBERS);
5527 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.unbanUser(this.guildId, this.userId);
5528 }
5529
5530 /**
5531 * Moves this user to another voice channel.
5532 * @param {GuildVoiceChannel} channel The channel to move this user to
5533 */
5534 move(channel) {
5535 this.assertPermissions("MOVE_MEMBERS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.MOVE_MEMBERS);
5536 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.setChannel(this.guildId, this.userId, channel.id);
5537 }
5538
5539 /**
5540 * Mutes this user for everyone in the guild.
5541 */
5542 mute(active = true) {
5543 this.assertPermissions("MUTE_MEMBERS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.MUTE_MEMBERS);
5544 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.setServerMute(this.guildId, this.userId, active);
5545 }
5546
5547 /**
5548 * Unmutes this user.
5549 */
5550 unmute() {
5551 this.mute(false);
5552 }
5553
5554 /**
5555 * Deafens this user.
5556 */
5557 deafen(active = true) {
5558 this.assertPermissions("DEAFEN_MEMBERS", modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordPermissions.DEAFEN_MEMBERS);
5559 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].GuildActions.setServerDeaf(this.guildId, this.userId, active);
5560 }
5561
5562 /**
5563 * Undeafens this user.
5564 */
5565 undeafen() {
5566 this.deafen(false);
5567 }
5568
5569 /**
5570 * Gives this user a role.
5571 * @param {Role} role The role to add
5572 * @return {Promise}
5573 */
5574 addRole(...roles) {
5575 const newRoles = this.roleIds.concat([]);
5576 let changed = false;
5577 for (let role of roles) {
5578 if (newRoles.includes(role.id || role)) continue;
5579 newRoles.push(role.id || role);
5580 changed = true;
5581 }
5582 if (!changed) return;
5583 return this.updateRoles(newRoles);
5584 }
5585
5586 /**
5587 * Removes a role from this user.
5588 * @param {Role} role The role to remove
5589 * @return {Promise}
5590 */
5591 removeRole(...roles) {
5592 const newRoles = this.roleIds.concat([]);
5593 let changed = false;
5594 for (let role of roles) {
5595 if (!newRoles.includes(role.id || role)) continue;
5596 modules__WEBPACK_IMPORTED_MODULE_0__["Utilities"].removeFromArray(newRoles, role.id || role);
5597 changed = true;
5598 }
5599 if (!changed) return;
5600 return this.updateRoles(newRoles);
5601 }
5602
5603 /**
5604 * Updates this user's roles.
5605 * @param {Array} roles An array of Role objects or role IDs
5606 * @return {Promise}
5607 */
5608 updateRoles(roles) {
5609 roles = roles.map(r => r.id || r);
5610 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].APIModule.patch({
5611 url: `${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].DiscordConstants.Endpoints.GUILD_MEMBERS(this.guildId)}/${this.userId}`,
5612 body: { roles }
5613 });
5614 }
5615}
5616
5617
5618/***/ }),
5619
5620/***/ "./src/structs/discord/usersettings.js":
5621/*!*********************************************!*\
5622 !*** ./src/structs/discord/usersettings.js ***!
5623 \*********************************************/
5624/*! exports provided: UserSettings */
5625/***/ (function(module, __webpack_exports__, __webpack_require__) {
5626
5627"use strict";
5628__webpack_require__.r(__webpack_exports__);
5629/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UserSettings", function() { return UserSettings; });
5630/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
5631/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! structs */ "./src/structs/structs.js");
5632/* harmony import */ var _guild__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./guild */ "./src/structs/discord/guild.js");
5633/**
5634 * BetterDiscord Channel Struct
5635 * Copyright (c) 2018-present JsSucks
5636 * All rights reserved.
5637 *
5638 * This source code is licensed under the MIT license found at
5639 * https://github.com/JsSucks/BetterDiscordApp/blob/master/LICENSE
5640*/
5641
5642
5643
5644
5645
5646
5647
5648/**
5649 * @memberof module:DiscordAPI
5650 */
5651class UserSettings {
5652 /**
5653 * Opens Discord's settings UI.
5654 */
5655 static open(section = "ACCOUNT") {
5656 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsWindow.setSection(section);
5657 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsWindow.open();
5658 }
5659
5660 /**
5661 * The user's current status. Either "online", "idle", "dnd" or "invisible".
5662 */
5663 static get status() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.status; }
5664
5665 /**
5666 * The user's selected explicit content filter level.
5667 * 0 == off, 1 == everyone except friends, 2 == everyone
5668 * Configurable in the privacy and safety panel.
5669 */
5670 static get explicitContentFilter() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.explicitContentFilter; }
5671
5672 /**
5673 * Whether to disallow direct messages from server members by default.
5674 */
5675 static get defaultGuildsRestricted() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.defaultGuildsRestricted; }
5676
5677 /**
5678 * An array of guilds to disallow direct messages from their members.
5679 * This is bypassed if the member is has another mutual guild with this disabled, or the member is friends with the current user.
5680 * Configurable in each server's privacy settings.
5681 */
5682 static get restrictedGuildIds() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.restrictedGuilds; }
5683
5684 static get restrictedGuilds() {
5685 return structs__WEBPACK_IMPORTED_MODULE_1__["List"].from(this.restrictedGuildIds, id => _guild__WEBPACK_IMPORTED_MODULE_2__["Guild"].fromId(id) || id);
5686 }
5687
5688 /**
5689 * An array of flags specifying who should be allowed to add the current user as a friend.
5690 * If everyone is checked, this will only have one item, "all". Otherwise it has either "mutual_friends", "mutual_guilds", both or neither.
5691 * Configurable in the privacy and safety panel.
5692 */
5693 static get friendSourceFlags() { return Object.keys(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.friendSourceFlags); }
5694 static get friendSourceEveryone() { return this.friend_source_flags.include("all"); }
5695 static get friendSourceMutual_friends() { return this.friend_source_flags.include("all") || this.friend_source_flags.include("mutual_friends"); }
5696 static get friendSourceMutual_guilds() { return this.friend_source_flags.include("all") || this.friend_source_flags.include("mutual_guilds"); }
5697 static get friendSourceAnyone() { return this.friend_source_flags.length > 0; }
5698
5699 /**
5700 * Whether to automatically add accounts from other platforms running on the user's computer.
5701 * Configurable in the connections panel.
5702 */
5703 static get detectPlatformAccounts() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.detectPlatformAccounts; }
5704
5705 /**
5706 * The number of seconds Discord will wait for activity before sending mobile push notifications.
5707 * Configurable in the notifications panel.
5708 */
5709 static get afkTimeout() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.afkTimeout; }
5710
5711 /**
5712 * Whether to display the currently running game as a status message.
5713 * Configurable in the games panel.
5714 */
5715 static get showCurrentGame() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.showCurrentGame; }
5716
5717 /**
5718 * Whether to show images uploaded directly to Discord.
5719 * Configurable in the text and images panel.
5720 */
5721 static get inlineAttachmentMedia() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.inlineAttachmentMedia; }
5722
5723 /**
5724 * Whether to show images linked in Discord.
5725 * Configurable in the text and images panel.
5726 */
5727 static get inlineEmbedMedia() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.inlineEmbedMedia; }
5728
5729 /**
5730 * Whether to automatically play GIFs when the Discord window is active without having to hover the mouse over the image.
5731 * Configurable in the text and images panel.
5732 */
5733 static get autoplayGifs() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.gifAutoPlay; }
5734
5735 /**
5736 * Whether to show content from HTTP[s] links as embeds.
5737 * Configurable in the text and images panel.
5738 */
5739 static get showEmbeds() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.renderEmbeds; }
5740
5741 /**
5742 * Whether to show a message's reactions.
5743 * Configurable in the text and images panel.
5744 */
5745 static get showReactions() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.renderReactions; }
5746
5747 /**
5748 * Whether to play animated emoji.
5749 * Configurable in the text and images panel.
5750 */
5751 static get animateEmoji() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.animateEmoji; }
5752
5753 /**
5754 * Whether to convert ASCII emoticons to emoji.
5755 * Configurable in the text and images panel.
5756 */
5757 static get convertEmoticons() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.convertEmoticons; }
5758
5759 /**
5760 * Whether to allow playing text-to-speech messages.
5761 * Configurable in the text and images panel.
5762 */
5763 static get allowTts() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.enableTTSCommand; }
5764
5765 /**
5766 * The user's selected theme. Either "dark" or "light".
5767 * Configurable in the appearance panel.
5768 */
5769 static get theme() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.theme; }
5770
5771 /**
5772 * Whether the user has enabled compact mode.
5773 * `true` if compact mode is enabled, `false` if cozy mode is enabled.
5774 * Configurable in the appearance panel.
5775 */
5776 static get displayCompact() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.messageDisplayCompact; }
5777
5778 /**
5779 * Whether the user has enabled developer mode.
5780 * Currently only adds a "Copy ID" option to the context menu on users, guilds and channels.
5781 * Configurable in the appearance panel.
5782 */
5783 static get developerMode() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.developerMode; }
5784
5785 /**
5786 * The user's selected language code.
5787 * Configurable in the language panel.
5788 */
5789 static get locale() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.locale; }
5790
5791 /**
5792 * The user's timezone offset in hours.
5793 * This is not configurable.
5794 */
5795 static get timezoneOffset() { return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserSettingsStore.timezoneOffset; }
5796}
5797
5798
5799
5800/***/ }),
5801
5802/***/ "./src/structs/dom/classname.js":
5803/*!**************************************!*\
5804 !*** ./src/structs/dom/classname.js ***!
5805 \**************************************/
5806/*! exports provided: default */
5807/***/ (function(module, __webpack_exports__, __webpack_require__) {
5808
5809"use strict";
5810__webpack_require__.r(__webpack_exports__);
5811/* harmony import */ var _selector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./selector */ "./src/structs/dom/selector.js");
5812
5813
5814/**
5815 * Representation of a Class Name
5816 * @memberof module:DOMTools
5817 **/
5818class ClassName {
5819 /**
5820 *
5821 * @param {string} name - name of the class to represent
5822 */
5823 constructor(name) {
5824 this.value = name;
5825 }
5826
5827 /**
5828 * Concatenates new class names to the current one using spaces.
5829 * @param {string} classNames - list of class names to add to this class name
5830 * @returns {ClassName} returns self to allow chaining
5831 */
5832 add(...classNames) {
5833 for (let i = 0; i < classNames.length; i++) this.value += " " + classNames[i];
5834 return this;
5835 }
5836
5837 /**
5838 * Returns the raw class name, this is how native function get the value.
5839 * @returns {string} raw class name.
5840 */
5841 toString() {
5842 return this.value;
5843 }
5844
5845 /**
5846 * Returns the raw class name, this is how native function get the value.
5847 * @returns {string} raw class name.
5848 */
5849 valueOf() {
5850 return this.value;
5851 }
5852
5853 /**
5854 * Returns the classname represented as {@link module:DOMTools.Selector}.
5855 * @returns {Selector} selector representation of this class name.
5856 */
5857 get selector() {
5858 return new _selector__WEBPACK_IMPORTED_MODULE_0__["default"](this.value);
5859 }
5860
5861 get single() {
5862 return this.value.split(" ")[0];
5863 }
5864
5865 get first() {
5866 return this.value.split(" ")[0];
5867 }
5868}
5869
5870/* harmony default export */ __webpack_exports__["default"] = (ClassName);
5871
5872/***/ }),
5873
5874/***/ "./src/structs/dom/observer.js":
5875/*!*************************************!*\
5876 !*** ./src/structs/dom/observer.js ***!
5877 \*************************************/
5878/*! exports provided: default */
5879/***/ (function(module, __webpack_exports__, __webpack_require__) {
5880
5881"use strict";
5882__webpack_require__.r(__webpack_exports__);
5883/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
5884/**
5885 * BetterDiscord Client DOM Module
5886 * Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
5887 * All rights reserved.
5888 * https://betterdiscord.net
5889 *
5890 * This source code is licensed under the MIT license found in the
5891 * LICENSE file in the root directory of this source tree.
5892*/
5893
5894
5895
5896/**
5897 * Representation of a MutationObserver but with helpful utilities.
5898 * @memberof module:DOMTools
5899 **/
5900class DOMObserver {
5901 constructor(root, options) {
5902 this.observe = this.observe.bind(this);
5903 this.subscribe = this.subscribe.bind(this);
5904 this.observerCallback = this.observerCallback.bind(this);
5905
5906 this.active = false;
5907 this.root = root || document.getElementById("app-mount");
5908 this.options = options || {attributes: true, childList: true, subtree: true};
5909
5910 this.observer = new MutationObserver(this.observerCallback);
5911 this.observe();
5912 }
5913
5914 observerCallback(mutations) {
5915 for (const sub of Array.from(this.subscriptions)) {
5916 try {
5917 const filteredMutations = sub.filter ? mutations.filter(sub.filter) : mutations;
5918
5919 if (sub.group) {
5920 if (!filteredMutations.length) continue;
5921 sub.callback.call(sub.bind || sub, filteredMutations);
5922 }
5923 else {
5924 for (const mutation of filteredMutations) sub.callback.call(sub.bind || sub, mutation);
5925 }
5926 }
5927 catch (err) {
5928 modules__WEBPACK_IMPORTED_MODULE_0__["Logger"].stacktrace("DOMObserver", "Error in observer callback", err);
5929 }
5930 }
5931 }
5932
5933 /**
5934 * Starts observing the element. This will be called when attaching a callback.
5935 * You don't need to call this manually.
5936 */
5937 observe() {
5938 if (this.active) return;
5939 this.observer.observe(this.root, this.options);
5940 this.active = true;
5941 }
5942
5943 /**
5944 * Disconnects this observer. This stops callbacks being called, but does not unbind them.
5945 * You probably want to use observer.unsubscribeAll instead.
5946 */
5947 disconnect() {
5948 if (!this.active) return;
5949 this.observer.disconnect();
5950 this.active = false;
5951 }
5952
5953 reconnect() {
5954 if (this.active) {
5955 this.disconnect();
5956 this.observe();
5957 }
5958 }
5959
5960 get root() { return this._root; }
5961 set root(root) { this._root = root; this.reconnect(); }
5962
5963 get options() { return this._options; }
5964 set options(options) { this._options = options; this.reconnect(); }
5965
5966 get subscriptions() {
5967 return this._subscriptions || (this._subscriptions = []);
5968 }
5969
5970 /**
5971 * Subscribes to mutations.
5972 * @param {Function} callback A function to call when on a mutation
5973 * @param {Function} filter A function to call to filter mutations
5974 * @param {Any} bind Something to bind the callback to
5975 * @param {Boolean} group Whether to call the callback with an array of mutations instead of a single mutation
5976 * @return {Object}
5977 */
5978 subscribe(callback, filter, bind, group) {
5979 const subscription = {callback, filter, bind, group};
5980 this.subscriptions.push(subscription);
5981 this.observe();
5982 return subscription;
5983 }
5984
5985 /**
5986 * Removes a subscription and disconnect if there are none left.
5987 * @param {Object} subscription A subscription object returned by observer.subscribe
5988 */
5989 unsubscribe(subscription) {
5990 if (!this.subscriptions.includes(subscription)) subscription = this.subscriptions.find(s => s.callback === subscription);
5991 modules__WEBPACK_IMPORTED_MODULE_0__["Utilities"].removeFromArray(this.subscriptions, subscription);
5992 if (!this.subscriptions.length) this.disconnect();
5993 }
5994
5995 unsubscribeAll() {
5996 this.subscriptions.splice(0, this.subscriptions.length);
5997 this.disconnect();
5998 }
5999
6000 /**
6001 * Subscribes to mutations that affect an element matching a selector.
6002 * @param {Function} callback A function to call when on a mutation
6003 * @param {Function} filter A function to call to filter mutations
6004 * @param {Any} bind Something to bind the callback to
6005 * @param {Boolean} group Whether to call the callback with an array of mutations instead of a single mutation
6006 * @return {Object}
6007 */
6008 subscribeToQuerySelector(callback, selector, bind, group) {
6009 return this.subscribe(callback, mutation => {
6010 return mutation.target.matches(selector) // If the target matches the selector
6011 || Array.from(mutation.addedNodes).concat(Array.from(mutation.removedNodes)) // Or if either an added or removed node
6012 .find(n => n instanceof Element && (n.matches(selector) || n.querySelector(selector))); // match or contain an element matching the selector
6013 }, bind, group);
6014 }
6015}
6016
6017/* harmony default export */ __webpack_exports__["default"] = (DOMObserver);
6018
6019/***/ }),
6020
6021/***/ "./src/structs/dom/selector.js":
6022/*!*************************************!*\
6023 !*** ./src/structs/dom/selector.js ***!
6024 \*************************************/
6025/*! exports provided: default */
6026/***/ (function(module, __webpack_exports__, __webpack_require__) {
6027
6028"use strict";
6029__webpack_require__.r(__webpack_exports__);
6030/**
6031 * Representation of a Selector
6032 * @memberof module:DOMTools
6033 **/
6034class Selector {
6035 /**
6036 *
6037 * @param {string} classname - class to create selector for
6038 */
6039 constructor(className) {
6040 this.value = " ." + className.split(" ").join(".");
6041 }
6042
6043 /**
6044 * Returns the raw selector, this is how native function get the value.
6045 * @returns {string} raw selector.
6046 */
6047 toString() {
6048 return this.value;
6049 }
6050
6051 /**
6052 * Returns the raw selector, this is how native function get the value.
6053 * @returns {string} raw selector.
6054 */
6055 valueOf() {
6056 return this.value;
6057 }
6058
6059 selector(symbol, other) {
6060 this.value = `${this.toString()} ${symbol} ${other.toString()}`;
6061 return this;
6062 }
6063
6064 /**
6065 * Adds another selector as a direct child `>` to this one.
6066 * @param {string|DOMTools.Selector} other - Selector to add as child
6067 * @returns {DOMTools.Selector} returns self to allow chaining
6068 */
6069 child(other) {
6070 return this.selector(">", other);
6071 }
6072
6073 /**
6074 * Adds another selector as a adjacent sibling `+` to this one.
6075 * @param {string|DOMTools.Selector} other - Selector to add as adjacent sibling
6076 * @returns {DOMTools.Selector} returns self to allow chaining
6077 */
6078 adjacent(other) {
6079 return this.selector("+", other);
6080 }
6081
6082 /**
6083 * Adds another selector as a general sibling `~` to this one.
6084 * @param {string|DOMTools.Selector} other - Selector to add as sibling
6085 * @returns {DOMTools.Selector} returns self to allow chaining
6086 */
6087 sibling(other) {
6088 return this.selector("~", other);
6089 }
6090
6091 /**
6092 * Adds another selector as a descendent `(space)` to this one.
6093 * @param {string|DOMTools.Selector} other - Selector to add as descendent
6094 * @returns {DOMTools.Selector} returns self to allow chaining
6095 */
6096 descend(other) {
6097 return this.selector(" ", other);
6098 }
6099
6100 /**
6101 * Adds another selector to this one via `,`.
6102 * @param {string|DOMTools.Selector} other - Selector to add
6103 * @returns {DOMTools.Selector} returns self to allow chaining
6104 */
6105 and(other) {
6106 return this.selector(",", other);
6107 }
6108}
6109
6110/* harmony default export */ __webpack_exports__["default"] = (Selector);
6111
6112/***/ }),
6113
6114/***/ "./src/structs/errors/permissionserror.js":
6115/*!************************************************!*\
6116 !*** ./src/structs/errors/permissionserror.js ***!
6117 \************************************************/
6118/*! exports provided: default, InsufficientPermissions */
6119/***/ (function(module, __webpack_exports__, __webpack_require__) {
6120
6121"use strict";
6122__webpack_require__.r(__webpack_exports__);
6123/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InsufficientPermissions", function() { return InsufficientPermissions; });
6124class PermissionsError extends Error {
6125 constructor(message) {
6126 super(message);
6127 this.name = "PermissionsError";
6128 }
6129}
6130
6131/**
6132 * @memberof module:DiscordAPI
6133 */
6134class InsufficientPermissions extends PermissionsError {
6135 constructor(message) {
6136 super(`Missing Permission — ${message}`);
6137 this.name = "InsufficientPermissions";
6138 }
6139}
6140
6141/* harmony default export */ __webpack_exports__["default"] = (PermissionsError);
6142
6143
6144/***/ }),
6145
6146/***/ "./src/structs/list.js":
6147/*!*****************************!*\
6148 !*** ./src/structs/list.js ***!
6149 \*****************************/
6150/*! exports provided: default */
6151/***/ (function(module, __webpack_exports__, __webpack_require__) {
6152
6153"use strict";
6154__webpack_require__.r(__webpack_exports__);
6155/**
6156 * @memberof module:DiscordAPI
6157 */
6158
6159/**
6160 * Extension of Array that adds simple utilities.
6161 */
6162class List extends Array {
6163
6164 constructor() {
6165 super(...arguments);
6166 }
6167
6168 /**
6169 * Allows multiple filters at once
6170 * @param {...callable} filters - set a filters to filter the list by
6171 */
6172 get(...filters) {
6173 return this.find(item => {
6174 for (const filter of filters) {
6175 for (const key in filter) {
6176 if (filter.hasOwnProperty(key)) {
6177 if (item[key] !== filter[key]) return false;
6178 }
6179 }
6180 }
6181 return true;
6182 });
6183 }
6184}
6185
6186/* harmony default export */ __webpack_exports__["default"] = (List);
6187
6188/***/ }),
6189
6190/***/ "./src/structs/listenable.js":
6191/*!***********************************!*\
6192 !*** ./src/structs/listenable.js ***!
6193 \***********************************/
6194/*! exports provided: default */
6195/***/ (function(module, __webpack_exports__, __webpack_require__) {
6196
6197"use strict";
6198__webpack_require__.r(__webpack_exports__);
6199/**
6200 * Acts as an interface for anything that should be listenable.
6201 */
6202class Listenable {
6203
6204 constructor() {
6205 this.listeners = [];
6206 }
6207
6208 /**
6209 * Adds a listener to the current object.
6210 * @param {callable} callback - callback for when the event occurs
6211 * @returns {callable} - a way to cancel the listener without needing to call `removeListener`
6212 */
6213 addListener(callback) {
6214 if (typeof(callback) !== "function") return;
6215 this.listeners.push(callback);
6216 return () => {
6217 this.listeners.splice(this.listeners.indexOf(callback), 1);
6218 };
6219 }
6220
6221 /**
6222 * Removes a listener from the current object.
6223 * @param {callable} callback - callback that was originally registered
6224 */
6225 removeListener(callback) {
6226 if (typeof(callback) !== "function") return;
6227 this.listeners.splice(this.listeners.indexOf(callback), 1);
6228 }
6229
6230 /**
6231 * Alerts the listeners that an event occurred. Data passed is optional
6232 * @param {*} [...data] - Any data desired to be passed to listeners
6233 */
6234 alertListeners(...data) {
6235 for (let l = 0; l < this.listeners.length; l++) this.listeners[l](...data);
6236 }
6237}
6238
6239/* harmony default export */ __webpack_exports__["default"] = (Listenable);
6240
6241/***/ }),
6242
6243/***/ "./src/structs/plugin.js":
6244/*!*******************************!*\
6245 !*** ./src/structs/plugin.js ***!
6246 \*******************************/
6247/*! exports provided: default */
6248/***/ (function(module, __webpack_exports__, __webpack_require__) {
6249
6250"use strict";
6251__webpack_require__.r(__webpack_exports__);
6252/* harmony import */ var _modules_pluginupdater__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/pluginupdater */ "./src/modules/pluginupdater.js");
6253/* harmony import */ var _modules_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/logger */ "./src/modules/logger.js");
6254/* harmony import */ var _modules_reacttools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/reacttools */ "./src/modules/reacttools.js");
6255/* harmony import */ var _ui_modals__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../ui/modals */ "./src/ui/modals.js");
6256/* harmony import */ var _modules_pluginutilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../modules/pluginutilities */ "./src/modules/pluginutilities.js");
6257/* harmony import */ var _modules_utilities__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../modules/utilities */ "./src/modules/utilities.js");
6258/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../modules/discordmodules */ "./src/modules/discordmodules.js");
6259/* harmony import */ var _ui_settings__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../ui/settings */ "./src/ui/settings/index.js");
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269/* harmony default export */ __webpack_exports__["default"] = (function(config) {
6270 return class Plugin {
6271 constructor() {
6272 this._config = config;
6273 this._enabled = false;
6274 if (typeof(config.defaultConfig) != "undefined") {
6275 this.defaultSettings = {};
6276 for (let s = 0; s < config.defaultConfig.length; s++) {
6277 const current = config.defaultConfig[s];
6278 if (current.type != "category") {this.defaultSettings[current.id] = current.value;}
6279 else {
6280 this.defaultSettings[current.id] = {};
6281 for (let s = 0; s < current.settings.length; s++) {
6282 const subCurrent = current.settings[s];
6283 this.defaultSettings[current.id][subCurrent.id] = subCurrent.value;
6284 }
6285 }
6286 }
6287 this._hasConfig = true;
6288 this.settings = _modules_utilities__WEBPACK_IMPORTED_MODULE_5__["default"].deepclone(this.defaultSettings);
6289 }
6290 }
6291 getName() { return this._config.info.name.replace(" ", ""); }
6292 getDescription() { return this._config.info.description; }
6293 getVersion() { return this._config.info.version; }
6294 getAuthor() { return this._config.info.authors.map(a => a.name).join(", "); }
6295 load() {
6296 const currentVersionInfo = _modules_pluginutilities__WEBPACK_IMPORTED_MODULE_4__["default"].loadData(this.getName(), "currentVersionInfo", {version: this.getVersion(), hasShownChangelog: false});
6297 if (currentVersionInfo.version != this.getVersion() || !currentVersionInfo.hasShownChangelog) {
6298 this.showChangelog();
6299 _modules_pluginutilities__WEBPACK_IMPORTED_MODULE_4__["default"].saveData(this.getName(), "currentVersionInfo", {version: this.getVersion(), hasShownChangelog: true});
6300 }
6301 _modules_pluginupdater__WEBPACK_IMPORTED_MODULE_0__["default"].checkForUpdate(this.getName(), this.getVersion(), this._config.info.github_raw);
6302 }
6303 async start() {
6304 _modules_logger__WEBPACK_IMPORTED_MODULE_1__["default"].info(this.getName(), `version ${this.getVersion()} has started.`);
6305 if (this.defaultSettings) this.settings = this.loadSettings();
6306 this._enabled = true;
6307 if (typeof(this.onStart) == "function") this.onStart();
6308 }
6309 stop() {
6310 _modules_logger__WEBPACK_IMPORTED_MODULE_1__["default"].info(this.getName(), `version ${this.getVersion()} has stopped.`);
6311 this._enabled = false;
6312 if (typeof(this.onStop) == "function") this.onStop();
6313 }
6314
6315 get isEnabled() {return this._enabled;}
6316 get strings() {
6317 if (!this._config.strings) return {};
6318 const locale = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_6__["default"].UserSettingsStore.locale.split("-")[0];
6319 if (this._config.strings.hasOwnProperty(locale)) return this._config.strings[locale];
6320 if (this._config.strings.hasOwnProperty("en")) return this._config.strings.en;
6321 return this._config.strings;
6322 }
6323
6324 set strings(strings) {
6325 this._config.strings = strings;
6326 }
6327
6328 showSettingsModal() {
6329 if (typeof(this.getSettingsPanel) != "function") return;
6330 _ui_modals__WEBPACK_IMPORTED_MODULE_3__["default"].showModal(this.getName() + " Settings", _modules_reacttools__WEBPACK_IMPORTED_MODULE_2__["default"].createWrappedElement(this.getSettingsPanel()), {
6331 cancelText: "",
6332 confirmText: "Done",
6333 size: _ui_modals__WEBPACK_IMPORTED_MODULE_3__["default"].ModalSizes.MEDIUM
6334 });
6335 }
6336
6337 showChangelog(footer) {
6338 if (typeof(this._config.changelog) == "undefined") return;
6339 _ui_modals__WEBPACK_IMPORTED_MODULE_3__["default"].showChangelogModal(this.getName() + " Changelog", this.getVersion(), this._config.changelog, footer);
6340 }
6341
6342 saveSettings(settings) {
6343 _modules_pluginutilities__WEBPACK_IMPORTED_MODULE_4__["default"].saveSettings(this.getName(), this.settings ? this.settings : settings);
6344 }
6345
6346 loadSettings(defaultSettings) {
6347 return _modules_pluginutilities__WEBPACK_IMPORTED_MODULE_4__["default"].loadSettings(this.getName(), this.defaultSettings ? this.defaultSettings : defaultSettings);
6348 }
6349
6350 buildSetting(data) {
6351 const {name, note, type, value, onChange, id} = data;
6352 let setting = null;
6353 if (type == "color") {
6354 setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_7__["ColorPicker"](name, note, value, onChange, {disabled: data.disabled, presetColors: data.presetColors});
6355 }
6356 else if (type == "dropdown") {
6357 setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_7__["Dropdown"](name, note, value, data.options, onChange);
6358 }
6359 else if (type == "file") {
6360 setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_7__["FilePicker"](name, note, onChange);
6361 }
6362 else if (type == "keybind") {
6363 setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_7__["Keybind"](name, note, value, onChange);
6364 }
6365 else if (type == "radio") {
6366 setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_7__["RadioGroup"](name, note, value, data.options, onChange, {disabled: data.disabled});
6367 }
6368 else if (type == "slider") {
6369 const options = {};
6370 if (typeof(data.markers) != "undefined") options.markers = data.markers;
6371 if (typeof(data.stickToMarkers) != "undefined") options.stickToMarkers = data.stickToMarkers;
6372 setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_7__["Slider"](name, note, data.min, data.max, value, onChange, options);
6373 }
6374 else if (type == "switch") {
6375 setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_7__["Switch"](name, note, value, onChange, {disabled: data.disabled});
6376 }
6377 else if (type == "textbox") {
6378 setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_7__["Textbox"](name, note, value, onChange, {placeholder: data.placeholder || ""});
6379 }
6380 if (id) setting.id = id;
6381 return setting;
6382 }
6383
6384 buildSettingsPanel() {
6385 const config = this._config.defaultConfig;
6386 const buildGroup = (group) => {
6387 const {name, id, collapsible, shown, settings} = group;
6388 // this.settings[id] = {};
6389
6390 const list = [];
6391 for (let s = 0; s < settings.length; s++) {
6392 const current = Object.assign({}, settings[s]);
6393 current.value = this.settings[id][current.id];
6394 current.onChange = (value) => {
6395 this.settings[id][current.id] = value;
6396 };
6397 if (Object.keys(this.strings).length && this.strings.settings && this.strings.settings[id] && this.strings.settings[id][current.id]) {
6398 const {name, note} = this.strings.settings[id][current.id];
6399 current.name = name;
6400 current.note = note;
6401 }
6402 list.push(this.buildSetting(current));
6403 }
6404
6405 const settingGroup = new _ui_settings__WEBPACK_IMPORTED_MODULE_7__["SettingGroup"](name, {shown, collapsible}).append(...list);
6406 settingGroup.id = id;
6407 return settingGroup;
6408 };
6409 const list = [];
6410 for (let s = 0; s < config.length; s++) {
6411 const current = Object.assign({}, config[s]);
6412 if (current.type != "category") {
6413 current.value = this.settings[current.id];
6414 current.onChange = (value) => {
6415 this.settings[current.id] = value;
6416 };
6417 if (Object.keys(this.strings).length && this.strings.settings && this.strings.settings[current.id]) {
6418 const {name, note} = this.strings.settings[current.id];
6419 current.name = name;
6420 current.note = note;
6421 }
6422 list.push(this.buildSetting(current));
6423 }
6424 else {
6425 list.push(buildGroup(current));
6426 }
6427 }
6428
6429 return new _ui_settings__WEBPACK_IMPORTED_MODULE_7__["SettingPanel"](this.saveSettings.bind(this), ...list);
6430 }
6431 };
6432});
6433
6434/***/ }),
6435
6436/***/ "./src/structs/screen.js":
6437/*!*******************************!*\
6438 !*** ./src/structs/screen.js ***!
6439 \*******************************/
6440/*! exports provided: default */
6441/***/ (function(module, __webpack_exports__, __webpack_require__) {
6442
6443"use strict";
6444__webpack_require__.r(__webpack_exports__);
6445/**
6446 * Representation of the screen such as width and height.
6447 */
6448class Screen {
6449 /** Document/window width */
6450 static get width() { return Math.max(document.documentElement.clientWidth, window.innerWidth || 0); }
6451 /** Document/window height */
6452 static get height() { return Math.max(document.documentElement.clientHeight, window.innerHeight || 0); }
6453}
6454
6455/* harmony default export */ __webpack_exports__["default"] = (Screen);
6456
6457/***/ }),
6458
6459/***/ "./src/structs/structs.js":
6460/*!********************************!*\
6461 !*** ./src/structs/structs.js ***!
6462 \********************************/
6463/*! exports provided: List, Screen, Selector, ClassName, DOMObserver, InsufficientPermissions, Plugin, Listenable, User, GuildMember, Role, Emoji, Guild, Channel, PermissionOverwrite, RolePermissionOverwrite, MemberPermissionOverwrite, GuildChannel, GuildTextChannel, GuildVoiceChannel, ChannelCategory, PrivateChannel, DirectMessageChannel, GroupChannel, Reaction, Embed, Message, DefaultMessage, RecipientAddMessage, RecipientRemoveMessage, CallMessage, GroupChannelNameChangeMessage, GroupChannelIconChangeMessage, MessagePinnedMessage, GuildMemberJoinMessage, UserSettings */
6464/***/ (function(module, __webpack_exports__, __webpack_require__) {
6465
6466"use strict";
6467__webpack_require__.r(__webpack_exports__);
6468/* harmony import */ var _list__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./list */ "./src/structs/list.js");
6469/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "List", function() { return _list__WEBPACK_IMPORTED_MODULE_0__["default"]; });
6470
6471/* harmony import */ var _screen__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./screen */ "./src/structs/screen.js");
6472/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Screen", function() { return _screen__WEBPACK_IMPORTED_MODULE_1__["default"]; });
6473
6474/* harmony import */ var _dom_selector__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./dom/selector */ "./src/structs/dom/selector.js");
6475/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Selector", function() { return _dom_selector__WEBPACK_IMPORTED_MODULE_2__["default"]; });
6476
6477/* harmony import */ var _dom_classname__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./dom/classname */ "./src/structs/dom/classname.js");
6478/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ClassName", function() { return _dom_classname__WEBPACK_IMPORTED_MODULE_3__["default"]; });
6479
6480/* harmony import */ var _dom_observer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./dom/observer */ "./src/structs/dom/observer.js");
6481/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DOMObserver", function() { return _dom_observer__WEBPACK_IMPORTED_MODULE_4__["default"]; });
6482
6483/* harmony import */ var _errors_permissionserror__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./errors/permissionserror */ "./src/structs/errors/permissionserror.js");
6484/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "InsufficientPermissions", function() { return _errors_permissionserror__WEBPACK_IMPORTED_MODULE_5__["InsufficientPermissions"]; });
6485
6486/* harmony import */ var _discord_user__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./discord/user */ "./src/structs/discord/user.js");
6487/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "User", function() { return _discord_user__WEBPACK_IMPORTED_MODULE_6__["User"]; });
6488
6489/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "GuildMember", function() { return _discord_user__WEBPACK_IMPORTED_MODULE_6__["GuildMember"]; });
6490
6491/* harmony import */ var _discord_guild__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./discord/guild */ "./src/structs/discord/guild.js");
6492/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Role", function() { return _discord_guild__WEBPACK_IMPORTED_MODULE_7__["Role"]; });
6493
6494/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Emoji", function() { return _discord_guild__WEBPACK_IMPORTED_MODULE_7__["Emoji"]; });
6495
6496/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Guild", function() { return _discord_guild__WEBPACK_IMPORTED_MODULE_7__["Guild"]; });
6497
6498/* harmony import */ var _discord_channel__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./discord/channel */ "./src/structs/discord/channel.js");
6499/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Channel", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["Channel"]; });
6500
6501/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "PermissionOverwrite", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["PermissionOverwrite"]; });
6502
6503/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "RolePermissionOverwrite", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["RolePermissionOverwrite"]; });
6504
6505/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MemberPermissionOverwrite", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["MemberPermissionOverwrite"]; });
6506
6507/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "GuildChannel", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["GuildChannel"]; });
6508
6509/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "GuildTextChannel", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["GuildTextChannel"]; });
6510
6511/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "GuildVoiceChannel", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["GuildVoiceChannel"]; });
6512
6513/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ChannelCategory", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["ChannelCategory"]; });
6514
6515/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "PrivateChannel", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["PrivateChannel"]; });
6516
6517/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DirectMessageChannel", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["DirectMessageChannel"]; });
6518
6519/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "GroupChannel", function() { return _discord_channel__WEBPACK_IMPORTED_MODULE_8__["GroupChannel"]; });
6520
6521/* harmony import */ var _discord_message__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./discord/message */ "./src/structs/discord/message.js");
6522/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Reaction", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["Reaction"]; });
6523
6524/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Embed", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["Embed"]; });
6525
6526/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Message", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["Message"]; });
6527
6528/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DefaultMessage", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["DefaultMessage"]; });
6529
6530/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "RecipientAddMessage", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["RecipientAddMessage"]; });
6531
6532/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "RecipientRemoveMessage", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["RecipientRemoveMessage"]; });
6533
6534/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "CallMessage", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["CallMessage"]; });
6535
6536/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "GroupChannelNameChangeMessage", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["GroupChannelNameChangeMessage"]; });
6537
6538/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "GroupChannelIconChangeMessage", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["GroupChannelIconChangeMessage"]; });
6539
6540/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MessagePinnedMessage", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["MessagePinnedMessage"]; });
6541
6542/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "GuildMemberJoinMessage", function() { return _discord_message__WEBPACK_IMPORTED_MODULE_9__["GuildMemberJoinMessage"]; });
6543
6544/* harmony import */ var _discord_usersettings__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./discord/usersettings */ "./src/structs/discord/usersettings.js");
6545/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "UserSettings", function() { return _discord_usersettings__WEBPACK_IMPORTED_MODULE_10__["UserSettings"]; });
6546
6547/* harmony import */ var _plugin__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./plugin */ "./src/structs/plugin.js");
6548/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Plugin", function() { return _plugin__WEBPACK_IMPORTED_MODULE_11__["default"]; });
6549
6550/* harmony import */ var _listenable__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./listenable */ "./src/structs/listenable.js");
6551/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Listenable", function() { return _listenable__WEBPACK_IMPORTED_MODULE_12__["default"]; });
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572/***/ }),
6573
6574/***/ "./src/styles/settings.css":
6575/*!*********************************!*\
6576 !*** ./src/styles/settings.css ***!
6577 \*********************************/
6578/*! no static exports found */
6579/***/ (function(module, exports) {
6580
6581module.exports = ".plugin-input-group {\r\n margin-top: 5px;\r\n}\r\n\r\n.plugin-input-group .button-collapse {\r\n background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FscXVlXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSItOTUwIDUzMiAxOCAxOCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAtOTUwIDUzMiAxOCAxODsiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCgkuc3Qwe2ZpbGw6bm9uZTt9DQoJLnN0MXtmaWxsOm5vbmU7c3Ryb2tlOiNGRkZGRkY7c3Ryb2tlLXdpZHRoOjEuNTtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTS05MzIsNTMydjE4aC0xOHYtMThILTkzMnoiLz4NCjxwb2x5bGluZSBjbGFzcz0ic3QxIiBwb2ludHM9Ii05MzYuNiw1MzguOCAtOTQxLDU0My4yIC05NDUuNCw1MzguOCAiLz4NCjwvc3ZnPg0K);\r\n height: 16px;\r\n width: 16px;\r\n display: inline-block;\r\n vertical-align: bottom;\r\n transition: transform .3s ease;\r\n transform: rotate(0);\r\n}\r\n\r\n.plugin-input-group .button-collapse.collapsed {\r\n transition: transform .3s ease;\r\n transform: rotate(-90deg);\r\n}\r\n\r\n.plugin-input-group h2 {\r\n font-size: 14px;\r\n}\r\n\r\n.plugin-input-group .plugin-input-group h2 {\r\n margin-left: 16px;\r\n}\r\n\r\n.plugin-inputs {\r\n height: auto;\r\n overflow: hidden;\r\n transition: height 300ms cubic-bezier(0.47, 0, 0.745, 0.715);\r\n}\r\n\r\n.plugin-inputs.collapsed {\r\n height: 0px;\r\n}\r\n\r\n.file-input {\r\n\r\n}\r\n\r\n.file-input::-webkit-file-upload-button {\r\n\tcolor: white;\r\n\tbackground: #7289DA;\r\n\toutline: 0;\r\n\tborder: 0;\r\n\tpadding: 10px;\r\n\tvertical-align: top;\r\n\tmargin-top: -10px;\r\n\tmargin-left: -10px;\r\n\tborder-radius: 3px 0 0 3px;\r\n\tfont-size: 14px;\r\n font-weight: 500;\r\n\tfont-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;\r\n\tcursor: pointer;\r\n}\r\n"
6582
6583/***/ }),
6584
6585/***/ "./src/styles/toasts.css":
6586/*!*******************************!*\
6587 !*** ./src/styles/toasts.css ***!
6588 \*******************************/
6589/*! no static exports found */
6590/***/ (function(module, exports) {
6591
6592module.exports = ".toasts {\r\n position: fixed;\r\n display: flex;\r\n top: 0;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: flex-end;\r\n pointer-events: none;\r\n z-index: 4000;\r\n}\r\n\r\n@keyframes toast-up {\r\n from {\r\n transform: translateY(0);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n.toast {\r\n animation: toast-up 300ms ease;\r\n transform: translateY(-10px);\r\n background: #36393F;\r\n padding: 10px;\r\n border-radius: 5px;\r\n box-shadow: 0 0 0 1px rgba(32,34,37,.6), 0 2px 10px 0 rgba(0,0,0,.2);\r\n font-weight: 500;\r\n color: #fff;\r\n user-select: text;\r\n font-size: 14px;\r\n opacity: 1;\r\n margin-top: 10px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n}\r\n\r\n@keyframes toast-down {\r\n to {\r\n transform: translateY(0px);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n.toast.closing {\r\n animation: toast-down 200ms ease;\r\n animation-fill-mode: forwards;\r\n opacity: 1;\r\n transform: translateY(-10px);\r\n}\r\n\r\n.toast.toast-info {\r\n background-color: #4a90e2;\r\n}\r\n\r\n.toast.toast-success {\r\n background-color: #43b581;\r\n}\r\n\r\n.toast.toast-danger,\r\n.toast.toast-error {\r\n background-color: #f04747;\r\n}\r\n\r\n.toast.toast-warning,\r\n.toast.toast-warn {\r\n background-color: #FFA600;\r\n}\r\n\r\n.toast-icon {\r\n margin-right: 5px;\r\n fill: white;\r\n border-radius: 50%;\r\n overflow: hidden;\r\n height: 20px;\r\n width: 20px;\r\n}\r\n\r\n.toast-text {\r\n line-height: 20px;\r\n}"
6593
6594/***/ }),
6595
6596/***/ "./src/styles/updates.css":
6597/*!********************************!*\
6598 !*** ./src/styles/updates.css ***!
6599 \********************************/
6600/*! no static exports found */
6601/***/ (function(module, exports) {
6602
6603module.exports = "#pluginNotice {\r\n -webkit-app-region: drag;\r\n border-radius: 0;\r\n overflow: hidden;\r\n height: 36px;\r\n animation: open-updates 400ms ease;\r\n}\r\n\r\n@keyframes open-updates {\r\n from { height: 0; }\r\n}\r\n\r\n#pluginNotice.closing {\r\n transition: height 400ms ease;\r\n height: 0;\r\n}\r\n\r\n#outdatedPlugins {\r\n font-weight: 700;\r\n}\r\n\r\n#outdatedPlugins>span {\r\n -webkit-app-region: no-drag;\r\n color: #fff;\r\n cursor: pointer;\r\n}\r\n\r\n#outdatedPlugins>span:hover {\r\n text-decoration: underline;\r\n}"
6604
6605/***/ }),
6606
6607/***/ "./src/ui/contextmenu.js":
6608/*!*******************************!*\
6609 !*** ./src/ui/contextmenu.js ***!
6610 \*******************************/
6611/*! exports provided: updateDiscordMenu, Menu, ItemGroup, MenuItem, TextItem, ImageItem, SubMenuItem, ToggleItem */
6612/***/ (function(module, __webpack_exports__, __webpack_require__) {
6613
6614"use strict";
6615__webpack_require__.r(__webpack_exports__);
6616/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "updateDiscordMenu", function() { return updateDiscordMenu; });
6617/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Menu", function() { return Menu; });
6618/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ItemGroup", function() { return ItemGroup; });
6619/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MenuItem", function() { return MenuItem; });
6620/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextItem", function() { return TextItem; });
6621/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ImageItem", function() { return ImageItem; });
6622/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubMenuItem", function() { return SubMenuItem; });
6623/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ToggleItem", function() { return ToggleItem; });
6624/* harmony import */ var _modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/discordclasses */ "./src/modules/discordclasses.js");
6625/* harmony import */ var _modules_discordselectors__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/discordselectors */ "./src/modules/discordselectors.js");
6626/* harmony import */ var _modules_reacttools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/reacttools */ "./src/modules/reacttools.js");
6627/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../modules/discordmodules */ "./src/modules/discordmodules.js");
6628/* harmony import */ var _modules_domtools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../modules/domtools */ "./src/modules/domtools.js");
6629/* harmony import */ var _structs_screen__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../structs/screen */ "./src/structs/screen.js");
6630/**
6631 * Self-made context menus that emulate Discord's own context menus.
6632 * @module ContextMenu
6633 * @version 0.1.0
6634 */
6635
6636
6637
6638
6639
6640
6641
6642
6643/**
6644 * Updates the location of a Discord menu, especially useful when adding items to the menu via DOM.
6645 * @param {HTMLElement|jQuery} menu - The original discord menu
6646 */
6647function updateDiscordMenu(menu) {
6648 if (!(menu instanceof window.jQuery) && !(menu instanceof Element)) return;
6649 const updateHeight = _modules_reacttools__WEBPACK_IMPORTED_MODULE_2__["default"].getReactProperty(menu, "return.return.return.stateNode.updatePosition");
6650 if (updateHeight) updateHeight();
6651}
6652
6653/** Main menu class for creating custom context menus. */
6654class Menu {
6655 /**
6656 *
6657 * @param {boolean} [scroll=false] - should this menu be a scrolling menu (usually only used for submenus)
6658 */
6659 constructor(submenu = false, scroll = false) {
6660 this.theme = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_3__["default"].UserSettingsStore.theme == "dark" ? "theme-dark" : "theme-light";
6661 this.isSubmenu = submenu;
6662 this.element = _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.contextMenu} plugin-context-menu ${this.theme}"></div>`);
6663 this.scroll = scroll;
6664 if (!scroll) return;
6665 this.scroller = _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].Scrollers.scroller} ${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.scroller}"></div>`);
6666 this.scrollerWrap = _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].Scrollers.scrollerWrap} ${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].Scrollers.scrollerThemed} ${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].Scrollers.themeGhostHairline}"></div>`);
6667 this.scrollerWrap.append(this.scroller);
6668 this.element.append(this.scrollerWrap);
6669 }
6670
6671 /**
6672 * Adds an item group to the menu. The group should already be populated.
6673 * @param {module:ContextMenu.ItemGroup} contextGroup - group to add to the menu
6674 * @returns {module:ContextMenu.Menu} returns self for chaining
6675 */
6676 addGroup(contextGroup) {
6677 if (this.scroll) this.scroller.append(contextGroup.getElement());
6678 else this.element.append(contextGroup.getElement());
6679 return this;
6680 }
6681
6682 /**
6683 * Adds items to the context menu directly. It is recommended to add to a group and use
6684 * {@link module:ContextMenu.Menu.addGroup} instead to behave as natively as possible.
6685 * @param {module:ContextMenu.MenuItem} contextItems - list of items to add to the context menu
6686 * @returns {module:ContextMenu.Menu} returns self for chaining
6687 */
6688 addItems(...contextItems) {
6689 for (let i = 0; i < contextItems.length; i++) {
6690 if (this.scroll) this.scroller.append(contextItems[i].getElement());
6691 else this.element.append(contextItems[i].getElement());
6692 }
6693 return this;
6694 }
6695
6696 /**
6697 * Shows the menu at a specific x and y position. This generally comes from the
6698 * pointer position on a right click event.
6699 * @param {number} x - x coordinate for the menu to show at
6700 * @param {number} y - y coordinate for the menu to show at
6701 */
6702 show(x, y) {
6703 const mouseX = x;
6704 const mouseY = y;
6705
6706 const parents = this.element.parents(this.parentSelector);
6707 const depth = parents.length;
6708 // if (depth == 0) {
6709 const layer = _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].TooltipLayers.layer}"></div>`);
6710 let elementToAdd = this.element;
6711 if (this.isSubmenu) {
6712 const submenu = _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.subMenuContext}"></div>`);
6713 submenu.append(this.element);
6714 elementToAdd = submenu;
6715 }
6716 layer.append(elementToAdd);
6717 layer.appendTo(_modules_discordselectors__WEBPACK_IMPORTED_MODULE_1__["default"].Popouts.popouts.sibling(_modules_discordselectors__WEBPACK_IMPORTED_MODULE_1__["default"].TooltipLayers.layerContainer).toString());
6718 // }
6719 this.element.css("top", mouseY + "px").css("left", mouseX + "px");
6720
6721 // if (depth > 0) {
6722 // const top = parents[parents.length - 1];
6723 // const closest = parents[0];
6724 // const negate = closest.hasClass(DiscordClasses.ContextMenu.invertChildX) ? -1 : 1;
6725 // const value = negate * closest.find(DiscordSelectors.ContextMenu.item).outerWidth() + closest.offset().left - top.offset().left;
6726 // this.element.css("margin-left", `${value}px`);
6727 // }
6728
6729 if (mouseY + this.element.outerHeight() >= _structs_screen__WEBPACK_IMPORTED_MODULE_5__["default"].height) {
6730 this.element.addClass("invertY").addClass(_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.invertY);
6731 this.element.css("top", `${mouseY - this.element.outerHeight()}px`);
6732 if (depth > 0) this.element.css("top", `${(mouseY + this.element.parent().outerHeight()) - this.element.outerHeight()}px`);
6733 }
6734 if (this.element.offset().left + this.element.outerWidth() >= _structs_screen__WEBPACK_IMPORTED_MODULE_5__["default"].width) {
6735 this.element.addClass("invertX");
6736 this.element.css("left", `${mouseX - this.element.outerWidth()}px`);
6737 }
6738 if (this.element.offset().left + 2 * this.element.outerWidth() >= _structs_screen__WEBPACK_IMPORTED_MODULE_5__["default"].width) {
6739 this.element.addClass(_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.invertChildX);
6740 }
6741
6742 if (depth !== 0) return;
6743 _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].on(document, "mousedown.zctx", (e) => { if (!this.element.contains(e.target) && !this.element.isSameNode(e.target)) this.removeMenu(); });
6744 _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].on(document, "click.zctx", (e) => { if (this.element.contains(e.target)) this.removeMenu(); });
6745 _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].on(document, "keyup.zctx", (e) => { if (e.keyCode === 27) this.removeMenu(); });
6746 }
6747
6748 /** Allows you to remove the menu. */
6749 removeMenu() {
6750 this.element.parents(_modules_discordselectors__WEBPACK_IMPORTED_MODULE_1__["default"].TooltipLayers.layer.toString())[0].remove();
6751 const childs = this.element.findAll(this.parentSelector);
6752 if (childs) childs.forEach(c => c.remove());
6753 _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].off(document, ".zctx");
6754 }
6755
6756 /**
6757 * Used to attach a menu to a menu item. This is how to create a submenu.
6758 * If using {@link module:ContextMenu.SubMenuItem} then you do not need
6759 * to call this function as it is done automatically. If you want to attach
6760 * a submenu to an existing Discord context menu, then you should use this
6761 * method.
6762 * @param {(HTMLElement|jQuery)} menuItem - item to attach to
6763 */
6764 attachTo(menuItem) {
6765 this.menuItem = $(menuItem);
6766 menuItem.on("mouseenter", () => {
6767 // this.element.appendTo(DiscordSelectors.Popouts.popouts.sibling(DiscordSelectors.TooltipLayers.layerContainer).toString());
6768 // const left = this.element.parents(this.parentSelector)[0].css("left");
6769 //console.log(parseInt(menuItem.offset().left), parseInt(menuItem.offset().top));
6770 this.show(parseInt(menuItem.offset().right), parseInt(menuItem.offset().top));
6771 });
6772 menuItem.on("mouseleave", () => { this.element.parents(_modules_discordselectors__WEBPACK_IMPORTED_MODULE_1__["default"].TooltipLayers.layer.toString())[0].remove(); });
6773 }
6774
6775 get parentSelector() {return this.element.parents(".plugin-context-menu").length > this.element.parents(_modules_discordselectors__WEBPACK_IMPORTED_MODULE_1__["default"].ContextMenu.contextMenu).length ? ".plugin-context-menu" : _modules_discordselectors__WEBPACK_IMPORTED_MODULE_1__["default"].ContextMenu.contextMenu;}
6776}
6777
6778/** Class that represents a group of menu items. */
6779class ItemGroup {
6780 /** Creates an item group. */
6781 constructor() {
6782 this.element = _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.itemGroup}"></div>`);
6783 }
6784
6785 /**
6786 * This is the method of adding menu items to a menu group.
6787 * @param {module:ContextMenu.MenuItem} contextItems - list of context menu items to add to this group
6788 * @returns {module:ContextMenu.ItemGroup} returns self for chaining
6789 */
6790 addItems(...contextItems) {
6791 for (let i = 0; i < contextItems.length; i++) {
6792 this.element.append(contextItems[i].getElement());
6793 }
6794 return this;
6795 }
6796
6797 /** @returns {HTMLElement} returns the DOM node for the group */
6798 getElement() { return this.element; }
6799}
6800
6801/**
6802 * Fires when the attached menu item it clicked.
6803 * @param {MouseEvent} event - the mouse event from clicking the item
6804 * @callback module:ContextMenu~clickEvent
6805 */
6806
6807 /**
6808 * Fires when the checkbox item changes state.
6809 * @param {boolean} isChecked - if the checkbox is now checked
6810 * @callback module:ContextMenu~onChange
6811 */
6812
6813/** Base class for all other menu items. */
6814class MenuItem {
6815 /**
6816 * @param {string} label - label to show on the menu item
6817 * @param {object} options - additional options for the item
6818 * @param {boolean} [options.danger=false] - should the item show as danger
6819 * @param {module:ContextMenu~clickEvent} [options.callback] - callback for when it is clicked
6820 */
6821 constructor(label, options = {}) {
6822 const {danger = false, callback} = options;
6823 this.element = _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.item}"></div>`);
6824 this.label = label;
6825 if (danger) this.element.addClass(_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.danger);
6826 this.element.on("click", (event) => {
6827 if (!Array.from(this.element.children).some(c => c.isSameNode(event.target)) && !this.element.isSameNode(event.target)) return;
6828 if (typeof(callback) == "function") callback(event);
6829 else event.stopPropagation();
6830 });
6831 }
6832 getElement() { return this.element;}
6833}
6834
6835/**
6836 * Creates a text menu item that can have a hint.
6837 * @extends module:ContextMenu.MenuItem
6838 */
6839class TextItem extends MenuItem {
6840 /**
6841 * @param {string} label - label to show on the menu item
6842 * @param {object} options - additional options for the item
6843 * @param {string} [options.hint=""] - hint to show on the item (usually used for key combos)
6844 * @param {boolean} [options.danger=false] - should the item show as danger
6845 * @param {module:ContextMenu~clickEvent} [options.callback] - callback for when it is clicked
6846 */
6847 constructor(label, options = {}) {
6848 super(label, options);
6849 const {hint = ""} = options;
6850 this.element.append(_modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<span>${label}</span>`));
6851 this.element.append(_modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.hint}">${hint}</div>`));
6852 }
6853}
6854
6855/**
6856 * Creates an image menu item that can have an image.
6857 * @extends module:ContextMenu.MenuItem
6858 */
6859class ImageItem extends MenuItem {
6860 /**
6861 * @param {string} label - label to show on the menu item
6862 * @param {string} imageSrc - link to the image to embed
6863 * @param {object} options - additional options for the item
6864 * @param {string} [options.hint=""] - hint to show on the item (usually used for key combos)
6865 * @param {boolean} [options.danger=false] - should the item show as danger
6866 * @param {module:ContextMenu~clickEvent} [options.callback] - callback for when it is clicked
6867 */
6868 constructor(label, imageSrc, options = {}) {
6869 super(label, options);
6870 this.element.addClass(_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.itemImage);
6871 this.element.append(_modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.label}">${label}</div>`));
6872 this.element.append(_modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<img src="${imageSrc}">`));
6873 }
6874}
6875
6876/**
6877 * Creates a menu item with an attached submenu.
6878 * @extends module:ContextMenu.MenuItem
6879 */
6880class SubMenuItem extends MenuItem {
6881 /**
6882 * @param {string} label - label to show on the menu item
6883 * @param {module:ContextMenu.Menu} subMenu - context menu that should be attached to this item
6884 * @param {object} options - additional options for the item
6885 * @param {string} [options.hint=""] - hint to show on the item (usually used for key combos)
6886 * @param {boolean} [options.danger=false] - should the item show as danger
6887 * @param {module:ContextMenu~clickEvent} [options.callback] - callback for when it is clicked
6888 */
6889 constructor(label, subMenu, options = {}) {
6890 // if (!(subMenu instanceof ContextSubMenu)) throw "subMenu must be of ContextSubMenu type.";
6891 super(label, options);
6892 this.element.addClass(_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.itemSubMenu);
6893 this.element.append(_modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.label}">${label}</div>`));
6894 this.element.append(_modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<svg class="caret-UIZBlm da-caret" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M16.59 8.59004L12 13.17L7.41 8.59004L6 10L12 16L18 10L16.59 8.59004Z"></path></svg>`));
6895 this.subMenu = subMenu;
6896 this.subMenu.attachTo(this.getElement());
6897 }
6898}
6899
6900/**
6901 * Creates a menu item with a checkbox.
6902 * @extends module:ContextMenu.MenuItem
6903 */
6904class ToggleItem extends MenuItem {
6905 /**
6906 * @param {string} label - label to show on the menu item
6907 * @param {boolean} checked - should the item start out checked
6908 * @param {object} options - additional options for the item
6909 * @param {string} [options.hint=""] - hint to show on the item (usually used for key combos)
6910 * @param {boolean} [options.danger=false] - should the item show as danger
6911 * @param {module:ContextMenu~onChange} [options.callback] - callback for when the checkbox changes
6912 */
6913 constructor(label, checked, options = {}) {
6914 const {callback: onChange} = options;
6915 if (options.callback) delete options.callback;
6916 super(label, options);
6917 this.element.addClass(_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.itemToggle);
6918 this.element.append(_modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.label}">${label}</div>`));
6919 this.checkbox = _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="checkbox ${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].Checkbox.checkbox} ${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenu.checkbox}" role="button"></div>`);
6920 this.checkbox.append(_modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<div class="checkbox-inner ${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].Checkbox.checkboxInner}"></div>`));
6921 this.checkbox.append(_modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement("<span>"));
6922 this.input = _modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement(`<input type="checkbox" class="${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_0__["default"].Checkbox.checkboxElement}">`);
6923 this.input.checked = checked;
6924 this.checkbox.find(".checkbox-inner").append(this.input);
6925 this.checkbox.find(".checkbox-inner").append(_modules_domtools__WEBPACK_IMPORTED_MODULE_4__["default"].createElement("<span>"));
6926 this.element.append(this.checkbox);
6927 this.element.on("click", (e) => {
6928 if (!Array.from(this.element.children).some(c => c.isSameNode(e.target)) && !this.element.isSameNode(e.target)) return;
6929 e.stopPropagation();
6930 this.input.checked = !this.input.checked;
6931 if (typeof(onChange) == "function") onChange(this.input.checked);
6932 });
6933 }
6934}
6935
6936/***/ }),
6937
6938/***/ "./src/ui/contextmenu/contextmenu.js":
6939/*!*******************************************!*\
6940 !*** ./src/ui/contextmenu/contextmenu.js ***!
6941 \*******************************************/
6942/*! exports provided: default */
6943/***/ (function(module, __webpack_exports__, __webpack_require__) {
6944
6945"use strict";
6946__webpack_require__.r(__webpack_exports__);
6947/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../modules/discordmodules */ "./src/modules/discordmodules.js");
6948/* harmony import */ var _modules_discordclasses__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../modules/discordclasses */ "./src/modules/discordclasses.js");
6949/* harmony import */ var _errorboundary__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../errorboundary */ "./src/ui/errorboundary.js");
6950
6951
6952
6953
6954
6955const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React;
6956
6957/**
6958 * This creates the main context menu
6959 *
6960 * @param {object} props - props to pass to the react renderer
6961 * @param {Array<object>} props.children - items and groups to show
6962 *
6963 * @memberof module:DiscordContextMenu
6964 */
6965class ContextMenu extends React.Component {
6966
6967 static get defaultProps() {
6968 return {
6969 className: _modules_discordclasses__WEBPACK_IMPORTED_MODULE_1__["default"].ContextMenu.contextMenu,
6970 config: {},
6971 position: "right",
6972 align: "top",
6973 theme: "dark"
6974 };
6975 }
6976
6977 render() {
6978 return React.createElement("div", Object.assign({}, ContextMenu.defaultProps, this.props));
6979 }
6980}
6981
6982/* harmony default export */ __webpack_exports__["default"] = (Object(_errorboundary__WEBPACK_IMPORTED_MODULE_2__["WrapBoundary"])(ContextMenu));
6983
6984/***/ }),
6985
6986/***/ "./src/ui/contextmenu/imageitem.js":
6987/*!*****************************************!*\
6988 !*** ./src/ui/contextmenu/imageitem.js ***!
6989 \*****************************************/
6990/*! exports provided: default */
6991/***/ (function(module, __webpack_exports__, __webpack_require__) {
6992
6993"use strict";
6994__webpack_require__.r(__webpack_exports__);
6995/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../modules/discordmodules */ "./src/modules/discordmodules.js");
6996/* harmony import */ var _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../modules/webpackmodules */ "./src/modules/webpackmodules.js");
6997/* harmony import */ var _errorboundary__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../errorboundary */ "./src/ui/errorboundary.js");
6998
6999
7000
7001
7002
7003const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React;
7004const ContextMenuActions = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenuActions;
7005const DiscordComponent = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("ImageMenuItem");
7006
7007/**
7008 * Fires when the item is clicked.
7009 * @param {boolean} value - The new value of `active`
7010 * @callback module:DiscordContextMenu~ImageMenuItemOnClick
7011 */
7012
7013/**
7014 * This creates a menu item with an image or custom icon on the side.
7015 *
7016 * @param {object} props - props to pass to the react renderer
7017 * @param {string} props.label - label to show on the menu item
7018 * @param {string} [props.hint] - hint to show on the right hand side (usually keyboard combo)
7019 * @param {string} [props.image] - link to image to show on the side
7020 * @param {function} [props.icon] - react component to render on the side
7021 * @param {module:DiscordContextMenu~ImageMenuItemOnClick} [props.action] - function to perform on click
7022 * @param {module:DiscordContextMenu~ImageMenuItemOnClick} [props.onClick] - function to perform on click (alias of `action`)
7023 * @param {boolean} [props.closeOnClick=false] - should the context menu close after clicing this item
7024 * @param {boolean} [props.danger=false] - should the item show as danger (red)
7025 * @param {boolean} [props.active=false] - if this "on" can be used to make custom toggles using icons
7026 * @param {boolean} [props.disabled=false] - should the item be disabled/unclickable
7027 *
7028 * @memberof module:DiscordContextMenu
7029 */
7030class ImageMenuItem extends React.Component {
7031 handleClick() {
7032 this.props.active = !this.props.active;
7033 if (this.props.onClick) this.props.onClick(this.props.active);
7034 if (this.props.action) this.props.action(this.props.active);
7035 if (this.props.closeOnClick) ContextMenuActions.closeContextMenu();
7036 this.forceUpdate();
7037 }
7038 render() {
7039 const Component = DiscordComponent ? DiscordComponent.default || DiscordComponent : null;
7040 return React.createElement(Component, Object.assign({}, this.props, {action: this.handleClick.bind(this)}));
7041 }
7042}
7043
7044/* harmony default export */ __webpack_exports__["default"] = (Object(_errorboundary__WEBPACK_IMPORTED_MODULE_2__["WrapBoundary"])(ImageMenuItem));
7045
7046// Discord's implementation for reference
7047// function (e, t, n) {
7048// "use strict";
7049// t.__esModule = !0, t.default = void 0;
7050// ! function (e) {
7051// if (e && e.__esModule) return e;
7052// var t = {};
7053// if (null != e)
7054// for (var n in e)
7055// if (Object.prototype.hasOwnProperty.call(e, n)) {
7056// var r = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(e, n) : {};
7057// r.get || r.set ? Object.defineProperty(t, n, r) : t[n] = e[n]
7058// } t.default = e
7059// }(n(0));
7060// var r, a = l(n(9)),
7061// o = l(n(197)),
7062// i = l(n(1024));
7063
7064// function l(e) {
7065// return e && e.__esModule ? e : {
7066// default: e
7067// }
7068// }
7069
7070// function u(e, t, n, a) {
7071// r || (r = "function" == typeof Symbol && Symbol.for && Symbol.for("react.element") || 60103);
7072// var o = e && e.defaultProps,
7073// i = arguments.length - 3;
7074// if (t || 0 === i || (t = {
7075// children: void 0
7076// }), t && o)
7077// for (var l in o) void 0 === t[l] && (t[l] = o[l]);
7078// else t || (t = o || {});
7079// if (1 === i) t.children = a;
7080// else if (i > 1) {
7081// for (var u = new Array(i), s = 0; s < i; s++) u[s] = arguments[s + 3];
7082// t.children = u
7083// }
7084// return {
7085// $$typeof: r,
7086// type: e,
7087// key: void 0 === n ? null : "" + n,
7088// ref: null,
7089// props: t,
7090// _owner: null
7091// }
7092// }
7093// var s = function (e) {
7094// var t, n, r = e.image,
7095// l = e.icon,
7096// s = e.label,
7097// d = e.action,
7098// c = e.active,
7099// f = void 0 !== c && c,
7100// p = e.disabled,
7101// v = void 0 !== p && p,
7102// h = e.danger,
7103// _ = void 0 !== h && h;
7104// return v || (n = function (e) {
7105// return d(e, s, f)
7106// }), u(o.default, {
7107// className: (0, a.default)(i.default.item, i.default.itemImage, (t = {}, t[i.default.clickable] = !v, t[i.default.disabled] = v, t[i.default.danger] = _, t)),
7108// onClick: n
7109// }, void 0, u("div", {
7110// className: i.default.label
7111// }, void 0, s), null != r ? u("img", {
7112// alt: "",
7113// src: r,
7114// className: i.default.image
7115// }) : null, null != l ? u(l, {
7116// className: i.default.image
7117// }) : null)
7118// };
7119// s.displayName = "ImageMenuItem";
7120// var d = s;
7121// t.default = d
7122
7123/***/ }),
7124
7125/***/ "./src/ui/contextmenu/itemgroup.js":
7126/*!*****************************************!*\
7127 !*** ./src/ui/contextmenu/itemgroup.js ***!
7128 \*****************************************/
7129/*! exports provided: default */
7130/***/ (function(module, __webpack_exports__, __webpack_require__) {
7131
7132"use strict";
7133__webpack_require__.r(__webpack_exports__);
7134/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../modules/discordmodules */ "./src/modules/discordmodules.js");
7135/* harmony import */ var _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../modules/webpackmodules */ "./src/modules/webpackmodules.js");
7136/* harmony import */ var _errorboundary__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../errorboundary */ "./src/ui/errorboundary.js");
7137
7138
7139
7140
7141
7142const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React;
7143const DiscordComponent = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByString("className", "itemGroup");
7144
7145/**
7146 * This holds all the items together in a group.
7147 *
7148 * @param {object} props - props to pass to the react renderer
7149 * @param {Array<object>} [props.children] - items to contain in this group
7150 * @param {Array<object>} [props.items] - alias for `children`
7151 *
7152 * @memberof module:DiscordContextMenu
7153 */
7154class ItemGroup extends React.Component {
7155 render() {
7156 const Component = DiscordComponent ? DiscordComponent.default || DiscordComponent : null;
7157 return React.createElement(Component, this.props, this.props.children || this.props.items);
7158 }
7159}
7160
7161/* harmony default export */ __webpack_exports__["default"] = (Object(_errorboundary__WEBPACK_IMPORTED_MODULE_2__["WrapBoundary"])(ItemGroup));
7162
7163/***/ }),
7164
7165/***/ "./src/ui/contextmenu/menuitem.js":
7166/*!****************************************!*\
7167 !*** ./src/ui/contextmenu/menuitem.js ***!
7168 \****************************************/
7169/*! exports provided: default */
7170/***/ (function(module, __webpack_exports__, __webpack_require__) {
7171
7172"use strict";
7173__webpack_require__.r(__webpack_exports__);
7174/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../modules/discordmodules */ "./src/modules/discordmodules.js");
7175/* harmony import */ var _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../modules/webpackmodules */ "./src/modules/webpackmodules.js");
7176/* harmony import */ var _errorboundary__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../errorboundary */ "./src/ui/errorboundary.js");
7177
7178
7179
7180
7181
7182const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React;
7183const ContextMenuActions = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenuActions;
7184const DiscordComponent = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByRegex(/\.label\b.*\.hint\b.*\.action\b/);
7185
7186/**
7187 * Fires when the item is clicked.
7188 * @param {MouseEvent} event - event object invoked on click
7189 * @callback module:DiscordContextMenu~MenuItemOnClick
7190 */
7191
7192/**
7193 * This creates a basic menu item with a lot of options.
7194 *
7195 * @param {object} props - props to pass to the react renderer
7196 * @param {string} props.label - label to show on the menu item
7197 * @param {string} [props.hint] - hint to show on the right hand side (usually keyboard combo)
7198 * @param {string} [props.className] - additional class name for this item
7199 * @param {string} [props.tooltip] - text to show on hover
7200 * @param {Array<object>} [props.children] - array of children to render underneath
7201 * @param {module:DiscordContextMenu~MenuItemOnClick} [props.action] - function to perform on click
7202 * @param {module:DiscordContextMenu~MenuItemOnClick} [props.onClick] - function to perform on click (alias of `action`)
7203 * @param {boolean} [props.closeOnClick=false] - should the context menu close after clicing this item
7204 * @param {boolean} [props.danger=false] - should the item show as danger (red)
7205 * @param {boolean} [props.brand=false] - should the item be blurple (branded)
7206 * @param {boolean} [props.disabled=false] - should the item be disabled/unclickable
7207 *
7208 * @memberof module:DiscordContextMenu
7209 */
7210class MenuItem extends React.Component {
7211 handleClick(event) {
7212 if (this.props.onClick) this.props.onClick(event);
7213 if (this.props.action) this.props.action(event);
7214 if (this.props.closeOnClick) ContextMenuActions.closeContextMenu();
7215 }
7216 render() {
7217 const Component = DiscordComponent ? DiscordComponent.default || DiscordComponent : null;
7218 return React.createElement(Component, Object.assign({}, this.props, {action: this.handleClick.bind(this)}));
7219 }
7220}
7221
7222/* harmony default export */ __webpack_exports__["default"] = (Object(_errorboundary__WEBPACK_IMPORTED_MODULE_2__["WrapBoundary"])(MenuItem));
7223
7224// Discord's implementation for reference
7225// var c = function (e) {
7226// var t, n = e.style,
7227// r = e.label,
7228// s = e.hint,
7229// c = e.action,
7230// f = e.danger,
7231// p = void 0 !== f && f,
7232// v = e.disabled,
7233// h = void 0 !== v && v,
7234// _ = e.brand,
7235// m = void 0 !== _ && _,
7236// y = e.children,
7237// g = e.className,
7238// E = e.tooltip,
7239// S = d(i.default, {
7240// className: (0, o.default)(u.default.item, (t = {}, t[u.default.clickable] = !h, t[u.default.danger] = p, t[u.default.disabled] = h, t[u.default.brand] = m, t), g),
7241// style: n,
7242// role: "menuitem",
7243// onClick: h ? void 0 : c
7244// }, void 0, d("div", {
7245// className: u.default.label
7246// }, void 0, r), d("div", {
7247// className: u.default.hint
7248// }, void 0, s), y);
7249// return null != E ? d(l.default, {
7250// text: E
7251// }, void 0, function (e) {
7252// return a.createElement("div", e, S)
7253// }) : S
7254// };
7255// t.default = c
7256
7257/***/ }),
7258
7259/***/ "./src/ui/contextmenu/slideritem.js":
7260/*!******************************************!*\
7261 !*** ./src/ui/contextmenu/slideritem.js ***!
7262 \******************************************/
7263/*! exports provided: default */
7264/***/ (function(module, __webpack_exports__, __webpack_require__) {
7265
7266"use strict";
7267__webpack_require__.r(__webpack_exports__);
7268/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../modules/discordmodules */ "./src/modules/discordmodules.js");
7269/* harmony import */ var _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../modules/webpackmodules */ "./src/modules/webpackmodules.js");
7270/* harmony import */ var _errorboundary__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../errorboundary */ "./src/ui/errorboundary.js");
7271
7272
7273
7274
7275
7276const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React;
7277const DiscordComponent = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("SliderMenuItem");
7278
7279/**
7280 * Fires when the item is clicked.
7281 * @param {Number} value - The new value selected
7282 * @callback module:DiscordContextMenu~SliderMenuItemOnChange
7283 */
7284
7285/**
7286 * Fires when the item is clicked.
7287 * @param {Number} value - The value to render
7288 * @returns {string} the text to show in the tooltip
7289 * @callback module:DiscordContextMenu~SliderMenuItemRenderValue
7290 */
7291
7292/**
7293 * This creates a setting style slider inside of a menu item.
7294 *
7295 * @param {object} props - props to pass to the react renderer
7296 * @param {string} props.label - label to show on the menu item
7297 * @param {Number} [props.defaultValue=0] - the initial value of the slider
7298 * @param {Number} [props.minValue=0] - the minimum value of the slider
7299 * @param {Number} [props.maxValue=100] - the maximum value of the slider
7300 * @param {module:DiscordContextMenu~SliderMenuItemOnChange} [props.onValueChange] - function to perform on a value change
7301 * @param {module:DiscordContextMenu~SliderMenuItemOnChange} [props.onChange] - alias of `onValueChange`
7302 * @param {module:DiscordContextMenu~SliderMenuItemRenderValue} [props.onValueRender] - function to call to render the value in the tooltip
7303 * @param {module:DiscordContextMenu~SliderMenuItemRenderValue} [props.renderValue] - alias of `onValueChange`
7304 *
7305 * @memberof module:DiscordContextMenu
7306 */
7307class SliderMenuItem extends React.Component {
7308 onChange(value) {
7309 if (this.props.onChange) this.props.onChange(value);
7310 if (this.props.onValueChange) this.props.onValueChange(value);
7311 }
7312 render() {
7313 const onValueRender = this.props.renderValue || this.props.onValueRender || undefined;
7314 const Component = DiscordComponent ? DiscordComponent.default || DiscordComponent : null;
7315 return React.createElement(Component, Object.assign({}, this.props, {onValueChange: this.onChange.bind(this), onValueRender}));
7316 }
7317}
7318
7319/* harmony default export */ __webpack_exports__["default"] = (Object(_errorboundary__WEBPACK_IMPORTED_MODULE_2__["WrapBoundary"])(SliderMenuItem));
7320
7321// Discord's implementation for reference
7322// function (e, t, n) {
7323// "use strict";
7324// t.__esModule = !0, t.default = void 0;
7325// ! function (e) {
7326// if (e && e.__esModule) return e;
7327// var t = {};
7328// if (null != e)
7329// for (var n in e)
7330// if (Object.prototype.hasOwnProperty.call(e, n)) {
7331// var r = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(e, n) : {};
7332// r.get || r.set ? Object.defineProperty(t, n, r) : t[n] = e[n]
7333// } t.default = e
7334// }(n(0));
7335// var r, a = l(n(9)),
7336// o = l(n(6325)),
7337// i = l(n(1024));
7338
7339// function l(e) {
7340// return e && e.__esModule ? e : {
7341// default: e
7342// }
7343// }
7344
7345// function u(e, t, n, a) {
7346// r || (r = "function" == typeof Symbol && Symbol.for && Symbol.for("react.element") || 60103);
7347// var o = e && e.defaultProps,
7348// i = arguments.length - 3;
7349// if (t || 0 === i || (t = {
7350// children: void 0
7351// }), t && o)
7352// for (var l in o) void 0 === t[l] && (t[l] = o[l]);
7353// else t || (t = o || {});
7354// if (1 === i) t.children = a;
7355// else if (i > 1) {
7356// for (var u = new Array(i), s = 0; s < i; s++) u[s] = arguments[s + 3];
7357// t.children = u
7358// }
7359// return {
7360// $$typeof: r,
7361// type: e,
7362// key: void 0 === n ? null : "" + n,
7363// ref: null,
7364// props: t,
7365// _owner: null
7366// }
7367// }
7368// var s = function (e) {
7369// var t = e.defaultValue,
7370// n = void 0 === t ? 0 : t,
7371// r = e.minValue,
7372// l = void 0 === r ? 0 : r,
7373// s = e.maxValue,
7374// d = void 0 === s ? 100 : s,
7375// c = e.onValueChange,
7376// f = e.onValueRender,
7377// p = e.label;
7378// return u("div", {
7379// className: (0, a.default)(i.default.itemSlider)
7380// }, void 0, u("div", {
7381// className: i.default.label
7382// }, void 0, p), u(o.default, {
7383// mini: !0,
7384// handleSize: 16,
7385// className: i.default.slider,
7386// initialValue: n,
7387// minValue: l,
7388// maxValue: d,
7389// onValueChange: c,
7390// onValueRender: f
7391// }))
7392// };
7393// s.displayName = "SliderMenuItem";
7394// var d = s;
7395// t.default = d
7396// }
7397
7398/***/ }),
7399
7400/***/ "./src/ui/contextmenu/submenuitem.js":
7401/*!*******************************************!*\
7402 !*** ./src/ui/contextmenu/submenuitem.js ***!
7403 \*******************************************/
7404/*! exports provided: default */
7405/***/ (function(module, __webpack_exports__, __webpack_require__) {
7406
7407"use strict";
7408__webpack_require__.r(__webpack_exports__);
7409/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../modules/discordmodules */ "./src/modules/discordmodules.js");
7410/* harmony import */ var _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../modules/webpackmodules */ "./src/modules/webpackmodules.js");
7411/* harmony import */ var _errorboundary__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../errorboundary */ "./src/ui/errorboundary.js");
7412
7413
7414
7415
7416
7417const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React;
7418const ContextMenuActions = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenuActions;
7419const DiscordComponent = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].find(m => m.default && m.default.displayName && m.default.displayName.includes("SubMenuItem"));
7420
7421/**
7422 * Fires when the item is clicked.
7423 * @param {MouseEvent} event - The event generated on click
7424 * @callback module:DiscordContextMenu~SubMenuItemOnClick
7425 */
7426
7427/**
7428 * This creates a menu item that shows a submenu on hover.
7429 *
7430 * @param {object} props - props to pass to the react renderer
7431 * @param {string} props.label - label to show on the menu item
7432 * @param {string} [props.theme=currentTheme] - whether to show the submenu as light or dark
7433 * @param {string} [props.align="center"] - how to align the submenu: "top", "bottom", "center"
7434 * @param {Array<object>} [props.render] - array of items to render in the submenu
7435 * @param {Array<object>} [props.items] - alias of `render`
7436 * @param {module:DiscordContextMenu~SubMenuItemOnClick} [props.action] - function to perform on click
7437 * @param {module:DiscordContextMenu~SubMenuItemOnClick} [props.onClick] - function to perform on click (alias of `action`)
7438 * @param {boolean} [props.disabled=false] - should the item be disabled/unclickable
7439 *
7440 * @memberof module:DiscordContextMenu
7441 */
7442class SubMenuItem extends React.Component {
7443 handleClick(event) {
7444 if (this.props.onClick) this.props.onClick(event);
7445 if (this.props.action) this.props.action(event);
7446 if (this.props.closeOnClick) ContextMenuActions.closeContextMenu();
7447 }
7448 render() {
7449 const Component = DiscordComponent ? DiscordComponent.default || DiscordComponent : null;
7450 return React.createElement(Component, Object.assign({}, this.props, {render: this.props.render || this.props.items, action: this.handleClick.bind(this)}));
7451 }
7452}
7453
7454/* harmony default export */ __webpack_exports__["default"] = (Object(_errorboundary__WEBPACK_IMPORTED_MODULE_2__["WrapBoundary"])(SubMenuItem));
7455
7456// Discord's implementation for reference
7457// function l() {
7458// let e, t = this.props,
7459// n = t.label,
7460// r = t.render,
7461// a = t.disabled,
7462// l = t.action,
7463// u = t.theme,
7464// _ = t.align,
7465// y = this.state.open,
7466// E = "function" == typeof r ? r() : r.filter(function (e) {
7467// return e
7468// }),
7469// S = (0, i.isFragment)(E) ? E.props.children.length : E.length;
7470// return 0 === S ? null : m(s.default, {
7471// innerRef: this.setRef,
7472// className: (0, o.default)(h.default.itemSubMenu, (e = {}, e[h.default.selected] = y, e)),
7473// onClick: a ? function () {} : l,
7474// onMouseEnter: a ? void 0 : this.handleMouseEnter,
7475// onMouseLeave: a ? void 0 : this.handleMouseLeave
7476// }, void 0, m("div", {
7477// className: h.default.label
7478// }, void 0, n), m(c.default, {
7479// className: h.default.caret
7480// }), y ? m(p.AppReferencePositionLayer, {
7481// position: f.Positions.RIGHT,
7482// align: _ || f.Align.CENTER,
7483// autoInvert: !0,
7484// nudgeAlignIntoViewport: !0,
7485// spacing: 12,
7486// reference: this.ref
7487// }, void 0, function () {
7488// return m("div", {
7489// className: h.default.subMenuContext,
7490// onClick: g
7491// }, void 0, S > 8 ? m(d.default, {
7492// className: (0, o.default)(h.default.contextMenu, h.default.scroller),
7493// theme: d.default.Themes.GHOST_HAIRLINE,
7494// backgroundColor: u === v.ThemeTypes.LIGHT ? v.Colors.WHITE : v.Colors.PRIMARY_DARK_800
7495// }, void 0, E) : m("div", {
7496// className: h.default.contextMenu
7497// }, void 0, E))
7498// }) : null)
7499// }
7500
7501/***/ }),
7502
7503/***/ "./src/ui/contextmenu/toggleitem.js":
7504/*!******************************************!*\
7505 !*** ./src/ui/contextmenu/toggleitem.js ***!
7506 \******************************************/
7507/*! exports provided: default */
7508/***/ (function(module, __webpack_exports__, __webpack_require__) {
7509
7510"use strict";
7511__webpack_require__.r(__webpack_exports__);
7512/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../modules/discordmodules */ "./src/modules/discordmodules.js");
7513/* harmony import */ var _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../modules/webpackmodules */ "./src/modules/webpackmodules.js");
7514/* harmony import */ var _errorboundary__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../errorboundary */ "./src/ui/errorboundary.js");
7515
7516
7517
7518
7519
7520const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React;
7521const DiscordComponent = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByString("itemToggle", "checkbox");
7522
7523/**
7524 * Fires when the item is clicked.
7525 * @param {boolean} value - The new value of `active`
7526 * @callback module:DiscordContextMenu~ToggleMenuItemOnClick
7527 */
7528
7529/**
7530 * This creates a menu item with a checkbox toggle.
7531 *
7532 * @param {object} props - props to pass to the react renderer
7533 * @param {string} props.label - label to show on the menu item
7534 * @param {string} [props.className] - additional class name for the label
7535 * @param {object} [props.style] - css styles for the main label
7536 * @param {object} [props.checkboxStyle] - css styles for the checkbox
7537 * @param {module:DiscordContextMenu~ToggleMenuItemOnClick} [props.action] - function to perform on click
7538 * @param {module:DiscordContextMenu~ToggleMenuItemOnClick} [props.onClick] - function to perform on click (alias of `action`)
7539 * @param {boolean} [props.loading=false] - should the text show as loading... not super useful
7540 * @param {boolean} [props.danger=false] - should the item show as danger (red)
7541 * @param {boolean} [props.active=false] - should the checkbox be checked
7542 * @param {boolean} [props.disabled=false] - should the item be disabled/unclickable
7543 *
7544 * @memberof module:DiscordContextMenu
7545 */
7546class ToggleMenuItem extends React.Component {
7547 handleToggle() {
7548 this.props.active = !this.props.active;
7549 if (this.props.action) this.props.action(this.props.active);
7550 this.forceUpdate();
7551 }
7552 render() {
7553 const Component = DiscordComponent ? DiscordComponent.default || DiscordComponent : null;
7554 return React.createElement(Component, Object.assign({}, this.props, {action: this.handleToggle.bind(this)}));
7555 }
7556}
7557
7558/* harmony default export */ __webpack_exports__["default"] = (Object(_errorboundary__WEBPACK_IMPORTED_MODULE_2__["WrapBoundary"])(ToggleMenuItem));
7559
7560// Discord's implementation for reference
7561// const f = function (e) {
7562// let t, n, r = e.label,
7563// s = e.action,
7564// f = e.active,
7565// p = void 0 !== f && f,
7566// v = e.disabled,
7567// h = void 0 !== v && v,
7568// _ = e.danger,
7569// m = void 0 !== _ && _,
7570// y = e.loading,
7571// g = void 0 !== y && y,
7572// E = e.style,
7573// S = e.checkboxStyle,
7574// O = e.className;
7575// return h || (n = function (e) {
7576// return s(e, r, p)
7577// }), d(i.default, {
7578// className: (0, a.default)(u.default.item, u.default.itemToggle, O, (t = {}, t[u.default.clickable] = !h, t[u.default.disabled] = h, t[u.default.danger] = m, t)),
7579// onClick: n
7580// }, void 0, d("div", {
7581// className: u.default.label,
7582// style: E
7583// }, void 0, g ? d(l.default, {
7584// type: l.default.Type.PULSING_ELLIPSIS
7585// }) : r), d(o.default, {
7586// checked: p,
7587// containerClassName: u.default.checkbox,
7588// onChange: c,
7589// style: S
7590// }))
7591// };
7592
7593/***/ }),
7594
7595/***/ "./src/ui/discordcontextmenu.js":
7596/*!**************************************!*\
7597 !*** ./src/ui/discordcontextmenu.js ***!
7598 \**************************************/
7599/*! exports provided: default */
7600/***/ (function(module, __webpack_exports__, __webpack_require__) {
7601
7602"use strict";
7603__webpack_require__.r(__webpack_exports__);
7604/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return DiscordContextMenu; });
7605/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/discordmodules */ "./src/modules/discordmodules.js");
7606/* harmony import */ var _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/webpackmodules */ "./src/modules/webpackmodules.js");
7607/* harmony import */ var _modules_reacttools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/reacttools */ "./src/modules/reacttools.js");
7608/* harmony import */ var _modules_patcher__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../modules/patcher */ "./src/modules/patcher.js");
7609/* harmony import */ var _modules_utilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../modules/utilities */ "./src/modules/utilities.js");
7610/* harmony import */ var _modules_discordselectors__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../modules/discordselectors */ "./src/modules/discordselectors.js");
7611/* harmony import */ var _contextmenu_contextmenu__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./contextmenu/contextmenu */ "./src/ui/contextmenu/contextmenu.js");
7612/* harmony import */ var _contextmenu_itemgroup__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./contextmenu/itemgroup */ "./src/ui/contextmenu/itemgroup.js");
7613/* harmony import */ var _contextmenu_menuitem__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./contextmenu/menuitem */ "./src/ui/contextmenu/menuitem.js");
7614/* harmony import */ var _contextmenu_imageitem__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./contextmenu/imageitem */ "./src/ui/contextmenu/imageitem.js");
7615/* harmony import */ var _contextmenu_toggleitem__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./contextmenu/toggleitem */ "./src/ui/contextmenu/toggleitem.js");
7616/* harmony import */ var _contextmenu_submenuitem__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./contextmenu/submenuitem */ "./src/ui/contextmenu/submenuitem.js");
7617/* harmony import */ var _contextmenu_slideritem__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./contextmenu/slideritem */ "./src/ui/contextmenu/slideritem.js");
7618
7619
7620
7621
7622
7623
7624
7625
7626
7627
7628
7629
7630
7631
7632
7633
7634
7635const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React;
7636const ContextMenuActions = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenuActions;
7637
7638const ce = React.createElement;
7639
7640/**
7641 * A utility for building and rendering Discord's own menus.
7642 * @module DiscordContextMenu
7643 * @version 0.0.1
7644 */
7645class DiscordContextMenu {
7646
7647 static get ContextMenu() {return _contextmenu_contextmenu__WEBPACK_IMPORTED_MODULE_6__["default"];}
7648 static get ItemGroup() {return _contextmenu_itemgroup__WEBPACK_IMPORTED_MODULE_7__["default"];}
7649 static get MenuItem() {return _contextmenu_menuitem__WEBPACK_IMPORTED_MODULE_8__["default"];}
7650 static get ToggleMenuItem() {return _contextmenu_toggleitem__WEBPACK_IMPORTED_MODULE_10__["default"];}
7651 static get SubMenuItem() {return _contextmenu_submenuitem__WEBPACK_IMPORTED_MODULE_11__["default"];}
7652 static get ImageMenuItem() {return _contextmenu_imageitem__WEBPACK_IMPORTED_MODULE_9__["default"];}
7653 static get SliderMenuItem() {return _contextmenu_slideritem__WEBPACK_IMPORTED_MODULE_12__["default"];}
7654
7655 /**
7656 * Builds a single menu item. The only prop shown here is the type, the rest should
7657 * match the actual component being built. View those to see what options exist
7658 * for each, they often have less in common than you might think. See {@link module:DiscordContextMenu.MenuItem}
7659 * for the majority of props commonly available. Check the documentation for the
7660 * rest of the components.
7661 *
7662 * @param {object} props - props used to build the item
7663 * @param {string} [props.type="text"] - type of the item, options: text, image, submenu, toggle, slider
7664 * @returns {object} the created component
7665 *
7666 * @see {@link module:DiscordContextMenu.MenuItem}
7667 * @see {@link module:DiscordContextMenu.ToggleMenuItem}
7668 * @see {@link module:DiscordContextMenu.SubMenuItem}
7669 * @see {@link module:DiscordContextMenu.ImageMenuItem}
7670 * @see {@link module:DiscordContextMenu.SliderMenuItem}
7671 *
7672 * @example
7673 * // Creates a single menu item that prints "MENU ITEM" on click
7674 * DiscordContextMenu.buildMenuItem({
7675 * label: "Menu Item",
7676 * action: () => {console.log("MENU ITEM");}
7677 * });
7678 *
7679 * @example
7680 * // Creates a single toggle item that starts unchecked
7681 * // and print the new value on every toggle
7682 * DiscordContextMenu.buildMenuItem({
7683 * type: "toggle",
7684 * label: "Item Toggle",
7685 * active: false,
7686 * action: (newValue) => {console.log(newValue);}
7687 * });
7688 */
7689 static buildMenuItem(props) {
7690 const {type} = props;
7691 let Component = _contextmenu_menuitem__WEBPACK_IMPORTED_MODULE_8__["default"];
7692 if (type === "image") {
7693 Component = _contextmenu_imageitem__WEBPACK_IMPORTED_MODULE_9__["default"];
7694 }
7695 else if (type === "submenu") {
7696 Component = _contextmenu_submenuitem__WEBPACK_IMPORTED_MODULE_11__["default"];
7697 if (!props.render) props.render = this.buildMenuChildren(props.render || props.items);
7698 }
7699 else if (type === "toggle") {
7700 Component = _contextmenu_toggleitem__WEBPACK_IMPORTED_MODULE_10__["default"];
7701 }
7702 else if (type === "slider") {
7703 Component = _contextmenu_slideritem__WEBPACK_IMPORTED_MODULE_12__["default"];
7704 }
7705 return ce(Component, props);
7706 }
7707
7708 /**
7709 * Creates the all the items **and groups** of a context menu recursively.
7710 * There is no hard limit to the number of groups within groups or number
7711 * of items in a menu.
7712 * @param {Array<object>} setup - array of item props used to build items. See {@link module:DiscordContextMenu.buildMenuItem}
7713 * @returns {Array<object>} array of the created component
7714 *
7715 * @example
7716 * // Creates a single item group item with a toggle item
7717 * DiscordContextMenu.buildMenuChildren([{
7718 * type: "group",
7719 * items: [{
7720 * type: "toggle",
7721 * label: "Item Toggle",
7722 * active: false,
7723 * action: (newValue) => {console.log(newValue);}
7724 * }]
7725 * }]);
7726 *
7727 * @example
7728 * // Creates two item groups with a single toggle item each
7729 * DiscordContextMenu.buildMenuChildren([{
7730 * type: "group",
7731 * items: [{
7732 * type: "toggle",
7733 * label: "Item Toggle",
7734 * active: false,
7735 * action: (newValue) => {
7736 * console.log(newValue);
7737 * }
7738 * }]
7739 * }, {
7740 * type: "group",
7741 * items: [{
7742 * type: "toggle",
7743 * label: "Item Toggle",
7744 * active: false,
7745 * action: (newValue) => {
7746 * console.log(newValue);
7747 * }
7748 * }]
7749 * }]);
7750 */
7751 static buildMenuChildren(setup) {
7752 const mapper = s => {
7753 if (s.type === "group") return buildGroup(s);
7754 return this.buildMenuItem(s);
7755 };
7756 const buildGroup = function(group) {
7757 const items = group.items.map(mapper).filter(i => i);
7758 return ce(_contextmenu_itemgroup__WEBPACK_IMPORTED_MODULE_7__["default"], null, items);
7759 };
7760 return setup.map(mapper).filter(i => i);
7761 }
7762
7763 /**
7764 * Creates the menu *component* including the wrapping `ContextMenu`.
7765 * Calls {@link module:DiscordContextMenu.buildMenuChildren} under the covers.
7766 * Used to call in combination with {@link module:DiscordContextMenu.openContextMenu}.
7767 * @param {Array<object>} setup - array of item props used to build items. See {@link module:DiscordContextMenu.buildMenuChildren}
7768 * @returns {function} the unique context menu component
7769 */
7770 static buildMenu(setup) {
7771 return (props) => {return ce(_contextmenu_contextmenu__WEBPACK_IMPORTED_MODULE_6__["default"], props, this.buildMenuChildren(setup));};
7772 }
7773
7774 /**
7775 *
7776 * @param {MouseEvent} event - The context menu event. This can be emulated, requires target, and all X, Y locations.
7777 * @param {function} menuComponent - Component to render. This can be any react component or output of {@link module:DiscordContextMenu.buildMenu}
7778 * @param {object} config - configuration/props for the context menu
7779 * @param {string} [config.position="right"] - default position for the menu, options: "left", "right"
7780 * @param {string} [config.align="top"] - default alignment for the menu, options: "bottom", "top"
7781 * @param {function} [config.onClose] - function to run when the menu is closed
7782 * @param {boolean} [config.noBlurEvent=false] - No clue
7783 */
7784 static openContextMenu(event, menuComponent, config) {
7785 return ContextMenuActions.openContextMenu(event, function(e) {
7786 return ce(menuComponent, e);
7787 }, config);
7788 }
7789
7790 /**
7791 * Attempts to find and return a specific context menu type's module. Useful
7792 * when patching the render of these menus.
7793 * @param {string} type - name of the context menu type
7794 * @returns {Promise<object>} the webpack module the menu was found in
7795 */
7796 static async getDiscordMenu(type) {
7797 return new Promise(resolve => {
7798 const cancel = _modules_patcher__WEBPACK_IMPORTED_MODULE_3__["default"].after("ZeresLibrary.DiscordContextMenu", ContextMenuActions, "openContextMenu", (_, [, component]) => {
7799 const rendered = component();
7800 const menuType = rendered.props && rendered.props.type || (rendered.type && rendered.type.displayName);
7801 if (!menuType || typeof(menuType) != "string" || !menuType.includes(type)) return;
7802 cancel();
7803 return resolve(_modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.default == rendered.type));
7804 });
7805 });
7806 }
7807
7808 /**
7809 * Calls `forceUpdate()` on all context menus it can find. Useful for
7810 * after patching a menu.
7811 */
7812 static forceUpdateMenus() {
7813 const menus = document.querySelectorAll(_modules_discordselectors__WEBPACK_IMPORTED_MODULE_5__["default"].ContextMenu.contextMenu);
7814 for (const menu of menus) {
7815 const stateNode = _modules_utilities__WEBPACK_IMPORTED_MODULE_4__["default"].findInTree(_modules_reacttools__WEBPACK_IMPORTED_MODULE_2__["default"].getReactInstance(menu), m=>m && m.forceUpdate && m.updatePosition, {walkable: ["return", "stateNode"]});
7816 if (!stateNode) continue;
7817 stateNode.forceUpdate();
7818 stateNode.updatePosition();
7819 }
7820 }
7821}
7822
7823/***/ }),
7824
7825/***/ "./src/ui/emulatedtooltip.js":
7826/*!***********************************!*\
7827 !*** ./src/ui/emulatedtooltip.js ***!
7828 \***********************************/
7829/*! exports provided: default */
7830/***/ (function(module, __webpack_exports__, __webpack_require__) {
7831
7832"use strict";
7833__webpack_require__.r(__webpack_exports__);
7834/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return EmulatedTooltip; });
7835/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
7836/* harmony import */ var _structs_screen__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../structs/screen */ "./src/structs/screen.js");
7837/**
7838 * Tooltip that automatically show and hide themselves on mouseenter and mouseleave events.
7839 * Will also remove themselves if the node to watch is removed from DOM through
7840 * a MutationObserver.
7841 *
7842 * Note this is not using Discord's internals but normal DOM manipulation and emulates
7843 * Discord's own tooltips as closely as possible.
7844 *
7845 * @module EmulatedTooltip
7846 * @version 0.0.1
7847 */
7848
7849
7850
7851
7852const getClass = function(sideOrColor) {
7853 const upperCase = sideOrColor[0].toUpperCase() + sideOrColor.slice(1);
7854 const tooltipClass = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].Tooltips[`tooltip${upperCase}`];
7855 if (tooltipClass) return tooltipClass;
7856 return null;
7857};
7858
7859const classExists = function(sideOrColor) {
7860 return getClass(sideOrColor) ? true : false;
7861};
7862
7863const toPx = function(value) {
7864 return `${value}px`;
7865};
7866
7867/* <div class="layer-v9HyYc da-layer" style="left: 234.5px; bottom: 51px;">
7868 <div class="tooltip-2QfLtc da-tooltip tooltipTop-XDDSxx tooltipBlack-PPG47z">
7869 <div class="tooltipPointer-3ZfirK da-tooltipPointer"></div>
7870 User Settings
7871 </div>
7872</div> */
7873
7874class EmulatedTooltip {
7875 /**
7876 *
7877 * @constructor
7878 * @param {(HTMLElement|jQuery)} node - DOM node to monitor and show the tooltip on
7879 * @param {string} tip - string to show in the tooltip
7880 * @param {object} options - additional options for the tooltip
7881 * @param {string} [options.style=black] - correlates to the discord styling/colors (black, brand, green, grey, red, yellow)
7882 * @param {string} [options.side=top] - can be any of top, right, bottom, left
7883 * @param {boolean} [options.preventFlip=false] - prevents moving the tooltip to the opposite side if it is too big or goes offscreen
7884 * @param {boolean} [options.disabled=false] - whether the tooltip should be disabled from showing on hover
7885 */
7886 constructor(node, text, options = {}) {
7887 const {style = "black", side = "top", preventFlip = false, disabled = false} = options;
7888 this.node = node instanceof jQuery ? node[0] : node;
7889 this.label = text;
7890 this.style = style.toLowerCase();
7891 this.side = side.toLowerCase();
7892 this.preventFlip = preventFlip;
7893 this.disabled = disabled;
7894
7895 if (!classExists(this.side)) return modules__WEBPACK_IMPORTED_MODULE_0__["Logger"].err("EmulatedTooltip", `Side ${this.side} does not exist.`);
7896 if (!classExists(this.style)) return modules__WEBPACK_IMPORTED_MODULE_0__["Logger"].err("EmulatedTooltip", `Style ${this.style} does not exist.`);
7897
7898 this.element = modules__WEBPACK_IMPORTED_MODULE_0__["DOMTools"].createElement(`<div class="${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].TooltipLayers.layer}">`);
7899 this.tooltipElement = modules__WEBPACK_IMPORTED_MODULE_0__["DOMTools"].createElement(`<div class="${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].Tooltips.tooltip} ${getClass(this.style)}"><div class="${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].Tooltips.tooltipPointer}"></div>${this.label}</div>`);
7900 this.labelElement = this.tooltipElement.childNodes[1];
7901 this.element.append(this.tooltipElement);
7902
7903
7904 this.node.addEventListener("mouseenter", () => {
7905 if (this.disabled) return;
7906 this.show();
7907
7908 const observer = new MutationObserver((mutations) => {
7909 mutations.forEach((mutation) => {
7910 const nodes = Array.from(mutation.removedNodes);
7911 const directMatch = nodes.indexOf(this.node) > -1;
7912 const parentMatch = nodes.some(parent => parent.contains(this.node));
7913 if (directMatch || parentMatch) {
7914 this.hide();
7915 observer.disconnect();
7916 }
7917 });
7918 });
7919
7920 observer.observe(document.body, {subtree: true, childList: true});
7921 });
7922
7923 this.node.addEventListener("mouseleave", () => {
7924 this.hide();
7925 });
7926 }
7927
7928 /** Container where the tooltip will be appended. */
7929 get container() { return document.querySelector(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordSelectors"].Popouts.popouts.sibling(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordSelectors"].TooltipLayers.layerContainer)); }
7930 /** Boolean representing if the tooltip will fit on screen above the element */
7931 get canShowAbove() { return this.node.offset().top - this.element.outerHeight() >= 0; }
7932 /** Boolean representing if the tooltip will fit on screen below the element */
7933 get canShowBelow() { return this.node.offset().top + this.node.outerHeight() + this.element.outerHeight() <= _structs_screen__WEBPACK_IMPORTED_MODULE_1__["default"].height; }
7934 /** Boolean representing if the tooltip will fit on screen to the left of the element */
7935 get canShowLeft() { return this.node.offset().left - this.element.outerWidth() >= 0; }
7936 /** Boolean representing if the tooltip will fit on screen to the right of the element */
7937 get canShowRight() { return this.node.offset().left + this.node.outerWidth() + this.element.outerWidth() <= _structs_screen__WEBPACK_IMPORTED_MODULE_1__["default"].width; }
7938
7939 /** Hides the tooltip. Automatically called on mouseleave. */
7940 hide() {
7941 this.element.remove();
7942 this.tooltipElement.className = this._className;
7943 }
7944
7945 /** Shows the tooltip. Automatically called on mouseenter. Will attempt to flip if position was wrong. */
7946 show() {
7947 this.tooltipElement.className = `${modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].Tooltips.tooltip} ${getClass(this.style)}`;
7948 this.labelElement.textContent = this.label;
7949 this.element.appendTo(this.container);
7950
7951 if (this.side == "top") {
7952 if (this.canShowAbove || (!this.canShowAbove && this.preventFlip)) this.showAbove();
7953 else this.showBelow();
7954 }
7955
7956 if (this.side == "bottom") {
7957 if (this.canShowBelow || (!this.canShowBelow && this.preventFlip)) this.showBelow();
7958 else this.showAbove();
7959 }
7960
7961 if (this.side == "left") {
7962 if (this.canShowLeft || (!this.canShowLeft && this.preventFlip)) this.showLeft();
7963 else this.showRight();
7964 }
7965
7966 if (this.side == "right") {
7967 if (this.canShowRight || (!this.canShowRight && this.preventFlip)) this.showRight();
7968 else this.showLeft();
7969 }
7970 }
7971
7972 /** Force showing the tooltip above the node. */
7973 showAbove() {
7974 this.tooltipElement.addClass(getClass("top"));
7975 this.element.css("top", toPx(this.node.offset().top - this.element.outerHeight() - 10));
7976 this.centerHorizontally();
7977 }
7978
7979 /** Force showing the tooltip below the node. */
7980 showBelow() {
7981 this.tooltipElement.addClass(getClass("bottom"));
7982 this.element.css("top", toPx(this.node.offset().top + this.node.outerHeight() + 10));
7983 this.centerHorizontally();
7984 }
7985
7986 /** Force showing the tooltip to the left of the node. */
7987 showLeft() {
7988 this.tooltipElement.addClass(getClass("left"));
7989 this.element.css("left", toPx(this.node.offset().left - this.element.outerWidth() - 10));
7990 this.centerVertically();
7991 }
7992
7993 /** Force showing the tooltip to the right of the node. */
7994 showRight() {
7995 this.tooltipElement.addClass(getClass("right"));
7996 this.element.css("left", toPx(this.node.offset().left + this.node.outerWidth() + 10));
7997 this.centerVertically();
7998 }
7999
8000 centerHorizontally() {
8001 const nodecenter = this.node.offset().left + (this.node.outerWidth() / 2);
8002 this.element.css("left", toPx(nodecenter - (this.element.outerWidth() / 2)));
8003 }
8004
8005 centerVertically() {
8006 const nodecenter = this.node.offset().top + (this.node.outerHeight() / 2);
8007 this.element.css("top", toPx(nodecenter - (this.element.outerHeight() / 2)));
8008 }
8009}
8010
8011/***/ }),
8012
8013/***/ "./src/ui/errorboundary.js":
8014/*!*********************************!*\
8015 !*** ./src/ui/errorboundary.js ***!
8016 \*********************************/
8017/*! exports provided: default, WrapBoundary */
8018/***/ (function(module, __webpack_exports__, __webpack_require__) {
8019
8020"use strict";
8021__webpack_require__.r(__webpack_exports__);
8022/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return ErrorBoundary; });
8023/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WrapBoundary", function() { return WrapBoundary; });
8024/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/discordmodules */ "./src/modules/discordmodules.js");
8025
8026
8027const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React;
8028const ce = React.createElement;
8029
8030class ErrorBoundary extends React.Component {
8031 constructor(props) {
8032 super(props);
8033 this.state = {hasError: false};
8034 }
8035
8036 componentDidCatch() {
8037 this.setState({hasError: true});
8038 }
8039
8040 render() {
8041 if (this.state.hasError) return ce("div", {className: "error"}, "Component Error");
8042 return this.props.children;
8043 }
8044}
8045
8046function WrapBoundary(Original) {
8047 return class ErrorBoundaryWrapper extends React.Component {
8048 render() {
8049 return ce(ErrorBoundary, null, ce(Original, this.props));
8050 }
8051 };
8052}
8053
8054/***/ }),
8055
8056/***/ "./src/ui/icons.js":
8057/*!*************************!*\
8058 !*** ./src/ui/icons.js ***!
8059 \*************************/
8060/*! exports provided: IconError, IconInfo, IconSuccess, IconWarning */
8061/***/ (function(module, __webpack_exports__, __webpack_require__) {
8062
8063"use strict";
8064__webpack_require__.r(__webpack_exports__);
8065/* harmony import */ var _icons_error__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./icons/error */ "./src/ui/icons/error.js");
8066/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "IconError", function() { return _icons_error__WEBPACK_IMPORTED_MODULE_0__["default"]; });
8067
8068/* harmony import */ var _icons_info__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./icons/info */ "./src/ui/icons/info.js");
8069/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "IconInfo", function() { return _icons_info__WEBPACK_IMPORTED_MODULE_1__["default"]; });
8070
8071/* harmony import */ var _icons_success__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./icons/success */ "./src/ui/icons/success.js");
8072/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "IconSuccess", function() { return _icons_success__WEBPACK_IMPORTED_MODULE_2__["default"]; });
8073
8074/* harmony import */ var _icons_warning__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./icons/warning */ "./src/ui/icons/warning.js");
8075/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "IconWarning", function() { return _icons_warning__WEBPACK_IMPORTED_MODULE_3__["default"]; });
8076
8077
8078
8079
8080
8081
8082/***/ }),
8083
8084/***/ "./src/ui/icons/error.js":
8085/*!*******************************!*\
8086 !*** ./src/ui/icons/error.js ***!
8087 \*******************************/
8088/*! exports provided: default */
8089/***/ (function(module, __webpack_exports__, __webpack_require__) {
8090
8091"use strict";
8092__webpack_require__.r(__webpack_exports__);
8093/**
8094 * Error Icon
8095 * @param {number} size - Size of the icon.
8096 */
8097/* harmony default export */ __webpack_exports__["default"] = (function(size) {
8098 return `<svg width="${size || 24}" height="${size || 24}" viewBox="0 0 24 24">
8099 <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" />
8100 </svg>`;
8101});
8102
8103/***/ }),
8104
8105/***/ "./src/ui/icons/info.js":
8106/*!******************************!*\
8107 !*** ./src/ui/icons/info.js ***!
8108 \******************************/
8109/*! exports provided: default */
8110/***/ (function(module, __webpack_exports__, __webpack_require__) {
8111
8112"use strict";
8113__webpack_require__.r(__webpack_exports__);
8114/**
8115 * Info Icon
8116 * @param {number} size - Size of the icon.
8117 */
8118/* harmony default export */ __webpack_exports__["default"] = (function(size) {
8119 return `<svg width="${size || 24}" height="${size || 24}" viewBox="0 0 24 24">
8120 <path d="M0 0h24v24H0z" fill="none"/>
8121 <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
8122 </svg>`;
8123});
8124
8125/***/ }),
8126
8127/***/ "./src/ui/icons/success.js":
8128/*!*********************************!*\
8129 !*** ./src/ui/icons/success.js ***!
8130 \*********************************/
8131/*! exports provided: default */
8132/***/ (function(module, __webpack_exports__, __webpack_require__) {
8133
8134"use strict";
8135__webpack_require__.r(__webpack_exports__);
8136/**
8137 * Success Icon
8138 * @param {number} size - Size of the icon.
8139 */
8140/* harmony default export */ __webpack_exports__["default"] = (function(size) {
8141 return `<svg width="${size || 24}" height="${size || 24}" viewBox="0 0 24 24">
8142 <path d="M0 0h24v24H0z" fill="none"/>
8143 <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
8144 </svg>`;
8145});
8146
8147/***/ }),
8148
8149/***/ "./src/ui/icons/warning.js":
8150/*!*********************************!*\
8151 !*** ./src/ui/icons/warning.js ***!
8152 \*********************************/
8153/*! exports provided: default */
8154/***/ (function(module, __webpack_exports__, __webpack_require__) {
8155
8156"use strict";
8157__webpack_require__.r(__webpack_exports__);
8158/**
8159 * Warning Icon
8160 * @param {number} size - Size of the icon.
8161 */
8162/* harmony default export */ __webpack_exports__["default"] = (function(size) {
8163 return `<svg width="${size || 24}" height="${size || 24}" viewBox="0 0 24 24">
8164 <path d="M0 0h24v24H0z" fill="none"/>
8165 <path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>
8166 </svg>`;
8167});
8168
8169/***/ }),
8170
8171/***/ "./src/ui/modals.js":
8172/*!**************************!*\
8173 !*** ./src/ui/modals.js ***!
8174 \**************************/
8175/*! exports provided: default */
8176/***/ (function(module, __webpack_exports__, __webpack_require__) {
8177
8178"use strict";
8179__webpack_require__.r(__webpack_exports__);
8180/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return Modals; });
8181/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
8182/**
8183 * Allows an easy way to create and show modals.
8184 * @module Modals
8185 * @version 0.0.1
8186 */
8187
8188
8189
8190const React = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].React;
8191const ce = React.createElement;
8192const Markdown = modules__WEBPACK_IMPORTED_MODULE_0__["WebpackModules"].getByDisplayName("Markdown");
8193
8194class Modals {
8195
8196 /** Sizes of modals. */
8197 static get ModalSizes() {return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].ConfirmationModal.Sizes;}
8198
8199 /**
8200 * Shows the user profile modal for a given user.
8201 * @param {string} userId - id of the user to show profile for
8202 */
8203 static showUserProfile(userId) {
8204 return modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].UserProfileModal.open(userId);
8205 }
8206
8207 /**
8208 * Acts as a wrapper for {@link module:Modals.showModal} where the `children` is a text element.
8209 * @param {string} title - title of the modal
8210 * @param {string} content - text to show inside the modal. Can be markdown.
8211 * @param {object} [options] - see {@link module:Modals.showModal}
8212 * @see module:Modals.showModal
8213 */
8214 static showConfirmationModal(title, content, options = {}) {
8215 this.showModal(title, ce(Markdown, null, content), options);
8216 }
8217
8218 /**
8219 * Shows a very simple alert modal that has title, content and an okay button.
8220 * @param {string} title - title of the modal
8221 * @param {string} body - text to show inside the modal
8222 */
8223 static showAlertModal(title, body) {
8224 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].ModalStack.push(function(props) {
8225 return ce(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].AlertModal, Object.assign({
8226 title: title,
8227 body: body,
8228 }, props));
8229 });
8230 }
8231
8232 /**
8233 * Shows a generic but very customizable modal.
8234 * @param {string} title - title of the modal
8235 * @param {(ReactElement|Array<ReactElement>)} children - a single or array of rendered react elements to act as children
8236 * @param {object} [options] - options to modify the modal
8237 * @param {boolean} [options.danger=false] - whether the main button should be red or not
8238 * @param {string} [options.confirmText=Okay] - text for the confirmation/submit button
8239 * @param {string} [options.cancelText=Cancel] - text for the cancel button
8240 * @param {callable} [options.onConfirm=NOOP] - callback to occur when clicking the submit button
8241 * @param {callable} [options.onCancel=NOOP] - callback to occur when clicking the cancel button
8242 * @param {module:Modals.ModalSizes} [options.size=module:Modals.ModalSizes.SMALL] - overall size of the modal
8243 */
8244 static showModal(title, children, options = {}) {
8245 const {danger = false, confirmText = "Okay", cancelText = "Cancel", onConfirm = () => {}, onCancel = () => {}, size = this.ModalSizes.SMALL} = options;
8246 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].ModalStack.push(function(props) {
8247 return ce(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].ConfirmationModal, Object.assign({
8248 header: title,
8249 red: danger,
8250 size: size,
8251 confirmText: confirmText,
8252 cancelText: cancelText,
8253 onConfirm: onConfirm,
8254 onCancel: onCancel,
8255 children: Array.isArray(children) ? children : [children]
8256 }, props));
8257 });
8258 }
8259
8260 /**
8261 * @interface
8262 * @name module:Modals~Changelog
8263 * @property {string} title - title of the changelog section
8264 * @property {string} [type=added] - type information of the section. Options: added, improved, fixed, progress.
8265 * @property {Array<string>} items - itemized list of items to show in that section. Can use markdown.
8266 */
8267
8268 /**
8269 * Shows a changelog modal based on changelog data.
8270 * @param {string} title - title of the modal
8271 * @param {string} version - subtitle (usually version or date) of the modal
8272 * @param {module:Modals~Changelog} changelog - changelog to show inside the modal
8273 * @param {string} footer - either an html element or text to show in the footer of the modal. Can use markdown.
8274 */
8275 static showChangelogModal(title, version, changelog, footer) {
8276 const TextElement = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].TextElement;
8277 const changelogItems = [];
8278 for (let c = 0; c < changelog.length; c++) {
8279 const entry = changelog[c];
8280 const type = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].Changelog[entry.type] ? modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].Changelog[entry.type] : modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].Changelog.added;
8281 const margin = c == 0 ? modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].Changelog.marginTop : "";
8282 changelogItems.push(ce("h1", {className: `${type} ${margin}`,}, entry.title));
8283 const list = ce("ul", null, entry.items.map(i => ce("li", null, ce(Markdown, null, i))));
8284 changelogItems.push(list);
8285 }
8286 const renderHeader = function() {
8287 return ce(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].FlexChild.Child, {grow: 1, shrink: 1},
8288 ce(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].Titles.default, {tag: modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].Titles.Tags.H4}, title),
8289 ce(TextElement.default,
8290 {size: TextElement.Sizes.SMALL, color: TextElement.Colors.PRIMARY, className: modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].Changelog.date.toString()},
8291 "Version " + version
8292 )
8293 );
8294 };
8295 const renderFooter = footer ? function() {
8296 return ce(Markdown, null, footer);
8297 } : null;
8298 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].ModalStack.push(function(props) {
8299 return ce(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].Changelog, Object.assign({
8300 className: modules__WEBPACK_IMPORTED_MODULE_0__["DiscordClasses"].Changelog.container.toString(),
8301 selectable: true,
8302 onScroll: _ => _,
8303 onClose: _ => _,
8304 renderHeader: renderHeader,
8305 renderFooter: renderFooter,
8306 children: changelogItems
8307 }, props));
8308 });
8309 }
8310}
8311
8312/***/ }),
8313
8314/***/ "./src/ui/popouts.js":
8315/*!***************************!*\
8316 !*** ./src/ui/popouts.js ***!
8317 \***************************/
8318/*! exports provided: default */
8319/***/ (function(module, __webpack_exports__, __webpack_require__) {
8320
8321"use strict";
8322__webpack_require__.r(__webpack_exports__);
8323/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return Popouts; });
8324/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! structs */ "./src/structs/structs.js");
8325/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
8326/**
8327 * Allows an easy way to create and show popouts.
8328 * @module Popouts
8329 * @version 0.0.1
8330 */
8331
8332
8333
8334
8335class Popouts {
8336 /**
8337 * Shows the user popout for a user relative to a target element
8338 * @param {HTMLElement} target - Element to show the popout in relation to
8339 * @param {object} user - Discord User object for the user to show
8340 * @param {object} [options] - Options to modify the request
8341 * @param {string} [options.guild="currentGuildId"] - Id of the guild (uses current if not specified)
8342 * @param {string} [options.channel="currentChannelId"] - Id of the channel (uses current if not specified)
8343 * @param {string} [options.position="right"] - Positioning relative to element
8344 */
8345 static showUserPopout(target, user, options = {}) {
8346 const {guild = modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].SelectedGuildStore.getGuildId(), channel = modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].SelectedChannelStore.getChannelId()} = options;
8347 let {position = "right"} = options;
8348 target = modules__WEBPACK_IMPORTED_MODULE_1__["DOMTools"].resolveElement(target);
8349 if (target.getBoundingClientRect().right + 250 >= structs__WEBPACK_IMPORTED_MODULE_0__["Screen"].width) position = "left";
8350 modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].PopoutOpener.openPopout(target, {
8351 position: position,
8352 offsetX: 0,
8353 offsetY: 0,
8354 animationType: "default",
8355 preventInvert: false,
8356 zIndexBoost: 0,
8357 closeOnScroll: false,
8358 shadow: false,
8359 backdrop: false,
8360 toggleClose: true,
8361 render: (props) => {
8362 return modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].React.createElement(modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].UserPopout, Object.assign({}, props, {
8363 userId: user.id,
8364 guildId: guild,
8365 channelId: channel
8366 }));
8367 }
8368 }, "ZeresLibrary");
8369 }
8370}
8371
8372/***/ }),
8373
8374/***/ "./src/ui/settings/index.js":
8375/*!**********************************!*\
8376 !*** ./src/ui/settings/index.js ***!
8377 \**********************************/
8378/*! exports provided: CSS, SettingField, SettingGroup, SettingPanel, Textbox, ColorPicker, FilePicker, Slider, Switch, Dropdown, Keybind, RadioGroup, ReactSetting */
8379/***/ (function(module, __webpack_exports__, __webpack_require__) {
8380
8381"use strict";
8382__webpack_require__.r(__webpack_exports__);
8383/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CSS", function() { return CSS; });
8384/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./settingfield */ "./src/ui/settings/settingfield.js");
8385/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ReactSetting", function() { return _settingfield__WEBPACK_IMPORTED_MODULE_0__["ReactSetting"]; });
8386
8387/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "SettingField", function() { return _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"]; });
8388
8389/* harmony import */ var _settinggroup__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./settinggroup */ "./src/ui/settings/settinggroup.js");
8390/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "SettingGroup", function() { return _settinggroup__WEBPACK_IMPORTED_MODULE_1__["default"]; });
8391
8392/* harmony import */ var _settingpanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./settingpanel */ "./src/ui/settings/settingpanel.js");
8393/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "SettingPanel", function() { return _settingpanel__WEBPACK_IMPORTED_MODULE_2__["default"]; });
8394
8395/* harmony import */ var _types_textbox__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./types/textbox */ "./src/ui/settings/types/textbox.js");
8396/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Textbox", function() { return _types_textbox__WEBPACK_IMPORTED_MODULE_3__["default"]; });
8397
8398/* harmony import */ var _types_color__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./types/color */ "./src/ui/settings/types/color.js");
8399/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ColorPicker", function() { return _types_color__WEBPACK_IMPORTED_MODULE_4__["default"]; });
8400
8401/* harmony import */ var _types_file__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./types/file */ "./src/ui/settings/types/file.js");
8402/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "FilePicker", function() { return _types_file__WEBPACK_IMPORTED_MODULE_5__["default"]; });
8403
8404/* harmony import */ var _types_slider__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./types/slider */ "./src/ui/settings/types/slider.js");
8405/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Slider", function() { return _types_slider__WEBPACK_IMPORTED_MODULE_6__["default"]; });
8406
8407/* harmony import */ var _types_switch__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./types/switch */ "./src/ui/settings/types/switch.js");
8408/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Switch", function() { return _types_switch__WEBPACK_IMPORTED_MODULE_7__["default"]; });
8409
8410/* harmony import */ var _types_dropdown__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./types/dropdown */ "./src/ui/settings/types/dropdown.js");
8411/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Dropdown", function() { return _types_dropdown__WEBPACK_IMPORTED_MODULE_8__["default"]; });
8412
8413/* harmony import */ var _types_keybind__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./types/keybind */ "./src/ui/settings/types/keybind.js");
8414/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Keybind", function() { return _types_keybind__WEBPACK_IMPORTED_MODULE_9__["default"]; });
8415
8416/* harmony import */ var _types_radiogroup__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./types/radiogroup */ "./src/ui/settings/types/radiogroup.js");
8417/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "RadioGroup", function() { return _types_radiogroup__WEBPACK_IMPORTED_MODULE_10__["default"]; });
8418
8419/**
8420 * An object that makes generating settings panel 10x easier.
8421 * @module Settings
8422 * @version 1.1.2
8423 */
8424
8425const CSS = __webpack_require__(/*! ../../styles/settings.css */ "./src/styles/settings.css");
8426
8427
8428
8429
8430
8431
8432
8433
8434
8435
8436
8437
8438
8439
8440/***/ }),
8441
8442/***/ "./src/ui/settings/settingfield.js":
8443/*!*****************************************!*\
8444 !*** ./src/ui/settings/settingfield.js ***!
8445 \*****************************************/
8446/*! exports provided: default, ReactSetting */
8447/***/ (function(module, __webpack_exports__, __webpack_require__) {
8448
8449"use strict";
8450__webpack_require__.r(__webpack_exports__);
8451/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReactSetting", function() { return ReactSetting; });
8452/* harmony import */ var _structs_listenable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../structs/listenable */ "./src/structs/listenable.js");
8453/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
8454
8455
8456
8457/**
8458 * Setting field to extend to create new settings
8459 * @memberof module:Settings
8460 * @version 1.0.1
8461 */
8462class SettingField extends _structs_listenable__WEBPACK_IMPORTED_MODULE_0__["default"] {
8463 /**
8464 * @param {string} name - name label of the setting
8465 * @param {string} note - help/note to show underneath or above the setting
8466 * @param {callable} onChange - callback to perform on setting change
8467 * @param {(ReactComponent|HTMLElement)} settingtype - actual setting to render
8468 * @param {object} [props] - object of props to give to the setting and the settingtype
8469 * @param {boolean} [props.noteOnTop=false] - determines if the note should be shown above the element or not.
8470 */
8471 constructor(name, note, onChange, settingtype, props = {}) {
8472 super();
8473 this.name = name;
8474 this.note = note;
8475 if (typeof(onChange) == "function") this.addListener(onChange);
8476 this.inputWrapper = modules__WEBPACK_IMPORTED_MODULE_1__["DOMTools"].parseHTML(`<div class="plugin-input-container"></div>`);
8477 this.type = typeof(settingtype) == "function" ? settingtype : modules__WEBPACK_IMPORTED_MODULE_1__["ReactTools"].wrapElement(settingtype);
8478 this.props = props;
8479 modules__WEBPACK_IMPORTED_MODULE_1__["DOMTools"].onAdded(this.getElement(), () => {this.onAdded();});
8480 modules__WEBPACK_IMPORTED_MODULE_1__["DOMTools"].onRemoved(this.getElement(), () => {this.onRemoved();});
8481 }
8482
8483 /** @returns {HTMLElement} - root element for setting */
8484 getElement() { return this.inputWrapper; }
8485
8486 /** Fires onchange to listeners */
8487 onChange() {
8488 this.alertListeners(...arguments);
8489 }
8490
8491 /** Fired when root node added to DOM */
8492 onAdded() {
8493 const reactElement = modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].ReactDOM.render(modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].React.createElement(ReactSetting, Object.assign({
8494 title: this.name,
8495 type: this.type,
8496 note: this.note,
8497 }, this.props)), this.getElement());
8498
8499 if (this.props.onChange) reactElement.props.onChange = this.props.onChange(reactElement);
8500 reactElement.forceUpdate();
8501 }
8502
8503 /** Fired when root node removed from DOM */
8504 onRemoved() {
8505 modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].ReactDOM.unmountComponentAtNode(this.getElement());
8506 }
8507}
8508
8509/* harmony default export */ __webpack_exports__["default"] = (SettingField);
8510
8511class ReactSetting extends modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].React.Component {
8512 constructor(props) {
8513 super(props);
8514 }
8515
8516 get noteElement() {
8517 const className = this.props.noteOnTop ? modules__WEBPACK_IMPORTED_MODULE_1__["DiscordClasses"].Margins.marginBottom8 : modules__WEBPACK_IMPORTED_MODULE_1__["DiscordClasses"].Margins.marginTop8;
8518 return modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].React.createElement(modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].SettingsNote, {children: this.props.note, type: "description", className: className.toString()});
8519 }
8520
8521 get dividerElement() { return modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].React.createElement("div", {className: modules__WEBPACK_IMPORTED_MODULE_1__["DiscordClasses"].Dividers.divider.add(modules__WEBPACK_IMPORTED_MODULE_1__["DiscordClasses"].Dividers.dividerDefault).toString()}); }
8522
8523 render() {
8524 const SettingElement = modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].React.createElement(this.props.type, this.props);
8525 return modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].React.createElement(modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].SettingsWrapper, {
8526 className: modules__WEBPACK_IMPORTED_MODULE_1__["DiscordClasses"].Margins.marginBottom20.toString(),
8527 title: this.props.title,
8528 children: [
8529 this.props.noteOnTop ? this.noteElement : SettingElement,
8530 this.props.noteOnTop ? SettingElement : this.noteElement,
8531 this.dividerElement
8532 ]
8533 });
8534 }
8535}
8536
8537
8538
8539/***/ }),
8540
8541/***/ "./src/ui/settings/settinggroup.js":
8542/*!*****************************************!*\
8543 !*** ./src/ui/settings/settinggroup.js ***!
8544 \*****************************************/
8545/*! exports provided: default */
8546/***/ (function(module, __webpack_exports__, __webpack_require__) {
8547
8548"use strict";
8549__webpack_require__.r(__webpack_exports__);
8550/* harmony import */ var _structs_listenable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../structs/listenable */ "./src/structs/listenable.js");
8551/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
8552/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./settingfield */ "./src/ui/settings/settingfield.js");
8553
8554
8555
8556
8557/**
8558 * Grouping of controls for easier management in settings panels.
8559 * @memberof module:Settings
8560 * @version 1.0.2
8561 */
8562class SettingGroup extends _structs_listenable__WEBPACK_IMPORTED_MODULE_0__["default"] {
8563 /**
8564 * @param {string} groupName - title for the group of settings
8565 * @param {object} [options] - additional options for the group
8566 * @param {callback} [options.callback] - callback called on settings changed
8567 * @param {boolean} [options.collapsible=true] - determines if the group should be collapsible
8568 * @param {boolean} [options.shown=false] - determines if the group should be expanded by default
8569 */
8570 constructor(groupName, options = {}) {
8571 super();
8572 const {collapsible = true, shown = false, callback = () => {}} = options;
8573 this.addListener(callback);
8574 this.onChange = this.onChange.bind(this);
8575
8576 const collapsed = shown || !collapsible ? "" : "collapsed";
8577 const group = modules__WEBPACK_IMPORTED_MODULE_1__["DOMTools"].parseHTML(`<div class="plugin-input-group">
8578 <h2 class="${modules__WEBPACK_IMPORTED_MODULE_1__["DiscordClasses"].Titles.h5} ${modules__WEBPACK_IMPORTED_MODULE_1__["DiscordClasses"].Titles.defaultMarginh5} ${modules__WEBPACK_IMPORTED_MODULE_1__["DiscordClasses"].Titles.defaultColor}">
8579 <span class="button-collapse ${collapsed}"></span> ${groupName}
8580 </h2>
8581 <div class="plugin-inputs collapsible ${collapsed}"></div>
8582 </div>`);
8583 const label = group.querySelector("h2");
8584 const controls = group.querySelector(".plugin-inputs");
8585
8586 this.group = group;
8587 this.label = label;
8588 this.controls = controls;
8589
8590 if (!collapsible) return;
8591 label.addEventListener("click", async () => {
8592 const button = label.querySelector(".button-collapse");
8593 const wasCollapsed = button.classList.contains("collapsed");
8594 group.parentElement.querySelectorAll(":scope > .plugin-input-group > .collapsible:not(.collapsed)").forEach((element) => {
8595 element.style.setProperty("height", element.scrollHeight + "px");
8596 element.classList.add("collapsed");
8597 setImmediate(() => {element.style.setProperty("height", "");});
8598 });
8599 group.parentElement.querySelectorAll(":scope > .plugin-input-group > h2 > .button-collapse").forEach(e => e.classList.add("collapsed"));
8600 if (!wasCollapsed) return;
8601 controls.style.setProperty("height", controls.scrollHeight + "px");
8602 controls.classList.remove("collapsed");
8603 button.classList.remove("collapsed");
8604 await new Promise(resolve => setTimeout(resolve, 300));
8605 controls.style.setProperty("height", "");
8606 });
8607 }
8608
8609 /** @returns {HTMLElement} - root node for the group. */
8610 getElement() {return this.group;}
8611
8612 /**
8613 * Adds multiple nodes to this group.
8614 * @param {(...HTMLElement|...jQuery|...module:Settings.SettingField|...module:Settings.SettingGroup)} nodes - list of nodes to add to the group container
8615 * @returns {module:Settings.SettingGroup} - returns self for chaining
8616 */
8617 append(...nodes) {
8618 for (let i = 0; i < nodes.length; i++) {
8619 if (nodes[i] instanceof jQuery || nodes[i] instanceof Element) this.controls.append(nodes[i]);
8620 else if (nodes[i] instanceof _settingfield__WEBPACK_IMPORTED_MODULE_2__["default"] || nodes[i] instanceof SettingGroup) this.controls.append(nodes[i].getElement());
8621 if (nodes[i] instanceof _settingfield__WEBPACK_IMPORTED_MODULE_2__["default"]) {
8622 nodes[i].addListener(((node) => (value) => {
8623 this.onChange(node.id || node.name, value);
8624 })(nodes[i]));
8625 }
8626 else if (nodes[i] instanceof SettingGroup) {
8627 nodes[i].addListener(((node) => (settingId, value) => {
8628 this.onChange(node.id || node.name, settingId, value);
8629 })(nodes[i]));
8630 }
8631 }
8632 return this;
8633 }
8634
8635 /**
8636 * Appends this node to another
8637 * @param {HTMLElement} node - node to attach the group to.
8638 * @returns {module:Settings.SettingGroup} - returns self for chaining
8639 */
8640 appendTo(node) {
8641 node.append(this.group);
8642 return this;
8643 }
8644
8645 /** Fires onchange to listeners */
8646 onChange() {
8647 this.alertListeners(...arguments);
8648 }
8649}
8650
8651/* harmony default export */ __webpack_exports__["default"] = (SettingGroup);
8652
8653/***/ }),
8654
8655/***/ "./src/ui/settings/settingpanel.js":
8656/*!*****************************************!*\
8657 !*** ./src/ui/settings/settingpanel.js ***!
8658 \*****************************************/
8659/*! exports provided: default */
8660/***/ (function(module, __webpack_exports__, __webpack_require__) {
8661
8662"use strict";
8663__webpack_require__.r(__webpack_exports__);
8664/* harmony import */ var _structs_listenable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../structs/listenable */ "./src/structs/listenable.js");
8665/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
8666/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./settingfield */ "./src/ui/settings/settingfield.js");
8667/* harmony import */ var _settinggroup__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./settinggroup */ "./src/ui/settings/settinggroup.js");
8668
8669
8670
8671
8672
8673/**
8674 * Grouping of controls for easier management in settings panels.
8675 * @memberof module:Settings
8676 * @version 1.0.2
8677 */
8678class SettingPanel extends _structs_listenable__WEBPACK_IMPORTED_MODULE_0__["default"] {
8679
8680 /**
8681 * Creates a new settings panel
8682 * @param {callable} onChange - callback to fire when settings change
8683 * @param {(...HTMLElement|...jQuery|...module:Settings.SettingField|...module:Settings.SettingGroup)} nodes - list of nodes to add to the panel container
8684 */
8685 constructor(onChange, ...nodes) {
8686 super();
8687 this.element = modules__WEBPACK_IMPORTED_MODULE_1__["DOMTools"].parseHTML(`<div class="plugin-form-container"></div>`);
8688 if (typeof(onChange) == "function") this.addListener(onChange);
8689 this.onChange = this.onChange.bind(this);
8690 this.append(...nodes);
8691 }
8692
8693 /**
8694 * Creates a new settings panel
8695 * @param {callable} onChange - callback to fire when settings change
8696 * @param {(...HTMLElement|...jQuery|...module:Settings.SettingField|...module:Settings.SettingGroup)} nodes - list of nodes to add to the panel container
8697 * @returns {HTMLElement} - root node for the panel.
8698 */
8699 static build(onChange, ...nodes) {
8700 return (new SettingPanel(onChange, ...nodes)).getElement();
8701 }
8702
8703 /** @returns {HTMLElement} - root node for the panel. */
8704 getElement() {return this.element;}
8705
8706 /**
8707 * Adds multiple nodes to this panel.
8708 * @param {(...HTMLElement|...jQuery|...SettingField|...SettingGroup)} nodes - list of nodes to add to the panel container
8709 * @returns {module:Settings.SettingPanel} - returns self for chaining
8710 */
8711 append(...nodes) {
8712 for (let i = 0; i < nodes.length; i++) {
8713 if (nodes[i] instanceof jQuery || nodes[i] instanceof Element) this.element.append(nodes[i]);
8714 else if (nodes[i] instanceof _settingfield__WEBPACK_IMPORTED_MODULE_2__["default"] || nodes[i] instanceof _settinggroup__WEBPACK_IMPORTED_MODULE_3__["default"]) this.element.append(nodes[i].getElement());
8715 if (nodes[i] instanceof _settingfield__WEBPACK_IMPORTED_MODULE_2__["default"]) {
8716 nodes[i].addListener(((node) => (value) => {
8717 this.onChange(node.id || node.name, value);
8718 })(nodes[i]));
8719 }
8720 else if (nodes[i] instanceof _settinggroup__WEBPACK_IMPORTED_MODULE_3__["default"]) {
8721 nodes[i].addListener(((node) => (settingId, value) => {
8722 this.onChange(node.id || node.name, settingId, value);
8723 })(nodes[i]));
8724 }
8725 }
8726 return this;
8727 }
8728
8729 /** Fires onchange to listeners */
8730 onChange() {
8731 this.alertListeners(...arguments);
8732 }
8733}
8734
8735/* harmony default export */ __webpack_exports__["default"] = (SettingPanel);
8736
8737/***/ }),
8738
8739/***/ "./src/ui/settings/types/color.js":
8740/*!****************************************!*\
8741 !*** ./src/ui/settings/types/color.js ***!
8742 \****************************************/
8743/*! exports provided: default */
8744/***/ (function(module, __webpack_exports__, __webpack_require__) {
8745
8746"use strict";
8747__webpack_require__.r(__webpack_exports__);
8748/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js");
8749/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
8750
8751
8752
8753
8754const presetColors = [1752220, 3066993, 3447003, 10181046, 15277667, 15844367, 15105570, 15158332, 9807270, 6323595, 1146986, 2067276, 2123412, 7419530, 11342935, 12745742, 11027200, 10038562, 9936031, 5533306];
8755
8756/**
8757 * Creates a color picker using Discord's built in color picker
8758 * as a base. Input and output using hex strings.
8759 * @memberof module:Settings
8760 * @version 0.1.0
8761 * @extends module:Settings.SettingField
8762 */
8763class ColorPicker extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] {
8764 /**
8765 * @param {string} name - name label of the setting
8766 * @param {string} note - help/note to show underneath or above the setting
8767 * @param {string} value - current hex color
8768 * @param {callable} onChange - callback to perform on setting change, callback receives hex string
8769 * @param {object} [options] - object of options to give to the setting
8770 * @param {boolean} [options.disabled=false] - should the setting be disabled
8771 * @param {Array<number>} [options.colors=presetColors] - preset list of colors
8772 */
8773 constructor(name, note, value, onChange, options = {}) {
8774 super(name, note, onChange, modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].ColorPicker, {
8775 disabled: options.disabled ? true : false,
8776 onChange: reactElement => color => {
8777 reactElement.props.value = color;
8778 reactElement.forceUpdate();
8779 this.onChange(modules__WEBPACK_IMPORTED_MODULE_1__["ColorConverter"].int2hex(color));
8780 },
8781 colors: Array.isArray(options.colors) ? options.colors : presetColors,
8782 defaultColor: typeof(value) == "number" ? value : modules__WEBPACK_IMPORTED_MODULE_1__["ColorConverter"].hex2int(value),
8783 value: 0
8784 });
8785 }
8786
8787 /** Default colors for ColorPicker */
8788 static get presetColors() {return presetColors;}
8789}
8790
8791
8792
8793/* harmony default export */ __webpack_exports__["default"] = (ColorPicker);
8794
8795/***/ }),
8796
8797/***/ "./src/ui/settings/types/dropdown.js":
8798/*!*******************************************!*\
8799 !*** ./src/ui/settings/types/dropdown.js ***!
8800 \*******************************************/
8801/*! exports provided: default */
8802/***/ (function(module, __webpack_exports__, __webpack_require__) {
8803
8804"use strict";
8805__webpack_require__.r(__webpack_exports__);
8806/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js");
8807/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
8808
8809
8810
8811/**
8812 * @interface
8813 * @name module:Settings~DropdownItem
8814 * @property {string} label - label to show in the dropdown
8815 * @property {*} value - actual value represented by label (this is passed via onChange)
8816 */
8817
8818/**
8819 * Creates a dropdown using discord's built in dropdown.
8820 * @memberof module:Settings
8821 * @version 0.0.1
8822 * @extends module:Settings.SettingField
8823 */
8824class Dropdown extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] {
8825 /**
8826 * @param {string} name - name label of the setting
8827 * @param {string} note - help/note to show underneath or above the setting
8828 * @param {*} defaultValue - currently selected value
8829 * @param {Array<module:Settings~DropdownItem>} values - array of all options available
8830 * @param {callable} onChange - callback to perform on setting change, callback item value
8831 * @param {object} [options] - object of options to give to the setting
8832 * @param {boolean} [options.clearable=false] - should be able to empty the field value
8833 * @param {boolean} [options.searchable=false] - should user be able to search the dropdown
8834 * @param {boolean} [options.disabled=false] - should the setting be disabled
8835 */
8836 constructor(name, note, defaultValue, values, onChange, options = {}) {
8837 const {clearable = false, searchable = false, disabled = false} = options;
8838 super(name, note, onChange, modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].Dropdown, {
8839 clearable: clearable,
8840 searchable: searchable,
8841 disabled: disabled,
8842 options: values,
8843 onChange: dropdown => opt => {
8844 dropdown.props.value = opt.value;
8845 dropdown.forceUpdate();
8846 this.onChange(opt.value);
8847 },
8848 value: defaultValue
8849 });
8850 }
8851}
8852
8853/* harmony default export */ __webpack_exports__["default"] = (Dropdown);
8854
8855/***/ }),
8856
8857/***/ "./src/ui/settings/types/file.js":
8858/*!***************************************!*\
8859 !*** ./src/ui/settings/types/file.js ***!
8860 \***************************************/
8861/*! exports provided: default */
8862/***/ (function(module, __webpack_exports__, __webpack_require__) {
8863
8864"use strict";
8865__webpack_require__.r(__webpack_exports__);
8866/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js");
8867/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
8868
8869
8870
8871/**
8872 * Creates a file picker using chromium's default.
8873 * @memberof module:Settings
8874 * @version 0.0.1
8875 * @extends module:Settings.SettingField
8876 */
8877class FilePicker extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] {
8878 /**
8879 * @param {string} name - name label of the setting
8880 * @param {string} note - help/note to show underneath or above the setting
8881 * @param {callable} onChange - callback to perform on setting change, callback receives File object
8882 * @param {object} [options] - object of options to give to the setting
8883 * @param {boolean} [options.disabled=false] - should the setting be disabled
8884 * @param {Array<string>|string} [options.accept] - what file types should be accepted
8885 * @param {boolean} [options.multiple=false] - should multiple files be accepted
8886 */
8887 constructor(name, note, onChange, options = {}) {
8888 const classes = modules__WEBPACK_IMPORTED_MODULE_1__["DiscordClasses"].BasicInputs.inputDefault.add("file-input");
8889 if(options.disabled) classes.add(modules__WEBPACK_IMPORTED_MODULE_1__["DiscordClasses"].BasicInputs.disabled);
8890 const ReactFilePicker = modules__WEBPACK_IMPORTED_MODULE_1__["DOMTools"].parseHTML(`<input type="file" class="${classes}">`);
8891 if(options.disabled) ReactFilePicker.setAttribute("disabled", "");
8892 if(options.multiple) ReactFilePicker.setAttribute("multiple", "");
8893 if(options.accept) ReactFilePicker.setAttribute("accept", Array.isArray(options.accept) ? options.accept.join(",") : options.accept);
8894 ReactFilePicker.addEventListener("change", (event) => {
8895 this.onChange(event.target.files[0]);
8896 });
8897 super(name, note, onChange, ReactFilePicker);
8898 }
8899}
8900
8901/* harmony default export */ __webpack_exports__["default"] = (FilePicker);
8902
8903/***/ }),
8904
8905/***/ "./src/ui/settings/types/keybind.js":
8906/*!******************************************!*\
8907 !*** ./src/ui/settings/types/keybind.js ***!
8908 \******************************************/
8909/*! exports provided: default */
8910/***/ (function(module, __webpack_exports__, __webpack_require__) {
8911
8912"use strict";
8913__webpack_require__.r(__webpack_exports__);
8914/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js");
8915/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
8916
8917
8918
8919/**
8920 * Creates a keybind setting using discord's built in keybind recorder.
8921 * @memberof module:Settings
8922 * @version 0.0.1
8923 * @extends module:Settings.SettingField
8924 */
8925class Keybind extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] {
8926 /**
8927 * @param {string} name - name label of the setting
8928 * @param {string} note - help/note to show underneath or above the setting
8929 * @param {Array<number>} value - array of keycodes
8930 * @param {callable} onChange - callback to perform on setting change, callback receives array of keycodes
8931 * @param {object} [options] - object of options to give to the setting
8932 * @param {boolean} [options.disabled=false] - should the setting be disabled
8933 */
8934 constructor(label, help, value, onChange, options = {}) {
8935 const {disabled=false} = options;
8936 super(label, help, onChange, modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].Keybind, {
8937 disabled: disabled,
8938 defaultValue: value.map(a => [0, a]),
8939 onChange: element => value => {
8940 if (!Array.isArray(value)) return;
8941 element.props.value = value;
8942 this.onChange(value.map(a => a[1]));
8943 }
8944 });
8945 }
8946}
8947
8948/* harmony default export */ __webpack_exports__["default"] = (Keybind);
8949
8950/***/ }),
8951
8952/***/ "./src/ui/settings/types/radiogroup.js":
8953/*!*********************************************!*\
8954 !*** ./src/ui/settings/types/radiogroup.js ***!
8955 \*********************************************/
8956/*! exports provided: default */
8957/***/ (function(module, __webpack_exports__, __webpack_require__) {
8958
8959"use strict";
8960__webpack_require__.r(__webpack_exports__);
8961/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js");
8962/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
8963
8964
8965
8966/**
8967 * @interface
8968 * @name module:Settings~RadioItem
8969 * @property {string} name - label to show in the dropdown
8970 * @property {*} value - actual value represented by label (this is passed via onChange)
8971 * @property {string} desc - description/help text to show below name
8972 * @property {string} color - hex string to color the item
8973 */
8974
8975/**
8976 * Creates a radio group using discord's built in radios.
8977 * @memberof module:Settings
8978 * @version 0.0.1
8979 * @extends module:Settings.SettingField
8980 */
8981class RadioGroup extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] {
8982 /**
8983 * @param {string} name - name label of the setting
8984 * @param {string} note - help/note to show underneath or above the setting
8985 * @param {*} defaultValue - currently selected value
8986 * @param {Array<module:Settings~RadioItem>} values - array of all options available
8987 * @param {callable} onChange - callback to perform on setting change, callback item value
8988 * @param {object} [options] - object of options to give to the setting
8989 * @param {boolean} [options.disabled=false] - should the setting be disabled
8990 */
8991 constructor(name, note, defaultValue, values, onChange, options = {}) {
8992 super(name, note, onChange, modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].RadioGroup, {
8993 noteOnTop: true,
8994 disabled: options.disabled ? true : false,
8995 options: values,
8996 onChange: reactElement => option => {
8997 reactElement.props.value = option.value;
8998 reactElement.forceUpdate();
8999 this.onChange(option.value);
9000 },
9001 value: defaultValue
9002 });
9003 }
9004}
9005
9006/* harmony default export */ __webpack_exports__["default"] = (RadioGroup);
9007
9008
9009
9010/***/ }),
9011
9012/***/ "./src/ui/settings/types/slider.js":
9013/*!*****************************************!*\
9014 !*** ./src/ui/settings/types/slider.js ***!
9015 \*****************************************/
9016/*! exports provided: default */
9017/***/ (function(module, __webpack_exports__, __webpack_require__) {
9018
9019"use strict";
9020__webpack_require__.r(__webpack_exports__);
9021/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js");
9022/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
9023
9024
9025
9026//TODO: Documentation
9027
9028/**
9029 * Creates a slider/range using discord's built in slider.
9030 * @memberof module:Settings
9031 * @version 0.1.0
9032 * @extends module:Settings.SettingField
9033 */
9034class Slider extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] {
9035 /**
9036 *
9037 * @param {string} name - name label of the setting
9038 * @param {string} note - help/note to show underneath or above the setting
9039 * @param {number} min - minimum value allowed
9040 * @param {number} max - maximum value allowed
9041 * @param {number} value - currently selected value
9042 * @param {callable} onChange - callback to fire when setting is changed, callback receives number
9043 * @param {object} [options] - object of options to give to the setting
9044 * @param {boolean} [options.disabled=false] - should the setting be disabled
9045 * @param {object} [options.fillStyles] - object of css styles to add to active slider
9046 * @param {Array<number>} [options.markers] - array of vertical markers to show on the slider
9047 * @param {boolean} [options.stickToMarkers] - should the slider be forced to use markers
9048 * @param {boolean} [options.equidistant] - should the markers be scaled to be equidistant
9049 */
9050 constructor(name, note, min, max, value, onChange, options = {}) {
9051 const props = {
9052 onChange: _ => _,
9053 initialValue: value,
9054 disabled: options.disabled ? true : false,
9055 minValue: min,
9056 maxValue: max,
9057 handleSize: 10
9058 };
9059 if (options.fillStyles) props.fillStyles = options.fillStyles;
9060 if (options.markers) props.markers = options.markers;
9061 if (options.stickToMarkers) props.stickToMarkers = options.stickToMarkers;
9062 if (typeof(options.equidistant) != "undefined") props.equidistant = options.equidistant;
9063 super(name, note, onChange, modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].Slider, Object.assign(props, {onValueChange: v => this.onChange(v)}));
9064 }
9065}
9066
9067/* harmony default export */ __webpack_exports__["default"] = (Slider);
9068
9069/***/ }),
9070
9071/***/ "./src/ui/settings/types/switch.js":
9072/*!*****************************************!*\
9073 !*** ./src/ui/settings/types/switch.js ***!
9074 \*****************************************/
9075/*! exports provided: default */
9076/***/ (function(module, __webpack_exports__, __webpack_require__) {
9077
9078"use strict";
9079__webpack_require__.r(__webpack_exports__);
9080/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js");
9081/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
9082
9083
9084
9085//TODO: Documentation
9086
9087/**
9088 * Creates a switch using discord's built in switch.
9089 * @memberof module:Settings
9090 * @version 0.1.0
9091 * @extends module:Settings.SettingField
9092 */
9093class Switch extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] {
9094 /**
9095 * @param {string} name - name label of the setting
9096 * @param {string} note - help/note to show underneath or above the setting
9097 * @param {boolean} isChecked - should switch be checked
9098 * @param {callable} onChange - callback to perform on setting change, callback receives boolean
9099 * @param {object} [options] - object of options to give to the setting
9100 * @param {boolean} [options.disabled=false] - should the setting be disabled
9101 */
9102 constructor(name, note, isChecked, onChange, options = {}) {
9103 super(name, note, onChange);
9104 this.disabled = options.disabled ? true : false;
9105 this.value = isChecked ? true : false;
9106 }
9107
9108 onAdded() {
9109 const reactElement = modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].ReactDOM.render(modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].React.createElement(modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].SwitchRow, {
9110 children: this.name,
9111 note: this.note,
9112 disabled: this.disabled,
9113 hideBorder: false,
9114 value: this.value,
9115 onChange: (e) => {
9116 const checked = e.currentTarget.checked;
9117 reactElement.props.value = checked;
9118 reactElement.forceUpdate();
9119 this.onChange(checked);
9120 }
9121 }), this.getElement());
9122 }
9123}
9124
9125/* harmony default export */ __webpack_exports__["default"] = (Switch);
9126
9127/***/ }),
9128
9129/***/ "./src/ui/settings/types/textbox.js":
9130/*!******************************************!*\
9131 !*** ./src/ui/settings/types/textbox.js ***!
9132 \******************************************/
9133/*! exports provided: default */
9134/***/ (function(module, __webpack_exports__, __webpack_require__) {
9135
9136"use strict";
9137__webpack_require__.r(__webpack_exports__);
9138/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js");
9139/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
9140
9141
9142
9143//TODO: Documentation
9144
9145/**
9146 * Creates a textbox using discord's built in textbox.
9147 * @memberof module:Settings
9148 * @version 0.1.0
9149 * @extends module:Settings.SettingField
9150 */
9151class Textbox extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] {
9152 /**
9153 * @param {string} name - name label of the setting
9154 * @param {string} note - help/note to show underneath or above the setting
9155 * @param {string} value - current text in box
9156 * @param {callable} onChange - callback to perform on setting change, callback receives text
9157 * @param {object} [options] - object of options to give to the setting
9158 * @param {string} [options.placeholder=""] - placeholder for when textbox is empty
9159 * @param {boolean} [options.disabled=false] - should the setting be disabled
9160 */
9161 constructor(name, note, value, onChange, options = {}) {
9162 const {placeholder = "", disabled=false} = options;
9163 super(name, note, onChange, modules__WEBPACK_IMPORTED_MODULE_1__["DiscordModules"].Textbox, {
9164 onChange: textbox => value => {
9165 textbox.props.value = value;
9166 textbox.forceUpdate();
9167 this.onChange(value);
9168 },
9169 value: value,
9170 disabled: disabled,
9171 placeholder: placeholder || ""
9172 });
9173 }
9174}
9175
9176/* harmony default export */ __webpack_exports__["default"] = (Textbox);
9177
9178/***/ }),
9179
9180/***/ "./src/ui/toasts.js":
9181/*!**************************!*\
9182 !*** ./src/ui/toasts.js ***!
9183 \**************************/
9184/*! exports provided: default */
9185/***/ (function(module, __webpack_exports__, __webpack_require__) {
9186
9187"use strict";
9188__webpack_require__.r(__webpack_exports__);
9189/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return Toast; });
9190/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
9191/* harmony import */ var ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ui */ "./src/ui/ui.js");
9192/**
9193 * Toast maker similar to Android.
9194 *
9195 * @module Toasts
9196 * @version 0.0.1
9197 */
9198
9199
9200
9201class Toast {
9202
9203 static get CSS() {return __webpack_require__(/*! ../styles/toasts.css */ "./src/styles/toasts.css");}
9204
9205 /** Shorthand for `type = "success"` for {@link module:Toasts.show} */
9206 static async success(content, options = {}) {return this.show(content, Object.assign(options, {type: "success"}));}
9207
9208 /** Shorthand for `type = "info"` for {@link module:Toasts.show} */
9209 static async info(content, options = {}) {return this.show(content, Object.assign(options, {type: "info"}));}
9210
9211 /** Shorthand for `type = "warning"` for {@link module:Toasts.show} */
9212 static async warning(content, options = {}) {return this.show(content, Object.assign(options, {type: "warning"}));}
9213
9214 /** Shorthand for `type = "error"` for {@link module:Toasts.show} */
9215 static async error(content, options = {}) {return this.show(content, Object.assign(options, {type: "error"}));}
9216
9217 /** Shorthand for `type = "default"` for {@link module:Toasts.show} */
9218 static async default(content, options = {}) {return this.show(content, Object.assign(options, {type: "default"}));}
9219
9220
9221 /**
9222 * Shows a simple toast, similar to Android, centered over
9223 * the textarea if it exists, and center screen otherwise.
9224 * Vertically it shows towards the bottom like in Android.
9225 * @param {string} content - The string to show in the toast.
9226 * @param {object} options - additional options for the toast
9227 * @param {string} [options.type] - Changes the type of the toast stylistically and semantically. {@link module:Toasts.ToastTypes}
9228 * @param {string} [options.icon] - URL to an optional icon
9229 * @param {number} [options.timeout=3000] - Adjusts the time (in ms) the toast should be shown for before disappearing automatically
9230 * @returns {Promise} - Promise that resolves when the toast is removed from the DOM
9231 */
9232 static async show(content, options = {}) {
9233 const {type = "", icon = "", timeout = 3000} = options;
9234 this.ensureContainer();
9235 const toast = modules__WEBPACK_IMPORTED_MODULE_0__["DOMTools"].parseHTML(this.buildToast(content, this.parseType(type), icon));
9236 document.querySelector(".toasts").appendChild(toast);
9237 await new Promise(resolve => setTimeout(resolve, timeout));
9238 toast.classList.add("closing");
9239 await new Promise(resolve => setTimeout(resolve, 300));
9240 toast.remove();
9241 if (!document.querySelectorAll(".toasts .toast").length) document.querySelector(".toasts").remove();
9242 }
9243
9244 static buildToast(message, type, icon) {
9245 const hasIcon = type || icon;
9246 const className = `toast ${hasIcon ? "toast-has-icon" : ""} ${type && type != "default" ? `toast-${type}` : ""}`;
9247 if (!icon && type) icon = type;
9248 return modules__WEBPACK_IMPORTED_MODULE_0__["Utilities"].formatString(`<div class="{{className}}">{{icon}}<div class="toast-text">{{message}}</div></div>`, {
9249 className: className,
9250 icon: hasIcon ? this.getIcon(icon) : "",
9251 message: message
9252 });
9253 }
9254
9255 static getIcon(icon) {
9256 let iconInner = `<img src="${icon}" width="20" height="20" />`;
9257 switch (icon) {
9258 case "success": iconInner = ui__WEBPACK_IMPORTED_MODULE_1__["Icons"].IconSuccess(20); break;
9259 case "warning": iconInner = ui__WEBPACK_IMPORTED_MODULE_1__["Icons"].IconWarning(20); break;
9260 case "info": iconInner = ui__WEBPACK_IMPORTED_MODULE_1__["Icons"].IconInfo(20); break;
9261 case "error": iconInner = ui__WEBPACK_IMPORTED_MODULE_1__["Icons"].IconError(20);
9262 }
9263 return modules__WEBPACK_IMPORTED_MODULE_0__["Utilities"].formatString(`<div class="toast-icon">{{icon}}</div>`, {icon: iconInner});
9264 }
9265
9266 static ensureContainer() {
9267 if (document.querySelector(".toasts")) return;
9268 const channelClass = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordSelectors"].ChannelList.sidebar;
9269 const container = channelClass ? document.querySelector(channelClass.adjacent("div")) : null;
9270 const memberlist = container ? container.querySelector(modules__WEBPACK_IMPORTED_MODULE_0__["DiscordSelectors"].MemberList.membersWrap) : null;
9271 const form = container ? container.querySelector("form") : null;
9272 const left = container ? container.getBoundingClientRect().left : 310;
9273 const right = memberlist ? memberlist.getBoundingClientRect().left : 0;
9274 const width = right ? right - container.getBoundingClientRect().left : container.offsetWidth;
9275 const bottom = form ? form.offsetHeight : 80;
9276 const toastWrapper = document.createElement("div");
9277 toastWrapper.classList.add("toasts");
9278 toastWrapper.style.setProperty("left", left + "px");
9279 toastWrapper.style.setProperty("width", width + "px");
9280 toastWrapper.style.setProperty("bottom", bottom + "px");
9281 document.querySelector("#app-mount").appendChild(toastWrapper);
9282 }
9283
9284 static parseType(type) {
9285 return this.ToastTypes.hasOwnProperty(type) ? this.ToastTypes[type] : "";
9286 }
9287
9288 /**
9289 * Enumeration of accepted types.
9290 */
9291 static get ToastTypes() {
9292 return {
9293 "default": "",
9294 "error": "error",
9295 "success": "success",
9296 "warning": "warning",
9297 "info": "info"
9298 };
9299 }
9300}
9301
9302/***/ }),
9303
9304/***/ "./src/ui/tooltip.js":
9305/*!***************************!*\
9306 !*** ./src/ui/tooltip.js ***!
9307 \***************************/
9308/*! exports provided: default */
9309/***/ (function(module, __webpack_exports__, __webpack_require__) {
9310
9311"use strict";
9312__webpack_require__.r(__webpack_exports__);
9313/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return Tooltip; });
9314/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js");
9315/* harmony import */ var _structs_screen__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../structs/screen */ "./src/structs/screen.js");
9316/**
9317 * Tooltips that automatically show and hide themselves on mouseenter and mouseleave events.
9318 * Will also remove themselves if the node to watch is removed from DOM through
9319 * a MutationObserver.
9320 *
9321 * @module Tooltip
9322 * @version 0.0.2
9323 */
9324
9325
9326
9327
9328class Tooltip {
9329 /**
9330 *
9331 * @constructor
9332 * @param {(HTMLElement|jQuery)} node - DOM node to monitor and show the tooltip on
9333 * @param {string} tip - string to show in the tooltip
9334 * @param {object} options - additional options for the tooltip
9335 * @param {string} [options.style=black] - correlates to the discord styling
9336 * @param {string} [options.side=top] - can be any of top, right, bottom, left
9337 * @param {boolean} [options.preventFlip=false] - prevents moving the tooltip to the opposite side if it is too big or goes offscreen
9338 * @param {boolean} [options.disabled=false] - whether the tooltip should be disabled from showing on hover
9339 */
9340 constructor(node, text, options = {}) {
9341 if (!(node instanceof jQuery) && !(node instanceof Element)) return undefined;
9342 this.node = node instanceof jQuery ? node[0] : node;
9343 const {style = "black", side = "top", disabled = false} = options;
9344 this.label = text;
9345 this.style = style;
9346 this.side = side;
9347 this.disabled = disabled;
9348 this.id = modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].KeyGenerator();
9349
9350 this.node.addEventListener("mouseenter", () => {
9351 if (this.disabled) return;
9352 this.show();
9353
9354 const observer = new MutationObserver((mutations) => {
9355 mutations.forEach((mutation) => {
9356 const nodes = Array.from(mutation.removedNodes);
9357 const directMatch = nodes.indexOf(this.node) > -1;
9358 const parentMatch = nodes.some(parent => parent.contains(this.node));
9359 if (directMatch || parentMatch) {
9360 this.hide();
9361 observer.disconnect();
9362 }
9363 });
9364 });
9365
9366 observer.observe(document.body, {subtree: true, childList: true});
9367 });
9368
9369 this.node.addEventListener("mouseleave", () => {
9370 this.hide();
9371 });
9372 }
9373
9374 /**
9375 * Disabled the tooltip and prevents it from showing on hover.
9376 */
9377 disable() {
9378 this.disabled = true;
9379 }
9380
9381 /**
9382 * Enables the tooltip and allows it to show on hover.
9383 */
9384 enable() {
9385 this.disabled = false;
9386 }
9387
9388 /** Hides the tooltip. Automatically called on mouseleave. */
9389 hide() {
9390 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].Tooltips.hide(this.id);
9391 }
9392
9393 /** Shows the tooltip. Automatically called on mouseenter. */
9394 show() {
9395 const {left, top, width, height} = this.node.getBoundingClientRect();
9396 modules__WEBPACK_IMPORTED_MODULE_0__["DiscordModules"].Tooltips.show(this.id, {
9397 position: this.side,
9398 text: this.label,
9399 color: this.style,
9400 targetWidth: width,
9401 targetHeight: height,
9402 windowWidth: _structs_screen__WEBPACK_IMPORTED_MODULE_1__["default"].width,
9403 windowHeight: _structs_screen__WEBPACK_IMPORTED_MODULE_1__["default"].height,
9404 x: left,
9405 y: top
9406 });
9407 }
9408}
9409
9410/***/ }),
9411
9412/***/ "./src/ui/ui.js":
9413/*!**********************!*\
9414 !*** ./src/ui/ui.js ***!
9415 \**********************/
9416/*! exports provided: Tooltip, EmulatedTooltip, Toasts, Popouts, Modals, DiscordContextMenu, Settings, ContextMenu, Icons */
9417/***/ (function(module, __webpack_exports__, __webpack_require__) {
9418
9419"use strict";
9420__webpack_require__.r(__webpack_exports__);
9421/* harmony import */ var _settings__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./settings */ "./src/ui/settings/index.js");
9422/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "Settings", function() { return _settings__WEBPACK_IMPORTED_MODULE_0__; });
9423/* harmony import */ var _contextmenu__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./contextmenu */ "./src/ui/contextmenu.js");
9424/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "ContextMenu", function() { return _contextmenu__WEBPACK_IMPORTED_MODULE_1__; });
9425/* harmony import */ var _icons__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./icons */ "./src/ui/icons.js");
9426/* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "Icons", function() { return _icons__WEBPACK_IMPORTED_MODULE_2__; });
9427/* harmony import */ var _tooltip__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./tooltip */ "./src/ui/tooltip.js");
9428/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Tooltip", function() { return _tooltip__WEBPACK_IMPORTED_MODULE_3__["default"]; });
9429
9430/* harmony import */ var _emulatedtooltip__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./emulatedtooltip */ "./src/ui/emulatedtooltip.js");
9431/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "EmulatedTooltip", function() { return _emulatedtooltip__WEBPACK_IMPORTED_MODULE_4__["default"]; });
9432
9433/* harmony import */ var _toasts__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./toasts */ "./src/ui/toasts.js");
9434/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Toasts", function() { return _toasts__WEBPACK_IMPORTED_MODULE_5__["default"]; });
9435
9436/* harmony import */ var _popouts__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./popouts */ "./src/ui/popouts.js");
9437/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Popouts", function() { return _popouts__WEBPACK_IMPORTED_MODULE_6__["default"]; });
9438
9439/* harmony import */ var _modals__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./modals */ "./src/ui/modals.js");
9440/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Modals", function() { return _modals__WEBPACK_IMPORTED_MODULE_7__["default"]; });
9441
9442/* harmony import */ var _discordcontextmenu__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./discordcontextmenu */ "./src/ui/discordcontextmenu.js");
9443/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "DiscordContextMenu", function() { return _discordcontextmenu__WEBPACK_IMPORTED_MODULE_8__["default"]; });
9444
9445
9446
9447
9448
9449
9450
9451
9452
9453
9454
9455
9456
9457/***/ }),
9458
9459/***/ "electron":
9460/*!***********************************************!*\
9461 !*** external "window.require(\"electron\")" ***!
9462 \***********************************************/
9463/*! no static exports found */
9464/***/ (function(module, exports) {
9465
9466module.exports = window.require("electron");
9467
9468/***/ }),
9469
9470/***/ "fs":
9471/*!*****************************************!*\
9472 !*** external "window.require(\"fs\")" ***!
9473 \*****************************************/
9474/*! no static exports found */
9475/***/ (function(module, exports) {
9476
9477module.exports = window.require("fs");
9478
9479/***/ }),
9480
9481/***/ "path":
9482/*!*******************************************!*\
9483 !*** external "window.require(\"path\")" ***!
9484 \*******************************************/
9485/*! no static exports found */
9486/***/ (function(module, exports) {
9487
9488module.exports = window.require("path");
9489
9490/***/ }),
9491
9492/***/ "process":
9493/*!**************************!*\
9494 !*** external "process" ***!
9495 \**************************/
9496/*! no static exports found */
9497/***/ (function(module, exports) {
9498
9499module.exports = require("process");
9500
9501/***/ }),
9502
9503/***/ "request":
9504/*!**********************************************!*\
9505 !*** external "window.require(\"request\")" ***!
9506 \**********************************************/
9507/*! no static exports found */
9508/***/ (function(module, exports) {
9509
9510module.exports = window.require("request");
9511
9512/***/ })
9513
9514/******/ })["default"];
9515/*@end@*/