fix caching system
This commit is contained in:
+35
-1
@@ -831,6 +831,23 @@ select option:disabled {
|
|||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.packet-button.cached:after{
|
||||||
|
content: "cached";
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
color: gray;
|
||||||
|
border-radius: 50%;
|
||||||
|
position:relative;
|
||||||
|
transform: translate(15px, 5.5px) rotate(270deg);
|
||||||
|
display: inline-block;
|
||||||
|
right: 0;
|
||||||
|
font-size: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-button.out-of-date{
|
||||||
|
color: darkslategray
|
||||||
|
}
|
||||||
|
|
||||||
.save-button {
|
.save-button {
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
@@ -1061,4 +1078,21 @@ display: block
|
|||||||
height: 72px;
|
height: 72px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#submit-error-overlay {
|
||||||
|
opacity: 0.9;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: black;
|
||||||
|
width: 100%;
|
||||||
|
user-select: text;
|
||||||
|
-moz-user-select: text;
|
||||||
|
-webkit-user-select: text;
|
||||||
|
z-index: 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cache-out-of-date {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
+8
-1
@@ -64,7 +64,8 @@
|
|||||||
<div id="options-panel" class="fullscreen-overlay">
|
<div id="options-panel" class="fullscreen-overlay">
|
||||||
<a href="#" id="overlay-close" class="close"></a>
|
<a href="#" id="overlay-close" class="close"></a>
|
||||||
<div id="database-buttons">
|
<div id="database-buttons">
|
||||||
<input type='button' id='btn-delete-databases' value='Delete all saved answers'>
|
<input type='button' id='btn-delete-answer-databases' value='Delete all saved answers'>
|
||||||
|
<input type='button' id='btn-delete-cached-questions' value='Delete all cached questions'>
|
||||||
</div>
|
</div>
|
||||||
<div id="packets">
|
<div id="packets">
|
||||||
<p>Available Packets:</p>
|
<p>Available Packets:</p>
|
||||||
@@ -83,6 +84,12 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="storage-details">
|
||||||
|
</div>
|
||||||
|
<div id="cache-details">
|
||||||
|
<ul>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="review-overlay" class="fullscreen-overlay">
|
<div id="review-overlay" class="fullscreen-overlay">
|
||||||
<a href="#" id="review-overlay-close" class="close"></a>
|
<a href="#" id="review-overlay-close" class="close"></a>
|
||||||
|
|||||||
@@ -30,3 +30,35 @@ export function formatBytes(bytes, decimals = 2) {
|
|||||||
|
|
||||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format bytes as human-readable text.
|
||||||
|
*
|
||||||
|
* @param bytes Number of bytes.
|
||||||
|
* @param si True to use metric (SI) units, aka powers of 1000. False to use
|
||||||
|
* binary (IEC), aka powers of 1024.
|
||||||
|
* @param dp Number of decimal places to display.
|
||||||
|
*
|
||||||
|
* @return Formatted string.
|
||||||
|
*/
|
||||||
|
export function humanFileSize(bytes, si=false, dp=1) {
|
||||||
|
const thresh = si ? 1000 : 1024;
|
||||||
|
|
||||||
|
if (Math.abs(bytes) < thresh) {
|
||||||
|
return bytes + ' B';
|
||||||
|
}
|
||||||
|
|
||||||
|
const units = si
|
||||||
|
? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||||
|
: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
||||||
|
let u = -1;
|
||||||
|
const r = 10**dp;
|
||||||
|
|
||||||
|
do {
|
||||||
|
bytes /= thresh;
|
||||||
|
++u;
|
||||||
|
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
|
||||||
|
|
||||||
|
|
||||||
|
return bytes.toFixed(dp) + ' ' + units[u];
|
||||||
|
}
|
||||||
+42
-20
@@ -76,18 +76,18 @@ export function postAnswers(ans, config, exam_details) {
|
|||||||
alert(`${data.question_count} answers sucessfully submitted.`);
|
alert(`${data.question_count} answers sucessfully submitted.`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
submissionError(data, ans);
|
submissionError(data, ans, exam_details);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.fail((e) => {
|
.fail((e) => {
|
||||||
// Will occur with server error such as 500
|
// Will occur with server error such as 500
|
||||||
console.log("error", e);
|
console.log("error", e);
|
||||||
submissionError(e, ans);
|
submissionError(e, ans, exam_details);
|
||||||
});
|
});
|
||||||
// $.post( "http://localhost:8000/submit_answers", JSON.stringify(ans));
|
// $.post( "http://localhost:8000/submit_answers", JSON.stringify(ans));
|
||||||
}
|
}
|
||||||
|
|
||||||
function submissionError(data, ans) {
|
function submissionError(data, answer_json, exam_details) {
|
||||||
// error will not be defined with server errors
|
// error will not be defined with server errors
|
||||||
if (data.error != undefined) {
|
if (data.error != undefined) {
|
||||||
alert(`Error submitting answers: ${data.error}`);
|
alert(`Error submitting answers: ${data.error}`);
|
||||||
@@ -96,26 +96,48 @@ function submissionError(data, ans) {
|
|||||||
}
|
}
|
||||||
var docHeight = $(document).height();
|
var docHeight = $(document).height();
|
||||||
|
|
||||||
$("body").append(
|
let answers = JSON.parse(answer_json.answers)
|
||||||
`<div id='submit-error-overlay'><span style='color: white'><p>An error has occured when submit your answers. A copy of your answers are displayed below, you may wish to save a copy. Please try submitting again or refresh this page to continue.</p>${JSON.stringify(
|
|
||||||
ans
|
|
||||||
)}</span></div>`
|
|
||||||
);
|
|
||||||
|
|
||||||
$("#nav-submit-button").prependTo("#submit-error-overlay");
|
let answer_map = {}
|
||||||
|
|
||||||
$("#submit-error-overlay").height(docHeight).css({
|
answers.forEach((ans, n) => {
|
||||||
opacity: 0.9,
|
if (!answer_map.hasOwnProperty(ans.qid)) {
|
||||||
position: "absolute",
|
answer_map[ans.qid] = [];
|
||||||
top: 0,
|
}
|
||||||
left: 0,
|
|
||||||
"background-color": "black",
|
answer_map[ans.qid].push(ans);
|
||||||
width: "100%",
|
|
||||||
"user-select": "text",
|
|
||||||
"-moz-user-select": "text",
|
|
||||||
"-webkit-user-select": "text",
|
|
||||||
"z-index": 5000,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let html = $("<ul></ul>");
|
||||||
|
|
||||||
|
exam_details.question_order.forEach((i, j) => {
|
||||||
|
console.log(i, answer_map)
|
||||||
|
if (i in answer_map) {
|
||||||
|
console.log("YES", i, answer_map)
|
||||||
|
let ans_array = answer_map[i];
|
||||||
|
ans_array.forEach((x, y) => {
|
||||||
|
$(html).append(`<li><b>Question ${j+1}.${y}:</b> ${x.ans}</li>`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(exam_details.question_order);
|
||||||
|
console.log(answer_map);
|
||||||
|
console.log(html);
|
||||||
|
|
||||||
|
if ($("#submit-error-overlay").length < 1) {
|
||||||
|
$("body").append(
|
||||||
|
`<div id='submit-error-overlay'><span style='color: white'><p>An error has occured when submit your answers. A copy of your answers are displayed below, you may wish to save a copy. Please try submitting again or refresh this page to continue.</p><p>${html.get(0).innerHTML}</p><p>${JSON.stringify(
|
||||||
|
answer_json
|
||||||
|
)}</p></span></div>`
|
||||||
|
);
|
||||||
|
|
||||||
|
$("#nav-submit-button").prependTo("#submit-error-overlay");
|
||||||
|
|
||||||
|
$("#submit-error-overlay").height(docHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getQuestion(url, question_number, question_total) {
|
export function getQuestion(url, question_number, question_total) {
|
||||||
|
|||||||
+360
-201
@@ -5,26 +5,18 @@ 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');
|
||||||
|
|
||||||
// cid = null;
|
|
||||||
//window.aid = null;
|
|
||||||
//window.cid = "";
|
|
||||||
//window.eid = 5678;
|
|
||||||
|
|
||||||
let exam_details = {
|
let exam_details = {
|
||||||
aid: null,
|
aid: null,
|
||||||
cid: "",
|
cid: "",
|
||||||
eid: 5678,
|
eid: 5678,
|
||||||
exam_mode: false,
|
exam_mode: false,
|
||||||
number_of_questions: null,
|
number_of_questions: null,
|
||||||
|
question_order: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
//window.exam_mode = false;
|
|
||||||
|
|
||||||
let packet_list = [];
|
let packet_list = [];
|
||||||
let packet_name = null;
|
let packet_name = null;
|
||||||
//window.questions = null;
|
|
||||||
let questions = null;
|
let questions = null;
|
||||||
let question_order = [];
|
|
||||||
let questions_correct = {};
|
let questions_correct = {};
|
||||||
let question_type = null;
|
let question_type = null;
|
||||||
let loaded_question = null;
|
let loaded_question = null;
|
||||||
@@ -41,10 +33,6 @@ let timer = null;
|
|||||||
|
|
||||||
let use_local_question_cache = false;
|
let use_local_question_cache = false;
|
||||||
|
|
||||||
//window.dfile = null;
|
|
||||||
|
|
||||||
//config = config;
|
|
||||||
|
|
||||||
cornerstone.imageCache.setMaximumSizeBytes(5128800);
|
cornerstone.imageCache.setMaximumSizeBytes(5128800);
|
||||||
|
|
||||||
// Set up cornerstone (the dicom viewer)
|
// Set up cornerstone (the dicom viewer)
|
||||||
@@ -80,12 +68,14 @@ db.version(1).stores({
|
|||||||
|
|
||||||
const question_db = new Dexie("question_database");
|
const question_db = new Dexie("question_database");
|
||||||
question_db.version(1).stores({
|
question_db.version(1).stores({
|
||||||
question_data: "[eid+qid], eid",
|
question_data: "&[qid+type], qid, type",
|
||||||
saved_exams: "eid, type, exam_mode, name, order, time, generated",
|
saved_exams: "&eid, type, exam_mode, name, order, time, generated",
|
||||||
});
|
});
|
||||||
|
|
||||||
retrievePacketList();
|
retrievePacketList();
|
||||||
|
|
||||||
|
refreshDatabaseSettings();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a list of available packets via JSON ajax requests
|
* Retrieves a list of available packets via JSON ajax requests
|
||||||
* Will initially try /packets/ (for example if index.php generates the list)
|
* Will initially try /packets/ (for example if index.php generates the list)
|
||||||
@@ -123,9 +113,6 @@ function retrievePacketList() {
|
|||||||
loadPacketList(data);
|
loadPacketList(data);
|
||||||
}
|
}
|
||||||
}).fail(function (jqXHR, textStatus, errorThrown) {
|
}).fail(function (jqXHR, textStatus, errorThrown) {
|
||||||
//console.log(jqXHR);
|
|
||||||
//console.log(textStatus);
|
|
||||||
//console.log(errorThrown);
|
|
||||||
console.log("No packet list available");
|
console.log("No packet list available");
|
||||||
showLoginDialog();
|
showLoginDialog();
|
||||||
});
|
});
|
||||||
@@ -154,9 +141,7 @@ async function loadExamList(data) {
|
|||||||
$("#database-error").append(delete_button);
|
$("#database-error").append(delete_button);
|
||||||
$("#database-error").show();
|
$("#database-error").show();
|
||||||
});
|
});
|
||||||
// db.session
|
|
||||||
// .where("packet")
|
|
||||||
// .equals()
|
|
||||||
let exams_started = [];
|
let exams_started = [];
|
||||||
let exams_completed = [];
|
let exams_completed = [];
|
||||||
sessions.forEach((s) => {
|
sessions.forEach((s) => {
|
||||||
@@ -167,15 +152,26 @@ async function loadExamList(data) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let exam_list = [];
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
window.exam_list = data.exams;
|
exam_list = data.exams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let exam_generated_map = {};
|
||||||
$("#packet-list").empty();
|
$("#packet-list").empty();
|
||||||
window.exam_list.forEach(function (exam) {
|
exam_list.forEach(function (exam) {
|
||||||
let name = exam["name"];
|
let name = exam["name"];
|
||||||
let url = exam["url"];
|
let url = exam["url"];
|
||||||
let eid = exam["eid"];
|
let eid = exam["eid"];
|
||||||
let generated = exam["json_creation_time"];
|
let generated = exam["json_creation_time"];
|
||||||
|
|
||||||
|
let question_timestamp_hash = {};
|
||||||
|
|
||||||
|
if (exam.hasOwnProperty("multi_question_json")) {
|
||||||
|
question_timestamp_hash = exam["multi_question_json"];
|
||||||
|
}
|
||||||
|
exam_generated_map[eid] = [generated, question_timestamp_hash];
|
||||||
|
|
||||||
let c = "";
|
let c = "";
|
||||||
if (exams_started.indexOf(name) > -1) {
|
if (exams_started.indexOf(name) > -1) {
|
||||||
c = " session-started";
|
c = " session-started";
|
||||||
@@ -198,7 +194,9 @@ async function loadExamList(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
list.append(
|
list.append(
|
||||||
$(`<div class='packet-button${c}' title='Load packet'></div>`)
|
$(
|
||||||
|
`<div class='packet-button${c}' data-eid='${eid}' title='Load packet'></div>`
|
||||||
|
)
|
||||||
.text(name)
|
.text(name)
|
||||||
.click(function () {
|
.click(function () {
|
||||||
loadPacketFromAjax(url, eid, generated);
|
loadPacketFromAjax(url, eid, generated);
|
||||||
@@ -214,6 +212,81 @@ async function loadExamList(data) {
|
|||||||
`<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>`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the database for exams that have been saved
|
||||||
|
question_db.saved_exams.toArray().then((saved_exams) => {
|
||||||
|
saved_exams.forEach((saved_exam, n) => {
|
||||||
|
$("#cache-details ul").append(
|
||||||
|
`<li class="cache-item" data-eid=${saved_exam.eid}>Exam: ${saved_exam.exam_name} [${saved_exam.eid}]: ${saved_exam.generated}`
|
||||||
|
);
|
||||||
|
//Compared saved exams to those available
|
||||||
|
if (exam_generated_map.hasOwnProperty(saved_exam.eid)) {
|
||||||
|
// If the timestamps differ delete and force a refresh
|
||||||
|
const exam_timestamp = exam_generated_map[saved_exam.eid][0];
|
||||||
|
const question_timestamp_hash = exam_generated_map[saved_exam.eid][1];
|
||||||
|
if (Date.parse(saved_exam.generated) != Date.parse(exam_timestamp)) {
|
||||||
|
question_db.saved_exams.where("eid").equals(saved_exam.eid).delete();
|
||||||
|
|
||||||
|
$(`li.cache-item[data-eid="${saved_exam.eid}"]`).addClass(
|
||||||
|
"cache-out-of-date"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$(`.packet-button[data-eid="${saved_exam.eid}"]`).addClass("cached");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let q in question_timestamp_hash) {
|
||||||
|
let new_timestamp = question_timestamp_hash[q];
|
||||||
|
q = q.toString();
|
||||||
|
$("#cache-details ul").append(
|
||||||
|
`<li class="cache-item" data-qid=${q}>Question (${saved_exam.exam_type}): ${q}`
|
||||||
|
);
|
||||||
|
// If a single question is out of date we invalidate the lot...
|
||||||
|
const q_object = { qid: q, type: saved_exam.exam_type };
|
||||||
|
question_db.question_data
|
||||||
|
.get(q_object)
|
||||||
|
.then((d) => {
|
||||||
|
// d is undefined if the question is not saved
|
||||||
|
// we should really just requeue the required question for dowload...
|
||||||
|
if (
|
||||||
|
d == undefined ||
|
||||||
|
Date.parse(d.data.generated) != Date.parse(new_timestamp)
|
||||||
|
) {
|
||||||
|
$(`li.cache-item[data-eid="${saved_exam.eid}"]`).addClass(
|
||||||
|
"cache-out-of-date"
|
||||||
|
);
|
||||||
|
$(`li.cache-item[data-qid="${q}"]`).addClass(
|
||||||
|
"cache-out-of-date"
|
||||||
|
);
|
||||||
|
$(`.packet-button[data-eid="${saved_exam.eid}"]`).addClass(
|
||||||
|
"out-of-date"
|
||||||
|
);
|
||||||
|
|
||||||
|
//question_db.saved_exams.where("eid").equals(saved_exam.eid).delete();
|
||||||
|
question_db.question_data.where(["qid", "type"]).equals([q, saved_exam.exam_type]).delete();
|
||||||
|
}
|
||||||
|
d = null;
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
// If the question isn't found in the cache...
|
||||||
|
$(`li.cache-item[data-eid="${saved_exam.eid}"]`).addClass(
|
||||||
|
"cache-out-of-date"
|
||||||
|
);
|
||||||
|
$(`li.cache-item[data-qid="${q}"]`)
|
||||||
|
.addClass("cache-out-of-date")
|
||||||
|
.append("[Not found]");
|
||||||
|
$(`.packet-button[data-eid="${saved_exam.eid}"]`).addClass(
|
||||||
|
"out-of-date"
|
||||||
|
);
|
||||||
|
|
||||||
|
//question_db.saved_exams.where("eid").equals(saved_exam.eid).delete();
|
||||||
|
question_db.question_data.where(["qid", "type"]).equals([q, saved_exam.exam_type]).delete();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$("#options-panel").show();
|
$("#options-panel").show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,9 +384,8 @@ function loadPacketFromAjax(path, eid, generated) {
|
|||||||
exam == undefined ||
|
exam == undefined ||
|
||||||
Date.parse(exam["generated"]) != Date.parse(generated)
|
Date.parse(exam["generated"]) != Date.parse(generated)
|
||||||
) {
|
) {
|
||||||
ajaxRequestionPacket();
|
ajaxRequestionPacket(true);
|
||||||
} else {
|
} else {
|
||||||
console.log(exam);
|
|
||||||
// We have an up to date exam in the database
|
// We have an up to date exam in the database
|
||||||
// TODO: check the questions are valid
|
// TODO: check the questions are valid
|
||||||
use_local_question_cache = true;
|
use_local_question_cache = true;
|
||||||
@@ -332,14 +404,19 @@ function loadPacketFromAjax(path, eid, generated) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ajaxRequestionPacket() {
|
function ajaxRequestionPacket(force_refresh) {
|
||||||
//console.log("loading packet from " + path);
|
//console.log("loading packet from " + path);
|
||||||
$("#progress").html(`Requesting packet: ${path}`);
|
$("#progress").html(`Requesting packet: ${path}`);
|
||||||
|
|
||||||
|
let browser_cache = true;
|
||||||
|
if (force_refresh) {
|
||||||
|
browser_cache = false;
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
url: path,
|
url: path,
|
||||||
cache: true,
|
cache: browser_cache,
|
||||||
progress: function (e) {
|
progress: function (e) {
|
||||||
if (e.lengthComputable) {
|
if (e.lengthComputable) {
|
||||||
var completedPercentage = Math.round((e.loaded * 100) / e.total);
|
var completedPercentage = Math.round((e.loaded * 100) / e.total);
|
||||||
@@ -360,109 +437,6 @@ function loadPacketFromAjax(path, eid, generated) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the currently loaded quiz
|
|
||||||
*/
|
|
||||||
function setUpQuestions(load_previous) {
|
|
||||||
if (questions == undefined) {
|
|
||||||
//return;
|
|
||||||
} else {
|
|
||||||
if (!use_local_question_cache) {
|
|
||||||
Object.keys(questions).forEach(function (e) {
|
|
||||||
// Store question data into dexie
|
|
||||||
let d = {
|
|
||||||
eid: exam_details.eid,
|
|
||||||
qid: e,
|
|
||||||
data: questions[e],
|
|
||||||
};
|
|
||||||
|
|
||||||
question_db.question_data.put(d);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set an order for the questions
|
|
||||||
if (!load_previous) {
|
|
||||||
if (question_order.length < 1) {
|
|
||||||
question_order = [];
|
|
||||||
Object.keys(questions).forEach(function (e) {
|
|
||||||
question_order.push(e);
|
|
||||||
|
|
||||||
// Make sure answers are arrays
|
|
||||||
if (!Array.isArray(questions[e]["answers"])) {
|
|
||||||
questions[e]["answers"] = [questions[e]["answers"]];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let randomise_order = true;
|
|
||||||
if (config.randomise_order != undefined) {
|
|
||||||
randomise_order = config.randomise_order;
|
|
||||||
}
|
|
||||||
if (randomise_order) {
|
|
||||||
question_order = helper.shuffleArray(question_order);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exam_details.number_of_questions = question_order.length;
|
|
||||||
review_mode = false;
|
|
||||||
|
|
||||||
// Horrible way to get type of questions
|
|
||||||
// We assume they are all of the same type....
|
|
||||||
//question_type = questions[Object.keys(questions)[0]].type;
|
|
||||||
|
|
||||||
if (exam_details.exam_mode) {
|
|
||||||
$("#options-button, #review-overlay-button").hide();
|
|
||||||
} else {
|
|
||||||
$("#submit-button").hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
questions = null;
|
|
||||||
|
|
||||||
//console.log(question_type);
|
|
||||||
|
|
||||||
// exam_time can be defined in packets
|
|
||||||
if (!load_previous && exam_time == null) {
|
|
||||||
if (question_type == "rapid") {
|
|
||||||
exam_time = 35 * 60;
|
|
||||||
} else if (question_type == "anatomy") {
|
|
||||||
exam_time = 90 * 60;
|
|
||||||
} else if (question_type == "long") {
|
|
||||||
exam_time = 75 * 60;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$(".exam-time")
|
|
||||||
.val(exam_time / 60)
|
|
||||||
.change(() => {
|
|
||||||
exam_time = $(".exam-time").val() * 60;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (exam_details.exam_mode) {
|
|
||||||
// NOTE: changing the CID when restoring a session will not affect the time left
|
|
||||||
$("#candidate-number2")
|
|
||||||
.val(exam_details.cid)
|
|
||||||
.change(() => {
|
|
||||||
exam_details.cid = parseInt($("#candidate-number2").val());
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#start-dialog").addClass("no-close");
|
|
||||||
$("#start-dialog .exam-time").prop("disabled", "true");
|
|
||||||
$("#exam-candidate-number").show();
|
|
||||||
$(".packet-database-options").hide();
|
|
||||||
$("#start-dialog").modal({
|
|
||||||
closeExisting: false, // Close existing modals. Set this to false if you need to stack multiple modal instances.
|
|
||||||
escapeClose: false, // Allows the user to close the modal by pressing `ESC`
|
|
||||||
clickClose: false, // Allows the user to close the modal by clicking the overlay
|
|
||||||
showClose: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$("#start-dialog").modal();
|
|
||||||
}
|
|
||||||
|
|
||||||
loadQuestion(0, 1, true);
|
|
||||||
createQuestionListPanel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the packet and extract metadata (if it exists)
|
* Parse the packet and extract metadata (if it exists)
|
||||||
* Will then call setUpQuestions() to load the packet
|
* Will then call setUpQuestions() to load the packet
|
||||||
@@ -499,7 +473,30 @@ function setUpPacket(data, path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.hasOwnProperty("exam_order")) {
|
if (data.hasOwnProperty("exam_order")) {
|
||||||
question_order = data.exam_order;
|
exam_details.question_order = data.exam_order;
|
||||||
|
} else {
|
||||||
|
exam_details.question_order = [];
|
||||||
|
Object.keys(questions).forEach(function (e) {
|
||||||
|
exam_details.question_order.push(e);
|
||||||
|
|
||||||
|
// Make sure answers are arrays
|
||||||
|
if (!Array.isArray(questions[e]["answers"])) {
|
||||||
|
questions[e]["answers"] = [questions[e]["answers"]];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let randomise_order = true;
|
||||||
|
if (config.randomise_order != undefined) {
|
||||||
|
randomise_order = config.randomise_order;
|
||||||
|
}
|
||||||
|
if (randomise_order) {
|
||||||
|
exam_details.question_order = helper.shuffleArray(
|
||||||
|
exam_details.question_order
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// We add this here so the question order is maintained
|
||||||
|
// when loading from cache
|
||||||
|
data["exam_order"] = exam_details.question_order
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.hasOwnProperty("exam_time")) {
|
if (data.hasOwnProperty("exam_time")) {
|
||||||
@@ -508,19 +505,33 @@ function setUpPacket(data, path) {
|
|||||||
packet_time = data.exam_time;
|
packet_time = data.exam_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_local_question_cache) {
|
//if (use_local_question_cache && force_question_refresh.length < 1) {
|
||||||
// If loading form cache nothing else to do here
|
// // If loading form cache nothing else to do here
|
||||||
loadSession();
|
// loadSession();
|
||||||
return;
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (!use_local_question_cache) {
|
||||||
|
// Save the details to the question database
|
||||||
|
var clone_data = Object.assign({}, data, { questions: "cached" });
|
||||||
|
//clone_data["cached_questions"] = Object.keys(data["questions"]);
|
||||||
|
question_db.saved_exams.put(clone_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the details to the question database
|
// If question_requests is set we need to do a request for each question
|
||||||
var clone_data = Object.assign({}, data, { questions: undefined });
|
if (data.hasOwnProperty("question_requests") && (Object.keys(data["question_requests"]).length > 0)) {
|
||||||
question_db.saved_exams.put(clone_data);
|
// Will happen if loading from cache
|
||||||
|
//if (data["questions"] == "cached") {
|
||||||
// If the question_requests is set we need to do a request for each question
|
// let a = {};
|
||||||
if (data.hasOwnProperty("question_requests") && data["question_requests"]) {
|
// data["cached_questions"].forEach((q, n) => {
|
||||||
const question_total = Object.keys(data["questions"]).length;
|
// let s = JSON.stringify()
|
||||||
|
// if (force_question_refresh.includes(s)) {
|
||||||
|
// a[q] = 1;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// data["questions"] = a;
|
||||||
|
//}
|
||||||
|
let question_total = Object.keys(data["question_requests"]).length;
|
||||||
let question_number = 0;
|
let question_number = 0;
|
||||||
|
|
||||||
var requests = [];
|
var requests = [];
|
||||||
@@ -528,10 +539,18 @@ function setUpPacket(data, path) {
|
|||||||
|
|
||||||
// For loop to generate requests
|
// For loop to generate requests
|
||||||
(async () => {
|
(async () => {
|
||||||
for (const n in data["questions"]) {
|
for (const n in data["question_requests"]) {
|
||||||
const question_url = `${path}/${n}`;
|
|
||||||
question_number++;
|
question_number++;
|
||||||
|
|
||||||
|
let obj = {qid: n, type: question_type};
|
||||||
|
let question_in_db = await question_db.question_data.get(obj);
|
||||||
|
|
||||||
|
// If the question is in the db we can load
|
||||||
|
// invalid questions should have already been removed
|
||||||
|
if (question_in_db != undefined) {continue}
|
||||||
|
|
||||||
|
const question_url = `${path}/${n}`;
|
||||||
|
|
||||||
//console.log("Creating ", question_url, question_number, question_total);
|
//console.log("Creating ", question_url, question_number, question_total);
|
||||||
//$("#progress").html(`Downloading [${question_number}/${question_total}]`);
|
//$("#progress").html(`Downloading [${question_number}/${question_total}]`);
|
||||||
let question_json = {};
|
let question_json = {};
|
||||||
@@ -539,8 +558,8 @@ function setUpPacket(data, path) {
|
|||||||
.getQuestion(question_url, question_number, question_total)
|
.getQuestion(question_url, question_number, question_total)
|
||||||
.fail((jqXHR, textStatus, errorThrown) => {
|
.fail((jqXHR, textStatus, errorThrown) => {
|
||||||
//console.log(jqXHR, textStatus, errorThrown);
|
//console.log(jqXHR, textStatus, errorThrown);
|
||||||
console.log("error loading question");
|
console.log(`error loading question: ${n}`);
|
||||||
data["questions"][n] = {};
|
//data["questions"][n] = {};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (question_json.hasOwnProperty("cached") && question_json["cached"]) {
|
if (question_json.hasOwnProperty("cached") && question_json["cached"]) {
|
||||||
@@ -561,17 +580,21 @@ function setUpPacket(data, path) {
|
|||||||
|
|
||||||
// Store question data into dexie
|
// Store question data into dexie
|
||||||
let d = {
|
let d = {
|
||||||
eid: exam_details.eid,
|
//eid: exam_details.eid,
|
||||||
qid: n,
|
qid: n,
|
||||||
data: question_json,
|
data: question_json,
|
||||||
|
type: question_json.type,
|
||||||
};
|
};
|
||||||
|
|
||||||
question_db.question_data.put(d);
|
question_db.question_data.put(d);
|
||||||
use_local_question_cache = true;
|
|
||||||
}
|
}
|
||||||
// Once all questions have been downloaded we carry on loading
|
// Once all questions have been downloaded we carry on loading
|
||||||
|
use_local_question_cache = true;
|
||||||
loadSession();
|
loadSession();
|
||||||
})();
|
})().catch((error) => {
|
||||||
|
alert("Error downloading, try refreshing");
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// Just carry on loading
|
// Just carry on loading
|
||||||
loadSession();
|
loadSession();
|
||||||
@@ -579,7 +602,7 @@ function setUpPacket(data, path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadSession() {
|
function loadSession() {
|
||||||
//console.log("load session");
|
console.log("load session", exam_details, db.session);
|
||||||
// Either continue session or create a new one
|
// Either continue session or create a new one
|
||||||
db.session
|
db.session
|
||||||
// .where("status")
|
// .where("status")
|
||||||
@@ -655,7 +678,7 @@ function loadSession() {
|
|||||||
|
|
||||||
exam_time = time_left;
|
exam_time = time_left;
|
||||||
|
|
||||||
question_order = sessions[parseInt(s)].question_order;
|
exam_details.question_order = sessions[parseInt(s)].question_order;
|
||||||
|
|
||||||
if (sessions[parseInt(s)].status == "complete") {
|
if (sessions[parseInt(s)].status == "complete") {
|
||||||
review_mode = true;
|
review_mode = true;
|
||||||
@@ -672,6 +695,90 @@ function loadSession() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the currently loaded quiz
|
||||||
|
*/
|
||||||
|
function setUpQuestions(load_previous) {
|
||||||
|
if (questions == undefined) {
|
||||||
|
//return;
|
||||||
|
} else {
|
||||||
|
if (!use_local_question_cache) {
|
||||||
|
Object.keys(questions).forEach(function (e) {
|
||||||
|
// Store question data into dexie
|
||||||
|
let d = {
|
||||||
|
//eid: exam_details.eid,
|
||||||
|
qid: e,
|
||||||
|
type: questions[e].type,
|
||||||
|
data: questions[e],
|
||||||
|
//timestamp: questions[e]["generated"],
|
||||||
|
};
|
||||||
|
|
||||||
|
question_db.question_data.put(d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set an order for the questions
|
||||||
|
if (!load_previous) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exam_details.number_of_questions = exam_details.question_order.length;
|
||||||
|
review_mode = false;
|
||||||
|
|
||||||
|
// Horrible way to get type of questions
|
||||||
|
// We assume they are all of the same type....
|
||||||
|
//question_type = questions[Object.keys(questions)[0]].type;
|
||||||
|
|
||||||
|
if (exam_details.exam_mode) {
|
||||||
|
$("#options-button, #review-overlay-button").hide();
|
||||||
|
} else {
|
||||||
|
$("#submit-button").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
questions = null;
|
||||||
|
|
||||||
|
// exam_time can be defined in packets
|
||||||
|
if (!load_previous && exam_time == null) {
|
||||||
|
if (question_type == "rapid") {
|
||||||
|
exam_time = 35 * 60;
|
||||||
|
} else if (question_type == "anatomy") {
|
||||||
|
exam_time = 90 * 60;
|
||||||
|
} else if (question_type == "long") {
|
||||||
|
exam_time = 75 * 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(".exam-time")
|
||||||
|
.val(exam_time / 60)
|
||||||
|
.change(() => {
|
||||||
|
exam_time = $(".exam-time").val() * 60;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exam_details.exam_mode) {
|
||||||
|
// NOTE: changing the CID when restoring a session will not affect the time left
|
||||||
|
$("#candidate-number2")
|
||||||
|
.val(exam_details.cid)
|
||||||
|
.change(() => {
|
||||||
|
exam_details.cid = parseInt($("#candidate-number2").val());
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#start-dialog").addClass("no-close");
|
||||||
|
$("#start-dialog .exam-time").prop("disabled", "true");
|
||||||
|
$("#exam-candidate-number").show();
|
||||||
|
$(".packet-database-options").hide();
|
||||||
|
$("#start-dialog").modal({
|
||||||
|
closeExisting: false, // Close existing modals. Set this to false if you need to stack multiple modal instances.
|
||||||
|
escapeClose: false, // Allows the user to close the modal by pressing `ESC`
|
||||||
|
clickClose: false, // Allows the user to close the modal by clicking the overlay
|
||||||
|
showClose: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$("#start-dialog").modal();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadQuestion(0, 1, true);
|
||||||
|
createQuestionListPanel();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a specific question
|
* Loads a specific question
|
||||||
* @param {number} n - Question number to load
|
* @param {number} n - Question number to load
|
||||||
@@ -688,16 +795,6 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
n = parseInt(n);
|
n = parseInt(n);
|
||||||
//console.log("loading question (n)", n);
|
//console.log("loading question (n)", n);
|
||||||
|
|
||||||
const qid = question_order[n];
|
|
||||||
|
|
||||||
let q = { qid: qid.toString(), eid: eid };
|
|
||||||
|
|
||||||
let return_data = await question_db.question_data.get(q);
|
|
||||||
const question_data = return_data.data;
|
|
||||||
return_data = null;
|
|
||||||
|
|
||||||
//const current_question = window.questions[qid];
|
|
||||||
|
|
||||||
if (n == loaded_question && force_reload == false) {
|
if (n == loaded_question && force_reload == false) {
|
||||||
// Question already loaded
|
// Question already loaded
|
||||||
setFocus(section);
|
setFocus(section);
|
||||||
@@ -705,6 +802,15 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const qid = exam_details.question_order[n];
|
||||||
|
|
||||||
|
let q = { qid: qid.toString(), type: question_type };
|
||||||
|
|
||||||
|
let return_data = await question_db.question_data.get(q);
|
||||||
|
const question_data = return_data.data;
|
||||||
|
return_data = null;
|
||||||
|
|
||||||
|
|
||||||
loaded_question = n;
|
loaded_question = n;
|
||||||
|
|
||||||
// Set up question navigation
|
// Set up question navigation
|
||||||
@@ -897,7 +1003,9 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
if (evt.target.value.length < 1) {
|
if (evt.target.value.length < 1) {
|
||||||
db.answers.delete([aid, cid, eid, qid, "2"]);
|
db.answers.delete([aid, cid, eid, qid, "2"]);
|
||||||
$(
|
$(
|
||||||
"#question-list-item-" + question_order.indexOf(qid) + "-2"
|
"#question-list-item-" +
|
||||||
|
exam_details.question_order.indexOf(qid) +
|
||||||
|
"-2"
|
||||||
).removeClass("question-saved-localdb");
|
).removeClass("question-saved-localdb");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -913,9 +1021,11 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
// db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value});
|
// db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value});
|
||||||
db.answers.put(answer);
|
db.answers.put(answer);
|
||||||
|
|
||||||
$("#question-list-item-" + question_order.indexOf(qid) + "-2").addClass(
|
$(
|
||||||
"question-saved-localdb"
|
"#question-list-item-" +
|
||||||
);
|
exam_details.question_order.indexOf(qid) +
|
||||||
|
"-2"
|
||||||
|
).addClass("question-saved-localdb");
|
||||||
|
|
||||||
saveSession();
|
saveSession();
|
||||||
updateQuestionListPanel(answer);
|
updateQuestionListPanel(answer);
|
||||||
@@ -979,7 +1089,9 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
if (evt.target.value.length < 1) {
|
if (evt.target.value.length < 1) {
|
||||||
db.answers.delete([aid, cid, eid, qid, "1"]);
|
db.answers.delete([aid, cid, eid, qid, "1"]);
|
||||||
$(
|
$(
|
||||||
"#question-list-item-" + question_order.indexOf(qid) + "-1"
|
"#question-list-item-" +
|
||||||
|
exam_details.question_order.indexOf(qid) +
|
||||||
|
"-1"
|
||||||
).removeClass("question-saved-localdb");
|
).removeClass("question-saved-localdb");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -995,9 +1107,11 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
// db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value});
|
// db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value});
|
||||||
db.answers.put(answer);
|
db.answers.put(answer);
|
||||||
|
|
||||||
$("#question-list-item-" + question_order.indexOf(qid) + "-1").addClass(
|
$(
|
||||||
"question-saved-localdb"
|
"#question-list-item-" +
|
||||||
);
|
exam_details.question_order.indexOf(qid) +
|
||||||
|
"-1"
|
||||||
|
).addClass("question-saved-localdb");
|
||||||
saveSession();
|
saveSession();
|
||||||
updateQuestionListPanel(answer);
|
updateQuestionListPanel(answer);
|
||||||
});
|
});
|
||||||
@@ -1065,7 +1179,10 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
if (evt.target.value.length < 1) {
|
if (evt.target.value.length < 1) {
|
||||||
db.answers.delete([aid, cid, eid, qid, qidn]);
|
db.answers.delete([aid, cid, eid, qid, qidn]);
|
||||||
$(
|
$(
|
||||||
"#question-list-item-" + question_order.indexOf(qid) + "-" + qidn
|
"#question-list-item-" +
|
||||||
|
exam_details.question_order.indexOf(qid) +
|
||||||
|
"-" +
|
||||||
|
qidn
|
||||||
).removeClass("question-saved-localdb");
|
).removeClass("question-saved-localdb");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1080,10 +1197,12 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
db.answers.put(answer);
|
db.answers.put(answer);
|
||||||
console.log("SAVE", qid, qidn, evt.target.value);
|
|
||||||
|
|
||||||
$(
|
$(
|
||||||
"#question-list-item-" + question_order.indexOf(qid) + "-" + qidn
|
"#question-list-item-" +
|
||||||
|
exam_details.question_order.indexOf(qid) +
|
||||||
|
"-" +
|
||||||
|
qidn
|
||||||
).addClass("question-saved-localdb");
|
).addClass("question-saved-localdb");
|
||||||
saveSession();
|
saveSession();
|
||||||
updateQuestionListPanel(answer);
|
updateQuestionListPanel(answer);
|
||||||
@@ -1094,14 +1213,15 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
//
|
//
|
||||||
|
|
||||||
for (let qidn_count = 1; qidn_count < 6; qidn_count++) {
|
for (let qidn_count = 1; qidn_count < 6; qidn_count++) {
|
||||||
db.answers
|
let obj = {
|
||||||
.get({
|
|
||||||
aid: aid,
|
aid: aid,
|
||||||
cid: cid,
|
cid: cid,
|
||||||
eid: eid,
|
eid: eid,
|
||||||
qid: qid,
|
qid: qid,
|
||||||
qidn: qidn_count.toString(),
|
qidn: qidn_count.toString(),
|
||||||
})
|
}
|
||||||
|
db.answers
|
||||||
|
.get(obj)
|
||||||
.then(function (answer) {
|
.then(function (answer) {
|
||||||
if (answer != undefined) {
|
if (answer != undefined) {
|
||||||
$(".long-answer")
|
$(".long-answer")
|
||||||
@@ -1165,22 +1285,24 @@ function setFocus(section) {
|
|||||||
function updateQuestionListPanel(answer) {
|
function updateQuestionListPanel(answer) {
|
||||||
$(
|
$(
|
||||||
"#question-list-item-" +
|
"#question-list-item-" +
|
||||||
question_order.indexOf(answer.qid) +
|
exam_details.question_order.indexOf(answer.qid) +
|
||||||
"-" +
|
"-" +
|
||||||
answer.qidn
|
answer.qidn
|
||||||
).addClass("question-saved-localdb");
|
).addClass("question-saved-localdb");
|
||||||
|
|
||||||
if (question_type == "rapid" && answer.qidn == "1") {
|
if (question_type == "rapid" && answer.qidn == "1") {
|
||||||
if (answer.ans == "Abnormal") {
|
if (answer.ans == "Abnormal") {
|
||||||
$("#question-list-item-" + question_order.indexOf(answer.qid) + "-2").css(
|
$(
|
||||||
"display",
|
"#question-list-item-" +
|
||||||
"block"
|
exam_details.question_order.indexOf(answer.qid) +
|
||||||
);
|
"-2"
|
||||||
|
).css("display", "block");
|
||||||
} else {
|
} else {
|
||||||
$("#question-list-item-" + question_order.indexOf(answer.qid) + "-2").css(
|
$(
|
||||||
"display",
|
"#question-list-item-" +
|
||||||
"none"
|
exam_details.question_order.indexOf(answer.qid) +
|
||||||
);
|
"-2"
|
||||||
|
).css("display", "none");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1188,7 +1310,7 @@ function updateQuestionListPanel(answer) {
|
|||||||
function deleteQuestionListPanelFlags(answer) {
|
function deleteQuestionListPanelFlags(answer) {
|
||||||
$(
|
$(
|
||||||
"#question-list-item-" +
|
"#question-list-item-" +
|
||||||
question_order.indexOf(answer.qid) +
|
exam_details.question_order.indexOf(answer.qid) +
|
||||||
"-" +
|
"-" +
|
||||||
answer.qidn +
|
answer.qidn +
|
||||||
" span"
|
" span"
|
||||||
@@ -1198,7 +1320,7 @@ function deleteQuestionListPanelFlags(answer) {
|
|||||||
function updateQuestionListPanelFlags(answer) {
|
function updateQuestionListPanelFlags(answer) {
|
||||||
$(
|
$(
|
||||||
"#question-list-item-" +
|
"#question-list-item-" +
|
||||||
question_order.indexOf(answer.qid) +
|
exam_details.question_order.indexOf(answer.qid) +
|
||||||
"-" +
|
"-" +
|
||||||
answer.qidn +
|
answer.qidn +
|
||||||
" span"
|
" span"
|
||||||
@@ -1214,7 +1336,6 @@ function rebuildQuestionListPanel() {
|
|||||||
const cid = exam_details.cid;
|
const cid = exam_details.cid;
|
||||||
const eid = exam_details.eid;
|
const eid = exam_details.eid;
|
||||||
|
|
||||||
//console.log("UP");
|
|
||||||
db.answers
|
db.answers
|
||||||
.where({ aid: aid, cid: cid, eid: eid })
|
.where({ aid: aid, cid: cid, eid: eid })
|
||||||
.toArray()
|
.toArray()
|
||||||
@@ -1250,7 +1371,7 @@ function rebuildQuestionListPanel() {
|
|||||||
if (review_mode == true) {
|
if (review_mode == true) {
|
||||||
$(".question-panel-ans").remove();
|
$(".question-panel-ans").remove();
|
||||||
for (const qid in questions_correct) {
|
for (const qid in questions_correct) {
|
||||||
let q_no = question_order.indexOf(qid);
|
let q_no = exam_details.question_order.indexOf(qid);
|
||||||
//console.log("q", q_no, qid, questions_correct[qid]);
|
//console.log("q", q_no, qid, questions_correct[qid]);
|
||||||
let question_list_elements = $(`.question-list-item[data-qid='${q_no}']`);
|
let question_list_elements = $(`.question-list-item[data-qid='${q_no}']`);
|
||||||
//console.log(question_list_elements, questions_correct[qid]);
|
//console.log(question_list_elements, questions_correct[qid]);
|
||||||
@@ -1468,7 +1589,7 @@ function reviewQuestions() {
|
|||||||
let undercall_number = 0;
|
let undercall_number = 0;
|
||||||
let overcall_number = 0;
|
let overcall_number = 0;
|
||||||
let incorrectcall_number = 0;
|
let incorrectcall_number = 0;
|
||||||
question_order.forEach(function (qid, n) {
|
exam_details.question_order.forEach(function (qid, n) {
|
||||||
if (question_type == "long") {
|
if (question_type == "long") {
|
||||||
$("#review-answer-table").append(
|
$("#review-answer-table").append(
|
||||||
$(
|
$(
|
||||||
@@ -1700,7 +1821,10 @@ function reviewQuestions() {
|
|||||||
score = correct_count;
|
score = correct_count;
|
||||||
|
|
||||||
$("#review-score").text(
|
$("#review-score").text(
|
||||||
"Score: " + correct_count + " out of " + question_order.length
|
"Score: " +
|
||||||
|
correct_count +
|
||||||
|
" out of " +
|
||||||
|
exam_details.question_order.length
|
||||||
);
|
);
|
||||||
|
|
||||||
if (question_type == "rapid") {
|
if (question_type == "rapid") {
|
||||||
@@ -1915,7 +2039,7 @@ function addFlagEvents() {
|
|||||||
$("button.flag").click(function (event) {
|
$("button.flag").click(function (event) {
|
||||||
const el = $(this);
|
const el = $(this);
|
||||||
const nqid = el.attr("data-qid");
|
const nqid = el.attr("data-qid");
|
||||||
const qid = question_order[nqid];
|
const qid = exam_details.question_order[nqid];
|
||||||
const qidn = el.attr("data-qidn");
|
const qidn = el.attr("data-qidn");
|
||||||
|
|
||||||
el.toggleClass("flag flag-selected");
|
el.toggleClass("flag flag-selected");
|
||||||
@@ -2047,7 +2171,7 @@ $(".start-packet-button").click(function (evt) {
|
|||||||
$.modal.close();
|
$.modal.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#btn-delete-databases").click(function (evt) {
|
$("#btn-delete-answer-databases").click(function (evt) {
|
||||||
var r = confirm(
|
var r = confirm(
|
||||||
"This will delete ALL saved answers (including saved correct answers)!"
|
"This will delete ALL saved answers (including saved correct answers)!"
|
||||||
);
|
);
|
||||||
@@ -2071,16 +2195,40 @@ $("#btn-delete-databases").click(function (evt) {
|
|||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$("#btn-delete-cached-questions").click(function (evt) {
|
||||||
|
var r = confirm(
|
||||||
|
"Delete cached questions?"
|
||||||
|
);
|
||||||
|
if (r == true) {
|
||||||
|
question_db.delete()
|
||||||
|
.then(() => {
|
||||||
|
$.notify("Database successfully deleted", "success");
|
||||||
|
$.notify("The page will now reload", "warn");
|
||||||
|
setTimeout(() => {
|
||||||
|
location.reload();
|
||||||
|
}, 2000);
|
||||||
|
console.log("Database successfully deleted");
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
$.notify("Error deleting databases", "error");
|
||||||
|
console.error("Could not delete database");
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
// Do what should be done next...
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$("#btn-delete-current").click(function (evt) {
|
$("#btn-delete-current").click(function (evt) {
|
||||||
if (question_order.length < 1) {
|
if (exam_details.question_order.length < 1) {
|
||||||
$.notify("No packet is currently loaded", "warn");
|
$.notify("No packet is currently loaded", "warn");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
db.flags
|
db.flags
|
||||||
.where("qid")
|
.where("qid")
|
||||||
.anyOf(question_order)
|
.anyOf(exam_details.question_order)
|
||||||
.delete()
|
.delete()
|
||||||
.then(function (deleteCount) {
|
.then(function (deleteCount) {
|
||||||
$.notify("Packet flags deleted", "success");
|
$.notify("Packet flags deleted", "success");
|
||||||
@@ -2092,7 +2240,7 @@ $("#btn-delete-current").click(function (evt) {
|
|||||||
|
|
||||||
db.answers
|
db.answers
|
||||||
.where("qid")
|
.where("qid")
|
||||||
.anyOf(question_order)
|
.anyOf(exam_details.question_order)
|
||||||
.delete()
|
.delete()
|
||||||
.then(function (deleteCount) {
|
.then(function (deleteCount) {
|
||||||
$.notify("Packet successfully reset", "success");
|
$.notify("Packet successfully reset", "success");
|
||||||
@@ -2111,14 +2259,14 @@ $("#btn-delete-current").click(function (evt) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#btn-delete-current-saved-answers").click(function (evt) {
|
$("#btn-delete-current-saved-answers").click(function (evt) {
|
||||||
if (question_order.length < 1) {
|
if (exam_details.question_order.length < 1) {
|
||||||
$.notify("No packet is currently loaded", "warn");
|
$.notify("No packet is currently loaded", "warn");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
db.user_answers
|
db.user_answers
|
||||||
.where("qid")
|
.where("qid")
|
||||||
.anyOf(question_order)
|
.anyOf(exam_details.question_order)
|
||||||
.delete()
|
.delete()
|
||||||
.then(function (deleteCount) {
|
.then(function (deleteCount) {
|
||||||
$.notify("Packet flags deleted", "success");
|
$.notify("Packet flags deleted", "success");
|
||||||
@@ -2138,7 +2286,6 @@ $(document).ajaxStop(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function saveSession(start_review) {
|
function saveSession(start_review) {
|
||||||
|
|
||||||
if (start_review == true) {
|
if (start_review == true) {
|
||||||
review_mode = true;
|
review_mode = true;
|
||||||
}
|
}
|
||||||
@@ -2165,12 +2312,24 @@ function saveSession(start_review) {
|
|||||||
max_score: exam_details.number_of_questions,
|
max_score: exam_details.number_of_questions,
|
||||||
exam_time: exam_time,
|
exam_time: exam_time,
|
||||||
time_left: time_remaining,
|
time_left: time_remaining,
|
||||||
question_order: question_order,
|
question_order: exam_details.question_order,
|
||||||
questions_answered: 0, // TODO
|
questions_answered: 0, // TODO
|
||||||
total_questions: exam_details.number_of_questions,
|
total_questions: exam_details.number_of_questions,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//window.saveSession = saveSession;
|
//window.saveSession = saveSession;
|
||||||
|
function refreshDatabaseSettings() {
|
||||||
|
navigator.storage.estimate().then((value) => {
|
||||||
|
$("#storage-details").empty();
|
||||||
|
$("#storage-details").append(
|
||||||
|
`Local space used: ${helper.humanFileSize(
|
||||||
|
value.usage
|
||||||
|
)}, available: ${helper.humanFileSize(value.quota)}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$(document).on("saveSessionEvent", {}, (evt, review) => { saveSession(review) })
|
$(document).on("saveSessionEvent", {}, (evt, review) => {
|
||||||
|
saveSession(review);
|
||||||
|
});
|
||||||
|
|||||||
@@ -336,6 +336,7 @@ export function changeControlSelection() {
|
|||||||
disableFullscreen(dicom_element);
|
disableFullscreen(dicom_element);
|
||||||
}
|
}
|
||||||
if (dicom_element != undefined) {
|
if (dicom_element != undefined) {
|
||||||
|
// See https://github.com/cornerstonejs/cornerstoneTools/issues/1337
|
||||||
cornerstone.removeElementData(dicom_element);
|
cornerstone.removeElementData(dicom_element);
|
||||||
cornerstone.disable(dicom_element);
|
cornerstone.disable(dicom_element);
|
||||||
$(".canvas-panel").remove();
|
$(".canvas-panel").remove();
|
||||||
|
|||||||
Reference in New Issue
Block a user