fix all circulars, start i18n

This commit is contained in:
Zack Rauen 2019-06-24 15:47:24 -04:00
parent 1f4535427f
commit 22e3072304
15 changed files with 210 additions and 124 deletions

File diff suppressed because one or more lines are too long

2
js/main.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
import Builtin from "../structs/builtin";
import {DataStore, Utilities, Events} from "modules";
import {Utilities, Events} from "modules";
import EmoteModule from "./emotes";
@ -50,7 +50,6 @@ export default new class EmoteMenu extends Builtin {
constructor() {
super();
this.lastTab = "bda-qem-emojis";
this.favoriteEmotes = {};
this.qmeHeader = Utilities.parseHTML(headerHTML);
for (const button of this.qmeHeader.getElementsByTagName("button")) button.addEventListener("click", this.switchMenu.bind(this));
@ -67,13 +66,6 @@ export default new class EmoteMenu extends Builtin {
this.updateTwitchEmotes = this.updateTwitchEmotes.bind(this);
}
initialize() {
super.initialize();
const fe = DataStore.getBDData("bdfavemotes");
if (fe !== "" && fe !== null) this.favoriteEmotes = JSON.parse(window.atob(fe));
this.updateFavorites();
}
async enabled() {
this.log("Starting to observe");
this.observer.observe(document.getElementById("app-mount"), {
@ -121,7 +113,7 @@ export default new class EmoteMenu extends Builtin {
event.preventDefault();
event.stopPropagation();
$(em).remove();
delete this.favoriteEmotes[$(em).attr("title")];
EmoteModule.removeFavorite($(em).attr("title"));
this.updateFavorites();
$(document).off("mousedown.emotemenu");
});
@ -180,11 +172,6 @@ export default new class EmoteMenu extends Builtin {
this.switchMenu(this.lastTab);
}
favorite(name, url) {
if (!this.favoriteEmotes.hasOwnProperty(name)) this.favoriteEmotes[name] = url;
this.updateFavorites();
}
updateTwitchEmotes() {
while (this.teContainerInner.firstChild) this.teContainerInner.firstChild.remove();
for (const emote in EmoteModule.getCategory("TwitchGlobal")) {
@ -197,12 +184,12 @@ export default new class EmoteMenu extends Builtin {
updateFavorites() {
while (this.faContainerInner.firstChild) this.faContainerInner.firstChild.remove();
for (const emote in this.favoriteEmotes) {
const url = this.favoriteEmotes[emote];
for (const emote in EmoteModule.favorites) {
const url = EmoteModule.favorites[emote];
const emoteElement = makeEmote(emote, url, {onClick: this.insertEmote.bind(this, emote), onContextMenu: this.favContext.bind(this)});
this.faContainerInner.append(emoteElement);
}
DataStore.setBDData("bdfavemotes", window.btoa(JSON.stringify(this.favoriteEmotes)));
EmoteModule.saveFavorites();
}
};

View File

@ -4,6 +4,7 @@ import {Config, EmoteInfo, EmoteConfig} from "data";
import {Utilities, WebpackModules, DataStore, DiscordModules, Events, Settings} from "modules";
import BDEmote from "../ui/emote";
import Toasts from "../ui/toasts";
// import EmoteMenu from "./emotemenu";
const Emotes = {
TwitchGlobal: {},
@ -32,13 +33,9 @@ export default new class EmoteModule extends Builtin {
get id() {return "emotes";}
get categories() { return Object.keys(bdEmoteSettingIDs).filter(k => this.isCategoryEnabled(bdEmoteSettingIDs[k])); }
isCategoryEnabled(id) {
return super.get("emotes", "categories", id);
}
isCategoryEnabled(id) {return super.get("emotes", "categories", id);}
get(id) {
return super.get("emotes", "general", id);
}
get(id) {return super.get("emotes", "general", id);}
get MessageContentComponent() {return WebpackModules.getModule(m => m.defaultProps && m.defaultProps.hasOwnProperty("disableButtons"));}
@ -49,6 +46,7 @@ export default new class EmoteModule extends Builtin {
get FrankerFaceZ() {return Emotes.FrankerFaceZ;}
get BTTV2() {return Emotes.BTTV2;}
get blacklist() {return blacklist;}
get favorites() {return this.favoriteEmotes;}
getCategory(category) {
return Emotes[category];
@ -56,6 +54,12 @@ export default new class EmoteModule extends Builtin {
initialize() {
super.initialize();
this.favoriteEmotes = {};
const fe = DataStore.getBDData("bdfavemotes");
if (fe !== "" && fe !== null) this.favoriteEmotes = JSON.parse(window.atob(fe));
this.saveFavorites();
this.addFavorite = this.addFavorite.bind(this);
this.removeFavorite = this.removeFavorite.bind(this);
// EmoteConfig;
// emoteCollection.button = {title: "Clear Emote Cache", onClick: () => { this.clearEmoteData(); this.loadEmoteData(EmoteInfo); }};
}
@ -68,9 +72,13 @@ export default new class EmoteModule extends Builtin {
// while (!this.MessageContentComponent) await new Promise(resolve => setTimeout(resolve, 100));
// this.patchMessageContent();
Events.on("emotes-favorite-added", this.addFavorite);
Events.on("emotes-favorite-removed", this.removeFavorite);
}
disabled() {
Events.off("emotes-favorite-added", this.addFavorite);
Events.off("emotes-favorite-removed", this.removeFavorite);
Settings.removeCollection("emotes");
this.emptyEmotes();
if (!this.cancelEmoteRender) return;
@ -78,6 +86,25 @@ export default new class EmoteModule extends Builtin {
delete this.cancelEmoteRender;
}
addFavorite(name, url) {
if (!this.favoriteEmotes.hasOwnProperty(name)) this.favoriteEmotes[name] = url;
this.saveFavorites();
}
removeFavorite(name) {
if (!this.favoriteEmotes.hasOwnProperty(name)) return;
delete this.favoriteEmotes[name];
this.saveFavorites();
}
isFavorite(name) {
return this.favoriteEmotes.hasOwnProperty(name);
}
saveFavorites() {
DataStore.setBDData("bdfavemotes", window.btoa(JSON.stringify(this.favoriteEmotes)));
}
emptyEmotes() {
for (const cat in Emotes) Object.assign(Emotes, {[cat]: {}});
}
@ -127,7 +154,7 @@ export default new class EmoteModule extends Builtin {
const pre = nodes[n].substring(0, results.index + results[1].length);
const post = nodes[n].substring(results.index + results[0].length - results[2].length);
nodes[n] = pre;
const emoteComponent = DiscordModules.React.createElement(BDEmote, {name: emoteName, url: Emotes[current][emoteName], modifier: emoteModifier});
const emoteComponent = DiscordModules.React.createElement(BDEmote, {name: emoteName, url: Emotes[current][emoteName], modifier: emoteModifier, isFavorite: this.isFavorite(emoteName)});
nodes.splice(n + 1, 0, post);
nodes.splice(n + 1, 0, emoteComponent);
}

39
src/data/strings.js Normal file
View File

@ -0,0 +1,39 @@
export default {
en: {
Settings: {
PublicServers: {name: "Public Servers", description: "Display public servers button"},
MinimalMode: {name: "Minimal Mode", description: "Hide elements and reduce the size of elements."},
VoiceMode: {name: "Voice Mode", description: "Only show voice chat"},
HideChannels: {name: "Hide Channels", description: "Hide channels in minimal mode"},
DarkMode: {name: "Dark Mode", description: "Make certain elements dark by default"},
VoiceDisconnect: {name: "Voice Disconnect", description: "Disconnect from voice server when closing Discord"},
Timestamps: {name: "24 Hour Timestamps", description: "Replace 12hr timestamps with proper ones"},
ColoredText: {name: "Colored Text", description: "Make text colour the same as role colour"},
BDBlue: {name: "BandagedBD Blue", description: "Replace Discord blue with BD Blue"},
DeveloperMode: {name: "Developer Mode", description: "Developer Mode"},
ContentErrors: {name: "Content Error Modals", description: "Shows a modal with plugin/theme errors"},
Toasts: {name: "Show Toasts", description: "Shows a small notification for important information"},
Scroll: {name: "Scroll to Settings", description: "Auto-scrolls to a plugin's settings when the button is clicked (only if out of view)"},
AnimateOnHover: {name: "Animate On Hover", description: "Only animate the emote modifiers on hover"},
CopySelector: {name: "Copy Selector", description: "Adds a \"Copy Selector\" option to context menus when developer mode is active"},
DownloadEmotes: {name: "Download Emotes", description: "Download emotes when the cache is expired"},
NormalizeClasses: {name: "Normalize Classes", description: "Adds stable classes to elements to help themes. (e.g. adds .da-channels to .channels-Ie2l6A)"},
AutomaticLoading: {name: "Automatic Loading", description: "Automatically loads, reloads, and unloads plugins and themes"},
Transparency: {name: "Enable Transparency", description: "Enables the main window to be see-through (requires restart)"},
Twitch: {name: "Twitch Emotes", description: "Show Twitch emotes"},
FFZ: {name: "FrankerFaceZ Emotes", description: "Show FrankerFaceZ Emotes"},
BTTV: {name: "BetterTTV Emotes", description: "Show BetterTTV Emotes"},
EmoteMenu: {name: "Emote Menu", description: "Show Twitch/Favourite emotes in emote menu"},
EmojiMenu: {name: "Emoji Menu", description: "Show Discord emoji menu"},
AutoCaps: {name: "Auto Capitalization", description: "Autocapitalize emote commands"},
ShowNames: {name: "Show Names", description: "Show emote names on hover"},
Modifiers: {name: "Emote Modifiers", description: "Enable emote mods (flip, spin, pulse, spin2, spin3, 1spin, 2spin, 3spin, tr, bl, br, shake, shake2, shake3, flap)"}
}
},
es: {
Settings: {
PublicServers: {name: "Public Sefasasfasfasfrvers", description: "Display public servers button"},
MinimalMode: {name: "Minafimal Mode", description: "Hide elements and reduce the size of elements."}
}
}
};

View File

@ -1,41 +0,0 @@
{
"en": {
"settings": {
"core": {
"PublicServers": {"name": "Public Servers", "description": "Display public servers button"},
"MinimalMode": {"name": "Minimal Mode", "description": "Hide elements and reduce the size of elements."},
"VoiceMode": {"name": "Voice Mode", "description": "Only show voice chat"},
"HideChannels": {"name": "Hide Channels", "description": "Hide channels in minimal mode"},
"DarkMode": {"name": "Dark Mode", "description": "Make certain elements dark by default"},
"VoiceDisconnect": {"name": "Voice Disconnect", "description": "Disconnect from voice server when closing Discord"},
"Timestamps": {"name": "24 Hour Timestamps", "description": "Replace 12hr timestamps with proper ones"},
"ColoredText": {"name": "Colored Text", "description": "Make text colour the same as role colour"},
"BDBlue": {"name": "BandagedBD Blue", "description": "Replace Discord blue with BD Blue"},
"DeveloperMode": {"name": "Developer Mode", "description": "Developer Mode"}
},
"fork": {
"ContentErrors": {"name": "Content Error Modals", "description": "Shows a modal with plugin/theme errors"},
"Toasts": {"name": "Show Toasts", "description": "Shows a small notification for important information"},
"Scroll": {"name": "Scroll to Settings", "description": "Auto-scrolls to a plugin's settings when the button is clicked (only if out of view)"},
"AnimateOnHover": {"name": "Animate On Hover", "description": "Only animate the emote modifiers on hover"},
"CopySelector": {"name": "Copy Selector", "description": "Adds a \"Copy Selector\" option to context menus when developer mode is active"},
"DownloadEmotes": {"name": "Download Emotes", "description": "Download emotes when the cache is expired"},
"NormalizeClasses": {"name": "Normalize Classes", "description": "Adds stable classes to elements to help themes. (e.g. adds .da-channels to .channels-Ie2l6A)"},
"AutomaticLoading": {"name": "Automatic Loading", "description": "Automatically loads, reloads, and unloads plugins and themes"},
"Transparency": {"name": "Enable Transparency", "description": "Enables the main window to be see-through (requires restart)"}
},
"emote": {
"Twitch": {"name": "Twitch Emotes", "description": "Show Twitch emotes"},
"FFZ": {"name": "FrankerFaceZ Emotes", "description": "Show FrankerFaceZ Emotes"},
"BTTV": {"name": "BetterTTV Emotes", "description": "Show BetterTTV Emotes"},
"EmoteMenu": {"name": "Emote Menu", "description": "Show Twitch/Favourite emotes in emote menu"},
"EmojiMenu": {"name": "Emoji Menu", "description": "Show Discord emoji menu"},
"AutoCaps": {"name": "Auto Capitalization", "description": "Autocapitalize emote commands"},
"ShowNames": {"name": "Show Names", "description": "Show emote names on hover"},
"Modifiers": {"name": "Emote Modifiers", "description": "Enable emote mods (flip, spin, pulse, spin2, spin3, 1spin, 2spin, 3spin, tr, bl, br, shake, shake2, shake3, flap)"}
}
}
}
}

View File

@ -10,6 +10,7 @@ import EmoteModule from "./builtins/emotes";
import DomManager from "./modules/dommanager";
import Utilities from "./modules/utilities";
import ReactComponents from "./modules/reactcomponents";
import Strings from "./modules/strings";
// Perform some setup
// proxyLocalStorage();
@ -41,6 +42,7 @@ window.Components = ReactComponents;
window.BDEvents = Events;
window.bdConfig = Config;
window.Strings = Strings;
export default class CoreWrapper {
constructor(config) {

View File

@ -4,7 +4,7 @@ import Utilities from "./utilities";
import Patcher from "./patcher";
import BDLogo from "../ui/icons/bdlogo";
export default new class V2 {
export default new class ComponentPatcher {
initialize() {
Utilities.suppressErrors(this.patchSocial.bind(this), "BD Social Patch")();

View File

@ -38,12 +38,16 @@ export default class ContentManager {
this.timeCache = {};
this.contentList = [];
this.state = {};
}
initialize() {
this.originalRequire = Module._extensions[this.moduleExtension];
Module._extensions[this.moduleExtension] = this.getContentRequire();
Settings.on(this.collection, this.category, this.id, (enabled) => {
if (enabled) this.watchContent();
else this.unwatchContent();
});
return this.loadAllContent();
}
// Subclasses should overload this and modify the content object as needed to fully load it

View File

@ -1,4 +1,4 @@
import BDV2 from "./bdv2";
import ComponentPatcher from "./componentpatcher";
import Logger from "./logger";
import {Config} from "data";
// import EmoteModule from "./emotes";
@ -43,17 +43,14 @@ Core.prototype.init = async function() {
DOMManager.initialize();
await this.waitForGuilds();
BDV2.initialize();
ComponentPatcher.initialize();
for (const module in Builtins) Builtins[module].initialize();
Logger.log("Startup", "Loading Plugins");
const pluginErrors = PluginManager.loadAllPlugins();
const pluginErrors = PluginManager.initialize();
Logger.log("Startup", "Loading Themes");
const themeErrors = ThemeManager.loadAllThemes();
// PublicServers.initialize();
// EmoteModule.autoCapitalize();
const themeErrors = ThemeManager.initialize();
Logger.log("Startup", "Removing Loading Icon");
document.getElementsByClassName("bd-loaderv2")[0].remove();

View File

@ -29,8 +29,21 @@ export default new class PluginManager extends ContentManager {
});
}
initialize() {
const errors = super.initialize();
this.setupFunctions();
Settings.registerPanel("plugins", "Plugins", {element: () => SettingsRenderer.getContentPanel("Plugins", this.contentList, this.state, {
folder: this.contentFolder,
onChange: this.togglePlugin.bind(this),
reload: this.reloadPlugin.bind(this),
refreshList: this.updatePluginList.bind(this)
})});
return errors;
}
/* Aliases */
updatePluginList() {return this.updateList();}
loadAllPlugins() {return this.loadAllContent();}
enablePlugin(idOrContent) {return this.enableContent(idOrContent);}
disablePlugin(idOrContent) {return this.disableContent(idOrContent);}
@ -49,18 +62,6 @@ export default new class PluginManager extends ContentManager {
return typeof(idOrFileOrContent) == "string" ? this.contentList.find(c => c.id == idOrFileOrContent || c.filename == idOrFileOrContent) : idOrFileOrContent;
}
loadAllPlugins() {
const errors = this.loadAllContent();
this.setupFunctions();
Settings.registerPanel("plugins", "Plugins", {element: () => SettingsRenderer.getContentPanel("Plugins", this.contentList, this.state, {
folder: this.contentFolder,
onChange: this.togglePlugin.bind(this),
reload: this.reloadPlugin.bind(this),
refreshList: this.updatePluginList.bind(this)
})});
return errors;
}
/* Overrides */
initializeContent(content) {
if (!content.type) return new ContentError(content.name, content.filename, "Plugin had no exports", {message: "Plugin had no exports or no name property.", stack: ""});

View File

@ -1,11 +1,31 @@
import {KnownModules} from "./webpackmodules";
import strings from "../data/strings";
import DiscordModules from "./discordmodules";
import RawStrings from "../data/strings";
import Utilities from "./utilities";
const {Dispatcher, DiscordConstants} = DiscordModules;
const Messages = {};
export let currentLocale = "en";
export function setLocale(newLocale) {
currentLocale = newLocale;
Utilities.extend(Messages, RawStrings[currentLocale]);
}
Utilities.extend(Messages, RawStrings[currentLocale]);
Dispatcher.subscribe(DiscordConstants.ActionTypes.USER_SETTINGS_UPDATE, ({settings}) => {
const newLocale = settings.locale;
if (newLocale && newLocale != currentLocale) setLocale(newLocale.split("-")[0]);
});
export default new Proxy(Messages, {
get: function(strings, category) {
if (strings.hasOwnProperty(category)) return strings[category];
return new Proxy({}, {
get: function() {
return `String group "${category}" not found.`;
}
});
}
});
Object.defineProperty(module, "exports", {
get: () => {
if (!strings) return {};
const locale = KnownModules.UserSettingsStore.locale.split("-")[0];
if (strings.hasOwnProperty(locale)) return strings[locale];
return strings.en;
}
});

View File

@ -16,18 +16,21 @@ export default new class ThemeManager extends ContentManager {
get contentFolder() {return path.resolve(Config.dataPath, "themes");}
get prefix() {return "theme";}
/* Aliases */
updateThemeList() {return this.updateList();}
loadAllThemes() {
initialize() {
const errors = super.initialize();
Settings.registerPanel("themes", "Themes", {element: () => SettingsRenderer.getContentPanel("Themes", this.contentList, this.state, {
folder: this.contentFolder,
onChange: this.toggleTheme.bind(this),
reload: this.reloadTheme.bind(this),
refreshList: this.updateThemeList.bind(this)
})});
return this.loadAllContent();
return errors;
}
/* Aliases */
updateThemeList() {return this.updateList();}
loadAllThemes() {return this.loadAllContent();}
enableTheme(idOrContent) {return this.enableContent(idOrContent);}
disableTheme(idOrContent) {return this.disableContent(idOrContent);}
toggleTheme(id) {return this.toggleContent(id);}

View File

@ -149,6 +149,28 @@ export default class Utilities {
return proxy;
}
/**
* Deep extends an object with a set of other objects. Objects later in the list
* of `extenders` have priority, that is to say if one sets a key to be a primitive,
* it will be overwritten with the next one with the same key. If it is an object,
* and the keys match, the object is extended. This happens recursively.
* @param {object} extendee - Object to be extended
* @param {...object} extenders - Objects to extend with
* @returns {object} - A reference to `extendee`
*/
static extend(extendee, ...extenders) {
for (let i = 0; i < extenders.length; i++) {
for (const key in extenders[i]) {
if (extenders[i].hasOwnProperty(key)) {
if (typeof extendee[key] === "object" && typeof extenders[i][key] === "object") this.extend(extendee[key], extenders[i][key]);
else if (typeof extenders[i][key] === "object") extendee[key] = {}, this.extend(extendee[key], extenders[i][key]);
else extendee[key] = extenders[i][key];
}
}
}
return extendee;
}
/**
* Format strings with placeholders (`{{placeholder}}`) into full strings.
* Quick example: `PluginUtilities.formatString("Hello, {{user}}", {user: "Zerebos"})`

View File

@ -1,5 +1,5 @@
import {Settings, React, WebpackModules} from "modules";
import EmoteMenu from "../builtins/emotemenu";
import {Settings, React, WebpackModules, Events} from "modules";
// import EmoteMenu from "../builtins/emotemenu";
const TooltipWrapper = WebpackModules.getByDisplayName("TooltipDeprecated");
@ -7,10 +7,9 @@ export default class BDEmote extends React.Component {
constructor(props) {
super(props);
const isFav = EmoteMenu && EmoteMenu.favoriteEmotes && EmoteMenu.favoriteEmotes[this.label] ? true : false;
this.state = {
shouldAnimate: !this.animateOnHover,
isFavorite: isFav
isFavorite: this.props.isFavorite
};
this.onMouseEnter = this.onMouseEnter.bind(this);
@ -32,8 +31,8 @@ export default class BDEmote extends React.Component {
onMouseEnter() {
if (!this.state.shouldAnimate && this.animateOnHover) this.setState({shouldAnimate: true});
if (!this.state.isFavorite && EmoteMenu.favoriteEmotes[this.label]) this.setState({isFavorite: true});
else if (this.state.isFavorite && !EmoteMenu.favoriteEmotes[this.label]) this.setState({isFavorite: false});
// if (!this.state.isFavorite && EmoteMenu.favoriteEmotes[this.label]) this.setState({isFavorite: true});
// else if (this.state.isFavorite && !EmoteMenu.favoriteEmotes[this.label]) this.setState({isFavorite: false});
}
onMouseLeave() {
@ -72,11 +71,13 @@ export default class BDEmote extends React.Component {
e.preventDefault();
e.stopPropagation();
if (this.state.isFavorite) {
delete EmoteMenu.favoriteEmotes[this.label];
EmoteMenu.updateFavorites();
Events.emit("emotes-favorite-removed", this.label);
// delete EmoteMenu.favoriteEmotes[this.label];
// EmoteMenu.updateFavorites();
}
else {
EmoteMenu.favorite(this.label, this.props.url);
Events.emit("emotes-favorite-added", this.label, this.props.url);
// EmoteMenu.favorite(this.label, this.props.url);
}
this.setState({isFavorite: !this.state.isFavorite});
}