// Bind Listeners $("input[name='font-select']").change(function(){ let $choice = $(this).val(); set_font($choice); }); $("input[name='font-size']").change(function(){ let $choice = $(this).val(); set_font_size($choice); }); $("input[name='bg-select']").change(function(){ let $choice = $(this).val(); set_bg_colour($choice); }); $(".bg-select-area").click(function(event){ $(this).find("input[name='bg-select']").prop("checked", true).change(); }); $("#btn-toggle-navigator").click(function(event){ check_answered(); update_navigator(); if ($quiz_navigator.is(":hidden")) { if ($quiz_settings.is(":visible")) { toggle_settings = true; $quiz_settings.fadeOut(); } $quiz_render.fadeOut(); $quiz_navigator.fadeIn(); $(".navigator-text").fadeIn(); $(".review-text").fadeOut(); toggle_navigator = false; $(window).scrollTop(0); } else { $quiz_navigator.fadeOut(); if (toggle_settings) { $quiz_settings.fadeIn(); $(window).scrollTop(0); toggle_settings = false; } else { $quiz_render.fadeIn(); $(window).scrollTop(0); } } event.preventDefault(); }); $("#btn-toggle-settings").click(function(event){ if (($quiz_settings).is(":hidden")) { if ($quiz_navigator.is(":visible")) { toggle_navigator = true; $quiz_navigator.fadeOut(); } $quiz_render.fadeOut(); $quiz_settings.fadeIn(); $(window).scrollTop(0); toggle_settings = false; } else { $quiz_settings.fadeOut(); if (toggle_navigator) { $quiz_navigator.fadeIn(); toggle_navigator = false; $(window).scrollTop(0); } else { $quiz_render.fadeIn(); $(window).scrollTop(0); } } event.preventDefault(); }); $(".btn-quiz-return").click(function(event){ $quiz_navigator.fadeOut(); $quiz_settings.fadeOut(); $quiz_render.fadeIn(); $(window).scrollTop(0); toggle_settings = false; toggle_navigator = false; event.preventDefault(); }); $(".btn-dummy").click(function(event){ event.preventDefault(); }); $("#navigator-container").on("click", ".q-navigator-button", function(event){ check_answered(); update_navigator(); current_question = parseInt($(this).prop("name")); $quiz_navigator.fadeOut(); $quiz_render.fadeIn(); $question_title.focus(); $(window).scrollTop(0); toggle_navigator = false; toggle_settings = false; render_question(); check_flag(); event.preventDefault(); }); $(".q-question-nav").click(function(event){ check_answered(); update_navigator(); if ($(this).prop("id") == "q-nav-next") { if (current_question < questions.length) { current_question ++; } } else if ($(this).prop("id") == "q-nav-prev") { if (current_question > 0) { current_question --; } } else if ($(this).hasClass("q-navigator-button")) { current_question = $(this).prop("name"); $quiz_render.fadeIn(); $quiz_navigator.fadeOut(); toggle_navigator = false; toggle_settings = false; } render_question(); check_flag(); event.preventDefault(); }); $("#q-nav-flag").click(function(event){ if (question_status[current_question] != 1) { question_status[current_question] = 1; $(this).removeClass().addClass("btn btn-warning"); $(this).prop("title", "Question Flagged for revision. Click to un-flag."); } else { question_status[current_question] = 0; $(this).removeClass().addClass("btn btn-secondary"); $(this).prop("title", "Question Un-Flagged. Click to flag for revision."); } window.localStorage.setItem('question_status', JSON.stringify(question_status)); update_navigator(); event.preventDefault(); }); $("#btn-start-quiz").click(function(event){ $.ajax({ url: `/api/questions/`, type: 'POST', data: JSON.stringify({'id': id}), contentType: "application/json", success: function(response) { $(this).fadeOut(); $(".btn-quiz-return").fadeIn(); $(".quiz-console").fadeIn(); $("#quiz-settings").fadeOut(); $("#quiz-navigator").fadeOut(); $(".quiz-start-text").fadeOut(); time_limit = response.time_limit; start_time = response.start_time; questions = response.questions; total_questions = questions.length; window.localStorage.setItem('questions', JSON.stringify(questions)); window.localStorage.setItem('start_time', JSON.stringify(start_time)); window.localStorage.setItem('time_limit', JSON.stringify(time_limit)); render_question(); build_navigator(); check_flag(); if (time_limit != 'null' && time_limit != null) { $("#q-timer-widget").fadeIn(); time_remaining = get_time_remaining(); clock = setInterval(timer, 1000); } if (response.time_adjustment > 0) { const $alert = $("#alert-box"); $alert.html( ` ` ); $alert.focus(); } }, error: function(response) { error_response(response); } }); event.preventDefault(); }); $("#quiz-question-options").on("change", ".quiz-option", function(event){ $name = parseInt($(this).prop("name")); $value = $(this).prop("value"); answers[$name] = $value; window.localStorage.setItem('answers', JSON.stringify(answers)); }); $("#q-review-answers").click(function(event){ check_answered(); update_navigator(); if ($quiz_navigator.is(":hidden")) { if ($quiz_settings.is(":visible")) { toggle_settings = true; $quiz_settings.fadeOut(); } $quiz_render.fadeOut(); $quiz_navigator.fadeIn(); $(".navigator-text").fadeOut(); $(".review-text").fadeIn(); toggle_navigator = false; $(window).scrollTop(0); } else { $quiz_navigator.fadeOut(); if (toggle_settings) { $quiz_settings.fadeIn(); toggle_settings = false; } else { $quiz_render.fadeIn(); } } event.preventDefault(); }); $(".quiz-button-submit").click(function(event){ let submission = { 'id': id, 'answers': answers } $.ajax({ url: `/api/submit/`, type: 'POST', data: JSON.stringify(submission), contentType: "application/json", success: function(response) { window.localStorage.clear(); window.location.href = `/result/`; }, error: function(response) { error_response(response); } }); event.preventDefault(); }); // Functions function set_font(value = 'osdefault') { let font_styles = ['arial', 'comicsans', 'opendyslexic', 'tahoma', 'verdana'] for (let i = 0; i < font_styles.length; i ++) { if (font_styles[i] != value) { $("body").removeClass( `q-f-${font_styles[i]}` ); }; }; if (value != 'osdefault') { $("body").addClass(`q-f-${value}`); }; display_settings['font-select'] = value; window.localStorage.setItem('display_settings', JSON.stringify(display_settings)); $('input[name="font-select"][value="' + value + '"]').prop('checked', true); } function set_font_size(value = '14pt') { let font_sizes = ['12pt', '16pt', '18pt'] for (let i = 0; i < font_sizes.length; i ++) { if (font_sizes[i] != value) { $("body").removeClass( `q-f-${font_sizes[i]}` ); }; }; if (value != '14pt') { $("body").addClass(`q-f-${value}`); }; display_settings['font-size'] = value; window.localStorage.setItem('display_settings', JSON.stringify(display_settings)); $('input[name="font-size"][value="' + value + '"]').prop('checked', true); } function set_bg_colour(value = 'bg-light') { let backgrounds = ['bg-light', 'q-bg-light-1', 'q-bg-light-2', 'alert-primary', 'alert-secondary', 'alert-dark', 'bg-dark'] for (let i = 0; i < backgrounds.length; i ++) { if (backgrounds[i] != value) { $("body").removeClass(backgrounds[i]); if (backgrounds[i] == 'bg-dark') { $("body").removeClass('text-light'); }; if (backgrounds[i] == 'alert-primary' || backgrounds[i] == 'alert-secondary' || backgrounds[i] == 'alert-dark') { $("body").removeClass('text-dark'); }; }; }; $("body").addClass(value); if (value == 'bg-dark') { $("body").addClass('text-light'); }; if (value == 'alert-primary' || value == 'alert-secondary' || value == 'alert-dark') { $("body").addClass('text-dark'); }; display_settings['bg-select'] = value; window.localStorage.setItem('display_settings', JSON.stringify(display_settings)); $('input[name="bg-select"][value="' + value + '"]').prop('checked', true); } function get_settings_from_storage() { let display_settings = window.localStorage.getItem('display_settings') if (display_settings != null) { return JSON.parse(display_settings); }; return { 'font-select': 'osdefault', 'font-size': '14pt', 'bg-select': 'bg-light' } } function apply_settings(settings) { set_font(settings['font-select']); set_font_size(settings['font-size']); set_bg_colour(settings['bg-select']); } function render_question() { if (current_question == 0) { $nav_prev.addClass('disabled'); } if (current_question == questions.length - 1) { $nav_next.addClass('disabled'); } if ($nav_prev.hasClass('disabled') && current_question > 0) { $nav_prev.removeClass('disabled'); } if ($nav_next.hasClass('disabled') && current_question < questions.length - 1) { $nav_next.removeClass('disabled'); } var question = questions[current_question]; let header_text = question.question_header; var block_length = 0; if ('block_length' in question) { block_length = question['block_length']; }; var block_q_no = 0; if ('block_q_no' in question) { block_q_no = question['block_q_no']; } let remaining_qs = (block_length - block_q_no).toString(); if (block_length - block_q_no > 1) { remaining_qs += ' questions'; } else { remaining_qs += ' question'; } header_text = header_text.replace('', remaining_qs); $question_header.html(header_text); $question_text.html(question.text); $question_title.html(`Question ${current_question + 1} of ${ questions.length }.`); var q_no = question['q_no']; var options = question.options; var options_output = ''; for (let i = 0; i < options.length; i ++) { var add_checked = '' if (q_no in answers) { if (answers[q_no] == options[i][0]) { add_checked = 'checked'; } } options_output += `
`; } $question_options.html(options_output); let skipped = count_questions(-1); let answered = count_questions(2); let flagged = count_questions(1); $progress_skipped.prop('title', `Skipped: ${skipped}`); $progress_skipped.prop('aria-valuenow', skipped); $progress_skipped.css('width', `${skipped}%`); $skipped_count.text(`Skipped: ${skipped}`); if (skipped < 1) { $skipped_count.fadeOut() } else { $skipped_count.fadeIn() } $progress_flagged.prop('title', `Flagged: ${flagged}`); $progress_flagged.prop('aria-valuenow', flagged); $progress_flagged.css('width', `${flagged}%`); $flagged_count.text(`Flagged: ${flagged}`); if (flagged < 1) { $flagged_count.fadeOut() } else { $flagged_count.fadeIn() } $progress_answered.prop('title', `Answered: ${answered}`); $progress_answered.prop('aria-valuenow', answered); $progress_answered.css('width', `${answered}%`); $answered_count.text(`Answered: ${answered}`); if (answered < 1) { $answered_count.fadeOut() } else { $answered_count.fadeIn() } $question_title.focus(); $(window).scrollTop(0); } function check_answered() { var question = questions[current_question]; var name = question.q_no; if (question_status[current_question] == 0 || question_status[current_question] == -1) { if (!$(`input[name='${name}']:checked`).val()) { question_status[current_question] = -1; } else { question_status[current_question] = 2; } window.localStorage.setItem('question_status', JSON.stringify(question_status)); } } function check_flag() { if (!(current_question in question_status)) { question_status[current_question] = 0; window.localStorage.setItem('question_status', JSON.stringify(question_status)); } switch (question_status[current_question]) { case -1: $nav_flag.removeClass().addClass('btn btn-danger progress-bar-striped'); $nav_flag.prop("title", "Question Incomplete. Click to flag for revision."); break; case 1: $nav_flag.removeClass().addClass('btn btn-warning'); $nav_flag.prop("title", "Question Flagged for revision. Click to un-flag."); break; case 2: $nav_flag.removeClass().addClass('btn btn-success'); $nav_flag.prop("title", "Question Answered. Click to flag for revision."); break; default: $nav_flag.removeClass().addClass('btn btn-secondary'); $nav_flag.prop("title", "Question Un-Flagged. Click to flag for revision."); } } function build_navigator() { $nav_container.html('') var output = '' for (let i = 0; i < questions.length; i ++) { let add_class, add_href, add_status = ''; switch (question_status[i]) { case -1: add_class = 'btn-danger progress-bar-striped'; add_href = 'href="#"'; add_status = 'Incomplete'; break; case 1: add_class = 'btn-warning'; add_href = 'href="#"'; add_status = 'Flagged'; break; case 2: add_class = 'btn-success'; add_href = 'href="#"'; add_status = 'Answered'; break; default: add_class = 'btn-secondary disabled'; add_href = ''; add_status = 'Unseen'; } output += `Q${i + 1}`; } $nav_container.html(output); } function update_navigator() { let button = $(`.q-navigator-button[name=${current_question}]`) if (current_question in question_status) { switch (question_status[current_question]) { case -1: button.removeClass().addClass("q-navigator-button btn btn-danger progress-bar-striped"); button.prop("title", `Question ${current_question + 1}: Incomplete`); break; case 1: button.removeClass().addClass("q-navigator-button btn btn-warning"); button.prop("title", `Question ${current_question + 1}: Flagged`); break; case 2: button.removeClass().addClass("q-navigator-button btn btn-success"); button.prop("title", `Question ${current_question + 1}: Answered`); break; default: button.removeClass().addClass("q-navigator-button btn btn-secondary disabled"); button.prop("title", `Question ${current_question + 1}: Unseen`); } } } function start() { $("#btn-start-quiz").fadeOut(); $(".btn-quiz-return").fadeIn(); $(".quiz-console").fadeIn(); $("#quiz-settings").fadeOut(); $("#quiz-navigator").fadeOut(); $(".quiz-start-text").fadeOut(); questions = JSON.parse(window.localStorage.getItem('questions')); total_questions = questions.length; start_time = window.localStorage.getItem('start_time'); time_limit = window.localStorage.getItem('time_limit'); let get_answers = window.localStorage.getItem('answers'); if (get_answers != null) { answers = JSON.parse(get_answers); } let get_status = window.localStorage.getItem('question_status'); if (get_status != null) { question_status = JSON.parse(get_status); } render_question(); build_navigator(); check_flag(); if (time_limit != 'null' && time_limit != null) { $("#q-timer-widget").fadeIn(); time_remaining = get_time_remaining(); clock = setInterval(timer, 1000); } } function check_started() { let questions = window.localStorage.getItem('questions'); let time_limit = window.localStorage.getItem('time_limit'); let start_time = window.localStorage.getItem('start_time') if (questions != null && start_time != null && time_limit != null) { start(); } } function get_time_remaining() { var end_time = new Date(time_limit).getTime(); var _start_time = new Date().getTime(); return end_time - _start_time; } function timer() { var hours = Math.floor((time_remaining % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); var minutes = Math.floor((time_remaining % (1000 * 60 * 60)) / (1000 * 60)); var seconds = Math.floor((time_remaining % (1000 * 60)) / 1000); if (time_remaining > 0) { var timer_display = ''; if (hours > 0) { timer_display = `${hours.toString()}:`; } if (minutes > 0 || hours > 0) { if (minutes < 10) { timer_display += `0${minutes.toString()}:`; } else { timer_display += `${minutes.toString()}:`; } } if (seconds < 10) { timer_display += `0${seconds.toString()}`; } else { timer_display += seconds.toString(); } $timer.html(timer_display); time_remaining -= 1000 } else { $timer.html('Expired'); clearInterval(clock); stop() } } function stop() { $quiz_render.fadeOut(); $quiz_navigator.fadeOut(); $quiz_timeout.fadeIn(); $("#btn-toggle-navigator").addClass('disabled'); $("#btn-toggle-settings").addClass('disabled') } function count_questions(status) { output = 0; for (let i = 0; i < Object.keys(question_status).length; i++) { key = Object.keys(question_status)[i]; if (question_status[key] == status){ output ++; } } return output; } // Variable Definitions const id = window.localStorage.getItem('id'); var current_question = 0; var total_questions = 0; var question_status = {}; var answers = {}; var questions = []; var time_limit, start_time, time_remaining; var display_settings = get_settings_from_storage(); const $quiz_settings = $("#quiz-settings"); const $quiz_navigator = $("#quiz-navigator"); const $quiz_render = $("#quiz-render"); const $quiz_timeout = $("#quiz-timeout"); const $nav_flag = $("#q-nav-flag"); const $nav_next = $("#q-nav-next"); const $nav_prev = $("#q-nav-prev"); const $nav_container = $("#navigator-container"); const $timer = $("#q-timer-display"); var clock var toggle_settings = false; var toggle_navigator = false; const $question_title = $("#quiz-question-title"); const $question_header = $("#quiz-question-header"); const $question_text = $("#quiz-question-text"); const $question_options = $("#quiz-question-options"); const $progress_skipped = $("#skipped-bar"); const $progress_answered = $("#answered-bar"); const $progress_flagged = $("#flagged-bar"); const $skipped_count = $("#skipped-count"); const $answered_count = $("#answered-count"); const $flagged_count = $("#flagged-count"); // Execution on Load apply_settings(display_settings); check_started();