TorViet Shoutbox Enhancer

A small script to tweak the shoutbox

目前为 2016-03-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name TorViet Shoutbox Enhancer
  3. // @namespace http://torviet.com/userdetails.php?id=1662
  4. // @version 0.9.5
  5. // @license http://www.wtfpl.net/txt/copying/
  6. // @homepageURL https://github.com/S-a-l-a-d/TorViet-Shoutbox-Enhancer
  7. // @supportURL https://github.com/S-a-l-a-d/TorViet-Shoutbox-Enhancer/issues
  8. // @icon http://torviet.com/pic/salad.png
  9. // @description A small script to tweak the shoutbox
  10. // @author Salad
  11. // @match http://torviet.com/qa.php*
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_deleteValue
  15. // @grant GM_addStyle
  16. // ==/UserScript==
  17.  
  18. (function() {
  19. // First let's get the elements which we will work on.
  20. var allWrapper = document.getElementById("all-wrapper"),
  21. boxHead = document.getElementById("boxHead"),
  22. marquee = document.getElementById("marquee"),
  23. sltTheme = document.getElementById("sltTheme"),
  24. boxQuestion = document.getElementById("boxQuestion"),
  25. clock = document.getElementById("clock"),
  26. idQuestion = document.getElementById("idQuestion"),
  27. emoGroup = document.getElementById("emo-group"),
  28. emoGroupDetail = document.getElementById("emo-group-detail");
  29.  
  30. // Also create a namespace.
  31. var EMOTICON = (function() {
  32. var emoList = GM_getValue("emoList"),
  33. emoListHtml = GM_getValue("emoListHtml") || "",
  34. emoHtml = "";
  35.  
  36. var promptForEmoList = function(action, list) {
  37. var message = "Chọn bộ emoticon bạn muốn" + " " + action + ":\n",
  38. answer;
  39.  
  40. for (var i = 0, len = list.length; i < len; i++) {
  41. message += i + 1 + ". " + list[i] + "\n";
  42. }
  43.  
  44. message += "Điền tên bộ emoticon, ngăn cách bằng dấu phẩy, phân biệt hoa/thường." + " " +
  45. "Có thể điền emoticon đơn bằng cách điền tên tập tin emoticon đó.\nVí dụ: Voz,707,Rage";
  46.  
  47. do {
  48. answer = prompt(message);
  49. }
  50. while (!answer || answer.trim() === "");
  51.  
  52. return answer.replace(/\s{2,}/g, " ").trim().split(",");
  53. };
  54. var initemoList = function() {
  55. var emoListAvailable = [];
  56. for (var i = 0, options = emoGroup.options, len = options.length; i < len; i++) {
  57. emoListAvailable.push(options[i].text);
  58. }
  59.  
  60. emoList = promptForEmoList("sử dụng", emoListAvailable);
  61. GM_setValue("emoList", emoList);
  62. };
  63. var requestEmoticons = function(groupName) {
  64. var request = new XMLHttpRequest();
  65. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  66. * Using synchronous request here is the simplest implementation to make it work. *
  67. * This process is fast enough so the user will hardly notice the unresponsive moment *
  68. * while the browser is sending the request and receiving the response. *
  69. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  70. request.open("POST", "qa_smiley_ajax.php", false);
  71. request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  72. request.onreadystatechange = function() {
  73. request.readyState == 4 && request.status == 200 &&
  74. (emoHtml = JSON.parse(request.responseText).str);
  75. };
  76. request.send("group=" + groupName);
  77. };
  78. var makeEmoticonHtml = function(emoName) {
  79. emoHtml = "<div style=\"height:43px;width:43px;float:left;display:inline-block;margin:0 0 1px 1px;\">" +
  80. "<img style=\"max-width: 43px; max-height: 43px; cursor: pointer;\" src=\"/pic/smilies/" + emoName +
  81. ".gif\" alt=\"[em" + emoName + "]\"></div>";
  82. };
  83.  
  84. return {
  85. checkemoList: function() {
  86. !emoList && initemoList();
  87. },
  88. add: function() {
  89. var emoListAvailable = [];
  90. for (var i = 0, options = emoGroup.options, len = options.length; i < len; i++) {
  91. (emoList.indexOf(options[i].text) === -1) &&
  92. emoListAvailable.push(options[i].text);
  93. }
  94.  
  95. var emoListToAdd = promptForEmoList("thêm", emoListAvailable);
  96. for (var i = 0, len = emoListToAdd.length; i < len; i++) {
  97. (emoList.indexOf(emoListToAdd[i]) === -1) &&
  98. emoList.push(emoListToAdd[i]);
  99. }
  100.  
  101. GM_setValue("emoList", emoList);
  102. GM_deleteValue("emoListHtml");
  103. location.href = "qa.php";
  104. },
  105. remove: function() {
  106. var emoListToRemove = promptForEmoList("xóa", emoList);
  107. for (var i = 0, len = emoListToRemove.length; i < len; i++) {
  108. var index = emoList.indexOf(emoListToRemove[i]);
  109. (index > -1) && emoList.splice(index, 1);
  110. }
  111.  
  112. GM_setValue("emoList", emoList);
  113. GM_deleteValue("emoListHtml");
  114. location.href = "qa.php";
  115. },
  116. clear: function() {
  117. GM_deleteValue("emoList");
  118. GM_deleteValue("emoListHtml");
  119. location.href = "qa.php";
  120. },
  121. getEmoticons: function(groupName) {
  122. requestEmoticons(groupName);
  123. return emoHtml;
  124. },
  125. generateEmoticons: function(emoName) {
  126. makeEmoticonHtml(emoName);
  127. return emoHtml;
  128. },
  129. addEmosToEmoGroup: function() {
  130. emoGroupDetail.innerHTML = "";
  131.  
  132. if (emoListHtml === "") {
  133. for (var i = 0, len = emoList.length; i < len; i++) {
  134. emoListHtml += isNaN(emoList[i]) ?
  135. this.getEmoticons(emoList[i]) :
  136. this.generateEmoticons(emoList[i]);
  137. }
  138.  
  139. GM_setValue("emoListHtml", emoListHtml);
  140. }
  141.  
  142. emoGroupDetail.innerHTML = emoListHtml;
  143. },
  144. addEmoGroupEvent: function() {
  145. // Let's add click events for the newly added emoticons.
  146. for (var i = 0, emos = emoGroupDetail.childNodes, len = emos.length; i < len; i++)
  147. emos[i].firstChild.addEventListener("click", function(e) {
  148. idQuestion.value += e.target.parentNode.getAttribute("alt");
  149. idQuestion.focus();
  150. });
  151. }
  152. };
  153. })();
  154.  
  155. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  156. * Now remove the unnecessary elements including the box containing new torrents *
  157. * and football news, the warning, the theme drop-down list and the clock. *
  158. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  159. allWrapper.className = "";
  160. boxHead.parentNode.removeChild(boxHead);
  161. marquee.parentNode.removeChild(marquee);
  162. sltTheme.parentNode.removeChild(sltTheme);
  163. while (clock.lastChild) {
  164. clock.removeChild(clock.lastChild);
  165. }
  166.  
  167. // And polish things with our custom CSS.
  168. var specialCase = typeof InstallTrigger !== "undefined" ?
  169. "#wrapper-below {" +
  170. " height: calc(100% - 67px);" +
  171. "}" +
  172. "#emo-section {" +
  173. " height: calc(100% - 74px);" +
  174. "}" :
  175. "#wrapper-below {" +
  176. " height: calc(100% - 62px);" +
  177. "}" +
  178. "#emo-section {" +
  179. " height: calc(100% - 69px);" +
  180. "}";
  181.  
  182. GM_addStyle(
  183. ".slimScrollDiv, #emo-group-detail {" +
  184. " height: 100% !important;" +
  185. "}" +
  186. specialCase
  187. );
  188.  
  189. var toBeAppendedToClock = document.createDocumentFragment(),
  190. someText = document.createElement("span"),
  191. btnAdd = document.createElement("input"),
  192. btnRemove = document.createElement("input"),
  193. btnClear = document.createElement("input");
  194.  
  195. someText.innerHTML = "For custom emoticon group<br />";
  196.  
  197. btnAdd.type = "button";
  198. btnAdd.value = "Add";
  199. btnAdd.addEventListener("click", EMOTICON.add);
  200.  
  201. btnRemove.type = "button";
  202. btnRemove.value = "Remove";
  203. btnRemove.addEventListener("click", EMOTICON.remove);
  204.  
  205. btnClear.type = "button";
  206. btnClear.value = "Clear";
  207. btnClear.addEventListener("click", EMOTICON.clear);
  208.  
  209. toBeAppendedToClock.appendChild(emoGroup.parentNode);
  210. toBeAppendedToClock.appendChild(someText);
  211. toBeAppendedToClock.appendChild(btnAdd);
  212. toBeAppendedToClock.appendChild(btnRemove);
  213. toBeAppendedToClock.appendChild(btnClear);
  214. clock.appendChild(toBeAppendedToClock);
  215.  
  216. // Here comes our own functions.
  217. function changeEmoGroup() {
  218. emoGroupDetail.innerHTML = EMOTICON.getEmoticons(emoGroup.value);
  219. // EMOTICON.addEmoGroupEvent();
  220. }
  221.  
  222. function keyEvent(e) {
  223. switch (e.keyCode) {
  224. // Down arrow.
  225. case 40:
  226. emoGroup !== document.activeElement &&
  227. emoGroup.selectedIndex !== emoGroup.length - 1 &&
  228. emoGroup.selectedIndex++;
  229. changeEmoGroup();
  230. break;
  231. // Up arrow.
  232. case 38:
  233. emoGroup !== document.activeElement &&
  234. emoGroup.selectedIndex !== 0 &&
  235. emoGroup.selectedIndex--;
  236. console.log(emoGroup.value);
  237. changeEmoGroup();
  238. break;
  239. // Enter.
  240. case 13:
  241. var inputText = idQuestion.value;
  242. inputText = inputText.replace(/(:\^\))|(\/:\))/g, "[em528]");
  243. inputText = inputText.replace(/:\)/g, "[em564]");
  244. inputText = inputText.replace(/:\({2}/g, "[em7]");
  245. inputText = inputText.replace(/:\(/g, "[em561]");
  246. inputText = inputText.replace(/:x/g, "[em535]");
  247. inputText = inputText.replace(/:"\>/g, "[em23]");
  248. inputText = inputText.replace(/:\-?\*/g, "[em570]");
  249. inputText = inputText.replace(/=\(\(/g, "[em572]");
  250. inputText = inputText.replace(/:\-?[oO]/g, "[em222]");
  251. inputText = inputText.replace(/[xX]\-?\(/g, "[em541]");
  252. inputText = inputText.replace(/[bB]\-\)/g, "[em555]");
  253. inputText = inputText.replace(/\>:\)/g, "[em552]");
  254. inputText = inputText.replace(/\(:\|/g, "[em571]");
  255. inputText = inputText.replace(/:\|/g, "[em206]");
  256. inputText = inputText.replace(/:\-&/g, "[em37]");
  257. inputText = inputText.replace(/:\-?\?/g, "[em223]");
  258. inputText = inputText.replace(/=\)\)/g, "[em707]");
  259. inputText = inputText.replace(/:\-?[dD]/g, "[em536]");
  260. inputText = inputText.replace(/;;\)/g, "[em524]");
  261. inputText = inputText.replace(/:\-?\>/g, "[em537]");
  262. inputText = inputText.replace(/:\-[sS]/g, "[em558]");
  263. inputText = inputText.replace(/\[\-\(/g, "[em200]");
  264. inputText = inputText.replace(/=[pP]~/g, "[em566]");
  265. inputText = inputText.replace(/;\)\)/g, "[em18]");
  266. inputText = inputText.replace(/[tT]_[tT]/g, "[em544]");
  267. inputText = inputText.replace(/\-_\-/g, "[em136]");
  268. inputText = inputText.replace(/\(finger\)/g, "[em720]");
  269. idQuestion.value = inputText;
  270. break;
  271. default:
  272. }
  273. }
  274.  
  275. function arrayIsNumeric(messageArray) {
  276. return messageArray.every(element => !isNaN(element));
  277. }
  278.  
  279. function encodedArrayToString(messageArray) {
  280. if (messageArray[0].length === 8) {
  281. return String.fromCharCode.apply(null, messageArray.map(element => parseInt(element, 2).toString(10)));
  282. }
  283.  
  284. return String.fromCharCode.apply(null, messageArray);
  285. }
  286.  
  287. function messageIsUrl(message) {
  288. return /^(http)/.test(message);
  289. }
  290.  
  291. function formatMessage(message) {
  292. return "<a class=\"faqlink\" href=\"" + message + "\" target=\"_blank\">" +
  293. (message.length > 80 ?
  294. (message.substr(0, 20) + "..." +
  295. message.substring(message.length - 30, message.length) + "</a>") : message);
  296. }
  297.  
  298. function decodeMessages() {
  299. $(".Q1, .Q1-right").find("span").not(".nowrap, .time").each(function () {
  300. var message = $(this).html(),
  301. messageArray = message.split(" ");
  302.  
  303. if ((!arrayIsNumeric(messageArray)) || messageArray.length <= 1) {
  304. return true;
  305. }
  306.  
  307. message = encodedArrayToString(messageArray);
  308.  
  309. $(this).html(messageIsUrl(message) ? formatMessage(message) : message);
  310. });
  311. }
  312.  
  313. function observeMessages() {
  314. var observer = new MutationObserver(function (mutations, observer) {
  315. var nodes = mutations[0].addedNodes[0].getElementsByTagName("span"),
  316. targetNode = nodes[nodes.length -1],
  317. parentNodeClassName = targetNode.parentNode.className,
  318. message = targetNode.innerHTML,
  319. messageArray = message.split(" ");
  320.  
  321. if (parentNodeClassName !== "Q1" && parentNodeClassName !== "Q1-right") {
  322. return false;
  323. }
  324.  
  325. if ((!arrayIsNumeric(messageArray)) || messageArray.length <= 1) {
  326. return false;
  327. }
  328.  
  329. message = encodedArrayToString(messageArray);
  330.  
  331. if (messageIsUrl(message)) {
  332. targetNode.innerHTML = formatMessage(message);
  333. } else {
  334. targetNode.innerHTML = message;
  335. }
  336. });
  337.  
  338. observer.observe(boxQuestion, {
  339. childList: true,
  340. subtree : true
  341. });
  342. }
  343.  
  344. // The following should run at startup.
  345. document.addEventListener("keydown", keyEvent);
  346. decodeMessages();
  347. observeMessages();
  348. EMOTICON.checkemoList();
  349. EMOTICON.addEmosToEmoGroup();
  350. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  351. * Let's see if the user is using Firefox. *
  352. * This method is taken from http://stackoverflow.com/questions/9847580/ *
  353. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  354. // typeof InstallTrigger === "undefined" && EMOTICON.addEmoGroupEvent();
  355. idQuestion.focus();
  356. })();