AnkiWeb Quiz

Shows quiz on ankiweb

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

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