mirror of
https://github.com/Lightcord/Lightcord.git
synced 2025-04-12 00:55:40 +02:00
Add edit button
This commit is contained in:
parent
22ff405d40
commit
c96f94b314
2
BetterDiscordApp/css/main.min.css
vendored
2
BetterDiscordApp/css/main.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
BetterDiscordApp/js/main.min.js
vendored
2
BetterDiscordApp/js/main.min.js
vendored
File diff suppressed because one or more lines are too long
@ -77,11 +77,12 @@ export const settings = {
|
||||
"Normalize Classes": {id: "fork-ps-4", info: "Adds stable classes to elements to help themes. (e.g. adds .da-channels to .channels-Ie2l6A)", implemented: true, hidden: false, cat: "core", category: "modules"},
|
||||
|
||||
/* Content */
|
||||
"Content Error Modal": {id: "fork-ps-1", info: "Shows a modal with plugin/theme errors", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Scan Plugins": {id: "fork-ps-6", info: "Scan plugins for any threat that can be hidden inside.", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Show Toasts": {id: "fork-ps-2", info: "Shows a small notification for important information", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Scroll To Settings": {id: "fork-ps-3", info: "Auto-scrolls to a plugin's settings when the button is clicked (only if out of view)", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Automatic Loading": {id: "fork-ps-5", info: "Automatically loads, reloads, and unloads plugins and themes", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Content Error Modal": {id: "fork-ps-1", info: "Shows a modal with plugin/theme errors", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Scan Plugins": {id: "fork-ps-6", info: "Scan plugins for any threat that can be hidden inside.", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Show Toasts": {id: "fork-ps-2", info: "Shows a small notification for important information", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Scroll To Settings": {id: "fork-ps-3", info: "Auto-scrolls to a plugin's settings when the button is clicked (only if out of view)", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Automatic Loading": {id: "fork-ps-5", info: "Automatically loads, reloads, and unloads plugins and themes", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
"Enable Edit Button": {id: "fork-ps-7", info: "Enable an Edit Button on the plugin and theme panel.", implemented: true, hidden: false, cat: "core", category: "content manager"},
|
||||
|
||||
/* Developer */
|
||||
"Developer Mode": {id: "bda-gs-8", info: "Developer Mode Toggle", implemented: true, hidden: false, cat: "core", category: "developer settings"},
|
||||
@ -135,6 +136,7 @@ export const defaultCookie = {
|
||||
"fork-ps-4": true,
|
||||
"fork-ps-5": true,
|
||||
"fork-ps-6": true,
|
||||
"fork-ps-7": false,
|
||||
"fork-es-2": false,
|
||||
"fork-es-3": true,
|
||||
"fork-wp-1": false,
|
||||
|
@ -1,138 +1,138 @@
|
||||
import WebpackModules from "./webpackModules";
|
||||
|
||||
const normalizedPrefix = "da";
|
||||
const randClass = new RegExp(`^(?!${normalizedPrefix}-)((?:[A-Za-z]|[0-9]|-)+)-(?:[A-Za-z]|[0-9]|-|_){6}$`);
|
||||
|
||||
export default new class ClassNormalizer {
|
||||
constructor(){
|
||||
window.Lightcord.BetterDiscord.BDEvents = this
|
||||
}
|
||||
stop() {
|
||||
if (!this.hasPatched) return;
|
||||
this.unpatchClassModules(WebpackModules.findAll(this.moduleFilter.bind(this)));
|
||||
this.revertElement(document.querySelector("#app-mount"));
|
||||
this.hasPatched = false;
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.hasPatched) return;
|
||||
this.patchClassModules(WebpackModules.findAll(this.moduleFilter.bind(this)));
|
||||
this.normalizeElement(document.querySelector("#app-mount"));
|
||||
this.hasPatched = true;
|
||||
this.patchDOMMethods();
|
||||
}
|
||||
|
||||
patchClassModules(modules) {
|
||||
for (const module of modules) {
|
||||
this.patchClassModule(normalizedPrefix, module);
|
||||
}
|
||||
}
|
||||
|
||||
unpatchClassModules(modules) {
|
||||
for (const module of modules) {
|
||||
this.unpatchClassModule(normalizedPrefix, module);
|
||||
}
|
||||
}
|
||||
|
||||
shouldIgnore(value) {
|
||||
if (!isNaN(value)) return true;
|
||||
if (value.endsWith("px") || value.endsWith("ch") || value.endsWith("em") || value.endsWith("ms")) return true;
|
||||
if (value.startsWith("layerContainer-")) return true;
|
||||
if (value.startsWith("#") && (value.length == 7 || value.length == 4)) return true;
|
||||
if (value.includes("calc(") || value.includes("rgba")) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
moduleFilter(module) {
|
||||
if (typeof module !== "object" || Array.isArray(module)) return false;
|
||||
if (module.__esModule) return false;
|
||||
if (!Object.keys(module).length) return false;
|
||||
for (const baseClassName in module) {
|
||||
const value = module[baseClassName];
|
||||
if (typeof value !== "string") return false;
|
||||
if (this.shouldIgnore(value)) continue;
|
||||
if (value.split("-").length === 1) return false;
|
||||
if (!randClass.test(value.split(" ")[0])) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
patchClassModule(componentName, classNames) {
|
||||
for (const baseClassName in classNames) {
|
||||
const value = classNames[baseClassName];
|
||||
if (this.shouldIgnore(value)) continue;
|
||||
const classList = value.split(" ");
|
||||
for (const normalClass of classList) {
|
||||
const match = normalClass.match(randClass);
|
||||
if (!match || !match.length || match.length < 2) continue; // Shouldn't ever happen since they passed the moduleFilter, but you never know
|
||||
const camelCase = match[1].split("-").map((s, i) => i ? s[0].toUpperCase() + s.slice(1) : s).join("");
|
||||
classNames[baseClassName] += ` ${componentName}-${camelCase}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unpatchClassModule(componentName, classNames) {
|
||||
for (const baseClassName in classNames) {
|
||||
const value = classNames[baseClassName];
|
||||
if (this.shouldIgnore(value)) continue;
|
||||
let newString = "";
|
||||
const classList = value.split(" ");
|
||||
for (const normalClass of classList) {
|
||||
if (normalClass.startsWith(`${componentName}-`)) continue;
|
||||
newString += ` ${normalClass}`;
|
||||
}
|
||||
classNames[baseClassName] = newString.trim();
|
||||
}
|
||||
}
|
||||
|
||||
normalizeElement(element) {
|
||||
if (!(element instanceof Element)) return;
|
||||
const classes = element.classList;
|
||||
for (let c = 0, clen = classes.length; c < clen; c++) {
|
||||
if (!randClass.test(classes[c])) continue;
|
||||
const match = classes[c].match(randClass)[1];
|
||||
const newClass = match.split("-").map((s, i) => i ? s[0].toUpperCase() + s.slice(1) : s).join("");
|
||||
element.classList.add(`${normalizedPrefix}-${newClass}`);
|
||||
}
|
||||
for (const child of element.children) this.normalizeElement(child);
|
||||
}
|
||||
|
||||
revertElement(element) {
|
||||
if (!(element instanceof Element)) return;
|
||||
if (element.children && element.children.length) this.revertElement(element.children[0]);
|
||||
if (element.nextElementSibling) this.revertElement(element.nextElementSibling);
|
||||
const classes = element.classList;
|
||||
const toRemove = [];
|
||||
for (let c = 0; c < classes.length; c++) {
|
||||
if (classes[c].startsWith(`${normalizedPrefix}-`)) toRemove.push(classes[c]);
|
||||
}
|
||||
element.classList.remove(...toRemove);
|
||||
}
|
||||
|
||||
patchDOMMethods() {
|
||||
const contains = DOMTokenList.prototype.contains;
|
||||
DOMTokenList.prototype.contains = function(token) {
|
||||
// const tokens = token.split(" ");
|
||||
return Reflect.apply(contains, this, [token.split(" ")[0]]);
|
||||
// return tokens.every(t => contains.call(this, t));
|
||||
};
|
||||
|
||||
const add = DOMTokenList.prototype.add;
|
||||
DOMTokenList.prototype.add = function(...tokens) {
|
||||
for (let t = 0; t < tokens.length; t++) {
|
||||
tokens[t] = tokens[t].split(" ")[0];
|
||||
}
|
||||
return Reflect.apply(add, this, tokens);
|
||||
};
|
||||
|
||||
const remove = DOMTokenList.prototype.remove;
|
||||
DOMTokenList.prototype.remove = function(...tokens) {
|
||||
for (let t = 0; t < tokens.length; t++) {
|
||||
tokens[t] = tokens[t].split(" ")[0];
|
||||
}
|
||||
return Reflect.apply(remove, this, tokens);
|
||||
};
|
||||
}
|
||||
|
||||
import WebpackModules from "./webpackModules";
|
||||
|
||||
const normalizedPrefix = "da";
|
||||
const randClass = new RegExp(`^(?!${normalizedPrefix}-)((?:[A-Za-z]|[0-9]|-)+)-(?:[A-Za-z]|[0-9]|-|_){6}$`);
|
||||
|
||||
export default new class ClassNormalizer {
|
||||
constructor(){
|
||||
window.Lightcord.BetterDiscord.ClassNormalizer = this
|
||||
}
|
||||
stop() {
|
||||
if (!this.hasPatched) return;
|
||||
this.unpatchClassModules(WebpackModules.findAll(this.moduleFilter.bind(this)));
|
||||
this.revertElement(document.querySelector("#app-mount"));
|
||||
this.hasPatched = false;
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.hasPatched) return;
|
||||
this.patchClassModules(WebpackModules.findAll(this.moduleFilter.bind(this)));
|
||||
this.normalizeElement(document.querySelector("#app-mount"));
|
||||
this.hasPatched = true;
|
||||
this.patchDOMMethods();
|
||||
}
|
||||
|
||||
patchClassModules(modules) {
|
||||
for (const module of modules) {
|
||||
this.patchClassModule(normalizedPrefix, module);
|
||||
}
|
||||
}
|
||||
|
||||
unpatchClassModules(modules) {
|
||||
for (const module of modules) {
|
||||
this.unpatchClassModule(normalizedPrefix, module);
|
||||
}
|
||||
}
|
||||
|
||||
shouldIgnore(value) {
|
||||
if (!isNaN(value)) return true;
|
||||
if (value.endsWith("px") || value.endsWith("ch") || value.endsWith("em") || value.endsWith("ms")) return true;
|
||||
if (value.startsWith("layerContainer-")) return true;
|
||||
if (value.startsWith("#") && (value.length == 7 || value.length == 4)) return true;
|
||||
if (value.includes("calc(") || value.includes("rgba")) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
moduleFilter(module) {
|
||||
if (typeof module !== "object" || Array.isArray(module)) return false;
|
||||
if (module.__esModule) return false;
|
||||
if (!Object.keys(module).length) return false;
|
||||
for (const baseClassName in module) {
|
||||
const value = module[baseClassName];
|
||||
if (typeof value !== "string") return false;
|
||||
if (this.shouldIgnore(value)) continue;
|
||||
if (value.split("-").length === 1) return false;
|
||||
if (!randClass.test(value.split(" ")[0])) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
patchClassModule(componentName, classNames) {
|
||||
for (const baseClassName in classNames) {
|
||||
const value = classNames[baseClassName];
|
||||
if (this.shouldIgnore(value)) continue;
|
||||
const classList = value.split(" ");
|
||||
for (const normalClass of classList) {
|
||||
const match = normalClass.match(randClass);
|
||||
if (!match || !match.length || match.length < 2) continue; // Shouldn't ever happen since they passed the moduleFilter, but you never know
|
||||
const camelCase = match[1].split("-").map((s, i) => i ? s[0].toUpperCase() + s.slice(1) : s).join("");
|
||||
classNames[baseClassName] += ` ${componentName}-${camelCase}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unpatchClassModule(componentName, classNames) {
|
||||
for (const baseClassName in classNames) {
|
||||
const value = classNames[baseClassName];
|
||||
if (this.shouldIgnore(value)) continue;
|
||||
let newString = "";
|
||||
const classList = value.split(" ");
|
||||
for (const normalClass of classList) {
|
||||
if (normalClass.startsWith(`${componentName}-`)) continue;
|
||||
newString += ` ${normalClass}`;
|
||||
}
|
||||
classNames[baseClassName] = newString.trim();
|
||||
}
|
||||
}
|
||||
|
||||
normalizeElement(element) {
|
||||
if (!(element instanceof Element)) return;
|
||||
const classes = element.classList;
|
||||
for (let c = 0, clen = classes.length; c < clen; c++) {
|
||||
if (!randClass.test(classes[c])) continue;
|
||||
const match = classes[c].match(randClass)[1];
|
||||
const newClass = match.split("-").map((s, i) => i ? s[0].toUpperCase() + s.slice(1) : s).join("");
|
||||
element.classList.add(`${normalizedPrefix}-${newClass}`);
|
||||
}
|
||||
for (const child of element.children) this.normalizeElement(child);
|
||||
}
|
||||
|
||||
revertElement(element) {
|
||||
if (!(element instanceof Element)) return;
|
||||
if (element.children && element.children.length) this.revertElement(element.children[0]);
|
||||
if (element.nextElementSibling) this.revertElement(element.nextElementSibling);
|
||||
const classes = element.classList;
|
||||
const toRemove = [];
|
||||
for (let c = 0; c < classes.length; c++) {
|
||||
if (classes[c].startsWith(`${normalizedPrefix}-`)) toRemove.push(classes[c]);
|
||||
}
|
||||
element.classList.remove(...toRemove);
|
||||
}
|
||||
|
||||
patchDOMMethods() {
|
||||
const contains = DOMTokenList.prototype.contains;
|
||||
DOMTokenList.prototype.contains = function(token) {
|
||||
// const tokens = token.split(" ");
|
||||
return Reflect.apply(contains, this, [token.split(" ")[0]]);
|
||||
// return tokens.every(t => contains.call(this, t));
|
||||
};
|
||||
|
||||
const add = DOMTokenList.prototype.add;
|
||||
DOMTokenList.prototype.add = function(...tokens) {
|
||||
for (let t = 0; t < tokens.length; t++) {
|
||||
tokens[t] = tokens[t].split(" ")[0];
|
||||
}
|
||||
return Reflect.apply(add, this, tokens);
|
||||
};
|
||||
|
||||
const remove = DOMTokenList.prototype.remove;
|
||||
DOMTokenList.prototype.remove = function(...tokens) {
|
||||
for (let t = 0; t < tokens.length; t++) {
|
||||
tokens[t] = tokens[t].split(" ")[0];
|
||||
}
|
||||
return Reflect.apply(remove, this, tokens);
|
||||
};
|
||||
}
|
||||
|
||||
};
|
@ -1,220 +1,220 @@
|
||||
import ErrorBoundary from "./errorBoundary";
|
||||
import ContentColumn from "./contentColumn";
|
||||
import Tools from "./tools";
|
||||
import ReloadIcon from "./reloadIcon";
|
||||
import AddonCard from "./addoncard";
|
||||
import Scroller from "./scroller";
|
||||
import Dropdown from "./components/dropdown";
|
||||
import Search from "./components/search";
|
||||
|
||||
import {settingsCookie, pluginCookie, themeCookie} from "../0globals";
|
||||
import ContentManager from "../modules/contentManager";
|
||||
import BDV2 from "../modules/v2";
|
||||
import pluginModule from "../modules/pluginModule";
|
||||
import themeModule from "../modules/themeModule";
|
||||
import WebpackModules from "../modules/webpackModules";
|
||||
import BdApi from "../modules/bdApi";
|
||||
import Utils from "../modules/utils";
|
||||
import tooltipWrap from "./tooltipWrap";
|
||||
|
||||
const Tooltip = WebpackModules.findByDisplayName("Tooltip");
|
||||
|
||||
const React = BDV2.react;
|
||||
|
||||
export default class CardList extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {sort: "name", ascending: true, query: ""};
|
||||
this.isPlugins = this.props.type == "plugins";
|
||||
this.cookie = this.isPlugins ? pluginCookie : themeCookie;
|
||||
this.manager = this.isPlugins ? pluginModule : themeModule;
|
||||
|
||||
this.sort = this.sort.bind(this);
|
||||
this.reverse = this.reverse.bind(this);
|
||||
this.search = this.search.bind(this);
|
||||
}
|
||||
|
||||
openFolder() {
|
||||
require("electron").shell.openItem(this.isPlugins ? ContentManager.pluginsFolder : ContentManager.themesFolder);
|
||||
}
|
||||
|
||||
edit(name) {
|
||||
console.log(name);
|
||||
this.manager.edit(name);
|
||||
}
|
||||
|
||||
async delete(name) {
|
||||
const shouldDelete = await this.confirmDelete(name);
|
||||
if (!shouldDelete) return;
|
||||
this.manager.delete(name);
|
||||
}
|
||||
|
||||
confirmDelete(name) {
|
||||
return new Promise(resolve => {
|
||||
BdApi.showConfirmationModal("Are You Sure?", `Are you sure you want to delete ${name}?`, {
|
||||
danger: true,
|
||||
confirmText: "Delete",
|
||||
onConfirm: () => {resolve(true);},
|
||||
onCancel: () => {resolve(false);}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
get sortOptions() {
|
||||
return [
|
||||
{label: "Name", value: "name"},
|
||||
{label: "Author", value: "author"},
|
||||
{label: "Version", value: "version"},
|
||||
{label: "Recently Added", value: "added"},
|
||||
{label: "Last Modified", value: "modified"},
|
||||
{label: "File Size", value: "size"},
|
||||
];
|
||||
}
|
||||
|
||||
get directions() {
|
||||
return [
|
||||
{label: "Ascending", value: true},
|
||||
{label: "Descending", value: false}
|
||||
];
|
||||
}
|
||||
|
||||
reverse(value) {
|
||||
this.setState({ascending: value});
|
||||
}
|
||||
|
||||
sort(value) {
|
||||
this.setState({sort: value});
|
||||
}
|
||||
|
||||
search(event) {
|
||||
this.setState({query: event.target.value.toLocaleLowerCase()});
|
||||
}
|
||||
|
||||
getProps(addon) {
|
||||
return {
|
||||
key: this.getName(addon),
|
||||
enabled: this.cookie[this.getName(addon)],
|
||||
toggle: this.manager.toggle.bind(this.manager),
|
||||
//edit: this.edit.bind(this),
|
||||
remove: this.delete.bind(this),
|
||||
addon: addon,
|
||||
hash: addon.hash
|
||||
};
|
||||
}
|
||||
|
||||
getString(value) {
|
||||
if (!value) return "???";
|
||||
return typeof value == "string" ? value : value.toString();
|
||||
}
|
||||
|
||||
get list(){
|
||||
return this.props.type === "plugins" ? Object.values(bdplugins) : Object.values(bdthemes);
|
||||
}
|
||||
|
||||
getAddons() {
|
||||
const sortedAddons = this.list.sort((a, b) => {
|
||||
const cap = this.state.sort.charAt(0).toUpperCase() + this.state.sort.slice(1);
|
||||
const first = a.plugin && a.plugin[`get${cap}`] ? this.getString(a.plugin[`get${cap}`]()) : a[this.state.sort];
|
||||
const second = b.plugin && b.plugin[`get${cap}`] ? this.getString(b.plugin[`get${cap}`]()) : b[this.state.sort];
|
||||
if (typeof(first) == "string") return first.toLocaleLowerCase().localeCompare(second.toLocaleLowerCase());
|
||||
if (first > second) return 1;
|
||||
if (second > first) return -1;
|
||||
return 0;
|
||||
});
|
||||
if (!this.state.ascending) sortedAddons.reverse();
|
||||
const rendered = [];
|
||||
for (let a = 0; a < sortedAddons.length; a++) {
|
||||
const addon = sortedAddons[a];
|
||||
if (this.state.query) {
|
||||
let matches = null;
|
||||
const name = this.getName(addon);
|
||||
const author = this.getAuthor(addon);
|
||||
const description = this.getDescription(addon);
|
||||
const version = this.getVersion(addon);
|
||||
if (name) matches = name.toLocaleLowerCase().includes(this.state.query);
|
||||
if (author) matches = matches || author.toLocaleLowerCase().includes(this.state.query);
|
||||
if (description) matches = matches || description.toLocaleLowerCase().includes(this.state.query);
|
||||
if (version) matches = matches || version.toLocaleLowerCase().includes(this.state.query);
|
||||
if (!matches) continue;
|
||||
}
|
||||
const props = this.getProps(addon);
|
||||
rendered.push(<ErrorBoundary><AddonCard {...props} reload={!settingsCookie["fork-ps-5"] && this.manager.reload.bind(this.manager)} /></ErrorBoundary>);
|
||||
}
|
||||
return rendered;
|
||||
}
|
||||
|
||||
getName(addon) {return this.getString(addon.plugin ? addon.plugin.getName() : addon.name);}
|
||||
getAuthor(addon) {return this.getString(addon.plugin ? addon.plugin.getAuthor() : addon.author);}
|
||||
getDescription(addon) {return this.getString(addon.plugin ? addon.plugin.getDescription() : addon.description);}
|
||||
getVersion(addon) {return this.getString(addon.plugin ? addon.plugin.getVersion() : addon.version);}
|
||||
|
||||
renderCheckUpdates(){
|
||||
if(!window.ZeresPluginLibrary)return null
|
||||
if(!window.PluginUpdates)return null
|
||||
if(typeof window.PluginUpdates.checkAll !== "function")return null
|
||||
if(!this.isPlugins)return null
|
||||
|
||||
return <tooltipWrap text="Checks for updates of plugins that support this feature. Right-click for a list.">
|
||||
<span style={{marginLeft: "10px"}}>
|
||||
<Lightcord.Api.Components.inputs.Button color="brand" look="filled" size="min" hoverColor="default" onClick={() => {
|
||||
try{
|
||||
Utils.showToast("Plugin update check in progress.", {type: "info"})
|
||||
window.PluginUpdates.checkAll()
|
||||
.then(() => {
|
||||
Utils.showToast("Plugin update check complete.", {type: "success"})
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
Utils.showToast("An error occured while checking update.", {type: "error"})
|
||||
})
|
||||
}catch(e){
|
||||
console.error(e)
|
||||
Utils.showToast("An error occured while checking update.", {type: "error"})
|
||||
}
|
||||
}} wrapper={false} disabled={false}>
|
||||
Check for Updates
|
||||
</Lightcord.Api.Components.inputs.Button>
|
||||
</span>
|
||||
</tooltipWrap>
|
||||
}
|
||||
|
||||
render() {
|
||||
const refreshIcon = <Tooltip color="black" position="top" text="Reload List">
|
||||
{(props) =>
|
||||
<ReloadIcon {...props} className="bd-icon bd-reload bd-reload-header" size="18px" onClick={async () => {
|
||||
if (this.isPlugins) pluginModule.updatePluginList();
|
||||
else themeModule.updateThemeList();
|
||||
this.forceUpdate();
|
||||
}} />
|
||||
}</Tooltip>;
|
||||
const addonCards = this.getAddons();
|
||||
|
||||
return <ContentColumn title={`${this.props.type.toUpperCase()}—${addonCards.length}`}>
|
||||
<button key="folder-button" className="bd-button bd-pfbtn" onClick={this.openFolder.bind(this)}>Open {this.isPlugins ? "Plugin" : "Theme"} Folder</button>
|
||||
{this.renderCheckUpdates()}
|
||||
{!settingsCookie["fork-ps-5"] && refreshIcon}
|
||||
<div className="bd-controls bd-addon-controls">
|
||||
<Search onChange={this.search} placeholder={`Search ${this.props.type}...`} />
|
||||
<div className="bd-addon-dropdowns">
|
||||
<div className="bd-select-wrapper">
|
||||
<label className="bd-label">Sort by:</label>
|
||||
<Dropdown options={this.sortOptions} onChange={this.sort} style="transparent" />
|
||||
</div>
|
||||
<div className="bd-select-wrapper">
|
||||
<label className="bd-label">Order:</label>
|
||||
<Dropdown options={this.directions} onChange={this.reverse} style="transparent" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className="bda-slist bd-addon-list">{addonCards}</div>
|
||||
</ContentColumn>
|
||||
}
|
||||
}
|
||||
|
||||
const originalRender = CardList.prototype.render;
|
||||
Object.defineProperty(CardList.prototype, "render", {
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
set: function() {console.warn("Addon policy for plugins #5 https://github.com/rauenzi/BetterDiscordApp/wiki/Addon-Policies#plugins");},
|
||||
get: () => originalRender
|
||||
import ErrorBoundary from "./errorBoundary";
|
||||
import ContentColumn from "./contentColumn";
|
||||
import Tools from "./tools";
|
||||
import ReloadIcon from "./reloadIcon";
|
||||
import AddonCard from "./addoncard";
|
||||
import Scroller from "./scroller";
|
||||
import Dropdown from "./components/dropdown";
|
||||
import Search from "./components/search";
|
||||
|
||||
import {settingsCookie, pluginCookie, themeCookie} from "../0globals";
|
||||
import ContentManager from "../modules/contentManager";
|
||||
import BDV2 from "../modules/v2";
|
||||
import pluginModule from "../modules/pluginModule";
|
||||
import themeModule from "../modules/themeModule";
|
||||
import WebpackModules from "../modules/webpackModules";
|
||||
import BdApi from "../modules/bdApi";
|
||||
import Utils from "../modules/utils";
|
||||
import tooltipWrap from "./tooltipWrap";
|
||||
|
||||
const Tooltip = WebpackModules.findByDisplayName("Tooltip");
|
||||
|
||||
const React = BDV2.react;
|
||||
|
||||
export default class CardList extends BDV2.reactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {sort: "name", ascending: true, query: ""};
|
||||
this.isPlugins = this.props.type == "plugins";
|
||||
this.cookie = this.isPlugins ? pluginCookie : themeCookie;
|
||||
this.manager = this.isPlugins ? pluginModule : themeModule;
|
||||
|
||||
this.sort = this.sort.bind(this);
|
||||
this.reverse = this.reverse.bind(this);
|
||||
this.search = this.search.bind(this);
|
||||
}
|
||||
|
||||
openFolder() {
|
||||
require("electron").shell.openItem(this.isPlugins ? ContentManager.pluginsFolder : ContentManager.themesFolder);
|
||||
}
|
||||
|
||||
edit(name) {
|
||||
console.log(name);
|
||||
this.manager.edit(name);
|
||||
}
|
||||
|
||||
async delete(name) {
|
||||
const shouldDelete = await this.confirmDelete(name);
|
||||
if (!shouldDelete) return;
|
||||
this.manager.delete(name);
|
||||
}
|
||||
|
||||
confirmDelete(name) {
|
||||
return new Promise(resolve => {
|
||||
BdApi.showConfirmationModal("Are You Sure?", `Are you sure you want to delete ${name}?`, {
|
||||
danger: true,
|
||||
confirmText: "Delete",
|
||||
onConfirm: () => {resolve(true);},
|
||||
onCancel: () => {resolve(false);}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
get sortOptions() {
|
||||
return [
|
||||
{label: "Name", value: "name"},
|
||||
{label: "Author", value: "author"},
|
||||
{label: "Version", value: "version"},
|
||||
{label: "Recently Added", value: "added"},
|
||||
{label: "Last Modified", value: "modified"},
|
||||
{label: "File Size", value: "size"},
|
||||
];
|
||||
}
|
||||
|
||||
get directions() {
|
||||
return [
|
||||
{label: "Ascending", value: true},
|
||||
{label: "Descending", value: false}
|
||||
];
|
||||
}
|
||||
|
||||
reverse(value) {
|
||||
this.setState({ascending: value});
|
||||
}
|
||||
|
||||
sort(value) {
|
||||
this.setState({sort: value});
|
||||
}
|
||||
|
||||
search(event) {
|
||||
this.setState({query: event.target.value.toLocaleLowerCase()});
|
||||
}
|
||||
|
||||
getProps(addon) {
|
||||
return {
|
||||
key: this.getName(addon),
|
||||
enabled: this.cookie[this.getName(addon)],
|
||||
toggle: this.manager.toggle.bind(this.manager),
|
||||
edit: settingsCookie["fork-ps-7"] ? this.edit.bind(this) : null,
|
||||
remove: this.delete.bind(this),
|
||||
addon: addon,
|
||||
hash: addon.hash
|
||||
};
|
||||
}
|
||||
|
||||
getString(value) {
|
||||
if (!value) return "???";
|
||||
return typeof value == "string" ? value : value.toString();
|
||||
}
|
||||
|
||||
get list(){
|
||||
return this.props.type === "plugins" ? Object.values(bdplugins) : Object.values(bdthemes);
|
||||
}
|
||||
|
||||
getAddons() {
|
||||
const sortedAddons = this.list.sort((a, b) => {
|
||||
const cap = this.state.sort.charAt(0).toUpperCase() + this.state.sort.slice(1);
|
||||
const first = a.plugin && a.plugin[`get${cap}`] ? this.getString(a.plugin[`get${cap}`]()) : a[this.state.sort];
|
||||
const second = b.plugin && b.plugin[`get${cap}`] ? this.getString(b.plugin[`get${cap}`]()) : b[this.state.sort];
|
||||
if (typeof(first) == "string") return first.toLocaleLowerCase().localeCompare(second.toLocaleLowerCase());
|
||||
if (first > second) return 1;
|
||||
if (second > first) return -1;
|
||||
return 0;
|
||||
});
|
||||
if (!this.state.ascending) sortedAddons.reverse();
|
||||
const rendered = [];
|
||||
for (let a = 0; a < sortedAddons.length; a++) {
|
||||
const addon = sortedAddons[a];
|
||||
if (this.state.query) {
|
||||
let matches = null;
|
||||
const name = this.getName(addon);
|
||||
const author = this.getAuthor(addon);
|
||||
const description = this.getDescription(addon);
|
||||
const version = this.getVersion(addon);
|
||||
if (name) matches = name.toLocaleLowerCase().includes(this.state.query);
|
||||
if (author) matches = matches || author.toLocaleLowerCase().includes(this.state.query);
|
||||
if (description) matches = matches || description.toLocaleLowerCase().includes(this.state.query);
|
||||
if (version) matches = matches || version.toLocaleLowerCase().includes(this.state.query);
|
||||
if (!matches) continue;
|
||||
}
|
||||
const props = this.getProps(addon);
|
||||
rendered.push(<ErrorBoundary><AddonCard {...props} reload={!settingsCookie["fork-ps-5"] && this.manager.reload.bind(this.manager)} /></ErrorBoundary>);
|
||||
}
|
||||
return rendered;
|
||||
}
|
||||
|
||||
getName(addon) {return this.getString(addon.plugin ? addon.plugin.getName() : addon.name);}
|
||||
getAuthor(addon) {return this.getString(addon.plugin ? addon.plugin.getAuthor() : addon.author);}
|
||||
getDescription(addon) {return this.getString(addon.plugin ? addon.plugin.getDescription() : addon.description);}
|
||||
getVersion(addon) {return this.getString(addon.plugin ? addon.plugin.getVersion() : addon.version);}
|
||||
|
||||
renderCheckUpdates(){
|
||||
if(!window.ZeresPluginLibrary)return null
|
||||
if(!window.PluginUpdates)return null
|
||||
if(typeof window.PluginUpdates.checkAll !== "function")return null
|
||||
if(!this.isPlugins)return null
|
||||
|
||||
return <tooltipWrap text="Checks for updates of plugins that support this feature. Right-click for a list.">
|
||||
<span style={{marginLeft: "10px"}}>
|
||||
<Lightcord.Api.Components.inputs.Button color="brand" look="filled" size="min" hoverColor="default" onClick={() => {
|
||||
try{
|
||||
Utils.showToast("Plugin update check in progress.", {type: "info"})
|
||||
window.PluginUpdates.checkAll()
|
||||
.then(() => {
|
||||
Utils.showToast("Plugin update check complete.", {type: "success"})
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
Utils.showToast("An error occured while checking update.", {type: "error"})
|
||||
})
|
||||
}catch(e){
|
||||
console.error(e)
|
||||
Utils.showToast("An error occured while checking update.", {type: "error"})
|
||||
}
|
||||
}} wrapper={false} disabled={false}>
|
||||
Check for Updates
|
||||
</Lightcord.Api.Components.inputs.Button>
|
||||
</span>
|
||||
</tooltipWrap>
|
||||
}
|
||||
|
||||
render() {
|
||||
const refreshIcon = <Tooltip color="black" position="top" text="Reload List">
|
||||
{(props) =>
|
||||
<ReloadIcon {...props} className="bd-icon bd-reload bd-reload-header" size="18px" onClick={async () => {
|
||||
if (this.isPlugins) pluginModule.updatePluginList();
|
||||
else themeModule.updateThemeList();
|
||||
this.forceUpdate();
|
||||
}} />
|
||||
}</Tooltip>;
|
||||
const addonCards = this.getAddons();
|
||||
|
||||
return <ContentColumn title={`${this.props.type.toUpperCase()}—${addonCards.length}`}>
|
||||
<button key="folder-button" className="bd-button bd-pfbtn" onClick={this.openFolder.bind(this)}>Open {this.isPlugins ? "Plugin" : "Theme"} Folder</button>
|
||||
{this.renderCheckUpdates()}
|
||||
{!settingsCookie["fork-ps-5"] && refreshIcon}
|
||||
<div className="bd-controls bd-addon-controls">
|
||||
<Search onChange={this.search} placeholder={`Search ${this.props.type}...`} />
|
||||
<div className="bd-addon-dropdowns">
|
||||
<div className="bd-select-wrapper">
|
||||
<label className="bd-label">Sort by:</label>
|
||||
<Dropdown options={this.sortOptions} onChange={this.sort} style="transparent" />
|
||||
</div>
|
||||
<div className="bd-select-wrapper">
|
||||
<label className="bd-label">Order:</label>
|
||||
<Dropdown options={this.directions} onChange={this.reverse} style="transparent" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className="bda-slist bd-addon-list">{addonCards}</div>
|
||||
</ContentColumn>
|
||||
}
|
||||
}
|
||||
|
||||
const originalRender = CardList.prototype.render;
|
||||
Object.defineProperty(CardList.prototype, "render", {
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
set: function() {console.warn("Addon policy for plugins #5 https://github.com/rauenzi/BetterDiscordApp/wiki/Addon-Policies#plugins");},
|
||||
get: () => originalRender
|
||||
});
|
File diff suppressed because one or more lines are too long
2
LightcordApi/js/main.min.js
vendored
2
LightcordApi/js/main.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user