rearrange + etags
This commit is contained in:
parent
1e084d31b4
commit
2d1d48e0fd
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -168,7 +168,7 @@
|
|||
"title": "{{name}} v{{version}} by {{author}}",
|
||||
"openFolder": "Open {{type}} Folder",
|
||||
"reload": "Reload",
|
||||
"pluginSettings": "Settings",
|
||||
"addonSettings": "Settings",
|
||||
"website": "Website",
|
||||
"source": "Source",
|
||||
"server": "Support Server",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
{
|
||||
"LatestVersion":"0.3.2",
|
||||
"CDN":"cdn.rawgit.com"
|
||||
"injectorVersion": "0.3.2"
|
||||
}
|
50
js/main.js
50
js/main.js
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,7 @@ import {Utilities, WebpackModules, DataStore, DiscordModules, Events, Settings,
|
|||
import BDEmote from "../ui/emote";
|
||||
import Toasts from "../ui/toasts";
|
||||
// import EmoteMenu from "./emotemenu";
|
||||
const request = require("request");
|
||||
|
||||
const Emotes = {
|
||||
TwitchGlobal: {},
|
||||
|
@ -67,11 +68,11 @@ export default new class EmoteModule extends Builtin {
|
|||
async enabled() {
|
||||
Settings.registerCollection("emotes", "Emotes", EmoteConfig, {title: Strings.Emotes.clearEmotes, onClick: () => { this.clearEmoteData(); this.loadEmoteData(EmoteInfo); }});
|
||||
// Disable emote module for now because it's annoying and slow
|
||||
// await this.getBlacklist();
|
||||
// await this.loadEmoteData(EmoteInfo);
|
||||
await this.getBlacklist();
|
||||
await this.loadEmoteData(EmoteInfo);
|
||||
|
||||
// while (!this.MessageContentComponent) await new Promise(resolve => setTimeout(resolve, 100));
|
||||
// this.patchMessageContent();
|
||||
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);
|
||||
}
|
||||
|
@ -234,7 +235,10 @@ export default new class EmoteModule extends Builtin {
|
|||
}
|
||||
|
||||
downloadEmotes(emoteMeta) {
|
||||
const request = require("request");
|
||||
const repoFile = Utilities.repoUrl(`data/emotes/${emoteMeta.variable.toLowerCase()}.json`);
|
||||
if (emoteMeta.url && !emoteMeta.backup) emoteMeta.backup = repoFile;
|
||||
if (!emoteMeta.url) emoteMeta.url = repoFile;
|
||||
|
||||
const options = {
|
||||
url: emoteMeta.url,
|
||||
timeout: emoteMeta.timeout ? emoteMeta.timeout : 5000,
|
||||
|
@ -244,10 +248,10 @@ export default new class EmoteModule extends Builtin {
|
|||
this.log(`Downloading: ${emoteMeta.variable} (${emoteMeta.url})`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request(options, (error, response, parsedData) => {
|
||||
request.get(options, (error, response, parsedData) => {
|
||||
if (error) {
|
||||
this.stacktrace("Could not download " + emoteMeta.variable, error);
|
||||
if (emoteMeta.backup) {
|
||||
if (emoteMeta.backup || emoteMeta.url) {
|
||||
emoteMeta.url = emoteMeta.backup;
|
||||
emoteMeta.backup = null;
|
||||
if (emoteMeta.backupParser) emoteMeta.parser = emoteMeta.backupParser;
|
||||
|
@ -273,8 +277,9 @@ export default new class EmoteModule extends Builtin {
|
|||
|
||||
getBlacklist() {
|
||||
return new Promise(resolve => {
|
||||
$.getJSON(`https://rauenzi.github.io/BetterDiscordApp/data/emotefilter.json`, function (data) {
|
||||
resolve(blacklist.push(...data.blacklist));
|
||||
request.get({url: Utilities.repoUrl(`data/emotes/blacklist.json`), json: true}, (err, resp, data) => {
|
||||
if (err || resp.statusCode != 200) return resolve();
|
||||
resolve(blacklist.push(...data));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
export default {
|
||||
TwitchGlobal: {
|
||||
url: "https://twitchemotes.com/api_cache/v3/global.json",
|
||||
backup: `https://rauenzi.github.io/BetterDiscordApp/data/emotedata_twitch_global.json`,
|
||||
variable: "TwitchGlobal",
|
||||
getEmoteURL: (e) => `https://static-cdn.jtvnw.net/emoticons/v1/${e.id}/1.0`,
|
||||
getOldData: (url, name) => { return {id: url.match(/\/([0-9]+)\//)[1], code: name, emoticon_set: 0, description: null}; }
|
||||
getOldData: (url, name) => {return {id: url.match(/\/([0-9]+)\//)[1], code: name, emoticon_set: 0, description: null};}
|
||||
},
|
||||
TwitchSubscriber: {
|
||||
url: `https://rauenzi.github.io/BetterDiscordApp/data/emotedata_twitch_subscriber.json`,
|
||||
variable: "TwitchSubscriber",
|
||||
getEmoteURL: (e) => `https://static-cdn.jtvnw.net/emoticons/v1/${e}/1.0`,
|
||||
getOldData: (url) => url.match(/\/([0-9]+)\//)[1]
|
||||
},
|
||||
FrankerFaceZ: {
|
||||
url: `https://rauenzi.github.io/BetterDiscordApp/data/emotedata_ffz.json`,
|
||||
variable: "FrankerFaceZ",
|
||||
getEmoteURL: (e) => `https://cdn.frankerfacez.com/emoticon/${e}/1`,
|
||||
getOldData: (url) => url.match(/\/([0-9]+)\//)[1]
|
||||
|
@ -33,7 +30,6 @@ export default {
|
|||
getOldData: (url) => url
|
||||
},
|
||||
BTTV2: {
|
||||
url: `https://rauenzi.github.io/BetterDiscordApp/data/emotedata_bttv.json`,
|
||||
variable: "BTTV2",
|
||||
oldVariable: "emotesBTTV2",
|
||||
getEmoteURL: (e) => `https://cdn.betterttv.net/emote/${e}/1x`,
|
||||
|
|
|
@ -168,7 +168,7 @@ export default {
|
|||
title: "{{name}} v{{version}} by {{author}}",
|
||||
openFolder: "Open {{type}} Folder",
|
||||
reload: "Reload",
|
||||
pluginSettings: "Settings",
|
||||
addonSettings: "Settings",
|
||||
website: "Website",
|
||||
source: "Source",
|
||||
server: "Support Server",
|
||||
|
|
|
@ -17,44 +17,31 @@ export default new class DataStore {
|
|||
constructor() {
|
||||
this.data = {misc: {}};
|
||||
this.pluginData = {};
|
||||
this.localeHashes = {};
|
||||
}
|
||||
|
||||
initialize() {
|
||||
if (!fs.existsSync(this.baseFolder)) fs.mkdirSync(this.baseFolder);
|
||||
if (!fs.existsSync(this.dataFolder)) fs.mkdirSync(this.dataFolder);
|
||||
if (!fs.existsSync(this.localeFolder)) fs.mkdirSync(this.localeFolder);
|
||||
if (!fs.existsSync(this.localeCache)) fs.writeFileSync(this.localeCache, JSON.stringify({}));
|
||||
if (!fs.existsSync(this.BDFile)) fs.writeFileSync(this.BDFile, JSON.stringify(this.data.misc, null, 4));
|
||||
if (!fs.existsSync(this.customCSS)) fs.writeFileSync(this.customCSS, "");
|
||||
const dataFiles = fs.readdirSync(this.dataFolder).filter(f => !fs.statSync(path.resolve(this.dataFolder, f)).isDirectory() && f.endsWith(".json"));
|
||||
for (const file of dataFiles) {
|
||||
this.data[file.split(".")[0]] = __non_webpack_require__(path.resolve(this.dataFolder, file));
|
||||
}
|
||||
// this.data = __non_webpack_require__(this.BDFile);
|
||||
// if (data.hasOwnProperty("settings")) this.data = data;
|
||||
// if (!fs.existsSync(this.settingsFile)) return;
|
||||
// let settings = __non_webpack_require__(this.settingsFile);
|
||||
// fs.unlinkSync(this.settingsFile);
|
||||
// if (settings.hasOwnProperty("settings")) settings = Object.assign({stable: {}, canary: {}, ptb: {}}, {[releaseChannel]: settings});
|
||||
// else settings = Object.assign({stable: {}, canary: {}, ptb: {}}, settings);
|
||||
// this.setBDData("settings", settings);
|
||||
this.localeHashes = JSON.parse(fs.readFileSync(this.localeCache).toString());
|
||||
}
|
||||
|
||||
get customCSS() {return this._customCSS || (this._customCSS = path.resolve(this.dataFolder, "custom.css"));}
|
||||
get baseFolder() {return this._baseFolder || (this._baseFolder = path.resolve(Config.dataPath, "data"));}
|
||||
get dataFolder() {return this._dataFolder || (this._dataFolder = path.resolve(this.baseFolder, `${releaseChannel}`));}
|
||||
get localeFolder() {return this._localeFolder || (this._localeFolder = path.resolve(this.baseFolder, `locales`));}
|
||||
get localeCache() {return this._localeCache || (this._localeCache = path.resolve(this.localeFolder, `.cache`));}
|
||||
get BDFile() {return this._BDFile || (this._BDFile = path.resolve(Config.dataPath, "data", `${releaseChannel}.json`));}
|
||||
// get settingsFile() {return this._settingsFile || (this._settingsFile = path.resolve(Config.dataPath, "bdsettings.json"));}
|
||||
getPluginFile(pluginName) {return path.resolve(Config.dataPath, "plugins", pluginName + ".config.json");}
|
||||
|
||||
// getSettingGroup(key) {
|
||||
// return this.data.settings[key] || null;
|
||||
// }
|
||||
|
||||
// setSettingGroup(key, data) {
|
||||
// this.data.settings[key] = data;
|
||||
// fs.writeFileSync(this.BDFile, JSON.stringify(this.data, null, 4));
|
||||
// }
|
||||
|
||||
_getFile(key) {
|
||||
if (key == "settings" || key == "plugins" || key == "themes") return path.resolve(this.dataFolder, `${key}.json`);
|
||||
|
@ -80,6 +67,15 @@ export default new class DataStore {
|
|||
fs.writeFileSync(path.resolve(this.localeFolder, `${locale}.json`), JSON.stringify(strings, null, 4));
|
||||
}
|
||||
|
||||
getLocaleHash(locale) {
|
||||
return this.localeHashes[locale] || "";
|
||||
}
|
||||
|
||||
saveLocaleHash(locale, hash) {
|
||||
this.localeHashes[locale] = hash;
|
||||
fs.writeFileSync(this.localeCache, JSON.stringify(this.localeHashes, null, 4));
|
||||
}
|
||||
|
||||
getData(key) {
|
||||
return this.data[key] || "";
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ export default new class LocaleManager {
|
|||
this.locale = "";
|
||||
this.strings = {};
|
||||
}
|
||||
|
||||
|
||||
async initialize() {
|
||||
await this.setLocale(this.discordLocale);
|
||||
Dispatcher.subscribe(DiscordConstants.ActionTypes.USER_SETTINGS_UPDATE, ({settings}) => {
|
||||
|
@ -27,8 +27,7 @@ export default new class LocaleManager {
|
|||
async setLocale(newLocale) {
|
||||
let newStrings;
|
||||
if (newLocale != this.defaultLocale) {
|
||||
const savedStrings = DataStore.getLocale(newLocale);
|
||||
newStrings = savedStrings || await this.downloadLocale(newLocale);
|
||||
newStrings = await this.getLocaleStrings(newLocale);
|
||||
if (!newStrings) return this.setLocale(this.defaultLocale);
|
||||
}
|
||||
else {
|
||||
|
@ -39,16 +38,28 @@ export default new class LocaleManager {
|
|||
Events.emit("strings-updated");
|
||||
}
|
||||
|
||||
downloadLocale(locale) {
|
||||
async getLocaleStrings(locale) {
|
||||
const hash = DataStore.getLocaleHash(locale);
|
||||
if (!hash) return await this.downloadLocale(locale);
|
||||
const invalid = await this.downloadLocale(locale, hash);
|
||||
if (!invalid) return DataStore.getLocale(locale);
|
||||
return invalid;
|
||||
}
|
||||
|
||||
downloadLocale(locale, hash = "") {
|
||||
return new Promise(resolve => {
|
||||
const options = {
|
||||
url: `https://raw.githubusercontent.com/rauenzi/BetterDiscordApp/development/data/locales/${locale}.json`,//`https://rauenzi.github.io/BetterDiscordApp/data/locales/${discordLocale}.json`,
|
||||
url: Utilities.repoUrl(`data/locales/${locale}.json`),
|
||||
timeout: 2000,
|
||||
json: true
|
||||
};
|
||||
if (hash) options.headers = {"If-None-Match": hash};
|
||||
console.log(options.headers);
|
||||
request.get(options, (err, resp, newStrings) => {
|
||||
if (err || resp.statusCode !== 200) return resolve(null);
|
||||
DataStore.saveLocale(locale, newStrings);
|
||||
if (err || resp.statusCode !== 200) return resolve(null);
|
||||
console.log(resp);
|
||||
DataStore.saveLocale(locale, newStrings);
|
||||
DataStore.saveLocaleHash(locale, resp.headers.etag);
|
||||
resolve(newStrings);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import {Config} from "data";
|
||||
import Logger from "./logger";
|
||||
|
||||
export default class Utilities {
|
||||
|
||||
static repoUrl(path) {
|
||||
return `https://cdn.staticaly.com/gh/${Config.repo}/BetterDiscordApp/${Config.hash}/${path}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string of HTML and returns the results. If the second parameter is true,
|
||||
* the parsed HTML will be returned as a document fragment {@see https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment}.
|
||||
|
|
|
@ -2,22 +2,21 @@ import {React, Logger, Strings} from "modules";
|
|||
import CloseButton from "../icons/close";
|
||||
import ReloadIcon from "../icons/reload";
|
||||
|
||||
export default class PluginCard extends React.Component {
|
||||
export default class AddonCard extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.showSettings = this.showSettings.bind(this);
|
||||
this.state = {
|
||||
checked: this.props.enabled,
|
||||
settingsOpen: false
|
||||
};
|
||||
this.hasSettings = typeof this.props.addon.plugin.getSettingsPanel === "function";
|
||||
|
||||
this.settingsPanel = "";
|
||||
this.panelRef = React.createRef();
|
||||
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.reload = this.reload.bind(this);
|
||||
// this.onReload = this.onReload.bind(this);
|
||||
this.showSettings = this.showSettings.bind(this);
|
||||
this.closeSettings = this.closeSettings.bind(this);
|
||||
}
|
||||
|
||||
|
@ -50,6 +49,16 @@ export default class PluginCard extends React.Component {
|
|||
|
||||
getString(value) {return typeof value == "string" ? value : value.toString();}
|
||||
|
||||
onChange() {
|
||||
this.setState({checked: !this.state.checked});
|
||||
this.props.onChange && this.props.onChange(this.props.addon.id);
|
||||
}
|
||||
|
||||
showSettings() {
|
||||
if (!this.props.hasSettings) return;
|
||||
this.setState({settingsOpen: true});
|
||||
}
|
||||
|
||||
closeSettings() {
|
||||
this.panelRef.current.innerHTML = "";
|
||||
this.setState({settingsOpen: false});
|
||||
|
@ -69,10 +78,10 @@ export default class PluginCard extends React.Component {
|
|||
get settingsComponent() {
|
||||
const addon = this.props.addon;
|
||||
const name = this.getString(addon.name);
|
||||
try { this.settingsPanel = addon.plugin.getSettingsPanel(); }
|
||||
catch (err) { Logger.stacktrace("Plugin Settings", "Unable to get settings panel for " + name + ".", err); }
|
||||
try { this.settingsPanel = this.props.getSettingsPanel(); }
|
||||
catch (err) { Logger.stacktrace("Addon Settings", "Unable to get settings panel for " + name + ".", err); }
|
||||
|
||||
const props = {id: `plugin-settings-${name}`, className: "plugin-settings", ref: this.panelRef};
|
||||
const props = {id: `${name}-settings`, className: "addon-settings", ref: this.panelRef};
|
||||
if (typeof(settingsPanel) == "string") props.dangerouslySetInnerHTML = this.settingsPanel;
|
||||
|
||||
return <li className="settings-open bd-switch-item">
|
||||
|
@ -89,18 +98,18 @@ export default class PluginCard extends React.Component {
|
|||
|
||||
get footer() {
|
||||
const links = ["website", "source"];
|
||||
if (!links.some(l => this.props.addon[l]) && !this.hasSettings) return null;
|
||||
if (!links.some(l => this.props.addon[l]) && !this.props.hasSettings) return null;
|
||||
const linkComponents = links.map(this.buildLink.bind(this)).filter(c => c);
|
||||
return <div className="bd-footer">
|
||||
<span className="bd-links">{linkComponents.map((comp, i) => i < linkComponents.length - 1 ? [comp, " | "] : [comp]).flat()}</span>
|
||||
{this.hasSettings && <button onClick={this.showSettings} className="bd-button bd-button-plugin-settings" disabled={!this.state.checked}>{Strings.Addons.pluginSettings}</button>}
|
||||
{this.props.hasSettings && <button onClick={this.showSettings} className="bd-button bd-button-addon-settings" disabled={!this.state.checked}>{Strings.Addons.addonSettings}</button>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.settingsOpen) return this.settingsComponent;
|
||||
|
||||
const {addon} = this.props;
|
||||
const addon = this.props.addon;
|
||||
const name = this.getString(addon.name);
|
||||
const author = this.getString(addon.author);
|
||||
const description = this.getString(addon.description);
|
||||
|
@ -111,7 +120,7 @@ export default class PluginCard extends React.Component {
|
|||
<span className="bd-header-title">{this.buildTitle(name, version, author)}</span>
|
||||
<div className="bd-controls">
|
||||
{this.props.showReloadIcon && <ReloadIcon className="bd-reload bd-reload-card" onClick={this.reload} />}
|
||||
<label className="bd-switch-wrapper bd-flex-child">
|
||||
<label className="bd-switch-wrapper">
|
||||
<input className="bd-switch-checkbox" checked={this.state.checked} onChange={this.onChange} type="checkbox" />
|
||||
<div className={this.state.checked ? "bd-switch checked" : "bd-switch"} />
|
||||
</label>
|
||||
|
@ -121,14 +130,4 @@ export default class PluginCard extends React.Component {
|
|||
{this.footer}
|
||||
</li>;
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.setState({checked: !this.state.checked});
|
||||
this.props.onChange && this.props.onChange(this.props.addon.id);
|
||||
}
|
||||
|
||||
showSettings() {
|
||||
if (!this.hasSettings) return;
|
||||
this.setState({settingsOpen: true});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import {React, Settings, Strings} from "modules";
|
||||
|
||||
import SettingsTitle from "./title";
|
||||
import PluginCard from "./plugincard";
|
||||
import ThemeCard from "./themecard";
|
||||
import ReloadIcon from "../icons/reload";
|
||||
import AddonCard from "./addoncard";
|
||||
|
||||
export default class AddonList extends React.Component {
|
||||
|
||||
|
@ -20,8 +19,9 @@ export default class AddonList extends React.Component {
|
|||
<SettingsTitle key="title" text={title} button={button} otherChildren={showReloadIcon && <ReloadIcon className="bd-reload" onClick={this.reload.bind(this)} />} />,
|
||||
<ul key="addonList" className={"bd-slist"}>
|
||||
{addonList.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())).map(addon => {
|
||||
const CardType = addon.type ? PluginCard : ThemeCard;
|
||||
return <CardType showReloadIcon={showReloadIcon} key={addon.id} enabled={addonState[addon.id]} addon={addon} onChange={onChange} reload={reload} />;
|
||||
const hasSettings = addon.type && typeof(addon.plugin.getSettingsPanel) === "function";
|
||||
const getSettings = hasSettings && addon.plugin.getSettingsPanel.bind(addon.plugin);
|
||||
return <AddonCard showReloadIcon={showReloadIcon} key={addon.id} enabled={addonState[addon.id]} addon={addon} onChange={onChange} reload={reload} hasSettings={hasSettings} getSettingsPanel={getSettings} />;
|
||||
})}
|
||||
</ul>
|
||||
];
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
import {React, Logger, Strings} from "modules";
|
||||
import CloseButton from "../icons/close";
|
||||
import ReloadIcon from "../icons/reload";
|
||||
|
||||
export default class PluginCard extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.showSettings = this.showSettings.bind(this);
|
||||
this.state = {
|
||||
checked: this.props.enabled,
|
||||
settingsOpen: false
|
||||
};
|
||||
this.hasSettings = typeof this.props.addon.plugin.getSettingsPanel === "function";
|
||||
this.settingsPanel = "";
|
||||
this.panelRef = React.createRef();
|
||||
|
||||
this.reload = this.reload.bind(this);
|
||||
// this.onReload = this.onReload.bind(this);
|
||||
this.closeSettings = this.closeSettings.bind(this);
|
||||
}
|
||||
|
||||
reload() {
|
||||
if (!this.props.reload) return;
|
||||
this.props.addon = this.props.reload(this.props.addon.id);
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (!this.state.settingsOpen) return;
|
||||
if (this.settingsPanel instanceof Node) this.panelRef.current.appendChild(this.settingsPanel);
|
||||
|
||||
// if (!SettingsCookie["fork-ps-3"]) return;
|
||||
const isHidden = (container, element) => {
|
||||
const cTop = container.scrollTop;
|
||||
const cBottom = cTop + container.clientHeight;
|
||||
const eTop = element.offsetTop;
|
||||
const eBottom = eTop + element.clientHeight;
|
||||
return (eTop < cTop || eBottom > cBottom);
|
||||
};
|
||||
|
||||
const panel = $(this.panelRef.current);
|
||||
const container = panel.parents(".scroller-2FKFPG");
|
||||
if (!isHidden(container[0], panel[0])) return;
|
||||
container.animate({
|
||||
scrollTop: panel.offset().top - container.offset().top + container.scrollTop() - 30
|
||||
}, 300);
|
||||
}
|
||||
|
||||
getString(value) {return typeof value == "string" ? value : value.toString();}
|
||||
|
||||
closeSettings() {
|
||||
this.panelRef.current.innerHTML = "";
|
||||
this.setState({settingsOpen: false});
|
||||
}
|
||||
|
||||
buildTitle(name, version, author) {
|
||||
const title = Strings.Addons.title.split(/({{[A-Za-z]+}})/);
|
||||
const nameIndex = title.findIndex(s => s == "{{name}}");
|
||||
if (nameIndex) title[nameIndex] = React.createElement("span", {className: "bd-name"}, name);
|
||||
const versionIndex = title.findIndex(s => s == "{{version}}");
|
||||
if (nameIndex) title[versionIndex] = React.createElement("span", {className: "bd-version"}, version);
|
||||
const authorIndex = title.findIndex(s => s == "{{author}}");
|
||||
if (nameIndex) title[authorIndex] = React.createElement("span", {className: "bd-author"}, author);
|
||||
return title.flat();
|
||||
}
|
||||
|
||||
get settingsComponent() {
|
||||
const addon = this.props.addon;
|
||||
const name = this.getString(addon.name);
|
||||
try { this.settingsPanel = addon.plugin.getSettingsPanel(); }
|
||||
catch (err) { Logger.stacktrace("Plugin Settings", "Unable to get settings panel for " + name + ".", err); }
|
||||
|
||||
const props = {id: `plugin-settings-${name}`, className: "plugin-settings", ref: this.panelRef};
|
||||
if (typeof(settingsPanel) == "string") props.dangerouslySetInnerHTML = this.settingsPanel;
|
||||
|
||||
return <li className="settings-open bd-switch-item">
|
||||
<div className="bd-close" onClick={this.closeSettings}><CloseButton /></div>
|
||||
<div {...props}>{this.settingsPanel instanceof React.Component ? this.settingsPanel : null}</div>
|
||||
</li>;
|
||||
}
|
||||
|
||||
buildLink(which) {
|
||||
const url = this.props.addon[which];
|
||||
if (!url) return null;
|
||||
return <a className="bd-link bd-link-website" href={url} target="_blank" rel="noopener noreferrer">{Strings.Addons[which]}</a>;
|
||||
}
|
||||
|
||||
get footer() {
|
||||
const links = ["website", "source"];
|
||||
if (!links.some(l => this.props.addon[l]) && !this.hasSettings) return null;
|
||||
const linkComponents = links.map(this.buildLink.bind(this)).filter(c => c);
|
||||
return <div className="bd-footer">
|
||||
<span className="bd-links">{linkComponents.map((comp, i) => i < linkComponents.length - 1 ? [comp, " | "] : [comp]).flat()}</span>
|
||||
{this.hasSettings && <button onClick={this.showSettings} className="bd-button bd-button-plugin-settings" disabled={!this.state.checked}>{Strings.Addons.pluginSettings}</button>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.settingsOpen) return this.settingsComponent;
|
||||
|
||||
const {addon} = this.props;
|
||||
const name = this.getString(addon.name);
|
||||
const author = this.getString(addon.author);
|
||||
const description = this.getString(addon.description);
|
||||
const version = this.getString(addon.version);
|
||||
|
||||
return <li dataName={name} dataVersion={version} className="settings-closed bd-switch-item">
|
||||
<div className="bd-header">
|
||||
<span className="bd-header-title">{this.buildTitle(name, version, author)}</span>
|
||||
<div className="bd-controls">
|
||||
{this.props.showReloadIcon && <ReloadIcon className="bd-reload bd-reload-card" onClick={this.reload} />}
|
||||
<label className="bd-switch-wrapper bd-flex-child">
|
||||
<input className="bd-switch-checkbox" checked={this.state.checked} onChange={this.onChange} type="checkbox" />
|
||||
<div className={this.state.checked ? "bd-switch checked" : "bd-switch"} />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bd-description-wrap scroller-wrap fade"><div className="bd-description scroller">{description}</div></div>
|
||||
{this.footer}
|
||||
</li>;
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.setState({checked: !this.state.checked});
|
||||
this.props.onChange && this.props.onChange(this.props.addon.id);
|
||||
}
|
||||
|
||||
showSettings() {
|
||||
if (!this.hasSettings) return;
|
||||
this.setState({settingsOpen: true});
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
import {React, Strings} from "modules";
|
||||
import ReloadIcon from "../icons/reload";
|
||||
// import Toasts from "../toasts";
|
||||
|
||||
export default class ThemeCard extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
checked: this.props.enabled,
|
||||
reloads: 0
|
||||
};
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.reload = this.reload.bind(this);
|
||||
}
|
||||
|
||||
reload() {
|
||||
if (!this.props.reload) return;
|
||||
this.props.addon = this.props.reload(this.props.addon.id);
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
buildTitle(name, version, author) {
|
||||
const title = Strings.Addons.title.split(/({{[A-Za-z]+}})/);
|
||||
const nameIndex = title.findIndex(s => s == "{{name}}");
|
||||
if (nameIndex) title[nameIndex] = React.createElement("span", {className: "bd-name"}, name);
|
||||
const versionIndex = title.findIndex(s => s == "{{version}}");
|
||||
if (nameIndex) title[versionIndex] = React.createElement("span", {className: "bd-version"}, version);
|
||||
const authorIndex = title.findIndex(s => s == "{{author}}");
|
||||
if (nameIndex) title[authorIndex] = React.createElement("span", {className: "bd-author"}, author);
|
||||
return title.flat();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {addon} = this.props;
|
||||
const name = addon.name;
|
||||
const description = addon.description;
|
||||
const version = addon.version;
|
||||
const author = addon.author;
|
||||
const website = addon.website;
|
||||
const source = addon.source;
|
||||
|
||||
return React.createElement("li", {"data-name": name, "data-version": version, "className": "settings-closed bd-switch-item"},
|
||||
React.createElement("div", {className: "bd-header"},
|
||||
React.createElement("span", {className: "bd-header-title"},
|
||||
this.buildTitle(name, version, author)
|
||||
),
|
||||
React.createElement("div", {className: "bd-controls"},
|
||||
this.props.showReloadIcon && React.createElement(ReloadIcon, {className: "bd-reload bd-reload-card", onClick: this.reload}),
|
||||
React.createElement("label", {className: "bd-switch-wrapper bd-flex-child", style: {flex: "0 0 auto"}},
|
||||
React.createElement("input", {checked: this.state.checked, onChange: this.onChange, className: "bd-switch-checkbox", type: "checkbox"}),
|
||||
React.createElement("div", {className: this.state.checked ? "bd-switch checked" : "bd-switch"})
|
||||
)
|
||||
)
|
||||
),
|
||||
React.createElement("div", {className: "bd-description-wrap scroller-wrap fade"},
|
||||
React.createElement("div", {className: "bd-description scroller"}, description)
|
||||
),
|
||||
(website || source) && React.createElement("div", {className: "bd-footer"},
|
||||
React.createElement("span", {className: "bd-links"},
|
||||
website && React.createElement("a", {className: "bd-link", href: website, target: "_blank"}, "Website"),
|
||||
website && source && " | ",
|
||||
source && React.createElement("a", {className: "bd-link", href: source, target: "_blank"}, "Source")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.setState({checked: !this.state.checked});
|
||||
this.props.onChange && this.props.onChange(this.props.addon.id);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue