BetterDiscordApp-rauenzi/src/modules/utilities.js

165 lines
5.8 KiB
JavaScript
Raw Normal View History

2019-06-04 21:17:23 +02:00
/* eslint-disable no-console */
2019-05-29 05:48:41 +02:00
export default class Utilities {
2019-05-28 20:19:48 +02:00
static stripBOM(content) {
if (content.charCodeAt(0) === 0xFEFF) {
content = content.slice(1);
}
return content;
}
static getTextArea() {
return $(".channelTextArea-1LDbYG textarea");
}
static getInternalInstance(node) {
return node[Object.keys(node).find(k => k.startsWith("__reactInternalInstance"))] || null;
}
static insertText(textarea, text) {
textarea.focus();
textarea.selectionStart = 0;
textarea.selectionEnd = textarea.value.length;
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) {
2019-06-19 05:09:49 +02:00
return id.replace(/^[^a-z]+|[^\w-]+/gi, "-");
2019-05-28 20:19:48 +02:00
}
static escape(s) {
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
}
static testJSON(data) {
try {
2019-06-19 21:24:05 +02:00
return JSON.parse(data);
2019-05-28 20:19:48 +02:00
}
catch (err) {
return false;
}
}
static suppressErrors(method, message) {
return (...params) => {
try { return method(...params); }
catch (e) { this.err("SuppressedError", "Error occurred in " + message, e); }
};
}
static monkeyPatch(what, methodName, options) {
const {before, after, instead, once = false, silent = false, force = false} = options;
const displayName = options.displayName || what.displayName || what.name || what.constructor.displayName || what.constructor.name;
if (!silent) console.log("patch", methodName, "of", displayName); // eslint-disable-line no-console
if (!what[methodName]) {
if (force) what[methodName] = function() {};
else return console.error(methodName, "does not exist for", displayName); // eslint-disable-line no-console
}
const origMethod = what[methodName];
const cancel = () => {
if (!silent) console.log("unpatch", methodName, "of", displayName); // eslint-disable-line no-console
what[methodName] = origMethod;
};
what[methodName] = function() {
const data = {
thisObject: this,
methodArguments: arguments,
cancelPatch: cancel,
originalMethod: origMethod,
callOriginalMethod: () => data.returnValue = data.originalMethod.apply(data.thisObject, data.methodArguments)
};
if (instead) {
2019-05-29 05:48:41 +02:00
const tempRet = Utilities.suppressErrors(instead, "`instead` callback of " + what[methodName].displayName)(data);
2019-05-28 20:19:48 +02:00
if (tempRet !== undefined) data.returnValue = tempRet;
}
else {
2019-05-29 05:48:41 +02:00
if (before) Utilities.suppressErrors(before, "`before` callback of " + what[methodName].displayName)(data);
2019-05-28 20:19:48 +02:00
data.callOriginalMethod();
2019-05-29 05:48:41 +02:00
if (after) Utilities.suppressErrors(after, "`after` callback of " + what[methodName].displayName)(data);
2019-05-28 20:19:48 +02:00
}
if (once) cancel();
return data.returnValue;
};
what[methodName].__monkeyPatched = true;
if (!what[methodName].__originalMethod) what[methodName].__originalMethod = origMethod;
what[methodName].displayName = "patched " + (what[methodName].displayName || methodName);
return cancel;
}
static onRemoved(node, callback) {
const observer = new MutationObserver((mutations) => {
for (let m = 0; m < mutations.length; m++) {
const mutation = mutations[m];
const nodes = Array.from(mutation.removedNodes);
const directMatch = nodes.indexOf(node) > -1;
const parentMatch = nodes.some(parent => parent.contains(node));
if (directMatch || parentMatch) {
observer.disconnect();
callback();
}
}
});
observer.observe(document.body, {subtree: true, childList: true});
}
2019-06-07 22:27:44 +02:00
static isEmpty(obj) {
if (obj == null || obj == undefined || obj == "") return true;
if (typeof(obj) !== "object") return false;
if (Array.isArray(obj)) return obj.length == 0;
for (const key in obj) {
if (obj.hasOwnProperty(key)) return false;
}
return true;
}
2019-05-28 20:19:48 +02:00
/**
* Generates an automatically memoizing version of an object.
* @author Zerebos
* @param {Object} object - object to memoize
* @returns {Proxy} the proxy to the object that memoizes properties
*/
static memoizeObject(object) {
const proxy = new Proxy(object, {
get: function(obj, mod) {
if (!obj.hasOwnProperty(mod)) return undefined;
if (Object.getOwnPropertyDescriptor(obj, mod).get) {
2019-05-30 07:06:17 +02:00
const value = obj[mod];
2019-05-28 20:19:48 +02:00
delete obj[mod];
obj[mod] = value;
}
return obj[mod];
},
set: function(obj, mod, value) {
if (obj.hasOwnProperty(mod)) return this.err("MemoizedObject", "Trying to overwrite existing property");
obj[mod] = value;
return obj[mod];
}
});
Object.defineProperty(proxy, "hasOwnProperty", {value: function(prop) {
return this[prop] !== undefined;
}});
return proxy;
}
2019-05-29 05:48:41 +02:00
}