Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

New feature:

Maximum-number-of-questions-per-page
  • Loading branch information...
commit d70ccc495ca904789940f281655b94d9a8e8637b 1 parent edb42f0
kaipe authored
2  lang/en/quiz.php
View
@@ -11,6 +11,7 @@
$string['addrandom2'] = 'random questions ';
$string['addselectedtoquiz'] = 'Add selected to quiz';
$string['aiken'] = 'Aiken format';
+$string['allinone'] = 'Unlimited';
$string['allowreview'] = 'Allow review';
$string['alreadysubmitted'] = 'It is likely that you have already submitted this attempt';
$string['alternativeunits'] = 'Alternative Units';
@@ -199,6 +200,7 @@
$string['questionname'] = 'Question name';
$string['questionnametoolong'] = 'Question name too long at line $a (255 char. max). It has been truncated.';
$string['questions'] = 'Questions';
+$string['questionsperpage'] = 'Max number of questions per page';
$string['quizavailable'] = 'The quiz is available until: $a';
$string['quizclose'] = 'Close the quiz';
$string['quizclosed'] = 'This quiz closed on $a';
78 mod/quiz/attempt.php
View
@@ -165,6 +165,9 @@
} else if ('shuffleorder' == $key) {
$shuffleorder = explode(",", $value); // Actual order questions were given in
+ } else if ('navigation' == $key) {
+ $navigation = $value; // Determines next page to show in quiz
+
} else { // Useful for debugging new question types. Must be last.
error("Unrecognizable input has been posted ($key -> $value)");
}
@@ -184,13 +187,16 @@
$questions[$qid]->maxgrade = $grade->grade;
}
- if (!$result = quiz_grade_responses($quiz, $questions)) {
+ if (!$result = quiz_grade_responses($quiz, $questions, $unattempt->id)) {
error("Could not grade your quiz attempt!");
}
- if ($attempt = quiz_save_attempt($quiz, $questions, $result, $attemptnumber)) {
- add_to_log($course->id, "quiz", "submit",
+ if ($attempt = quiz_save_attempt($quiz, $questions, $result,
+ $attemptnumber, 0 == $navigation)) {
+ if (empty($navigation)) {
+ add_to_log($course->id, "quiz", "submit",
"review.php?id=$cm->id&attempt=$attempt->id", "$quiz->id", $cm->id);
+ }
} else {
notice(get_string("alreadysubmitted", "quiz"), "view.php?id=$cm->id");
if (empty($quiz->popup)) {
@@ -199,38 +205,51 @@
exit;
}
- if (! quiz_save_best_grade($quiz, $USER->id)) {
- error("Sorry! Could not calculate your best grade!");
- }
-
- if (empty($quiz->popup) and !$quiz->feedback) {
- // No need to stop on this page, go directly to view.php
- redirect('view.php?q='.$quiz->id);
- }
+ if (empty($navigation)) {
+ /// Attempt has finished
- $strgrade = get_string("grade");
- $strscore = get_string("score", "quiz");
+ if (! quiz_save_best_grade($quiz, $USER->id)) {
+ error("Sorry! Could not calculate your best grade!");
+ }
+
+ if (empty($quiz->popup) and !$quiz->feedback) {
+ // No need to stop on this page, go directly to view.php
+ redirect('view.php?q='.$quiz->id);
+ }
- if ($quiz->grade) {
- print_heading("$strscore: $result->sumgrades/$quiz->sumgrades ($result->percentage %)");
- print_heading("$strgrade: $result->grade/$quiz->grade");
- }
+ $strgrade = get_string("grade");
+ $strscore = get_string("score", "quiz");
- /// continue button - use javascript to close down child window if in popup
- include('attempt_close_js.php');
+ if ($quiz->grade) {
+ print_heading("$strscore: $result->sumgrades/$quiz->sumgrades ($result->percentage %)");
+ print_heading("$strgrade: $result->grade/$quiz->grade");
+ }
- if ($quiz->feedback) {
- $quiz->shuffleanswers = false; // Never shuffle answers in feedback
- quiz_print_quiz_questions($quiz, $questions, $result, $shuffleorder);
/// continue button - use javascript to close down child window if in popup
include('attempt_close_js.php');
- }
- if (empty($quiz->popup)) {
- print_footer($course);
- }
+ if ($quiz->feedback) {
+ $quiz->shuffleanswers = false; // Never shuffle answers in feedback
+
+ /// Make sure to get all questions in case not all are shown
+ /// in quiz all the time.
+ $questions = quiz_get_attempt_questions($quiz, $attempt);
+ quiz_print_quiz_questions($quiz, $questions,
+ quiz_grade_responses($quiz, $questions, $unattempt->id),
+ $shuffleorder);
+ /// continue button - use javascript to close down child window if in popup
+ include('attempt_close_js.php');
+ }
- exit;
+ if (empty($quiz->popup)) {
+ print_footer($course);
+ }
+
+ exit;
+ }
+ } else {
+ $navigation= 1;
+ $shuffleorder= NULL;
}
@@ -289,7 +308,7 @@
$questions = quiz_get_attempt_questions($quiz, $attempt, true);
if ($quiz->attemptonlast && $attemptnumber >= 2 and
- $quiz->attempts == 0 || !unattempt) {
+ $quiz->attempts == 0 || !$unattempt) {
// There are unlimited attempts or it is a new attempt.
// As the attempt also builds on the last, we can here
// have the student see the scores of the pre-entered
@@ -303,7 +322,8 @@
// We do not show feedback or correct answers during an attempt:
$quiz->feedback = $quiz->correctanswers = false;
- if (!quiz_print_quiz_questions($quiz, $questions, $result)) {
+ if (!quiz_print_quiz_questions($quiz, $questions,
+ $result, $shuffleorder, $navigation)) {
print_continue("view.php?id=$cm->id");
}
3  mod/quiz/db/mysql.php
View
@@ -302,6 +302,9 @@ function quiz_upgrade($oldversion) {
table_column('quiz_categories', '', 'sortorder', '', '', '', '999');
}
+ if ($oldversion < 2005010300) {
+ table_column("quiz", "", "questionsperpage", "integer", "10", "", "0", "not null", "review");
+ }
return true;
}
1  mod/quiz/db/mysql.sql
View
@@ -26,6 +26,7 @@ CREATE TABLE `prefix_quiz` (
`correctanswers` tinyint(4) NOT NULL default '1',
`grademethod` tinyint(4) NOT NULL default '1',
`review` tinyint(4) NOT NULL default '0',
+ `questionsperpage` int(10) NOT NULL default '0',
`shufflequestions` tinyint(4) NOT NULL default '0',
`shuffleanswers` tinyint(4) NOT NULL default '0',
`questions` text NOT NULL,
6 mod/quiz/db/postgres7.php
View
@@ -275,7 +275,7 @@ function quiz_upgrade($oldversion) {
}
if ($oldversion < 2004120501) {
- table_column("quiz_calculated", "", "correctanswerformat", "integer", "10", "", "2", "not null", "correctanswerlength");
+ table_column("quiz_calculated", "", "correctanswerformat", "integer", "10", "", "0", "not null", "correctanswerlength");
}
if ($oldversion < 2004121400) { // New field to determine popup window behaviour
@@ -287,6 +287,10 @@ function quiz_upgrade($oldversion) {
table_column('quiz_categories', '', 'sortorder', '', '', '', '999');
}
+ if ($oldversion < 2005010300) {
+ table_column("quiz", "", "questionsperpage", "integer", "10", "", "0", "not null", "review");
+ }
+
return true;
}
1  mod/quiz/db/postgres7.sql
View
@@ -26,6 +26,7 @@ CREATE TABLE prefix_quiz (
correctanswers integer NOT NULL default '1',
grademethod integer NOT NULL default '1',
review integer NOT NULL default '0',
+ questionsperpage integer NOT NULL default '0',
shufflequestions integer NOT NULL default '0',
shuffleanswers integer NOT NULL default '0',
questions text NOT NULL default '',
229 mod/quiz/lib.php
View
@@ -290,6 +290,13 @@ function print_question_formulation_and_controls($question,
.' been implemented for question type '.$this->name());
}
+ function actual_number_of_questions($question) {
+ /// Used for the feature number-of-questions-per-page
+ /// to determine the actual number of questions wrapped
+ /// by this question. The default is ONE!
+ return 1;
+ }
+
function grade_response($question, $nameprefix) {
// Analyzes $question->response[] and determines the result
// The result is to be returned in this structure:
@@ -809,7 +816,7 @@ function quiz_get_attempt_questions($quiz, $attempt, $attempting = false) {
$prevresponses= array();
while (--$prevattempt) {
$prevresponses = get_records_sql("
- SELECT r.question, r.answer, r.attempt
+ SELECT r.question, r.answer, r.attempt, r.grade
FROM {$CFG->prefix}quiz_responses r, {$CFG->prefix}quiz_attempts a
WHERE a.quiz='$quiz->id' AND a.userid='$attempt->userid'
AND a.attempt='$prevattempt' AND r.attempt=a.id ");
@@ -984,10 +991,125 @@ function quiz_print_possible_question_image($quizid, $question) {
}
}
-function quiz_print_quiz_questions($quiz, $questions,
- $results=NULL, $shuffleorder=NULL) {
+function quiz_navigation_javascript($link) {
+ return "javascript:navigate($link);";
+}
+
+function quiz_print_navigation_panel($questions, $questionsperpage, $navigation) {
+ global $QUIZ_QTYPES;
+
+ $numberinglayout = array();
+ $nextqnumber = 1;
+ foreach ($questions as $question) {
+ if ($qnumberinc = $QUIZ_QTYPES[$question->qtype]
+ ->actual_number_of_questions($question)) {
+ $numberinglayout[] = $nextqnumber;
+ $nextqnumber += $qnumberinc;
+ }
+ }
+
+ if ($nextqnumber - $qnumberinc <= $questionsperpage) {
+ /// The total number of questions does not exceed the maximum
+ /// number of allowed questions per page so...
+ return 0;
+ }
+ /// else - Navigation menu will be printed!
+
+ ///////////////////////////////////////////////
+ /// Determine the layout of the navigation menu
+ ///////////////////////////////////////////////
+ if (1 == $questionsperpage) {
+ /// The simple case:
+ $pagelinkagelayout = $pagenavigationlayout = $numberinglayout;
+
+ } else {
+ /// More complicated:
+ $pagenavigationlayout = array();
+ $pagelinkagelayout = array($currentpagestart = 1);
+ foreach ($numberinglayout as $questionnumber) {
+ if ($questionnumber - $currentpagestart >= $questionsperpage) {
+ $pagenavigationlayout[] = $currentpagestart
+ .'-'. ($questionnumber - 1);
+ if ($currentpagestart < $navigation
+ && $navigation < $questionnumber) {
+ // $navigation is out of sync so adjust for robustness
+ $navigation = $currentpagestart;
+ }
+ $pagelinkagelayout[] = $currentpagestart = $questionnumber;
+ }
+ }
+ $pagenavigationlayout[] = $currentpagestart .'-'. ($nextqnumber - 1);
+ if ($currentpagestart < $navigation) {
+ // $firsquestion is out of sync so adjust it for robustness...
+ $navigation = $currentpagestart;
+ }
+ }
+
+ foreach ($pagelinkagelayout as $key => $link) {
+ if ($link < $navigation) {
+ $previouspagelink = $link;
+ } else if ($link == $navigation) {
+ $currentnavigationtitle = $pagenavigationlayout[$key];
+ } else {
+ $endpagelink = $link;
+ if (false == isset($nextpagelink)) {
+ $nextpagelink = $link;
+ }
+ }
+ }
+
+ ///////////////////////////////////////////////
+ /// Print the navigation meny
+ ///////////////////////////////////////////////
+ print_simple_box_start('center', '*');
+ echo '<table><tr><td colspan="5" align="center"><table><tr>';
+ foreach ($pagelinkagelayout as $key => $link) {
+ echo '<td align="center">&nbsp;';
+ if ($link != $navigation) {
+ echo '<a href="' . quiz_navigation_javascript($link) . '">';
+ }
+ echo $pagenavigationlayout[$key];
+ if ($link != $navigation) {
+ echo '</a>';
+ }
+ echo '&nbsp;</td>';
+ }
+ echo '</tr></table></td></tr><tr><td width="20%" align="left">';
+ if (isset($previouspagelink)) {
+ echo '<a href="' . quiz_navigation_javascript('1') . '">|&lt;&lt;&lt;</a></td><td width="20%" align="center" cellpadding="2">';
+ echo '<a href="' . quiz_navigation_javascript($previouspagelink) . '">&lt;&lt;&lt;</a></td>';
+ } else {
+ echo '</td><td width="20%"></td>';
+ }
+ echo '<td width="20%" align="center"><b>';
+ echo $currentnavigationtitle;
+ echo '</b></td><td width="20%" align="center" cellpadding="2">';
+ if (isset($nextpagelink)) {
+ echo '<a href="';
+ echo quiz_navigation_javascript($nextpagelink);
+ echo '">&gt;&gt;&gt;</a></td><td width="20%" align="right"><a href="';
+ echo quiz_navigation_javascript($endpagelink);
+ echo '">&gt;&gt;&gt;|</a>';
+ } else {
+ echo '</td><td width="20%">';
+ }
+ echo '</td></tr></table>';
+ print_simple_box_end();
+
+ ////////////////////////////////////////////////
+ /// Return the potentially adjusted $navigation
+ ////////////////////////////////////////////////
+ return $navigation;
+}
+
+function quiz_print_quiz_questions($quiz, $questions, $results=NULL,
+ $shuffleorder=NULL, $navigation=0) {
// Prints a whole quiz on one page.
+ if ($navigation < 0) {
+ $navigation = 0; // For robustness
+ }
+
global $QUIZ_QTYPES;
/// Check arguments
@@ -1025,7 +1147,7 @@ function quiz_print_quiz_questions($quiz, $questions,
?>
<script language="javascript" type="text/javascript">
<!--
- document.write("<form method=\"post\" action=\"attempt.php\" <?php print(addslashes($onsubmit));?>>\n");
+ document.write("<form name=\"responseform\" method=\"post\" action=\"attempt.php\" <?php print(addslashes($onsubmit));?>>\n");
// -->
</script>
<noscript>
@@ -1033,12 +1155,19 @@ function quiz_print_quiz_questions($quiz, $questions,
</noscript>
<?php
} else {
- echo "<form method=\"post\" action=\"attempt.php\" $onsubmit>\n";
+ echo "<form name=\"responseform\" method=\"post\" action=\"attempt.php\" $onsubmit>\n";
}
// END EDIT
echo "<input type=\"hidden\" name=\"q\" value=\"$quiz->id\" />\n";
- // $count = 0;
+ if ($navigation && $quiz->questionsperpage) {
+ echo '<input type="hidden" id="navigation" name="navigation" value="0" />';
+ $navigation = quiz_print_navigation_panel($questions,
+ $quiz->questionsperpage, $navigation);
+ } else {
+ $navigation = 0;
+ }
+
$nextquestionnumber = 1;
$questionorder = array();
@@ -1055,18 +1184,31 @@ function quiz_print_quiz_questions($quiz, $questions,
$questionorder[] = $question->id;
- if ($results && isset($results->details[$question->id])) {
- $details = $results->details[$question->id];
+ if (0 == $navigation
+ || $navigation <= $nextquestionnumber
+ && $nextquestionnumber - $navigation < $quiz->questionsperpage) {
+ if ($results && isset($results->details[$question->id])) {
+ $details = $results->details[$question->id];
+ } else {
+ $details = false;
+ }
+
+ echo "<br />";
+ print_simple_box_start("center", "90%");
+ $nextquestionnumber = $QUIZ_QTYPES[$question->qtype]->print_question
+ ($nextquestionnumber, $quiz, $question, $readonly, $details);
+ print_simple_box_end();
} else {
- $details = false;
+ $nextquestionnumber += $QUIZ_QTYPES[$question->qtype]
+ ->actual_number_of_questions($question);
}
+ }
- print_simple_box_start("center", "90%");
- $nextquestionnumber = $QUIZ_QTYPES[$question->qtype]->print_question
- ($nextquestionnumber, $quiz, $question, $readonly, $details);
- print_simple_box_end();
- echo "<br />";
+ if ($navigation) {
+ quiz_print_navigation_panel($questions, $quiz->questionsperpage,
+ $navigation);
}
+ echo "<br />";
if (empty($readonly)) {
if (!empty($quiz->shufflequestions)) { // Things have been mixed up, so pass the question order
@@ -1083,11 +1225,20 @@ function quiz_print_quiz_questions($quiz, $questions,
echo "<center><strong>".get_string("noscript","quiz")."</strong></center>\n";
echo "</noscript>\n";
} else {
- echo "<center>\n<input type=\"submit\" value=\"".get_string("savemyanswers", "quiz")."\" />\n</center>";
- }
+ echo "<center>\n<input type=\"submit\" value=\"".get_string("savemyanswers", "quiz")."\" />\n</center>";
+ }
}
echo "</form>";
+ if ($navigation && $quiz->questionsperpage) {
+ echo '<script language="javascript" type="text/javascript">';
+ echo "function navigate(link) {
+ document.responseform.navigation.value=link;
+ document.responseform.submit();
+ }
+ </script>";
+ }
+
return true;
}
@@ -1695,7 +1846,8 @@ function quiz_calculate_best_attempt($quiz, $attempts) {
}
-function quiz_save_attempt($quiz, $questions, $result, $attemptnum) {
+function quiz_save_attempt($quiz, $questions, $result,
+ $attemptnum, $finished = true) {
/// Given a quiz, a list of attempted questions and a total grade
/// this function saves EVERYTHING so it can be reconstructed later
/// if necessary.
@@ -1718,7 +1870,9 @@ function quiz_save_attempt($quiz, $questions, $result, $attemptnum) {
// Now let's complete this record and save it
$attempt->sumgrades = $result->sumgrades;
- $attempt->timefinish = time();
+ if ($finished) {
+ $attempt->timefinish = time();
+ }
$attempt->timemodified = time();
if (!update_record("quiz_attempts", $attempt)) {
@@ -1741,7 +1895,8 @@ function quiz_save_attempt($quiz, $questions, $result, $attemptnum) {
->convert_to_response_answer_field($question->response);
$response->answer = $responseanswerfield;
- } else {
+
+ } else if (!isset($response->answer)) {
$response->answer = '';
}
@@ -1770,7 +1925,7 @@ function quiz_extract_correctanswers($answers, $nameprefix) {
return $correctanswers;
}
-function quiz_grade_responses($quiz, $questions) {
+function quiz_grade_responses($quiz, $questions, $attemptid=0) {
/// Given a list of questions (including ->response[] and ->maxgrade
/// on each question) this function does all the hard work of calculating the
/// score for each question, as well as a total grade for
@@ -1786,6 +1941,8 @@ function quiz_grade_responses($quiz, $questions) {
/// []->grade (Grade awarded on the specifik question)
/// []->answers[] (result answer records for the question response(s))
/// []->correctanswers[] (answer records if question response(s) had been correct)
+/// - HOWEVER, ->answers[] and ->correctanswers[] are supplied only
+/// if there is a response on the question...
/// The array ->answers[] is indexed like ->respoonse[] on its corresponding
/// element in $questions. It is the case for ->correctanswers[] when
/// there can be multiple responses per question but if there can be only one
@@ -1802,23 +1959,33 @@ function quiz_grade_responses($quiz, $questions) {
$result->sumgrades = 0.0;
foreach ($questions as $qid => $question) {
- if (empty($question->qtype)) {
+ if (!isset($question->response) && $attemptid) {
+ /// No response on the question
+ /// This case is common if the quiz shows a limited
+ /// number of questions per page.
+ $response = get_record('quiz_responses', 'attempt',
+ $attemptid, 'question', $qid);
+ $resultdetails->grade = $response->grade;
+
+ } else if (empty($question->qtype)) {
continue;
- }
- $resultdetails = $QUIZ_QTYPES[$question->qtype]->grade_response
+ } else {
+
+ $resultdetails = $QUIZ_QTYPES[$question->qtype]->grade_response
($question, quiz_qtype_nameprefix($question));
- // Negative grades will not do:
- if (((float)($resultdetails->grade)) <= 0.0) {
- $resultdetails->grade = 0.0;
+ // Negative grades will not do:
+ if (((float)($resultdetails->grade)) <= 0.0) {
+ $resultdetails->grade = 0.0;
- // Neither will extra credit:
- } else if (((float)($resultdetails->grade)) >= 1.0) {
- $resultdetails->grade = $question->maxgrade;
+ // Neither will extra credit:
+ } else if (((float)($resultdetails->grade)) >= 1.0) {
+ $resultdetails->grade = $question->maxgrade;
- } else {
- $resultdetails->grade *= $question->maxgrade;
+ } else {
+ $resultdetails->grade *= $question->maxgrade;
+ }
}
// if time limit is enabled and exceeded, return zero grades
19 mod/quiz/mod.html
View
@@ -63,6 +63,9 @@
if (!isset($form->review)) {
$form->review = $CFG->quiz_allowreview;
}
+ if (!isset($form->questionsperpage)) {
+ $form->questionsperpage = 0;
+ }
if (!isset($form->shufflequestions)) {
$form->shufflequestions = $CFG->quiz_shufflequestions;
}
@@ -194,6 +197,22 @@
</tr>
<?php } ?>
+<tr valign="top">
+ <td align="right"><b><?php print_string('questionsperpage', 'quiz') ?>:</b></td>
+ <td>
+ <?php
+ $perpage= array();
+ for ($i=0; $i<=50; ++$i) {
+ $perpage[$i] = $i;
+ }
+ $perpage[0] = get_string('allinone', 'quiz');
+
+ choose_from_menu($perpage, 'questionsperpage', $form->questionsperpage, '');
+ helpbutton('questionsperpage', get_string('questionsperpage'), 'quiz');
+ ?>
+ </td>
+</tr>
+
<?php if (!$CFG->quiz_fix_shufflequestions) { ?>
<tr valign="top">
<td align="right"><b><?php print_string("shufflequestions", "quiz") ?>:</b></td>
9 mod/quiz/questiontypes/description/questiontype.php
View
@@ -40,6 +40,15 @@ function print_question($currentnumber, $quiz, $question,
return $currentnumber;
}
+ function actual_number_of_questions($question) {
+ /// Used for the feature number-of-questions-per-page
+ /// to determine the actual number of questions wrapped
+ /// by this question.
+ /// The question type description is not even a question
+ /// in itself so it will return ZERO!
+ return 0;
+ }
+
function grade_response($question, $nameprefix) {
$result->grade = 0.0;
$result->answers = array();
2  mod/quiz/version.php
View
@@ -5,7 +5,7 @@
// This fragment is called by moodle_needs_upgrading() and /admin/index.php
////////////////////////////////////////////////////////////////////////////////
-$module->version = 2005010201; // The (date) version of this module
+$module->version = 2005010300; // The (date) version of this module
$module->requires = 2005010100; // Requires this Moodle version
$module->cron = 0; // How often should cron check this module (seconds)?
Please sign in to comment.
Something went wrong with that request. Please try again.