A Chrome extension that gives you finer control over MyAnimeList.net scores
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

278 行
9.4 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 = href.substr(href.indexOf("/anime/") + "/anime/".length);
  7. if (anime_id.indexOf("/") != -1)
  8. anime_id = anime_id.substr(0, anime_id.indexOf("/"));
  9. return anime_id;
  10. }
  11. function get_edit_id_from_href(href) {
  12. var anime_id = href.substr(href.indexOf("id=") + "id=".length);
  13. if (anime_id.indexOf("&") != -1)
  14. anime_id = anime_id.substr(0, anime_id.indexOf("&"));
  15. return anime_id;
  16. }
  17. function get_scores_from_element(elem) {
  18. var score_100 = parseInt(elem.val());
  19. var score_10 = Math.round(score_100 / 10.);
  20. if (isNaN(score_100) || score_100 < 1 || score_100 > 100) {
  21. alert("Invalid score: must be an integer between 1 and 100.");
  22. return null;
  23. }
  24. return [score_100, score_10];
  25. }
  26. /* Storage functions */
  27. function save_score(anime_id, score) {
  28. var bucket_id = (parseInt(anime_id) % MAX_BUCKETS).toString();
  29. chrome.storage.sync.get(bucket_id, function(data) {
  30. var bucket = data[bucket_id];
  31. if (bucket === undefined)
  32. bucket = data[bucket_id] = {};
  33. bucket[anime_id] = score;
  34. chrome.storage.sync.set(data);
  35. });
  36. }
  37. function retrieve_scores(anime_id, callback) {
  38. var bucket_id = null;
  39. if (anime_id !== null)
  40. bucket_id = (parseInt(anime_id) % MAX_BUCKETS).toString();
  41. chrome.storage.sync.get(bucket_id, function(data) {
  42. if (anime_id !== null) {
  43. var bucket = data[bucket_id];
  44. if (bucket !== undefined && bucket[anime_id] !== undefined)
  45. callback(bucket[anime_id]);
  46. else
  47. callback(null);
  48. }
  49. else
  50. callback(data);
  51. });
  52. }
  53. function remove_score(anime_id) {
  54. var bucket_id = (parseInt(anime_id) % MAX_BUCKETS).toString();
  55. chrome.storage.sync.get(bucket_id, function(data) {
  56. var bucket = data[bucket_id];
  57. if (bucket === undefined || bucket[anime_id] === undefined)
  58. return;
  59. delete bucket[anime_id];
  60. if ($.isEmptyObject(bucket))
  61. chrome.storage.sync.remove(bucket_id);
  62. else
  63. chrome.storage.sync.set(data);
  64. });
  65. }
  66. /* Event patches/injections */
  67. function update_list_score(anime_id) {
  68. var new_scores = get_scores_from_element($("#scoretext" + anime_id));
  69. if (new_scores === null)
  70. return;
  71. var new_score_100 = new_scores[0], new_score_10 = new_scores[1];
  72. var payload = {id: anime_id, score: new_score_10};
  73. $("#scorebutton" + anime_id).prop("disabled", true);
  74. $.post("/includes/ajax.inc.php?t=63", payload, function(data) {
  75. $("#scoreval" + anime_id).text(new_score_100);
  76. $("#scoretext" + anime_id).val("");
  77. $("#scorediv" + anime_id).css("display", "none");
  78. $("#scorebutton" + anime_id).prop("disabled", false);
  79. });
  80. save_score(anime_id, new_score_100);
  81. }
  82. function update_anime_score(anime_id, is_new) {
  83. var new_scores = get_scores_from_element($("#myinfo_score"));
  84. if (new_scores === null)
  85. return;
  86. var new_score_100 = new_scores[0], new_score_10 = new_scores[1];
  87. var t_id, payload = {score: new_score_10};
  88. payload["status"] = $("#myinfo_status").val();
  89. payload["epsseen"] = $("#myinfo_watchedeps").val();
  90. if (is_new) {
  91. payload["aid"] = anime_id;
  92. t_id = "61";
  93. }
  94. else {
  95. payload["alistid"] = anime_id;
  96. payload["aid"] = $("#myinfo_anime_id").val();
  97. payload["astatus"] = $("#myinfo_curstatus").val();
  98. t_id = "62";
  99. }
  100. $("#myinfoDisplay").html(LOADING_IMG);
  101. $.post("/includes/ajax.inc.php?t=" + t_id, payload, function(data) {
  102. if (is_new) {
  103. document.getElementById("myinfoDisplay").innerHTML = "";
  104. document.getElementById("addtolist").innerHTML = data;
  105. }
  106. else
  107. document.getElementById("myinfoDisplay").innerHTML = data;
  108. });
  109. save_score(anime_id, new_score_100);
  110. }
  111. function submit_edit_form(anime_id, submit_type, submit_button) {
  112. if (submit_type == 2) {
  113. var new_scores = get_scores_from_element($("#score_input"));
  114. if (new_scores === null)
  115. return;
  116. var new_score_100 = new_scores[0], new_score_10 = new_scores[1];
  117. $("select[name='score']").val(new_score_10);
  118. save_score(anime_id, new_score_100);
  119. }
  120. else if (submit_type == 3)
  121. remove_score(anime_id);
  122. submit_button[0].click();
  123. }
  124. /* Extension hooks */
  125. function hook_list() {
  126. retrieve_scores(null, function(data) {
  127. $("span[id^='scoreval']").each(function(i, elem) {
  128. var anime_id = elem.id.split("scoreval")[1];
  129. var bucket_id = (parseInt(anime_id) % MAX_BUCKETS).toString();
  130. var bucket = data[bucket_id];
  131. if (bucket !== undefined && bucket[anime_id] !== undefined)
  132. $(elem).text(bucket[anime_id]);
  133. else {
  134. var current = parseInt($(elem).text());
  135. if (!isNaN(current))
  136. $(elem).text(current * 10);
  137. }
  138. $("#scorediv" + anime_id)
  139. .after($("<div>")
  140. .attr("id", "scorediv" + anime_id)
  141. .css("display", "none")
  142. .append($('<input>')
  143. .attr("type", "text")
  144. .attr("id", "scoretext" + anime_id)
  145. .attr("size", "2")
  146. .keydown(function(a_id) {
  147. return function(ev) {
  148. if ((window.event ? window.event.keyCode : ev.which) == 13)
  149. update_list_score(a_id);
  150. else
  151. return true;
  152. }
  153. }(anime_id)))
  154. .append($("<input>")
  155. .attr("type", "button")
  156. .attr("id", "scorebutton" + anime_id)
  157. .attr("value", "Go")
  158. .click(function(a_id) {
  159. return function() { return update_list_score(a_id); }
  160. }(anime_id))))
  161. .remove();
  162. });
  163. });
  164. }
  165. function hook_anime(anime_id) {
  166. retrieve_scores(anime_id, function(score) {
  167. var old_input = $("#myinfo_score");
  168. var old_button = $("input[name='myinfo_submit']");
  169. var is_new = old_button.attr("value") == "Add";
  170. if (!is_new && score === null) {
  171. var old_score = parseInt(old_input.val());
  172. score = old_score == 0 ? "" : old_score * 10;
  173. }
  174. old_input.after($("<span> / 100</span>"))
  175. .after($("<input>")
  176. .attr("type", "text")
  177. .attr("id", "myinfo_score")
  178. .attr("name", "myinfo_score")
  179. .attr("class", "inputtext")
  180. .attr("value", (score === null) ? "" : score)
  181. .attr("size", "3"))
  182. .remove();
  183. old_button.after($("<input>")
  184. .attr("type", "button")
  185. .attr("name", "myinfo_submit")
  186. .attr("value", old_button.attr("value"))
  187. .attr("class", "inputButton")
  188. .click(function(a_id, is_new) {
  189. return function() { return update_anime_score(a_id, is_new); }
  190. }(anime_id, is_new)))
  191. .remove();
  192. });
  193. }
  194. function hook_edit(anime_id) {
  195. retrieve_scores(anime_id, function(score) {
  196. var old_input = $("select[name='score']");
  197. var old_edit = $("input[type='button'][onclick='checkValidSubmit(2)']");
  198. var old_delete = $("input[type='button'][onclick='checkValidSubmit(3)']");
  199. if (score === null) {
  200. var old_score = parseInt(old_input.val());
  201. score = old_score == 0 ? "" : old_score * 10;
  202. }
  203. old_input.after($("<span> / 100</span>"))
  204. .after($("<input>")
  205. .attr("type", "text")
  206. .attr("id", "score_input")
  207. .attr("class", "inputtext")
  208. .attr("value", score)
  209. .attr("size", "3"))
  210. .hide();
  211. old_edit.after($("<input>")
  212. .attr("type", "button")
  213. .attr("class", "inputButton")
  214. .attr("style", old_edit.attr("style"))
  215. .attr("value", old_edit.attr("value"))
  216. .click(function(a_id, button) {
  217. return function() { return submit_edit_form(a_id, 2, old_edit); }
  218. }(anime_id, old_edit)))
  219. .hide();
  220. old_delete.after($("<input>")
  221. .attr("type", "button")
  222. .attr("class", "inputButton")
  223. .attr("value", old_delete.attr("value"))
  224. .click(function(a_id, button) {
  225. return function() { return submit_edit_form(a_id, 3, old_delete); }
  226. }(anime_id, old_delete)))
  227. .hide();
  228. });
  229. }
  230. /* Main extension hook */
  231. $(document).ready(function() {
  232. var href = window.location.href;
  233. if (href.indexOf("/animelist/") != -1)
  234. hook_list();
  235. else if (href.indexOf("/anime/") != -1)
  236. hook_anime(get_anime_id_from_href(href));
  237. else if (href.indexOf("/editlist.php") != -1 && href.indexOf("type=anime") != -1)
  238. hook_edit(get_edit_id_from_href(href));
  239. });