improvements to local question cache
This commit is contained in:
@@ -613,6 +613,21 @@ img {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fullscreen-overlay-transparent {
|
||||||
|
position: fixed;
|
||||||
|
display: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 2;
|
||||||
|
cursor: pointer;
|
||||||
|
color: lightgray;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
#review-overlay {
|
#review-overlay {
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
|||||||
+1
-1
@@ -163,7 +163,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="question-loading" class="fullscreen-overlay">
|
<div id="question-loading" class="fullscreen-overlay-transparent">
|
||||||
<div class="progress-block">
|
<div class="progress-block">
|
||||||
<div class="lds-ripple"><div></div><div></div></div>
|
<div class="lds-ripple"><div></div><div></div></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+103
-56
@@ -30,13 +30,17 @@ let question_type = null;
|
|||||||
let loaded_question = null;
|
let loaded_question = null;
|
||||||
window.review = false;
|
window.review = false;
|
||||||
let exam_time = null;
|
let exam_time = null;
|
||||||
|
let packet_time = null;
|
||||||
let date_started = null;
|
let date_started = null;
|
||||||
let score = 0;
|
let score = 0;
|
||||||
|
let packet_generated = null;
|
||||||
|
|
||||||
let allow_self_marking = true;
|
let allow_self_marking = true;
|
||||||
|
|
||||||
let timer = null;
|
let timer = null;
|
||||||
|
|
||||||
|
let use_local_question_cache = false;
|
||||||
|
|
||||||
//window.dfile = null;
|
//window.dfile = null;
|
||||||
|
|
||||||
window.config = config;
|
window.config = config;
|
||||||
@@ -131,6 +135,8 @@ async function loadExamList(data) {
|
|||||||
window.exam_list.forEach(function (exam) {
|
window.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 generated = exam["json_creation_time"];
|
||||||
let c = "";
|
let c = "";
|
||||||
if (exams_started.indexOf(name) > -1) {
|
if (exams_started.indexOf(name) > -1) {
|
||||||
c = " session-started";
|
c = " session-started";
|
||||||
@@ -156,7 +162,7 @@ async function loadExamList(data) {
|
|||||||
$(`<div class='packet-button${c}' title='Load packet'></div>`)
|
$(`<div class='packet-button${c}' title='Load packet'></div>`)
|
||||||
.text(name)
|
.text(name)
|
||||||
.click(function () {
|
.click(function () {
|
||||||
loadPacketFromAjax(url);
|
loadPacketFromAjax(url, eid, generated);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -256,7 +262,38 @@ async function loadPacketList(data) {
|
|||||||
* Loads the requisite packet into the quiz system
|
* Loads the requisite packet into the quiz system
|
||||||
* @param {string} path - relative path to the packet json file
|
* @param {string} path - relative path to the packet json file
|
||||||
*/
|
*/
|
||||||
function loadPacketFromAjax(path) {
|
function loadPacketFromAjax(path, eid, generated) {
|
||||||
|
if (eid != undefined) {
|
||||||
|
// try and load the exam from the local indexedDB
|
||||||
|
question_db.saved_exams
|
||||||
|
.get(eid)
|
||||||
|
.then((exam) => {
|
||||||
|
if (
|
||||||
|
exam == undefined ||
|
||||||
|
Date.parse(exam["generated"]) != Date.parse(generated)
|
||||||
|
) {
|
||||||
|
ajaxRequestionPacket();
|
||||||
|
} else {
|
||||||
|
console.log(exam);
|
||||||
|
// We have an up to date exam in the database
|
||||||
|
// TODO: check the questions are valid
|
||||||
|
use_local_question_cache = true;
|
||||||
|
setUpPacket(exam, path);
|
||||||
|
$("#options-panel").hide();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
// Will be triggered if eid does not exist in database
|
||||||
|
console.log("Unable to load exam:", eid);
|
||||||
|
console.log("error-", error);
|
||||||
|
console.log("Exam will be downloaded");
|
||||||
|
ajaxRequestionPacket();
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ajaxRequestionPacket() {
|
||||||
//console.log("loading packet from " + path);
|
//console.log("loading packet from " + path);
|
||||||
$("#progress").html(`Requesting packet: ${path}`);
|
$("#progress").html(`Requesting packet: ${path}`);
|
||||||
|
|
||||||
@@ -275,16 +312,13 @@ function loadPacketFromAjax(path) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.done(function (data) {
|
.done(function (data) {
|
||||||
//setUpPacket(data, path.split("/").pop());
|
|
||||||
if (data.hasOwnProperty("cached") && data["cached"]) {
|
|
||||||
//console.log("loading cached packet");
|
|
||||||
}
|
|
||||||
setUpPacket(data, path);
|
setUpPacket(data, path);
|
||||||
$("#options-panel").hide();
|
$("#options-panel").hide();
|
||||||
})
|
})
|
||||||
.fail(function () {
|
.fail(function () {
|
||||||
//console.log("Unable to load packet at: " + path);
|
console.log("Unable to load packet at: " + path);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -292,9 +326,9 @@ function loadPacketFromAjax(path) {
|
|||||||
*/
|
*/
|
||||||
function setUpQuestions(load_previous) {
|
function setUpQuestions(load_previous) {
|
||||||
if (questions == undefined) {
|
if (questions == undefined) {
|
||||||
return;
|
//return;
|
||||||
}
|
} else {
|
||||||
|
if (!use_local_question_cache) {
|
||||||
Object.keys(questions).forEach(function (e) {
|
Object.keys(questions).forEach(function (e) {
|
||||||
// Store question data into dexie
|
// Store question data into dexie
|
||||||
let d = {
|
let d = {
|
||||||
@@ -305,6 +339,7 @@ function setUpQuestions(load_previous) {
|
|||||||
|
|
||||||
question_db.question_data.put(d);
|
question_db.question_data.put(d);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Set an order for the questions
|
// Set an order for the questions
|
||||||
if (!load_previous) {
|
if (!load_previous) {
|
||||||
@@ -328,13 +363,13 @@ function setUpQuestions(load_previous) {
|
|||||||
question_order = helper.shuffleArray(question_order);
|
question_order = helper.shuffleArray(question_order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
window.number_of_questions = Object.keys(questions).length;
|
}
|
||||||
|
window.number_of_questions = question_order.length;
|
||||||
window.review = false;
|
window.review = false;
|
||||||
|
|
||||||
// Horrible way to get type of questions
|
// Horrible way to get type of questions
|
||||||
// We assume they are all of the same type....
|
// We assume they are all of the same type....
|
||||||
question_type =
|
//question_type = questions[Object.keys(questions)[0]].type;
|
||||||
questions[Object.keys(questions)[0]].type;
|
|
||||||
|
|
||||||
if (window.exam_details.exam_mode) {
|
if (window.exam_details.exam_mode) {
|
||||||
$("#options-button, #review-overlay-button").hide();
|
$("#options-button, #review-overlay-button").hide();
|
||||||
@@ -344,7 +379,6 @@ function setUpQuestions(load_previous) {
|
|||||||
|
|
||||||
questions = null;
|
questions = null;
|
||||||
|
|
||||||
|
|
||||||
//console.log(question_type);
|
//console.log(question_type);
|
||||||
|
|
||||||
// exam_time can be defined in packets
|
// exam_time can be defined in packets
|
||||||
@@ -425,10 +459,10 @@ 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, data",
|
question_data: "[eid+qid], eid",
|
||||||
|
saved_exams: "eid, type, exam_mode, name, order, time, generated",
|
||||||
});
|
});
|
||||||
|
|
||||||
//db = db;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the packet and extract metadata (if it exists)
|
* Parse the packet and extract metadata (if it exists)
|
||||||
@@ -447,12 +481,16 @@ function setUpPacket(data, path) {
|
|||||||
window.exam_details.eid = data.eid;
|
window.exam_details.eid = data.eid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.hasOwnProperty("type")) {
|
if (data.hasOwnProperty("exam_type")) {
|
||||||
question_type = data.type;
|
question_type = data.exam_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.hasOwnProperty("generated")) {
|
||||||
|
packet_generated = data.generated;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.hasOwnProperty("exam_mode")) {
|
if (data.hasOwnProperty("exam_mode")) {
|
||||||
window.exam_details.exam_mode = data.exam_mode;
|
exam_details.exam_mode = data.exam_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.hasOwnProperty("questions")) {
|
if (data.hasOwnProperty("questions")) {
|
||||||
@@ -467,8 +505,20 @@ function setUpPacket(data, path) {
|
|||||||
|
|
||||||
if (data.hasOwnProperty("exam_time")) {
|
if (data.hasOwnProperty("exam_time")) {
|
||||||
exam_time = data.exam_time;
|
exam_time = data.exam_time;
|
||||||
|
// packet time is the time specificed by the packet
|
||||||
|
packet_time = data.exam_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_local_question_cache) {
|
||||||
|
// If loading form cache nothing else to do here
|
||||||
|
loadSession();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the details to the question database
|
||||||
|
var clone_data = Object.assign({}, data, { questions: undefined });
|
||||||
|
question_db.saved_exams.put(clone_data);
|
||||||
|
|
||||||
// If the question_requests is set we need to do a request for each question
|
// If the question_requests is set we need to do a request for each question
|
||||||
if (data.hasOwnProperty("question_requests") && data["question_requests"]) {
|
if (data.hasOwnProperty("question_requests") && data["question_requests"]) {
|
||||||
const question_total = Object.keys(data["questions"]).length;
|
const question_total = Object.keys(data["questions"]).length;
|
||||||
@@ -506,7 +556,19 @@ function setUpPacket(data, path) {
|
|||||||
|
|
||||||
//requests.push(request)
|
//requests.push(request)
|
||||||
//request_numbers.push(n)
|
//request_numbers.push(n)
|
||||||
data["questions"][n] = question_json;
|
|
||||||
|
// Using indexed db means that we can avoid loading all data into memory
|
||||||
|
//data["questions"][n] = question_json;
|
||||||
|
|
||||||
|
// Store question data into dexie
|
||||||
|
let d = {
|
||||||
|
eid: window.exam_details.eid,
|
||||||
|
qid: n,
|
||||||
|
data: question_json,
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
loadSession();
|
loadSession();
|
||||||
@@ -524,10 +586,7 @@ function loadSession() {
|
|||||||
// .where("status")
|
// .where("status")
|
||||||
// .equals("active")
|
// .equals("active")
|
||||||
.where("[packet+aid]")
|
.where("[packet+aid]")
|
||||||
.between(
|
.between([packet_name, Dexie.minKey], [packet_name, Dexie.maxKey])
|
||||||
[packet_name, Dexie.minKey],
|
|
||||||
[packet_name, Dexie.maxKey]
|
|
||||||
)
|
|
||||||
.toArray()
|
.toArray()
|
||||||
.then((sessions) => {
|
.then((sessions) => {
|
||||||
//console.log("sessions", sessions);
|
//console.log("sessions", sessions);
|
||||||
@@ -621,20 +680,18 @@ function loadSession() {
|
|||||||
* @param {boolean} force_reload - Force question to be reloaded if already loaded
|
* @param {boolean} force_reload - Force question to be reloaded if already loaded
|
||||||
*/
|
*/
|
||||||
async function loadQuestion(n, section = 1, force_reload = false) {
|
async function loadQuestion(n, section = 1, force_reload = false) {
|
||||||
|
|
||||||
$("#question-loading").show();
|
$("#question-loading").show();
|
||||||
const aid = window.exam_details.aid;
|
const aid = window.exam_details.aid;
|
||||||
const cid = window.exam_details.cid;
|
const cid = window.exam_details.cid;
|
||||||
const eid = window.exam_details.eid;
|
const eid = window.exam_details.eid;
|
||||||
|
|
||||||
|
|
||||||
// Make sure we have an integer
|
// Make sure we have an integer
|
||||||
n = parseInt(n);
|
n = parseInt(n);
|
||||||
//console.log("loading question (n)", n);
|
//console.log("loading question (n)", n);
|
||||||
|
|
||||||
const qid = question_order[n];
|
const qid = question_order[n];
|
||||||
|
|
||||||
let q = {qid: qid.toString(), eid: eid};
|
let q = { qid: qid.toString(), eid: eid };
|
||||||
|
|
||||||
let return_data = await question_db.question_data.get(q);
|
let return_data = await question_db.question_data.get(q);
|
||||||
const question_data = return_data.data;
|
const question_data = return_data.data;
|
||||||
@@ -645,6 +702,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
if (n == loaded_question && force_reload == false) {
|
if (n == loaded_question && force_reload == false) {
|
||||||
// Question already loaded
|
// Question already loaded
|
||||||
setFocus(section);
|
setFocus(section);
|
||||||
|
$("#question-loading").hide();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -856,9 +914,9 @@ 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-list-item-" + question_order.indexOf(qid) + "-2"
|
"question-saved-localdb"
|
||||||
).addClass("question-saved-localdb");
|
);
|
||||||
|
|
||||||
saveSession();
|
saveSession();
|
||||||
updateQuestionListPanel(answer);
|
updateQuestionListPanel(answer);
|
||||||
@@ -938,9 +996,9 @@ 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-list-item-" + question_order.indexOf(qid) + "-1"
|
"question-saved-localdb"
|
||||||
).addClass("question-saved-localdb");
|
);
|
||||||
saveSession();
|
saveSession();
|
||||||
updateQuestionListPanel(answer);
|
updateQuestionListPanel(answer);
|
||||||
});
|
});
|
||||||
@@ -1008,10 +1066,7 @@ 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-list-item-" + question_order.indexOf(qid) + "-" + qidn
|
||||||
question_order.indexOf(qid) +
|
|
||||||
"-" +
|
|
||||||
qidn
|
|
||||||
).removeClass("question-saved-localdb");
|
).removeClass("question-saved-localdb");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1029,10 +1084,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
console.log("SAVE", qid, qidn, evt.target.value);
|
console.log("SAVE", qid, qidn, evt.target.value);
|
||||||
|
|
||||||
$(
|
$(
|
||||||
"#question-list-item-" +
|
"#question-list-item-" + question_order.indexOf(qid) + "-" + qidn
|
||||||
question_order.indexOf(qid) +
|
|
||||||
"-" +
|
|
||||||
qidn
|
|
||||||
).addClass("question-saved-localdb");
|
).addClass("question-saved-localdb");
|
||||||
saveSession();
|
saveSession();
|
||||||
updateQuestionListPanel(answer);
|
updateQuestionListPanel(answer);
|
||||||
@@ -1081,8 +1133,8 @@ async function loadQuestion(n, section = 1, force_reload = false) {
|
|||||||
//rebuildQuestionListPanel();
|
//rebuildQuestionListPanel();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setFocus(section);
|
setFocus(section);
|
||||||
$("#question-loading").hide();
|
|
||||||
}, 200);
|
}, 200);
|
||||||
|
$("#question-loading").hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1121,17 +1173,15 @@ function updateQuestionListPanel(answer) {
|
|||||||
|
|
||||||
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(
|
||||||
"#question-list-item-" +
|
"display",
|
||||||
question_order.indexOf(answer.qid) +
|
"block"
|
||||||
"-2"
|
);
|
||||||
).css("display", "block");
|
|
||||||
} else {
|
} else {
|
||||||
$(
|
$("#question-list-item-" + question_order.indexOf(answer.qid) + "-2").css(
|
||||||
"#question-list-item-" +
|
"display",
|
||||||
question_order.indexOf(answer.qid) +
|
"none"
|
||||||
"-2"
|
);
|
||||||
).css("display", "none");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1651,10 +1701,7 @@ function reviewQuestions() {
|
|||||||
score = correct_count;
|
score = correct_count;
|
||||||
|
|
||||||
$("#review-score").text(
|
$("#review-score").text(
|
||||||
"Score: " +
|
"Score: " + correct_count + " out of " + question_order.length
|
||||||
correct_count +
|
|
||||||
" out of " +
|
|
||||||
question_order.length
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (question_type == "rapid") {
|
if (question_type == "rapid") {
|
||||||
|
|||||||
Reference in New Issue
Block a user