Duolingo input language switcher

This script allows you to type letters appropriate for current task without changing keyboard's layout

当前为 2018-01-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Duolingo input language switcher
  3. // @namespace https://www.duolingo.com/IVrL9
  4. // @match https://www.duolingo.com/*
  5. // @match https://www.duolingo.com/skill/*
  6. // @match https://www.duolingo.com/practice/*
  7. // @match https://www.example.com/*
  8. // @match https://example.com/*
  9. // @version 1.1.1
  10. // @description This script allows you to type letters appropriate for current task without changing keyboard's layout
  11. // @run-at document-start
  12. // @grant none
  13. // @license GPLv3
  14. // ==/UserScript==/// Generated by Haxe 3.4.2 (git build master @ 890f8c7)
  15. (function () { "use strict";
  16. var HxOverrides = function() { };
  17. HxOverrides.__name__ = true;
  18. HxOverrides.substr = function(s,pos,len) {
  19. if(len == null) {
  20. len = s.length;
  21. } else if(len < 0) {
  22. if(pos == 0) {
  23. len = s.length + len;
  24. } else {
  25. return "";
  26. }
  27. }
  28. return s.substr(pos,len);
  29. };
  30. var Main = function() {
  31. this.observerTargetSelector = "._1zuqL";
  32. this.ereg = new RegExp("duolingo\\.com/skill|practice/");
  33. this.isObserved = false;
  34. var _gthis = this;
  35. this.document = window.document;
  36. this.console = { };
  37. Object.assign(this.console,window.console);
  38. this.originalTrace = haxe_Log.trace;
  39. haxe_Log.trace = function(v,i) {
  40. _gthis.console.log("" + i.className + ":" + i.lineNumber + ":",v);
  41. };
  42. this.initLanguages();
  43. if(this.document.readyState == "interactive" || this.document.readyState == "complete") {
  44. this.onready();
  45. } else {
  46. this.document.addEventListener("DOMContentLoaded",$bind(this,this.onready));
  47. }
  48. };
  49. Main.__name__ = true;
  50. Main.main = function() {
  51. new Main();
  52. };
  53. Main.prototype = {
  54. initLanguages: function() {
  55. this.keyCodes = ["Backquote","Digit1","Digit2","Digit3","Digit4","Digit5","Digit6","Digit7","Digit8","Digit9","Digit0","Minus","Equal","Backslash","KeyQ","KeyW","KeyE","KeyR","KeyT","KeyY","KeyU","KeyI","KeyO","KeyP","BracketLeft","BracketRight","KeyA","KeyS","KeyD","KeyF","KeyG","KeyH","KeyJ","KeyK","KeyL","Semicolon","Quote","KeyZ","KeyX","KeyC","KeyV","KeyB","KeyN","KeyM","Comma","Period","Slash"];
  56. this.languages = { };
  57. this.languages.ru = "ё1234567890-=\\йцукенгшщзхъфывапролджэячсмитьбю.Ё!\"№;%:?*()_+/ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,";
  58. this.languages.en = "`1234567890-=\\qwertyuiop[]asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>?";
  59. var len = this.languages.ru.length;
  60. var _g = 0;
  61. var _g1 = Reflect.fields(this.languages);
  62. while(_g < _g1.length) {
  63. var f = _g1[_g];
  64. ++_g;
  65. var act = this.languages[f].length;
  66. if(act != len) {
  67. this.console.error("LangString test failed: expected len " + len + "; actual len " + act + "; lang name " + f);
  68. this.console.error(this.languages[f]);
  69. return;
  70. }
  71. if(act != this.keyCodes.length * 2) {
  72. this.console.error("KeyCodes and LangString test failed: expected lang string len " + this.keyCodes.length * 2 + "; actual len " + act + "; lang name " + f);
  73. return;
  74. }
  75. }
  76. }
  77. ,onready: function(e) {
  78. this.document.removeEventListener("DOMContentLoaded",$bind(this,this.onready));
  79. this.console.log("Duolingo input switcher inited");
  80. window.setInterval($bind(this,this.checkPage),1000);
  81. }
  82. ,checkPage: function() {
  83. var isThatPage = this.ereg.test(window.location.href);
  84. if(isThatPage) {
  85. if(!this.isObserved) {
  86. this.startObserver();
  87. }
  88. }
  89. if(this.isObserved && (!isThatPage || window.document.querySelector(this.observerTargetSelector) == null)) {
  90. this.disconnectObserver();
  91. }
  92. }
  93. ,startObserver: function(e) {
  94. var obsTarget = window.document.querySelector(this.observerTargetSelector);
  95. if(obsTarget == null) {
  96. this.console.error("There is no Node with selector \"" + this.observerTargetSelector + "\" , so nothing to observe ");
  97. return;
  98. }
  99. this.observer = new MutationObserver($bind(this,this.checkMutation));
  100. this.observer.observe(obsTarget,{ childList : true, subtree : true, attributes : true});
  101. this.isObserved = true;
  102. }
  103. ,disconnectObserver: function() {
  104. this.isObserved = false;
  105. if(this.observer == null) {
  106. return;
  107. }
  108. this.observer.disconnect();
  109. }
  110. ,checkMutation: function(records,obs) {
  111. this.nativeLanguage = "ru";
  112. this.foreignLanguage = "en";
  113. var translationInput = window.document.querySelector("textarea[data-test=challenge-translate-input]");
  114. if(translationInput != null) {
  115. var lang = translationInput.getAttribute("lang");
  116. if(lang == this.nativeLanguage) {
  117. this.initInput(translationInput,"ru","en");
  118. } else if(lang == this.foreignLanguage) {
  119. this.initInput(translationInput,"en","ru");
  120. }
  121. return;
  122. }
  123. var listenInput = window.document.querySelector("textarea[data-test=challenge-listen-input]");
  124. if(listenInput != null) {
  125. this.initInput(listenInput,"en","ru");
  126. return;
  127. }
  128. var nameInput = window.document.querySelector("input[data-test=challenge-name-input]");
  129. if(nameInput != null) {
  130. this.initInput(nameInput,"en","ru");
  131. }
  132. }
  133. ,initInput: function(input,targetLanguage,sourceLanguage) {
  134. this.targetLanguage = targetLanguage;
  135. this.sourceLanguage = sourceLanguage;
  136. input.addEventListener("keypress",$bind(this,this.onInput));
  137. input.addEventListener("keydown",$bind(this,this.refocus));
  138. }
  139. ,refocus: function(e) {
  140. if(e.keyCode == 13 || e.code == "Enter") {
  141. e.currentTarget.blur();
  142. }
  143. }
  144. ,onInput: function(e) {
  145. var targetLangStr = this.languages[this.targetLanguage];
  146. var keyCodeInd = this.keyCodes.indexOf(e.code);
  147. if(keyCodeInd != -1) {
  148. var targetChar = e.shiftKey ? targetLangStr.charAt(keyCodeInd + this.keyCodes.length) : targetLangStr.charAt(keyCodeInd);
  149. var input = e.currentTarget;
  150. window.setTimeout($bind(this,this.replaceChar),1,input,targetChar,input.selectionStart);
  151. }
  152. }
  153. ,replaceChar: function(target,newChar,position) {
  154. var val = target.value;
  155. val = val.substring(0,position) + newChar + HxOverrides.substr(val,position + 1,null);
  156. target.innerText = val;
  157. target.value = val;
  158. target.setSelectionRange(position + 1,position + 1);
  159. }
  160. };
  161. Math.__name__ = true;
  162. var Reflect = function() { };
  163. Reflect.__name__ = true;
  164. Reflect.fields = function(o) {
  165. var a = [];
  166. if(o != null) {
  167. var hasOwnProperty = Object.prototype.hasOwnProperty;
  168. for( var f in o ) {
  169. if(f != "__id__" && f != "hx__closures__" && hasOwnProperty.call(o,f)) {
  170. a.push(f);
  171. }
  172. }
  173. }
  174. return a;
  175. };
  176. var haxe_Log = function() { };
  177. haxe_Log.__name__ = true;
  178. haxe_Log.trace = function(v,infos) {
  179. js_Boot.__trace(v,infos);
  180. };
  181. var js_Boot = function() { };
  182. js_Boot.__name__ = true;
  183. js_Boot.__unhtml = function(s) {
  184. return s.split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;");
  185. };
  186. js_Boot.__trace = function(v,i) {
  187. var msg = i != null ? i.fileName + ":" + i.lineNumber + ": " : "";
  188. msg += js_Boot.__string_rec(v,"");
  189. if(i != null && i.customParams != null) {
  190. var _g = 0;
  191. var _g1 = i.customParams;
  192. while(_g < _g1.length) {
  193. var v1 = _g1[_g];
  194. ++_g;
  195. msg += "," + js_Boot.__string_rec(v1,"");
  196. }
  197. }
  198. var d;
  199. var tmp;
  200. if(typeof(document) != "undefined") {
  201. d = document.getElementById("haxe:trace");
  202. tmp = d != null;
  203. } else {
  204. tmp = false;
  205. }
  206. if(tmp) {
  207. d.innerHTML += js_Boot.__unhtml(msg) + "<br/>";
  208. } else if(typeof console != "undefined" && console.log != null) {
  209. console.log(msg);
  210. }
  211. };
  212. js_Boot.__string_rec = function(o,s) {
  213. if(o == null) {
  214. return "null";
  215. }
  216. if(s.length >= 5) {
  217. return "<...>";
  218. }
  219. var t = typeof(o);
  220. if(t == "function" && (o.__name__ || o.__ename__)) {
  221. t = "object";
  222. }
  223. switch(t) {
  224. case "function":
  225. return "<function>";
  226. case "object":
  227. if(o instanceof Array) {
  228. if(o.__enum__) {
  229. if(o.length == 2) {
  230. return o[0];
  231. }
  232. var str = o[0] + "(";
  233. s += "\t";
  234. var _g1 = 2;
  235. var _g = o.length;
  236. while(_g1 < _g) {
  237. var i = _g1++;
  238. if(i != 2) {
  239. str += "," + js_Boot.__string_rec(o[i],s);
  240. } else {
  241. str += js_Boot.__string_rec(o[i],s);
  242. }
  243. }
  244. return str + ")";
  245. }
  246. var l = o.length;
  247. var i1;
  248. var str1 = "[";
  249. s += "\t";
  250. var _g11 = 0;
  251. var _g2 = l;
  252. while(_g11 < _g2) {
  253. var i2 = _g11++;
  254. str1 += (i2 > 0 ? "," : "") + js_Boot.__string_rec(o[i2],s);
  255. }
  256. str1 += "]";
  257. return str1;
  258. }
  259. var tostr;
  260. try {
  261. tostr = o.toString;
  262. } catch( e ) {
  263. return "???";
  264. }
  265. if(tostr != null && tostr != Object.toString && typeof(tostr) == "function") {
  266. var s2 = o.toString();
  267. if(s2 != "[object Object]") {
  268. return s2;
  269. }
  270. }
  271. var k = null;
  272. var str2 = "{\n";
  273. s += "\t";
  274. var hasp = o.hasOwnProperty != null;
  275. for( var k in o ) {
  276. if(hasp && !o.hasOwnProperty(k)) {
  277. continue;
  278. }
  279. if(k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__") {
  280. continue;
  281. }
  282. if(str2.length != 2) {
  283. str2 += ", \n";
  284. }
  285. str2 += s + k + " : " + js_Boot.__string_rec(o[k],s);
  286. }
  287. s = s.substring(1);
  288. str2 += "\n" + s + "}";
  289. return str2;
  290. case "string":
  291. return o;
  292. default:
  293. return String(o);
  294. }
  295. };
  296. var $_, $fid = 0;
  297. function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $fid++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; o.hx__closures__[m.__id__] = f; } return f; }
  298. String.__name__ = true;
  299. Array.__name__ = true;
  300. Main.main();
  301. })();