AnkiWeb Quiz

Shows quiz on ankiweb

当前为 2017-04-21 提交的版本,查看 最新版本

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