diff --git a/package.json b/package.json
index 5276c79..b93782b 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"scripts": {
"build": "tsc",
"build-dev": "tsc && for file in dist/*.js; do sed -i \"s/%RELEASE_TYPE%/ - Development/g\" \"$file\";done",
+ "build-dev-win": "tsc && sed -i \"s/%RELEASE_TYPE%/ - Development/g\" \"dist/*\" && del \"dist\\*.\"",
"prettify": "prettier --tab-width 4 --write \"src/**/*.ts\""
},
"devDependencies": {
diff --git a/src/EGO Forum Enhancement.ts b/src/EGO Forum Enhancement.ts
index f86ff8c..6f9864f 100644
--- a/src/EGO Forum Enhancement.ts
+++ b/src/EGO Forum Enhancement.ts
@@ -3,7 +3,7 @@
// @namespace https://github.com/blankdvth/eGOScripts/blob/master/src/EGO%20Forum%20Enhancement.ts
// @downloadURL %DOWNLOAD_URL%
// @updateURL %DOWNLOAD_URL%
-// @version 4.3.1
+// @version 4.4.0
// @description Add various enhancements & QOL additions to the EdgeGamers Forums that are beneficial for Leadership members.
// @author blank_dvth, Skle, MSWS
// @match https://www.edgegamers.com/*
@@ -35,6 +35,11 @@ interface OnHold_Map {
explain: string;
}
+interface CannedResponse {
+ name: string;
+ response: string;
+}
+
declare var SteamIDConverter: any;
const completedMap: Completed_Map[] = [];
@@ -42,6 +47,7 @@ const signatureBlockList: string[] = [];
const navbarURLs: NavbarURL_Map[] = [];
const onHoldTemplates: OnHold_Map[] = [];
const autoMentionForums: string[] = [];
+const cannedResponses: { [category: string]: CannedResponse[] } = {};
const contestReportForums: string[] = ["1233", "1234", "1235", "1236"];
/**
@@ -182,8 +188,7 @@ function setupForumsConfig() {
},
"move-to-completed": {
type: "hidden",
- default:
- "Contest a Ban ?$;1236\nReport a Player ?$;1235\nContact Leadership ?$;853",
+ default: "1234;1236\n1233;1235\n852;853",
},
"signature-block-unchecked": {
label: "Signature Block List",
@@ -234,8 +239,8 @@ function setupForumsConfig() {
"auto-mention-unchecked": {
label: "Auto Mention (Subforum IDs)",
section: [
- "Autofill",
- "Autofill various content into the post editor.",
+ "Automention",
+ "Automatically mention the OP in the editor in certain forums",
],
type: "textarea",
save: false,
@@ -251,10 +256,40 @@ function setupForumsConfig() {
default: true,
},
"auto-mention-focus": {
- label: "Autofocus after mentioning (only on load mode)",
+ label: "Focus after mentioning (only on load mode)",
type: "checkbox",
default: false,
},
+ "canned-responses-unchecked": {
+ label: "Canned Responses",
+ section: [
+ "Canned Responses",
+ "See this guide on how to format your canned responses.",
+ ],
+ type: "textarea",
+ save: false,
+ default: "",
+ },
+ "canned-responses": {
+ type: "hidden",
+ default: "",
+ },
+ "canned-response-min-width": {
+ label: "Minimum width of dropdown (in pixels)",
+ type: "int",
+ min: 0,
+ default: 125,
+ },
+ "canned-response-focus": {
+ label: "Focus after inserting canned response",
+ type: "checkbox",
+ default: true,
+ },
+ "canned-response-trigger-automention": {
+ label: "Attempt to trigger automention before inserting canned response",
+ type: "checkbox",
+ default: true,
+ },
},
events: {
init: function () {
@@ -275,6 +310,10 @@ function setupForumsConfig() {
"auto-mention-unchecked",
GM_config.get("auto-mention")
);
+ GM_config.set(
+ "canned-responses-unchecked",
+ GM_config.get("canned-responses")
+ );
},
open: function (doc) {
GM_config.fields[
@@ -356,6 +395,25 @@ function setupForumsConfig() {
)
GM_config.set("auto-mention", autoMention);
});
+ GM_config.fields[
+ "canned-responses-unchecked"
+ ].node?.addEventListener("change", function () {
+ const cannedResponses = GM_config.get(
+ "canned-responses-unchecked",
+ true
+ ) as string;
+ // Check if entire config matches the regex by matching all and rejoining the matches, then comparing to the original
+ if (
+ [
+ ...cannedResponses.matchAll(
+ /(?:===\n|^)- (?.+)\n- (?.+)\n(?(?:.|\n)+?)\n===/gm
+ ),
+ ]
+ .map((i) => i[0])
+ .join("\n") === cannedResponses
+ )
+ GM_config.set("canned-responses", cannedResponses);
+ });
},
save: function (forgotten) {
if (
@@ -390,6 +448,13 @@ function setupForumsConfig() {
alert(
"Invalid auto mention list. Ensure each ID is on it's own line and all IDs are numerical."
);
+ if (
+ forgotten["canned-responses-unchecked"] !==
+ GM_config.get("canned-responses")
+ )
+ alert(
+ "Invalid canned responses list. Ensure each response is in the proper format (see the wiki for more information)."
+ );
},
},
css: "textarea {width: 100%; height: 160px; resize: vertical;}",
@@ -507,6 +572,25 @@ function loadAutoMentionList() {
});
}
+/**
+ * Loads the canned responses from config
+ */
+function loadCannedResponses() {
+ const cannedResponsesRaw = GM_config.get("canned-responses") as string;
+ [
+ ...cannedResponsesRaw.matchAll(
+ /(?:===\n|^)- (?.+)\n- (?.+)\n(?(?:.|\n)+?)\n===/gm
+ ),
+ ].forEach((match) => {
+ const category = match.groups!.category;
+ if (!cannedResponses[category]) cannedResponses[category] = [];
+ cannedResponses[category].push({
+ name: match.groups!.name,
+ response: match.groups!.response,
+ });
+ });
+}
+
/**
* Adds a MAUL profile button to the given div
* @param {HTMLDivElement} div Div to add to
@@ -754,6 +838,36 @@ function editPostBox(text: string, append: boolean = false) {
}
}
+/**
+ * Get the ID of the current forum
+ * @returns {string} Forum ID
+ */
+function getForumId() {
+ return document
+ .getElementById("XF")!
+ .dataset.containerKey?.replace("node-", "");
+}
+
+/**
+ * Get the username of the current user
+ * @returns {string} Username of current user
+ */
+function getUsername() {
+ return (
+ document.querySelector(
+ "a.p-navgroup-link--user > span.p-navgroup-linkText"
+ ) as HTMLSpanElement | null
+ )?.innerText;
+}
+
+/**
+ * Get the username of the OP of the current thread
+ * @returns {string} Username of the OP
+ */
+function getOP() {
+ return document.querySelector("a.username") as HTMLAnchorElement | null;
+}
+
/**
* Generates large, transparent text (basically a watermark)
* @param {string} top CSS Top Style
@@ -775,13 +889,12 @@ function generateRedText(top: string, str: string = "Confidential") {
}
/**
- * Get the ID of the current forum
- * @returns {string} Forum ID
+ * Fills in placeholders in a canned response string with the proper data then returns it
*/
-function getForumId() {
- return document
- .getElementById("XF")!
- .dataset.containerKey?.replace("node-", "");
+function generateResponseText(response: string) {
+ return response
+ .replaceAll("{{{username}}}", getUsername() ?? "")
+ .replaceAll("{{{op username}}}", getOP()?.innerText ?? "");
}
/**
@@ -948,26 +1061,6 @@ function handleGenericThread() {
// Ban Contest or Report
handleBanReportContest();
- if (autoMentionForums.includes(forumId)) {
- const observer = new MutationObserver((mutations) => {
- mutations.forEach((mutation) => {
- if (!mutation.addedNodes) return;
-
- for (let i = 0; i < mutation.addedNodes.length; i++) {
- const node = mutation.addedNodes[i];
- if (node.nodeName === "DIV")
- handleAutoMention(observer);
- }
- });
- });
- observer.observe(document.body, {
- childList: true,
- subtree: true,
- attributes: false,
- characterData: false,
- });
- }
-
const button_group = document.querySelector("div.buttonGroup");
for (var i = 0; i < completedMap.length; i++) {
if (forumId == completedMap[i].originId) {
@@ -993,6 +1086,29 @@ function handleGenericThread() {
// LE Forums
handleLeadership();
+ const observer = new MutationObserver((mutations) => {
+ mutations.every((mutation) => {
+ // Using every so that we can return false to stop observing
+ if (!mutation.addedNodes) return true;
+
+ for (let i = 0; i < mutation.addedNodes.length; i++) {
+ const node = mutation.addedNodes[i];
+ if (node.nodeName === "DIV") {
+ handlePostBox(observer);
+ return false;
+ }
+ }
+
+ return true;
+ });
+ });
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true,
+ attributes: false,
+ characterData: false,
+ });
+
blockSignatures();
}
@@ -1140,7 +1256,7 @@ function handleLeadership() {
* @param focus Whether to focus the post box after mentioning the user
*/
function autoMention(focus: boolean) {
- const user = document.querySelector("a.username") as HTMLAnchorElement;
+ const user = getOP();
if (!user) return;
const username = user.innerText;
const userId = user.dataset.userId;
@@ -1150,23 +1266,125 @@ function autoMention(focus: boolean) {
}
/**
- * Handles adding auto mention functionality to the post box
- * @param {MutationObserver} observer
+ * Handles operations that should be performed when the post box is loaded
+ * @param observer
*/
-function handleAutoMention(observer: MutationObserver) {
+function handlePostBox(observer: MutationObserver) {
const postBox = document.querySelector("div.fr-box") as HTMLDivElement;
if (!postBox) return;
+ const forumId = getForumId();
observer.disconnect();
+
+ if (forumId && autoMentionForums.includes(forumId)) handleAutoMention();
+ handleCannedResponses();
+}
+
+/**
+ * Handles adding auto mention functionality to the post box
+ */
+function handleAutoMention() {
+ const postBox = document.querySelector("div.fr-box") as HTMLDivElement;
if (GM_config.get("auto-mention-onclick")) {
- postBox.addEventListener("click", function () {
+ function autoMentionListener() {
autoMention(true);
- });
+ postBox.removeEventListener("click", autoMentionListener);
+ }
+ postBox.addEventListener("click", autoMentionListener);
} else {
postBox.click();
autoMention(GM_config.get("auto-mention-focus") as boolean);
}
}
+/**
+ * Handles adding canned responses to the post box
+ */
+function handleCannedResponses() {
+ const bar = document.querySelector(
+ "div.formButtonGroup-extra"
+ ) as HTMLDivElement;
+ if (!bar) {
+ console.warn("Could not find post box button bar");
+ return;
+ }
+ Object.entries(cannedResponses).forEach((cannedResponse) => {
+ const [category, responses] = cannedResponse;
+ const dropdown = document.createElement("span");
+ dropdown.classList.add("p-navEl-splitTrigger"); // Adds various styling for dropdowns, technically for the navbar but it works here
+ dropdown.style.float = "none"; // Class makes it float left, so we need to override it
+ dropdown.style.textAlign = "center";
+ dropdown.style.lineHeight = bar.clientHeight + "px";
+ dropdown.style.paddingLeft = "8px";
+ dropdown.dataset.category = category;
+ dropdown.innerText = category;
+
+ var dropdownMenu = document.createElement("div");
+ dropdownMenu.classList.add(
+ "menu",
+ "menu--structural",
+ "menu--potentialFixed",
+ "menu--left"
+ );
+ dropdownMenu.style.zIndex = "800";
+ dropdownMenu.style.display = "none";
+ dropdownMenu.style.position = "fixed";
+ dropdownMenu.style.minWidth =
+ GM_config.get("canned-response-min-width") + "px";
+ dropdownMenu.style.overflow = "auto";
+ dropdownMenu.hidden = true;
+
+ dropdown.append(dropdownMenu);
+ dropdown.addEventListener("mouseover", function () {
+ var rect = dropdown.getBoundingClientRect();
+ dropdownMenu.hidden = false;
+ dropdownMenu.style.display = "block";
+ dropdownMenu.style.top = rect.bottom + "px";
+ dropdownMenu.style.left = rect.left + "px";
+ dropdownMenu.style.maxHeight =
+ window.innerHeight - rect.top - 25 + "px";
+ dropdownMenu.style.maxWidth =
+ window.innerWidth - rect.left - 25 + "px";
+ dropdownContent.style.maxHeight = dropdownMenu.style.maxHeight;
+ dropdownMenu.classList.add("is-active");
+ });
+ dropdown.addEventListener("mouseout", function () {
+ dropdownMenu.hidden = true;
+ dropdownMenu.style.display = "none";
+ dropdownMenu.classList.remove("is-active");
+ });
+
+ const dropdownContent = document.createElement("div");
+ dropdownContent.classList.add("menu-content");
+ dropdownContent.style.overflow = "none";
+ dropdownMenu.append(dropdownContent);
+ bar.append(dropdown);
+
+ responses.forEach((response) => {
+ const btn = document.createElement("a");
+ btn.classList.add("menu-linkRow", "u-indentDepth0");
+ btn.innerText = response.name;
+ btn.style.cursor = "pointer";
+ btn.style.paddingLeft = "4px";
+ btn.style.paddingRight = "0px";
+ btn.style.paddingTop = "1px";
+ btn.style.paddingBottom = "1px";
+ btn.addEventListener("click", function () {
+ const postBox = getPostBoxEl();
+ if (GM_config.get("canned-response-trigger-automention")) {
+ const forumId = getForumId();
+ if (forumId && autoMentionForums.includes(forumId))
+ autoMention(false);
+ }
+ editPostBox(generateResponseText(response.response), true);
+ dropdown.dispatchEvent(new MouseEvent("mouseout"));
+ postBox.dispatchEvent(new Event("autosize:update"));
+ if (GM_config.get("canned-response-focus")) postBox.focus();
+ });
+ dropdownContent.append(btn);
+ });
+ });
+}
+
/**
* Changes the target of the application links to open in a new tab
* @returns void
@@ -1419,6 +1637,7 @@ function blockSignatures() {
loadNavbarURLs();
loadOnHoldTemplates();
loadAutoMentionList();
+ loadCannedResponses();
// Determine what page we're on
const url = window.location.href;