Compare commits
106 Commits
v2.0.0-bet
...
master
Author | SHA1 | Date |
---|---|---|
Alexei Stukov | 835cc3134c | |
Jiiks | 02b30153ee | |
Alexei Stukov | d09dc5a2a5 | |
Mega-Mewthree | 98d9a30027 | |
Alexei Stukov | 5cb4bc15bd | |
Alexei Stukov | bb2aba04d5 | |
Samuel Elliott | 82e9b0bd6a | |
Samuel Elliott | 47575d3449 | |
Samuel Elliott | 32e2582ded | |
Samuel Elliott | d58dda6f50 | |
Samuel Elliott | 648954d533 | |
Samuel Elliott | 4aa38f4582 | |
Samuel Elliott | b3ba1aef13 | |
Samuel Elliott | 2a6cbd39b7 | |
Samuel Elliott | ce5bcb9b85 | |
Samuel Elliott | 5a3821ad3e | |
Samuel Elliott | fd0032b24c | |
Samuel Elliott | 226719b36e | |
Samuel Elliott | fcfee53928 | |
Samuel Elliott | 285ae34b50 | |
Alexei Stukov | a170a97688 | |
Samuel Elliott | a770f57b28 | |
Samuel Elliott | 5757fc20c9 | |
Samuel Elliott | 421289f63b | |
Samuel Elliott | ac85316578 | |
Samuel Elliott | 08af9be061 | |
Samuel Elliott | ead0fbbd1e | |
Samuel Elliott | dc85a808f8 | |
Samuel Elliott | aecfa814f9 | |
Samuel Elliott | 436f3d3c36 | |
Alexei Stukov | 68a8187964 | |
Alexei Stukov | f30e4c12fe | |
Alexei Stukov | 686514ed1d | |
Alexei Stukov | d795da1750 | |
Alexei Stukov | 3219ff7c6e | |
Alexei Stukov | 33567a2cfd | |
Jiiks | 85310bfbff | |
Jiiks | d1d79a37b7 | |
Jiiks | d95592acc9 | |
Jiiks | f6a3fb65da | |
Alexei Stukov | 6788cca363 | |
Lars van der Zande | 1fb442e096 | |
Jiiks | 6e64ff61c5 | |
Jiiks | dd8fe68a11 | |
Jiiks | a3829089f9 | |
Jiiks | 174c1ee791 | |
Jiiks | b8793fd2b6 | |
Jiiks | 31986ca3a0 | |
Jiiks | 10ff740f75 | |
Jiiks | 83fbab63c0 | |
Jiiks | c4670946e6 | |
Jiiks | e5239d952e | |
Jiiks | a57783a9d8 | |
Jiiks | 001a6e4fda | |
Jiiks | dd621038f9 | |
Jiiks | 288c233447 | |
Jiiks | 399c6e792b | |
Jiiks | 0be6facba4 | |
Jiiks | dc7247a12d | |
Jiiks | 377c4fd104 | |
Jiiks | 252d496dc2 | |
Jiiks | 83e334c3f8 | |
Jiiks | e72ad10dfc | |
Jiiks | 9ef392c575 | |
Jiiks | 76057efbb7 | |
Jiiks | dcb121750a | |
Jiiks | 13fa769e9e | |
Jiiks | 3143991239 | |
Jiiks | 1ae0c5aa4d | |
Jiiks | 5ea39f86f7 | |
Jiiks | d6a946e096 | |
Jiiks | b68c1fbd04 | |
Jiiks | 07d3629622 | |
Jiiks | 15daa9acef | |
Jiiks | 817a4a03b6 | |
Jiiks | e63386e9eb | |
Jiiks | 402acdfea9 | |
Jiiks | b440206d07 | |
Jiiks | c7bea4a743 | |
Jiiks | 2528d87b8f | |
Alexei Stukov | 405d74fada | |
Alexei Stukov | b311220132 | |
Alexei Stukov | 66b47457b1 | |
Alexei Stukov | 6e9f9f8bf8 | |
Alexei Stukov | 88a113dc8f | |
Alexei Stukov | a61f860466 | |
Jiiks | 729a4607bd | |
Jiiks | d81dcc9aa2 | |
Jiiks | 1e4f3fa82b | |
Alexei Stukov | 150a1d63c4 | |
Jiiks | 6b481733b9 | |
Jiiks | e07b9b1550 | |
Jiiks | 99c2b53ec6 | |
Jiiks | 2a93e5d2a3 | |
Jiiks | 3661207602 | |
Jiiks | 92845728cc | |
Jiiks | c99753fc8c | |
Jiiks | 688e6022a0 | |
Jiiks | 5408d994be | |
Zack Rauen | 003c9766bc | |
Zack Rauen | 82e9c257ce | |
Jiiks | 6167cc7c4b | |
Jiiks | 1bacecf8d4 | |
Jiiks | d102686379 | |
Jiiks | 1160955629 | |
Jiiks | e60f765a50 |
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: "[Bug]"
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [ ] Used appropriate template for the issue type
|
||||||
|
- [ ] Searched both open and closed issues for duplicates of this issue
|
||||||
|
- [ ] Title adequately and _concisely_ reflects the feature or the bug
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
<!-- A clear and concise description of what the bug is. -->
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
<!-- Steps to reproduce the behavior -->
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
<!-- A clear and concise description of what you expected to happen. -->
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||||
|
|
||||||
|
**System information**
|
||||||
|
<!-- os, discord branch etc -->
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
<!-- Add any other context about the problem here. -->
|
||||||
|
|
||||||
|
**Are you willing and able to fix this?**
|
||||||
|
<!-- "Yes" or, if "no", what can current contributors do to help you create a PR? -->
|
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
name: Custom issue template
|
||||||
|
about: Describe this issue template's purpose here.
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [ ] Used appropriate template for the issue type
|
||||||
|
- [ ] Searched both open and closed issues for duplicates of this issue
|
||||||
|
- [ ] Title adequately and _concisely_ reflects the feature or the bug
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: "[Feature]"
|
||||||
|
labels: feature
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- [ ] Used appropriate template for the issue type
|
||||||
|
- [ ] Searched both open and closed issues for duplicates of this issue
|
||||||
|
- [ ] Title adequately and _concisely_ reflects the feature or the bug
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
<!-- A clear and concise description of what you want to happen. -->
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
<!-- Add any other context or screenshots about the feature request here. -->
|
||||||
|
|
||||||
|
**Are you willing and able to implement this?**
|
||||||
|
<!-- "Yes" or, if "no", what can current contributors do to help you create a PR? -->
|
|
@ -4,6 +4,7 @@ dist
|
||||||
etc
|
etc
|
||||||
release
|
release
|
||||||
|
|
||||||
|
tests/tmp
|
||||||
tests/log.txt
|
tests/log.txt
|
||||||
|
|
||||||
# User data
|
# User data
|
||||||
|
|
10
README.md
10
README.md
|
@ -1,4 +1,12 @@
|
||||||
# BetterDiscordApp [![Travis][build-badge]][build]
|
# BetterDiscordApp [![Travis][build-badge]][build] [![Snyk][snyk-badge]][snyk-url] [![deps][deps-badge]][deps-url] [![devdeps][devdeps-badge]][devdeps-url]
|
||||||
|
|
||||||
[build-badge]: https://img.shields.io/travis/JsSucks/BetterDiscordApp/master.svg
|
[build-badge]: https://img.shields.io/travis/JsSucks/BetterDiscordApp/master.svg
|
||||||
[build]: https://travis-ci.org/JsSucks/BetterDiscordApp
|
[build]: https://travis-ci.org/JsSucks/BetterDiscordApp
|
||||||
|
|
||||||
|
[snyk-badge]: https://snyk.io/test/github/JsSucks/BetterDiscordApp/badge.svg
|
||||||
|
[snyk-url]: https://snyk.io/test/github/JsSucks/BetterDiscordApp
|
||||||
|
|
||||||
|
[deps-badge]: https://david-dm.org/JsSucks/BetterDiscordApp.svg
|
||||||
|
[deps-url]: https://david-dm.org/JsSucks/BetterDiscordApp
|
||||||
|
[devdeps-badge]: https://david-dm.org/JsSucks/BetterDiscordApp/dev-status.svg
|
||||||
|
[devdeps-url]: https://david-dm.org/JsSucks/BetterDiscordApp?type=dev
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
module.exports = function(api) {
|
||||||
|
|
||||||
|
api.cache(true);
|
||||||
|
|
||||||
|
const presets = [['@babel/env', {
|
||||||
|
targets: {
|
||||||
|
'node': '8.6.0'
|
||||||
|
}
|
||||||
|
}]];
|
||||||
|
|
||||||
|
const plugins = [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
presets,
|
||||||
|
plugins
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
module.exports = function(api) {
|
||||||
|
|
||||||
|
api.cache(true);
|
||||||
|
|
||||||
|
const presets = [['@babel/env', {
|
||||||
|
targets: {
|
||||||
|
'node': '8.6.0',
|
||||||
|
'chrome': '60'
|
||||||
|
}
|
||||||
|
}], '@babel/react'];
|
||||||
|
|
||||||
|
const plugins = [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
presets,
|
||||||
|
plugins
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "bdclient",
|
"name": "bdclient",
|
||||||
"description": "BetterDiscord client package",
|
"description": "BetterDiscord client package",
|
||||||
"author": "Jiiks",
|
"author": "Jiiks",
|
||||||
"version": "2.0.0b",
|
"version": "2.0.0-beta.6",
|
||||||
"homepage": "https://betterdiscord.net",
|
"homepage": "https://betterdiscord.net",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/betterdiscord.client.js",
|
"main": "dist/betterdiscord.client.js",
|
||||||
|
|
|
@ -21,7 +21,7 @@ export default new class BlockedMessages extends BuiltinModule {
|
||||||
async enabled(e) {
|
async enabled(e) {
|
||||||
const MessageListComponents = Reflection.module.byProps('BlockedMessageGroup');
|
const MessageListComponents = Reflection.module.byProps('BlockedMessageGroup');
|
||||||
MessageListComponents.OriginalBlockedMessageGroup = MessageListComponents.BlockedMessageGroup;
|
MessageListComponents.OriginalBlockedMessageGroup = MessageListComponents.BlockedMessageGroup;
|
||||||
MessageListComponents.BlockedMessageGroup = () => { return null; };
|
MessageListComponents.BlockedMessageGroup = () => null;
|
||||||
this.cancelBlockedMessages = () => {
|
this.cancelBlockedMessages = () => {
|
||||||
MessageListComponents.BlockedMessageGroup = MessageListComponents.OriginalBlockedMessageGroup;
|
MessageListComponents.BlockedMessageGroup = MessageListComponents.OriginalBlockedMessageGroup;
|
||||||
delete MessageListComponents.OriginalBlockedMessageGroup;
|
delete MessageListComponents.OriginalBlockedMessageGroup;
|
||||||
|
|
|
@ -22,10 +22,10 @@ export default class BuiltinModule {
|
||||||
this.patch = this.patch.bind(this);
|
this.patch = this.patch.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
async init() {
|
||||||
this.setting.on('setting-updated', this._settingUpdated);
|
this.setting.on('setting-updated', this._settingUpdated);
|
||||||
if (this.setting.value) {
|
if (this.setting.value) {
|
||||||
if (this.enabled) this.enabled();
|
if (this.enabled) await this.enabled();
|
||||||
if (this.applyPatches) this.applyPatches();
|
if (this.applyPatches) this.applyPatches();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,16 +38,15 @@ export default class BuiltinModule {
|
||||||
return Patcher.getPatchesByCaller(`BD:${this.moduleName}`);
|
return Patcher.getPatchesByCaller(`BD:${this.moduleName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
_settingUpdated(e) {
|
async _settingUpdated(e) {
|
||||||
const { value } = e;
|
if (e.value) {
|
||||||
if (value === true) {
|
if (this.enabled) await this.enabled(e);
|
||||||
if (this.enabled) this.enabled(e);
|
if (this.applyPatches) await this.applyPatches();
|
||||||
if (this.applyPatches) this.applyPatches();
|
if (this.rerenderPatchedComponents) this.rerenderPatchedComponents();
|
||||||
return;
|
} else {
|
||||||
}
|
if (this.disabled) await this.disabled(e);
|
||||||
if (value === false) {
|
|
||||||
if (this.disabled) this.disabled(e);
|
|
||||||
this.unpatch();
|
this.unpatch();
|
||||||
|
if (this.rerenderPatchedComponents) this.rerenderPatchedComponents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +74,14 @@ export default class BuiltinModule {
|
||||||
*/
|
*/
|
||||||
patch(module, fnName, cb, when = 'after') {
|
patch(module, fnName, cb, when = 'after') {
|
||||||
if (!['before', 'after', 'instead'].includes(when)) when = 'after';
|
if (!['before', 'after', 'instead'].includes(when)) when = 'after';
|
||||||
Patch(`BD:${this.moduleName}`, module)[when](fnName, cb.bind(this));
|
return Patch(`BD:${this.moduleName}`, module)[when](fnName, cb.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
childPatch(module, fnName, child, cb, when = 'after') {
|
childPatch(module, fnName, child, cb, when = 'after') {
|
||||||
|
const last = child.pop();
|
||||||
|
|
||||||
this.patch(module, fnName, (component, args, retVal) => {
|
this.patch(module, fnName, (component, args, retVal) => {
|
||||||
this.patch(retVal[child[0]], child[1], cb, when);
|
const unpatch = this.patch(child.reduce((obj, key) => obj[key], retVal), last, function(...args) {unpatch(); return cb.call(this, component, ...args);}, when);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,10 @@ export default new class ColoredText extends BuiltinModule {
|
||||||
this.intensitySetting.off('setting-updated', this._intensityUpdated);
|
this.intensitySetting.off('setting-updated', this._intensityUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rerenderPatchedComponents() {
|
||||||
|
if (this.MessageContent) this.MessageContent.forceUpdateAll();
|
||||||
|
}
|
||||||
|
|
||||||
/* Methods */
|
/* Methods */
|
||||||
_intensityUpdated() {
|
_intensityUpdated() {
|
||||||
this.MessageContent.forceUpdateAll();
|
this.MessageContent.forceUpdateAll();
|
||||||
|
@ -50,16 +54,16 @@ export default new class ColoredText extends BuiltinModule {
|
||||||
/* Patches */
|
/* Patches */
|
||||||
async applyPatches() {
|
async applyPatches() {
|
||||||
if (this.patches.length) return;
|
if (this.patches.length) return;
|
||||||
this.MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector }, m => m.defaultProps && m.defaultProps.hasOwnProperty('disableButtons'));
|
this.MessageContent = await ReactComponents.getComponent('MessageContent');
|
||||||
this.patch(this.MessageContent.component.prototype, 'render', this.injectColoredText);
|
this.patch(this.MessageContent.component.prototype, 'render', this.injectColoredText);
|
||||||
this.MessageContent.forceUpdateAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set markup text colour to match role colour
|
* Set markup text colour to match role colour
|
||||||
*/
|
*/
|
||||||
injectColoredText(thisObject, args, originalReturn) {
|
injectColoredText(thisObject, args, originalReturn) {
|
||||||
this.patch(originalReturn.props, 'children', function(obj, args, returnValue) {
|
const unpatch = this.patch(originalReturn.props, 'children', (obj, args, returnValue) => {
|
||||||
|
unpatch();
|
||||||
const { TinyColor } = Reflection.modules;
|
const { TinyColor } = Reflection.modules;
|
||||||
const markup = Utils.findInReactTree(returnValue, m => m && m.props && m.props.className && m.props.className.includes('da-markup'));
|
const markup = Utils.findInReactTree(returnValue, m => m && m.props && m.props.className && m.props.className.includes('da-markup'));
|
||||||
const roleColor = thisObject.props.message.colorString;
|
const roleColor = thisObject.props.message.colorString;
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings, Cache, Events } from 'modules';
|
import { Settings, Cache, Events } from 'modules';
|
||||||
import BuiltinModule from './BuiltinModule';
|
import BuiltinModule from '../BuiltinModule';
|
||||||
import { Reflection, ReactComponents, MonkeyPatch, Patcher, DiscordApi, Security } from 'modules';
|
import { Reflection, ReactComponents, DiscordApi, Security } from 'modules';
|
||||||
import { VueInjector, Modals, Toasts } from 'ui';
|
import { VueInjector, Modals, Toasts } from 'ui';
|
||||||
import { ClientLogger as Logger, ClientIPC } from 'common';
|
import { ClientLogger as Logger, ClientIPC } from 'common';
|
||||||
import { request } from 'vendor';
|
import { request } from 'vendor';
|
||||||
|
@ -172,7 +172,7 @@ export default new class E2EE extends BuiltinModule {
|
||||||
this.patch(Dispatcher, 'dispatch', this.dispatcherPatch, 'before');
|
this.patch(Dispatcher, 'dispatch', this.dispatcherPatch, 'before');
|
||||||
this.patchMessageContent();
|
this.patchMessageContent();
|
||||||
|
|
||||||
const ChannelTextArea = await ReactComponents.getComponent('ChannelTextArea', { selector: Reflection.resolve('channelTextArea', 'emojiButton').selector });
|
const ChannelTextArea = await ReactComponents.getComponent('ChannelTextArea');
|
||||||
this.patchChannelTextArea(ChannelTextArea);
|
this.patchChannelTextArea(ChannelTextArea);
|
||||||
this.patchChannelTextAreaSubmit(ChannelTextArea);
|
this.patchChannelTextAreaSubmit(ChannelTextArea);
|
||||||
ChannelTextArea.forceUpdateAll();
|
ChannelTextArea.forceUpdateAll();
|
||||||
|
@ -236,12 +236,14 @@ export default new class E2EE extends BuiltinModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
async patchMessageContent() {
|
async patchMessageContent() {
|
||||||
const MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector }, m => m.defaultProps && m.defaultProps.hasOwnProperty('disableButtons'));
|
const MessageContent = await ReactComponents.getComponent('MessageContent');
|
||||||
this.patch(MessageContent.component.prototype, 'render', this.beforeRenderMessageContent, 'before');
|
this.patch(MessageContent.component.prototype, 'render', this.beforeRenderMessageContent, 'before');
|
||||||
this.patch(MessageContent.component.prototype, 'render', this.afterRenderMessageContent);
|
this.childPatch(MessageContent.component.prototype, 'render', ['props', 'children'], this.afterRenderMessageContent);
|
||||||
|
MessageContent.forceUpdateAll();
|
||||||
|
|
||||||
const ImageWrapper = await ReactComponents.getComponent('ImageWrapper', { selector: Reflection.resolve('imageWrapper').selector });
|
const ImageWrapper = await ReactComponents.getComponent('ImageWrapper');
|
||||||
this.patch(ImageWrapper.component.prototype, 'render', this.beforeRenderImageWrapper, 'before');
|
this.patch(ImageWrapper.component.prototype, 'render', this.beforeRenderImageWrapper, 'before');
|
||||||
|
ImageWrapper.forceUpdateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeRenderMessageContent(component) {
|
beforeRenderMessageContent(component) {
|
||||||
|
@ -285,10 +287,16 @@ export default new class E2EE extends BuiltinModule {
|
||||||
component.props.message.contentParsed = create.contentParsed;
|
component.props.message.contentParsed = create.contentParsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
afterRenderMessageContent(component, args, retVal) {
|
afterRenderMessageContent(component, _childrenObject, args, retVal) {
|
||||||
if (!component.props.message.bd_encrypted) return;
|
if (!component.props.message.bd_encrypted) return;
|
||||||
const buttons = Utils.findInReactTree(retVal, m => Array.isArray(m) && m[1].props && m[1].props.currentUserId);
|
|
||||||
|
const { className } = Reflection.resolve('buttonContainer', 'avatar', 'username');
|
||||||
|
const buttonContainer = Utils.findInReactTree(retVal, m => m && m.className && m.className.indexOf(className) !== -1);
|
||||||
|
if (!buttonContainer) return;
|
||||||
|
|
||||||
|
const buttons = buttonContainer.children.props.children;
|
||||||
if (!buttons) return;
|
if (!buttons) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
buttons.unshift(VueInjector.createReactElement(E2EEMessageButton));
|
buttons.unshift(VueInjector.createReactElement(E2EEMessageButton));
|
||||||
} catch (err) {
|
} catch (err) {
|
|
@ -45,7 +45,7 @@
|
||||||
import { E2EE } from 'builtin';
|
import { E2EE } from 'builtin';
|
||||||
import { Settings, DiscordApi, Reflection } from 'modules';
|
import { Settings, DiscordApi, Reflection } from 'modules';
|
||||||
import { Toasts } from 'ui';
|
import { Toasts } from 'ui';
|
||||||
import { MiLock, MiImagePlus, MiIcVpnKey } from '../ui/components/common/MaterialIcon';
|
import { MiLock, MiImagePlus, MiIcVpnKey } from 'commoncomponents';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
|
@ -17,7 +17,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { MiLock } from '../ui/components/common/MaterialIcon';
|
import { MiLock } from 'commoncomponents';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
|
@ -0,0 +1,3 @@
|
||||||
|
export { default as default } from './E2EE';
|
||||||
|
export { default as E2EEComponent } from './E2EEComponent.vue';
|
||||||
|
export { default as E2EEMessageButton } from './E2EEMessageButton.vue';
|
|
@ -9,18 +9,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Settings } from 'modules';
|
import { Settings } from 'modules';
|
||||||
|
import BuiltinModule from '../BuiltinModule';
|
||||||
import BuiltinModule from './BuiltinModule';
|
import EmoteModule, { EMOTE_SOURCES } from './EmoteModule';
|
||||||
import EmoteModule from './EmoteModule';
|
import GlobalAc from 'autocomplete';
|
||||||
import GlobalAc from '../ui/autocomplete';
|
|
||||||
import { BdContextMenu } from 'ui';
|
import { BdContextMenu } from 'ui';
|
||||||
|
|
||||||
const EMOTE_SOURCES = [
|
|
||||||
'https://static-cdn.jtvnw.net/emoticons/v1/:id/1.0',
|
|
||||||
'https://cdn.frankerfacez.com/emoticon/:id/1',
|
|
||||||
'https://cdn.betterttv.net/emote/:id/1x'
|
|
||||||
]
|
|
||||||
|
|
||||||
export default new class EmoteAc extends BuiltinModule {
|
export default new class EmoteAc extends BuiltinModule {
|
||||||
|
|
||||||
/* Getters */
|
/* Getters */
|
|
@ -8,15 +8,10 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import VrWrapper from '../ui/vrwrapper';
|
import VrWrapper from '../../ui/vrwrapper';
|
||||||
|
import { EMOTE_SOURCES } from '.';
|
||||||
import EmoteComponent from './EmoteComponent.vue';
|
import EmoteComponent from './EmoteComponent.vue';
|
||||||
|
|
||||||
const EMOTE_SOURCES = [
|
|
||||||
'https://static-cdn.jtvnw.net/emoticons/v1/:id/1.0',
|
|
||||||
'https://cdn.frankerfacez.com/emoticon/:id/1',
|
|
||||||
'https://cdn.betterttv.net/emote/:id/1x'
|
|
||||||
]
|
|
||||||
|
|
||||||
export default class Emote extends VrWrapper {
|
export default class Emote extends VrWrapper {
|
||||||
|
|
||||||
constructor(type, id, name) {
|
constructor(type, id, name) {
|
|
@ -5,7 +5,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { ClientLogger as Logger } from 'common';
|
import { ClientLogger as Logger } from 'common';
|
||||||
import EmoteModule from './EmoteModule';
|
import EmoteModule from './EmoteModule';
|
||||||
import { MiStar } from '../ui/components/common';
|
import { MiStar } from 'commoncomponents';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
|
@ -8,20 +8,17 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import BuiltinModule from './BuiltinModule';
|
import BuiltinModule from '../BuiltinModule';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { request } from 'vendor';
|
import { request } from 'vendor';
|
||||||
|
|
||||||
import { Utils, FileUtils } from 'common';
|
import { Utils, FileUtils, ClientLogger as Logger } from 'common';
|
||||||
import { DiscordApi, Settings, Globals, Reflection, ReactComponents, Database } from 'modules';
|
import { DiscordApi, Settings, Globals, Reflection, ReactComponents, Database } from 'modules';
|
||||||
import { DiscordContextMenu } from 'ui';
|
import { DiscordContextMenu } from 'ui';
|
||||||
|
|
||||||
import Emote from './EmoteComponent.js';
|
import Emote from './EmoteComponent.js';
|
||||||
import Autocomplete from '../ui/components/common/Autocomplete.vue';
|
|
||||||
|
|
||||||
import GlobalAc from '../ui/autocomplete';
|
export const EMOTE_SOURCES = [
|
||||||
|
|
||||||
const EMOTE_SOURCES = [
|
|
||||||
'https://static-cdn.jtvnw.net/emoticons/v1/:id/1.0',
|
'https://static-cdn.jtvnw.net/emoticons/v1/:id/1.0',
|
||||||
'https://cdn.frankerfacez.com/emoticon/:id/1',
|
'https://cdn.frankerfacez.com/emoticon/:id/1',
|
||||||
'https://cdn.betterttv.net/emote/:id/1x'
|
'https://cdn.betterttv.net/emote/:id/1x'
|
||||||
|
@ -131,6 +128,8 @@ export default new class EmoteModule extends BuiltinModule {
|
||||||
|
|
||||||
this.database.set(id, { id: emote.value.id || value, type });
|
this.database.set(id, { id: emote.value.id || value, type });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.log('EmoteModule', ['Loaded emote database']);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadUserData() {
|
async loadUserData() {
|
||||||
|
@ -218,15 +217,18 @@ export default new class EmoteModule extends BuiltinModule {
|
||||||
async applyPatches() {
|
async applyPatches() {
|
||||||
this.patchMessageContent();
|
this.patchMessageContent();
|
||||||
this.patchSendAndEdit();
|
this.patchSendAndEdit();
|
||||||
const ImageWrapper = await ReactComponents.getComponent('ImageWrapper', { selector: Reflection.resolve('imageWrapper').selector });
|
this.patchSpoiler();
|
||||||
this.patch(ImageWrapper.component.prototype, 'render', this.beforeRenderImageWrapper, 'before');
|
|
||||||
|
const MessageAccessories = await ReactComponents.getComponent('MessageAccessories');
|
||||||
|
this.patch(MessageAccessories.component.prototype, 'render', this.afterRenderMessageAccessories, 'after');
|
||||||
|
MessageAccessories.forceUpdateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patches MessageContent render method
|
* Patches MessageContent render method
|
||||||
*/
|
*/
|
||||||
async patchMessageContent() {
|
async patchMessageContent() {
|
||||||
const MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector }, m => m.defaultProps && m.defaultProps.hasOwnProperty('disableButtons'));
|
const MessageContent = await ReactComponents.getComponent('MessageContent');
|
||||||
this.childPatch(MessageContent.component.prototype, 'render', ['props', 'children'], this.afterRenderMessageContent);
|
this.childPatch(MessageContent.component.prototype, 'render', ['props', 'children'], this.afterRenderMessageContent);
|
||||||
MessageContent.forceUpdateAll();
|
MessageContent.forceUpdateAll();
|
||||||
}
|
}
|
||||||
|
@ -240,10 +242,26 @@ export default new class EmoteModule extends BuiltinModule {
|
||||||
this.patch(MessageActions, 'editMessage', this.handleEditMessage, 'instead');
|
this.patch(MessageActions, 'editMessage', this.handleEditMessage, 'instead');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async patchSpoiler() {
|
||||||
|
const Spoiler = await ReactComponents.getComponent('Spoiler');
|
||||||
|
this.childPatch(Spoiler.component.prototype, 'render', ['props', 'children', 'props', 'children'], this.afterRenderSpoiler);
|
||||||
|
Spoiler.forceUpdateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
afterRenderSpoiler(component, _childrenObject, args, retVal) {
|
||||||
|
const markup = Utils.findInReactTree(retVal, filter =>
|
||||||
|
filter &&
|
||||||
|
filter.className &&
|
||||||
|
filter.className.includes('inlineContent'));
|
||||||
|
if (!markup) return;
|
||||||
|
|
||||||
|
markup.children = this.processMarkup(markup.children);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle message render
|
* Handle message render
|
||||||
*/
|
*/
|
||||||
afterRenderMessageContent(component, args, retVal) {
|
afterRenderMessageContent(component, _childrenObject, args, retVal) {
|
||||||
const markup = Utils.findInReactTree(retVal, filter =>
|
const markup = Utils.findInReactTree(retVal, filter =>
|
||||||
filter &&
|
filter &&
|
||||||
filter.className &&
|
filter.className &&
|
||||||
|
@ -256,13 +274,15 @@ export default new class EmoteModule extends BuiltinModule {
|
||||||
/**
|
/**
|
||||||
* Handle send message
|
* Handle send message
|
||||||
*/
|
*/
|
||||||
async handleSendMessage(component, args, orig) {
|
async handleSendMessage(MessageActions, args, orig) {
|
||||||
if (!args.length) return orig(...args);
|
if (!args.length) return orig(...args);
|
||||||
const { content } = args[1];
|
const { content } = args[1];
|
||||||
if (!content) return orig(...args);
|
if (!content) return orig(...args);
|
||||||
|
|
||||||
|
Logger.log('EmoteModule', ['Sending message', MessageActions, args, orig]);
|
||||||
|
|
||||||
const emoteAsImage = Settings.getSetting('emotes', 'default', 'emoteasimage').value &&
|
const emoteAsImage = Settings.getSetting('emotes', 'default', 'emoteasimage').value &&
|
||||||
(DiscordApi.currentChannel.type === 'DM' || DiscordApi.currentChannel.checkPermissions(DiscordApi.modules.DiscordPermissions.ATTACH_FILES));
|
(DiscordApi.currentChannel.type === 'DM' || DiscordApi.currentChannel.type === 'GROUP_DM' || DiscordApi.currentChannel.checkPermissions(DiscordApi.modules.DiscordPermissions.ATTACH_FILES));
|
||||||
|
|
||||||
if (!emoteAsImage || content.split(' ').length > 1) {
|
if (!emoteAsImage || content.split(' ').length > 1) {
|
||||||
args[1].content = args[1].content.split(' ').map(word => {
|
args[1].content = args[1].content.split(' ').map(word => {
|
||||||
|
@ -271,7 +291,7 @@ export default new class EmoteModule extends BuiltinModule {
|
||||||
const emote = this.findByName(isEmote[1], true);
|
const emote = this.findByName(isEmote[1], true);
|
||||||
if (!emote) return word;
|
if (!emote) return word;
|
||||||
this.addToMostUsed(emote);
|
this.addToMostUsed(emote);
|
||||||
return emote ? `:${isEmote[1]}:` : word;
|
return emote ? `;${isEmote[1]};` : word;
|
||||||
}
|
}
|
||||||
return word;
|
return word;
|
||||||
}).join(' ');
|
}).join(' ');
|
||||||
|
@ -305,23 +325,27 @@ export default new class EmoteModule extends BuiltinModule {
|
||||||
if (!content) return orig(...args);
|
if (!content) return orig(...args);
|
||||||
args[2].content = args[2].content.split(' ').map(word => {
|
args[2].content = args[2].content.split(' ').map(word => {
|
||||||
const isEmote = /;(.*?);/g.exec(word);
|
const isEmote = /;(.*?);/g.exec(word);
|
||||||
return isEmote ? `:${isEmote[1]}:` : word;
|
return isEmote ? `;${isEmote[1]};` : word;
|
||||||
}).join(' ');
|
}).join(' ');
|
||||||
return orig(...args);
|
return orig(...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle imagewrapper render
|
* Handle MessageAccessories render
|
||||||
*/
|
*/
|
||||||
beforeRenderImageWrapper(component, args, retVal) {
|
afterRenderMessageAccessories(component, args, retVal) {
|
||||||
if (!component.props || !component.props.src) return;
|
if (!component.props || !component.props.message) return;
|
||||||
|
if (!component.props.message.attachments || component.props.message.attachments.length !== 1) return;
|
||||||
|
|
||||||
const src = component.props.original || component.props.src.split('?')[0];
|
const filename = component.props.message.attachments[0].filename;
|
||||||
if (!src || !src.includes('.bdemote.')) return;
|
const match = filename.match(/([^/]*)\.bdemote\.(gif|png)$/i);
|
||||||
const emoteName = src.split('/').pop().split('.')[0];
|
if (!match) return;
|
||||||
const emote = this.findByName(emoteName);
|
|
||||||
|
const emote = this.findByName(match[1]);
|
||||||
if (!emote) return;
|
if (!emote) return;
|
||||||
retVal.props.children = emote.render();
|
|
||||||
|
emote.jumboable = true;
|
||||||
|
retVal.props.children[2] = emote.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -339,14 +363,14 @@ export default new class EmoteModule extends BuiltinModule {
|
||||||
for (const child of markup) {
|
for (const child of markup) {
|
||||||
if (typeof child !== 'string') {
|
if (typeof child !== 'string') {
|
||||||
if (typeof child === 'object') {
|
if (typeof child === 'object') {
|
||||||
const isEmoji = Utils.findInReactTree(child, 'emojiName');
|
const isEmoji = Utils.findInReactTree(child, filter => filter && filter.emojiName);
|
||||||
if (isEmoji) child.props.children.props.jumboable = jumboable;
|
if (isEmoji) isEmoji.jumboable = jumboable;
|
||||||
}
|
}
|
||||||
newMarkup.push(child);
|
newMarkup.push(child);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!/:(\w+):/g.test(child)) {
|
if (!/;(\w+);/g.test(child)) {
|
||||||
newMarkup.push(child);
|
newMarkup.push(child);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -355,7 +379,7 @@ export default new class EmoteModule extends BuiltinModule {
|
||||||
|
|
||||||
let s = '';
|
let s = '';
|
||||||
for (const word of words) {
|
for (const word of words) {
|
||||||
const isemote = /:(.*?):/g.exec(word);
|
const isemote = /;(.*?);/g.exec(word);
|
||||||
if (!isemote) {
|
if (!isemote) {
|
||||||
s += word;
|
s += word;
|
||||||
continue;
|
continue;
|
|
@ -0,0 +1,4 @@
|
||||||
|
export { default as EmoteModule, EMOTE_SOURCES } from './EmoteModule';
|
||||||
|
export { default as Emote } from './EmoteComponent';
|
||||||
|
export { default as EmoteComponent } from './EmoteComponent.vue';
|
||||||
|
export { default as EmoteAc } from './EmoteAc';
|
|
@ -1,16 +1,19 @@
|
||||||
import { default as EmoteModule } from './EmoteModule';
|
import { EmoteModule, EmoteAc } from './Emotes';
|
||||||
import { default as ReactDevtoolsModule } from './ReactDevtoolsModule';
|
import ReactDevtoolsModule from './ReactDevtoolsModule';
|
||||||
import { default as VueDevtoolsModule } from './VueDevToolsModule';
|
import VueDevtoolsModule from './VueDevToolsModule';
|
||||||
import { default as TrackingProtection } from './TrackingProtection';
|
import TrackingProtection from './TrackingProtection';
|
||||||
import { default as E2EE } from './E2EE';
|
import E2EE from './E2EE';
|
||||||
import { default as ColoredText } from './ColoredText';
|
import ColoredText from './ColoredText';
|
||||||
import { default as TwentyFourHour } from './24Hour';
|
import TwentyFourHour from './24Hour';
|
||||||
import { default as KillClyde } from './KillClyde';
|
import KillClyde from './KillClyde';
|
||||||
import { default as BlockedMessages } from './BlockedMessages';
|
import BlockedMessages from './BlockedMessages';
|
||||||
import { default as VoiceDisconnect } from './VoiceDisconnect';
|
import VoiceDisconnect from './VoiceDisconnect';
|
||||||
import { default as EmoteAc } from './EmoteAc';
|
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
|
static get modules() {
|
||||||
|
return require('./builtin');
|
||||||
|
}
|
||||||
|
|
||||||
static initAll() {
|
static initAll() {
|
||||||
EmoteModule.init();
|
EmoteModule.init();
|
||||||
ReactDevtoolsModule.init();
|
ReactDevtoolsModule.init();
|
||||||
|
|
|
@ -12,7 +12,7 @@ import BuiltinModule from './BuiltinModule';
|
||||||
|
|
||||||
import { Reflection } from 'modules';
|
import { Reflection } from 'modules';
|
||||||
|
|
||||||
export default new class E2EE extends BuiltinModule {
|
export default new class TrackingProtection extends BuiltinModule {
|
||||||
|
|
||||||
/* Getters */
|
/* Getters */
|
||||||
get moduleName() { return 'TrackingProtection' }
|
get moduleName() { return 'TrackingProtection' }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export { default as EmoteModule } from './EmoteModule';
|
export { EmoteModule, EmoteAc } from './Emotes';
|
||||||
export { default as ReactDevtoolsModule } from './ReactDevtoolsModule';
|
export { default as ReactDevtoolsModule } from './ReactDevtoolsModule';
|
||||||
export { default as VueDevtoolsModule } from './VueDevToolsModule';
|
export { default as VueDevtoolsModule } from './VueDevToolsModule';
|
||||||
export { default as TrackingProtection } from './TrackingProtection';
|
export { default as TrackingProtection } from './TrackingProtection';
|
||||||
|
|
|
@ -8,17 +8,16 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DOM, BdUI, BdMenu, Modals, Toasts, Notifications, BdContextMenu, DiscordContextMenu } from 'ui';
|
import { DOM, BdUI, BdMenu, Modals, Toasts, Notifications, BdContextMenu, DiscordContextMenu, Autocomplete } from 'ui';
|
||||||
import BdCss from './styles/index.scss';
|
import BdCss from './styles/index.scss';
|
||||||
import { Events, Globals, Settings, Database, Updater, ModuleManager, PluginManager, ThemeManager, ExtModuleManager, Vendor, Patcher, MonkeyPatch, ReactComponents, ReactHelpers, ReactAutoPatcher, DiscordApi, BdWebApi, Connectivity, Cache, Reflection, PackageInstaller } from 'modules';
|
import { Events, Globals, Settings, Database, Updater, ModuleManager, PluginManager, ThemeManager, ExtModuleManager, Vendor, Patcher, MonkeyPatch, ReactComponents, ReactHelpers, ReactAutoPatcher, DiscordApi, BdWebApi, Connectivity, Cache, Reflection, PackageInstaller } from 'modules';
|
||||||
import { ClientLogger as Logger, ClientIPC, Utils } from 'common';
|
import { ClientLogger as Logger, ClientIPC, Utils, Axi } from 'common';
|
||||||
import { BuiltinManager, EmoteModule, ReactDevtoolsModule, VueDevtoolsModule, TrackingProtection, E2EE } from 'builtin';
|
import { BuiltinManager, EmoteModule, ReactDevtoolsModule, VueDevtoolsModule, TrackingProtection, E2EE } from 'builtin';
|
||||||
import electron from 'electron';
|
import electron from 'electron';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { setTimeout } from 'timers';
|
|
||||||
|
|
||||||
const tests = typeof PRODUCTION === 'undefined';
|
const tests = typeof PRODUCTION === 'undefined';
|
||||||
const ignoreExternal = true;
|
const ignoreExternal = tests && true;
|
||||||
|
|
||||||
class BetterDiscord {
|
class BetterDiscord {
|
||||||
|
|
||||||
|
@ -28,18 +27,18 @@ class BetterDiscord {
|
||||||
Logger.log('main', 'BetterDiscord starting');
|
Logger.log('main', 'BetterDiscord starting');
|
||||||
|
|
||||||
this._bd = {
|
this._bd = {
|
||||||
DOM, BdUI, BdMenu, Modals, Reflection, Toasts, Notifications, BdContextMenu, DiscordContextMenu,
|
DOM, BdUI, BdMenu, Modals, Reflection, Toasts, Notifications, BdContextMenu, DiscordContextMenu, Autocomplete,
|
||||||
|
|
||||||
Events, Globals, Settings, Database, Updater,
|
Events, Globals, Settings, Database, Updater,
|
||||||
ModuleManager, PluginManager, ThemeManager, ExtModuleManager, PackageInstaller,
|
ModuleManager, PluginManager, ThemeManager, ExtModuleManager, PackageInstaller,
|
||||||
Vendor,
|
Vendor,
|
||||||
|
|
||||||
Patcher, MonkeyPatch, ReactComponents, ReactHelpers, ReactAutoPatcher, DiscordApi,
|
Patcher, MonkeyPatch, ReactComponents, ReactHelpers, ReactAutoPatcher, DiscordApi,
|
||||||
EmoteModule,
|
BuiltinManager, EmoteModule,
|
||||||
BdWebApi,
|
BdWebApi,
|
||||||
Connectivity,
|
Connectivity,
|
||||||
Cache,
|
Cache,
|
||||||
Logger, ClientIPC, Utils,
|
Logger, ClientIPC, Utils, Axi,
|
||||||
|
|
||||||
plugins: PluginManager.localContent,
|
plugins: PluginManager.localContent,
|
||||||
themes: ThemeManager.localContent,
|
themes: ThemeManager.localContent,
|
||||||
|
|
|
@ -65,6 +65,10 @@ export default class Content extends AsyncEventEmitter {
|
||||||
get config() { return this.settings.categories }
|
get config() { return this.settings.categories }
|
||||||
get data() { return this.userConfig.data || (this.userConfig.data = {}) }
|
get data() { return this.userConfig.data || (this.userConfig.data = {}) }
|
||||||
|
|
||||||
|
get packed() { return this.dirName.packed }
|
||||||
|
get packagePath() { return this.dirName.packagePath }
|
||||||
|
get packageName() { return this.dirName.pkg }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a settings modal for this content.
|
* Opens a settings modal for this content.
|
||||||
* @return {Modal}
|
* @return {Modal}
|
||||||
|
|
|
@ -220,6 +220,7 @@ export default class {
|
||||||
const unpackedPath = path.join(Globals.getPath('tmp'), packageName);
|
const unpackedPath = path.join(Globals.getPath('tmp'), packageName);
|
||||||
|
|
||||||
asar.extractAll(packagePath, unpackedPath);
|
asar.extractAll(packagePath, unpackedPath);
|
||||||
|
|
||||||
return this.preloadContent({
|
return this.preloadContent({
|
||||||
config,
|
config,
|
||||||
contentPath: unpackedPath,
|
contentPath: unpackedPath,
|
||||||
|
@ -228,8 +229,8 @@ export default class {
|
||||||
packageName,
|
packageName,
|
||||||
packed: true
|
packed: true
|
||||||
}, reload, index);
|
}, reload, index);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
Logger.log('ContentManager', ['Error extracting packed content', err]);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,12 +323,6 @@ export default class {
|
||||||
return content;
|
return content;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw err;
|
throw err;
|
||||||
} finally {
|
|
||||||
if (typeof dirName === 'object' && dirName.packed) {
|
|
||||||
rimraf(dirName.contentPath, err => {
|
|
||||||
if (err) Logger.err(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,6 +348,7 @@ export default class {
|
||||||
await unload;
|
await unload;
|
||||||
|
|
||||||
await FileUtils.recursiveDeleteDirectory(content.paths.contentPath);
|
await FileUtils.recursiveDeleteDirectory(content.paths.contentPath);
|
||||||
|
if (content.packed) await FileUtils.recursiveDeleteDirectory(content.packagePath);
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Logger.err(this.moduleName, err);
|
Logger.err(this.moduleName, err);
|
||||||
|
@ -384,7 +380,7 @@ export default class {
|
||||||
|
|
||||||
if (this.unloadContentHook) this.unloadContentHook(content);
|
if (this.unloadContentHook) this.unloadContentHook(content);
|
||||||
|
|
||||||
if (reload) return content.packed ? this.preloadPackedContent(content.packed.pkg, true, index) : this.preloadContent(content.dirName, true, index);
|
if (reload) return content.packed ? this.preloadPackedContent(content.packagePath, true, index) : this.preloadContent(content.dirName, true, index);
|
||||||
|
|
||||||
this.localContent.splice(index, 1);
|
this.localContent.splice(index, 1);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -126,6 +126,7 @@ export default class DiscordApi {
|
||||||
static get currentGuild() {
|
static get currentGuild() {
|
||||||
const guild = Modules.GuildStore.getGuild(Modules.SelectedGuildStore.getGuildId());
|
const guild = Modules.GuildStore.getGuild(Modules.SelectedGuildStore.getGuildId());
|
||||||
if (guild) return Guild.from(guild);
|
if (guild) return Guild.from(guild);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,6 +136,7 @@ export default class DiscordApi {
|
||||||
static get currentChannel() {
|
static get currentChannel() {
|
||||||
const channel = Modules.ChannelStore.getChannel(Modules.SelectedChannelStore.getChannelId());
|
const channel = Modules.ChannelStore.getChannel(Modules.SelectedChannelStore.getChannelId());
|
||||||
if (channel) return Channel.from(channel);
|
if (channel) return Channel.from(channel);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,6 +146,7 @@ export default class DiscordApi {
|
||||||
static get currentUser() {
|
static get currentUser() {
|
||||||
const user = Modules.UserStore.getCurrentUser();
|
const user = Modules.UserStore.getCurrentUser();
|
||||||
if (user) return User.from(user);
|
if (user) return User.from(user);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -36,10 +36,6 @@ export default new class extends Module {
|
||||||
|
|
||||||
async first() {
|
async first() {
|
||||||
const config = await ClientIPC.send('getConfig');
|
const config = await ClientIPC.send('getConfig');
|
||||||
config.paths.push({
|
|
||||||
id: 'tmp',
|
|
||||||
path: path.join(config.paths.find(p => p.id === 'base').path, 'tmp')
|
|
||||||
});
|
|
||||||
this.setState({ config });
|
this.setState({ config });
|
||||||
|
|
||||||
// This is for Discord to stop error reporting :3
|
// This is for Discord to stop error reporting :3
|
||||||
|
@ -102,7 +98,7 @@ export default new class extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
get version() {
|
get version() {
|
||||||
return this.config.version;
|
return this.config.versions.core;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ export default class Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(newState) {
|
setState(newState) {
|
||||||
const oldState = this.state;
|
const oldState = Object.assign({}, this.state);
|
||||||
Object.assign(this.state, newState);
|
Object.assign(this.state, newState);
|
||||||
if (this.stateChanged) this.stateChanged(oldState, newState);
|
if (this.stateChanged) this.stateChanged(oldState, newState);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,14 @@ import rimraf from 'rimraf';
|
||||||
|
|
||||||
import { request } from 'vendor';
|
import { request } from 'vendor';
|
||||||
import { Modals } from 'ui';
|
import { Modals } from 'ui';
|
||||||
import { Utils } from 'common';
|
import { Utils, FileUtils } from 'common';
|
||||||
import PluginManager from './pluginmanager';
|
import PluginManager from './pluginmanager';
|
||||||
import Globals from './globals';
|
import Globals from './globals';
|
||||||
import Security from './security';
|
import Security from './security';
|
||||||
import { ReactComponents } from './reactcomponents';
|
|
||||||
import Reflection from './reflection';
|
import Reflection from './reflection';
|
||||||
import DiscordApi from './discordapi';
|
import DiscordApi from './discordapi';
|
||||||
import ThemeManager from './thememanager';
|
import ThemeManager from './thememanager';
|
||||||
|
import { MonkeyPatch } from './patcher';
|
||||||
import { DOM } from 'ui';
|
import { DOM } from 'ui';
|
||||||
|
|
||||||
export default class PackageInstaller {
|
export default class PackageInstaller {
|
||||||
|
@ -84,15 +84,10 @@ export default class PackageInstaller {
|
||||||
|
|
||||||
await oldContent.unload(true);
|
await oldContent.unload(true);
|
||||||
|
|
||||||
if (oldContent.packed && oldContent.packed.packageName !== nameOrId) {
|
if (oldContent.packed && oldContent.packageName !== nameOrId) {
|
||||||
rimraf(oldContent.packed.packagePath, err => {
|
await FileUtils.deleteFile(oldContent.packagePath).catch(err => null);
|
||||||
if (err) throw err;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
rimraf(oldContent.contentPath, err => {
|
|
||||||
if (err) throw err;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
await FileUtils.recursiveDeleteDirectory(oldContent.contentPath).catch(err => null);
|
||||||
|
|
||||||
return manager.preloadPackedContent(outputName);
|
return manager.preloadPackedContent(outputName);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -133,41 +128,51 @@ export default class PackageInstaller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async handleDrop(stateNode, e, original) {
|
||||||
|
if (!e.dataTransfer.files.length || !e.dataTransfer.files[0].name.endsWith('.bd')) return original && original.call(stateNode, e);
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
if (stateNode) stateNode.clearDragging();
|
||||||
|
|
||||||
|
const currentChannel = DiscordApi.currentChannel;
|
||||||
|
const canUpload = currentChannel ?
|
||||||
|
currentChannel.checkPermissions(Reflection.modules.DiscordConstants.Permissions.SEND_MESSAGES) &&
|
||||||
|
currentChannel.checkPermissions(Reflection.modules.DiscordConstants.Permissions.ATTACH_FILES) : false;
|
||||||
|
|
||||||
|
const files = Array.from(e.dataTransfer.files).slice(0);
|
||||||
|
const actionCode = await this.dragAndDropHandler(e.dataTransfer.files[0].path, canUpload);
|
||||||
|
|
||||||
|
if (actionCode === 0 && stateNode) stateNode.promptToUpload(files, currentChannel.id, true, !e.shiftKey);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patches Discord upload area for .bd files
|
* Patches Discord upload area for .bd files
|
||||||
*/
|
*/
|
||||||
static async uploadAreaPatch() {
|
static async uploadAreaPatch(UploadArea) {
|
||||||
const { selector } = Reflection.resolve('uploadArea');
|
|
||||||
this.UploadArea = await ReactComponents.getComponent('UploadArea', { selector });
|
|
||||||
|
|
||||||
const reflect = Reflection.DOM(selector);
|
|
||||||
const stateNode = reflect.getComponentStateNode(this.UploadArea);
|
|
||||||
const callback = async function (e) {
|
|
||||||
if (!e.dataTransfer.files.length || !e.dataTransfer.files[0].name.endsWith('.bd')) return;
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
stateNode.clearDragging();
|
|
||||||
const currentChannel = DiscordApi.currentChannel;
|
|
||||||
const canUpload = currentChannel ? currentChannel.checkPermissions(Reflection.modules.DiscordConstants.Permissions.ATTACH_FILES) : false;
|
|
||||||
const files = Array.from(e.dataTransfer.files).slice(0);
|
|
||||||
const actionCode = await PackageInstaller.dragAndDropHandler(e.dataTransfer.files[0].path, canUpload);
|
|
||||||
if (actionCode === 0) stateNode.promptToUpload(files, currentChannel.id, true, !e.shiftKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add a listener to root for when not in a channel
|
// Add a listener to root for when not in a channel
|
||||||
const root = DOM.getElement('#app-mount');
|
const root = DOM.getElement('#app-mount');
|
||||||
root.addEventListener('drop', callback);
|
const rootHandleDrop = this.handleDrop.bind(this, undefined);
|
||||||
|
root.addEventListener('drop', rootHandleDrop);
|
||||||
|
|
||||||
// Remove their handler, add ours, then read theirs to give ours priority to stop theirs when we get a .bd file.
|
const unpatchUploadAreaHandleDrop = MonkeyPatch('BD:ReactComponents', UploadArea.component.prototype).instead('handleDrop', (component, [e], original) => this.handleDrop(component, e, original));
|
||||||
reflect.element.removeEventListener('drop', stateNode.handleDrop);
|
|
||||||
reflect.element.addEventListener('drop', callback);
|
|
||||||
reflect.element.addEventListener('drop', stateNode.handleDrop);
|
|
||||||
|
|
||||||
this.unpatchUploadArea = function () {
|
this.unpatchUploadArea = () => {
|
||||||
reflect.element.removeEventListener('drop', callback);
|
unpatchUploadAreaHandleDrop();
|
||||||
root.removeEventListener('drop', callback);
|
root.removeEventListener('drop', rootHandleDrop);
|
||||||
|
this.unpatchUploadArea = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (const element of document.querySelectorAll(UploadArea.important.selector)) {
|
||||||
|
const stateNode = Reflection.DOM(element).getComponentStateNode(UploadArea);
|
||||||
|
|
||||||
|
element.removeEventListener('drop', stateNode.handleDrop);
|
||||||
|
stateNode.handleDrop = UploadArea.component.prototype.handleDrop.bind(stateNode);
|
||||||
|
element.addEventListener('drop', stateNode.handleDrop);
|
||||||
|
|
||||||
|
stateNode.forceUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,21 +109,9 @@ export default class extends ContentManager {
|
||||||
throw {message: `Plugin ${info.name} did not return a class that extends Plugin.`};
|
throw {message: `Plugin ${info.name} did not return a class that extends Plugin.`};
|
||||||
|
|
||||||
const instance = new plugin({
|
const instance = new plugin({
|
||||||
configs, info, main,
|
configs, info, main, paths
|
||||||
paths: {
|
|
||||||
contentPath: paths.contentPath,
|
|
||||||
dirName: packed ? packed.packageName : paths.dirName,
|
|
||||||
mainPath: paths.mainPath
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (packed) instance.packed = {
|
|
||||||
pkg: packed.pkg,
|
|
||||||
packageName: packed.packageName,
|
|
||||||
packagePath: packed.packagePath,
|
|
||||||
packed: true
|
|
||||||
}; else instance.packed = false;
|
|
||||||
|
|
||||||
if (instance.enabled && this.loaded) {
|
if (instance.enabled && this.loaded) {
|
||||||
instance.userConfig.enabled = false;
|
instance.userConfig.enabled = false;
|
||||||
instance.start(false);
|
instance.start(false);
|
||||||
|
|
|
@ -173,9 +173,18 @@ class ReactComponent {
|
||||||
this.important = important;
|
this.important = important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get elements() {
|
||||||
|
if (!this.important || !this.important.selector) return [];
|
||||||
|
|
||||||
|
return document.querySelectorAll(this.important.selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
get stateNodes() {
|
||||||
|
return [...this.elements].map(e => Reflection.DOM(e).getComponentStateNode(this));
|
||||||
|
}
|
||||||
|
|
||||||
forceUpdateAll() {
|
forceUpdateAll() {
|
||||||
if (!this.important || !this.important.selector) return;
|
for (const e of this.elements) {
|
||||||
for (const e of document.querySelectorAll(this.important.selector)) {
|
|
||||||
Reflection.DOM(e).forceUpdate(this);
|
Reflection.DOM(e).forceUpdate(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,6 +195,7 @@ export class ReactComponents {
|
||||||
static get unknownComponents() { return this._unknownComponents || (this._unknownComponents = []) }
|
static get unknownComponents() { return this._unknownComponents || (this._unknownComponents = []) }
|
||||||
static get listeners() { return this._listeners || (this._listeners = []) }
|
static get listeners() { return this._listeners || (this._listeners = []) }
|
||||||
static get nameSetters() { return this._nameSetters || (this._nameSetters = []) }
|
static get nameSetters() { return this._nameSetters || (this._nameSetters = []) }
|
||||||
|
static get componentAliases() { return this._componentAliases || (this._componentAliases = []) }
|
||||||
|
|
||||||
static get ReactComponent() { return ReactComponent }
|
static get ReactComponent() { return ReactComponent }
|
||||||
|
|
||||||
|
@ -222,6 +232,8 @@ export class ReactComponents {
|
||||||
* @return {Promise => ReactComponent}
|
* @return {Promise => ReactComponent}
|
||||||
*/
|
*/
|
||||||
static async getComponent(name, important, filter) {
|
static async getComponent(name, important, filter) {
|
||||||
|
name = this.getComponentName(name);
|
||||||
|
|
||||||
const have = this.components.find(c => c.id === name);
|
const have = this.components.find(c => c.id === name);
|
||||||
if (have) return have;
|
if (have) return have;
|
||||||
|
|
||||||
|
@ -239,7 +251,13 @@ export class ReactComponents {
|
||||||
let component, reflect;
|
let component, reflect;
|
||||||
for (const element of elements) {
|
for (const element of elements) {
|
||||||
reflect = Reflection.DOM(element);
|
reflect = Reflection.DOM(element);
|
||||||
component = filter ? reflect.components.find(filter) : reflect.component;
|
component = filter ? reflect.components.find(component => {
|
||||||
|
try {
|
||||||
|
return filter.call(undefined, component);
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}) : reflect.component;
|
||||||
if (component) break;
|
if (component) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,6 +294,19 @@ export class ReactComponents {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getComponentName(name) {
|
||||||
|
const resolvedAliases = [];
|
||||||
|
|
||||||
|
while (this.componentAliases[name]) {
|
||||||
|
resolvedAliases.push(name);
|
||||||
|
name = this.componentAliases[name];
|
||||||
|
|
||||||
|
if (resolvedAliases.includes(name)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
static setName(name, filter) {
|
static setName(name, filter) {
|
||||||
const have = this.components.find(c => c.id === name);
|
const have = this.components.find(c => c.id === name);
|
||||||
if (have) return have;
|
if (have) return have;
|
||||||
|
@ -351,6 +382,21 @@ export class ReactAutoPatcher {
|
||||||
this.Message.forceUpdateAll();
|
this.Message.forceUpdateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async patchMessageContent() {
|
||||||
|
const { selector } = Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited');
|
||||||
|
this.MessageContent = await ReactComponents.getComponent('MessageContent', {selector}, c => c.defaultProps && c.defaultProps.hasOwnProperty('disableButtons'));
|
||||||
|
}
|
||||||
|
|
||||||
|
static async patchSpoiler() {
|
||||||
|
const { selector } = Reflection.resolve('spoilerText', 'spoilerContainer');
|
||||||
|
this.Spoiler = await ReactComponents.getComponent('Spoiler', {selector}, c => c.prototype.renderSpoilerText);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async patchMessageAccessories() {
|
||||||
|
const { selector } = Reflection.resolve('container', 'containerCozy', 'embedWrapper');
|
||||||
|
this.MessageAccessories = await ReactComponents.getComponent('MessageAccessories', {selector});
|
||||||
|
}
|
||||||
|
|
||||||
static async patchMessageGroup() {
|
static async patchMessageGroup() {
|
||||||
const { selector } = Reflection.resolve('container', 'message', 'messageCozy');
|
const { selector } = Reflection.resolve('container', 'message', 'messageCozy');
|
||||||
this.MessageGroup = await ReactComponents.getComponent('MessageGroup', {selector});
|
this.MessageGroup = await ReactComponents.getComponent('MessageGroup', {selector});
|
||||||
|
@ -369,7 +415,16 @@ export class ReactAutoPatcher {
|
||||||
this.MessageGroup.forceUpdateAll();
|
this.MessageGroup.forceUpdateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async patchImageWrapper() {
|
||||||
|
ReactComponents.componentAliases.ImageWrapper = 'Image';
|
||||||
|
|
||||||
|
const { selector } = Reflection.resolve('imageWrapper');
|
||||||
|
this.ImageWrapper = await ReactComponents.getComponent('ImageWrapper', {selector}, c => typeof c.defaultProps.children === 'function');
|
||||||
|
}
|
||||||
|
|
||||||
static async patchChannelMember() {
|
static async patchChannelMember() {
|
||||||
|
ReactComponents.componentAliases.ChannelMember = 'MemberListItem';
|
||||||
|
|
||||||
const { selector } = Reflection.resolve('member', 'memberInner', 'activity');
|
const { selector } = Reflection.resolve('member', 'memberInner', 'activity');
|
||||||
this.ChannelMember = await ReactComponents.getComponent('ChannelMember', {selector}, m => m.prototype.renderActivity);
|
this.ChannelMember = await ReactComponents.getComponent('ChannelMember', {selector}, m => m.prototype.renderActivity);
|
||||||
|
|
||||||
|
@ -385,8 +440,13 @@ export class ReactAutoPatcher {
|
||||||
this.ChannelMember.forceUpdateAll();
|
this.ChannelMember.forceUpdateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async patchNameTag() {
|
||||||
|
const { selector } = Reflection.resolve('nameTag', 'username', 'discriminator', 'ownerIcon');
|
||||||
|
this.NameTag = await ReactComponents.getComponent('NameTag', {selector});
|
||||||
|
}
|
||||||
|
|
||||||
static async patchGuild() {
|
static async patchGuild() {
|
||||||
const selector = `div.${Reflection.resolve('guild', 'guildsWrapper').className}:not(:first-child)`;
|
const selector = `div.${Reflection.resolve('container', 'guildIcon', 'selected', 'unread').className}:not(:first-child)`;
|
||||||
this.Guild = await ReactComponents.getComponent('Guild', {selector}, m => m.prototype.renderBadge);
|
this.Guild = await ReactComponents.getComponent('Guild', {selector}, m => m.prototype.renderBadge);
|
||||||
|
|
||||||
this.unpatchGuild = MonkeyPatch('BD:ReactComponents', this.Guild.component.prototype).after('render', (component, args, retVal) => {
|
this.unpatchGuild = MonkeyPatch('BD:ReactComponents', this.Guild.component.prototype).after('render', (component, args, retVal) => {
|
||||||
|
@ -403,7 +463,7 @@ export class ReactAutoPatcher {
|
||||||
* The Channel component contains the header, message scroller, message form and member list.
|
* The Channel component contains the header, message scroller, message form and member list.
|
||||||
*/
|
*/
|
||||||
static async patchChannel() {
|
static async patchChannel() {
|
||||||
const selector = '.chat';
|
const { selector } = Reflection.resolve('chat', 'title', 'channelName');
|
||||||
this.Channel = await ReactComponents.getComponent('Channel', {selector});
|
this.Channel = await ReactComponents.getComponent('Channel', {selector});
|
||||||
|
|
||||||
this.unpatchChannel = MonkeyPatch('BD:ReactComponents', this.Channel.component.prototype).after('render', (component, args, retVal) => {
|
this.unpatchChannel = MonkeyPatch('BD:ReactComponents', this.Channel.component.prototype).after('render', (component, args, retVal) => {
|
||||||
|
@ -419,10 +479,17 @@ export class ReactAutoPatcher {
|
||||||
this.Channel.forceUpdateAll();
|
this.Channel.forceUpdateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async patchChannelTextArea() {
|
||||||
|
const { selector } = Reflection.resolve('channelTextArea', 'autocomplete');
|
||||||
|
this.ChannelTextArea = await ReactComponents.getComponent('ChannelTextArea', {selector});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The GuildTextChannel component represents a text channel in the guild channel list.
|
* The GuildTextChannel component represents a text channel in the guild channel list.
|
||||||
*/
|
*/
|
||||||
static async patchGuildTextChannel() {
|
static async patchGuildTextChannel() {
|
||||||
|
ReactComponents.componentAliases.GuildTextChannel = 'TextChannel';
|
||||||
|
|
||||||
const { selector } = Reflection.resolve('containerDefault', 'actionIcon');
|
const { selector } = Reflection.resolve('containerDefault', 'actionIcon');
|
||||||
this.GuildTextChannel = await ReactComponents.getComponent('GuildTextChannel', {selector}, c => c.prototype.renderMentionBadge);
|
this.GuildTextChannel = await ReactComponents.getComponent('GuildTextChannel', {selector}, c => c.prototype.renderMentionBadge);
|
||||||
|
|
||||||
|
@ -435,6 +502,8 @@ export class ReactAutoPatcher {
|
||||||
* The GuildVoiceChannel component represents a voice channel in the guild channel list.
|
* The GuildVoiceChannel component represents a voice channel in the guild channel list.
|
||||||
*/
|
*/
|
||||||
static async patchGuildVoiceChannel() {
|
static async patchGuildVoiceChannel() {
|
||||||
|
ReactComponents.componentAliases.GuildVoiceChannel = 'VoiceChannel';
|
||||||
|
|
||||||
const { selector } = Reflection.resolve('containerDefault', 'actionIcon');
|
const { selector } = Reflection.resolve('containerDefault', 'actionIcon');
|
||||||
this.GuildVoiceChannel = await ReactComponents.getComponent('GuildVoiceChannel', {selector}, c => c.prototype.handleVoiceConnect);
|
this.GuildVoiceChannel = await ReactComponents.getComponent('GuildVoiceChannel', {selector}, c => c.prototype.handleVoiceConnect);
|
||||||
|
|
||||||
|
@ -447,7 +516,9 @@ export class ReactAutoPatcher {
|
||||||
* The DirectMessage component represents a channel in the direct messages list.
|
* The DirectMessage component represents a channel in the direct messages list.
|
||||||
*/
|
*/
|
||||||
static async patchDirectMessage() {
|
static async patchDirectMessage() {
|
||||||
const selector = '.channel.private';
|
ReactComponents.componentAliases.DirectMessage = 'PrivateChannel';
|
||||||
|
|
||||||
|
const { selector } = Reflection.resolve('channel', 'avatar', 'name');
|
||||||
this.DirectMessage = await ReactComponents.getComponent('DirectMessage', {selector}, c => c.prototype.renderAvatar);
|
this.DirectMessage = await ReactComponents.getComponent('DirectMessage', {selector}, c => c.prototype.renderAvatar);
|
||||||
|
|
||||||
this.unpatchDirectMessage = MonkeyPatch('BD:ReactComponents', this.DirectMessage.component.prototype).after('render', this._afterChannelRender);
|
this.unpatchDirectMessage = MonkeyPatch('BD:ReactComponents', this.DirectMessage.component.prototype).after('render', this._afterChannelRender);
|
||||||
|
@ -469,15 +540,18 @@ export class ReactAutoPatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async patchUserProfileModal() {
|
static async patchUserProfileModal() {
|
||||||
|
ReactComponents.componentAliases.UserProfileModal = 'UserProfileBody';
|
||||||
|
|
||||||
const { selector } = Reflection.resolve('root', 'topSectionNormal');
|
const { selector } = Reflection.resolve('root', 'topSectionNormal');
|
||||||
this.UserProfileModal = await ReactComponents.getComponent('UserProfileModal', {selector}, Filters.byPrototypeFields(['renderHeader', 'renderBadges']));
|
this.UserProfileModal = await ReactComponents.getComponent('UserProfileModal', {selector}, c => c.prototype.renderHeader && c.prototype.renderBadges);
|
||||||
|
|
||||||
this.unpatchUserProfileModal = MonkeyPatch('BD:ReactComponents', this.UserProfileModal.component.prototype).after('render', (component, args, retVal) => {
|
this.unpatchUserProfileModal = MonkeyPatch('BD:ReactComponents', this.UserProfileModal.component.prototype).after('render', (component, args, retVal) => {
|
||||||
|
const root = retVal.props.children[0] || retVal.props.children;
|
||||||
const { user } = component.props;
|
const { user } = component.props;
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
retVal.props['data-user-id'] = user.id;
|
root.props['data-user-id'] = user.id;
|
||||||
if (user.bot) retVal.props.className += ' bd-isBot';
|
if (user.bot) root.props.className += ' bd-isBot';
|
||||||
if (user.id === DiscordApi.currentUser.id) retVal.props.className += ' bd-isCurrentUser';
|
if (user.id === DiscordApi.currentUser.id) root.props.className += ' bd-isCurrentUser';
|
||||||
});
|
});
|
||||||
|
|
||||||
this.UserProfileModal.forceUpdateAll();
|
this.UserProfileModal.forceUpdateAll();
|
||||||
|
@ -485,24 +559,28 @@ export class ReactAutoPatcher {
|
||||||
|
|
||||||
static async patchUserPopout() {
|
static async patchUserPopout() {
|
||||||
const { selector } = Reflection.resolve('userPopout', 'headerNormal');
|
const { selector } = Reflection.resolve('userPopout', 'headerNormal');
|
||||||
this.UserPopout = await ReactComponents.getComponent('UserPopout', {selector});
|
this.UserPopout = await ReactComponents.getComponent('UserPopout', {selector}, c => c.prototype.renderHeader);
|
||||||
|
|
||||||
this.unpatchUserPopout = MonkeyPatch('BD:ReactComponents', this.UserPopout.component.prototype).after('render', (component, args, retVal) => {
|
this.unpatchUserPopout = MonkeyPatch('BD:ReactComponents', this.UserPopout.component.prototype).after('render', (component, args, retVal) => {
|
||||||
|
const root = retVal.props.children[0] || retVal.props.children;
|
||||||
const { user, guild, guildMember } = component.props;
|
const { user, guild, guildMember } = component.props;
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
retVal.props['data-user-id'] = user.id;
|
root.props['data-user-id'] = user.id;
|
||||||
if (user.bot) retVal.props.className += ' bd-isBot';
|
if (user.bot) root.props.className += ' bd-isBot';
|
||||||
if (user.id === DiscordApi.currentUser.id) retVal.props.className += ' bd-isCurrentUser';
|
if (user.id === DiscordApi.currentUser.id) root.props.className += ' bd-isCurrentUser';
|
||||||
if (guild) retVal.props['data-guild-id'] = guild.id;
|
if (guild) root.props['data-guild-id'] = guild.id;
|
||||||
if (guild && user.id === guild.ownerId) retVal.props.className += ' bd-isGuildOwner';
|
if (guild && user.id === guild.ownerId) root.props.className += ' bd-isGuildOwner';
|
||||||
if (guild && guildMember) retVal.props.className += ' bd-isGuildMember';
|
if (guild && guildMember) root.props.className += ' bd-isGuildMember';
|
||||||
if (guildMember && guildMember.roles.length) retVal.props.className += ' bd-hasRoles';
|
if (guildMember && guildMember.roles.length) root.props.className += ' bd-hasRoles';
|
||||||
});
|
});
|
||||||
|
|
||||||
this.UserPopout.forceUpdateAll();
|
this.UserPopout.forceUpdateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
static async patchUploadArea() {
|
static async patchUploadArea() {
|
||||||
PackageInstaller.uploadAreaPatch();
|
const { selector } = Reflection.resolve('uploadArea');
|
||||||
|
this.UploadArea = await ReactComponents.getComponent('UploadArea', {selector});
|
||||||
|
|
||||||
|
PackageInstaller.uploadAreaPatch(this.UploadArea);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -288,7 +288,7 @@ class Module {
|
||||||
if (this._require) return this._require;
|
if (this._require) return this._require;
|
||||||
|
|
||||||
const __webpack_require__ = this.getWebpackRequire();
|
const __webpack_require__ = this.getWebpackRequire();
|
||||||
if (!__webpack_require__) return;
|
if (!__webpack_require__) return null;
|
||||||
|
|
||||||
this.hookWebpackRequireCache(__webpack_require__);
|
this.hookWebpackRequireCache(__webpack_require__);
|
||||||
return this._require = __webpack_require__;
|
return this._require = __webpack_require__;
|
||||||
|
|
|
@ -272,7 +272,7 @@ class WebpackModules {
|
||||||
if (this._require) return this._require;
|
if (this._require) return this._require;
|
||||||
|
|
||||||
const __webpack_require__ = this.getWebpackRequire();
|
const __webpack_require__ = this.getWebpackRequire();
|
||||||
if (!__webpack_require__) return;
|
if (!__webpack_require__) return null;
|
||||||
|
|
||||||
this.hookWebpackRequireCache(__webpack_require__);
|
this.hookWebpackRequireCache(__webpack_require__);
|
||||||
return this._require = __webpack_require__;
|
return this._require = __webpack_require__;
|
||||||
|
|
|
@ -69,10 +69,11 @@ export default class Theme extends Content {
|
||||||
path: this.paths.mainPath.replace(/\\/g, '/')
|
path: this.paths.mainPath.replace(/\\/g, '/')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Why are these getters?
|
||||||
Logger.log(this.name, ['Finished compiling theme', new class Info {
|
Logger.log(this.name, ['Finished compiling theme', new class Info {
|
||||||
get SCSS_variables() { console.log(config); }
|
get SCSS_variables() { console.log(config); return ''; }
|
||||||
get Compiled_SCSS() { console.log(result.css.toString()); }
|
get Compiled_SCSS() { console.log(result.css.toString()); return ''; }
|
||||||
get Result() { console.log(result); }
|
get Result() { console.log(result); return ''; }
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -146,6 +147,11 @@ export default class Theme extends Content {
|
||||||
* @param {Array} files Files to watch
|
* @param {Array} files Files to watch
|
||||||
*/
|
*/
|
||||||
set watchfiles(files) {
|
set watchfiles(files) {
|
||||||
|
if (this.packed) {
|
||||||
|
// Don't watch files for packed themes
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!files) files = [];
|
if (!files) files = [];
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
|
|
|
@ -36,12 +36,7 @@ export default class ThemeManager extends ContentManager {
|
||||||
static async loadTheme(paths, configs, info, main) {
|
static async loadTheme(paths, configs, info, main) {
|
||||||
try {
|
try {
|
||||||
const instance = new Theme({
|
const instance = new Theme({
|
||||||
configs, info, main,
|
configs, info, main, paths
|
||||||
paths: {
|
|
||||||
contentPath: paths.contentPath,
|
|
||||||
dirName: paths.dirName,
|
|
||||||
mainPath: paths.mainPath
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if (instance.enabled) {
|
if (instance.enabled) {
|
||||||
instance.userConfig.enabled = false;
|
instance.userConfig.enabled = false;
|
||||||
|
|
|
@ -8,81 +8,183 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Events from './events';
|
import { Notifications } from 'ui';
|
||||||
import Globals from './globals';
|
import { Reflection, Globals } from 'modules';
|
||||||
import { ClientLogger as Logger } from 'common';
|
|
||||||
import request from 'request-promise-native';
|
|
||||||
|
|
||||||
export default new class {
|
import Events from './events';
|
||||||
|
import Module from './imodule';
|
||||||
|
|
||||||
|
export default new class extends Module {
|
||||||
|
|
||||||
|
get updates() { return this.state.updates }
|
||||||
|
get bdUpdates() { return this.state.updates.bd }
|
||||||
|
get error() { return null; }
|
||||||
|
get updatesAvailable() { return this.state.updatesAvailable; }
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.updatesAvailable = false;
|
super({
|
||||||
this.latestVersion = undefined;
|
updatesAvailable: false,
|
||||||
this.error = undefined;
|
error: null,
|
||||||
|
updates: { bd: [] },
|
||||||
this.init = this.init.bind(this);
|
updating: false
|
||||||
this.checkForUpdates = this.checkForUpdates.bind(this);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bindings() {
|
||||||
* The interval to wait before checking for updates.
|
this.restartNotif = this.restartNotif.bind(this);
|
||||||
*/
|
this.reloadNotif = this.reloadNotif.bind(this);
|
||||||
get interval() {
|
this.startUpdate = this.startUpdate.bind(this);
|
||||||
return 60 * 1000 * 30;
|
this.setUpdateStatus = this.setUpdateStatus.bind(this);
|
||||||
|
this.testUi = this.testUi.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
restartNotif() {
|
||||||
this.updateInterval = setInterval(this.checkForUpdates, this.interval);
|
Notifications.add('Updates Finished!', 'Restart required.', [
|
||||||
|
{
|
||||||
|
text: 'Restart Later',
|
||||||
|
onClick: () => { setTimeout(this.restartNotif, 5 * 60000); return true; }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Restart Now',
|
||||||
|
onClick: () => {
|
||||||
|
try {
|
||||||
|
const { remote } = Globals.require('electron');
|
||||||
|
window.close();
|
||||||
|
Reflection.module.byProps('showToken', 'hideToken').showToken();
|
||||||
|
remote.app.relaunch();
|
||||||
|
remote.app.exit(0);
|
||||||
|
} catch (err) {
|
||||||
|
console.err(err);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
reloadNotif() {
|
||||||
* Installs an update.
|
Notifications.add('Updates Finished!', 'Reload required.', [
|
||||||
* TODO
|
{
|
||||||
*/
|
text: 'Reload Later',
|
||||||
async update() {
|
onClick: () => { setTimeout(this.reloadNotif, 5 * 60000); return true; }
|
||||||
try {
|
},
|
||||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
{
|
||||||
|
text: 'Reload Now',
|
||||||
this.updatesAvailable = false;
|
onClick: () => {
|
||||||
this.latestVersion = Globals.version;
|
document.location.reload();
|
||||||
Events.emit('update-check-end');
|
}
|
||||||
} catch (err) {
|
}
|
||||||
this.error = err;
|
]);
|
||||||
this.checkForUpdates();
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
events(ipc) {
|
||||||
* Checks for updates.
|
ipc.on('updater-checkForUpdates', () => {
|
||||||
* @return {Promise}
|
if (this.state.updating) return; // We're already updating. Updater should be paused anyways at this point.
|
||||||
*/
|
Events.emit('update-check-start');
|
||||||
async checkForUpdates() {
|
});
|
||||||
if (this.updatesAvailable) return true;
|
|
||||||
Events.emit('update-check-start');
|
|
||||||
Logger.info('Updater', 'Checking for updates');
|
|
||||||
|
|
||||||
try {
|
ipc.on('updater-noUpdates', () => {
|
||||||
const response = await request({
|
if (this.state.updatesAvailable) return; // If for some reason we get this even though we have updates already.
|
||||||
uri: 'https://rawgit.com/JsSucks/BetterDiscordApp/master/package.json',
|
this.setState({
|
||||||
json: true
|
updatesAvailable: false,
|
||||||
|
updates: {}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
this.latestVersion = response.version;
|
ipc.on('updater-updatesAvailable', (_, updates) => {
|
||||||
Events.emit('update-check-end');
|
console.log(updates);
|
||||||
Logger.info('Updater', `Latest Version: ${response.version} - Current Version: ${Globals.version}`);
|
if (this.state.updating) return; // If for some reason we get more updates when we're already updating
|
||||||
|
updates.bd = updates.bd.map(update => {
|
||||||
|
update.text = `${update.id.charAt(0).toUpperCase()}${update.id.slice(1)}`;
|
||||||
|
update.hint = `Current: ${update.currentVersion} | Latest: ${update.version}`;
|
||||||
|
update.status = {
|
||||||
|
update: true,
|
||||||
|
updating: false,
|
||||||
|
updated: false,
|
||||||
|
error: null
|
||||||
|
};
|
||||||
|
|
||||||
if (this.latestVersion !== Globals.version) {
|
return update;
|
||||||
this.updatesAvailable = true;
|
});
|
||||||
Events.emit('updates-available');
|
this.setState({
|
||||||
return true;
|
updates,
|
||||||
|
updatesAvailable: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ipc.on('updater-updated', (_, info) => {
|
||||||
|
const { reloadRequired, restartRequired } = info;
|
||||||
|
if (restartRequired) {
|
||||||
|
this.restartNotif();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
if (reloadRequired) {
|
||||||
} catch (err) {
|
this.reloadNotif();
|
||||||
Events.emit('update-check-fail', err);
|
return;
|
||||||
throw err;
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipc.on('updater-updateFinished', (_, update) => {
|
||||||
|
this.setUpdateStatus(update.id, 'updated', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipc.on('updater-updateError', (_, update) => {
|
||||||
|
this.setUpdateStatus(update.id, 'error', update.error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stateChanged(oldState, newState) {
|
||||||
|
if (!newState.updatesAvailable) return Events.emit('update-check-end');
|
||||||
|
if (!oldState.updatesAvailable && newState.updatesAvailable) {
|
||||||
|
Events.emit('updates-available');
|
||||||
|
Notifications.add('', 'Updates Available!', [
|
||||||
|
{
|
||||||
|
text: 'Ignore',
|
||||||
|
onClick: () => { return true; }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Show Updates',
|
||||||
|
onClick: () => {
|
||||||
|
Events.emit('bd-open-menu', 'updater');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setUpdateStatus(updateId, statusChild, statusValue) {
|
||||||
|
for (const u of this.bdUpdates) {
|
||||||
|
if (u.id === updateId) {
|
||||||
|
u.status[statusChild] = statusValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleUpdate(update) {
|
||||||
|
update.status.update = !update.status.update;
|
||||||
|
}
|
||||||
|
|
||||||
|
async startUpdate() {
|
||||||
|
console.log('start update');
|
||||||
|
const updates = { bd: [] };
|
||||||
|
for (const update of this.bdUpdates) {
|
||||||
|
if (update.status.update) {
|
||||||
|
update.status.updating = true;
|
||||||
|
updates.bd.push(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(updates);
|
||||||
|
this.send('updater-startUpdate', updates);
|
||||||
|
}
|
||||||
|
|
||||||
|
testUi(updates) {
|
||||||
|
this.setState({
|
||||||
|
updates,
|
||||||
|
updatesAvailable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
import jQuery from 'jquery';
|
import jQuery from 'jquery';
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
import { Axi } from 'common';
|
||||||
|
|
||||||
import request from 'request-promise-native';
|
import request from 'request-promise-native';
|
||||||
|
|
||||||
|
@ -40,6 +41,8 @@ export default class {
|
||||||
*/
|
*/
|
||||||
static get Vue() { return Vue }
|
static get Vue() { return Vue }
|
||||||
|
|
||||||
|
static get axios() { return Axi.axios }
|
||||||
|
|
||||||
static get request() { return request }
|
static get request() { return request }
|
||||||
|
|
||||||
static get Combokeys() { return Combokeys }
|
static get Combokeys() { return Combokeys }
|
||||||
|
|
|
@ -179,7 +179,7 @@ export class PermissionOverwrite {
|
||||||
}
|
}
|
||||||
|
|
||||||
get guild() {
|
get guild() {
|
||||||
if (this.channel) return this.channel.guild;
|
return this.channel ? this.channel.guild : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ export class RolePermissionOverwrite extends PermissionOverwrite {
|
||||||
get roleId() { return this.discordObject.id }
|
get roleId() { return this.discordObject.id }
|
||||||
|
|
||||||
get role() {
|
get role() {
|
||||||
if (this.guild) return this.guild.roles.find(r => r.id === this.roleId);
|
return this.guild ? this.guild.roles.find(r => r.id === this.roleId) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,14 +166,14 @@ export class Guild {
|
||||||
* The guild's AFK channel.
|
* The guild's AFK channel.
|
||||||
*/
|
*/
|
||||||
get afkChannel() {
|
get afkChannel() {
|
||||||
if (this.afkChannelId) return Channel.fromId(this.afkChannelId);
|
return this.afkChannelId ? Channel.fromId(this.afkChannelId) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The channel system messages are sent to.
|
* The channel system messages are sent to.
|
||||||
*/
|
*/
|
||||||
get systemChannel() {
|
get systemChannel() {
|
||||||
if (this.systemChannelId) return Channel.fromId(this.systemChannelId);
|
return this.systemChannelId ? Channel.fromId(this.systemChannelId) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -42,11 +42,11 @@ export class Reaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
get message() {
|
get message() {
|
||||||
if (this.channel) return this.channel.messages.find(m => m.id === this.messageId);
|
return this.channel ? this.channel.messages.find(m => m.id === this.messageId) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get guild() {
|
get guild() {
|
||||||
if (this.channel) return this.channel.guild;
|
return this.channel ? this.channel.guild : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,11 +84,11 @@ export class Embed {
|
||||||
}
|
}
|
||||||
|
|
||||||
get message() {
|
get message() {
|
||||||
if (this.channel) return this.channel.messages.find(m => m.id === this.messageId);
|
return this.channel ? this.channel.messages.find(m => m.id === this.messageId) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get guild() {
|
get guild() {
|
||||||
if (this.channel) return this.channel.guild;
|
return this.channel ? this.channel.guild : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +143,7 @@ export class Message {
|
||||||
|
|
||||||
get author() {
|
get author() {
|
||||||
if (this.discordObject.author && !this.webhookId) return User.from(this.discordObject.author);
|
if (this.discordObject.author && !this.webhookId) return User.from(this.discordObject.author);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get channel() {
|
get channel() {
|
||||||
|
@ -150,7 +151,7 @@ export class Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
get guild() {
|
get guild() {
|
||||||
if (this.channel) return this.channel.guild;
|
return this.channel ? this.channel.guild : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,7 +203,7 @@ export class DefaultMessage extends Message {
|
||||||
get application() { return this.discordObject.application }
|
get application() { return this.discordObject.application }
|
||||||
|
|
||||||
get webhook() {
|
get webhook() {
|
||||||
if (this.webhookId) return this.discordObject.author;
|
return this.webhookId ? this.discordObject.author : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get mentions() {
|
get mentions() {
|
||||||
|
|
|
@ -77,7 +77,7 @@ export class User {
|
||||||
|
|
||||||
get note() {
|
get note() {
|
||||||
const note = Modules.UserNoteStore.getNote(this.id);
|
const note = Modules.UserNoteStore.getNote(this.id);
|
||||||
if (note) return note;
|
return note ? note : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
.bd-contentColumn .bd-devview {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 33% 33% 33%;
|
||||||
|
|
||||||
|
.bd-button {
|
||||||
|
font-size: 10px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,3 +10,4 @@
|
||||||
@import './kvp';
|
@import './kvp';
|
||||||
@import './collection';
|
@import './collection';
|
||||||
@import './e2ee';
|
@import './e2ee';
|
||||||
|
@import './devview';
|
||||||
|
|
|
@ -3,4 +3,22 @@
|
||||||
margin: 0 0 10px;
|
margin: 0 0 10px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bd-settingSwitch {
|
||||||
|
.bd-spinner7 {
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bd-updaterStatus {
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
&.bd-err {
|
||||||
|
color: $colerr;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bd-ok {
|
||||||
|
color: $colok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// sass-lint:disable-all
|
// sass-lint:disable-all
|
||||||
body:not(.bd-hideButton) {
|
body:not(.bd-hideButton) {
|
||||||
[class*='guildsWrapper-'] {
|
[class*='layer-'] > * > [class*='wrapper-'] {
|
||||||
padding-top: 49px !important;
|
padding-top: 49px !important;
|
||||||
}
|
}
|
||||||
.platform-osx [class*='guildsWrapper-'] {
|
.platform-osx [class*='layer-'] > * > [class*='wrapper-'] {
|
||||||
margin-top: 26px;
|
margin-top: 26px;
|
||||||
}
|
}
|
||||||
|
|
||||||
[class*='guildsWrapper-'] + [class*='flex'] {
|
[class*='layer-'] > * > [class*='wrapper-'] + [class*='flex'] {
|
||||||
border-radius: 0 0 0 5px;
|
border-radius: 0 0 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,3 +27,9 @@ body:not(.bd-hideButton) {
|
||||||
.bd-settingsWrapper.platform-linux {
|
.bd-settingsWrapper.platform-linux {
|
||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the margin on message attachments with an emote
|
||||||
|
.da-containerCozy + .da-containerCozy > * > .bd-emote {
|
||||||
|
margin-top: -8px;
|
||||||
|
margin-bottom: -8px;
|
||||||
|
}
|
||||||
|
|
|
@ -22,12 +22,12 @@
|
||||||
|
|
||||||
> .bd-scroller {
|
> .bd-scroller {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.bd-settings & {
|
.bd-settings & {
|
||||||
.platform-darwin & { // sass-lint:disable-line class-name-format
|
.platform-darwin & { // sass-lint:disable-line class-name-format
|
||||||
padding-top: 22px;
|
padding-top: 22px;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default new class Autocomplete {
|
||||||
}
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
this.cta = await ReactComponents.getComponent('ChannelTextArea', { selector: Reflection.resolve('channelTextArea', 'emojiButton').selector });
|
this.cta = await ReactComponents.getComponent('ChannelTextArea');
|
||||||
MonkeyPatch('BD:Autocomplete', this.cta.component.prototype).after('render', this.channelTextAreaAfterRender.bind(this));
|
MonkeyPatch('BD:Autocomplete', this.cta.component.prototype).after('render', this.channelTextAreaAfterRender.bind(this));
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|
||||||
<div slot="sidebarfooter" class="bd-info">
|
<div slot="sidebarfooter" class="bd-info">
|
||||||
<span class="bd-vtext">v2.0.0a by Jiiks/JsSucks</span>
|
<span class="bd-vtext">{{versionString}}</span>
|
||||||
<div @click="openGithub" v-tooltip="'GitHub'" class="bd-materialButton">
|
<div @click="openGithub" v-tooltip="'GitHub'" class="bd-materialButton">
|
||||||
<MiGithubCircle size="16" />
|
<MiGithubCircle size="16" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -63,11 +63,11 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Imports
|
// Imports
|
||||||
import { Events, Settings } from 'modules';
|
import { Events, Settings, Globals, Reflection } from 'modules';
|
||||||
import { BdMenuItems } from 'ui';
|
import { BdMenuItems } from 'ui';
|
||||||
import { shell } from 'electron';
|
import { shell } from 'electron';
|
||||||
import { SidebarView, Sidebar, SidebarItem, ContentColumn } from './sidebar';
|
import { SidebarView, Sidebar, SidebarItem, ContentColumn } from './sidebar';
|
||||||
import { SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView, UpdaterView, ConnectivityView } from './bd';
|
import { SettingsWrapper, SettingsPanel, CssEditorView, PluginsView, ThemesView, UpdaterView, ConnectivityView, SuperSecretView } from './bd';
|
||||||
import { SvgX, MiGithubCircle, MiWeb, MiClose, MiTwitterCircle } from './common';
|
import { SvgX, MiGithubCircle, MiWeb, MiClose, MiTwitterCircle } from './common';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -96,6 +96,9 @@
|
||||||
category.push(item);
|
category.push(item);
|
||||||
}
|
}
|
||||||
return categories;
|
return categories;
|
||||||
|
},
|
||||||
|
versionString() {
|
||||||
|
return Globals.version;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -123,6 +126,13 @@
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
Events.on('bd-open-menu', this.openMenuHandler = item => item && this.itemOnClick(this.items.find(i => i === item || i.id === item || i.contentid === item || i.set === item).id));
|
Events.on('bd-open-menu', this.openMenuHandler = item => item && this.itemOnClick(this.items.find(i => i === item || i.id === item || i.contentid === item || i.set === item).id));
|
||||||
|
|
||||||
|
try {
|
||||||
|
const currentUser = Reflection.module.byName('UserStore').getCurrentUser();
|
||||||
|
if (['81388395867156480', '98003542823944192', '249746236008169473', '284056145272766465', '478559353516064769'].includes(currentUser.id)) {
|
||||||
|
BdMenuItems.addVueComponent('BD Devs', 'Super Secret', SuperSecretView);
|
||||||
|
}
|
||||||
|
} catch (err) {}
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
if (this.openMenuHandler) Events.off('bd-open-menu', this.openMenuHandler);
|
if (this.openMenuHandler) Events.off('bd-open-menu', this.openMenuHandler);
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Developer View Component
|
||||||
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||||
|
* All rights reserved.
|
||||||
|
* https://betterdiscord.net
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<SettingsWrapper headertext="Super Secret">
|
||||||
|
<div class="bd-flex bd-flexCol bd-devview">
|
||||||
|
<FormButton @click="forceUpdate">Force Update</FormButton>
|
||||||
|
<FormButton @click="debugConfig">Config Debug</FormButton>
|
||||||
|
<FormButton @click="testUpdateUi">Update UI Test</FormButton>
|
||||||
|
</div>
|
||||||
|
</SettingsWrapper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import SettingsWrapper from './SettingsWrapper.vue';
|
||||||
|
import { FormButton } from '../common';
|
||||||
|
import { Globals, Events, Updater } from 'modules';
|
||||||
|
import { ClientIPC } from 'common';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
SettingsWrapper,
|
||||||
|
FormButton
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
forceUpdate() {
|
||||||
|
ClientIPC.send('debug-updater-forceUpdate');
|
||||||
|
},
|
||||||
|
debugConfig() {
|
||||||
|
console.log(Globals);
|
||||||
|
},
|
||||||
|
testUpdateUi() {
|
||||||
|
Updater.testUi({
|
||||||
|
'bd': [
|
||||||
|
{
|
||||||
|
'id': 'update',
|
||||||
|
'version': '3.0.0',
|
||||||
|
'currentVersion': '2.0.0',
|
||||||
|
'text': 'Update test',
|
||||||
|
'hint': 'Current: 2.0.0 | Latest: 3.0.0',
|
||||||
|
'status': {
|
||||||
|
'update': true,
|
||||||
|
'updating': false,
|
||||||
|
'updated': false,
|
||||||
|
'error': null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'updating',
|
||||||
|
'version': '3.0.0',
|
||||||
|
'currentVersion': '2.0.0',
|
||||||
|
'text': 'Updating test',
|
||||||
|
'hint': 'Current: 2.0.0 | Latest: 3.0.0',
|
||||||
|
'status': {
|
||||||
|
'update': true,
|
||||||
|
'updating': true,
|
||||||
|
'updated': false,
|
||||||
|
'error': null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'updated',
|
||||||
|
'version': '3.0.0',
|
||||||
|
'currentVersion': '2.0.0',
|
||||||
|
'text': 'Updated test',
|
||||||
|
'hint': 'Current: 2.0.0 | Latest: 3.0.0',
|
||||||
|
'status': {
|
||||||
|
'update': true,
|
||||||
|
'updating': true,
|
||||||
|
'updated': true,
|
||||||
|
'error': null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'error',
|
||||||
|
'version': '3.0.0',
|
||||||
|
'currentVersion': '2.0.0',
|
||||||
|
'text': 'Error test',
|
||||||
|
'hint': 'Current: 2.0.0 | Latest: 3.0.0',
|
||||||
|
'status': {
|
||||||
|
'update': true,
|
||||||
|
'updating': true,
|
||||||
|
'updated': false,
|
||||||
|
'error': 'Failed to update.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'haveUpdates': true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Updater Status Component
|
||||||
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||||
|
* All rights reserved.
|
||||||
|
* https://betterdiscord.net
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="bd-settingSwitch">
|
||||||
|
<div class="bd-title">
|
||||||
|
<h3>{{item.text}}</h3>
|
||||||
|
<h3 class="bd-updaterStatus bd-err" v-if="item.status.error">Update Failed!</h3>
|
||||||
|
<h3 class="bd-updaterStatus bd-ok" v-else-if="item.status.updated">Done</h3>
|
||||||
|
<div class="bd-spinner7" v-else-if="item.status.updating" />
|
||||||
|
<h3 class="bd-updaterStatus" v-else>Unknown</h3>
|
||||||
|
</div>
|
||||||
|
<div class="bd-hint">{{item.hint}}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: ['item']
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Updater Switch Component
|
||||||
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||||
|
* All rights reserved.
|
||||||
|
* https://betterdiscord.net
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="bd-settingSwitch">
|
||||||
|
<div class="bd-title">
|
||||||
|
<h3>{{item.text}}</h3>
|
||||||
|
<div class="bd-switchWrapper" @click="() => toggle(item)">
|
||||||
|
<input type="checkbox" class="bd-switchCheckbox" />
|
||||||
|
<div class="bd-switch" :class="{'bd-checked': item.status.update}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bd-hint">{{item.hint}}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: ['item', 'toggle']
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -11,19 +11,22 @@
|
||||||
<template>
|
<template>
|
||||||
<SettingsWrapper headertext="Updates">
|
<SettingsWrapper headertext="Updates">
|
||||||
<div class="bd-flex bd-flexCol bd-updaterview">
|
<div class="bd-flex bd-flexCol bd-updaterview">
|
||||||
<div v-if="error" class="bd-formItem">
|
<div class="bd-settingsCategories">
|
||||||
<h5 style="margin-bottom: 10px;">Error installing updates</h5>
|
<div class="bd-settingsCategory" v-if="bdUpdates && bdUpdates.length">
|
||||||
<div class="bd-err bd-preWrap"><div class="bd-pre">{{ error.formatted }}</div></div>
|
<div class="bd-formItem">
|
||||||
<div class="bd-formDivider"></div>
|
<h5>BetterDiscord</h5>
|
||||||
|
</div>
|
||||||
|
<div class="bd-formDivider"></div>
|
||||||
|
<div v-for="update in bdUpdates">
|
||||||
|
<UpdaterStatus :item="update" v-if="update.status.updating" />
|
||||||
|
<UpdaterToggle :item="update" :toggle="() => updater.toggleUpdate(update)" v-else />
|
||||||
|
<div class="bd-formDivider"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bd-formButton bd-button" @click="update">
|
||||||
|
Update
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="updatesAvailable">
|
|
||||||
<p>Version {{ newVersion }} is available. You are currently running version {{ currentVersion }}.</p>
|
|
||||||
<FormButton :onClick="install" :loading="updating">Install</FormButton>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<p>You're all up to date!</p>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</SettingsWrapper>
|
</SettingsWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
@ -32,7 +35,8 @@
|
||||||
import { Globals, Updater } from 'modules';
|
import { Globals, Updater } from 'modules';
|
||||||
import { ClientLogger as Logger } from 'common';
|
import { ClientLogger as Logger } from 'common';
|
||||||
import SettingsWrapper from './SettingsWrapper.vue';
|
import SettingsWrapper from './SettingsWrapper.vue';
|
||||||
import { FormButton } from '../common';
|
import UpdaterToggle from './UpdaterToggle.vue';
|
||||||
|
import UpdaterStatus from './UpdaterStatus.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
|
@ -44,26 +48,29 @@
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
SettingsWrapper,
|
SettingsWrapper,
|
||||||
FormButton
|
UpdaterToggle,
|
||||||
|
UpdaterStatus
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
updatesAvailable() {
|
updatesAvailable() {
|
||||||
return this.updater.updatesAvailable;
|
return this.updater.updatesAvailable;
|
||||||
},
|
},
|
||||||
newVersion() {
|
newVersion() {
|
||||||
return this.updater.latestVersion;
|
return '2.0.0-beta.4';
|
||||||
},
|
},
|
||||||
error() {
|
error() {
|
||||||
return this.updater.error;
|
return this.updater.error;
|
||||||
|
},
|
||||||
|
updates() {
|
||||||
|
return this.updater.updates;
|
||||||
|
},
|
||||||
|
bdUpdates() {
|
||||||
|
return this.updater.bdUpdates;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async install() {
|
update() {
|
||||||
this.updating = true;
|
this.updater.startUpdate();
|
||||||
try {
|
|
||||||
await this.updater.update();
|
|
||||||
} catch (err) {}
|
|
||||||
this.updating = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,8 @@ export { default as CssEditorView } from './CssEditor.vue';
|
||||||
export { default as PluginsView } from './PluginsView.vue';
|
export { default as PluginsView } from './PluginsView.vue';
|
||||||
export { default as ThemesView } from './ThemesView.vue';
|
export { default as ThemesView } from './ThemesView.vue';
|
||||||
export { default as UpdaterView } from './UpdaterView.vue';
|
export { default as UpdaterView } from './UpdaterView.vue';
|
||||||
|
export { default as UpdaterStatus } from './UpdaterStatus.vue';
|
||||||
|
export { default as UpdaterToggle } from './UpdaterToggle.vue';
|
||||||
export { default as BdBadge } from './BdBadge.vue';
|
export { default as BdBadge } from './BdBadge.vue';
|
||||||
export { default as ConnectivityView } from './ConnectivityView.vue';
|
export { default as ConnectivityView } from './ConnectivityView.vue';
|
||||||
|
export { default as SuperSecretView } from './SuperSecretView.vue';
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Utils, ClientLogger as Logger } from 'common';
|
import { Utils, ClientLogger as Logger } from 'common';
|
||||||
import { ReactComponents, Reflection, MonkeyPatch } from 'modules';
|
import { Reflection, MonkeyPatch } from 'modules';
|
||||||
import { VueInjector, Toasts } from 'ui';
|
import { VueInjector, Toasts } from 'ui';
|
||||||
import CMGroup from './components/contextmenu/Group.vue';
|
import CMGroup from './components/contextmenu/Group.vue';
|
||||||
|
|
||||||
|
|
|
@ -87,8 +87,7 @@ export default class extends Module {
|
||||||
async patchNameTag() {
|
async patchNameTag() {
|
||||||
if (this.PatchedNameTag) return this.PatchedNameTag;
|
if (this.PatchedNameTag) return this.PatchedNameTag;
|
||||||
|
|
||||||
const selector = Reflection.resolve('nameTag', 'username', 'discriminator', 'ownerIcon').selector;
|
const NameTag = await ReactComponents.getComponent('NameTag');
|
||||||
const NameTag = await ReactComponents.getComponent('NameTag', {selector});
|
|
||||||
|
|
||||||
this.PatchedNameTag = class extends NameTag.component {
|
this.PatchedNameTag = class extends NameTag.component {
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -9,6 +9,7 @@ export * from './contextmenus';
|
||||||
export { default as VueInjector } from './vueinjector';
|
export { default as VueInjector } from './vueinjector';
|
||||||
export { default as Reflection } from './reflection';
|
export { default as Reflection } from './reflection';
|
||||||
|
|
||||||
|
export { default as Autocomplete } from './autocomplete';
|
||||||
export { default as ProfileBadges } from './profilebadges';
|
export { default as ProfileBadges } from './profilebadges';
|
||||||
export { default as ClassNormaliser } from './classnormaliser';
|
export { default as ClassNormaliser } from './classnormaliser';
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ export default class {
|
||||||
|
|
||||||
get vueMount() {
|
get vueMount() {
|
||||||
const element = ReactDOM.findDOMNode(this);
|
const element = ReactDOM.findDOMNode(this);
|
||||||
if (!element) return;
|
if (!element) return null;
|
||||||
if (this.props.mountAtTop) return element;
|
if (this.props.mountAtTop) return element;
|
||||||
if (element.firstChild) return element.firstChild;
|
if (element.firstChild) return element.firstChild;
|
||||||
const newElement = document.createElement('span');
|
const newElement = document.createElement('span');
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||||
|
|
||||||
|
const jsLoader = {
|
||||||
|
test: /\.(js|jsx)$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const vueLoader = {
|
||||||
|
test: /\.(vue)$/,
|
||||||
|
use: 'vue-loader'
|
||||||
|
};
|
||||||
|
|
||||||
|
const scssLoader = {
|
||||||
|
test: /\.scss$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: ['css-loader', 'sass-loader']
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: './src/index.js',
|
||||||
|
module: {
|
||||||
|
rules: [jsLoader, vueLoader, scssLoader]
|
||||||
|
},
|
||||||
|
externals: {
|
||||||
|
electron: 'require("electron")',
|
||||||
|
fs: 'require("fs")',
|
||||||
|
path: 'require("path")',
|
||||||
|
util: 'require("util")',
|
||||||
|
process: 'require("process")',
|
||||||
|
net: 'require("net")',
|
||||||
|
request: 'require(require("path").join(require("electron").remote.app.getAppPath(), "node_modules", "request"))',
|
||||||
|
sparkplug: 'require("../../core/dist/sparkplug")',
|
||||||
|
'node-crypto': 'require("crypto")',
|
||||||
|
'child_process': 'require("child_process")'
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js')
|
||||||
|
},
|
||||||
|
modules: [
|
||||||
|
path.resolve('..', 'node_modules'),
|
||||||
|
path.resolve('..', 'common', 'modules'),
|
||||||
|
path.resolve('src', 'modules'),
|
||||||
|
path.resolve('src', 'ui'),
|
||||||
|
path.resolve('src', 'plugins'),
|
||||||
|
path.resolve('src', 'structs'),
|
||||||
|
path.resolve('src', 'builtin')
|
||||||
|
]
|
||||||
|
},
|
||||||
|
node: {
|
||||||
|
process: false,
|
||||||
|
__filename: false,
|
||||||
|
__dirname: false
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new VueLoaderPlugin()
|
||||||
|
]
|
||||||
|
};
|
|
@ -1,68 +1,22 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
const baseconfig = require('./webpack.base.config');
|
||||||
|
|
||||||
|
const merge = require('webpack-merge');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
|
||||||
const jsLoader = {
|
const config = {
|
||||||
test: /\.(js|jsx)$/,
|
mode: 'development',
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'babel-loader',
|
|
||||||
query: {
|
|
||||||
presets: ['react']
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const vueLoader = {
|
|
||||||
test: /\.(vue)$/,
|
|
||||||
loader: 'vue-loader'
|
|
||||||
};
|
|
||||||
|
|
||||||
const scssLoader = {
|
|
||||||
test: /\.scss$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: ['css-loader', 'sass-loader']
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: './src/index.js',
|
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
filename: 'betterdiscord.client.js'
|
filename: 'betterdiscord.client.js'
|
||||||
},
|
},
|
||||||
module: {
|
|
||||||
loaders: [jsLoader, vueLoader, scssLoader]
|
|
||||||
},
|
|
||||||
externals: {
|
|
||||||
electron: 'require("electron")',
|
|
||||||
asar: 'require("asar")',
|
|
||||||
fs: 'require("fs")',
|
|
||||||
path: 'require("path")',
|
|
||||||
util: 'require("util")',
|
|
||||||
process: 'require("process")',
|
|
||||||
net: 'require("net")',
|
|
||||||
request: 'require(require("path").join(require("electron").remote.app.getAppPath(), "node_modules", "request"))',
|
|
||||||
sparkplug: 'require("../../core/dist/sparkplug")',
|
|
||||||
'node-crypto': 'require("crypto")'
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js')
|
|
||||||
},
|
|
||||||
modules: [
|
|
||||||
path.resolve('..', 'node_modules'),
|
|
||||||
path.resolve('..', 'common', 'modules'),
|
|
||||||
path.resolve('src', 'modules'),
|
|
||||||
path.resolve('src', 'ui'),
|
|
||||||
path.resolve('src', 'plugins'),
|
|
||||||
path.resolve('src', 'structs'),
|
|
||||||
path.resolve('src', 'builtin')
|
|
||||||
]
|
|
||||||
},
|
|
||||||
node: {
|
|
||||||
process: false,
|
|
||||||
__filename: false,
|
|
||||||
__dirname: false
|
|
||||||
},
|
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.NamedModulesPlugin(),
|
new webpack.NamedModulesPlugin()
|
||||||
new webpack.EvalSourceMapDevToolPlugin()
|
],
|
||||||
]
|
externals: {
|
||||||
|
asar: 'require("asar")'
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports = merge(baseconfig, config);
|
||||||
|
|
|
@ -1,71 +1,24 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
const baseconfig = require('./webpack.base.config');
|
||||||
|
|
||||||
|
const merge = require('webpack-merge');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
|
||||||
|
|
||||||
const jsLoader = {
|
const config = {
|
||||||
test: /\.(js|jsx)$/,
|
mode: 'production',
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'babel-loader',
|
|
||||||
query: {
|
|
||||||
presets: ['react']
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const vueLoader = {
|
|
||||||
test: /\.(vue)$/,
|
|
||||||
loader: 'vue-loader'
|
|
||||||
};
|
|
||||||
|
|
||||||
const scssLoader = {
|
|
||||||
test: /\.scss$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: ['css-loader', 'sass-loader']
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: './src/index.js',
|
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
filename: 'betterdiscord.client-release.js'
|
filename: 'betterdiscord.client-release.js'
|
||||||
},
|
},
|
||||||
module: {
|
|
||||||
loaders: [jsLoader, vueLoader, scssLoader]
|
|
||||||
},
|
|
||||||
externals: {
|
|
||||||
electron: 'require("electron")',
|
|
||||||
fs: 'require("fs")',
|
|
||||||
path: 'require("path")',
|
|
||||||
util: 'require("util")',
|
|
||||||
process: 'require("process")',
|
|
||||||
net: 'require("net")',
|
|
||||||
request: 'require(require("path").join(require("electron").remote.app.getAppPath(), "node_modules", "request"))',
|
|
||||||
sparkplug: 'require("./sparkplug")',
|
|
||||||
'node-crypto': 'require("crypto")',
|
|
||||||
'child_process': 'require("child_process")'
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js')
|
|
||||||
},
|
|
||||||
modules: [
|
|
||||||
path.resolve('..', 'node_modules'),
|
|
||||||
path.resolve('..', 'common', 'modules'),
|
|
||||||
path.resolve('src', 'modules'),
|
|
||||||
path.resolve('src', 'ui'),
|
|
||||||
path.resolve('src', 'plugins'),
|
|
||||||
path.resolve('src', 'structs'),
|
|
||||||
path.resolve('src', 'builtin')
|
|
||||||
]
|
|
||||||
},
|
|
||||||
node: {
|
|
||||||
process: false,
|
|
||||||
__filename: false,
|
|
||||||
__dirname: false
|
|
||||||
},
|
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
PRODUCTION: JSON.stringify(true)
|
PRODUCTION: JSON.stringify(true)
|
||||||
}),
|
})
|
||||||
new UglifyJsPlugin()
|
],
|
||||||
]
|
externals: {
|
||||||
|
sparkplug: 'require("./sparkplug")'
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports = merge(baseconfig, config);
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord axios wrapper
|
||||||
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||||
|
* All rights reserved.
|
||||||
|
* https://betterdiscord.net
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
export default class AxiosWrapper {
|
||||||
|
|
||||||
|
static get axios() { return axios; }
|
||||||
|
|
||||||
|
static get github() {
|
||||||
|
return this._github ? this._github : (
|
||||||
|
this._github = {
|
||||||
|
main: this.create('https://github.com'),
|
||||||
|
api: this.create('https://api.github.com')
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get zl() {
|
||||||
|
return this._zl ? this._zl : (this._zl = {
|
||||||
|
api: this.create('https://zl', 1000, this.zlHeaders),
|
||||||
|
cdn: this.create('https://zl', 1000, this.zlHeaders)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(baseUrl, timeout = 1000, headers = null) {
|
||||||
|
return axios.create({ baseURL: baseUrl, timeout, headers: headers ? headers : this.defaultHeaders });
|
||||||
|
}
|
||||||
|
|
||||||
|
static get defaultHeaders() {
|
||||||
|
return {
|
||||||
|
'User-Agent': 'BetterDiscordApp User'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static get zlHeaders() {
|
||||||
|
return {
|
||||||
|
'User-Agent': 'BetterDiscordApp User',
|
||||||
|
'X-ZL-Apikey': '1a20cce89a2dbd163fc9570f3246c20891e62b2818ada55f82fa3d1d96fa7ef4',
|
||||||
|
'X-ZL-User': 'anonymous'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,3 +3,4 @@ export { default as Filters } from './filters';
|
||||||
export { default as Logger, ClientLogger } from './logger';
|
export { default as Logger, ClientLogger } from './logger';
|
||||||
export { default as ClientIPC } from './bdipc';
|
export { default as ClientIPC } from './bdipc';
|
||||||
export { default as AsyncEventEmitter } from './async-eventemitter';
|
export { default as AsyncEventEmitter } from './async-eventemitter';
|
||||||
|
export { default as Axi } from './axi';
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
module.exports = function(api) {
|
||||||
|
|
||||||
|
api.cache(true);
|
||||||
|
|
||||||
|
const presets = [['@babel/env', {
|
||||||
|
targets: {
|
||||||
|
'node': '8.6.0'
|
||||||
|
}
|
||||||
|
}]];
|
||||||
|
|
||||||
|
const plugins = [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
presets,
|
||||||
|
plugins
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "bdcore",
|
"name": "bdcore",
|
||||||
"description": "BetterDiscord core package",
|
"description": "BetterDiscord core package",
|
||||||
"author": "Jiiks",
|
"author": "Jiiks",
|
||||||
"version": "2.0.0b",
|
"version": "2.0.0-beta.6",
|
||||||
"homepage": "https://betterdiscord.net",
|
"homepage": "https://betterdiscord.net",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"img-src": [
|
||||||
|
"https://cdn.betterttv.net",
|
||||||
|
"https://cdn.frankerfacez.com",
|
||||||
|
"https://i.imgur.com"
|
||||||
|
],
|
||||||
|
"style-src": [
|
||||||
|
"https://fonts.googleapis.com"
|
||||||
|
],
|
||||||
|
"script-src": [
|
||||||
|
"'sha256-fSHKdpQGCHaIqWP3SpJOuUHrLp49jy4dWHzZ/RBJ/p4='",
|
||||||
|
"'sha256-VFJcfKY5B3EBkFDgQnv3CozPwBlZcxwssfLVWlPFfZU='",
|
||||||
|
"'sha256-VzDmLZ4PxPkOS/KY7ITzLQsSWhfCnvUrNculcj8UNgE='",
|
||||||
|
"'sha256-l6K+77Z1cmldR9gIvaVWlboF/zr5MXCQHcsEHfnr5TU='"
|
||||||
|
],
|
||||||
|
"connect-src": [
|
||||||
|
"https://github.com",
|
||||||
|
"https://api.github.com",
|
||||||
|
"https://betterdiscord.net",
|
||||||
|
"https://api.betterdiscord.net",
|
||||||
|
"https://cdn.betterdiscord.net",
|
||||||
|
"https://api.supersecretbdapiandcdn.net",
|
||||||
|
"https://cdn.supersecretbdapiandcdn.net"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
React Devtools: sha256-fSHKdpQGCHaIqWP3SpJOuUHrLp49jy4dWHzZ/RBJ/p4=
|
||||||
|
Vue Devtools: sha256-VFJcfKY5B3EBkFDgQnv3CozPwBlZcxwssfLVWlPFfZU=
|
||||||
|
Vue Detector: sha256-l6K+77Z1cmldR9gIvaVWlboF/zr5MXCQHcsEHfnr5TU=
|
|
@ -8,11 +8,24 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*PRODUCTION*/
|
||||||
const TESTS = typeof PRODUCTION === 'undefined';
|
const TESTS = typeof PRODUCTION === 'undefined';
|
||||||
const TEST_ARGS = () => {
|
const TEST_ARGS = () => {
|
||||||
const _basePath = path.resolve(__dirname, '..', '..');
|
const _basePath = path.resolve(__dirname, '..', '..');
|
||||||
const _baseDataPath = path.resolve(_basePath, 'tests');
|
const _baseDataPath = path.resolve(_basePath, 'tests');
|
||||||
|
|
||||||
|
const _corePkg = require(path.resolve(_basePath, 'core', 'package.json'));
|
||||||
|
const _clientPkg = require(path.resolve(_basePath, 'client', 'package.json'));
|
||||||
|
const _editorPkg = require(path.resolve(_basePath, 'editor', 'package.json'));
|
||||||
|
|
||||||
|
const coreVersion = _corePkg.version;
|
||||||
|
const clientVersion = _clientPkg.version;
|
||||||
|
const editorVersion = _editorPkg.version;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
coreVersion,
|
||||||
|
clientVersion,
|
||||||
|
editorVersion,
|
||||||
'options': {
|
'options': {
|
||||||
'autoInject': true,
|
'autoInject': true,
|
||||||
'commonCore': true,
|
'commonCore': true,
|
||||||
|
@ -22,12 +35,16 @@ const TEST_ARGS = () => {
|
||||||
'client': path.resolve(_basePath, 'client', 'dist'),
|
'client': path.resolve(_basePath, 'client', 'dist'),
|
||||||
'core': path.resolve(_basePath, 'core', 'dist'),
|
'core': path.resolve(_basePath, 'core', 'dist'),
|
||||||
'data': path.resolve(_baseDataPath, 'data'),
|
'data': path.resolve(_baseDataPath, 'data'),
|
||||||
'editor': path.resolve(_basePath, 'editor', 'dist')
|
'editor': path.resolve(_basePath, 'editor', 'dist'),
|
||||||
|
// tmp: path.join(_basePath, 'tmp')
|
||||||
|
tmp: path.join(os.tmpdir(), 'betterdiscord', `${process.getuid()}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const TEST_EDITOR = true;
|
const TEST_EDITOR = TESTS && true;
|
||||||
|
|
||||||
|
import process from 'process';
|
||||||
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import sass from 'node-sass';
|
import sass from 'node-sass';
|
||||||
import { BrowserWindow as OriginalBrowserWindow, dialog, session, shell } from 'electron';
|
import { BrowserWindow as OriginalBrowserWindow, dialog, session, shell } from 'electron';
|
||||||
|
@ -35,21 +52,13 @@ import deepmerge from 'deepmerge';
|
||||||
import ContentSecurityPolicy from 'csp-parse';
|
import ContentSecurityPolicy from 'csp-parse';
|
||||||
import keytar from 'keytar';
|
import keytar from 'keytar';
|
||||||
|
|
||||||
import { FileUtils, BDIpc, Config, WindowUtils, CSSEditor, Editor, Database } from './modules';
|
import { FileUtils, BDIpc, Config, WindowUtils, Updater, Editor, Database } from './modules';
|
||||||
|
|
||||||
const packageJson = require(path.resolve(__dirname, 'package.json'));
|
|
||||||
const sparkplug = path.resolve(__dirname, 'sparkplug.js');
|
const sparkplug = path.resolve(__dirname, 'sparkplug.js');
|
||||||
|
|
||||||
let configProxy;
|
let configProxy;
|
||||||
|
|
||||||
const CSP = {
|
const CSP = TESTS ? require('../src/csp.json') : require('./csp.json');
|
||||||
'img-src': ['https://cdn.betterttv.net', 'https://cdn.frankerfacez.com'],
|
|
||||||
'script-src': [
|
|
||||||
`'sha256-fSHKdpQGCHaIqWP3SpJOuUHrLp49jy4dWHzZ/RBJ/p4='`, // React Devtools
|
|
||||||
`'sha256-VFJcfKY5B3EBkFDgQnv3CozPwBlZcxwssfLVWlPFfZU='`, // Vue Devtools
|
|
||||||
`'sha256-VzDmLZ4PxPkOS/KY7ITzLQsSWhfCnvUrNculcj8UNgE=' 'sha256-l6K+77Z1cmldR9gIvaVWlboF/zr5MXCQHcsEHfnr5TU='` // Vue Detector
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
class Comms {
|
class Comms {
|
||||||
constructor(bd) {
|
constructor(bd) {
|
||||||
|
@ -195,6 +204,8 @@ export class BetterDiscord {
|
||||||
get config() { return this._config ? this._config : (this._config = new Config(this._args)); }
|
get config() { return this._config ? this._config : (this._config = new Config(this._args)); }
|
||||||
get window() { return this.windowUtils ? this.windowUtils.window : undefined; }
|
get window() { return this.windowUtils ? this.windowUtils.window : undefined; }
|
||||||
get editor() { return this._editor ? this._editor : (this._editor = new Editor(this, this.config.getPath('editor'))); }
|
get editor() { return this._editor ? this._editor : (this._editor = new Editor(this, this.config.getPath('editor'))); }
|
||||||
|
get updater() { return this._updater ? this._updater : (this._updater = new Updater(this)); }
|
||||||
|
get sendToDiscord() { return this.windowUtils.send; }
|
||||||
|
|
||||||
constructor(args) {
|
constructor(args) {
|
||||||
if (TESTS) args = TEST_ARGS();
|
if (TESTS) args = TEST_ARGS();
|
||||||
|
@ -209,13 +220,15 @@ export class BetterDiscord {
|
||||||
this.config.compatibility();
|
this.config.compatibility();
|
||||||
|
|
||||||
this.bindings();
|
this.bindings();
|
||||||
this.parseClientPackage();
|
|
||||||
this.extraPaths();
|
this.extraPaths();
|
||||||
this.database.init();
|
this.parseClientPackage();
|
||||||
|
this.parseEditorPackage();
|
||||||
|
this.parseCorePackage();
|
||||||
|
|
||||||
configProxy = () => this.config;
|
configProxy = () => this.config;
|
||||||
const autoInitComms = this.comms;
|
const autoInitComms = this.comms;
|
||||||
const autoInitEditor = this.editor;
|
const autoInitEditor = this.editor;
|
||||||
|
this.updater.start();
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +293,7 @@ export class BetterDiscord {
|
||||||
*/
|
*/
|
||||||
parseClientPackage() {
|
parseClientPackage() {
|
||||||
const clientPath = this.config.getPath('client');
|
const clientPath = this.config.getPath('client');
|
||||||
const clientPkg = TESTS ? require(`${path.resolve(clientPath, '..')}/package.json`) :require(`${clientPath}/package.json`);
|
const clientPkg = TESTS ? require(`${path.resolve(clientPath, '..')}/package.json`) : require(`${clientPath}/package.json`);
|
||||||
const { version } = clientPkg;
|
const { version } = clientPkg;
|
||||||
const main = TESTS ? 'betterdiscord.client.js' : clientPkg.main;
|
const main = TESTS ? 'betterdiscord.client.js' : clientPkg.main;
|
||||||
this.config.addPath('client_script', `${clientPath}/${main}`);
|
this.config.addPath('client_script', `${clientPath}/${main}`);
|
||||||
|
@ -288,6 +301,20 @@ export class BetterDiscord {
|
||||||
console.log(`[BetterDiscord] Client v${this.config.clientVersion} - ${this.config.getPath('client_script')}`);
|
console.log(`[BetterDiscord] Client v${this.config.clientVersion} - ${this.config.getPath('client_script')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parseCorePackage() {
|
||||||
|
const corePath = this.config.getPath('core');
|
||||||
|
const corePkg = TESTS ? require(`${path.resolve(corePath, '..')}/package.json`) : require(`${corePath}/package.json`);
|
||||||
|
const { version } = corePkg;
|
||||||
|
this.config.setCoreVersion(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseEditorPackage() {
|
||||||
|
const editorPath = this.config.getPath('editor');
|
||||||
|
const editorPkg = TESTS ? require(`${path.resolve(editorPath, '..')}/package.json`) : require(`${editorPath}/package.json`);
|
||||||
|
const { version } = editorPkg;
|
||||||
|
this.config.setEditorVersion(version);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add extra paths to config
|
* Add extra paths to config
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord axios wrapper
|
||||||
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||||
|
* All rights reserved.
|
||||||
|
* https://betterdiscord.net
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
export default class AxiosWrapper {
|
||||||
|
|
||||||
|
static get axios() { return axios; }
|
||||||
|
|
||||||
|
static get(url) { return axios.get(url) }
|
||||||
|
|
||||||
|
static get github() {
|
||||||
|
return this._github ? this._github : (
|
||||||
|
this._github = {
|
||||||
|
main: this.create('https://github.com'),
|
||||||
|
api: this.create('https://api.github.com')
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get zl() {
|
||||||
|
return this._zl ? this._zl : (this._zl = {
|
||||||
|
api: this.create('https://zl', 1000, this.zlHeaders),
|
||||||
|
cdn: this.create('https://zl', 1000, this.zlHeaders)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static create(baseUrl, timeout = 1000, headers = null) {
|
||||||
|
return axios.create({ baseURL: baseUrl, timeout, headers: headers ? headers : this.defaultHeaders });
|
||||||
|
}
|
||||||
|
|
||||||
|
static get defaultHeaders() {
|
||||||
|
return {
|
||||||
|
'User-Agent': 'BetterDiscordApp User'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static get zlHeaders() {
|
||||||
|
return {
|
||||||
|
'User-Agent': 'BetterDiscordApp User',
|
||||||
|
'X-ZL-Apikey': '1a20cce89a2dbd163fc9570f3246c20891e62b2818ada55f82fa3d1d96fa7ef4',
|
||||||
|
'X-ZL-User': 'anonymous'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,12 +16,36 @@ export default class Config extends Module {
|
||||||
return this.args.version;
|
return this.args.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get versions() {
|
||||||
|
return {
|
||||||
|
core: this.coreVersion,
|
||||||
|
client: this.clientVersion,
|
||||||
|
editor: this.editorVersion
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get coreVersion() {
|
||||||
|
return this.state.coreVersion;
|
||||||
|
}
|
||||||
|
|
||||||
get clientVersion() {
|
get clientVersion() {
|
||||||
return this.args.clientVersion;
|
return this.state.clientVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
get editorVersion() {
|
||||||
|
return this.state.editorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
setClientVersion(clientVersion) {
|
setClientVersion(clientVersion) {
|
||||||
this.args.clientVersion = clientVersion;
|
this.state.clientVersion = clientVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCoreVersion(coreVersion) {
|
||||||
|
this.state.coreVersion = coreVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
setEditorVersion(editorVersion) {
|
||||||
|
this.state.editorVersion = editorVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
get paths() {
|
get paths() {
|
||||||
|
@ -41,6 +65,7 @@ export default class Config extends Module {
|
||||||
get config() {
|
get config() {
|
||||||
return {
|
return {
|
||||||
version: this.version,
|
version: this.version,
|
||||||
|
versions: this.versions,
|
||||||
paths: this.paths
|
paths: this.paths
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,3 +4,4 @@ export { default as Config } from './config';
|
||||||
export { default as CSSEditor } from './csseditor';
|
export { default as CSSEditor } from './csseditor';
|
||||||
export { default as Editor } from './editor';
|
export { default as Editor } from './editor';
|
||||||
export { default as Database } from './database';
|
export { default as Database } from './database';
|
||||||
|
export { default as Updater } from './updater';
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
/**
|
/**
|
||||||
* Base Module that every non-static module should extend.
|
* Base Module that every non-static module should extend.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { default as BDIpc } from './bdipc';
|
||||||
|
|
||||||
export default class Module {
|
export default class Module {
|
||||||
|
|
||||||
constructor(args) {
|
constructor(args) {
|
||||||
|
@ -24,6 +27,7 @@ export default class Module {
|
||||||
init() {
|
init() {
|
||||||
if (this.bindings) this.bindings();
|
if (this.bindings) this.bindings();
|
||||||
if (this.setInitialState) this.setInitialState(this.state);
|
if (this.setInitialState) this.setInitialState(this.state);
|
||||||
|
if (this.events) this.events(BDIpc);
|
||||||
}
|
}
|
||||||
|
|
||||||
set args(t) {}
|
set args(t) {}
|
||||||
|
|
|
@ -0,0 +1,286 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Updater Module
|
||||||
|
* Copyright (c) 2015-present JsSucks - https://github.com/JsSucks
|
||||||
|
* All rights reserved.
|
||||||
|
* https://github.com/JsSucks - https://betterdiscord.net
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Module from './modulebase';
|
||||||
|
import { FileUtils } from './utils';
|
||||||
|
import semver from 'semver';
|
||||||
|
import Axi from './axi';
|
||||||
|
import zlib from 'zlib';
|
||||||
|
import tarfs from 'tar-fs';
|
||||||
|
|
||||||
|
const TEST_UPDATE = [
|
||||||
|
{
|
||||||
|
'id': 'core',
|
||||||
|
'version': '2.0.0-beta.5'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'client',
|
||||||
|
'version': '2.0.0-beta.5'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'editor',
|
||||||
|
'version': '0.4.1'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
class ReleaseInfo {
|
||||||
|
|
||||||
|
constructor(versions) {
|
||||||
|
this.versions = versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
get core() {
|
||||||
|
const f = this.files.find(f => f.id === 'core');
|
||||||
|
f.upToDate = semver.satisfies(this.versions.core, `>=${f.version}`, { includePrerelease: true });
|
||||||
|
f.currentVersion = this.versions.core;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
get client() {
|
||||||
|
const f = this.files.find(f => f.id === 'client');
|
||||||
|
f.upToDate = semver.satisfies(this.versions.client, `>=${f.version}`, { includePrerelease: true });
|
||||||
|
f.currentVersion = this.versions.client;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
get editor() {
|
||||||
|
const f = this.files.find(f => f.id === 'editor');
|
||||||
|
f.upToDate = semver.satisfies(this.versions.editor, `>=${f.version}`, { includePrerelease: true });
|
||||||
|
f.currentVersion = this.versions.editor;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
test() {
|
||||||
|
this.files = TEST_UPDATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Updater extends Module {
|
||||||
|
|
||||||
|
constructor(bd) {
|
||||||
|
super();
|
||||||
|
this.bd = bd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings() {
|
||||||
|
this.checkForUpdates = this.checkForUpdates.bind(this);
|
||||||
|
this.checkForBdUpdates = this.checkForBdUpdates.bind(this);
|
||||||
|
this.updateAll = this.updateAll.bind(this);
|
||||||
|
this.updateFinished = this.updateFinished.bind(this);
|
||||||
|
this.start = this.start.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
events(ipc) {
|
||||||
|
ipc.on('updater-startUpdate', (_, updates) => {
|
||||||
|
clearInterval(this.updaterThread);
|
||||||
|
this.updateAll(updates);
|
||||||
|
});
|
||||||
|
ipc.on('debug-updater-forceUpdate', () => {
|
||||||
|
this.checkForUpdates(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateBd(update) {
|
||||||
|
try {
|
||||||
|
console.log('[BetterDiscord:Updater] Updating', update.id);
|
||||||
|
await this.downloadTarGz(`https://github.com/JsSucks/BetterDiscordApp${update.remote}`, this.bd.config.getPath('base'));
|
||||||
|
this.updateFinished(update);
|
||||||
|
// Cleanup
|
||||||
|
await FileUtils.rm(`${this.bd.config.getPath(update.id)}_old`);
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[BetterDiscord:Updater] Failed to update', update.id);
|
||||||
|
console.log(err);
|
||||||
|
update.error = err;
|
||||||
|
this.bd.sendToDiscord('updater-updateError', update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAll(updates) {
|
||||||
|
const bd = updates.bd || [];
|
||||||
|
const plugins = updates.plugins || [];
|
||||||
|
const themes = updates.themes || [];
|
||||||
|
const modules = updates.modules || [];
|
||||||
|
|
||||||
|
this.restartRequired = this.reloadRequired = false;
|
||||||
|
this.finishedUpdates = 0;
|
||||||
|
this.totalUpdates = bd.length + plugins.length + themes.length + modules.length;
|
||||||
|
|
||||||
|
const renamed = [];
|
||||||
|
// TODO cleaner
|
||||||
|
if (bd.length) {
|
||||||
|
for (const update of bd) {
|
||||||
|
try {
|
||||||
|
await FileUtils.rm(`${this.bd.config.getPath(update.id)}_old`);
|
||||||
|
// Try to rename dirs first
|
||||||
|
await FileUtils.rn(this.bd.config.getPath(update.id), `${this.bd.config.getPath(update.id)}_old`);
|
||||||
|
renamed.push({ 'old': this.bd.config.getPath(update.id), 'new': `${this.bd.config.getPath(update.id)}_old`});
|
||||||
|
} catch (err) {
|
||||||
|
if (renamed.length) {
|
||||||
|
// Restore dirs
|
||||||
|
for (const r of renamed) {
|
||||||
|
await FileUtils.rn(r.new, r.old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const update of bd) {
|
||||||
|
this.updateBd(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFinished(update) {
|
||||||
|
if (update.id === 'core') this.restartRequired = true;
|
||||||
|
if (update.id === 'client') this.reloadRequired = true;
|
||||||
|
|
||||||
|
console.log('[BetterDiscord:Updater] Finished updating', update.id);
|
||||||
|
this.bd.sendToDiscord('updater-updateFinished', update);
|
||||||
|
|
||||||
|
this.finishedUpdates++;
|
||||||
|
if (this.finishedUpdates >= this.totalUpdates) {
|
||||||
|
this.bd.sendToDiscord('updater-updated', { restartRequired: this.restartRequired, reloadRequired: this.reloadRequired });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start(interval = 30) {
|
||||||
|
this.updaterThread = setInterval(this.checkForUpdates, interval * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(releaseInfo) {
|
||||||
|
return releaseInfo &&
|
||||||
|
typeof releaseInfo === 'object' &&
|
||||||
|
releaseInfo.files &&
|
||||||
|
Array.isArray(releaseInfo.files) &&
|
||||||
|
releaseInfo.files.length >= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
async latestRelease() {
|
||||||
|
try {
|
||||||
|
const release = await Axi.github.api.get('repos/JsSucks/BetterDiscordApp/releases/latest'); // TODO replace with config
|
||||||
|
const releaseInfoAsset = release.data.assets.find(asset => asset.name === 'releaseinfo.json');
|
||||||
|
const releaseInfo = await Axi.get(releaseInfoAsset['browser_download_url']);
|
||||||
|
|
||||||
|
if (this.validate(releaseInfo.data)) return releaseInfo.data;
|
||||||
|
return this.latestReleaseFallback();
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
return this.latestReleaseFallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async latestReleaseFallback() {
|
||||||
|
console.log('fallback');
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkForBdUpdates(forced = false) {
|
||||||
|
try {
|
||||||
|
const { coreVersion, clientVersion, editorVersion } = this.bd.config;
|
||||||
|
const releaseInfo = new ReleaseInfo({ core: coreVersion, client: clientVersion, editor: editorVersion });
|
||||||
|
|
||||||
|
const latestRelease = await this.latestRelease();
|
||||||
|
|
||||||
|
if (forced) {
|
||||||
|
latestRelease.files = latestRelease.files.map(file => {
|
||||||
|
file.version = '10.0.0';
|
||||||
|
return file;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseInfo.files = latestRelease.files;
|
||||||
|
|
||||||
|
const updates = [];
|
||||||
|
|
||||||
|
const { core, client, editor } = releaseInfo;
|
||||||
|
if (!core.upToDate) updates.push(core);
|
||||||
|
if (!client.upToDate) updates.push(client);
|
||||||
|
if (!editor.upToDate) updates.push(editor);
|
||||||
|
|
||||||
|
return updates;
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[BetterDiscord:Updater]', err);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkForUpdates(forced = false) {
|
||||||
|
console.log('[BetterDiscord:Updater] Checking for updates');
|
||||||
|
this.bd.sendToDiscord('updater-checkForUpdates', '');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const bd = await this.checkForBdUpdates(forced);
|
||||||
|
const updates = { bd, haveUpdates: false };
|
||||||
|
|
||||||
|
if (bd.length) updates.haveUpdates = true;
|
||||||
|
|
||||||
|
if (!updates.haveUpdates) {
|
||||||
|
this.bd.sendToDiscord('updater-noUpdates', '');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bd.sendToDiscord('updater-updatesAvailable', updates);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[BetterDiscord:Updater]', err);
|
||||||
|
this.bd.sendToDiscord('updater-error', err);
|
||||||
|
return 'err';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async downloadTarGz(url, dest, responseType = 'stream', headers = null) {
|
||||||
|
try {
|
||||||
|
const stream = await Axi.axios({
|
||||||
|
url,
|
||||||
|
type: 'GET',
|
||||||
|
responseType,
|
||||||
|
headers: headers ||
|
||||||
|
{
|
||||||
|
'Content-Type': 'application/octet-stream',
|
||||||
|
'Accept': 'application/octet-stream'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
stream.data.pipe(zlib.createGunzip()).pipe(tarfs.extract(dest)).on('finish', resolve).on('error', reject);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(releaseInfo) {
|
||||||
|
const { core, client, editor } = releaseInfo;
|
||||||
|
if (!core.upToDate) {
|
||||||
|
console.log(`[BetterDiscord:Updater] Core update available: ${core.currentVersion} > ${core.version}`);
|
||||||
|
} else {
|
||||||
|
console.log(`[BetterDiscord:Updater] Core up to date: ${core.currentVersion} = ${core.version}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!client.upToDate) {
|
||||||
|
console.log(`[BetterDiscord:Updater] Client update available: ${client.currentVersion} > ${client.version}`);
|
||||||
|
} else {
|
||||||
|
console.log(`[BetterDiscord:Updater] Client up to date: ${client.currentVersion} = ${client.version}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!editor.upToDate) {
|
||||||
|
console.log(`[BetterDiscord:Updater] Editor update available: ${editor.currentVersion} > ${editor.version}`);
|
||||||
|
} else {
|
||||||
|
console.log(`[BetterDiscord:Updater] Editor up to date: ${editor.currentVersion} = ${editor.version}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"name": "bdcsseditor",
|
|
||||||
"description": "BetterDiscord css editor package",
|
|
||||||
"author": "Jiiks",
|
|
||||||
"version": "0.4.0",
|
|
||||||
"homepage": "https://betterdiscord.net",
|
|
||||||
"license": "MIT",
|
|
||||||
"main": "dist/csseditor.js",
|
|
||||||
"contributors": [
|
|
||||||
"Jiiks",
|
|
||||||
"Pohky"
|
|
||||||
],
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/JsSucks/BetterDiscordApp.git"
|
|
||||||
},
|
|
||||||
"private": false,
|
|
||||||
"scripts": {
|
|
||||||
"build": "webpack --progress --colors",
|
|
||||||
"watch": "webpack --progress --colors --watch",
|
|
||||||
"release": "webpack --progress --colors --config=webpack.production.config.js"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,191 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="container">
|
|
||||||
<div class="titlebar">
|
|
||||||
<div class="draggable"></div>
|
|
||||||
<div class="icon">
|
|
||||||
<div class="inner"></div>
|
|
||||||
</div>
|
|
||||||
<div class="title">CSS Editor</div>
|
|
||||||
<div class="flex-spacer"></div>
|
|
||||||
<div class="controls">
|
|
||||||
<button :class="{active: alwaysOnTop}" ref="aot" title="Toggle always on top" @click="toggleaot">P</button>
|
|
||||||
<button title="Close CSS Editor" @click="close">X</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="spinner" v-if="loading">
|
|
||||||
<div class="valign">Loading Please Wait...</div>
|
|
||||||
</div>
|
|
||||||
<div id="editor" class="editor">
|
|
||||||
<codemirror ref="mycm" :options="cmOptions" @input="cmOnChange" />
|
|
||||||
</div>
|
|
||||||
<div class="parser-error" v-if="error">{{ error.formatted }}</div>
|
|
||||||
<div class="tools">
|
|
||||||
<div class="flex-row">
|
|
||||||
<button @click="save">Save</button>
|
|
||||||
<button @click="update">Update</button>
|
|
||||||
<div class="flex-spacer"></div>
|
|
||||||
<div id="chkboxLiveUpdate">
|
|
||||||
<label><input type="checkbox" @click="toggleLiveUpdate" v-model="liveUpdate" /><span>Live Update</span></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { ClientIPC } from 'common';
|
|
||||||
|
|
||||||
import { remote } from 'electron';
|
|
||||||
|
|
||||||
import 'codemirror/addon/scroll/simplescrollbars.js';
|
|
||||||
import 'codemirror/mode/css/css.js';
|
|
||||||
import 'codemirror/addon/hint/css-hint.js';
|
|
||||||
import 'codemirror/addon/search/search.js';
|
|
||||||
import 'codemirror/addon/search/searchcursor.js';
|
|
||||||
import 'codemirror/addon/search/jump-to-line.js';
|
|
||||||
import 'codemirror/addon/dialog/dialog.js';
|
|
||||||
import 'codemirror/addon/hint/show-hint.js';
|
|
||||||
|
|
||||||
const ExcludedIntelliSenseTriggerKeys = {
|
|
||||||
'8': 'backspace',
|
|
||||||
'9': 'tab',
|
|
||||||
'13': 'enter',
|
|
||||||
'16': 'shift',
|
|
||||||
'17': 'ctrl',
|
|
||||||
'18': 'alt',
|
|
||||||
'19': 'pause',
|
|
||||||
'20': 'capslock',
|
|
||||||
'27': 'escape',
|
|
||||||
'33': 'pageup',
|
|
||||||
'34': 'pagedown',
|
|
||||||
'35': 'end',
|
|
||||||
'36': 'home',
|
|
||||||
'37': 'left',
|
|
||||||
'38': 'up',
|
|
||||||
'39': 'right',
|
|
||||||
'40': 'down',
|
|
||||||
'45': 'insert',
|
|
||||||
'46': 'delete',
|
|
||||||
'91': 'left window key',
|
|
||||||
'92': 'right window key',
|
|
||||||
'93': 'select',
|
|
||||||
'107': 'add',
|
|
||||||
'109': 'subtract',
|
|
||||||
'110': 'decimal point',
|
|
||||||
'111': 'divide',
|
|
||||||
'112': 'f1',
|
|
||||||
'113': 'f2',
|
|
||||||
'114': 'f3',
|
|
||||||
'115': 'f4',
|
|
||||||
'116': 'f5',
|
|
||||||
'117': 'f6',
|
|
||||||
'118': 'f7',
|
|
||||||
'119': 'f8',
|
|
||||||
'120': 'f9',
|
|
||||||
'121': 'f10',
|
|
||||||
'122': 'f11',
|
|
||||||
'123': 'f12',
|
|
||||||
'144': 'numlock',
|
|
||||||
'145': 'scrolllock',
|
|
||||||
'186': 'semicolon',
|
|
||||||
'187': 'equalsign',
|
|
||||||
'188': 'comma',
|
|
||||||
'189': 'dash',
|
|
||||||
'190': 'period',
|
|
||||||
'191': 'slash',
|
|
||||||
'192': 'graveaccent',
|
|
||||||
'220': 'backslash',
|
|
||||||
'222': 'quote'
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loading: true,
|
|
||||||
codeMirror: null,
|
|
||||||
alwaysOnTop: false,
|
|
||||||
liveUpdate: false,
|
|
||||||
cmOptions: {
|
|
||||||
indentUnit: 4,
|
|
||||||
tabSize: 4,
|
|
||||||
mode: 'text/x-scss',
|
|
||||||
lineNumbers: true,
|
|
||||||
theme: 'material',
|
|
||||||
scrollbarStyle: 'overlay',
|
|
||||||
extraKeys: {
|
|
||||||
'Ctrl-Space': 'autocomplete'
|
|
||||||
},
|
|
||||||
dialog: {
|
|
||||||
'position': 'bottom'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
codemirror() {
|
|
||||||
return this.$refs.mycm.codemirror;
|
|
||||||
},
|
|
||||||
CodeMirror() {
|
|
||||||
return this.$refs.mycm;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
ClientIPC.on('set-scss', (_, scss) => this.setScss(scss));
|
|
||||||
|
|
||||||
ClientIPC.on('scss-error', (_, err) => {
|
|
||||||
this.error = err;
|
|
||||||
this.$forceUpdate();
|
|
||||||
if (err)
|
|
||||||
console.error('SCSS parse error:', err);
|
|
||||||
});
|
|
||||||
|
|
||||||
ClientIPC.on('set-liveupdate', (e, liveUpdate) => this.liveUpdate = liveUpdate);
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.codemirror.on('keyup', this.cmOnKeyUp);
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
this.setScss(await ClientIPC.sendToDiscord('get-scss'));
|
|
||||||
this.liveUpdate = await ClientIPC.sendToDiscord('get-liveupdate');
|
|
||||||
})();
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
liveUpdate(liveUpdate) {
|
|
||||||
ClientIPC.sendToDiscord('set-liveupdate', liveUpdate);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
save() {
|
|
||||||
const scss = this.codemirror.getValue();
|
|
||||||
ClientIPC.sendToDiscord('save-scss', scss);
|
|
||||||
},
|
|
||||||
update() {
|
|
||||||
const scss = this.codemirror.getValue();
|
|
||||||
ClientIPC.sendToDiscord('update-scss', scss);
|
|
||||||
},
|
|
||||||
toggleaot() {
|
|
||||||
this.alwaysOnTop = !this.alwaysOnTop;
|
|
||||||
remote.getCurrentWindow().setAlwaysOnTop(this.alwaysOnTop);
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
window.close();
|
|
||||||
},
|
|
||||||
setScss(scss) {
|
|
||||||
this.loading = false;
|
|
||||||
this.codemirror.setValue(scss || '');
|
|
||||||
},
|
|
||||||
cmOnChange(value) {
|
|
||||||
if(this.liveUpdate) ClientIPC.sendToDiscord('update-scss', value);
|
|
||||||
},
|
|
||||||
cmOnKeyUp(editor, event) {
|
|
||||||
if (event.ctrlKey) return;
|
|
||||||
if (ExcludedIntelliSenseTriggerKeys[event.keyCode]) return;
|
|
||||||
cmCommands.autocomplete(editor, null, { completeSingle: false });
|
|
||||||
},
|
|
||||||
toggleLiveUpdate(e) {
|
|
||||||
this.liveUpdate = !this.liveUpdate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,27 +0,0 @@
|
||||||
// const styles = require('./styles/index.scss');
|
|
||||||
|
|
||||||
import Vue from 'vue';
|
|
||||||
import VueCodemirror from 'vue-codemirror';
|
|
||||||
|
|
||||||
import Editor from './Editor.vue';
|
|
||||||
import styles from './styles/index.scss';
|
|
||||||
|
|
||||||
Vue.use(VueCodemirror, {});
|
|
||||||
|
|
||||||
window.cmCommands = VueCodemirror.CodeMirror.commands;
|
|
||||||
|
|
||||||
const mount = document.createElement('div');
|
|
||||||
mount.classList.add('container');
|
|
||||||
document.body.appendChild(mount);
|
|
||||||
|
|
||||||
const vue = new Vue({
|
|
||||||
el: mount,
|
|
||||||
components: { Editor },
|
|
||||||
template: '<Editor/>'
|
|
||||||
});
|
|
||||||
|
|
||||||
const style = document.createElement('style');
|
|
||||||
style.id = 'bd-main';
|
|
||||||
style.type = 'text/css';
|
|
||||||
style.appendChild(document.createTextNode(styles));
|
|
||||||
document.head.appendChild(style);
|
|
|
@ -1,105 +0,0 @@
|
||||||
.CodeMirror-scroll {
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-overlayscroll .CodeMirror-scrollbar-filler {
|
|
||||||
background: #38444a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-overlayscroll-horizontal div,
|
|
||||||
.CodeMirror-overlayscroll-vertical div {
|
|
||||||
background: rgb(41, 43, 47);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-overlayscroll-horizontal,
|
|
||||||
.CodeMirror-overlayscroll-horizontal div {
|
|
||||||
height: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-overlayscroll-vertical,
|
|
||||||
.CodeMirror-overlayscroll-vertical div {
|
|
||||||
width: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-scrollbar-filler {
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
background: rgb(41, 43, 47);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-material.CodeMirror {
|
|
||||||
background: #36393f;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-scroll {
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-material .CodeMirror-gutters {
|
|
||||||
background: #292b2f;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-gutter {
|
|
||||||
min-width: 34px;
|
|
||||||
border-right: 1px solid hsla(218,5%,47%,.3);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-hints {
|
|
||||||
/*background: #1e262a;*/
|
|
||||||
background: #292b2f;
|
|
||||||
box-shadow: 2px 3px 5px rgba(4, 4, 4, 0.22);
|
|
||||||
border: 1px solid #262f33;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background-color: rgba(0,0,0,.4);
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb,
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background-clip: padding-box;
|
|
||||||
border-width: 3px;
|
|
||||||
border-style: solid;
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background-color: transparent;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-linenumber,
|
|
||||||
.CodeMirror-line {
|
|
||||||
padding: 0 5px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-linenumber {
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cm-s-material .CodeMirror-linenumber {
|
|
||||||
color: #f6f6f7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-hint {
|
|
||||||
color: #bac9d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.CodeMirror-hint-active {
|
|
||||||
color: #bac9d2;
|
|
||||||
/*background: #3b4950;*/
|
|
||||||
background: #36393f;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-dialog-top {
|
|
||||||
bottom: 0;
|
|
||||||
top: auto;
|
|
||||||
border: none;
|
|
||||||
background: #1e262a;
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
.editor {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.vue-codemirror {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&, & .CodeMirror {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
$logoSmallGw: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkltYWdlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMiA1MTI7IiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGUgdHlwZT0idGV4dC9jc3MiPi5zdDB7ZGlzcGxheTpub25lO30uc3Qxe2Rpc3BsYXk6aW5saW5lO2ZpbGw6IzAyMDAzNTtzdHJva2U6IzAwMDAwMDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9LnN0MntmaWxsOiMzRUNDOUU7fS5zdDN7ZmlsbDojRkZGRkZGO308L3N0eWxlPjxnIGlkPSJMYXllcl8yIiBjbGFzcz0ic3QwIj48cmVjdCB4PSItNjQiIHk9Ii0zMiIgY2xhc3M9InN0MSIgd2lkdGg9IjYxOCIgaGVpZ2h0PSI1NzIiLz48L2c+PGcgaWQ9IkxheWVyXzEiIHhtbG5zOnZlY3Rvcm5hdG9yPSJodHRwOi8vdmVjdG9ybmF0b3IuaW8iPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik03MCwxOC44Yy0xMy43LDAtMjcuMywxMy43LTI3LjMsMjcuM3YyMzMuNkM0Mi43LDM5Ny43LDEzNy45LDQ5MywyNTYsNDkzYzI5LjcsMCw1OC02LjEsODMuNi0xN1YzNDEuNWMtMTksMjUuNi00OS4zLDQyLjItODMuNiw0Mi4yYy01Ny42LDAtMTA0LjEtNDYuNS0xMDQuMS0xMDQuMVY0Ni4xYzAtMTMuNy0xMy43LTI3LjMtMjcuMy0yNy4zSDcweiIvPjxwYXRoIGNsYXNzPSJzdDMiIGQ9Ik0zODcuNCwxOC44Yy0xMy43LDAtMjcuMywxMy43LTI3LjMsMjcuM3Y0Ny4zQzMyOS4zLDc2LjIsMjkzLjksNjYuMywyNTYsNjYuM2MtMjkuOCwwLTU3LjksNi4zLTgzLjYsMTcuM3YxMzQuMmMxOS0yNS42LDQ5LjMtNDIuMiw4My42LTQyLjJjNTcuNiwwLDEwNC4xLDQ2LjUsMTA0LjEsMTA0LjF2MTg2LjJjNjUuMi0zNi40LDEwOS4yLTEwNiwxMDkuMi0xODYuMlY0Ni4xYzAtMTguOC0xMy43LTI3LjMtMjcuMy0yNy4zSDM4Ny40eiIvPjwvZz48L3N2Zz4=);
|
|
||||||
$bdicon: $logoSmallGw;
|
|
|
@ -1,13 +0,0 @@
|
||||||
@import '../../../node_modules/codemirror/lib/codemirror.css';
|
|
||||||
@import '../../../node_modules/codemirror/theme/material.css';
|
|
||||||
@import '../../../node_modules/codemirror/addon/scroll/simplescrollbars.css';
|
|
||||||
@import '../../../node_modules/codemirror/addon/dialog/dialog.css';
|
|
||||||
@import '../../../node_modules/codemirror/addon/hint/show-hint.css';
|
|
||||||
|
|
||||||
@import './images.scss';
|
|
||||||
@import './main.scss';
|
|
||||||
@import './titlebar.scss';
|
|
||||||
@import './spinner.scss';
|
|
||||||
@import './editor.scss';
|
|
||||||
@import './tools.scss';
|
|
||||||
@import './codemirror.scss';
|
|
|
@ -1,36 +0,0 @@
|
||||||
html, body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
max-height: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: #2c383e;
|
|
||||||
min-width: 700px;
|
|
||||||
min-height: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-spacer {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-row {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.valign {
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
#spinner {
|
|
||||||
background: rgba(51, 48, 48, 0.41);
|
|
||||||
position: absolute;
|
|
||||||
top: 34px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
color: #bac9d2;
|
|
||||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 2em;
|
|
||||||
z-index: 90000;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
.titlebar {
|
|
||||||
display: flex;
|
|
||||||
height: 25px;
|
|
||||||
padding: 4px 5px;
|
|
||||||
background: #292b2f;
|
|
||||||
border-bottom: 1px solid hsla(218,5%,47%,.3);
|
|
||||||
user-select: none;
|
|
||||||
cursor: default;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 31px;
|
|
||||||
height: 25px;
|
|
||||||
|
|
||||||
.inner {
|
|
||||||
width: 25px;
|
|
||||||
height: 25px;
|
|
||||||
background-image: $bdicon;
|
|
||||||
background-size: 22px 22px;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
color: #bac9d2;
|
|
||||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
|
||||||
line-height: 25px;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.controls {
|
|
||||||
margin: 0 0 0 2px;
|
|
||||||
font-size: 0;
|
|
||||||
|
|
||||||
button {
|
|
||||||
-webkit-app-region: no-drag;
|
|
||||||
border-radius: 3px;
|
|
||||||
width: 25px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
background: #36393f;
|
|
||||||
color: #bac9d2;
|
|
||||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
|
||||||
transition: background-color .2s ease, color .2s ease;
|
|
||||||
cursor: default;
|
|
||||||
border: 0;
|
|
||||||
height: 25px;
|
|
||||||
z-index: 900062;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0 0 0 4px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: #44474e;
|
|
||||||
color: #FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: #3a71c1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.draggable {
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 63px;
|
|
||||||
position: absolute;
|
|
||||||
height: 33px;
|
|
||||||
-webkit-app-region: drag;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
.parser-error {
|
|
||||||
padding: 4px 6px;
|
|
||||||
background: #292b2f;
|
|
||||||
border-top: 1px solid hsla(218,5%,47%,.3);
|
|
||||||
color: #d84040;
|
|
||||||
font-family: monospace;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools {
|
|
||||||
height: 36px;
|
|
||||||
background: #292b2f;
|
|
||||||
border-top: 1px solid hsla(218,5%,47%,.3);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
.flex-row {
|
|
||||||
flex-grow: 1;
|
|
||||||
padding: 4px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 3px;
|
|
||||||
width: 100px;
|
|
||||||
padding: 3px 10px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
background: #36393f;
|
|
||||||
color: #bac9d2;
|
|
||||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
|
||||||
transition: background-color .2s ease, color .2s ease;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 0;
|
|
||||||
margin-right: 4px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: #44474e;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#chkboxLiveUpdate {
|
|
||||||
padding: 3px 10px;
|
|
||||||
line-height: 22px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
label {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="checkbox"] {
|
|
||||||
margin: 0 6px 0 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #bac9d2;
|
|
||||||
font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
const path = require('path');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
|
||||||
|
|
||||||
const vueLoader = {
|
|
||||||
test: /\.(vue)$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'vue-loader'
|
|
||||||
};
|
|
||||||
|
|
||||||
const scssLoader = {
|
|
||||||
test: /\.(css|scss)$/,
|
|
||||||
loader: ['css-loader', 'sass-loader']
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: './src/index.js',
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, 'dist'),
|
|
||||||
filename: 'csseditor-release.js'
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
loaders: [vueLoader, scssLoader]
|
|
||||||
},
|
|
||||||
externals: {
|
|
||||||
electron: 'window.require("electron")',
|
|
||||||
fs: 'window.require("fs")',
|
|
||||||
util: 'window.require("util")',
|
|
||||||
process: 'require("process")'
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js')
|
|
||||||
},
|
|
||||||
modules: [
|
|
||||||
path.resolve('..', 'node_modules'),
|
|
||||||
path.resolve('..', 'common', 'modules')
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
PRODUCTION: JSON.stringify(true)
|
|
||||||
}),
|
|
||||||
new UglifyJsPlugin()
|
|
||||||
]
|
|
||||||
};
|
|
|
@ -5,7 +5,7 @@
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"homepage": "https://betterdiscord.net",
|
"homepage": "https://betterdiscord.net",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/csseditor.js",
|
"main": "dist/editor.js",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"Jiiks",
|
"Jiiks",
|
||||||
"Pohky"
|
"Pohky"
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||||
|
|
||||||
const vueLoader = {
|
const vueLoader = {
|
||||||
test: /\.(vue)$/,
|
test: /\.(vue)$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: 'vue-loader'
|
use: 'vue-loader'
|
||||||
};
|
};
|
||||||
|
|
||||||
const scssLoader = {
|
const scssLoader = {
|
||||||
test: /\.(css|scss)$/,
|
test: /\.(css|scss)$/,
|
||||||
loader: ['css-loader', 'sass-loader']
|
use: ['css-loader', 'sass-loader']
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: './src/index.js',
|
entry: './src/index.js',
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, 'dist'),
|
|
||||||
filename: 'csseditor.js'
|
|
||||||
},
|
|
||||||
module: {
|
module: {
|
||||||
loaders: [vueLoader, scssLoader]
|
rules: [vueLoader, scssLoader]
|
||||||
},
|
},
|
||||||
externals: {
|
externals: {
|
||||||
electron: 'window.require("electron")',
|
electron: 'window.require("electron")',
|
||||||
|
@ -35,5 +31,8 @@ module.exports = {
|
||||||
path.resolve('..', 'node_modules'),
|
path.resolve('..', 'node_modules'),
|
||||||
path.resolve('..', 'common', 'modules')
|
path.resolve('..', 'common', 'modules')
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
plugins: [
|
||||||
|
new VueLoaderPlugin()
|
||||||
|
]
|
||||||
};
|
};
|
|
@ -1,39 +1,16 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
const baseconfig = require('./webpack.base.config');
|
||||||
|
|
||||||
|
const merge = require('webpack-merge');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
|
||||||
const vueLoader = {
|
const config = {
|
||||||
test: /\.(vue)$/,
|
mode: 'development',
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'vue-loader'
|
|
||||||
};
|
|
||||||
|
|
||||||
const scssLoader = {
|
|
||||||
test: /\.(css|scss)$/,
|
|
||||||
loader: ['css-loader', 'sass-loader']
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: './src/index.js',
|
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
filename: 'editor.js'
|
filename: 'editor.js'
|
||||||
},
|
|
||||||
module: {
|
|
||||||
loaders: [vueLoader, scssLoader]
|
|
||||||
},
|
|
||||||
externals: {
|
|
||||||
electron: 'window.require("electron")',
|
|
||||||
fs: 'window.require("fs")',
|
|
||||||
util: 'window.require("util")',
|
|
||||||
process: 'require("process")'
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js')
|
|
||||||
},
|
|
||||||
modules: [
|
|
||||||
path.resolve('..', 'node_modules'),
|
|
||||||
path.resolve('..', 'common', 'modules')
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports = merge(baseconfig, config);
|
||||||
|
|
|
@ -1,43 +1,16 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
const baseconfig = require('./webpack.base.config');
|
||||||
|
|
||||||
|
const merge = require('webpack-merge');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
|
||||||
|
|
||||||
const vueLoader = {
|
const config = {
|
||||||
test: /\.(vue)$/,
|
mode: 'production',
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'vue-loader'
|
|
||||||
};
|
|
||||||
|
|
||||||
const scssLoader = {
|
|
||||||
test: /\.(css|scss)$/,
|
|
||||||
loader: ['css-loader', 'sass-loader']
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: './src/index.js',
|
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
filename: 'editor.release.js'
|
filename: 'editor.release.js'
|
||||||
},
|
}
|
||||||
module: {
|
|
||||||
loaders: [vueLoader, scssLoader]
|
|
||||||
},
|
|
||||||
externals: {
|
|
||||||
electron: 'window.require("electron")',
|
|
||||||
fs: 'window.require("fs")',
|
|
||||||
util: 'window.require("util")',
|
|
||||||
process: 'require("process")'
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
vue$: path.resolve('..', 'node_modules', 'vue', 'dist', 'vue.esm.js')
|
|
||||||
},
|
|
||||||
modules: [
|
|
||||||
path.resolve('..', 'node_modules'),
|
|
||||||
path.resolve('..', 'common', 'modules')
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new UglifyJsPlugin()
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports = merge(baseconfig, config);
|
||||||
|
|
|
@ -4,7 +4,8 @@ import del from 'del';
|
||||||
import copy from 'gulp-copy';
|
import copy from 'gulp-copy';
|
||||||
import rename from 'gulp-rename';
|
import rename from 'gulp-rename';
|
||||||
import inject from 'gulp-inject-string';
|
import inject from 'gulp-inject-string';
|
||||||
import copydeps from 'gulp-npm-copy-deps';
|
import replace from 'gulp-replace';
|
||||||
|
import copydeps from './scripts/copydeps';
|
||||||
import file from 'gulp-file';
|
import file from 'gulp-file';
|
||||||
import editjson from 'gulp-json-editor';
|
import editjson from 'gulp-json-editor';
|
||||||
|
|
||||||
|
@ -14,10 +15,10 @@ import editorpkg from './editor/package';
|
||||||
|
|
||||||
// core-release >
|
// core-release >
|
||||||
|
|
||||||
gulp.task('core-main', function () {
|
gulp.task('core-main', function() {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('core/dist/main.js'),
|
gulp.src('core/dist/main.js'),
|
||||||
inject.after(`'use strict';\n`, 'const PRODUCTION = true;\n'),
|
replace('/*PRODUCTION*/', 'const PRODUCTION = true;'),
|
||||||
rename(`core.${corepkg.version}.js`),
|
rename(`core.${corepkg.version}.js`),
|
||||||
gulp.dest('release/core')
|
gulp.dest('release/core')
|
||||||
]);
|
]);
|
||||||
|
@ -36,27 +37,34 @@ gulp.task('core-pkg', function() {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('core-modules', function () {
|
gulp.task('core-modules', function() {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('core/dist/modules/**/*'),
|
gulp.src('core/dist/modules/**/*'),
|
||||||
copy('release/core', { prefix: 2 })
|
copy('release/core', { prefix: 2 })
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('core-sparkplug', function () {
|
gulp.task('core-sparkplug', function() {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('core/dist/sparkplug.js'),
|
gulp.src('core/dist/sparkplug.js'),
|
||||||
gulp.dest('release/core')
|
gulp.dest('release/core')
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('core-release', gulp.parallel('core-main', 'core-pkg', 'core-sparkplug', 'core-modules'));
|
gulp.task('core-extras', function() {
|
||||||
|
return pump([
|
||||||
|
gulp.src(['core/src/csp.json']),
|
||||||
|
gulp.dest('release/core')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('core-release', gulp.parallel('core-main', 'core-pkg', 'core-sparkplug', 'core-modules', 'core-extras'));
|
||||||
|
|
||||||
// < core-release
|
// < core-release
|
||||||
|
|
||||||
// client
|
// client
|
||||||
|
|
||||||
gulp.task('client-main', function () {
|
gulp.task('client-main', function() {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('client/dist/*.client-release.js'),
|
gulp.src('client/dist/*.client-release.js'),
|
||||||
rename(`client.${clientpkg.version}.js`),
|
rename(`client.${clientpkg.version}.js`),
|
||||||
|
@ -76,7 +84,7 @@ gulp.task('client-pkg', function() {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('client-sparkplug', function () {
|
gulp.task('client-sparkplug', function() {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('core/dist/sparkplug.js'),
|
gulp.src('core/dist/sparkplug.js'),
|
||||||
gulp.dest('release/client')
|
gulp.dest('release/client')
|
||||||
|
@ -87,7 +95,7 @@ gulp.task('client-release', gulp.parallel('client-main', 'client-pkg', 'client-s
|
||||||
|
|
||||||
// Editor
|
// Editor
|
||||||
|
|
||||||
gulp.task('editor-main', function () {
|
gulp.task('editor-main', function() {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('editor/dist/editor.release.js'),
|
gulp.src('editor/dist/editor.release.js'),
|
||||||
rename(`editor.${editorpkg.version}.js`),
|
rename(`editor.${editorpkg.version}.js`),
|
||||||
|
@ -95,10 +103,10 @@ gulp.task('editor-main', function () {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('editor-pkg', function () {
|
gulp.task('editor-pkg', function() {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('editor/package.json'),
|
gulp.src('editor/package.json'),
|
||||||
editjson(function (pkg) {
|
editjson(function(pkg) {
|
||||||
pkg.main = `editor.${editorpkg.version}.js`;
|
pkg.main = `editor.${editorpkg.version}.js`;
|
||||||
delete pkg.scripts;
|
delete pkg.scripts;
|
||||||
return pkg;
|
return pkg;
|
||||||
|
@ -111,22 +119,25 @@ gulp.task('editor-release', gulp.parallel('editor-main', 'editor-pkg'));
|
||||||
|
|
||||||
// Deps
|
// Deps
|
||||||
|
|
||||||
gulp.task('node-modules', function () {
|
gulp.task('node-modules', function() {
|
||||||
return copydeps('.', 'release/core');
|
return pump([
|
||||||
|
gulp.src(copydeps({ignore: ['fsevents']}), { base: '.' }),
|
||||||
|
gulp.dest('./release/core')
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('node-sass-bindings', gulp.series(function () {
|
gulp.task('node-sass-bindings', gulp.series(function() {
|
||||||
return del(['release/node_modules/node-sass/vendor']);
|
return del(['release/node_modules/node-sass/vendor']);
|
||||||
}, function () {
|
}, function() {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('other/node_sass_bindings/**/*'),
|
gulp.src('other/node_sass_bindings/**/*'),
|
||||||
copy('release/core/node_modules/node-sass/vendor', { prefix: 2 })
|
copy('release/core/node_modules/node-sass/vendor', { prefix: 2 })
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
gulp.task('keytar-bindings', gulp.series(function () {
|
gulp.task('keytar-bindings', gulp.series(function() {
|
||||||
return del(['release/node_modules/keytar/build']);
|
return del(['release/node_modules/keytar/build']);
|
||||||
}, function () {
|
}, function() {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('other/keytar/**/*'),
|
gulp.src('other/keytar/**/*'),
|
||||||
copy('release/core/node_modules/keytar/build/Release', { prefix: 2 })
|
copy('release/core/node_modules/keytar/build/Release', { prefix: 2 })
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
const
|
const
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
webpack = require('webpack'),
|
webpack = require('webpack'),
|
||||||
HtmlWebpackPlugin = require('html-webpack-plugin');
|
HtmlWebpackPlugin = require('html-webpack-plugin'),
|
||||||
|
VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||||
|
|
||||||
const vueLoader = {
|
const vueLoader = {
|
||||||
test: /\.(vue)$/,
|
test: /\.(vue)$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: 'vue-loader'
|
use: 'vue-loader'
|
||||||
};
|
};
|
||||||
|
|
||||||
const scssLoader = {
|
const scssLoader = {
|
||||||
test: /\.(css|scss)$/,
|
test: /\.(css|scss)$/,
|
||||||
loader: ['css-loader', 'sass-loader']
|
use: ['css-loader', 'sass-loader']
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -21,7 +22,7 @@ module.exports = {
|
||||||
filename: 'installer.js'
|
filename: 'installer.js'
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
loaders: [vueLoader, scssLoader]
|
rules: [vueLoader, scssLoader]
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
@ -31,6 +32,7 @@ module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: './src/index.html'
|
template: './src/index.html'
|
||||||
})
|
}),
|
||||||
|
new VueLoaderPlugin()
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
### node-keytar bindings
|
### node-keytar bindings
|
||||||
|
|
||||||
Copy this directory to `node_modules/keytar/build/Release/keytar.node` to use.
|
Copy this directory to `node_modules/keytar/build/Release/keytar.node` to use.
|
||||||
|
|
||||||
keytar-4.3.0/linux-x64-64.node - poweredge-t30.fancy.org.uk
|
|
||||||
All others - https://github.com/atom/node-keytar/releases
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
const keytar_version = require('keytar/package').version;
|
const keytar_version = require('keytar/package').version;
|
||||||
|
|
||||||
// module.exports = require('./keytar-' + process.platform + '-' + process.versions.modules + '-' + process.arch + '.node');
|
|
||||||
module.exports = require(`./keytar-${keytar_version}/${process.platform}-${process.arch}-${process.versions.modules}.node`);
|
module.exports = require(`./keytar-${keytar_version}/${process.platform}-${process.arch}-${process.versions.modules}.node`);
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue