AnkiWeb Quiz

Shows quiz on ankiweb

目前為 2017-06-24 提交的版本,檢視 最新版本

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