Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit 8629d5d

Browse files
committed
Merge pull request #86 from ericsonga/master
Fixes to timed exams.
2 parents 574cb2e + 36d2112 commit 8629d5d

File tree

3 files changed

+132
-57
lines changed

3 files changed

+132
-57
lines changed

runestone/assess/css/bootstrap.min.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runestone/assess/js/timed.js

Lines changed: 130 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ Timed.prototype.init = function (opts) {
5757
this.taken = 0;
5858
this.score = 0;
5959
this.incorrect = 0;
60+
this.correctStr = "";
61+
this.incorrectStr = "";
62+
this.skippedStr = "";
6063
this.skipped = 0;
6164

6265
this.currentQuestionIndex = 0; // Which question is currently displaying on the page
@@ -90,6 +93,12 @@ Timed.prototype.renderTimedAssess = function () {
9093

9194
// Replace intermediate HTML with rendered HTML
9295
$(this.origElem).replaceWith(this.assessDiv);
96+
97+
// check if already taken and if so show results
98+
this.tookTimedExam();
99+
if (this.taken) {
100+
this.handlePrevAssessment();
101+
}
93102
};
94103

95104
Timed.prototype.renderContainer = function () {
@@ -98,9 +107,9 @@ Timed.prototype.renderContainer = function () {
98107
this.timedDiv = document.createElement("div"); // div that will hold the questions for the timed assessment
99108
this.navDiv = document.createElement("div"); // For navigation control
100109
$(this.navDiv).attr({"style": "text-align:center"});
101-
this.timedDiv.appendChild(this.navDiv);
102110
this.switchDiv = document.createElement("div"); // is replaced by the questions
103111
this.timedDiv.appendChild(this.switchDiv);
112+
this.timedDiv.appendChild(this.navDiv);
104113
$(this.timedDiv).attr({ // set the id, and style the div to be hidden
105114
"id": "timed_Test",
106115
"style": "display:none"
@@ -113,6 +122,7 @@ Timed.prototype.renderTimer = function () {
113122
this.wrapperDiv.id = "startWrapper";
114123
this.timerContainer.id = "output";
115124
this.wrapperDiv.appendChild(this.timerContainer);
125+
this.showTime();
116126
};
117127

118128
Timed.prototype.renderControlButtons = function () {
@@ -124,7 +134,7 @@ Timed.prototype.renderControlButtons = function () {
124134
this.startBtn = document.createElement("btn");
125135
this.pauseBtn = document.createElement("btn");
126136
$(this.startBtn).attr({
127-
"class": "btn btn-default",
137+
"class": "btn btn-success",
128138
"id": "start"
129139
});
130140
this.startBtn.textContent = "Start";
@@ -145,13 +155,15 @@ Timed.prototype.renderControlButtons = function () {
145155
this.assessDiv.appendChild(this.wrapperDiv);
146156
this.assessDiv.appendChild(this.controlDiv);
147157
};
158+
159+
148160
Timed.prototype.renderNavControls = function () {
149-
var _this = this;
161+
_this = this;
150162
this.pagNavList = document.createElement("ul");
151163
$(this.pagNavList).addClass("pagination");
152164
this.leftContainer = document.createElement("li");
153165
this.leftNavButton = document.createElement("a");
154-
this.leftNavButton.innerHTML = "&laquo";
166+
this.leftNavButton.innerHTML = "‹ Prev";
155167
$(this.leftNavButton).attr("aria-label", "Previous");
156168
$(this.leftNavButton).css("cursor", "pointer");
157169
this.leftNavButton.addEventListener("click", function () {
@@ -161,37 +173,17 @@ Timed.prototype.renderNavControls = function () {
161173
this.currentQuestionIndex--;
162174
this.renderTimedQuestion();
163175
this.ensureButtonSafety();
164-
for (var i = 0; i < _this.pagNavList.childNodes.length; i++) {
165-
$(this.pagNavList.childNodes[i]).removeClass("active");
176+
for (var i = 0; i < this.qNumList.childNodes.length; i++) {
177+
$(this.qNumList.childNodes[i]).removeClass("active");
166178
}
167-
$(this.pagNavList.childNodes[this.currentQuestionIndex + 1]).addClass("active");
179+
$(this.qNumList.childNodes[this.currentQuestionIndex]).addClass("active");
168180
}.bind(this), false);
169181
this.leftContainer.appendChild(this.leftNavButton);
170182
this.pagNavList.appendChild(this.leftContainer);
171-
for (var i = 0; i < this.renderedQuestionArray.length; i++) {
172-
var tmpLi = document.createElement("li");
173-
var tmpA = document.createElement("a");
174-
tmpA.innerHTML = i + 1;
175-
$(tmpA).css("cursor", "pointer");
176-
if (i === 0) {
177-
$(tmpLi).addClass("active");
178-
}
179-
tmpA.onclick = function () {
180-
_this.currentQuestionIndex = this.innerHTML - 1;
181-
_this.renderTimedQuestion();
182-
_this.ensureButtonSafety();
183-
for (var i = 0; i < _this.pagNavList.childNodes.length; i++) {
184-
$(_this.pagNavList.childNodes[i]).removeClass("active");
185-
}
186-
$(this.parentNode).addClass("active");
187-
};
188-
tmpLi.appendChild(tmpA);
189-
this.pagNavList.appendChild(tmpLi);
190-
}
191183
this.rightContainer = document.createElement("li");
192184
this.rightNavButton = document.createElement("a");
193185
$(this.rightNavButton).attr("aria-label", "Next");
194-
this.rightNavButton.innerHTML = "&raquo";
186+
this.rightNavButton.innerHTML = "Next &#8250;";
195187
$(this.rightNavButton).css("cursor", "pointer");
196188
this.rightNavButton.addEventListener("click", function () {
197189
if ($(this.rightContainer).hasClass("disabled")) {
@@ -200,17 +192,43 @@ Timed.prototype.renderNavControls = function () {
200192
this.currentQuestionIndex++;
201193
this.renderTimedQuestion();
202194
this.ensureButtonSafety();
203-
for (var i = 0; i < _this.pagNavList.childNodes.length; i++) {
204-
$(this.pagNavList.childNodes[i]).removeClass("active");
195+
for (var i = 0; i < this.qNumList.childNodes.length; i++) {
196+
$(this.qNumList.childNodes[i]).removeClass("active");
205197
}
206-
$(this.pagNavList.childNodes[this.currentQuestionIndex + 1]).addClass("active");
198+
$(this.qNumList.childNodes[this.currentQuestionIndex]).addClass("active");
207199
}.bind(this), false);
208200
this.rightContainer.appendChild(this.rightNavButton);
209201
this.pagNavList.appendChild(this.rightContainer);
210202
this.ensureButtonSafety();
211203
this.navDiv.appendChild(this.pagNavList);
204+
205+
// render the question number jump buttons
206+
this.qNumList = document.createElement("ul");
207+
$(this.qNumList).addClass("pagination");
208+
for (var i = 0; i < this.renderedQuestionArray.length; i++) {
209+
var tmpLi = document.createElement("li");
210+
var tmpA = document.createElement("a");
211+
tmpA.innerHTML = i + 1;
212+
$(tmpA).css("cursor", "pointer");
213+
if (i === 0) {
214+
$(tmpLi).addClass("active");
215+
}
216+
tmpA.onclick = function () {
217+
_this.currentQuestionIndex = this.innerHTML - 1;
218+
_this.renderTimedQuestion();
219+
_this.ensureButtonSafety();
220+
for (var i = 0; i < _this.qNumList.childNodes.length; i++) {
221+
$(_this.qNumList.childNodes[i]).removeClass("active");
222+
}
223+
$(this.parentNode).addClass("active");
224+
};
225+
tmpLi.appendChild(tmpA);
226+
this.qNumList.appendChild(tmpLi);
227+
}
228+
this.navDiv.appendChild(this.qNumList);
212229

213230
};
231+
214232
Timed.prototype.renderSubmitButton = function () {
215233
this.buttonContainer = document.createElement("div");
216234
$(this.buttonContainer).attr({"style": "text-align:center"});
@@ -219,7 +237,7 @@ Timed.prototype.renderSubmitButton = function () {
219237
"id": "finish",
220238
"class": "btn btn-inverse"
221239
});
222-
this.finishButton.textContent = "Submit answers";
240+
this.finishButton.textContent = "Submit Answers";
223241
this.finishButton.addEventListener("click", function () {
224242
this.finishAssessment();
225243
}.bind(this), false);
@@ -300,26 +318,32 @@ Timed.prototype.renderTimedQuestion = function () {
300318
=== Timer and control Functions ===
301319
=================================*/
302320

321+
Timed.prototype.handlePrevAssessment = function () {
322+
$(this.startBtn).hide();
323+
$(this.pauseBtn).attr("disabled", true);
324+
$(this.finishButton).attr("disabled", true);
325+
this.running = 0;
326+
this.done = 1;
327+
$(this.timedDiv).show();
328+
this.submitTimedProblems();
329+
}
330+
303331
Timed.prototype.startAssessment = function () {
332+
304333
this.tookTimedExam();
305334
if (!this.taken) {
306-
$(this.startBtn).attr("disabled", true);
335+
$(this.startBtn).hide();
307336
$(this.pauseBtn).attr("disabled", false);
308337
if (this.running === 0 && this.paused === 0) {
309338
this.running = 1;
310339
$(this.timedDiv).show();
311340
this.increment();
312341
this.logBookEvent({"event": "timedExam", "act": "start", "div_id": this.divid});
313-
localStorage.setItem(eBookConfig.email + ":" + this.divid, "started");
342+
var resultStr = "0; ;0; ;" + this.renderedQuestionArray.length +"; ;0";
343+
localStorage.setItem(eBookConfig.email + ":" + this.divid, resultStr);
314344
}
315345
} else {
316-
$(this.startBtn).attr("disabled", true);
317-
$(this.pauseBtn).attr("disabled", true);
318-
$(this.finishButton).attr("disabled", true);
319-
this.running = 0;
320-
this.done = 1;
321-
$(this.timedDiv).show();
322-
this.submitTimedProblems();
346+
this.handlePrevAssessment();
323347
}
324348
};
325349

@@ -413,7 +437,6 @@ Timed.prototype.checkIfFinished = function () {
413437
$(this.pauseBtn).attr("disabled", true);
414438
$(this.finishButton).attr("disabled", true);
415439
this.resetTimedMCMFStorage();
416-
//$(this.timedDiv).show();
417440
}
418441
};
419442

@@ -489,17 +512,32 @@ Timed.prototype.hideTimedFeedback = function () {
489512
};
490513

491514
Timed.prototype.checkScore = function () {
515+
this.correctStr = "";
516+
this.skippedStr = "";
517+
this.incorrectStr = "";
518+
492519
// Gets the score of each problem
493520
for (var i = 0; i < this.renderedQuestionArray.length; i++) {
494521
var correct = this.renderedQuestionArray[i].checkCorrectTimed();
495522
if (correct) {
496523
this.score++;
524+
this.correctStr = this.correctStr + (i + 1) + ", ";
497525
} else if (correct === null) {
498526
this.skipped++;
527+
this.skippedStr = this.skippedStr + (i + 1) + ", ";
499528
} else {
500529
this.incorrect++;
530+
this.incorrectStr = this.incorrectStr + (i + 1) + ", ";
501531
}
502532
}
533+
534+
// remove extra comma and space at end if any
535+
if (this.correctStr.length > 0) this.correctStr = this.correctStr.substring(0,this.correctStr.length-2);
536+
else this.correctStr = "None";
537+
if (this.skippedStr.length > 0) this.skippedStr = this.skippedStr.substring(0,this.skippedStr.length-2);
538+
else this.skippedStr = "None";
539+
if (this.incorrectStr.length > 0) this.incorrectStr = this.incorrectStr.substring(0,this.incorrectStr.length-2);
540+
else this.incorrectStr = "None";
503541
};
504542

505543
Timed.prototype.findTimeTaken = function () {
@@ -512,7 +550,7 @@ Timed.prototype.findTimeTaken = function () {
512550

513551
Timed.prototype.storeScore = function () {
514552
var storage_arr = [];
515-
storage_arr.push(this.score, this.incorrect, this.skipped, this.timeTaken);
553+
storage_arr.push(this.score, this.correctStr, this.incorrect, this.incorrectStr, this.skipped, this.skippedStr, this.timeTaken);
516554
localStorage.setItem(eBookConfig.email + ":" + this.divid, storage_arr.join(";"));
517555
};
518556

@@ -522,23 +560,60 @@ Timed.prototype.logScore = function () {
522560

523561
Timed.prototype.restoreFromStorage = function () {
524562
var tmpArr = localStorage.getItem(eBookConfig.email + ":" + this.divid).split(";");
525-
this.score = tmpArr[0];
526-
this.incorrect = tmpArr[1];
527-
this.skipped = tmpArr[2];
528-
this.timeTaken = tmpArr[3];
563+
if (tmpArr.length == 4)
564+
{
565+
this.score = tmpArr[0];
566+
this.incorrect = tmpArr[1];
567+
this.skipped = tmpArr[2];
568+
this.timeTaken = tmpArr[3];
569+
}
570+
else if (tmpArr.length == 7)
571+
{
572+
this.score = tmpArr[0];
573+
this.correctStr = tmpArr[1];
574+
this.incorrect = tmpArr[2];
575+
this.incorrectStr = tmpArr[3];
576+
this.skipped = tmpArr[4];
577+
this.skippedStr = tmpArr[5];
578+
this.timeTaken = tmpArr[6];
579+
}
580+
else {
581+
this.score = 0;
582+
this.incorrect = 0;
583+
this.skipped = this.renderedQuestionArray.length;
584+
this.timeTaken = 0;
585+
}
529586
this.displayScore();
530587
this.showTime();
531588
};
532589

533590
Timed.prototype.displayScore = function () {
534-
if (this.showResults) {
535-
var scoreString = "Num Correct: " + this.score + " Num Wrong: " + this.incorrect + " Num Skipped: " + this.skipped;
536-
var numQuestions = this.renderedQuestionArray.length;
537-
var percentCorrect = (this.score / numQuestions) * 100;
538-
scoreString += " Percent Correct: " + percentCorrect + "%";
539-
$(this.scoreDiv).text(scoreString);
540-
this.scoreDiv.style.display = "block";
541-
}
591+
if (this.showResults)
592+
{
593+
// If we have the list of
594+
if (this.correctStr.length > 0 || this.incorrectStr.length > 0 || this.skippedStr.length > 0)
595+
{
596+
var scoreString = "Num Correct: " + this.score + ". Questions: " + this.correctStr + "<br>" +
597+
"Num Wrong: " + this.incorrect + ". Questions: " + this.incorrectStr + "<br>" +
598+
"Num Skipped: " + this.skipped + ". Questions: " + this.skippedStr + "<br>";
599+
var numQuestions = this.renderedQuestionArray.length;
600+
var percentCorrect = (this.score / numQuestions) * 100;
601+
scoreString += "Percent Correct: " + percentCorrect + "%";
602+
$(this.scoreDiv).html(scoreString);
603+
this.scoreDiv.style.display = "block";
604+
}
605+
else
606+
{
607+
var scoreString = "Num Correct: " + this.score + "<br>" +
608+
"Num Wrong: " + this.incorrect + "<br>" +
609+
"Num Skipped: " + this.skipped + "<br>";
610+
var numQuestions = this.renderedQuestionArray.length;
611+
var percentCorrect = (this.score / numQuestions) * 100;
612+
scoreString += "Percent Correct: " + percentCorrect + "%";
613+
$(this.scoreDiv).html(scoreString);
614+
this.scoreDiv.style.display = "block";
615+
}
616+
}
542617
};
543618

544619
/*=======================================================

runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/static/bootstrap-3.0.0/css/bootstrap.min.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)