A Chrome extension that gives you finer control over MyAnimeList.net scores
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

368 rader
13 KiB

  1. /* ------------------------------- Constants ------------------------------- */
  2. var MAX_BUCKETS = 256;
  3. var LOADING_IMG = '<img src="http://cdn.myanimelist.net/images/xmlhttp-loader.gif" align="center">';
  4. /* ------------------------ Miscellaneous functions ------------------------ */
  5. function get_anime_id_from_href(href) {
  6. var anime_id;
  7. if (href.indexOf("/anime/") != -1)
  8. anime_id = href.substr(href.indexOf("/anime/") + "/anime/".length);
  9. else
  10. anime_id = href.substr(href.indexOf("id=") + "id=".length);
  11. if (anime_id.indexOf("/") != -1)
  12. anime_id = anime_id.substr(0, anime_id.indexOf("/"));
  13. if (anime_id.indexOf("&") != -1)
  14. anime_id = anime_id.substr(0, anime_id.indexOf("&"));
  15. return anime_id;
  16. }
  17. function get_edit_id_from_href(href) {
  18. var anime_id = href.substr(href.indexOf("id=") + "id=".length);
  19. if (anime_id.indexOf("&") != -1)
  20. anime_id = anime_id.substr(0, anime_id.indexOf("&"));
  21. return anime_id;
  22. }
  23. function get_scores_from_element(elem) {
  24. var score_100 = parseInt(elem.val());
  25. var score_10 = Math.round(score_100 / 10.);
  26. if (isNaN(score_100) || score_100 < 1 || score_100 > 100) {
  27. alert("Invalid score: must be an integer between 1 and 100.");
  28. return null;
  29. }
  30. return [score_100, score_10];
  31. }
  32. /* --------------------------- Storage functions --------------------------- */
  33. function save_score(anime_id, score) {
  34. var bucket_id = (parseInt(anime_id) % MAX_BUCKETS).toString();
  35. chrome.storage.sync.get(bucket_id, function(data) {
  36. var bucket = data[bucket_id];
  37. if (bucket === undefined)
  38. bucket = data[bucket_id] = {};
  39. bucket[anime_id] = score;
  40. chrome.storage.sync.set(data);
  41. });
  42. }
  43. function retrieve_scores(anime_id, callback) {
  44. var bucket_id = null;
  45. if (anime_id !== null)
  46. bucket_id = (parseInt(anime_id) % MAX_BUCKETS).toString();
  47. chrome.storage.sync.get(bucket_id, function(data) {
  48. if (anime_id !== null) {
  49. var bucket = data[bucket_id];
  50. if (bucket !== undefined && bucket[anime_id] !== undefined)
  51. callback(bucket[anime_id]);
  52. else
  53. callback(null);
  54. }
  55. else
  56. callback(data);
  57. });
  58. }
  59. function remove_score(anime_id) {
  60. var bucket_id = (parseInt(anime_id) % MAX_BUCKETS).toString();
  61. chrome.storage.sync.get(bucket_id, function(data) {
  62. var bucket = data[bucket_id];
  63. if (bucket === undefined || bucket[anime_id] === undefined)
  64. return;
  65. delete bucket[anime_id];
  66. if ($.isEmptyObject(bucket))
  67. chrome.storage.sync.remove(bucket_id);
  68. else
  69. chrome.storage.sync.set(data);
  70. });
  71. }
  72. /* ----------------------- Event patches/injections ------------------------ */
  73. function update_list_score(anime_id) {
  74. var new_scores = get_scores_from_element($("#scoretext" + anime_id));
  75. if (new_scores === null)
  76. return;
  77. var new_score_100 = new_scores[0], new_score_10 = new_scores[1];
  78. var payload = {id: anime_id, score: new_score_10};
  79. $("#scorebutton" + anime_id).prop("disabled", true);
  80. $.post("/includes/ajax.inc.php?t=63", payload, function(data) {
  81. $("#scoreval" + anime_id).text(new_score_100);
  82. $("#scoretext" + anime_id).val("");
  83. $("#scorediv" + anime_id).css("display", "none");
  84. $("#scorebutton" + anime_id).prop("disabled", false);
  85. });
  86. save_score(anime_id, new_score_100);
  87. }
  88. function update_anime_score(anime_id, is_new) {
  89. var new_scores = get_scores_from_element($("#myinfo_score"));
  90. if (new_scores === null)
  91. return;
  92. var new_score_100 = new_scores[0], new_score_10 = new_scores[1];
  93. var t_id, payload = {score: new_score_10};
  94. payload["status"] = $("#myinfo_status").val();
  95. payload["epsseen"] = $("#myinfo_watchedeps").val();
  96. if (is_new) {
  97. payload["aid"] = anime_id;
  98. t_id = "61";
  99. }
  100. else {
  101. payload["alistid"] = anime_id;
  102. payload["aid"] = $("#myinfo_anime_id").val();
  103. payload["astatus"] = $("#myinfo_curstatus").val();
  104. t_id = "62";
  105. }
  106. $("#myinfoDisplay").html(LOADING_IMG);
  107. $.post("/includes/ajax.inc.php?t=" + t_id, payload, function(data) {
  108. if (is_new) {
  109. document.getElementById("myinfoDisplay").innerHTML = "";
  110. document.getElementById("addtolist").innerHTML = data;
  111. }
  112. else
  113. document.getElementById("myinfoDisplay").innerHTML = data;
  114. });
  115. save_score(anime_id, new_score_100);
  116. }
  117. function submit_add_form(submit_button) {
  118. var anime_id = $("input[name='series_title']").val();
  119. if (!anime_id)
  120. return submit_button[0].click();
  121. var new_scores = get_scores_from_element($("#score_input"));
  122. if (new_scores === null)
  123. return;
  124. var new_score_100 = new_scores[0], new_score_10 = new_scores[1];
  125. $("select[name='score']").val(new_score_10);
  126. save_score(anime_id, new_score_100);
  127. submit_button[0].click();
  128. }
  129. function submit_edit_form(anime_id, submit_type, submit_button) {
  130. if (submit_type == 2) {
  131. var new_scores = get_scores_from_element($("#score_input"));
  132. if (new_scores === null)
  133. return;
  134. var new_score_100 = new_scores[0], new_score_10 = new_scores[1];
  135. $("select[name='score']").val(new_score_10);
  136. save_score(anime_id, new_score_100);
  137. }
  138. else if (submit_type == 3)
  139. remove_score(anime_id);
  140. submit_button[0].click();
  141. }
  142. /* -------------------------------- Sorting -------------------------------- */
  143. function sort_list() {
  144. var headers = [".header_cw", ".header_completed", ".header_onhold",
  145. ".header_dropped", ".header_ptw"];
  146. $.each(headers, function(i, header) {
  147. $(header).next()
  148. .nextUntil($(".category_totals").closest("table"))
  149. .wrapAll('<div class="list-chart-group"/>');
  150. });
  151. $(".list-chart-group table").each(function(i, row) {
  152. $(row).add($(row).next())
  153. .wrapAll('<div class="list-chart-row"/>');
  154. });
  155. $(".list-chart-group").each(function(i, group) {
  156. $(group).find(".list-chart-row").sort(function (a, b) {
  157. return $(b).find("span[id^='scoreval']").text() - $(a).find("span[id^='scoreval']").text();
  158. }).each(function(i, row) {
  159. $(group).append(row);
  160. });
  161. $(group).find(".list-chart-row").each(function(i, row) {
  162. $(row).find("tr").first().children().first().text(i + 1);
  163. $(row).find((i % 2) ? ".td1" : ".td2").toggleClass("td1 td2");
  164. });
  165. });
  166. }
  167. /* ---------------------------- Extension hooks ---------------------------- */
  168. function hook_list() {
  169. retrieve_scores(null, function(data) {
  170. $("span[id^='scoreval']").each(function(i, elem) {
  171. var anime_id = elem.id.split("scoreval")[1];
  172. var bucket_id = (parseInt(anime_id) % MAX_BUCKETS).toString();
  173. var bucket = data[bucket_id];
  174. if (bucket !== undefined && bucket[anime_id] !== undefined)
  175. $(elem).text(bucket[anime_id]);
  176. else {
  177. var current = parseInt($(elem).text());
  178. if (!isNaN(current))
  179. $(elem).text(current * 10);
  180. }
  181. $("#scorediv" + anime_id)
  182. .after($("<div>")
  183. .attr("id", "scorediv" + anime_id)
  184. .css("display", "none")
  185. .append($('<input>')
  186. .attr("type", "text")
  187. .attr("id", "scoretext" + anime_id)
  188. .attr("size", "2")
  189. .keydown(function(a_id) {
  190. return function(ev) {
  191. if ((window.event ? window.event.keyCode : ev.which) == 13)
  192. update_list_score(a_id);
  193. else
  194. return true;
  195. }
  196. }(anime_id)))
  197. .append($("<input>")
  198. .attr("type", "button")
  199. .attr("id", "scorebutton" + anime_id)
  200. .attr("value", "Go")
  201. .click(function(a_id) {
  202. return function() { return update_list_score(a_id); }
  203. }(anime_id))))
  204. .remove();
  205. });
  206. if (window.location.href.indexOf("order=4") != -1)
  207. sort_list();
  208. });
  209. }
  210. function hook_anime(anime_id) {
  211. retrieve_scores(anime_id, function(score) {
  212. var old_input = $("#myinfo_score");
  213. var old_button = $("input[name='myinfo_submit']");
  214. var is_new = old_button.attr("value") == "Add";
  215. if (!is_new && score === null) {
  216. var old_score = parseInt(old_input.val());
  217. score = old_score == 0 ? "" : old_score * 10;
  218. }
  219. old_input.after($("<span> / 100</span>"))
  220. .after($("<input>")
  221. .attr("type", "text")
  222. .attr("id", "myinfo_score")
  223. .attr("name", "myinfo_score")
  224. .attr("class", "inputtext")
  225. .attr("value", (score === null) ? "" : score)
  226. .attr("size", "3"))
  227. .remove();
  228. old_button.after($("<input>")
  229. .attr("type", "button")
  230. .attr("name", "myinfo_submit")
  231. .attr("value", old_button.attr("value"))
  232. .attr("class", "inputButton")
  233. .click(function(a_id, is_new) {
  234. return function() { return update_anime_score(a_id, is_new); }
  235. }(anime_id, is_new)))
  236. .remove();
  237. });
  238. }
  239. function hook_add() {
  240. var old_input = $("select[name='score']");
  241. var old_submit = $("input[type='button'][onclick='checkValidSubmit(1)']");
  242. old_input.after($("<span> / 100</span>"))
  243. .after($("<input>")
  244. .attr("type", "text")
  245. .attr("id", "score_input")
  246. .attr("class", "inputtext")
  247. .attr("size", "3"))
  248. .hide();
  249. old_submit.after($("<input>")
  250. .attr("type", "button")
  251. .attr("class", "inputButton")
  252. .attr("style", old_submit.attr("style"))
  253. .attr("value", old_submit.attr("value"))
  254. .click(function(button) {
  255. return function() { return submit_add_form(button); }
  256. }(old_submit)))
  257. .hide();
  258. }
  259. function hook_edit(anime_id) {
  260. retrieve_scores(anime_id, function(score) {
  261. var old_input = $("select[name='score']");
  262. var old_edit = $("input[type='button'][onclick='checkValidSubmit(2)']");
  263. var old_delete = $("input[type='button'][onclick='checkValidSubmit(3)']");
  264. if (score === null) {
  265. var old_score = parseInt(old_input.val());
  266. score = old_score == 0 ? "" : old_score * 10;
  267. }
  268. old_input.after($("<span> / 100</span>"))
  269. .after($("<input>")
  270. .attr("type", "text")
  271. .attr("id", "score_input")
  272. .attr("class", "inputtext")
  273. .attr("value", score)
  274. .attr("size", "3"))
  275. .hide();
  276. old_edit.after($("<input>")
  277. .attr("type", "button")
  278. .attr("class", "inputButton")
  279. .attr("style", old_edit.attr("style"))
  280. .attr("value", old_edit.attr("value"))
  281. .click(function(a_id, button) {
  282. return function() { return submit_edit_form(a_id, 2, button); }
  283. }(anime_id, old_edit)))
  284. .hide();
  285. old_delete.after($("<input>")
  286. .attr("type", "button")
  287. .attr("class", "inputButton")
  288. .attr("value", old_delete.attr("value"))
  289. .click(function(a_id, button) {
  290. return function() { return submit_edit_form(a_id, 3, button); }
  291. }(anime_id, old_delete)))
  292. .hide();
  293. });
  294. }
  295. function hook_addtolist() {
  296. /* TODO: this entry point is unimplemented - it's rarely used and difficult
  297. to inject into, so I'm avoiding it for now. */
  298. $("<p><b>Note:</b> For the time being, anime added through this " +
  299. "interface cannot be given scores on the 100-point scale (the old " +
  300. "10-point system is used).</p><p>To give a more specific number, " +
  301. "simply add the anime here, then go to its own page or to your list " +
  302. "page, and update the score.</p>").insertAfter($("#stype").parent());
  303. }
  304. /* ------------------------------- Main hook ------------------------------- */
  305. $(document).ready(function() {
  306. var href = window.location.href;
  307. if (href.indexOf("/animelist/") != -1)
  308. hook_list();
  309. else if (href.indexOf("/anime/") != -1 || href.indexOf("/anime.php") != -1)
  310. hook_anime(get_anime_id_from_href(href));
  311. else if (href.indexOf("/panel.php") != -1 && href.indexOf("go=add") != -1)
  312. hook_add();
  313. else if (href.indexOf("/editlist.php") != -1 && href.indexOf("type=anime") != -1)
  314. hook_edit(get_edit_id_from_href(href));
  315. else if (href.indexOf("/addtolist.php") != -1)
  316. hook_addtolist();
  317. });