AnkiWeb Quiz

Shows quiz on ankiweb

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

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