WK Double Check

Toggle the mark given by WaniKani

  1. // ==UserScript==
  2. // @name WK Double Check
  3. // @namespace WKDblChk
  4. // @version 0.2
  5. // @description Toggle the mark given by WaniKani
  6. // @author Ethan
  7. // @include http*://www.wanikani.com/review/session*
  8. // @grant none
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. //Much of the following code is from the jQuery application extension used on WaniKani.com, which is resleased under the MIT license.
  13. //Modifications have been made to the code where necessary.
  14.  
  15. var e = {
  16. processCompleted: function (e,t){
  17. //to have only the visual activity of the original function
  18. var s;
  19. s = $.jStorage.get("currentItem");
  20. if (t.mc >= 1 && t.rc >= 1 || e.charAt(0) === "r" && s.mc >= 1) {
  21. //srs level up/down
  22. $.jStorage.get("r/srsIndicator") && Srs.load($.jStorage.get(e), s.srs);
  23.  
  24. }
  25. },
  26. processUncompleted: function (){
  27. //to reverse the changes that 'processCompleted' and 'renderPostAnswer' (and itself) makes
  28. //Toggle srs animation
  29. var oldSrs=document.getElementsByClassName("srs-down");
  30. if(oldSrs.length === 0){oldSrs=document.getElementsByClassName("srs-up")}
  31. if(typeof oldSrs[0] === "object"){
  32. var newSrs = oldSrs[0].cloneNode(true);
  33. newSrs.style.webkitAnimationDirection=newSrs.style.webkitAnimationDirection?"":"reverse"; //chrome
  34. newSrs.style.animationDirection=newSrs.style.animationDirection?"":"reverse"; //firefox
  35. oldSrs[0].parentNode.replaceChild(newSrs, oldSrs[0]);
  36. }
  37. //Change the meaning/reading correct/incorrect counters
  38. var currentItem = $.jStorage.get("currentItem");
  39. var currentId = (currentItem.voc?"v":currentItem.kan?"k":"r")+currentItem.id;
  40. var stats = $.jStorage.get(currentId);
  41. var questionType = $.jStorage.get("questionType");
  42. var counter = questionType[0];
  43. stats[counter+"c"]?
  44. delete stats[counter+"c"] && stats[counter+"i"]?stats[counter+"i"]++:stats[counter+"i"]=1:
  45. (stats[counter+"c"]=1) && stats[counter+"i"]?stats[counter+"i"]--:stats[counter+"i"]=0;
  46.  
  47. //Toggle answer field class
  48. $("#answer-form fieldset").hasClass("incorrect") ?
  49. $("#answer-form fieldset").addClass("correct").removeClass("incorrect") && $("#option-double-check").find("i").removeClass("icon-thumbs-up").addClass("icon-thumbs-down"):
  50. $("#answer-form fieldset").addClass("incorrect").removeClass("correct") && $("#option-double-check").find("i").removeClass("icon-thumbs-down").addClass("icon-thumbs-up");
  51.  
  52. },
  53. commitAnswer: function (e,t){
  54. console.log(e,t);
  55. //to do all the 'point of no return commands previously performed by 'processCompleted'
  56. var n, r, i, s, o, u, a, f, l;
  57. if (t.mc >= 1 && t.rc >= 1 || e.charAt(0) === "r" && t.mc >= 1) {
  58. s = $.jStorage.get("currentItem");
  59. n = $.jStorage.get("activeQueue");
  60. f = $.jStorage.get("reviewQueue");
  61. t.mi = t.mi || 0;
  62. t.ri = t.ri || 0;
  63. l = "/json/progress?" + e + "[]=" + t.mi + "&" + e + "[]=" + t.ri;
  64. r = $.jStorage.get("completedCount") + 1
  65. $.jStorage.set("completedCount", r);
  66.  
  67. a = function() {
  68. switch (e.charAt(0)) {
  69. case "r":
  70. return "recentCompletedRadicals";
  71. case "k":
  72. return "recentCompletedKanji";
  73. case "v":
  74. return "recentCompletedVocabulary"
  75. }
  76. }();
  77.  
  78.  
  79. i = $.jStorage.get(a) || [];
  80. i.push(e.slice(1));
  81. i = i.slice(Math.max(i.length - 10, 0));
  82. $.jStorage.set(a, i);
  83. $.jStorage.setTTL(a, 6e5), lastItems.addToList(e);
  84. //---where srs indicator used to be
  85. $.getJSON(l, function() {
  86. return !1
  87. }).done(function() {
  88. return !1
  89. }).fail(function() {
  90. var n;
  91. return n = $.jStorage.get("submitFailedQueue") || [], n.push({
  92. id: e,
  93. mi: t.mi,
  94. ri: t.ri
  95. }), $.jStorage.set("submitFailedQueue", n)
  96. }), u = $.grep(n, function(e) {
  97. return e.id === s.id && (s.rad && e.rad || s.kan && e.kan || s.voc && e.voc) ? !1 : !0
  98. });
  99. if (!$.jStorage.get("r/wrap-up") && f.length !== 0) {
  100. o = 11 - u.length;
  101. while (o -= 1) u.push(f.pop());
  102. u.filter(function(e) {
  103. return e
  104. })
  105. }
  106. return $.jStorage.set("activeQueue", u), $.jStorage.set("reviewQueue", f), $.jStorage.deleteKey(e)
  107. }
  108. },
  109. getQueueAndAssignQuestion: function() {
  110. var t, n, r, i, s, o;
  111. o = "/review/queue?", n = $.jStorage.get("recentCompletedRadicals") || [], t = $.jStorage.get("recentCompletedKanji") || [], r = $.jStorage.get("recentCompletedVocabulary") || [];
  112. if (n.length > 0)
  113. for (s in n)
  114. i = n[s], o += "r[]=" + i + "&";
  115. if (t.length > 0)
  116. for (s in t)
  117. i = t[s], o += "k[]=" + i + "&";
  118. if (r.length > 0)
  119. for (s in r)
  120. i = r[s], o += "v[]=" + i + "&";
  121. return $.getJSON(o, function(t) {
  122. var n;
  123. return n = t.splice(0, 10), $.jStorage.set("reviewQueue", t), $.jStorage.set("activeQueue", n), n.length > 0 ? ($("#reviews").is(":hidden") && $("#reviews").show(), e.nextQuestion()) : window.location = "/review/"
  124. }).done(function() {
  125. return e.countersReset()
  126. })
  127. },answerException: function(e) {
  128. var t, n;
  129. t = $("#additional-content"), n = $.jStorage.get("questionType"), $("#answer-exception").remove();
  130. if (!e.passed)
  131. return t.append($('<div id="answer-exception"><span>Need help? View the correct ' + n + " and mnemonic</span></div>").addClass("animated fadeInUp"));
  132. if (e.accurate && e.multipleAnswers)
  133. return t.append($('<div id="answer-exception"><span>Did you know this item has multiple possible ' + n + "s?</span></div>").addClass("animated fadeInUp"));
  134. if (!e.accurate)
  135. return t.append($('<div id="answer-exception"><span>Your answer was a bit off. Check the ' + n + " to make sure you are correct</span></div>").addClass("animated fadeInUp"))
  136. },buttons: function() {
  137. var t;
  138. return t = $("#user-response"), $("#submit-errors").hover(function() {
  139. return $(this).children("#submit-errors-ext-text").css("display", "inline")
  140. }, function() {
  141. return $(this).children("#submit-errors-ext-text").css("display", "none")
  142. }), $("#option-item-info").click(function() {
  143. if (t.is(":disabled"))
  144. return $("#answer-exception").remove()
  145. }), $("#submit-errors").click(function() {
  146. return e.submitFailedQueue({newQuestion: !1})
  147. })
  148. },counters: function() {
  149. return e.countersReset(), $.jStorage.listenKeyChange("questionCount", function(e, t) {
  150. var n, r, i;
  151. return r = $.jStorage.get("questionCount"), i = $.jStorage.get("wrongCount"), n = r === 0 ? 100 : Math.round((r - i) / r * 100), $("#correct-rate").html(n)
  152. }), $.jStorage.listenKeyChange("completedCount", function(e, t) {
  153. var n, r, i;
  154. return n = parseInt($("#completed-count").text()) + parseInt($("#available-count").text()), r = $.jStorage.get("completedCount"), i = Math.round(r / n * 100), i = isNaN(i) ? 0 : i, $("#completed-count").html(r), $("#progress-bar #bar").css("width", i + "%")
  155. }), $.jStorage.listenKeyChange("activeQueue", function(e, t) {
  156. var n;
  157. return n = $.jStorage.get("reviewQueue").length + $.jStorage.get("activeQueue").length, $("#available-count").html(n)
  158. })
  159. },countersIncr: function(e) {
  160. var t, n;
  161. return e || (n = $.jStorage.get("wrongCount") + 1, $.jStorage.set("wrongCount", n)), t = $.jStorage.get("questionCount") + 1, $.jStorage.set("questionCount", t)
  162. },countersReset: function() {
  163. return $.jStorage.set("questionCount", 0), $.jStorage.set("completedCount", 0), $.jStorage.set("wrongCount", 0)
  164. },load: function() {
  165. return e.submitFailedQueue({newQuestion: !0})
  166. },nextQuestion: function() {
  167. var t, n;
  168. return t = $.jStorage.get("activeQueue") || [], n = $.jStorage.get("r/wrap-up"), t.length > 0 ? e.randomQuestion() : n ? ($.jStorage.deleteKey("r/wrap-up"), window.location = "/review/") : e.submitFailedQueue({newQuestion: !0})
  169. },randomQuestion: function() {
  170. var e, t, n, r;
  171. return n = $.jStorage.get("activeQueue"), e = n[Math.floor(Math.random() * n.length)], t = e.kan ? $.jStorage.get("k" + e.id) : e.voc ? $.jStorage.get("v" + e.id) : void 0, r = e.rad ? "meaning" : t === null || typeof t.mc == "undefined" && typeof t.rc == "undefined" ? ["meaning", "reading"][Math.floor(Math.random() * 2)] : t.mc >= 1 ? "reading" : t.rc >= 1 ? "meaning" : void 0, $.jStorage.set("questionType", r), $.jStorage.set("currentItem", e)
  172. },renderPostAnswer: function(t) {
  173. return t.passed ? ($("#answer-form fieldset").addClass("correct"),$("#option-double-check").find("i").removeClass("icon-thumbs-up").addClass("icon-thumbs-down")) : $("#answer-form fieldset").addClass("incorrect"), $("#user-response").prop("disabled", !0), additionalContent.enableButtons(), lastItems.disableSessionStats(), e.countersIncr(t.passed), e.answerException(t), e.updateLocalItemStat(t.passed)
  174. },listenRenderView: function() {
  175. return $.jStorage.listenKeyChange("currentItem", function(e, t) {
  176. var n, r, i;
  177. return n = $.jStorage.get(e), r = $("#user-response"), i = $.jStorage.get("questionType"), $("html, body").animate({scrollTop: 0}, 200), additionalContent.disableItemInfo(), additionalContent.disableAudio(), Srs.remove(), $("#answer-form fieldset").removeClass(), r.prop("disabled", !1).val("").focus(), wanakana.unbind(r[0]), i === "reading" && wanakana.bind(r[0]), r.val(""), n.rad ? (n.custom_font_name ? $("#character span").html('<i class="radical-' + n.custom_font_name + '"></i>') : /.png/i.test(n.rad) ? $("#character span").html('<img src="https://s3.amazonaws.com/s3.wanikani.com/images/radicals/' + n.rad + '">') : $("#character span").html(n.rad), $("#character").removeClass().addClass("radical"), $("#question-type").removeClass().addClass(i), $("#question-type h1").html("Radical <strong>Name</strong>")) : n.kan ? ($("#character span").html(n.kan), $("#character").removeClass().addClass("kanji"), $("#question-type").removeClass().addClass(i), $("#question-type h1").html("Kanji <strong>" + i + "</strong>")) : n.voc && ($("#character span").html(n.voc), $("#character").removeClass().addClass("vocabulary"), $("#question-type").removeClass().addClass(i), $("#question-type h1").html("Vocabulary <strong>" + i + "</strong>")), i === "meaning" ? r.removeAttr("lang").attr("placeholder", "Your Response") : r.attr({lang: "ja",placeholder: "答え"}), loadingScreen.remove()
  178. })
  179. },submitFailedQueue: function(t) {
  180. var n, r, i, s;
  181. t.newQuestion = t.newQuestion || !1, i = $.jStorage.get("submitFailedQueue") || [];
  182. if (i.length > 0) {
  183. s = "/json/progress?";
  184. for (n in i)
  185. r = i[n], s += r.id + "[]=" + r.mi + "&" + r.id + "[]=" + r.ri + "&";
  186. return $.getJSON(s, function() {
  187. return !1
  188. }).done(function() {
  189. $.jStorage.deleteKey("submitFailedQueue");
  190. if (t.newQuestion === !0)
  191. return e.getQueueAndAssignQuestion()
  192. }).fail(function() {
  193. return $("#timeout").show(), $("#timeout-session-end").show(), idleTime.view(), $("#timeout-idle").hide()
  194. })
  195. }
  196. return e.getQueueAndAssignQuestion()
  197. },updateLocalItemStat: function(t) {
  198. var n, r, i, s, o;
  199. return n = $.jStorage.get("currentItem"), s = $.jStorage.get("questionType"), r = n.rad ? "r" : n.kan ? "k" : "v", r += n.id, i = $.jStorage.get(r) || {}, s === "meaning" ? t ? i.mc = 1 : i.mi = typeof i.mi == "undefined" ? 1 : i.mi + 1 : t ? i.rc = 1 : i.ri = typeof i.ri == "undefined" ? 1 : i.ri + 1, o = $.jStorage.set(r, i), $.jStorage.setTTL(r, 72e5), e.processCompleted(r, o);
  200. },listenSubmitFailedQueue: function() {
  201. return $.jStorage.listenKeyChange("submitFailedQueue", function(e, t) {
  202. var n;
  203. switch (t) {
  204. case "deleted":
  205. return !1;
  206. case "updated":
  207. return n = $.jStorage.get(e), $("#timeout").show(), $("#timeout-session-end").show(), idleTime.view(), $("#timeout-idle").hide()
  208. }
  209. })
  210. },listenWrapUp: function() {
  211. return $.jStorage.deleteKey("r/wrap-up"), $.jStorage.listenKeyChange("activeQueue", function(e, t) {
  212. var n;
  213. if ($.jStorage.get("r/wrap-up"))
  214. switch (t) {
  215. case "updated":
  216. return n = ($.jStorage.get("activeQueue") || []).length, $("#wrap-up-countdown").text(n)
  217. }
  218. })
  219. }
  220. };
  221.  
  222.  
  223.  
  224. function DoubleCheck(e){
  225.  
  226.  
  227. console.log("DoubleCheck loaded. e = ", e);
  228. $("#additional-content ul").append('<li id="option-double-check" class="disabled"><span title="Change Result"><i class="icon-thumbs-up"></i></span></li>');
  229.  
  230. $("#additional-content ul li").css("width", "16.2%"); //make space in the buttons row
  231. var customStyle = document.createElement("style");
  232. customStyle.innerHTML = "#answer-exception span:before {left: 40.5%}"; //get the arrow to point to the eye again
  233. document.head.appendChild(customStyle);
  234.  
  235. $("#option-double-check").click(function(){
  236. if (this.className !== "disabled"){
  237.  
  238.  
  239. e.processUncompleted();
  240.  
  241. var t = $.jStorage.get("currentItem");
  242. var r = t.rad ? "r" : t.kan ? "k" : "v";
  243. r += t.id;
  244. var o = $.jStorage.get(r);
  245. console.log(r,o);
  246. e.processCompleted(r, o);
  247. }
  248. });
  249.  
  250. $("#answer-form button")[0].id = "answer-submit", //give the existing button a hook
  251. $("#answer-submit").unbind();
  252.  
  253. //Reassign click event for submission
  254. $("#answer-submit").click(function() {
  255. var t, n, r, i, s;
  256. r = $("#answer-form button");
  257. i = $("#answer-form form");
  258. s = $("#user-response");
  259. t = function() { //method to mark answer
  260. $("#option-double-check").removeClass("disabled");
  261.  
  262. var t, n, r, o;
  263. return r = answerChecker.evaluate($.jStorage.get("questionType"), s.val()), $("html, body").animate({scrollTop: 0}, 200), r.exception ? (t = $.jStorage.get("currentItem"), i = $("#answer-form form"), o = $("#reviews"), i.is(":animated") || (o.css("overflow-x", "hidden"), n = t.emph === "onyomi" ? "on'yomi" : "kun'yomi", i.effect("shake", {}, 100, function() {
  264. return o.css("overflow-x", "visible"), i.append($('<div id="answer-exception" class="answer-exception-form"><span>WaniKani is looking for the ' + n + " reading</span></div>").addClass("animated fadeInUp"))
  265. }).find("input").focus()), !1) : (s.blur(), e.renderPostAnswer(r), !1)
  266. };
  267. n = function() { //method for after marking complete
  268. $("#option-double-check").addClass("disabled").find("i").removeClass("icon-thumbs-down").addClass("icon-thumbs-up");//reset the button
  269.  
  270.  
  271. var n = $.jStorage.get("currentItem");
  272. var r = n.rad ? "r" : n.kan ? "k" : "v";
  273. r += n.id;
  274. var i = $.jStorage.get(r) || {};
  275. e.commitAnswer(r, i)
  276.  
  277. return $("#answer-exception").remove(), e.nextQuestion(), additionalContent.closeItemInfo(), !1
  278. };
  279.  
  280.  
  281. if (s.is(":disabled"))
  282. return n();
  283. if ($.jStorage.get("questionType") === "reading" && answerChecker.isAsciiPresent(s.val()) || $.jStorage.get("questionType") === "meaning" && answerChecker.isNonAsciiPresent(s.val()) || s.val().length === 0)
  284. return i.is(":animated") || ($("#reviews").css("overflow-x", "hidden"), i.effect("shake", {}, 100, function() {
  285. return $("#reviews").css("overflow-x", "visible")
  286. })), !1;
  287. if (s.val().length !== 0){
  288. return t();
  289. }
  290. });
  291. }
  292.  
  293.  
  294.  
  295. if (document.readyState === 'complete'){
  296. console.info("About to initialise DoubleCheck");
  297. DoubleCheck(e);
  298. } else {
  299. console.info("Window not ready yet, adding listener");
  300. window.addEventListener("load", function() { DoubleCheck(e); }, false);
  301. }