WaniKani Nippongrammar Extension

Svg Canvas used to draw Kanji on reviews and lessons, using website code.

当前为 2016-02-24 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name WaniKani Nippongrammar Extension
  3. // @namespace WK-nippongrammar
  4. // @version 0.8
  5. // @website http://nippongrammar.appspot.com/
  6. // @description Svg Canvas used to draw Kanji on reviews and lessons, using website code.
  7. // @author Code by Aaron Drew, Wanikani adaption by Ethan McCoy
  8. // @include *.wanikani.com/*
  9. // @include *.wanikani.com/review/session*
  10. // @include *.wanikani.com/lesson/session*
  11. // @grant none
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. //"use strict";
  16.  
  17. $("head").prepend('<script type="text/javascript" src="https://greasyfork.org/scripts/11949-kanjisvg/code/kanjiSvg.js"></script>');
  18. $("head").prepend('<script type="text/javascript" src="https://greasyfork.org/scripts/11951-kanjirender/code/kanjirender.js"></script>');
  19.  
  20.  
  21. var NG = {
  22. strokesShown: true,
  23. strokeDiv: document.getElementById('strokeChar'),
  24.  
  25.  
  26. showStrokes : function(){
  27. this.strokesShown = true;
  28. this.strokeDiv && (this.strokeDiv.style.display = "block");
  29. this.charDiv && (this.charDiv.style.display = "none");
  30. },
  31.  
  32. showOriginal: function(){
  33. this.strokesShown = false;
  34. this.strokeDiv && (this.strokeDiv.style.display = "none");
  35. this.charDiv && (this.charDiv.style.display = "block");
  36. },
  37.  
  38. showImage: function(){
  39. //as above but don't change strokesShown
  40. this.strokeDiv && (this.strokeDiv.style.display = "none");
  41. this.charDiv && (this.charDiv.style.display = "block");
  42. },
  43.  
  44. animateStrokes: function(text){
  45. if (this.strokeDiv === null){
  46. this.strokeDiv = document.createElement('div'),
  47. this.strokeDiv.style = "padding: 20px 20px 0; height: 110px; width: 110px",
  48. this.strokeDiv.id = "strokeChar";
  49.  
  50. this.charDiv && this.charDiv.parentNode.insertBefore(this.strokeDiv, this.charDiv);
  51.  
  52. }
  53. this.strokeDiv.style.border = "1px";
  54. //add replay functionality
  55. this.strokeDiv.removeEventListener("click", handlers.onDivClick);
  56. this.strokeDiv.addEventListener("click", handlers.onDivClick);
  57.  
  58. //from kanjirender.js
  59. animateWriting(text,'strokeChar',10);
  60.  
  61.  
  62. if (this.strokesShown)
  63. this.showStrokes();
  64.  
  65. },
  66. };
  67.  
  68. var handlers = {
  69. switchViews: function(e){
  70. e.shiftKey && e.keyCode === 37 && NG.showStrokes();
  71. e.shiftKey && e.keyCode === 39 && NG.showOriginal();
  72. },
  73.  
  74. onDivClick: function(){
  75. NG.animateStrokes(NG.text||"");
  76. },
  77.  
  78. handleKeyChange: function(key, action){
  79.  
  80. console.groupCollapsed("animate strokes userscript");
  81.  
  82. switch (key){
  83. case "l/currentLesson":
  84. case "l/currentQuizItem":
  85. //for lessons and their following quizzes
  86. NG.charDiv = document.getElementById("character");
  87. break;
  88. case "currentItem":
  89. //for reviews
  90. var spanArr = document.getElementById("character").getElementsByTagName("span");
  91. NG.charDiv = spanArr[spanArr.length-1]; //animate strokes may insert spans for chars it doesn't know.
  92. break;
  93. }
  94. var cur = $.jStorage.get(key);
  95. NG.text = cur.voc || cur.kan || cur.rad || "";
  96. if (NG.text.indexOf(".png") === -1) { //weed out picture radicals for now, extend svg library later
  97. NG.animateStrokes(NG.text);
  98. //introduce hotkey switching
  99. document.addEventListener("keyup", handlers.switchViews);
  100. }else{
  101. //remove hotkey switching
  102. document.removeEventListener("keyup", handlers.switchViews);
  103. NG.showImage();
  104. }
  105. console.groupEnd();
  106. }
  107. };
  108.  
  109. var handleLevelsPage = function(){
  110. };
  111.  
  112.  
  113.  
  114.  
  115. function main() {
  116.  
  117. if (document.URL.match(/.wanikani.com\/level\//)){
  118. false&&handleLevelsPage();
  119. }else{
  120. $.jStorage.listenKeyChange("currentItem", handlers.handleKeyChange);
  121. $.jStorage.listenKeyChange("l/currentQuizItem", handlers.handleKeyChange);
  122. $.jStorage.listenKeyChange("l/currentLesson", handlers.handleKeyChange);
  123. }
  124.  
  125.  
  126. }
  127.  
  128. function animateWriting(txt, div_id, millisecondsPerStroke)
  129. {
  130. if (typeof div_id === 'string'){
  131. document.getElementById(div_id).innerHTML = "";
  132. }else{
  133. div_id.innerHTML = "";
  134. }
  135. var renderQueue = [];
  136.  
  137. function renderNext() {
  138. if(renderQueue.length)
  139. renderQueue.shift()();
  140. }
  141.  
  142. for(var i=0;i<txt.length;i++) {
  143. var ch = txt.charAt(i);
  144. var canvas = document.createElement("canvas");
  145. canvas.width = 110;
  146. canvas.height = 110;
  147. canvas.style.width = "110";
  148. canvas.style.height = "110";
  149.  
  150. if (typeof div_id === 'string'){
  151. document.getElementById(div_id).appendChild(canvas);
  152. }else{
  153. div_id.appendChild(canvas);;
  154. }
  155.  
  156. renderQueue.push(renderMojiOrSpan(canvas, ch, millisecondsPerStroke));
  157. }
  158.  
  159. function nextStroke() {
  160. if(renderQueue.length)
  161. {
  162. renderQueue.shift()(nextStroke, function() {
  163. nextStroke();
  164. });
  165. }
  166. };
  167. nextStroke();
  168. };
  169.  
  170. if (document.readyState === 'complete')
  171. main();
  172. else
  173. window.addEventListener("load", main, false);