remove jquery and stuff
This commit is contained in:
parent
dbcf2f9cef
commit
ded3f96b07
|
@ -45,6 +45,7 @@
|
|||
"Promise": false,
|
||||
"ace": false,
|
||||
"Reflect": false,
|
||||
"Array": false,
|
||||
"DiscordNative": false,
|
||||
"self": "off",
|
||||
"name": "off",
|
||||
|
|
122
js/main.js
122
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
|
@ -2,34 +2,24 @@
|
|||
export const minimumDiscordVersion = "0.0.306";
|
||||
export const currentDiscordVersion = (window.DiscordNative && window.DiscordNative.remoteApp && window.DiscordNative.remoteApp.getVersion && window.DiscordNative.remoteApp.getVersion()) || "0.0.306";
|
||||
export const minSupportedVersion = "0.3.0";
|
||||
export const bbdVersion = "0.3.1";
|
||||
export const bbdVersion = "0.3.2";
|
||||
export const bbdChangelog = {
|
||||
description: "There's some pretty big things in this one, and even bigger things coming. Most of this information is repeated from the `0.3.0` update just in case people hadn't seen the changelog yet.",
|
||||
description: "More big things.",
|
||||
changes: [
|
||||
{
|
||||
title: "What's New?",
|
||||
items: [
|
||||
"**RepoControls**-like controls are now integrated into BD and everyone can enjoy sorting and searching their plugins and themes.",
|
||||
"BandagedBD has undergone an internal restructure--it's no longer one messy file but *several*. Users shouldn't see any breaking changes (hopefully).",
|
||||
"**Plugin Developers:** You'll begin (or continue for some) to see deprecation notices for several BD globals. Please take these seriously and update your plugins to use `BdApi`, the globals **_will_** be removed. If you find the API to be missing something that you could do before, please message me in BD2's <#603225817262194699> chat.",
|
||||
"**Also Plugin Developers:** There is now an option to enable React Developer Tools in the Developer Options in settings. Just make sure to have the extension installed in your local Chrome installation."
|
||||
"**jQuery** is no longer used internally in BBD. This should speed things up and hopefully close some memory leaks.",
|
||||
"**VoiceMode** was redone to act more like it used to."
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Minor Stuff",
|
||||
title: "Improvements",
|
||||
type: "improved",
|
||||
items: [
|
||||
"**BD Blue** is now the default accent color for BBD elements in settings. Themes can customize it easily through some new variables: `--bd-blue`, `--bd-blue-hover`, `--bd-blue-active`",
|
||||
"Some improvements have been made to the plugins and themes pages that should hopefully prevent plugins from causing errors when displaying.",
|
||||
"You can now review the changelog after you close it by clicking this button in settings: https://i.imgur.com/I3ZdAxG.png"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Minor Stuff",
|
||||
type: "fixed",
|
||||
items: [
|
||||
"**Quick Emote Menu** works again, sorry about that!",
|
||||
"Fixed an issue with searching plugin/theme lists."
|
||||
"**Copy Selector** option was revamped to be more consistent and functional.",
|
||||
"**Emote Menu** has gone through some serious changes to be more efficient and less buggy.",
|
||||
"Some speed improvements when entering the plugins and themes tabs."
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@ -76,7 +66,7 @@ export const settings = {
|
|||
"BetterTTV Emotes": {id: "bda-es-2", info: "Show BetterTTV Emotes", implemented: true, hidden: false, cat: "emote"},
|
||||
"Emote Menu": {id: "bda-es-0", info: "Show Twitch/Favourite emotes in emote menu", implemented: true, hidden: false, cat: "emote"},
|
||||
"Emoji Menu": {id: "bda-es-9", info: "Show Discord emoji menu", implemented: true, hidden: false, cat: "emote"},
|
||||
"Emote Auto Capitalization": {id: "bda-es-4", info: "Autocapitalize emote commands", implemented: true, hidden: false, cat: "emote"},
|
||||
"Emote Auto Capitalization": {id: "bda-es-4", info: "Autocapitalize emote commands", implemented: false, hidden: false, cat: "emote"},
|
||||
"Show Names": {id: "bda-es-6", info: "Show emote names on hover", implemented: true, hidden: false, cat: "emote"},
|
||||
"Show emote modifiers": {id: "bda-es-8", info: "Enable emote mods (flip, spin, pulse, spin2, spin3, 1spin, 2spin, 3spin, tr, bl, br, shake, shake2, shake3, flap)", implemented: true, hidden: false, cat: "emote"},
|
||||
"Animate On Hover": {id: "fork-es-2", info: "Only animate the emote modifiers on hover", implemented: true, hidden: false, cat: "emote"}
|
||||
|
|
|
@ -30,7 +30,6 @@ import DataStore from "./modules/dataStore";
|
|||
import emoteModule from "./modules/emoteModule";
|
||||
import ContentManager from "./modules/contentManager";
|
||||
import ClassNormalizer from "./modules/classNormalizer";
|
||||
import quickEmoteMenu from "./modules/quickEmoteMenu";
|
||||
|
||||
deprecateGlobal("BDV2", BDV2);
|
||||
deprecateGlobal("pluginModule", pluginModule);
|
||||
|
@ -44,7 +43,6 @@ deprecateGlobal("ContentManager", ContentManager);
|
|||
deprecateGlobal("ClassNormalizer", ClassNormalizer);
|
||||
|
||||
window.BdApi = BdApi;
|
||||
window.quickEmoteMenu = quickEmoteMenu;
|
||||
|
||||
import Core from "./modules/core";
|
||||
export default class CoreWrapper {
|
||||
|
|
|
@ -6,6 +6,7 @@ import DataStore from "./dataStore";
|
|||
import pluginModule from "./pluginModule";
|
||||
import themeModule from "./themeModule";
|
||||
import settingsPanel from "./settingsPanel";
|
||||
import DOM from "./domtools";
|
||||
|
||||
const BdApi = {
|
||||
get React() { return BDV2.React; },
|
||||
|
@ -34,26 +35,26 @@ BdApi.setWindowPreference = function(key, value) {
|
|||
//id = id of element
|
||||
//css = custom css
|
||||
BdApi.injectCSS = function (id, css) {
|
||||
$("head").append($("<style>", {id: Utils.escapeID(id), text: css}));
|
||||
DOM.addStyle(DOM.escapeID(id), css);
|
||||
};
|
||||
|
||||
//Clear css/remove any element
|
||||
//id = id of element
|
||||
BdApi.clearCSS = function (id) {
|
||||
$("#" + Utils.escapeID(id)).remove();
|
||||
DOM.removeStyle(DOM.escapeID(id));
|
||||
};
|
||||
|
||||
//Inject CSS to document head
|
||||
//id = id of element
|
||||
//css = custom css
|
||||
BdApi.linkJS = function (id, url) {
|
||||
$("head").append($("<script>", {id: Utils.escapeID(id), src: url, type: "text/javascript"}));
|
||||
DOM.addScript(DOM.escapeID(id), url);
|
||||
};
|
||||
|
||||
//Clear css/remove any element
|
||||
//id = id of element
|
||||
BdApi.unlinkJS = function (id) {
|
||||
$("#" + Utils.escapeID(id)).remove();
|
||||
DOM.removeScript(DOM.escapeID(id));
|
||||
};
|
||||
|
||||
//Get another plugin
|
||||
|
|
|
@ -113,8 +113,6 @@ export default new class ContentManager {
|
|||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
getContentRequire(type) {
|
||||
const isPlugin = type === "plugin";
|
||||
const self = this;
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import {bdConfig, minSupportedVersion, bbdVersion, settingsCookie, bdpluginErrors, bdthemeErrors, bbdChangelog, defaultCookie, minimumDiscordVersion, currentDiscordVersion} from "../0globals";
|
||||
import {bdConfig, minSupportedVersion, bbdVersion, settingsCookie, bdpluginErrors, bdthemeErrors, bbdChangelog, defaultCookie, currentDiscordVersion} from "../0globals";
|
||||
import Utils from "./utils";
|
||||
import emoteModule from "./emoteModule";
|
||||
import quickEmoteMenu from "./quickEmoteMenu";
|
||||
// import publicServersModule from "./publicServers";
|
||||
// import voiceMode from "./voiceMode";
|
||||
// import dMode from "./devMode";
|
||||
|
||||
import BDV2 from "./v2";
|
||||
import settingsPanel from "./settingsPanel";
|
||||
import pluginModule from "./pluginModule";
|
||||
import themeModule from "./themeModule";
|
||||
import DataStore from "./dataStore";
|
||||
import WebpackModules from "./webpackModules";
|
||||
import DOM from "./domtools";
|
||||
|
||||
import BDLogo from "../ui/bdLogo";
|
||||
import TooltipWrap from "../ui/tooltipWrap";
|
||||
|
@ -22,10 +21,10 @@ Core.prototype.setConfig = function(config) {
|
|||
};
|
||||
|
||||
Core.prototype.init = async function() {
|
||||
// if (currentDiscordVersion < minimumDiscordVersion) {
|
||||
// Utils.alert("Not Supported", "BetterDiscord v" + bbdVersion + " does not support this old version (" + currentDiscordVersion + ") of Discord. Please update your Discord installation before proceeding.");
|
||||
// return;
|
||||
// }
|
||||
if (!Array.prototype.flat) {
|
||||
Utils.alert("Not Supported", "BetterDiscord v" + bbdVersion + " does not support this old version (" + currentDiscordVersion + ") of Discord. Please update your Discord installation before proceeding.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdConfig.version < minSupportedVersion) {
|
||||
Utils.alert("Not Supported", "BetterDiscord v" + bdConfig.version + " (your version)" + " is not supported by the latest js (" + bbdVersion + ").<br><br> Please download the latest version from <a href='https://github.com/rauenzi/BetterDiscordApp/releases/latest' target='_blank'>GitHub</a>");
|
||||
|
@ -52,43 +51,33 @@ Core.prototype.init = async function() {
|
|||
|
||||
Utils.log("Startup", "Initializing Settings");
|
||||
this.initSettings();
|
||||
// emoteModule = new EmoteModule();
|
||||
// quickEmoteMenu = new QuickEmoteMenu();
|
||||
Utils.log("Startup", "Initializing EmoteModule");
|
||||
window.emotePromise = emoteModule.init().then(() => {
|
||||
emoteModule.initialized = true;
|
||||
Utils.log("Startup", "Initializing QuickEmoteMenu");
|
||||
quickEmoteMenu.init();
|
||||
});
|
||||
// publicServersModule = new V2_PublicServers();
|
||||
|
||||
// voiceMode = new VoiceMode();
|
||||
// dMode = new devMode();
|
||||
|
||||
this.injectExternals();
|
||||
|
||||
await this.checkForGuilds();
|
||||
BDV2.initialize();
|
||||
Utils.log("Startup", "Updating Settings");
|
||||
// settingsPanel = new V2_SettingsPanel();
|
||||
settingsPanel.initializeSettings();
|
||||
|
||||
Utils.log("Startup", "Loading Plugins");
|
||||
// pluginModule = new PluginModule();
|
||||
pluginModule.loadPlugins();
|
||||
|
||||
Utils.log("Startup", "Loading Themes");
|
||||
// themeModule = new ThemeModule();
|
||||
themeModule.loadThemes();
|
||||
|
||||
$("#customcss").detach().appendTo(document.head);
|
||||
DOM.addStyle("customcss", atob(DataStore.getBDData("bdcustomcss")));
|
||||
|
||||
window.addEventListener("beforeunload", function() {
|
||||
if (settingsCookie["bda-dc-0"]) document.querySelector(".btn.btn-disconnect").click();
|
||||
});
|
||||
|
||||
emoteModule.autoCapitalize();
|
||||
|
||||
Utils.log("Startup", "Removing Loading Icon");
|
||||
if (document.getElementsByClassName("bd-loaderv2").length) document.getElementsByClassName("bd-loaderv2")[0].remove();
|
||||
Utils.log("Startup", "Initializing Main Observer");
|
||||
|
@ -124,14 +113,13 @@ Core.prototype.checkForGuilds = function() {
|
|||
else if (timesChecked >= 50) return resolve(bdConfig.deferLoaded = true);
|
||||
setTimeout(checkForGuilds, 100);
|
||||
};
|
||||
$(document).ready(function () {
|
||||
setTimeout(checkForGuilds, 100);
|
||||
});
|
||||
if (document.readyState != "loading") setTimeout(checkForGuilds, 100);
|
||||
document.addEventListener("DOMContentLoaded", () => {setTimeout(checkForGuilds, 100);});
|
||||
});
|
||||
};
|
||||
|
||||
Core.prototype.injectExternals = async function() {
|
||||
await Utils.injectJs("https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js");
|
||||
await DOM.addScript("ace-script", "https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js");
|
||||
if (window.require.original) window.require = window.require.original;
|
||||
};
|
||||
|
||||
|
@ -143,7 +131,6 @@ Core.prototype.initSettings = function () {
|
|||
}
|
||||
else {
|
||||
settingsPanel.loadSettings();
|
||||
$("<style id=\"customcss\">").text(atob(DataStore.getBDData("bdcustomcss"))).appendTo(document.head);
|
||||
for (const setting in defaultCookie) {
|
||||
if (settingsCookie[setting] == undefined) {
|
||||
settingsCookie[setting] = defaultCookie[setting];
|
||||
|
|
|
@ -1,89 +1,104 @@
|
|||
import {settingsCookie} from "../0globals";
|
||||
import BDV2 from "./v2";
|
||||
import DOM from "./domtools";
|
||||
|
||||
function devMode() {}
|
||||
export default new class DevMode {
|
||||
constructor() {
|
||||
this.debugListener = this.debugListener.bind(this);
|
||||
this.copySelectorListener = this.copySelectorListener.bind(this);
|
||||
}
|
||||
|
||||
devMode.prototype.enable = function(selectorMode) {
|
||||
const self = this;
|
||||
this.disable();
|
||||
$(document).on("keydown.bdDevmode", function(e) {
|
||||
if (e.which === 119 || e.which == 118) {//F8
|
||||
start() {
|
||||
this.startDebugListener();
|
||||
if (settingsCookie["fork-dm-1"]) this.startCopySelector();
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.stopDebugListener();
|
||||
this.stopCopySelector();
|
||||
}
|
||||
|
||||
startDebugListener() {
|
||||
this.stopDebugListener();
|
||||
document.addEventListener("keydown", this.debugListener);
|
||||
}
|
||||
|
||||
stopDebugListener() {
|
||||
document.removeEventListener("keydown", this.debugListener);
|
||||
}
|
||||
|
||||
startCopySelector() {
|
||||
this.stopCopySelector();
|
||||
document.addEventListener("contextmenu", this.copySelectorListener);
|
||||
}
|
||||
|
||||
stopCopySelector() {
|
||||
document.removeEventListener("contextmenu", this.copySelectorListener);
|
||||
}
|
||||
|
||||
debugListener(e) {
|
||||
if (e.which === 119 || e.which == 118) {//F8
|
||||
console.log("%c[%cDevMode%c] %cBreak/Resume", "color: red;", "color: #303030; font-weight:700;", "color:red;", "");
|
||||
debugger; // eslint-disable-line no-debugger
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!selectorMode) return;
|
||||
$(document).on("contextmenu.bdDevmode", function(e) {
|
||||
self.lastSelector = self.getSelector(e.toElement);
|
||||
|
||||
function attach() {
|
||||
let cm = $(".contextMenu-HLZMGh");
|
||||
if (cm.length <= 0) {
|
||||
cm = $("<div class=\"contextMenu-HLZMGh bd-context-menu\"></div>");
|
||||
cm.addClass($(".app, .app-2rEoOp").hasClass("theme-dark") ? "theme-dark" : "theme-light");
|
||||
cm.appendTo(".app, .app-2rEoOp");
|
||||
cm.css("top", e.clientY);
|
||||
cm.css("left", e.clientX);
|
||||
$(document).on("click.bdDevModeCtx", () => {
|
||||
cm.remove();
|
||||
$(document).off(".bdDevModeCtx");
|
||||
});
|
||||
$(document).on("contextmenu.bdDevModeCtx", () => {
|
||||
cm.remove();
|
||||
$(document).off(".bdDevModeCtx");
|
||||
});
|
||||
$(document).on("keyup.bdDevModeCtx", (e) => {
|
||||
if (e.keyCode === 27) {
|
||||
cm.remove();
|
||||
$(document).off(".bdDevModeCtx");
|
||||
}
|
||||
});
|
||||
copySelectorListener(e) {
|
||||
e.stopPropagation();
|
||||
const selector = this.getSelector(e.target);
|
||||
function attach() {
|
||||
let cm = DOM.query(".contextMenu-HLZMGh");
|
||||
if (!cm) {
|
||||
const container = DOM.query("#app-mount");
|
||||
const cmWrap = DOM.createElement(`<div class="layer-v9HyYc da-layer">`);
|
||||
cm = DOM.createElement(`<div class="contextMenu-HLZMGh da-contextMenu bd-context-menu"></div>`);
|
||||
cmWrap.append(cm);
|
||||
container.append(cmWrap);
|
||||
cmWrap.style.top = e.clientY + "px";
|
||||
cmWrap.style.left = e.clientX + "px";
|
||||
cmWrap.style.zIndex = "1002";
|
||||
const removeCM = function(e) {
|
||||
if (e.keyCode && e.keyCode !== 27) return;
|
||||
cmWrap.remove();
|
||||
document.removeEventListener("click", removeCM);
|
||||
document.removeEventListener("contextmenu", removeCM);
|
||||
document.removeEventListener("keyup", removeCM);
|
||||
};
|
||||
document.addEventListener("click", removeCM);
|
||||
document.addEventListener("contextmenu", removeCM);
|
||||
document.addEventListener("keyup", removeCM);
|
||||
}
|
||||
|
||||
const cmo = $("<div/>", {
|
||||
"class": "itemGroup-1tL0uz"
|
||||
const cmg = DOM.createElement(`<div class="itemGroup-1tL0uz da-itemGroup">`);
|
||||
const cmi = DOM.createElement(`<div class="item-1Yvehc itemBase-tz5SeC da-item da-itemBase clickable-11uBi- da-clickable">`);
|
||||
cmi.append(DOM.createElement(`<div class="label-JWQiNe da-label">Copy Selector</div>`));
|
||||
cmi.addEventListener("click", () => {
|
||||
BDV2.NativeModule.copy(selector);
|
||||
cm.style.display = "none";
|
||||
});
|
||||
const cmi = $("<div/>", {
|
||||
"class": "item-1Yvehc",
|
||||
"click": function() {
|
||||
BDV2.NativeModule.copy(self.lastSelector);
|
||||
cm.hide();
|
||||
}
|
||||
}).append($("<span/>", {text: "Copy Selector"}));
|
||||
cmo.append(cmi);
|
||||
cm.append(cmo);
|
||||
if (cm.hasClass("undefined")) cm.css("top", "-=" + cmo.outerHeight());
|
||||
}
|
||||
cmg.append(cmi);
|
||||
cm.append(cmg);
|
||||
}
|
||||
|
||||
setImmediate(attach);
|
||||
setImmediate(attach);
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
});
|
||||
};
|
||||
getSelector(element) {
|
||||
if (element.id) return `#${element.id}`;
|
||||
const rules = this.getRules(element);
|
||||
const latestRule = rules[rules.length - 1];
|
||||
if (latestRule) return latestRule.selectorText;
|
||||
else if (element.classList.length) return `.${Array.from(element.classList).join(".")}`;
|
||||
return `.${Array.from(element.parentElement.classList).join(".")}`;
|
||||
}
|
||||
|
||||
devMode.prototype.getRules = function(element, css = element.ownerDocument.styleSheets) {
|
||||
//if (window.getMatchedCSSRules) return window.getMatchedCSSRules(element);
|
||||
const sheets = [...css].filter(s => !s.href || !s.href.includes("BetterDiscordApp"));
|
||||
const rules = sheets.map(s => [...(s.cssRules || [])]).flat();
|
||||
const elementRules = rules.filter(r => r && r.selectorText && element.matches(r.selectorText) && r.style.length && r.selectorText.split(", ").length < 8 && !r.selectorText.split(", ").includes("*"));
|
||||
return elementRules;
|
||||
};
|
||||
|
||||
devMode.prototype.getSelector = function(element) {
|
||||
if (element.id) return `#${element.id}`;
|
||||
const rules = this.getRules(element);
|
||||
const latestRule = rules[rules.length - 1];
|
||||
if (latestRule) return latestRule.selectorText;
|
||||
else if (element.classList.length) return `.${Array.from(element.classList).join(".")}`;
|
||||
return `.${Array.from(element.parentElement.classList).join(".")}`;
|
||||
};
|
||||
|
||||
devMode.prototype.disable = function() {
|
||||
$(document).off("keydown.bdDevmode");
|
||||
$(document).off("contextmenu.bdDevmode");
|
||||
$(document).off("contextmenu.bdDevModeCtx");
|
||||
};
|
||||
|
||||
export default new devMode();
|
||||
getRules(element, css = element.ownerDocument.styleSheets) {
|
||||
//if (window.getMatchedCSSRules) return window.getMatchedCSSRules(element);
|
||||
const sheets = [...css].filter(s => !s.href || !s.href.includes("BetterDiscordApp"));
|
||||
const rules = sheets.map(s => [...(s.cssRules || [])]).flat();
|
||||
const elementRules = rules.filter(r => r && r.selectorText && element.matches(r.selectorText) && r.style.length && r.selectorText.split(", ").length < 8 && !r.selectorText.split(", ").includes("*"));
|
||||
return elementRules;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,753 @@
|
|||
/**
|
||||
* Copyright 2018 Zachary Rauen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* From: https://github.com/rauenzi/BDPluginLibrary
|
||||
*/
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @name Offset
|
||||
* @property {number} top - Top offset of the target element.
|
||||
* @property {number} right - Right offset of the target element.
|
||||
* @property {number} bottom - Bottom offset of the target element.
|
||||
* @property {number} left - Left offset of the target element.
|
||||
* @property {number} height - Outer height of the target element.
|
||||
* @property {number} width - Outer width of the target element.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function that automatically removes added listener.
|
||||
* @callback module:DOMTools~CancelListener
|
||||
*/
|
||||
|
||||
export default class DOMTools {
|
||||
|
||||
static escapeID(id) {
|
||||
return id.replace(/^[^a-z]+|[^\w-]+/gi, "-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a style to the document.
|
||||
* @param {string} id - identifier to use as the element id
|
||||
* @param {string} css - css to add to the document
|
||||
*/
|
||||
static addStyle(id, css) {
|
||||
document.head.append(DOMTools.createElement(`<style id="${id}">${css}</style>`));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a style from the document.
|
||||
* @param {string} id - original identifier used
|
||||
*/
|
||||
static removeStyle(id) {
|
||||
const element = document.getElementById(id);
|
||||
if (element) element.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds/requires a remote script to be loaded
|
||||
* @param {string} id - identifier to use for this script
|
||||
* @param {string} url - url from which to load the script
|
||||
* @returns {Promise} promise that resolves when the script is loaded
|
||||
*/
|
||||
static addScript(id, url) {
|
||||
return new Promise(resolve => {
|
||||
const script = document.createElement("script");
|
||||
script.id = id;
|
||||
script.src = url;
|
||||
script.type = "text/javascript";
|
||||
script.onload = resolve;
|
||||
document.head.append(script);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a remote script from the document.
|
||||
* @param {string} id - original identifier used
|
||||
*/
|
||||
static removeScript(id) {
|
||||
id = this.escapeID(id);
|
||||
const element = document.getElementById(id);
|
||||
if (element) element.remove();
|
||||
}
|
||||
|
||||
// https://javascript.info/js-animation
|
||||
static animate({timing = _ => _, update, duration}) {
|
||||
const start = performance.now();
|
||||
|
||||
requestAnimationFrame(function animate(time) {
|
||||
// timeFraction goes from 0 to 1
|
||||
let timeFraction = (time - start) / duration;
|
||||
if (timeFraction > 1) timeFraction = 1;
|
||||
|
||||
// calculate the current animation state
|
||||
const progress = timing(timeFraction);
|
||||
|
||||
update(progress); // draw it
|
||||
|
||||
if (timeFraction < 1) {
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This is my shit version of not having to use `$` from jQuery. Meaning
|
||||
* that you can pass a selector and it will automatically run {@link module:DOMTools.query}.
|
||||
* It also means that you can pass a string of html and it will perform and return `parseHTML`.
|
||||
* @see module:DOMTools.parseHTML
|
||||
* @see module:DOMTools.query
|
||||
* @param {string} selector - Selector to query or HTML to parse
|
||||
* @returns {(DocumentFragment|NodeList|HTMLElement)} - Either the result of `parseHTML` or `query`
|
||||
*/
|
||||
static Q(selector) {
|
||||
const element = this.parseHTML(selector);
|
||||
const isHTML = element instanceof NodeList ? Array.from(element).some(n => n.nodeType === 1) : element.nodeType === 1;
|
||||
if (isHTML) return element;
|
||||
return this.query(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Essentially a shorthand for `document.querySelector`. If the `baseElement` is not provided
|
||||
* `document` is used by default.
|
||||
* @param {string} selector - Selector to query
|
||||
* @param {Element} [baseElement] - Element to base the query from
|
||||
* @returns {(Element|null)} - The found element or null if not found
|
||||
*/
|
||||
static query(selector, baseElement) {
|
||||
if (!baseElement) baseElement = document;
|
||||
return baseElement.querySelector(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Essentially a shorthand for `document.querySelectorAll`. If the `baseElement` is not provided
|
||||
* `document` is used by default.
|
||||
* @param {string} selector - Selector to query
|
||||
* @param {Element} [baseElement] - Element to base the query from
|
||||
* @returns {Array<Element>} - Array of all found elements
|
||||
*/
|
||||
static queryAll(selector, baseElement) {
|
||||
if (!baseElement) baseElement = document;
|
||||
return baseElement.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string of HTML and returns the results. If the second parameter is true,
|
||||
* the parsed HTML will be returned as a document fragment {@see https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment}.
|
||||
* This is extremely useful if you have a list of elements at the top level, they can then be appended all at once to another node.
|
||||
*
|
||||
* If the second parameter is false, then the return value will be the list of parsed
|
||||
* nodes and there were multiple top level nodes, otherwise the single node is returned.
|
||||
* @param {string} html - HTML to be parsed
|
||||
* @param {boolean} [fragment=false] - Whether or not the return should be the raw `DocumentFragment`
|
||||
* @returns {(DocumentFragment|NodeList|HTMLElement)} - The result of HTML parsing
|
||||
*/
|
||||
static parseHTML(html, fragment = false) {
|
||||
const template = document.createElement("template");
|
||||
template.innerHTML = html;
|
||||
const node = template.content.cloneNode(true);
|
||||
if (fragment) return node;
|
||||
return node.childNodes.length > 1 ? node.childNodes : node.childNodes[0];
|
||||
}
|
||||
|
||||
/** Alternate name for {@link module:DOMTools.parseHTML} */
|
||||
static createElement(html, fragment = false) {return this.parseHTML(html, fragment);}
|
||||
|
||||
/**
|
||||
* Takes a string of html and escapes it using the brower's own escaping mechanism.
|
||||
* @param {String} html - html to be escaped
|
||||
*/
|
||||
static escapeHTML(html) {
|
||||
const textNode = document.createTextNode("");
|
||||
const spanElement = document.createElement("span");
|
||||
spanElement.append(textNode);
|
||||
textNode.nodeValue = html;
|
||||
return spanElement.innerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list of classes from the target element.
|
||||
* @param {Element} element - Element to edit classes of
|
||||
* @param {...string} classes - Names of classes to add
|
||||
* @returns {Element} - `element` to allow for chaining
|
||||
*/
|
||||
static addClass(element, ...classes) {
|
||||
classes = classes.flat().filter(c => c);
|
||||
for (let c = 0; c < classes.length; c++) classes[c] = classes[c].toString().split(" ");
|
||||
classes = classes.flat().filter(c => c);
|
||||
element.classList.add(...classes);
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a list of classes from the target element.
|
||||
* @param {Element} element - Element to edit classes of
|
||||
* @param {...string} classes - Names of classes to remove
|
||||
* @returns {Element} - `element` to allow for chaining
|
||||
*/
|
||||
static removeClass(element, ...classes) {
|
||||
for (let c = 0; c < classes.length; c++) classes[c] = classes[c].toString().split(" ");
|
||||
classes = classes.flat().filter(c => c);
|
||||
element.classList.remove(...classes);
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* When only one argument is present: Toggle class value;
|
||||
* i.e., if class exists then remove it and return false, if not, then add it and return true.
|
||||
* When a second argument is present:
|
||||
* If the second argument evaluates to true, add specified class value, and if it evaluates to false, remove it.
|
||||
* @param {Element} element - Element to edit classes of
|
||||
* @param {string} classname - Name of class to toggle
|
||||
* @param {boolean} [indicator] - Optional indicator for if the class should be toggled
|
||||
* @returns {Element} - `element` to allow for chaining
|
||||
*/
|
||||
static toggleClass(element, classname, indicator) {
|
||||
classname = classname.toString().split(" ").filter(c => c);
|
||||
if (typeof(indicator) !== "undefined") classname.forEach(c => element.classList.toggle(c, indicator));
|
||||
else classname.forEach(c => element.classList.toggle(c));
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an element has a specific class
|
||||
* @param {Element} element - Element to edit classes of
|
||||
* @param {string} classname - Name of class to check
|
||||
* @returns {boolean} - `true` if the element has the class, `false` otherwise.
|
||||
*/
|
||||
static hasClass(element, classname) {
|
||||
return classname.toString().split(" ").filter(c => c).every(c => element.classList.contains(c));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces one class with another
|
||||
* @param {Element} element - Element to edit classes of
|
||||
* @param {string} oldName - Name of class to replace
|
||||
* @param {string} newName - New name for the class
|
||||
* @returns {Element} - `element` to allow for chaining
|
||||
*/
|
||||
static replaceClass(element, oldName, newName) {
|
||||
element.classList.replace(oldName, newName);
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends `thisNode` to `thatNode`
|
||||
* @param {Node} thisNode - Node to be appended to another node
|
||||
* @param {Node} thatNode - Node for `thisNode` to be appended to
|
||||
* @returns {Node} - `thisNode` to allow for chaining
|
||||
*/
|
||||
static appendTo(thisNode, thatNode) {
|
||||
if (typeof(thatNode) == "string") thatNode = this.query(thatNode);
|
||||
if (!thatNode) return null;
|
||||
thatNode.append(thisNode);
|
||||
return thisNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends `thisNode` to `thatNode`
|
||||
* @param {Node} thisNode - Node to be prepended to another node
|
||||
* @param {Node} thatNode - Node for `thisNode` to be prepended to
|
||||
* @returns {Node} - `thisNode` to allow for chaining
|
||||
*/
|
||||
static prependTo(thisNode, thatNode) {
|
||||
if (typeof(thatNode) == "string") thatNode = this.query(thatNode);
|
||||
if (!thatNode) return null;
|
||||
thatNode.prepend(thisNode);
|
||||
return thisNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert after a specific element, similar to jQuery's `thisElement.insertAfter(otherElement)`.
|
||||
* @param {Node} thisNode - The node to insert
|
||||
* @param {Node} targetNode - Node to insert after in the tree
|
||||
* @returns {Node} - `thisNode` to allow for chaining
|
||||
*/
|
||||
static insertAfter(thisNode, targetNode) {
|
||||
targetNode.parentNode.insertBefore(thisNode, targetNode.nextSibling);
|
||||
return thisNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert after a specific element, similar to jQuery's `thisElement.after(newElement)`.
|
||||
* @param {Node} thisNode - The node to insert
|
||||
* @param {Node} newNode - Node to insert after in the tree
|
||||
* @returns {Node} - `thisNode` to allow for chaining
|
||||
*/
|
||||
static after(thisNode, newNode) {
|
||||
thisNode.parentNode.insertBefore(newNode, thisNode.nextSibling);
|
||||
return thisNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next sibling element that matches the selector.
|
||||
* @param {Element} element - Element to get the next sibling of
|
||||
* @param {string} [selector=""] - Optional selector
|
||||
* @returns {Element} - The sibling element
|
||||
*/
|
||||
static next(element, selector = "") {
|
||||
return selector ? element.querySelector("+ " + selector) : element.nextElementSibling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all subsequent siblings.
|
||||
* @param {Element} element - Element to get next siblings of
|
||||
* @returns {NodeList} - The list of siblings
|
||||
*/
|
||||
static nextAll(element) {
|
||||
return element.querySelectorAll("~ *");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subsequent siblings until an element matches the selector.
|
||||
* @param {Element} element - Element to get the following siblings of
|
||||
* @param {string} selector - Selector to stop at
|
||||
* @returns {Array<Element>} - The list of siblings
|
||||
*/
|
||||
static nextUntil(element, selector) {
|
||||
const next = [];
|
||||
while (element.nextElementSibling && !element.nextElementSibling.matches(selector)) next.push(element = element.nextElementSibling);
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous sibling element that matches the selector.
|
||||
* @param {Element} element - Element to get the previous sibling of
|
||||
* @param {string} [selector=""] - Optional selector
|
||||
* @returns {Element} - The sibling element
|
||||
*/
|
||||
static previous(element, selector = "") {
|
||||
const previous = element.previousElementSibling;
|
||||
if (selector) return previous && previous.matches(selector) ? previous : null;
|
||||
return previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all preceeding siblings.
|
||||
* @param {Element} element - Element to get preceeding siblings of
|
||||
* @returns {NodeList} - The list of siblings
|
||||
*/
|
||||
static previousAll(element) {
|
||||
const previous = [];
|
||||
while (element.previousElementSibling) previous.push(element = element.previousElementSibling);
|
||||
return previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the preceeding siblings until an element matches the selector.
|
||||
* @param {Element} element - Element to get the preceeding siblings of
|
||||
* @param {string} selector - Selector to stop at
|
||||
* @returns {Array<Element>} - The list of siblings
|
||||
*/
|
||||
static previousUntil(element, selector) {
|
||||
const previous = [];
|
||||
while (element.previousElementSibling && !element.previousElementSibling.matches(selector)) previous.push(element = element.previousElementSibling);
|
||||
return previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find which index in children a certain node is. Similar to jQuery's `$.index()`
|
||||
* @param {HTMLElement} node - The node to find its index in parent
|
||||
* @returns {number} Index of the node
|
||||
*/
|
||||
static indexInParent(node) {
|
||||
const children = node.parentNode.childNodes;
|
||||
let num = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (children[i] == node) return num;
|
||||
if (children[i].nodeType == 1) num++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Shorthand for {@link module:DOMTools.indexInParent} */
|
||||
static index(node) {return this.indexInParent(node);}
|
||||
|
||||
/**
|
||||
* Gets the parent of the element if it matches the selector,
|
||||
* otherwise returns null.
|
||||
* @param {Element} element - Element to get parent of
|
||||
* @param {string} [selector=""] - Selector to match parent
|
||||
* @returns {(Element|null)} - The sibling element or null
|
||||
*/
|
||||
static parent(element, selector = "") {
|
||||
return !selector || element.parentElement.matches(selector) ? element.parentElement : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all children of Element that match the selector if provided.
|
||||
* @param {Element} element - Element to get all children of
|
||||
* @param {string} selector - Selector to match the children to
|
||||
* @returns {Array<Element>} - The list of children
|
||||
*/
|
||||
static findChild(element, selector) {
|
||||
return element.querySelector(":scope > " + selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all children of Element that match the selector if provided.
|
||||
* @param {Element} element - Element to get all children of
|
||||
* @param {string} selector - Selector to match the children to
|
||||
* @returns {Array<Element>} - The list of children
|
||||
*/
|
||||
static findChildren(element, selector) {
|
||||
return element.querySelectorAll(":scope > " + selector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all ancestors of Element that match the selector if provided.
|
||||
* @param {Element} element - Element to get all parents of
|
||||
* @param {string} [selector=""] - Selector to match the parents to
|
||||
* @returns {Array<Element>} - The list of parents
|
||||
*/
|
||||
static parents(element, selector = "") {
|
||||
const parents = [];
|
||||
if (selector) while (element.parentElement && element.parentElement.closest(selector)) parents.push(element = element.parentElement.closest(selector));
|
||||
else while (element.parentElement) parents.push(element = element.parentElement);
|
||||
return parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ancestors until an element matches the selector.
|
||||
* @param {Element} element - Element to get the ancestors of
|
||||
* @param {string} selector - Selector to stop at
|
||||
* @returns {Array<Element>} - The list of parents
|
||||
*/
|
||||
static parentsUntil(element, selector) {
|
||||
const parents = [];
|
||||
while (element.parentElement && !element.parentElement.matches(selector)) parents.push(element = element.parentElement);
|
||||
return parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all siblings of the element that match the selector.
|
||||
* @param {Element} element - Element to get all siblings of
|
||||
* @param {string} [selector="*"] - Selector to match the siblings to
|
||||
* @returns {Array<Element>} - The list of siblings
|
||||
*/
|
||||
static siblings(element, selector = "*") {
|
||||
return Array.from(element.parentElement.children).filter(e => e != element && e.matches(selector));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or gets css styles for a specific element. If `value` is provided
|
||||
* then it sets the style and returns the element to allow for chaining,
|
||||
* otherwise returns the style.
|
||||
* @param {Element} element - Element to set the CSS of
|
||||
* @param {string} attribute - Attribute to get or set
|
||||
* @param {string} [value] - Value to set for attribute
|
||||
* @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned.
|
||||
*/
|
||||
static css(element, attribute, value) {
|
||||
if (typeof(value) == "undefined") return global.getComputedStyle(element)[attribute];
|
||||
element.style[attribute] = value;
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or gets the width for a specific element. If `value` is provided
|
||||
* then it sets the width and returns the element to allow for chaining,
|
||||
* otherwise returns the width.
|
||||
* @param {Element} element - Element to set the CSS of
|
||||
* @param {string} [value] - Width to set
|
||||
* @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned.
|
||||
*/
|
||||
static width(element, value) {
|
||||
if (typeof(value) == "undefined") return parseInt(getComputedStyle(element).width);
|
||||
element.style.width = value;
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or gets the height for a specific element. If `value` is provided
|
||||
* then it sets the height and returns the element to allow for chaining,
|
||||
* otherwise returns the height.
|
||||
* @param {Element} element - Element to set the CSS of
|
||||
* @param {string} [value] - Height to set
|
||||
* @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned.
|
||||
*/
|
||||
static height(element, value) {
|
||||
if (typeof(value) == "undefined") return parseInt(getComputedStyle(element).height);
|
||||
element.style.height = value;
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the inner text of an element if given a value, otherwise returns it.
|
||||
* @param {Element} element - Element to set the text of
|
||||
* @param {string} [text] - Content to set
|
||||
* @returns {string} - Either the string set by this call or the current text content of the node.
|
||||
*/
|
||||
static text(element, text) {
|
||||
if (typeof(text) == "undefined") return element.textContent;
|
||||
return element.textContent = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the innerWidth of the element.
|
||||
* @param {Element} element - Element to retrieve inner width of
|
||||
* @return {number} - The inner width of the element.
|
||||
*/
|
||||
static innerWidth(element) {
|
||||
return element.clientWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the innerHeight of the element.
|
||||
* @param {Element} element - Element to retrieve inner height of
|
||||
* @return {number} - The inner height of the element.
|
||||
*/
|
||||
static innerHeight(element) {
|
||||
return element.clientHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the outerWidth of the element.
|
||||
* @param {Element} element - Element to retrieve outer width of
|
||||
* @return {number} - The outer width of the element.
|
||||
*/
|
||||
static outerWidth(element) {
|
||||
return element.offsetWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the outerHeight of the element.
|
||||
* @param {Element} element - Element to retrieve outer height of
|
||||
* @return {number} - The outer height of the element.
|
||||
*/
|
||||
static outerHeight(element) {
|
||||
return element.offsetHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset of the element in the page.
|
||||
* @param {Element} element - Element to get offset of
|
||||
* @return {Offset} - The offset of the element
|
||||
*/
|
||||
static offset(element) {
|
||||
return element.getBoundingClientRect();
|
||||
}
|
||||
|
||||
static get listeners() { return this._listeners || (this._listeners = {}); }
|
||||
|
||||
/**
|
||||
* This is similar to jQuery's `on` function and can *hopefully* be used in the same way.
|
||||
*
|
||||
* Rather than attempt to explain, I'll show some example usages.
|
||||
*
|
||||
* The following will add a click listener (in the `myPlugin` namespace) to `element`.
|
||||
* `DOMTools.on(element, "click.myPlugin", () => {console.log("clicked!");});`
|
||||
*
|
||||
* The following will add a click listener (in the `myPlugin` namespace) to `element` that only fires when the target is a `.block` element.
|
||||
* `DOMTools.on(element, "click.myPlugin", ".block", () => {console.log("clicked!");});`
|
||||
*
|
||||
* The following will add a click listener (without namespace) to `element`.
|
||||
* `DOMTools.on(element, "click", () => {console.log("clicked!");});`
|
||||
*
|
||||
* The following will add a click listener (without namespace) to `element` that only fires once.
|
||||
* `const cancel = DOMTools.on(element, "click", () => {console.log("fired!"); cancel();});`
|
||||
*
|
||||
* @param {Element} element - Element to add listener to
|
||||
* @param {string} event - Event to listen to with option namespace (e.g. "event.namespace")
|
||||
* @param {(string|callable)} delegate - Selector to run on element to listen to
|
||||
* @param {callable} [callback] - Function to fire on event
|
||||
* @returns {module:DOMTools~CancelListener} - A function that will undo the listener
|
||||
*/
|
||||
static on(element, event, delegate, callback) {
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
element.addEventListener(type, eventFunc);
|
||||
const cancel = () => {
|
||||
element.removeEventListener(type, eventFunc);
|
||||
};
|
||||
if (namespace) {
|
||||
if (!this.listeners[namespace]) this.listeners[namespace] = [];
|
||||
const newCancel = () => {
|
||||
cancel();
|
||||
this.listeners[namespace].splice(this.listeners[namespace].findIndex(l => l.event == type && l.element == element), 1);
|
||||
};
|
||||
this.listeners[namespace].push({
|
||||
event: type,
|
||||
element: element,
|
||||
cancel: newCancel
|
||||
});
|
||||
return newCancel;
|
||||
}
|
||||
return cancel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Functionality for this method matches {@link module:DOMTools.on} but automatically cancels itself
|
||||
* and removes the listener upon the first firing of the desired event.
|
||||
*
|
||||
* @param {Element} element - Element to add listener to
|
||||
* @param {string} event - Event to listen to with option namespace (e.g. "event.namespace")
|
||||
* @param {(string|callable)} delegate - Selector to run on element to listen to
|
||||
* @param {callable} [callback] - Function to fire on event
|
||||
* @returns {module:DOMTools~CancelListener} - A function that will undo the listener
|
||||
*/
|
||||
static once(element, event, delegate, callback) {
|
||||
const [type, namespace] = event.split(".");
|
||||
const hasDelegate = delegate && callback;
|
||||
if (!callback) callback = delegate;
|
||||
const eventFunc = !hasDelegate ? function(event) {
|
||||
callback(event);
|
||||
element.removeEventListener(type, eventFunc);
|
||||
} : function(event) {
|
||||
if (!event.target.matches(delegate)) return;
|
||||
callback(event);
|
||||
element.removeEventListener(type, eventFunc);
|
||||
};
|
||||
|
||||
element.addEventListener(type, eventFunc);
|
||||
const cancel = () => {
|
||||
element.removeEventListener(type, eventFunc);
|
||||
};
|
||||
if (namespace) {
|
||||
if (!this.listeners[namespace]) this.listeners[namespace] = [];
|
||||
const newCancel = () => {
|
||||
cancel();
|
||||
this.listeners[namespace].splice(this.listeners[namespace].findIndex(l => l.event == type && l.element == element), 1);
|
||||
};
|
||||
this.listeners[namespace].push({
|
||||
event: type,
|
||||
element: element,
|
||||
cancel: newCancel
|
||||
});
|
||||
return newCancel;
|
||||
}
|
||||
return cancel;
|
||||
}
|
||||
|
||||
static __offAll(event, element) {
|
||||
const [type, namespace] = event.split(".");
|
||||
let matchFilter = listener => listener.event == type, defaultFilter = _ => _;
|
||||
if (element) matchFilter = l => l.event == type && l.element == element, defaultFilter = l => l.element == element;
|
||||
const listeners = this.listeners[namespace] || [];
|
||||
const list = type ? listeners.filter(matchFilter) : listeners.filter(defaultFilter);
|
||||
for (let c = 0; c < list.length; c++) list[c].cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is similar to jQuery's `off` function and can *hopefully* be used in the same way.
|
||||
*
|
||||
* Rather than attempt to explain, I'll show some example usages.
|
||||
*
|
||||
* The following will remove a click listener called `onClick` (in the `myPlugin` namespace) from `element`.
|
||||
* `DOMTools.off(element, "click.myPlugin", onClick);`
|
||||
*
|
||||
* The following will remove a click listener called `onClick` (in the `myPlugin` namespace) from `element` that only fired when the target is a `.block` element.
|
||||
* `DOMTools.off(element, "click.myPlugin", ".block", onClick);`
|
||||
*
|
||||
* The following will remove a click listener (without namespace) from `element`.
|
||||
* `DOMTools.off(element, "click", onClick);`
|
||||
*
|
||||
* The following will remove all listeners in namespace `myPlugin` from `element`.
|
||||
* `DOMTools.off(element, ".myPlugin");`
|
||||
*
|
||||
* The following will remove all click listeners in namespace `myPlugin` from *all elements*.
|
||||
* `DOMTools.off("click.myPlugin");`
|
||||
*
|
||||
* The following will remove all listeners in namespace `myPlugin` from *all elements*.
|
||||
* `DOMTools.off(".myPlugin");`
|
||||
*
|
||||
* @param {(Element|string)} element - Element to remove listener from
|
||||
* @param {string} [event] - Event to listen to with option namespace (e.g. "event.namespace")
|
||||
* @param {(string|callable)} [delegate] - Selector to run on element to listen to
|
||||
* @param {callable} [callback] - Function to fire on event
|
||||
* @returns {Element} - The original element to allow for chaining
|
||||
*/
|
||||
static off(element, event, delegate, callback) {
|
||||
if (typeof(element) == "string") return this.__offAll(element);
|
||||
const [type, namespace] = event.split(".");
|
||||
if (namespace) return this.__offAll(event, element);
|
||||
|
||||
const hasDelegate = delegate && callback;
|
||||
if (!callback) callback = delegate;
|
||||
const eventFunc = !hasDelegate ? callback : function(event) {
|
||||
if (event.target.matches(delegate)) {
|
||||
callback(event);
|
||||
}
|
||||
};
|
||||
|
||||
element.removeEventListener(type, eventFunc);
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener for when the node is added/removed from the document body.
|
||||
* The listener is automatically removed upon firing.
|
||||
* @param {HTMLElement} node - node to wait for
|
||||
* @param {callable} callback - function to be performed on event
|
||||
* @param {boolean} onMount - determines if it should fire on Mount or on Unmount
|
||||
*/
|
||||
static onMountChange(node, callback, onMount = true) {
|
||||
const wrappedCallback = () => {
|
||||
this.observer.unsubscribe(wrappedCallback);
|
||||
callback();
|
||||
};
|
||||
this.observer.subscribe(wrappedCallback, mutation => {
|
||||
const nodes = Array.from(onMount ? mutation.addedNodes : mutation.removedNodes);
|
||||
const directMatch = nodes.indexOf(node) > -1;
|
||||
const parentMatch = nodes.some(parent => parent.contains(node));
|
||||
return directMatch || parentMatch;
|
||||
});
|
||||
return node;
|
||||
}
|
||||
|
||||
/** Shorthand for {@link module:DOMTools.onMountChange} with third parameter `true` */
|
||||
static onMount(node, callback) { return this.onMountChange(node, callback); }
|
||||
|
||||
/** Shorthand for {@link module:DOMTools.onMountChange} with third parameter `false` */
|
||||
static onUnmount(node, callback) { return this.onMountChange(node, callback, false); }
|
||||
|
||||
/** Alias for {@link module:DOMTools.onMount} */
|
||||
static onAdded(node, callback) { return this.onMount(node, callback); }
|
||||
|
||||
/** Alias for {@link module:DOMTools.onUnmount} */
|
||||
static onRemoved(node, callback) { return this.onUnmount(node, callback, false); }
|
||||
|
||||
/**
|
||||
* Helper function which combines multiple elements into one parent element
|
||||
* @param {Array<HTMLElement>} elements - array of elements to put into a single parent
|
||||
*/
|
||||
static wrap(elements) {
|
||||
const domWrapper = this.parseHTML(`<div class="dom-wrapper"></div>`);
|
||||
for (let e = 0; e < elements.length; e++) domWrapper.appendChild(elements[e]);
|
||||
return domWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the node to an HTMLElement. This is mainly used by library modules.
|
||||
* @param {(jQuery|Element)} node - node to resolve
|
||||
*/
|
||||
static resolveElement(node) {
|
||||
if (!(node instanceof jQuery) && !(node instanceof Element)) return undefined;
|
||||
return node instanceof jQuery ? node[0] : node;
|
||||
}
|
||||
}
|
|
@ -122,7 +122,6 @@ EmoteModule.prototype.init = async function () {
|
|||
};
|
||||
|
||||
EmoteModule.prototype.disable = function() {
|
||||
this.disableAutoCapitalize();
|
||||
if (this.cancelEmoteRender) return;
|
||||
this.cancelEmoteRender();
|
||||
this.cancelEmoteRender = null;
|
||||
|
@ -247,42 +246,11 @@ EmoteModule.prototype.downloadEmotes = function(emoteMeta) {
|
|||
|
||||
EmoteModule.prototype.getBlacklist = function () {
|
||||
return new Promise(resolve => {
|
||||
$.getJSON(`https://rauenzi.github.io/BetterDiscordApp/data/emotefilter.json`, function (data) {
|
||||
resolve(bemotes.concat(data.blacklist));
|
||||
require("request").get({url: "https://rauenzi.github.io/BetterDiscordApp/data/emotefilter.json", json: true}, function (err, resp, data) {
|
||||
if (err) return resolve(bemotes);
|
||||
resolve(bemotes.splice(0, 0, ...data.blacklist));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
EmoteModule.prototype.autoCapitalize = function () {
|
||||
if (!settingsCookie["bda-es-4"] || this.autoCapitalizeActive) return;
|
||||
$("body").on("keyup.bdac change.bdac paste.bdac", $(".channelTextArea-rNsIhG textarea:first"), () => {
|
||||
const text = $(".channelTextArea-rNsIhG 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) {
|
||||
Utils.insertText(Utils.getTextArea()[0], text.replace(lastWord, ret));
|
||||
}
|
||||
}
|
||||
});
|
||||
this.autoCapitalizeActive = true;
|
||||
};
|
||||
|
||||
EmoteModule.prototype.capitalize = function (value) {
|
||||
const res = bdEmotes.TwitchGlobal;
|
||||
for (const p in res) {
|
||||
if (res.hasOwnProperty(p) && value == (p + "").toLowerCase()) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EmoteModule.prototype.disableAutoCapitalize = function() {
|
||||
this.autoCapitalizeActive = false;
|
||||
$("body").off(".bdac");
|
||||
};
|
||||
|
||||
export default new EmoteModule();
|
|
@ -5,12 +5,15 @@ import BDEvents from "./bdEvents";
|
|||
import Utils from "./utils";
|
||||
|
||||
function PluginModule() {
|
||||
|
||||
this.getString = function(value) {
|
||||
if (!value) return "???";
|
||||
return typeof value == "string" ? value : value.toString();
|
||||
};
|
||||
}
|
||||
|
||||
PluginModule.prototype.loadPlugins = function () {
|
||||
this.loadPluginData();
|
||||
bdpluginErrors.concat(ContentManager.loadPlugins());
|
||||
bdpluginErrors.splice(0, 0, ...ContentManager.loadPlugins());
|
||||
const plugins = Object.keys(bdplugins);
|
||||
for (let i = 0; i < plugins.length; i++) {
|
||||
let plugin, name;
|
||||
|
@ -19,6 +22,11 @@ PluginModule.prototype.loadPlugins = function () {
|
|||
plugin = bdplugins[plugins[i]].plugin;
|
||||
name = plugin.getName();
|
||||
if (plugin.load && typeof(plugin.load) == "function") plugin.load();
|
||||
const meta = bdplugins[plugins[i]];
|
||||
meta.name = this.getString(plugin.getName());
|
||||
meta.author = this.getString(plugin.getAuthor());
|
||||
meta.description = this.getString(plugin.getDescription());
|
||||
meta.version = this.getString(plugin.getVersion());
|
||||
}
|
||||
catch (err) {
|
||||
pluginCookie[name] = false;
|
||||
|
|
|
@ -2,9 +2,10 @@ import {settingsCookie} from "../0globals";
|
|||
import BDV2 from "./v2";
|
||||
import webpackModules from "./webpackModules";
|
||||
import Utils from "./utils";
|
||||
import DOM from "./domtools";
|
||||
|
||||
import V2C_PublicServers from "../ui/publicServers";
|
||||
import Layer from "../ui/layer";
|
||||
import V2C_PublicServers from "../ui/publicservers/publicServers";
|
||||
import Layer from "../ui/publicservers/layer";
|
||||
|
||||
export default new class V2_PublicServers {
|
||||
|
||||
|
@ -13,7 +14,7 @@ export default new class V2_PublicServers {
|
|||
}
|
||||
|
||||
get component() {
|
||||
return BDV2.react.createElement(Layer, {rootId: "pubslayerroot", id: "pubslayer", children: BDV2.react.createElement(V2C_PublicServers, {rootId: "pubslayerroot"})});
|
||||
return BDV2.react.createElement(Layer, {rootId: "pubslayerroot", id: "pubslayer"}, BDV2.react.createElement(V2C_PublicServers, {rootId: "pubslayerroot"}));
|
||||
}
|
||||
|
||||
get root() {
|
||||
|
@ -26,15 +27,13 @@ export default new class V2_PublicServers {
|
|||
}
|
||||
|
||||
injectRoot() {
|
||||
if (!$(".layers, .layers-3iHuyZ").length) return false;
|
||||
$(".layers, .layers-3iHuyZ").append($("<div/>", {
|
||||
id: "pubslayerroot"
|
||||
}));
|
||||
const layers = DOM.query(".layers, .layers-3iHuyZ");
|
||||
if (!layers) return false;
|
||||
layers.append(DOM.createElement("<div id='pubslayerroot'>"));
|
||||
return true;
|
||||
}
|
||||
|
||||
render() {
|
||||
// BdApi.alert("Broken", "Sorry but the Public Servers modules is currently broken, I recommend disabling this feature for now.");
|
||||
const root = this.root;
|
||||
if (!root) {
|
||||
console.log("FAILED TO LOCATE ROOT: .layers");
|
||||
|
@ -44,25 +43,19 @@ export default new class V2_PublicServers {
|
|||
}
|
||||
|
||||
get button() {
|
||||
const btn = $("<div/>", {
|
||||
"class": BDV2.guildClasses.listItem,
|
||||
"id": "bd-pub-li",
|
||||
"style": settingsCookie["bda-gs-1"] ? "" : "display: none;"
|
||||
}).append($("<div/>", {
|
||||
"class": "wrapper-25eVIn " + BDV2.guildClasses.circleButtonMask,
|
||||
"text": "public",
|
||||
"id": "bd-pub-button",
|
||||
"click": () => { this.render(); }
|
||||
}));
|
||||
|
||||
const btn = DOM.createElement(`<div id="bd-pub-li" class="${BDV2.guildClasses.listItem}">`);
|
||||
if (!settingsCookie["bda-gs-1"]) btn.style.display = "none";
|
||||
const label = DOM.createElement(`<div id="bd-pub-button" class="${"wrapper-25eVIn " + BDV2.guildClasses.circleButtonMask}">public</div>`);
|
||||
label.addEventListener("click", () => {this.render();});
|
||||
btn.append(label);
|
||||
return btn;
|
||||
}
|
||||
|
||||
_appendButton() {
|
||||
if ($("#bd-pub-li").length) return;
|
||||
if (DOM.query("#bd-pub-li")) return;
|
||||
const wrapper = BDV2.guildClasses.wrapper.split(" ")[0];
|
||||
const guilds = $(`.${wrapper} .scroller-2FKFPG >:first-child`);
|
||||
guilds.after(this.button);
|
||||
const guilds = DOM.query(`.${wrapper} .scroller-2FKFPG >:first-child`);
|
||||
DOM.after(guilds, this.button);
|
||||
}
|
||||
|
||||
addButton() {
|
||||
|
@ -75,6 +68,6 @@ export default new class V2_PublicServers {
|
|||
removeButton() {
|
||||
this.guildPatch();
|
||||
delete this.guildPatch;
|
||||
$("#bd-pub-li").remove();
|
||||
DOM.query("#bd-pub-li").remove();
|
||||
}
|
||||
};
|
|
@ -2,194 +2,154 @@ import {settingsCookie, bdEmotes} from "../0globals";
|
|||
import DataStore from "./dataStore";
|
||||
import BDV2 from "./v2";
|
||||
import Utils from "./utils";
|
||||
import DOM from "./domtools";
|
||||
|
||||
function QuickEmoteMenu() {
|
||||
|
||||
this.switchHandler = this.switchHandler.bind(this);
|
||||
this.favContext = this.favContext.bind(this);
|
||||
}
|
||||
|
||||
const insertEmote = function(e) {
|
||||
const emote = e.target.getAttribute("title");
|
||||
const newTextarea = document.querySelector(`.${BDV2.slateEditorClasses.slateTextArea.split(" ")[0]}`);
|
||||
if (newTextarea) {
|
||||
const instance = BDV2.getInternalInstance(newTextarea);
|
||||
const insert = Utils.getNestedProp(instance, "memoizedProps.children.props.editor.insertText");
|
||||
if (insert) insert(` ${emote} `);
|
||||
}
|
||||
else {
|
||||
const ta = Utils.getTextArea();
|
||||
Utils.insertText(ta, ta.value.slice(-1) == " " ? ta.value + emote : ta.value + " " + emote);
|
||||
}
|
||||
};
|
||||
|
||||
const makeEmote = function(name, url, {click = insertEmote, contextmenu} = {}) {
|
||||
const emote = DOM.createElement(`<div class="emote-container"><img class="emote-icon" alt="${name}" src="${url}" title="${name}"></div>`);
|
||||
if (click) emote.addEventListener("click", click);
|
||||
if (contextmenu) emote.addEventListener("contextmenu", contextmenu);
|
||||
return emote;
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.init = function() {
|
||||
this.initialized = true;
|
||||
$(document).on("mousedown", function(e) {
|
||||
if (e.target.id != "rmenu") $("#rmenu").remove();
|
||||
});
|
||||
this.favoriteEmotes = {};
|
||||
const fe = DataStore.getBDData("bdfavemotes");
|
||||
if (fe !== "" && fe !== null) {
|
||||
this.favoriteEmotes = JSON.parse(atob(fe));
|
||||
}
|
||||
if (fe !== "" && fe !== null) this.favoriteEmotes = JSON.parse(atob(fe));
|
||||
|
||||
let qmeHeader = "";
|
||||
qmeHeader += "<div id=\"bda-qem\">";
|
||||
qmeHeader += " <button class=\"active\" id=\"bda-qem-twitch\" onclick='quickEmoteMenu.switchHandler(this); return false;'>Twitch</button>";
|
||||
qmeHeader += " <button id=\"bda-qem-favourite\" onclick='quickEmoteMenu.switchHandler(this); return false;'>Favourite</button>";
|
||||
qmeHeader += " <button id=\"bda-qem-emojis\" onclick='quickEmoteMenu.switchHandler(this); return false;'>Emojis</buttond>";
|
||||
qmeHeader += "</div>";
|
||||
this.qmeHeader = qmeHeader;
|
||||
this.qmeHeader = DOM.createElement(`<div id="bda-qem">`);
|
||||
this.twitchButton = DOM.createElement(`<button class="active" id="bda-qem-twitch">Twitch</button>`);
|
||||
this.favoriteButton = DOM.createElement(`<button id="bda-qem-favourite">Favorite</button>`);
|
||||
this.emojiButton = DOM.createElement(`<button id="bda-qem-emojis">Emojis</buttond>`);
|
||||
this.twitchButton.addEventListener("click", this.switchHandler);
|
||||
this.favoriteButton.addEventListener("click", this.switchHandler);
|
||||
this.emojiButton.addEventListener("click", this.switchHandler);
|
||||
this.qmeHeader.append(this.twitchButton, this.favoriteButton, this.emojiButton);
|
||||
|
||||
let teContainer = "";
|
||||
teContainer += "<div id=\"bda-qem-twitch-container\">";
|
||||
teContainer += " <div class=\"scroller-wrap scrollerWrap-2lJEkd fade\">";
|
||||
teContainer += " <div class=\"scroller scroller-2FKFPG\">";
|
||||
teContainer += " <div class=\"emote-menu-inner\">";
|
||||
let url = "";
|
||||
|
||||
this.teContainer = DOM.createElement(`<div id="bda-qem-twitch-container"><div class="scroller-wrap scrollerWrap-2lJEkd fade"><div class="scroller scroller-2FKFPG"><div class="emote-menu-inner"></div></div></div></div>`);
|
||||
this.teInner = this.teContainer.querySelector(".emote-menu-inner");
|
||||
for (const emote in bdEmotes.TwitchGlobal) {
|
||||
if (bdEmotes.TwitchGlobal.hasOwnProperty(emote)) {
|
||||
url = bdEmotes.TwitchGlobal[emote];
|
||||
teContainer += "<div class=\"emote-container\">";
|
||||
teContainer += " <img class=\"emote-icon\" alt=\"\" src=\"" + url + "\" title=\"" + emote + "\">";
|
||||
teContainer += " </img>";
|
||||
teContainer += "</div>";
|
||||
}
|
||||
if (!bdEmotes.TwitchGlobal.hasOwnProperty(emote)) continue;
|
||||
this.teInner.append(makeEmote(emote, bdEmotes.TwitchGlobal[emote]));
|
||||
}
|
||||
teContainer += " </div>";
|
||||
teContainer += " </div>";
|
||||
teContainer += " </div>";
|
||||
teContainer += "</div>";
|
||||
this.teContainer = teContainer;
|
||||
|
||||
let faContainer = "";
|
||||
faContainer += "<div id=\"bda-qem-favourite-container\">";
|
||||
faContainer += " <div class=\"scroller-wrap scrollerWrap-2lJEkd fade\">";
|
||||
faContainer += " <div class=\"scroller scroller-2FKFPG\">";
|
||||
faContainer += " <div class=\"emote-menu-inner\">";
|
||||
this.faContainer = DOM.createElement(`<div id="bda-qem-favourite-container"><div class="scroller-wrap scrollerWrap-2lJEkd fade"><div class="scroller scroller-2FKFPG"><div class="emote-menu-inner"></div></div></div></div>`);
|
||||
this.faInner = this.faContainer.querySelector(".emote-menu-inner");
|
||||
for (const emote in this.favoriteEmotes) {
|
||||
url = this.favoriteEmotes[emote];
|
||||
faContainer += "<div class=\"emote-container\">";
|
||||
faContainer += " <img class=\"emote-icon\" alt=\"\" src=\"" + url + "\" title=\"" + emote + "\" oncontextmenu='quickEmoteMenu.favContext(event, this);'>";
|
||||
faContainer += " </img>";
|
||||
faContainer += "</div>";
|
||||
this.faInner.append(makeEmote(emote, this.favoriteEmotes[emote], {contextmenu: this.favContext}));
|
||||
}
|
||||
faContainer += " </div>";
|
||||
faContainer += " </div>";
|
||||
faContainer += " </div>";
|
||||
faContainer += "</div>";
|
||||
this.faContainer = faContainer;
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.favContext = function(e, em) {
|
||||
QuickEmoteMenu.prototype.favContext = function(e) {
|
||||
e.stopPropagation();
|
||||
const menu = $("<div>", {"id": "removemenu", "data-emoteid": $(em).prop("title"), "text": "Remove", "class": "bd-context-menu context-menu theme-dark"});
|
||||
menu.css({
|
||||
top: e.pageY - $("#bda-qem-favourite-container").offset().top,
|
||||
left: e.pageX - $("#bda-qem-favourite-container").offset().left
|
||||
});
|
||||
$(em).parent().append(menu);
|
||||
const self = this;
|
||||
menu.on("click", function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$(this).remove();
|
||||
const container = DOM.query("#app-mount");
|
||||
const cmWrap = DOM.createElement(`<div class="layer-v9HyYc da-layer">`);
|
||||
const cm = DOM.createElement(`<div class="contextMenu-HLZMGh da-contextMenu bd-context-menu"></div>`);
|
||||
cmWrap.append(cm);
|
||||
container.append(cmWrap);
|
||||
cmWrap.style.top = e.clientY + "px";
|
||||
cmWrap.style.left = e.clientX + "px";
|
||||
cmWrap.style.zIndex = "1002";
|
||||
const removeCM = function(e) {
|
||||
if (e && e.keyCode && e.keyCode !== 27) return;
|
||||
cmWrap.remove();
|
||||
document.removeEventListener("click", removeCM);
|
||||
document.removeEventListener("contextmenu", removeCM);
|
||||
document.removeEventListener("keyup", removeCM);
|
||||
};
|
||||
document.addEventListener("click", removeCM);
|
||||
document.addEventListener("contextmenu", removeCM);
|
||||
document.addEventListener("keyup", removeCM);
|
||||
|
||||
delete self.favoriteEmotes[$(this).data("emoteid")];
|
||||
self.updateFavorites();
|
||||
return false;
|
||||
const cmg = DOM.createElement(`<div class="itemGroup-1tL0uz da-itemGroup">`);
|
||||
const cmi = DOM.createElement(`<div class="item-1Yvehc itemBase-tz5SeC da-item da-itemBase clickable-11uBi- da-clickable">`);
|
||||
cmi.append(DOM.createElement(`<div class="label-JWQiNe da-label">Remove</div>`));
|
||||
cmi.addEventListener("click", () => {
|
||||
delete this.favoriteEmotes[e.target.getAttribute("title")];
|
||||
e.target.parentElement.remove();
|
||||
this.saveFavorites();
|
||||
removeCM();
|
||||
});
|
||||
return false;
|
||||
cmg.append(cmi);
|
||||
cm.append(cmg);
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.switchHandler = function(e) {
|
||||
this.switchQem($(e).attr("id"));
|
||||
this.switchQem(e.target.id);
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.switchQem = function(id) {
|
||||
const twitch = $("#bda-qem-twitch");
|
||||
const fav = $("#bda-qem-favourite");
|
||||
const emojis = $("#bda-qem-emojis");
|
||||
twitch.removeClass("active");
|
||||
fav.removeClass("active");
|
||||
emojis.removeClass("active");
|
||||
this.twitchButton.classList.remove("active");
|
||||
this.favoriteButton.classList.remove("active");
|
||||
this.emojiButton.classList.remove("active");
|
||||
|
||||
$(".emojiPicker-3m1S-j").hide();
|
||||
$("#bda-qem-favourite-container").hide();
|
||||
$("#bda-qem-twitch-container").hide();
|
||||
const emojiPicker = DOM.query(".emojiPicker-3m1S-j");
|
||||
emojiPicker.style.display = "none";
|
||||
this.faContainer.style.display = "none";
|
||||
this.teContainer.style.display = "none";
|
||||
|
||||
switch (id) {
|
||||
case "bda-qem-twitch":
|
||||
twitch.addClass("active");
|
||||
$("#bda-qem-twitch-container").show();
|
||||
this.twitchButton.classList.add("active");
|
||||
this.teContainer.style.display = "";
|
||||
break;
|
||||
case "bda-qem-favourite":
|
||||
fav.addClass("active");
|
||||
$("#bda-qem-favourite-container").show();
|
||||
this.favoriteButton.classList.add("active");
|
||||
this.faContainer.style.display = "";
|
||||
break;
|
||||
case "bda-qem-emojis":
|
||||
emojis.addClass("active");
|
||||
$(".emojiPicker-3m1S-j").show();
|
||||
$(".emojiPicker-3m1S-j input").focus();
|
||||
this.emojiButton.classList.add("active");
|
||||
emojiPicker.style.display = "";
|
||||
emojiPicker.querySelector("input").focus();
|
||||
break;
|
||||
}
|
||||
this.lastTab = id;
|
||||
|
||||
const emoteIcon = $(".emote-icon");
|
||||
emoteIcon.off();
|
||||
emoteIcon.on("click", function () {
|
||||
const emote = $(this).attr("title");
|
||||
const newTextarea = document.querySelector(`.${BDV2.slateEditorClasses.slateTextArea.split(" ")[0]}`);
|
||||
if (newTextarea) {
|
||||
const instance = BDV2.getInternalInstance(newTextarea);
|
||||
const insert = Utils.getNestedProp(instance, "memoizedProps.children.props.editor.insertText");
|
||||
if (insert) insert(` ${emote} `);
|
||||
}
|
||||
else {
|
||||
const ta = Utils.getTextArea();
|
||||
Utils.insertText(ta[0], ta.val().slice(-1) == " " ? ta.val() + emote : ta.val() + " " + emote);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.obsCallback = function (elem) {
|
||||
if (!this.initialized) return;
|
||||
const e = $(elem);
|
||||
if (!settingsCookie["bda-es-9"]) {
|
||||
e.addClass("bda-qme-hidden");
|
||||
}
|
||||
else {
|
||||
e.removeClass("bda-qme-hidden");
|
||||
}
|
||||
if (!settingsCookie["bda-es-9"]) elem.classList.add("bda-qme-hidden");
|
||||
else elem.classList.remove("bda-qme-hidden");
|
||||
|
||||
if (!settingsCookie["bda-es-0"]) return;
|
||||
|
||||
e.prepend(this.qmeHeader);
|
||||
e.append(this.teContainer);
|
||||
e.append(this.faContainer);
|
||||
|
||||
if (this.lastTab == undefined) {
|
||||
this.lastTab = "bda-qem-emojis";
|
||||
}
|
||||
this.switchQem(this.lastTab);
|
||||
DOM.prependTo(this.qmeHeader, elem);
|
||||
elem.append(this.teContainer);
|
||||
elem.append(this.faContainer);
|
||||
this.switchQem("bda-qem-emojis");
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.favorite = function (name, url) {
|
||||
|
||||
if (!this.favoriteEmotes.hasOwnProperty(name)) {
|
||||
this.favoriteEmotes[name] = url;
|
||||
}
|
||||
|
||||
if (!this.favoriteEmotes.hasOwnProperty(name)) this.favoriteEmotes[name] = url;
|
||||
this.updateFavorites();
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.updateFavorites = function () {
|
||||
|
||||
let faContainer = "";
|
||||
faContainer += "<div id=\"bda-qem-favourite-container\">";
|
||||
faContainer += " <div class=\"scroller-wrap scrollerWrap-2lJEkd fade\">";
|
||||
faContainer += " <div class=\"scroller scroller-2FKFPG\">";
|
||||
faContainer += " <div class=\"emote-menu-inner\">";
|
||||
for (const emote in this.favoriteEmotes) {
|
||||
const url = this.favoriteEmotes[emote];
|
||||
faContainer += "<div class=\"emote-container\">";
|
||||
faContainer += " <img class=\"emote-icon\" alt=\"\" src=\"" + url + "\" title=\"" + emote + "\" oncontextmenu=\"quickEmoteMenu.favContext(event, this);\">";
|
||||
faContainer += " </img>";
|
||||
faContainer += "</div>";
|
||||
}
|
||||
faContainer += " </div>";
|
||||
faContainer += " </div>";
|
||||
faContainer += " </div>";
|
||||
faContainer += "</div>";
|
||||
this.faContainer = faContainer;
|
||||
|
||||
$("#bda-qem-favourite-container").replaceWith(faContainer);
|
||||
QuickEmoteMenu.prototype.saveFavorites = function () {
|
||||
DataStore.setBDData("bdfavemotes", btoa(JSON.stringify(this.favoriteEmotes)));
|
||||
};
|
||||
|
||||
QuickEmoteMenu.prototype.updateFavorites = function () {
|
||||
this.faInner.innerHTML = "";
|
||||
for (const emote in this.favoriteEmotes) this.faInner.append(makeEmote(emote, this.favoriteEmotes[emote], {contextmenu: this.favContext}));
|
||||
this.saveFavorites();
|
||||
};
|
||||
|
||||
export default new QuickEmoteMenu();
|
|
@ -8,6 +8,7 @@ import BDEvents from "./bdEvents";
|
|||
import coloredText from "./coloredText";
|
||||
import tfHour from "./24hour";
|
||||
import reactDevTools from "./reactDevTools";
|
||||
import DOM from "./domtools";
|
||||
|
||||
import publicServersModule from "./publicServers";
|
||||
import voiceMode from "./voiceMode";
|
||||
|
@ -26,34 +27,32 @@ import CardList from "../ui/addonlist";
|
|||
export default new class V2_SettingsPanel {
|
||||
|
||||
constructor() {
|
||||
const self = this;
|
||||
self.sideBarOnClick = self.sideBarOnClick.bind(self);
|
||||
self.onChange = self.onChange.bind(self);
|
||||
self.updateSettings = this.updateSettings.bind(self);
|
||||
self.sidebar = new V2_SettingsPanel_Sidebar(self.sideBarOnClick);
|
||||
this.sideBarOnClick = this.sideBarOnClick.bind(this);
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.updateSettings = this.updateSettings.bind(this);
|
||||
this.sidebar = new V2_SettingsPanel_Sidebar(this.sideBarOnClick);
|
||||
this.buildPluginProps = this.buildPluginProps.bind(this);
|
||||
this.buildThemeProps = this.buildThemeProps.bind(this);
|
||||
this.showOriginal = this.showOriginal.bind(this);
|
||||
}
|
||||
|
||||
get root() {
|
||||
const _root = $("#bd-settingspane-container");
|
||||
if (!_root.length) {
|
||||
const _root = DOM.query("#bd-settingspane-container");
|
||||
if (!_root) {
|
||||
if (!this.injectRoot()) return null;
|
||||
return this.root;
|
||||
}
|
||||
return _root[0];
|
||||
return _root;
|
||||
}
|
||||
|
||||
injectRoot() {
|
||||
if (!$(".layer-3QrUeG .standardSidebarView-3F1I7i, .layer-3QrUeG .ui-standard-sidebar-view").length) return false;
|
||||
const root = $("<div/>", {
|
||||
"class": "contentRegion-3nDuYy content-region",
|
||||
"id": "bd-settingspane-container"
|
||||
});
|
||||
$(".layer-3QrUeG .standardSidebarView-3F1I7i, .layer-3QrUeG .ui-standard-sidebar-view").append(root);
|
||||
const sidebar = DOM.query(".layer-3QrUeG .standardSidebarView-3F1I7i, .layer-3QrUeG .ui-standard-sidebar-view");
|
||||
if (!sidebar) return false;
|
||||
const root = DOM.createElement(`<div id="bd-settingspane-container" class="contentRegion-3nDuYy content-region">`);
|
||||
sidebar.append(root);
|
||||
|
||||
Utils.onRemoved(root[0], () => {
|
||||
BDV2.reactDom.unmountComponentAtNode(root[0]);
|
||||
Utils.onRemoved(root, () => {
|
||||
BDV2.reactDom.unmountComponentAtNode(root);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -80,24 +79,24 @@ export default new class V2_SettingsPanel {
|
|||
}
|
||||
|
||||
sideBarOnClick(id) {
|
||||
const self = this;
|
||||
$(".contentRegion-3nDuYy, .content-region").first().hide();
|
||||
$(self.root).show();
|
||||
const contentRegion = DOM.query(".contentRegion-3nDuYy, .content-region");
|
||||
contentRegion.style.display = "none";
|
||||
this.root.style.display = "";
|
||||
switch (id) {
|
||||
case "core":
|
||||
self.renderCoreSettings();
|
||||
this.renderCoreSettings();
|
||||
break;
|
||||
case "emotes":
|
||||
self.renderEmoteSettings();
|
||||
this.renderEmoteSettings();
|
||||
break;
|
||||
case "customcss":
|
||||
self.renderCustomCssEditor();
|
||||
this.renderCustomCssEditor();
|
||||
break;
|
||||
case "plugins":
|
||||
self.renderPluginPane();
|
||||
this.renderPluginPane();
|
||||
break;
|
||||
case "themes":
|
||||
self.renderThemePane();
|
||||
this.renderThemePane();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -111,19 +110,14 @@ export default new class V2_SettingsPanel {
|
|||
updateSettings(id, enabled) {
|
||||
settingsCookie[id] = enabled;
|
||||
|
||||
// if (id == "bda-gs-b") {
|
||||
// if (enabled) $("body").addClass("bd-blue");
|
||||
// else $("body").removeClass("bd-blue");
|
||||
// }
|
||||
|
||||
if (id == "bda-gs-2") {
|
||||
if (enabled) $("body").addClass("bd-minimal");
|
||||
else $("body").removeClass("bd-minimal");
|
||||
if (enabled) DOM.addClass(document.body, "bd-minimal");
|
||||
else DOM.removeClass(document.body, "bd-minimal");
|
||||
}
|
||||
|
||||
if (id == "bda-gs-3") {
|
||||
if (enabled) $("body").addClass("bd-minimal-chan");
|
||||
else $("body").removeClass("bd-minimal-chan");
|
||||
if (enabled) DOM.addClass(document.body, "bd-minimal-chan");
|
||||
else DOM.removeClass(document.body, "bd-minimal-chan");
|
||||
}
|
||||
|
||||
if (id == "bda-gs-1") {
|
||||
|
@ -132,13 +126,13 @@ export default new class V2_SettingsPanel {
|
|||
}
|
||||
|
||||
if (id == "bda-gs-4") {
|
||||
if (enabled) voiceMode.enable();
|
||||
else voiceMode.disable();
|
||||
if (enabled) voiceMode.start();
|
||||
else voiceMode.stop();
|
||||
}
|
||||
|
||||
if (id == "bda-gs-5") {
|
||||
if (enabled) $("#app-mount").addClass("bda-dark");
|
||||
else $("#app-mount").removeClass("bda-dark");
|
||||
if (enabled) DOM.addClass(DOM.query("#app-mount"), "bda-dark");
|
||||
else DOM.removeClass(DOM.query("#app-mount"), "bda-dark");
|
||||
}
|
||||
|
||||
if (enabled && id == "bda-gs-6") tfHour.inject24Hour();
|
||||
|
@ -148,11 +142,6 @@ export default new class V2_SettingsPanel {
|
|||
else coloredText.removeColoredText();
|
||||
}
|
||||
|
||||
if (id == "bda-es-4") {
|
||||
if (enabled) emoteModule.autoCapitalize();
|
||||
else emoteModule.disableAutoCapitalize();
|
||||
}
|
||||
|
||||
if (id == "fork-ps-4") {
|
||||
if (enabled) ClassNormalizer.start();
|
||||
else ClassNormalizer.stop();
|
||||
|
@ -182,12 +171,13 @@ export default new class V2_SettingsPanel {
|
|||
|
||||
|
||||
if (id == "bda-gs-8") {
|
||||
if (enabled) dMode.enable(settingsCookie["fork-dm-1"]);
|
||||
else dMode.disable();
|
||||
if (enabled) dMode.startDebugListener();
|
||||
else dMode.stopDebugListener();
|
||||
}
|
||||
|
||||
if (id == "fork-dm-1") {
|
||||
if (settingsCookie["bda-gs-8"]) dMode.enable(enabled);
|
||||
if (enabled) dMode.startCopySelector();
|
||||
else dMode.stopCopySelector();
|
||||
}
|
||||
|
||||
if (id === "reactDevTools") {
|
||||
|
@ -199,15 +189,13 @@ export default new class V2_SettingsPanel {
|
|||
}
|
||||
|
||||
async initializeSettings() {
|
||||
// if (settingsCookie["bda-gs-b"]) $("body").addClass("bd-blue");
|
||||
if (settingsCookie["bda-gs-2"]) $("body").addClass("bd-minimal");
|
||||
if (settingsCookie["bda-gs-3"]) $("body").addClass("bd-minimal-chan");
|
||||
if (settingsCookie["bda-gs-2"]) DOM.addClass(document.body, "bd-minimal");
|
||||
if (settingsCookie["bda-gs-3"]) DOM.addClass(document.body, "bd-minimal-chan");
|
||||
if (settingsCookie["bda-gs-1"]) publicServersModule.addButton();
|
||||
if (settingsCookie["bda-gs-4"]) voiceMode.enable();
|
||||
if (settingsCookie["bda-gs-5"]) $("#app-mount").addClass("bda-dark");
|
||||
if (settingsCookie["bda-gs-4"]) voiceMode.start();
|
||||
if (settingsCookie["bda-gs-5"]) DOM.addClass(DOM.query("#app-mount"), "bda-dark");
|
||||
if (settingsCookie["bda-gs-6"]) tfHour.inject24Hour();
|
||||
if (settingsCookie["bda-gs-7"]) coloredText.injectColoredText();
|
||||
if (settingsCookie["bda-es-4"]) emoteModule.autoCapitalize();
|
||||
if (settingsCookie["fork-ps-4"]) ClassNormalizer.start();
|
||||
|
||||
if (settingsCookie["fork-ps-5"]) {
|
||||
|
@ -215,7 +203,8 @@ export default new class V2_SettingsPanel {
|
|||
ContentManager.watchContent("theme");
|
||||
}
|
||||
|
||||
if (settingsCookie["bda-gs-8"]) dMode.enable(settingsCookie["fork-dm-1"]);
|
||||
if (settingsCookie["bda-gs-8"]) dMode.startDebugListener();
|
||||
if (settingsCookie["fork-dm-1"]) dMode.startCopySelector();
|
||||
if (settingsCookie.reactDevTools) reactDevTools.start();
|
||||
|
||||
this.saveSettings();
|
||||
|
@ -229,14 +218,19 @@ export default new class V2_SettingsPanel {
|
|||
Object.assign(settingsCookie, DataStore.getSettingGroup("settings"));
|
||||
}
|
||||
|
||||
showOriginal() {
|
||||
BDV2.reactDom.unmountComponentAtNode(this.root);
|
||||
this.root.style.display = "none";
|
||||
DOM.query(".contentRegion-3nDuYy, .content-region").style.display = "";
|
||||
}
|
||||
|
||||
renderSidebar() {
|
||||
const self = this;
|
||||
$("[class*='side-'] > [class*='item-']").off("click.v2settingspanel").on("click.v2settingspanel", () => {
|
||||
BDV2.reactDom.unmountComponentAtNode(self.root);
|
||||
$(self.root).hide();
|
||||
$(".contentRegion-3nDuYy, .content-region").first().show();
|
||||
});
|
||||
self.sidebar.render();
|
||||
const tabs = document.querySelectorAll("[class*='side-'] > [class*='item-']");
|
||||
for (const element of tabs) {
|
||||
element.removeEventListener("click", this.showOriginal);
|
||||
element.addEventListener("click", this.showOriginal);
|
||||
}
|
||||
this.sidebar.render();
|
||||
}
|
||||
|
||||
get coreComponent() {
|
||||
|
@ -322,7 +316,7 @@ export default new class V2_SettingsPanel {
|
|||
|
||||
getAddonList(type) {
|
||||
const isPlugins = type === "plugins";
|
||||
const list = isPlugins ? Object.values(bdplugins).map(this.buildPluginProps) : Object.values(bdthemes).map(this.buildThemeProps);
|
||||
const list = isPlugins ? Object.values(bdplugins) : Object.values(bdthemes);
|
||||
return BDV2.react.createElement(CardList, {type, list});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {bbdChangelog} from "../0globals";
|
||||
import Utils from "./utils";
|
||||
import BDV2 from "./v2";
|
||||
import DOM from "./domtools";
|
||||
|
||||
import SideBar from "../ui/sidebar";
|
||||
import History from "../ui/icons/history";
|
||||
|
@ -28,18 +29,19 @@ export default class V2_SettingsPanel_Sidebar {
|
|||
}
|
||||
|
||||
get root() {
|
||||
const _root = $("#bd-settings-sidebar");
|
||||
if (!_root.length) {
|
||||
const _root = DOM.query("#bd-settings-sidebar");
|
||||
if (!_root) {
|
||||
if (!this.injectRoot()) return null;
|
||||
return this.root;
|
||||
}
|
||||
return _root[0];
|
||||
return _root;
|
||||
}
|
||||
|
||||
injectRoot() {
|
||||
const changeLog = $("[class*='side-'] > [class*='item-']:not([class*=Danger])").last();
|
||||
if (!changeLog.length) return false;
|
||||
$("<span/>", {id: "bd-settings-sidebar"}).insertBefore(changeLog.prev());
|
||||
const tabs = DOM.queryAll("[class*='side-'] > [class*='item-']:not([class*=Danger])");
|
||||
const changeLog = tabs[tabs.length - 1];
|
||||
if (!changeLog) return false;
|
||||
changeLog.parentElement.insertBefore(DOM.createElement(`<div id="bd-settings-sidebar">`), changeLog.previousElementSibling);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,20 +3,28 @@ import ContentManager from "./contentManager";
|
|||
import DataStore from "./dataStore";
|
||||
import BDEvents from "./bdEvents";
|
||||
import Utils from "./utils";
|
||||
import DOM from "./domtools";
|
||||
|
||||
function ThemeModule() {
|
||||
|
||||
this.getString = function(value) {
|
||||
if (!value) return "???";
|
||||
return typeof value == "string" ? value : value.toString();
|
||||
};
|
||||
}
|
||||
|
||||
ThemeModule.prototype.loadThemes = function () {
|
||||
this.loadThemeData();
|
||||
bdthemeErrors.concat(ContentManager.loadThemes());
|
||||
bdthemeErrors.splice(0, 0, ...ContentManager.loadThemes());
|
||||
const themes = Object.keys(bdthemes);
|
||||
|
||||
for (let i = 0; i < themes.length; i++) {
|
||||
const theme = bdthemes[themes[i]];
|
||||
theme.name = this.getString(theme.name);
|
||||
theme.author = this.getString(theme.author);
|
||||
theme.description = this.getString(theme.description);
|
||||
theme.version = this.getString(theme.version);
|
||||
if (!themeCookie[theme.name]) themeCookie[theme.name] = false;
|
||||
if (themeCookie[theme.name]) $("head").append($("<style>", {id: theme.id, text: unescape(theme.css)}));
|
||||
if (themeCookie[theme.name]) DOM.addStyle(DOM.escapeID(theme.id), unescape(theme.css));
|
||||
}
|
||||
for (const theme in themeCookie) {
|
||||
if (!bdthemes[theme]) delete themeCookie[theme];
|
||||
|
@ -29,7 +37,7 @@ ThemeModule.prototype.enableTheme = function(name, reload = false) {
|
|||
themeCookie[name] = true;
|
||||
this.saveThemeData();
|
||||
const theme = bdthemes[name];
|
||||
$("head").append($("<style>", {id: theme.id, text: unescape(theme.css)}));
|
||||
DOM.addStyle(DOM.escapeID(theme.id), unescape(theme.css));
|
||||
if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${theme.name} v${theme.version} has been applied.`);
|
||||
};
|
||||
|
||||
|
@ -41,7 +49,7 @@ ThemeModule.prototype.disableTheme = function(name, reload = false) {
|
|||
themeCookie[name] = false;
|
||||
this.saveThemeData();
|
||||
const theme = bdthemes[name];
|
||||
$(`#${theme.id}`).remove();
|
||||
DOM.removeStyle(DOM.escapeID(theme.id));
|
||||
if (settingsCookie["fork-ps-2"] && !reload) Utils.showToast(`${theme.name} v${theme.version} has been disabled.`);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {bbdVersion} from "../0globals";
|
||||
import WebpackModules from "./webpackModules";
|
||||
import BDV2 from "./v2";
|
||||
import DOM from "./domtools";
|
||||
|
||||
export default class Utils {
|
||||
/** Document/window width */
|
||||
|
@ -49,7 +50,7 @@ export default class Utils {
|
|||
}
|
||||
|
||||
static getTextArea() {
|
||||
return $(".channelTextArea-rNsIhG textarea");
|
||||
return DOM.query(".channelTextArea-rNsIhG textarea");
|
||||
}
|
||||
|
||||
static insertText(textarea, text) {
|
||||
|
@ -59,24 +60,6 @@ export default class Utils {
|
|||
document.execCommand("insertText", false, text);
|
||||
}
|
||||
|
||||
static injectCss(uri) {
|
||||
$("<link/>", {
|
||||
type: "text/css",
|
||||
rel: "stylesheet",
|
||||
href: uri
|
||||
}).appendTo($("head"));
|
||||
}
|
||||
|
||||
static injectJs(uri) {
|
||||
return new Promise(resolve => {
|
||||
$("<script/>", {
|
||||
type: "text/javascript",
|
||||
src: uri,
|
||||
onload: resolve
|
||||
}).appendTo($("body"));
|
||||
});
|
||||
}
|
||||
|
||||
static escapeID(id) {
|
||||
return id.replace(/^[^a-z]+|[^\w-]+/gi, "-");
|
||||
}
|
||||
|
@ -231,7 +214,7 @@ export default class Utils {
|
|||
}
|
||||
|
||||
static alert(title, content) {
|
||||
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 modal-1UGdnR">
|
||||
<div class="bd-modal-inner inner-1JeGVc">
|
||||
|
@ -251,21 +234,21 @@ export default class Utils {
|
|||
</div>
|
||||
</div>
|
||||
</div>`);
|
||||
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");
|
||||
DOM.query("#app-mount").append(modal);
|
||||
}
|
||||
|
||||
static showContentErrors({plugins: pluginErrors = [], themes: themeErrors = []}) {
|
||||
if (!pluginErrors || !themeErrors) 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">
|
||||
|
@ -288,7 +271,7 @@ export default class Utils {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer footer-2yfCgX">
|
||||
<div class="footer footer-2yfCgX footer-3rDWdC footer-2gL1pp">
|
||||
<button type="button">Okay</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -296,19 +279,19 @@ export default class Utils {
|
|||
</div>`);
|
||||
|
||||
function generateTab(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();
|
||||
Utils.err("ContentManager", `Error details for ${err.name ? err.name : err.file}.`, err.error);
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
return container;
|
||||
|
@ -316,24 +299,27 @@ export default class Utils {
|
|||
|
||||
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").on("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 = {}) {
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
function VoiceMode() {
|
||||
import DOM from "./domtools";
|
||||
|
||||
}
|
||||
const style = `
|
||||
.container-2Rl01u {
|
||||
display: none!important;
|
||||
}
|
||||
|
||||
VoiceMode.prototype.enable = function () {
|
||||
$(".scroller.guild-channels ul").first().css("display", "none");
|
||||
$(".scroller.guild-channels header").first().css("display", "none");
|
||||
$(".app.flex-vertical, .app-2rEoOp").first().css("overflow", "hidden");
|
||||
$(".chat-3bRxxu").first().css("visibility", "hidden").css("min-width", "0px");
|
||||
$(".flex-vertical.channels-wrap").first().css("flex-grow", "100000");
|
||||
$(".guild-header .btn.btn-hamburger").first().css("visibility", "hidden");
|
||||
};
|
||||
.chat-3bRxxu {
|
||||
display: none!important;
|
||||
}
|
||||
|
||||
VoiceMode.prototype.disable = function () {
|
||||
$(".scroller.guild-channels ul").first().css("display", "");
|
||||
$(".scroller.guild-channels header").first().css("display", "");
|
||||
$(".app.flex-vertical, .app-2rEoOp").first().css("overflow", "");
|
||||
$(".chat-3bRxxu").first().css("visibility", "").css("min-width", "");
|
||||
$(".flex-vertical.channels-wrap").first().css("flex-grow", "");
|
||||
$(".guild-header .btn.btn-hamburger").first().css("visibility", "");
|
||||
};
|
||||
.sidebar-2K8pFh {
|
||||
flex-grow: 1!important;
|
||||
}
|
||||
`;
|
||||
|
||||
export default new VoiceMode();
|
||||
export default new class VoiceMode {
|
||||
start() {
|
||||
DOM.addStyle("VoiceMode", style);
|
||||
}
|
||||
|
||||
stop() {
|
||||
DOM.removeStyle("VoiceMode");
|
||||
}
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
import {settingsCookie} from "../0globals";
|
||||
import BDV2 from "../modules/v2";
|
||||
import Utils from "../modules/utils";
|
||||
import DOM from "../modules/domtools";
|
||||
|
||||
import XSvg from "./xSvg";
|
||||
import ReloadIcon from "./reloadIcon";
|
||||
|
@ -18,7 +19,7 @@ export default class V2C_PluginCard extends BDV2.reactComponent {
|
|||
this.onChange = this.onChange.bind(this);
|
||||
this.showSettings = this.showSettings.bind(this);
|
||||
this.setInitialState();
|
||||
this.hasSettings = typeof this.props.addon.getSettingsPanel === "function";
|
||||
this.hasSettings = this.props.addon.plugin && typeof this.props.addon.plugin.getSettingsPanel === "function";
|
||||
this.settingsPanel = "";
|
||||
|
||||
this.edit = this.edit.bind(this);
|
||||
|
@ -51,20 +52,30 @@ export default class V2C_PluginCard extends BDV2.reactComponent {
|
|||
}
|
||||
|
||||
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);
|
||||
};
|
||||
setImmediate(() => {
|
||||
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 thisNode = $(BDV2.reactDom.findDOMNode(this));
|
||||
const container = thisNode.parents(".scroller");
|
||||
if (!isHidden(container[0], thisNode[0])) return;
|
||||
container.animate({
|
||||
scrollTop: thisNode.offset().top - container.offset().top + container.scrollTop() - 30
|
||||
}, 300);
|
||||
const thisNode = this.refs.cardNode;
|
||||
const container = thisNode.closest(".scroller");
|
||||
if (!isHidden(container, thisNode)) return;
|
||||
const thisNodeOffset = DOM.offset(thisNode);
|
||||
const containerOffset = DOM.offset(container);
|
||||
const original = container.scrollTop;
|
||||
const endPoint = thisNodeOffset.top - containerOffset.top + container.scrollTop - 30;
|
||||
DOM.animate({
|
||||
duration: 300,
|
||||
update: function(progress) {
|
||||
if (endPoint > original) container.scrollTop = original + (progress * (endPoint - original));
|
||||
else container.scrollTop = original - (progress * (original - endPoint));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -76,10 +87,10 @@ export default class V2C_PluginCard extends BDV2.reactComponent {
|
|||
get settingsComponent() {
|
||||
const name = this.getString(this.props.addon.name);
|
||||
|
||||
try { this.settingsPanel = this.props.addon.getSettingsPanel(); }
|
||||
try { this.settingsPanel = this.props.addon.plugin.getSettingsPanel(); }
|
||||
catch (err) { Utils.err("Plugins", "Unable to get settings panel for " + this.props.addon.name + ".", err); }
|
||||
|
||||
return BDV2.react.createElement("div", {className: "bd-card bd-addon-card settings-open ui-switch-item"},
|
||||
return BDV2.react.createElement("div", {className: "bd-card bd-addon-card settings-open ui-switch-item", ref: "cardNode"},
|
||||
BDV2.react.createElement("div", {style: {"float": "right", "cursor": "pointer"}, onClick: () => {
|
||||
this.refs.settingspanel.innerHTML = "";
|
||||
this.setState({settings: false});
|
||||
|
@ -184,41 +195,4 @@ export default class V2C_PluginCard extends BDV2.reactComponent {
|
|||
this.footer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// get settingsComponent() {
|
||||
// const addon = this.props.addon;
|
||||
// const name = this.getString(addon.name);
|
||||
// try { this.settingsPanel = this.props.getSettingsPanel(); }
|
||||
// catch (err) { Logger.stacktrace("Addon Settings", "Unable to get settings panel for " + name + ".", err); }
|
||||
|
||||
// const props = {id: `${name}-settings`, className: "addon-settings", ref: this.panelRef};
|
||||
// if (typeof(settingsPanel) == "string") props.dangerouslySetInnerHTML = this.settingsPanel;
|
||||
|
||||
// return <div className="bd-addon-card settings-open bd-switch-item">
|
||||
// <div className="bd-close" onClick={this.closeSettings}><CloseButton /></div>
|
||||
// <div {...props}>{this.settingsPanel instanceof React.Component ? this.settingsPanel : null}</div>
|
||||
// </div>;
|
||||
// }
|
||||
|
||||
// componentDidUpdate() {
|
||||
// if (!this.state.settingsOpen) return;
|
||||
// if (this.settingsPanel instanceof Node) this.panelRef.current.appendChild(this.settingsPanel);
|
||||
|
||||
// // if (!SettingsCookie["fork-ps-3"]) return;
|
||||
// const isHidden = (container, element) => {
|
||||
// const cTop = container.scrollTop;
|
||||
// const cBottom = cTop + container.clientHeight;
|
||||
// const eTop = element.offsetTop;
|
||||
// const eBottom = eTop + element.clientHeight;
|
||||
// return (eTop < cTop || eBottom > cBottom);
|
||||
// };
|
||||
|
||||
// const panel = $(this.panelRef.current);
|
||||
// const container = panel.parents(".scroller-2FKFPG");
|
||||
// if (!isHidden(container[0], panel[0])) return;
|
||||
// container.animate({
|
||||
// scrollTop: panel.offset().top - container.offset().top + container.scrollTop() - 30
|
||||
// }, 300);
|
||||
// }
|
||||
}
|
|
@ -33,7 +33,7 @@ export default class CardList extends BDV2.reactComponent {
|
|||
}
|
||||
|
||||
openFolder() {
|
||||
require("electron").shell.openItem(this.isPlugins ? ContentManager.pluginsFolder : ContentManager.themesFolder);
|
||||
require("electron").shell.showItemInFolder(this.isPlugins ? ContentManager.pluginsFolder : ContentManager.themesFolder);
|
||||
}
|
||||
|
||||
edit(name) {
|
||||
|
@ -109,18 +109,20 @@ export default class CardList extends BDV2.reactComponent {
|
|||
return 0;
|
||||
});
|
||||
if (!this.state.ascending) sortedAddons.reverse();
|
||||
const rendered = sortedAddons.map((addon) => {
|
||||
const rendered = [];
|
||||
for (let a = 0; a < sortedAddons.length; a++) {
|
||||
const addon = sortedAddons[a];
|
||||
if (this.state.query) {
|
||||
let matches = null;
|
||||
if (addon.name) matches = addon.name.toLocaleLowerCase().includes(this.state.query);
|
||||
if (addon.author) matches = matches || addon.author.toLocaleLowerCase().includes(this.state.query);
|
||||
if (addon.description) matches = matches || addon.description.toLocaleLowerCase().includes(this.state.query);
|
||||
if (addon.version) matches = matches || addon.version.toLocaleLowerCase().includes(this.state.query);
|
||||
if (!matches) return null;
|
||||
if (!matches) continue;
|
||||
}
|
||||
const props = this.getProps(addon);
|
||||
return <ErrorBoundary><AddonCard {...props} reload={!settingsCookie["fork-ps-5"] && this.manager.reload.bind(this.manager)} /></ErrorBoundary>;
|
||||
});
|
||||
rendered.push(<ErrorBoundary><AddonCard {...props} reload={!settingsCookie["fork-ps-5"] && this.manager.reload.bind(this.manager)} /></ErrorBoundary>);
|
||||
}
|
||||
return rendered;
|
||||
}
|
||||
|
||||
|
@ -133,7 +135,7 @@ export default class CardList extends BDV2.reactComponent {
|
|||
this.forceUpdate();
|
||||
}} />
|
||||
}</Tooltip>;
|
||||
const addonCards = this.getAddons().filter(c => c);
|
||||
const addonCards = this.getAddons();
|
||||
|
||||
return <Scroller contentColumn={true} fade={true} dark={true}>
|
||||
<ContentColumn title={`${this.props.type.toUpperCase()}—${addonCards.length}`}>
|
||||
|
|
|
@ -2,6 +2,7 @@ import {settingsCookie} from "../0globals";
|
|||
import Settings from "../modules/settingsPanel";
|
||||
import BDV2 from "../modules/v2";
|
||||
import DataStore from "../modules/dataStore";
|
||||
import DOM from "../modules/domtools";
|
||||
|
||||
import SettingsTitle from "./settingsTitle";
|
||||
import Checkbox from "./checkbox";
|
||||
|
@ -188,10 +189,8 @@ export default class V2C_CssEditor extends BDV2.reactComponent {
|
|||
}
|
||||
|
||||
updateCss() {
|
||||
if ($("#customcss").length == 0) {
|
||||
$("head").append("<style id=\"customcss\"></style>");
|
||||
}
|
||||
$("#customcss").text(this.editor.session.getValue()).detach().appendTo(document.head);
|
||||
DOM.removeStyle("customcss");
|
||||
DOM.addStyle("customcss", this.editor.session.getValue());
|
||||
}
|
||||
|
||||
saveCss() {
|
||||
|
@ -212,19 +211,18 @@ export default class V2C_CssEditor extends BDV2.reactComponent {
|
|||
}
|
||||
|
||||
get detachedRoot() {
|
||||
const _root = $("#bd-customcss-detach-container");
|
||||
if (!_root.length) {
|
||||
const _root = DOM.query("#bd-customcss-detach-container");
|
||||
if (!_root) {
|
||||
if (!this.injectDetachedRoot()) return null;
|
||||
return this.detachedRoot;
|
||||
}
|
||||
return _root[0];
|
||||
return _root;
|
||||
}
|
||||
|
||||
injectDetachedRoot() {
|
||||
if (!$(".app, .app-2rEoOp").length) return false;
|
||||
$("<div/>", {
|
||||
id: "bd-customcss-detach-container"
|
||||
}).insertAfter($(".app, .app-2rEoOp"));
|
||||
const app = DOM.query(".app, .app-2rEoOp");
|
||||
if (!app) return false;
|
||||
DOM.insertAfter(DOM.createElement(`<div id="bd-customcss-detach-container">`), app);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import {settingsCookie} from "../0globals";
|
|||
import Settings from "../modules/settingsPanel";
|
||||
import BDV2 from "../modules/v2";
|
||||
import DataStore from "../modules/dataStore";
|
||||
import DOM from "../modules/domtools";
|
||||
|
||||
import Checkbox from "./checkbox";
|
||||
|
||||
|
@ -17,7 +18,7 @@ export default class V2C_CssEditorDetached extends BDV2.reactComponent {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
$("#app-mount").addClass("bd-detached-editor");
|
||||
DOM.addClass(DOM.query("#app-mount"), "bd-detached-editor");
|
||||
BDV2.editorDetached = true;
|
||||
// this.updateLineCount();
|
||||
this.editor = ace.edit("bd-customcss-editor-detached");
|
||||
|
@ -34,7 +35,7 @@ export default class V2C_CssEditorDetached extends BDV2.reactComponent {
|
|||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
$("#app-mount").removeClass("bd-detached-editor");
|
||||
DOM.removeClass(DOM.query("#app-mount"), "bd-detached-editor");
|
||||
BDV2.editorDetached = false;
|
||||
this.editor.destroy();
|
||||
}
|
||||
|
@ -66,19 +67,18 @@ export default class V2C_CssEditorDetached extends BDV2.reactComponent {
|
|||
}
|
||||
|
||||
get root() {
|
||||
const _root = $("#bd-customcss-detach-container");
|
||||
if (!_root.length) {
|
||||
const _root = DOM.query("#bd-customcss-detach-container");
|
||||
if (!_root) {
|
||||
if (!this.injectRoot()) return null;
|
||||
return this.detachedRoot;
|
||||
}
|
||||
return _root[0];
|
||||
return _root;
|
||||
}
|
||||
|
||||
injectRoot() {
|
||||
if (!$(".app, .app-2rEoOp").length) return false;
|
||||
$("<div/>", {
|
||||
id: "bd-customcss-detach-container"
|
||||
}).insertAfter($(".app, .app-2rEoOp"));
|
||||
const app = DOM.query(".app, .app-2rEoOp");
|
||||
if (!app) return false;
|
||||
DOM.insertAfter(DOM.createElement(`<div id="bd-customcss-detach-container">`), app);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ export default class V2C_CssEditorDetached extends BDV2.reactComponent {
|
|||
const self = this;
|
||||
switch (id) {
|
||||
case "attach":
|
||||
if ($("#editor-detached").length) self.props.attach();
|
||||
if (DOM.query("#editor-detached")) self.props.attach();
|
||||
BDV2.reactDom.unmountComponentAtNode(self.root);
|
||||
self.root.remove();
|
||||
break;
|
||||
|
@ -163,10 +163,8 @@ export default class V2C_CssEditorDetached extends BDV2.reactComponent {
|
|||
}
|
||||
|
||||
updateCss() {
|
||||
if ($("#customcss").length == 0) {
|
||||
$("head").append("<style id=\"customcss\"></style>");
|
||||
}
|
||||
$("#customcss").text(this.editor.session.getValue()).detach().appendTo(document.head);
|
||||
DOM.removeStyle("customcss");
|
||||
DOM.addStyle("customcss", this.editor.session.getValue());
|
||||
}
|
||||
|
||||
saveCss() {
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
import BDV2 from "../modules/v2";
|
||||
|
||||
export default class V2C_Layer extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
$(window).on(`keyup.${this.props.id}`, e => {
|
||||
if (e.which === 27) {
|
||||
BDV2.reactDom.unmountComponentAtNode(this.refs.root.parentNode);
|
||||
}
|
||||
});
|
||||
|
||||
$(`#${this.props.id}`).animate({opacity: 1}, {
|
||||
step: function(now) {
|
||||
$(this).css("transform", `scale(${1.1 - 0.1 * now}) translateZ(0px)`);
|
||||
},
|
||||
duration: 200,
|
||||
done: () => {$(`#${this.props.id}`).css("opacity", "").css("transform", "");}
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
$(window).off(`keyup.${this.props.id}`);
|
||||
$(`#${this.props.id}`).animate({opacity: 0}, {
|
||||
step: function(now) {
|
||||
$(this).css("transform", `scale(${1.1 - 0.1 * now}) translateZ(0px)`);
|
||||
},
|
||||
duration: 200,
|
||||
done: () => {$(`#${this.props.rootId}`).remove();}
|
||||
});
|
||||
|
||||
$("[class*=\"layer-\"]").removeClass("publicServersOpen").animate({opacity: 1}, {
|
||||
step: function(now) {
|
||||
$(this).css("transform", `scale(${0.07 * now + 0.93}) translateZ(0px)`);
|
||||
},
|
||||
duration: 200,
|
||||
done: () => {$("[class*=\"layer-\"]").css("opacity", "").css("transform", "");}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
$("[class*=\"layer-\"]").addClass("publicServersOpen").animate({opacity: 0}, {
|
||||
step: function(now) {
|
||||
$(this).css("transform", `scale(${0.07 * now + 0.93}) translateZ(0px)`);
|
||||
},
|
||||
duration: 200
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "layer bd-layer layer-3QrUeG", id: this.props.id, ref: "root", style: {opacity: 0, transform: "scale(1.1) translateZ(0px)"}},
|
||||
this.props.children
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,257 +0,0 @@
|
|||
import {settingsCookie, pluginCookie, bdplugins} from "../0globals";
|
||||
import BDV2 from "../modules/v2";
|
||||
import pluginModule from "../modules/pluginModule";
|
||||
import Utils from "../modules/utils";
|
||||
|
||||
import XSvg from "./xSvg";
|
||||
import ReloadIcon from "./reloadIcon";
|
||||
import TooltipWrap from "./tooltipWrap";
|
||||
import Switch from "./components/switch";
|
||||
|
||||
const React = BDV2.React;
|
||||
|
||||
export default class V2C_PluginCard extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const self = this;
|
||||
self.onChange = self.onChange.bind(self);
|
||||
self.showSettings = self.showSettings.bind(self);
|
||||
self.setInitialState();
|
||||
self.hasSettings = typeof self.props.plugin.getSettingsPanel === "function";
|
||||
self.settingsPanel = "";
|
||||
|
||||
this.reload = this.reload.bind(this);
|
||||
this.onReload = this.onReload.bind(this);
|
||||
}
|
||||
|
||||
setInitialState() {
|
||||
this.state = {
|
||||
checked: pluginCookie[this.props.plugin.getName()],
|
||||
settings: false,
|
||||
reloads: 0
|
||||
};
|
||||
}
|
||||
|
||||
// componentDidMount() {
|
||||
// BDEvents.on("plugin-reloaded", this.onReload);
|
||||
// }
|
||||
|
||||
// componentWillUnmount() {
|
||||
// BDEvents.off("plugin-reloaded", this.onReload);
|
||||
// }
|
||||
|
||||
onReload(pluginName) {
|
||||
if (pluginName !== this.props.plugin.getName()) return;
|
||||
this.setState({reloads: this.state.reloads + 1});
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.settings) {
|
||||
if (typeof this.settingsPanel === "object") {
|
||||
this.refs.settingspanel.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 self = $(BDV2.reactDom.findDOMNode(this));
|
||||
const container = self.parents(".scroller");
|
||||
if (!isHidden(container[0], self[0])) return;
|
||||
container.animate({
|
||||
scrollTop: self.offset().top - container.offset().top + container.scrollTop() - 30
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
reload() {
|
||||
const plugin = this.props.plugin.getName();
|
||||
pluginModule.reloadPlugin(plugin);
|
||||
this.props.plugin = bdplugins[plugin].plugin;
|
||||
this.onReload(this.props.plugin.getName());
|
||||
}
|
||||
|
||||
getString(value) {
|
||||
if (!value) return "???";
|
||||
return typeof value == "string" ? value : value.toString();
|
||||
}
|
||||
|
||||
get settingsComponent() {
|
||||
const self = this;
|
||||
const {plugin} = this.props;
|
||||
const name = this.getString(plugin.getName());
|
||||
|
||||
try { self.settingsPanel = plugin.getSettingsPanel(); }
|
||||
catch (err) { Utils.err("Plugins", "Unable to get settings panel for " + plugin.getName() + ".", err); }
|
||||
|
||||
return BDV2.react.createElement("div", {className: "settings-open ui-switch-item bd-addon-card"},
|
||||
BDV2.react.createElement("div", {style: {"float": "right", "cursor": "pointer"}, onClick: () => {
|
||||
this.refs.settingspanel.innerHTML = "";
|
||||
self.setState({settings: false});
|
||||
}},
|
||||
BDV2.react.createElement(XSvg, null)
|
||||
),
|
||||
typeof self.settingsPanel === "object" && BDV2.react.createElement("div", {id: `plugin-settings-${name}`, className: "plugin-settings", ref: "settingspanel"}),
|
||||
typeof self.settingsPanel !== "object" && BDV2.react.createElement("div", {id: `plugin-settings-${name}`, className: "plugin-settings", ref: "settingspanel", dangerouslySetInnerHTML: {__html: self.settingsPanel}})
|
||||
);
|
||||
}
|
||||
|
||||
buildTitle(name, version, author) {
|
||||
const title = "{{name}} v{{version}} by {{author}}".split(/({{[A-Za-z]+}})/);
|
||||
const nameIndex = title.findIndex(s => s == "{{name}}");
|
||||
if (nameIndex) title[nameIndex] = React.createElement("span", {className: "bd-name bda-name"}, name);
|
||||
const versionIndex = title.findIndex(s => s == "{{version}}");
|
||||
if (nameIndex) title[versionIndex] = React.createElement("span", {className: "bd-version bda-version"}, version);
|
||||
const authorIndex = title.findIndex(s => s == "{{author}}");
|
||||
if (nameIndex) {
|
||||
const props = {className: "bd-author bda-author"};
|
||||
if (author.link || author.id) {
|
||||
props.className += ` ${BDV2.anchorClasses.anchor} ${BDV2.anchorClasses.anchorUnderlineOnHover}`;
|
||||
props.target = "_blank";
|
||||
|
||||
if (author.link) props.href = author.link;
|
||||
if (author.id) props.onClick = () => {BDV2.LayerStack.popLayer(); BDV2.openDM(author.id);};
|
||||
}
|
||||
title[authorIndex] = React.createElement(author.link || author.id ? "a" : "span", props, author.name);
|
||||
}
|
||||
return title.flat();
|
||||
}
|
||||
|
||||
makeLink(title, url) {
|
||||
const props = {className: "bda-link bda-link-website", target: "_blank"};
|
||||
if (typeof(url) == "string") props.href = url;
|
||||
if (typeof(url) == "function") props.onClick = (event) => {event.preventDefault(); event.stopPropagation(); url();};
|
||||
return BDV2.react.createElement("a", props, title);
|
||||
}
|
||||
|
||||
makeButton(title, children, action) {
|
||||
return <TooltipWrap color="black" position="top" text={title}>
|
||||
{(props) => {
|
||||
return <div {...props} className="bd-addon-button" onClick={action}>{children}</div>;
|
||||
}}
|
||||
</TooltipWrap>;
|
||||
}
|
||||
|
||||
getLinks(meta) {
|
||||
const links = [];
|
||||
if (meta.website) links.push(this.makeLink("Website", meta.website));
|
||||
if (meta.source) links.push(this.makeLink("Source", meta.source));
|
||||
if (meta.invite) {
|
||||
links.push(this.makeLink("Support Server", () => {
|
||||
const tester = /\.gg\/(.*)$/;
|
||||
let code = meta.invite;
|
||||
if (tester.test(code)) code = code.match(tester)[1];
|
||||
BDV2.LayerStack.popLayer();
|
||||
BDV2.InviteActions.acceptInviteAndTransitionToInviteChannel(code);
|
||||
}));
|
||||
}
|
||||
if (meta.donate) links.push(this.makeLink("Donate", meta.donate));
|
||||
if (meta.patreon) links.push(this.makeLink("Patreon", meta.patreon));
|
||||
return links;
|
||||
}
|
||||
|
||||
getFooter(meta) {
|
||||
const links = this.getLinks(meta);
|
||||
return (links.length || this.hasSettings) && BDV2.react.createElement("div", {className: "bda-footer"},
|
||||
BDV2.react.createElement("span", {className: "bda-links"},
|
||||
...(links.map((element, index) => index < links.length - 1 ? [element, " | "] : element).flat())
|
||||
),
|
||||
this.hasSettings && BDV2.react.createElement("button", {onClick: this.showSettings, className: "bda-settings-button", disabled: !this.state.checked}, "Settings")
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.settings) return this.settingsComponent;
|
||||
|
||||
const {plugin} = this.props;
|
||||
const name = this.getString(plugin.getName());
|
||||
const author = this.getString(plugin.getAuthor());
|
||||
const description = this.getString(plugin.getDescription());
|
||||
const version = this.getString(plugin.getVersion());
|
||||
const meta = bdplugins[name];
|
||||
|
||||
return BDV2.react.createElement("div", {"data-name": name, "data-version": version, "className": "settings-closed ui-switch-item bd-addon-card"},
|
||||
BDV2.react.createElement("div", {className: "bd-addon-header bda-header"},
|
||||
BDV2.react.createElement("div", {className: "bd-title bda-header-title"}, this.buildTitle(name, version, {name: author, id: meta.authorId, link: meta.authorLink})),
|
||||
BDV2.react.createElement("div", {className: "bd-addon-controls bda-controls"},
|
||||
!settingsCookie["fork-ps-5"] && BDV2.react.createElement(TooltipWrap(ReloadIcon, {color: "black", side: "top", text: "Reload"}), {className: "bd-reload-card", onClick: this.reload}),
|
||||
React.createElement(Switch, {onChange: this.onChange, checked: this.state.checked})
|
||||
// BDV2.react.createElement("label", {className: "ui-switch-wrapper ui-flex-child", style: {flex: "0 0 auto"}},
|
||||
// BDV2.react.createElement("input", {checked: this.state.checked, onChange: this.onChange, className: "ui-switch-checkbox", type: "checkbox"}),
|
||||
// BDV2.react.createElement("div", {className: this.state.checked ? "ui-switch checked" : "ui-switch"})
|
||||
// )
|
||||
)
|
||||
),
|
||||
BDV2.react.createElement("div", {className: "bd-scroller-wrap bda-description-wrap scroller-wrap fade"},
|
||||
BDV2.react.createElement("div", {className: "bd-addon-description bda-description scroller"}, description)
|
||||
),
|
||||
this.getFooter(meta)
|
||||
);
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.setState({checked: !this.state.checked});
|
||||
pluginModule.togglePlugin(this.props.plugin.getName());
|
||||
}
|
||||
|
||||
showSettings() {
|
||||
if (!this.hasSettings) return;
|
||||
this.setState({settings: true});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// <div className="bd-controls">
|
||||
// {this.props.editAddon && this.makeButton(Strings.Addons.editAddon, <EditIcon />, this.props.editAddon)}
|
||||
// {this.props.deleteAddon && this.makeButton(Strings.Addons.deleteAddon, <DeleteIcon />, this.props.deleteAddon)}
|
||||
// {this.props.showReloadIcon && this.makeButton(Strings.Addons.reload, <ReloadIcon className="bd-reload bd-reload-card" />, this.reload)}
|
||||
// <Switch checked={this.props.enabled} onChange={this.onChange} />
|
||||
// </div>
|
||||
|
||||
|
||||
|
||||
// componentDidUpdate() {
|
||||
// if (!this.state.settingsOpen) return;
|
||||
// if (this.settingsPanel instanceof Node) this.panelRef.current.appendChild(this.settingsPanel);
|
||||
|
||||
// // if (!SettingsCookie["fork-ps-3"]) return;
|
||||
// const isHidden = (container, element) => {
|
||||
// const cTop = container.scrollTop;
|
||||
// const cBottom = cTop + container.clientHeight;
|
||||
// const eTop = element.offsetTop;
|
||||
// const eBottom = eTop + element.clientHeight;
|
||||
// return (eTop < cTop || eBottom > cBottom);
|
||||
// };
|
||||
|
||||
// const panel = $(this.panelRef.current);
|
||||
// const container = panel.parents(".scroller-2FKFPG");
|
||||
// if (!isHidden(container[0], panel[0])) return;
|
||||
// container.animate({
|
||||
// scrollTop: panel.offset().top - container.offset().top + container.scrollTop() - 30
|
||||
// }, 300);
|
||||
// }
|
||||
|
||||
|
||||
// get settingsComponent() {
|
||||
// const addon = this.props.addon;
|
||||
// const name = this.getString(addon.name);
|
||||
// try { this.settingsPanel = this.props.getSettingsPanel(); }
|
||||
// catch (err) { Logger.stacktrace("Addon Settings", "Unable to get settings panel for " + name + ".", err); }
|
||||
|
||||
// const props = {id: `${name}-settings`, className: "addon-settings", ref: this.panelRef};
|
||||
// if (typeof(settingsPanel) == "string") props.dangerouslySetInnerHTML = this.settingsPanel;
|
||||
|
||||
// return <div className="bd-addon-card settings-open bd-switch-item">
|
||||
// <div className="bd-close" onClick={this.closeSettings}><CloseButton /></div>
|
||||
// <div {...props}>{this.settingsPanel instanceof React.Component ? this.settingsPanel : null}</div>
|
||||
// </div>;
|
||||
// }
|
|
@ -0,0 +1,89 @@
|
|||
import BDV2 from "../../modules/v2";
|
||||
import DOM from "../../modules/domtools";
|
||||
|
||||
export default class V2C_Layer extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.keyupListener = this.keyupListener.bind(this);
|
||||
}
|
||||
|
||||
keyupListener(e) {
|
||||
if (e.which === 27) {
|
||||
BDV2.reactDom.unmountComponentAtNode(this.refs.root.parentNode);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener("keyup", this.keyupListener);
|
||||
|
||||
const thisNode = DOM.query(`#${this.props.id}`);
|
||||
DOM.animate({
|
||||
duration: 200,
|
||||
update: function(progress) {
|
||||
thisNode.style.transform = `scale(${1.1 - 0.1 * progress}) translateZ(0px)`;
|
||||
thisNode.style.opacity = progress;
|
||||
if (progress == 1) {
|
||||
setImmediate(() => {
|
||||
thisNode.style.transform = "";
|
||||
thisNode.style.opacity = "";
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("keyup", this.keyupListener);
|
||||
|
||||
const thisNode = DOM.query(`#${this.props.id}`);
|
||||
DOM.animate({
|
||||
duration: 200,
|
||||
update: function(progress) {
|
||||
thisNode.style.transform = `scale(${1.1 - 0.1 * (1 - progress)}) translateZ(0px)`;
|
||||
thisNode.style.opacity = 1 - progress;
|
||||
if (progress == 1) {
|
||||
setImmediate(() => {
|
||||
thisNode.remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const layer = DOM.query(".publicServersOpen");
|
||||
layer.classList.remove("publicServersOpen");
|
||||
DOM.animate({
|
||||
duration: 200,
|
||||
update: function(progress) {
|
||||
layer.style.transform = `scale(${0.07 * progress + 0.93}) translateZ(0px)`;
|
||||
layer.style.opacity = progress;
|
||||
if (progress == 1) {
|
||||
setImmediate(() => {
|
||||
layer.style.transform = "";
|
||||
layer.style.opacity = "";
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
const layer = DOM.query("[class*=\"layer-\"]");
|
||||
layer.classList.add("publicServersOpen");
|
||||
DOM.animate({
|
||||
duration: 200,
|
||||
update: function(progress) {
|
||||
layer.style.transform = `scale(${0.07 * (1 - progress) + 0.93}) translateZ(0px)`;
|
||||
layer.style.opacity = 1 - progress;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "layer bd-layer layer-3QrUeG", id: this.props.id, ref: "root", style: {opacity: 0, transform: "scale(1.1) translateZ(0px)"}},
|
||||
this.props.children
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
import BDV2 from "../modules/v2";
|
||||
import BDV2 from "../../modules/v2";
|
||||
|
||||
import Tools from "../tools";
|
||||
import SettingsTitle from "../settingsTitle";
|
||||
import TabBarSeparator from "../tabBarSeparator";
|
||||
import TabBarHeader from "../tabBarHeader";
|
||||
import TabBarItem from "../tabBarItem";
|
||||
|
||||
import Tools from "./tools";
|
||||
import ServerCard from "./serverCard";
|
||||
import SidebarView from "./sidebarView";
|
||||
import SettingsTitle from "./settingsTitle";
|
||||
import TabBarSeparator from "./tabBarSeparator";
|
||||
import TabBarHeader from "./tabBarHeader";
|
||||
import TabBarItem from "./tabBarItem";
|
||||
|
||||
export default class V2C_PublicServers extends BDV2.reactComponent {
|
||||
|
||||
|
@ -51,76 +52,68 @@ export default class V2C_PublicServers extends BDV2.reactComponent {
|
|||
|
||||
search(query, clear) {
|
||||
const self = this;
|
||||
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: `${self.endPoint}${query}${query ? "&schema=new" : "?schema=new"}`,
|
||||
success: data => {
|
||||
let servers = data.results.reduce((arr, server) => {
|
||||
server.joined = false;
|
||||
arr.push(server);
|
||||
// arr.push(<ServerCard server={server} join={self.join}/>);
|
||||
return arr;
|
||||
}, []);
|
||||
|
||||
if (!clear) {
|
||||
servers = self.state.servers.concat(servers);
|
||||
}
|
||||
else {
|
||||
//servers.unshift(self.bdServer);
|
||||
}
|
||||
|
||||
let end = data.size + data.from;
|
||||
data.next = `?from=${end}`;
|
||||
if (self.state.term) data.next += `&term=${self.state.term}`;
|
||||
if (self.state.selectedCategory) data.next += `&category=${self.categoryButtons[self.state.selectedCategory]}`;
|
||||
if (end >= data.total) {
|
||||
end = data.total;
|
||||
data.next = null;
|
||||
}
|
||||
|
||||
let title = `Showing 1-${end} of ${data.total} results in ${self.categoryButtons[self.state.selectedCategory]}`;
|
||||
if (self.state.term) title += ` for ${self.state.term}`;
|
||||
|
||||
self.setState({
|
||||
loading: false,
|
||||
title: title,
|
||||
servers: servers,
|
||||
next: data.next
|
||||
});
|
||||
|
||||
if (clear) {
|
||||
//console.log(self);
|
||||
self.refs.sbv.refs.contentScroller.scrollTop = 0;
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
self.setState({
|
||||
const request = require("request");
|
||||
request.get({url: `${self.endPoint}${query}${query ? "&schema=new" : "?schema=new"}`, json: true}, function (err, resp, data) {
|
||||
if (err) {
|
||||
return self.setState({
|
||||
loading: false,
|
||||
title: "Failed to load servers. Check console for details"
|
||||
});
|
||||
}
|
||||
let servers = data.results.reduce((arr, server) => {
|
||||
server.joined = false;
|
||||
arr.push(server);
|
||||
// arr.push(<ServerCard server={server} join={self.join}/>);
|
||||
return arr;
|
||||
}, []);
|
||||
|
||||
if (!clear) {
|
||||
servers = self.state.servers.concat(servers);
|
||||
}
|
||||
else {
|
||||
//servers.unshift(self.bdServer);
|
||||
}
|
||||
|
||||
let end = data.size + data.from;
|
||||
data.next = `?from=${end}`;
|
||||
if (self.state.term) data.next += `&term=${self.state.term}`;
|
||||
if (self.state.selectedCategory) data.next += `&category=${self.categoryButtons[self.state.selectedCategory]}`;
|
||||
if (end >= data.total) {
|
||||
end = data.total;
|
||||
data.next = null;
|
||||
}
|
||||
|
||||
let title = `Showing 1-${end} of ${data.total} results in ${self.categoryButtons[self.state.selectedCategory]}`;
|
||||
if (self.state.term) title += ` for ${self.state.term}`;
|
||||
|
||||
self.setState({
|
||||
loading: false,
|
||||
title: title,
|
||||
servers: servers,
|
||||
next: data.next
|
||||
});
|
||||
|
||||
if (clear) {
|
||||
//console.log(self);
|
||||
self.refs.sbv.refs.contentScroller.scrollTop = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
join(serverCard) {
|
||||
async join(serverCard) {
|
||||
if (serverCard.props.pinned) return this.InviteActions.acceptInvite(serverCard.props.invite_code);
|
||||
$.ajax({
|
||||
|
||||
await fetch(`${this.joinEndPoint}/${serverCard.props.server.identifier}`,{
|
||||
method: "GET",
|
||||
url: `${this.joinEndPoint}/${serverCard.props.server.identifier}`,
|
||||
credentials: "include",
|
||||
mode: "cors",
|
||||
headers: {
|
||||
"Accept": "application/json;",
|
||||
"Content-Type": "application/json;" ,
|
||||
"x-discord-token": this.state.connection.user.accessToken
|
||||
},
|
||||
crossDomain: true,
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
},
|
||||
success: () => {
|
||||
serverCard.setState({joined: true});
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
serverCard.setState({joined: true});
|
||||
}
|
||||
|
||||
connect() {
|
||||
|
@ -187,44 +180,27 @@ export default class V2C_PublicServers extends BDV2.reactComponent {
|
|||
return "https://join.discordservers.com/connect";
|
||||
}
|
||||
|
||||
checkConnection() {
|
||||
async checkConnection() {
|
||||
const self = this;
|
||||
try {
|
||||
$.ajax({
|
||||
const response = await fetch(`https://auth.discordservers.com/info`,{
|
||||
method: "GET",
|
||||
url: `https://auth.discordservers.com/info`,
|
||||
credentials: "include",
|
||||
mode: "cors",
|
||||
headers: {
|
||||
"Accept": "application/json;",
|
||||
"Content-Type": "application/json;"
|
||||
},
|
||||
crossDomain: true,
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
},
|
||||
success: data => {
|
||||
// Utils.log("PublicServer", "Got data: " + JSON.stringify(data));
|
||||
self.setState({
|
||||
selectedCategory: 0,
|
||||
connection: {
|
||||
state: 2,
|
||||
user: data
|
||||
}
|
||||
});
|
||||
self.search("", true);
|
||||
|
||||
},
|
||||
error: () => {
|
||||
self.setState({
|
||||
title: "Not connected to discordservers.com!",
|
||||
loading: true,
|
||||
selectedCategory: -1,
|
||||
connection: {
|
||||
state: 1,
|
||||
user: null
|
||||
}
|
||||
});
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
self.setState({
|
||||
selectedCategory: 0,
|
||||
connection: {
|
||||
state: 2,
|
||||
user: data
|
||||
}
|
||||
});
|
||||
self.search("", true);
|
||||
}
|
||||
catch (error) {
|
||||
self.setState({
|
||||
|
@ -240,7 +216,7 @@ export default class V2C_PublicServers extends BDV2.reactComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
return BDV2.react.createElement(SidebarView, {ref: "sbv", children: this.component});
|
||||
return BDV2.react.createElement(SidebarView, {ref: "sbv"}, this.component);
|
||||
}
|
||||
|
||||
get component() {
|
|
@ -1,4 +1,4 @@
|
|||
import BDV2 from "../modules/v2";
|
||||
import BDV2 from "../../modules/v2";
|
||||
|
||||
export default class V2C_ServerCard extends BDV2.reactComponent {
|
||||
constructor(props) {
|
|
@ -1,6 +1,6 @@
|
|||
import BDV2 from "../modules/v2";
|
||||
import BDV2 from "../../modules/v2";
|
||||
|
||||
import Scroller from "./scroller";
|
||||
import Scroller from "../scroller";
|
||||
|
||||
export default class V2C_SidebarView extends BDV2.reactComponent {
|
||||
|
||||
|
@ -16,7 +16,7 @@ export default class V2C_SidebarView extends BDV2.reactComponent {
|
|||
BDV2.react.createElement(
|
||||
"div",
|
||||
{className: "sidebarRegion-VFTUkN sidebar-region"},
|
||||
BDV2.react.createElement(Scroller, {key: "sidebarScroller", ref: "sidebarScroller", sidebar: true, fade: sidebar.fade || true, dark: sidebar.dark || true, children: sidebar.component})
|
||||
BDV2.react.createElement(Scroller, {key: "sidebarScroller", ref: "sidebarScroller", sidebar: true, fade: sidebar.fade || true, dark: sidebar.dark || true}, sidebar.component)
|
||||
),
|
||||
BDV2.react.createElement("div", {className: "contentRegion-3nDuYy content-region"},
|
||||
BDV2.react.createElement("div", {className: "contentTransitionWrap-3hqOEW content-transition-wrap"},
|
|
@ -8,18 +8,22 @@ export default class V2C_SideBar extends BDV2.reactComponent {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const self = this;
|
||||
const si = $("[class*=side-] > [class*=selected]");
|
||||
if (si.length) self.scn = si.attr("class");
|
||||
const ns = $("[class*=side-] > [class*='item-']:not([class*=selected])");
|
||||
if (ns.length) self.nscn = ns.attr("class");
|
||||
$("[class*='side-'] > [class*='item-']").on("click", () => {
|
||||
self.setState({
|
||||
selected: null
|
||||
const si = document.querySelector("[class*=side-] > [class*=selected]");
|
||||
if (si) this.scn = si.className;
|
||||
const ns = document.querySelector("[class*=side-] > [class*='item-']:not([class*=selected])");
|
||||
if (ns) this.nscn = ns.className;
|
||||
const tabs = document.querySelectorAll("[class*='side-'] > [class*='item-']");
|
||||
for (const element of tabs) {
|
||||
element.addEventListener("click", () => {
|
||||
this.setState({
|
||||
selected: null
|
||||
});
|
||||
});
|
||||
});
|
||||
self.setInitialState();
|
||||
self.onClick = self.onClick.bind(self);
|
||||
}
|
||||
|
||||
this.setInitialState();
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.setSelected = this.setSelected.bind(this);
|
||||
}
|
||||
|
||||
setInitialState() {
|
||||
|
@ -53,19 +57,21 @@ export default class V2C_SideBar extends BDV2.reactComponent {
|
|||
);
|
||||
}
|
||||
|
||||
setSelected(e) {
|
||||
e.target.className = this.scn;
|
||||
}
|
||||
|
||||
onClick(id) {
|
||||
const self = this;
|
||||
const si = $("[class*=side] > [class*=selected]");
|
||||
if (si.length) {
|
||||
si.off("click.bdsb").on("click.bsb", e => {
|
||||
$(e.target).attr("class", self.scn);
|
||||
});
|
||||
si.attr("class", self.nscn);
|
||||
const si = document.querySelector("[class*=side] > [class*=selected]");
|
||||
if (si) {
|
||||
si.removeEventListener("click", this.setSelected);
|
||||
si.addEventListener("click", this.setSelected);
|
||||
si.className = this.nscn;
|
||||
}
|
||||
|
||||
self.setState({selected: null});
|
||||
self.setState({selected: id});
|
||||
this.setState({selected: null});
|
||||
this.setState({selected: id});
|
||||
|
||||
if (self.props.onClick) self.props.onClick(id);
|
||||
if (this.props.onClick) this.props.onClick(id);
|
||||
}
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
import {settingsCookie, themeCookie, bdthemes} from "../0globals";
|
||||
import Utils from "../modules/utils";
|
||||
import BDV2 from "../modules/v2";
|
||||
import themeModule from "../modules/themeModule";
|
||||
|
||||
import ReloadIcon from "./reloadIcon";
|
||||
import TooltipWrap from "./tooltipWrap";
|
||||
|
||||
export default class V2C_ThemeCard extends BDV2.reactComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.setInitialState();
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.reload = this.reload.bind(this);
|
||||
}
|
||||
|
||||
setInitialState() {
|
||||
this.state = {
|
||||
checked: themeCookie[this.props.theme.name],
|
||||
reloads: 0
|
||||
};
|
||||
}
|
||||
|
||||
// componentDidMount() {
|
||||
// BDEvents.on("theme-reloaded", this.onReload);
|
||||
// }
|
||||
|
||||
// componentWillUnmount() {
|
||||
// BDEvents.off("theme-reloaded", this.onReload);
|
||||
// }
|
||||
|
||||
onReload(themeName) {
|
||||
if (themeName !== this.props.theme.name) return;
|
||||
this.setState({reloads: this.state.reloads + 1});
|
||||
}
|
||||
|
||||
reload() {
|
||||
const theme = this.props.theme.name;
|
||||
const error = themeModule.reloadTheme(theme);
|
||||
if (error) Utils.showToast(`Could not reload ${bdthemes[theme].name}. Check console for details.`, {type: "error"});
|
||||
else Utils.showToast(`${bdthemes[theme].name} v${bdthemes[theme].version} has been reloaded.`, {type: "success"});
|
||||
// this.setState(this.state);
|
||||
this.props.theme = bdthemes[theme];
|
||||
this.onReload(this.props.theme.name);
|
||||
}
|
||||
|
||||
makeLink(title, url) {
|
||||
const props = {className: "bda-link bda-link-website", target: "_blank"};
|
||||
if (typeof(url) == "string") props.href = url;
|
||||
if (typeof(url) == "function") props.onClick = (event) => {event.preventDefault(); event.stopPropagation(); url();};
|
||||
return BDV2.react.createElement("a", props, title);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {theme} = this.props;
|
||||
const name = theme.name;
|
||||
const description = theme.description;
|
||||
const version = theme.version;
|
||||
const author = theme.author;
|
||||
const meta = bdthemes[name];
|
||||
|
||||
const links = [];
|
||||
if (meta.website) links.push(this.makeLink("Website", meta.website));
|
||||
if (meta.source) links.push(this.makeLink("Source", meta.source));
|
||||
if (meta.invite) {
|
||||
links.push(this.makeLink("Support Server", () => {
|
||||
const tester = /\.gg\/(.*)$/;
|
||||
let code = meta.invite;
|
||||
if (tester.test(code)) code = code.match(tester)[1];
|
||||
BDV2.LayerStack.popLayer();
|
||||
BDV2.InviteActions.acceptInviteAndTransitionToInviteChannel(code);
|
||||
}));
|
||||
}
|
||||
if (meta.donate) links.push(this.makeLink("Donate", meta.donate));
|
||||
if (meta.patreon) links.push(this.makeLink("Patreon", meta.patreon));
|
||||
|
||||
const authorProps = {className: "bda-author"};
|
||||
if (meta.authorLink || meta.authorId) {
|
||||
authorProps.className += ` ${BDV2.anchorClasses.anchor} ${BDV2.anchorClasses.anchorUnderlineOnHover}`;
|
||||
authorProps.target = "_blank";
|
||||
|
||||
if (meta.authorLink) authorProps.href = meta.authorLink;
|
||||
if (meta.authorId) authorProps.onClick = () => {BDV2.LayerStack.popLayer(); BDV2.openDM(meta.authorId);};
|
||||
}
|
||||
|
||||
return BDV2.react.createElement("div", {"data-name": name, "data-version": version, "className": "settings-closed ui-switch-item bd-addon-card"},
|
||||
BDV2.react.createElement("div", {className: "bda-header"},
|
||||
BDV2.react.createElement("span", {className: "bda-header-title"},
|
||||
BDV2.react.createElement("span", {className: "bda-name"}, name),
|
||||
" v",
|
||||
BDV2.react.createElement("span", {className: "bda-version"}, version),
|
||||
" by ",
|
||||
BDV2.react.createElement(meta.authorLink || meta.authorId ? "a" : "span", authorProps, author)
|
||||
),
|
||||
BDV2.react.createElement("div", {className: "bda-controls"},
|
||||
!settingsCookie["fork-ps-5"] && BDV2.react.createElement(TooltipWrap(ReloadIcon, {color: "black", side: "top", text: "Reload"}), {className: "bd-reload-card", onClick: this.reload}),
|
||||
BDV2.react.createElement("label", {className: "ui-switch-wrapper ui-flex-child", style: {flex: "0 0 auto"}},
|
||||
BDV2.react.createElement("input", {checked: this.state.checked, onChange: this.onChange, className: "ui-switch-checkbox", type: "checkbox"}),
|
||||
BDV2.react.createElement("div", {className: this.state.checked ? "ui-switch checked" : "ui-switch"})
|
||||
)
|
||||
)
|
||||
),
|
||||
BDV2.react.createElement("div", {className: "bda-description-wrap scroller-wrap fade"},
|
||||
BDV2.react.createElement("div", {className: "bda-description scroller"}, description)
|
||||
),
|
||||
(!!links.length) && BDV2.react.createElement("div", {className: "bda-footer"},
|
||||
BDV2.react.createElement("span", {className: "bda-links"},
|
||||
...(links.map((element, index) => index < links.length - 1 ? [element, " | "] : element).flat())
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.setState({checked: !this.state.checked});
|
||||
themeModule.toggleTheme(this.props.theme.name);
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ export default class V2C_Tools extends BDV2.reactComponent {
|
|||
if (this.props.onClick) {
|
||||
this.props.onClick();
|
||||
}
|
||||
$(".closeButton-1tv5uR").first().click();
|
||||
const closeButton = document.querySelector(".closeButton-1tv5uR");
|
||||
if (closeButton) closeButton.click();
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
import Utils from "../modules/utils";
|
||||
import WebpackModules from "../modules/webpackModules";
|
||||
import DOM from "../modules/domtools";
|
||||
|
||||
const TooltipClasses = WebpackModules.findByProps("tooltip", "tooltipBlack");
|
||||
const TooltipLayers = WebpackModules.findByProps("layer", "layerContainer");
|
||||
|
@ -62,8 +63,8 @@ export default class EmulatedTooltip {
|
|||
if (!classExists(this.side)) return Utils.err("EmulatedTooltip", `Side ${this.side} does not exist.`);
|
||||
if (!classExists(this.style)) return Utils.err("EmulatedTooltip", `Style ${this.style} does not exist.`);
|
||||
|
||||
this.element = $(`<div class="${TooltipLayers.layer}">`)[0];
|
||||
this.tooltipElement = $(`<div class="${TooltipClasses.tooltip} ${getClass(this.style)}"><div class="${TooltipClasses.tooltipPointer}"></div>${this.label}</div>`)[0];
|
||||
this.element = DOM.createElement(`<div class="${TooltipLayers.layer}">`);
|
||||
this.tooltipElement = DOM.createElement(`<div class="${TooltipClasses.tooltip} ${getClass(this.style)}"><div class="${TooltipClasses.tooltipPointer}"></div>${this.label}</div>`);
|
||||
this.labelElement = this.tooltipElement.childNodes[1];
|
||||
this.element.append(this.tooltipElement);
|
||||
|
||||
|
|
Loading…
Reference in New Issue