AnkiWeb Quiz

Shows quiz on ankiweb

当前为 2017-03-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name AnkiWeb Quiz
  3. // @namespace https://greasyfork.org/users/102866
  4. // @description Shows quiz on ankiweb
  5. // @include https://ankiweb.net/*
  6. // @include http://ankiweb.net/*
  7. // @require https://code.jquery.com/jquery-3.1.1.min.js
  8. // @author TiLied
  9. // @version 0.1.1
  10. // @grant GM_getResourceText
  11. // @grant GM_listValues
  12. // @grant GM_deleteValue
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // @resource ankiDeck PUT_HERE_YOUR_DECK.txt
  16. // ==/UserScript==
  17.  
  18. var originAnkiDeck = GM_getResourceText("ankiDeck");
  19. var stringArray = [];
  20. var tempStrings = [];
  21. var searchFor;
  22. var trueAnswer;
  23. var falseAnswers = [];
  24. var inB = [];
  25. var inE = [];
  26. var inBstring = "<awq>";
  27. var inEstring = "</awq>";
  28. var inBegAnswer = "<awq_answer>";
  29. var inEndAnswer = "</awq_answer>";
  30. var trueId, id;
  31. var buttons = [];
  32. var tempArr = [];
  33. var debug;
  34. var rubyVal;
  35. var amountButtons;
  36.  
  37.  
  38. Main();
  39.  
  40. function Main()
  41. {
  42. inB = findIndexes(inBstring, originAnkiDeck);
  43. inE = findIndexes(inEstring, originAnkiDeck);
  44. console.log(inB);
  45. console.log(inE);
  46.  
  47. for (var i = 0; i < inB.length; i++)
  48. {
  49. tempStrings[i] = originAnkiDeck.slice(inB[i] + 5, inE[i]);
  50. //console.log(tempStrings[i]);
  51. }
  52. console.log(tempStrings);
  53. cssAdd();
  54. //setSettings();
  55. }
  56.  
  57. //Settings
  58. function setSettings()
  59. {
  60. const settings = $("<li class=nav-item></li>").html("<a id=awq_settings class=nav-link>Settings Ankiweb Quiz</a> \
  61. <div id=awq_settingsPanel class=awq_settingsP>\
  62. <form> \
  63. <br> \
  64. Debug: <input type=checkbox name=debug id=awq_debug></input>\
  65. </form>\
  66. <button class=awq_style>Hide</button>\
  67. <button class=awq_style>Yep</button>\
  68. </div>\
  69. ");
  70.  
  71.  
  72. $(".navbar-nav:first").append(settings);
  73. $("#awq_settings").addClass("awq_settings");
  74. $("#awq_settingsPanel").hide();
  75. setEventSettings();
  76. loadSettings();
  77. }
  78.  
  79. function loadSettings()
  80. {
  81. var vals = [];
  82. for (var i = 0; i < GM_listValues().length; i++)
  83. {
  84. vals[i] = GM_listValues()[i];
  85. }
  86.  
  87. if (vals.length === 0)
  88. {
  89. GM_setValue("awq_debug", false);
  90. debug = false;
  91. $("#awq_debug").prop("checked", false);
  92. //console.log("debug: " + debug);
  93. }
  94.  
  95. //console.log(vals);
  96.  
  97. for (var i = 0; i < vals.length; i++)
  98. {
  99. if (vals[i] === "awq_debug")
  100. {
  101. debug = GM_getValue("awq_debug");
  102. if (debug)
  103. {
  104. $("#awq_debug").prop("checked", debug);
  105. } else
  106. {
  107. $("#awq_debug").prop("checked", debug);
  108. }
  109. } else
  110. {
  111. //GM_setValue("awq_debug", false);
  112. //debug = false;
  113. //$("#awq_debug").prop("checked", false);
  114. //console.log("debug: " + debug);
  115. }
  116. }
  117.  
  118. if (debug)
  119. {
  120. for (var i = 0; i < vals.length; i++)
  121. {
  122. console.log(vals[i] + " val:" + GM_getValue(vals[i]));
  123. }
  124. }
  125. }
  126.  
  127. function setEventSettings()
  128. {
  129. $("#awq_settings").click(function ()
  130. {
  131. $("#awq_settingsPanel").toggle();
  132. });
  133.  
  134. $("#awq_debug").change(function ()
  135. {
  136. GM_setValue("awq_debug", $(this).prop("checked"));
  137. debug = $(this).prop("checked");
  138. alert("Settings has been changed. Please reload the page.");
  139. });
  140. }
  141.  
  142. function findIndexes(searchStr, str, caseSensitive)
  143. {
  144. var searchStrLen = searchStr.length;
  145. if (searchStrLen == 0) {
  146. return [];
  147. }
  148. var startIndex = 0, index, indices = [];
  149. if (!caseSensitive) {
  150. str = str.toLowerCase();
  151. searchStr = searchStr.toLowerCase();
  152. }
  153. while ((index = str.indexOf(searchStr, startIndex)) > -1) {
  154. indices.push(index);
  155. startIndex = index + searchStrLen;
  156. }
  157. return indices;
  158. }
  159.  
  160. //css styles adds
  161. function cssAdd()
  162. {
  163. $("head").append($("<style type=text/css></style>").text("button.awq_btn { \
  164. \
  165. }"));
  166.  
  167. $("head").append($("<style type=text/css></style>").text("a.awq_settings { \
  168. cursor: pointer;\
  169. }"));
  170.  
  171. $("head").append($("<style type=text/css></style>").text("div.awq_settingsP { \
  172. position:absolute; width:300px; background-color: #fff; border-color: #eee!important; border-radius: .3rem; border: 2px solid transparent; z-index: 150;\
  173. }"));
  174.  
  175. $("head").append($("<style type=text/css></style>").text("button.awq_style { \
  176. cursor: pointer; color: #fff; background-color: #0275d8; border-color: #0275d8; padding: .75rem 1.5rem; font-size: 1rem; border-radius: .3rem; border: 1px solid transparent; max-width:200px; margin:5px;\
  177. }"));
  178.  
  179. $("head").append($("<style type=text/css></style>").text("button.awq_style:hover { \
  180. cursor: pointer; color: #fff; background-color: #025aa5; border-color: #01549b; padding: .75rem 1.5rem; font-size: 1rem; border-radius: .3rem; border: 1px solid transparent;\
  181. }"));
  182.  
  183. $("head").append($("<style type=text/css></style>").text("div.awq_rstyle { \
  184. width:100%; margin-top:30px; z-index: 100;\
  185. }"));
  186.  
  187. $("head").append($("<style type=text/css></style>").text("button.awq_true { \
  188. background-color: #75d802; border-color: #75d802;\
  189. }"));
  190.  
  191. $("head").append($("<style type=text/css></style>").text("button.awq_true:hover { \
  192. background-color: #5aa502; border-color: #5aa502;\
  193. }"));
  194.  
  195. $("head").append($("<style type=text/css></style>").text("button.awq_false { \
  196. background-color: #d80275; border-color: #d80275;\
  197. }"));
  198.  
  199. $("head").append($("<style type=text/css></style>").text("button.awq_false:hover { \
  200. background-color: #a5025a; border-color: #a5025a;\
  201. }"));
  202. }
  203.  
  204. $(document).ready(function () {
  205.  
  206. // Append some text to the element with id someText using the jQuery library.
  207. //$("#studynow").append(" more text...................");
  208.  
  209. $("#studynow").click(function () {
  210. setTimeout(function ()
  211. {
  212. setUI();
  213. searchFor = searchQuestion();
  214. if (debug)
  215. {
  216. console.log("searchFor:" + searchFor);
  217. }
  218. getTrueAnswer(searchFor);
  219. if (debug) {
  220. console.log('Study Click');
  221. }
  222. }, 1500);
  223. });
  224.  
  225. function setUI()
  226. {
  227. const buttonP = $("<button id=awq_quiz class=btn style=margin-left:4px></button>").text("Quiz");
  228. const button = $("<div class=awq_rstyle></div>").html("<button class=awq_btn></button><button class=awq_btn></button><button class=awq_btn></button><button class=awq_btn></button><button class=awq_btn></button><button class=awq_btn></button><button class=awq_btn></button><button class=awq_btn></button>");
  229.  
  230. $(".pt-1").before("<br>");
  231. $(".pt-1").before(button);
  232.  
  233. $("#leftStudyMenu").after(buttonP);
  234.  
  235. settingsEvents();
  236.  
  237. $("#awq_quiz").addClass("btn-secondary");
  238. $(".awq_btn").addClass("awq_style");
  239. $(".awq_rstyle").hide();
  240. }
  241.  
  242. function settingsEvents()
  243. {
  244.  
  245. $("#awq_quiz").click(function () {
  246. $(".awq_rstyle").toggle();
  247. });
  248.  
  249. $("#ansbuta").click(function ()
  250. {
  251. setTimeout(function ()
  252. {
  253. if (debug)
  254. {
  255. console.log("Button check");
  256. }
  257. $("#ease1").click(function ()
  258. {
  259. otherEvent();
  260. });
  261. $("#ease2").click(function ()
  262. {
  263. otherEvent();
  264. });
  265. $("#ease3").click(function ()
  266. {
  267. otherEvent();
  268. });
  269. $("#ease4").click(function ()
  270. {
  271. otherEvent();
  272. });
  273. }, 500);
  274. });
  275.  
  276. $(".awq_btn").click(function ()
  277. {
  278. if (debug)
  279. {
  280. if ($(this).attr("title"))
  281. {
  282. console.log("html:" + $(this).attr("title"));
  283. console.log("true:" + trueAnswer);
  284. } else
  285. {
  286. console.log("html:" + $(this).html);
  287. console.log("true:" + trueAnswer);
  288. }
  289. }
  290.  
  291. if ($(this).attr("title"))
  292. {
  293. if (trueAnswer == $(this).attr("title"))
  294. {
  295. $(this).addClass("awq_true");
  296. } else
  297. {
  298. $(this).addClass("awq_false");
  299. }
  300. } else
  301. {
  302. if (trueAnswer == $(this).html())
  303. {
  304. $(this).addClass("awq_true");
  305. } else
  306. {
  307. $(this).addClass("awq_false");
  308. }
  309. }
  310. });
  311. }
  312.  
  313. function escapeRegExp(string)
  314. {
  315. return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
  316. }
  317.  
  318. function searchQuestion()
  319. {
  320. if (debug)
  321. {
  322. console.log("span: ");
  323. console.log($("awq_question").has("span"));
  324. }
  325. if ($("awq_question").has("span").length >= 1)
  326. {
  327. var contentText = $("awq_question").contents().filter(function ()
  328. {
  329. return this.nodeType == 3;
  330. });
  331.  
  332. var contentSpan = $("awq_question").contents().filter(function ()
  333. {
  334. return this.nodeType == 1;
  335. });
  336.  
  337. if (debug)
  338. {
  339. console.log(contentText);
  340. console.log(contentSpan);
  341. }
  342.  
  343. rubyVal = "";
  344.  
  345.  
  346. //This is if first goes hiragana/katakana
  347. if (contentText[0].nodeValue != "")
  348. {
  349. rubyVal = $.trim(contentText[0].nodeValue);
  350. rubyVal += "<ruby><rb>";
  351.  
  352. rubyVal += $.trim($(contentSpan[0]).contents().filter(function ()
  353. {
  354. return this.nodeType == 3;
  355. })[0].nodeValue) + "</rb><rt>";
  356.  
  357. rubyVal += $(contentSpan[0]).contents()[0].innerHTML + "</rt></ruby>";
  358.  
  359. //After kanji goes hiragana/katakana if not return
  360. if (contentText[1] != null)
  361. {
  362. rubyVal += $.trim(contentText[1].nodeValue);
  363. if (contentSpan[1] != null)
  364. {
  365. rubyVal += "<ruby><rb>";
  366. rubyVal += $.trim($(contentSpan[1]).contents().filter(function ()
  367. {
  368. return this.nodeType == 3;
  369. })[0].nodeValue) + "</rb><rt>";
  370.  
  371. rubyVal += $(contentSpan[1]).contents()[0].innerHTML + "</rt></ruby>";
  372.  
  373. //After kanji goes hiragana/katakana if not return
  374. if (contentText[2] != null)
  375. {
  376. rubyVal += $.trim(contentText[2].nodeValue);
  377. if (contentSpan[2] != null)
  378. {
  379. //TODO THIRD
  380. } else
  381. {
  382. if (debug)
  383. {
  384. console.log("Here actua this: " + rubyVal);
  385. }
  386. return rubyVal;
  387. }
  388. } else
  389. {
  390. if (debug)
  391. {
  392. console.log("Here actua this: " + rubyVal);
  393. }
  394. return rubyVal;
  395. }
  396. } else
  397. {
  398. if (debug)
  399. {
  400. console.log("Here actua this: " + rubyVal);
  401. }
  402. return rubyVal;
  403. }
  404. } else
  405. {
  406. if (debug)
  407. {
  408. console.log("Here actua this: " + rubyVal);
  409. }
  410. return rubyVal;
  411. }
  412.  
  413. if (debug)
  414. {
  415. console.log("value first:" + contentText[0].nodeValue);
  416. console.log(contentSpan);
  417. console.log(contentSpan[0].innerHTML);
  418. }
  419. }
  420.  
  421. if (debug)
  422. {
  423. console.log(contentText);
  424. console.log("IT DOES");
  425. console.log($("awq_question").contents());
  426. //rubyVal = $("awq_question").contents().filter(function ()
  427. //{
  428. // return this.nodeType == 3;
  429. //})[0].nodeValue;
  430. console.log("Here actua this: " + rubyVal);
  431. }
  432. } else
  433. {
  434. return $.trim($("awq_question").html());
  435. }
  436. }
  437.  
  438. function getTrueAnswer(sFor)
  439. {
  440. var regex = '(^|\\s|\\b|(\\>))';
  441. regex += escapeRegExp(sFor);
  442. regex += '($|\\s|\\b|(\\<))';
  443.  
  444. if (debug)
  445. {
  446. console.log(regex);
  447. }
  448.  
  449. for (var i = 0; i < tempStrings.length; i++) {
  450. //console.log('sFor =' + sFor + " leng " + sFor.length + " debug : " + new RegExp(regex, "g").test(tempStrings[i]));
  451. //contains = tempStrings[i].matches(".*\\bram\\b.*");
  452. if (new RegExp(regex, "g").test(tempStrings[i]))
  453. {
  454. const str = tempStrings[i].toString();
  455. trueAnswer = $.trim(str.slice(str.indexOf(inBegAnswer) + 12, str.indexOf(inEndAnswer)));
  456. trueId = i;
  457. if (debug)
  458. {
  459. //console.log(tempStrings[i - 1]);
  460. console.log(str);
  461. //console.log(tempStrings[i + 1]);
  462. console.log("True answer : " + trueAnswer + " id trueAnsw = " + trueId);
  463. }
  464. getFalseAnswers(trueId);
  465. break;
  466. }
  467. }
  468. }
  469.  
  470. function getFalseAnswers(trueId) {
  471. tempArr.length = 0;
  472. for (var i = 0; i < 7; i++) {
  473. id = get_rand(tempStrings);
  474. if (id != trueId) {
  475. if (debug) {
  476. console.log(tempStrings[id]);
  477. }
  478. const str = tempStrings[id].toString();
  479. falseAnswers[i] = str.slice(str.indexOf(inBegAnswer) + 12, str.indexOf(inEndAnswer));
  480. if (debug) {
  481. console.log("***False answer " + i + " : " + falseAnswers[i] + " id: " + id);
  482. //console.log("inBegAnswer: " + str.indexOf(inBegAnswer) + " : " + str.indexOf(inEndAnswer) + " inEndAnswer");
  483. }
  484. } else {
  485. id = get_rand(tempStrings);
  486. i--;
  487. }
  488. }
  489. ramdomButton();
  490. }
  491.  
  492. function otherEvent()
  493. {
  494. if (debug) {
  495. console.log("Button click");
  496. console.log("---------------");
  497. }
  498. searchFor = "";
  499. //searchFor = $("awq_question").html();
  500. searchFor = searchQuestion();
  501. if (debug) {
  502. console.log("searchFor:" + searchFor);
  503. console.log($("awq").text().length);
  504. }
  505. $(".awq_rstyle").hide();
  506. if (searchFor == "") {
  507. setTimeout(function () {
  508. if ($("awq").text().length === 0) {
  509. setTimeout(function () {
  510. //searchFor = $("awq_question").html();
  511. searchFor = searchQuestion();
  512. if (debug) {
  513. console.log("searchFor:::" + searchFor);
  514. }
  515. getTrueAnswer(searchFor);
  516. }, 3000);
  517. } else {
  518. //searchFor = $("awq_question").html();
  519. searchFor = searchQuestion();
  520. if (debug) {
  521. console.log("searchFor::" + searchFor);
  522. }
  523. getTrueAnswer(searchFor);
  524. }
  525. }, 1000);
  526. } else {
  527. getTrueAnswer(searchFor);
  528. }
  529. }
  530.  
  531. //random functions
  532. function in_array(array, el) {
  533. for (var i = 0 ; i < array.length; i++)
  534. if (array[i] == el) return true;
  535. return false;
  536. }
  537.  
  538. function get_rand(array) {
  539. var rand = Math.floor(Math.random() * array.length);
  540. if (!in_array(tempArr, rand)) {
  541. tempArr.push(rand);
  542. return rand;
  543. }
  544. return get_rand(array);
  545. }
  546. //end of random functions
  547.  
  548. function ramdomButton()
  549. {
  550. buttons.length = 0;
  551. tempArr.length = 0;
  552. var allAnswers = [];
  553. allAnswers[0] = trueAnswer;
  554. for (var i = 1; i <= falseAnswers.length; i++) {
  555. allAnswers[i] = falseAnswers[i - 1];
  556. }
  557. if (debug) {
  558. console.log("False answers :");
  559. console.log(falseAnswers);
  560. console.log("ALL answers :");
  561. console.log(allAnswers);
  562. }
  563. for (var i = 0; i < allAnswers.length; i++) {
  564. buttons[i] = $.trim(allAnswers[get_rand(allAnswers)]);
  565. }
  566. if (debug) {
  567. console.log("Random order :) = " + buttons);
  568. // console.log($(".awq_LeftSide").html());
  569. }
  570. uiButtons();
  571. }
  572.  
  573. function uiButtons()
  574. {
  575. const sel = document.querySelectorAll("button.awq_btn");
  576. if (debug)
  577. {
  578. console.log("*HERE UI BUTTONS :");
  579. }
  580.  
  581. for (var i = 0; i < buttons.length; i++)
  582. {
  583. //Delete arttribute
  584. if ($(sel[i]).attr("title"))
  585. {
  586. $(sel[i]).removeAttr("title");
  587. }
  588.  
  589. if (buttons[i].length <= 40 || buttons[i].includes("</ruby>"))
  590. {
  591. $(sel[i]).html(buttons[i]);
  592. } else
  593. {
  594. $(sel[i]).html(buttons[i].slice(0, 40) + "...");
  595. $(sel[i]).attr("title", buttons[i]);
  596. }
  597. if (debug)
  598. {
  599. //console.log(sel[i]);
  600. console.log(buttons[i] + " Length: " + buttons[i].length);
  601. console.log(buttons[i].includes("</ruby>"));
  602. }
  603. }
  604.  
  605. checkPresedButtons();
  606. }
  607.  
  608. function checkPresedButtons()
  609. {
  610. $(".awq_btn").removeClass("awq_true");
  611. $(".awq_btn").removeClass("awq_false");
  612. }
  613.  
  614. console.log("AnkiWeb Quiz v" + GM_info.script.version + " Initialized");
  615. });
  616.  
  617.  
  618. // ------------
  619. // TODO
  620. // ------------
  621.  
  622. /* TODO STARTS
  623. ✓ 1)Make it only one element of buttons //DONE 0.0.9
  624. 1.1)Increase numbers of buttons to 10-12(optional through settings???)
  625. ✓ 2)Make it limit of length answer and put whole in attribute title //DONE 0.1.0
  626. 3)Make it settings, almost done in 0.1.0
  627. ✓ 3.1)Debug //DONE 0.1.0
  628. 3.2)Add txt file ***RESEARCH NEEDED***
  629. 3.2.1)Choose them
  630. 3.3)Make it always show quiz
  631. ✓ 4)Make it full functionality of Japanese deck, partial done in 0.0.8 //DONE 0.0.9 Happy with that :)
  632. 5)Search question in between tags <awq_question> and </awq_question> not in whole sentence
  633. 6)TODO for loop in finding question
  634. TODO ENDS */