diff --git a/.vscode/settings.json b/.vscode/settings.json
index c5f7c9e..0ec6bc1 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -3,5 +3,6 @@
"javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
"javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": false,
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false,
- "javascript.format.enable": false
+ "javascript.format.enable": false,
+ "liveServer.settings.port": 5502
}
\ No newline at end of file
diff --git a/css/base.css b/css/base.css
index 2f72a42..f984c3f 100644
--- a/css/base.css
+++ b/css/base.css
@@ -1,18 +1,67 @@
-html, body, div, span, applet, object, iframe,
-h1, h2, h3, h4, h5, h6, p, blockquote, pre,
-a, abbr, acronym, address, big, cite, code,
-del, dfn, em, font, img, ins, kbd, q, s, samp,
-small, strike, strong, sub, sup, tt, var,
-dl, dt, dd, ol, ul, li,
-fieldset, form, label, legend,
-table, caption, tbody, tfoot, thead, tr, th, td {
+html,
+body,
+div,
+span,
+applet,
+object,
+iframe,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+blockquote,
+pre,
+a,
+abbr,
+acronym,
+address,
+big,
+cite,
+code,
+del,
+dfn,
+em,
+font,
+img,
+ins,
+kbd,
+q,
+s,
+samp,
+small,
+strike,
+strong,
+sub,
+sup,
+tt,
+var,
+dl,
+dt,
+dd,
+ol,
+ul,
+li,
+fieldset,
+form,
+label,
+legend,
+table,
+caption,
+tbody,
+tfoot,
+thead,
+tr,
+th,
+td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
- font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
@@ -27,7 +76,8 @@ body {
background: white;
}
-ol, ul {
+ol,
+ul {
list-style: none;
}
@@ -36,17 +86,21 @@ table {
border-spacing: 0;
}
-caption, th, td {
+caption,
+th,
+td {
text-align: left;
font-weight: normal;
}
-blockquote:before, blockquote:after,
-q:before, q:after {
+blockquote:before,
+blockquote:after,
+q:before,
+q:after {
content: "";
}
-blockquote, q {
- quotes: "" "";
-}
-
+blockquote,
+q {
+ quotes: """";
+}
\ No newline at end of file
diff --git a/css/main.css b/css/main.css
index 3cc6f56..f864045 100644
--- a/css/main.css
+++ b/css/main.css
@@ -3,7 +3,7 @@
@import url("https://fonts.googleapis.com/css?family=Noto+Sans:400,700");
/* Colourscheme from https://www.materialui.co/colors */
-* {
+* {
-webkit-font-smoothing: antialiased;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@@ -17,7 +17,6 @@
appearance: none;
font-family: "Noto Sans", sans-serif !important;
font-weight: 400;
- font-size: 1.6rem;
text-rendering: optimizeLegibility;
line-height: 1.5;
}
@@ -49,7 +48,12 @@ html {
font-size: 62.5%;
}
-html, body, input:not([type=text]), button, select, option {
+html,
+body,
+input:not([type=text]),
+button,
+select,
+option {
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
@@ -57,11 +61,18 @@ html, body, input:not([type=text]), button, select, option {
-o-user-select: none;
}
-html, body, input, button, select, option, textarea {
- vertical-align:top;
+html,
+body,
+input,
+button,
+select,
+option,
+textarea {
+ vertical-align: top;
margin: 0;
padding: 0;
- color: black; /*#1d3850;*/
+ color: black;
+ /*#1d3850;*/
/*font-family: 'Noto Sans', sans-serif;*/
overflow: hidden;
}
@@ -72,7 +83,11 @@ body {
font-weight: 400;
}
-input, button, select, option, textarea {
+input,
+button,
+select,
+option,
+textarea {
background-color: white;
font-size: 100%;
padding: 0.4rem 0.8rem;
@@ -174,8 +189,8 @@ td {
}
.question-list-flag {
- float: right;
- color: #311B92;
+ float: right;
+ color: #311B92;
visibility: hidden;
}
@@ -247,7 +262,7 @@ td {
}
.no-touch .navigation:hover {
- background-color: #1a237e;
+ background-color: #1a237e;
border-color: #ddd;
}
@@ -275,7 +290,7 @@ td {
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
-
+
.question * {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
@@ -350,7 +365,7 @@ td {
.canvas-panel {
display: block;
padding: 0;
- margin: 0;
+ margin: 0;
background-color: black;
image-rendering: optimizeSpeed;
image-rendering: -moz-crisp-edges;
@@ -529,7 +544,7 @@ img {
width: 100vw;
height: 100vh;
overflow: auto;
- background-color: rgba(0,0,0,0.4);
+ background-color: rgba(0, 0, 0, 0.4);
text-align: center;
}
@@ -541,7 +556,7 @@ img {
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
border-radius: 5px;
padding: 0px;
-
+
}
.dialog-title {
@@ -606,9 +621,9 @@ img {
left: 0;
right: 0;
bottom: 0;
- background-color: rgba(0,0,0,0.9);
+ background-color: rgba(0, 0, 0, 0.9);
z-index: 2;
- cursor: pointer;
+ cursor: pointer;
color: lightgray;
overflow: auto;
}
@@ -623,7 +638,7 @@ img {
right: 0;
bottom: 0;
z-index: 2;
- cursor: pointer;
+ cursor: pointer;
color: lightgray;
overflow: auto;
}
@@ -652,7 +667,8 @@ img {
opacity: 1;
}
-.close:before, .close:after {
+.close:before,
+.close:after {
position: absolute;
left: 15px;
content: ' ';
@@ -796,7 +812,7 @@ select option:disabled {
}
.feedback {
- padding-top: 0.8rem;
+ padding-top: 0.8rem;
}
#options-panel {
@@ -816,72 +832,89 @@ select option:disabled {
padding-top: 20px;
}
-.packet-button {
- display:inline-block;
- padding:0.35em 1.2em;
- border:0.1em solid #FFFFFF;
- margin:0 0.3em 0.3em 0;
- border-radius:0.12em;
+
+.login-button {
+ display: inline-block;
+ padding: 0.35em 1.2em;
+ border: 0.1em solid purple;
+ margin: 0 0.3em 0.3em 0;
+ border-radius: 0.12em;
box-sizing: border-box;
- text-decoration:none;
- font-family:'Roboto',sans-serif;
- font-weight:300;
- color:#FFFFFF;
- text-align:center;
+ text-decoration: none;
+ font-family: 'Roboto', sans-serif;
+ font-weight: 300;
+ color: rgb(201, 0, 201);
+ text-align: center;
+ transition: all 0.2s;
+ background-color: black;
+}
+
+.packet-button {
+ display: inline-block;
+ padding: 0.35em 1.2em;
+ border: 0.1em solid #FFFFFF;
+ margin: 0 0.3em 0.3em 0;
+ border-radius: 0.12em;
+ box-sizing: border-box;
+ text-decoration: none;
+ font-family: 'Roboto', sans-serif;
+ font-weight: 300;
+ color: #FFFFFF;
+ text-align: center;
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.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
+.packet-button.out-of-date {
+ color: darkslategray
}
.save-button {
- display:inline-block;
+ display: inline-block;
margin-left: 10px;
- color:#FFFFFF;
- border-bottom:2px solid transparent;
+ color: #FFFFFF;
+ border-bottom: 2px solid transparent;
}
-.save-button a {
- color: inherit;
-}
+.save-button a {
+ color: inherit;
+}
.save-button:hover {
- color: #311B92;
- border-bottom:2px solid #311B92;
+ color: #311B92;
+ border-bottom: 2px solid #311B92;
}
-.packet-button:hover{
- color:lightblue;
- border-color:blue;
+.packet-button:hover {
+ color: lightblue;
+ border-color: blue;
}
.progress-block {
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- font-size: smaller;
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ font-size: smaller;
}
#timer {
- /* left: 50%; */
- margin: auto;
- margin-right: 1em;
- opacity: 25%;
+ /* left: 50%; */
+ margin: auto;
+ margin-right: 1em;
+ opacity: 25%;
}
#timer:hover:before {
@@ -889,69 +922,97 @@ select option:disabled {
}
.sk-cube-grid {
- width: 60px;
- height: 60px;
+ width: 60px;
+ height: 60px;
}
.sk-cube-grid .sk-cube {
- width: 33%;
- height: 33%;
- background-color: #4527A0;
- float: left;
- -webkit-animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
- animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
+ width: 33%;
+ height: 33%;
+ background-color: #4527A0;
+ float: left;
+ -webkit-animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
+ animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
}
+
.sk-cube-grid .sk-cube1 {
- -webkit-animation-delay: 0.2s;
- animation-delay: 0.2s; }
+ -webkit-animation-delay: 0.2s;
+ animation-delay: 0.2s;
+}
+
.sk-cube-grid .sk-cube2 {
- -webkit-animation-delay: 0.3s;
- animation-delay: 0.3s; }
+ -webkit-animation-delay: 0.3s;
+ animation-delay: 0.3s;
+}
+
.sk-cube-grid .sk-cube3 {
- -webkit-animation-delay: 0.4s;
- animation-delay: 0.4s; }
+ -webkit-animation-delay: 0.4s;
+ animation-delay: 0.4s;
+}
+
.sk-cube-grid .sk-cube4 {
- -webkit-animation-delay: 0.1s;
- animation-delay: 0.1s; }
+ -webkit-animation-delay: 0.1s;
+ animation-delay: 0.1s;
+}
+
.sk-cube-grid .sk-cube5 {
- -webkit-animation-delay: 0.2s;
- animation-delay: 0.2s; }
+ -webkit-animation-delay: 0.2s;
+ animation-delay: 0.2s;
+}
+
.sk-cube-grid .sk-cube6 {
- -webkit-animation-delay: 0.3s;
- animation-delay: 0.3s; }
+ -webkit-animation-delay: 0.3s;
+ animation-delay: 0.3s;
+}
+
.sk-cube-grid .sk-cube7 {
- -webkit-animation-delay: 0s;
- animation-delay: 0s; }
+ -webkit-animation-delay: 0s;
+ animation-delay: 0s;
+}
+
.sk-cube-grid .sk-cube8 {
- -webkit-animation-delay: 0.1s;
- animation-delay: 0.1s; }
+ -webkit-animation-delay: 0.1s;
+ animation-delay: 0.1s;
+}
+
.sk-cube-grid .sk-cube9 {
- -webkit-animation-delay: 0.2s;
- animation-delay: 0.2s; }
+ -webkit-animation-delay: 0.2s;
+ animation-delay: 0.2s;
+}
@-webkit-keyframes sk-cubeGridScaleDelay {
- 0%, 70%, 100% {
- -webkit-transform: scale3D(1, 1, 1);
- transform: scale3D(1, 1, 1);
- } 35% {
- -webkit-transform: scale3D(0, 0, 1);
- transform: scale3D(0, 0, 1);
- }
+
+ 0%,
+ 70%,
+ 100% {
+ -webkit-transform: scale3D(1, 1, 1);
+ transform: scale3D(1, 1, 1);
+ }
+
+ 35% {
+ -webkit-transform: scale3D(0, 0, 1);
+ transform: scale3D(0, 0, 1);
+ }
}
@keyframes sk-cubeGridScaleDelay {
- 0%, 70%, 100% {
- -webkit-transform: scale3D(1, 1, 1);
- transform: scale3D(1, 1, 1);
- } 35% {
- -webkit-transform: scale3D(0, 0, 1);
- transform: scale3D(0, 0, 1);
- }
+
+ 0%,
+ 70%,
+ 100% {
+ -webkit-transform: scale3D(1, 1, 1);
+ transform: scale3D(1, 1, 1);
+ }
+
+ 35% {
+ -webkit-transform: scale3D(0, 0, 1);
+ transform: scale3D(0, 0, 1);
+ }
}
.displayblock {
-display: block
+ display: block
}
.review-list-header {
@@ -971,30 +1032,30 @@ display: block
padding-bottom: 0px;
opacity: 50%;
text-align: center;
- }
+}
#resume-exam-button {
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
}
#pause-text {
- position: fixed;
- /* left: 50%; */
- width: 100%;
- text-align: center;
- top: 20%;
- font-size: xxx-large;
- transform: translate(0%, 20%);
+ position: fixed;
+ /* left: 50%; */
+ width: 100%;
+ text-align: center;
+ top: 20%;
+ font-size: xxx-large;
+ transform: translate(0%, 20%);
}
#pause-time-remaining {
- width: auto;
- font-size: large;
- /* position: fixed; */
- text-align: center;
+ width: auto;
+ font-size: large;
+ /* position: fixed; */
+ text-align: center;
}
.packet-database-options {
@@ -1048,36 +1109,40 @@ display: block
.lds-ripple {
- display: inline-block;
- position: relative;
- width: 80px;
- height: 80px;
+ display: inline-block;
+ position: relative;
+ width: 80px;
+ height: 80px;
}
+
.lds-ripple div {
- position: absolute;
- border: 4px solid #4527A0;
- opacity: 1;
- border-radius: 50%;
- animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
-}
-.lds-ripple div:nth-child(2) {
- animation-delay: -0.5s;
-}
-@keyframes lds-ripple {
- 0% {
- top: 36px;
- left: 36px;
- width: 0;
- height: 0;
+ position: absolute;
+ border: 4px solid #4527A0;
opacity: 1;
- }
- 100% {
- top: 0px;
- left: 0px;
- width: 72px;
- height: 72px;
- opacity: 0;
- }
+ border-radius: 50%;
+ animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
+}
+
+.lds-ripple div:nth-child(2) {
+ animation-delay: -0.5s;
+}
+
+@keyframes lds-ripple {
+ 0% {
+ top: 36px;
+ left: 36px;
+ width: 0;
+ height: 0;
+ opacity: 1;
+ }
+
+ 100% {
+ top: 0px;
+ left: 0px;
+ width: 72px;
+ height: 72px;
+ opacity: 0;
+ }
}
#submit-error-overlay {
@@ -1095,4 +1160,30 @@ display: block
.cache-out-of-date {
color: red;
- }
\ No newline at end of file
+}
+
+.user-text {
+ color: darkslateblue;
+}
+
+.inactive::before {
+ content: "inactive";
+ transform: rotate(45deg);
+ color: red;
+ font-size: 1rem;
+ font-weight: 900;
+ border: 0.25rem solid red;
+ display: inline-block;
+ /* padding: 0.25rem 1rem; */
+ text-transform: uppercase;
+ border-radius: 1rem;
+ font-family: 'Courier';
+ /* mix-blend-mode: multiply; */
+ opacity: 30%;
+ margin-left: -2em;
+ position: absolute;
+}
+
+.invalid-login {
+ color: red;
+}
\ No newline at end of file
diff --git a/index.html b/index.html
index 8ee7df7..9c720d3 100644
--- a/index.html
+++ b/index.html
@@ -19,8 +19,8 @@
-
+
@@ -152,12 +163,13 @@
submit
-
-
Select exam
+
@@ -179,7 +191,10 @@
@@ -202,7 +217,7 @@
-
+
diff --git a/js/interact.js b/js/interact.js
index a829979..9477279 100644
--- a/js/interact.js
+++ b/js/interact.js
@@ -8,6 +8,8 @@ export function submitAnswers(exam_details, db, config) {
.then((a) => {
let json = {
eid: exam_details.eid,
+ cid: exam_details.cid,
+ start_time: exam_details.start_time,
answers: JSON.stringify(a),
};
postAnswers(json, config, exam_details);
@@ -25,10 +27,10 @@ export function submitAnswers(exam_details, db, config) {
export function getJsonAnswers(exam_details, db) {
console.log(exam_details)
console.log({
- aid: exam_details.aid,
- cid: exam_details.cid,
- eid: exam_details.eid,
- })
+ aid: exam_details.aid,
+ cid: exam_details.cid,
+ eid: exam_details.eid,
+ })
return db.answers
.where({
aid: exam_details.aid,
@@ -56,7 +58,7 @@ export function postAnswers(ans, config, exam_details) {
);
if (ret) {
- $( document ).trigger( "saveSessionEvent", [ true ] );
+ $(document).trigger("saveSessionEvent", [true]);
if (config.exam_results_url != "") {
let url = config.exam_results_url;
@@ -70,8 +72,7 @@ export function postAnswers(ans, config, exam_details) {
);
}
$("#options-panel").show();
- } else {
- }
+ } else {}
} else {
alert(`${data.question_count} answers sucessfully submitted.`);
}
@@ -100,13 +101,13 @@ function submissionError(data, answer_json, exam_details) {
let answer_map = {}
- answers.forEach((ans, n) => {
+ answers.forEach((ans, n) => {
if (!answer_map.hasOwnProperty(ans.qid)) {
answer_map[ans.qid] = [];
}
answer_map[ans.qid].push(ans);
-
+
});
let html = $("
");
@@ -114,13 +115,13 @@ function submissionError(data, answer_json, exam_details) {
exam_details.question_order.forEach((i, j) => {
console.log(i, answer_map)
if (i in answer_map) {
- console.log("YES", i, answer_map)
+ console.log("YES", i, answer_map)
let ans_array = answer_map[i];
ans_array.forEach((x, y) => {
- $(html).append(`
Question ${j+1}.${y}: ${x.ans}`);
+ $(html).append(`
Question ${j+1}.${y}: ${x.ans}`);
});
}
-
+
})
console.log(exam_details.question_order);
@@ -145,10 +146,7 @@ export function getQuestion(url, question_number, question_total) {
return $.ajax({
dataType: "json",
url: url,
- progress: function (e) {
- $("#progress").html(
- `Downloading question [${question_number}/${question_total}]
This file is compressed (no size available)`
- );
+ progress: function(e) {
if (e.lengthComputable) {
var completedPercentage = Math.round((e.loaded * 100) / e.total);
@@ -157,6 +155,10 @@ export function getQuestion(url, question_number, question_total) {
e.total
)}`
);
+ } else {
+ $("#progress").html(
+ `Downloading question [${question_number}/${question_total}]
This file is compressed (downloaded ${helper.humanFileSize(e.loaded)})`
+ );
}
},
error: (jqXHR, textStatus, errorThrown) => {
@@ -170,14 +172,18 @@ export function getQuestion(url, question_number, question_total) {
}
export function postSavedAnswer(type, qid, answer, e, db_object, db) {
-console.log("post", type, qid, answer, e)
-return $.ajax({
+ console.log("post", type, qid, answer, e)
+ return $.ajax({
type: "POST",
url: config.question_answer_submit_url,
- data: JSON.stringify({ qid: `${type}/${qid}`, answer: answer, status: 2 }),
+ data: JSON.stringify({
+ qid: `${type}/${qid}`,
+ answer: answer,
+ status: 2
+ }),
contentType: "application/json; charset=utf-8",
dataType: "json",
- success: function(data){
+ success: function(data) {
db_object.submitted = true;
db.user_answers.put(db_object);
e.target.remove()
@@ -185,7 +191,7 @@ return $.ajax({
},
error: function(errMsg) {
- alert(errMsg);
+ alert(errMsg);
}
-});
-}
+ });
+}
\ No newline at end of file
diff --git a/js/main.js b/js/main.js
index 48030aa..b1afc04 100644
--- a/js/main.js
+++ b/js/main.js
@@ -9,9 +9,11 @@ let exam_details = {
aid: null,
cid: "",
eid: 5678,
+ passcode: "",
exam_mode: false,
number_of_questions: null,
question_order: [],
+ start_time: null,
};
let packet_list = [];
@@ -27,12 +29,17 @@ let date_started = null;
let score = 0;
let packet_json_id = null;
+let global_cid = null;
+let global_passcode = null;
+
let allow_self_marking = true;
let timer = null;
let use_local_question_cache = false;
+
+
cornerstone.imageCache.setMaximumSizeBytes(5128800);
// Set up cornerstone (the dicom viewer)
@@ -59,11 +66,10 @@ cornerstoneTools.init();
// Set up database
const db = new Dexie("answers_database");
db.version(1).stores({
- answers: "[aid+cid+eid+qid+qidn], [aid+cid+eid], qid, ans",
+ answers: "[aid+cid+eid+qid+qidn], [aid+cid+eid], qid, ans, eid",
flags: "[aid+cid+eid+qid+qidn], [aid+cid+eid], qid",
user_answers: "[qid+type+ans], [qid+type]",
- session:
- "[packet+aid], packet, aid, status, date, score, max_score, exam_time, time_left, question_order, questions_answered, total_questions",
+ session: "[eid+aid], eid, packet, aid, status, date, score, max_score, exam_time, time_left, question_order, questions_answered, total_questions",
});
const question_db = new Dexie("question_database");
@@ -72,6 +78,11 @@ question_db.version(1).stores({
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();
refreshDatabaseSettings();
@@ -83,45 +94,115 @@ refreshDatabaseSettings();
*
* if exam_query_url is defined in config.js this will be used in preference
*/
-function retrievePacketList() {
+async function retrievePacketList() {
let url = "packets/packets.json";
//console.log(config.exam_query_url);
+ let users = await user_db.user.toArray();
+ console.log(users)
+
+ if (users.length > 0) {
+ global_cid = users[0].cid;
+ global_passcode = users[0].passcode;
+
+ $(".exam-wrapper").toggle();
+
+ let logout = $("
[x]")
+ logout.click(() => {
+ user_db.user.clear().then(() => {
+ window.location = window.location.pathname;
+ return;
+ });
+ })
+
+ if (config.exam_results_url != "" && config.exam_results_url != undefined) {
+ let url = `${config.exam_results_url}${global_cid}/${global_passcode}`;
+
+ $("#options-link")
+ .empty()
+ .append(
+ `
Results and answers
`
+ );
+ }
+
+ $("#candidate-details").append(`Current: CID ${global_cid} / Passcode ${global_passcode} `).append(logout);
+ } else {
+
+
+ let items = window.location.search.substr(1).split("&");
+ if (items.length == 2) {
+ let cid = "";
+ let passcode = "";
+ for (let index = 0; index < items.length; index++) {
+ const item = items[index];
+ let s = item.split("=");
+
+ if (s[0] == "cid") {
+ cid = s[1];
+ }
+ if (s[0] == "passcode") {
+ passcode = s[1];
+ }
+
+ };
+ console.log(cid, passcode)
+
+ user_db.user.add({
+ cid: cid,
+ passcode: passcode
+ })
+ location.reload();
+ }
+
+ }
try {
if (config.exam_query_url != undefined) {
- url = config.exam_query_url;
+
+ if (global_cid == null) {
+ url = config.exam_query_url;
+ } else {
+ url = `${config.exam_query_url}/${global_cid}/${global_passcode}`;
+ }
}
} catch (e) {
//
}
$.ajax({
- dataType: "json",
- cache: false,
- url: url,
- success: function (data) {
- if (data.hasOwnProperty("exams")) {
- loadExamList(data);
- } else {
- loadPacketList(data);
- }
- },
- })
- .done(function () {})
- .fail(function () {
- $.getJSON("packets", function (data) {
+ dataType: "json",
+ cache: false,
+ url: url,
+ success: function(data) {
if (data.hasOwnProperty("exams")) {
loadExamList(data);
} else {
loadPacketList(data);
}
- }).fail(function (jqXHR, textStatus, errorThrown) {
+ },
+ error: function(httpObj, textStatus) {
+ console.log(httpObj);
+ if (httpObj.status == 401 || httpObj.status == 404) {
+ $.notify("Unable to login", "error");
+ $("#options-panel").show();
+ $("#candidate-details").addClass("invalid-login");
+ }
+ },
+ })
+ .done(function() {})
+ .fail(function() {
+ $.getJSON("packets", function(data) {
+ if (data.hasOwnProperty("exams")) {
+ loadExamList(data);
+ } else {
+ loadPacketList(data);
+ }
+ }).fail(function(jqXHR, textStatus, errorThrown) {
console.log("No packet list available");
- showLoginDialog();
+ //showLoginDialog();
});
})
- .always(function () {});
+ .always(function() {});
}
/**
@@ -131,7 +212,7 @@ function retrievePacketList() {
* @param {JSON} data - json containing available exams
*/
async function loadExamList(data) {
- let sessions = await db.session.toArray().catch(function (error) {
+ let sessions = await db.session.toArray().catch(function(error) {
console.log("Error loading session", error);
$("#database-error").text(
"Error loading the database, schema has probably changed and needs updating. You will probably need to delete the local database."
@@ -146,6 +227,13 @@ async function loadExamList(data) {
$("#database-error").show();
});
+ //Display user info if it exists
+ if (data.hasOwnProperty("user") && data.user) {
+ $("#user").append(`User: ${data.user}`);
+ $(".exam-wrapper").show();
+ }
+
+
let exams_started = [];
let exams_completed = [];
sessions.forEach((s) => {
@@ -164,7 +252,9 @@ async function loadExamList(data) {
let exam_generated_map = {};
$("#packet-list").empty();
//exam_list.sort((a, b) => (a.name > b.name) ? 1 : -1).forEach(function (exam) {
- exam_list.forEach(function (exam) {
+ for (let index = 0; index < exam_list.length; index++) {
+ const exam = exam_list[index];
+ console.log(exam)
let name = exam["name"];
let url = exam["url"];
let eid = exam["eid"];
@@ -185,39 +275,40 @@ async function loadExamList(data) {
c = " session-completed";
}
+ if (!exam.exam_active) {
+ c = c + " inactive";
+ }
+
+ let target_list = "packet-list";
+ if (exam.exam_mode) {
+ target_list = "exam-list";
+ }
+
let list;
if (exam.type != undefined) {
- if ($(`#packet-list .${exam.type}`).length) {
- list = $(`#packet-list .${exam.type}`);
+ if ($(`.${target_list}.${exam.type}`).length) {
+ list = $(`.${target_list}.${exam.type}`);
} else {
- list = $("#packet-list").append(
- `
${exam.type}
`
- );
+ list = $(`
${exam.type}
`);
+ $(`#${target_list}`).append(list);
+
}
} else {
list = $("#packet-list");
}
- list.append(
+ $(list).append(
$(
`
`
)
- .text(name)
- .click(function () {
- loadPacketFromAjax(url, eid, exam_json_id);
- })
+ .text(name)
+ .click(function() {
+ loadPacketFromAjax(url, eid, exam_json_id);
+ })
);
- });
- if (config.exam_results_url != "" && config.exam_results_url != undefined) {
- let url = config.exam_results_url;
-
- $("#options-link")
- .empty()
- .append(
- `
Results and answers
`
- );
}
+
// Check the database for exams that have been saved
question_db.saved_exams.toArray().then((saved_exams) => {
if (saved_exams.length < 1) {
@@ -226,7 +317,7 @@ async function loadExamList(data) {
$("#cache-details summary").append("
Cached exams / questions:");
}
console.log("Loop through saved exams");
- saved_exams.forEach((saved_exam, n) => {
+ saved_exams.forEach(async (saved_exam, n) => {
console.log("Check", saved_exam);
$("#cache-details ul").append(
`
Exam: ${saved_exam.exam_name} [${saved_exam.eid}]: ${saved_exam.exam_json_id}`
@@ -240,6 +331,7 @@ async function loadExamList(data) {
if (saved_exam.exam_json_id != exam_json_id) {
console.log("id mismath", saved_exam.exam_json_id, exam_json_id);
question_db.saved_exams.where("eid").equals(saved_exam.eid).delete();
+ db.answers.where("eid").equals(saved_exam.eid).delete();
console.log("HOL");
$(`li.cache-item[data-eid="${saved_exam.eid}"]`)
@@ -259,54 +351,63 @@ async function loadExamList(data) {
`Question (${saved_exam.exam_type}): ${q} [New JSON id: ${new_question_json_id}]`
);
// If a single question is out of date we invalidate the lot...
- const q_object = { qid: String(q), type: saved_exam.exam_type };
- console.log("q_object", q_object);
- question_db.question_data
- .get(q_object)
- .then((d) => {
- console.log("saved question data", d)
- // d is undefined if the question is not saved
- // we should really just requeue the required question for dowload...
- if (d == undefined || d.data.question_json_id != new_question_json_id) {
- $(`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"
- );
+ const q_object = {
+ qid: String(q),
+ type: saved_exam.exam_type
+ };
+ console.log(q_object);
- //question_db.saved_exams.where("eid").equals(saved_exam.eid).delete();
- question_db.question_data
- .where(["qid", "type"])
- .equals([String(q), saved_exam.exam_type])
- .delete();
- }
- d = null;
- })
- .catch((e) => {
- console.log("Error loading qusetion data", q_object);
- console.log(e);
- console.log("1234", saved_exam.eid);
- // If the question isn't found in the cache...
+ let save_question_data = await question_db.question_data.get(q_object);
+
+ try {
+ console.log("saved question data", save_question_data, new_question_json_id)
+ // saved_question_data is undefined if the question is not saved
+ // we should really just requeue the required question for dowload...
+ if (save_question_data == undefined || save_question_data.data.question_json_id != new_question_json_id) {
+ console.log(`INVALIDATE eid: ${saved_exam.eid}, q ${q}`);
$(`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]");
+ $(`li.cache-item[data-qid="${q}"]`).addClass(
+ "cache-out-of-date"
+ );
$(`.packet-button[data-eid="${saved_exam.eid}"]`).addClass(
"out-of-date"
);
+ // Invalidate associated exam
+ question_db.saved_exams.where("eid").equals(saved_exam.eid).delete();
+
+ // Invalidate and any associated answers
+ db.answers.where("eid").equals(saved_exam.eid).delete();
+
//question_db.saved_exams.where("eid").equals(saved_exam.eid).delete();
question_db.question_data
.where(["qid", "type"])
.equals([String(q), saved_exam.exam_type])
.delete();
- });
+ }
+ } catch (e) {
+ console.log("Error loading qusetion data", q_object);
+ console.log(e);
+ console.log("1234", saved_exam.eid);
+ // 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([String(q), saved_exam.exam_type])
+ .delete();
+ }
}
}
});
@@ -314,30 +415,30 @@ async function loadExamList(data) {
// Sort different lists
$(".packet-list.rapid div")
- .sort(function (a, b) {
- return a.dataset.eid > b.dataset.eid
- ? 1
- : a.dataset.eid < b.dataset.eid
- ? -1
- : 0;
+ .sort(function(a, b) {
+ return a.dataset.eid > b.dataset.eid ?
+ 1 :
+ a.dataset.eid < b.dataset.eid ?
+ -1 :
+ 0;
})
.appendTo(".packet-list.rapid");
$(".packet-list.anatomy div")
- .sort(function (a, b) {
- return a.dataset.eid > b.dataset.eid
- ? 1
- : a.dataset.eid < b.dataset.eid
- ? -1
- : 0;
+ .sort(function(a, b) {
+ return a.dataset.eid > b.dataset.eid ?
+ 1 :
+ a.dataset.eid < b.dataset.eid ?
+ -1 :
+ 0;
})
.appendTo(".packet-list.anatomy");
$(".packet-list.long div")
- .sort(function (a, b) {
- return a.dataset.eid > b.dataset.eid
- ? 1
- : a.dataset.eid < b.dataset.eid
- ? -1
- : 0;
+ .sort(function(a, b) {
+ return a.dataset.eid > b.dataset.eid ?
+ 1 :
+ a.dataset.eid < b.dataset.eid ?
+ -1 :
+ 0;
})
.appendTo(".packet-list.long");
@@ -351,7 +452,7 @@ async function loadExamList(data) {
*/
// TODO: remove (data formats should be switched to the exam format)
async function loadPacketList(data) {
- let sessions = await db.session.toArray().catch(function (error) {
+ let sessions = await db.session.toArray().catch(function(error) {
console.log("Error loading session", error);
$("#database-error").text(
"Error loading the database, schema has probably changed and needs updating. You will probably need to delete the local database."
@@ -383,7 +484,13 @@ async function loadPacketList(data) {
}
$("#packet-list").empty();
- packet_list.forEach(function (packet) {
+
+ if (packet_json_id == undefined) {
+ $("#options-panel").show();
+ return
+ }
+ //console.log(packet_list)
+ packet_list.forEach(function(packet) {
// Seperate packet types
let list;
if (packet.type != undefined) {
@@ -408,18 +515,18 @@ async function loadPacketList(data) {
}
list.append(
$(``)
- .text(packet)
- .click(function () {
- loadPacketFromAjax("packets/" + packet, packet);
+ .text(packet)
+ .click(function() {
+ loadPacketFromAjax("packets/" + packet, packet);
+ })
+ .append(
+ $(
+ ``
+ ).click(function(evt) {
+ //console.log("packets/" + packet);
+ evt.stopPropagation();
})
- .append(
- $(
- ``
- ).click(function (evt) {
- //console.log("packets/" + packet);
- evt.stopPropagation();
- })
- )
+ )
);
});
$("#options-panel").show();
@@ -435,8 +542,7 @@ function loadPacketFromAjax(path, eid, exam_json_id) {
question_db.saved_exams
.get(eid)
.then((exam) => {
- if (exam == undefined || (exam["exam_json_id"] != exam_json_id))
- {
+ if (exam == undefined || (exam["exam_json_id"] != exam_json_id)) {
console.log("AjaxRequestPacket:", eid);
ajaxRequestionPacket(true);
} else {
@@ -448,7 +554,7 @@ function loadPacketFromAjax(path, eid, exam_json_id) {
$("#options-panel").hide();
}
})
- .catch(function (error) {
+ .catch(function(error) {
// Will be triggered if eid does not exist in database
console.log("Unable to load exam:", eid);
console.log("error-", error);
@@ -469,24 +575,24 @@ function loadPacketFromAjax(path, eid, exam_json_id) {
}
$.ajax({
- dataType: "json",
- url: path,
- cache: browser_cache,
- progress: function (e) {
- if (e.lengthComputable) {
- var completedPercentage = Math.round((e.loaded * 100) / e.total);
+ dataType: "json",
+ url: path,
+ cache: browser_cache,
+ progress: function(e) {
+ if (e.lengthComputable) {
+ var completedPercentage = Math.round((e.loaded * 100) / e.total);
- $("#progress").html(
- `${completedPercentage}%
${helper.formatBytes(e.total)}`
- );
- }
- },
- })
- .done(function (data) {
+ $("#progress").html(
+ `${completedPercentage}%
${helper.formatBytes(e.total)}`
+ );
+ }
+ },
+ })
+ .done(function(data) {
setUpPacket(data, path);
$("#options-panel").hide();
})
- .fail(function () {
+ .fail(function() {
console.log("Unable to load packet at: " + path);
});
}
@@ -507,6 +613,8 @@ function setUpPacket(data, path) {
if (data.hasOwnProperty("eid")) {
exam_details.eid = data.eid;
+ } else {
+ exam_details.eid = packet_name
}
if (data.hasOwnProperty("exam_type")) {
@@ -531,7 +639,7 @@ function setUpPacket(data, path) {
exam_details.question_order = data.exam_order;
} else {
exam_details.question_order = [];
- Object.keys(questions).forEach(function (e) {
+ Object.keys(questions).forEach(function(e) {
exam_details.question_order.push(e);
// Make sure answers are arrays
@@ -568,7 +676,9 @@ function setUpPacket(data, path) {
if (!use_local_question_cache) {
// Save the details to the question database
- var clone_data = Object.assign({}, data, { questions: "cached" });
+ var clone_data = Object.assign({}, data, {
+ questions: "cached"
+ });
console.log(clone_data)
//clone_data["cached_questions"] = Object.keys(data["questions"]);
question_db.saved_exams.put(clone_data);
@@ -602,7 +712,10 @@ function setUpPacket(data, path) {
question_number++;
n = String(n);
- let obj = { qid: n, type: question_type };
+ 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
@@ -631,8 +744,7 @@ function setUpPacket(data, path) {
if (
question_json.hasOwnProperty("images_json") &&
question_json["images_json"]
- ) {
- }
+ ) {}
//requests.push(request)
//request_numbers.push(n)
@@ -669,8 +781,8 @@ function loadSession() {
db.session
// .where("status")
// .equals("active")
- .where("[packet+aid]")
- .between([packet_name, Dexie.minKey], [packet_name, Dexie.maxKey])
+ .where("[eid+aid]")
+ .between([exam_details.eid, Dexie.minKey], [exam_details.eid, Dexie.maxKey])
.toArray()
.then((sessions) => {
//console.log("sessions", sessions);
@@ -714,9 +826,15 @@ function loadSession() {
if (sessions[i].status == "active") {
text = text + `\r${i}: ${formatted_date} [In progress]`;
} else {
- text =
- text +
- `\r${i}: ${formatted_date} [Complete - score ${sessions[i].score}/${sessions[i].max_score}]`;
+ if (!exam_details.exam_mode) {
+ text =
+ text +
+ `\r${i}: ${formatted_date} [Complete - score ${sessions[i].score}/${sessions[i].max_score}]`;
+ } else {
+ text =
+ text +
+ `\r${i}: ${formatted_date} [Complete]`;
+ }
}
}
@@ -765,7 +883,7 @@ function setUpQuestions(load_previous) {
//return;
} else {
if (!use_local_question_cache) {
- Object.keys(questions).forEach(function (e) {
+ Object.keys(questions).forEach(function(e) {
// Store question data into dexie
let d = {
//eid: exam_details.eid,
@@ -780,8 +898,7 @@ function setUpQuestions(load_previous) {
}
// Set an order for the questions
- if (!load_previous) {
- }
+ if (!load_previous) {}
}
exam_details.number_of_questions = exam_details.question_order.length;
review_mode = false;
@@ -817,11 +934,14 @@ function setUpQuestions(load_previous) {
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());
- });
+ //$("#candidate-number2")
+ // .val(exam_details.cid)
+ // .change(() => {
+ // exam_details.cid = parseInt($("#candidate-number2").val());
+ // });
+ exam_details.cid = global_cid;
+ $("#candidate-number2").val(global_cid)
+ exam_details.passcode = global_passcode;
$("#start-dialog").addClass("no-close");
$("#start-dialog .exam-time").prop("disabled", "true");
@@ -852,6 +972,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
const aid = exam_details.aid;
const cid = exam_details.cid;
const eid = exam_details.eid;
+ const passcode = exam_details.passcode;
n = parseInt(n);
//console.log("loading question (n)", n);
@@ -867,7 +988,10 @@ async function loadQuestion(n, section = 1, force_reload = false) {
const qid = exam_details.question_order[n];
console.log("qid", qid)
- let q = { qid: String(qid), type: question_type };
+ let q = {
+ qid: String(qid),
+ type: question_type
+ };
console.log(q)
console.log(question_db.question_data)
@@ -885,7 +1009,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
} else {
$(".navigation[value='previous']")
.removeAttr("disabled")
- .click(function () {
+ .click(function() {
loadQuestion(n - 1);
});
}
@@ -895,7 +1019,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
} else {
$(".navigation[value='next']")
.removeAttr("disabled")
- .click(function () {
+ .click(function() {
loadQuestion(n + 1);
});
}
@@ -971,7 +1095,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
// convert the data url to a file
viewer
.urltoFile(based_img, "dicom", "application/dicom")
- .then(function (dfile) {
+ .then(function(dfile) {
// load the file using cornerstoneWADO file loader
const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(
dfile
@@ -986,7 +1110,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
const element = document.getElementById("thumb-" + id);
cornerstone.enable(element);
//cornerstone.loadImage(imageId).then(function (image) {
- cornerstone.loadAndCacheImage(imageId).then(function (image) {
+ cornerstone.loadAndCacheImage(imageId).then(function(image) {
cornerstone.displayImage(element, image);
cornerstone.resize(element);
}); // .catch( function(error) {
@@ -1021,7 +1145,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
});
function handleThumbnailClicks(id, thumbnail) {
- $(thumbnail).click(function (event) {
+ $(thumbnail).click(function(event) {
viewer.openMainImage(question_data, event, this);
});
}
@@ -1038,20 +1162,20 @@ async function loadQuestion(n, section = 1, force_reload = false) {
case "rapid": {
ap.append(
'' +
- display_n +
- '.1Case normal/abnormal⚐
'
+ display_n +
+ '.1Case normal/abnormal⚐ '
);
ap.append(
'' +
- display_n +
- '.2Reason⚐
'
+ display_n +
+ '.2Reason⚐'
);
// Handle changing display of optional answer fields and saving of data
- $("#rapid-option").change(function (evt) {
+ $("#rapid-option").change(function(evt) {
if (evt.target.value == "Abnormal") {
$("#rapid-text").css("display", "block");
} else {
@@ -1064,6 +1188,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
eid: eid,
qid: qid,
qidn: "1",
+ passcode: passcode,
ans: evt.target.value,
};
@@ -1073,14 +1198,14 @@ async function loadQuestion(n, section = 1, force_reload = false) {
});
// Save long answers on textchange
- $(".long-answer").change(function (evt) {
+ $(".long-answer").change(function(evt) {
// ignore blank text and delete any stored value
if (evt.target.value.length < 1) {
db.answers.delete([aid, cid, eid, qid, "2"]);
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(qid) +
- "-2"
+ exam_details.question_order.indexOf(qid) +
+ "-2"
).removeClass("question-saved-localdb");
return;
}
@@ -1091,6 +1216,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
eid: eid,
qid: qid,
qidn: "2",
+ passcode: passcode,
ans: evt.target.value,
};
// db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value});
@@ -1098,8 +1224,8 @@ async function loadQuestion(n, section = 1, force_reload = false) {
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(qid) +
- "-2"
+ exam_details.question_order.indexOf(qid) +
+ "-2"
).addClass("question-saved-localdb");
saveSession();
@@ -1110,8 +1236,15 @@ async function loadQuestion(n, section = 1, force_reload = false) {
// they have been loaded (should probably use then or after)
db.answers
- .get({ aid: aid, cid: cid, eid: eid, qid: qid, qidn: "1" })
- .then(function (answer) {
+ .get({
+ aid: aid,
+ cid: cid,
+ eid: eid,
+ qid: qid,
+ passcode: passcode,
+ qidn: "1"
+ })
+ .then(function(answer) {
if (answer != undefined) {
$("#rapid-option option:contains(" + answer.ans + ")").prop(
"selected",
@@ -1124,22 +1257,29 @@ async function loadQuestion(n, section = 1, force_reload = false) {
$("#rapid-option-not-answered").remove();
}
})
- .catch(function (error) {
+ .catch(function(error) {
console.log("DB", cid, eid, qid);
console.log("error-", error);
})
.then(
db.answers
- .get({ aid: aid, cid: cid, eid: eid, qid: qid, qidn: "2" })
- .then(function (answer) {
- if (answer != undefined) {
- $(".long-answer").text(answer.ans);
- }
- markAnswer(qid, question_data, n);
- })
- .catch(function (error) {
- console.log("error-", error);
- })
+ .get({
+ aid: aid,
+ cid: cid,
+ eid: eid,
+ qid: qid,
+ qidn: "2",
+ passcode: passcode,
+ })
+ .then(function(answer) {
+ if (answer != undefined) {
+ $(".long-answer").text(answer.ans);
+ }
+ markAnswer(qid, question_data, n);
+ })
+ .catch(function(error) {
+ console.log("error-", error);
+ })
);
addFlagEvents();
@@ -1151,22 +1291,22 @@ async function loadQuestion(n, section = 1, force_reload = false) {
case "anatomy": {
ap.append(
'' +
- display_n +
- '.1' +
- question_data.question +
- '⚐
'
+ display_n +
+ '.1' +
+ question_data.question +
+ '⚐'
);
- $(".long-answer").change(function (evt) {
+ $(".long-answer").change(function(evt) {
// ignore blank text and delete any stored value
if (evt.target.value.length < 1) {
db.answers.delete([aid, cid, eid, qid, "1"]);
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(qid) +
- "-1"
+ exam_details.question_order.indexOf(qid) +
+ "-1"
).removeClass("question-saved-localdb");
return;
}
@@ -1177,29 +1317,35 @@ async function loadQuestion(n, section = 1, force_reload = false) {
eid: eid,
qid: qid,
qidn: "1",
+ passcode: passcode,
ans: evt.target.value,
};
- // db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value});
db.answers.put(answer);
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(qid) +
- "-1"
+ exam_details.question_order.indexOf(qid) +
+ "-1"
).addClass("question-saved-localdb");
saveSession();
updateQuestionListPanel(answer);
});
db.answers
- .get({ aid: aid, cid: cid, eid: eid, qid: qid, qidn: "1" })
- .then(function (answer) {
+ .get({
+ aid: aid,
+ cid: cid,
+ eid: eid,
+ qid: qid,
+ qidn: "1"
+ })
+ .then(function(answer) {
if (answer != undefined) {
$(".long-answer").text(answer.ans);
}
markAnswer(qid, question_data, n);
})
- .catch(function (error) {
+ .catch(function(error) {
console.log(error);
});
@@ -1212,42 +1358,42 @@ async function loadQuestion(n, section = 1, force_reload = false) {
case "long": {
ap.append(
'' +
- display_n +
- '.1Observations⚐
'
+ display_n +
+ '.1Observations⚐'
);
ap.append(
'' +
- display_n +
- '.2Interpretation⚐
'
+ display_n +
+ '.2Interpretation⚐'
);
ap.append(
'' +
- display_n +
- '.3Principal Diagnosis⚐
'
+ display_n +
+ '.3Principal Diagnosis⚐'
);
ap.append(
'' +
- display_n +
- '.4Differential Diagnosis⚐
'
+ display_n +
+ '.4Differential Diagnosis⚐'
);
ap.append(
'' +
- display_n +
- '.5Management (if appropriate)⚐
'
+ display_n +
+ '.5Management (if appropriate)⚐'
);
// Save long answers on textchange
- $(".long-answer").change(function (evt) {
+ $(".long-answer").change(function(evt) {
const qidn = evt.target.dataset.qidn.toString();
// ignore blank text and delete any stored value
@@ -1255,19 +1401,19 @@ async function loadQuestion(n, section = 1, force_reload = false) {
db.answers.delete([aid, cid, eid, qid, qidn]);
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(qid) +
- "-" +
- qidn
+ exam_details.question_order.indexOf(qid) +
+ "-" +
+ qidn
).removeClass("question-saved-localdb");
return;
}
- // db.answers.put({aid: [cid, eid, qidn], ans: evt.target.value});
const answer = {
aid: aid,
cid: cid,
eid: eid,
qid: qid,
qidn: qidn,
+ passcode: passcode,
ans: evt.target.value,
};
@@ -1275,9 +1421,9 @@ async function loadQuestion(n, section = 1, force_reload = false) {
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(qid) +
- "-" +
- qidn
+ exam_details.question_order.indexOf(qid) +
+ "-" +
+ qidn
).addClass("question-saved-localdb");
saveSession();
updateQuestionListPanel(answer);
@@ -1297,7 +1443,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
};
db.answers
.get(obj)
- .then(function (answer) {
+ .then(function(answer) {
if (answer != undefined) {
$(".long-answer")
.eq(parseInt(answer.qidn) - 1)
@@ -1308,7 +1454,7 @@ async function loadQuestion(n, section = 1, force_reload = false) {
markAnswer(qid, question_data, n);
}
})
- .catch(function (error) {
+ .catch(function(error) {
console.log(error);
});
}
@@ -1360,23 +1506,23 @@ function setFocus(section) {
function updateQuestionListPanel(answer) {
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(answer.qid) +
- "-" +
- answer.qidn
+ exam_details.question_order.indexOf(answer.qid) +
+ "-" +
+ answer.qidn
).addClass("question-saved-localdb");
if (question_type == "rapid" && answer.qidn == "1") {
if (answer.ans == "Abnormal") {
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(answer.qid) +
- "-2"
+ exam_details.question_order.indexOf(answer.qid) +
+ "-2"
).css("display", "block");
} else {
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(answer.qid) +
- "-2"
+ exam_details.question_order.indexOf(answer.qid) +
+ "-2"
).css("display", "none");
}
}
@@ -1385,20 +1531,20 @@ function updateQuestionListPanel(answer) {
function deleteQuestionListPanelFlags(answer) {
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(answer.qid) +
- "-" +
- answer.qidn +
- " span"
+ exam_details.question_order.indexOf(answer.qid) +
+ "-" +
+ answer.qidn +
+ " span"
).css("visibility", "hidden");
}
function updateQuestionListPanelFlags(answer) {
$(
"#question-list-item-" +
- exam_details.question_order.indexOf(answer.qid) +
- "-" +
- answer.qidn +
- " span"
+ exam_details.question_order.indexOf(answer.qid) +
+ "-" +
+ answer.qidn +
+ " span"
).css("visibility", "visible");
}
/**
@@ -1412,34 +1558,42 @@ function rebuildQuestionListPanel() {
const eid = exam_details.eid;
db.answers
- .where({ aid: aid, cid: cid, eid: eid })
+ .where({
+ aid: aid,
+ cid: cid,
+ eid: eid
+ })
.toArray()
- .then(function (answers) {
+ .then(function(answers) {
// Reset all classes (of question-list-item s)
$(".question-list-panel div")
.slice(1)
.attr("class", "question-list-item");
// Loop through each saved answer
- answers.forEach(function (answer, n) {
+ answers.forEach(function(answer, n) {
updateQuestionListPanel(answer);
});
// $(".long-answer").text(answer.ans);
})
- .catch(function (error) {
+ .catch(function(error) {
console.log("error - ", error);
});
db.flags
- .where({ aid: aid, cid: cid, eid: eid })
+ .where({
+ aid: aid,
+ cid: cid,
+ eid: eid
+ })
.toArray()
- .then(function (answers) {
- answers.forEach(function (answer, n) {
+ .then(function(answers) {
+ answers.forEach(function(answer, n) {
updateQuestionListPanelFlags(answer);
});
// $(".long-answer").text(answer.ans);
})
- .catch(function (error) {
+ .catch(function(error) {
console.log("error - ", error);
});
@@ -1482,18 +1636,18 @@ function createQuestionListPanel() {
const qn = n - 1;
const el = $(
'' +
- n +
- "." +
- qidn +
- '⚑
'
+ qn +
+ "-" +
+ qidn +
+ '" data-qid=' +
+ qn +
+ ' data-qidn="' +
+ qidn +
+ '" class="question-list-item">' +
+ n +
+ "." +
+ qidn +
+ '⚑'
);
$(".question-list-panel").append(el);
// return the new element so it can be hidden if necessary
@@ -1520,31 +1674,31 @@ function createQuestionListPanel() {
}
}
- $(".question-list-item").click(function (evt) {
+ $(".question-list-item").click(function(evt) {
loadQuestion($(this).attr("data-qid"), $(this).attr("data-qidn"));
});
rebuildQuestionListPanel();
}
-$("#btn-local-file-load").click(function (evt) {
+$("#btn-local-file-load").click(function(evt) {
loadLocalQuestionSet();
});
-$(".submit-button").click(function (evt) {
+$(".submit-button").click(function(evt) {
interact.submitAnswers(exam_details, db, config);
});
-$("#review-button").click(function (evt) {
+$("#review-button").click(function(evt) {
$(".question-list-panel").toggle();
});
-$("#options-button").click(function (evt) {
+$("#options-button").click(function(evt) {
loadPacketList(null);
$("#options-panel").toggle();
});
-$("#review-overlay-button").click(function (evt) {
+$("#review-overlay-button").click(function(evt) {
if (review_mode == true) {
reviewQuestions();
} else {
@@ -1552,7 +1706,7 @@ $("#review-overlay-button").click(function (evt) {
}
});
-$("#fullscreen-overlay-button").click(function (evt) {
+$("#fullscreen-overlay-button").click(function(evt) {
if (document.fullscreen == false) {
document.documentElement.requestFullscreen();
} else {
@@ -1560,25 +1714,25 @@ $("#fullscreen-overlay-button").click(function (evt) {
}
});
-$("#finish-exam, #time-up-review-button").click(function (evt) {
+$("#finish-exam, #time-up-review-button").click(function(evt) {
review_mode = true;
reviewQuestions();
$.modal.close();
});
-$("#time-up-continue-button").click(function (evt) {
+$("#time-up-continue-button").click(function(evt) {
$.modal.close();
});
-$("#finish-cancel").click(function (evt) {
+$("#finish-cancel").click(function(evt) {
$.modal.close();
});
-$("#overlay-close").click(function (evt) {
+$("#overlay-close").click(function(evt) {
$("#options-panel").hide();
});
-$("#review-overlay-close").click(function (evt) {
+$("#review-overlay-close").click(function(evt) {
$("#review-overlay").hide();
});
@@ -1645,11 +1799,15 @@ function reviewQuestions() {
loadQuestion(0, 0, true);
db.answers
- .where({ aid: aid, cid: cid, eid: eid })
+ .where({
+ aid: aid,
+ cid: cid,
+ eid: eid
+ })
.toArray()
- .then(function (answers) {
+ .then(function(answers) {
let current_answers = {};
- answers.forEach(function (arr, n) {
+ answers.forEach(function(arr, n) {
let answer = arr["ans"];
if (answer == undefined) {
answer = "Not answered";
@@ -1665,8 +1823,11 @@ function reviewQuestions() {
let undercall_number = 0;
let overcall_number = 0;
let incorrectcall_number = 0;
- exam_details.question_order.forEach(async function (qid, n) {
- const q_object = { qid: String(qid), type: question_type };
+ exam_details.question_order.forEach(async function(qid, n) {
+ const q_object = {
+ qid: String(qid),
+ type: question_type
+ };
let question = await question_db.question_data.get(q_object);
question = question.data;
if (question_type == "long") {
@@ -1734,12 +1895,12 @@ function reviewQuestions() {
// TOOD fix
$("#review-answer-table tr")
- .sort(function (a, b) {
- return a.dataset.qid > b.dataset.qid
- ? 1
- : a.dataset.qid < b.dataset.qid
- ? -1
- : 0;
+ .sort(function(a, b) {
+ return a.dataset.qid > b.dataset.qid ?
+ 1 :
+ a.dataset.qid < b.dataset.qid ?
+ -1 :
+ 0;
})
.appendTo("#review-answer-table");
return;
@@ -1747,24 +1908,32 @@ function reviewQuestions() {
$("#review-answer-list").append(
"Question " +
- (n + 1) +
- ": Not answered"
+ qid +
+ "' data-qid=" +
+ n.toString().padStart(2, "0") +
+ "'>Question " +
+ (n + 1) +
+ ": Not answered"
);
- $("#review-answer-list a").click(function (evt) {
+ $("#review-answer-list a").click(function(evt) {
loadQuestion(this.dataset.qid);
$("#review-overlay").hide();
});
+ console.log(db.user_answers)
+ console.log({
+ type: question_type,
+ qid: qid
+ })
db.user_answers
- .where({ type: question_type, qid: qid })
+ .where({
+ type: question_type,
+ qid: qid
+ })
.toArray()
- .then(function (answers) {
+ .then(function(answers) {
// Merge the question answers with the user saved answers
let question_answers = question["answers"];
if (answers != undefined) {
@@ -1811,25 +1980,26 @@ function reviewQuestions() {
) {
if (normal) {
el.html(
- "Answer: " +
- user_answer +
- " (Normal)"
+ `Answer: ${user_answer} (Normal)`
);
} else {
el.html(
- "Answer: " +
- user_answer +
- " (Abnormal: " +
- question_answers.join(", ") +
- ")"
+ `Answer: ${user_answer} (Abnormal: ${question_answers.join(', ')})`
);
}
}
+ function setAnatomyReviewAnswer(
+ el,
+ c,
+ user_answer,
+ question_answers
+ ) {
+ el.html(
+ `Answer: ${user_answer} (Correct answers: ${question_answers.join(', ')})`
+ )
+ }
+
if (question_type == "rapid") {
// First check normal vs abnormal
if (question["normal"] == true) {
@@ -1877,8 +2047,7 @@ function reviewQuestions() {
);
questions_correct[qid] = false;
- if (section_1_answer == "Not Answered") {
- } else if (section_1_answer == "Normal") {
+ if (section_1_answer == "Not Answered") {} else if (section_1_answer == "Normal") {
undercall_number++;
} else {
// Incorrect calls could be correct if
@@ -1898,20 +2067,18 @@ function reviewQuestions() {
// Anatomy answers are either correct or incorrect
if (answerInArray(question_answers, section_1_answer)) {
correct_count++;
- setReviewAnswer(
+ setAnatomyReviewAnswer(
el,
"correct",
section_1_answer,
- false,
question_answers
);
questions_correct[qid] = true;
} else {
- setReviewAnswer(
+ setAnatomyReviewAnswer(
el,
"incorrect",
section_1_answer,
- false,
question_answers
);
questions_correct[qid] = false;
@@ -1922,9 +2089,9 @@ function reviewQuestions() {
$("#review-score").text(
"Score: " +
- correct_count +
- " out of " +
- exam_details.question_order.length
+ correct_count +
+ " out of " +
+ exam_details.question_order.length
);
if (question_type == "rapid") {
@@ -1939,7 +2106,7 @@ function reviewQuestions() {
$("#exam-stats").show();
}
})
- .catch(function (error) {
+ .catch(function(error) {
console.log("error-", error);
})
.finally(() => {
@@ -1948,18 +2115,18 @@ function reviewQuestions() {
rebuildQuestionListPanel();
$("#review-answer-list li")
- .sort(function (a, b) {
- return a.dataset.qid > b.dataset.qid
- ? 1
- : a.dataset.qid < b.dataset.qid
- ? -1
- : 0;
+ .sort(function(a, b) {
+ return a.dataset.qid > b.dataset.qid ?
+ 1 :
+ a.dataset.qid < b.dataset.qid ?
+ -1 :
+ 0;
})
.appendTo("#review-answer-list");
});
});
})
- .catch(function (error) {
+ .catch(function(error) {
console.log("error - ", error);
});
}
@@ -2025,13 +2192,16 @@ function markAnswer(qid, current_question, n) {
// Load user saved answers
db.user_answers
- .where({ type: type, qid: qid })
+ .where({
+ type: type,
+ qid: qid
+ })
.toArray()
- .then(function (saved_user_answers) {
+ .then(function(saved_user_answers) {
// check if given answer matches a user saved answer
if (saved_user_answers != undefined) {
//console.log(saved_user_answers);
- saved_user_answers.forEach(function (saved_answer_object, n) {
+ saved_user_answers.forEach(function(saved_answer_object, n) {
let saved_answer = saved_answer_object.ans;
//console.log("ua", user_answer, saved_answer);
ul.append("" + saved_answer + "");
@@ -2059,7 +2229,7 @@ function markAnswer(qid, current_question, n) {
}
// check if given answer matches an answer from the question
- current_question.answers.forEach(function (answer, n) {
+ current_question.answers.forEach(function(answer, n) {
ul.append("" + answer + "");
if (compareString(answer, user_answer)) {
textarea.removeClass("incorrect").addClass("correct");
@@ -2080,7 +2250,7 @@ function markAnswer(qid, current_question, n) {
if (allow_self_marking) {
$(".answer-panel").append(
$("Mark Correct").click(
- function () {
+ function() {
markCorrect(qid, user_answer, type);
loadQuestion(n, 0, true);
}
@@ -2090,7 +2260,7 @@ function markAnswer(qid, current_question, n) {
}
}
})
- .catch(function (error) {
+ .catch(function(error) {
console.log("error-", error);
});
addFeedback(current_question, qid);
@@ -2107,8 +2277,8 @@ function addFeedback(current_question, qid) {
$(".answer-panel").append(
$(
"Feedback
" +
- current_question.feedback +
- ""
+ current_question.feedback +
+ ""
)
);
}
@@ -2173,8 +2343,8 @@ function compareString(a, b) {
function answerInArray(arr, ans) {
return (
arr
- .map((v) => v.toLowerCase().replace(/\s/g, ""))
- .includes(ans.toLowerCase().replace(/\s/g, "")) == true
+ .map((v) => v.toLowerCase().replace(/\s/g, ""))
+ .includes(ans.toLowerCase().replace(/\s/g, "")) == true
);
}
@@ -2184,7 +2354,7 @@ function addFlagEvents() {
const eid = exam_details.eid;
// Bind flag change events
- $("button.flag").click(function (event) {
+ $("button.flag").click(function(event) {
const el = $(this);
const nqid = el.attr("data-qid");
const qid = exam_details.question_order[nqid];
@@ -2192,7 +2362,13 @@ function addFlagEvents() {
el.toggleClass("flag flag-selected");
- const flag_db_data = { aid: aid, cid: cid, eid: eid, qid: qid, qidn: qidn };
+ const flag_db_data = {
+ aid: aid,
+ cid: cid,
+ eid: eid,
+ qid: qid,
+ qidn: qidn
+ };
if (el.hasClass("flag")) {
$("#question-list-item-" + nqid + "-" + qidn + " span").css(
@@ -2218,15 +2394,21 @@ function loadFlagsFromDb(qid, n) {
const cid = exam_details.cid;
const eid = exam_details.eid;
db.flags
- .get({ aid: aid, cid: cid, eid: eid, qid: qid, qidn: n })
- .then(function (answer) {
+ .get({
+ aid: aid,
+ cid: cid,
+ eid: eid,
+ qid: qid,
+ qidn: n
+ })
+ .then(function(answer) {
if (answer != undefined) {
$("button.flag, button.flag-selected")
.eq(parseInt(answer.qidn) - 1)
.toggleClass("flag flag-selected");
}
})
- .catch(function (error) {
+ .catch(function(error) {
console.log(error);
});
}
@@ -2235,18 +2417,41 @@ function showLoginDialog() {
$("#login-dialog").modal();
}
-$("#start-exam-button").click(function (evt) {
- exam_details.cid = parseInt($("#candidate-number").val());
+$("#btn-candidate-login").click(function(evt) {
+ $("#login-dialog").modal({
+ escapeClose: false,
+ clickClose: false,
+ showClose: false
+ });
+ $("#options-panel").toggle();
+ $(".exam-wrapper").toggle();
+});
+
+
+$("#login-button").click(function(evt) {
+ global_cid = parseInt($("#candidate-number").val());
+ global_passcode = $("#passcode").val();
+
+ user_db.user.clear().then(() => {
+ user_db.user.add({
+ cid: global_cid,
+ passcode: global_passcode
+ })
+ location.reload();
+ });
$.modal.close();
});
-$(".start-packet-button").click(function (evt) {
- if (exam_details.exam_mode) {
- if (!Number.isInteger(parseInt($("#candidate-number2").val()))) {
- alert("Please enter a valid candidate number.");
- return;
- }
- }
+$(".start-packet-button").click(function(evt) {
+ // No longer needed as candidates log in...
+ //if (exam_details.exam_mode) {
+ // if (!Number.isInteger(parseInt($("#candidate-number2").val()))) {
+ // alert("Please enter a valid candidate number.");
+ // return;
+ // }
+ //}
+
+ exam_details.start_time = new Date().getTime() / 1000;
if (timer != null) {
timer.stop();
@@ -2255,11 +2460,16 @@ $(".start-packet-button").click(function (evt) {
timer = new easytimer.Timer();
//exam_time = 2;
- timer.start({ countdown: true, startValues: { seconds: exam_time } });
- timer.addEventListener("secondsUpdated", function (e) {
+ timer.start({
+ countdown: true,
+ startValues: {
+ seconds: exam_time
+ }
+ });
+ timer.addEventListener("secondsUpdated", function(e) {
$("#timer").html("Time left: " + timer.getTimeValues().toString());
});
- timer.addEventListener("targetAchieved", function (e) {
+ timer.addEventListener("targetAchieved", function(e) {
if (exam_details.exam_mode == true) {
$(
"#dialog-submit-button, #time-up-review-button, #time-up-continue-button"
@@ -2317,7 +2527,7 @@ $(".start-packet-button").click(function (evt) {
$.modal.close();
});
-$("#btn-delete-answer-databases").click(function (evt) {
+$("#btn-delete-answer-databases").click(function(evt) {
var r = confirm(
"This will delete ALL saved answers (including saved correct answers)!"
);
@@ -2338,10 +2548,9 @@ $("#btn-delete-answer-databases").click(function (evt) {
.finally(() => {
// Do what should be done next...
});
- } else {
- }
+ } else {}
});
-$("#btn-delete-cached-questions").click(function (evt) {
+$("#btn-delete-cached-questions").click(function(evt) {
var r = confirm("Delete cached questions?");
if (r == true) {
question_db
@@ -2361,11 +2570,10 @@ $("#btn-delete-cached-questions").click(function (evt) {
.finally(() => {
// Do what should be done next...
});
- } else {
- }
+ } else {}
});
-$("#btn-delete-current").click(function (evt) {
+$("#btn-delete-current").click(function(evt) {
if (exam_details.question_order.length < 1) {
$.notify("No packet is currently loaded", "warn");
return;
@@ -2375,7 +2583,7 @@ $("#btn-delete-current").click(function (evt) {
.where("qid")
.anyOf(exam_details.question_order)
.delete()
- .then(function (deleteCount) {
+ .then(function(deleteCount) {
$.notify("Packet flags deleted", "success");
})
.catch((err) => {
@@ -2387,7 +2595,7 @@ $("#btn-delete-current").click(function (evt) {
.where("qid")
.anyOf(exam_details.question_order)
.delete()
- .then(function (deleteCount) {
+ .then(function(deleteCount) {
$.notify("Packet successfully reset", "success");
loadQuestion(0, 0, true);
// $.notify("The page will now reload", "warn");
@@ -2403,7 +2611,7 @@ $("#btn-delete-current").click(function (evt) {
});
});
-$("#btn-delete-current-saved-answers").click(function (evt) {
+$("#btn-delete-current-saved-answers").click(function(evt) {
if (exam_details.question_order.length < 1) {
$.notify("No packet is currently loaded", "warn");
return;
@@ -2414,7 +2622,7 @@ $("#btn-delete-current-saved-answers").click(function (evt) {
.where("qid")
.anyOf(exam_details.question_order)
.delete()
- .then(function (deleteCount) {
+ .then(function(deleteCount) {
$.notify("Packet answers deleted", "success");
})
.catch((err) => {
@@ -2423,11 +2631,11 @@ $("#btn-delete-current-saved-answers").click(function (evt) {
});
});
-$(document).ajaxStart(function () {
+$(document).ajaxStart(function() {
$("#loading").show();
});
-$(document).ajaxStop(function () {
+$(document).ajaxStop(function() {
$("#loading").hide();
});
@@ -2450,8 +2658,10 @@ function saveSession(start_review) {
time_values.seconds;
db.session.put({
packet: packet_name,
+ eid: exam_details.eid,
aid: exam_details.aid,
cid: exam_details.cid,
+ passcode: exam_details.passcode,
status: status,
date: date_started,
score: score,
@@ -2485,10 +2695,14 @@ $(document).on("saveSessionEvent", {}, (evt, review) => {
saveSession(review);
});
+$(document).contextmenu(() => {
+ return false;
+})
+
// Helper to compare dates
function compareDates(d1, d2) {
console.log("compare", d1, d2);
console.log("compare striped", Date.parse(d1.split("+")[0]), Date.parse(d2.split("+")[0]));
console.log("compare striped", Date.parse(d1.split("+")[0]), Date.parse(d2.split("+")[0]));
return Date.parse(d1.split("+")[0]) != Date.parse(d2.split("+")[0]);
-}
+}
\ No newline at end of file