Guest User

Untitled

a guest
Mar 17th, 2018
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.72 KB | None | 0 0
  1. const QUIZ_API = 'quiz.json';
  2. const RESULT_API = 'result.json';
  3. const QUIZ_ID = 12; // Used to identify the quiz in the JSON file.
  4.  
  5. let jsonQuizData;
  6. let questionNo = 0; // Current question number
  7. let answerSubmitted = false; // Is set to true once the user submits an answer to the current question and still hasn't proceeded to the next one.
  8. let points = 0; // User's current score
  9. let maxPoints = 0; // Max possible score for quiz
  10.  
  11. /*
  12. * When the document is ready, adds a key listener to enable playing the quiz using the keyboard only, and loads quiz data.
  13. */
  14. $(document).ready(() => {
  15. // Allow submitting answer with Enter key
  16. document.addEventListener('keyup', (event) => {
  17. if (event.keyCode === 13) // 13 is the Enter key
  18. $('#next-btn').click();
  19. });
  20.  
  21. $.getJSON( QUIZ_API, { quiz_id: QUIZ_ID})
  22. .done((resp) => {
  23. jsonQuizData = resp;
  24. $('h1').text(resp.title);
  25. $('h2').html('“' + resp.description + '”');
  26. updateQuestionDisplay(resp.questions[0]);
  27. })
  28. .fail(() => {
  29. alert('The quiz is not available at the moment! Please try again later.');
  30. });
  31. });
  32.  
  33. /*
  34. * Displays the current question and its possible answers
  35. * @param {Object} qObject - Object representing the current question
  36. */
  37. function updateQuestionDisplay(qObject) {
  38. /* Question image */
  39. const imageAlt = `Question ${questionNo + 1} image`;
  40. $('#question').find('img').attr({
  41. src: qObject.img,
  42. alt: imageAlt
  43. });
  44.  
  45. /* Question header (Question number, question title, question points) */
  46. let maxStr = ''; // Questions with multiple answers will have the word 'max' after the number of points, in order to show that the user may receive fewer points for a partially correct answer.
  47. if (qObject.question_type === 'mutiplechoice-multiple')
  48. maxStr = ' max';
  49. let ptsStr = qObject.points === 1? ' pt': ' pts';
  50. $('#qTitle').html(qObject.q_id + '. ' + qObject.title + ' <strong>[' + qObject.points + ptsStr + maxStr + ']</strong>');
  51.  
  52. /* Question type */
  53. let inputType;
  54. switch(qObject.question_type) {
  55. case 'mutiplechoice-multiple':
  56. inputType = 'checkbox';
  57. break;
  58. default:
  59. inputType = 'radio';
  60. }
  61.  
  62. /* Answers */
  63. const inputsContainer = $('#inputs');
  64. inputsContainer.css('text-align', 'left');
  65.  
  66. if (qObject.question_type === 'truefalse') {
  67. inputsContainer.append(`
  68. <div class="option">
  69. <input type="${inputType}" id="true" name="${qObject.q_id}" value="true">
  70. <label for="true">True</label>
  71. </div>
  72. `);
  73. inputsContainer.append(`
  74. <div class="option">
  75. <input type="${inputType}" id="false" name="${qObject.q_id}" value="false">
  76. <label for="false">False</label>
  77. </div>
  78. `);
  79. }
  80. else
  81. qObject.possible_answers.forEach((item) => {
  82. inputsContainer.append(`
  83. <div class="option">
  84. <input type="${inputType}" id="${item.a_id}" name="${qObject.q_id}" value="${item.a_id}">
  85. <label for="${item.a_id}">${item.caption}</label>
  86. </div>
  87. `);
  88. });
  89. }
  90.  
  91. /*
  92. * Performs appropriate task on clicking button based on answerSubmitted
  93. */
  94. function nextButtonClicked() {
  95. if (answerSubmitted)
  96. nextQuestion();
  97. else
  98. submitAnswer();
  99. }
  100.  
  101. /*
  102. * Validates and submits the user's answer, changes document and styles accordingly.
  103. */
  104. function submitAnswer() {
  105. const inputs = $('input');
  106. let ans = []; // ans is an array to accomodate the case of multiple answer questions.
  107. inputs.each((i, obj) => {
  108. if (obj.checked)
  109. ans.push(obj.id); // obj.id is always a string.
  110. });
  111. if (!ans.length)
  112. alert('No answer selected!');
  113. else { // If an answer was selected
  114. answerSubmitted = true;
  115. checkAnswer(ans);
  116.  
  117. const nextBtn = $('#next-btn');
  118.  
  119. inputs.attr('disabled', 'disabled');
  120. nextBtn.attr('disabled', 'disabled');
  121. $('#inputs').css('text-align', 'center');
  122.  
  123. let newButtonText = jsonQuizData.questions[questionNo + 1]? 'Next question': 'See results!';
  124.  
  125. $(this).delay(500).queue(() => {
  126. nextBtn.text(newButtonText);
  127. nextBtn.removeAttr('disabled');
  128. $(this).dequeue();
  129. });
  130. }
  131. }
  132.  
  133. /*
  134. * Performs 2 tasks:
  135. * 1. Add css to indicate the correct answer and highlight the user's chosen answer.
  136. * 2. Check answer and update points.
  137. * @param {string[]} answer - User's submitted answer
  138. */
  139. function checkAnswer(answer) {
  140. const correctAnswer = jsonQuizData.questions[questionNo].correct_answer;
  141. let pointsToAward = jsonQuizData.questions[questionNo].points;
  142. maxPoints += pointsToAward; // Update maxPoints for the current question.
  143.  
  144. /* 1. Add css to indicate the correct answer and highlight the user's answer. */
  145. if (jsonQuizData.questions[questionNo].question_type === 'truefalse') { // For true-false questions it is straightforward
  146. $('label[for="' + correctAnswer.toString() + '"]').addClass('correct');
  147. $('label[for="' + (!(correctAnswer)).toString() + '"]').addClass('incorrect');
  148. $('label[for="' + answer.toString() + '"]').parent().addClass('selected');
  149. }
  150. else { // For questions which are not of true-false type
  151. jsonQuizData.questions[questionNo].possible_answers.forEach((obj, i) => {
  152. if (answer.includes(obj.a_id.toString()))
  153. $('label[for="' + obj.a_id.toString() + '"]').parent().addClass('selected');
  154. if (typeof correctAnswer === 'object' && correctAnswer != null && correctAnswer.includes(jsonQuizData.questions[questionNo].possible_answers[i].a_id) || correctAnswer === obj.a_id)
  155. $('label[for="' + obj.a_id.toString() + '"]').addClass('correct');
  156. else
  157. $('label[for="' + obj.a_id.toString() + '"]').addClass('incorrect');
  158. });
  159. }
  160.  
  161. /* 2. Check answer and update points. */
  162. if (typeof jsonQuizData.questions[questionNo].correct_answer === 'object' && jsonQuizData.questions[questionNo].correct_answer != null) { // The if statement checks if it is a question with multiple answers. This is because 'object' is the type of arrays, and of null. Since correct_answer might be null, we check if it's not null as well.
  163. const noOfItems = jsonQuizData.questions[questionNo].possible_answers.length;
  164. let resultBool = new Array(noOfItems).fill(false); // For each option, resultBool[i] is false if the user's answer is wrong, else true.
  165.  
  166. // Setting resultBool
  167. jsonQuizData.questions[questionNo].possible_answers.forEach((obj, i) => {
  168. if (correctAnswer.includes(obj.a_id) && answer.includes(obj.a_id.toString()) || !correctAnswer.includes(obj.a_id) && !answer.includes(obj.a_id.toString()))
  169. resultBool[i] = true;
  170. });
  171.  
  172. resultBool.forEach((obj) => {
  173. if (!obj)
  174. pointsToAward = pointsToAward - !!pointsToAward; // Decrements pointsToAward by 1 if it's greater than 0.
  175. });
  176.  
  177. points += pointsToAward;
  178. }
  179. else { // Questions with a single answer
  180. if (answer[0] === correctAnswer.toString())
  181. points += pointsToAward;
  182. }
  183. }
  184.  
  185. /*
  186. * If a subsequent question exists, increments questionNo and displays the next question
  187. * with the help of updateQuestionDisplay(). Else, calls displayResults.
  188. */
  189. function nextQuestion() {
  190. if (jsonQuizData.questions[questionNo + 1]) { // If there is a next question
  191. // Remove current options
  192. $('.option').each((i, obj) => {
  193. obj.remove();
  194. });
  195.  
  196. // Replace image with placeholder image so users with slow internet connections do not see the previous level's image while the new level's image is still loading.
  197. $('.img-container-small').find('img').attr('src', 'img/placeholder-image.png');
  198.  
  199. // Set button text
  200. $('#next-btn').text('Submit');
  201.  
  202. // Set answerSubmitted to false
  203. answerSubmitted = false;
  204.  
  205. // Increment question number and display next question
  206. updateQuestionDisplay(jsonQuizData.questions[++questionNo]);
  207. }
  208. else
  209. displayResults();
  210. }
  211.  
  212. /*
  213. * Calculates the user's score as a percentage, loads the result data, finds the user's
  214. * result group, displays the user's result.
  215. */
  216. function displayResults() {
  217. const pointsPercent = Math.round(points / maxPoints * 100);
  218. let resultGroupIndex = 0;
  219.  
  220. let jsonResultsData;
  221. $.getJSON( RESULT_API, { quiz_id: QUIZ_ID})
  222. .done((resp) => {
  223. jsonResultsData = resp;
  224. jsonResultsData.results.forEach((obj, i) => {
  225. if (pointsPercent >= obj.minpoints)
  226. resultGroupIndex = i;
  227. });
  228.  
  229. $('main').html(`
  230. <section>
  231. <h3>Quiz completed! Points earned: <strong>${points}/${maxPoints} (${pointsPercent}%)</strong></h3>
  232. <p class="huge-font m-y-sm">${jsonResultsData.results[resultGroupIndex].title}</p>
  233. <div class="img-container-medium"><img src="${jsonResultsData.results[resultGroupIndex].img}" alt="Result image"></div>
  234. <p class="p-b-md">${jsonResultsData.results[resultGroupIndex].message}</p>
  235. </section>
  236. `);
  237. })
  238. .fail(() => {
  239. alert('Your result is not available at the moment! Please try again later.');
  240. });
  241. }
  242.  
  243. <button id="next-btn" onclick="nextButtonClicked()">Submit</button>
  244.  
  245. <button id="next-btn" onclick="nextButtonClicked()">Submit</button>
  246.  
  247. (function() {
  248. const QUIZ_API = 'quiz.json';
  249. const RESULT_API = 'result.json';
  250. const QUIZ_ID = 12; // Used to identify the quiz in the JSON file.
  251. // ... Rest of code ...
  252. }());
  253.  
  254. $(document).ready(() => {
  255. document.getElementById("next-btn").addEventListener("click", nextButtonClicked);
  256. });
  257.  
  258. else
  259. qObject.possible_answers.forEach((item) => {
  260.  
  261. (function($) {
  262. $(document).ready(function() {
  263. // Code
  264. });
  265. })(jQuery);
  266.  
  267. $(document).ready(() => {
  268. //move this out of submitAnswer()
  269. nextBtn = $('#next-btn');
  270.  
  271. <button id="next-btn">Submit</button>
  272.  
  273. let inputType;
  274. switch(qObject.question_type) {
  275. case 'mutiplechoice-multiple':
  276. inputType = 'checkbox';
  277. break;
  278. default:
  279. inputType = 'radio';
  280. }
  281.  
  282. let inputType;
  283. if (qObject.question_type == 'mutiplechoice-multiple') {
  284. inputType = 'checkbox';
  285. }
  286. else {
  287. inputType = 'radio';
  288. }
  289.  
  290. let inputType = 'radio';
  291. if (qObject.question_type == 'mutiplechoice-multiple') {
  292. inputType = 'checkbox';
  293. }
  294.  
  295. let newButtonText = jsonQuizData.questions[questionNo + 1]? 'Next question': 'See results!';
  296.  
  297. document.addEventListener('keyup', (event) => {
  298.  
  299. $(document).on('keyup', (event) => { ... })
Add Comment
Please, Sign In to add comment