Merge pull request #284 from JsSucks/installer-compliance
Installer compliance
This commit is contained in:
commit
d3db696616
|
@ -12,3 +12,4 @@ user.config.json
|
||||||
/.vs
|
/.vs
|
||||||
/npm-debug.log
|
/npm-debug.log
|
||||||
/tests/ext/extensions
|
/tests/ext/extensions
|
||||||
|
/tests/userdata
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
import { DOM, BdUI, BdMenu, Modals, Toasts, Notifications, BdContextMenu, DiscordContextMenu } from 'ui';
|
import { DOM, BdUI, BdMenu, Modals, Toasts, Notifications, BdContextMenu, DiscordContextMenu } from 'ui';
|
||||||
import BdCss from './styles/index.scss';
|
import BdCss from './styles/index.scss';
|
||||||
import { Events, CssEditor, 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 } 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';
|
||||||
|
@ -18,7 +18,7 @@ import path from 'path';
|
||||||
import { setTimeout } from 'timers';
|
import { setTimeout } from 'timers';
|
||||||
|
|
||||||
const tests = typeof PRODUCTION === 'undefined';
|
const tests = typeof PRODUCTION === 'undefined';
|
||||||
const ignoreExternal = false;
|
const ignoreExternal = true;
|
||||||
|
|
||||||
class BetterDiscord {
|
class BetterDiscord {
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ class BetterDiscord {
|
||||||
this._bd = {
|
this._bd = {
|
||||||
DOM, BdUI, BdMenu, Modals, Reflection, Toasts, Notifications, BdContextMenu, DiscordContextMenu,
|
DOM, BdUI, BdMenu, Modals, Reflection, Toasts, Notifications, BdContextMenu, DiscordContextMenu,
|
||||||
|
|
||||||
Events, CssEditor, Globals, Settings, Database, Updater,
|
Events, Globals, Settings, Database, Updater,
|
||||||
ModuleManager, PluginManager, ThemeManager, ExtModuleManager, PackageInstaller,
|
ModuleManager, PluginManager, ThemeManager, ExtModuleManager, PackageInstaller,
|
||||||
Vendor,
|
Vendor,
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,14 @@ export default new class {
|
||||||
ClientIPC.on('bd-get-scss', () => this.scss, true);
|
ClientIPC.on('bd-get-scss', () => this.scss, true);
|
||||||
ClientIPC.on('bd-update-scss', (e, scss) => this.updateScss(scss));
|
ClientIPC.on('bd-update-scss', (e, scss) => this.updateScss(scss));
|
||||||
ClientIPC.on('bd-save-csseditor-bounds', (e, bounds) => this.saveEditorBounds(bounds));
|
ClientIPC.on('bd-save-csseditor-bounds', (e, bounds) => this.saveEditorBounds(bounds));
|
||||||
|
ClientIPC.on('bd-editor-runScript', (e, script) => {
|
||||||
|
try {
|
||||||
|
new Function(script)();
|
||||||
|
e.reply('ok');
|
||||||
|
} catch (err) {
|
||||||
|
e.reply({ err: err.stack || err });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ClientIPC.on('bd-save-scss', async (e, scss) => {
|
ClientIPC.on('bd-save-scss', async (e, scss) => {
|
||||||
await this.updateScss(scss);
|
await this.updateScss(scss);
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Editor Module
|
||||||
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
||||||
|
* All rights reserved.
|
||||||
|
* https://betterdiscord.net
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Module from './imodule';
|
||||||
|
import { DOM } from 'ui';
|
||||||
|
|
||||||
|
export default new class extends Module {
|
||||||
|
|
||||||
|
get name() { return 'Editor' }
|
||||||
|
get delay() { return false; }
|
||||||
|
|
||||||
|
setInitialState(state) {
|
||||||
|
return {
|
||||||
|
editorBounds: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
super.initialize();
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
// TODO this is temporary
|
||||||
|
const userScss = await this.send('readDataFile', 'user.scss');
|
||||||
|
const compiled = await this.send('compileSass', { data: userScss });
|
||||||
|
this.injectStyle('customcss', compiled.css.toString());
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('SCSS Compilation error', err);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
events(ipc) {
|
||||||
|
ipc.on('editor-runScript', (e, script) => {
|
||||||
|
try {
|
||||||
|
new Function(script)();
|
||||||
|
e.reply('ok');
|
||||||
|
} catch (err) {
|
||||||
|
e.reply({ err: err.stack || err });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipc.on('editor-injectStyle', (e, { id, style }) => {
|
||||||
|
this.injectStyle(id, style);
|
||||||
|
e.reply('ok');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
injectStyle(id, style) {
|
||||||
|
return DOM.injectStyle(style, `userstyle-${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show editor, flashes if already visible.
|
||||||
|
*/
|
||||||
|
async show() {
|
||||||
|
await this.send('editor-open', this.state.editorBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Module Base
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Module that every non-static module should extend
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ClientLogger as Logger, ClientIPC } from 'common';
|
||||||
|
|
||||||
|
export default class Module {
|
||||||
|
|
||||||
|
constructor(args) {
|
||||||
|
this.__ = {
|
||||||
|
state: args || {},
|
||||||
|
args
|
||||||
|
};
|
||||||
|
this.setState = this.setState.bind(this);
|
||||||
|
|
||||||
|
if (this.delay) { // If delay is set then module is set to load delayed from modulemanager
|
||||||
|
this.initialize = this.initialize.bind(this);
|
||||||
|
this.init = this.initialize;
|
||||||
|
} else {
|
||||||
|
this.initialize();
|
||||||
|
this.init = () => { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
if (this.bindings) this.bindings();
|
||||||
|
if (this.setInitialState) this.setState(this.setInitialState(this.state));
|
||||||
|
if (this.events) this.events(ClientIPC);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(newState) {
|
||||||
|
const oldState = this.state;
|
||||||
|
Object.assign(this.state, newState);
|
||||||
|
if (this.stateChanged) this.stateChanged(oldState, newState);
|
||||||
|
}
|
||||||
|
|
||||||
|
set args(t) { }
|
||||||
|
get args() { return this.__.args; }
|
||||||
|
|
||||||
|
set state(state) { return this.__.state = state; }
|
||||||
|
get state() { return this.__.state; }
|
||||||
|
|
||||||
|
async send(channel, message) {
|
||||||
|
return ClientIPC.send(channel, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
log(msg) {
|
||||||
|
Logger.log(this.name, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
warn(msg) {
|
||||||
|
Logger.log(this.name, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
err(msg) {
|
||||||
|
Logger.log(this.name, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
info(msg) {
|
||||||
|
Logger.log(this.name, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,7 +9,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ClientLogger as Logger } from 'common';
|
import { ClientLogger as Logger } from 'common';
|
||||||
import { SocketProxy, EventHook, CssEditor } from 'modules';
|
import { SocketProxy, EventHook } from 'modules';
|
||||||
import { ProfileBadges, ClassNormaliser } from 'ui';
|
import { ProfileBadges, ClassNormaliser } from 'ui';
|
||||||
import Updater from './updater';
|
import Updater from './updater';
|
||||||
|
|
||||||
|
@ -27,7 +27,6 @@ export default class {
|
||||||
new ClassNormaliser(),
|
new ClassNormaliser(),
|
||||||
new SocketProxy(),
|
new SocketProxy(),
|
||||||
new EventHook(),
|
new EventHook(),
|
||||||
CssEditor,
|
|
||||||
Updater
|
Updater
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
export { default as Events } from './events';
|
export { default as Events } from './events';
|
||||||
export { default as CssEditor } from './csseditor';
|
export { default as CssEditor } from './csseditor';
|
||||||
|
export { default as Editor } from './editor';
|
||||||
export { default as Globals } from './globals';
|
export { default as Globals } from './globals';
|
||||||
export { default as Settings } from './settings';
|
export { default as Settings } from './settings';
|
||||||
export { default as Database } from './database';
|
export { default as Database } from './database';
|
||||||
|
|
|
@ -1,122 +1,125 @@
|
||||||
.bd-settingsButton {
|
.bd-settingsButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
top: 22px;
|
top: 22px;
|
||||||
width: 70px;
|
width: 70px;
|
||||||
height: 48px;
|
|
||||||
left: 0;
|
|
||||||
box-shadow: 0 1px 0 rgba(0, 0, 0, .2), 0 2px 0 rgba(0, 0, 0, .06);
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
.platform-darwin & { // sass-lint:disable-line class-name-format
|
|
||||||
top: 27px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.platform-linux & { // sass-lint:disable-line class-name-format
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bd-settingsButtonBtn {
|
|
||||||
backface-visibility: hidden;
|
|
||||||
-webkit-backface-visibility: hidden;
|
|
||||||
width: 70px;
|
|
||||||
height: 48px;
|
height: 48px;
|
||||||
cursor: pointer;
|
left: 0;
|
||||||
filter: grayscale(100%);
|
box-shadow: 0 1px 0 rgba(0, 0, 0, .2), 0 2px 0 rgba(0, 0, 0, .06);
|
||||||
opacity: .5;
|
opacity: 1;
|
||||||
position: relative;
|
|
||||||
transition: all .3s cubic-bezier(.4,0,0,1);
|
|
||||||
|
|
||||||
&::before,
|
.platform-darwin & { // sass-lint:disable-line class-name-format
|
||||||
&::after {
|
top: 27px;
|
||||||
content:"";
|
}
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top:0;
|
|
||||||
left:0;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
.platform-linux & { // sass-lint:disable-line class-name-format
|
||||||
width: 70px;
|
top: 0;
|
||||||
height: 48px;
|
}
|
||||||
background-image: $logoSmallBw;
|
|
||||||
background-size: 50% 50%;
|
|
||||||
opacity: 1;
|
|
||||||
transition:all .3s cubic-bezier(.4,0,0,1), opacity .01s;
|
|
||||||
}
|
|
||||||
&::after {
|
|
||||||
width: 130px;
|
|
||||||
height: 43px;
|
|
||||||
background-image: $logoBigBw;
|
|
||||||
background-size: 100% 100%;
|
|
||||||
transform:translate(-7px,2px)scale(0.5);
|
|
||||||
opacity: 0;
|
|
||||||
transition:all .3s cubic-bezier(.4,0,0,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.bd-loading) {
|
.bd-settingsButtonBtn {
|
||||||
&:hover {
|
backface-visibility: hidden;
|
||||||
filter: none;
|
-webkit-backface-visibility: hidden;
|
||||||
opacity: 1;
|
width: 70px;
|
||||||
}
|
height: 48px;
|
||||||
}
|
cursor: pointer;
|
||||||
|
filter: grayscale(100%);
|
||||||
|
opacity: .5;
|
||||||
|
position: relative;
|
||||||
|
transition: all .3s cubic-bezier(.4, 0, 0, 1);
|
||||||
|
|
||||||
&.bd-loading {
|
&::before,
|
||||||
animation: bd-settingsButtonPulse 1.5s infinite;
|
&::after {
|
||||||
}
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
&.bd-updates {
|
&::before {
|
||||||
filter: hue-rotate(250deg) !important; // sass-lint:disable-line no-important
|
width: 70px;
|
||||||
opacity: 1 !important; // sass-lint:disable-line no-important
|
height: 48px;
|
||||||
}
|
background-image: $logoSmallBw;
|
||||||
}
|
background-size: 50% 50%;
|
||||||
|
opacity: 1;
|
||||||
|
transition: all .3s cubic-bezier(.4, 0, 0, 1), opacity .01s;
|
||||||
|
}
|
||||||
|
|
||||||
&.bd-hideButton {
|
&::after {
|
||||||
animation: bd-fadeOut .4s ease-out;
|
width: 130px;
|
||||||
|
height: 43px;
|
||||||
|
background-image: $logoBigBw;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
transform: translate(-7px, 2px) scale(.5);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all .3s cubic-bezier(.4, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
&.bd-active {
|
&:not(.bd-loading) {
|
||||||
animation: bd-fadeIn .4s ease-in;
|
&:hover {
|
||||||
}
|
filter: none;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:not(.bd-active) {
|
&.bd-loading {
|
||||||
&:not(.bd-animating) {
|
animation: bd-settingsButtonPulse 1.5s infinite;
|
||||||
display: none;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.bd-active {
|
&.bd-updates {
|
||||||
opacity: 1;
|
filter: hue-rotate(250deg) !important; // sass-lint:disable-line no-important
|
||||||
}
|
opacity: 1 !important; // sass-lint:disable-line no-important
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.bd-active,
|
&.bd-hideButton {
|
||||||
&.bd-hideButton {
|
animation: bd-fadeOut .4s ease-out;
|
||||||
background: transparent;
|
|
||||||
box-shadow: none;
|
|
||||||
|
|
||||||
.bd-settingsButtonBtn {
|
&.bd-active {
|
||||||
filter: none;
|
animation: bd-fadeIn .4s ease-in;
|
||||||
opacity: 1;
|
}
|
||||||
width: 130px;
|
|
||||||
height: 43px;
|
|
||||||
transform:translate(25px,18px);
|
|
||||||
cursor: default;
|
|
||||||
&::before{
|
|
||||||
opacity:0;
|
|
||||||
transform:translate(-16px,-3px)scale(1.9);
|
|
||||||
transition:all .3s cubic-bezier(.4,0,0,1), opacity .1s .3s;
|
|
||||||
}
|
|
||||||
&::after{
|
|
||||||
opacity: 1;
|
|
||||||
transform:scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.bd-active,
|
&:not(.bd-active) {
|
||||||
&.bd-animating {
|
&:not(.bd-animating) {
|
||||||
z-index: 3001;
|
display: none;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bd-active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bd-active,
|
||||||
|
&.bd-hideButton {
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
.bd-settingsButtonBtn {
|
||||||
|
filter: none;
|
||||||
|
opacity: 1;
|
||||||
|
width: 130px;
|
||||||
|
height: 43px;
|
||||||
|
transform: translate(25px, 18px);
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-16px, -3px) scale(1.9);
|
||||||
|
transition: all .3s cubic-bezier(.4, 0, 0, 1), opacity .1s .3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bd-active,
|
||||||
|
&.bd-animating {
|
||||||
|
z-index: 3001;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,180 +1,180 @@
|
||||||
.bd-settings {
|
.bd-settings {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
backface-visibility: hidden;
|
backface-visibility: hidden;
|
||||||
-webkit-backface-visibility: hidden;
|
-webkit-backface-visibility: hidden;
|
||||||
top: 22px;
|
top: 22px;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
width: 310px;
|
width: 310px;
|
||||||
transform: translateX(-310px);
|
transform: translateX(-310px);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: transform .3s cubic-bezier(.4,0,0,1), opacity .25s ease;
|
transition: transform .3s cubic-bezier(.4, 0, 0, 1), opacity .25s ease;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
&.bd-active {
|
&.bd-active {
|
||||||
width: 900px;
|
width: 900px;
|
||||||
transform: none;
|
transform: none;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-settingsX {
|
.bd-settingsX {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 18px;
|
top: 18px;
|
||||||
left: 255px;
|
left: 255px;
|
||||||
border: 2px solid #6e6e6e;
|
border: 2px solid #6e6e6e;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.platform-darwin & { // sass-lint:disable-line class-name-format
|
.platform-darwin & { // sass-lint:disable-line class-name-format
|
||||||
top: 43px;
|
top: 43px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-xText {
|
.bd-xText {
|
||||||
color: #72767d;
|
color: #72767d;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 32px;
|
top: 32px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-materialDesignIcon {
|
.bd-materialDesignIcon {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
fill: #72767d;
|
fill: #72767d;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: hsla(218, 5%, 47%, .3);
|
background-color: hsla(218, 5%, 47%, .3);
|
||||||
|
|
||||||
.bd-materialDesignIcon {
|
.bd-materialDesignIcon {
|
||||||
fill: #fff;
|
fill: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-info {
|
.bd-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 0 25px;
|
padding: 0 25px;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
|
|
||||||
.bd-vtext {
|
.bd-vtext {
|
||||||
color: #414245;
|
color: #414245;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-materialButton {
|
.bd-materialButton {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.bd-materialDesignIcon {
|
.bd-materialDesignIcon {
|
||||||
fill: #fff;
|
fill: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-materialDesignIcon {
|
.bd-materialDesignIcon {
|
||||||
fill: #414245;
|
fill: #414245;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
fill: #fff;
|
fill: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-sidebarView {
|
.bd-sidebarView {
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 310px;
|
width: 310px;
|
||||||
background-color: #202225;
|
background-color: #202225;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-sidebarRegion {
|
.bd-sidebarRegion {
|
||||||
.bd-scroller {
|
.bd-scroller {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-contentRegion {
|
.bd-contentRegion {
|
||||||
width: 590px;
|
width: 590px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.bd-active {
|
&.bd-active {
|
||||||
.bd-contentRegion {
|
.bd-contentRegion {
|
||||||
transition: all .3s cubic-bezier(.4,0,0,1);
|
transition: all .3s cubic-bezier(.4, 0, 0, 1);
|
||||||
transform: none;
|
transform: none;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.bd-stop {
|
&.bd-stop {
|
||||||
.bd-sidebarRegion {
|
.bd-sidebarRegion {
|
||||||
z-index: 1003;
|
z-index: 1003;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-contentRegion {
|
.bd-contentRegion {
|
||||||
z-index: 1002;
|
z-index: 1002;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.platform-darwin & { // sass-lint:disable-line class-name-format
|
.platform-darwin & { // sass-lint:disable-line class-name-format
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
||||||
.bd-sidebarView {
|
.bd-sidebarView {
|
||||||
.bd-sidebarRegion {
|
.bd-sidebarRegion {
|
||||||
padding-top: 22px;
|
padding-top: 22px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.platform-linux & { // sass-lint:disable-line class-name-format
|
.platform-linux & { // sass-lint:disable-line class-name-format
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.bd-active) > .bd-sidebarView.bd-active, // sass-lint:disable-line force-element-nesting
|
&:not(.bd-active) > .bd-sidebarView.bd-active, // sass-lint:disable-line force-element-nesting
|
||||||
&.bd-settingsOut .bd-sidebarView.bd-active { // sass-lint:disable-line force-element-nesting
|
&.bd-settingsOut .bd-sidebarView.bd-active { // sass-lint:disable-line force-element-nesting
|
||||||
.bd-contentRegion {
|
.bd-contentRegion {
|
||||||
transform: translate(-600px, 0%);
|
transform: translate(-600px, 0%);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
width: 590px;
|
width: 590px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.bd-active) {
|
&:not(.bd-active) {
|
||||||
.bd-sidebarView {
|
.bd-sidebarView {
|
||||||
&.bd-active {
|
&.bd-active {
|
||||||
.bd-contentRegion {
|
.bd-contentRegion {
|
||||||
transform: translate(-600px, 100%);
|
transform: translate(-600px, 100%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-sidebar {
|
.bd-sidebar {
|
||||||
.bd-settingsButton {
|
.bd-settingsButton {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
||||||
.platform-darwin & { // sass-lint:disable-line class-name-format
|
.platform-darwin & { // sass-lint:disable-line class-name-format
|
||||||
top: 22px;
|
top: 22px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,21 +28,23 @@
|
||||||
|
|
||||||
.bd-chevron1 {
|
.bd-chevron1 {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
svg{
|
|
||||||
|
svg {
|
||||||
transform: scale(1) translateY(0);
|
transform: scale(1) translateY(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-chevron2{
|
.bd-chevron2 {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
svg{
|
|
||||||
|
svg {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
transform: scale(1.4,.5) translateY(6px) rotate(180deg);
|
transform: scale(1.4, .5) translateY(6px) rotate(180deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
transition: transform .2s cubic-bezier(.2,0,0,1);
|
transition: transform .2s cubic-bezier(.2, 0, 0, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +81,7 @@
|
||||||
.bd-drawerOpenButton {
|
.bd-drawerOpenButton {
|
||||||
.bd-chevron1 {
|
.bd-chevron1 {
|
||||||
svg {
|
svg {
|
||||||
transform: scale(1.4,.5) translateY(-6px);
|
transform: scale(1.4, .5) translateY(-6px);
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
bottom: 3px;
|
bottom: 3px;
|
||||||
background: #f6f6f7;
|
background: #f6f6f7;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
transition: all .15s cubic-bezier(.2,0,0,1);
|
transition: all .15s cubic-bezier(.2, 0, 0, 1);
|
||||||
box-shadow: 0 3px 1px 0 rgba(0, 0, 0, .05), 0 2px 2px 0 rgba(0, 0, 0, .1), 0 3px 3px 0 rgba(0, 0, 0, .05);
|
box-shadow: 0 3px 1px 0 rgba(0, 0, 0, .05), 0 2px 2px 0 rgba(0, 0, 0, .1), 0 3px 3px 0 rgba(0, 0, 0, .05);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,50 +1,51 @@
|
||||||
.bd-sidebar {
|
.bd-sidebar {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
.bd-header {
|
.bd-header {
|
||||||
padding: 6px 0;
|
padding: 6px 0;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
color: rgba(255, 255, 255, .15);
|
color: rgba(255, 255, 255, .15);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif;
|
font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bd-item {
|
.bd-item {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
padding-bottom: 6px;
|
padding-bottom: 6px;
|
||||||
padding-top: 6px;
|
padding-top: 6px;
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
color: $coldimwhite;
|
color: $coldimwhite;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif;
|
font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(185,185,185,.1);
|
background-color: rgba(185, 185, 185, .1);
|
||||||
color: #f6f6f6;
|
color: #f6f6f6;
|
||||||
}
|
}
|
||||||
&.bd-active {
|
|
||||||
background: $colbdgreen;
|
&.bd-active {
|
||||||
color: #fff;
|
background: $colbdgreen;
|
||||||
cursor: default;
|
color: #fff;
|
||||||
}
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// TODO this should be remade as editor instead of css editor
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<SettingsWrapper headertext="CSS Editor">
|
<SettingsWrapper headertext="CSS Editor">
|
||||||
<div class="bd-cssEditor">
|
<div class="bd-cssEditor">
|
||||||
|
@ -49,7 +51,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Imports
|
// Imports
|
||||||
import { Settings, CssEditor } from 'modules';
|
import { Settings, Editor } from 'modules';
|
||||||
import { SettingsWrapper } from './';
|
import { SettingsWrapper } from './';
|
||||||
import { FormButton } from '../common';
|
import { FormButton } from '../common';
|
||||||
import SettingsPanel from './SettingsPanel.vue';
|
import SettingsPanel from './SettingsPanel.vue';
|
||||||
|
@ -64,18 +66,18 @@
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
CssEditor
|
Editor
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
error() {
|
error() {
|
||||||
return this.CssEditor.error;
|
return this.Editor.error;
|
||||||
},
|
},
|
||||||
compiling() {
|
compiling() {
|
||||||
return this.CssEditor.compiling;
|
return this.Editor.compiling;
|
||||||
},
|
},
|
||||||
systemEditorPath() {
|
systemEditorPath() {
|
||||||
return this.CssEditor.filePath;
|
return this.Editor.filePath;
|
||||||
},
|
},
|
||||||
liveUpdateSetting() {
|
liveUpdateSetting() {
|
||||||
return Settings.getSetting('css', 'default', 'live-update');
|
return Settings.getSetting('css', 'default', 'live-update');
|
||||||
|
@ -92,13 +94,13 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openInternalEditor() {
|
openInternalEditor() {
|
||||||
this.CssEditor.show();
|
this.Editor.show();
|
||||||
},
|
},
|
||||||
openSystemEditor() {
|
openSystemEditor() {
|
||||||
this.CssEditor.openSystemEditor();
|
// this.Editor.openSystemEditor();
|
||||||
},
|
},
|
||||||
recompile() {
|
recompile() {
|
||||||
this.CssEditor.recompile();
|
// this.Editor.recompile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,8 @@ module.exports = {
|
||||||
net: 'require("net")',
|
net: 'require("net")',
|
||||||
request: 'require(require("path").join(require("electron").remote.app.getAppPath(), "node_modules", "request"))',
|
request: 'require(require("path").join(require("electron").remote.app.getAppPath(), "node_modules", "request"))',
|
||||||
sparkplug: 'require("./sparkplug")',
|
sparkplug: 'require("./sparkplug")',
|
||||||
'node-crypto': 'require("crypto")'
|
'node-crypto': 'require("crypto")',
|
||||||
|
'child_process': 'require("child_process")'
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
|
310
core/src/main.js
310
core/src/main.js
|
@ -8,52 +8,39 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const TESTS = typeof PRODUCTION === 'undefined';
|
||||||
|
const TEST_ARGS = () => {
|
||||||
|
const _basePath = path.resolve(__dirname, '..', '..');
|
||||||
|
const _baseDataPath = path.resolve(_basePath, 'tests');
|
||||||
|
return {
|
||||||
|
'options': {
|
||||||
|
'autoInject': true,
|
||||||
|
'commonCore': true,
|
||||||
|
'commonData': true
|
||||||
|
},
|
||||||
|
'paths': {
|
||||||
|
'client': path.resolve(_basePath, 'client', 'dist'),
|
||||||
|
'core': path.resolve(_basePath, 'core', 'dist'),
|
||||||
|
'data': path.resolve(_baseDataPath, 'data'),
|
||||||
|
'editor': path.resolve(_basePath, 'editor', 'dist')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const TEST_EDITOR = true;
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import sass from 'node-sass';
|
import sass from 'node-sass';
|
||||||
import { BrowserWindow as OriginalBrowserWindow, dialog, session } from 'electron';
|
import { BrowserWindow as OriginalBrowserWindow, dialog, session, shell } from 'electron';
|
||||||
import deepmerge from 'deepmerge';
|
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, Database } from './modules';
|
import { FileUtils, BDIpc, Config, WindowUtils, CSSEditor, Editor, Database } from './modules';
|
||||||
|
|
||||||
const tests = typeof PRODUCTION === 'undefined';
|
|
||||||
|
|
||||||
const _basePath = tests ? path.resolve(__dirname, '..', '..') : __dirname;
|
|
||||||
const _baseDataPath = tests ? path.resolve(_basePath, 'tests') : _basePath;
|
|
||||||
|
|
||||||
|
const packageJson = require(path.resolve(__dirname, 'package.json'));
|
||||||
const sparkplug = path.resolve(__dirname, 'sparkplug.js');
|
const sparkplug = path.resolve(__dirname, 'sparkplug.js');
|
||||||
|
|
||||||
const _clientScript = tests
|
let configProxy;
|
||||||
? path.resolve(_basePath, 'client', 'dist', 'betterdiscord.client.js')
|
|
||||||
: path.resolve(_basePath, 'betterdiscord.client.js');
|
|
||||||
const _cssEditorPath = tests
|
|
||||||
? path.resolve(__dirname, '..', '..', 'csseditor', 'dist')
|
|
||||||
: path.resolve(__dirname, 'csseditor');
|
|
||||||
|
|
||||||
const _dataPath = path.resolve(_baseDataPath, 'data');
|
|
||||||
const _extPath = path.resolve(_baseDataPath, 'ext');
|
|
||||||
const _pluginPath = path.resolve(_extPath, 'plugins');
|
|
||||||
const _themePath = path.resolve(_extPath, 'themes');
|
|
||||||
const _modulePath = path.resolve(_extPath, 'modules');
|
|
||||||
|
|
||||||
const version = require(path.resolve(_basePath, 'package.json')).version;
|
|
||||||
|
|
||||||
const paths = [
|
|
||||||
{ id: 'base', path: _basePath },
|
|
||||||
{ id: 'cs', path: _clientScript },
|
|
||||||
{ id: 'data', path: _dataPath },
|
|
||||||
{ id: 'ext', path: _extPath },
|
|
||||||
{ id: 'plugins', path: _pluginPath },
|
|
||||||
{ id: 'themes', path: _themePath },
|
|
||||||
{ id: 'modules', path: _modulePath },
|
|
||||||
{ id: 'csseditor', path: _cssEditorPath }
|
|
||||||
];
|
|
||||||
|
|
||||||
const globals = {
|
|
||||||
version,
|
|
||||||
paths
|
|
||||||
};
|
|
||||||
|
|
||||||
const CSP = {
|
const CSP = {
|
||||||
'img-src': ['https://cdn.betterttv.net', 'https://cdn.frankerfacez.com'],
|
'img-src': ['https://cdn.betterttv.net', 'https://cdn.frankerfacez.com'],
|
||||||
|
@ -64,45 +51,6 @@ const CSP = {
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
class BrowserWindow extends OriginalBrowserWindow {
|
|
||||||
constructor(originalOptions) {
|
|
||||||
const userOptions = BrowserWindow.userWindowPreferences;
|
|
||||||
|
|
||||||
const options = deepmerge(originalOptions, userOptions);
|
|
||||||
options.webPreferences = Object.assign({}, options.webPreferences);
|
|
||||||
|
|
||||||
// Make sure Node integration is enabled
|
|
||||||
options.webPreferences.preload = sparkplug;
|
|
||||||
|
|
||||||
super(options);
|
|
||||||
|
|
||||||
Object.defineProperty(this, '__bd_preload', {value: []});
|
|
||||||
|
|
||||||
if (originalOptions.webPreferences && originalOptions.webPreferences.preload) {
|
|
||||||
this.__bd_preload.push(originalOptions.webPreferences.preload);
|
|
||||||
}
|
|
||||||
if (userOptions.webPreferences && userOptions.webPreferences.preload) {
|
|
||||||
this.__bd_preload.push(path.resolve(_dataPath, userOptions.webPreferences.preload));
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.defineProperty(this, '__bd_options', {value: options});
|
|
||||||
Object.freeze(options);
|
|
||||||
Object.freeze(options.webPreferences);
|
|
||||||
Object.freeze(this.__bd_preload);
|
|
||||||
}
|
|
||||||
|
|
||||||
static get userWindowPreferences() {
|
|
||||||
try {
|
|
||||||
const userWindowPreferences = require(path.join(_dataPath, 'window'));
|
|
||||||
if (typeof userWindowPreferences === 'object') return userWindowPreferences;
|
|
||||||
} catch (err) {
|
|
||||||
console.log('[BetterDiscord] Error getting window preferences:', err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Comms {
|
class Comms {
|
||||||
constructor(bd) {
|
constructor(bd) {
|
||||||
this.bd = bd;
|
this.bd = bd;
|
||||||
|
@ -116,8 +64,9 @@ class Comms {
|
||||||
|
|
||||||
BDIpc.on('bd-sendToDiscord', (event, m) => this.sendToDiscord(m.channel, m.message), true);
|
BDIpc.on('bd-sendToDiscord', (event, m) => this.sendToDiscord(m.channel, m.message), true);
|
||||||
|
|
||||||
BDIpc.on('bd-openCssEditor', (event, options) => this.bd.csseditor.openEditor(options), true);
|
// BDIpc.on('bd-openCssEditor', (event, options) => this.bd.csseditor.openEditor(options), true);
|
||||||
BDIpc.on('bd-sendToCssEditor', (event, m) => this.sendToCssEditor(m.channel, m.message), true);
|
// BDIpc.on('bd-sendToCssEditor', (event, m) => this.sendToCssEditor(m.channel, m.message), true);
|
||||||
|
// BDIpc.on('bd-openCssEditor', (event, options) => this.bd.editor.openEditor(options), true);
|
||||||
|
|
||||||
BDIpc.on('bd-native-open', (event, options) => {
|
BDIpc.on('bd-native-open', (event, options) => {
|
||||||
dialog.showOpenDialog(OriginalBrowserWindow.fromWebContents(event.ipcEvent.sender), options, filenames => {
|
dialog.showOpenDialog(OriginalBrowserWindow.fromWebContents(event.ipcEvent.sender), options, filenames => {
|
||||||
|
@ -137,12 +86,54 @@ class Comms {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
BDIpc.on('bd-dba', (event, options) => this.bd.dbInstance.exec(options), true);
|
BDIpc.on('bd-dba', (event, options) => this.bd.database.exec(options), true);
|
||||||
|
|
||||||
BDIpc.on('bd-keytar-get', (event, {service, account}) => keytar.getPassword(service, account), true);
|
BDIpc.on('bd-keytar-get', (event, { service, account }) => keytar.getPassword(service, account), true);
|
||||||
BDIpc.on('bd-keytar-set', (event, {service, account, password}) => keytar.setPassword(service, account, password), true);
|
BDIpc.on('bd-keytar-set', (event, { service, account, password }) => keytar.setPassword(service, account, password), true);
|
||||||
BDIpc.on('bd-keytar-delete', (event, {service, account}) => keytar.deletePassword(service, account), true);
|
BDIpc.on('bd-keytar-delete', (event, { service, account }) => keytar.deletePassword(service, account), true);
|
||||||
BDIpc.on('bd-keytar-find-credentials', (event, {service}) => keytar.findCredentials(service), true);
|
BDIpc.on('bd-keytar-find-credentials', (event, { service }) => keytar.findCredentials(service), true);
|
||||||
|
|
||||||
|
BDIpc.on('bd-readDataFile', async (event, fileName) => {
|
||||||
|
const rf = await FileUtils.readFile(path.resolve(configProxy().getPath('data'), fileName));
|
||||||
|
event.reply(rf);
|
||||||
|
});
|
||||||
|
|
||||||
|
BDIpc.on('bd-explorer', (_, _path) => {
|
||||||
|
if (_path.static) _path = this.bd.config.getPath(_path.static);
|
||||||
|
else if (_path.full) _path = _path.full;
|
||||||
|
else if (_path.sub) _path = path.resolve(this.bd.config.getPath(_path.sub.base), [..._path.sub.subs]);
|
||||||
|
try {
|
||||||
|
shell.openItem(_path);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BDIpc.on('bd-getPath', (event, paths) => {
|
||||||
|
event.reply(path.resolve(this.bd.config.getPath(paths[0]), ...paths.splice(1)));
|
||||||
|
});
|
||||||
|
|
||||||
|
BDIpc.on('bd-rmFile', async (event, paths) => {
|
||||||
|
const fullPath = path.resolve(this.bd.config.getPath(paths[0]), ...paths.splice(1));
|
||||||
|
try {
|
||||||
|
await FileUtils.rm(fullPath);
|
||||||
|
event.reply('ok');
|
||||||
|
} catch (err) {
|
||||||
|
event.reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BDIpc.on('bd-rnFile', async (event, paths) => {
|
||||||
|
const oldPath = path.resolve(this.bd.config.getPath(paths.oldName[0]), ...paths.oldName.splice(1));
|
||||||
|
const newPath = path.resolve(this.bd.config.getPath(paths.newName[0]), ...paths.newName.splice(1));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await FileUtils.rn(oldPath, newPath);
|
||||||
|
event.reply('ok');
|
||||||
|
} catch (err) {
|
||||||
|
event.reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async send(channel, message) {
|
async send(channel, message) {
|
||||||
|
@ -158,38 +149,86 @@ class Comms {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BrowserWindow extends OriginalBrowserWindow {
|
||||||
|
constructor(originalOptions) {
|
||||||
|
const userOptions = BrowserWindow.userWindowPreferences;
|
||||||
|
|
||||||
|
const options = deepmerge(originalOptions, userOptions);
|
||||||
|
options.webPreferences = Object.assign({}, options.webPreferences);
|
||||||
|
|
||||||
|
// Make sure Node integration is enabled
|
||||||
|
options.webPreferences.preload = sparkplug;
|
||||||
|
|
||||||
|
super(options);
|
||||||
|
|
||||||
|
Object.defineProperty(this, '__bd_preload', { value: [] });
|
||||||
|
|
||||||
|
if (originalOptions.webPreferences && originalOptions.webPreferences.preload) {
|
||||||
|
this.__bd_preload.push(originalOptions.webPreferences.preload);
|
||||||
|
}
|
||||||
|
if (userOptions.webPreferences && userOptions.webPreferences.preload) {
|
||||||
|
this.__bd_preload.push(path.resolve(configProxy().getPath('data'), userOptions.webPreferences.preload));
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(this, '__bd_options', { value: options });
|
||||||
|
Object.freeze(options);
|
||||||
|
Object.freeze(options.webPreferences);
|
||||||
|
Object.freeze(this.__bd_preload);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get userWindowPreferences() {
|
||||||
|
try {
|
||||||
|
const userWindowPreferences = require(path.join(configProxy().getPath('data'), 'window'));
|
||||||
|
if (typeof userWindowPreferences === 'object') return userWindowPreferences;
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[BetterDiscord] Error getting window preferences:', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class BetterDiscord {
|
export class BetterDiscord {
|
||||||
|
|
||||||
|
get comms() { return this._comms ? this._comms : (this._commas = new Comms(this)); }
|
||||||
|
get database() { return this._db ? this._db : (this._db = new Database(this.config.getPath('data'))); }
|
||||||
|
get config() { return this._config ? this._config : (this._config = new Config(this._args)); }
|
||||||
|
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'))); }
|
||||||
|
|
||||||
constructor(args) {
|
constructor(args) {
|
||||||
|
if (TESTS) args = TEST_ARGS();
|
||||||
|
console.log('[BetterDiscord|args] ', JSON.stringify(args, null, 4));
|
||||||
if (BetterDiscord.loaded) {
|
if (BetterDiscord.loaded) {
|
||||||
console.log('Creating two BetterDiscord objects???');
|
console.log('[BetterDiscord] Creating two BetterDiscord objects???');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
BetterDiscord.loaded = true;
|
BetterDiscord.loaded = true;
|
||||||
|
this._args = args;
|
||||||
|
this.config.compatibility();
|
||||||
|
|
||||||
this.injectScripts = this.injectScripts.bind(this);
|
this.bindings();
|
||||||
this.ignite = this.ignite.bind(this);
|
this.parseClientPackage();
|
||||||
|
this.extraPaths();
|
||||||
this.config = new Config(args || globals);
|
this.database.init();
|
||||||
this.dbInstance = new Database(this.config.getPath('data'));
|
|
||||||
this.comms = new Comms(this);
|
|
||||||
|
|
||||||
|
configProxy = () => this.config;
|
||||||
|
const autoInitComms = this.comms;
|
||||||
|
const autoInitEditor = this.editor;
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindings() {
|
||||||
|
this.injectScripts = this.injectScripts.bind(this);
|
||||||
|
this.ignite = this.ignite.bind(this);
|
||||||
|
this.ensureDirectories = this.ensureDirectories.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
console.log('[BetterDiscord] init');
|
||||||
await this.waitForWindowUtils();
|
await this.waitForWindowUtils();
|
||||||
|
await this.ensureDirectories();
|
||||||
if (!tests) {
|
|
||||||
const basePath = this.config.getPath('base');
|
|
||||||
const files = await FileUtils.listDirectory(basePath);
|
|
||||||
const latestCs = FileUtils.resolveLatest(files, file => file.endsWith('.js') && file.startsWith('client.'), file => file.replace('client.', '').replace('.js', ''), 'client.', '.js');
|
|
||||||
this.config.getPath('cs', true).path = path.resolve(basePath, latestCs);
|
|
||||||
}
|
|
||||||
|
|
||||||
await FileUtils.ensureDirectory(this.config.getPath('ext'));
|
|
||||||
|
|
||||||
this.csseditor = new CSSEditor(this, this.config.getPath('csseditor'));
|
|
||||||
|
|
||||||
this.windowUtils.on('did-finish-load', () => this.injectScripts(true));
|
this.windowUtils.on('did-finish-load', () => this.injectScripts(true));
|
||||||
|
|
||||||
|
@ -199,9 +238,30 @@ export class BetterDiscord {
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.injectScripts();
|
this.injectScripts();
|
||||||
|
if (TEST_EDITOR) this.editor.openEditor({});
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async ensureDirectories() {
|
||||||
|
await FileUtils.ensureDirectory(this.config.getPath('ext'));
|
||||||
|
await FileUtils.ensureDirectory(this.config.getPath('userdata'));
|
||||||
|
await Promise.all([
|
||||||
|
FileUtils.ensureDirectory(this.config.getPath('plugins')),
|
||||||
|
FileUtils.ensureDirectory(this.config.getPath('themes')),
|
||||||
|
FileUtils.ensureDirectory(this.config.getPath('modules')),
|
||||||
|
FileUtils.ensureDirectory(this.config.getPath('userfiles'))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitForWindowUtils() {
|
||||||
|
if (this.windowUtils) return this.windowUtils;
|
||||||
|
const window = await this.waitForWindow();
|
||||||
|
return this.windowUtils = new WindowUtils({ window });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for Discord to load before doing any injection
|
||||||
|
*/
|
||||||
async waitForWindow() {
|
async waitForWindow() {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const defer = setInterval(() => {
|
const defer = setInterval(() => {
|
||||||
|
@ -215,14 +275,41 @@ export class BetterDiscord {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForWindowUtils() {
|
/**
|
||||||
if (this.windowUtils) return this.windowUtils;
|
* Parses the package.json of client script into config
|
||||||
const window = await this.waitForWindow();
|
*/
|
||||||
return this.windowUtils = new WindowUtils({ window });
|
parseClientPackage() {
|
||||||
|
const clientPath = this.config.getPath('client');
|
||||||
|
const clientPkg = TESTS ? require(`${path.resolve(clientPath, '..')}/package.json`) :require(`${clientPath}/package.json`);
|
||||||
|
const { version } = clientPkg;
|
||||||
|
const main = TESTS ? 'betterdiscord.client.js' : clientPkg.main;
|
||||||
|
this.config.addPath('client_script', `${clientPath}/${main}`);
|
||||||
|
this.config.setClientVersion(version);
|
||||||
|
console.log(`[BetterDiscord] Client v${this.config.clientVersion} - ${this.config.getPath('client_script')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
get window() {
|
/**
|
||||||
return this.windowUtils ? this.windowUtils.window : undefined;
|
* Add extra paths to config
|
||||||
|
*/
|
||||||
|
extraPaths() {
|
||||||
|
const base = path.resolve(this.config.getPath('data'), '..');
|
||||||
|
const userdata = path.resolve(base, 'userdata');
|
||||||
|
const ext = path.resolve(base, 'ext');
|
||||||
|
const plugins = path.resolve(ext, 'plugins');
|
||||||
|
const themes = path.resolve(ext, 'themes');
|
||||||
|
const modules = path.resolve(ext, 'modules');
|
||||||
|
const userfiles = path.resolve(userdata, 'files');
|
||||||
|
const snippets = path.resolve(userdata, 'snippets.json');
|
||||||
|
|
||||||
|
this.config.addPath('base', base);
|
||||||
|
this.config.addPath('ext', ext);
|
||||||
|
this.config.addPath('plugins', plugins);
|
||||||
|
this.config.addPath('themes', themes);
|
||||||
|
this.config.addPath('modules', modules);
|
||||||
|
this.config.addPath('userdata', userdata);
|
||||||
|
this.config.addPath('userfiles', userfiles);
|
||||||
|
this.config.addPath('snippets', snippets);
|
||||||
|
if (!this.config.getPath('editor')) this.config.addPath('editor', path.resolve(base, 'editor'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -245,8 +332,8 @@ export class BetterDiscord {
|
||||||
* @param {Boolean} reload Whether the main window was reloaded
|
* @param {Boolean} reload Whether the main window was reloaded
|
||||||
*/
|
*/
|
||||||
async injectScripts(reload = false) {
|
async injectScripts(reload = false) {
|
||||||
console.log(`RELOAD? ${reload}`);
|
console.log(`[BetterDiscord] injecting ${this.config.getPath('client_script')}. Reload: ${reload}`);
|
||||||
return this.windowUtils.injectScript(this.config.getPath('cs'));
|
return this.windowUtils.injectScript(this.config.getPath('client_script'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -255,10 +342,11 @@ export class BetterDiscord {
|
||||||
* Basically BetterDiscord needs to load before discord_desktop_core.
|
* Basically BetterDiscord needs to load before discord_desktop_core.
|
||||||
*/
|
*/
|
||||||
static patchBrowserWindow() {
|
static patchBrowserWindow() {
|
||||||
|
console.log('[BetterDiscord] patching BrowserWindow');
|
||||||
const electron = require('electron');
|
const electron = require('electron');
|
||||||
const electron_path = require.resolve('electron');
|
const electron_path = require.resolve('electron');
|
||||||
Object.assign(BrowserWindow, electron.BrowserWindow); // Assigns the new chrome-specific ones
|
Object.assign(BrowserWindow, electron.BrowserWindow); // Assigns the new chrome-specific ones
|
||||||
const newElectron = Object.assign({}, electron, {BrowserWindow});
|
const newElectron = Object.assign({}, electron, { BrowserWindow });
|
||||||
require.cache[electron_path].exports = newElectron;
|
require.cache[electron_path].exports = newElectron;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,6 +354,7 @@ export class BetterDiscord {
|
||||||
* Attaches an event handler for HTTP requests to update the Content Security Policy.
|
* Attaches an event handler for HTTP requests to update the Content Security Policy.
|
||||||
*/
|
*/
|
||||||
static hookSessionRequest() {
|
static hookSessionRequest() {
|
||||||
|
console.log('[BetterDiscord] hook session request');
|
||||||
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
||||||
for (const [header, values] of Object.entries(details.responseHeaders)) {
|
for (const [header, values] of Object.entries(details.responseHeaders)) {
|
||||||
if (!header.match(/^Content-Security-Policy(-Report-Only)?$/i)) continue;
|
if (!header.match(/^Content-Security-Policy(-Report-Only)?$/i)) continue;
|
||||||
|
@ -283,7 +372,6 @@ export class BetterDiscord {
|
||||||
callback({ responseHeaders: details.responseHeaders });
|
callback({ responseHeaders: details.responseHeaders });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BetterDiscord.patchBrowserWindow();
|
BetterDiscord.patchBrowserWindow();
|
||||||
|
|
|
@ -16,15 +16,28 @@ export default class Config extends Module {
|
||||||
return this.args.version;
|
return this.args.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get clientVersion() {
|
||||||
|
return this.args.clientVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
setClientVersion(clientVersion) {
|
||||||
|
this.args.clientVersion = clientVersion;
|
||||||
|
}
|
||||||
|
|
||||||
get paths() {
|
get paths() {
|
||||||
return this.args.paths;
|
return this.args.paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPath(id, full) {
|
getPath(id, full) {
|
||||||
const path = this.paths.find(path => path.id === id);
|
const path = this.paths.find(p => p.id === id);
|
||||||
|
if (!path) return null;
|
||||||
return full ? path : path.path;
|
return full ? path : path.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addPath(id, path) {
|
||||||
|
this.paths.push({ id, path });
|
||||||
|
}
|
||||||
|
|
||||||
get config() {
|
get config() {
|
||||||
return {
|
return {
|
||||||
version: this.version,
|
version: this.version,
|
||||||
|
@ -32,4 +45,8 @@ export default class Config extends Module {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compatibility with old client code and new installer args
|
||||||
|
compatibility() {
|
||||||
|
this.args.paths = Object.entries(this.args.paths).map(([id, path]) => ({ id, path }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,285 @@
|
||||||
|
/**
|
||||||
|
* BetterDiscord Editor 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 path from 'path';
|
||||||
|
import { BrowserWindow } from 'electron';
|
||||||
|
|
||||||
|
import Module from './modulebase';
|
||||||
|
import { WindowUtils, FileUtils } from './utils';
|
||||||
|
import BDIpc from './bdipc';
|
||||||
|
import sass from 'node-sass';
|
||||||
|
import chokidar from 'chokidar';
|
||||||
|
|
||||||
|
export default class Editor extends Module {
|
||||||
|
|
||||||
|
constructor(bd, path) {
|
||||||
|
super();
|
||||||
|
this.editorPath = path;
|
||||||
|
this.bd = bd;
|
||||||
|
this.initListeners();
|
||||||
|
this.initWatchers();
|
||||||
|
}
|
||||||
|
|
||||||
|
initListeners() {
|
||||||
|
BDIpc.on('openCssEditor', (event, options) => this.openEditor(options), true);
|
||||||
|
BDIpc.on('editor-open', (event, options) => this.openEditor(options), true);
|
||||||
|
|
||||||
|
BDIpc.on('editor-runScript', async (event, script) => {
|
||||||
|
const result = await this.sendToDiscord('editor-runScript', script);
|
||||||
|
event.reply(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
BDIpc.on('editor-getFiles', async (event) => {
|
||||||
|
try {
|
||||||
|
const files = await FileUtils.listDirectory(this.bd.config.getPath('userfiles'));
|
||||||
|
|
||||||
|
const constructFiles = await Promise.all(files.map(async file => {
|
||||||
|
// const content = await FileUtils.readFile(path.resolve(this.bd.config.getPath('userfiles'), file));
|
||||||
|
return { type: 'file', name: file, saved: true, mode: this.resolveMode(file), content: '', savedContent: '', read: false, changed: false };
|
||||||
|
}));
|
||||||
|
|
||||||
|
const userscssPath = path.resolve(this.bd.config.getPath('data'), 'user.scss');
|
||||||
|
|
||||||
|
await FileUtils.ensureFile(userscssPath);
|
||||||
|
|
||||||
|
const userscss = await FileUtils.readFile(userscssPath);
|
||||||
|
constructFiles.push({
|
||||||
|
caption: 'userstyle',
|
||||||
|
type: 'file',
|
||||||
|
name: 'user.scss',
|
||||||
|
saved: true,
|
||||||
|
mode: 'scss',
|
||||||
|
content: userscss,
|
||||||
|
savedContent: userscss,
|
||||||
|
hoisted: true,
|
||||||
|
liveUpdate: true,
|
||||||
|
read: true,
|
||||||
|
changed: false
|
||||||
|
});
|
||||||
|
|
||||||
|
event.reply(constructFiles);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
event.reject({ err });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BDIpc.on('editor-getSnippets', async (event) => {
|
||||||
|
try {
|
||||||
|
const snippets = await FileUtils.readJsonFromFile(this.bd.config.getPath('snippets'));
|
||||||
|
event.reply(snippets.map(snippet => {
|
||||||
|
return {
|
||||||
|
type: 'snippet',
|
||||||
|
name: snippet.name,
|
||||||
|
mode: this.resolveMode(snippet.name),
|
||||||
|
content: snippet.content,
|
||||||
|
savedContent: snippet.content,
|
||||||
|
read: true,
|
||||||
|
saved: true
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
event.reply([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BDIpc.on('editor-saveFile', async (event, file) => {
|
||||||
|
const filePath = (file.hoisted && file.name === 'user.scss') ?
|
||||||
|
path.resolve(this.bd.config.getPath('data'), 'user.scss') :
|
||||||
|
path.resolve(this.bd.config.getPath('userfiles'), file.name);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await FileUtils.writeFile(filePath, file.content);
|
||||||
|
event.reply('ok');
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
event.reject({ err });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BDIpc.on('editor-saveSnippet', async (event, snippet) => {
|
||||||
|
try {
|
||||||
|
await FileUtils.writeFile(this.bd.config.getPath('snippets'), JSON.stringify(snippet));
|
||||||
|
event.reply('ok');
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
event.reject({ err });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BDIpc.on('editor-injectStyle', async (event, { id, style, mode }) => {
|
||||||
|
if (mode !== 'scss') {
|
||||||
|
await this.sendToDiscord('editor-injectStyle', { id, style });
|
||||||
|
event.reply('ok');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
style = await Promise.all(style.split('\n').map(async(line) => {
|
||||||
|
if (!line.startsWith('@import')) return line;
|
||||||
|
const filename = line.split(' ')[1].replace(/'|"|;/g, '');
|
||||||
|
const filePath = path.resolve(this.bd.config.getPath('userfiles'), filename).replace(/\\/g, '/');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await FileUtils.fileExists(filePath);
|
||||||
|
} catch (err) {
|
||||||
|
`/*${filename}*/`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `@import '${filePath}';`;
|
||||||
|
}));
|
||||||
|
|
||||||
|
style = style.join('\n');
|
||||||
|
|
||||||
|
sass.render({ data: style }, (err, result) => {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
event.reply({ err });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { css } = result;
|
||||||
|
(async () => {
|
||||||
|
await this.sendToDiscord('editor-injectStyle', { id, style: css.toString() });
|
||||||
|
event.reply('ok');
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
BDIpc.on('editor-readFile', async (event, file) => {
|
||||||
|
const content = await FileUtils.readFile(path.resolve(this.bd.config.getPath('userfiles'), file.name));
|
||||||
|
event.reply(content);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initWatchers() {
|
||||||
|
this.fileWatcher = chokidar.watch(this.bd.config.getPath('userfiles'));
|
||||||
|
|
||||||
|
this.fileWatcher.on('add', file => {
|
||||||
|
const fileName = path.basename(file);
|
||||||
|
try {
|
||||||
|
this.send('editor-addFile', {
|
||||||
|
type: 'file',
|
||||||
|
name: fileName,
|
||||||
|
saved: true,
|
||||||
|
mode: this.resolveMode(fileName),
|
||||||
|
content: '',
|
||||||
|
savedContent: ''
|
||||||
|
});
|
||||||
|
} catch (err) {}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fileWatcher.on('unlink', file => {
|
||||||
|
const fileName = path.basename(file);
|
||||||
|
try {
|
||||||
|
this.send('editor-remFile', { name: fileName });
|
||||||
|
} catch (err) {}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fileWatcher.on('change', file => {
|
||||||
|
this.send('editor-fileChange', { name: path.basename(file) });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveMode(fileName) {
|
||||||
|
if (!fileName.includes('.')) return 'text';
|
||||||
|
const ext = fileName.substr(fileName.lastIndexOf('.') + 1);
|
||||||
|
if (this.modes.hasOwnProperty(ext)) return this.modes[ext];
|
||||||
|
return 'text';
|
||||||
|
}
|
||||||
|
|
||||||
|
get modes() {
|
||||||
|
return {
|
||||||
|
'css': 'css',
|
||||||
|
'scss': 'scss',
|
||||||
|
'js': 'javascript',
|
||||||
|
'txt': 'text',
|
||||||
|
'json': 'json'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens an editor.
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
async openEditor(options) {
|
||||||
|
if (!this.editorPkg) {
|
||||||
|
this.editorPkg = await FileUtils.readJsonFromFile(path.join(this.editorPath, 'package.json'));
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(this.editorPkg);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (this.editor) {
|
||||||
|
if (this.editor.isFocused()) return;
|
||||||
|
|
||||||
|
this.editor.focus();
|
||||||
|
this.editor.flashFrame(true);
|
||||||
|
return resolve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
options = Object.assign({}, this.options, options);
|
||||||
|
|
||||||
|
this.editor = new BrowserWindow(options);
|
||||||
|
this.editor.loadURL('about:blank');
|
||||||
|
this.editor.setSheetOffset(33);
|
||||||
|
this.editorUtils = new WindowUtils({ window: this.editor });
|
||||||
|
|
||||||
|
this.editor.on('close', () => {
|
||||||
|
this.bd.windowUtils.send('bd-save-csseditor-bounds', this.editor.getBounds());
|
||||||
|
this.editor = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.editor.once('ready-to-show', () => {
|
||||||
|
this.editor.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.editor.webContents.on('did-finish-load', () => {
|
||||||
|
this.editorUtils.injectScript(path.join(this.editorPath, this.editorPkg.main));
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends data to the editor.
|
||||||
|
* @param {String} channel
|
||||||
|
* @param {Any} data
|
||||||
|
*/
|
||||||
|
send(channel, data) {
|
||||||
|
if (!this.editor) throw { message: 'The CSS editor is not open.' };
|
||||||
|
return BDIpc.send(this.editor, channel, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendToDiscord(channel, message) {
|
||||||
|
return this.bd.windowUtils.send(channel, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the CSS editor's always on top flag.
|
||||||
|
*/
|
||||||
|
set alwaysOnTop(state) {
|
||||||
|
if (!this.editor) return;
|
||||||
|
this.editor.setAlwaysOnTop(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default options to pass to BrowserWindow.
|
||||||
|
*/
|
||||||
|
get options() {
|
||||||
|
return {
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
show: false,
|
||||||
|
frame: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,4 +2,5 @@ export { default as BDIpc } from './bdipc';
|
||||||
export { Utils, FileUtils, WindowUtils } from './utils';
|
export { Utils, FileUtils, WindowUtils } from './utils';
|
||||||
export { default as Config } from './config';
|
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 Database } from './database';
|
export { default as Database } from './database';
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
// TODO Use common
|
// TODO Use common
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import rimraf from 'rimraf';
|
||||||
|
|
||||||
import Module from './modulebase';
|
import Module from './modulebase';
|
||||||
import BDIpc from './bdipc';
|
import BDIpc from './bdipc';
|
||||||
|
@ -84,6 +85,20 @@ export class FileUtils {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async ensureFile(path) {
|
||||||
|
try {
|
||||||
|
await this.fileExists(path);
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
try {
|
||||||
|
await this.writeFile(path, '');
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static async readJsonFromFile(path) {
|
static async readJsonFromFile(path) {
|
||||||
let readFile;
|
let readFile;
|
||||||
try {
|
try {
|
||||||
|
@ -99,6 +114,15 @@ export class FileUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async writeFile(path, data, options = {}) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fs.writeFile(path, data, options, err => {
|
||||||
|
if (err) return reject(err);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static async listDirectory(path) {
|
static async listDirectory(path) {
|
||||||
try {
|
try {
|
||||||
await this.directoryExists(path);
|
await this.directoryExists(path);
|
||||||
|
@ -155,6 +179,27 @@ export class FileUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async rm(path) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
rimraf(path, err => {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static async rn(oldPath, newPath) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fs.rename(oldPath, newPath, err => {
|
||||||
|
if (err) return reject(err);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WindowUtils extends Module {
|
export class WindowUtils extends Module {
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"name": "bdeditorwindow",
|
||||||
|
"description": "BetterDiscord editor window",
|
||||||
|
"author": "JsSucks",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,275 @@
|
||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="titlebar">
|
||||||
|
<div class="draggable"></div>
|
||||||
|
<div class="icon">
|
||||||
|
<div class="inner"></div>
|
||||||
|
</div>
|
||||||
|
<div class="title">Content 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>
|
||||||
|
<BDEdit :files="files"
|
||||||
|
:parentLoading="loading"
|
||||||
|
:snippets="snippets"
|
||||||
|
:updateContent="updateContent"
|
||||||
|
:runScript="runScript"
|
||||||
|
:newFile="newFile"
|
||||||
|
:saveFile="saveFile"
|
||||||
|
:newSnippet="newSnippet"
|
||||||
|
:saveSnippet="saveSnippet"
|
||||||
|
:readFile="readFile"
|
||||||
|
:readSnippet="readSnippet"
|
||||||
|
:injectStyle="injectStyle"
|
||||||
|
:toggleLiveUpdate="toggleLiveUpdate"
|
||||||
|
:ctxAction="ctxAction"
|
||||||
|
:toast="toast"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ClientIPC } from 'common';
|
||||||
|
import { remote } from 'electron';
|
||||||
|
|
||||||
|
import { BDEdit } from 'bdedit';
|
||||||
|
|
||||||
|
ace.acequire = ace.require;
|
||||||
|
|
||||||
|
const modes = {
|
||||||
|
'css': 'css',
|
||||||
|
'scss': 'scss',
|
||||||
|
'js': 'javascript',
|
||||||
|
'txt': 'text',
|
||||||
|
'json': 'json'
|
||||||
|
};
|
||||||
|
|
||||||
|
function resolveMode(fileName) {
|
||||||
|
if (!fileName.includes('.')) return 'text';
|
||||||
|
const ext = fileName.substr(fileName.lastIndexOf('.') + 1);
|
||||||
|
if (modes.hasOwnProperty(ext)) return modes[ext];
|
||||||
|
return 'text';
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
files: [],
|
||||||
|
snippets: [],
|
||||||
|
loading: true,
|
||||||
|
alwaysOnTop: false,
|
||||||
|
error: undefined,
|
||||||
|
lastSaved: undefined,
|
||||||
|
toast: { active: false, msg: '' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: { BDEdit },
|
||||||
|
created() {
|
||||||
|
ClientIPC.on('bd-editor-addFile', (_, file) => {
|
||||||
|
if (this.files.find(f => f.name === file.name)) return;
|
||||||
|
this.addFile(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
ClientIPC.on('bd-editor-remFile', (_, file) => {
|
||||||
|
this.files = this.files.filter(f => f.name !== file.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
ClientIPC.on('bd-editor-addSnippet', (_, snippet) => {
|
||||||
|
if (this.snippets.find(s => s.name === snippet.name)) return;
|
||||||
|
this.addSnippet(snippet);
|
||||||
|
});
|
||||||
|
|
||||||
|
ClientIPC.on('bd-editor-remSnippet', (_, snippet) => {
|
||||||
|
this.snippets = this.snippets.filter(s => s.name !== snippet.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
ClientIPC.on('bd-editor-fileChange', (_, file) => {
|
||||||
|
if (this.lastSaved && this.lastSaved.name === file.name) { // If we saved in our editor then don't trigger
|
||||||
|
this.lastSaved = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const f = this.files.find(f => f.name === file.name);
|
||||||
|
if (f) f.changed = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
this.files = await ClientIPC.send('bd-editor-getFiles');
|
||||||
|
this.snippets = await ClientIPC.send('bd-editor-getSnippets');
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
addFile(file) {
|
||||||
|
this.files.push(file);
|
||||||
|
},
|
||||||
|
|
||||||
|
addSnippet(snippet) { this.snippets.push(file) },
|
||||||
|
|
||||||
|
updateContent(item, content) {
|
||||||
|
item.content = content;
|
||||||
|
item.saved = item.content === item.savedContent;
|
||||||
|
|
||||||
|
if (this.liveUpdateTimeout) clearTimeout(this.liveUpdateTimeout);
|
||||||
|
if (item.liveUpdateEnabled) {
|
||||||
|
this.liveUpdateTimeout = setTimeout(() => {
|
||||||
|
this.injectStyle(item);
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async runScript(script) {
|
||||||
|
return ClientIPC.send('editor-runScript', script);
|
||||||
|
},
|
||||||
|
|
||||||
|
newFile(fileName) {
|
||||||
|
const prefix = fileName;
|
||||||
|
const mode = resolveMode(fileName);
|
||||||
|
|
||||||
|
let newName = prefix;
|
||||||
|
let iter = 0;
|
||||||
|
|
||||||
|
while (this.files.find(file => file.name === newName)) {
|
||||||
|
newName = `${prefix.split('.')[0]}_${iter}.${prefix.split('.')[1]}`;
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newItem = { type: 'file', name: newName, content: '', mode, saved: false, read: true };
|
||||||
|
this.files.push(newItem);
|
||||||
|
return newItem;
|
||||||
|
},
|
||||||
|
|
||||||
|
newSnippet(snippetName) {
|
||||||
|
const prefix = snippetName;
|
||||||
|
const mode = resolveMode(snippetName);
|
||||||
|
|
||||||
|
let newName = prefix;
|
||||||
|
let iter = 0;
|
||||||
|
|
||||||
|
while (this.snippets.find(snippet => snippet.name === newName)) {
|
||||||
|
newName = `${prefix}_${iter}`;
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newItem = { type: 'snippet', name: newName, content: '', savedContent: '', mode, saved: false, read: true };
|
||||||
|
this.snippets.push(newItem);
|
||||||
|
return newItem;
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveFile(file) {
|
||||||
|
try {
|
||||||
|
this.lastSaved = file;
|
||||||
|
const result = await ClientIPC.send('bd-editor-saveFile', file);
|
||||||
|
file.savedContent = file.content;
|
||||||
|
file.saved = true;
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async saveSnippet(snippet) {
|
||||||
|
snippet.saved = true;
|
||||||
|
snippet.savedContent = snippet.content;
|
||||||
|
const result = await ClientIPC.send('bd-editor-saveSnippet', this.snippets.map(snippet => {
|
||||||
|
return {
|
||||||
|
name: snippet.name,
|
||||||
|
content: snippet.savedContent
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
async readFile(file) {
|
||||||
|
const content = await ClientIPC.send('editor-readFile', file);
|
||||||
|
file.read = true;
|
||||||
|
file.changed = false;
|
||||||
|
file.content = file.savedContent = content;
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
|
||||||
|
async readSnippet(snippet) {
|
||||||
|
const content = await ClientIPC.send('editor-readSnippet', snippet);
|
||||||
|
snippet.read = true;
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
|
||||||
|
async injectStyle(item) {
|
||||||
|
const style = item.content.length <= 0 ? ' ' : item.content;
|
||||||
|
const result = await ClientIPC.send('bd-editor-injectStyle', { id: item.name.split('.')[0], style, mode: item.mode });
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
async ctxAction(action, item) {
|
||||||
|
if (action === 'reveal') {
|
||||||
|
ClientIPC.send('explorer', { 'static': 'userfiles' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'copy') {
|
||||||
|
remote.clipboard.writeText(item.content);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'copyPath') {
|
||||||
|
const fullPath = await ClientIPC.send('getPath', ['userfiles', item.name]);
|
||||||
|
remote.clipboard.writeText(fullPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'rename') { // TODO select correct file after
|
||||||
|
this.loading = true;
|
||||||
|
const { oldName, newName } = item;
|
||||||
|
|
||||||
|
if (this.files.find(f => f.name === newName)) {
|
||||||
|
this.loading = false;
|
||||||
|
this.showToast('err', `File ${newName} already exists`);
|
||||||
|
return {
|
||||||
|
err: `File ${newName} already exists`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ClientIPC.send('rnFile', { oldName: ['userfiles', oldName], newName: ['userfiles', newName] });
|
||||||
|
return item;
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
return { err };
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'delete') {
|
||||||
|
this.loading = true;
|
||||||
|
try {
|
||||||
|
await ClientIPC.send('rmFile', ['userfiles', item.name]);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
showToast(type, msg, timeout = 3000) {
|
||||||
|
this.toast = { active: true, type, msg };
|
||||||
|
setTimeout(() => { this.toast.active = false }, timeout);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleLiveUpdate(item) {
|
||||||
|
item.liveUpdateEnabled = !item.liveUpdateEnabled;
|
||||||
|
return item;
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleaot() {
|
||||||
|
this.alwaysOnTop = !this.alwaysOnTop;
|
||||||
|
remote.getCurrentWindow().setAlwaysOnTop(this.alwaysOnTop);
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,22 @@
|
||||||
|
// const styles = require('./styles/index.scss');
|
||||||
|
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
import Editor from './Editor.vue';
|
||||||
|
import styles from './styles/index.scss';
|
||||||
|
|
||||||
|
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);
|
|
@ -0,0 +1,20 @@
|
||||||
|
@import './vars.scss';
|
||||||
|
@import './titlebar.scss';
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
max-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background: #2c383e;
|
||||||
|
min-width: 700px;
|
||||||
|
min-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-spacer {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
margin: 0 0 0 2px;
|
||||||
|
font-size: 0;
|
||||||
|
|
||||||
|
button {
|
||||||
|
-webkit-app-region: no-drag;
|
||||||
|
outline: none !important;
|
||||||
|
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: $bdGreen;
|
||||||
|
color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: $bdGreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 63px;
|
||||||
|
position: absolute;
|
||||||
|
height: 33px;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
$logoSmallGw: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkltYWdlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMiA1MTI7IiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGUgdHlwZT0idGV4dC9jc3MiPi5zdDB7ZGlzcGxheTpub25lO30uc3Qxe2Rpc3BsYXk6aW5saW5lO2ZpbGw6IzAyMDAzNTtzdHJva2U6IzAwMDAwMDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9LnN0MntmaWxsOiMzRUNDOUU7fS5zdDN7ZmlsbDojRkZGRkZGO308L3N0eWxlPjxnIGlkPSJMYXllcl8yIiBjbGFzcz0ic3QwIj48cmVjdCB4PSItNjQiIHk9Ii0zMiIgY2xhc3M9InN0MSIgd2lkdGg9IjYxOCIgaGVpZ2h0PSI1NzIiLz48L2c+PGcgaWQ9IkxheWVyXzEiIHhtbG5zOnZlY3Rvcm5hdG9yPSJodHRwOi8vdmVjdG9ybmF0b3IuaW8iPjxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik03MCwxOC44Yy0xMy43LDAtMjcuMywxMy43LTI3LjMsMjcuM3YyMzMuNkM0Mi43LDM5Ny43LDEzNy45LDQ5MywyNTYsNDkzYzI5LjcsMCw1OC02LjEsODMuNi0xN1YzNDEuNWMtMTksMjUuNi00OS4zLDQyLjItODMuNiw0Mi4yYy01Ny42LDAtMTA0LjEtNDYuNS0xMDQuMS0xMDQuMVY0Ni4xYzAtMTMuNy0xMy43LTI3LjMtMjcuMy0yNy4zSDcweiIvPjxwYXRoIGNsYXNzPSJzdDMiIGQ9Ik0zODcuNCwxOC44Yy0xMy43LDAtMjcuMywxMy43LTI3LjMsMjcuM3Y0Ny4zQzMyOS4zLDc2LjIsMjkzLjksNjYuMywyNTYsNjYuM2MtMjkuOCwwLTU3LjksNi4zLTgzLjYsMTcuM3YxMzQuMmMxOS0yNS42LDQ5LjMtNDIuMiw4My42LTQyLjJjNTcuNiwwLDEwNC4xLDQ2LjUsMTA0LjEsMTA0LjF2MTg2LjJjNjUuMi0zNi40LDEwOS4yLTEwNiwxMDkuMi0xODYuMlY0Ni4xYzAtMTguOC0xMy43LTI3LjMtMjcuMy0yNy4zSDM4Ny40eiIvPjwvZz48L3N2Zz4=);
|
||||||
|
$bdicon: $logoSmallGw;
|
||||||
|
$bdGreen: #3ecc9c;
|
|
@ -0,0 +1,39 @@
|
||||||
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
|
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: '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')
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,43 @@
|
||||||
|
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: '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()
|
||||||
|
]
|
||||||
|
};
|
|
@ -10,68 +10,109 @@ import editjson from 'gulp-json-editor';
|
||||||
|
|
||||||
import corepkg from './core/package';
|
import corepkg from './core/package';
|
||||||
import clientpkg from './client/package';
|
import clientpkg from './client/package';
|
||||||
|
import editorpkg from './editor/package';
|
||||||
|
|
||||||
gulp.task('release-package', function () {
|
// core-release >
|
||||||
return pump([
|
|
||||||
gulp.src('package.json'),
|
|
||||||
editjson(function (mainpkg) {
|
|
||||||
delete mainpkg.main;
|
|
||||||
delete mainpkg.devDependencies;
|
|
||||||
delete mainpkg.scripts;
|
|
||||||
return mainpkg;
|
|
||||||
}),
|
|
||||||
gulp.dest('release')
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('client', function () {
|
gulp.task('core-main', function () {
|
||||||
return pump([
|
|
||||||
gulp.src('client/dist/*.client-release.js'),
|
|
||||||
rename(`client.${clientpkg.version}.js`),
|
|
||||||
gulp.dest('release')
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('core', 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'),
|
inject.after(`'use strict';\n`, 'const PRODUCTION = true;\n'),
|
||||||
rename(`core.${corepkg.version}.js`),
|
rename(`core.${corepkg.version}.js`),
|
||||||
gulp.dest('release')
|
gulp.dest('release/core')
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('sparkplug', function () {
|
gulp.task('core-pkg', function() {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('core/dist/sparkplug.js'),
|
gulp.src('core/package.json'),
|
||||||
gulp.dest('release')
|
editjson(function(pkg) {
|
||||||
|
pkg.main = `core.${corepkg.version}.js`;
|
||||||
|
delete pkg.devDependencies;
|
||||||
|
delete pkg.scripts;
|
||||||
|
return pkg;
|
||||||
|
}),
|
||||||
|
gulp.dest('release/core')
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
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', { prefix: 2 })
|
copy('release/core', { prefix: 2 })
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('index', function () {
|
gulp.task('core-sparkplug', function () {
|
||||||
return pump([
|
return pump([
|
||||||
file('index.js', `module.exports = require('./core.${corepkg.version}.js');`, {src: true}),
|
gulp.src('core/dist/sparkplug.js'),
|
||||||
gulp.dest('release')
|
gulp.dest('release/core')
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('css-editor', function () {
|
gulp.task('core-release', gulp.parallel('core-main', 'core-pkg', 'core-sparkplug', 'core-modules'));
|
||||||
|
|
||||||
|
// < core-release
|
||||||
|
|
||||||
|
// client
|
||||||
|
|
||||||
|
gulp.task('client-main', function () {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('csseditor/dist/csseditor-release.js'),
|
gulp.src('client/dist/*.client-release.js'),
|
||||||
rename('csseditor.js'),
|
rename(`client.${clientpkg.version}.js`),
|
||||||
gulp.dest('release/csseditor')
|
gulp.dest('release/client')
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task('client-pkg', function() {
|
||||||
|
return pump([
|
||||||
|
gulp.src('client/package.json'),
|
||||||
|
editjson(function (pkg) {
|
||||||
|
pkg.main = `client.${clientpkg.version}.js`;
|
||||||
|
delete pkg.scripts;
|
||||||
|
return pkg;
|
||||||
|
}),
|
||||||
|
gulp.dest('release/client')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('client-sparkplug', function () {
|
||||||
|
return pump([
|
||||||
|
gulp.src('core/dist/sparkplug.js'),
|
||||||
|
gulp.dest('release/client')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('client-release', gulp.parallel('client-main', 'client-pkg', 'client-sparkplug'));
|
||||||
|
|
||||||
|
// Editor
|
||||||
|
|
||||||
|
gulp.task('editor-main', function () {
|
||||||
|
return pump([
|
||||||
|
gulp.src('editor/dist/editor.release.js'),
|
||||||
|
rename(`editor.${editorpkg.version}.js`),
|
||||||
|
gulp.dest('release/editor')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('editor-pkg', function () {
|
||||||
|
return pump([
|
||||||
|
gulp.src('editor/package.json'),
|
||||||
|
editjson(function (pkg) {
|
||||||
|
pkg.main = `editor.${editorpkg.version}.js`;
|
||||||
|
delete pkg.scripts;
|
||||||
|
return pkg;
|
||||||
|
}),
|
||||||
|
gulp.dest('release/editor')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('editor-release', gulp.parallel('editor-main', 'editor-pkg'));
|
||||||
|
|
||||||
|
// Deps
|
||||||
|
|
||||||
gulp.task('node-modules', function () {
|
gulp.task('node-modules', function () {
|
||||||
return copydeps('.', 'release');
|
return copydeps('.', 'release/core');
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('node-sass-bindings', gulp.series(function () {
|
gulp.task('node-sass-bindings', gulp.series(function () {
|
||||||
|
@ -79,7 +120,7 @@ gulp.task('node-sass-bindings', gulp.series(function () {
|
||||||
}, function () {
|
}, function () {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('other/node_sass_bindings/**/*'),
|
gulp.src('other/node_sass_bindings/**/*'),
|
||||||
copy('release/node_modules/node-sass/vendor', { prefix: 2 })
|
copy('release/core/node_modules/node-sass/vendor', { prefix: 2 })
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -88,14 +129,16 @@ gulp.task('keytar-bindings', gulp.series(function () {
|
||||||
}, function () {
|
}, function () {
|
||||||
return pump([
|
return pump([
|
||||||
gulp.src('other/keytar/**/*'),
|
gulp.src('other/keytar/**/*'),
|
||||||
copy('release/node_modules/keytar/build/Release', {prefix: 2})
|
copy('release/core/node_modules/keytar/build/Release', { prefix: 2 })
|
||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
gulp.task('dependencies', gulp.series('node-modules', gulp.parallel('node-sass-bindings', 'keytar-bindings')));
|
// Other
|
||||||
|
|
||||||
gulp.task('build-release', gulp.parallel('release-package', 'client', 'core', 'sparkplug', 'core-modules', 'index', 'css-editor', 'dependencies'));
|
gulp.task('del-release', function() {
|
||||||
|
|
||||||
gulp.task('release', gulp.series(function () {
|
|
||||||
return del(['release/**/*']);
|
return del(['release/**/*']);
|
||||||
}, 'build-release'));
|
});
|
||||||
|
|
||||||
|
gulp.task('dependencies', gulp.series('node-modules', gulp.parallel('node-sass-bindings', 'keytar-bindings')));
|
||||||
|
gulp.task('build-release', gulp.parallel('core-release', 'client-release', 'editor-release', 'dependencies'));
|
||||||
|
gulp.task('release', gulp.series('del-release', 'build-release'));
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
|
@ -16,16 +16,19 @@
|
||||||
},
|
},
|
||||||
"private": false,
|
"private": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"asar": "^0.14.6",
|
||||||
|
"bdedit": "github:JsSucks/bdedit",
|
||||||
"csp-parse": "github:macropodhq/csp-parse",
|
"csp-parse": "github:macropodhq/csp-parse",
|
||||||
"deepmerge": "^2.2.1",
|
"deepmerge": "^2.2.1",
|
||||||
"fs-extra": "^7.0.0",
|
"fs-extra": "^7.0.0",
|
||||||
"keytar": "^4.3.0",
|
"keytar": "^4.3.0",
|
||||||
"nedb": "^1.8.0",
|
"nedb": "^1.8.0",
|
||||||
"node-sass": "^4.10.0",
|
"node-sass": "^4.10.0",
|
||||||
"asar": "^0.14.3"
|
"original-fs": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"aes256": "^1.0.4",
|
"aes256": "^1.0.4",
|
||||||
|
"archiver": "^3.0.0",
|
||||||
"babel-core": "^6.26.3",
|
"babel-core": "^6.26.3",
|
||||||
"babel-loader": "^7.1.5",
|
"babel-loader": "^7.1.5",
|
||||||
"babel-preset-env": "^1.7.0",
|
"babel-preset-env": "^1.7.0",
|
||||||
|
@ -50,6 +53,7 @@
|
||||||
"gulp-npm-copy-deps": "^1.0.2",
|
"gulp-npm-copy-deps": "^1.0.2",
|
||||||
"gulp-rename": "^1.4.0",
|
"gulp-rename": "^1.4.0",
|
||||||
"gulp-watch": "^5.0.1",
|
"gulp-watch": "^5.0.1",
|
||||||
|
"hash-files": "^1.1.1",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^3.2.0",
|
||||||
"jquery": "^3.2.1",
|
"jquery": "^3.2.1",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
|
@ -79,15 +83,16 @@
|
||||||
"watch_core": "npm run watch --prefix core",
|
"watch_core": "npm run watch --prefix core",
|
||||||
"build_csseditor": "npm run build --prefix csseditor",
|
"build_csseditor": "npm run build --prefix csseditor",
|
||||||
"watch_csseditor": "npm run watch --prefix csseditor",
|
"watch_csseditor": "npm run watch --prefix csseditor",
|
||||||
"build_installer": "npm run build --prefix installer",
|
"build_editor": "npm run build --prefix editor",
|
||||||
"watch_installer": "npm run watch --prefix installer",
|
"watch_editor": "npm run watch --prefix editor",
|
||||||
"lint": "eslint -f unix client/src core/src csseditor/src common && npm run sasslint",
|
"lint": "eslint -f unix client/src core/src editor/src common && npm run sasslint",
|
||||||
"lint_fix": "eslint -f unix client/src core/src csseditor/src common --fix",
|
"lint_fix": "eslint -f unix client/src core/src csseditor/src common --fix",
|
||||||
"sasslint": "sass-lint client/src/styles/**/*.scss -v",
|
"sasslint": "sass-lint client/src/styles/**/*.scss -v",
|
||||||
"test": "npm run build && npm run lint",
|
"test": "npm run build && npm run lint",
|
||||||
"build_node-sass": "node scripts/build-node-sass.js",
|
"build_node-sass": "node scripts/build-node-sass.js",
|
||||||
"build_release": "npm run release --prefix client && npm run build --prefix core && npm run release --prefix csseditor",
|
"build_release": "npm run release --prefix client && npm run build --prefix core && npm run release --prefix editor",
|
||||||
"package_release": "node scripts/package-release.js",
|
"package_release": "node scripts/package-release.js",
|
||||||
|
"gulp_release": "gulp release",
|
||||||
"release": "npm run lint && npm run build_release && gulp release && npm run package_release",
|
"release": "npm run lint && npm run build_release && gulp release && npm run package_release",
|
||||||
"update_release": "npm run build_release && gulp build-release",
|
"update_release": "npm run build_release && gulp build-release",
|
||||||
"inject": "node scripts/inject.js"
|
"inject": "node scripts/inject.js"
|
||||||
|
|
|
@ -1,65 +1,155 @@
|
||||||
|
const args = process.argv;
|
||||||
|
const tag = args.length > 2 ? args[2] : ':rel';
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const archiver = require('archiver');
|
const archiver = require('archiver');
|
||||||
|
const hashfiles = require('hash-files');
|
||||||
|
|
||||||
|
const releaseStub = require('./releasestub.json');
|
||||||
|
|
||||||
|
releaseStub.files = releaseStub.files.map(file => {
|
||||||
|
file.remote = file.remote.replace(':rel', tag);
|
||||||
|
return file;
|
||||||
|
});
|
||||||
|
|
||||||
const releasepkg = require('../release/package.json');
|
|
||||||
const mainpkg = require('../package.json');
|
const mainpkg = require('../package.json');
|
||||||
const corepkg = require('../core/package.json');
|
const corepkg = require('../release/core/package.json');
|
||||||
const clientpkg = require('../client/package.json');
|
const clientpkg = require('../release/client/package.json');
|
||||||
const editorpkg = require('../csseditor/package.json');
|
const editorpkg = require('../release/editor/package.json');
|
||||||
|
|
||||||
// core.zip
|
const createArchiver = (level = 1) => {
|
||||||
const core = new Promise((resolve, reject) => {
|
return archiver('tar', {
|
||||||
const core_zip = archiver('zip');
|
gzip: true,
|
||||||
core_zip.file('./release/package.json', {name: 'package.json'});
|
gzipOptions: {
|
||||||
core_zip.file('./release/index.js', {name: 'index.js'});
|
level
|
||||||
core_zip.file(`./release/core.${corepkg.version}.js`, {name: `core.${corepkg.version}.js`});
|
}
|
||||||
core_zip.file('./release/sparkplug.js', {name: 'sparkplug.js'});
|
});
|
||||||
core_zip.directory('./release/modules', 'modules');
|
};
|
||||||
core_zip.directory('./release/node_modules', 'node_modules');
|
|
||||||
|
|
||||||
const core_zip_stream = fs.createWriteStream('./release/core.zip');
|
async function hashFile(fn) {
|
||||||
core_zip.pipe(core_zip_stream);
|
return new Promise((resolve, reject) => {
|
||||||
|
hashfiles({ files: [fn], algorithm: 'sha256' }, (error, hash) => {
|
||||||
|
if (error) return reject();
|
||||||
|
resolve(hash);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
core_zip.on('end', resolve);
|
async function fileSize(fn) {
|
||||||
core_zip.on('error', reject);
|
return new Promise((resolve, reject) => {
|
||||||
core_zip.finalize();
|
fs.stat(fn, (err, stats) => {
|
||||||
});
|
if (err) return reject();
|
||||||
|
resolve(stats['size']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// client.zip
|
// Core
|
||||||
const client = new Promise((resolve, reject) => {
|
async function archiveCore(out = './release/core.tar.gz') {
|
||||||
const client_zip = archiver('zip');
|
return new Promise((resolve, reject) => {
|
||||||
client_zip.file(`./release/client.${clientpkg.version}.js`, {name: `client.${clientpkg.version}.js`});
|
console.log('packaging core');
|
||||||
|
const mainFn = `core.${corepkg.version}.js`;
|
||||||
|
const coreArchive = createArchiver(6);
|
||||||
|
coreArchive.file('./release/core/package.json', { name: 'core/package.json' });
|
||||||
|
coreArchive.file('./release/core/index.js', { name: 'core/index.js' });
|
||||||
|
coreArchive.file(`./release/core/${mainFn}`, { name: `core/${mainFn}` });
|
||||||
|
coreArchive.file('./release/core/sparkplug.js', { name: 'core/sparkplug.js' });
|
||||||
|
coreArchive.directory('./release/core/modules', 'core/modules');
|
||||||
|
coreArchive.directory('./release/core/node_modules', 'core/node_modules');
|
||||||
|
|
||||||
const client_zip_stream = fs.createWriteStream('./release/client.zip');
|
const coreZipStream = fs.createWriteStream(out);
|
||||||
client_zip.pipe(client_zip_stream);
|
coreArchive.pipe(coreZipStream);
|
||||||
|
|
||||||
client_zip.on('end', resolve);
|
coreArchive.on('end', () => resolve(out));
|
||||||
client_zip.on('error', reject);
|
coreArchive.on('error', reject);
|
||||||
client_zip.finalize();
|
coreArchive.finalize();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// csseditor.zip
|
// Client
|
||||||
const csseditor = new Promise((resolve, reject) => {
|
async function archiveClient(out = './release/client.tar.gz') {
|
||||||
const csseditor_zip = archiver('zip');
|
return new Promise((resolve, reject) => {
|
||||||
csseditor_zip.directory('./release/csseditor', 'csseditor');
|
console.log('packaging client');
|
||||||
|
const mainFn = `client.${clientpkg.version}.js`;
|
||||||
|
const clientArchive = createArchiver();
|
||||||
|
clientArchive.file('./release/client/package.json', { name: 'client/package.json' });
|
||||||
|
clientArchive.file('./release/core/sparkplug.js', { name: 'client/sparkplug.js' });
|
||||||
|
clientArchive.file(`./release/client/${mainFn}`, { name: `client/${mainFn}` });
|
||||||
|
|
||||||
const csseditor_zip_stream = fs.createWriteStream('./release/csseditor.zip');
|
const clientZipStream = fs.createWriteStream(out);
|
||||||
csseditor_zip.pipe(csseditor_zip_stream);
|
clientArchive.pipe(clientZipStream);
|
||||||
|
|
||||||
csseditor_zip.on('end', resolve);
|
clientArchive.on('end', () => resolve(out));
|
||||||
csseditor_zip.on('error', reject);
|
clientArchive.on('error', reject);
|
||||||
csseditor_zip.finalize();
|
clientArchive.finalize();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// full.zip
|
// Editor
|
||||||
Promise.all([core, client, csseditor]).then(() => {
|
async function archiveEditor(out = './release/editor.tar.gz') {
|
||||||
const full_zip = archiver('zip');
|
return new Promise((resolve, reject) => {
|
||||||
full_zip.file('./release/core.zip', {name: 'core.zip'});
|
console.log('packaging editor');
|
||||||
full_zip.file('./release/client.zip', {name: 'client.zip'});
|
const mainFn = `editor.${editorpkg.version}.js`;
|
||||||
full_zip.file('./release/csseditor.zip', {name: 'csseditor.zip'});
|
const editorArchive = createArchiver();
|
||||||
|
editorArchive.directory('./release/editor', 'editor');
|
||||||
|
|
||||||
const full_zip_stream = fs.createWriteStream('./release/full.zip');
|
const editorZipStream = fs.createWriteStream(out);
|
||||||
full_zip.pipe(full_zip_stream);
|
editorArchive.pipe(editorZipStream);
|
||||||
full_zip.finalize();
|
|
||||||
});
|
editorArchive.on('end', () => resolve(out));
|
||||||
|
editorArchive.on('error', reject);
|
||||||
|
editorArchive.finalize();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function pack() {
|
||||||
|
const coreArchive = await archiveCore();
|
||||||
|
const coreHash = await hashFile(coreArchive);
|
||||||
|
const coreSize = await fileSize(coreArchive);
|
||||||
|
console.log(`${coreArchive} ${coreSize} | ${coreHash}`);
|
||||||
|
|
||||||
|
const coreStub = releaseStub.files.find(f => f.id === 'core');
|
||||||
|
coreStub.name = 'core.tar.gz';
|
||||||
|
coreStub.version = corepkg.version;
|
||||||
|
coreStub.hash = coreHash;
|
||||||
|
coreStub.size = coreSize;
|
||||||
|
coreStub.remote = coreStub.remote.replace(':fn', 'core.tar.gz');
|
||||||
|
|
||||||
|
const clientArchive = await archiveClient();
|
||||||
|
const clientHash = await hashFile(clientArchive);
|
||||||
|
const clientSize = await fileSize(clientArchive);
|
||||||
|
console.log(`${clientArchive} ${clientSize} | ${clientHash}`);
|
||||||
|
|
||||||
|
const clientStub = releaseStub.files.find(f => f.id === 'client');
|
||||||
|
clientStub.name = 'client.tar.gz';
|
||||||
|
clientStub.version = clientpkg.version;
|
||||||
|
clientStub.hash = clientHash;
|
||||||
|
clientStub.size = clientSize;
|
||||||
|
clientStub.remote = clientStub.remote.replace(':fn', 'client.tar.gz');
|
||||||
|
|
||||||
|
const editorArchive = await archiveEditor();
|
||||||
|
const editorHash = await hashFile(editorArchive);
|
||||||
|
const editorSize = await fileSize(editorArchive);
|
||||||
|
console.log(`${editorArchive} ${editorSize} | ${editorHash}`);
|
||||||
|
|
||||||
|
const editorStub = releaseStub.files.find(f => f.id === 'editor');
|
||||||
|
editorStub.name = 'editor.tar.gz';
|
||||||
|
editorStub.version = editorpkg.version;
|
||||||
|
editorStub.hash = editorHash;
|
||||||
|
editorStub.size = editorSize;
|
||||||
|
editorStub.remote = editorStub.remote.replace(':fn', 'editor.tar.gz');
|
||||||
|
|
||||||
|
releaseStub.mver = mainpkg.version;
|
||||||
|
releaseStub.files = [
|
||||||
|
releaseStub.files.find(f => f.id === 'stub'),
|
||||||
|
coreStub,
|
||||||
|
clientStub,
|
||||||
|
editorStub
|
||||||
|
];
|
||||||
|
|
||||||
|
fs.writeFile('./release/releaseinfo.json', JSON.stringify(releaseStub, null, 4), (err) => {
|
||||||
|
console.log(`all done! ${tag === ':rel' ? `Don't forget to update :rel` : ''}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pack();
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const archiver = require('archiver');
|
||||||
|
|
||||||
|
const releasepkg = require('../release/package.json');
|
||||||
|
const mainpkg = require('../package.json');
|
||||||
|
const corepkg = require('../core/package.json');
|
||||||
|
const clientpkg = require('../client/package.json');
|
||||||
|
const editorpkg = require('../csseditor/package.json');
|
||||||
|
|
||||||
|
// core.zip
|
||||||
|
const core = new Promise((resolve, reject) => {
|
||||||
|
const core_zip = archiver('zip');
|
||||||
|
core_zip.file('./release/package.json', {name: 'package.json'});
|
||||||
|
core_zip.file('./release/index.js', {name: 'index.js'});
|
||||||
|
core_zip.file(`./release/core.${corepkg.version}.js`, {name: `core.${corepkg.version}.js`});
|
||||||
|
core_zip.file('./release/sparkplug.js', {name: 'sparkplug.js'});
|
||||||
|
core_zip.directory('./release/modules', 'modules');
|
||||||
|
core_zip.directory('./release/node_modules', 'node_modules');
|
||||||
|
|
||||||
|
const core_zip_stream = fs.createWriteStream('./release/core.zip');
|
||||||
|
core_zip.pipe(core_zip_stream);
|
||||||
|
|
||||||
|
core_zip.on('end', resolve);
|
||||||
|
core_zip.on('error', reject);
|
||||||
|
core_zip.finalize();
|
||||||
|
});
|
||||||
|
|
||||||
|
// client.zip
|
||||||
|
const client = new Promise((resolve, reject) => {
|
||||||
|
const client_zip = archiver('zip');
|
||||||
|
client_zip.file(`./release/client.${clientpkg.version}.js`, {name: `client.${clientpkg.version}.js`});
|
||||||
|
|
||||||
|
const client_zip_stream = fs.createWriteStream('./release/client.zip');
|
||||||
|
client_zip.pipe(client_zip_stream);
|
||||||
|
|
||||||
|
client_zip.on('end', resolve);
|
||||||
|
client_zip.on('error', reject);
|
||||||
|
client_zip.finalize();
|
||||||
|
});
|
||||||
|
|
||||||
|
// csseditor.zip
|
||||||
|
const csseditor = new Promise((resolve, reject) => {
|
||||||
|
const csseditor_zip = archiver('zip');
|
||||||
|
csseditor_zip.directory('./release/csseditor', 'csseditor');
|
||||||
|
|
||||||
|
const csseditor_zip_stream = fs.createWriteStream('./release/csseditor.zip');
|
||||||
|
csseditor_zip.pipe(csseditor_zip_stream);
|
||||||
|
|
||||||
|
csseditor_zip.on('end', resolve);
|
||||||
|
csseditor_zip.on('error', reject);
|
||||||
|
csseditor_zip.finalize();
|
||||||
|
});
|
||||||
|
|
||||||
|
// full.zip
|
||||||
|
Promise.all([core, client, csseditor]).then(() => {
|
||||||
|
const full_zip = archiver('zip');
|
||||||
|
full_zip.file('./release/core.zip', {name: 'core.zip'});
|
||||||
|
full_zip.file('./release/client.zip', {name: 'client.zip'});
|
||||||
|
full_zip.file('./release/csseditor.zip', {name: 'csseditor.zip'});
|
||||||
|
|
||||||
|
const full_zip_stream = fs.createWriteStream('./release/full.zip');
|
||||||
|
full_zip.pipe(full_zip_stream);
|
||||||
|
full_zip.finalize();
|
||||||
|
});
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"mver": "",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"id": "stub",
|
||||||
|
"name": "stub.js",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"size": 0,
|
||||||
|
"remote": "/master/installer/stub.js",
|
||||||
|
"hash": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "client",
|
||||||
|
"name": "",
|
||||||
|
"version": "",
|
||||||
|
"size": "",
|
||||||
|
"remote": "/releases/download/:rel/:fn",
|
||||||
|
"hash": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "core",
|
||||||
|
"name": "",
|
||||||
|
"version": "",
|
||||||
|
"size": "",
|
||||||
|
"remote": "/releases/download/:rel/:fn",
|
||||||
|
"hash": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "editor",
|
||||||
|
"name": "",
|
||||||
|
"version": "",
|
||||||
|
"size": "",
|
||||||
|
"remote": "/releases/download/:rel/:fn",
|
||||||
|
"hash": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue