Merge branch 'master' into discord-api
This commit is contained in:
commit
525fd3145d
|
@ -34,13 +34,7 @@ export default new class EmoteModule {
|
|||
|
||||
const dataPath = Globals.getPath('data');
|
||||
try {
|
||||
const emotes = await FileUtils.readJsonFromFile(path.join(dataPath, 'emotes.json'));
|
||||
for (let emote of emotes) {
|
||||
const uri = emote.type === 2 ? 'https://cdn.betterttv.net/emote/:id/1x' : emote.type === 1 ? 'https://cdn.frankerfacez.com/emoticon/:id/1' : 'https://static-cdn.jtvnw.net/emoticons/v1/:id/1.0';
|
||||
emote.name = emote.id;
|
||||
emote.src = uri.replace(':id', emote.value.id || emote.value);
|
||||
this.emotes.set(emote.id, emote);
|
||||
}
|
||||
await this.load(path.join(dataPath, 'emotes.json'));
|
||||
} catch (err) {
|
||||
Logger.err('EmoteModule', [`Failed to load emote data. Make sure you've downloaded the emote data and placed it in ${dataPath}:`, err]);
|
||||
return;
|
||||
|
@ -53,6 +47,20 @@ export default new class EmoteModule {
|
|||
}
|
||||
}
|
||||
|
||||
async load(dataPath) {
|
||||
const emotes = await FileUtils.readJsonFromFile(dataPath);
|
||||
for (let [index, emote] of emotes.entries()) {
|
||||
// Pause every 10000 emotes so the window doesn't freeze
|
||||
if ((index % 10000) === 0)
|
||||
await Utils.wait();
|
||||
|
||||
const uri = emote.type === 2 ? 'https://cdn.betterttv.net/emote/:id/1x' : emote.type === 1 ? 'https://cdn.frankerfacez.com/emoticon/:id/1' : 'https://static-cdn.jtvnw.net/emoticons/v1/:id/1.0';
|
||||
emote.name = emote.id;
|
||||
emote.src = uri.replace(':id', emote.value.id || emote.value);
|
||||
this.emotes.set(emote.id, emote);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an emote as favourite.
|
||||
* @param {String} emote The name of the emote
|
||||
|
@ -61,6 +69,7 @@ export default new class EmoteModule {
|
|||
* @return {Promise}
|
||||
*/
|
||||
setFavourite(emote, favourite, save = true) {
|
||||
emote = emote.id || emote;
|
||||
if (favourite && !this.favourite_emotes.includes(emote)) this.favourite_emotes.push(emote);
|
||||
if (!favourite) Utils.removeFromArray(this.favourite_emotes, emote);
|
||||
if (save) return Settings.saveSettings();
|
||||
|
@ -75,6 +84,7 @@ export default new class EmoteModule {
|
|||
}
|
||||
|
||||
isFavourite(emote) {
|
||||
emote = emote.id || emote;
|
||||
return this.favourite_emotes.includes(emote);
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ export default new class {
|
|||
if (sendSource)
|
||||
this.sendToEditor('set-scss', scss);
|
||||
|
||||
if (!scss) {
|
||||
if (!scss && !await this.fileExists()) {
|
||||
this._scss = this.css = '';
|
||||
this.sendToEditor('scss-error', null);
|
||||
return;
|
||||
|
|
|
@ -88,6 +88,7 @@ export default class PluginApi {
|
|||
deepfreeze: (...args) => Utils.deepfreeze.apply(Utils, args),
|
||||
removeFromArray: (...args) => Utils.removeFromArray.apply(Utils, args),
|
||||
defineSoftGetter: (...args) => Utils.defineSoftGetter.apply(Utils, args),
|
||||
wait: (...args) => Utils.wait.apply(Utils, args),
|
||||
until: (...args) => Utils.until.apply(Utils, args)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ export default new class Settings {
|
|||
Events.emit(`setting-updated-${set.id}_${category.id}_${setting.id}`, event);
|
||||
});
|
||||
|
||||
set.on('settings-updated', async (event) => {
|
||||
await this.saveSettings();
|
||||
set.on('settings-updated', async event => {
|
||||
if (!event.data || !event.data.dont_save) await this.saveSettings();
|
||||
Events.emit('settings-updated', event);
|
||||
});
|
||||
|
||||
|
@ -43,6 +43,8 @@ export default new class Settings {
|
|||
* Loads BetterDiscord's settings.
|
||||
*/
|
||||
async loadSettings() {
|
||||
Logger.log('Settings', ['Loading settings']);
|
||||
|
||||
try {
|
||||
await FileUtils.ensureDirectory(this.dataPath);
|
||||
|
||||
|
@ -53,7 +55,7 @@ export default new class Settings {
|
|||
for (let set of this.settings) {
|
||||
const newSet = settings.find(s => s.id === set.id);
|
||||
if (!newSet) continue;
|
||||
await set.merge(newSet);
|
||||
await set.merge(newSet, {dont_save: true});
|
||||
set.setSaved();
|
||||
}
|
||||
|
||||
|
@ -71,6 +73,8 @@ export default new class Settings {
|
|||
* Saves BetterDiscord's settings including CSS editor data.
|
||||
*/
|
||||
async saveSettings() {
|
||||
Logger.log('Settings', ['Saving settings']);
|
||||
|
||||
try {
|
||||
await FileUtils.ensureDirectory(this.dataPath);
|
||||
|
||||
|
|
|
@ -148,6 +148,8 @@ export default class Theme extends Content {
|
|||
* @param {Array} files Files to watch
|
||||
*/
|
||||
set watchfiles(files) {
|
||||
if (!files) files = [];
|
||||
|
||||
for (let file of files) {
|
||||
if (!this.watchfiles.includes(file)) {
|
||||
this.filewatcher.add(file);
|
||||
|
|
|
@ -24,6 +24,13 @@ export default class Event {
|
|||
return this.__eventInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra data associated with this event.
|
||||
*/
|
||||
get data() {
|
||||
return this.args.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* The first argument that was passed to the constructor, which contains information about the event.
|
||||
*/
|
||||
|
|
|
@ -412,7 +412,8 @@ export default class SettingsSet extends AsyncEventEmitter {
|
|||
|
||||
if (emit_multi)
|
||||
await this.emit('settings-updated', new SettingsUpdatedEvent({
|
||||
updatedSettings
|
||||
updatedSettings,
|
||||
data: typeof emit_multi !== 'boolean' ? emit_multi : undefined
|
||||
}));
|
||||
|
||||
return updatedSettings;
|
||||
|
|
|
@ -21,7 +21,10 @@
|
|||
vertical-align: -.4em;
|
||||
max-height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-emotewrapper,
|
||||
.bd-autocomplete-selector {
|
||||
.bd-emote-favourite-button {
|
||||
display: none;
|
||||
width: 16px;
|
||||
|
@ -46,7 +49,20 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.bd-selected .bd-emote-favourite-button,
|
||||
&:hover .bd-emote-favourite-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.bd-autocomplete-selector {
|
||||
.bd-emote-favourite-button {
|
||||
margin-left: 8px;
|
||||
margin-right: 0;
|
||||
opacity: .5;
|
||||
|
||||
&.bd-active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,4 +77,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bd-active + [class*="inner"] {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,7 +185,7 @@ export default class extends EventListener {
|
|||
const root = document.createElement('span');
|
||||
const parent = document.querySelector('[class*="channelTextArea"] > [class*="inner"]');
|
||||
if (!parent) return;
|
||||
parent.append(root);
|
||||
parent.parentElement.insertBefore(root, parent);
|
||||
VueInjector.inject(root, {
|
||||
components: { Autocomplete },
|
||||
data: { initial: e.target.value },
|
||||
|
|
|
@ -45,6 +45,10 @@
|
|||
if (this.$refs.settings.activeIndex !== -1) this.$refs.settings.closeContent();
|
||||
else this.active = false;
|
||||
e.stopImmediatePropagation();
|
||||
},
|
||||
prevent(e) {
|
||||
if (this.active && e.which === 27)
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -68,12 +72,14 @@
|
|||
Events.on('update-check-end', e => this.updating = 1);
|
||||
Events.on('updates-available', e => this.updating = 2);
|
||||
window.addEventListener('keyup', this.keyupListener);
|
||||
window.addEventListener('keydown', this.prevent, true);
|
||||
|
||||
const menuKeybind = Settings.getSetting('core', 'default', 'menu-keybind');
|
||||
menuKeybind.on('keybind-activated', () => this.active = !this.active);
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('keyup', this.keyupListener);
|
||||
window.removeEventListener('keydown', this.prevent);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
<template>
|
||||
<div class="bd-autocomplete">
|
||||
<div class="bd-autocomplete" :class="{'bd-active': emotes && emotes.length}">
|
||||
<div v-if="emotes && emotes.length" class="bd-autocomplete-inner">
|
||||
<div class="bd-autocomplete-row">
|
||||
<div class="bd-autocomplete-selector">
|
||||
|
@ -20,10 +20,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<div v-for="(emote, index) in emotes" class="bd-autocomplete-row" :key="index">
|
||||
<div class="bd-autocomplete-selector bd-selectable" :class="{'bd-selected': index === selectedIndex}" @mouseover="() => { selected = emote.id }" @click="() => inject(emote)">
|
||||
<div class="bd-autocomplete-selector bd-selectable" :class="{'bd-selected': index === selectedIndex, 'bd-emote-favourite': isFavourite(emote)}" @mouseover="selected = emote.id" @click="inject(emote)">
|
||||
<div class="bd-autocomplete-field">
|
||||
<img :src="getEmoteSrc(emote)"/>
|
||||
<div>{{emote.id}}</div>
|
||||
<img :src="emote.src" :alt="emote.name" />
|
||||
<div class="bd-flex-grow">{{emote.id}}</div>
|
||||
<div class="bd-emote-favourite-button" :class="{'bd-active': isFavourite(emote)}" @click.stop="toggleFavourite(emote)">
|
||||
<MiStar :size="16" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -33,12 +36,17 @@
|
|||
|
||||
<script>
|
||||
import { EmoteModule } from 'builtin';
|
||||
import { Events } from 'modules';
|
||||
import { Events, Settings } from 'modules';
|
||||
import { DOM } from 'ui';
|
||||
import { MiStar } from './MaterialIcon';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MiStar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
EmoteModule,
|
||||
emotes: [],
|
||||
title: '',
|
||||
selIndex: 0,
|
||||
|
@ -54,24 +62,38 @@
|
|||
// this.open = this.emotes.length;
|
||||
},
|
||||
created() {
|
||||
window.addEventListener('keydown', this.prevents);
|
||||
const ta = document.querySelector('.chat textarea');
|
||||
if(!ta) return;
|
||||
ta.addEventListener('keydown', this.setCaret);
|
||||
ta.addEventListener('keyup', this.searchEmotes);
|
||||
const enabled = Settings.getSetting('emotes', 'default', 'enable');
|
||||
enabled.on('setting-updated', event => {
|
||||
if (event.value) return this.addEventListeners();
|
||||
this.removeEventListeners();
|
||||
this.reset();
|
||||
});
|
||||
|
||||
if (enabled.value) this.addEventListeners();
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('keydown', this.prevents);
|
||||
const ta = document.querySelector('.chat textarea');
|
||||
if (!ta) return;
|
||||
ta.removeEventListener('keydown', this.setCaret);
|
||||
ta.removeEventListener('keyup', this.searchEmotes);
|
||||
this.removeEventListeners();
|
||||
},
|
||||
methods: {
|
||||
addEventListeners() {
|
||||
window.addEventListener('keydown', this.prevents);
|
||||
const ta = document.querySelector('.chat textarea');
|
||||
if (!ta) return;
|
||||
ta.addEventListener('keydown', this.setCaret);
|
||||
ta.addEventListener('keyup', this.searchEmotes);
|
||||
},
|
||||
removeEventListeners() {
|
||||
window.removeEventListener('keydown', this.prevents);
|
||||
const ta = document.querySelector('.chat textarea');
|
||||
if (!ta) return;
|
||||
ta.removeEventListener('keydown', this.setCaret);
|
||||
ta.removeEventListener('keyup', this.searchEmotes);
|
||||
},
|
||||
prevents(e) {
|
||||
if (!this.open) return;
|
||||
if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp' && e.key !== 'Tab' && e.key !== 'Enter') return;
|
||||
this.traverse(e);
|
||||
if (e.which === 27) this.reset();
|
||||
else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') this.traverse(e);
|
||||
else if (e.key !== 'Tab' && e.key !== 'Enter') return;
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
},
|
||||
|
@ -84,8 +106,14 @@
|
|||
const uri = emote.type === 2 ? 'https://cdn.betterttv.net/emote/:id/1x' : emote.type === 1 ? 'https://cdn.frankerfacez.com/emoticon/:id/1' : 'https://static-cdn.jtvnw.net/emoticons/v1/:id/1.0';
|
||||
return uri.replace(':id', value);
|
||||
},
|
||||
isFavourite(emote) {
|
||||
return EmoteModule.isFavourite(emote);
|
||||
},
|
||||
toggleFavourite(emote) {
|
||||
return EmoteModule.setFavourite(emote, !this.isFavourite(emote));
|
||||
},
|
||||
searchEmotes(e) {
|
||||
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') return;
|
||||
if (e.which === 27 || e.key === 'ArrowDown' || e.key === 'ArrowUp') return;
|
||||
if (e.key === 'Tab' || e.key === 'Enter' && this.open) {
|
||||
const selected = this.emotes[this.selectedIndex];
|
||||
if (!selected) return;
|
||||
|
@ -113,11 +141,11 @@
|
|||
traverse(e) {
|
||||
if (!this.open) return;
|
||||
if (e.key === 'ArrowUp') {
|
||||
this.selectedIndex = (this.selectedIndex - 1) < 0 ? 9 : this.selectedIndex - 1;
|
||||
this.selectedIndex = (this.selectedIndex - 1) < 0 ? Math.min(this.emotes.length, 10) - 1 : this.selectedIndex - 1;
|
||||
return;
|
||||
}
|
||||
if (e.key === 'ArrowDown') {
|
||||
this.selectedIndex = (this.selectedIndex + 1) >= 10 ? 0 : this.selectedIndex + 1;
|
||||
this.selectedIndex = (this.selectedIndex + 1) >= Math.min(this.emotes.length, 10) ? 0 : this.selectedIndex + 1;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="bd-dropdown-options bd-flex bd-flex-col" ref="options" v-if="active">
|
||||
<div class="bd-dropdown-option" v-for="option in options" :class="{'bd-dropdown-option-selected': selected === option.value}" @click="select(option)">{{ option.text }}</div>
|
||||
<div class="bd-dropdown-option" v-for="option in options" :class="{'bd-dropdown-option-selected': value === option.value}" @click="select(option)">{{ option.text }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -32,8 +32,8 @@
|
|||
},
|
||||
methods: {
|
||||
getSelectedText() {
|
||||
const selected_option = this.options.find(option => option.value === this.selected);
|
||||
return selected_option ? selected_option.text : this.selected;
|
||||
const selected_option = this.options.find(option => option.value === this.value);
|
||||
return selected_option ? selected_option.text : this.value;
|
||||
},
|
||||
select(option) {
|
||||
this.$emit('input', option.value);
|
||||
|
|
|
@ -89,6 +89,13 @@ export default class extends Module {
|
|||
const nameTag = retVal.props.children.props.children[1].props.children[0];
|
||||
nameTag.type = this.PatchedNameTag || nameTag.type;
|
||||
});
|
||||
|
||||
// Rerender all channel members
|
||||
if (this.PatchedNameTag) {
|
||||
for (const channelMember of document.querySelectorAll('.member-2FrNV0')) {
|
||||
Reflection(channelMember).forceUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,8 +142,10 @@ export default class extends Module {
|
|||
};
|
||||
|
||||
// Rerender all channel members
|
||||
for (const channelMember of document.querySelectorAll('.member-2FrNV0')) {
|
||||
Reflection(channelMember).forceUpdate();
|
||||
if (this.unpatchChannelMemberRender) {
|
||||
for (const channelMember of document.querySelectorAll('.member-2FrNV0')) {
|
||||
Reflection(channelMember).forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
return this.PatchedNameTag;
|
||||
|
|
|
@ -32,7 +32,7 @@ export class Utils {
|
|||
return JSON.parse(jsonString);
|
||||
} catch (err) {
|
||||
throw ({
|
||||
'message': 'Failed to parse json',
|
||||
message: 'Failed to parse json',
|
||||
err
|
||||
});
|
||||
}
|
||||
|
@ -160,6 +160,10 @@ export class Utils {
|
|||
});
|
||||
}
|
||||
|
||||
static wait(time = 0) {
|
||||
return new Promise(resolve => setTimeout(resolve, time));
|
||||
}
|
||||
|
||||
static async until(check, time = 0) {
|
||||
let value, i;
|
||||
do {
|
||||
|
|
|
@ -78,5 +78,5 @@ const node_sass_bindings = function() {
|
|||
};
|
||||
|
||||
gulp.task('release', function () {
|
||||
del(['./release/**/*']).then(() => merge(releasepkg(), client(), core(), sparkplug(), core_modules(), index(), cssEditor(), deps(), node_sass_bindings()));
|
||||
return del(['./release/**/*']).then(() => merge(releasepkg(), client(), core(), sparkplug(), core_modules(), index(), cssEditor(), deps(), node_sass_bindings()));
|
||||
});
|
||||
|
|
|
@ -7852,6 +7852,16 @@
|
|||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
|
||||
"dev": true
|
||||
},
|
||||
"pump": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
|
||||
"integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"end-of-stream": "1.4.1",
|
||||
"once": "1.4.0"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
|
||||
|
@ -9872,9 +9882,9 @@
|
|||
}
|
||||
},
|
||||
"pump": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
|
||||
"integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"end-of-stream": "1.4.1",
|
||||
|
@ -9884,7 +9894,7 @@
|
|||
"end-of-stream": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
|
||||
"integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=",
|
||||
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "1.4.0"
|
||||
|
@ -9901,6 +9911,27 @@
|
|||
"duplexify": "3.5.4",
|
||||
"inherits": "2.0.3",
|
||||
"pump": "2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"end-of-stream": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
|
||||
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "1.4.0"
|
||||
}
|
||||
},
|
||||
"pump": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
|
||||
"integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"end-of-stream": "1.4.1",
|
||||
"once": "1.4.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"punycode": {
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
"lodash": "^4.17.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-gyp": "^3.6.2",
|
||||
"pump": "^2.0.0",
|
||||
"pump": "^3.0.0",
|
||||
"sass-loader": "^6.0.6",
|
||||
"uglifyjs-webpack-plugin": "^1.2.4",
|
||||
"v-tooltip": "^2.0.0-rc.30",
|
||||
|
|
Loading…
Reference in New Issue