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)
|
### To Do (Remote Side)
|
||||||
- Dependency loading (jquery, css, config file)
|
- Dependency loading (jquery, css, config file)
|
||||||
- Stop depending on injector giving config
|
- Stop depending on injector giving config
|
||||||
- Fix emote render
|
- Abstract out more UI strings
|
||||||
|
|
||||||
### To Do (Injector)
|
### To Do (Injector)
|
||||||
- Update to new windowprefs location
|
- 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",
|
"homepage": "https://github.com/rauenzi/BetterDiscordApp#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.3.4",
|
"@babel/core": "^7.10.5",
|
||||||
"@babel/preset-env": "^7.3.4",
|
"@babel/preset-env": "^7.10.4",
|
||||||
"@babel/preset-react": "^7.0.0",
|
"@babel/preset-react": "^7.10.4",
|
||||||
"@babel/register": "^7.0.0",
|
"@babel/register": "^7.10.5",
|
||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^8.1.0",
|
||||||
"circular-dependency-plugin": "^5.0.2",
|
"circular-dependency-plugin": "^5.2.0",
|
||||||
"gulp": "^4.0.0",
|
"gulp": "^4.0.2",
|
||||||
"gulp-csso": "^3.0.1",
|
"gulp-csso": "^4.0.1",
|
||||||
"gulp-rename": "^1.4.0",
|
"gulp-rename": "^2.0.0",
|
||||||
"webpack": "^4.29.6",
|
"webpack": "^4.43.0",
|
||||||
"webpack-cli": "^3.2.3"
|
"webpack-cli": "^3.3.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Builtin from "../structs/builtin";
|
import Builtin from "../structs/builtin";
|
||||||
import {Settings, DataStore, React, WebpackModules, Events, DOMManager, Strings} from "modules";
|
import {Settings, DataStore, React, WebpackModules, Events, DOMManager, Strings} from "modules";
|
||||||
import CSSEditor from "../ui/customcss/csseditor";
|
import CSSEditor from "../ui/customcss/csseditor";
|
||||||
import FloatingWindowContainer from "../ui/floating/container";
|
import FloatingWindows from "../ui/floatingwindows";
|
||||||
import SettingsTitle from "../ui/settings/title";
|
import SettingsTitle from "../ui/settings/title";
|
||||||
import Utilities from "../modules/utilities";
|
import Utilities from "../modules/utilities";
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ export default new class CustomCSS extends Builtin {
|
||||||
onChange: this.onChange.bind(this)
|
onChange: this.onChange.bind(this)
|
||||||
});
|
});
|
||||||
|
|
||||||
FloatingWindowContainer.open({
|
FloatingWindows.open({
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
this.isDetached = false;
|
this.isDetached = false;
|
||||||
},
|
},
|
||||||
|
|
|
@ -37,7 +37,7 @@ export default new class EmoteModule extends Builtin {
|
||||||
|
|
||||||
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"));}
|
get MessageComponent() {return WebpackModules.find(m => m.default && m.default.displayName && m.default.displayName == "Message");}
|
||||||
|
|
||||||
get Emotes() {return Emotes;}
|
get Emotes() {return Emotes;}
|
||||||
get TwitchGlobal() {return Emotes.TwitchGlobal;}
|
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-added", this.addFavorite);
|
||||||
Events.on("emotes-favorite-removed", this.removeFavorite);
|
Events.on("emotes-favorite-removed", this.removeFavorite);
|
||||||
Events.on("setting-updated", this.onCategoryToggle);
|
Events.on("setting-updated", this.onCategoryToggle);
|
||||||
|
this.patchMessageContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
disabled() {
|
disabled() {
|
||||||
|
@ -113,71 +114,66 @@ export default new class EmoteModule extends Builtin {
|
||||||
|
|
||||||
patchMessageContent() {
|
patchMessageContent() {
|
||||||
if (this.cancelEmoteRender) return;
|
if (this.cancelEmoteRender) return;
|
||||||
this.cancelEmoteRender = this.after(this.MessageContentComponent.prototype, "render", (thisObj, args, retVal) => {
|
this.cancelEmoteRender = this.before(this.MessageComponent, "default", (thisObj, args) => {
|
||||||
this.after(retVal.props, "children", (t, a, returnValue) => {
|
const nodes = args[0].childrenMessageContent.props.content;
|
||||||
if (this.categories.length == 0) return;
|
if (!nodes || !nodes.length) return;
|
||||||
const markup = returnValue.props.children[1];
|
for (let n = 0; n < nodes.length; n++) {
|
||||||
if (!markup.props.children) return;
|
const node = nodes[n];
|
||||||
const nodes = markup.props.children[1];
|
if (typeof(node) !== "string") continue;
|
||||||
if (!nodes || !nodes.length) return;
|
const words = node.split(/([^\s]+)([\s]|$)/g);
|
||||||
for (let n = 0; n < nodes.length; n++) {
|
for (let c = 0, clen = this.categories.length; c < clen; c++) {
|
||||||
const node = nodes[n];
|
for (let w = 0, wlen = words.length; w < wlen; w++) {
|
||||||
if (typeof(node) !== "string") continue;
|
const emote = words[w];
|
||||||
const words = node.split(/([^\s]+)([\s]|$)/g);
|
const emoteSplit = emote.split(":");
|
||||||
for (let c = 0, clen = this.categories.length; c < clen; c++) {
|
const emoteName = emoteSplit[0];
|
||||||
for (let w = 0, wlen = words.length; w < wlen; w++) {
|
let emoteModifier = emoteSplit[1] ? emoteSplit[1] : "";
|
||||||
const emote = words[w];
|
let emoteOverride = emoteModifier.slice(0);
|
||||||
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 (emoteName.length < 4 || blacklist.includes(emoteName)) continue;
|
||||||
if (!modifiers.includes(emoteModifier) || !Settings.get("emotes", "general", "modifiers")) emoteModifier = "";
|
if (!modifiers.includes(emoteModifier) || !Settings.get("emotes", "general", "modifiers")) emoteModifier = "";
|
||||||
if (!overrides.includes(emoteOverride)) emoteOverride = "";
|
if (!overrides.includes(emoteOverride)) emoteOverride = "";
|
||||||
else emoteModifier = emoteOverride;
|
else emoteModifier = emoteOverride;
|
||||||
|
|
||||||
let current = this.categories[c];
|
let current = this.categories[c];
|
||||||
if (emoteOverride === "twitch") {
|
if (emoteOverride === "twitch") {
|
||||||
if (Emotes.TwitchGlobal[emoteName]) current = "TwitchGlobal";
|
if (Emotes.TwitchGlobal[emoteName]) current = "TwitchGlobal";
|
||||||
else if (Emotes.TwitchSubscriber[emoteName]) current = "TwitchSubscriber";
|
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);
|
|
||||||
}
|
}
|
||||||
|
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;
|
const onlyEmotes = nodes.every(r => {
|
||||||
else if (r.type && r.type.name == "BDEmote") return true;
|
if (typeof(r) == "string" && r.replace(/\s*/, "") == "") return true;
|
||||||
else if (r.props && r.props.children && r.props.children.props && r.props.children.props.emojiName) return true;
|
else if (r.type && r.type.name == "BDEmote") return true;
|
||||||
return false;
|
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;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
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",
|
deleteAddon: "Delete",
|
||||||
confirmDelete: "Are you sure you want to delete {{name}}?",
|
confirmDelete: "Are you sure you want to delete {{name}}?",
|
||||||
confirmationText: "You have unsaved changes to {{name}}. Closing this window will lose all those changes.",
|
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: {
|
Emotes: {
|
||||||
loading: "Loading emotes in the background do not reload.",
|
loading: "Loading emotes in the background do not reload.",
|
||||||
|
|
|
@ -10,7 +10,7 @@ import DiscordModules from "./discordmodules";
|
||||||
import Strings from "./strings";
|
import Strings from "./strings";
|
||||||
|
|
||||||
import AddonEditor from "../ui/misc/addoneditor";
|
import AddonEditor from "../ui/misc/addoneditor";
|
||||||
import FloatingWindowContainer from "../ui/floating/container";
|
import FloatingWindows from "../ui/floatingwindows";
|
||||||
|
|
||||||
const React = DiscordModules.React;
|
const React = DiscordModules.React;
|
||||||
|
|
||||||
|
@ -82,21 +82,22 @@ export default class AddonManager {
|
||||||
Logger.log(this.name, `Starting to watch ${this.prefix} addons.`);
|
Logger.log(this.name, `Starting to watch ${this.prefix} addons.`);
|
||||||
this.watcher = fs.watch(this.addonFolder, {persistent: false}, async (eventType, filename) => {
|
this.watcher = fs.watch(this.addonFolder, {persistent: false}, async (eventType, filename) => {
|
||||||
if (!eventType || !filename || !filename.endsWith(this.extension)) return;
|
if (!eventType || !filename || !filename.endsWith(this.extension)) return;
|
||||||
await new Promise(r => setTimeout(r, 50));
|
await new Promise(r => setTimeout(r, 100));
|
||||||
try {fs.statSync(path.resolve(this.addonFolder, filename));}
|
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) {
|
catch (err) {
|
||||||
if (err.code !== "ENOENT") return;
|
if (err.code !== "ENOENT") return;
|
||||||
delete this.timeCache[filename];
|
delete this.timeCache[filename];
|
||||||
this.unloadAddon(filename, true);
|
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);
|
fileContent = stripBOM(fileContent);
|
||||||
const stats = fs.statSync(filename);
|
const stats = fs.statSync(filename);
|
||||||
const meta = self.extractMeta(fileContent);
|
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.id = meta.name;
|
||||||
meta.filename = path.basename(filename);
|
meta.filename = path.basename(filename);
|
||||||
meta.added = stats.atimeMs;
|
meta.added = stats.atimeMs;
|
||||||
|
@ -301,7 +305,7 @@ export default class AddonManager {
|
||||||
language: this.language
|
language: this.language
|
||||||
});
|
});
|
||||||
|
|
||||||
FloatingWindowContainer.open({
|
FloatingWindows.open({
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
this.isDetached = false;
|
this.isDetached = false;
|
||||||
},
|
},
|
||||||
|
|
|
@ -249,7 +249,7 @@ BdApi.setBDData = function(key, data) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeAddonAPI = (manager) => new class AddonAPI {
|
const makeAddonAPI = (manager) => new class AddonAPI {
|
||||||
get folder() {return manager.folder;}
|
get folder() {return manager.addonFolder;}
|
||||||
isEnabled(idOrFile) {return manager.isEnabled(idOrFile);}
|
isEnabled(idOrFile) {return manager.isEnabled(idOrFile);}
|
||||||
enable(idOrAddon) {return manager.enableAddon(idOrAddon);}
|
enable(idOrAddon) {return manager.enableAddon(idOrAddon);}
|
||||||
disable(idOrAddon) {return manager.disableAddon(idOrAddon);}
|
disable(idOrAddon) {return manager.disableAddon(idOrAddon);}
|
||||||
|
|
|
@ -112,7 +112,7 @@ export default new class PluginManager extends AddonManager {
|
||||||
try {
|
try {
|
||||||
plugin.start();
|
plugin.start();
|
||||||
this.emit("started", addon.id);
|
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) {
|
catch (err) {
|
||||||
this.state[addon.id] = false;
|
this.state[addon.id] = false;
|
||||||
|
@ -129,7 +129,7 @@ export default new class PluginManager extends AddonManager {
|
||||||
try {
|
try {
|
||||||
plugin.stop();
|
plugin.stop();
|
||||||
this.emit("stopped", addon.id);
|
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) {
|
catch (err) {
|
||||||
this.state[addon.id] = false;
|
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;
|
const addon = typeof(idOrAddon) == "string" ? this.addonList.find(p => p.id == idOrAddon) : idOrAddon;
|
||||||
if (!addon) return;
|
if (!addon) return;
|
||||||
DOMManager.injectTheme(addon.id, addon.css);
|
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) {
|
removeTheme(idOrAddon) {
|
||||||
const addon = typeof(idOrAddon) == "string" ? this.addonList.find(p => p.id == idOrAddon) : idOrAddon;
|
const addon = typeof(idOrAddon) == "string" ? this.addonList.find(p => p.id == idOrAddon) : idOrAddon;
|
||||||
if (!addon) return;
|
if (!addon) return;
|
||||||
DOMManager.removeTheme(addon.id);
|
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);
|
Logger.stacktrace(this.name, message, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
before(object, func, callback) {
|
||||||
|
return Patcher.before(this.name, object, func, callback);
|
||||||
|
}
|
||||||
|
|
||||||
after(object, func, callback) {
|
after(object, func, callback) {
|
||||||
return Patcher.after(this.name, 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";
|
import FloatingWindow from "./window";
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ class FloatingWindowContainer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
get minY() {
|
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;
|
if (appContainer) return appContainer.offsetTop;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -48,10 +48,4 @@ class FloatingWindowContainer extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerRef = React.createRef();
|
export default FloatingWindowContainer;
|
||||||
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;
|
|
|
@ -121,17 +121,6 @@ export default class FloatingWindow extends React.Component {
|
||||||
</div>;
|
</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() {
|
maximize() {
|
||||||
this.window.current.style.width = "100%";
|
this.window.current.style.width = "100%";
|
||||||
this.window.current.style.height = "100%";
|
this.window.current.style.height = "100%";
|
||||||
|
@ -145,8 +134,35 @@ export default class FloatingWindow extends React.Component {
|
||||||
const right = left + width;
|
const right = left + width;
|
||||||
const bottom = top + height;
|
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 (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";
|
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() {
|
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 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 ModalStack() {return WebpackModules.getByProps("push", "update", "pop", "popWithKey");}
|
||||||
static get AlertModal() {return WebpackModules.getByPrototypes("handleCancel", "handleSubmit", "handleMinorConfirm");}
|
static get AlertModal() {return WebpackModules.getByPrototypes("handleCancel", "handleSubmit", "handleMinorConfirm");}
|
||||||
static get TextElement() {return WebpackModules.getByProps("Sizes", "Weights");}
|
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 get Markdown() {return WebpackModules.findByDisplayName("Markdown");}
|
||||||
|
|
||||||
static default(title, content) {
|
static default(title, content) {
|
||||||
|
@ -64,9 +65,9 @@ export default class Modals {
|
||||||
static showConfirmationModal(title, content, options = {}) {
|
static showConfirmationModal(title, content, options = {}) {
|
||||||
const Markdown = this.Markdown;
|
const Markdown = this.Markdown;
|
||||||
const ConfirmationModal = this.ConfirmationModal;
|
const ConfirmationModal = this.ConfirmationModal;
|
||||||
const ModalStack = this.ModalStack;
|
const ModalActions = this.ModalActions;
|
||||||
if (content instanceof FormattableString) content = content.toString();
|
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 emptyFunction = () => {};
|
||||||
const {onConfirm = emptyFunction, onCancel = emptyFunction, confirmText = Strings.Modals.okay, cancelText = Strings.Modals.cancel, danger = false, key = undefined} = options;
|
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];
|
if (!Array.isArray(content)) content = [content];
|
||||||
content = content.map(c => typeof(c) === "string" ? React.createElement(Markdown, null, c) : c);
|
content = content.map(c => typeof(c) === "string" ? React.createElement(Markdown, null, c) : c);
|
||||||
|
|
||||||
return ModalStack.push(ConfirmationModal, {
|
return ModalActions.openModal(props => {
|
||||||
header: title,
|
return React.createElement(ConfirmationModal, Object.assign({
|
||||||
children: content,
|
header: title,
|
||||||
red: danger,
|
red: danger,
|
||||||
confirmText: confirmText,
|
confirmText: confirmText,
|
||||||
cancelText: cancelText,
|
cancelText: cancelText,
|
||||||
onConfirm: onConfirm,
|
onConfirm: onConfirm,
|
||||||
onCancel: onCancel
|
onCancel: onCancel
|
||||||
}, key);
|
}, props), content);
|
||||||
|
}, {modalKey: key});
|
||||||
}
|
}
|
||||||
|
|
||||||
static showAddonErrors({plugins: pluginErrors = [], themes: themeErrors = []}) {
|
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 channelsClass = WebpackModules.getByProps("sidebar", "hasNotice").sidebar.split(" ")[0];
|
||||||
const membersWrapClass = WebpackModules.getByProps("membersWrap").membersWrap.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("left", left + "px");
|
||||||
toastWrapper.style.setProperty("width", width + "px");
|
toastWrapper.style.setProperty("width", width + "px");
|
||||||
toastWrapper.style.setProperty("bottom", bottom + "px");
|
toastWrapper.style.setProperty("bottom", bottom + "px");
|
||||||
document.querySelector("#app-mount").appendChild(toastWrapper);
|
DOMManager.bdBody.appendChild(toastWrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue