From: kaipe Date: Mon, 3 Jan 2005 00:41:33 +0000 (+0000) Subject: New feature: X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=d70ccc495ca904789940f281655b94d9a8e8637b;p=moodle.git New feature: Maximum-number-of-questions-per-page --- diff --git a/lang/en/quiz.php b/lang/en/quiz.php index 17474deb10..6b3e121959 100644 --- a/lang/en/quiz.php +++ b/lang/en/quiz.php @@ -11,6 +11,7 @@ $string['addrandom1'] = ' Add '; $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['questioninuse'] = 'The question \'$a\' is currently being used:'; $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'; diff --git a/mod/quiz/attempt.php b/mod/quiz/attempt.php index ccc1647aaf..7d46c9bb7d 100644 --- a/mod/quiz/attempt.php +++ b/mod/quiz/attempt.php @@ -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"); } diff --git a/mod/quiz/db/mysql.php b/mod/quiz/db/mysql.php index ce3f8a7ffb..591bd5cceb 100644 --- a/mod/quiz/db/mysql.php +++ b/mod/quiz/db/mysql.php @@ -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; } diff --git a/mod/quiz/db/mysql.sql b/mod/quiz/db/mysql.sql index a99cb95d11..0f53ecdb75 100644 --- a/mod/quiz/db/mysql.sql +++ b/mod/quiz/db/mysql.sql @@ -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, diff --git a/mod/quiz/db/postgres7.php b/mod/quiz/db/postgres7.php index 874388c426..ec013e6a49 100644 --- a/mod/quiz/db/postgres7.php +++ b/mod/quiz/db/postgres7.php @@ -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; } diff --git a/mod/quiz/db/postgres7.sql b/mod/quiz/db/postgres7.sql index ff3ca3b8bf..391af35d64 100644 --- a/mod/quiz/db/postgres7.sql +++ b/mod/quiz/db/postgres7.sql @@ -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 '', diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php index 6afb62d47e..7146103ff4 100644 --- a/mod/quiz/lib.php +++ b/mod/quiz/lib.php @@ -290,6 +290,13 @@ class quiz_default_questiontype { .' 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 ''; + } else { + echo ''; + } + echo '
'; + foreach ($pagelinkagelayout as $key => $link) { + echo ''; + } + echo '
 '; + if ($link != $navigation) { + echo ''; + } + echo $pagenavigationlayout[$key]; + if ($link != $navigation) { + echo ''; + } + echo ' 
'; + if (isset($previouspagelink)) { + echo '|<<<'; + echo '<<<'; + echo $currentnavigationtitle; + echo ''; + if (isset($nextpagelink)) { + echo '>>>>>>|'; + } else { + echo ''; + } + echo '
'; + 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, ?> \n"; + echo "
\n"; } // END EDIT echo "id\" />\n"; - // $count = 0; + if ($navigation && $quiz->questionsperpage) { + echo ''; + $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 "
"; + 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 "
"; + if ($navigation) { + quiz_print_navigation_panel($questions, $quiz->questionsperpage, + $navigation); } + echo "
"; 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 "
".get_string("noscript","quiz")."
\n"; echo "\n"; } else { - echo "
\n\n
"; - } + echo "
\n\n
"; + } } echo "
"; + if ($navigation && $quiz->questionsperpage) { + echo '"; + } + 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 diff --git a/mod/quiz/mod.html b/mod/quiz/mod.html index 4ff3814589..8fc002d2f8 100644 --- a/mod/quiz/mod.html +++ b/mod/quiz/mod.html @@ -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 @@ + + : + + questionsperpage, ''); + helpbutton('questionsperpage', get_string('questionsperpage'), 'quiz'); + ?> + + + quiz_fix_shufflequestions) { ?> : diff --git a/mod/quiz/questiontypes/description/questiontype.php b/mod/quiz/questiontypes/description/questiontype.php index 2e90d0a785..f067300d56 100644 --- a/mod/quiz/questiontypes/description/questiontype.php +++ b/mod/quiz/questiontypes/description/questiontype.php @@ -40,6 +40,15 @@ class quiz_description_qtype extends quiz_default_questiontype { 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(); diff --git a/mod/quiz/version.php b/mod/quiz/version.php index 9d272aba95..0dc77dec81 100644 --- a/mod/quiz/version.php +++ b/mod/quiz/version.php @@ -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)?