AnkiWeb Quiz

Shows quiz on ankiweb

当前为 2017-05-12 提交的版本,查看 最新版本

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