[Reddit] ModmailExtraInfo

Shows additional user information on the sidebar of modmail

目前為 2021-11-19 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name [Reddit] ModmailExtraInfo
  3. // @namespace HKR
  4. // @match https://mod.reddit.com/mail/*
  5. // @grant none
  6. // @version 1.3
  7. // @author HKR
  8. // @description Shows additional user information on the sidebar of modmail
  9. // @require https://greasyfork.org/scripts/21927-arrive-js/code/arrivejs.js
  10. // @icon https://www.redditstatic.com/modmail/favicon/favicon-32x32.png
  11. // @supportURL https://github.com/Hakorr/Userscripts/issues
  12. // ==/UserScript==
  13.  
  14. /* SETTINGS */
  15. var textColor = "#6e6e6e";
  16. var dataColor = "#0079d3";
  17. var titleColor = "#2c2c2c";
  18.  
  19. var enableCustomResponses = true;
  20. var responses = [
  21. {
  22. "name":"Select a template",
  23. "content":``
  24. },
  25. {
  26. "name":"Approved!",
  27. "content":`Hey, approved the post!`
  28. },
  29. {
  30. "name":"Rule broken",
  31. "content":`Your post broke our rules.
  32. The action will not be reverted.`
  33. }
  34. ];
  35.  
  36. /* --------- */
  37.  
  38. function Get(url) {
  39. var xmlHttp = new XMLHttpRequest();
  40. xmlHttp.open( "GET", url, false );
  41. xmlHttp.send( null );
  42. return xmlHttp.responseText;
  43. }
  44.  
  45. function time(UNIX_timestamp){
  46. var a = new Date(UNIX_timestamp * 1000);
  47. var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
  48. var year = a.getFullYear();
  49. var month = months[a.getMonth()];
  50. var date = a.getDate();
  51. var hour = fixnumber(a.getHours());
  52. var min = fixnumber(a.getMinutes());
  53. var sec = fixnumber(a.getSeconds());
  54. var time = date + ' ' + month + ' ' + year + ' ' + hour + ':' + min + ':' + sec ;
  55. return time;
  56. }
  57.  
  58. function fixnumber(number) {
  59. if(number < 10) return "0" + number;
  60. else return number;
  61. }
  62.  
  63. function sanitize(evilstring) {
  64. const decoder = document.createElement('div')
  65. decoder.innerHTML = evilstring;
  66. return decoder.textContent;
  67. }
  68.  
  69. //Function that appends HTML into the Modmail page
  70. function addInfo(){
  71. //Load and parse username
  72. var username = document.getElementsByClassName("InfoBar__username")[0].innerText;
  73. var about = "https://www.reddit.com/user/" + username + "/about.json";
  74. var user = JSON.parse(Get(about));
  75.  
  76. //Separator HTML element
  77. var seperator = document.createElement('div');
  78. seperator.innerHTML = '<div class="InfoBar__modActions"></div>';
  79.  
  80. //HTML element that contains all the data
  81. var userDetails = document.createElement('div');
  82. userDetails.classList.add("InfoBar__age");
  83. userDetails.innerHTML = `
  84. <img class="profileIcon" src="${user.data.icon_img}" width="25">
  85. <a class="InfoBar__username" href="https://www.reddit.com/user/${user.data.name}">${user.data.subreddit.display_name_prefixed}</a>
  86.  
  87. <h1 style="color: ${textColor} ; font-size: 11px; margin-top: 17px; margin-bottom: 10px;">${sanitize(user.data.subreddit.public_description)}</h1>
  88.  
  89. <h1 class="dataTitle">Main</h1>
  90. <div class="dataText">
  91. <p>Created: <span class="value">${time(user.data.created)}</span></p>
  92. <p>UserID: <span class="value">${user.data.id}</span></p>
  93. <p>Verified: <span class="value">${user.data.verified}</span></p>
  94. <p>Employee: <span class="value">${user.data.is_employee}</span></p>
  95. <p>NSFW Profile: <span class="value">${user.data.subreddit.over_18}</span></p>
  96. </div>
  97.  
  98. <h1 class="dataTitle">Karma</h1>
  99. <div class="dataText">
  100. <p>Post: <span class="value">${user.data.link_karma}</span></p>
  101. <p>Comment: <span class="value">${user.data.comment_karma}</span></p>
  102. <p>Total: <span class="value">${user.data.total_karma}</span></p>
  103. <p>Awardee: <span class="value">${user.data.awardee_karma}</span></p>
  104. <p>Awarder: <span class="value">${user.data.awarder_karma}</span></p>
  105. </div>
  106.  
  107. <h1 class="dataTitle">Links</h1>
  108. <div style="padding-left: 10px;">
  109. <a class="InfoBar__recent" href="https://redditmetis.com/user/${user.data.name}" target="_blank">Redditmetis</a>
  110. <a class="InfoBar__recent" href="https://www.reddit.com/search?q=${user.data.name}" target="_blank">Reddit Search</a>
  111. <a class="InfoBar__recent" href="https://www.google.com/search?q=%22${user.data.name}%22" target="_blank">Google Search</a>
  112. </div>
  113. `;
  114. //Arrange items and append
  115. document.getElementsByClassName("ThreadViewer__infobar")[0].appendChild(seperator);
  116. document.getElementsByClassName("ThreadViewer__infobar")[0].appendChild(userDetails);
  117. document.getElementsByClassName("ThreadViewer__infobar")[0].appendChild(document.getElementsByClassName("ThreadViewer__infobar")[0].firstChild);
  118. document.getElementsByClassName("InfoBar")[0].appendChild(document.getElementsByClassName("InfoBar__modActions")[0]);
  119. document.getElementsByClassName("InfoBar")[0].insertBefore(document.getElementsByClassName("InfoBar__modActions")[0],document.getElementsByClassName("InfoBar")[0].firstChild);
  120. if(document.getElementsByClassName("InfoBar__banText")[0])
  121. document.getElementsByClassName("ThreadViewer__infobar")[0].insertBefore(document.getElementsByClassName("InfoBar__banText")[0],document.getElementsByClassName("ThreadViewer__infobar")[0].firstChild);
  122. document.getElementsByClassName("InfoBar__username")[1].outerHTML = "";
  123. document.getElementsByClassName("InfoBar__age")[1].outerHTML = "";
  124. document.getElementsByClassName("InfoBar__modActions")[1].outerHTML = "";
  125. }
  126.  
  127. function addResponseBox() {
  128. //Listbox element
  129. var responseBox = document.createElement('div');
  130. responseBox.classList.add("select");
  131. responseBox.innerHTML = `
  132. <select id="responseListbox" onchange="listBoxChanged(this.value);" onfocus="this.selectedIndex = -1;"/>
  133. <span class="focus"></span>
  134. `;
  135.  
  136. //Script element to head
  137. var headJS = document.createElement('script');
  138. headJS.innerHTML = `
  139. function listBoxChanged(message) {
  140. var messageBox = document.getElementsByClassName("Textarea ThreadViewerReplyForm__replyText")[0];
  141. //messageBox.focus();
  142. messageBox.value = message;
  143. console.log("Set message to: " + message);
  144. }
  145. `;
  146.  
  147. function populate() {
  148. var select = document.getElementById("responseListbox");
  149. for(var i = 0; i < responses.length; i++) {
  150. select.options[select.options.length] = new Option(responses[i].name, responses[i].content);
  151. }
  152. }
  153.  
  154. document.getElementsByClassName("ThreadViewer__replyContainer")[0].prepend(responseBox);
  155. var head = document.getElementsByTagName('head')[0];
  156. head.appendChild(headJS);
  157.  
  158. populate();
  159. }
  160.  
  161. //When Modmail conversation has been opened, load the HTML elements with the correct data
  162. const elementToWatch = 'a[class="InfoBar__username"]';
  163. document.arrive(elementToWatch, function () {
  164. addInfo();
  165. if(enableCustomResponses) addResponseBox();
  166. });
  167.  
  168. if(document.getElementsByClassName("InfoBar__username")[0]) {
  169. addInfo();
  170. if(enableCustomResponses) addResponseBox();
  171. }
  172.  
  173. var css = `
  174. .profileIcon:hover {
  175. -ms-transform: scale(6);
  176. -webkit-transform: scale(6);
  177. transform: scale(6);
  178. }
  179. .profileIcon {
  180. position: relative;
  181. bottom: 4px;
  182. margin-bottom: 10px;
  183. float: left; border-radius: 50%;
  184. transition: transform .2s;
  185. }
  186. .InfoBar__recentsNone {
  187. color: #6e6e6e;
  188. }
  189. .InfoBar__metadata, .InfoBar__recents {
  190. margin: 6px 0;
  191. margin-left: 10px;
  192. }
  193. .value {
  194. color: ${dataColor};
  195. }
  196. .InfoBar__banText {
  197. padding-bottom: 15px;
  198. }
  199. .InfoBar__username, .InfoBar__username:visited {
  200. padding-left: 10px;
  201. }
  202. .ThreadViewer__infobarContainer {
  203. display: table;
  204. }
  205. .ThreadViewer__threadContainer.m-has-infobar {
  206. right: 340px;
  207. }
  208. .dataText {
  209. color: ${textColor};
  210. font-size: 13px;
  211. padding-left: 10px;
  212. }
  213. .dataTitle {
  214. color: ${titleColor};
  215. font-size: 15px;
  216. margin-bottom: 3px;
  217. margin-top: 5px;
  218. }
  219. .responseListbox {
  220. width: 50%;
  221. }
  222.  
  223. :root {
  224. --select-border: #777;
  225. --select-focus: blue;
  226. --select-arrow: var(--select-border);
  227. }
  228. *,
  229. *::before,
  230. *::after {
  231. box-sizing: border-box;
  232. }
  233. select {
  234. // A reset of styles, including removing the default dropdown arrow
  235. appearance: none;
  236. // Additional resets for further consistency
  237. background-color: transparent;
  238. border: none;
  239. padding: 0 1em 0 0;
  240. margin: 0;
  241. width: 100%;
  242. font-family: inherit;
  243. font-size: inherit;
  244. cursor: inherit;
  245. line-height: inherit;
  246. outline: none;
  247. position: relative;
  248. }
  249. .select {
  250. width: 100%;
  251. min-width: 15ch;
  252. max-width: 30ch;
  253. border: 1px solid var(--select-border);
  254. border-radius: 0.25em;
  255. padding: 0.25em 0.5em;
  256. font-size: 1rem;
  257. cursor: pointer;
  258. line-height: 1.1;
  259. background-color: #fff;
  260. background-image: linear-gradient(to top, #f9f9f9, #fff 33%);
  261. }
  262. select::-ms-expand {
  263. display: none;
  264. }
  265. option {
  266. white-space: normal;
  267.  
  268. // Only affects Chrome
  269. outline-color: var(--select-focus);
  270. }
  271. select:focus + .focus {
  272. position: absolute;
  273. top: -1px;
  274. left: -1px;
  275. right: -1px;
  276. bottom: -1px;
  277. border: 2px solid var(--select-focus);
  278. border-radius: inherit;
  279. }
  280. `;
  281.  
  282. //Apply the custom css
  283. var styleSheet = document.createElement("style");
  284. styleSheet.type = "text/css";
  285. styleSheet.innerText = css;
  286. document.head.appendChild(styleSheet);