bugfixes
- Floating window going below min on low resolution - Floating window editor not usable in settings - Confirmation modal component gone - Fix addon toast strings - Fix emote render - Add folder in AddonAPIs - Restructure FloatingWindows
This commit is contained in:
parent
c648d37ab3
commit
e5d099ebce
2
TODO.md
2
TODO.md
|
@ -7,7 +7,7 @@ Note: The items listed here are not in any sort of priority order.
|
|||
### To Do (Remote Side)
|
||||
- Dependency loading (jquery, css, config file)
|
||||
- Stop depending on injector giving config
|
||||
- Fix emote render
|
||||
- Abstract out more UI strings
|
||||
|
||||
### To Do (Injector)
|
||||
- Update to new windowprefs location
|
||||
|
|
94
js/main.js
94
js/main.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
|
@ -23,16 +23,16 @@
|
|||
},
|
||||
"homepage": "https://github.com/rauenzi/BetterDiscordApp#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.3.4",
|
||||
"@babel/preset-env": "^7.3.4",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/register": "^7.0.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"circular-dependency-plugin": "^5.0.2",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-csso": "^3.0.1",
|
||||
"gulp-rename": "^1.4.0",
|
||||
"webpack": "^4.29.6",
|
||||
"webpack-cli": "^3.2.3"
|
||||
"@babel/core": "^7.10.5",
|
||||
"@babel/preset-env": "^7.10.4",
|
||||
"@babel/preset-react": "^7.10.4",
|
||||
"@babel/register": "^7.10.5",
|
||||
"babel-loader": "^8.1.0",
|
||||
"circular-dependency-plugin": "^5.2.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-csso": "^4.0.1",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.12"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Builtin from "../structs/builtin";
|
||||
import {Settings, DataStore, React, WebpackModules, Events, DOMManager, Strings} from "modules";
|
||||
import CSSEditor from "../ui/customcss/csseditor";
|
||||
import FloatingWindowContainer from "../ui/floating/container";
|
||||
import FloatingWindows from "../ui/floatingwindows";
|
||||
import SettingsTitle from "../ui/settings/title";
|
||||
import Utilities from "../modules/utilities";
|
||||
|
||||
|
@ -131,7 +131,7 @@ export default new class CustomCSS extends Builtin {
|
|||
onChange: this.onChange.bind(this)
|
||||
});
|
||||
|
||||
FloatingWindowContainer.open({
|
||||
FloatingWindows.open({
|
||||
onClose: () => {
|
||||
this.isDetached = false;
|
||||
},
|
||||
|
|
|
@ -37,7 +37,7 @@ export default new class EmoteModule extends Builtin {
|
|||
|
||||
get(id) {return super.get("emotes", "general", id);}
|
||||
|
||||
get MessageContentComponent() {return WebpackModules.getModule(m => m.defaultProps && m.defaultProps.hasOwnProperty("disableButtons"));}
|
||||
get MessageComponent() {return WebpackModules.find(m => m.default && m.default.displayName && m.default.displayName == "Message");}
|
||||
|
||||
get Emotes() {return Emotes;}
|
||||
get TwitchGlobal() {return Emotes.TwitchGlobal;}
|
||||
|
@ -69,6 +69,7 @@ export default new class EmoteModule extends Builtin {
|
|||
Events.on("emotes-favorite-added", this.addFavorite);
|
||||
Events.on("emotes-favorite-removed", this.removeFavorite);
|
||||
Events.on("setting-updated", this.onCategoryToggle);
|
||||
this.patchMessageContent();
|
||||
}
|
||||
|
||||
disabled() {
|
||||
|
@ -113,71 +114,66 @@ export default new class EmoteModule extends Builtin {
|
|||
|
||||
patchMessageContent() {
|
||||
if (this.cancelEmoteRender) return;
|
||||
this.cancelEmoteRender = this.after(this.MessageContentComponent.prototype, "render", (thisObj, args, retVal) => {
|
||||
this.after(retVal.props, "children", (t, a, returnValue) => {
|
||||
if (this.categories.length == 0) return;
|
||||
const markup = returnValue.props.children[1];
|
||||
if (!markup.props.children) return;
|
||||
const nodes = markup.props.children[1];
|
||||
if (!nodes || !nodes.length) return;
|
||||
for (let n = 0; n < nodes.length; n++) {
|
||||
const node = nodes[n];
|
||||
if (typeof(node) !== "string") continue;
|
||||
const words = node.split(/([^\s]+)([\s]|$)/g);
|
||||
for (let c = 0, clen = this.categories.length; c < clen; c++) {
|
||||
for (let w = 0, wlen = words.length; w < wlen; w++) {
|
||||
const emote = words[w];
|
||||
const emoteSplit = emote.split(":");
|
||||
const emoteName = emoteSplit[0];
|
||||
let emoteModifier = emoteSplit[1] ? emoteSplit[1] : "";
|
||||
let emoteOverride = emoteModifier.slice(0);
|
||||
this.cancelEmoteRender = this.before(this.MessageComponent, "default", (thisObj, args) => {
|
||||
const nodes = args[0].childrenMessageContent.props.content;
|
||||
if (!nodes || !nodes.length) return;
|
||||
for (let n = 0; n < nodes.length; n++) {
|
||||
const node = nodes[n];
|
||||
if (typeof(node) !== "string") continue;
|
||||
const words = node.split(/([^\s]+)([\s]|$)/g);
|
||||
for (let c = 0, clen = this.categories.length; c < clen; c++) {
|
||||
for (let w = 0, wlen = words.length; w < wlen; w++) {
|
||||
const emote = words[w];
|
||||
const emoteSplit = emote.split(":");
|
||||
const emoteName = emoteSplit[0];
|
||||
let emoteModifier = emoteSplit[1] ? emoteSplit[1] : "";
|
||||
let emoteOverride = emoteModifier.slice(0);
|
||||
|
||||
if (emoteName.length < 4 || blacklist.includes(emoteName)) continue;
|
||||
if (!modifiers.includes(emoteModifier) || !Settings.get("emotes", "general", "modifiers")) emoteModifier = "";
|
||||
if (!overrides.includes(emoteOverride)) emoteOverride = "";
|
||||
else emoteModifier = emoteOverride;
|
||||
if (emoteName.length < 4 || blacklist.includes(emoteName)) continue;
|
||||
if (!modifiers.includes(emoteModifier) || !Settings.get("emotes", "general", "modifiers")) emoteModifier = "";
|
||||
if (!overrides.includes(emoteOverride)) emoteOverride = "";
|
||||
else emoteModifier = emoteOverride;
|
||||
|
||||
let current = this.categories[c];
|
||||
if (emoteOverride === "twitch") {
|
||||
if (Emotes.TwitchGlobal[emoteName]) current = "TwitchGlobal";
|
||||
else if (Emotes.TwitchSubscriber[emoteName]) current = "TwitchSubscriber";
|
||||
}
|
||||
else if (emoteOverride === "subscriber") {
|
||||
if (Emotes.TwitchSubscriber[emoteName]) current = "TwitchSubscriber";
|
||||
}
|
||||
else if (emoteOverride === "bttv") {
|
||||
if (Emotes.BTTV[emoteName]) current = "BTTV";
|
||||
}
|
||||
else if (emoteOverride === "ffz") {
|
||||
if (Emotes.FrankerFaceZ[emoteName]) current = "FrankerFaceZ";
|
||||
}
|
||||
|
||||
if (!Emotes[current][emoteName]) continue;
|
||||
const results = nodes[n].match(new RegExp(`([\\s]|^)${Utilities.escape(emoteModifier ? emoteName + ":" + emoteModifier : emoteName)}([\\s]|$)`));
|
||||
if (!results) continue;
|
||||
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: EmoteURLs[current].format({id: Emotes[current][emoteName]}), modifier: emoteModifier, isFavorite: this.isFavorite(emoteName)});
|
||||
nodes.splice(n + 1, 0, post);
|
||||
nodes.splice(n + 1, 0, emoteComponent);
|
||||
let current = this.categories[c];
|
||||
if (emoteOverride === "twitch") {
|
||||
if (Emotes.TwitchGlobal[emoteName]) current = "TwitchGlobal";
|
||||
else if (Emotes.TwitchSubscriber[emoteName]) current = "TwitchSubscriber";
|
||||
}
|
||||
else if (emoteOverride === "subscriber") {
|
||||
if (Emotes.TwitchSubscriber[emoteName]) current = "TwitchSubscriber";
|
||||
}
|
||||
else if (emoteOverride === "bttv") {
|
||||
if (Emotes.BTTV[emoteName]) current = "BTTV";
|
||||
}
|
||||
else if (emoteOverride === "ffz") {
|
||||
if (Emotes.FrankerFaceZ[emoteName]) current = "FrankerFaceZ";
|
||||
}
|
||||
|
||||
if (!Emotes[current][emoteName]) continue;
|
||||
const results = nodes[n].match(new RegExp(`([\\s]|^)${Utilities.escape(emoteModifier ? emoteName + ":" + emoteModifier : emoteName)}([\\s]|$)`));
|
||||
if (!results) continue;
|
||||
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: EmoteURLs[current].format({id: Emotes[current][emoteName]}), modifier: emoteModifier, isFavorite: this.isFavorite(emoteName)});
|
||||
nodes.splice(n + 1, 0, post);
|
||||
nodes.splice(n + 1, 0, emoteComponent);
|
||||
}
|
||||
}
|
||||
const onlyEmotes = nodes.every(r => {
|
||||
if (typeof(r) == "string" && r.replace(/\s*/, "") == "") return true;
|
||||
else if (r.type && r.type.name == "BDEmote") return true;
|
||||
else if (r.props && r.props.children && r.props.children.props && r.props.children.props.emojiName) return true;
|
||||
return false;
|
||||
});
|
||||
if (!onlyEmotes) return;
|
||||
|
||||
for (const node of nodes) {
|
||||
if (typeof(node) != "object") continue;
|
||||
if (node.type.name == "BDEmote") node.props.jumboable = true;
|
||||
else if (node.props && node.props.children && node.props.children.props && node.props.children.props.emojiName) node.props.children.props.jumboable = true;
|
||||
}
|
||||
}
|
||||
const onlyEmotes = nodes.every(r => {
|
||||
if (typeof(r) == "string" && r.replace(/\s*/, "") == "") return true;
|
||||
else if (r.type && r.type.name == "BDEmote") return true;
|
||||
else if (r.props && r.props.children && r.props.children.props && r.props.children.props.emojiName) return true;
|
||||
return false;
|
||||
});
|
||||
if (!onlyEmotes) return;
|
||||
|
||||
for (const node of nodes) {
|
||||
if (typeof(node) != "object") continue;
|
||||
if (node.type.name == "BDEmote") node.props.jumboable = true;
|
||||
else if (node.props && node.props.children && node.props.children.props && node.props.children.props.emojiName) node.props.children.props.jumboable = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -209,6 +209,10 @@ export default {
|
|||
deleteAddon: "Delete",
|
||||
confirmDelete: "Are you sure you want to delete {{name}}?",
|
||||
confirmationText: "You have unsaved changes to {{name}}. Closing this window will lose all those changes.",
|
||||
enabled: "{{name}} has been enabled.",
|
||||
disabled: "{{name}} has been disabled.",
|
||||
unknownAuthor: "Unknown Author",
|
||||
noDescription: "Description not provided."
|
||||
},
|
||||
Emotes: {
|
||||
loading: "Loading emotes in the background do not reload.",
|
||||
|
|
|
@ -10,7 +10,7 @@ import DiscordModules from "./discordmodules";
|
|||
import Strings from "./strings";
|
||||
|
||||
import AddonEditor from "../ui/misc/addoneditor";
|
||||
import FloatingWindowContainer from "../ui/floating/container";
|
||||
import FloatingWindows from "../ui/floatingwindows";
|
||||
|
||||
const React = DiscordModules.React;
|
||||
|
||||
|
@ -82,21 +82,22 @@ export default class AddonManager {
|
|||
Logger.log(this.name, `Starting to watch ${this.prefix} addons.`);
|
||||
this.watcher = fs.watch(this.addonFolder, {persistent: false}, async (eventType, filename) => {
|
||||
if (!eventType || !filename || !filename.endsWith(this.extension)) return;
|
||||
await new Promise(r => setTimeout(r, 50));
|
||||
try {fs.statSync(path.resolve(this.addonFolder, filename));}
|
||||
await new Promise(r => setTimeout(r, 100));
|
||||
try {
|
||||
const stats = fs.statSync(path.resolve(this.addonFolder, filename));
|
||||
if (!stats.isFile()) return;
|
||||
if (!stats || !stats.mtime || !stats.mtime.getTime()) return;
|
||||
if (typeof(stats.mtime.getTime()) !== "number") return;
|
||||
if (this.timeCache[filename] == stats.mtime.getTime()) return;
|
||||
this.timeCache[filename] = stats.mtime.getTime();
|
||||
if (eventType == "rename") this.loadAddon(filename, true);
|
||||
if (eventType == "change") this.reloadAddon(filename, true);
|
||||
}
|
||||
catch (err) {
|
||||
if (err.code !== "ENOENT") return;
|
||||
delete this.timeCache[filename];
|
||||
this.unloadAddon(filename, true);
|
||||
}
|
||||
if (!fs.statSync(path.resolve(this.addonFolder, filename)).isFile()) return;
|
||||
const stats = fs.statSync(path.resolve(this.addonFolder, filename));
|
||||
if (!stats || !stats.mtime || !stats.mtime.getTime()) return;
|
||||
if (typeof(stats.mtime.getTime()) !== "number") return;
|
||||
if (this.timeCache[filename] == stats.mtime.getTime()) return;
|
||||
this.timeCache[filename] = stats.mtime.getTime();
|
||||
if (eventType == "rename") this.loadAddon(filename, true);
|
||||
if (eventType == "change") this.reloadAddon(filename, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -160,6 +161,9 @@ export default class AddonManager {
|
|||
fileContent = stripBOM(fileContent);
|
||||
const stats = fs.statSync(filename);
|
||||
const meta = self.extractMeta(fileContent);
|
||||
if (!meta.author) meta.author = Strings.Addons.unknownAuthor;
|
||||
if (!meta.version) meta.version = "???";
|
||||
if (!meta.description) meta.description = Strings.Addons.noDescription;
|
||||
meta.id = meta.name;
|
||||
meta.filename = path.basename(filename);
|
||||
meta.added = stats.atimeMs;
|
||||
|
@ -301,7 +305,7 @@ export default class AddonManager {
|
|||
language: this.language
|
||||
});
|
||||
|
||||
FloatingWindowContainer.open({
|
||||
FloatingWindows.open({
|
||||
onClose: () => {
|
||||
this.isDetached = false;
|
||||
},
|
||||
|
|
|
@ -249,7 +249,7 @@ BdApi.setBDData = function(key, data) {
|
|||
};
|
||||
|
||||
const makeAddonAPI = (manager) => new class AddonAPI {
|
||||
get folder() {return manager.folder;}
|
||||
get folder() {return manager.addonFolder;}
|
||||
isEnabled(idOrFile) {return manager.isEnabled(idOrFile);}
|
||||
enable(idOrAddon) {return manager.enableAddon(idOrAddon);}
|
||||
disable(idOrAddon) {return manager.disableAddon(idOrAddon);}
|
||||
|
|
|
@ -112,7 +112,7 @@ export default new class PluginManager extends AddonManager {
|
|||
try {
|
||||
plugin.start();
|
||||
this.emit("started", addon.id);
|
||||
Toasts.show(`${addon.name} v${addon.version} has started.`);
|
||||
Toasts.show(Strings.Addons.enabled.format({name: addon.name, version: addon.version}));
|
||||
}
|
||||
catch (err) {
|
||||
this.state[addon.id] = false;
|
||||
|
@ -129,7 +129,7 @@ export default new class PluginManager extends AddonManager {
|
|||
try {
|
||||
plugin.stop();
|
||||
this.emit("stopped", addon.id);
|
||||
Toasts.show(`${addon.name} v${addon.version} has stopped.`);
|
||||
Toasts.show(Strings.Addons.disabled.format({name: addon.name, version: addon.version}));
|
||||
}
|
||||
catch (err) {
|
||||
this.state[addon.id] = false;
|
||||
|
|
|
@ -66,13 +66,13 @@ export default new class ThemeManager extends AddonManager {
|
|||
const addon = typeof(idOrAddon) == "string" ? this.addonList.find(p => p.id == idOrAddon) : idOrAddon;
|
||||
if (!addon) return;
|
||||
DOMManager.injectTheme(addon.id, addon.css);
|
||||
Toasts.show(`${addon.name} v${addon.version} has been applied.`);
|
||||
Toasts.show(Strings.Addons.enabled.format({name: addon.name, version: addon.version}));
|
||||
}
|
||||
|
||||
removeTheme(idOrAddon) {
|
||||
const addon = typeof(idOrAddon) == "string" ? this.addonList.find(p => p.id == idOrAddon) : idOrAddon;
|
||||
if (!addon) return;
|
||||
DOMManager.removeTheme(addon.id);
|
||||
Toasts.show(`${addon.name} v${addon.version} has been removed.`);
|
||||
Toasts.show(Strings.Addons.disabled.format({name: addon.name, version: addon.version}));
|
||||
}
|
||||
};
|
|
@ -84,6 +84,10 @@ export default class BuiltinModule {
|
|||
Logger.stacktrace(this.name, message, error);
|
||||
}
|
||||
|
||||
before(object, func, callback) {
|
||||
return Patcher.before(this.name, object, func, callback);
|
||||
}
|
||||
|
||||
after(object, func, callback) {
|
||||
return Patcher.after(this.name, object, func, callback);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {React, ReactDOM, DOM, WebpackModules} from "modules";
|
||||
import {React, DOM} from "modules";
|
||||
|
||||
import FloatingWindow from "./window";
|
||||
|
||||
|
@ -10,7 +10,7 @@ class FloatingWindowContainer extends React.Component {
|
|||
}
|
||||
|
||||
get minY() {
|
||||
const appContainer = DOM.query(`#app-mount > div[class*="app-"`);
|
||||
const appContainer = DOM.query(`#app-mount > div[class*="app-"]`);
|
||||
if (appContainer) return appContainer.offsetTop;
|
||||
return 0;
|
||||
}
|
||||
|
@ -48,10 +48,4 @@ class FloatingWindowContainer extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const containerRef = React.createRef();
|
||||
const container = <FloatingWindowContainer ref={containerRef} />;
|
||||
const wrapped = React.createElement(WebpackModules.getByProps("AppReferencePositionLayer").AppLayerProvider().props.layerContext.Provider, {value: [document.querySelector("#app-mount > .layerContainer-yqaFcK")]}, container);
|
||||
const div = DOM.createElement(`<div id="floating-windows-layer">`);
|
||||
DOM.query("#app-mount").append(div);
|
||||
ReactDOM.render(wrapped, div);
|
||||
export default containerRef.current;
|
||||
export default FloatingWindowContainer;
|
|
@ -121,17 +121,6 @@ export default class FloatingWindow extends React.Component {
|
|||
</div>;
|
||||
}
|
||||
|
||||
async close() {
|
||||
let shouldClose = true;
|
||||
const confirmClose = typeof(this.props.confirmClose) == "function" ? this.props.confirmClose() : this.props.confirmClose;
|
||||
if (confirmClose) {
|
||||
this.setState({modalOpen: true});
|
||||
shouldClose = await this.confirmClose();
|
||||
this.setState({modalOpen: false});
|
||||
}
|
||||
if (this.props.close && shouldClose) this.props.close();
|
||||
}
|
||||
|
||||
maximize() {
|
||||
this.window.current.style.width = "100%";
|
||||
this.window.current.style.height = "100%";
|
||||
|
@ -145,8 +134,35 @@ export default class FloatingWindow extends React.Component {
|
|||
const right = left + width;
|
||||
const bottom = top + height;
|
||||
|
||||
// Prevent expanding off the bottom and right and readjust position
|
||||
if (bottom > this.maxY) this.window.current.style.top = (this.maxY - height) + "px";
|
||||
if (right > this.maxX) this.window.current.style.left = (this.maxX - width) + "px";
|
||||
|
||||
const newLeft = parseInt(this.window.current.style.left);
|
||||
const newTop = parseInt(this.window.current.style.top);
|
||||
|
||||
// For small screens it's possible this pushes us off the other direction... we need to readjust size
|
||||
if (newTop < this.minY) {
|
||||
const difference = this.minY - newTop;
|
||||
this.window.current.style.top = this.minY + "px";
|
||||
this.window.current.style.height = (height - difference) + "px";
|
||||
}
|
||||
if (newLeft < this.minX) {
|
||||
const difference = this.minX - newLeft;
|
||||
this.window.current.style.left = this.minX + "px";
|
||||
this.window.current.style.height = (width - difference) + "px";
|
||||
}
|
||||
}
|
||||
|
||||
async close() {
|
||||
let shouldClose = true;
|
||||
const confirmClose = typeof(this.props.confirmClose) == "function" ? this.props.confirmClose() : this.props.confirmClose;
|
||||
if (confirmClose) {
|
||||
this.setState({modalOpen: true});
|
||||
shouldClose = await this.confirmClose();
|
||||
this.setState({modalOpen: false});
|
||||
}
|
||||
if (this.props.close && shouldClose) this.props.close();
|
||||
}
|
||||
|
||||
confirmClose() {
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import {WebpackModules, React, ReactDOM, DOM, DOMManager} from "modules";
|
||||
import FloatingWindowContainer from "./floating/container";
|
||||
|
||||
export default class FloatingWindows {
|
||||
static initialize() {
|
||||
const containerRef = React.createRef();
|
||||
const container = <FloatingWindowContainer ref={containerRef} />;
|
||||
const wrapped = React.createElement(WebpackModules.getByProps("AppReferencePositionLayer").AppLayerProvider().props.layerContext.Provider, {value: [document.querySelector("#app-mount > .layerContainer-yqaFcK")]}, container);
|
||||
const div = DOM.createElement(`<div id="floating-windows-layer">`);
|
||||
DOMManager.bdBody.append(div);
|
||||
ReactDOM.render(wrapped, div);
|
||||
this.ref = containerRef;
|
||||
}
|
||||
|
||||
static open(window) {
|
||||
if (!this.ref) this.initialize();
|
||||
return this.ref.current.open(window);
|
||||
}
|
||||
}
|
|
@ -6,10 +6,11 @@ export default class Modals {
|
|||
|
||||
static get shouldShowAddonErrors() {return Settings.get("settings", "addons", "addonErrors");}
|
||||
|
||||
static get ModalActions() {return WebpackModules.getByProps("openModal", "updateModal");}
|
||||
static get ModalStack() {return WebpackModules.getByProps("push", "update", "pop", "popWithKey");}
|
||||
static get AlertModal() {return WebpackModules.getByPrototypes("handleCancel", "handleSubmit", "handleMinorConfirm");}
|
||||
static get TextElement() {return WebpackModules.getByProps("Sizes", "Weights");}
|
||||
static get ConfirmationModal() {return WebpackModules.getModule(m => m.defaultProps && m.key && m.key() == "confirm-modal");}
|
||||
static get ConfirmationModal() {return WebpackModules.findByDisplayName("ConfirmModal");}
|
||||
static get Markdown() {return WebpackModules.findByDisplayName("Markdown");}
|
||||
|
||||
static default(title, content) {
|
||||
|
@ -64,9 +65,9 @@ export default class Modals {
|
|||
static showConfirmationModal(title, content, options = {}) {
|
||||
const Markdown = this.Markdown;
|
||||
const ConfirmationModal = this.ConfirmationModal;
|
||||
const ModalStack = this.ModalStack;
|
||||
const ModalActions = this.ModalActions;
|
||||
if (content instanceof FormattableString) content = content.toString();
|
||||
if (!this.ModalStack || !this.ConfirmationModal || !this.Markdown) return this.default(title, content);
|
||||
if (!this.ModalActions || !this.ConfirmationModal || !this.Markdown) return this.default(title, content);
|
||||
|
||||
const emptyFunction = () => {};
|
||||
const {onConfirm = emptyFunction, onCancel = emptyFunction, confirmText = Strings.Modals.okay, cancelText = Strings.Modals.cancel, danger = false, key = undefined} = options;
|
||||
|
@ -74,15 +75,16 @@ export default class Modals {
|
|||
if (!Array.isArray(content)) content = [content];
|
||||
content = content.map(c => typeof(c) === "string" ? React.createElement(Markdown, null, c) : c);
|
||||
|
||||
return ModalStack.push(ConfirmationModal, {
|
||||
header: title,
|
||||
children: content,
|
||||
red: danger,
|
||||
confirmText: confirmText,
|
||||
cancelText: cancelText,
|
||||
onConfirm: onConfirm,
|
||||
onCancel: onCancel
|
||||
}, key);
|
||||
return ModalActions.openModal(props => {
|
||||
return React.createElement(ConfirmationModal, Object.assign({
|
||||
header: title,
|
||||
red: danger,
|
||||
confirmText: confirmText,
|
||||
cancelText: cancelText,
|
||||
onConfirm: onConfirm,
|
||||
onCancel: onCancel
|
||||
}, props), content);
|
||||
}, {modalKey: key});
|
||||
}
|
||||
|
||||
static showAddonErrors({plugins: pluginErrors = [], themes: themeErrors = []}) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {WebpackModules, Settings} from "modules";
|
||||
import {WebpackModules, Settings, DOMManager} from "modules";
|
||||
|
||||
const channelsClass = WebpackModules.getByProps("sidebar", "hasNotice").sidebar.split(" ")[0];
|
||||
const membersWrapClass = WebpackModules.getByProps("membersWrap").membersWrap.split(" ")[0];
|
||||
|
@ -65,6 +65,6 @@ export default class Toasts {
|
|||
toastWrapper.style.setProperty("left", left + "px");
|
||||
toastWrapper.style.setProperty("width", width + "px");
|
||||
toastWrapper.style.setProperty("bottom", bottom + "px");
|
||||
document.querySelector("#app-mount").appendChild(toastWrapper);
|
||||
DOMManager.bdBody.appendChild(toastWrapper);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue