This commit is contained in:
Ross
2023-05-15 09:34:56 +01:00
7 changed files with 40391 additions and 1662 deletions
+6 -3
View File
@@ -1,8 +1,11 @@
{ {
"editor.autoIndent": "keep", "editor.autoIndent": "keep",
"javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, "javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
"javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": false, "javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": true,
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false, "javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false,
"javascript.format.enable": false, "javascript.format.enable": true,
"liveServer.settings.port": 5502 "liveServer.settings.port": 5502,
"javascript.format.insertSpaceAfterConstructor": true,
"javascript.format.insertSpaceBeforeFunctionParenthesis": false,
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false
} }
+9 -11
View File
@@ -17,15 +17,12 @@
<div id="content"> <div id="content">
<div class="content-panel"> <div class="content-panel">
<div class="nav-bar"> <div class="nav-bar">
<button id="review-button" class="navigation nav-right"><b></b></button> <button id="btn-review" class="navigation nav-right"><b></b></button>
<button id="nav-submit-button" class="submit-button navigation nav-right"><b>submit</b></button> <button id="btn-submit-nav" class="submit-button navigation nav-right"><b>submit</b></button>
<!--<button id="options-button" class="navigation nav-right" <button id="btn-review-overlay" class="navigation nav-right"
title="click to load new packet or manage saved answers">options</button>-->
<button id="review-overlay-button" class="navigation nav-right"
title="click to finish exam and review answers">review</button> title="click to finish exam and review answers">review</button>
<button id="fullscreen-overlay-button" class="navigation nav-right" <button id="btn-fullscreen-overlay" class="navigation nav-right"
title="click to toggle fullscreen">fullscreen</button> title="click to toggle fullscreen">fullscreen</button>
<!--<button id="logout-button" class="navigation nav-right">logout</button>-->
<div class="app-name nav-left">RTS</div> <div class="app-name nav-left">RTS</div>
<div id="timer" title="click to pause"></div> <div id="timer" title="click to pause"></div>
<div class="exam-name" title="currently loaded packet"></div> <div class="exam-name" title="currently loaded packet"></div>
@@ -161,7 +158,7 @@
<div class="dialog-text"> <div class="dialog-text">
Allocated time has ended. You can review or continue. Allocated time has ended. You can review or continue.
</div> </div>
<button id="time-up-review-button" class="navigation dialog-review">Review</button> <button id="btn-time-up-review" class="navigation dialog-review">Review</button>
<button id="time-up-continue-button" class="navigation dialog-yes">Continue</button> <button id="time-up-continue-button" class="navigation dialog-yes">Continue</button>
<button id="dialog-submit-button" class="submit-button navigation dialog-review hidden"><b>submit</b></button> <button id="dialog-submit-button" class="submit-button navigation dialog-review hidden"><b>submit</b></button>
</div> </div>
@@ -172,7 +169,7 @@
Candidate number: <input type="number" id="candidate-number" name="candidate" required size="10"><br /> Candidate number: <input type="number" id="candidate-number" name="candidate" required size="10"><br />
Passcode: <input type="text" id="passcode" name="passcode" required size="10"><br /> Passcode: <input type="text" id="passcode" name="passcode" required size="10"><br />
</div> </div>
<button id="login-button" class="navigation dialog-yes">Login</button> <button id="btn-login" class="navigation dialog-yes">Login</button>
</div> </div>
<div id="loading" class="fullscreen-overlay"> <div id="loading" class="fullscreen-overlay">
@@ -210,16 +207,17 @@
<div id="database-error" class="fullscreen-overlay"> <div id="database-error" class="fullscreen-overlay">
</div> </div>
<script src="lib/loglevel.min.js"></script>
<script src="lib/uuidv4.min.js" type="module"></script> <script src="lib/uuidv4.min.js" type="module"></script>
<script src="lib/jquery-3.4.1.min.js" type="text/javascript"></script> <script src="lib/jquery-3.4.1.min.js" type="text/javascript"></script>
<script src="lib/jq-ajax-progress.min.js" type="text/javascript"></script> <script src="lib/jq-ajax-progress.min.js" type="text/javascript"></script>
<script src="lib/easytimer.min.js" type="module"></script> <script src="lib/easytimer.min.js" type="module"></script>
<script src="lib/hammer.js"></script> <script src="lib/hammer.js"></script>
<script src="https://unpkg.com/cornerstone-core/dist/cornerstone.js"></script> <script src="lib/cornerstone.js"></script>
<script src="lib/dicomParser.min.js"></script> <script src="lib/dicomParser.min.js"></script>
<script src="lib/cornerstoneMath.min.js"></script> <script src="lib/cornerstoneMath.min.js"></script>
<!-- <script src="lib/cornerstoneTools.min.js"></script> --> <!-- <script src="lib/cornerstoneTools.min.js"></script> -->
<script src="https://www.unpkg.com/cornerstone-tools@5.2.0/dist/cornerstoneTools.js"></script> <script src="lib/cornerstoneTools.js"></script>
<script src="lib/cornerstoneWebImageLoader.min.js"></script> <script src="lib/cornerstoneWebImageLoader.min.js"></script>
<script src="lib/cornerstoneWADOImageLoader.js"></script> <script src="lib/cornerstoneWADOImageLoader.js"></script>
<script src="lib/cornerstone-base64-image-loader.umd.js"></script> <script src="lib/cornerstone-base64-image-loader.umd.js"></script>
+3 -3
View File
@@ -138,7 +138,7 @@ export function submissionError(data, answer_json, exam_details) {
)}</p></span></div>` )}</p></span></div>`
); );
$("#nav-submit-button").prependTo("#submit-error-overlay"); $("#btn-submit-nav").prependTo("#submit-error-overlay");
$("#submit-error-overlay").height(docHeight); $("#submit-error-overlay").height(docHeight);
@@ -180,11 +180,11 @@ export function getQuestion(url, question_number, question_total) {
}); });
} }
export function postSavedAnswer(type, qid, answer, e, db_object, db) { export function postSavedAnswer(type, qid, answer, e, db_object, db, submit_url) {
console.debug("post", type, qid, answer, e) console.debug("post", type, qid, answer, e)
return $.ajax({ return $.ajax({
type: "POST", type: "POST",
url: config.question_answer_submit_url, url: submit_url,
data: JSON.stringify({ data: JSON.stringify({
qid: `${type}/${qid}`, qid: `${type}/${qid}`,
answer: answer, answer: answer,
+124 -81
View File
@@ -5,6 +5,37 @@ import * as interact from "./interact.js";
import * as config from "./config.js"; import * as config from "./config.js";
// const { v4: uuidv4 } = require('uuid'); // const { v4: uuidv4 } = require('uuid');
log.setDefaultLevel("warn")
let URLS = {};
// Generate urls base on base_url
if (config.base_url != "" && config.base_url != undefined) {
URLS.base_url = config.base_url;
URLS.exam_query_url = config.base_url + "exam/json";
URLS.exam_submit_url = config.base_url + "exam/submit";
URLS.exam_results_url = config.base_url + "cid/";
URLS.question_feedback_url = config.base_url + "feedback/";
URLS.question_answer_submit_url = config.base_url + "feedback/answer";
URLS.login_url = config.base_url + "accounts/login/?next=/rts";
URLS.logout_url = config.base_url + "accounts/logout/?next=/rts";
}
// Override individual urls
let urls_to_check = ["exam_query_url", "exam_submit_url",
"exam_results_url", "question_feedback_url",
"quetion_answer_submit_url", "login_url", "logout_url"]
for (let url of urls_to_check) {
if (config[url] != "" && config[url] != undefined) {
URLS[url] = config[url];
}
}
log.debug(URLS)
let exam_details = { let exam_details = {
aid: null, aid: null,
cid: "", cid: "",
@@ -80,18 +111,13 @@ question_db.version(1).stores({
saved_exams: "&eid, type, exam_mode, name, order, time, exam_json_id", saved_exams: "&eid, type, exam_mode, name, order, time, exam_json_id",
}); });
const user_db = new Dexie("user_database");
user_db.version(1).stores({
user: "cid, passcode",
});
retrievePacketList(); retrievePacketList();
try { try {
refreshDatabaseSettings(); refreshDatabaseSettings();
} }
catch { catch {
console.log("unable to check database settings") log.warn("unable to check database settings")
} }
/** /**
@@ -104,42 +130,42 @@ console.log("unable to check database settings")
async function retrievePacketList() { async function retrievePacketList() {
let url = "packets/packets.json"; let url = "packets/packets.json";
//console.debug(config.exam_query_url); log.debug(`Load users from database...`)
let users = await user_db.user.toArray(); //let users = await user_db.user.toArray();
console.debug(users) //log.debug(`available users "${users}"`)
let cid = localStorage.getItem("cid.cid")
let passcode = localStorage.getItem("cid.passcode")
if (users.length > 0) { if (cid != null && passcode != null) {
global_cid = users[0].cid; global_cid = cid;
global_passcode = users[0].passcode; global_passcode = passcode;
//$(".exam-wrapper").toggle();
let logout = $("<span>[x]</span>") let logout = $("<span>[x]</span>")
logout.click(() => { logout.click(() => {
user_db.user.clear().then(() => { localStorage.removeItem("cid.cid");
localStorage.removeItem("cid.passcode");
window.location = window.location.pathname; window.location = window.location.pathname;
return;
});
}) })
if (config.exam_results_url != "" && config.exam_results_url != undefined) { if (URLS.exam_results_url != "" && URLS.exam_results_url != undefined) {
let url = `${config.exam_results_url}${global_cid}/${global_passcode}`; let url = `${URLS.exam_results_url}${global_cid}/${global_passcode}`;
log.debug(`Setting exam results url to ${URLS.exam_results_url}`);
$("#options-link") $("#options-link")
.empty() .empty()
.append( .append(
`<a href="${url}" target="_blank"><div class="packet-button">Results and answers</div></a>` `<a href="${url}" target="_blank"><div class="packet-button">Results and answers</div></a>`
); );
} else {
log.debug("No exams results url set in config.");
} }
$("#candidate-details").append(`Current: CID ${global_cid} / Passcode ${global_passcode} `).append(logout); $("#candidate-details").append(`Current: CID ${global_cid} / Passcode ${global_passcode} `).append(logout);
} else { } else {
log.debug("Try and set CID / Passcode from current URL")
let items = window.location.search.substr(1).split("&"); let items = window.location.search.substr(1).split("&");
if (items.length == 2) { if (items.length == 2) {
let cid = "";
let passcode = "";
for (let index = 0; index < items.length; index++) { for (let index = 0; index < items.length; index++) {
const item = items[index]; const item = items[index];
let s = item.split("="); let s = item.split("=");
@@ -152,28 +178,30 @@ async function retrievePacketList() {
} }
}; };
console.debug(cid, passcode) log.debug("CID and passcode extracted from URL", cid, passcode)
log.debug("adding to local db")
user_db.user.add({ localStorage.setItem("cid.cid", cid)
cid: cid, localStorage.setItem("cid.passcode", passcode)
passcode: passcode log.debug("reload page")
})
location.reload(); location.reload();
} }
} }
try { try {
if (config.exam_query_url != undefined) { log.debug("Try to set exam query url")
if (URLS.exam_query_url != undefined) {
if (global_cid == null) { if (global_cid == null) {
url = config.exam_query_url; url = URLS.exam_query_url;
} else { } else {
url = `${config.exam_query_url}/${global_cid}/${global_passcode}`; url = `${URLS.exam_query_url}/${global_cid}/${global_passcode}`;
} }
} }
log.debug(`url: {url}`)
} catch (e) { } catch (e) {
// log.debug("Unable to set exam query url", e)
log.debug("this will default to packets/packets.json")
} }
$.ajax({ $.ajax({
@@ -198,6 +226,7 @@ async function retrievePacketList() {
}) })
.done(function() {}) .done(function() {})
.fail(function() { .fail(function() {
log.debug("Unable to load packets / exams, try loading '/packets' (legacy)")
$.getJSON("packets", function(data) { $.getJSON("packets", function(data) {
if (data.hasOwnProperty("exams")) { if (data.hasOwnProperty("exams")) {
loadExamList(data); loadExamList(data);
@@ -205,8 +234,7 @@ async function retrievePacketList() {
loadPacketList(data); loadPacketList(data);
} }
}).fail(function(jqXHR, textStatus, errorThrown) { }).fail(function(jqXHR, textStatus, errorThrown) {
console.debug("No packet list available"); console.warn("No packet list available");
//showLoginDialog();
}); });
}) })
.always(function() {}); .always(function() {});
@@ -219,8 +247,10 @@ async function retrievePacketList() {
* @param {JSON} data - json containing available exams * @param {JSON} data - json containing available exams
*/ */
async function loadExamList(data) { async function loadExamList(data) {
log.debug(`Load exam list: ${data}`)
log.debug("Loading saved sessions")
let sessions = await db.session.toArray().catch(function(error) { let sessions = await db.session.toArray().catch(function(error) {
console.debug("Error loading session", error); log.debug("Error loading session", error);
$("#database-error").text( $("#database-error").text(
"Error loading the database, schema has probably changed and needs updating. You will probably need to delete the local database." "Error loading the database, schema has probably changed and needs updating. You will probably need to delete the local database."
); );
@@ -233,8 +263,11 @@ async function loadExamList(data) {
$("#database-error").append(delete_button); $("#database-error").append(delete_button);
$("#database-error").show(); $("#database-error").show();
}); });
log.debug(sessions)
//Display user info if it exists //Display user info if it exists
// If a user is loggged into the server it any exam responses
// should have the details embedded
if (data.hasOwnProperty("user") && data.user) { if (data.hasOwnProperty("user") && data.user) {
$("#user").append(`User: ${data.user}`); $("#user").append(`User: ${data.user}`);
//$(".exam-wrapper").show(); //$(".exam-wrapper").show();
@@ -250,10 +283,9 @@ async function loadExamList(data) {
let logout = $("<span>[x]</span>") let logout = $("<span>[x]</span>")
logout.click(() => { logout.click(() => {
user_db.user.clear().then(() => { localStorage.removeItem("cid.cid");
window.location = "/accounts/logout/"; localStorage.removeItem("cid.passcode");
return; window.location = URLS.logout_url;
});
}) })
$("#user").append(logout); $("#user").append(logout);
} }
@@ -261,70 +293,86 @@ async function loadExamList(data) {
let exams_started = []; let exams_started = [];
let exams_completed = []; let exams_completed = [];
sessions.forEach((s) => { log.debug("Check status of saved exams")
for (const s of sessions) {
log.debug(`checking status of`, s)
if (s.status == "active") { if (s.status == "active") {
exams_started.push(s.packet); exams_started.push(s.packet);
} else { } else {
exams_completed.push(s.packet); exams_completed.push(s.packet);
} }
}); };
// Wouldn't we be better terminating ealier in this situation
let exam_list = []; let exam_list = [];
if (data != null) { if (data != null) {
exam_list = data.exams; exam_list = data.exams;
} }
// exam_generated_map stores the exam and its json ID to
// enable invalidation when the question is updated on the server
let exam_generated_map = {}; let exam_generated_map = {};
$("#packet-list").empty(); $("#packet-list").empty();
//exam_list.sort((a, b) => (a.name > b.name) ? 1 : -1).forEach(function (exam) {
for (let index = 0; index < exam_list.length; index++) { log.debug("Loop available exams")
const exam = exam_list[index]; for (const exam of exam_list) {
console.debug(exam) log.debug(exam)
let name = exam["name"]; const name = exam["name"];
let url = exam["url"]; const url = exam["url"];
let eid = exam["eid"]; const eid = exam["eid"];
let exam_json_id = exam["exam_json_id"]; const exam_json_id = exam["exam_json_id"];
let question_json_id_hash = {}; let question_json_id_hash = {};
// In the case of multiquestion exams (longs) we
// check each question json_id in addition
if (exam.hasOwnProperty("multi_question_json")) { if (exam.hasOwnProperty("multi_question_json")) {
question_json_id_hash = exam["multi_question_json"]; question_json_id_hash = exam["multi_question_json"];
} }
exam_generated_map[eid] = [exam_json_id, question_json_id_hash]; exam_generated_map[eid] = [exam_json_id, question_json_id_hash];
let c = ""; // The exam against stored session data
let item_class = "";
if (exams_started.indexOf(name) > -1) { if (exams_started.indexOf(name) > -1) {
c = " session-started"; item_class = " session-started";
} }
if (exams_completed.indexOf(name) > -1) { if (exams_completed.indexOf(name) > -1) {
c = " session-completed"; item_class = " session-completed";
} }
if (!exam.exam_active) { if (!exam.exam_active) {
c = c + " inactive"; item_class = item_class + " inactive";
} }
// Place the exam under the relavant subheading
// by defailt they will be under the packet section
let target_list = "packet-list"; let target_list = "packet-list";
// if in exam mode we place them under the exam section
if (exam.exam_mode) { if (exam.exam_mode) {
target_list = "exam-list"; target_list = "exam-list";
} }
let list; let list;
if (exam.type != undefined) { if (exam.type != undefined) {
// If the relevant subheading exists target_it it
if ($(`.${target_list}.${exam.type}`).length) { if ($(`.${target_list}.${exam.type}`).length) {
list = $(`.${target_list}.${exam.type}`); list = $(`.${target_list}.${exam.type}`);
// or create and add it
} else { } else {
list = $(`<div class='${target_list} ${exam.type}'><span class='packet-list-title'>${exam.type}</span><br/></div>`); list = $(`<div class='${target_list} ${exam.type}'><span class='packet-list-title'>${exam.type}</span><br/></div>`);
$(`#${target_list}`).append(list); $(`#${target_list}`).append(list);
} }
// if the packet / exam type is not defined just add it at the bottom
// TODO: do we actually want this?
} else { } else {
list = $("#packet-list"); list = $("#packet-list");
} }
// Add the button that is used to load the packet/exam
$(list).append( $(list).append(
$( $(
`<div class='packet-button${c}' data-eid='${eid}' title='Load packet'></div>` `<div class='packet-button${item_class}' data-eid='${eid}' title='Load packet'></div>`
) )
.text(name) .text(name)
.click(function() { .click(function() {
@@ -933,7 +981,7 @@ function setUpQuestions(load_previous) {
//question_type = questions[Object.keys(questions)[0]].type; //question_type = questions[Object.keys(questions)[0]].type;
if (exam_details.exam_mode) { if (exam_details.exam_mode) {
$("#options-button, #review-overlay-button").hide(); $("#options-button, #btn-review-overlay").hide();
} else { } else {
$(".submit-button").hide(); $(".submit-button").hide();
} }
@@ -1728,7 +1776,7 @@ $(".submit-button").click(function(evt) {
interact.submitAnswers(exam_details, db, config); interact.submitAnswers(exam_details, db, config);
}); });
$("#review-button").click(function(evt) { $("#btn-review").click(function(evt) {
$(".question-list-panel").toggle(); $(".question-list-panel").toggle();
}); });
@@ -1737,7 +1785,7 @@ $("#options-button").click(function(evt) {
$("#options-panel").toggle(); $("#options-panel").toggle();
}); });
$("#review-overlay-button").click(function(evt) { $("#btn-review-overlay").click(function(evt) {
if (review_mode == true) { if (review_mode == true) {
reviewQuestions(); reviewQuestions();
} else { } else {
@@ -1745,7 +1793,7 @@ $("#review-overlay-button").click(function(evt) {
} }
}); });
$("#fullscreen-overlay-button").click(function(evt) { $("#btn-fullscreen-overlay").click(function(evt) {
if (document.fullscreen == false) { if (document.fullscreen == false) {
document.documentElement.requestFullscreen(); document.documentElement.requestFullscreen();
} else { } else {
@@ -1753,13 +1801,13 @@ $("#fullscreen-overlay-button").click(function(evt) {
} }
}); });
$("#finish-exam, #time-up-review-button").click(function(evt) { $("#finish-exam, #btn-time-up-review").click(function(evt) {
review_mode = true; review_mode = true;
reviewQuestions(); reviewQuestions();
$.modal.close(); $.modal.close();
}); });
$("#time-up-continue-button").click(function(evt) { $("#btn-time-up-continue").click(function(evt) {
$.modal.close(); $.modal.close();
}); });
@@ -1872,10 +1920,8 @@ function reviewQuestions() {
if (question_type == "long") { if (question_type == "long") {
$("#review-answer-table").append( $("#review-answer-table").append(
$( $(
`<tr class='review-table-heading' data-qid=${ `<tr class='review-table-heading' data-qid=${n + 1
n + 1 } title='Click to load question ${n + 1
} title='Click to load question ${
n + 1
}'><td colspan=2>Question ${n + 1}</td></tr>` }'><td colspan=2>Question ${n + 1}</td></tr>`
).click(() => { ).click(() => {
loadQuestion(n); loadQuestion(n);
@@ -1884,8 +1930,7 @@ function reviewQuestions() {
); );
// $("#review-answer-table").append(`<tr id='review-answer-${qid}'><td class='review-user-answer-cell'></td><td class='review-model-answer-cell'></td></tr>`); // $("#review-answer-table").append(`<tr id='review-answer-${qid}'><td class='review-user-answer-cell'></td><td class='review-model-answer-cell'></td></tr>`);
$("#review-answer-table").append( $("#review-answer-table").append(
`<tr class='answer-sub' data-qid=${ `<tr class='answer-sub' data-qid=${n + 1
n + 1
}><td>Your answers</td><td>Model answers</td></tr>` }><td>Your answers</td><td>Model answers</td></tr>`
); );
@@ -1926,8 +1971,7 @@ function reviewQuestions() {
model_answers[title.toLowerCase()]; model_answers[title.toLowerCase()];
$("#review-answer-table").append( $("#review-answer-table").append(
`<tr class='' data-qid=${ `<tr class='' data-qid=${n + 1
n + 1
}><td>${user_ans}</td><td>${model_ans}</td></tr>` }><td>${user_ans}</td><td>${model_ans}</td></tr>`
); );
}); });
@@ -2260,7 +2304,8 @@ function markAnswer(qid, current_question, n) {
saved_answer, saved_answer,
e, e,
saved_answer_object, saved_answer_object,
db db,
URLS.question_answer_submit_url
); );
}) })
); );
@@ -2337,7 +2382,7 @@ function addFeedback(current_question, qid) {
$(".answer-panel").append( $(".answer-panel").append(
$( $(
`<div class='feedback-link'><a href=${config.question_feedback_url}${current_question.type}/${qid} target=”_blank”>Submit question feedback</a></div>` `<div class='feedback-link'><a href=${URLS.question_feedback_url}${current_question.type}/${qid} target=”_blank”>Submit question feedback</a></div>`
) )
); );
} }
@@ -2470,23 +2515,19 @@ $("#btn-candidate-login").click(function(evt) {
}); });
$("#btn-user-login").click(function(evt) { $("#btn-user-login").click(function(evt) {
window.location = "/accounts/login/?next=/rts" window.location = URLS.login_url;
//$(".exam-wrapper").toggle(); //$(".exam-wrapper").toggle();
}); });
$("#login-button").click(function(evt) { $("#btn-login").click(function(evt) {
global_cid = parseInt($("#candidate-number").val()); global_cid = parseInt($("#candidate-number").val());
global_passcode = $("#passcode").val(); global_passcode = $("#passcode").val();
user_db.user.clear().then(() => { localStorage.setItem("cid.cid", global_cid)
user_db.user.add({ localStorage.setItem("cid.passcode", global_passcode)
cid: global_cid,
passcode: global_passcode
})
location.reload(); location.reload();
});
$.modal.close(); $.modal.close();
}); });
@@ -2516,7 +2557,7 @@ $(".start-packet-button").click(function(evt) {
timer.addEventListener("targetAchieved", function(e) { timer.addEventListener("targetAchieved", function(e) {
if (exam_details.exam_mode == true) { if (exam_details.exam_mode == true) {
$( $(
"#dialog-submit-button, #time-up-review-button, #time-up-continue-button" "#btn-dialog-submit, #btn-time-up-review, #btn-time-up-continue"
).toggle(); ).toggle();
$("#time-up-dialog .dialog-text").text( $("#time-up-dialog .dialog-text").text(
"Allocated time has ended. Click to submit answers." "Allocated time has ended. Click to submit answers."
@@ -2674,7 +2715,8 @@ $("#btn-reset-local").click(function(evt) {
if (r == true) { if (r == true) {
delete_answer_db(); delete_answer_db();
delete_question_db(); delete_question_db();
delete_user_db(); localStorage.removeItem("cid.cid")
localStorage.removeItem("cid.passcode")
} else {} } else {}
}); });
@@ -2800,6 +2842,7 @@ $(document).on("saveSessionEvent", {}, (evt, review) => {
saveSession(review); saveSession(review);
}); });
// Disable right click
$(document).contextmenu(() => { $(document).contextmenu(() => {
return false; return false;
}) })
+952 -467
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
/*! loglevel - v1.8.1 - https://github.com/pimterry/loglevel - (c) 2022 Tim Perry - licensed MIT */
!function(a,b){"use strict";"function"==typeof define&&define.amd?define(b):"object"==typeof module&&module.exports?module.exports=b():a.log=b()}(this,function(){"use strict";function a(a,b){var c=a[b];if("function"==typeof c.bind)return c.bind(a);try{return Function.prototype.bind.call(c,a)}catch(b){return function(){return Function.prototype.apply.apply(c,[a,arguments])}}}function b(){console.log&&(console.log.apply?console.log.apply(console,arguments):Function.prototype.apply.apply(console.log,[console,arguments])),console.trace&&console.trace()}function c(c){return"debug"===c&&(c="log"),typeof console!==i&&("trace"===c&&j?b:void 0!==console[c]?a(console,c):void 0!==console.log?a(console,"log"):h)}function d(a,b){for(var c=0;c<k.length;c++){var d=k[c];this[d]=c<a?h:this.methodFactory(d,a,b)}this.log=this.debug}function e(a,b,c){return function(){typeof console!==i&&(d.call(this,b,c),this[a].apply(this,arguments))}}function f(a,b,d){return c(a)||e.apply(this,arguments)}function g(a,b,c){function e(a){var b=(k[a]||"silent").toUpperCase();if(typeof window!==i&&m){try{return void(window.localStorage[m]=b)}catch(a){}try{window.document.cookie=encodeURIComponent(m)+"="+b+";"}catch(a){}}}function g(){var a;if(typeof window!==i&&m){try{a=window.localStorage[m]}catch(a){}if(typeof a===i)try{var b=window.document.cookie,c=b.indexOf(encodeURIComponent(m)+"=");-1!==c&&(a=/^([^;]+)/.exec(b.slice(c))[1])}catch(a){}return void 0===l.levels[a]&&(a=void 0),a}}function h(){if(typeof window!==i&&m){try{return void window.localStorage.removeItem(m)}catch(a){}try{window.document.cookie=encodeURIComponent(m)+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC"}catch(a){}}}var j,l=this;b=null==b?"WARN":b;var m="loglevel";"string"==typeof a?m+=":"+a:"symbol"==typeof a&&(m=void 0),l.name=a,l.levels={TRACE:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,SILENT:5},l.methodFactory=c||f,l.getLevel=function(){return j},l.setLevel=function(b,c){if("string"==typeof b&&void 0!==l.levels[b.toUpperCase()]&&(b=l.levels[b.toUpperCase()]),!("number"==typeof b&&b>=0&&b<=l.levels.SILENT))throw"log.setLevel() called with invalid level: "+b;if(j=b,!1!==c&&e(b),d.call(l,b,a),typeof console===i&&b<l.levels.SILENT)return"No console available for logging"},l.setDefaultLevel=function(a){b=a,g()||l.setLevel(a,!1)},l.resetLevel=function(){l.setLevel(b,!1),h()},l.enableAll=function(a){l.setLevel(l.levels.TRACE,a)},l.disableAll=function(a){l.setLevel(l.levels.SILENT,a)};var n=g();null==n&&(n=b),l.setLevel(n,!1)}var h=function(){},i="undefined",j=typeof window!==i&&typeof window.navigator!==i&&/Trident\/|MSIE /.test(window.navigator.userAgent),k=["trace","debug","info","warn","error"],l=new g,m={};l.getLogger=function(a){if("symbol"!=typeof a&&"string"!=typeof a||""===a)throw new TypeError("You must supply a name when creating a logger.");var b=m[a];return b||(b=m[a]=new g(a,l.getLevel(),l.methodFactory)),b};var n=typeof window!==i?window.log:void 0;return l.noConflict=function(){return typeof window!==i&&window.log===l&&(window.log=n),l},l.getLoggers=function(){return m},l.default=l,l});