remove jquery use + fixes #255

This commit is contained in:
Zack Rauen 2020-07-16 17:17:02 -04:00
parent 0f49e4257b
commit 82ae0782fe
24 changed files with 222 additions and 284 deletions

View File

@ -63,7 +63,6 @@
"defaultstatus": "off",
"event": "off",
"external": "off",
"fetch": "off",
"find": "off",
"focus": "off",
"frames": "off",

View File

@ -5,12 +5,9 @@ This list only reflects the items that have needed to be done since July 2020, t
Note: The items listed here are not in any sort of priority order.
### To Do (Remote Side)
- Use DOM in place of jQuery
- Use fetch/require in place of $.ajax
- Dependency loading (jquery, css, config file)
- Stop depending on injector giving config
- Fix floating window module
- Dummyproof public servers
- Fix emote render
### To Do (Injector)
- Update to new windowprefs location

View File

@ -195,6 +195,7 @@
-webkit-app-region: no-drag;
position: fixed;
z-index: 1001;
box-sizing: border-box;
}
.floating-window.modal-open {

2
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
js/main.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ export {default as VoiceMode} from "./appearance/voicemode";
export {default as EmoteModule} from "./emotes/emotes";
export {default as EmoteMenu} from "./emotes/emotemenu";
export {default as EmoteAutocaps} from "./emotes/emoteautocaps";
// export {default as EmoteAutocaps} from "./emotes/emoteautocaps";
export {default as CopySelector} from "./developer/copyselector";
export {default as Debugger} from "./developer/debugger";

View File

@ -1,42 +0,0 @@
import Builtin from "../../structs/builtin";
import {Utilities} from "modules";
import EmoteModule from "./emotes";
export default new class EmoteAutocaps extends Builtin {
get name() {return "EmoteAutocapitalize";}
get collection() {return "emotes";}
get category() {return "general";}
get id() {return "autoCaps";}
enabled() {
$("body").off(".bdac");
$("body").on("keyup.bdac change.bdac paste.bdac", $(".channelTextArea-1LDbYG textarea:first"), () => {
const text = $(".channelTextArea-1LDbYG textarea:first").val();
if (text == undefined) return;
const lastWord = text.split(" ").pop();
if (lastWord.length > 3) {
if (lastWord == "danSgame") return;
const ret = this.capitalize(lastWord.toLowerCase());
if (ret !== null && ret !== undefined) {
Utilities.insertText(Utilities.getTextArea()[0], text.replace(lastWord, ret));
}
}
});
}
disabled() {
$("body").off(".bdac");
}
capitalize(value) {
const res = EmoteModule.getCategory("TwitchGlobal");
for (const p in res) {
if (res.hasOwnProperty(p) && value == (p + "").toLowerCase()) {
return p;
}
}
}
};

View File

@ -1,5 +1,6 @@
import Builtin from "../../structs/builtin";
import {Utilities, Events} from "modules";
import {Utilities, Events, DOM} from "modules";
import Modals from "../../ui/modals";
import EmoteModule from "./emotes";
@ -31,7 +32,7 @@ const favoritesHTML = `<div id="bd-qem-favourite-container">
const makeEmote = (emote, url, options = {}) => {
const {onContextMenu, onClick} = options;
const emoteContainer = Utilities.parseHTML(`<div class="emote-container">
const emoteContainer = DOM.createElement(`<div class="emote-container">
<img class="emote-icon" alt="${emote}" src="${url}" title="${emote}">
</div>`);
if (onContextMenu) emoteContainer.addEventListener("contextmenu", onContextMenu);
@ -51,13 +52,13 @@ export default new class EmoteMenu extends Builtin {
super();
this.lastTab = "bd-qem-emojis";
this.qmeHeader = Utilities.parseHTML(headerHTML);
this.qmeHeader = DOM.createElement(headerHTML);
for (const button of this.qmeHeader.getElementsByTagName("button")) button.addEventListener("click", this.switchMenu.bind(this));
this.teContainer = Utilities.parseHTML(twitchEmoteHTML);
this.teContainer = DOM.createElement(twitchEmoteHTML);
this.teContainerInner = this.teContainer.querySelector(".emote-menu-inner");
this.faContainer = Utilities.parseHTML(favoritesHTML);
this.faContainer = DOM.createElement(favoritesHTML);
this.faContainerInner = this.faContainer.querySelector(".emote-menu-inner");
this.observer = new MutationObserver(mutations => {for (const mutation of mutations) this.observe(mutation);});
@ -67,16 +68,17 @@ export default new class EmoteMenu extends Builtin {
}
async enabled() {
this.log("Starting to observe");
this.observer.observe(document.getElementById("app-mount"), {
childList: true,
subtree: true
});
this.hideEmojiCancel = this.registerSetting(this.hideEmojisID, this.enableHideEmojis, this.disableHideEmojis);
if (this.hideEmojis) this.enableHideEmojis();
if (EmoteModule.emotesLoaded) this.updateTwitchEmotes();
this.updateFavorites();
Events.on("emotes-loaded", this.updateTwitchEmotes);
return Modals.alert("Emote Menu Broken", "Emote Menu is currently broken, it is recommended to disable this until it is fixed.");
// this.log("Starting to observe");
// this.observer.observe(document.getElementById("app-mount"), {
// childList: true,
// subtree: true
// });
// this.hideEmojiCancel = this.registerSetting(this.hideEmojisID, this.enableHideEmojis, this.disableHideEmojis);
// if (this.hideEmojis) this.enableHideEmojis();
// if (EmoteModule.emotesLoaded) this.updateTwitchEmotes();
// this.updateFavorites();
// Events.on("emotes-loaded", this.updateTwitchEmotes);
}
disabled() {

View File

@ -38,17 +38,5 @@ export default new class PublicServers extends Builtin {
label.addEventListener("click", () => {this.openPublicServers();});
btn.append(label);
return btn;
// const btn = $("<div/>", {
// "class": DiscordModules.GuildClasses.listItem,
// "id": "bd-pub-li"
// }).append($("<div/>", {
// "class": "wrapper-25eVIn " + DiscordModules.GuildClasses.circleButtonMask,
// "text": Strings.PublicServers.button,
// "id": "bd-pub-button",
// "click": () => { this.openPublicServers(); }
// }));
// return btn;
}
};

View File

@ -7,11 +7,6 @@ export default new class WindowPrefs extends Builtin {
get category() {return "window";}
get id() {return "transparency";}
initialize() {
super.initialize();
this.prefs = DataStore.getData("windowprefs") || {};
}
enabled() {
this.setWindowPreference("transparent", true);
this.setWindowPreference("backgroundColor", "#00000000");
@ -25,6 +20,7 @@ export default new class WindowPrefs extends Builtin {
}
showModal(info) {
if (!this.initialized) return;
Modals.showConfirmationModal(Strings.Modals.additionalInfo, info, {
confirmText: Strings.Modals.restartNow,
cancelText: Strings.Modals.restartLater,
@ -37,16 +33,19 @@ export default new class WindowPrefs extends Builtin {
}
getWindowPreference(key) {
return this.prefs[key];
const prefs = DataStore.getData("windowprefs") || {};
return prefs[key];
}
setWindowPreference(key, value) {
this.prefs[key] = value;
DataStore.setData("windowprefs", this.prefs);
const prefs = DataStore.getData("windowprefs") || {};
prefs[key] = value;
DataStore.setData("windowprefs", prefs);
}
deleteWindowPreference(key) {
delete this.prefs[key];
DataStore.setData("windowprefs", this.prefs);
const prefs = DataStore.getData("windowprefs") || {};
delete prefs[key];
DataStore.setData("windowprefs", prefs);
}
};

View File

@ -8,7 +8,6 @@ export default [
{type: "switch", id: "download", value: true},
{type: "switch", id: "emoteMenu", value: true},
{type: "switch", id: "hideEmojiMenu", value: false, enableWith: "emoteMenu"},
{type: "switch", id: "autoCaps", value: false},
{type: "switch", id: "showNames", value: true},
{type: "switch", id: "modifiers", value: true},
{type: "switch", id: "animateOnHover", value: false}

View File

@ -43,8 +43,6 @@ Core.prototype.init = async function() {
return Modals.alert(Strings.Startup.notSupported, Strings.Startup.incompatibleApp.format({app: "Powercord"}));
}
console.log(Config);
const latestLocalVersion = Config.updater ? Config.updater.LatestVersion : Config.latestVersion;
if (latestLocalVersion > Config.version) {
Modals.showConfirmationModal(Strings.Startup.updateAvailable, Strings.Startup.updateInfo.format({version: latestLocalVersion}), {
@ -66,8 +64,6 @@ Core.prototype.init = async function() {
});
}
Logger.log("Startup", "Initializing Settings");
Settings.initialize();
@ -93,7 +89,7 @@ Core.prototype.init = async function() {
const previousVersion = DataStore.getBDData("version");
if (Config.bbdVersion > previousVersion) {
this.showChangelogModal(Changelog);
Modals.showChangelogModal(Changelog);
DataStore.setBDData("version", Config.bbdVersion);
}
};

View File

@ -575,9 +575,9 @@ export default class DOMTools {
const [type, namespace] = event.split(".");
const hasDelegate = delegate && callback;
if (!callback) callback = delegate;
const eventFunc = !hasDelegate ? callback : function(event) {
if (event.target.matches(delegate)) {
callback(event);
const eventFunc = !hasDelegate ? callback : function(ev) {
if (ev.target.matches(delegate)) {
callback(ev);
}
};
@ -615,12 +615,12 @@ export default class DOMTools {
const [type, namespace] = event.split(".");
const hasDelegate = delegate && callback;
if (!callback) callback = delegate;
const eventFunc = !hasDelegate ? function(event) {
callback(event);
const eventFunc = !hasDelegate ? function(ev) {
callback(ev);
element.removeEventListener(type, eventFunc);
} : function(event) {
if (!event.target.matches(delegate)) return;
callback(event);
} : function(ev) {
if (!ev.target.matches(delegate)) return;
callback(ev);
element.removeEventListener(type, eventFunc);
};
@ -689,9 +689,9 @@ export default class DOMTools {
const hasDelegate = delegate && callback;
if (!callback) callback = delegate;
const eventFunc = !hasDelegate ? callback : function(event) {
if (event.target.matches(delegate)) {
callback(event);
const eventFunc = !hasDelegate ? callback : function(ev) {
if (ev.target.matches(delegate)) {
callback(ev);
}
};

View File

@ -1,3 +1,4 @@
import {Config} from "data";
import Utilities from "./utilities";
import WebpackModules from "./webpackmodules";
import DiscordModules from "./discordmodules";
@ -13,40 +14,24 @@ import Logger from "./logger";
const BdApi = {
get React() { return DiscordModules.React; },
get ReactDOM() { return DiscordModules.ReactDOM; },
get WindowConfigFile() {
if (this._windowConfigFile) return this._windowConfigFile;
const electron = require("electron").remote.app;
const path = require("path");
const base = electron.getAppPath();
const roamingBase = electron.getPath("userData");
const roamingLocation = path.resolve(roamingBase, electron.getVersion(), "modules", "discord_desktop_core", "injector", "config.json");
const location = path.resolve(base, "..", "app", "config.json");
const fs = require("fs");
const realLocation = fs.existsSync(location) ? location : fs.existsSync(roamingLocation) ? roamingLocation : null;
if (!realLocation) return this._windowConfigFile = null;
return this._windowConfigFile = realLocation;
},
get WindowConfigFile() {return "";},
get settings() {return Settings.collections;},
get emotes() {return {};}
get emotes() {return {};},
get version() {return Config.version;}
};
BdApi.getAllWindowPreferences = function() {
if (!this.WindowConfigFile) return {};
return __non_webpack_require__(this.WindowConfigFile);
return DataStore.getData("windowprefs") || {};
};
BdApi.getWindowPreference = function(key) {
if (!this.WindowConfigFile) return undefined;
return this.getAllWindowPreferences()[key];
};
BdApi.setWindowPreference = function(key, value) {
if (!this.WindowConfigFile) return;
const fs = require("fs");
const prefs = this.getAllWindowPreferences();
prefs[key] = value;
delete require.cache[this.WindowConfigFile];
fs.writeFileSync(this.WindowConfigFile, JSON.stringify(prefs, null, 4));
return DataStore.setData("windowprefs", prefs);
};
//Inject CSS to document head
@ -277,4 +262,8 @@ const makeAddonAPI = (manager) => new class AddonAPI {
BdApi.Plugins = makeAddonAPI(PluginManager);
BdApi.Themes = makeAddonAPI(ThemeManager);
Object.freeze(BdApi);
Object.freeze(BdApi.Plugins);
Object.freeze(BdApi.Themes);
export default BdApi;

View File

@ -136,7 +136,7 @@ export default class PluginUpdater {
* @returns {HTMLElement} check for update button
*/
static createUpdateButton() {
const updateButton = DOMTools.parseHTML(`<button class="bd-pfbtn bd-updatebtn" style="left: 220px;">Check for Updates</button>`);
const updateButton = DOMTools.createElement(`<button class="bd-pfbtn bd-updatebtn" style="left: 220px;">Check for Updates</button>`);
updateButton.onclick = function () {
window.PluginUpdates.checkAll();
};
@ -181,7 +181,7 @@ export default class PluginUpdater {
if (oldRNM || newRNM || BBDLoader) return;
if (!window.PluginUpdates.downloaded) {
window.PluginUpdates.downloaded = [];
const button = DOMTools.parseHTML(`<button class="btn btn-reload ${DiscordClasses.Notices.btn} ${DiscordClasses.Notices.button}">Reload</button>`);
const button = DOMTools.createElement(`<button class="btn btn-reload ${DiscordClasses.Notices.btn} ${DiscordClasses.Notices.button}">Reload</button>`);
const tooltip = new EmulatedTooltip(button, window.PluginUpdates.downloaded.join(", "), {side: "top"});
button.addEventListener("click", (e) => {
e.preventDefault();
@ -205,7 +205,7 @@ export default class PluginUpdater {
*/
static showUpdateNotice(pluginName, updateLink) {
if (!document.getElementById("pluginNotice")) {
const noticeElement = DOMTools.parseHTML(`<div class="${DiscordClasses.Notices.notice} ${DiscordClasses.Notices.noticeInfo}" id="pluginNotice">
const noticeElement = DOMTools.createElement(`<div class="${DiscordClasses.Notices.notice} ${DiscordClasses.Notices.noticeInfo}" id="pluginNotice">
<div class="${DiscordClasses.Notices.dismiss}" id="pluginNoticeDismiss"></div>
<span class="notice-message">The following plugins have updates:</span>&nbsp;&nbsp;<strong id="outdatedPlugins"></strong>
</div>`);
@ -218,7 +218,7 @@ export default class PluginUpdater {
}
const pluginNoticeID = pluginName + "-notice";
if (document.getElementById(pluginNoticeID)) return;
const pluginNoticeElement = DOMTools.parseHTML(`<span id="${pluginNoticeID}">${pluginName}</span>`);
const pluginNoticeElement = DOMTools.createElement(`<span id="${pluginNoticeID}">${pluginName}</span>`);
pluginNoticeElement.addEventListener("click", () => {
this.downloadPlugin(pluginName, updateLink);
});

View File

@ -1,5 +1,6 @@
import {Config} from "data";
import Logger from "./logger";
import DOM from "./domtools";
export default class Utilities {
@ -27,7 +28,7 @@ export default class Utilities {
}
static getTextArea() {
return $(".channelTextArea-1LDbYG textarea");
return DOM.query(".channelTextArea-1LDbYG textarea");
}
static insertText(textarea, text) {

View File

@ -17,6 +17,7 @@ export default class BuiltinModule {
if (enabled) this.enable();
else this.disable();
});
this.initialized = true;
}
registerSetting(collection, category, id, onEnable, onDisable) {

View File

@ -22,78 +22,66 @@ export default class PublicServersConnection {
}
static search({term = "", category = "", from = 0} = {}) {
const request = require("request");
return new Promise(resolve => {
const queries = [];
if (category) queries.push(`category=${category.replace(/ /g, "%20")}`);
if (term) queries.push(`term=${term.replace(/ /g, "%20")}`);
if (from) queries.push(`from=${from}`);
const query = `?${queries.join("&")}`;
$.ajax({
method: "GET",
url: `${this.endPoint}${query}`,
success: data => {
const next = data.size + data.from;
resolve({
servers: data.results,
size: data.size,
from: data.from,
total: data.total,
next: next >= data.total ? null : next
});
},
error: () => resolve(null)
});
});
}
static join(id, native = false) {
return new Promise(resolve => {
if (native) return InviteActions.acceptInvite(id), resolve(true);
$.ajax({
method: "GET",
url: `${this.joinEndPoint}/${id}`,
headers: {
"Accept": "application/json;",
"Content-Type": "application/json;" ,
"x-discord-token": this._accessToken
},
crossDomain: true,
xhrFields: {
withCredentials: true
},
success: () => resolve(true),
error: () => resolve(false)
});
});
}
static checkConnection() {
return new Promise(resolve => {
try {
$.ajax({
method: "GET",
url: this.connectEndPoint,
headers: {
"Accept": "application/json;",
"Content-Type": "application/json;"
},
crossDomain: true,
xhrFields: {
withCredentials: true
},
success: data => {
this._accessToken = data.access_token;
resolve(data);
},
error: () => resolve(false)
request.get({url: `${this.endPoint}${query}${query ? "&schema=new" : "?schema=new"}`, json: true}, (err, resp, data) => {
if (err) return resolve(null);
const next = data.size + data.from;
resolve({
servers: data.results,
size: data.size,
from: data.from,
total: data.total,
next: next >= data.total ? null : next
});
}
catch (error) {
resolve(false);
}
});
});
}
static async join(id, native = false) {
if (native) return InviteActions.acceptInvite(id);
try {
await fetch(`${this.joinEndPoint}/${id}`,{
method: "GET",
credentials: "include",
mode: "cors",
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
});
return true;
}
catch (e) {
return false;
}
}
static async checkConnection() {
try {
const response = await fetch(`https://auth.discordservers.com/info`,{
method: "GET",
credentials: "include",
mode: "cors",
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
});
const data = await response.json();
this._accessToken = data.access_token;
return data;
}
catch (error) {
return false;
}
}
static connect() {
return new Promise(resolve => {
const joinWindow = new BrowserWindow(this.windowOptions);

View File

@ -1,4 +1,4 @@
import {React, Utilities, Patcher} from "modules";
import {React, ReactDOM, DOM, WebpackModules} from "modules";
import FloatingWindow from "./window";
@ -9,9 +9,15 @@ class FloatingWindowContainer extends React.Component {
this.state = {windows: []};
}
get minY() {
const appContainer = DOM.query(`#app-mount > div[class*="app-"`);
if (appContainer) return appContainer.offsetTop;
return 0;
}
render() {
return this.state.windows.map(window =>
<FloatingWindow {...window} close={this.close.bind(this, window.id)}>
<FloatingWindow {...window} close={this.close.bind(this, window.id)} minY={this.minY}>
{window.children}
</FloatingWindow>
);
@ -43,11 +49,9 @@ class FloatingWindowContainer extends React.Component {
}
const containerRef = React.createRef();
// const container = <FloatingWindowContainer ref={containerRef} />;
// const App = Utilities.findInReactTree(Utilities.getReactInstance(document.querySelector(".app-19_DXt")), m => m && m.type && m.type.displayName && m.type.displayName == "App");
// Patcher.after("FloatingContainer", App.type.prototype, "render", (thisObject, args, returnValue) => {
// const group = Utilities.findInRenderTree(returnValue, m => m && m[6] && m[6].type && m[6].type.displayName == "LayerContainer", {walkable: ["children", "props"]});
// group.push(container);
// });
// App.stateNode.forceUpdate();
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;

View File

@ -5,6 +5,20 @@ import CloseButton from "../icons/close";
import MaximizeIcon from "../icons/fullscreen";
import Modals from "../modals";
// const Draggable = WebpackModules.getByDisplayName("Draggable");
// {
// "dragAnywhere": true,
// "className": "pictureInPictureWindow-1B5qSe",
// "maxX": 1969,
// "maxY": this.maxY,
// "onDragStart": "ƒ () {}",
// "onDrag": "ƒ () {}",
// "onDragEnd": "ƒ () {}",
// "children": "<div />",
// "initialX": 0,
// "initialY": 0
// }
export default class FloatingWindow extends React.Component {
constructor(props) {
@ -15,6 +29,11 @@ export default class FloatingWindow extends React.Component {
this.offX = 0;
this.offY = 0;
this.maxX = this.props.maxX || Screen.width;
this.maxY = this.props.maxY || Screen.height;
this.minX = this.props.minX || 0;
this.minY = this.props.minY || 0;
this.titlebar = React.createRef();
this.window = React.createRef();
@ -33,19 +52,23 @@ export default class FloatingWindow extends React.Component {
}
onResizeStart() {
this.currentWidth = this.window.current.style.width;
this.currentHeight = this.window.current.style.height;
this.currentWidth = this.window.current.offsetWidth;
this.currentHeight = this.window.current.offsetHeight;
}
onDragStop() {
document.removeEventListener("mousemove", this.onDrag, true);
if (this.props.onResize) {
const width = this.window.current.style.width;
const height = this.window.current.style.height;
if (width != this.currentWidth || height != this.currentHeight) this.props.onResize();
this.currentWidth = width;
this.currentHeight = height;
const width = this.window.current.offsetWidth;
const height = this.window.current.offsetHeight;
if (width != this.currentWidth || height != this.currentHeight) {
if (this.props.onResize) this.props.onResize();
const left = parseInt(this.window.current.style.left);
const top = parseInt(this.window.current.style.top);
if (left + width >= this.maxX) this.window.current.style.width = (this.maxX - left) + "px";
if (top + height >= this.maxY) this.window.current.style.height = (this.maxY - top) + "px";
}
this.currentWidth = width;
this.currentHeight = height;
}
onDragStart(e) {
@ -57,8 +80,16 @@ export default class FloatingWindow extends React.Component {
onDrag(e) {
const div = this.window.current;
div.style.top = (e.clientY - this.offY) + "px";
div.style.left = (e.clientX - this.offX) + "px";
let newTop = (e.clientY - this.offY);
if (newTop <= this.minY) newTop = this.minY;
if (newTop + this.currentHeight >= this.maxY) newTop = this.maxY - this.currentHeight;
let newLeft = (e.clientX - this.offX);
if (newLeft <= this.minX) newLeft = this.minX;
if (newLeft + this.currentWidth >= this.maxX) newLeft = this.maxX - this.currentWidth;
div.style.top = newTop + "px";
div.style.left = newLeft + "px";
}
componentWillUnmount() {
@ -104,9 +135,18 @@ export default class FloatingWindow extends React.Component {
maximize() {
this.window.current.style.width = "100%";
this.window.current.style.height = "100%";
this.window.current.style.top = "20px";
this.window.current.style.left = "0px";
if (this.props.onResize) this.props.onResize();
const width = this.window.current.offsetWidth;
const height = this.window.current.offsetHeight;
const left = parseInt(this.window.current.style.left);
const top = parseInt(this.window.current.style.top);
const right = left + width;
const bottom = top + height;
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";
}
confirmClose() {

View File

@ -1,5 +1,5 @@
import {Config} from "data";
import {Logger, WebpackModules, Utilities, React, Settings, Strings, DOM, DiscordModules} from "modules";
import {Logger, WebpackModules, React, Settings, Strings, DOM, DiscordModules} from "modules";
import FormattableString from "../structs/string";
export default class Modals {
@ -13,7 +13,7 @@ export default class Modals {
static get Markdown() {return WebpackModules.findByDisplayName("Markdown");}
static default(title, content) {
const modal = Utilities.parseHTML(`<div class="bd-modal-wrapper theme-dark">
const modal = DOM.createElement(`<div class="bd-modal-wrapper theme-dark">
<div class="bd-backdrop backdrop-1wrmKB"></div>
<div class="bd-modal modal-1UGdnR">
<div class="bd-modal-inner inner-1JeGVc">
@ -34,11 +34,11 @@ export default class Modals {
</div>
</div>`);
modal.querySelector(".footer button").addEventListener("click", () => {
modal.addClass("closing");
modal.classList.add("closing");
setTimeout(() => { modal.remove(); }, 300);
});
modal.querySelector(".bd-backdrop").addEventListener("click", () => {
modal.addClass("closing");
modal.classList.add("closing");
setTimeout(() => { modal.remove(); }, 300);
});
document.querySelector("#app-mount").append(modal);
@ -88,7 +88,7 @@ export default class Modals {
static showAddonErrors({plugins: pluginErrors = [], themes: themeErrors = []}) {
if (!pluginErrors || !themeErrors || !this.shouldShowAddonErrors) return;
if (!pluginErrors.length && !themeErrors.length) return;
const modal = $(`<div class="bd-modal-wrapper theme-dark">
const modal = DOM.createElement(`<div class="bd-modal-wrapper theme-dark">
<div class="bd-backdrop backdrop-1wrmKB"></div>
<div class="bd-modal bd-content-modal modal-1UGdnR">
<div class="bd-modal-inner inner-1JeGVc">
@ -119,19 +119,19 @@ export default class Modals {
</div>`);
const generateTab = function(errors) {
const container = $(`<div class="errors">`);
const container = DOM.createElement(`<div class="errors">`);
for (const err of errors) {
const error = $(`<div class="error">
const error = DOM.createElement(`<div class="error">
<div class="table-column column-name">${err.name ? err.name : err.file}</div>
<div class="table-column column-message">${err.message}</div>
<div class="table-column column-error"><a class="error-link" href="">${err.error ? err.error.message : ""}</a></div>
</div>`);
container.append(error);
if (err.error) {
error.find("a").on("click", (e) => {
error.querySelectorAll("a").forEach(el => el.addEventListener("click", (e) => {
e.preventDefault();
Logger.stacktrace("AddonError", `Error details for ${err.name ? err.name : err.file}.`, err.error);
});
}));
}
}
return container;
@ -139,24 +139,27 @@ export default class Modals {
const tabs = [generateTab(pluginErrors), generateTab(themeErrors)];
modal.find(".tab-bar-item").on("click", (e) => {
modal.querySelectorAll(".tab-bar-item").forEach(el => el.addEventListener("click", (e) => {
e.preventDefault();
modal.find(".tab-bar-item").removeClass("selected");
$(e.target).addClass("selected");
modal.find(".scroller").empty().append(tabs[$(e.target).index()]);
});
const selected = modal.querySelector(".tab-bar-item.selected");
if (selected) DOM.removeClass(selected, "selected");
DOM.addClass(e.target, "selected");
const scroller = modal.querySelector(".scroller");
scroller.innerHTML = "";
scroller.append(tabs[DOM.index(e.target)]);
}));
modal.find(".footer button").on("click", () => {
modal.addClass("closing");
modal.querySelector(".footer button").addEventListener("click", () => {
DOM.addClass(modal, "closing");
setTimeout(() => { modal.remove(); }, 300);
});
modal.find(".bd-backdrop").on("click", () => {
modal.addClass("closing");
modal.querySelector(".bd-backdrop").addEventListener("click", () => {
DOM.addClass(modal, "closing");
setTimeout(() => { modal.remove(); }, 300);
});
modal.appendTo("#app-mount");
if (pluginErrors.length) modal.find(".tab-bar-item")[0].click();
else modal.find(".tab-bar-item")[1].click();
DOM.query("#app-mount").append(modal);
if (pluginErrors.length) modal.querySelector(".tab-bar-item").click();
else modal.querySelectorAll(".tab-bar-item")[1].click();
}
static showChangelogModal(options = {}) {

View File

@ -32,6 +32,7 @@ export default class PublicServers extends React.Component {
this.searchKeyDown = this.searchKeyDown.bind(this);
this.connect = this.connect.bind(this);
this.loadNextPage = this.loadNextPage.bind(this);
this.join = this.join.bind(this);
}
componentDidMount() {
@ -106,7 +107,7 @@ export default class PublicServers extends React.Component {
const connectButton = this.state.user ? null : {title: Strings.PublicServers.connect, onClick: this.connect};
const pinned = this.state.category == "All" || !this.state.user ? this.bdServer : null;
const servers = this.state.results.servers.map((server) => {
return React.createElement(ServerCard, {key: server.identifier, server: server, joined: Connection.hasJoined(server.identifier), defaultAvatar: Connection.getDefaultAvatar});
return React.createElement(ServerCard, {key: server.identifier, server: server, joined: Connection.hasJoined(server.identifier), join: this.join, defaultAvatar: Connection.getDefaultAvatar});
});
return [React.createElement(SettingsTitle, {text: this.title, button: connectButton}),
pinned,

View File

@ -35,22 +35,6 @@ export default class AddonCard extends React.Component {
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);
setImmediate(() => {
const isHidden = (container, element) => {
const cTop = container.scrollTop;