AnkiWeb Quiz

Shows quiz on ankiweb

目前為 2017-05-28 提交的版本,檢視 最新版本

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