Duolingo input language switcher

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

当前为 2018-02-06 提交的版本,查看 最新版本

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