Game Highlighter

Searches the games table for settable game names and highlights them.

当前为 2015-02-15 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Game Highlighter
  3. // @author Timo Gebauer
  4. // @namespace t.gebauer@hg-software.de
  5. // @version 0.2.1
  6. // @grant none
  7. // @include http://makemehost.com/games.php
  8. // @description Searches the games table for settable game names and highlights them.
  9. // ==/UserScript==
  10.  
  11. /******************************************************************************/
  12. // use MakeMeHosts jQuery version
  13. $ = unsafeWindow.jQuery;
  14.  
  15. // Groß- und Kleinschreibung wird in den Suchtexten nicht beachtet
  16. // Treffer, die einen Sound abspielen, werden bis zur nächsten Aktualisierung mit farbigem Hintergrund hervorgehoben
  17.  
  18. // nur in den Games Spalten suchen?
  19. var searchGamesOnly = false;
  20.  
  21. // red, blue, cyan, purple, yellow, orange, green, pink, grey, CadetBlue, darkgreen, brown
  22. var highlights = [];
  23.  
  24. var sounds = {
  25. s_solemn: 'http://www.oringz.com/oringz-uploads/sounds-882-solemn.mp3',
  26. s_comm: 'http://www.oringz.com/oringz-uploads/sounds-917-communication-channel.mp3'
  27. };
  28.  
  29. /******************************************************************************/
  30. /*
  31. * Ajax Request "hijacken" nach jeder erfolgreichen Übertragung die Funktion highlightArray() ausführen
  32. * Das Ergebnis des Requests kann hier nicht abgefangen werden, da der Eventlistener erst aufgerufen wird,
  33. * nachdem der eigentliche Aufrufer das Ergebnis bereits verarbeitet hat
  34. */
  35. // backup original "send" function reference
  36. XMLHttpRequest.prototype.oldSend = XMLHttpRequest.prototype.send;
  37. var newSend = function(a) {
  38. var xhr = this;
  39. var onload = function() {
  40. highlightArray();
  41. };
  42. xhr.addEventListener("load", onload, false);
  43.  
  44. this.oldSend(a);
  45. };
  46. XMLHttpRequest.prototype.send = newSend;
  47.  
  48. /*******************************************************************************/
  49. /*
  50. * TODO:
  51. * - highlights hoch und runterverschieben
  52. * - color-picker ?
  53. * - mute sound checkbox
  54. * - "mute" elements
  55. * - Rückgangig button
  56. * - erst beim schließen vollständig anwenden
  57. * - sound-fenster (neu, entfernen, etc..)
  58. */
  59. function initGui() {
  60. // var html = "<div><button id=\"button_save\">Speichern</button></div>";
  61. $('.refreshMe').next().after('<div align="center"><a class="changelink-unactive" id="btn_options"> Highlight Settings</a></div>');
  62. document.getElementById('btn_options').addEventListener('click', showGui, true);
  63. $("body").append('<div id="popup_overlay" class="overlay"></div>');
  64. $("body").append('<div id="popup" class="popup"></div>');
  65. document.getElementById('popup_overlay').addEventListener('click', hideGui, true);
  66. // popup window
  67. var html = '<p>Auflistung aller aktiven Highlights<br>'
  68. + 'Groß- und Kleinschreibung wird in den Suchtexten nicht beachtet'
  69. + '<br>Treffer, die einen Sound abspielen, werden bis zur nächsten Aktualisierung mit farbigem Hintergrund hervorgehoben</p>'
  70. + '<button id="btn_add">New Highlight</button>'
  71. + '<button id="btn_load">Load (JSON)</button>'
  72. + '<button id="btn_save">Save (JSON)</button>'
  73. + '<button id="btn_remove_all">Remove all</button>'
  74. + '<div id="highlight_container"></div>';
  75. $("#popup").append(html);
  76. // load / save
  77. $("#btn_load").click(function() {
  78. showInputDialog("", function() {
  79. highlights = JSON.parse($("#inputDialogInput").attr("value"));
  80. updateGui();
  81. });
  82. });
  83. $("#btn_save").click(function() {
  84. alert("Save this stringified options somewhere \n\n"
  85. + JSON.stringify(highlights));
  86. });
  87. // add a new highlight
  88. $("#btn_add").click(function() {
  89. highlights.splice(0,0,{search:[]});
  90. updateGui();
  91. });
  92. // remove all
  93. $("#btn_remove_all").click(function() {
  94. highlights = [];
  95. updateGui();
  96. });
  97. updateGui();
  98. // append custom stylesheet
  99. $("head").append('<style type="text/css"><!--\n'
  100. + "#btn_options {"
  101. + "cursor: pointer;"
  102. + "font-size: 20px;"
  103. + "}"
  104. + ".overlay {"
  105. + "left: 0;"
  106. + "top: 0;"
  107. + "bottom: 0;"
  108. + "right: 0;"
  109. + "z-index: 100;"
  110. + "position: fixed;"
  111. + "background-color: #000;"
  112. + "filter: alpha(opacity=20);"
  113. + "opacity: 0.2;"
  114. + "cursor: pointer;"
  115. + "display: none;"
  116. + "}"
  117. + ".popup {"
  118. + "display: none;"
  119. + "background: #fff;"
  120. + "padding: 1%;"
  121. + "width: 50%;"
  122. + "position: fixed;"
  123. + "top: 10%;"
  124. + "left: 50%;"
  125. + "margin: 0 0 0 -20%;" /* add negative left margin for half the width to center the div */
  126. + "cursor: default;"
  127. + "z-index: 200;"
  128. + "border-radius: 4px;"
  129. + "box-shadow: 0 0 5px rgba(0,0,0,0.9);"
  130. + "max-height: 80%;"
  131. + "overflow: auto;"
  132. + "}"
  133. + ".highlight_wrapper {"
  134. // + "background-color: red;"
  135. + "height: auto;"
  136. + "margin: 40px;"
  137. + "padding: 5px;"
  138. + "clear: both;"
  139. + "border: 1px solid grey;"
  140. // + "vertical-align: middle;"
  141. + "}"
  142. + ".index {"
  143. + "margin-right: 30px;"
  144. + "float:left;"
  145. + "}"
  146. + ".btn_color {"
  147. + "margin-right: 30px;"
  148. // + "float: left;"
  149. + "width: 20px;"
  150. + "height: 20px;"
  151. // + "vertical-align: top;"
  152. + "float:left;"
  153. +"}"
  154. + ".search_wrapper {"
  155. // + "font: helvetica, arial, san-serif;"
  156. // + "vertical-align: top;"
  157. + "width: 40%;"
  158. + "float:left;"
  159. + "}"
  160. + ".highlight_search {"
  161. + "resize: none;"
  162. + "float: left;"
  163. + "}"
  164. + ".end_wrapper {"
  165. + "clear:both;"
  166. + "}"
  167. + "#inputDialog {"
  168. + "display: none;"
  169. + "position: fixed;"
  170. + "top: 20%;"
  171. + "left: 50%;"
  172. + "margin-left: -10%;"
  173. + "z-index: 300;"
  174. + "}"
  175. + "#inputDialogOverlay {"
  176. + "z-index: 250;"
  177. + "}"
  178. + '\n--></style>');
  179. // input dialog
  180. var html = '<div id="inputDialogOverlay" class="overlay"></div>'
  181. + '<div id="inputDialog">'
  182. + '<input id="inputDialogInput" type="text"></input>'
  183. + '<button id="inputDialogButton">Ok</button>'
  184. + '</div>';
  185. $("body").append(html);
  186. $("#inputDialog").hide();
  187. $("#inputDialogOverlay").click(function() {
  188. $("#inputDialog").hide();
  189. $("#inputDialogOverlay").hide();
  190. });
  191. $("#inputDialogInput").focus(function(){
  192. var that = this;
  193. setTimeout(function(){$(that).select();}, 10);
  194. });
  195. $("#inputDialogInput").keypress(function(event){
  196. if(event.keyCode == 13){
  197. $("#inputDialogButton").click();
  198. }
  199. });
  200. }
  201.  
  202. function updateGui() {
  203. // save changes
  204. saveLocalData();
  205. // reset all previous highlights
  206. resetHighlights();
  207. // apply new highlights
  208. highlightArray();
  209. $("#highlight_container").empty();
  210. $.each(highlights, function(index, elem) {
  211. var html = '<div class="highlight_wrapper">'
  212. + '<span class="index">' + index + '</span>'
  213. + '';
  214. // make sure, elem.search is an array
  215. elem.search = elem.search instanceof Array ? elem.search : [elem.search];
  216. var text = "";
  217. $.each(elem.search, function(index, search_value) {
  218. if(index != 0)
  219. text += "\n";
  220. text += search_value;
  221. });
  222. html += '<textarea class="highlight_search" index="'+index+'" rows="'
  223. + elem.search.length + '">' + text + '</textarea>';
  224. html += '<button class="btn_color" value="' + index
  225. + '" style="background-color:' + elem.color + ';">&nbsp</button>';
  226. html += '<select class="sound_select" index="'+index+'">';
  227. html += '<option'
  228. if(elem.sound === false)
  229. html += ' selected=selected';
  230. html += '></option>';
  231. $.each(sounds, function(sound, url) {
  232. html += '<option';
  233. if(elem.sound === sound)
  234. html += ' selected=selected';
  235. html += '>' + sound + '</option>';
  236. });
  237. html += '</select>';
  238. html += '<button class="btn_remove" index="' + index + '">X</button>';
  239. html += '<div class="end_wrapper"></div></div>';
  240. $("#highlight_container").append(html);
  241. // $(".highlight_wrapper").css("background-color","red");
  242. });
  243. // register events
  244. $(".highlight_search").change(function() {
  245. highlights[$(this).attr("index")].search = cleanArray($(this).val().split("\n")) ;
  246. saveLocalData();
  247. resetHighlights();
  248. highlightArray();
  249. });
  250. $(".highlight_search").keyup(function(event) {
  251. // if(event.keyCode == 13) {
  252. // }
  253. $(this).attr("rows", $(this).val().split("\n").length);
  254. });
  255. $(".btn_color").click(function() {
  256. var index = $(this).attr("value");
  257. showInputDialog(highlights[index].color, function() {
  258. var color = $("#inputDialogInput").attr("value");
  259. highlights[index].color = color;
  260. updateGui();
  261. $('.btn_color[value="'+index+'"]').focus();
  262. });
  263. });
  264. $(".sound_select").change(function(){
  265. highlights[$(this).attr("index")].sound = $(this).val();
  266. // no need to update the gui here, only save the changes
  267. saveLocalData();
  268. });
  269. $(".btn_remove").click(function() {
  270. highlights.splice($(this).attr("index"),1);
  271. updateGui();
  272. });
  273. }
  274.  
  275. function showInputDialog(text, okFunction) {
  276. $("#inputDialogInput").attr("value", text);
  277. $("#inputDialogInput").focus();
  278. $("#inputDialog").show();
  279. $("#inputDialogOverlay").show();
  280. $("#inputDialogButton").unbind("click")
  281. $("#inputDialogButton").click(function() {
  282. $("#inputDialog").hide();
  283. $("#inputDialogOverlay").hide();
  284. });
  285. $("#inputDialogButton").click(okFunction);
  286. }
  287.  
  288. function showGui() {
  289. $("#popup_overlay").show();
  290. $("#popup").show();
  291. }
  292.  
  293. function hideGui() {
  294. $("#popup_overlay").css("display", "none");
  295. $("#popup").css("display", "none");
  296. }
  297.  
  298. /******************************************************************************/
  299.  
  300. function saveLocalData() {
  301. localStorage.setItem("highlights", JSON.stringify(highlights));
  302. }
  303.  
  304. function loadLocalData() {
  305. // alert("load");
  306. highlights = JSON.parse(localStorage.getItem("highlights"));
  307. if(highlights === null) {
  308. highlights = [];
  309. }
  310. // alert("afterLoad");
  311. }
  312.  
  313. /******************************************************************************/
  314. $(document).ready(function () {
  315.  
  316. // Riesigen Header entfernen
  317. $('#rt-header-overlay').remove();
  318. // Sounds vorladen
  319. $.each(sounds, function(name, url) {
  320. $("body").append("<audio id='"+name+"' src='"+url+"' hidden=true preload=auto></audio>");
  321. });
  322. // Einstellungen laden
  323. loadLocalData();
  324. // eigenes GUI einfügen
  325. initGui();
  326. });
  327.  
  328. /******************************************************************************/
  329. // enthalten die Namen der gefundenen Spiele
  330. var knownGames = {};
  331. var foundGames = {};
  332.  
  333. function resetHighlights() {
  334. $("#mmh td").css({
  335. backgroundColor: "transparent",
  336. color: "black"
  337. });
  338. }
  339.  
  340. function highlightArray() {
  341. foundGames = {};
  342. $.each(highlights, function(index, elem) {
  343. if (elem === null)
  344. return;
  345. var color = elem.color;
  346. var sound = elem.sound;
  347. var arr = elem.search instanceof Array ? elem.search : [elem.search];
  348. if(!(arr.length == 1 && arr[0] === ""))
  349. $.each(arr, function(index, text) {
  350. highlight(text, elem.color, elem.sound);
  351. });
  352. });
  353. knownGames = foundGames;
  354. }
  355.  
  356. function highlight(search, color, sound) {
  357. getNodes(search).each(function(){
  358. // Schrift färben?
  359. if(color)
  360. $(this).css("color", color);
  361. // Spiel unbekannt?
  362. if(!($(this).text() in knownGames)) {
  363. // Sound abspielen?
  364. if(sound) {
  365. document.getElementById(sound).play();
  366. // neu gefundene Spiele kurzzeitig hervorheben
  367. $(this).css("background-color", "orange");
  368. $(this).css("color", "black");
  369. }
  370. }
  371. foundGames[$(this).text()] = $(this).text();
  372. });
  373. }
  374.  
  375. function getNodes(text) {
  376. // Nur in Games Spalten suchen?
  377. if (searchGamesOnly) {
  378. var tds = $('#mmh table:first-child td:nth-child(4)')
  379. .add('#mmh table:last-child td:nth-child(2)');
  380. } else {
  381. var tds = $('td');
  382. }
  383. return tds.filter(':Contains(' + text + ')');
  384. }
  385.  
  386. /******************************************************************************/
  387. /*
  388. * removes every "falsy" value: undefined, null, 0, false, NaN and '':
  389. */
  390. function cleanArray(actual){
  391. var newArray = new Array();
  392. for(var i = 0; i<actual.length; i++){
  393. if (actual[i]){
  394. newArray.push(actual[i]);
  395. }
  396. }
  397. return newArray;
  398. }
  399.  
  400. /******************************************************************************/
  401. // jQuery :contains Case-Insensitive
  402. // http://css-tricks.com/snippets/jquery/make-jquery-contains-case-insensitive/
  403. jQuery.expr[':'].Contains = function(a, i, m) {
  404. return jQuery(a).text().toUpperCase()
  405. .indexOf(m[3].toUpperCase()) >= 0;
  406. };