|
1 | 1 | // ==UserScript== |
2 | 2 | // @name EdgeGamers Forum Enhancement%RELEASE_TYPE% |
3 | 3 | // @namespace https://github.com/blankdvth/eGOScripts/blob/master/src/EGO%20Forum%20Enhancement.ts |
4 | | -// @version 4.10.1 |
| 4 | +// @version 4.11.1 |
5 | 5 | // @description Add various enhancements & QOL additions to the EdgeGamers Forums that are beneficial for Leadership members. |
6 | 6 | // @author blank_dvth, Skle, MSWS, PixeL |
7 | 7 | // @match https://www.edgegamers.com/* |
@@ -207,6 +207,18 @@ function setupForumsConfig() { |
207 | 207 | type: "text", |
208 | 208 | default: "", |
209 | 209 | }, |
| 210 | + "enable-post-unapprove-btn": { |
| 211 | + label: "Enable post & unapprove button", |
| 212 | + title: "Whether to add a button that will safely post an unapproved reply.", |
| 213 | + type: "checkbox", |
| 214 | + default: true, |
| 215 | + }, |
| 216 | + "rich-override": { |
| 217 | + label: "Allow post & unapprove in rich editor (NOT SUPPORTED)", |
| 218 | + title: "The post & unapprove button in the rich editor is not supported, and will cause formatting issues in your message. If you want to use it anyway, check this box, no support will be provided.", |
| 219 | + type: "checkbox", |
| 220 | + default: false, |
| 221 | + }, |
210 | 222 | "move-to-completed-unchecked": { |
211 | 223 | label: "Completed Forums Map", |
212 | 224 | section: [ |
@@ -973,16 +985,14 @@ function addPostActionBarButtons() { |
973 | 985 | async function setPostApprovalStatus( |
974 | 986 | threadId: string, |
975 | 987 | postId: string, |
976 | | - approve: boolean |
| 988 | + approve: boolean, |
| 989 | + reload: boolean = true |
977 | 990 | ) { |
978 | | - const xfTokenElement = document.querySelector( |
979 | | - "input[name='_xfToken']" |
980 | | - ) as HTMLInputElement; |
981 | | - if (!xfTokenElement) { |
982 | | - console.error("Failed to find _xfToken input"); |
| 991 | + const xfToken = getXFToken(); |
| 992 | + if (!xfToken) { |
| 993 | + console.error("Failed to get XF token"); |
983 | 994 | return; |
984 | 995 | } |
985 | | - const xfToken = xfTokenElement.value; |
986 | 996 |
|
987 | 997 | // cookies cannot be set in the request unfortunately. |
988 | 998 | document.cookie = `xf_inlinemod_post=${postId}; Path=/; Secure=true;`; |
@@ -1037,7 +1047,51 @@ async function setPostApprovalStatus( |
1037 | 1047 | return; |
1038 | 1048 | } |
1039 | 1049 |
|
1040 | | - window.location.reload(); |
| 1050 | + if (reload) window.location.reload(); |
| 1051 | +} |
| 1052 | + |
| 1053 | +async function editPost( |
| 1054 | + threadId: string, |
| 1055 | + postId: string, |
| 1056 | + message: string, |
| 1057 | + silent: boolean = false, |
| 1058 | + clearEdits: boolean = false |
| 1059 | +) { |
| 1060 | + const xfToken = getXFToken(); |
| 1061 | + if (!xfToken) { |
| 1062 | + console.error("Failed to get XF token"); |
| 1063 | + return; |
| 1064 | + } |
| 1065 | + |
| 1066 | + const formdata = new FormData(); |
| 1067 | + formdata.append("_xfToken", xfToken); |
| 1068 | + formdata.append("_xfInlineEdit", "1"); |
| 1069 | + formdata.append("_xfRequestUri", `/threads/${threadId}/`); |
| 1070 | + formdata.append("_xfWithData", "1"); |
| 1071 | + formdata.append("_xfResponseType", "json"); |
| 1072 | + formdata.append("message", message); |
| 1073 | + if (silent) formdata.append("silent", "1"); |
| 1074 | + if (clearEdits) formdata.append("clear_edit", "1"); |
| 1075 | + |
| 1076 | + const response = await fetch( |
| 1077 | + `https://www.edgegamers.com/posts/${postId}/edit`, |
| 1078 | + { |
| 1079 | + method: "POST", |
| 1080 | + credentials: "same-origin", |
| 1081 | + body: formdata, |
| 1082 | + } |
| 1083 | + ); |
| 1084 | + if (!response.ok) { |
| 1085 | + console.error("Failed to edit post"); |
| 1086 | + return; |
| 1087 | + } |
| 1088 | + |
| 1089 | + const data = await response.json(); |
| 1090 | + if (data.status != "ok") { |
| 1091 | + console.error("Server rejected post edit"); |
| 1092 | + console.log(data); |
| 1093 | + return; |
| 1094 | + } |
1041 | 1095 | } |
1042 | 1096 |
|
1043 | 1097 | /** |
@@ -1242,6 +1296,10 @@ function getSteamID_F(unparsed_id: string): Promise<string> { |
1242 | 1296 | }); |
1243 | 1297 | } |
1244 | 1298 |
|
| 1299 | +function getXFToken() { |
| 1300 | + return document.getElementById("XF")?.dataset.csrf; |
| 1301 | +} |
| 1302 | + |
1245 | 1303 | /** |
1246 | 1304 | * Add or append text to the post editor box |
1247 | 1305 | * @param text Text to add to post box |
@@ -1998,6 +2056,8 @@ function handlePostBox(observer: MutationObserver) { |
1998 | 2056 | ) |
1999 | 2057 | handleAutoCount(); |
2000 | 2058 | handleCannedResponses(); |
| 2059 | + if (GM_config.get("enable-post-unapprove-btn")) |
| 2060 | + handleUnapprovePost(postBox); |
2001 | 2061 | } |
2002 | 2062 |
|
2003 | 2063 | /** |
@@ -2138,6 +2198,87 @@ function handleCannedResponses() { |
2138 | 2198 | }); |
2139 | 2199 | } |
2140 | 2200 |
|
| 2201 | +/** |
| 2202 | + * Handles adding a post & unapprove button to the postbox |
| 2203 | + */ |
| 2204 | +function handleUnapprovePost(postBox: HTMLDivElement) { |
| 2205 | + if ( |
| 2206 | + !document.querySelector("#xfBbCode-1")?.classList.contains("fr-active") |
| 2207 | + ) { |
| 2208 | + if (GM_config.get("rich-override")) |
| 2209 | + console.warn( |
| 2210 | + "Post box is in rich editor mode, but rich editor override is enabled. The rich editor is NOT supported." |
| 2211 | + ); |
| 2212 | + else return; |
| 2213 | + } |
| 2214 | + const threadId = getThreadId(); |
| 2215 | + const threadBody = document.querySelector( |
| 2216 | + "div.block-body.js-replyNewMessageContainer" |
| 2217 | + ) as HTMLDivElement; |
| 2218 | + const postButton = document.querySelector( |
| 2219 | + "button.button--icon--reply:not(#post-unapprove-button)" |
| 2220 | + ) as HTMLButtonElement; |
| 2221 | + const postUnapproveButton = document.createElement("a"); // Using a so that it doesn't submit the form |
| 2222 | + postUnapproveButton.classList.add( |
| 2223 | + "button--primary", |
| 2224 | + "button", |
| 2225 | + "button--icon", |
| 2226 | + "button--icon--reply" |
| 2227 | + ); |
| 2228 | + postUnapproveButton.style.marginRight = "4px"; |
| 2229 | + postUnapproveButton.id = "post-unapprove-button"; |
| 2230 | + postUnapproveButton.innerHTML = '<span class="button-text">UA</span>'; |
| 2231 | + postUnapproveButton.title = "Post & Unapprove"; |
| 2232 | + |
| 2233 | + postUnapproveButton.addEventListener("click", function () { |
| 2234 | + const postBoxContent = getPostBox(); |
| 2235 | + if (!postBoxContent) return; |
| 2236 | + editPostBox("🐰🥚", false); |
| 2237 | + postButton.click(); |
| 2238 | + |
| 2239 | + const observer = new MutationObserver((mutations) => { |
| 2240 | + mutations.every((mutation) => { |
| 2241 | + if (!mutation.addedNodes) return true; |
| 2242 | + for (let i = 0; i < mutation.addedNodes.length; i++) { |
| 2243 | + const node = mutation.addedNodes[i] as HTMLElement; |
| 2244 | + if (node.nodeName === "ARTICLE") { |
| 2245 | + const postId = node.dataset.content?.replaceAll( |
| 2246 | + "post-", |
| 2247 | + "" |
| 2248 | + ); |
| 2249 | + if (threadId && postId) |
| 2250 | + setPostApprovalStatus( |
| 2251 | + threadId, |
| 2252 | + postId, |
| 2253 | + false, |
| 2254 | + false |
| 2255 | + ).then(() => { |
| 2256 | + editPost( |
| 2257 | + threadId, |
| 2258 | + postId, |
| 2259 | + postBoxContent, |
| 2260 | + true |
| 2261 | + ).then(() => { |
| 2262 | + window.location.reload(); |
| 2263 | + }); |
| 2264 | + }); |
| 2265 | + observer.disconnect(); |
| 2266 | + return false; |
| 2267 | + } |
| 2268 | + } |
| 2269 | + }); |
| 2270 | + }); |
| 2271 | + observer.observe(threadBody, { |
| 2272 | + childList: true, |
| 2273 | + subtree: true, |
| 2274 | + attributes: false, |
| 2275 | + characterData: false, |
| 2276 | + }); |
| 2277 | + }); |
| 2278 | + |
| 2279 | + postButton.parentElement?.insertBefore(postUnapproveButton, postButton); |
| 2280 | +} |
| 2281 | + |
2141 | 2282 | /** |
2142 | 2283 | * Changes the target of the application links to open in a new tab |
2143 | 2284 | * @returns void |
|
0 commit comments