WK Auto Commit

Auto commit for Wanikani

  1. // ==UserScript==
  2. // @name WK Auto Commit
  3. // @namespace WKAUTOCOMMIT
  4. // @version 0.4.8
  5. // @description Auto commit for Wanikani
  6. // @author Johannes Mikulasch
  7. // @match http://www.wanikani.com/subjects/*
  8. // @match https://www.wanikani.com/subjects/*
  9. // @match http://www.wanikani.com/subject-lessons/*
  10. // @match https://www.wanikani.com/subject-lessons/*
  11. // @grant none
  12. // @run-at document-end
  13. // @license
  14. // ==/UserScript==
  15.  
  16. /*
  17. * WK Auto Commit
  18. * If you typed in the correct answer then it is automatically commited.
  19. * Therefore, you have to use the 'enter' key way less than before.
  20. *
  21. * Version 0.4.8
  22. * Fix: Run this script on "wanikani.com/subject-lessons", as Wanikani have just renamed their lessons URL
  23. * Version 0.4.7
  24. * Fix: show button to activate/deactivate in footer again.
  25. * Version 0.4.6
  26. * Revert input detection to onkeyup, as "input" event missed kana input
  27. * Version 0.4.5
  28. * Consider user-defined synonyms for the meaning of a vocab/kanji/radical as well
  29. * Further prevent double commits by using the "input" element's "input" event instead of the "onkeyup" function
  30. * Version 0.4.4
  31. * Bugfix: correctly detect double-check from lightning mode
  32. * Version 0.4.3
  33. * Bugfix: prevent a double commit when typing fast, which led to a shaking input window or in the worst case to
  34. * wrong input.
  35. * Version 0.4.2
  36. * Quickfix: adapt to Wanikani update, which was deployed on March 27th, 2023
  37. * (see https://community.wanikani.com/t/updates-to-lessons-reviews-and-extra-study/60912)
  38. * - removed jStorage and jQuery references
  39. * - changed the @match for the new lesson and review urls
  40. * - Note: did not check with compatibilites of other user scripts (like Lightning mode or Katakana for On'yomi) yet.
  41. * Version 0.4.1
  42. * Bugfix: call commit() at most one time for each item
  43. * (see https://community.wanikani.com/t/userscript-auto-commit-the-end-of-the-enter-key/11825/64)
  44. * Version 0.4
  45. * Compatibility with Lightning mode from the Double-Check userscript
  46. * Compatibility with Katakana For On'yomi userscript
  47. * Version 0.3
  48. * Script works now on the Lessons page too
  49. * Version 0.2
  50. * Makes script work with Greasemonkey and Firefox
  51. * Version 0.1
  52. * Initial version
  53. *
  54. */
  55.  
  56. /* jshint -W097 */
  57. 'use strict';
  58.  
  59. var activated = true;
  60. var click_threshold = 600;
  61.  
  62. let expected_answers = [];
  63. let synonyms = {};
  64.  
  65. var is_userscript_lightningmode_active = function () {
  66. /* Returns true if "Lightning Mode" from Userscript Double-Check is active */
  67. return Boolean(document.querySelector('.doublecheck-active'));
  68. };
  69.  
  70. var toggle = function () {
  71. var button = document.querySelector("#WKAUTOCOMMIT_button");
  72. if (activated) {
  73. // Deactivates WK Auto Commit mode
  74. button.title = "Switch auto commit on";
  75. button.style.opacity = 0.5;
  76. button.textContent = "Auto Commit is off";
  77. activated = false;
  78. } else {
  79. // Activates WK Auto Commit mode
  80. button.title = "Switch auto commit off";
  81. button.style.opacity = 1.0;
  82. button.textContent = "Auto Commit is on";
  83. activated = true;
  84. }
  85. };
  86.  
  87. var sanitize = function (str1) {
  88. var str2 = str1.replace(/\s/g, ''); // Removes Whitespaces
  89. str2 = str2.toLowerCase();
  90. return str2;
  91. };
  92.  
  93. var commit = function () {
  94. if(!commit.usable) return;
  95. // Temporarily deactivate the commit function to prevent double commits
  96. commit.usable = false;
  97. const inputbutton = document.querySelector(".quiz-input__submit-button");
  98. inputbutton.click();
  99. if (!is_userscript_lightningmode_active()) {
  100. setTimeout(function(){ inputbutton.click();}, click_threshold);
  101. }
  102.  
  103. };
  104.  
  105. var check_input = function () {
  106. const currentresponse = document.querySelector("#user-response").value;
  107. //console.log("Checking Input", currentresponse, expected_answers);
  108. for (var i in expected_answers) {
  109. if (sanitize(currentresponse) === sanitize(expected_answers[i])) {
  110. commit();
  111. break;
  112. }
  113. }
  114. };
  115.  
  116. var register_check_input = function () {
  117. var userinput = document.querySelector("#user-response");
  118. //userinput.addEventListener("input", function (event) {
  119. userinput.onkeyup = function (event) {
  120. if (activated) {
  121. check_input();
  122. }
  123. };
  124. };
  125.  
  126. var addButton = function () {
  127. /* Define button */
  128. var button = document.querySelector("#WKAUTOCOMMIT_button");
  129. if (!button) {
  130. button = document.createElement("div");
  131. button.id = "WKAUTOCOMMIT_button";
  132. button.title = "Toggle Auto Commit Mode";
  133. button.textContent = "Auto Commit is on";
  134. button.style.backgroundColor = "#C55";
  135. button.style.opacity = 1;
  136. button.style.display = "inline-block";
  137. button.style.fontSize = "0.8125em";
  138. button.style.color = "#FFF";
  139. button.style.cursor = "pointer"
  140. button.style.padding = "10px";
  141. button.style.marginLeft = "10px";
  142. button.style.verticalAlign = "bottom";
  143. button.onclick = toggle;
  144.  
  145. /* Prepend button to footer */
  146. var footer = document.querySelector(".quiz-footer");
  147. footer.appendChild(button);
  148. }
  149. };
  150.  
  151. /* Load user synonyms. Load them only once. */
  152. var loadSynonyms = function () {
  153. if (loadSynonyms.loaded) return;
  154. const dataUserSynonyms = document.querySelector('script[data-quiz-user-synonyms-target]');
  155. if (!dataUserSynonyms) return;
  156. synonyms = JSON.parse(dataUserSynonyms.innerHTML);
  157. loadSynonyms.loaded = true;
  158. };
  159.  
  160. /* Save synonyms added by the user during the quiz session */
  161. window.addEventListener("didUpdateUserSynonyms", function(event) {
  162. //console.log("Received didUpdateUserSynonyms event from WaniKani", event);
  163. synonyms[event.detail.subjectId] = event.detail.synonyms;
  164. });
  165.  
  166. /* React on a willShowNextQuestion event, which is triggered by WaniKani when a new question is shown */
  167. window.addEventListener("willShowNextQuestion", function(event) {
  168. //console.log("Received willShowNextQuestion event from WaniKani", event);
  169. register_check_input();
  170. addButton();
  171. loadSynonyms();
  172.  
  173. /* Get expected answers from current item depending on the task (reading or meaning) */
  174. expected_answers = []
  175. const item = event.detail;
  176. const subject = item.subject;
  177. if (item.questionType === "meaning") {
  178. expected_answers = expected_answers.concat(subject.meanings);
  179. const subjectSynonyms = (subject.id in synonyms) ? synonyms[subject.id] : [];
  180. expected_answers = expected_answers.concat(subjectSynonyms);
  181. } else if (item.questionType === "reading") {
  182. if (subject.type === 'Vocabulary') {
  183. expected_answers = expected_answers.concat(subject.readings.map((e) => e.reading));
  184. } else if (subject.type === 'Kanji') {
  185. if (subject.primary_reading_type === 'kunyomi') {
  186. expected_answers = expected_answers.concat(subject.kunyomi);
  187. } else if (subject.primary_reading_type === 'onyomi') {
  188. expected_answers = expected_answers.concat(subject.onyomi);
  189. }
  190. }
  191. }
  192.  
  193. // Make the commit function usable again
  194. commit.usable = true;
  195. });
  196.  
  197. (function () {
  198. console.log('WK Auto Commit (a plugin for Wanikani): Initialized');
  199. })();
  200.