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.7
  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.  
  368. for (var i = 0; i < contentSpan.length; i++)
  369. {
  370. //This is if first goes hiragana/katakana
  371. if (contentText[i].nodeValue != "")
  372. {
  373. rubyVal += $.trim(contentText[i].nodeValue);
  374. rubyVal += "<ruby><rb>";
  375.  
  376. for (var x = 0; x < contentSpan.length; x++)
  377. {
  378.  
  379. }
  380. rubyVal += $.trim($(contentSpan[i]).contents().filter(function ()
  381. {
  382. return this.nodeType == 3;
  383. })[0].nodeValue) + "</rb><rt>";
  384.  
  385. rubyVal += $(contentSpan[i]).contents()[0].innerHTML + "</rt></ruby>";
  386. }
  387.  
  388. }
  389.  
  390. return rubyVal;
  391. //This is if first goes hiragana/katakana
  392. //if (contentText[0].nodeValue != "")
  393. //{
  394. // rubyVal = $.trim(contentText[0].nodeValue);
  395. // rubyVal += "<ruby><rb>";
  396.  
  397. // rubyVal += $.trim($(contentSpan[0]).contents().filter(function ()
  398. // {
  399. // return this.nodeType == 3;
  400. // })[0].nodeValue) + "</rb><rt>";
  401.  
  402. // rubyVal += $(contentSpan[0]).contents()[0].innerHTML + "</rt></ruby>";
  403.  
  404. // //After kanji goes hiragana/katakana if not return
  405. // if (contentText[1] != null)
  406. // {
  407. // rubyVal += $.trim(contentText[1].nodeValue);
  408. // if (contentSpan[1] != null)
  409. // {
  410. // rubyVal += "<ruby><rb>";
  411. // rubyVal += $.trim($(contentSpan[1]).contents().filter(function ()
  412. // {
  413. // return this.nodeType == 3;
  414. // })[0].nodeValue) + "</rb><rt>";
  415.  
  416. // rubyVal += $(contentSpan[1]).contents()[0].innerHTML + "</rt></ruby>";
  417.  
  418. // //After kanji goes hiragana/katakana if not return
  419. // if (contentText[2] != null)
  420. // {
  421. // rubyVal += $.trim(contentText[2].nodeValue);
  422. // if (contentSpan[2] != null)
  423. // {
  424. // //TODO THIRD
  425. // } else
  426. // {
  427. // if (debug)
  428. // {
  429. // console.log("Here actua this: " + rubyVal);
  430. // }
  431. // return rubyVal;
  432. // }
  433. // } else
  434. // {
  435. // if (debug)
  436. // {
  437. // console.log("Here actua this: " + rubyVal);
  438. // }
  439. // return rubyVal;
  440. // }
  441. // } else
  442. // {
  443. // if (debug)
  444. // {
  445. // console.log("Here actua this: " + rubyVal);
  446. // }
  447. // return rubyVal;
  448. // }
  449. // } else
  450. // {
  451. // if (debug)
  452. // {
  453. // console.log("Here actua this: " + rubyVal);
  454. // }
  455. // return rubyVal;
  456. // }
  457.  
  458. // if (debug)
  459. // {
  460. // console.log("value first:" + contentText[0].nodeValue);
  461. // console.log(contentSpan);
  462. // console.log(contentSpan[0].innerHTML);
  463. // }
  464. //}
  465.  
  466. if (debug)
  467. {
  468. console.log(contentText);
  469. console.log("IT DOES");
  470. console.log($("awq_question").contents());
  471. //rubyVal = $("awq_question").contents().filter(function ()
  472. //{
  473. // return this.nodeType == 3;
  474. //})[0].nodeValue;
  475. console.log("Here actua this: " + rubyVal);
  476. }
  477. } else
  478. {
  479. return $.trim($("awq_question").text());
  480. }
  481. }
  482.  
  483. //Replace wrong <br>'s or other html tags, should work perfectly but it isn't >:( Fixed(probably)
  484. function ReplaceString(str)
  485. {
  486. var trueString = str;
  487.  
  488. while (trueString.search("<br />") !== -1)
  489. {
  490. trueString = str.replace(/<br \/>/g, "<br>");
  491. }
  492.  
  493. return trueString;
  494. }
  495.  
  496. function GetTrueAnswer(sFor)
  497. {
  498. var regex = '(^|\\s|\\b|(n\\>))';
  499. var tempQuestion;
  500. var strQ;
  501. regex += EscapeRegExp(sFor);
  502. regex += '($|\\s|\\b|(\\<\\/a))';
  503.  
  504. if (debug)
  505. {
  506. console.log(regex);
  507. }
  508.  
  509. for (var i = 0; i < tempStrings.length; i++) {
  510. //console.log('sFor =' + sFor + " leng " + sFor.length + " debug : " + new RegExp(regex, "g").test(tempStrings[i]));
  511. //contains = tempStrings[i].matches(".*\\bram\\b.*");
  512. //tempQuestion = '';
  513. //strQ = '';
  514. //strQ = tempStrings[i].toString();
  515. //tempQuestion = $.trim(str.slice(str.indexOf("<awq_question>") + 14, str.indexOf("</awq_question>")));
  516. //console.log(tempQuestion);
  517. if (new RegExp(regex, "g").test(tempStrings[i]))
  518. {
  519. const str = tempStrings[i].toString();
  520. trueAnswer = ReplaceString($.trim(str.slice(str.indexOf(inBegAnswer) + 12, str.indexOf(inEndAnswer))));
  521. trueId = i;
  522. if (debug)
  523. {
  524. //console.log(tempStrings[i - 1]);
  525. console.log(str);
  526. //console.log(tempQuestion);
  527. //console.log(tempStrings[i + 1]);
  528. console.log("True answer : " + trueAnswer + " id trueAnsw = " + trueId);
  529. }
  530. GetFalseAnswers(trueId);
  531. break;
  532. }
  533. }
  534. }
  535.  
  536. function GetFalseAnswers(trueId) {
  537. tempArr.length = 0;
  538. for (var i = 0; i < 7; i++) {
  539. id = GetRand(tempStrings);
  540. if (id != trueId) {
  541. if (debug) {
  542. console.log(tempStrings[id]);
  543. }
  544. const str = tempStrings[id].toString();
  545. falseAnswers[i] = str.slice(str.indexOf(inBegAnswer) + 12, str.indexOf(inEndAnswer));
  546. if (debug) {
  547. console.log("***False answer " + i + " : " + falseAnswers[i] + " id: " + id);
  548. //console.log("inBegAnswer: " + str.indexOf(inBegAnswer) + " : " + str.indexOf(inEndAnswer) + " inEndAnswer");
  549. }
  550. } else {
  551. id = GetRand(tempStrings);
  552. i--;
  553. }
  554. }
  555. RamdomButton();
  556. }
  557.  
  558. function OtherEvent()
  559. {
  560. if (debug) {
  561. console.log("Button click");
  562. console.log("---------------");
  563. }
  564. searchFor = "";
  565. //searchFor = $("awq_question").html();
  566. searchFor = SearchQuestion();
  567. if (debug) {
  568. console.log("searchFor:" + searchFor);
  569. console.log($("awq").text().length);
  570. }
  571. $(".awq_rstyle").hide();
  572. if (searchFor == "") {
  573. setTimeout(function () {
  574. if ($("awq").text().length === 0) {
  575. setTimeout(function () {
  576. //searchFor = $("awq_question").html();
  577. searchFor = SearchQuestion();
  578. if (debug) {
  579. console.log("searchFor:::" + searchFor);
  580. }
  581. GetTrueAnswer(searchFor);
  582. }, 3000);
  583. } else {
  584. //searchFor = $("awq_question").html();
  585. searchFor = SearchQuestion();
  586. if (debug) {
  587. console.log("searchFor::" + searchFor);
  588. }
  589. GetTrueAnswer(searchFor);
  590. }
  591. }, 1000);
  592. } else {
  593. GetTrueAnswer(searchFor);
  594. }
  595. }
  596.  
  597. //random functions
  598. function InArray(array, el) {
  599. for (var i = 0 ; i < array.length; i++)
  600. if (array[i] == el) return true;
  601. return false;
  602. }
  603.  
  604. function GetRand(array) {
  605. var rand = Math.floor(Math.random() * array.length);
  606. if (!InArray(tempArr, rand)) {
  607. tempArr.push(rand);
  608. return rand;
  609. }
  610. return GetRand(array);
  611. }
  612. //end of random functions
  613.  
  614. function RamdomButton()
  615. {
  616. buttons.length = 0;
  617. tempArr.length = 0;
  618. var allAnswers = [];
  619. allAnswers[0] = trueAnswer;
  620. for (var i = 1; i <= falseAnswers.length; i++) {
  621. allAnswers[i] = falseAnswers[i - 1];
  622. }
  623. if (debug) {
  624. console.log("False answers :");
  625. console.log(falseAnswers);
  626. console.log("ALL answers :");
  627. console.log(allAnswers);
  628. }
  629. for (var i = 0; i < allAnswers.length; i++) {
  630. buttons[i] = $.trim(allAnswers[GetRand(allAnswers)]);
  631. }
  632. if (debug) {
  633. console.log("Random order :) = " + buttons);
  634. // console.log($(".awq_LeftSide").html());
  635. }
  636. UiButtons();
  637. }
  638.  
  639. function UiButtons()
  640. {
  641. const sel = document.querySelectorAll("button.awq_btn");
  642. if (debug)
  643. {
  644. console.log("*HERE UI BUTTONS :");
  645. }
  646.  
  647. for (var i = 0; i < buttons.length; i++)
  648. {
  649. //Delete arttribute
  650. if ($(sel[i]).attr("title"))
  651. {
  652. $(sel[i]).removeAttr("title");
  653. }
  654.  
  655. if (buttons[i].length <= 40 || buttons[i].includes("</ruby>"))
  656. {
  657. $(sel[i]).html(buttons[i]);
  658. } else
  659. {
  660. $(sel[i]).html(buttons[i].slice(0, 40) + "...");
  661. $(sel[i]).attr("title", buttons[i]);
  662. }
  663. if (debug)
  664. {
  665. //console.log(sel[i]);
  666. console.log(buttons[i] + " Length: " + buttons[i].length);
  667. console.log(buttons[i].includes("</ruby>"));
  668. }
  669. }
  670.  
  671. CheckPresedButtons();
  672. }
  673.  
  674. function CheckPresedButtons()
  675. {
  676. $(".awq_btn").removeClass("awq_true");
  677. $(".awq_btn").removeClass("awq_false");
  678. }
  679.  
  680. console.log("AnkiWeb Quiz v" + GM_info.script.version + " Initialized");
  681. });
  682.  
  683.  
  684. // ------------
  685. // TODO
  686. // ------------
  687.  
  688. /* TODO STARTS
  689. ✓ 1)Make it only one element of buttons //DONE 0.0.9
  690. 1.1)Increase numbers of buttons to 10-12(optional through settings???)
  691. ✓ 2)Make it limit of length answer and put whole in attribute title //DONE 0.1.0
  692. 3)Make it settings, almost done in 0.1.0
  693. ✓ 3.1)Debug //DONE 0.1.0
  694. 3.2)Add txt file ***RESEARCH NEEDED***
  695. 3.2.1)Choose them
  696. 3.3)Make it always show quiz
  697. ✓ 4)Make it full functionality of Japanese deck, partial done in 0.0.8 //DONE 0.0.9 Happy with that :)
  698. 5)Search question in between tags <awq_question> and </awq_question> not in whole sentence, almost done in 0.1.2
  699. ✓ 6)TODO for loop in finding question NEED TEST IT //DONE 0.1.7
  700. TODO ENDS */